1
0
mirror of https://github.com/bec-project/bec_widgets.git synced 2026-05-04 22:04:21 +02:00

Compare commits

...

3 Commits

Author SHA1 Message Date
perl_d c170cc7bd3 feat: add device browser to menu 2025-10-17 14:03:55 +02:00
perl_d 3b850fa730 fix: safely access device config 2025-10-17 14:03:55 +02:00
perl_d 2c6db345d3 feat(devicebrowser): show enabled and readonly status 2025-10-17 14:03:55 +02:00
4 changed files with 43 additions and 8 deletions
+2 -1
View File
@@ -1,5 +1,6 @@
import time
from types import SimpleNamespace
from typing import Literal
from bec_qthemes import material_icon
from qtpy.QtCore import Property, Qt, Signal
@@ -39,7 +40,7 @@ class LedLabel(QLabel):
self.setState("default")
self.setFixedSize(20, 20)
def setState(self, state: str):
def setState(self, state: Literal["success", "default", "warning", "emergency"]):
match state:
case "success":
r, g, b, a = self.palette.success.getRgb()
@@ -37,6 +37,7 @@ from bec_widgets.widgets.plots.waveform.waveform import Waveform
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar
from bec_widgets.widgets.services.bec_queue.bec_queue import BECQueue
from bec_widgets.widgets.services.bec_status_box.bec_status_box import BECStatusBox
from bec_widgets.widgets.services.device_browser.device_browser import DeviceBrowser
from bec_widgets.widgets.utility.logpanel.logpanel import LogPanel
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
@@ -185,6 +186,12 @@ class BECDockArea(BECWidget, QWidget):
filled=True,
parent=self,
),
"device_browser": MaterialIconAction(
icon_name=DeviceBrowser.ICON_NAME,
tooltip="Add Device Browser",
filled=True,
parent=self,
),
},
),
)
@@ -312,6 +319,9 @@ class BECDockArea(BECWidget, QWidget):
menu_devices.actions["positioner_box"].action.triggered.connect(
lambda: self._create_widget_from_toolbar(widget_name="PositionerBox")
)
menu_devices.actions["device_browser"].action.triggered.connect(
lambda: self._create_widget_from_toolbar(widget_name="DeviceBrowser")
)
# Menu Utils
menu_utils.actions["queue"].action.triggered.connect(
@@ -125,10 +125,8 @@ class DeviceBrowser(BECWidget, QWidget):
action (str): The action that triggered the event.
content (dict): The content of the config update.
"""
if action in ["add", "remove", "reload"]:
self.devices_changed.emit()
if action in ["update", "reload"]:
self.device_update.emit(action, content)
self.devices_changed.emit()
self.device_update.emit(action, content)
def init_device_list(self):
self.dev_list.clear()
@@ -10,8 +10,17 @@ from bec_lib.messages import ConfigAction
from bec_qthemes import material_icon
from qtpy.QtCore import QMimeData, QSize, Qt, QThreadPool, Signal
from qtpy.QtGui import QDrag
from qtpy.QtWidgets import QApplication, QHBoxLayout, QTabWidget, QToolButton, QVBoxLayout, QWidget
from qtpy.QtWidgets import (
QApplication,
QHBoxLayout,
QLabel,
QTabWidget,
QToolButton,
QVBoxLayout,
QWidget,
)
from bec_widgets.utils.compact_popup import LedLabel
from bec_widgets.utils.error_popups import SafeSlot
from bec_widgets.utils.expandable_frame import ExpandableGroupFrame
from bec_widgets.widgets.services.device_browser.device_item.config_communicator import (
@@ -56,6 +65,10 @@ class DeviceItem(ExpandableGroupFrame):
self._expanded_first_time = False
self._data = None
self.device = device
self._deleting = False
self._ro_pixmap = material_icon(icon_name="keyboard_off", size=(15, 15))
self._we_pixmap = material_icon(icon_name="keyboard", size=(15, 15))
self._layout = QHBoxLayout()
self._layout.setContentsMargins(0, 0, 0, 0)
@@ -78,6 +91,7 @@ class DeviceItem(ExpandableGroupFrame):
self.set_layout(self._layout)
self.adjustSize()
self._reload_config()
def _create_title_layout(self, title: str, icon: str):
super()._create_title_layout(title, icon)
@@ -92,6 +106,11 @@ class DeviceItem(ExpandableGroupFrame):
self._title_layout.insertWidget(self._title_layout.count() - 1, self.delete_button)
self.delete_button.clicked.connect(self._delete_device)
self.enabled_led = LedLabel()
self._title_layout.insertWidget(1, self.enabled_led)
self.readonly_label = QLabel()
self._title_layout.insertWidget(2, self.readonly_label)
@SafeSlot()
def _create_edit_dialog(self):
dialog = DeviceConfigDialog(
@@ -106,6 +125,7 @@ class DeviceItem(ExpandableGroupFrame):
@SafeSlot()
def _delete_device(self):
self._deleting = True
self.expanded = False
deleter = CommunicateConfigAction(self._config_helper, self.device, None, "remove")
deleter.signals.error.connect(self._deletion_error)
@@ -147,17 +167,23 @@ class DeviceItem(ExpandableGroupFrame):
@SafeSlot(str, dict)
def config_update(self, action: ConfigAction, content: dict) -> None:
if self.device in content:
if (self.device in content or action == "reload") and not self._deleting:
self._reload_config()
@SafeSlot(popup_error=True)
def _reload_config(self, *_):
self.set_display_config(self.dev[self.device]._config)
# Guard in case we attempt to reload config while a device is being removed/readded
if (dev := self.dev.get(self.device)) is not None:
self.set_display_config(dev._config)
def set_display_config(self, config_dict: dict):
"""Set the displayed information from a device config dict, which must conform to the
bec_lib.atlas_models.Device config model."""
self._data = DeviceConfigModel.model_validate(config_dict)
self.enabled_led.setState("success" if self._data.enabled else "emergency")
self.enabled_led.setToolTip("enabled" if self._data.enabled else "disabled")
self.readonly_label.setPixmap(self._ro_pixmap if self._data.readOnly else self._we_pixmap)
self.readonly_label.setToolTip("read only" if self._data.readOnly else "writing enabled")
if self._expanded_first_time:
self.form.set_data(self._data)