diff --git a/bec_widgets/examples/device_manager_view/device_manager_view.py b/bec_widgets/examples/device_manager_view/device_manager_view.py index bf2fbd36..7ff81c0f 100644 --- a/bec_widgets/examples/device_manager_view/device_manager_view.py +++ b/bec_widgets/examples/device_manager_view/device_manager_view.py @@ -152,18 +152,37 @@ class DeviceManagerView(BECWidget, QWidget): # self.set_default_view([2, 8, 2], [2, 2, 4]) # Connect slots - self.device_table_view.selected_devices.connect(self.dm_config_view.on_select_config) - self.device_table_view.selected_devices.connect(self.dm_docs_view.on_select_config) - self.available_devices.selected_devices.connect(self.dm_config_view.on_select_config) - self.available_devices.selected_devices.connect(self.dm_docs_view.on_select_config) - self.ophyd_test_view.device_validated.connect( - self.device_table_view.update_device_validation - ) - for slot in [ - self.ophyd_test_view.change_device_configs, - self.available_devices.mark_devices_used, + for signal, slots in [ + ( + self.device_table_view.selected_devices, + (self.dm_config_view.on_select_config, self.dm_docs_view.on_select_config), + ), + ( + self.available_devices.selected_devices, + (self.dm_config_view.on_select_config, self.dm_docs_view.on_select_config), + ), + ( + self.ophyd_test_view.device_validated, + (self.device_table_view.update_device_validation,), + ), + ( + self.device_table_view.device_configs_changed, + ( + self.ophyd_test_view.change_device_configs, + self.available_devices.mark_devices_used, + ), + ), + ( + self.available_devices.add_selected_devices, + (self.device_table_view.add_device_configs,), + ), + ( + self.available_devices.del_selected_devices, + (self.device_table_view.remove_device_configs,), + ), ]: - self.device_table_view.device_configs_changed.connect(slot) + for slot in slots: + signal.connect(slot) self._add_toolbar() diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py index c45f1131..f4bbf784 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_group_ui.py @@ -1,8 +1,5 @@ -from functools import partial - -from bec_qthemes import material_icon from qtpy.QtCore import QMetaObject, Qt -from qtpy.QtWidgets import QLabel, QListWidget, QToolButton, QVBoxLayout +from qtpy.QtWidgets import QLabel, QListWidget, QVBoxLayout from bec_widgets.widgets.control.device_manager.components._util import mimedata_from_configs from bec_widgets.widgets.control.device_manager.components.constants import ( @@ -41,26 +38,6 @@ class Ui_AvailableDeviceGroup(object): self.n_included.setObjectName("n_included") title_layout.addWidget(self.n_included) - self.delete_tag_button = QToolButton(AvailableDeviceGroup) - self.delete_tag_button.setObjectName("delete_tag_button") - title_layout.addWidget(self.delete_tag_button) - - self.remove_from_composition_button = QToolButton(AvailableDeviceGroup) - self.remove_from_composition_button.setObjectName("remove_from_composition_button") - title_layout.addWidget(self.remove_from_composition_button) - - self.add_to_composition_button = QToolButton(AvailableDeviceGroup) - self.add_to_composition_button.setObjectName("add_to_composition_button") - title_layout.addWidget(self.add_to_composition_button) - - self.remove_all_button = QToolButton(AvailableDeviceGroup) - self.remove_all_button.setObjectName("remove_all_from_composition_button") - title_layout.addWidget(self.remove_all_button) - - self.add_all_button = QToolButton(AvailableDeviceGroup) - self.add_all_button.setObjectName("add_all_to_composition_button") - title_layout.addWidget(self.add_all_button) - self.device_list = _DeviceListWiget(AvailableDeviceGroup) self.device_list.setSelectionMode(QListWidget.SelectionMode.ExtendedSelection) self.device_list.setObjectName("device_list") @@ -70,19 +47,4 @@ class Ui_AvailableDeviceGroup(object): self.device_list.setDefaultDropAction(Qt.DropAction.CopyAction) self.verticalLayout.addWidget(self.device_list) - self.set_icons() - QMetaObject.connectSlotsByName(AvailableDeviceGroup) - - def set_icons(self): - icon = partial(material_icon, size=(15, 15), convert_to_pixmap=False) - self.delete_tag_button.setIcon(icon("delete")) - self.delete_tag_button.setToolTip("Delete tag group") - self.remove_from_composition_button.setIcon(icon("remove")) - self.remove_from_composition_button.setToolTip("Remove selected from composition") - self.add_to_composition_button.setIcon(icon("add")) - self.add_to_composition_button.setToolTip("Add selected to composition") - self.remove_all_button.setIcon(icon("chips")) - self.remove_all_button.setToolTip("Remove all with this tag from composition") - self.add_all_button.setIcon(icon("add_box")) - self.add_all_button.setToolTip("Add all with this tag to composition") diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py index f6bf6616..93e81015 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources.py @@ -2,7 +2,7 @@ from random import randint from typing import Any, Iterable from uuid import uuid4 -from qtpy.QtCore import QItemSelection, Signal +from qtpy.QtCore import QItemSelection, Signal # type: ignore from qtpy.QtWidgets import QWidget from bec_widgets.utils.bec_widget import BECWidget @@ -24,6 +24,8 @@ from bec_widgets.widgets.control.device_manager.components.constants import CONF class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources): selected_devices = Signal(list) # list[dict[str,Any]] of device configs currently selected + add_selected_devices = Signal(list) + del_selected_devices = Signal(list) def __init__(self, parent=None, shared_selection_signal=SharedSelectionSignal(), **kwargs): super().__init__(parent=parent, **kwargs) @@ -41,6 +43,9 @@ class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources): self.grouping_selector.currentTextChanged.connect(self._grouping_selection_changed) self.search_box.textChanged.connect(self.device_groups_list.update_filter) + self.tb_add_selected.action.triggered.connect(self._add_selected_action) + self.tb_del_selected.action.triggered.connect(self._del_selected_action) + def refresh_full_list(self, device_groups: dict[str, set[HashableDevice]]): self.device_groups_list.clear() for device_group, devices in device_groups.items(): @@ -67,9 +72,17 @@ class AvailableDeviceResources(BECWidget, QWidget, Ui_availableDeviceResources): for list_item, device_group_widget in self.device_groups_list.item_widget_pairs(): list_item.setSizeHint(device_group_widget.sizeHint()) + @SafeSlot() + def _add_selected_action(self): + self.add_selected_devices.emit(self.device_groups_list.any_selected_devices()) + + @SafeSlot() + def _del_selected_action(self): + self.del_selected_devices.emit(self.device_groups_list.any_selected_devices()) + @SafeSlot(QItemSelection, QItemSelection) def _on_selection_changed(self, selected: QItemSelection, deselected: QItemSelection) -> None: - self.selected_devices.emit(self.device_groups_list.selected_devices()) + self.selected_devices.emit(self.device_groups_list.selected_devices_from_groups()) self._shared_selection_signal.proc.emit(self._shared_selection_uuid) @SafeSlot(str) diff --git a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py index 3b9ebb22..4cba0bf5 100644 --- a/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py +++ b/bec_widgets/widgets/control/device_manager/components/available_device_resources/available_device_resources_ui.py @@ -1,8 +1,11 @@ from __future__ import annotations import itertools +from functools import partial from typing import Generator +from bec_qthemes import material_icon +from PySide6.QtWidgets import QListWidgetItem, QWidget from qtpy.QtCore import QMetaObject, Qt from qtpy.QtWidgets import ( QAbstractItemView, @@ -16,6 +19,9 @@ from qtpy.QtWidgets import ( ) from bec_widgets.utils.list_of_expandable_frames import ListOfExpandableFrames +from bec_widgets.utils.toolbars.actions import MaterialIconAction +from bec_widgets.utils.toolbars.bundles import ToolbarBundle +from bec_widgets.utils.toolbars.toolbar import ModularToolBar from bec_widgets.widgets.control.device_manager.components._util import mimedata_from_configs from bec_widgets.widgets.control.device_manager.components.available_device_resources.available_device_group import ( AvailableDeviceGroup, @@ -28,11 +34,21 @@ from bec_widgets.widgets.control.device_manager.components.constants import ( class _ListOfDeviceGroups(ListOfExpandableFrames[AvailableDeviceGroup]): - def selected_devices(self): + def itemWidget(self, item: QListWidgetItem) -> AvailableDeviceGroup: + return super().itemWidget(item) # type: ignore + + def any_selected_devices(self): + return self.selected_individual_devices() or self.selected_devices_from_groups() + + def selected_individual_devices(self): + for widget in (self.itemWidget(self.item(i)) for i in range(self.count())): + if (selected := widget.get_selection()) != set(): + return [dev.as_normal_device().model_dump() for dev in selected] + return [] + + def selected_devices_from_groups(self): selected_items = (self.item(r.row()) for r in self.selectionModel().selectedRows()) - widgets: Generator[AvailableDeviceGroup, None, None] = ( - self.itemWidget(item) for item in selected_items # type: ignore - ) + widgets = (self.itemWidget(item) for item in selected_items) return list(itertools.chain.from_iterable(w.device_list.all_configs() for w in widgets)) def mimeTypes(self): @@ -51,6 +67,8 @@ class Ui_availableDeviceResources(object): self.verticalLayout = QVBoxLayout(availableDeviceResources) self.verticalLayout.setObjectName("verticalLayout") + self._add_toolbar() + self.search_layout = QHBoxLayout() self.verticalLayout.addLayout(self.search_layout) self.search_layout.addWidget(QLabel("Filter groups: ")) @@ -82,3 +100,23 @@ class Ui_availableDeviceResources(object): self.verticalLayout.addWidget(self.device_groups_list) QMetaObject.connectSlotsByName(availableDeviceResources) + + def _add_toolbar(self): + self.toolbar = ModularToolBar(self) + io_bundle = ToolbarBundle("IO", self.toolbar.components) + self.toolbar.add_bundle(io_bundle) + + self.tb_add_selected = MaterialIconAction( + icon_name="add_box", parent=self, tooltip="Add selected devices to composition" + ) + self.toolbar.components.add_safe("add_selected", self.tb_add_selected) + io_bundle.add_action("add_selected") + + self.tb_del_selected = MaterialIconAction( + icon_name="chips", parent=self, tooltip="Remove selected devices from composition" + ) + self.toolbar.components.add_safe("del_selected", self.tb_del_selected) + io_bundle.add_action("del_selected") + + self.verticalLayout.addWidget(self.toolbar) + self.toolbar.show_bundles(["IO"])