From 72219ee2ed7848b7932cfa4d2524ebee5361be10 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Thu, 25 Jul 2024 02:49:01 +0200 Subject: [PATCH 1/8] tab feature --- src/compas_viewer/components/objectsetting.py | 47 ++++++++++++++----- 1 file changed, 35 insertions(+), 12 deletions(-) diff --git a/src/compas_viewer/components/objectsetting.py b/src/compas_viewer/components/objectsetting.py index 2a536befb3..c2a954cd82 100644 --- a/src/compas_viewer/components/objectsetting.py +++ b/src/compas_viewer/components/objectsetting.py @@ -5,6 +5,7 @@ from PySide6.QtWidgets import QDialog from PySide6.QtWidgets import QPushButton from PySide6.QtWidgets import QScrollArea +from PySide6.QtWidgets import QTabWidget from PySide6.QtWidgets import QVBoxLayout from PySide6.QtWidgets import QWidget @@ -60,15 +61,37 @@ def __init__(self, viewer: "Viewer", items: list[dict]): # Main layout self.main_layout = QVBoxLayout(self) - # Scroll area setup - self.scroll_area = QScrollArea(self) - self.scroll_area.setWidgetResizable(True) - self.scroll_content = QWidget() - self.scroll_layout = QVBoxLayout(self.scroll_content) - self.scroll_layout.setAlignment(Qt.AlignTop) - self.scroll_area.setWidget(self.scroll_content) - - self.main_layout.addWidget(self.scroll_area) + # Tab widget setup + self.tab_widget = QTabWidget(self) + + # Tab 1 setup + self.tab1_content = QWidget() + self.tab1_scroll_area = QScrollArea(self.tab1_content) + self.tab1_scroll_area.setWidgetResizable(True) + self.tab1_scroll_content = QWidget() + self.tab1_scroll_layout = QVBoxLayout(self.tab1_scroll_content) + self.tab1_scroll_layout.setAlignment(Qt.AlignTop) + self.tab1_scroll_area.setWidget(self.tab1_scroll_content) + + tab1_layout = QVBoxLayout(self.tab1_content) + tab1_layout.addWidget(self.tab1_scroll_area) + self.tab_widget.addTab(self.tab1_content, "Tab 1") + + # Tab 2 setup + self.tab2_content = QWidget() + self.tab2_scroll_area = QScrollArea(self.tab2_content) + self.tab2_scroll_area.setWidgetResizable(True) + self.tab2_scroll_content = QWidget() + self.tab2_scroll_layout = QVBoxLayout(self.tab2_scroll_content) + self.tab2_scroll_layout.setAlignment(Qt.AlignTop) + self.tab2_scroll_area.setWidget(self.tab2_scroll_content) + + tab2_layout = QVBoxLayout(self.tab2_content) + tab2_layout.addWidget(self.tab2_scroll_area) + self.tab_widget.addTab(self.tab2_content, "Tab 2") + + # Add tab widget to main layout + self.main_layout.addWidget(self.tab_widget) def clear_layout(self, layout): """Clear all widgets from the layout.""" @@ -84,18 +107,18 @@ def clear_layout(self, layout): def update(self): """Update the layout with the latest object settings.""" - self.clear_layout(self.scroll_layout) + self.clear_layout(self.tab1_scroll_layout) self.setting_layout.generate_layout() if len(self.setting_layout.widgets) != 0: - self.scroll_layout.addLayout(self.setting_layout.layout) + self.tab1_scroll_layout.addLayout(self.setting_layout.layout) for _, widget in self.setting_layout.widgets.items(): if isinstance(widget, DoubleEdit): widget.spinbox.valueChanged.connect(self.obj_update) elif isinstance(widget, TextEdit): widget.text_edit.textChanged.connect(self.obj_update) else: - self.scroll_layout.addWidget(LabelWidget(text="No object Selected", alignment="center")) + self.tab1_scroll_layout.addWidget(LabelWidget(text="No object Selected", alignment="center")) def obj_update(self): """Apply the settings from spin boxes to the selected objects.""" From 5d256a82cabbecf2557bef48b194596756e852f8 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 26 Jul 2024 02:45:29 +0200 Subject: [PATCH 2/8] factory pattern --- scripts/example.py | 2 +- src/compas_viewer/components/objectsetting.py | 64 +++++---------- src/compas_viewer/components/sceneform.py | 8 +- src/compas_viewer/config.py | 4 +- src/compas_viewer/ui/sidebar.py | 79 ++++++++++++------- 5 files changed, 79 insertions(+), 78 deletions(-) diff --git a/scripts/example.py b/scripts/example.py index e4b5e0d8a9..bbd0826b2a 100644 --- a/scripts/example.py +++ b/scripts/example.py @@ -21,5 +21,5 @@ facecolor=Color(i / N, j / M, 0.0), name=f"Box_{i}_{j}", ) - +# viewer.ui.sidebar.show_objectsetting = False viewer.show() diff --git a/src/compas_viewer/components/objectsetting.py b/src/compas_viewer/components/objectsetting.py index c2a954cd82..6a8ed3e52a 100644 --- a/src/compas_viewer/components/objectsetting.py +++ b/src/compas_viewer/components/objectsetting.py @@ -1,11 +1,8 @@ -from typing import TYPE_CHECKING - from PySide6.QtCore import Qt from PySide6.QtCore import Signal from PySide6.QtWidgets import QDialog from PySide6.QtWidgets import QPushButton from PySide6.QtWidgets import QScrollArea -from PySide6.QtWidgets import QTabWidget from PySide6.QtWidgets import QVBoxLayout from PySide6.QtWidgets import QWidget @@ -15,9 +12,6 @@ from compas_viewer.components.layout import SettingLayout from compas_viewer.components.textedit import TextEdit -if TYPE_CHECKING: - from compas_viewer import Viewer - class ObjectSetting(QWidget): """ @@ -53,45 +47,28 @@ class ObjectSetting(QWidget): update_requested = Signal() - def __init__(self, viewer: "Viewer", items: list[dict]): + def __init__(self, items: list[dict]): super().__init__() - self.viewer = viewer self.items = items - self.setting_layout = SettingLayout(viewer=self.viewer, items=self.items, type="obj_setting") + # self.setting_layout = SettingLayout(viewer=self.viewer, items=self.items, type="obj_setting") # Main layout self.main_layout = QVBoxLayout(self) - # Tab widget setup - self.tab_widget = QTabWidget(self) - - # Tab 1 setup - self.tab1_content = QWidget() - self.tab1_scroll_area = QScrollArea(self.tab1_content) - self.tab1_scroll_area.setWidgetResizable(True) - self.tab1_scroll_content = QWidget() - self.tab1_scroll_layout = QVBoxLayout(self.tab1_scroll_content) - self.tab1_scroll_layout.setAlignment(Qt.AlignTop) - self.tab1_scroll_area.setWidget(self.tab1_scroll_content) - - tab1_layout = QVBoxLayout(self.tab1_content) - tab1_layout.addWidget(self.tab1_scroll_area) - self.tab_widget.addTab(self.tab1_content, "Tab 1") - - # Tab 2 setup - self.tab2_content = QWidget() - self.tab2_scroll_area = QScrollArea(self.tab2_content) - self.tab2_scroll_area.setWidgetResizable(True) - self.tab2_scroll_content = QWidget() - self.tab2_scroll_layout = QVBoxLayout(self.tab2_scroll_content) - self.tab2_scroll_layout.setAlignment(Qt.AlignTop) - self.tab2_scroll_area.setWidget(self.tab2_scroll_content) - - tab2_layout = QVBoxLayout(self.tab2_content) - tab2_layout.addWidget(self.tab2_scroll_area) - self.tab_widget.addTab(self.tab2_content, "Tab 2") - - # Add tab widget to main layout - self.main_layout.addWidget(self.tab_widget) + # Scroll area setup + self.scroll_area = QScrollArea(self) + self.scroll_area.setWidgetResizable(True) + self.scroll_content = QWidget() + self.scroll_layout = QVBoxLayout(self.scroll_content) + self.scroll_layout.setAlignment(Qt.AlignTop) + self.scroll_area.setWidget(self.scroll_content) + + self.main_layout.addWidget(self.scroll_area) + + @property + def viewer(self): + from compas_viewer import Viewer + + return Viewer() def clear_layout(self, layout): """Clear all widgets from the layout.""" @@ -107,18 +84,19 @@ def clear_layout(self, layout): def update(self): """Update the layout with the latest object settings.""" - self.clear_layout(self.tab1_scroll_layout) + self.clear_layout(self.scroll_layout) + self.setting_layout = SettingLayout(viewer=self.viewer, items=self.items, type="obj_setting") self.setting_layout.generate_layout() if len(self.setting_layout.widgets) != 0: - self.tab1_scroll_layout.addLayout(self.setting_layout.layout) + self.scroll_layout.addLayout(self.setting_layout.layout) for _, widget in self.setting_layout.widgets.items(): if isinstance(widget, DoubleEdit): widget.spinbox.valueChanged.connect(self.obj_update) elif isinstance(widget, TextEdit): widget.text_edit.textChanged.connect(self.obj_update) else: - self.tab1_scroll_layout.addWidget(LabelWidget(text="No object Selected", alignment="center")) + self.scroll_layout.addWidget(LabelWidget(text="No object Selected", alignment="center")) def obj_update(self): """Apply the settings from spin boxes to the selected objects.""" diff --git a/src/compas_viewer/components/sceneform.py b/src/compas_viewer/components/sceneform.py index a0f9d13224..0045fd25a6 100644 --- a/src/compas_viewer/components/sceneform.py +++ b/src/compas_viewer/components/sceneform.py @@ -36,16 +36,16 @@ class Sceneform(QTreeWidget): def __init__( self, - columns: list[dict], + items: list[dict], column_editable: Optional[list[bool]] = None, show_headers: bool = True, callback: Optional[Callable] = None, ): super().__init__() - self.columns = columns + self.columns = items 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)) + self.column_editable = (column_editable or [False]) + [False] * (len(self.columns) - len(column_editable or [False])) + self.setColumnCount(len(self.columns)) self.setHeaderLabels(col["title"] for col in self.columns) self.setHeaderHidden(not show_headers) self.setSelectionMode(QTreeWidget.SingleSelection) diff --git a/src/compas_viewer/config.py b/src/compas_viewer/config.py index 4dac80c12a..5e9fc8559b 100644 --- a/src/compas_viewer/config.py +++ b/src/compas_viewer/config.py @@ -250,12 +250,14 @@ class SidebarConfig(ConfigBase): default_factory=lambda: [ { "type": "Sceneform", - "columns": [ + "items": [ {"title": "Name", "type": "label", "text": lambda obj: obj.name}, {"title": "Show", "type": "checkbox", "checked": lambda obj: obj.show, "action": lambda obj, checked: setattr(obj, "show", checked)}, ], }, { + "area": "tab", + "title": "OBJ", "type": "ObjectSetting", "items": [ {"title": "Name", "items": [{"type": "text_edit", "action": lambda obj: obj.name}]}, diff --git a/src/compas_viewer/ui/sidebar.py b/src/compas_viewer/ui/sidebar.py index 0fe5b52f88..841de8eb87 100644 --- a/src/compas_viewer/ui/sidebar.py +++ b/src/compas_viewer/ui/sidebar.py @@ -3,6 +3,7 @@ from PySide6 import QtCore from PySide6.QtWidgets import QSplitter +from PySide6.QtWidgets import QTabWidget from compas_viewer.components import Sceneform from compas_viewer.components.objectsetting import ObjectSetting @@ -10,44 +11,42 @@ if TYPE_CHECKING: from .ui import UI +# Factory registry +type_registry = { + "Sceneform": Sceneform, + "ObjectSetting": ObjectSetting, +} + class SideBarRight: def __init__(self, ui: "UI", show: bool, items: list[dict[str, Callable]]) -> None: self.ui = ui self.widget = QSplitter(QtCore.Qt.Orientation.Vertical) self.widget.setChildrenCollapsible(True) + self._tab_widget = None self.show = show self.hide_widget = True self.items = items - def add_items(self) -> None: - if not self.items: - return - - for item in self.items: - itemtype = item.get("type", None) + # # Tab 1 setup + # self.tab1_content = QWidget() + # self.tab1_scroll_area = QScrollArea(self.tab1_content) + # self.tab1_scroll_area.setWidgetResizable(True) + # self.tab1_scroll_content = QWidget() + # self.tab1_scroll_layout = QVBoxLayout(self.tab1_scroll_content) + # self.tab1_scroll_layout.setAlignment(Qt.AlignTop) + # self.tab1_scroll_area.setWidget(self.tab1_scroll_content) - if itemtype == "Sceneform": - columns = item.get("columns", None) - if columns is None: - raise ValueError("Please setup config for Sceneform") - self.sceneform = Sceneform(columns=columns) - self.widget.addWidget(self.sceneform) + # tab1_layout = QVBoxLayout(self.tab1_content) + # tab1_layout.addWidget(self.tab1_scroll_area) + # self.tab_widget.addTab(self.tab1_content, "Tab 1") - elif itemtype == "ObjectSetting": - items = item.get("items", None) - if items is None: - raise ValueError("Please setup config for ObjectSetting") - self.object_setting = ObjectSetting(viewer=self.ui.viewer, items=items) - self.widget.addWidget(self.object_setting) - - self.show_sceneform = True - self.show_objectsetting = True + @property + def tab_widget(self): + if self._tab_widget is None: + self._tab_widget = QTabWidget(self.widget) - def update(self): - self.widget.update() - for widget in self.widget.children(): - widget.update() + return self._tab_widget @property def show(self): @@ -59,16 +58,38 @@ def show(self, value: bool): @property def show_sceneform(self): - return self.sceneform.isVisible() + return self.Sceneform.isVisible() @show_sceneform.setter def show_sceneform(self, value: bool): - self.sceneform.setVisible(value) + self.Sceneform.setVisible(value) @property def show_objectsetting(self): - return self.object_setting.isVisible() + return self.ObjectSetting.isVisible() @show_objectsetting.setter def show_objectsetting(self, value: bool): - self.object_setting.setVisible(value) + self.ObjectSetting.setVisible(value) + + def add_items(self) -> None: + if not self.items: + return + + for item in self.items: + # area = item.get("area", None) + itemtype = item.get("type", None) + items = item.get("items", None) + + if itemtype in type_registry: + if items is None: + raise ValueError("Please setup config for Sceneform") + widget = type_registry[itemtype](items=items) + # set the attribute dynamically + setattr(self, itemtype, widget) + self.widget.addWidget(widget) + + def update(self): + self.widget.update() + for widget in self.widget.children(): + widget.update() From 3dffd5da7e4e0f7d79acfcde41aec48cf44ac91a Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 26 Jul 2024 03:28:38 +0200 Subject: [PATCH 3/8] tab widget --- scripts/example.py | 2 +- src/compas_viewer/components/objectsetting.py | 2 +- src/compas_viewer/ui/sidebar.py | 43 +++++++++---------- 3 files changed, 22 insertions(+), 25 deletions(-) diff --git a/scripts/example.py b/scripts/example.py index bbd0826b2a..e4b5e0d8a9 100644 --- a/scripts/example.py +++ b/scripts/example.py @@ -21,5 +21,5 @@ facecolor=Color(i / N, j / M, 0.0), name=f"Box_{i}_{j}", ) -# viewer.ui.sidebar.show_objectsetting = False + viewer.show() diff --git a/src/compas_viewer/components/objectsetting.py b/src/compas_viewer/components/objectsetting.py index 6a8ed3e52a..1cec990dd3 100644 --- a/src/compas_viewer/components/objectsetting.py +++ b/src/compas_viewer/components/objectsetting.py @@ -50,7 +50,6 @@ class ObjectSetting(QWidget): def __init__(self, items: list[dict]): super().__init__() self.items = items - # self.setting_layout = SettingLayout(viewer=self.viewer, items=self.items, type="obj_setting") # Main layout self.main_layout = QVBoxLayout(self) @@ -84,6 +83,7 @@ def clear_layout(self, layout): def update(self): """Update the layout with the latest object settings.""" + print("Updating object settings") self.clear_layout(self.scroll_layout) self.setting_layout = SettingLayout(viewer=self.viewer, items=self.items, type="obj_setting") self.setting_layout.generate_layout() diff --git a/src/compas_viewer/ui/sidebar.py b/src/compas_viewer/ui/sidebar.py index 841de8eb87..7da91d70f0 100644 --- a/src/compas_viewer/ui/sidebar.py +++ b/src/compas_viewer/ui/sidebar.py @@ -1,9 +1,12 @@ from typing import TYPE_CHECKING from typing import Callable +from typing import Optional from PySide6 import QtCore +from PySide6.QtWidgets import QHeaderView from PySide6.QtWidgets import QSplitter from PySide6.QtWidgets import QTabWidget +from PySide6.QtWidgets import QWidget from compas_viewer.components import Sceneform from compas_viewer.components.objectsetting import ObjectSetting @@ -23,29 +26,16 @@ def __init__(self, ui: "UI", show: bool, items: list[dict[str, Callable]]) -> No self.ui = ui self.widget = QSplitter(QtCore.Qt.Orientation.Vertical) self.widget.setChildrenCollapsible(True) - self._tab_widget = None + self._tab_widget: Optional[QTabWidget] = None self.show = show self.hide_widget = True self.items = items - # # Tab 1 setup - # self.tab1_content = QWidget() - # self.tab1_scroll_area = QScrollArea(self.tab1_content) - # self.tab1_scroll_area.setWidgetResizable(True) - # self.tab1_scroll_content = QWidget() - # self.tab1_scroll_layout = QVBoxLayout(self.tab1_scroll_content) - # self.tab1_scroll_layout.setAlignment(Qt.AlignTop) - # self.tab1_scroll_area.setWidget(self.tab1_scroll_content) - - # tab1_layout = QVBoxLayout(self.tab1_content) - # tab1_layout.addWidget(self.tab1_scroll_area) - # self.tab_widget.addTab(self.tab1_content, "Tab 1") - @property def tab_widget(self): if self._tab_widget is None: self._tab_widget = QTabWidget(self.widget) - + self.widget.addWidget(self._tab_widget) return self._tab_widget @property @@ -58,26 +48,26 @@ def show(self, value: bool): @property def show_sceneform(self): - return self.Sceneform.isVisible() + return getattr(self, "Sceneform", QWidget()).isVisible() @show_sceneform.setter def show_sceneform(self, value: bool): - self.Sceneform.setVisible(value) + getattr(self, "Sceneform", QWidget()).setVisible(value) @property def show_objectsetting(self): - return self.ObjectSetting.isVisible() + return getattr(self, "ObjectSetting", QWidget()).isVisible() @show_objectsetting.setter def show_objectsetting(self, value: bool): - self.ObjectSetting.setVisible(value) + getattr(self, "ObjectSetting", QWidget()).setVisible(value) def add_items(self) -> None: if not self.items: return for item in self.items: - # area = item.get("area", None) + area = item.get("area", None) itemtype = item.get("type", None) items = item.get("items", None) @@ -87,9 +77,16 @@ def add_items(self) -> None: widget = type_registry[itemtype](items=items) # set the attribute dynamically setattr(self, itemtype, widget) - self.widget.addWidget(widget) + if area == "tab": + self.tab_widget.addTab(widget, itemtype) + else: + self.widget.addWidget(widget) def update(self): - self.widget.update() - for widget in self.widget.children(): + self._update_recursive(self.widget) + + def _update_recursive(self, widget: QWidget) -> None: + if not isinstance(widget, QHeaderView) and hasattr(widget, "update"): widget.update() + for child in widget.findChildren(QWidget): + self._update_recursive(child) From 8653d3e92e81bd46d9c6e534c750bef649fe1c80 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 26 Jul 2024 04:45:48 +0200 Subject: [PATCH 4/8] update_widgets --- src/compas_viewer/config.py | 2 +- src/compas_viewer/ui/sidebar.py | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/compas_viewer/config.py b/src/compas_viewer/config.py index 5e9fc8559b..80570a8b67 100644 --- a/src/compas_viewer/config.py +++ b/src/compas_viewer/config.py @@ -249,6 +249,7 @@ class SidebarConfig(ConfigBase): items: list[dict] = field( default_factory=lambda: [ { + "area": "splitter", "type": "Sceneform", "items": [ {"title": "Name", "type": "label", "text": lambda obj: obj.name}, @@ -257,7 +258,6 @@ class SidebarConfig(ConfigBase): }, { "area": "tab", - "title": "OBJ", "type": "ObjectSetting", "items": [ {"title": "Name", "items": [{"type": "text_edit", "action": lambda obj: obj.name}]}, diff --git a/src/compas_viewer/ui/sidebar.py b/src/compas_viewer/ui/sidebar.py index 7da91d70f0..5de7cbf3bd 100644 --- a/src/compas_viewer/ui/sidebar.py +++ b/src/compas_viewer/ui/sidebar.py @@ -3,7 +3,6 @@ from typing import Optional from PySide6 import QtCore -from PySide6.QtWidgets import QHeaderView from PySide6.QtWidgets import QSplitter from PySide6.QtWidgets import QTabWidget from PySide6.QtWidgets import QWidget @@ -14,7 +13,6 @@ if TYPE_CHECKING: from .ui import UI -# Factory registry type_registry = { "Sceneform": Sceneform, "ObjectSetting": ObjectSetting, @@ -31,11 +29,13 @@ def __init__(self, ui: "UI", show: bool, items: list[dict[str, Callable]]) -> No self.hide_widget = True self.items = items + # add widgets manualy to avoide multiple emits signals from QTabWidget + self.update_widgets = [] + @property def tab_widget(self): if self._tab_widget is None: self._tab_widget = QTabWidget(self.widget) - self.widget.addWidget(self._tab_widget) return self._tab_widget @property @@ -73,20 +73,18 @@ def add_items(self) -> None: if itemtype in type_registry: if items is None: - raise ValueError("Please setup config for Sceneform") + raise ValueError(f"Please setup config for {itemtype} widget") widget = type_registry[itemtype](items=items) # set the attribute dynamically setattr(self, itemtype, widget) if area == "tab": self.tab_widget.addTab(widget, itemtype) - else: + elif area == "splitter": self.widget.addWidget(widget) + self.update_widgets.append(widget) def update(self): - self._update_recursive(self.widget) - - def _update_recursive(self, widget: QWidget) -> None: - if not isinstance(widget, QHeaderView) and hasattr(widget, "update"): + self.widget.update() + for widget in self.update_widgets: widget.update() - for child in widget.findChildren(QWidget): - self._update_recursive(child) + From 2a8253f97bcbb56840f31ecaafc00c39b6a1f462 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 26 Jul 2024 04:48:46 +0200 Subject: [PATCH 5/8] change log --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2c6c774375..5fbcb0e52f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Added `ColorDialog` to manage color dialog. * Added `SettingLayout` to manage complex layout with config input. * Added `robot.py` example. +* Added `QTabWidget` to `SideBarRight`. ### Changed From b20c02bbeb6a5be669336c6352a9005253431c71 Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 26 Jul 2024 04:49:36 +0200 Subject: [PATCH 6/8] clean --- src/compas_viewer/components/objectsetting.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compas_viewer/components/objectsetting.py b/src/compas_viewer/components/objectsetting.py index 1cec990dd3..9addd5d19f 100644 --- a/src/compas_viewer/components/objectsetting.py +++ b/src/compas_viewer/components/objectsetting.py @@ -83,7 +83,6 @@ def clear_layout(self, layout): def update(self): """Update the layout with the latest object settings.""" - print("Updating object settings") self.clear_layout(self.scroll_layout) self.setting_layout = SettingLayout(viewer=self.viewer, items=self.items, type="obj_setting") self.setting_layout.generate_layout() From 43b9e7d26255fc1d488a360b85919af906cb29cf Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Fri, 26 Jul 2024 04:51:53 +0200 Subject: [PATCH 7/8] format --- src/compas_viewer/ui/sidebar.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/compas_viewer/ui/sidebar.py b/src/compas_viewer/ui/sidebar.py index 5de7cbf3bd..9da4520ddc 100644 --- a/src/compas_viewer/ui/sidebar.py +++ b/src/compas_viewer/ui/sidebar.py @@ -87,4 +87,3 @@ def update(self): self.widget.update() for widget in self.update_widgets: widget.update() - From bd31b91a45146effe47f338f3ab3363636f74cca Mon Sep 17 00:00:00 2001 From: PingHsunTsai <47770211+PingHsunTsai@users.noreply.github.com> Date: Thu, 5 Sep 2024 17:51:27 +0200 Subject: [PATCH 8/8] tab example --- scripts/tablayout.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 scripts/tablayout.py diff --git a/scripts/tablayout.py b/scripts/tablayout.py new file mode 100644 index 0000000000..f350297fec --- /dev/null +++ b/scripts/tablayout.py @@ -0,0 +1,25 @@ +from compas.colors import Color +from compas.geometry import Box +from compas.geometry import Frame +from compas_viewer.viewer import Viewer +from compas_viewer.config import Config + +config = Config() +for item in config.ui.sidebar.items: + if item['type'] == 'Sceneform': + item['area'] = 'tab' +viewer = Viewer(config) + +N = 10 +M = 10 + +for i in range(N): + for j in range(M): + viewer.scene.add( + Box(0.5, 0.5, 0.5, Frame([i, j, 0], [1, 0, 0], [0, 1, 0])), + linecolor=Color.white(), + facecolor=Color(i / N, j / M, 0.0), + name=f"Box_{i}_{j}", + ) + +viewer.show()