bec-widgets 1.25.0__py3-none-any.whl → 2.0.0__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 +11 -6
- CHANGELOG.md +650 -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 +186 -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 +37 -18
- bec_widgets/widgets/control/device_control/positioner_box/positioner_box/positioner_box.py +28 -4
- 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/spinner/spinner.py +2 -2
- 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.0.dist-info → bec_widgets-2.0.0.dist-info}/METADATA +3 -3
- {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/RECORD +169 -154
- 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.0.dist-info → bec_widgets-2.0.0.dist-info}/WHEEL +0 -0
- {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-1.25.0.dist-info → bec_widgets-2.0.0.dist-info}/licenses/LICENSE +0 -0
bec_widgets/utils/ui_loader.py
CHANGED
@@ -1,16 +1,17 @@
|
|
1
|
-
import
|
2
|
-
|
3
|
-
from qtpy import PYQT6, PYSIDE6, QT_VERSION
|
1
|
+
from bec_lib.logger import bec_logger
|
2
|
+
from qtpy import PYQT6, PYSIDE6
|
4
3
|
from qtpy.QtCore import QFile, QIODevice
|
5
4
|
|
6
5
|
from bec_widgets.utils.generate_designer_plugin import DesignerPluginInfo
|
7
6
|
from bec_widgets.utils.plugin_utils import get_custom_classes
|
8
7
|
|
8
|
+
logger = bec_logger.logger
|
9
|
+
|
9
10
|
if PYSIDE6:
|
10
11
|
from PySide6.QtUiTools import QUiLoader
|
11
12
|
|
12
13
|
class CustomUiLoader(QUiLoader):
|
13
|
-
def __init__(self, baseinstance, custom_widgets: dict = None):
|
14
|
+
def __init__(self, baseinstance, custom_widgets: dict | None = None):
|
14
15
|
super().__init__(baseinstance)
|
15
16
|
self.custom_widgets = custom_widgets or {}
|
16
17
|
|
@@ -18,10 +19,9 @@ if PYSIDE6:
|
|
18
19
|
|
19
20
|
def createWidget(self, class_name, parent=None, name=""):
|
20
21
|
if class_name in self.custom_widgets:
|
21
|
-
widget = self.custom_widgets[class_name](
|
22
|
-
widget.setObjectName(name)
|
22
|
+
widget = self.custom_widgets[class_name](self.baseinstance)
|
23
23
|
return widget
|
24
|
-
return super().createWidget(class_name,
|
24
|
+
return super().createWidget(class_name, self.baseinstance, name)
|
25
25
|
|
26
26
|
|
27
27
|
class UILoader:
|
@@ -51,7 +51,7 @@ class UILoader:
|
|
51
51
|
Returns:
|
52
52
|
QWidget: The loaded widget.
|
53
53
|
"""
|
54
|
-
|
54
|
+
parent = parent or self.parent
|
55
55
|
loader = CustomUiLoader(parent, self.custom_widgets)
|
56
56
|
file = QFile(ui_file)
|
57
57
|
if not file.open(QIODevice.ReadOnly):
|
bec_widgets/utils/widget_io.py
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# pylint: disable=no-name-in-module
|
2
|
+
from __future__ import annotations
|
3
|
+
|
2
4
|
from abc import ABC, abstractmethod
|
3
5
|
|
6
|
+
import shiboken6 as shb
|
4
7
|
from qtpy.QtWidgets import (
|
5
8
|
QApplication,
|
6
9
|
QCheckBox,
|
@@ -8,6 +11,7 @@ from qtpy.QtWidgets import (
|
|
8
11
|
QDoubleSpinBox,
|
9
12
|
QLabel,
|
10
13
|
QLineEdit,
|
14
|
+
QSlider,
|
11
15
|
QSpinBox,
|
12
16
|
QTableWidget,
|
13
17
|
QTableWidgetItem,
|
@@ -104,10 +108,10 @@ class TableWidgetHandler(WidgetHandler):
|
|
104
108
|
class SpinBoxHandler(WidgetHandler):
|
105
109
|
"""Handler for QSpinBox and QDoubleSpinBox widgets."""
|
106
110
|
|
107
|
-
def get_value(self, widget, **kwargs):
|
111
|
+
def get_value(self, widget: QSpinBox | QDoubleSpinBox, **kwargs):
|
108
112
|
return widget.value()
|
109
113
|
|
110
|
-
def set_value(self, widget, value):
|
114
|
+
def set_value(self, widget: QSpinBox | QDoubleSpinBox, value):
|
111
115
|
widget.setValue(value)
|
112
116
|
|
113
117
|
def connect_change_signal(self, widget: QSpinBox | QDoubleSpinBox, slot):
|
@@ -117,23 +121,36 @@ class SpinBoxHandler(WidgetHandler):
|
|
117
121
|
class CheckBoxHandler(WidgetHandler):
|
118
122
|
"""Handler for QCheckBox widgets."""
|
119
123
|
|
120
|
-
def get_value(self, widget, **kwargs):
|
124
|
+
def get_value(self, widget: QCheckBox, **kwargs):
|
121
125
|
return widget.isChecked()
|
122
126
|
|
123
|
-
def set_value(self, widget, value):
|
127
|
+
def set_value(self, widget: QCheckBox, value):
|
124
128
|
widget.setChecked(value)
|
125
129
|
|
126
130
|
def connect_change_signal(self, widget: QCheckBox, slot):
|
127
131
|
widget.toggled.connect(lambda val, w=widget: slot(w, val))
|
128
132
|
|
129
133
|
|
134
|
+
class SlideHandler(WidgetHandler):
|
135
|
+
"""Handler for QCheckBox widgets."""
|
136
|
+
|
137
|
+
def get_value(self, widget: QSlider, **kwargs):
|
138
|
+
return widget.value()
|
139
|
+
|
140
|
+
def set_value(self, widget: QSlider, value):
|
141
|
+
widget.setValue(value)
|
142
|
+
|
143
|
+
def connect_change_signal(self, widget: QSlider, slot):
|
144
|
+
widget.valueChanged.connect(lambda val, w=widget: slot(w, val))
|
145
|
+
|
146
|
+
|
130
147
|
class ToggleSwitchHandler(WidgetHandler):
|
131
148
|
"""Handler for ToggleSwitch widgets."""
|
132
149
|
|
133
|
-
def get_value(self, widget, **kwargs):
|
150
|
+
def get_value(self, widget: ToggleSwitch, **kwargs):
|
134
151
|
return widget.checked
|
135
152
|
|
136
|
-
def set_value(self, widget, value):
|
153
|
+
def set_value(self, widget: ToggleSwitch, value):
|
137
154
|
widget.checked = value
|
138
155
|
|
139
156
|
def connect_change_signal(self, widget: ToggleSwitch, slot):
|
@@ -143,7 +160,7 @@ class ToggleSwitchHandler(WidgetHandler):
|
|
143
160
|
class LabelHandler(WidgetHandler):
|
144
161
|
"""Handler for QLabel widgets."""
|
145
162
|
|
146
|
-
def get_value(self, widget, **kwargs):
|
163
|
+
def get_value(self, widget: QLabel, **kwargs):
|
147
164
|
return widget.text()
|
148
165
|
|
149
166
|
def set_value(self, widget: QLabel, value):
|
@@ -165,6 +182,7 @@ class WidgetIO:
|
|
165
182
|
QCheckBox: CheckBoxHandler,
|
166
183
|
QLabel: LabelHandler,
|
167
184
|
ToggleSwitch: ToggleSwitchHandler,
|
185
|
+
QSlider: SlideHandler,
|
168
186
|
}
|
169
187
|
|
170
188
|
@staticmethod
|
@@ -258,39 +276,162 @@ class WidgetHierarchy:
|
|
258
276
|
grab_values: bool = False,
|
259
277
|
prefix: str = "",
|
260
278
|
exclude_internal_widgets: bool = True,
|
279
|
+
only_bec_widgets: bool = False,
|
280
|
+
show_parent: bool = True,
|
261
281
|
) -> None:
|
262
282
|
"""
|
263
283
|
Print the widget hierarchy to the console.
|
264
284
|
|
265
285
|
Args:
|
266
|
-
widget: Widget to print the hierarchy of
|
286
|
+
widget: Widget to print the hierarchy of.
|
267
287
|
indent(int, optional): Level of indentation.
|
268
288
|
grab_values(bool,optional): Whether to grab the values of the widgets.
|
269
|
-
prefix(
|
289
|
+
prefix(str,optional): Custom string prefix for indentation.
|
270
290
|
exclude_internal_widgets(bool,optional): Whether to exclude internal widgets (e.g. QComboBox in PyQt6).
|
291
|
+
only_bec_widgets(bool, optional): Whether to print only widgets that are instances of BECWidget.
|
292
|
+
show_parent(bool, optional): Whether to display which BECWidget is the parent of each discovered BECWidget.
|
271
293
|
"""
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
294
|
+
from bec_widgets.utils import BECConnector
|
295
|
+
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
296
|
+
|
297
|
+
# 1) Filter out widgets that are not BECConnectors (if 'only_bec_widgets' is True)
|
298
|
+
is_bec = isinstance(widget, BECConnector)
|
299
|
+
if only_bec_widgets and not is_bec:
|
300
|
+
return
|
301
|
+
|
302
|
+
# 2) Determine and print the parent's info (closest BECConnector)
|
303
|
+
parent_info = ""
|
304
|
+
if show_parent and is_bec:
|
305
|
+
ancestor = WidgetHierarchy._get_becwidget_ancestor(widget)
|
306
|
+
if ancestor:
|
307
|
+
parent_label = ancestor.objectName() or ancestor.__class__.__name__
|
308
|
+
parent_info = f" parent={parent_label}"
|
309
|
+
else:
|
310
|
+
parent_info = " parent=None"
|
311
|
+
|
312
|
+
widget_info = f"{widget.__class__.__name__} ({widget.objectName()}){parent_info}"
|
278
313
|
print(prefix + widget_info)
|
279
314
|
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
315
|
+
# 3) If it's a Waveform, explicitly print the curves
|
316
|
+
if isinstance(widget, Waveform):
|
317
|
+
for curve in widget.curves:
|
318
|
+
curve_prefix = prefix + " └─ "
|
319
|
+
print(
|
320
|
+
f"{curve_prefix}{curve.__class__.__name__} ({curve.objectName()}) "
|
321
|
+
f"parent={widget.objectName()}"
|
322
|
+
)
|
323
|
+
|
324
|
+
# 4) Recursively handle each child if:
|
325
|
+
# - It's a QWidget
|
326
|
+
# - It is a BECConnector (or we don't care about filtering)
|
327
|
+
# - Its closest BECConnector parent is the current widget
|
328
|
+
for child in widget.findChildren(QWidget):
|
329
|
+
if only_bec_widgets and not isinstance(child, BECConnector):
|
287
330
|
continue
|
288
|
-
|
289
|
-
|
331
|
+
|
332
|
+
# if WidgetHierarchy._get_becwidget_ancestor(child) == widget:
|
333
|
+
child_prefix = prefix + " └─ "
|
290
334
|
WidgetHierarchy.print_widget_hierarchy(
|
291
|
-
child,
|
335
|
+
child,
|
336
|
+
indent=indent + 1,
|
337
|
+
grab_values=grab_values,
|
338
|
+
prefix=child_prefix,
|
339
|
+
exclude_internal_widgets=exclude_internal_widgets,
|
340
|
+
only_bec_widgets=only_bec_widgets,
|
341
|
+
show_parent=show_parent,
|
292
342
|
)
|
293
343
|
|
344
|
+
@staticmethod
|
345
|
+
def print_becconnector_hierarchy_from_app():
|
346
|
+
"""
|
347
|
+
Enumerate ALL BECConnector objects in the QApplication.
|
348
|
+
Also detect if a widget is a PlotBase, and add any data items
|
349
|
+
(PlotDataItem-like) that are also BECConnector objects.
|
350
|
+
|
351
|
+
Build a parent->children graph where each child's 'parent'
|
352
|
+
is its closest BECConnector ancestor. Print the entire hierarchy
|
353
|
+
from the root(s).
|
354
|
+
|
355
|
+
The result is a single, consolidated tree for your entire
|
356
|
+
running GUI, including PlotBase data items that are BECConnector.
|
357
|
+
"""
|
358
|
+
import sys
|
359
|
+
from collections import defaultdict
|
360
|
+
|
361
|
+
from qtpy.QtWidgets import QApplication
|
362
|
+
|
363
|
+
from bec_widgets.utils import BECConnector
|
364
|
+
from bec_widgets.widgets.plots.plot_base import PlotBase
|
365
|
+
|
366
|
+
# 1) Gather ALL QWidget-based BECConnector objects
|
367
|
+
all_qwidgets = QApplication.allWidgets()
|
368
|
+
bec_widgets = set(w for w in all_qwidgets if isinstance(w, BECConnector))
|
369
|
+
|
370
|
+
# 2) Also gather any BECConnector-based data items from PlotBase widgets
|
371
|
+
for w in all_qwidgets:
|
372
|
+
if isinstance(w, PlotBase) and hasattr(w, "plot_item"):
|
373
|
+
plot_item = w.plot_item
|
374
|
+
if hasattr(plot_item, "listDataItems"):
|
375
|
+
for data_item in plot_item.listDataItems():
|
376
|
+
if isinstance(data_item, BECConnector):
|
377
|
+
bec_widgets.add(data_item)
|
378
|
+
|
379
|
+
# 3) Build a map of (closest BECConnector parent) -> list of children
|
380
|
+
parent_map = defaultdict(list)
|
381
|
+
for w in bec_widgets:
|
382
|
+
parent_bec = WidgetHierarchy._get_becwidget_ancestor(w)
|
383
|
+
parent_map[parent_bec].append(w)
|
384
|
+
|
385
|
+
# 4) Define a recursive printer to show each object's children
|
386
|
+
def print_tree(parent, prefix=""):
|
387
|
+
children = parent_map[parent]
|
388
|
+
for i, child in enumerate(children):
|
389
|
+
connector_class = child.__class__.__name__
|
390
|
+
connector_name = child.objectName() or connector_class
|
391
|
+
|
392
|
+
if parent is None:
|
393
|
+
parent_label = "None"
|
394
|
+
else:
|
395
|
+
parent_label = parent.objectName() or parent.__class__.__name__
|
396
|
+
|
397
|
+
line = f"{connector_class} ({connector_name}) parent={parent_label}"
|
398
|
+
# Determine tree-branch symbols
|
399
|
+
is_last = i == len(children) - 1
|
400
|
+
branch_str = "└─ " if is_last else "├─ "
|
401
|
+
print(prefix + branch_str + line)
|
402
|
+
|
403
|
+
# Recurse deeper
|
404
|
+
next_prefix = prefix + (" " if is_last else "│ ")
|
405
|
+
print_tree(child, prefix=next_prefix)
|
406
|
+
|
407
|
+
# 5) Print top-level items (roots) whose BECConnector parent is None
|
408
|
+
roots = parent_map[None]
|
409
|
+
for r_i, root in enumerate(roots):
|
410
|
+
root_class = root.__class__.__name__
|
411
|
+
root_name = root.objectName() or root_class
|
412
|
+
line = f"{root_class} ({root_name}) parent=None"
|
413
|
+
is_last_root = r_i == len(roots) - 1
|
414
|
+
print(line)
|
415
|
+
# Recurse into its children
|
416
|
+
print_tree(root, prefix=" ")
|
417
|
+
|
418
|
+
@staticmethod
|
419
|
+
def _get_becwidget_ancestor(widget):
|
420
|
+
"""
|
421
|
+
Traverse up the parent chain to find the nearest BECConnector.
|
422
|
+
Returns None if none is found.
|
423
|
+
"""
|
424
|
+
from bec_widgets.utils import BECConnector
|
425
|
+
|
426
|
+
if not shb.isValid(widget):
|
427
|
+
return None
|
428
|
+
parent = widget.parent()
|
429
|
+
while parent is not None:
|
430
|
+
if isinstance(parent, BECConnector):
|
431
|
+
return parent
|
432
|
+
parent = parent.parent()
|
433
|
+
return None
|
434
|
+
|
294
435
|
@staticmethod
|
295
436
|
def export_config_to_dict(
|
296
437
|
widget: QWidget,
|
@@ -0,0 +1,364 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
from typing import TYPE_CHECKING, Literal, overload
|
4
|
+
|
5
|
+
from bec_lib.endpoints import MessageEndpoints
|
6
|
+
from bec_lib.logger import bec_logger
|
7
|
+
from bec_lib.messages import ScanStatusMessage
|
8
|
+
|
9
|
+
from bec_widgets.utils.error_popups import SafeSlot
|
10
|
+
from bec_widgets.widgets.containers.dock.dock_area import BECDockArea
|
11
|
+
from bec_widgets.widgets.containers.main_window.main_window import BECMainWindow
|
12
|
+
|
13
|
+
if TYPE_CHECKING: # pragma: no cover
|
14
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
15
|
+
from bec_widgets.widgets.containers.dock.dock import BECDock
|
16
|
+
from bec_widgets.widgets.plots.image.image import Image
|
17
|
+
from bec_widgets.widgets.plots.motor_map.motor_map import MotorMap
|
18
|
+
from bec_widgets.widgets.plots.multi_waveform.multi_waveform import MultiWaveform
|
19
|
+
from bec_widgets.widgets.plots.scatter_waveform.scatter_waveform import ScatterWaveform
|
20
|
+
from bec_widgets.widgets.plots.waveform.waveform import Waveform
|
21
|
+
|
22
|
+
|
23
|
+
logger = bec_logger.logger
|
24
|
+
|
25
|
+
|
26
|
+
class AutoUpdates(BECMainWindow):
|
27
|
+
_default_dock: BECDock
|
28
|
+
USER_ACCESS = ["enabled", "enabled.setter", "selected_device", "selected_device.setter"]
|
29
|
+
RPC = True
|
30
|
+
|
31
|
+
# enforce that subclasses have the same rpc widget class
|
32
|
+
rpc_widget_class = "AutoUpdates"
|
33
|
+
|
34
|
+
def __init__(
|
35
|
+
self, parent=None, gui_id: str = None, window_title="Auto Update", *args, **kwargs
|
36
|
+
):
|
37
|
+
super().__init__(parent=parent, gui_id=gui_id, window_title=window_title, **kwargs)
|
38
|
+
|
39
|
+
self.dock_area = BECDockArea(parent=self, object_name="dock_area")
|
40
|
+
self.setCentralWidget(self.dock_area)
|
41
|
+
self._auto_update_selected_device: str | None = None
|
42
|
+
|
43
|
+
self._default_dock = None # type:ignore
|
44
|
+
self.current_widget: BECWidget | None = None
|
45
|
+
self.dock_name = None
|
46
|
+
self._enabled = True
|
47
|
+
self.start_auto_update()
|
48
|
+
|
49
|
+
def start_auto_update(self):
|
50
|
+
"""
|
51
|
+
Establish all connections for the auto updates.
|
52
|
+
"""
|
53
|
+
self.bec_dispatcher.connect_slot(self._on_scan_status, MessageEndpoints.scan_status())
|
54
|
+
|
55
|
+
def stop_auto_update(self):
|
56
|
+
"""
|
57
|
+
Disconnect all connections for the auto updates.
|
58
|
+
"""
|
59
|
+
self.bec_dispatcher.disconnect_slot(
|
60
|
+
self._on_scan_status, MessageEndpoints.scan_status() # type:ignore
|
61
|
+
)
|
62
|
+
|
63
|
+
@property
|
64
|
+
def selected_device(self) -> str | None:
|
65
|
+
"""
|
66
|
+
Get the selected device from the auto update config.
|
67
|
+
|
68
|
+
Returns:
|
69
|
+
str: The selected device. If no device is selected, None is returned.
|
70
|
+
"""
|
71
|
+
return self._auto_update_selected_device
|
72
|
+
|
73
|
+
@selected_device.setter
|
74
|
+
def selected_device(self, value: str | None) -> None:
|
75
|
+
"""
|
76
|
+
Set the selected device in the auto update config.
|
77
|
+
|
78
|
+
Args:
|
79
|
+
value(str): The selected device.
|
80
|
+
"""
|
81
|
+
self._auto_update_selected_device = value
|
82
|
+
|
83
|
+
@SafeSlot()
|
84
|
+
def _on_scan_status(self, content: dict, metadata: dict) -> None:
|
85
|
+
"""
|
86
|
+
Callback for scan status messages.
|
87
|
+
"""
|
88
|
+
msg = ScanStatusMessage(**content, metadata=metadata)
|
89
|
+
if not self.enabled:
|
90
|
+
return
|
91
|
+
|
92
|
+
self.enable_gui_highlights(True)
|
93
|
+
|
94
|
+
match msg.status:
|
95
|
+
case "open":
|
96
|
+
self.on_scan_open(msg)
|
97
|
+
case "closed":
|
98
|
+
self.on_scan_closed(msg)
|
99
|
+
case ["aborted", "halted"]:
|
100
|
+
self.on_scan_abort(msg)
|
101
|
+
case _:
|
102
|
+
pass
|
103
|
+
|
104
|
+
def start_default_dock(self):
|
105
|
+
"""
|
106
|
+
Create a default dock for the auto updates.
|
107
|
+
"""
|
108
|
+
self.dock_name = "update_dock"
|
109
|
+
self._default_dock = self.dock_area.new(self.dock_name)
|
110
|
+
self.current_widget = self._default_dock.new("Waveform")
|
111
|
+
|
112
|
+
@overload
|
113
|
+
def set_dock_to_widget(self, widget: Literal["Waveform"]) -> Waveform: ...
|
114
|
+
|
115
|
+
@overload
|
116
|
+
def set_dock_to_widget(self, widget: Literal["Image"]) -> Image: ...
|
117
|
+
|
118
|
+
@overload
|
119
|
+
def set_dock_to_widget(self, widget: Literal["ScatterWaveform"]) -> ScatterWaveform: ...
|
120
|
+
|
121
|
+
@overload
|
122
|
+
def set_dock_to_widget(self, widget: Literal["MotorMap"]) -> MotorMap: ...
|
123
|
+
|
124
|
+
@overload
|
125
|
+
def set_dock_to_widget(self, widget: Literal["MultiWaveform"]) -> MultiWaveform: ...
|
126
|
+
|
127
|
+
def set_dock_to_widget(
|
128
|
+
self,
|
129
|
+
widget: Literal["Waveform", "Image", "ScatterWaveform", "MotorMap", "MultiWaveForm"] | str,
|
130
|
+
) -> BECWidget:
|
131
|
+
"""
|
132
|
+
Set the dock to the widget.
|
133
|
+
|
134
|
+
Args:
|
135
|
+
widget (str): The widget to set the dock to. Must be the name of a valid widget class.
|
136
|
+
|
137
|
+
Returns:
|
138
|
+
BECWidget: The widget that was set.
|
139
|
+
"""
|
140
|
+
if self._default_dock is None or self.current_widget is None:
|
141
|
+
logger.warning(
|
142
|
+
f"Auto Updates: No default dock found. Creating a new one with name {self.dock_name}"
|
143
|
+
)
|
144
|
+
self.start_default_dock()
|
145
|
+
assert self.current_widget is not None
|
146
|
+
|
147
|
+
if not self.current_widget.__class__.__name__ == widget:
|
148
|
+
self._default_dock.delete(self.current_widget.object_name)
|
149
|
+
self.current_widget = self._default_dock.new(widget)
|
150
|
+
return self.current_widget
|
151
|
+
|
152
|
+
def get_selected_device(
|
153
|
+
self, monitored_devices, selected_device: str | None = None
|
154
|
+
) -> str | None:
|
155
|
+
"""
|
156
|
+
Get the selected device for the plot. If no device is selected, the first
|
157
|
+
device in the monitored devices list is selected.
|
158
|
+
"""
|
159
|
+
|
160
|
+
if selected_device is None:
|
161
|
+
selected_device = self.selected_device
|
162
|
+
if selected_device:
|
163
|
+
return selected_device
|
164
|
+
if len(monitored_devices) > 0:
|
165
|
+
sel_device = monitored_devices[0]
|
166
|
+
return sel_device
|
167
|
+
return None
|
168
|
+
|
169
|
+
def enable_gui_highlights(self, enable: bool) -> None:
|
170
|
+
"""
|
171
|
+
Enable or disable GUI highlights.
|
172
|
+
|
173
|
+
Args:
|
174
|
+
enable (bool): Whether to enable or disable the highlights.
|
175
|
+
"""
|
176
|
+
if enable:
|
177
|
+
title = self.dock_area.window().windowTitle()
|
178
|
+
if " [Auto Updates]" in title:
|
179
|
+
return
|
180
|
+
self.dock_area.window().setWindowTitle(f"{title} [Auto Updates]")
|
181
|
+
else:
|
182
|
+
title = self.dock_area.window().windowTitle()
|
183
|
+
self.dock_area.window().setWindowTitle(title.replace(" [Auto Updates]", ""))
|
184
|
+
|
185
|
+
@property
|
186
|
+
def enabled(self) -> bool:
|
187
|
+
"""
|
188
|
+
Get the enabled status of the auto updates.
|
189
|
+
"""
|
190
|
+
return self._enabled
|
191
|
+
|
192
|
+
@enabled.setter
|
193
|
+
def enabled(self, value: bool) -> None:
|
194
|
+
"""
|
195
|
+
Set the enabled status of the auto updates.
|
196
|
+
"""
|
197
|
+
if self._enabled == value:
|
198
|
+
return
|
199
|
+
self._enabled = value
|
200
|
+
|
201
|
+
if value:
|
202
|
+
self.start_auto_update()
|
203
|
+
self.enable_gui_highlights(True)
|
204
|
+
self.on_start()
|
205
|
+
else:
|
206
|
+
self.stop_auto_update()
|
207
|
+
self.enable_gui_highlights(False)
|
208
|
+
self.on_stop()
|
209
|
+
|
210
|
+
def cleanup(self) -> None:
|
211
|
+
"""
|
212
|
+
Cleanup procedure to run when the auto updates are disabled.
|
213
|
+
"""
|
214
|
+
self.enabled = False
|
215
|
+
self.stop_auto_update()
|
216
|
+
self.dock_area.close()
|
217
|
+
self.dock_area.deleteLater()
|
218
|
+
self.dock_area = None
|
219
|
+
super().cleanup()
|
220
|
+
|
221
|
+
########################################################################
|
222
|
+
################# Update Functions #####################################
|
223
|
+
########################################################################
|
224
|
+
|
225
|
+
def simple_line_scan(self, info: ScanStatusMessage) -> None:
|
226
|
+
"""
|
227
|
+
Simple line scan.
|
228
|
+
|
229
|
+
Args:
|
230
|
+
info (ScanStatusMessage): The scan status message.
|
231
|
+
"""
|
232
|
+
|
233
|
+
# Set the dock to the waveform widget
|
234
|
+
wf = self.set_dock_to_widget("Waveform")
|
235
|
+
|
236
|
+
# Get the scan report devices reported by the scan
|
237
|
+
dev_x = info.scan_report_devices[0] # type:ignore
|
238
|
+
|
239
|
+
# For the y axis, get the selected device
|
240
|
+
dev_y = self.get_selected_device(info.readout_priority["monitored"]) # type:ignore
|
241
|
+
if not dev_y:
|
242
|
+
return
|
243
|
+
|
244
|
+
# Clear the waveform widget and plot the data
|
245
|
+
# with the scan number and device names
|
246
|
+
# as the label and title
|
247
|
+
wf.clear_all()
|
248
|
+
wf.plot(
|
249
|
+
x_name=dev_x,
|
250
|
+
y_name=dev_y,
|
251
|
+
label=f"Scan {info.scan_number} - {dev_y}",
|
252
|
+
title=f"Scan {info.scan_number}",
|
253
|
+
x_label=dev_x,
|
254
|
+
y_label=dev_y,
|
255
|
+
)
|
256
|
+
|
257
|
+
logger.info(
|
258
|
+
f"Auto Update [simple_line_scan]: Started plot with: x_name={dev_x}, y_name={dev_y}"
|
259
|
+
)
|
260
|
+
|
261
|
+
def simple_grid_scan(self, info: ScanStatusMessage) -> None:
|
262
|
+
"""
|
263
|
+
Simple grid scan.
|
264
|
+
|
265
|
+
Args:
|
266
|
+
info (ScanStatusMessage): The scan status message.
|
267
|
+
"""
|
268
|
+
# Set the dock to the scatter waveform widget
|
269
|
+
scatter = self.set_dock_to_widget("ScatterWaveform")
|
270
|
+
|
271
|
+
# Get the scan report devices reported by the scan
|
272
|
+
dev_x, dev_y = info.scan_report_devices[0], info.scan_report_devices[1] # type:ignore
|
273
|
+
dev_z = self.get_selected_device(info.readout_priority["monitored"]) # type:ignore
|
274
|
+
|
275
|
+
if None in (dev_x, dev_y, dev_z):
|
276
|
+
return
|
277
|
+
|
278
|
+
# Clear the scatter waveform widget and plot the data
|
279
|
+
scatter.clear_all()
|
280
|
+
scatter.plot(
|
281
|
+
x_name=dev_x, y_name=dev_y, z_name=dev_z, label=f"Scan {info.scan_number} - {dev_z}"
|
282
|
+
)
|
283
|
+
|
284
|
+
logger.info(
|
285
|
+
f"Auto Update [simple_grid_scan]: Started plot with: x_name={dev_x}, y_name={dev_y}, z_name={dev_z}"
|
286
|
+
)
|
287
|
+
|
288
|
+
def best_effort(self, info: ScanStatusMessage) -> None:
|
289
|
+
"""
|
290
|
+
Best effort scan.
|
291
|
+
|
292
|
+
Args:
|
293
|
+
info (ScanStatusMessage): The scan status message.
|
294
|
+
"""
|
295
|
+
|
296
|
+
# If the scan report devices are empty, there is nothing we can do
|
297
|
+
if not info.scan_report_devices:
|
298
|
+
return
|
299
|
+
dev_x = info.scan_report_devices[0] # type:ignore
|
300
|
+
dev_y = self.get_selected_device(info.readout_priority["monitored"]) # type:ignore
|
301
|
+
if not dev_y:
|
302
|
+
return
|
303
|
+
|
304
|
+
# Set the dock to the waveform widget
|
305
|
+
wf = self.set_dock_to_widget("Waveform")
|
306
|
+
|
307
|
+
# Clear the waveform widget and plot the data
|
308
|
+
wf.clear_all()
|
309
|
+
wf.plot(
|
310
|
+
x_name=dev_x,
|
311
|
+
y_name=dev_y,
|
312
|
+
label=f"Scan {info.scan_number} - {dev_y}",
|
313
|
+
title=f"Scan {info.scan_number}",
|
314
|
+
x_label=dev_x,
|
315
|
+
y_label=dev_y,
|
316
|
+
)
|
317
|
+
|
318
|
+
logger.info(f"Auto Update [best_effort]: Started plot with: x_name={dev_x}, y_name={dev_y}")
|
319
|
+
|
320
|
+
#######################################################################
|
321
|
+
################# GUI Callbacks #######################################
|
322
|
+
#######################################################################
|
323
|
+
|
324
|
+
def on_start(self) -> None:
|
325
|
+
"""
|
326
|
+
Procedure to run when the auto updates are enabled.
|
327
|
+
"""
|
328
|
+
self.start_default_dock()
|
329
|
+
|
330
|
+
def on_stop(self) -> None:
|
331
|
+
"""
|
332
|
+
Procedure to run when the auto updates are disabled.
|
333
|
+
"""
|
334
|
+
|
335
|
+
def on_scan_open(self, msg: ScanStatusMessage) -> None:
|
336
|
+
"""
|
337
|
+
Procedure to run when a scan starts.
|
338
|
+
|
339
|
+
Args:
|
340
|
+
msg (ScanStatusMessage): The scan status message.
|
341
|
+
"""
|
342
|
+
if msg.scan_name == "line_scan" and msg.scan_report_devices:
|
343
|
+
return self.simple_line_scan(msg)
|
344
|
+
if msg.scan_name == "grid_scan" and msg.scan_report_devices:
|
345
|
+
return self.simple_grid_scan(msg)
|
346
|
+
if msg.scan_report_devices:
|
347
|
+
return self.best_effort(msg)
|
348
|
+
return None
|
349
|
+
|
350
|
+
def on_scan_closed(self, msg: ScanStatusMessage) -> None:
|
351
|
+
"""
|
352
|
+
Procedure to run when a scan ends.
|
353
|
+
|
354
|
+
Args:
|
355
|
+
msg (ScanStatusMessage): The scan status message.
|
356
|
+
"""
|
357
|
+
|
358
|
+
def on_scan_abort(self, msg: ScanStatusMessage) -> None:
|
359
|
+
"""
|
360
|
+
Procedure to run when a scan is aborted.
|
361
|
+
|
362
|
+
Args:
|
363
|
+
msg (ScanStatusMessage): The scan status message.
|
364
|
+
"""
|