From 9ce31c9833ae38721b2246cdcac50f1154fba99d Mon Sep 17 00:00:00 2001 From: David Perl Date: Thu, 22 May 2025 09:34:42 +0200 Subject: [PATCH] refactor: move device config form to module --- bec_widgets/utils/forms_from_types/forms.py | 15 +++++++- .../device_item/device_config_form.py | 35 ++++++++++++++++++ .../device_browser/device_item/device_item.py | 37 +++---------------- tests/unit_tests/test_device_browser.py | 6 ++- 4 files changed, 58 insertions(+), 35 deletions(-) create mode 100644 bec_widgets/widgets/services/device_browser/device_item/device_config_form.py diff --git a/bec_widgets/utils/forms_from_types/forms.py b/bec_widgets/utils/forms_from_types/forms.py index 1fda8f57..9d8abf12 100644 --- a/bec_widgets/utils/forms_from_types/forms.py +++ b/bec_widgets/utils/forms_from_types/forms.py @@ -8,11 +8,12 @@ from bec_lib.logger import bec_logger from bec_qthemes import material_icon from pydantic import BaseModel, ValidationError from qtpy.QtCore import Signal # type: ignore -from qtpy.QtWidgets import QGridLayout, QLabel, QLayout, QSizePolicy, QVBoxLayout, QWidget +from qtpy.QtWidgets import QApplication, QGridLayout, QLabel, QVBoxLayout, QWidget from bec_widgets.utils.bec_widget import BECWidget from bec_widgets.utils.compact_popup import CompactPopupWidget from bec_widgets.utils.error_popups import SafeProperty +from bec_widgets.utils.forms_from_types import styles from bec_widgets.utils.forms_from_types.items import ( DynamicFormItem, DynamicFormItemType, @@ -207,6 +208,18 @@ class PydanticModelForm(TypedForm): self._layout.addWidget(self._validity) self.value_changed.connect(self.validate_form) + self._connect_to_theme_change() + + def set_pretty_display_theme(self, theme: str = "dark"): + if self._pretty_display: + self.setStyleSheet(styles.pretty_display_theme(theme)) + + def _connect_to_theme_change(self): + """Connect to the theme change signal.""" + qapp = QApplication.instance() + if hasattr(qapp, "theme_signal"): + qapp.theme_signal.theme_updated.connect(self.set_pretty_display_theme) # type: ignore + def set_schema(self, schema: type[BaseModel]): self._md_schema = schema self.populate() diff --git a/bec_widgets/widgets/services/device_browser/device_item/device_config_form.py b/bec_widgets/widgets/services/device_browser/device_item/device_config_form.py new file mode 100644 index 00000000..6c222533 --- /dev/null +++ b/bec_widgets/widgets/services/device_browser/device_item/device_config_form.py @@ -0,0 +1,35 @@ +from __future__ import annotations + +from bec_lib.atlas_models import Device as DeviceConfigModel +from qtpy.QtWidgets import QApplication + +from bec_widgets.utils.colors import get_theme_name +from bec_widgets.utils.forms_from_types import styles +from bec_widgets.utils.forms_from_types.forms import PydanticModelForm + + +class DeviceConfigForm(PydanticModelForm): + RPC = False + PLUGIN = False + + def __init__(self, parent=None, client=None, pretty_display=False, **kwargs): + super().__init__( + parent=parent, + data_model=DeviceConfigModel, + pretty_display=pretty_display, + client=client, + **kwargs, + ) + self._validity.setVisible(False) + self._connect_to_theme_change() + + def set_pretty_display_theme(self, theme: str | None = None): + if theme is None: + theme = get_theme_name() + self.setStyleSheet(styles.pretty_display_theme(theme)) + + def _connect_to_theme_change(self): + """Connect to the theme change signal.""" + qapp = QApplication.instance() + if hasattr(qapp, "theme_signal"): + qapp.theme_signal.theme_updated.connect(self.set_pretty_display_theme) # type: ignore diff --git a/bec_widgets/widgets/services/device_browser/device_item/device_item.py b/bec_widgets/widgets/services/device_browser/device_item/device_item.py index 3631ae50..8347b88e 100644 --- a/bec_widgets/widgets/services/device_browser/device_item/device_item.py +++ b/bec_widgets/widgets/services/device_browser/device_item/device_item.py @@ -8,11 +8,11 @@ from qtpy.QtCore import QMimeData, QSize, Qt, Signal from qtpy.QtGui import QDrag from qtpy.QtWidgets import QApplication, QHBoxLayout, QWidget -from bec_widgets.utils.colors import get_theme_name from bec_widgets.utils.error_popups import SafeSlot from bec_widgets.utils.expandable_frame import ExpandableGroupFrame -from bec_widgets.utils.forms_from_types import styles -from bec_widgets.utils.forms_from_types.forms import PydanticModelForm +from bec_widgets.widgets.services.device_browser.device_item.device_config_form import ( + DeviceConfigForm, +) from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton if TYPE_CHECKING: # pragma: no cover @@ -21,33 +21,6 @@ if TYPE_CHECKING: # pragma: no cover logger = bec_logger.logger -class DeviceItemForm(PydanticModelForm): - RPC = False - PLUGIN = False - - def __init__(self, parent=None, client=None, pretty_display=False, **kwargs): - super().__init__( - parent=parent, - data_model=DeviceConfigModel, - pretty_display=pretty_display, - client=client, - **kwargs, - ) - self._validity.setVisible(False) - self._connect_to_theme_change() - - def set_pretty_display_theme(self, theme: str | None = None): - if theme is None: - theme = get_theme_name() - self.setStyleSheet(styles.pretty_display_theme(theme)) - - def _connect_to_theme_change(self): - """Connect to the theme change signal.""" - qapp = QApplication.instance() - if hasattr(qapp, "theme_signal"): - qapp.theme_signal.theme_updated.connect(self.set_pretty_display_theme) # type: ignore - - class DeviceItem(ExpandableGroupFrame): broadcast_size_hint = Signal(QSize) @@ -72,7 +45,7 @@ class DeviceItem(ExpandableGroupFrame): def switch_expanded_state(self): if not self.expanded and not self._expanded_first_time: self._expanded_first_time = True - self.form = DeviceItemForm(parent=self, pretty_display=True) + self.form = DeviceConfigForm(parent=self, pretty_display=True) self._contents.layout().addWidget(self.form) if self._data: self.form.set_data(self._data) @@ -125,7 +98,7 @@ if __name__ == "__main__": # pragma: no cover widget = QWidget() layout = QHBoxLayout() widget.setLayout(layout) - item = DeviceItem("Device") + item = DeviceItem(widget, "Device") layout.addWidget(DarkModeButton()) layout.addWidget(item) item.set_display_config( diff --git a/tests/unit_tests/test_device_browser.py b/tests/unit_tests/test_device_browser.py index 18f11777..eba48e60 100644 --- a/tests/unit_tests/test_device_browser.py +++ b/tests/unit_tests/test_device_browser.py @@ -5,7 +5,9 @@ import pytest from qtpy.QtCore import QPoint, Qt from bec_widgets.widgets.services.device_browser.device_browser import DeviceBrowser -from bec_widgets.widgets.services.device_browser.device_item.device_item import DeviceItemForm +from bec_widgets.widgets.services.device_browser.device_item.device_config_form import ( + DeviceConfigForm, +) from .client_mocks import mocked_client @@ -84,7 +86,7 @@ def test_device_item_expansion(device_browser, qtbot): widget: DeviceItem = device_browser.ui.device_list.itemWidget(device_item) qtbot.mouseClick(widget._expansion_button, Qt.MouseButton.LeftButton) form = widget._contents.layout().itemAt(0).widget() - qtbot.waitUntil(lambda: isinstance(form, DeviceItemForm), timeout=500) + qtbot.waitUntil(lambda: isinstance(form, DeviceConfigForm), timeout=500) assert widget.expanded assert (name_field := form.widget_dict.get("name")) is not None assert name_field.getValue() == "samx"