From 323bbac4c154db7e536d2529af84d7de6c486c86 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 6 Sep 2024 00:46:28 +0200 Subject: [PATCH 1/4] update data type --- src/compas_viewer/components/sceneform.py | 2 +- src/compas_viewer/components/treeform.py | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/compas_viewer/components/sceneform.py b/src/compas_viewer/components/sceneform.py index 76f39c0356..9423c591a0 100644 --- a/src/compas_viewer/components/sceneform.py +++ b/src/compas_viewer/components/sceneform.py @@ -38,7 +38,7 @@ def __init__( self, columns: list[dict], column_editable: Optional[list[bool]] = None, - show_headers: bool = True, + show_headers: Optional[bool] = True, callback: Optional[Callable] = None, ): super().__init__() diff --git a/src/compas_viewer/components/treeform.py b/src/compas_viewer/components/treeform.py index 8d2cc68631..4f767554b8 100644 --- a/src/compas_viewer/components/treeform.py +++ b/src/compas_viewer/components/treeform.py @@ -16,10 +16,10 @@ class Treeform(QTreeWidget): Parameters ---------- - tree : :class:`compas.datastructures.Tree` + tree : :class:`compas.datastructures.Tree`, optional The tree to be displayed. An typical example is the scene object tree: :attr:`compas_viewer.viewer.Viewer._tree`. - columns : dict[str, callable] + columns : dict[str, callable], optional A dictionary of column names and their corresponding attributes. Example: ``{"Name": (lambda o: o.name), "Object": (lambda o: o)}`` show_headers : bool, optional @@ -67,10 +67,10 @@ class Treeform(QTreeWidget): def __init__( self, - tree: Tree = None, - columns: dict[str, Callable] = None, - show_headers: bool = True, - stretch: int = 2, + tree: Optional[Tree] = None, + columns: Optional[dict[str, Callable]] = None, + show_headers: Optional[bool] = True, + stretch: Optional[int] = 2, backgrounds: Optional[dict[str, Callable]] = None, callback: Optional[Callable] = None, ): From bca948e4f45fe6248b813a2948af141b2cb27a48 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 6 Sep 2024 03:05:55 +0200 Subject: [PATCH 2/4] add dynamic class to treeform --- src/compas_viewer/components/sceneform.py | 15 +++++++++++ src/compas_viewer/components/treeform.py | 31 +++++++++++++++++++++++ src/compas_viewer/config.py | 2 +- src/compas_viewer/ui/sidebar.py | 2 +- 4 files changed, 48 insertions(+), 2 deletions(-) diff --git a/src/compas_viewer/components/sceneform.py b/src/compas_viewer/components/sceneform.py index 9423c591a0..dfa7d087de 100644 --- a/src/compas_viewer/components/sceneform.py +++ b/src/compas_viewer/components/sceneform.py @@ -5,6 +5,8 @@ from PySide6.QtWidgets import QTreeWidget from PySide6.QtWidgets import QTreeWidgetItem +from compas_viewer.components.treeform import Treeform + class Sceneform(QTreeWidget): """ @@ -37,12 +39,14 @@ class Sceneform(QTreeWidget): def __init__( self, columns: list[dict], + show_selected_tree: Optional[bool] = True, column_editable: Optional[list[bool]] = None, show_headers: Optional[bool] = True, callback: Optional[Callable] = None, ): super().__init__() self.columns = columns + self.show_selected_tree = show_selected_tree self.checkbox_columns: dict[int, str] = {} self.column_editable = (column_editable or [False]) + [False] * (len(columns) - len(column_editable or [False])) self.setColumnCount(len(columns)) @@ -75,6 +79,8 @@ def update(self): if node.is_selected: self.expand(node.parent) self.scrollToItem(widget) + if self.show_selected_tree: + self.update_selected(node) else: self._sceneobjects = list(self.scene.objects) @@ -109,6 +115,8 @@ def update(self): widget.setSelected(node.is_selected) if node.is_selected: self.expand(node.parent) + if self.show_selected_tree: + self.update_selected(node) widget.setFlags(widget.flags() | Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | Qt.ItemIsEnabled) @@ -119,6 +127,13 @@ def update(self): self.adjust_column_widths() + def update_selected(self, node): + if not hasattr(self, "treeform"): + self.treeform = Treeform() + self.viewer.ui.sidebar.widget.addWidget(self.treeform) + + self.treeform.update_from_dict({"objtype": node.__class__, "item": node.item, "settings": node.settings}) + def expand(self, node): if node.attributes.get("widget"): node.attributes["widget"].setExpanded(True) diff --git a/src/compas_viewer/components/treeform.py b/src/compas_viewer/components/treeform.py index 4f767554b8..a06216d85a 100644 --- a/src/compas_viewer/components/treeform.py +++ b/src/compas_viewer/components/treeform.py @@ -5,9 +5,15 @@ from PySide6.QtWidgets import QTreeWidget from PySide6.QtWidgets import QTreeWidgetItem +import compas.datastructures as ds +import compas.geometry as geom from compas.datastructures import Tree from compas.datastructures import TreeNode +# Collect all classes from compas.geometry dynamically +geometry_types = tuple(getattr(geom, attr) for attr in dir(geom) if isinstance(getattr(geom, attr), type)) +datastructures_types = tuple(getattr(ds, attr) for attr in dir(ds) if isinstance(getattr(ds, attr), type)) + class Treeform(QTreeWidget): """ @@ -115,6 +121,7 @@ def tree_from_dict(self, data): def add_children(key, data, parent): if isinstance(data, dict): + # TODO: bug - if key == 0, TreeNode name show Treenode is not created node = TreeNode(name=key) for child_key, child_data in data.items(): add_children(child_key, child_data, node) @@ -122,6 +129,30 @@ def add_children(key, data, parent): node = TreeNode(name=key) for child_index, child_data in enumerate(data): add_children(child_index, child_data, node) + elif isinstance(data, geometry_types): + node = TreeNode(name=key) + for i, attr_name in enumerate(data.__data__): + if isinstance(attr_name, str): + if hasattr(data, attr_name): + attr_value = getattr(data, attr_name) + add_children(attr_name, attr_value, node) + elif isinstance(attr_name, float) and len(data.__data__) == 3: + attr_value = attr_name + if i == 0: + attr_name = "x" + elif i == 1: + attr_name = "y" + elif i == 2: + attr_name = "z" + add_children(attr_name, attr_value, node) + elif isinstance(data, datastructures_types): + node = TreeNode(name=key) + for attr_name in data.__data__: + if isinstance(attr_name, str): + if hasattr(data, attr_name): + attr_value = getattr(data, attr_name) + print(f"Attribute: {attr_name}, Value: {attr_value}") + add_children(attr_name, attr_value, node) else: node = TreeNode(name=key, value=data) diff --git a/src/compas_viewer/config.py b/src/compas_viewer/config.py index bf3571618f..628dd3819b 100644 --- a/src/compas_viewer/config.py +++ b/src/compas_viewer/config.py @@ -246,7 +246,7 @@ class StatusbarConfig(ConfigBase): class SidebarConfig(ConfigBase): show: bool = True show_widgets: bool = True - sceneform: bool = True + show_selected_tree: bool = True items: list[dict] = field( default_factory=lambda: [ { diff --git a/src/compas_viewer/ui/sidebar.py b/src/compas_viewer/ui/sidebar.py index 0fe5b52f88..5ccded7f71 100644 --- a/src/compas_viewer/ui/sidebar.py +++ b/src/compas_viewer/ui/sidebar.py @@ -31,7 +31,7 @@ def add_items(self) -> None: columns = item.get("columns", None) if columns is None: raise ValueError("Please setup config for Sceneform") - self.sceneform = Sceneform(columns=columns) + self.sceneform = Sceneform(columns=columns, show_selected_tree=self.ui.viewer.config.ui.sidebar.show_selected_tree) self.widget.addWidget(self.sceneform) elif itemtype == "ObjectSetting": From 4ba6816fead1082c562a3ecdf6cee3f186736b35 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 6 Sep 2024 10:25:27 +0200 Subject: [PATCH 3/4] change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 21f8e79768..f4be337111 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## Unreleased ### Added +* Added dynamic import to enable access from expended `TreeForm`. ### Changed From 20e349c60cae02286617c8e5b08689387eb90357 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 6 Sep 2024 11:06:29 +0200 Subject: [PATCH 4/4] todo --- src/compas_viewer/components/treeform.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compas_viewer/components/treeform.py b/src/compas_viewer/components/treeform.py index a06216d85a..e1381001d7 100644 --- a/src/compas_viewer/components/treeform.py +++ b/src/compas_viewer/components/treeform.py @@ -121,7 +121,7 @@ def tree_from_dict(self, data): def add_children(key, data, parent): if isinstance(data, dict): - # TODO: bug - if key == 0, TreeNode name show Treenode is not created + # TODO: bug - if key == 0, TreeNode name show Treenode instead of 0 node = TreeNode(name=key) for child_key, child_data in data.items(): add_children(child_key, child_data, node)