bec-widgets 1.25.1__py3-none-any.whl → 2.0.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- .gitlab-ci.yml +3 -5
- CHANGELOG.md +639 -0
- PKG-INFO +3 -3
- bec_widgets/__init__.py +4 -0
- bec_widgets/applications/bw_launch.py +23 -0
- bec_widgets/applications/launch_window.py +430 -0
- bec_widgets/assets/app_icons/auto_update.png +0 -0
- bec_widgets/assets/app_icons/ui_loader_tile.png +0 -0
- bec_widgets/cli/__init__.py +0 -1
- bec_widgets/cli/client.py +1779 -2064
- bec_widgets/cli/client_utils.py +346 -174
- bec_widgets/cli/generate_cli.py +143 -37
- bec_widgets/cli/rpc/rpc_base.py +152 -21
- bec_widgets/cli/rpc/rpc_register.py +113 -6
- bec_widgets/cli/rpc/rpc_widget_handler.py +13 -11
- bec_widgets/cli/server.py +125 -239
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +97 -145
- bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py +1 -1
- bec_widgets/utils/bec_connector.py +190 -21
- bec_widgets/utils/bec_designer.py +7 -0
- bec_widgets/utils/bec_dispatcher.py +71 -4
- bec_widgets/utils/bec_plugin_helper.py +89 -0
- bec_widgets/utils/bec_signal_proxy.py +1 -1
- bec_widgets/utils/bec_widget.py +26 -10
- bec_widgets/utils/colors.py +1 -1
- bec_widgets/{qt_utils → utils}/compact_popup.py +2 -0
- bec_widgets/utils/container_utils.py +37 -12
- bec_widgets/utils/crosshair.py +25 -8
- bec_widgets/utils/entry_validator.py +3 -1
- bec_widgets/{qt_utils → utils}/error_popups.py +18 -0
- bec_widgets/{qt_utils → utils}/expandable_frame.py +2 -2
- bec_widgets/utils/forms_from_types/forms.py +182 -0
- bec_widgets/{widgets/editors/scan_metadata/_metadata_widgets.py → utils/forms_from_types/items.py} +41 -30
- bec_widgets/utils/generate_designer_plugin.py +40 -36
- bec_widgets/utils/linear_region_selector.py +2 -0
- bec_widgets/utils/name_utils.py +16 -0
- bec_widgets/{qt_utils → utils}/palette_viewer.py +2 -2
- bec_widgets/utils/plot_indicator_items.py +2 -5
- bec_widgets/utils/plugin_utils.py +47 -1
- bec_widgets/{qt_utils → utils}/round_frame.py +14 -14
- bec_widgets/utils/rpc_server.py +277 -0
- bec_widgets/utils/serialization.py +44 -0
- bec_widgets/{qt_utils → utils}/settings_dialog.py +26 -1
- bec_widgets/{qt_utils → utils}/side_panel.py +17 -10
- bec_widgets/{qt_utils → utils}/toolbar.py +69 -25
- bec_widgets/utils/ui_loader.py +8 -8
- bec_widgets/utils/widget_io.py +166 -25
- bec_widgets/widgets/containers/auto_update/auto_updates.py +364 -0
- bec_widgets/widgets/containers/dock/dock.py +157 -49
- bec_widgets/widgets/containers/dock/dock_area.py +188 -138
- bec_widgets/widgets/containers/layout_manager/layout_manager.py +2 -1
- bec_widgets/widgets/containers/main_window/addons/web_links.py +15 -0
- bec_widgets/widgets/containers/main_window/main_window.py +189 -41
- bec_widgets/widgets/control/buttons/button_abort/button_abort.py +3 -4
- bec_widgets/widgets/control/buttons/button_reset/button_reset.py +3 -4
- bec_widgets/widgets/control/buttons/button_resume/button_resume.py +3 -3
- bec_widgets/widgets/control/buttons/stop_button/stop_button.py +18 -7
- bec_widgets/widgets/control/device_control/position_indicator/position_indicator.py +22 -3
- bec_widgets/widgets/control/device_control/positioner_box/_base/positioner_box_base.py +31 -13
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +3 -1
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.ui +27 -4
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.py +5 -2
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box_2d/positioner_box_2d.ui +97 -31
- bec_widgets/widgets/control/device_control/positioner_box/positioner_control_line/positioner_control_line.ui +11 -4
- bec_widgets/widgets/control/device_control/positioner_group/positioner_group.py +2 -3
- bec_widgets/widgets/control/device_input/base_classes/device_input_base.py +29 -4
- bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +1 -0
- bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py +2 -2
- bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py +2 -2
- bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py +1 -2
- bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py +1 -2
- bec_widgets/widgets/control/scan_control/scan_control.py +7 -5
- bec_widgets/widgets/control/scan_control/scan_group_box.py +28 -5
- bec_widgets/widgets/dap/dap_combo_box/dap_combo_box.py +1 -2
- bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog.py +3 -4
- bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog_vertical.ui +14 -8
- bec_widgets/widgets/editors/console/console.py +1 -1
- bec_widgets/widgets/editors/{scan_metadata/additional_metadata_table.py → dict_backed_table.py} +29 -6
- bec_widgets/widgets/editors/scan_metadata/__init__.py +0 -7
- bec_widgets/widgets/editors/scan_metadata/_util.py +1 -1
- bec_widgets/widgets/{plots/motor_map/register_bec_motor_map_widget.py → editors/scan_metadata/register_scan_metadata.py} +2 -4
- bec_widgets/widgets/editors/scan_metadata/scan_metadata.py +42 -136
- bec_widgets/widgets/editors/scan_metadata/scan_metadata.pyproject +1 -0
- bec_widgets/widgets/{plots/multi_waveform/bec_multi_waveform_widget_plugin.py → editors/scan_metadata/scan_metadata_plugin.py} +9 -9
- bec_widgets/widgets/editors/text_box/text_box.py +2 -3
- bec_widgets/widgets/editors/website/website.py +2 -2
- bec_widgets/widgets/games/minesweeper.py +3 -2
- bec_widgets/widgets/plots/image/image.py +960 -0
- bec_widgets/widgets/plots/image/image.pyproject +1 -0
- bec_widgets/widgets/plots/image/image_item.py +279 -0
- bec_widgets/widgets/plots/{motor_map/bec_motor_map_widget_plugin.py → image/image_plugin.py} +11 -13
- bec_widgets/widgets/{containers/figure/plots → plots}/image/image_processor.py +31 -64
- bec_widgets/widgets/plots/image/{register_bec_image_widget.py → register_image.py} +2 -2
- bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py +59 -0
- bec_widgets/widgets/plots/image/toolbar_bundles/processing.py +79 -0
- bec_widgets/widgets/plots/motor_map/motor_map.py +832 -0
- bec_widgets/widgets/plots/motor_map/motor_map.pyproject +1 -0
- bec_widgets/widgets/plots/motor_map/motor_map_plugin.py +54 -0
- bec_widgets/widgets/plots/{multi_waveform/register_bec_multi_waveform_widget.py → motor_map/register_motor_map.py} +2 -4
- bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.py +129 -0
- bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.ui +120 -0
- bec_widgets/widgets/plots/motor_map/toolbar_bundles/motor_selection.py +70 -0
- bec_widgets/widgets/plots/multi_waveform/multi_waveform.py +508 -0
- bec_widgets/widgets/plots/multi_waveform/multi_waveform.pyproject +1 -0
- bec_widgets/widgets/plots/multi_waveform/multi_waveform_plugin.py +54 -0
- bec_widgets/widgets/plots/multi_waveform/register_multi_waveform.py +15 -0
- bec_widgets/widgets/plots/multi_waveform/settings/control_panel.py +144 -0
- bec_widgets/widgets/plots/multi_waveform/settings/multi_waveform_controls.ui +164 -0
- bec_widgets/widgets/plots/multi_waveform/toolbar_bundles/monitor_selection.py +65 -0
- bec_widgets/widgets/{plots_next_gen → plots}/plot_base.py +321 -40
- bec_widgets/widgets/plots/{waveform/register_bec_waveform_widget.py → scatter_waveform/register_scatter_waveform.py} +3 -3
- bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py +197 -0
- bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py +553 -0
- bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.pyproject +1 -0
- bec_widgets/widgets/plots/{image/bec_image_widget_plugin.py → scatter_waveform/scatter_waveform_plugin.py} +9 -13
- bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py +138 -0
- bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui +195 -0
- bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui +204 -0
- bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings.py +8 -8
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/mouse_interactions.py +4 -18
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/plot_export.py +14 -3
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/roi_bundle.py +6 -1
- bec_widgets/widgets/{plots_next_gen → plots}/toolbar_bundles/save_state.py +2 -2
- bec_widgets/widgets/{containers/figure/plots/waveform/waveform_curve.py → plots/waveform/curve.py} +119 -49
- bec_widgets/widgets/plots/waveform/register_waveform.py +15 -0
- bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_setting.py +125 -0
- bec_widgets/widgets/plots/waveform/settings/curve_settings/curve_tree.py +576 -0
- bec_widgets/widgets/plots/waveform/utils/__init__.py +0 -0
- bec_widgets/widgets/plots/waveform/utils/roi_manager.py +84 -0
- bec_widgets/widgets/plots/waveform/waveform.py +1794 -0
- bec_widgets/widgets/plots/waveform/waveform.pyproject +1 -0
- bec_widgets/widgets/plots/waveform/{bec_waveform_widget_plugin.py → waveform_plugin.py} +9 -13
- bec_widgets/widgets/progress/bec_progressbar/bec_progressbar.py +1 -2
- bec_widgets/widgets/progress/ring_progress_bar/ring.py +11 -10
- bec_widgets/widgets/progress/ring_progress_bar/ring_progress_bar.py +24 -14
- bec_widgets/widgets/services/bec_queue/bec_queue.py +13 -11
- bec_widgets/widgets/services/bec_status_box/bec_status_box.py +3 -4
- bec_widgets/widgets/services/device_browser/device_browser.py +5 -2
- bec_widgets/widgets/services/device_browser/device_item/device_item.py +1 -1
- bec_widgets/widgets/utility/logpanel/logpanel.py +36 -17
- bec_widgets/widgets/utility/spinbox/decimal_spinbox.py +3 -3
- bec_widgets/widgets/utility/visual/color_button/color_button.py +1 -1
- bec_widgets/widgets/utility/visual/colormap_widget/colormap_widget.py +4 -6
- bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py +4 -8
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/METADATA +3 -3
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/RECORD +168 -153
- pyproject.toml +3 -3
- bec_widgets/applications/alignment/alignment_1d/alignment_1d.py +0 -198
- bec_widgets/applications/alignment/alignment_1d/alignment_1d.ui +0 -615
- bec_widgets/applications/bec_app.py +0 -84
- bec_widgets/cli/auto_updates.py +0 -168
- bec_widgets/widgets/containers/figure/__init__.py +0 -1
- bec_widgets/widgets/containers/figure/figure.py +0 -796
- bec_widgets/widgets/containers/figure/plots/axis_settings.py +0 -91
- bec_widgets/widgets/containers/figure/plots/axis_settings.ui +0 -256
- bec_widgets/widgets/containers/figure/plots/image/image.py +0 -772
- bec_widgets/widgets/containers/figure/plots/image/image_item.py +0 -337
- bec_widgets/widgets/containers/figure/plots/motor_map/motor_map.py +0 -525
- bec_widgets/widgets/containers/figure/plots/multi_waveform/multi_waveform.py +0 -340
- bec_widgets/widgets/containers/figure/plots/plot_base.py +0 -505
- bec_widgets/widgets/containers/figure/plots/waveform/waveform.py +0 -1563
- bec_widgets/widgets/plots/image/bec_image_widget.pyproject +0 -1
- bec_widgets/widgets/plots/image/image_widget.py +0 -515
- bec_widgets/widgets/plots/motor_map/bec_motor_map_widget.pyproject +0 -1
- bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.py +0 -56
- bec_widgets/widgets/plots/motor_map/motor_map_dialog/motor_map_settings.ui +0 -108
- bec_widgets/widgets/plots/motor_map/motor_map_widget.py +0 -234
- bec_widgets/widgets/plots/multi_waveform/bec_multi_waveform_widget.pyproject +0 -1
- bec_widgets/widgets/plots/multi_waveform/multi_waveform_controls.ui +0 -99
- bec_widgets/widgets/plots/multi_waveform/multi_waveform_widget.py +0 -536
- bec_widgets/widgets/plots/waveform/bec_waveform_widget.pyproject +0 -1
- bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py +0 -336
- bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui +0 -372
- bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py +0 -25
- bec_widgets/widgets/plots/waveform/waveform_widget.py +0 -751
- /bec_widgets/{qt_utils → utils}/collapsible_panel_manager.py +0 -0
- /bec_widgets/{applications/alignment → utils/forms_from_types}/__init__.py +0 -0
- /bec_widgets/{qt_utils → utils}/redis_message_waiter.py +0 -0
- /bec_widgets/{applications/alignment/alignment_1d → widgets/containers/auto_update}/__init__.py +0 -0
- /bec_widgets/{qt_utils → widgets/containers/main_window/addons}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots → plots/image/toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/image → plots/motor_map/settings}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/motor_map → plots/motor_map/toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/multi_waveform → plots/multi_waveform/settings}/__init__.py +0 -0
- /bec_widgets/widgets/{containers/figure/plots/waveform → plots/multi_waveform/toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/plots/{motor_map/motor_map_dialog → scatter_waveform}/__init__.py +0 -0
- /bec_widgets/widgets/plots/{waveform/waveform_popups → scatter_waveform/settings}/__init__.py +0 -0
- /bec_widgets/widgets/plots/{waveform/waveform_popups/curve_dialog → setting_menus}/__init__.py +0 -0
- /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_horizontal.ui +0 -0
- /bec_widgets/widgets/{plots_next_gen → plots}/setting_menus/axis_settings_vertical.ui +0 -0
- /bec_widgets/widgets/plots/{waveform/waveform_popups/dap_summary_dialog → toolbar_bundles}/__init__.py +0 -0
- /bec_widgets/widgets/{plots_next_gen/setting_menus → plots/waveform/settings}/__init__.py +0 -0
- /bec_widgets/widgets/{plots_next_gen/toolbar_bundles → plots/waveform/settings/curve_settings}/__init__.py +0 -0
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/WHEEL +0 -0
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/entry_points.txt +0 -0
- {bec_widgets-1.25.1.dist-info → bec_widgets-2.0.1.dist-info}/licenses/LICENSE +0 -0
@@ -3,36 +3,43 @@ from __future__ import annotations
|
|
3
3
|
from typing import Literal, Optional
|
4
4
|
from weakref import WeakValueDictionary
|
5
5
|
|
6
|
-
from bec_lib.
|
6
|
+
from bec_lib.logger import bec_logger
|
7
7
|
from pydantic import Field
|
8
8
|
from pyqtgraph.dockarea.DockArea import DockArea
|
9
9
|
from qtpy.QtCore import QSize, Qt
|
10
10
|
from qtpy.QtGui import QPainter, QPaintEvent
|
11
11
|
from qtpy.QtWidgets import QApplication, QSizePolicy, QVBoxLayout, QWidget
|
12
12
|
|
13
|
-
from bec_widgets.
|
14
|
-
from bec_widgets.
|
13
|
+
from bec_widgets.cli.rpc.rpc_register import RPCRegister
|
14
|
+
from bec_widgets.utils import ConnectionConfig, WidgetContainerUtils
|
15
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
16
|
+
from bec_widgets.utils.error_popups import SafeSlot
|
17
|
+
from bec_widgets.utils.name_utils import pascal_to_snake
|
18
|
+
from bec_widgets.utils.toolbar import (
|
15
19
|
ExpandableMenuAction,
|
16
20
|
MaterialIconAction,
|
17
21
|
ModularToolBar,
|
18
22
|
SeparatorAction,
|
19
23
|
)
|
20
|
-
from bec_widgets.utils import
|
21
|
-
from bec_widgets.utils.bec_widget import BECWidget
|
24
|
+
from bec_widgets.utils.widget_io import WidgetHierarchy
|
22
25
|
from bec_widgets.widgets.containers.dock.dock import BECDock, DockConfig
|
26
|
+
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
|
23
27
|
from bec_widgets.widgets.control.device_control.positioner_box import PositionerBox
|
24
28
|
from bec_widgets.widgets.control.scan_control.scan_control import ScanControl
|
25
29
|
from bec_widgets.widgets.editors.vscode.vscode import VSCodeEditor
|
26
|
-
from bec_widgets.widgets.plots.image.
|
27
|
-
from bec_widgets.widgets.plots.motor_map.
|
28
|
-
from bec_widgets.widgets.plots.multi_waveform.
|
29
|
-
from bec_widgets.widgets.plots.
|
30
|
+
from bec_widgets.widgets.plots.image.image import Image
|
31
|
+
from bec_widgets.widgets.plots.motor_map.motor_map import MotorMap
|
32
|
+
from bec_widgets.widgets.plots.multi_waveform.multi_waveform import MultiWaveform
|
33
|
+
from bec_widgets.widgets.plots.scatter_waveform.scatter_waveform import ScatterWaveform
|
34
|
+
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
30
35
|
from bec_widgets.widgets.progress.ring_progress_bar.ring_progress_bar import RingProgressBar
|
31
36
|
from bec_widgets.widgets.services.bec_queue.bec_queue import BECQueue
|
32
37
|
from bec_widgets.widgets.services.bec_status_box.bec_status_box import BECStatusBox
|
33
38
|
from bec_widgets.widgets.utility.logpanel.logpanel import LogPanel
|
34
39
|
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
|
35
40
|
|
41
|
+
logger = bec_logger.logger
|
42
|
+
|
36
43
|
|
37
44
|
class DockAreaConfig(ConnectionConfig):
|
38
45
|
docks: dict[str, DockConfig] = Field({}, description="The docks in the dock area.")
|
@@ -42,23 +49,27 @@ class DockAreaConfig(ConnectionConfig):
|
|
42
49
|
|
43
50
|
|
44
51
|
class BECDockArea(BECWidget, QWidget):
|
52
|
+
"""
|
53
|
+
Container for other widgets. Widgets can be added to the dock area and arranged in a grid layout.
|
54
|
+
"""
|
55
|
+
|
45
56
|
PLUGIN = True
|
46
57
|
USER_ACCESS = [
|
58
|
+
"_rpc_id",
|
47
59
|
"_config_dict",
|
48
|
-
"selected_device",
|
49
|
-
"panels",
|
50
|
-
"save_state",
|
51
|
-
"remove_dock",
|
52
|
-
"restore_state",
|
53
|
-
"add_dock",
|
54
|
-
"clear_all",
|
55
|
-
"detach_dock",
|
56
|
-
"attach_all",
|
57
60
|
"_get_all_rpc",
|
58
|
-
"
|
61
|
+
"new",
|
59
62
|
"show",
|
60
63
|
"hide",
|
64
|
+
"panels",
|
65
|
+
"panel_list",
|
61
66
|
"delete",
|
67
|
+
"delete_all",
|
68
|
+
"remove",
|
69
|
+
"detach_dock",
|
70
|
+
"attach_all",
|
71
|
+
"save_state",
|
72
|
+
"restore_state",
|
62
73
|
]
|
63
74
|
|
64
75
|
def __init__(
|
@@ -67,6 +78,8 @@ class BECDockArea(BECWidget, QWidget):
|
|
67
78
|
config: DockAreaConfig | None = None,
|
68
79
|
client=None,
|
69
80
|
gui_id: str = None,
|
81
|
+
object_name: str = None,
|
82
|
+
**kwargs,
|
70
83
|
) -> None:
|
71
84
|
if config is None:
|
72
85
|
config = DockAreaConfig(widget_class=self.__class__.__name__)
|
@@ -74,37 +87,47 @@ class BECDockArea(BECWidget, QWidget):
|
|
74
87
|
if isinstance(config, dict):
|
75
88
|
config = DockAreaConfig(**config)
|
76
89
|
self.config = config
|
77
|
-
super().__init__(
|
78
|
-
|
90
|
+
super().__init__(
|
91
|
+
parent=parent,
|
92
|
+
object_name=object_name,
|
93
|
+
client=client,
|
94
|
+
gui_id=gui_id,
|
95
|
+
config=config,
|
96
|
+
**kwargs,
|
97
|
+
)
|
98
|
+
self._parent = parent # TODO probably not needed
|
79
99
|
self.layout = QVBoxLayout(self)
|
80
100
|
self.layout.setSpacing(5)
|
81
101
|
self.layout.setContentsMargins(0, 0, 0, 0)
|
82
102
|
|
83
103
|
self._instructions_visible = True
|
84
104
|
|
85
|
-
self.
|
105
|
+
self.dark_mode_button = DarkModeButton(parent=self, toolbar=True)
|
106
|
+
self.dock_area = DockArea(parent=self)
|
86
107
|
self.toolbar = ModularToolBar(
|
108
|
+
parent=self,
|
87
109
|
actions={
|
88
110
|
"menu_plots": ExpandableMenuAction(
|
89
111
|
label="Add Plot ",
|
90
112
|
actions={
|
91
113
|
"waveform": MaterialIconAction(
|
92
|
-
icon_name=
|
93
|
-
|
114
|
+
icon_name=Waveform.ICON_NAME, tooltip="Add Waveform", filled=True
|
115
|
+
),
|
116
|
+
"scatter_waveform": MaterialIconAction(
|
117
|
+
icon_name=ScatterWaveform.ICON_NAME,
|
118
|
+
tooltip="Add Scatter Waveform",
|
94
119
|
filled=True,
|
95
120
|
),
|
96
121
|
"multi_waveform": MaterialIconAction(
|
97
|
-
icon_name=
|
122
|
+
icon_name=MultiWaveform.ICON_NAME,
|
98
123
|
tooltip="Add Multi Waveform",
|
99
124
|
filled=True,
|
100
125
|
),
|
101
126
|
"image": MaterialIconAction(
|
102
|
-
icon_name=
|
127
|
+
icon_name=Image.ICON_NAME, tooltip="Add Image", filled=True
|
103
128
|
),
|
104
129
|
"motor_map": MaterialIconAction(
|
105
|
-
icon_name=
|
106
|
-
tooltip="Add Motor Map",
|
107
|
-
filled=True,
|
130
|
+
icon_name=MotorMap.ICON_NAME, tooltip="Add Motor Map", filled=True
|
108
131
|
),
|
109
132
|
},
|
110
133
|
),
|
@@ -159,10 +182,10 @@ class BECDockArea(BECWidget, QWidget):
|
|
159
182
|
|
160
183
|
self.layout.addWidget(self.toolbar)
|
161
184
|
self.layout.addWidget(self.dock_area)
|
162
|
-
self.spacer = QWidget()
|
185
|
+
self.spacer = QWidget(parent=self)
|
163
186
|
self.spacer.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
164
187
|
self.toolbar.addWidget(self.spacer)
|
165
|
-
self.toolbar.addWidget(
|
188
|
+
self.toolbar.addWidget(self.dark_mode_button)
|
166
189
|
self._hook_toolbar()
|
167
190
|
|
168
191
|
def minimumSizeHint(self):
|
@@ -171,41 +194,44 @@ class BECDockArea(BECWidget, QWidget):
|
|
171
194
|
def _hook_toolbar(self):
|
172
195
|
# Menu Plot
|
173
196
|
self.toolbar.widgets["menu_plots"].widgets["waveform"].triggered.connect(
|
174
|
-
lambda: self.
|
197
|
+
lambda: self._create_widget_from_toolbar(widget_name="Waveform")
|
198
|
+
)
|
199
|
+
self.toolbar.widgets["menu_plots"].widgets["scatter_waveform"].triggered.connect(
|
200
|
+
lambda: self._create_widget_from_toolbar(widget_name="ScatterWaveform")
|
175
201
|
)
|
176
202
|
self.toolbar.widgets["menu_plots"].widgets["multi_waveform"].triggered.connect(
|
177
|
-
lambda: self.
|
203
|
+
lambda: self._create_widget_from_toolbar(widget_name="MultiWaveform")
|
178
204
|
)
|
179
205
|
self.toolbar.widgets["menu_plots"].widgets["image"].triggered.connect(
|
180
|
-
lambda: self.
|
206
|
+
lambda: self._create_widget_from_toolbar(widget_name="Image")
|
181
207
|
)
|
182
208
|
self.toolbar.widgets["menu_plots"].widgets["motor_map"].triggered.connect(
|
183
|
-
lambda: self.
|
209
|
+
lambda: self._create_widget_from_toolbar(widget_name="MotorMap")
|
184
210
|
)
|
185
211
|
|
186
212
|
# Menu Devices
|
187
213
|
self.toolbar.widgets["menu_devices"].widgets["scan_control"].triggered.connect(
|
188
|
-
lambda: self.
|
214
|
+
lambda: self._create_widget_from_toolbar(widget_name="ScanControl")
|
189
215
|
)
|
190
216
|
self.toolbar.widgets["menu_devices"].widgets["positioner_box"].triggered.connect(
|
191
|
-
lambda: self.
|
217
|
+
lambda: self._create_widget_from_toolbar(widget_name="PositionerBox")
|
192
218
|
)
|
193
219
|
|
194
220
|
# Menu Utils
|
195
221
|
self.toolbar.widgets["menu_utils"].widgets["queue"].triggered.connect(
|
196
|
-
lambda: self.
|
222
|
+
lambda: self._create_widget_from_toolbar(widget_name="BECQueue")
|
197
223
|
)
|
198
224
|
self.toolbar.widgets["menu_utils"].widgets["status"].triggered.connect(
|
199
|
-
lambda: self.
|
225
|
+
lambda: self._create_widget_from_toolbar(widget_name="BECStatusBox")
|
200
226
|
)
|
201
227
|
self.toolbar.widgets["menu_utils"].widgets["vs_code"].triggered.connect(
|
202
|
-
lambda: self.
|
228
|
+
lambda: self._create_widget_from_toolbar(widget_name="VSCodeEditor")
|
203
229
|
)
|
204
230
|
self.toolbar.widgets["menu_utils"].widgets["progress_bar"].triggered.connect(
|
205
|
-
lambda: self.
|
231
|
+
lambda: self._create_widget_from_toolbar(widget_name="RingProgressBar")
|
206
232
|
)
|
207
233
|
self.toolbar.widgets["menu_utils"].widgets["log_panel"].triggered.connect(
|
208
|
-
lambda: self.
|
234
|
+
lambda: self._create_widget_from_toolbar(widget_name="LogPanel")
|
209
235
|
)
|
210
236
|
|
211
237
|
# Icons
|
@@ -213,6 +239,14 @@ class BECDockArea(BECWidget, QWidget):
|
|
213
239
|
self.toolbar.widgets["save_state"].action.triggered.connect(self.save_state)
|
214
240
|
self.toolbar.widgets["restore_state"].action.triggered.connect(self.restore_state)
|
215
241
|
|
242
|
+
@SafeSlot()
|
243
|
+
def _create_widget_from_toolbar(self, widget_name: str) -> None:
|
244
|
+
# Run with RPC broadcast to namespace of all widgets
|
245
|
+
with RPCRegister.delayed_broadcast():
|
246
|
+
name = pascal_to_snake(widget_name)
|
247
|
+
dock_name = WidgetContainerUtils.generate_unique_name(name, self.panels.keys())
|
248
|
+
self.new(name=dock_name, widget=widget_name)
|
249
|
+
|
216
250
|
def paintEvent(self, event: QPaintEvent): # TODO decide if we want any default instructions
|
217
251
|
super().paintEvent(event)
|
218
252
|
if self._instructions_visible:
|
@@ -220,20 +254,9 @@ class BECDockArea(BECWidget, QWidget):
|
|
220
254
|
painter.drawText(
|
221
255
|
self.rect(),
|
222
256
|
Qt.AlignCenter,
|
223
|
-
"Add docks using '
|
257
|
+
"Add docks using 'new' method from CLI\n or \n Add widget docks using the toolbar",
|
224
258
|
)
|
225
259
|
|
226
|
-
@property
|
227
|
-
def selected_device(self) -> str:
|
228
|
-
gui_id = QApplication.instance().gui_id
|
229
|
-
auto_update_config = self.client.connector.get(
|
230
|
-
MessageEndpoints.gui_auto_update_config(gui_id)
|
231
|
-
)
|
232
|
-
try:
|
233
|
-
return auto_update_config.selected_device
|
234
|
-
except AttributeError:
|
235
|
-
return None
|
236
|
-
|
237
260
|
@property
|
238
261
|
def panels(self) -> dict[str, BECDock]:
|
239
262
|
"""
|
@@ -245,7 +268,17 @@ class BECDockArea(BECWidget, QWidget):
|
|
245
268
|
|
246
269
|
@panels.setter
|
247
270
|
def panels(self, value: dict[str, BECDock]):
|
248
|
-
self.dock_area.docks = WeakValueDictionary(value)
|
271
|
+
self.dock_area.docks = WeakValueDictionary(value) # This can not work can it?
|
272
|
+
|
273
|
+
@property
|
274
|
+
def panel_list(self) -> list[BECDock]:
|
275
|
+
"""
|
276
|
+
Get the docks in the dock area.
|
277
|
+
|
278
|
+
Returns:
|
279
|
+
list: The docks in the dock area.
|
280
|
+
"""
|
281
|
+
return list(self.dock_area.docks.values())
|
249
282
|
|
250
283
|
@property
|
251
284
|
def temp_areas(self) -> list:
|
@@ -275,6 +308,8 @@ class BECDockArea(BECWidget, QWidget):
|
|
275
308
|
"""
|
276
309
|
if state is None:
|
277
310
|
state = self.config.docks_state
|
311
|
+
if state is None:
|
312
|
+
return
|
278
313
|
self.dock_area.restoreState(state, missing=missing, extra=extra)
|
279
314
|
|
280
315
|
@SafeSlot()
|
@@ -289,36 +324,17 @@ class BECDockArea(BECWidget, QWidget):
|
|
289
324
|
self.config.docks_state = last_state
|
290
325
|
return last_state
|
291
326
|
|
292
|
-
def remove_dock(self, name: str):
|
293
|
-
"""
|
294
|
-
Remove a dock by name and ensure it is properly closed and cleaned up.
|
295
|
-
|
296
|
-
Args:
|
297
|
-
name(str): The name of the dock to remove.
|
298
|
-
"""
|
299
|
-
dock = self.dock_area.docks.pop(name, None)
|
300
|
-
self.config.docks.pop(name, None)
|
301
|
-
if dock:
|
302
|
-
dock.close()
|
303
|
-
dock.deleteLater()
|
304
|
-
if len(self.dock_area.docks) <= 1:
|
305
|
-
for dock in self.dock_area.docks.values():
|
306
|
-
dock.hide_title_bar()
|
307
|
-
|
308
|
-
else:
|
309
|
-
raise ValueError(f"Dock with name {name} does not exist.")
|
310
|
-
|
311
327
|
@SafeSlot(popup_error=True)
|
312
|
-
def
|
328
|
+
def new(
|
313
329
|
self,
|
314
|
-
name: str = None,
|
315
|
-
|
330
|
+
name: str | None = None,
|
331
|
+
widget: str | QWidget | None = None,
|
332
|
+
widget_name: str | None = None,
|
333
|
+
position: Literal["bottom", "top", "left", "right", "above", "below"] = "bottom",
|
316
334
|
relative_to: BECDock | None = None,
|
317
335
|
closable: bool = True,
|
318
336
|
floating: bool = False,
|
319
|
-
|
320
|
-
widget: str | QWidget | None = None,
|
321
|
-
row: int = None,
|
337
|
+
row: int | None = None,
|
322
338
|
col: int = 0,
|
323
339
|
rowspan: int = 1,
|
324
340
|
colspan: int = 1,
|
@@ -328,12 +344,11 @@ class BECDockArea(BECWidget, QWidget):
|
|
328
344
|
|
329
345
|
Args:
|
330
346
|
name(str): The name of the dock to be displayed and for further references. Has to be unique.
|
347
|
+
widget(str|QWidget|None): The widget to be added to the dock. While using RPC, only BEC RPC widgets from RPCWidgetHandler are allowed.
|
331
348
|
position(Literal["bottom", "top", "left", "right", "above", "below"]): The position of the dock.
|
332
349
|
relative_to(BECDock): The dock to which the new dock should be added relative to.
|
333
350
|
closable(bool): Whether the dock is closable.
|
334
351
|
floating(bool): Whether the dock is detached after creating.
|
335
|
-
prefix(str): The prefix for the dock name if no name is provided.
|
336
|
-
widget(str|QWidget|None): The widget to be added to the dock. While using RPC, only BEC RPC widgets from RPCWidgetHandler are allowed.
|
337
352
|
row(int): The row of the added widget.
|
338
353
|
col(int): The column of the added widget.
|
339
354
|
rowspan(int): The rowspan of the added widget.
|
@@ -342,21 +357,33 @@ class BECDockArea(BECWidget, QWidget):
|
|
342
357
|
Returns:
|
343
358
|
BECDock: The created dock.
|
344
359
|
"""
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
360
|
+
dock_names = [
|
361
|
+
dock.object_name for dock in self.panel_list
|
362
|
+
] # pylint: disable=protected-access
|
363
|
+
if name is not None: # Name is provided
|
364
|
+
if name in dock_names:
|
365
|
+
raise ValueError(
|
366
|
+
f"Name {name} must be unique for docks, but already exists in DockArea "
|
367
|
+
f"with name: {self.object_name} and id {self.gui_id}."
|
368
|
+
)
|
369
|
+
if not WidgetContainerUtils.has_name_valid_chars(name):
|
370
|
+
raise ValueError(
|
371
|
+
f"Name {name} contains invalid characters. "
|
372
|
+
f"Only alphanumeric characters and underscores are allowed."
|
373
|
+
)
|
374
|
+
else: # Name is not provided
|
375
|
+
name = WidgetContainerUtils.generate_unique_name(name="dock", list_of_names=dock_names)
|
376
|
+
|
377
|
+
dock = BECDock(
|
378
|
+
parent=self,
|
379
|
+
name=name, # this is dock name pyqtgraph property, this is displayed on label
|
380
|
+
object_name=name, # this is a real qt object name passed to BECConnector
|
381
|
+
parent_dock_area=self,
|
382
|
+
closable=closable,
|
383
|
+
)
|
357
384
|
dock.config.position = position
|
358
|
-
self.config.docks[name] = dock.config
|
359
|
-
|
385
|
+
self.config.docks[dock.name()] = dock.config
|
386
|
+
# The dock.name is equal to the name passed to BECDock
|
360
387
|
self.dock_area.addDock(dock=dock, position=position, relativeTo=relative_to)
|
361
388
|
|
362
389
|
if len(self.dock_area.docks) <= 1:
|
@@ -365,10 +392,11 @@ class BECDockArea(BECWidget, QWidget):
|
|
365
392
|
for dock in self.dock_area.docks.values():
|
366
393
|
dock.show_title_bar()
|
367
394
|
|
368
|
-
if widget is not None
|
369
|
-
|
370
|
-
|
371
|
-
|
395
|
+
if widget is not None:
|
396
|
+
# Check if widget name exists.
|
397
|
+
dock.new(
|
398
|
+
widget=widget, name=widget_name, row=row, col=col, rowspan=rowspan, colspan=colspan
|
399
|
+
)
|
372
400
|
if (
|
373
401
|
self._instructions_visible
|
374
402
|
): # TODO still decide how initial instructions should be handled
|
@@ -406,49 +434,24 @@ class BECDockArea(BECWidget, QWidget):
|
|
406
434
|
Remove a temporary area from the dock area.
|
407
435
|
This is a patched method of pyqtgraph's removeTempArea
|
408
436
|
"""
|
437
|
+
if area not in self.dock_area.tempAreas:
|
438
|
+
# FIXME add some context for the logging, I am not sure which object is passed.
|
439
|
+
# It looks like a pyqtgraph.DockArea
|
440
|
+
logger.info(f"Attempted to remove dock_area, but was not floating.")
|
441
|
+
return
|
409
442
|
self.dock_area.tempAreas.remove(area)
|
410
443
|
area.window().close()
|
411
444
|
area.window().deleteLater()
|
412
445
|
|
413
|
-
def clear_all(self):
|
414
|
-
"""
|
415
|
-
Close all docks and remove all temp areas.
|
416
|
-
"""
|
417
|
-
self.attach_all()
|
418
|
-
for dock in dict(self.dock_area.docks).values():
|
419
|
-
dock.remove()
|
420
|
-
self.dock_area.docks.clear()
|
421
|
-
|
422
446
|
def cleanup(self):
|
423
447
|
"""
|
424
448
|
Cleanup the dock area.
|
425
449
|
"""
|
426
|
-
self.
|
427
|
-
self.
|
428
|
-
self.
|
429
|
-
self.dock_area.close()
|
430
|
-
self.dock_area.deleteLater()
|
450
|
+
self.delete_all()
|
451
|
+
self.dark_mode_button.close()
|
452
|
+
self.dark_mode_button.deleteLater()
|
431
453
|
super().cleanup()
|
432
454
|
|
433
|
-
def closeEvent(self, event):
|
434
|
-
if self.parent() is None:
|
435
|
-
# we are at top-level (independent window)
|
436
|
-
if self.isVisible():
|
437
|
-
# we are visible => user clicked on [X]
|
438
|
-
# (when closeEvent is called from shutdown procedure,
|
439
|
-
# everything is hidden first)
|
440
|
-
# so, let's ignore "close", and do hide instead
|
441
|
-
event.ignore()
|
442
|
-
self.setVisible(False)
|
443
|
-
|
444
|
-
def close(self):
|
445
|
-
"""
|
446
|
-
Close the dock area and cleanup.
|
447
|
-
Has to be implemented to overwrite pyqtgraph event accept in Container close.
|
448
|
-
"""
|
449
|
-
self.cleanup()
|
450
|
-
super().close()
|
451
|
-
|
452
455
|
def show(self):
|
453
456
|
"""Show all windows including floating docks."""
|
454
457
|
super().show()
|
@@ -467,18 +470,65 @@ class BECDockArea(BECWidget, QWidget):
|
|
467
470
|
continue
|
468
471
|
docks.window().hide()
|
469
472
|
|
470
|
-
def
|
471
|
-
|
472
|
-
|
473
|
+
def delete_all(self) -> None:
|
474
|
+
"""
|
475
|
+
Delete all docks.
|
476
|
+
"""
|
477
|
+
self.attach_all()
|
478
|
+
for dock_name in self.panels.keys():
|
479
|
+
self.delete(dock_name)
|
480
|
+
|
481
|
+
def delete(self, dock_name: str):
|
482
|
+
"""
|
483
|
+
Delete a dock by name.
|
484
|
+
|
485
|
+
Args:
|
486
|
+
dock_name(str): The name of the dock to delete.
|
487
|
+
"""
|
488
|
+
dock = self.dock_area.docks.pop(dock_name, None)
|
489
|
+
self.config.docks.pop(dock_name, None)
|
490
|
+
if dock:
|
491
|
+
dock.close()
|
492
|
+
dock.deleteLater()
|
493
|
+
if len(self.dock_area.docks) <= 1:
|
494
|
+
for dock in self.dock_area.docks.values():
|
495
|
+
dock.hide_title_bar()
|
496
|
+
else:
|
497
|
+
raise ValueError(f"Dock with name {dock_name} does not exist.")
|
498
|
+
# self._broadcast_update()
|
499
|
+
|
500
|
+
def remove(self) -> None:
|
501
|
+
"""
|
502
|
+
Remove the dock area. If the dock area is embedded in a BECMainWindow and
|
503
|
+
is set as the central widget, the main window will be closed.
|
504
|
+
"""
|
505
|
+
parent = self.parent()
|
506
|
+
if isinstance(parent, BECMainWindow):
|
507
|
+
central_widget = parent.centralWidget()
|
508
|
+
if central_widget is self:
|
509
|
+
# Closing the parent will also close the dock area
|
510
|
+
parent.close()
|
511
|
+
return
|
512
|
+
|
513
|
+
self.close()
|
514
|
+
|
473
515
|
|
516
|
+
if __name__ == "__main__": # pragma: no cover
|
474
517
|
|
475
|
-
|
476
|
-
from qtpy.QtWidgets import QApplication
|
518
|
+
import sys
|
477
519
|
|
478
520
|
from bec_widgets.utils.colors import set_theme
|
479
521
|
|
480
522
|
app = QApplication([])
|
481
523
|
set_theme("auto")
|
482
524
|
dock_area = BECDockArea()
|
525
|
+
dock_1 = dock_area.new(name="dock_0", widget="DarkModeButton")
|
526
|
+
dock_1.new(widget="DarkModeButton")
|
527
|
+
# dock_1 = dock_area.new(name="dock_0", widget="Waveform")
|
528
|
+
dock_area.new(widget="DarkModeButton")
|
483
529
|
dock_area.show()
|
530
|
+
dock_area.setGeometry(100, 100, 800, 600)
|
531
|
+
app.topLevelWidgets()
|
532
|
+
WidgetHierarchy.print_becconnector_hierarchy_from_app()
|
484
533
|
app.exec_()
|
534
|
+
sys.exit(app.exec_())
|
@@ -1,3 +1,5 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
1
3
|
import math
|
2
4
|
import sys
|
3
5
|
from typing import Dict, Literal, Optional, Set, Tuple, Union
|
@@ -34,7 +36,6 @@ class LayoutManagerWidget(QWidget):
|
|
34
36
|
|
35
37
|
def __init__(self, parent=None, auto_reindex=True):
|
36
38
|
super().__init__(parent)
|
37
|
-
self.setObjectName("LayoutManagerWidget")
|
38
39
|
self.layout = QGridLayout(self)
|
39
40
|
self.auto_reindex = auto_reindex
|
40
41
|
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import webbrowser
|
2
|
+
|
3
|
+
|
4
|
+
class BECWebLinksMixin:
|
5
|
+
@staticmethod
|
6
|
+
def open_bec_docs():
|
7
|
+
webbrowser.open("https://beamline-experiment-control.readthedocs.io/en/latest/")
|
8
|
+
|
9
|
+
@staticmethod
|
10
|
+
def open_bec_widgets_docs():
|
11
|
+
webbrowser.open("https://bec.readthedocs.io/projects/bec-widgets/en/latest/")
|
12
|
+
|
13
|
+
@staticmethod
|
14
|
+
def open_bec_bug_report():
|
15
|
+
webbrowser.open("https://gitlab.psi.ch/groups/bec/-/issues/")
|