From 2eebba566288364c010986ede51e12ffbf36921d Mon Sep 17 00:00:00 2001 From: Jack Mac Date: Tue, 19 Oct 2021 11:44:01 -0400 Subject: [PATCH] updates tree node widgets --- imgui-examples/examples/test_window_impl.rs | 63 ++++++++------- imgui/src/widget/tree.rs | 86 +++++++++++++++------ 2 files changed, 96 insertions(+), 53 deletions(-) diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index d7a31c2..bd75cc9 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -383,24 +383,24 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.checkbox("No collapse", &mut state.no_collapse); ui.checkbox("No close", &mut state.no_close); - TreeNode::new("Style").build(ui, || { + if let Some(_t) = ui.tree_node("Style") { ui.show_default_style_editor(); - }); + } } if CollapsingHeader::new("Widgets").build(ui) { - TreeNode::new("Tree").build(ui, || { + if let Some(_t) = ui.tree_node("Tree") { for i in 0..5 { - TreeNode::new(format!("Child {}", i)).build(ui, || { + if let Some(_t) = ui.tree_node(format!("Child {}", i)) { ui.text("blah blah"); ui.same_line(); if ui.small_button("print") { println!("Child {} pressed", i); } - }); + } } - }); + } - TreeNode::new("Bullets").build(ui, || { + if let Some(_t) = ui.tree_node("Bullets") { ui.bullet_text("Bullet point 1"); ui.bullet_text("Bullet point 2\nOn multiple lines"); ui.bullet(); @@ -408,22 +408,23 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.bullet(); ui.small_button("Button"); - }); - TreeNode::new("Colored text").build(ui, || { + } + + if let Some(_t) = ui.tree_node("Colored text") { ui.text_colored([1.0, 0.0, 1.0, 1.0], "Pink"); ui.text_colored([1.0, 1.0, 0.0, 1.0], "Yellow"); ui.text_disabled("Disabled"); - }); + } - TreeNode::new("Multi-line text").build(ui, || { + if let Some(_t) = ui.tree_node("Multi-line text") { ui.input_text_multiline( "multiline", &mut state.text_multiline, [300., 100.], ).build(); - }); + } - TreeNode::new("Word wrapping").build(ui, || { + if let Some(_t) = ui.tree_node("Word wrapping") { ui.text_wrapped( "This text should automatically wrap on the edge of \ the window.The current implementation for text \ @@ -441,8 +442,9 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.text("Test paragraph 2:"); // TODO - }); - TreeNode::new("UTF-8 Text").build(ui, || { + } + + if let Some(_t) = ui.tree_node("UTF-8 Text") { ui.text_wrapped( "CJK text will only appear if the font was loaded \ with theappropriate CJK character ranges. Call \ @@ -454,7 +456,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.text("Kanjis: 日本語 (nihongo)"); ui.input_text("UTF-8 input", &mut state.buf) .build(); - }); + } ui.radio_button("radio a", &mut state.radio_button, 0); ui.same_line(); @@ -539,7 +541,7 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.input_scalar_n("input scalar int array", &mut state.vec3i).build(); ui.input_scalar_n("input scalar float array", &mut state.vec3f).build(); - TreeNode::new("Multi-component Widgets").build(ui, || { + if let Some(_t) = ui.tree_node("Multi-component Widgets") { ui.input_float2("input float2", &mut state.vec2f) .build(); ui.input_int2("input int2", &mut state.vec2i) @@ -551,9 +553,9 @@ fn show_test_window(ui: &Ui, state: &mut State, opened: &mut bool) { ui.input_int3("input int3", &mut state.vec3i) .build(); ui.spacing(); - }); + }; - TreeNode::new("Color/Picker Widgets").build(ui, || { + if let Some(_t) = ui.tree_node("Color/Picker Widgets") { let s = &mut state.color_edit; ui.checkbox("With HDR", &mut s.hdr); ui.same_line(); @@ -652,12 +654,12 @@ CTRL+click on individual component to input value.\n", b = b.reference_color(s.ref_color_v) } b.build(ui); - }); + } } if CollapsingHeader::new("Layout").build(ui) { - TreeNode::new("Tabs").build(ui, || { - TreeNode::new("Basic").build(ui, || { + if let Some(_t) = ui.tree_node("Tabs") { + if let Some(_t) = ui.tree_node("Basic") { TabBar::new("basictabbar").build(ui, || { TabItem::new("Avocado").build(ui, || { ui.text("This is the Avocado tab!"); @@ -672,9 +674,9 @@ CTRL+click on individual component to input value.\n", ui.text("blah blah blah blah blah"); }); }); + } - }); - TreeNode::new("Advanced & Close button").build(ui, || { + if let Some(_t) = ui.tree_node("Advanced & Close button") { ui.separator(); let s = &mut state.tabs; @@ -725,11 +727,12 @@ CTRL+click on individual component to input value.\n", }); }); - }); - }); + } + } } + if CollapsingHeader::new("Popups & Modal windows").build(ui) { - TreeNode::new("Popups").build(ui, || { + if let Some(_t) = ui.tree_node("Popups") { ui.text_wrapped( "When a popup is active, it inhibits interacting \ with windows that are behind the popup. Clicking \ @@ -759,9 +762,9 @@ CTRL+click on individual component to input value.\n", } } }); - }); + } - TreeNode::new("Modals").build(ui, || { + if let Some(_t) = ui.tree_node("Modals") { ui.text_wrapped( "Modal windows are like popups but the user cannot close \ them by clicking outside the window." @@ -814,7 +817,7 @@ CTRL+click on individual component to input value.\n", ui.close_current_popup(); } }); - }); + } } }); } diff --git a/imgui/src/widget/tree.rs b/imgui/src/widget/tree.rs index 654ddab..cedfc4f 100644 --- a/imgui/src/widget/tree.rs +++ b/imgui/src/widget/tree.rs @@ -86,39 +86,79 @@ impl From<*mut T> for TreeNodeId { } } -/// Builder for a tree node widget -#[derive(Copy, Clone, Debug)] -#[must_use] -pub struct TreeNode { - id: TreeNodeId, - label: Option, - opened: bool, - opened_cond: Condition, - flags: TreeNodeFlags, -} +impl Ui { + /// Constructs a new tree node with just a name, and pushes it. + /// + /// Use [tree_node_config] to access a builder to put additional + /// configurations on the tree node. + /// + /// [tree_node_config]: Self::tree_node_config + pub fn tree_node(&self, id: I) -> Option> + where + I: Into>, + T: AsRef, + { + self.tree_node_config(id).push() + } -impl> TreeNode { - /// Constructs a new tree node builder - pub fn new>>(id: I) -> TreeNode { + /// Constructs a new tree node builder. + /// + /// Use [tree_node] to build a simple node with just a name. + /// + /// [tree_node]: Self::tree_node + pub fn tree_node_config(&self, id: I) -> TreeNode<'_, T> + where + I: Into>, + T: AsRef, + { TreeNode { id: id.into(), label: None, opened: false, opened_cond: Condition::Never, flags: TreeNodeFlags::empty(), + ui: self, } } } -impl, L: AsRef> TreeNode { +/// Builder for a tree node widget +#[derive(Copy, Clone, Debug)] +#[must_use] +pub struct TreeNode<'a, T, L = &'static str> { + id: TreeNodeId, + label: Option, + opened: bool, + opened_cond: Condition, + flags: TreeNodeFlags, + ui: &'a Ui, +} + +impl<'a, T: AsRef> TreeNode<'a, T, &'static str> { + /// Constructs a new tree node builder + #[deprecated(since = "0.9.0", note = "use `ui.tree_node` or `ui.tree_node_config`")] + pub fn new>>(id: I, ui: &'a Ui) -> TreeNode<'a, T, &'static str> { + TreeNode { + id: id.into(), + label: None, + opened: false, + opened_cond: Condition::Never, + flags: TreeNodeFlags::empty(), + ui, + } + } +} + +impl<'a, T: AsRef, L: AsRef> TreeNode<'a, T, L> { /// Sets the tree node label - pub fn label>, L2: AsRef>(self, label: L2) -> TreeNode { + pub fn label>, L2: AsRef>(self, label: L2) -> TreeNode<'a, T, L2> { TreeNode { label: Some(label), id: self.id, opened: self.opened, opened_cond: self.opened_cond, flags: self.flags, + ui: self.ui, } } @@ -241,7 +281,7 @@ impl, L: AsRef> TreeNode { /// rendered, the token can be popped by calling `.pop()`. /// /// Returns `None` if the tree node is not open and no content should be rendered. - pub fn push(self, ui: &Ui) -> Option> { + pub fn push(self) -> Option> { let open = unsafe { if self.opened_cond != Condition::Never { sys::igSetNextItemOpen(self.opened, self.opened_cond as i32); @@ -249,9 +289,9 @@ impl, L: AsRef> TreeNode { match self.id { TreeNodeId::Str(id) => { let (id, label) = match self.label { - Some(label) => ui.scratch_txt_two(id, label), + Some(label) => self.ui.scratch_txt_two(id, label), None => { - let v = ui.scratch_txt(id); + let v = self.ui.scratch_txt(id); (v, v) } }; @@ -263,15 +303,15 @@ impl, L: AsRef> TreeNode { self.flags.bits() as i32, fmt_ptr(), match self.label { - Some(v) => ui.scratch_txt(v), - None => ui.scratch_txt(""), + Some(v) => self.ui.scratch_txt(v), + None => self.ui.scratch_txt(""), }, ), } }; if open { Some(TreeNodeToken::new( - ui, + self.ui, !self.flags.contains(TreeNodeFlags::NO_TREE_PUSH_ON_OPEN), )) } else { @@ -282,8 +322,8 @@ impl, L: AsRef> TreeNode { /// Returns the result of the closure, if it is called. /// /// Note: the closure is not called if the tree node is not open. - pub fn build R>(self, ui: &Ui, f: F) -> Option { - self.push(ui).map(|_node| f()) + pub fn build R>(self, f: F) -> Option { + self.push().map(|_node| f()) } }