From bb45d1c5b6fc0495dfe4d7814fab9aefbf9f7727 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 28 Jun 2021 15:27:30 +0530 Subject: [PATCH 01/45] feat: added TreeNode2D to UI --- fury/ui.py | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) diff --git a/fury/ui.py b/fury/ui.py index 99cace333..7a9aaa84b 100644 --- a/fury/ui.py +++ b/fury/ui.py @@ -4,6 +4,7 @@ from string import printable import numpy as np +from numpy.core.fromnumeric import size import vtk import os import abc @@ -5243,3 +5244,186 @@ def _set_position(self, coords): pass # self.actor.SetPosition(*coords) # self.container.SetPosition(*coords) + + +class TreeNode2D(UI): + """ + """ + def __init__(self, label, parent=None, children=None, + position=(0, 0), size=(200, 200), indent=5, + child_indent=10, child_height=25): + """ + """ + self.children = children + if self.children is None: + self.children = [] + + self._child_nodes = [] + self.parent = parent + self.indent = indent + + self.label = label + + self.child_indent = child_indent + self.child_height = child_height + self.content_panel_size = size + self.expanded = False + super(TreeNode2D, self).__init__(position) + self.resize(size) + self.panel.color = (0.3, 0.3, 0.3) + self.panel.opacity = 0.8 + + def _setup(self): + """Setup this UI element.""" + self.panel = Panel2D(size=(self.content_panel_size[0], + self.child_height)) + self.content_panel = Panel2D(size=self.content_panel_size) + + self.button_icons = [] + self.button_icons.append(('expand', + read_viz_icons(fname="circle-up.png"))) + self.button_icons.append(('collapse', + read_viz_icons(fname="circle-down.png"))) + + self.button = Button2D(icon_fnames=self.button_icons) + self.label_text = TextBlock2D(text=self.label) + + self.panel.add_element(self.label_text, + (self.indent, + self.panel.size[1]-self.child_height)) + + self.panel.add_element(self.button, self.panel.size-self.button.size) + self.panel.add_element(self.content_panel, + (0, -self.content_panel_size[1])) + + self.button.on_left_mouse_button_clicked = self.toggle_view + + if self.children: + for child in self.children: + self.add_node(child) + + if self.expanded: + self.button.set_icon_by_name('expand') + else: + self.button.set_icon_by_name('collapse') + + def _get_actors(self): + """ Get the actors composing this UI component. + """ + return self.panel.actors + + def _add_to_scene(self, _scene): + """ Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + """ + self.panel.add_to_scene(_scene) + + def _set_position(self, _coords): + """ Position the lower-left corner of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + """ + self.panel.position = _coords + + def _get_size(self): + self.panel.size + + def add_node(self, node): + """Add a child node in the current node. + + Parameters + ---------- + node: :class: `TreeNode2D` + Node that isto be added + """ + self._child_nodes.append(node) + node.parent = self + + _node_size = (self.panel.size[0] - self.indent - self.child_indent, + self.child_height) + + _node_coords = (self.indent+self.child_indent, + self.panel.size[1]-self._child_nodes[-1].position[1] - + self.child_height) + + node.resize(_node_size) + node.content_panel.set_visibility(False) + self.content_panel.add_element(node, _node_coords) + + def resize(self, size): + """ Resizes the Tree Node. + + Parameters + ---------- + size : (int, int) + New width and height in pixels. + """ + offset = 0 + self.panel.resize((size[0], self.child_height)) + self.content_panel.resize(size) + self.label_text.resize((size[0]-self.button.size[0], + self.child_height)) + + self.panel.update_element(self.label_text, + (self.indent, self.panel.size[1] - + self.child_height)) + + self.panel.update_element(self.button, + (self.panel.size - self.button.size)) + + self.panel.update_element(self.content_panel, (0, -size[1])) + + if self.children: + for _, child in enumerate(self._child_nodes): + offset += self.child_height + _child_size = (self.panel.size[0] - self.indent - + self.child_indent, self.child_height) + + _child_coords = (self.indent+self.child_indent, + self.content_panel.size[1]-offset) + + child.panel.resize(_child_size) + self.content_panel.update_element(child, _child_coords) + + def toggle_view(self, i_ren, _obj, _element): + self.expanded = not self.expanded + self.content_panel.set_visibility(self.expanded) + + if self.expanded: + if self.parent is not None: + idx = self.parent._child_nodes.index(self) + self.update_children_coords(idx, self.content_panel.size[1]) + + self.button.set_icon_by_name('expand') + else: + if self.parent is not None: + idx = self.parent._child_nodes.index(self) + self.update_children_coords(idx, -self.content_panel.size[1]) + + self.button.set_icon_by_name('collapse') + + i_ren.force_render() + + def update_children_coords(self, current_child_idx, size_offset): + """Updates the coords of the children below a specific child + + Parameters + ---------- + current_child_idx: int + The index of the current child + size_offset: int + Size by which below children are to be offset + """ + if 0 >= current_child_idx > len(self._child_nodes): + raise ValueError( + f'Child index {current_child_idx} does not exist' + ) + + for child in self.parent._child_nodes[current_child_idx+1:]: + child.position = (child.position[0], child.position[1]-size_offset) From 070b3b1327cec7b4da6009c30323b6764274ec95 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 30 Jun 2021 13:43:32 +0530 Subject: [PATCH 02/45] feat: added TreeNode2D, Tree2D to UI --- fury/ui.py | 358 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 316 insertions(+), 42 deletions(-) diff --git a/fury/ui.py b/fury/ui.py index 7a9aaa84b..935e00b03 100644 --- a/fury/ui.py +++ b/fury/ui.py @@ -13,7 +13,7 @@ from fury.interactor import CustomInteractorStyle from fury.io import load_image from fury.utils import set_input, rotate -from fury.actor import grid +from fury.actor import grid, label TWO_PI = 2 * np.pi @@ -5246,13 +5246,199 @@ def _set_position(self, coords): # self.container.SetPosition(*coords) -class TreeNode2D(UI): +class Tree2D(UI): + """Render nodes in tree form + + Attributes + ---------- + structure: List(Dict, Dict, .....) + [{'node': ['child', 'child']}, .....] + tree_name: str + Name of the tree + node_height: int + Space taken by each node vertically + indent: int + Global indentation for the parent/child nodes + nodes: list of :class: `TreeNode2D` + List of all parent nodes present in Tree2D + nodes_dict: dict + Dict with label, nodes as key/value pairs """ + + def __init__(self, structure, tree_name="", position=(0, 0), + size=(300, 300), node_height=30, color=(0.3, 0.3, 0.3), + opacity=0.8, indent=25): + """Initialize the UI element + + Parameter + --------- + structure: List(Dict, Dict, .....) + [{'node': ['child', 'child']}, .....] + tree_name: str, optional + Label for the tree + position : (float, float), optional + Absolute coordinates (x, y) of the lower-left corner of the + UI component + size : (int, int), optional + Width and height of the pixels of this UI component. + node_height: int, optional + Space taken by each node vertically + color : list of 3 floats, opational + Background color of the Tree2D + opacity: float, optional + Background opacity of the Tree2D + indent: int, optional + Global indentation for the parent/child nodes + """ + self.structure = structure + self.tree_name = tree_name + self.indent = indent + self._nodes = [] + self._nodes_dict = {} + self.node_height = node_height + + super(Tree2D, self).__init__(position) + self.resize(size) + self.base_node.color = color + self.base_node.opacity = opacity + + def _setup(self): + """Setup this UI element.""" + self.generate_tree(self.structure) + + self.base_node = TreeNode2D(label=self.tree_name, children=self._nodes, + expandable=False, expanded=True, + indent=self.indent, child_indent=self.indent, + child_height=self.node_height) + + def _get_actors(self): + """ Get the actors composing this UI component. + """ + return self.base_node.actors + + def _add_to_scene(self, _scene): + """ Add all subcomponents or VTK props that compose this UI component. + + Parameters + ---------- + scene : scene + """ + self.base_node.add_to_scene(_scene) + + def _set_position(self, _coords): + """ Position the lower-left corner of this UI component. + + Parameters + ---------- + coords: (float, float) + Absolute pixel coordinates (x, y). + """ + self.base_node.position = _coords + + def _get_size(self): + return self.base_node.size + + def generate_tree(self, structure): + """Generate the structure of the Tree2D + + Parameters + ---------- + structure: List(Dict, Dict, .....) + [{'node': ['child', 'child']}, .....] + """ + for obj in structure: + parent_label = list(obj.keys())[0] + child_labels = list(obj.values())[0] + + parent_node = TreeNode2D(label=parent_label) + child_nodes = [TreeNode2D(label=child_label) for child_label in + child_labels] + + for child_node in child_nodes: + parent_node.add_node(child_node) + + self._nodes.append(parent_node) + self._nodes_dict[parent_label] = parent_node + + def resize(self, size): + """ Resizes the Tree Node. + + Parameters + ---------- + size : (int, int) + New width and height in pixels. + """ + self.base_node.resize(size) + + @property + def nodes(self): + """Get all the nodes present in the Tree2D + + Returns + ------- + list of nodes + """ + return self._nodes + + @property + def nodes_dict(self): + """Get all the nodes present in the Tree2D in dict format + + Returns + ------- + dict with label, node as key, value + """ + return self._nodes_dict + + +class TreeNode2D(UI): + """Node/Leaf of a Tree2D UI + + Attributes + ---------- + children: list of :class: `TreeNode2D` + Sub nodes of the current node + parent: :class: `TreeNode2D` + Parent node of the current node + indent: int + Indentaion of the current node + label: str + Label text of the current node + expanded: bool + Whether the current node is expanded or not """ + def __init__(self, label, parent=None, children=None, position=(0, 0), size=(200, 200), indent=5, - child_indent=10, child_height=25): - """ + child_indent=10, child_height=25, color=(0.3, 0.3, 0.3), + opacity=0.8, expandable=True, expanded=False): + """Initialize the UI element + + Parameters + ---------- + label: str + Label text of the current node + children: list of :class: `TreeNode2D` + Sub nodes of the current node + parent: :class: `TreeNode2D` + Parent node of the current node + position : (float, float) + Absolute coordinates (x, y) of the lower-left corner of the + UI component + size : (int, int) + Width and height of the pixels of this UI component. + indent: int + Indentation of the current node + child_indent: int + Indentation of the child nodes + child_height: int + Space taken by each sub-node vertically + color : list of 3 floats + Background color of current node. + opacity: float + Background opacity of the current node + expandable: bool, optional + If the node should expand/collapse """ self.children = children if self.children is None: @@ -5266,37 +5452,45 @@ def __init__(self, label, parent=None, children=None, self.child_indent = child_indent self.child_height = child_height - self.content_panel_size = size - self.expanded = False + self.content_size = size + self.expandable = expandable + self.expanded = expanded + super(TreeNode2D, self).__init__(position) self.resize(size) - self.panel.color = (0.3, 0.3, 0.3) - self.panel.opacity = 0.8 + self.title_panel.color = color + self.title_panel.opacity = opacity def _setup(self): - """Setup this UI element.""" - self.panel = Panel2D(size=(self.content_panel_size[0], + """Setup this UI element. + Create a title panel. + Create a content panel. + Create expand/collapse button, label textblock. + Add all the sub UI elements to the title panel. + """ + self.title_panel = Panel2D(size=(self.content_size[0], self.child_height)) - self.content_panel = Panel2D(size=self.content_panel_size) + + self.content_panel = Panel2D(size=self.content_size) + self.label_text = TextBlock2D(text=self.label) self.button_icons = [] self.button_icons.append(('expand', read_viz_icons(fname="circle-up.png"))) + self.button_icons.append(('collapse', read_viz_icons(fname="circle-down.png"))) self.button = Button2D(icon_fnames=self.button_icons) - self.label_text = TextBlock2D(text=self.label) + self.button.on_left_mouse_button_clicked = self.toggle_view - self.panel.add_element(self.label_text, - (self.indent, - self.panel.size[1]-self.child_height)) + self.title_panel.add_element(self.label_text, (self.indent, 0)) - self.panel.add_element(self.button, self.panel.size-self.button.size) - self.panel.add_element(self.content_panel, - (0, -self.content_panel_size[1])) + self.title_panel.add_element(self.button, + self.title_panel.size-self.button.size) - self.button.on_left_mouse_button_clicked = self.toggle_view + self.title_panel.add_element(self.content_panel, + (0, -self.content_size[1])) if self.children: for child in self.children: @@ -5305,12 +5499,16 @@ def _setup(self): if self.expanded: self.button.set_icon_by_name('expand') else: + self.content_panel.set_visibility(False) self.button.set_icon_by_name('collapse') + if not self.expandable: + self.button.set_visibility(False) + def _get_actors(self): """ Get the actors composing this UI component. """ - return self.panel.actors + return self.title_panel.actors def _add_to_scene(self, _scene): """ Add all subcomponents or VTK props that compose this UI component. @@ -5319,7 +5517,7 @@ def _add_to_scene(self, _scene): ---------- scene : scene """ - self.panel.add_to_scene(_scene) + self.title_panel.add_to_scene(_scene) def _set_position(self, _coords): """ Position the lower-left corner of this UI component. @@ -5329,10 +5527,14 @@ def _set_position(self, _coords): coords: (float, float) Absolute pixel coordinates (x, y). """ - self.panel.position = _coords + self.title_panel.position = _coords def _get_size(self): - self.panel.size + if self.expanded: + return (self.title_panel.size[0], + self.title_panel.size[1]+self.content_panel.size[1]) + + return self.title_panel.size def add_node(self, node): """Add a child node in the current node. @@ -5345,14 +5547,9 @@ def add_node(self, node): self._child_nodes.append(node) node.parent = self - _node_size = (self.panel.size[0] - self.indent - self.child_indent, - self.child_height) - - _node_coords = (self.indent+self.child_indent, - self.panel.size[1]-self._child_nodes[-1].position[1] - + _node_coords = (self.indent+self.child_indent, self.children_size() - self.child_height) - node.resize(_node_size) node.content_panel.set_visibility(False) self.content_panel.add_element(node, _node_coords) @@ -5365,30 +5562,31 @@ def resize(self, size): New width and height in pixels. """ offset = 0 - self.panel.resize((size[0], self.child_height)) + self.title_panel.resize((size[0], self.child_height)) self.content_panel.resize(size) + self.label_text.resize((size[0]-self.button.size[0], self.child_height)) - self.panel.update_element(self.label_text, - (self.indent, self.panel.size[1] - - self.child_height)) + self.title_panel.update_element(self.label_text, + (self.indent, 0)) - self.panel.update_element(self.button, - (self.panel.size - self.button.size)) + self.title_panel.update_element(self.button, + (self.title_panel.size - + self.button.size)) - self.panel.update_element(self.content_panel, (0, -size[1])) + self.title_panel.update_element(self.content_panel, (0, -size[1])) - if self.children: - for _, child in enumerate(self._child_nodes): + if self._child_nodes: + for child in self._child_nodes: offset += self.child_height - _child_size = (self.panel.size[0] - self.indent - - self.child_indent, self.child_height) + _child_size = (size[0] - self.indent - + self.child_indent, child.children_size()) _child_coords = (self.indent+self.child_indent, self.content_panel.size[1]-offset) - child.panel.resize(_child_size) + child.resize(_child_size) self.content_panel.update_element(child, _child_coords) def toggle_view(self, i_ren, _obj, _element): @@ -5426,4 +5624,80 @@ def update_children_coords(self, current_child_idx, size_offset): ) for child in self.parent._child_nodes[current_child_idx+1:]: - child.position = (child.position[0], child.position[1]-size_offset) + new_position = (child.position[0], child.position[1]-size_offset) + coords = new_position - self.parent.content_panel.position + + self.parent.content_panel.update_element(child, coords) + + def children_size(self): + """Returns the size occupied by the children vertically + """ + _size = 0 + for child in self._child_nodes: + _size += child.size[1] + + return _size + + @property + def child_nodes(self): + """Returns all the child nodes of the crrent node + """ + return self._child_nodes + + @property + def color(self): + return self.title_panel.color + + @color.setter + def color(self, color): + """Sets background color of the title panel. + + Parameters + ---------- + color : list of 3 floats. + """ + self.title_panel.color = color + + @property + def opacity(self): + return self.title_panel.opacity + + @opacity.setter + def opacity(self, opacity): + """Sets the background opacity of title panel + + Parameters + ---------- + opacity: float + """ + self.title_panel.opacity = opacity + + @property + def content_color(self): + """Returns the background color of the content panel. + """ + return self.content_panel.color + + @content_color.setter + def content_color(self, color): + """Sets background color of the content panel. + + Parameters + ---------- + color : list of 3 floats. + """ + self.content_panel.color = color + + @property + def content_opacity(self): + return self.content_panel.opacity + + @content_opacity.setter + def content_opacity(self, opacity): + """Sets the background opacity of content panel + + Parameters + ---------- + opacity: float + """ + self.content_panel.opacity = opacity From 71528fc2e8f5f4de8c4a33bc0e036e8381e94073 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 30 Jun 2021 13:43:59 +0530 Subject: [PATCH 03/45] feat: example for Tree2D --- test.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 test.py diff --git a/test.py b/test.py new file mode 100644 index 000000000..d95271f0e --- /dev/null +++ b/test.py @@ -0,0 +1,22 @@ +from numpy.core.fromnumeric import size +from fury import ui +from fury.ui import TreeNode2D +from fury import window + + +structure = [{'node-1': ['node-1.1', 'node-1.2']}, + {'node-2': ['node-2.1', 'node-2.2']}, + {'node-3': ['node-3.1', 'node-3.2', 'node-3.3']}] + +tree = ui.Tree2D(structure, tree_name="Example Tree", size=(500, 500), position=(200, 200)) +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, + title="FURY Tree2D Example") + +show_manager.scene.add(tree) + +# To interact with the UI, set interactive = True +interactive = True + +if interactive: + show_manager.start() From 533b0b38fbd16723bd9136464f784c0295bc5a5c Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 30 Jun 2021 18:25:08 +0530 Subject: [PATCH 04/45] fix: code cleanup --- test.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test.py b/test.py index d95271f0e..8d494c19f 100644 --- a/test.py +++ b/test.py @@ -1,6 +1,4 @@ -from numpy.core.fromnumeric import size from fury import ui -from fury.ui import TreeNode2D from fury import window @@ -9,6 +7,7 @@ {'node-3': ['node-3.1', 'node-3.2', 'node-3.3']}] tree = ui.Tree2D(structure, tree_name="Example Tree", size=(500, 500), position=(200, 200)) + current_size = (1000, 1000) show_manager = window.ShowManager(size=current_size, title="FURY Tree2D Example") From 76ad5547ac8c7ca6fbf15626dea1aa703e345cd3 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Thu, 1 Jul 2021 00:13:44 +0530 Subject: [PATCH 05/45] removed redundant files --- test.py | 21 --------------------- 1 file changed, 21 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 8d494c19f..000000000 --- a/test.py +++ /dev/null @@ -1,21 +0,0 @@ -from fury import ui -from fury import window - - -structure = [{'node-1': ['node-1.1', 'node-1.2']}, - {'node-2': ['node-2.1', 'node-2.2']}, - {'node-3': ['node-3.1', 'node-3.2', 'node-3.3']}] - -tree = ui.Tree2D(structure, tree_name="Example Tree", size=(500, 500), position=(200, 200)) - -current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, - title="FURY Tree2D Example") - -show_manager.scene.add(tree) - -# To interact with the UI, set interactive = True -interactive = True - -if interactive: - show_manager.start() From abc0afa33f78be5f6efa6efb442f904a54af3769 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 5 Jul 2021 18:21:37 +0530 Subject: [PATCH 06/45] fix: code cleanup, reduced duplication, methods --- fury/ui.py | 153 ++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 116 insertions(+), 37 deletions(-) diff --git a/fury/ui.py b/fury/ui.py index 935e00b03..b81b61770 100644 --- a/fury/ui.py +++ b/fury/ui.py @@ -5310,6 +5310,9 @@ def _setup(self): expandable=False, expanded=True, indent=self.indent, child_indent=self.indent, child_height=self.node_height) + + for node in self.nodes_dict.values(): + node.set_visibility(False) def _get_actors(self): """ Get the actors composing this UI component. @@ -5350,11 +5353,16 @@ def generate_tree(self, structure): parent_label = list(obj.keys())[0] child_labels = list(obj.values())[0] - parent_node = TreeNode2D(label=parent_label) + if parent_label in self.nodes_dict.keys(): + parent_node = self.nodes_dict[parent_label] + else: + parent_node = TreeNode2D(label=parent_label) + child_nodes = [TreeNode2D(label=child_label) for child_label in child_labels] - for child_node in child_nodes: + for child_node, child_label in zip(child_nodes, child_labels): + self._nodes_dict[child_label] = child_node parent_node.add_node(child_node) self._nodes.append(parent_node) @@ -5370,6 +5378,37 @@ def resize(self, size): """ self.base_node.resize(size) + def add_content(self, node, content, coords=(0., 0.)): + """Add content to a sepcific node + + Parameters + ---------- + node: str + Label of the node + content: :class: `UI` or `TreeNode2D` + The content that is to be added in the node + coords : (float, float) or (int, int), optional + If float, normalized coordinates are assumed and they must be + between [0,1]. + If int, pixels coordinates are assumed and it must fit within the + content panel's size. + """ + _node = self.select_node(node) + _node.add_node(content, coords) + + _node.set_visibility(False) + + def select_node(self, node): + """Get the instance of a specific node + + Parameters + ---------- + node: str + Label of the node + """ + _node = self.nodes_dict[node] + return _node + @property def nodes(self): """Get all the nodes present in the Tree2D @@ -5411,7 +5450,8 @@ class TreeNode2D(UI): def __init__(self, label, parent=None, children=None, position=(0, 0), size=(200, 200), indent=5, child_indent=10, child_height=25, color=(0.3, 0.3, 0.3), - opacity=0.8, expandable=True, expanded=False): + opacity=0.8, expandable=True, expanded=False, + selected_color=(0.8, 0.3, 0.3)): """Initialize the UI element Parameters @@ -5455,12 +5495,19 @@ def __init__(self, label, parent=None, children=None, self.content_size = size self.expandable = expandable self.expanded = expanded + self.selected = False + self.selected_color = selected_color + self.unselected_color = color super(TreeNode2D, self).__init__(position) self.resize(size) self.title_panel.color = color self.title_panel.opacity = opacity + # hooks for selecting/de-selecting node + self.on_node_select = lambda ui: None + self.on_node_deselect = lambda ui: None + def _setup(self): """Setup this UI element. Create a title panel. @@ -5482,8 +5529,6 @@ def _setup(self): read_viz_icons(fname="circle-down.png"))) self.button = Button2D(icon_fnames=self.button_icons) - self.button.on_left_mouse_button_clicked = self.toggle_view - self.title_panel.add_element(self.label_text, (self.indent, 0)) self.title_panel.add_element(self.button, @@ -5492,14 +5537,18 @@ def _setup(self): self.title_panel.add_element(self.content_panel, (0, -self.content_size[1])) + self.button.on_left_mouse_button_clicked = self.toggle_view + self.title_panel.background.on_left_mouse_button_clicked = self.select_node + if self.children: for child in self.children: self.add_node(child) if self.expanded: + self.set_visibility(True) self.button.set_icon_by_name('expand') else: - self.content_panel.set_visibility(False) + self.set_visibility(False) self.button.set_icon_by_name('collapse') if not self.expandable: @@ -5536,22 +5585,31 @@ def _get_size(self): return self.title_panel.size - def add_node(self, node): + def add_node(self, node, coords=(0., 0.)): """Add a child node in the current node. Parameters ---------- - node: :class: `TreeNode2D` - Node that isto be added + node: :class: `TreeNode2D` or `UI` + Node/UI element that isto be added + coords: (float, float) or (int, int), optional + If float, normalized coordinates are assumed and they must be + between [0,1]. + If int, pixels coordinates are assumed and it must fit within the + content panel's size. """ self._child_nodes.append(node) - node.parent = self - _node_coords = (self.indent+self.child_indent, self.children_size() - - self.child_height) + if isinstance(node, type(self)): + node.parent = self + + _node_coords = (self.indent+self.child_indent, + self.children_size() - self.child_height) + else: + _node_coords = coords - node.content_panel.set_visibility(False) self.content_panel.add_element(node, _node_coords) + self.resize((self.size[0], self.children_size())) def resize(self, size): """ Resizes the Tree Node. @@ -5579,55 +5637,61 @@ def resize(self, size): if self._child_nodes: for child in self._child_nodes: - offset += self.child_height - _child_size = (size[0] - self.indent - - self.child_indent, child.children_size()) - _child_coords = (self.indent+self.child_indent, - self.content_panel.size[1]-offset) + if isinstance(child, type(self)): + offset += self.child_height + _child_size = (size[0] - self.indent - + self.child_indent, child.children_size()) + + _child_coords = (self.indent+self.child_indent, + self.content_panel.size[1]-offset) + else: + _child_size = child.size + + _child_coords = (self.indent+self.child_indent, + self.content_panel.size[1] - + self.children_size()) child.resize(_child_size) self.content_panel.update_element(child, _child_coords) def toggle_view(self, i_ren, _obj, _element): self.expanded = not self.expanded - self.content_panel.set_visibility(self.expanded) + self.set_visibility(self.expanded) if self.expanded: - if self.parent is not None: - idx = self.parent._child_nodes.index(self) - self.update_children_coords(idx, self.content_panel.size[1]) + self.update_children_coords(self, self.content_panel.size[1]) self.button.set_icon_by_name('expand') else: - if self.parent is not None: - idx = self.parent._child_nodes.index(self) - self.update_children_coords(idx, -self.content_panel.size[1]) + self.update_children_coords(self, -self.content_panel.size[1]) self.button.set_icon_by_name('collapse') i_ren.force_render() - def update_children_coords(self, current_child_idx, size_offset): + def update_children_coords(self, node, size_offset): """Updates the coords of the children below a specific child Parameters ---------- - current_child_idx: int - The index of the current child + node: :class: `TreeNode2D` + The node past which nodes are to be updated size_offset: int - Size by which below children are to be offset + Size by which below nodes are to be offset """ - if 0 >= current_child_idx > len(self._child_nodes): - raise ValueError( - f'Child index {current_child_idx} does not exist' - ) + if node.parent is not None: + current_child_idx = node.parent._child_nodes.index(node) + parent = node.parent - for child in self.parent._child_nodes[current_child_idx+1:]: - new_position = (child.position[0], child.position[1]-size_offset) - coords = new_position - self.parent.content_panel.position + for child in node.parent._child_nodes[current_child_idx+1:]: + new_position = (child.position[0], + child.position[1]-size_offset) - self.parent.content_panel.update_element(child, coords) + coords = new_position - parent.content_panel.position + parent.content_panel.update_element(child, coords) + + node.update_children_coords(node.parent, size_offset) def children_size(self): """Returns the size occupied by the children vertically @@ -5638,6 +5702,9 @@ def children_size(self): return _size + def set_visibility(self, visibility): + self.content_panel.set_visibility(visibility) + @property def child_nodes(self): """Returns all the child nodes of the crrent node @@ -5701,3 +5768,15 @@ def content_opacity(self, opacity): opacity: float """ self.content_panel.opacity = opacity + + def select_node(self, i_ren, _obj, _node2d): + self.selected = not self.selected + + if self.selected: + self.color = self.selected_color + self.on_node_select(self) + else: + self.color = self.unselected_color + self.on_node_deselect(self) + + i_ren.force_render() \ No newline at end of file From 62fbc477829c57f57a11bff7ef877926b92054ce Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 7 Jul 2021 16:49:02 +0530 Subject: [PATCH 07/45] fix: code clean-up --- fury/ui/elements.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index d9c9c0a76..5e690dfee 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -11,7 +11,6 @@ import numpy as np -from numpy.core.fromnumeric import size import vtk from fury.data import read_viz_icons @@ -3338,7 +3337,7 @@ def _setup(self): self.base_node = TreeNode2D(label=self.tree_name, children=self._nodes, expandable=False, expanded=True, indent=self.indent, child_indent=self.indent, - child_height=self.node_height) + child_height=self.node_height, auto_resize=False) for node in self.nodes_dict.values(): node.set_visibility(False) @@ -3386,6 +3385,8 @@ def generate_tree(self, structure): parent_node = self.nodes_dict[parent_label] else: parent_node = TreeNode2D(label=parent_label) + self._nodes.append(parent_node) + self._nodes_dict[parent_label] = parent_node child_nodes = [TreeNode2D(label=child_label) for child_label in child_labels] @@ -3394,9 +3395,6 @@ def generate_tree(self, structure): self._nodes_dict[child_label] = child_node parent_node.add_node(child_node) - self._nodes.append(parent_node) - self._nodes_dict[parent_label] = parent_node - def resize(self, size): """ Resizes the Tree Node. @@ -3480,7 +3478,7 @@ def __init__(self, label, parent=None, children=None, position=(0, 0), size=(200, 200), indent=5, child_indent=10, child_height=25, color=(0.3, 0.3, 0.3), opacity=0.8, expandable=True, expanded=False, - selected_color=(0.8, 0.3, 0.3)): + selected_color=(0.8, 0.3, 0.3), auto_resize=True): """Initialize the UI element Parameters @@ -3524,10 +3522,13 @@ def __init__(self, label, parent=None, children=None, self.content_size = size self.expandable = expandable self.expanded = expanded + self.selected = False self.selected_color = selected_color self.unselected_color = color + self.auto_resize = auto_resize + super(TreeNode2D, self).__init__(position) self.resize(size) self.title_panel.color = color @@ -3628,10 +3629,9 @@ def add_node(self, node, coords=(0., 0.)): content panel's size. """ self._child_nodes.append(node) - if isinstance(node, type(self)): node.parent = self - + node.set_visibility(False) _node_coords = (self.indent+self.child_indent, self.children_size() - self.child_height) else: @@ -3674,20 +3674,18 @@ def resize(self, size): _child_coords = (self.indent+self.child_indent, self.content_panel.size[1]-offset) - else: - _child_size = child.size - - _child_coords = (self.indent+self.child_indent, - self.content_panel.size[1] - - self.children_size()) - child.resize(_child_size) - self.content_panel.update_element(child, _child_coords) + child.resize(_child_size) + self.content_panel.update_element(child, _child_coords) def toggle_view(self, i_ren, _obj, _element): self.expanded = not self.expanded self.set_visibility(self.expanded) + # parent = self.parent + # if parent.auto_resize: + # parent.resize((parent.size[0], parent.children_size())) + if self.expanded: self.update_children_coords(self, self.content_panel.size[1]) @@ -3700,7 +3698,7 @@ def toggle_view(self, i_ren, _obj, _element): i_ren.force_render() def update_children_coords(self, node, size_offset): - """Updates the coords of the children below a specific child + """Updates the coords of the nodes below recursively Parameters ---------- @@ -3713,7 +3711,7 @@ def update_children_coords(self, node, size_offset): current_child_idx = node.parent._child_nodes.index(node) parent = node.parent - for child in node.parent._child_nodes[current_child_idx+1:]: + for child in parent._child_nodes[current_child_idx+1:]: new_position = (child.position[0], child.position[1]-size_offset) @@ -3732,8 +3730,12 @@ def children_size(self): return _size def set_visibility(self, visibility): + """Set visibility of this UI component.""" self.content_panel.set_visibility(visibility) + for child_node in self._child_nodes: + if isinstance(child_node, type(self)): + child_node.set_visibility(False) @property def child_nodes(self): """Returns all the child nodes of the crrent node From 4984f994ff5b8aebf858a5b04e9beb525c08bb33 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 7 Jul 2021 16:49:14 +0530 Subject: [PATCH 08/45] test files --- test.py | 68 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 test.py diff --git a/test.py b/test.py new file mode 100644 index 000000000..30816822b --- /dev/null +++ b/test.py @@ -0,0 +1,68 @@ +from fury.ui.core import Disk2D, Rectangle2D +from fury.ui.elements import LineSlider2D, ListBox2D +from fury.ui.containers import ImageContainer2D +from fury import ui, window + +structure = [{'Containers': ['Panels', 'ImageContainers']}, + {'Elements': ['ListBox', 'LineSlider']}, + {'Core': ['Rectangle', 'Disk']}] + +tree = ui.elements.Tree2D(structure=structure, tree_name="FURY UI Breakdown", size=(500, 500), position=(0, 0)) +############################################################################### +# Now, we create UI elements for the Containers node +# First, we create panles for the Panels node +panel = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) +panel_1 = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) + +############################################################################### +# Now, we create an ImageContainer2D for the ImageContainers node +img = ImageContainer2D(img_path="https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/fury-logo.png", size=(100, 100)) + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('Panels', panel_1) +tree.add_content('Panels', panel, (0.5, 0.5)) +tree.add_content('ImageContainers', img, (0.5, 0.5)) + +############################################################################### +# Now, lets create UI elements for the Elements node +# First we create Listbox for the ListBox node +listbox = ListBox2D(values=['First', 'Second', 'Third', 'Fourth']) + +############################################################################### +# Now, lets create a LineSlider for the LineSlider node +lineslider = LineSlider2D(length=200, orientation="vertical") + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('ListBox', listbox) +tree.add_content('LineSlider', lineslider, (0.5, 0.5)) + +############################################################################### +# Now, lets create UI elements for the Core node +# First we create Rectangle2D for teh Rectangle node +rect = Rectangle2D(size=(100, 100), color=(0.8, 0.4, 0.7)) + +############################################################################### +# Now, let's create Disk2D for the Disk node +disk = Disk2D(outer_radius=50, color=(0.6, 0.2, 0.8)) + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('Rectangle', rect) +tree.add_content('Disk', disk, (0.5, 0.5)) + +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, + title="FURY Bullet List Example") + +show_manager.scene.add(tree) + +# To interact with the UI, set interactive = True +interactive = True + +if interactive: + show_manager.start() \ No newline at end of file From 5e7fdac4c5e92ecb8fbbf4ce14ff520292ae7eef Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Thu, 8 Jul 2021 18:02:08 +0530 Subject: [PATCH 09/45] feat: icon for TreeNode2D --- fury/ui/elements.py | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 5e690dfee..f5c668190 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -16,7 +16,7 @@ from fury.data import read_viz_icons from fury.io import load_image from fury.ui.core import UI, Rectangle2D, TextBlock2D, Disk2D -from fury.ui.containers import Panel2D +from fury.ui.containers import ImageContainer2D, Panel2D from fury.ui.helpers import TWO_PI, clip_overflow from fury.utils import set_input @@ -3333,9 +3333,11 @@ def __init__(self, structure, tree_name="", position=(0, 0), def _setup(self): """Setup this UI element.""" self.generate_tree(self.structure) + _icon_path = 'https://img.icons8.com/material-rounded/24/000000/'\ + 'stacked-organizational-chart-highlighted-parent-node.png' self.base_node = TreeNode2D(label=self.tree_name, children=self._nodes, - expandable=False, expanded=True, + expandable=False, expanded=True, icon=_icon_path, indent=self.indent, child_indent=self.indent, child_height=self.node_height, auto_resize=False) @@ -3474,7 +3476,7 @@ class TreeNode2D(UI): Whether the current node is expanded or not """ - def __init__(self, label, parent=None, children=None, + def __init__(self, label, parent=None, children=None, icon=None, position=(0, 0), size=(200, 200), indent=5, child_indent=10, child_height=25, color=(0.3, 0.3, 0.3), opacity=0.8, expandable=True, expanded=False, @@ -3487,6 +3489,8 @@ def __init__(self, label, parent=None, children=None, Label text of the current node children: list of :class: `TreeNode2D` Sub nodes of the current node + icon: str + Path/URl to the icon placed next to the label parent: :class: `TreeNode2D` Parent node of the current node position : (float, float) @@ -3508,8 +3512,11 @@ def __init__(self, label, parent=None, children=None, If the node should expand/collapse """ self.children = children + self.icon = icon if self.children is None: self.children = [] + if self.icon is None: + self.icon = read_viz_icons(fname='stop2.png') self._child_nodes = [] self.parent = parent @@ -3550,6 +3557,7 @@ def _setup(self): self.content_panel = Panel2D(size=self.content_size) self.label_text = TextBlock2D(text=self.label) + self.label_image = ImageContainer2D(img_path=self.icon) self.button_icons = [] self.button_icons.append(('expand', @@ -3566,6 +3574,9 @@ def _setup(self): self.title_panel.add_element(self.content_panel, (0, -self.content_size[1])) + + self.title_panel.add_element(self.label_image, + (0., 0.)) self.button.on_left_mouse_button_clicked = self.toggle_view self.title_panel.background.on_left_mouse_button_clicked = self.select_node @@ -3655,12 +3666,18 @@ def resize(self, size): self.label_text.resize((size[0]-self.button.size[0], self.child_height)) + self.label_image.resize((self.child_height, self.child_height)) + self.button.resize((self.child_height, self.child_height)) + self.title_panel.update_element(self.label_text, - (self.indent, 0)) + (self.label_image.size[0], 0)) self.title_panel.update_element(self.button, (self.title_panel.size - self.button.size)) + + self.title_panel.update_element(self.label_image, + (0., 0.)) self.title_panel.update_element(self.content_panel, (0, -size[1])) From ec1844bd706cafdded57e4758124748136c4cc58 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Thu, 8 Jul 2021 18:02:22 +0530 Subject: [PATCH 10/45] test files --- test.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/test.py b/test.py index 30816822b..38cd83027 100644 --- a/test.py +++ b/test.py @@ -1,5 +1,5 @@ from fury.ui.core import Disk2D, Rectangle2D -from fury.ui.elements import LineSlider2D, ListBox2D +from fury.ui.elements import LineSlider2D, ListBox2D, TreeNode2D from fury.ui.containers import ImageContainer2D from fury import ui, window @@ -7,7 +7,9 @@ {'Elements': ['ListBox', 'LineSlider']}, {'Core': ['Rectangle', 'Disk']}] -tree = ui.elements.Tree2D(structure=structure, tree_name="FURY UI Breakdown", size=(500, 500), position=(0, 0)) +tree = ui.elements.Tree2D(structure=structure,tree_name="FURY UI Breakdown", + size=(500, 500), position=(0, 0), color=(0.8, 0.4, 0.2)) + ############################################################################### # Now, we create UI elements for the Containers node # First, we create panles for the Panels node @@ -16,7 +18,10 @@ ############################################################################### # Now, we create an ImageContainer2D for the ImageContainers node -img = ImageContainer2D(img_path="https://raw.githubusercontent.com/fury-gl/fury-communication-assets/main/fury-logo.png", size=(100, 100)) +path = "https://raw.githubusercontent.com/fury-gl/"\ + "fury-communication-assets/main/fury-logo.png" + +img = ImageContainer2D(img_path=path, size=(100, 100)) ############################################################################### # Now, we add the UI elements to their respective nodes. From 35ad93b0f889d8fb85148387567397da68d1bebf Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Thu, 8 Jul 2021 18:50:01 +0530 Subject: [PATCH 11/45] minor fixes --- fury/ui/elements.py | 1 + 1 file changed, 1 insertion(+) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index f5c668190..57b39077f 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3772,6 +3772,7 @@ def color(self, color): color : list of 3 floats. """ self.title_panel.color = color + self.unselected_color = color @property def opacity(self): From 0578e3ab9f6ebe589556d459c5bfc3bb7d6e1319 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 13 Jul 2021 19:22:41 +0530 Subject: [PATCH 12/45] feat: TreeNode2D parent auto resizing --- fury/ui/elements.py | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 57b39077f..16ba1b2fb 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3659,7 +3659,6 @@ def resize(self, size): size : (int, int) New width and height in pixels. """ - offset = 0 self.title_panel.resize((size[0], self.child_height)) self.content_panel.resize(size) @@ -3680,28 +3679,26 @@ def resize(self, size): (0., 0.)) self.title_panel.update_element(self.content_panel, (0, -size[1])) - + + _content_size = self.child_height if self._child_nodes: for child in self._child_nodes: if isinstance(child, type(self)): - offset += self.child_height _child_size = (size[0] - self.indent - self.child_indent, child.children_size()) + child.resize(_child_size) _child_coords = (self.indent+self.child_indent, - self.content_panel.size[1]-offset) + self.content_panel.size[1]-_content_size) - child.resize(_child_size) self.content_panel.update_element(child, _child_coords) + _content_size += child.size[1] def toggle_view(self, i_ren, _obj, _element): self.expanded = not self.expanded self.set_visibility(self.expanded) - - # parent = self.parent - # if parent.auto_resize: - # parent.resize((parent.size[0], parent.children_size())) + parent = self.parent if self.expanded: self.update_children_coords(self, self.content_panel.size[1]) @@ -3712,6 +3709,9 @@ def toggle_view(self, i_ren, _obj, _element): self.button.set_icon_by_name('collapse') + if parent.auto_resize: + parent.resize((parent.size[0], parent.children_size())) + i_ren.force_render() def update_children_coords(self, node, size_offset): @@ -3740,9 +3740,7 @@ def update_children_coords(self, node, size_offset): def children_size(self): """Returns the size occupied by the children vertically """ - _size = 0 - for child in self._child_nodes: - _size += child.size[1] + _size = sum([child.size[1] for child in self.child_nodes]) return _size From 69b5c563c0a06b065eef966c2be2d0624df1c332 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 14 Jul 2021 17:09:56 +0530 Subject: [PATCH 13/45] fix: fixed logic for auto resizing --- fury/ui/elements.py | 90 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 17 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 16ba1b2fb..91ffeb60e 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3339,7 +3339,7 @@ def _setup(self): self.base_node = TreeNode2D(label=self.tree_name, children=self._nodes, expandable=False, expanded=True, icon=_icon_path, indent=self.indent, child_indent=self.indent, - child_height=self.node_height, auto_resize=False) + child_height=self.node_height, auto_resize=True) for node in self.nodes_dict.values(): node.set_visibility(False) @@ -3487,29 +3487,37 @@ def __init__(self, label, parent=None, children=None, icon=None, ---------- label: str Label text of the current node - children: list of :class: `TreeNode2D` + children: list of :class: `TreeNode2D`, optional Sub nodes of the current node - icon: str + icon: str, optional Path/URl to the icon placed next to the label - parent: :class: `TreeNode2D` + parent: :class: `TreeNode2D`, optional Parent node of the current node - position : (float, float) + position : (float, float), optional Absolute coordinates (x, y) of the lower-left corner of the UI component - size : (int, int) + size : (int, int), optional Width and height of the pixels of this UI component. - indent: int + indent: int, optional Indentation of the current node - child_indent: int + child_indent: int, optional Indentation of the child nodes - child_height: int + child_height: int, optional Space taken by each sub-node vertically - color : list of 3 floats + color : list of 3 floats, optional Background color of current node. - opacity: float + opacity: float, optional Background opacity of the current node expandable: bool, optional If the node should expand/collapse + expanded: bool, optional + Whether the current node is expanded or not + selected_color: list of 3 floats, optional + Color of the selected node. + unselected_color: list of 3 floats, optional + Color of the unselected node. + auto_resize: bool, optional + If the node should automatically resize to fit its content. """ self.children = children self.icon = icon @@ -3643,8 +3651,10 @@ def add_node(self, node, coords=(0., 0.)): if isinstance(node, type(self)): node.parent = self node.set_visibility(False) + node.child_height = self.child_height + _node_coords = (self.indent+self.child_indent, - self.children_size() - self.child_height) + self.children_size() - node.child_height) else: _node_coords = coords @@ -3696,6 +3706,17 @@ def resize(self, size): _content_size += child.size[1] def toggle_view(self, i_ren, _obj, _element): + """Toggle the view of the node. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + Interactor style used to interact with the scene. + _obj: :class:`vtkActor` + The picked actor + _element: :class: `TreeNode2D` + Instance of the node + """ self.expanded = not self.expanded self.set_visibility(self.expanded) parent = self.parent @@ -3709,8 +3730,15 @@ def toggle_view(self, i_ren, _obj, _element): self.button.set_icon_by_name('collapse') - if parent.auto_resize: - parent.resize((parent.size[0], parent.children_size())) + while parent is not None: + if parent.auto_resize: + current_size = parent.content_panel.size[1] + if parent.children_size() > parent.content_panel.size[1]: + parent.resize((parent.size[0], parent.children_size())) + else: + parent.resize((parent.size[0], current_size)) + + parent = parent.parent i_ren.force_render() @@ -3738,7 +3766,7 @@ def update_children_coords(self, node, size_offset): node.update_children_coords(node.parent, size_offset) def children_size(self): - """Returns the size occupied by the children vertically + """Returns the size occupied by the children vertically. """ _size = sum([child.size[1] for child in self.child_nodes]) @@ -3753,7 +3781,7 @@ def set_visibility(self, visibility): child_node.set_visibility(False) @property def child_nodes(self): - """Returns all the child nodes of the crrent node + """Returns all the child nodes of the current node """ return self._child_nodes @@ -3770,7 +3798,6 @@ def color(self, color): color : list of 3 floats. """ self.title_panel.color = color - self.unselected_color = color @property def opacity(self): @@ -3816,7 +3843,36 @@ def content_opacity(self, opacity): """ self.content_panel.opacity = opacity + @property + def child_height(self): + return self._child_height + + @child_height.setter + def child_height(self, height): + """Sets the height of title panels. + + Parameters + ---------- + height: int + New height of the title panels + """ + self._child_height = height + + for node in self.child_nodes: + node.child_height = height + def select_node(self, i_ren, _obj, _node2d): + """Callback for when the node is clicked on. + + Parameters + ---------- + i_ren: :class:`CustomInteractorStyle` + Interactor style used to interact with the scene. + _obj: :class:`vtkActor` + The picked actor + _node2d: :class:`TreeNode2D` + Instance of the selected node + """ self.selected = not self.selected if self.selected: From 149225472a9da875296aef2b8ae82228012a971c Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 14 Jul 2021 18:12:35 +0530 Subject: [PATCH 14/45] fix: increased indentation for better visuals --- fury/ui/elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 91ffeb60e..a55c74b76 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3477,7 +3477,7 @@ class TreeNode2D(UI): """ def __init__(self, label, parent=None, children=None, icon=None, - position=(0, 0), size=(200, 200), indent=5, + position=(0, 0), size=(200, 200), indent=20, child_indent=10, child_height=25, color=(0.3, 0.3, 0.3), opacity=0.8, expandable=True, expanded=False, selected_color=(0.8, 0.3, 0.3), auto_resize=True): From 07cdf1c09b21e28093a041203e913015e26b58e8 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 14 Jul 2021 19:57:50 +0530 Subject: [PATCH 15/45] feat: tutorial for Tree2D --- docs/tutorials/02_ui/viz_tree_ui.py | 74 +++++++++++++++++++++++++++++ test.py | 2 +- 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 docs/tutorials/02_ui/viz_tree_ui.py diff --git a/docs/tutorials/02_ui/viz_tree_ui.py b/docs/tutorials/02_ui/viz_tree_ui.py new file mode 100644 index 000000000..2990660fd --- /dev/null +++ b/docs/tutorials/02_ui/viz_tree_ui.py @@ -0,0 +1,74 @@ +from fury import ui, window +from fury.ui.core import Disk2D, Rectangle2D +from fury.ui.elements import LineSlider2D, ListBox2D +from fury.ui.containers import ImageContainer2D + +structure = [{'Containers': ['Panels', 'ImageContainers']}, + {'Elements': ['ListBox', 'LineSlider']}, + {'Core': ['Rectangle', 'Disk']}] + +tree = ui.elements.Tree2D(structure=structure, tree_name="FURY UI Breakdown", + size=(500, 500), position=(0, 0), + color=(0.8, 0.4, 0.2)) + +############################################################################### +# Now, we create UI elements for the Containers node +# First, we create panles for the Panels node +panel = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) +panel_1 = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) + +############################################################################### +# Now, we create an ImageContainer2D for the ImageContainers node +path = "https://raw.githubusercontent.com/fury-gl/"\ + "fury-communication-assets/main/fury-logo.png" + +img = ImageContainer2D(img_path=path, size=(100, 100)) + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('Panels', panel_1) +tree.add_content('Panels', panel, (0.5, 0.5)) +tree.add_content('ImageContainers', img, (0.5, 0.5)) + +############################################################################### +# Now, lets create UI elements for the Elements node +# First we create Listbox for the ListBox node +listbox = ListBox2D(values=['First', 'Second', 'Third', 'Fourth']) + +############################################################################### +# Now, lets create a LineSlider for the LineSlider node +lineslider = LineSlider2D(length=200, orientation="vertical") + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('ListBox', listbox) +tree.add_content('LineSlider', lineslider, (0.5, 0.5)) + +############################################################################### +# Now, lets create UI elements for the Core node +# First we create Rectangle2D for teh Rectangle node +rect = Rectangle2D(size=(100, 100), color=(0.8, 0.4, 0.7)) + +############################################################################### +# Now, let's create Disk2D for the Disk node +disk = Disk2D(outer_radius=50, color=(0.6, 0.2, 0.8)) + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('Rectangle', rect) +tree.add_content('Disk', disk, (0.5, 0.5)) + +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, + title="FURY Bullet List Example") + +show_manager.scene.add(tree) + +# To interact with the UI, set interactive = True +interactive = True + +if interactive: + show_manager.start() diff --git a/test.py b/test.py index 38cd83027..3a379f8d5 100644 --- a/test.py +++ b/test.py @@ -8,7 +8,7 @@ {'Core': ['Rectangle', 'Disk']}] tree = ui.elements.Tree2D(structure=structure,tree_name="FURY UI Breakdown", - size=(500, 500), position=(0, 0), color=(0.8, 0.4, 0.2)) + size=(100, 100), position=(0, 0), color=(0.8, 0.4, 0.2)) ############################################################################### # Now, we create UI elements for the Containers node From b6dcf60b71f3251bab35b2b84fe5ecd078ac6ded Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 14 Jul 2021 19:58:12 +0530 Subject: [PATCH 16/45] removed redundant files --- test.py | 73 --------------------------------------------------------- 1 file changed, 73 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index 3a379f8d5..000000000 --- a/test.py +++ /dev/null @@ -1,73 +0,0 @@ -from fury.ui.core import Disk2D, Rectangle2D -from fury.ui.elements import LineSlider2D, ListBox2D, TreeNode2D -from fury.ui.containers import ImageContainer2D -from fury import ui, window - -structure = [{'Containers': ['Panels', 'ImageContainers']}, - {'Elements': ['ListBox', 'LineSlider']}, - {'Core': ['Rectangle', 'Disk']}] - -tree = ui.elements.Tree2D(structure=structure,tree_name="FURY UI Breakdown", - size=(100, 100), position=(0, 0), color=(0.8, 0.4, 0.2)) - -############################################################################### -# Now, we create UI elements for the Containers node -# First, we create panles for the Panels node -panel = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) -panel_1 = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) - -############################################################################### -# Now, we create an ImageContainer2D for the ImageContainers node -path = "https://raw.githubusercontent.com/fury-gl/"\ - "fury-communication-assets/main/fury-logo.png" - -img = ImageContainer2D(img_path=path, size=(100, 100)) - -############################################################################### -# Now, we add the UI elements to their respective nodes. - -tree.add_content('Panels', panel_1) -tree.add_content('Panels', panel, (0.5, 0.5)) -tree.add_content('ImageContainers', img, (0.5, 0.5)) - -############################################################################### -# Now, lets create UI elements for the Elements node -# First we create Listbox for the ListBox node -listbox = ListBox2D(values=['First', 'Second', 'Third', 'Fourth']) - -############################################################################### -# Now, lets create a LineSlider for the LineSlider node -lineslider = LineSlider2D(length=200, orientation="vertical") - -############################################################################### -# Now, we add the UI elements to their respective nodes. - -tree.add_content('ListBox', listbox) -tree.add_content('LineSlider', lineslider, (0.5, 0.5)) - -############################################################################### -# Now, lets create UI elements for the Core node -# First we create Rectangle2D for teh Rectangle node -rect = Rectangle2D(size=(100, 100), color=(0.8, 0.4, 0.7)) - -############################################################################### -# Now, let's create Disk2D for the Disk node -disk = Disk2D(outer_radius=50, color=(0.6, 0.2, 0.8)) - -############################################################################### -# Now, we add the UI elements to their respective nodes. - -tree.add_content('Rectangle', rect) -tree.add_content('Disk', disk, (0.5, 0.5)) - -current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, - title="FURY Bullet List Example") - -show_manager.scene.add(tree) - -# To interact with the UI, set interactive = True -interactive = True - -if interactive: - show_manager.start() \ No newline at end of file From ad210802f87b1bd0dff3475e3284a27934d08ea3 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Thu, 15 Jul 2021 22:02:07 +0530 Subject: [PATCH 17/45] fix: pep8 issues --- fury/ui/elements.py | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index a55c74b76..c8e2b1f97 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3337,10 +3337,12 @@ def _setup(self): 'stacked-organizational-chart-highlighted-parent-node.png' self.base_node = TreeNode2D(label=self.tree_name, children=self._nodes, - expandable=False, expanded=True, icon=_icon_path, - indent=self.indent, child_indent=self.indent, - child_height=self.node_height, auto_resize=True) - + expandable=False, expanded=True, + icon=_icon_path, indent=self.indent, + child_indent=self.indent, + child_height=self.node_height, + auto_resize=True) + for node in self.nodes_dict.values(): node.set_visibility(False) @@ -3406,7 +3408,7 @@ def resize(self, size): New width and height in pixels. """ self.base_node.resize(size) - + def add_content(self, node, content, coords=(0., 0.)): """Add content to a sepcific node @@ -3447,17 +3449,17 @@ def nodes(self): list of nodes """ return self._nodes - + @property def nodes_dict(self): """Get all the nodes present in the Tree2D in dict format - + Returns ------- dict with label, node as key, value """ return self._nodes_dict - + class TreeNode2D(UI): """Node/Leaf of a Tree2D UI @@ -3582,12 +3584,13 @@ def _setup(self): self.title_panel.add_element(self.content_panel, (0, -self.content_size[1])) - + self.title_panel.add_element(self.label_image, (0., 0.)) self.button.on_left_mouse_button_clicked = self.toggle_view - self.title_panel.background.on_left_mouse_button_clicked = self.select_node + self.title_panel.background.on_left_mouse_button_clicked = \ + self.select_node if self.children: for child in self.children: @@ -3684,12 +3687,12 @@ def resize(self, size): self.title_panel.update_element(self.button, (self.title_panel.size - self.button.size)) - + self.title_panel.update_element(self.label_image, (0., 0.)) self.title_panel.update_element(self.content_panel, (0, -size[1])) - + _content_size = self.child_height if self._child_nodes: for child in self._child_nodes: @@ -3700,14 +3703,14 @@ def resize(self, size): child.resize(_child_size) _child_coords = (self.indent+self.child_indent, - self.content_panel.size[1]-_content_size) + self.content_panel.size[1]-_content_size) self.content_panel.update_element(child, _child_coords) _content_size += child.size[1] def toggle_view(self, i_ren, _obj, _element): """Toggle the view of the node. - + Parameters ---------- i_ren: :class:`CustomInteractorStyle` @@ -3779,6 +3782,7 @@ def set_visibility(self, visibility): for child_node in self._child_nodes: if isinstance(child_node, type(self)): child_node.set_visibility(False) + @property def child_nodes(self): """Returns all the child nodes of the current node @@ -3842,15 +3846,15 @@ def content_opacity(self, opacity): opacity: float """ self.content_panel.opacity = opacity - + @property def child_height(self): return self._child_height - + @child_height.setter def child_height(self, height): """Sets the height of title panels. - + Parameters ---------- height: int @@ -3860,10 +3864,10 @@ def child_height(self, height): for node in self.child_nodes: node.child_height = height - + def select_node(self, i_ren, _obj, _node2d): """Callback for when the node is clicked on. - + Parameters ---------- i_ren: :class:`CustomInteractorStyle` From 43401354f36a6fdaca876790e608da1ef010d979 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 19 Jul 2021 15:52:14 +0530 Subject: [PATCH 18/45] feat: selected nodes attribute --- fury/ui/elements.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index c8e2b1f97..ff6bc4dcb 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3541,6 +3541,7 @@ def __init__(self, label, parent=None, children=None, icon=None, self.expanded = expanded self.selected = False + self.selected_nodes = [] self.selected_color = selected_color self.unselected_color = color @@ -3880,9 +3881,11 @@ def select_node(self, i_ren, _obj, _node2d): self.selected = not self.selected if self.selected: + self.selected_nodes.append(_node2d) self.color = self.selected_color self.on_node_select(self) else: + self.selected_nodes.remove(_node2d) self.color = self.unselected_color self.on_node_deselect(self) From 86654eb39c95d84e64068b49c7683774a8a9d004 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 19 Jul 2021 15:52:43 +0530 Subject: [PATCH 19/45] tests: added tests for Tree2D UI --- fury/ui/tests/test_elements.py | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index 4c823bc8f..4ce3a1381 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1020,3 +1020,58 @@ def timer_callback(_obj, _event): arr = window.snapshot(scene, offscreen=True) npt.assert_(np.sum(arr) > 0) + + +def test_ui_tree_2d(interactive=False): + filename = "test_ui_tree_ed" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") + + structure = [{'label-1': []}, {'label-2': []}, {'label-3': []}] + tree = ui.elements.Tree2D(structure=structure, tree_name="Example Tree") + + tree.resize((400, 400)) + npt.assert_equal(tree.size, (400, tree.node_height+400)) + + nodes = ['label-1', 'label-2', 'label-3'] + npt.assert_array_equal(nodes, [node.label for node in tree.nodes]) + npt.assert_array_equal(nodes, list(tree.nodes_dict.keys())) + + for node in nodes: + npt.assert_equal(tree.select_node(node).child_nodes, []) + + panel = ui.Panel2D(size=(100, 100), color=(0.1, 0.9, 0.7)) + listbox = ui.ListBox2D(values=['test', ]*2, size=(100, 100)) + line_slider = ui.LineSlider2D(length=100, orientation="vertical") + + # Adding the UI elements to different labels + tree.add_content('label-1', panel, (0., 0.)) + tree.add_content('label-2', listbox, (0., 0.)) + tree.add_content('label-3', line_slider, (0.5, 0.5)) + + for node in tree.nodes: + content_actor = node.content_panel.background.actor + npt.assert_equal(node.size[1], tree.node_height) + npt.assert_equal(content_actor.GetVisibility(), False) + + event_counter = EventCounter() + event_counter.monitor(tree) + + current_size = (800, 800) + show_manager = window.ShowManager( + size=current_size, title="Tree2D UI Example") + show_manager.scene.add(tree) + + if interactive: + show_manager.record_events_to_file(recording_filename) + print(list(event_counter.events_counts.items())) + event_counter.save(expected_events_counts_filename) + + else: + show_manager.play_events_from_file(recording_filename) + expected = EventCounter.load(expected_events_counts_filename) + event_counter.check_counts(expected) + + for node in tree.nodes: + child = node.child_nodes[0] + npt.assert_equal(node.size[1], child.size[1]+tree.node_height) From 84ca86a5478ad45f76f1f24cca0aa6df20c3bb67 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 19 Jul 2021 15:53:09 +0530 Subject: [PATCH 20/45] events recording --- fury/data/files/test_ui_tree_ed.json | 1 + fury/data/files/test_ui_tree_ed.log.gz | Bin 0 -> 6203 bytes 2 files changed, 1 insertion(+) create mode 100644 fury/data/files/test_ui_tree_ed.json create mode 100644 fury/data/files/test_ui_tree_ed.log.gz diff --git a/fury/data/files/test_ui_tree_ed.json b/fury/data/files/test_ui_tree_ed.json new file mode 100644 index 000000000..86af418fc --- /dev/null +++ b/fury/data/files/test_ui_tree_ed.json @@ -0,0 +1 @@ +{"CharEvent": 0, "MouseMoveEvent": 843, "KeyPressEvent": 0, "KeyReleaseEvent": 0, "LeftButtonPressEvent": 18, "LeftButtonReleaseEvent": 18, "RightButtonPressEvent": 0, "RightButtonReleaseEvent": 0, "MiddleButtonPressEvent": 0, "MiddleButtonReleaseEvent": 0} \ No newline at end of file diff --git a/fury/data/files/test_ui_tree_ed.log.gz b/fury/data/files/test_ui_tree_ed.log.gz new file mode 100644 index 0000000000000000000000000000000000000000..258321a6c8acf7c50f5f6e9c44f476afd1c8632c GIT binary patch literal 6203 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 ZAHMv#Lcjm}U%oyk{|6q;Uz~}{002Fe1}y*p literal 0 HcmV?d00001 From 101d04c7aad2a5966a38ef5e82b4eb1e4c05fc2f Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 19 Jul 2021 15:55:54 +0530 Subject: [PATCH 21/45] fix: pep8 issues --- fury/ui/tests/test_elements.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index 4ce3a1381..ee7ca8c7c 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1026,7 +1026,7 @@ def test_ui_tree_2d(interactive=False): filename = "test_ui_tree_ed" recording_filename = pjoin(DATA_DIR, filename + ".log.gz") expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") - + structure = [{'label-1': []}, {'label-2': []}, {'label-3': []}] tree = ui.elements.Tree2D(structure=structure, tree_name="Example Tree") @@ -1039,7 +1039,7 @@ def test_ui_tree_2d(interactive=False): for node in nodes: npt.assert_equal(tree.select_node(node).child_nodes, []) - + panel = ui.Panel2D(size=(100, 100), color=(0.1, 0.9, 0.7)) listbox = ui.ListBox2D(values=['test', ]*2, size=(100, 100)) line_slider = ui.LineSlider2D(length=100, orientation="vertical") @@ -1071,7 +1071,7 @@ def test_ui_tree_2d(interactive=False): show_manager.play_events_from_file(recording_filename) expected = EventCounter.load(expected_events_counts_filename) event_counter.check_counts(expected) - + for node in tree.nodes: child = node.child_nodes[0] npt.assert_equal(node.size[1], child.size[1]+tree.node_height) From e3d445a186e4cb69a18d380858a08acfde5a3a88 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 20 Jul 2021 15:14:10 +0530 Subject: [PATCH 22/45] feat: added a select child method --- fury/ui/elements.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index ff6bc4dcb..e3295bae7 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3654,7 +3654,7 @@ def add_node(self, node, coords=(0., 0.)): self._child_nodes.append(node) if isinstance(node, type(self)): node.parent = self - node.set_visibility(False) + node.title_panel.set_visibility(False) node.child_height = self.child_height _node_coords = (self.indent+self.child_indent, @@ -3783,6 +3783,18 @@ def set_visibility(self, visibility): for child_node in self._child_nodes: if isinstance(child_node, type(self)): child_node.set_visibility(False) + + def select_child(self, child_label): + """Get the instance of a particular child node. + + Parameters + ---------- + child_label: str + Label of the child node to be selected. + """ + lables = [child.label for child in self.child_nodes] + idx = lables.index(child_label) + return self.child_nodes[idx] @property def child_nodes(self): From 82d4703214613181f1d85346eb71ddc3562a6eb1 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 20 Jul 2021 15:14:36 +0530 Subject: [PATCH 23/45] tests: added tests for TreeNode2D --- fury/data/files/test_ui_treenode_2d.json | 1 + fury/data/files/test_ui_treenode_2d.log.gz | Bin 0 -> 4549 bytes fury/ui/tests/test_elements.py | 75 +++++++++++++++++++++ 3 files changed, 76 insertions(+) create mode 100644 fury/data/files/test_ui_treenode_2d.json create mode 100644 fury/data/files/test_ui_treenode_2d.log.gz diff --git a/fury/data/files/test_ui_treenode_2d.json b/fury/data/files/test_ui_treenode_2d.json new file mode 100644 index 000000000..fdf30f953 --- /dev/null +++ b/fury/data/files/test_ui_treenode_2d.json @@ -0,0 +1 @@ +{"CharEvent": 0, "MouseMoveEvent": 478, "KeyPressEvent": 0, "KeyReleaseEvent": 0, "LeftButtonPressEvent": 26, "LeftButtonReleaseEvent": 26, "RightButtonPressEvent": 0, "RightButtonReleaseEvent": 0, "MiddleButtonPressEvent": 0, "MiddleButtonReleaseEvent": 0} \ No newline at end of file diff --git a/fury/data/files/test_ui_treenode_2d.log.gz b/fury/data/files/test_ui_treenode_2d.log.gz new file mode 100644 index 0000000000000000000000000000000000000000..eb4459f62726be494bb67c33e043ac401e3f31eb GIT binary patch literal 4549 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 literal 0 HcmV?d00001 diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index ee7ca8c7c..bc98ee96a 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -4,6 +4,7 @@ import itertools import numpy as np +from numpy.lib.function_base import select import numpy.testing as npt import pytest @@ -1075,3 +1076,77 @@ def test_ui_tree_2d(interactive=False): for node in tree.nodes: child = node.child_nodes[0] npt.assert_equal(node.size[1], child.size[1]+tree.node_height) + + +def test_ui_treenode_2d(interactive=False): + filename = "test_ui_treenode_2d" + recording_filename = pjoin(DATA_DIR, filename + ".log.gz") + expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") + + non_expandable_node = ui.elements.TreeNode2D(label="Non Expandable", expandable=False, + expanded=False) + + content_actor = non_expandable_node.content_panel.background.actor + npt.assert_equal(content_actor.GetVisibility(), False) + + node_1 = ui.elements.TreeNode2D(label="Child-1") + node_2 = ui.elements.TreeNode2D(label="Child-2") + node_3 = ui.elements.TreeNode2D(label="Child-3") + nodes = [node_1, node_2, node_3] + children_size = sum([node.size[1] for node in nodes]) + + parent_node = ui.elements.TreeNode2D(label="Parent", children=nodes, auto_resize=False) + npt.assert_equal(parent_node.children_size(), children_size) + + node = ui.elements.TreeNode2D(label="Child-4") + nodes.append(node) + parent_node.add_node(node) + + npt.assert_equal(parent_node.parent, None) + npt.assert_array_equal(nodes, parent_node.child_nodes) + for node in parent_node.child_nodes: + npt.assert_equal(node.parent, parent_node) + + parent_node.child_height = 40 + for node in parent_node.child_nodes: + npt.assert_equal(node.child_height, 40) + + child_1 = ui.elements.TreeNode2D(label="Child-1") + child_2 = ui.elements.TreeNode2D(label="Child-2") + children = [child_1, child_2] + simple_parent = ui.elements.TreeNode2D(label="Simple Tree", children=children, expanded=True) + + child_1 = simple_parent.select_child('Child-1') + child_2 = simple_parent.select_child('Child-2') + simple_parent.update_children_coords(child_1, 50) + npt.assert_equal(child_2.position[1], child_1.position[1]-50-simple_parent.child_height) + + selected = [] + def node_select(node): + selected.append(node) + + def node_deselect(node): + selected.remove(node) + + parent_node.on_node_select = node_select + parent_node.on_node_deselect = node_deselect + + event_counter = EventCounter() + event_counter.monitor(parent_node) + + current_size = (800, 800) + show_manager = window.ShowManager( + size=current_size, title="Tree2D UI Example") + show_manager.scene.add(parent_node) + + if interactive: + show_manager.record_events_to_file(recording_filename) + print(list(event_counter.events_counts.items())) + event_counter.save(expected_events_counts_filename) + + else: + show_manager.play_events_from_file(recording_filename) + expected = EventCounter.load(expected_events_counts_filename) + event_counter.check_counts(expected) + + npt.assert_equal(parent_node.selected_nodes, selected) From 69f1bd20e3ec71c5f78cadf64a6fb22b5f892b0f Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 20 Jul 2021 15:20:14 +0530 Subject: [PATCH 24/45] fix: pep8 issues --- fury/ui/elements.py | 4 ++-- fury/ui/tests/test_elements.py | 20 +++++++++++++------- 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index e3295bae7..a10cb97c5 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3783,10 +3783,10 @@ def set_visibility(self, visibility): for child_node in self._child_nodes: if isinstance(child_node, type(self)): child_node.set_visibility(False) - + def select_child(self, child_label): """Get the instance of a particular child node. - + Parameters ---------- child_label: str diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index bc98ee96a..0c32f2f43 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1083,9 +1083,10 @@ def test_ui_treenode_2d(interactive=False): recording_filename = pjoin(DATA_DIR, filename + ".log.gz") expected_events_counts_filename = pjoin(DATA_DIR, filename + ".json") - non_expandable_node = ui.elements.TreeNode2D(label="Non Expandable", expandable=False, + non_expandable_node = ui.elements.TreeNode2D(label="Non Expandable", + expandable=False, expanded=False) - + content_actor = non_expandable_node.content_panel.background.actor npt.assert_equal(content_actor.GetVisibility(), False) @@ -1095,7 +1096,9 @@ def test_ui_treenode_2d(interactive=False): nodes = [node_1, node_2, node_3] children_size = sum([node.size[1] for node in nodes]) - parent_node = ui.elements.TreeNode2D(label="Parent", children=nodes, auto_resize=False) + parent_node = ui.elements.TreeNode2D(label="Parent", children=nodes, + auto_resize=False) + npt.assert_equal(parent_node.children_size(), children_size) node = ui.elements.TreeNode2D(label="Child-4") @@ -1106,7 +1109,7 @@ def test_ui_treenode_2d(interactive=False): npt.assert_array_equal(nodes, parent_node.child_nodes) for node in parent_node.child_nodes: npt.assert_equal(node.parent, parent_node) - + parent_node.child_height = 40 for node in parent_node.child_nodes: npt.assert_equal(node.child_height, 40) @@ -1114,17 +1117,20 @@ def test_ui_treenode_2d(interactive=False): child_1 = ui.elements.TreeNode2D(label="Child-1") child_2 = ui.elements.TreeNode2D(label="Child-2") children = [child_1, child_2] - simple_parent = ui.elements.TreeNode2D(label="Simple Tree", children=children, expanded=True) + simple_parent = ui.elements.TreeNode2D(label="Simple Tree", + children=children, expanded=True) child_1 = simple_parent.select_child('Child-1') child_2 = simple_parent.select_child('Child-2') simple_parent.update_children_coords(child_1, 50) - npt.assert_equal(child_2.position[1], child_1.position[1]-50-simple_parent.child_height) + npt.assert_equal(child_2.position[1], + child_1.position[1]-50-simple_parent.child_height) selected = [] + def node_select(node): selected.append(node) - + def node_deselect(node): selected.remove(node) From 4a2eccb2efd1811a23871f7dbe827384a41ac167 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 20 Jul 2021 15:43:47 +0530 Subject: [PATCH 25/45] fix: removed unused imports --- fury/ui/tests/test_elements.py | 1 - 1 file changed, 1 deletion(-) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index 0c32f2f43..854ad8154 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -4,7 +4,6 @@ import itertools import numpy as np -from numpy.lib.function_base import select import numpy.testing as npt import pytest From c12a96a995f29fd8dfc77fd2fa33b405c50525d1 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 21 Jul 2021 15:55:13 +0530 Subject: [PATCH 26/45] test example --- test.py | 148 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) create mode 100644 test.py diff --git a/test.py b/test.py new file mode 100644 index 000000000..c7b2e571d --- /dev/null +++ b/test.py @@ -0,0 +1,148 @@ +from fury.ui.elements import TreeNode2D +import numpy as np + +from fury import ui, window, actor, utils + +structure = [{'Cube': ['Translate', 'Color']}, + {'Test': ['Test-1']}] + +tree = ui.elements.Tree2D(structure=structure, tree_name="Actor Modifier", + size=(300, 300), position=(0, 0), + color=(0.8, 0.4, 0.2)) + +############################################################################### +# Slider Controls for the node Cube +# ========================================== +# +# Now we prepare content for the Cube node. + +ring_slider = ui.RingSlider2D(initial_value=0, + text_template="{angle:5.1f}°") + +line_slider_x = ui.LineSlider2D(initial_value=0, + min_value=-10, max_value=10, + orientation="horizontal", + text_alignment="Top") + +line_slider_y = ui.LineSlider2D(initial_value=0, + min_value=-10, max_value=10, + orientation="vertical", + text_alignment="Right") + +line_slider_r = ui.LineSlider2D(initial_value=0, + min_value=0, max_value=1, + orientation="vertical", + text_alignment="Left") + +line_slider_g = ui.LineSlider2D(initial_value=0, + min_value=0, max_value=1, + orientation="vertical", + text_alignment="Left") + +line_slider_b = ui.LineSlider2D(initial_value=0, + min_value=0, max_value=1, + orientation="vertical", + text_alignment="Left") + +cube = actor.box(centers=np.array([[10, 0, 0]]), + directions=np.array([[0, 1, 0]]), + colors=np.array([[0, 0, 1]]), + scales=np.array([[0.3, 0.3, 0.3]])) + +cube_x = 0 +cube_y = 0 +cube_r = 0 +cube_g = 0 +cube_b = 0 + +def rotate_cube(slider): + angle = slider.value + previous_angle = slider.previous_value + rotation_angle = angle - previous_angle + cube.RotateX(rotation_angle) + +def translate_cube_x(slider): + global cube_x, cube_y + cube_x = slider.value + cube.SetPosition(cube_x, cube_y, 0) + +def translate_cube_y(slider): + global cube_x, cube_y + cube_y = slider.value + cube.SetPosition(cube_x, cube_y, 0) + +def update_colors(): + global cube + vcolors = utils.colors_from_actor(cube) + colarr = np.array([cube_r, cube_g, cube_b])*255 + vcolors[:] = colarr + utils.update_actor(cube) + +def change_r(slider): + global cube_r, cube_g, cube_b + cube_r = slider.value + update_colors() + +def change_g(slider): + global cube_r, cube_g, cube_b + cube_g = slider.value + update_colors() + +def change_b(slider): + global cube_r, cube_g, cube_b + cube_b = slider.value + update_colors() + +ring_slider.on_change = rotate_cube +line_slider_x.on_change = translate_cube_x +line_slider_y.on_change = translate_cube_y + +# Callbacks for color sliders +line_slider_r.on_change = change_r +line_slider_g.on_change = change_g +line_slider_b.on_change = change_b + +############################################################################### +# Adding sliders to their respective nodes + +tree.add_content('Translate', ring_slider, (0., 0.)) +tree.add_content('Translate', line_slider_x, (0., 1.0)) +tree.add_content('Translate', line_slider_y, (0.5, 0.5)) + +tree.add_content('Color', line_slider_r, (0., 0.)) +tree.add_content('Color', line_slider_g, (0.25, 0.)) +tree.add_content('Color', line_slider_b, (0.5, 0.)) + +############################################################################### +# Defining hook to toggle the visibility of the cube + +def visibility_on(tree_ui): + global cube + cube.SetVisibility(1) + +def visibility_off(tree_ui): + global cube + cube.SetVisibility(0) + +############################################################################### +# Adding hooks to relevant nodes + +cube_node = tree.select_node('Cube') +color_node = tree.select_node('Color') + +cube.SetVisibility(False) + +cube_node.on_node_select = visibility_on +cube_node.on_node_deselect = visibility_off + +current_size = (800, 800) +show_manager = window.ShowManager(size=current_size, + title="FURY Tree2D Example") + +show_manager.scene.add(tree, cube) + +# To interact with the UI, set interactive = True +interactive = True + +if interactive: + show_manager.start() From dcd2ed923a96d846fce474d2c0d3e9460a08c32e Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 21 Jul 2021 15:56:20 +0530 Subject: [PATCH 27/45] UI fixes, addressed reviews --- fury/ui/elements.py | 77 +++++++++++++++++++++++++++++++++------------ 1 file changed, 57 insertions(+), 20 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index a10cb97c5..a8a7da9f7 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3324,6 +3324,7 @@ def __init__(self, structure, tree_name="", position=(0, 0), self._nodes = [] self._nodes_dict = {} self.node_height = node_height + self.content_size = size super(Tree2D, self).__init__(position) self.resize(size) @@ -3341,7 +3342,7 @@ def _setup(self): icon=_icon_path, indent=self.indent, child_indent=self.indent, child_height=self.node_height, - auto_resize=True) + auto_resize=True, size=self.content_size) for node in self.nodes_dict.values(): node.set_visibility(False) @@ -3529,16 +3530,17 @@ def __init__(self, label, parent=None, children=None, icon=None, self.icon = read_viz_icons(fname='stop2.png') self._child_nodes = [] + self.has_ui = False self.parent = parent - self.indent = indent + self.indent = np.clip(indent, 0, int(size[0]*0.025)) self.label = label - self.child_indent = child_indent + self.child_indent = np.clip(child_indent, 0, int(size[0]*0.025)) self.child_height = child_height self.content_size = size self.expandable = expandable - self.expanded = expanded + self._expanded = expanded self.selected = False self.selected_nodes = [] @@ -3548,6 +3550,7 @@ def __init__(self, label, parent=None, children=None, icon=None, self.auto_resize = auto_resize super(TreeNode2D, self).__init__(position) + self.expanded = expanded self.resize(size) self.title_panel.color = color self.title_panel.opacity = opacity @@ -3597,13 +3600,6 @@ def _setup(self): for child in self.children: self.add_node(child) - if self.expanded: - self.set_visibility(True) - self.button.set_icon_by_name('expand') - else: - self.set_visibility(False) - self.button.set_icon_by_name('collapse') - if not self.expandable: self.button.set_visibility(False) @@ -3653,17 +3649,22 @@ def add_node(self, node, coords=(0., 0.)): """ self._child_nodes.append(node) if isinstance(node, type(self)): + if self.has_ui: + raise ValueError('A tree node with UI elements cannot have child nodes') + node.parent = self + node.expanded = False node.title_panel.set_visibility(False) node.child_height = self.child_height _node_coords = (self.indent+self.child_indent, self.children_size() - node.child_height) else: + self.has_ui = True _node_coords = coords self.content_panel.add_element(node, _node_coords) - self.resize((self.size[0], self.children_size())) + self.resize((self.size[0], self.children_size(1))) def resize(self, size): """ Resizes the Tree Node. @@ -3679,7 +3680,11 @@ def resize(self, size): self.label_text.resize((size[0]-self.button.size[0], self.child_height)) - self.label_image.resize((self.child_height, self.child_height)) + if size[0] >= 200: + self.label_image.resize((self.child_height, self.child_height)) + else: + self.label_image.resize((0, 0)) + self.button.resize((self.child_height, self.child_height)) self.title_panel.update_element(self.label_text, @@ -3722,7 +3727,6 @@ def toggle_view(self, i_ren, _obj, _element): Instance of the node """ self.expanded = not self.expanded - self.set_visibility(self.expanded) parent = self.parent if self.expanded: @@ -3736,11 +3740,10 @@ def toggle_view(self, i_ren, _obj, _element): while parent is not None: if parent.auto_resize: - current_size = parent.content_panel.size[1] - if parent.children_size() > parent.content_panel.size[1]: + if parent.size[1] < parent.children_size(): parent.resize((parent.size[0], parent.children_size())) else: - parent.resize((parent.size[0], current_size)) + parent.resize(parent.content_size) parent = parent.parent @@ -3769,12 +3772,21 @@ def update_children_coords(self, node, size_offset): node.update_children_coords(node.parent, size_offset) - def children_size(self): + def children_size(self, relative=False): """Returns the size occupied by the children vertically. """ - _size = sum([child.size[1] for child in self.child_nodes]) + if relative: + sizes = [] + for child in self._child_nodes: + relative_size = child.size[1] + (child.position[1] - self.content_panel.position[1]) + sizes.append(relative_size) - return _size + if len(sizes): + return int(max(sizes)) + else: + return 0 + + return sum([child.size[1] for child in self._child_nodes]) def set_visibility(self, visibility): """Set visibility of this UI component.""" @@ -3878,6 +3890,31 @@ def child_height(self, height): for node in self.child_nodes: node.child_height = height + @property + def expanded(self): + return self._expanded + + @expanded.setter + def expanded(self, expanded): + """Sets the expanded state of the node. + + Parameters + ---------- + expanded: bool + True if the node is to be expanded, False otherwise + """ + self._expanded = expanded + self.set_visibility(expanded) + + if expanded: + self.set_visibility(True) + self.button.set_icon_by_name('expand') + else: + self.set_visibility(False) + self.button.set_icon_by_name('collapse') + for child in self.child_nodes: + child.expanded = False + def select_node(self, i_ren, _obj, _node2d): """Callback for when the node is clicked on. From 6f32fead20375988f0bffb109462cadc1135a024 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 21 Jul 2021 19:11:45 +0530 Subject: [PATCH 28/45] fix: updated the Tree2D Ui widgety --- fury/ui/elements.py | 36 +++++++++++++++++++----------------- test.py | 15 +++++++-------- 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index a8a7da9f7..6a5c8e67b 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3530,6 +3530,7 @@ def __init__(self, label, parent=None, children=None, icon=None, self.icon = read_viz_icons(fname='stop2.png') self._child_nodes = [] + self._largest_size = 0 self.has_ui = False self.parent = parent self.indent = np.clip(indent, 0, int(size[0]*0.025)) @@ -3658,13 +3659,26 @@ def add_node(self, node, coords=(0., 0.)): node.child_height = self.child_height _node_coords = (self.indent+self.child_indent, - self.children_size() - node.child_height) + self.children_size() - self.child_height) + + self.content_panel.add_element(node, _node_coords) + self.resize((self.size[0], self.children_size())) else: self.has_ui = True _node_coords = coords + is_floating = np.issubdtype(np.array(_node_coords).dtype, + np.floating) - self.content_panel.add_element(node, _node_coords) - self.resize((self.size[0], self.children_size(1))) + self.content_panel.add_element(node, _node_coords) + if is_floating: + relative_size = node.size[1] + \ + int(self.content_panel.size[1]*_node_coords[1]) + + if self._largest_size < relative_size: + self._largest_size = relative_size + self.resize((self.size[0], self._largest_size)) + else: + self.resize((self.size[0], self.children_size())) def resize(self, size): """ Resizes the Tree Node. @@ -3772,20 +3786,8 @@ def update_children_coords(self, node, size_offset): node.update_children_coords(node.parent, size_offset) - def children_size(self, relative=False): - """Returns the size occupied by the children vertically. - """ - if relative: - sizes = [] - for child in self._child_nodes: - relative_size = child.size[1] + (child.position[1] - self.content_panel.position[1]) - sizes.append(relative_size) - - if len(sizes): - return int(max(sizes)) - else: - return 0 - + def children_size(self): + """Returns the size occupied by the children vertically.""" return sum([child.size[1] for child in self._child_nodes]) def set_visibility(self, visibility): diff --git a/test.py b/test.py index c7b2e571d..7f610bdb0 100644 --- a/test.py +++ b/test.py @@ -4,10 +4,11 @@ from fury import ui, window, actor, utils structure = [{'Cube': ['Translate', 'Color']}, - {'Test': ['Test-1']}] + {'Cylinder': []}, + {'Cone': []}] tree = ui.elements.Tree2D(structure=structure, tree_name="Actor Modifier", - size=(300, 300), position=(0, 0), + size=(600, 600), position=(0, 0), color=(0.8, 0.4, 0.2)) ############################################################################### @@ -105,9 +106,9 @@ def change_b(slider): ############################################################################### # Adding sliders to their respective nodes -tree.add_content('Translate', ring_slider, (0., 0.)) -tree.add_content('Translate', line_slider_x, (0., 1.0)) -tree.add_content('Translate', line_slider_y, (0.5, 0.5)) +tree.add_content('Translate', ring_slider, (0.5, 0.5)) +tree.add_content('Translate', line_slider_x, (0, 0.)) +tree.add_content('Translate', line_slider_y, (0., 0.)) tree.add_content('Color', line_slider_r, (0., 0.)) tree.add_content('Color', line_slider_g, (0.25, 0.)) @@ -130,12 +131,10 @@ def visibility_off(tree_ui): cube_node = tree.select_node('Cube') color_node = tree.select_node('Color') -cube.SetVisibility(False) - cube_node.on_node_select = visibility_on cube_node.on_node_deselect = visibility_off -current_size = (800, 800) +current_size = (1000, 1000) show_manager = window.ShowManager(size=current_size, title="FURY Tree2D Example") From 6cc23c13168bc0563a683957e3ebb3ed570b5873 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Sun, 25 Jul 2021 19:32:11 +0530 Subject: [PATCH 29/45] feat: resize w.r.t largest child --- fury/ui/elements.py | 61 ++++++++++++++++++++++++++++++--------------- test.py | 17 ++++++++++--- 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 6a5c8e67b..24c063beb 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3530,7 +3530,7 @@ def __init__(self, label, parent=None, children=None, icon=None, self.icon = read_viz_icons(fname='stop2.png') self._child_nodes = [] - self._largest_size = 0 + self._normalized_children = [] self.has_ui = False self.parent = parent self.indent = np.clip(indent, 0, int(size[0]*0.025)) @@ -3651,7 +3651,9 @@ def add_node(self, node, coords=(0., 0.)): self._child_nodes.append(node) if isinstance(node, type(self)): if self.has_ui: - raise ValueError('A tree node with UI elements cannot have child nodes') + raise ValueError( + 'A tree node with UI elements cannot have child nodes' + ) node.parent = self node.expanded = False @@ -3660,33 +3662,30 @@ def add_node(self, node, coords=(0., 0.)): _node_coords = (self.indent+self.child_indent, self.children_size() - self.child_height) - - self.content_panel.add_element(node, _node_coords) - self.resize((self.size[0], self.children_size())) + + _node_size = (self.size[0], self.size[1] + node.size[1]) else: self.has_ui = True _node_coords = coords is_floating = np.issubdtype(np.array(_node_coords).dtype, np.floating) - self.content_panel.add_element(node, _node_coords) if is_floating: - relative_size = node.size[1] + \ - int(self.content_panel.size[1]*_node_coords[1]) + self._normalized_children.append({node: coords}) + _node_size = (self.size[0], self._largest_child_size()) - if self._largest_size < relative_size: - self._largest_size = relative_size - self.resize((self.size[0], self._largest_size)) - else: - self.resize((self.size[0], self.children_size())) + self.content_panel.add_element(node, _node_coords) + self.resize(_node_size) - def resize(self, size): + def resize(self, size, recursive=True): """ Resizes the Tree Node. Parameters ---------- size : (int, int) New width and height in pixels. + recursive : bool, optional + If True, all the children nodes are resized as well. """ self.title_panel.resize((size[0], self.child_height)) self.content_panel.resize(size) @@ -3718,10 +3717,13 @@ def resize(self, size): for child in self._child_nodes: if isinstance(child, type(self)): - _child_size = (size[0] - self.indent - - self.child_indent, child.children_size()) + if recursive: + _child_size = (size[0] - self.indent - + self.child_indent, + child.children_size()) + + child.resize(_child_size) - child.resize(_child_size) _child_coords = (self.indent+self.child_indent, self.content_panel.size[1]-_content_size) @@ -3755,9 +3757,11 @@ def toggle_view(self, i_ren, _obj, _element): while parent is not None: if parent.auto_resize: if parent.size[1] < parent.children_size(): - parent.resize((parent.size[0], parent.children_size())) + parent.resize((parent.size[0], parent.children_size()), + recursive=False) else: - parent.resize(parent.content_size) + parent.resize((parent.size[0], parent.content_size[1]), + recursive=False) parent = parent.parent @@ -3810,6 +3814,23 @@ def select_child(self, child_label): idx = lables.index(child_label) return self.child_nodes[idx] + def _largest_child_size(self): + """Returns the size occupied by the largest child node.""" + rel_sizes = [] + + for child in self._normalized_children: + child_node = list(child.keys())[0] + coords = list(child.values())[0] + relative_size = child_node.size[1] + \ + self.content_panel.size[1]*coords[1] + + rel_sizes.append(relative_size) + + if not len(rel_sizes): + rel_sizes = [0] + + return int(max(rel_sizes)) + @property def child_nodes(self): """Returns all the child nodes of the current node @@ -3895,7 +3916,7 @@ def child_height(self, height): @property def expanded(self): return self._expanded - + @expanded.setter def expanded(self, expanded): """Sets the expanded state of the node. diff --git a/test.py b/test.py index 7f610bdb0..c96f6160d 100644 --- a/test.py +++ b/test.py @@ -1,15 +1,15 @@ -from fury.ui.elements import TreeNode2D import numpy as np from fury import ui, window, actor, utils +from fury.ui.elements import TreeNode2D structure = [{'Cube': ['Translate', 'Color']}, {'Cylinder': []}, {'Cone': []}] tree = ui.elements.Tree2D(structure=structure, tree_name="Actor Modifier", - size=(600, 600), position=(0, 0), - color=(0.8, 0.4, 0.2)) + size=(400, 400), position=(0, 0), + color=(0.8, 0.4, 0.2), opacity=1) ############################################################################### # Slider Controls for the node Cube @@ -56,22 +56,26 @@ cube_g = 0 cube_b = 0 + def rotate_cube(slider): angle = slider.value previous_angle = slider.previous_value rotation_angle = angle - previous_angle cube.RotateX(rotation_angle) + def translate_cube_x(slider): global cube_x, cube_y cube_x = slider.value cube.SetPosition(cube_x, cube_y, 0) + def translate_cube_y(slider): global cube_x, cube_y cube_y = slider.value cube.SetPosition(cube_x, cube_y, 0) + def update_colors(): global cube vcolors = utils.colors_from_actor(cube) @@ -79,25 +83,30 @@ def update_colors(): vcolors[:] = colarr utils.update_actor(cube) + def change_r(slider): global cube_r, cube_g, cube_b cube_r = slider.value update_colors() + def change_g(slider): global cube_r, cube_g, cube_b cube_g = slider.value update_colors() + def change_b(slider): global cube_r, cube_g, cube_b cube_b = slider.value update_colors() + ring_slider.on_change = rotate_cube line_slider_x.on_change = translate_cube_x line_slider_y.on_change = translate_cube_y + # Callbacks for color sliders line_slider_r.on_change = change_r line_slider_g.on_change = change_g @@ -117,10 +126,12 @@ def change_b(slider): ############################################################################### # Defining hook to toggle the visibility of the cube + def visibility_on(tree_ui): global cube cube.SetVisibility(1) + def visibility_off(tree_ui): global cube cube.SetVisibility(0) From 60aa08e397a223e807ed31239040b85eb668edcf Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 26 Jul 2021 12:03:23 +0530 Subject: [PATCH 30/45] fix: fixed title panel resizing --- fury/ui/elements.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 24c063beb..8f4b9f65b 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3690,6 +3690,11 @@ def resize(self, size, recursive=True): self.title_panel.resize((size[0], self.child_height)) self.content_panel.resize(size) + if self.expandable: + self.button.resize((self.child_height, self.child_height)) + else: + self.button.resize((0, 0)) + self.label_text.resize((size[0]-self.button.size[0], self.child_height)) @@ -3698,8 +3703,6 @@ def resize(self, size, recursive=True): else: self.label_image.resize((0, 0)) - self.button.resize((self.child_height, self.child_height)) - self.title_panel.update_element(self.label_text, (self.label_image.size[0], 0)) From d6f9b0a25d8799654466758638e2e3b83b8f82c4 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 27 Jul 2021 01:53:54 +0530 Subject: [PATCH 31/45] docs: added actor modifier using tree in tutorials --- .../02_ui/viz_tree_actor_modifier.py | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) rename test.py => docs/tutorials/02_ui/viz_tree_actor_modifier.py (90%) diff --git a/test.py b/docs/tutorials/02_ui/viz_tree_actor_modifier.py similarity index 90% rename from test.py rename to docs/tutorials/02_ui/viz_tree_actor_modifier.py index c96f6160d..f67eac0f9 100644 --- a/test.py +++ b/docs/tutorials/02_ui/viz_tree_actor_modifier.py @@ -1,14 +1,24 @@ +# -*- coding: utf-8 -*- +""" +=============== +Actor Modifier using a Tree UI +=============== + +This example shows how to create an actor moidifier using a Tree UI. +The parameters that will be modified are the colors, position, +rotation of the cube. + +First, some imports. +""" import numpy as np - from fury import ui, window, actor, utils -from fury.ui.elements import TreeNode2D structure = [{'Cube': ['Translate', 'Color']}, {'Cylinder': []}, {'Cone': []}] tree = ui.elements.Tree2D(structure=structure, tree_name="Actor Modifier", - size=(400, 400), position=(0, 0), + size=(400, 400), position=(0, 400), color=(0.8, 0.4, 0.2), opacity=1) ############################################################################### @@ -152,7 +162,10 @@ def visibility_off(tree_ui): show_manager.scene.add(tree, cube) # To interact with the UI, set interactive = True -interactive = True +interactive = False if interactive: show_manager.start() + +window.record(show_manager.scene, size=current_size, + out_path="viz_tree_actor_modifier.png") \ No newline at end of file From ce4d8f90aa6cbb7e15c691f51e3ad1c556089d33 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 27 Jul 2021 01:54:48 +0530 Subject: [PATCH 32/45] fix: addressed comments --- docs/tutorials/02_ui/viz_tree_ui.py | 10 +++++----- fury/ui/elements.py | 29 ++++++++++++++++++----------- fury/ui/tests/test_elements.py | 5 +++-- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/docs/tutorials/02_ui/viz_tree_ui.py b/docs/tutorials/02_ui/viz_tree_ui.py index 2990660fd..3e36d4fde 100644 --- a/docs/tutorials/02_ui/viz_tree_ui.py +++ b/docs/tutorials/02_ui/viz_tree_ui.py @@ -14,8 +14,8 @@ ############################################################################### # Now, we create UI elements for the Containers node # First, we create panles for the Panels node -panel = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) -panel_1 = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) +panel_first = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) +panel_second = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) ############################################################################### # Now, we create an ImageContainer2D for the ImageContainers node @@ -27,8 +27,8 @@ ############################################################################### # Now, we add the UI elements to their respective nodes. -tree.add_content('Panels', panel_1) -tree.add_content('Panels', panel, (0.5, 0.5)) +tree.add_content('Panels', panel_first) +tree.add_content('Panels', panel_second, (0.5, 0.5)) tree.add_content('ImageContainers', img, (0.5, 0.5)) ############################################################################### @@ -68,7 +68,7 @@ show_manager.scene.add(tree) # To interact with the UI, set interactive = True -interactive = True +interactive = False if interactive: show_manager.start() diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 8f4b9f65b..d88412d13 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -2,7 +2,8 @@ __all__ = ["Button2D", "TextBox2D", "LineSlider2D", "LineDoubleSlider2D", "RingSlider2D", "RangeSlider", "Checkbox", "Option", "RadioButton", - "ComboBox2D", "ListBox2D", "ListBoxItem2D", "FileMenu2D"] + "ComboBox2D", "ListBox2D", "ListBoxItem2D", "FileMenu2D", "Tree2D", + "TreeNode2D"] import os from collections import OrderedDict @@ -3483,7 +3484,8 @@ def __init__(self, label, parent=None, children=None, icon=None, position=(0, 0), size=(200, 200), indent=20, child_indent=10, child_height=25, color=(0.3, 0.3, 0.3), opacity=0.8, expandable=True, expanded=False, - selected_color=(0.8, 0.3, 0.3), auto_resize=True): + selected_color=(0.8, 0.3, 0.3), auto_resize=True, + multiselect=True): """Initialize the UI element Parameters @@ -3521,13 +3523,13 @@ def __init__(self, label, parent=None, children=None, icon=None, Color of the unselected node. auto_resize: bool, optional If the node should automatically resize to fit its content. + multiselect: bool, optional + If multiple nodes can be selected. """ self.children = children self.icon = icon - if self.children is None: - self.children = [] - if self.icon is None: - self.icon = read_viz_icons(fname='stop2.png') + self.children = children or [] + self.icon = icon or read_viz_icons(fname='stop2.png') self._child_nodes = [] self._normalized_children = [] @@ -3547,6 +3549,7 @@ def __init__(self, label, parent=None, children=None, icon=None, self.selected_nodes = [] self.selected_color = selected_color self.unselected_color = color + self.multiselect = multiselect self.auto_resize = auto_resize @@ -3941,7 +3944,7 @@ def expanded(self, expanded): for child in self.child_nodes: child.expanded = False - def select_node(self, i_ren, _obj, _node2d): + def select_node(self, i_ren, _obj, _element): """Callback for when the node is clicked on. Parameters @@ -3950,17 +3953,21 @@ def select_node(self, i_ren, _obj, _node2d): Interactor style used to interact with the scene. _obj: :class:`vtkActor` The picked actor - _node2d: :class:`TreeNode2D` - Instance of the selected node + _element: :class: `Rectangle2D` + Element associated with the event. """ self.selected = not self.selected if self.selected: - self.selected_nodes.append(_node2d) + if self.parent: + self.parent.selected_nodes.append(self) + self.color = self.selected_color self.on_node_select(self) else: - self.selected_nodes.remove(_node2d) + if self.parent: + self.selected_nodes.remove(self) + self.color = self.unselected_color self.on_node_deselect(self) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index 854ad8154..5359de94a 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1133,8 +1133,9 @@ def node_select(node): def node_deselect(node): selected.remove(node) - parent_node.on_node_select = node_select - parent_node.on_node_deselect = node_deselect + for child_node in parent_node.child_nodes: + child_node.on_node_select = node_select + child_node.on_node_deselect = node_deselect event_counter = EventCounter() event_counter.monitor(parent_node) From ef7bab6a26ca675a94c28f3c5f692e98c0f4e377 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 27 Jul 2021 20:07:50 +0530 Subject: [PATCH 33/45] fix: fixed the tree2d tutorial --- .../tutorials/02_ui/viz_tree_actor_modifier.py | 4 ++-- docs/tutorials/02_ui/viz_tree_ui.py | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/docs/tutorials/02_ui/viz_tree_actor_modifier.py b/docs/tutorials/02_ui/viz_tree_actor_modifier.py index f67eac0f9..7a69eb5e2 100644 --- a/docs/tutorials/02_ui/viz_tree_actor_modifier.py +++ b/docs/tutorials/02_ui/viz_tree_actor_modifier.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- """ -=============== +============================== Actor Modifier using a Tree UI -=============== +============================== This example shows how to create an actor moidifier using a Tree UI. The parameters that will be modified are the colors, position, diff --git a/docs/tutorials/02_ui/viz_tree_ui.py b/docs/tutorials/02_ui/viz_tree_ui.py index 3e36d4fde..1d0b228e4 100644 --- a/docs/tutorials/02_ui/viz_tree_ui.py +++ b/docs/tutorials/02_ui/viz_tree_ui.py @@ -1,3 +1,14 @@ +# -*- coding: utf-8 -*- +""" +============================= +FURY UI Breakdown with Tree2D +============================= + +This example vizualizes different types of UI elements that are available, +in FURY's UI sub-module with the help of a Tree2D UI element. + +First, some imports. +""" from fury import ui, window from fury.ui.core import Disk2D, Rectangle2D from fury.ui.elements import LineSlider2D, ListBox2D @@ -8,7 +19,7 @@ {'Core': ['Rectangle', 'Disk']}] tree = ui.elements.Tree2D(structure=structure, tree_name="FURY UI Breakdown", - size=(500, 500), position=(0, 0), + size=(500, 500), position=(0, 500), color=(0.8, 0.4, 0.2)) ############################################################################### @@ -63,7 +74,7 @@ current_size = (1000, 1000) show_manager = window.ShowManager(size=current_size, - title="FURY Bullet List Example") + title="FURY Tree2D Example") show_manager.scene.add(tree) @@ -72,3 +83,6 @@ if interactive: show_manager.start() + +window.record(show_manager.scene, size=current_size, + out_path="viz_tree2d.png") From e1ce8a59244375d1849b8d3af6c572c141e1886c Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 27 Jul 2021 20:08:30 +0530 Subject: [PATCH 34/45] feat: added multiselct feature --- fury/ui/elements.py | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index d88412d13..d8f868f5d 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3296,7 +3296,7 @@ class Tree2D(UI): def __init__(self, structure, tree_name="", position=(0, 0), size=(300, 300), node_height=30, color=(0.3, 0.3, 0.3), - opacity=0.8, indent=25): + opacity=0.8, indent=25, multiselect=True): """Initialize the UI element Parameter @@ -3318,6 +3318,8 @@ def __init__(self, structure, tree_name="", position=(0, 0), Background opacity of the Tree2D indent: int, optional Global indentation for the parent/child nodes + multiselect: bool, optional + If multiple nodes can be selected. """ self.structure = structure self.tree_name = tree_name @@ -3326,6 +3328,7 @@ def __init__(self, structure, tree_name="", position=(0, 0), self._nodes_dict = {} self.node_height = node_height self.content_size = size + self.multiselect = multiselect super(Tree2D, self).__init__(position) self.resize(size) @@ -3343,7 +3346,8 @@ def _setup(self): icon=_icon_path, indent=self.indent, child_indent=self.indent, child_height=self.node_height, - auto_resize=True, size=self.content_size) + auto_resize=True, size=self.content_size, + multiselect=self.multiselect) for node in self.nodes_dict.values(): node.set_visibility(False) @@ -3390,11 +3394,14 @@ def generate_tree(self, structure): if parent_label in self.nodes_dict.keys(): parent_node = self.nodes_dict[parent_label] else: - parent_node = TreeNode2D(label=parent_label) + parent_node = TreeNode2D(label=parent_label, + multiselect=self.multiselect) + self._nodes.append(parent_node) self._nodes_dict[parent_label] = parent_node - child_nodes = [TreeNode2D(label=child_label) for child_label in + child_nodes = [TreeNode2D(label=child_label, + multiselect=self.multiselect) for child_label in child_labels] for child_node, child_label in zip(child_nodes, child_labels): @@ -3944,6 +3951,16 @@ def expanded(self, expanded): for child in self.child_nodes: child.expanded = False + def clear_selections(self): + """Clear all the selcted nodes.""" + for selected_node in self.selected_nodes: + selected_node.color = selected_node.unselected_color + selected_node.on_node_deselect(selected_node) + selected_node.selected = False + selected_node.clear_selections() + + self.selected_nodes.clear() + def select_node(self, i_ren, _obj, _element): """Callback for when the node is clicked on. @@ -3959,14 +3976,21 @@ def select_node(self, i_ren, _obj, _element): self.selected = not self.selected if self.selected: + if self.parent: + if not self.multiselect: + self.parent.clear_selections() + self.parent.selected_nodes.append(self) self.color = self.selected_color self.on_node_select(self) else: if self.parent: - self.selected_nodes.remove(self) + self.parent.selected_nodes.remove(self) + + if not self.multiselect: + self.parent.clear_selections() self.color = self.unselected_color self.on_node_deselect(self) From 5e6c66c9962a3275a344edf895af4e27045c8aaa Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Tue, 27 Jul 2021 20:08:45 +0530 Subject: [PATCH 35/45] test: updated tests for TreeNode2D --- fury/ui/tests/test_elements.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index 5359de94a..a937a51f3 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1156,3 +1156,5 @@ def node_deselect(node): event_counter.check_counts(expected) npt.assert_equal(parent_node.selected_nodes, selected) + parent_node.clear_selections() + npt.assert_equal(parent_node.selected_nodes, []) From ee49b34a2752f43c8309c592d89a4cef0164a77b Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Mon, 2 Aug 2021 15:14:56 +0530 Subject: [PATCH 36/45] feat: allow UI to be dragged by text/icon --- fury/ui/elements.py | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index d8f63a724..ba71abcea 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3382,10 +3382,6 @@ def _setup(self): self.title_panel.add_element(self.label_image, (0., 0.)) - self.button.on_left_mouse_button_clicked = self.toggle_view - self.title_panel.background.on_left_mouse_button_clicked = \ - self.select_node - if self.children: for child in self.children: self.add_node(child) @@ -3393,6 +3389,21 @@ def _setup(self): if not self.expandable: self.button.set_visibility(False) + # Adding event callbacks + self.button.on_left_mouse_button_clicked = self.toggle_view + self.label_text.on_left_mouse_button_pressed =\ + self.left_button_pressed + + self.label_image.on_left_mouse_button_pressed =\ + self.left_button_pressed + + self.title_panel.background.on_left_mouse_button_clicked = \ + self.select_node + + self.label_text.on_left_mouse_button_dragged = self.left_button_dragged + self.label_image.on_left_mouse_button_dragged =\ + self.left_button_dragged + def _get_actors(self): """ Get the actors composing this UI component. """ @@ -3775,3 +3786,15 @@ def select_node(self, i_ren, _obj, _element): self.on_node_deselect(self) i_ren.force_render() + + def left_button_pressed(self, i_ren, _obj, _sub_component): + click_pos = np.array(i_ren.event.position) + self._click_position = click_pos + i_ren.event.abort() + + def left_button_dragged(self, i_ren, _obj, _sub_component): + click_position = np.array(i_ren.event.position) + change = click_position - self._click_position + self.title_panel.position += change + self._click_position = click_position + i_ren.force_render() From 8f9fd88661a040d92e425a8c1f8d775cd81f27a8 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Sun, 8 Aug 2021 00:24:20 +0530 Subject: [PATCH 37/45] feat: icon setter/getter, click callback on text --- fury/ui/elements.py | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index ba71abcea..f27228bca 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -18,7 +18,7 @@ from fury.ui.containers import ImageContainer2D, Panel2D from fury.ui.helpers import TWO_PI, clip_overflow from fury.ui.core import Button2D - +from fury.io import load_image, set_input class TextBox2D(UI): """An editable 2D text box that behaves as a UI component. @@ -3313,9 +3313,8 @@ def __init__(self, label, parent=None, children=None, icon=None, If multiple nodes can be selected. """ self.children = children - self.icon = icon self.children = children or [] - self.icon = icon or read_viz_icons(fname='stop2.png') + self._icon = icon or read_viz_icons(fname='stop2.png') self._child_nodes = [] self._normalized_children = [] @@ -3393,6 +3392,9 @@ def _setup(self): self.button.on_left_mouse_button_clicked = self.toggle_view self.label_text.on_left_mouse_button_pressed =\ self.left_button_pressed + + self.label_text.on_left_mouse_button_clicked =\ + self.select_node self.label_image.on_left_mouse_button_pressed =\ self.left_button_pressed @@ -3463,7 +3465,7 @@ def add_node(self, node, coords=(0., 0.)): _node_coords = (self.indent+self.child_indent, self.children_size() - self.child_height) - _node_size = (self.size[0], self.size[1] + node.size[1]) + _node_size = (self.size[0], self.children_size() + node.size[1]) else: self.has_ui = True _node_coords = coords @@ -3473,6 +3475,8 @@ def add_node(self, node, coords=(0., 0.)): if is_floating: self._normalized_children.append({node: coords}) _node_size = (self.size[0], self._largest_child_size()) + else: + _node_size = (self.size[0], self._largest_child_size() + node.size[1]) self.content_panel.add_element(node, _node_coords) self.resize(_node_size) @@ -3495,14 +3499,14 @@ def resize(self, size, recursive=True): else: self.button.resize((0, 0)) - self.label_text.resize((size[0]-self.button.size[0], - self.child_height)) - if size[0] >= 200: self.label_image.resize((self.child_height, self.child_height)) else: self.label_image.resize((0, 0)) + self.label_text.resize((size[0]-self.button.size[0]-self.label_image.size[0], + self.child_height)) + self.title_panel.update_element(self.label_text, (self.label_image.size[0], 0)) @@ -3740,6 +3744,24 @@ def expanded(self, expanded): self.button.set_icon_by_name('collapse') for child in self.child_nodes: child.expanded = False + + @property + def icon(self): + return self._icon + + @icon.setter + def icon(self, icon): + """Set a new image as the label icon. + + Parameters + ---------- + icon : str + Path to the icon image + """ + self._icon = icon + _img_data = load_image(icon, as_vtktype=True) + self.label_image.texture = set_input(self.label_image.texture, + _img_data) def clear_selections(self): """Clear all the selcted nodes.""" From 201d7742f384a842c3634ad6ec4b32275fa44d35 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Sun, 8 Aug 2021 00:30:39 +0530 Subject: [PATCH 38/45] fix: pep8 --- fury/ui/elements.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index f27228bca..6119a39f0 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3392,7 +3392,7 @@ def _setup(self): self.button.on_left_mouse_button_clicked = self.toggle_view self.label_text.on_left_mouse_button_pressed =\ self.left_button_pressed - + self.label_text.on_left_mouse_button_clicked =\ self.select_node @@ -3476,7 +3476,8 @@ def add_node(self, node, coords=(0., 0.)): self._normalized_children.append({node: coords}) _node_size = (self.size[0], self._largest_child_size()) else: - _node_size = (self.size[0], self._largest_child_size() + node.size[1]) + _node_size = (self.size[0], + self._largest_child_size() + node.size[1]) self.content_panel.add_element(node, _node_coords) self.resize(_node_size) @@ -3504,8 +3505,8 @@ def resize(self, size, recursive=True): else: self.label_image.resize((0, 0)) - self.label_text.resize((size[0]-self.button.size[0]-self.label_image.size[0], - self.child_height)) + self.label_text.resize((size[0] - self.button.size[0] + - self.label_image.size[0], self.child_height)) self.title_panel.update_element(self.label_text, (self.label_image.size[0], 0)) @@ -3744,15 +3745,15 @@ def expanded(self, expanded): self.button.set_icon_by_name('collapse') for child in self.child_nodes: child.expanded = False - + @property def icon(self): return self._icon - + @icon.setter def icon(self, icon): """Set a new image as the label icon. - + Parameters ---------- icon : str From 62e47faf30707b097235e61109c9838bb9184991 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Sun, 8 Aug 2021 00:32:39 +0530 Subject: [PATCH 39/45] fix: pep8 fixes in example --- docs/tutorials/02_ui/viz_tree_actor_modifier.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorials/02_ui/viz_tree_actor_modifier.py b/docs/tutorials/02_ui/viz_tree_actor_modifier.py index 7a69eb5e2..71c3183d8 100644 --- a/docs/tutorials/02_ui/viz_tree_actor_modifier.py +++ b/docs/tutorials/02_ui/viz_tree_actor_modifier.py @@ -168,4 +168,4 @@ def visibility_off(tree_ui): show_manager.start() window.record(show_manager.scene, size=current_size, - out_path="viz_tree_actor_modifier.png") \ No newline at end of file + out_path="viz_tree_actor_modifier.png") From aa316e81b75b99a6187c8037dc338c7be1ff4f5a Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 25 Aug 2021 00:06:49 +0530 Subject: [PATCH 40/45] fix: auto-resizing, label_text coords --- fury/ui/elements.py | 4 +-- test.py | 88 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 2 deletions(-) create mode 100644 test.py diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 6119a39f0..35853c9c3 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -3509,7 +3509,7 @@ def resize(self, size, recursive=True): - self.label_image.size[0], self.child_height)) self.title_panel.update_element(self.label_text, - (self.label_image.size[0], 0)) + (self.label_image.size[0], -(size[1]//100))) self.title_panel.update_element(self.button, (self.title_panel.size - @@ -3564,7 +3564,7 @@ def toggle_view(self, i_ren, _obj, _element): while parent is not None: if parent.auto_resize: - if parent.size[1] < parent.children_size(): + if parent.content_size[1] < parent.children_size(): parent.resize((parent.size[0], parent.children_size()), recursive=False) else: diff --git a/test.py b/test.py new file mode 100644 index 000000000..e52c8e233 --- /dev/null +++ b/test.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- +""" +============================= +FURY UI Breakdown with Tree2D +============================= + +This example vizualizes different types of UI elements that are available, +in FURY's UI sub-module with the help of a Tree2D UI element. + +First, some imports. +""" +from fury import ui, window +from fury.ui.core import Disk2D, Rectangle2D +from fury.ui.elements import LineSlider2D, ListBox2D +from fury.ui.containers import ImageContainer2D + +structure = [{'Containers': ['Panels', 'ImageContainers']}, + {'Elements': ['ListBox', 'LineSlider']}, + {'Core': ['Rectangle', 'Disk']}] + +tree = ui.elements.Tree2D(structure=structure, tree_name="FURY UI Breakdown", + size=(500, 500), position=(0, 500), + color=(0.8, 0.4, 0.2)) + +############################################################################### +# Now, we create UI elements for the Containers node +# First, we create panles for the Panels node +panel_first = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) +panel_second = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) + +############################################################################### +# Now, we create an ImageContainer2D for the ImageContainers node +path = "https://raw.githubusercontent.com/fury-gl/"\ + "fury-communication-assets/main/fury-logo.png" + +img = ImageContainer2D(img_path=path, size=(100, 100)) + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('Panels', panel_first) +tree.add_content('Panels', panel_second, (0.5, 0.5)) +tree.add_content('ImageContainers', img, (0.5, 0.5)) + +############################################################################### +# Now, lets create UI elements for the Elements node +# First we create Listbox for the ListBox node +listbox = ListBox2D(values=['First', 'Second', 'Third', 'Fourth']) + +############################################################################### +# Now, lets create a LineSlider for the LineSlider node +lineslider = LineSlider2D(length=200, orientation="vertical") + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('ListBox', listbox) +tree.add_content('LineSlider', lineslider, (0.5, 0.5)) + +############################################################################### +# Now, lets create UI elements for the Core node +# First we create Rectangle2D for teh Rectangle node +rect = Rectangle2D(size=(100, 100), color=(0.8, 0.4, 0.7)) + +############################################################################### +# Now, let's create Disk2D for the Disk node +disk = Disk2D(outer_radius=50, color=(0.6, 0.2, 0.8)) + +############################################################################### +# Now, we add the UI elements to their respective nodes. + +tree.add_content('Rectangle', rect) +tree.add_content('Disk', disk, (0.5, 0.5)) + +current_size = (1000, 1000) +show_manager = window.ShowManager(size=current_size, + title="FURY Tree2D Example") + +show_manager.scene.add(tree) + +# To interact with the UI, set interactive = True +interactive = True + +if interactive: + show_manager.start() + +window.record(show_manager.scene, size=current_size, + out_path="viz_tree2d.png") From d5688364e33b62f32162054fac40bce3c472acc3 Mon Sep 17 00:00:00 2001 From: antrikshmisri Date: Wed, 25 Aug 2021 00:08:53 +0530 Subject: [PATCH 41/45] fix: removed redundant files --- test.py | 88 --------------------------------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 test.py diff --git a/test.py b/test.py deleted file mode 100644 index e52c8e233..000000000 --- a/test.py +++ /dev/null @@ -1,88 +0,0 @@ -# -*- coding: utf-8 -*- -""" -============================= -FURY UI Breakdown with Tree2D -============================= - -This example vizualizes different types of UI elements that are available, -in FURY's UI sub-module with the help of a Tree2D UI element. - -First, some imports. -""" -from fury import ui, window -from fury.ui.core import Disk2D, Rectangle2D -from fury.ui.elements import LineSlider2D, ListBox2D -from fury.ui.containers import ImageContainer2D - -structure = [{'Containers': ['Panels', 'ImageContainers']}, - {'Elements': ['ListBox', 'LineSlider']}, - {'Core': ['Rectangle', 'Disk']}] - -tree = ui.elements.Tree2D(structure=structure, tree_name="FURY UI Breakdown", - size=(500, 500), position=(0, 500), - color=(0.8, 0.4, 0.2)) - -############################################################################### -# Now, we create UI elements for the Containers node -# First, we create panles for the Panels node -panel_first = ui.Panel2D(size=(100, 100), color=(0.5, 0.7, 0.3)) -panel_second = ui.Panel2D(size=(100, 100), color=(0.3, 0.8, 0.5)) - -############################################################################### -# Now, we create an ImageContainer2D for the ImageContainers node -path = "https://raw.githubusercontent.com/fury-gl/"\ - "fury-communication-assets/main/fury-logo.png" - -img = ImageContainer2D(img_path=path, size=(100, 100)) - -############################################################################### -# Now, we add the UI elements to their respective nodes. - -tree.add_content('Panels', panel_first) -tree.add_content('Panels', panel_second, (0.5, 0.5)) -tree.add_content('ImageContainers', img, (0.5, 0.5)) - -############################################################################### -# Now, lets create UI elements for the Elements node -# First we create Listbox for the ListBox node -listbox = ListBox2D(values=['First', 'Second', 'Third', 'Fourth']) - -############################################################################### -# Now, lets create a LineSlider for the LineSlider node -lineslider = LineSlider2D(length=200, orientation="vertical") - -############################################################################### -# Now, we add the UI elements to their respective nodes. - -tree.add_content('ListBox', listbox) -tree.add_content('LineSlider', lineslider, (0.5, 0.5)) - -############################################################################### -# Now, lets create UI elements for the Core node -# First we create Rectangle2D for teh Rectangle node -rect = Rectangle2D(size=(100, 100), color=(0.8, 0.4, 0.7)) - -############################################################################### -# Now, let's create Disk2D for the Disk node -disk = Disk2D(outer_radius=50, color=(0.6, 0.2, 0.8)) - -############################################################################### -# Now, we add the UI elements to their respective nodes. - -tree.add_content('Rectangle', rect) -tree.add_content('Disk', disk, (0.5, 0.5)) - -current_size = (1000, 1000) -show_manager = window.ShowManager(size=current_size, - title="FURY Tree2D Example") - -show_manager.scene.add(tree) - -# To interact with the UI, set interactive = True -interactive = True - -if interactive: - show_manager.start() - -window.record(show_manager.scene, size=current_size, - out_path="viz_tree2d.png") From b96a4b2f59707c373b667e0fbaf5e16b911f528f Mon Sep 17 00:00:00 2001 From: Praneeth Shetty Date: Thu, 14 Sep 2023 08:48:06 +0530 Subject: [PATCH 42/45] updating the return actors from the TextBlock2D --- fury/ui/core.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fury/ui/core.py b/fury/ui/core.py index f184e7d16..891174ca0 100644 --- a/fury/ui/core.py +++ b/fury/ui/core.py @@ -781,7 +781,9 @@ def resize(self, size): def _get_actors(self): """Get the actors composing this UI component.""" - return [self.actor] + self.background.actors + if self.have_bg: + return [self.actor] + self.background.actors + return [self.actor] def _add_to_scene(self, scene): """Add all subcomponents or VTK props that compose this UI component. From a1895a28ee946dfc74ea2ffad6bcc0fae430dc59 Mon Sep 17 00:00:00 2001 From: Praneeth Shetty Date: Thu, 14 Sep 2023 08:55:01 +0530 Subject: [PATCH 43/45] updating set_visibility to set_content_visibility --- fury/ui/elements.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 030a06a01..72b32af7f 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -4641,7 +4641,10 @@ def _setup(self): multiselect=self.multiselect) for node in self.nodes_dict.values(): - node.set_visibility(False) + if node.parent != self.base_node: + node.set_visibility(False) + else: + node.set_content_visibility(False) def _get_actors(self): """ Get the actors composing this UI component. @@ -4824,7 +4827,6 @@ def __init__(self, label, parent=None, children=None, icon=None, multiselect: bool, optional If multiple nodes can be selected. """ - self.children = children self.children = children or [] self._icon = icon or read_viz_icons(fname='stop2.png') @@ -4971,7 +4973,6 @@ def add_node(self, node, coords=(0., 0.)): node.parent = self node.expanded = False - node.title_panel.set_visibility(False) node.child_height = self.child_height _node_coords = (self.indent+self.child_indent, @@ -5081,7 +5082,7 @@ def toggle_view(self, i_ren, _obj, _element): recursive=False) else: parent.resize((parent.size[0], parent.content_size[1]), - recursive=False) + recursive=True) parent = parent.parent @@ -5114,13 +5115,13 @@ def children_size(self): """Returns the size occupied by the children vertically.""" return sum([child.size[1] for child in self._child_nodes]) - def set_visibility(self, visibility): - """Set visibility of this UI component.""" + def set_content_visibility(self, visibility): + """Set content's visibility of this UI component.""" self.content_panel.set_visibility(visibility) - for child_node in self._child_nodes: - if isinstance(child_node, type(self)): - child_node.set_visibility(False) + for element in self.content_panel._elements: + if isinstance(element, type(self)): + element.set_content_visibility(element.expanded) def select_child(self, child_label): """Get the instance of a particular child node. @@ -5247,13 +5248,12 @@ def expanded(self, expanded): True if the node is to be expanded, False otherwise """ self._expanded = expanded - self.set_visibility(expanded) if expanded: - self.set_visibility(True) + self.set_content_visibility(True) self.button.set_icon_by_name('expand') else: - self.set_visibility(False) + self.set_content_visibility(False) self.button.set_icon_by_name('collapse') for child in self.child_nodes: child.expanded = False From fc44468ad83b873356f57fb4a4a9a2f560e1ee5c Mon Sep 17 00:00:00 2001 From: Praneeth Shetty Date: Thu, 14 Sep 2023 08:57:17 +0530 Subject: [PATCH 44/45] updating title label text position --- fury/ui/elements.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fury/ui/elements.py b/fury/ui/elements.py index 72b32af7f..2e48f3a8a 100644 --- a/fury/ui/elements.py +++ b/fury/ui/elements.py @@ -5022,7 +5022,7 @@ def resize(self, size, recursive=True): - self.label_image.size[0], self.child_height)) self.title_panel.update_element(self.label_text, - (self.label_image.size[0], -(size[1]//100))) + (self.label_image.size[0], 0)) self.title_panel.update_element(self.button, (self.title_panel.size - From 0e2bd11070be173a06e321dd30d25148c169ae6b Mon Sep 17 00:00:00 2001 From: Praneeth Shetty Date: Thu, 14 Sep 2023 09:57:12 +0530 Subject: [PATCH 45/45] updating tests --- fury/ui/tests/test_elements.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/fury/ui/tests/test_elements.py b/fury/ui/tests/test_elements.py index fd53ed543..d28d3a25d 100644 --- a/fury/ui/tests/test_elements.py +++ b/fury/ui/tests/test_elements.py @@ -1479,8 +1479,7 @@ def test_ui_tree_2d(interactive=False): event_counter.check_counts(expected) for node in tree.nodes: - child = node.child_nodes[0] - npt.assert_equal(node.size[1], child.size[1]+tree.node_height) + npt.assert_equal(node.size[1], tree.node_height) def test_ui_treenode_2d(interactive=False):