bec-widgets 1.4.0__py3-none-any.whl → 1.5.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.
@@ -0,0 +1,54 @@
1
+ # Copyright (C) 2022 The Qt Company Ltd.
2
+ # SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
3
+
4
+ from qtpy.QtDesigner import QDesignerCustomWidgetInterface
5
+
6
+ from bec_widgets.utils.bec_designer import designer_material_icon
7
+ from bec_widgets.widgets.multi_waveform.multi_waveform_widget import BECMultiWaveformWidget
8
+
9
+ DOM_XML = """
10
+ <ui language='c++'>
11
+ <widget class='BECMultiWaveformWidget' name='bec_multi_waveform_widget'>
12
+ </widget>
13
+ </ui>
14
+ """
15
+
16
+
17
+ class BECMultiWaveformWidgetPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
18
+ def __init__(self):
19
+ super().__init__()
20
+ self._form_editor = None
21
+
22
+ def createWidget(self, parent):
23
+ t = BECMultiWaveformWidget(parent)
24
+ return t
25
+
26
+ def domXml(self):
27
+ return DOM_XML
28
+
29
+ def group(self):
30
+ return "BEC Plots"
31
+
32
+ def icon(self):
33
+ return designer_material_icon(BECMultiWaveformWidget.ICON_NAME)
34
+
35
+ def includeFile(self):
36
+ return "bec_multi_waveform_widget"
37
+
38
+ def initialize(self, form_editor):
39
+ self._form_editor = form_editor
40
+
41
+ def isContainer(self):
42
+ return False
43
+
44
+ def isInitialized(self):
45
+ return self._form_editor is not None
46
+
47
+ def name(self):
48
+ return "BECMultiWaveformWidget"
49
+
50
+ def toolTip(self):
51
+ return "BECMultiWaveformWidget"
52
+
53
+ def whatsThis(self):
54
+ return self.toolTip()
@@ -0,0 +1,99 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <ui version="4.0">
3
+ <class>Form</class>
4
+ <widget class="QWidget" name="Form">
5
+ <property name="geometry">
6
+ <rect>
7
+ <x>0</x>
8
+ <y>0</y>
9
+ <width>561</width>
10
+ <height>86</height>
11
+ </rect>
12
+ </property>
13
+ <property name="windowTitle">
14
+ <string>Form</string>
15
+ </property>
16
+ <layout class="QGridLayout" name="gridLayout">
17
+ <item row="0" column="0">
18
+ <widget class="QLabel" name="label_curve_index">
19
+ <property name="text">
20
+ <string>Curve Index</string>
21
+ </property>
22
+ </widget>
23
+ </item>
24
+ <item row="0" column="1">
25
+ <widget class="QSlider" name="slider_index">
26
+ <property name="orientation">
27
+ <enum>Qt::Orientation::Horizontal</enum>
28
+ </property>
29
+ </widget>
30
+ </item>
31
+ <item row="0" column="2">
32
+ <widget class="QSpinBox" name="spinbox_index"/>
33
+ </item>
34
+ <item row="0" column="3" colspan="3">
35
+ <widget class="QCheckBox" name="checkbox_highlight">
36
+ <property name="text">
37
+ <string>Highlight always last curve</string>
38
+ </property>
39
+ </widget>
40
+ </item>
41
+ <item row="1" column="0">
42
+ <widget class="QLabel" name="label_opacity">
43
+ <property name="text">
44
+ <string>Opacity</string>
45
+ </property>
46
+ </widget>
47
+ </item>
48
+ <item row="1" column="1">
49
+ <widget class="QSlider" name="slider_opacity">
50
+ <property name="maximum">
51
+ <number>100</number>
52
+ </property>
53
+ <property name="orientation">
54
+ <enum>Qt::Orientation::Horizontal</enum>
55
+ </property>
56
+ </widget>
57
+ </item>
58
+ <item row="1" column="3">
59
+ <widget class="QLabel" name="label_max_trace">
60
+ <property name="text">
61
+ <string>Max Trace</string>
62
+ </property>
63
+ </widget>
64
+ </item>
65
+ <item row="1" column="4">
66
+ <widget class="QSpinBox" name="spinbox_max_trace">
67
+ <property name="toolTip">
68
+ <string>How many curves should be displayed</string>
69
+ </property>
70
+ <property name="maximum">
71
+ <number>500</number>
72
+ </property>
73
+ <property name="value">
74
+ <number>200</number>
75
+ </property>
76
+ </widget>
77
+ </item>
78
+ <item row="1" column="5">
79
+ <widget class="QCheckBox" name="checkbox_flush_buffer">
80
+ <property name="toolTip">
81
+ <string>If hiddne curves should be deleted.</string>
82
+ </property>
83
+ <property name="text">
84
+ <string>Flush Buffer</string>
85
+ </property>
86
+ </widget>
87
+ </item>
88
+ <item row="1" column="2">
89
+ <widget class="QSpinBox" name="spinbox_opacity">
90
+ <property name="maximum">
91
+ <number>100</number>
92
+ </property>
93
+ </widget>
94
+ </item>
95
+ </layout>
96
+ </widget>
97
+ <resources/>
98
+ <connections/>
99
+ </ui>
@@ -0,0 +1,533 @@
1
+ import os
2
+ from typing import Literal
3
+
4
+ import pyqtgraph as pg
5
+ from bec_lib.device import ReadoutPriority
6
+ from bec_lib.logger import bec_logger
7
+ from qtpy.QtCore import Slot
8
+ from qtpy.QtWidgets import QVBoxLayout, QWidget
9
+
10
+ from bec_widgets.qt_utils.error_popups import SafeSlot
11
+ from bec_widgets.qt_utils.settings_dialog import SettingsDialog
12
+ from bec_widgets.qt_utils.toolbar import (
13
+ DeviceSelectionAction,
14
+ MaterialIconAction,
15
+ ModularToolBar,
16
+ SeparatorAction,
17
+ WidgetAction,
18
+ )
19
+ from bec_widgets.utils import UILoader
20
+ from bec_widgets.utils.bec_widget import BECWidget
21
+ from bec_widgets.widgets.base_classes.device_input_base import BECDeviceFilter
22
+ from bec_widgets.widgets.colormap_widget.colormap_widget import BECColorMapWidget
23
+ from bec_widgets.widgets.device_combobox.device_combobox import DeviceComboBox
24
+ from bec_widgets.widgets.figure import BECFigure
25
+ from bec_widgets.widgets.figure.plots.axis_settings import AxisSettings
26
+ from bec_widgets.widgets.figure.plots.multi_waveform.multi_waveform import BECMultiWaveformConfig
27
+
28
+ logger = bec_logger.logger
29
+
30
+
31
+ class BECMultiWaveformWidget(BECWidget, QWidget):
32
+ ICON_NAME = "ssid_chart"
33
+ USER_ACCESS = [
34
+ "curves",
35
+ "set_monitor",
36
+ "set_curve_highlight",
37
+ "set_opacity",
38
+ "set_curve_limit",
39
+ "set_buffer_flush",
40
+ "set_highlight_last_curve",
41
+ "set_colormap",
42
+ "set",
43
+ "set_title",
44
+ "set_x_label",
45
+ "set_y_label",
46
+ "set_x_scale",
47
+ "set_y_scale",
48
+ "set_x_lim",
49
+ "set_y_lim",
50
+ "set_grid",
51
+ "set_colormap",
52
+ "enable_fps_monitor",
53
+ "lock_aspect_ratio",
54
+ "get_all_data",
55
+ "export",
56
+ ]
57
+
58
+ def __init__(
59
+ self,
60
+ parent: QWidget | None = None,
61
+ config: BECMultiWaveformConfig | dict = None,
62
+ client=None,
63
+ gui_id: str | None = None,
64
+ ) -> None:
65
+ if config is None:
66
+ config = BECMultiWaveformConfig(widget_class=self.__class__.__name__)
67
+ else:
68
+ if isinstance(config, dict):
69
+ config = BECMultiWaveformConfig(**config)
70
+ super().__init__(client=client, gui_id=gui_id)
71
+ QWidget.__init__(self, parent)
72
+
73
+ self.layout = QVBoxLayout(self)
74
+ self.layout.setSpacing(0)
75
+ self.layout.setContentsMargins(0, 0, 0, 0)
76
+
77
+ self.fig = BECFigure()
78
+ self.colormap_button = BECColorMapWidget(cmap="magma")
79
+ self.toolbar = ModularToolBar(
80
+ actions={
81
+ "monitor": DeviceSelectionAction(
82
+ "",
83
+ DeviceComboBox(
84
+ device_filter=BECDeviceFilter.DEVICE,
85
+ readout_priority_filter=ReadoutPriority.ASYNC,
86
+ ),
87
+ ),
88
+ "connect": MaterialIconAction(icon_name="link", tooltip="Connect Device"),
89
+ "separator_0": SeparatorAction(),
90
+ "colormap": WidgetAction(widget=self.colormap_button),
91
+ "separator_1": SeparatorAction(),
92
+ "save": MaterialIconAction(icon_name="save", tooltip="Open Export Dialog"),
93
+ "matplotlib": MaterialIconAction(
94
+ icon_name="photo_library", tooltip="Open Matplotlib Plot"
95
+ ),
96
+ "separator_2": SeparatorAction(),
97
+ "drag_mode": MaterialIconAction(
98
+ icon_name="drag_pan", tooltip="Drag Mouse Mode", checkable=True
99
+ ),
100
+ "rectangle_mode": MaterialIconAction(
101
+ icon_name="frame_inspect", tooltip="Rectangle Zoom Mode", checkable=True
102
+ ),
103
+ "auto_range": MaterialIconAction(
104
+ icon_name="open_in_full", tooltip="Autorange Plot"
105
+ ),
106
+ "crosshair": MaterialIconAction(
107
+ icon_name="point_scan", tooltip="Show Crosshair", checkable=True
108
+ ),
109
+ "separator_3": SeparatorAction(),
110
+ "fps_monitor": MaterialIconAction(
111
+ icon_name="speed", tooltip="Show FPS Monitor", checkable=True
112
+ ),
113
+ "axis_settings": MaterialIconAction(
114
+ icon_name="settings", tooltip="Open Configuration Dialog"
115
+ ),
116
+ },
117
+ target_widget=self,
118
+ )
119
+
120
+ self.layout.addWidget(self.toolbar)
121
+ self.layout.addWidget(self.fig)
122
+
123
+ self.waveform = self.fig.multi_waveform() # FIXME config should be injected here
124
+ self.config = config
125
+
126
+ self.create_multi_waveform_controls()
127
+
128
+ self._hook_actions()
129
+ self.waveform.monitor_signal_updated.connect(self.update_controls_limits)
130
+
131
+ def create_multi_waveform_controls(self):
132
+ """
133
+ Create the controls for the multi waveform widget.
134
+ """
135
+ current_path = os.path.dirname(__file__)
136
+ self.controls = UILoader(self).loader(
137
+ os.path.join(current_path, "multi_waveform_controls.ui")
138
+ )
139
+ self.layout.addWidget(self.controls)
140
+
141
+ # Hook default controls properties
142
+ self.controls.checkbox_highlight.setChecked(self.config.highlight_last_curve)
143
+ self.controls.spinbox_opacity.setValue(self.config.opacity)
144
+ self.controls.slider_opacity.setValue(self.config.opacity)
145
+ self.controls.spinbox_max_trace.setValue(self.config.curve_limit)
146
+ self.controls.checkbox_flush_buffer.setChecked(self.config.flush_buffer)
147
+
148
+ # Connect signals
149
+ self.controls.spinbox_max_trace.valueChanged.connect(self.set_curve_limit)
150
+ self.controls.checkbox_flush_buffer.toggled.connect(self.set_buffer_flush)
151
+ self.controls.slider_opacity.valueChanged.connect(self.controls.spinbox_opacity.setValue)
152
+ self.controls.spinbox_opacity.valueChanged.connect(self.controls.slider_opacity.setValue)
153
+ self.controls.slider_opacity.valueChanged.connect(self.set_opacity)
154
+ self.controls.spinbox_opacity.valueChanged.connect(self.set_opacity)
155
+ self.controls.slider_index.valueChanged.connect(self.controls.spinbox_index.setValue)
156
+ self.controls.spinbox_index.valueChanged.connect(self.controls.slider_index.setValue)
157
+ self.controls.slider_index.valueChanged.connect(self.set_curve_highlight)
158
+ self.controls.spinbox_index.valueChanged.connect(self.set_curve_highlight)
159
+ self.controls.checkbox_highlight.toggled.connect(self.set_highlight_last_curve)
160
+
161
+ # Trigger first round of settings
162
+ self.set_curve_limit(self.config.curve_limit)
163
+ self.set_opacity(self.config.opacity)
164
+ self.set_highlight_last_curve(self.config.highlight_last_curve)
165
+
166
+ @Slot()
167
+ def update_controls_limits(self):
168
+ """
169
+ Update the limits of the controls.
170
+ """
171
+ num_curves = len(self.waveform.curves)
172
+ if num_curves == 0:
173
+ num_curves = 1 # Avoid setting max to 0
174
+ current_index = num_curves - 1
175
+ self.controls.slider_index.setMinimum(0)
176
+ self.controls.slider_index.setMaximum(self.waveform.number_of_visible_curves - 1)
177
+ self.controls.spinbox_index.setMaximum(self.waveform.number_of_visible_curves - 1)
178
+ if self.controls.checkbox_highlight.isChecked():
179
+ self.controls.slider_index.setValue(current_index)
180
+ self.controls.spinbox_index.setValue(current_index)
181
+
182
+ def _hook_actions(self):
183
+ self.toolbar.widgets["connect"].action.triggered.connect(self._connect_action)
184
+ # Separator 0
185
+ self.toolbar.widgets["save"].action.triggered.connect(self.export)
186
+ self.toolbar.widgets["matplotlib"].action.triggered.connect(self.export_to_matplotlib)
187
+ self.toolbar.widgets["colormap"].widget.colormap_changed_signal.connect(self.set_colormap)
188
+ # Separator 1
189
+ self.toolbar.widgets["drag_mode"].action.triggered.connect(self.enable_mouse_pan_mode)
190
+ self.toolbar.widgets["rectangle_mode"].action.triggered.connect(
191
+ self.enable_mouse_rectangle_mode
192
+ )
193
+ self.toolbar.widgets["auto_range"].action.triggered.connect(self._auto_range_from_toolbar)
194
+ self.toolbar.widgets["crosshair"].action.triggered.connect(self.waveform.toggle_crosshair)
195
+ # Separator 2
196
+ self.toolbar.widgets["fps_monitor"].action.triggered.connect(self.enable_fps_monitor)
197
+ self.toolbar.widgets["axis_settings"].action.triggered.connect(self.show_axis_settings)
198
+
199
+ ###################################
200
+ # Dialog Windows
201
+ ###################################
202
+ @SafeSlot(popup_error=True)
203
+ def _connect_action(self):
204
+ monitor_combo = self.toolbar.widgets["monitor"].device_combobox
205
+ monitor_name = monitor_combo.currentText()
206
+ self.set_monitor(monitor=monitor_name)
207
+ monitor_combo.setStyleSheet("QComboBox { background-color: " "; }")
208
+
209
+ def show_axis_settings(self):
210
+ dialog = SettingsDialog(
211
+ self,
212
+ settings_widget=AxisSettings(),
213
+ window_title="Axis Settings",
214
+ config=self.waveform._config_dict["axis"],
215
+ )
216
+ dialog.exec()
217
+
218
+ ########################################
219
+ # User Access Methods from MultiWaveform
220
+ ########################################
221
+ @property
222
+ def curves(self) -> list[pg.PlotDataItem]:
223
+ """
224
+ Get the curves of the plot widget as a list
225
+ Returns:
226
+ list: List of curves.
227
+ """
228
+ return list(self.waveform.curves)
229
+
230
+ @curves.setter
231
+ def curves(self, value: list[pg.PlotDataItem]):
232
+ self.waveform.curves = value
233
+
234
+ @SafeSlot(popup_error=True)
235
+ def set_monitor(self, monitor: str) -> None:
236
+ """
237
+ Set the monitor of the plot widget.
238
+
239
+ Args:
240
+ monitor(str): The monitor to set.
241
+ """
242
+ self.waveform.set_monitor(monitor)
243
+ if self.toolbar.widgets["monitor"].device_combobox.currentText() != monitor:
244
+ self.toolbar.widgets["monitor"].device_combobox.setCurrentText(monitor)
245
+ self.toolbar.widgets["monitor"].device_combobox.setStyleSheet(
246
+ "QComboBox { background-color: " "; }"
247
+ )
248
+
249
+ @SafeSlot(int)
250
+ def set_curve_highlight(self, index: int) -> None:
251
+ """
252
+ Set the curve highlight of the plot widget by index
253
+
254
+ Args:
255
+ index(int): The index of the curve to highlight.
256
+ """
257
+ if self.controls.checkbox_highlight.isChecked():
258
+ # If always highlighting the last curve, set index to -1
259
+ self.waveform.set_curve_highlight(-1)
260
+ else:
261
+ self.waveform.set_curve_highlight(index)
262
+
263
+ @SafeSlot(int)
264
+ def set_opacity(self, opacity: int) -> None:
265
+ """
266
+ Set the opacity of the plot widget.
267
+
268
+ Args:
269
+ opacity(int): The opacity to set.
270
+ """
271
+ self.waveform.set_opacity(opacity)
272
+
273
+ @SafeSlot(int)
274
+ def set_curve_limit(self, curve_limit: int) -> None:
275
+ """
276
+ Set the maximum number of traces to display on the plot widget.
277
+
278
+ Args:
279
+ curve_limit(int): The maximum number of traces to display.
280
+ """
281
+ flush_buffer = self.controls.checkbox_flush_buffer.isChecked()
282
+ self.waveform.set_curve_limit(curve_limit, flush_buffer)
283
+ self.update_controls_limits()
284
+
285
+ @SafeSlot(bool)
286
+ def set_buffer_flush(self, flush_buffer: bool) -> None:
287
+ """
288
+ Set the buffer flush property of the plot widget.
289
+
290
+ Args:
291
+ flush_buffer(bool): True to flush the buffer, False to not flush the buffer.
292
+ """
293
+ curve_limit = self.controls.spinbox_max_trace.value()
294
+ self.waveform.set_curve_limit(curve_limit, flush_buffer)
295
+ self.update_controls_limits()
296
+
297
+ @SafeSlot(bool)
298
+ def set_highlight_last_curve(self, enable: bool) -> None:
299
+ """
300
+ Enable or disable highlighting of the last curve.
301
+
302
+ Args:
303
+ enable(bool): True to enable highlighting of the last curve, False to disable.
304
+ """
305
+ self.waveform.config.highlight_last_curve = enable
306
+ if enable:
307
+ self.controls.slider_index.setEnabled(False)
308
+ self.controls.spinbox_index.setEnabled(False)
309
+ self.controls.checkbox_highlight.setChecked(True)
310
+ self.waveform.set_curve_highlight(-1)
311
+ else:
312
+ self.controls.slider_index.setEnabled(True)
313
+ self.controls.spinbox_index.setEnabled(True)
314
+ self.controls.checkbox_highlight.setChecked(False)
315
+ index = self.controls.spinbox_index.value()
316
+ self.waveform.set_curve_highlight(index)
317
+
318
+ @SafeSlot()
319
+ def set_colormap(self, colormap: str) -> None:
320
+ """
321
+ Set the colormap of the plot widget.
322
+
323
+ Args:
324
+ colormap(str): The colormap to set.
325
+ """
326
+ self.waveform.set_colormap(colormap)
327
+
328
+ ###################################
329
+ # User Access Methods from PlotBase
330
+ ###################################
331
+ def set(self, **kwargs):
332
+ """
333
+ Set the properties of the plot widget.
334
+
335
+ Args:
336
+ **kwargs: Keyword arguments for the properties to be set.
337
+
338
+ Possible properties:
339
+ - title: str
340
+ - x_label: str
341
+ - y_label: str
342
+ - x_scale: Literal["linear", "log"]
343
+ - y_scale: Literal["linear", "log"]
344
+ - x_lim: tuple
345
+ - y_lim: tuple
346
+ - legend_label_size: int
347
+ """
348
+ self.waveform.set(**kwargs)
349
+
350
+ def set_title(self, title: str):
351
+ """
352
+ Set the title of the plot widget.
353
+
354
+ Args:
355
+ title(str): The title to set.
356
+ """
357
+ self.waveform.set_title(title)
358
+
359
+ def set_x_label(self, x_label: str):
360
+ """
361
+ Set the x-axis label of the plot widget.
362
+
363
+ Args:
364
+ x_label(str): The x-axis label to set.
365
+ """
366
+ self.waveform.set_x_label(x_label)
367
+
368
+ def set_y_label(self, y_label: str):
369
+ """
370
+ Set the y-axis label of the plot widget.
371
+
372
+ Args:
373
+ y_label(str): The y-axis label to set.
374
+ """
375
+ self.waveform.set_y_label(y_label)
376
+
377
+ def set_x_scale(self, x_scale: Literal["linear", "log"]):
378
+ """
379
+ Set the x-axis scale of the plot widget.
380
+
381
+ Args:
382
+ x_scale(str): The x-axis scale to set.
383
+ """
384
+ self.waveform.set_x_scale(x_scale)
385
+
386
+ def set_y_scale(self, y_scale: Literal["linear", "log"]):
387
+ """
388
+ Set the y-axis scale of the plot widget.
389
+
390
+ Args:
391
+ y_scale(str): The y-axis scale to set.
392
+ """
393
+ self.waveform.set_y_scale(y_scale)
394
+
395
+ def set_x_lim(self, x_lim: tuple):
396
+ """
397
+ Set x-axis limits of the plot widget.
398
+
399
+ Args:
400
+ x_lim(tuple): The x-axis limits to set.
401
+ """
402
+ self.waveform.set_x_lim(x_lim)
403
+
404
+ def set_y_lim(self, y_lim: tuple):
405
+ """
406
+ Set y-axis limits of the plot widget.
407
+
408
+ Args:
409
+ y_lim(tuple): The y-axis limits to set.
410
+ """
411
+ self.waveform.set_y_lim(y_lim)
412
+
413
+ def set_legend_label_size(self, legend_label_size: int):
414
+ """
415
+ Set the legend label size of the plot widget.
416
+
417
+ Args:
418
+ legend_label_size(int): The legend label size to set.
419
+ """
420
+ self.waveform.set_legend_label_size(legend_label_size)
421
+
422
+ def set_auto_range(self, enabled: bool, axis: str = "xy"):
423
+ """
424
+ Set the auto range of the plot widget.
425
+
426
+ Args:
427
+ enabled(bool): True to enable auto range, False to disable.
428
+ axis(str): The axis to set the auto range for. Default is "xy".
429
+ """
430
+ self.waveform.set_auto_range(enabled, axis)
431
+
432
+ def enable_fps_monitor(self, enabled: bool):
433
+ """
434
+ Enable or disable the FPS monitor
435
+
436
+ Args:
437
+ enabled(bool): True to enable the FPS monitor, False to disable.
438
+ """
439
+ self.waveform.enable_fps_monitor(enabled)
440
+ if self.toolbar.widgets["fps_monitor"].action.isChecked() != enabled:
441
+ self.toolbar.widgets["fps_monitor"].action.setChecked(enabled)
442
+
443
+ @SafeSlot()
444
+ def _auto_range_from_toolbar(self):
445
+ """
446
+ Set the auto range of the plot widget from the toolbar.
447
+ """
448
+ self.waveform.set_auto_range(True, "xy")
449
+
450
+ def set_grid(self, x_grid: bool, y_grid: bool):
451
+ """
452
+ Set the grid of the plot widget.
453
+
454
+ Args:
455
+ x_grid(bool): True to enable the x-grid, False to disable.
456
+ y_grid(bool): True to enable the y-grid, False to disable.
457
+ """
458
+ self.waveform.set_grid(x_grid, y_grid)
459
+
460
+ def set_outer_axes(self, show: bool):
461
+ """
462
+ Set the outer axes of the plot widget.
463
+
464
+ Args:
465
+ show(bool): True to show the outer axes, False to hide.
466
+ """
467
+ self.waveform.set_outer_axes(show)
468
+
469
+ def lock_aspect_ratio(self, lock: bool):
470
+ """
471
+ Lock the aspect ratio of the plot widget.
472
+
473
+ Args:
474
+ lock(bool): True to lock the aspect ratio, False to unlock.
475
+ """
476
+ self.waveform.lock_aspect_ratio(lock)
477
+
478
+ @SafeSlot()
479
+ def enable_mouse_rectangle_mode(self):
480
+ """
481
+ Enable the mouse rectangle mode of the plot widget.
482
+ """
483
+ self.toolbar.widgets["rectangle_mode"].action.setChecked(True)
484
+ self.toolbar.widgets["drag_mode"].action.setChecked(False)
485
+ self.waveform.plot_item.getViewBox().setMouseMode(pg.ViewBox.RectMode)
486
+
487
+ @SafeSlot()
488
+ def enable_mouse_pan_mode(self):
489
+ """
490
+ Enable the mouse pan mode of the plot widget.
491
+ """
492
+ self.toolbar.widgets["drag_mode"].action.setChecked(True)
493
+ self.toolbar.widgets["rectangle_mode"].action.setChecked(False)
494
+ self.waveform.plot_item.getViewBox().setMouseMode(pg.ViewBox.PanMode)
495
+
496
+ def export(self):
497
+ """
498
+ Export the plot widget.
499
+ """
500
+ self.waveform.export()
501
+
502
+ def export_to_matplotlib(self):
503
+ """
504
+ Export the plot widget to matplotlib.
505
+ """
506
+ try:
507
+ import matplotlib as mpl
508
+ except ImportError:
509
+ self.warning_util.show_warning(
510
+ title="Matplotlib not installed",
511
+ message="Matplotlib is required for this feature.",
512
+ detailed_text="Please install matplotlib in your Python environment by using 'pip install matplotlib'.",
513
+ )
514
+ return
515
+ self.waveform.export_to_matplotlib()
516
+
517
+ #######################################
518
+ # User Access Methods from BECConnector
519
+ ######################################
520
+ def cleanup(self):
521
+ self.fig.cleanup()
522
+ return super().cleanup()
523
+
524
+
525
+ if __name__ == "__main__": # pragma: no cover
526
+ import sys
527
+
528
+ from qtpy.QtWidgets import QApplication
529
+
530
+ app = QApplication(sys.argv)
531
+ widget = BECMultiWaveformWidget()
532
+ widget.show()
533
+ sys.exit(app.exec())
@@ -0,0 +1,17 @@
1
+ def main(): # pragma: no cover
2
+ from qtpy import PYSIDE6
3
+
4
+ if not PYSIDE6:
5
+ print("PYSIDE6 is not available in the environment. Cannot patch designer.")
6
+ return
7
+ from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
8
+
9
+ from bec_widgets.widgets.multi_waveform.bec_multi_waveform_widget_plugin import (
10
+ BECMultiWaveformWidgetPlugin,
11
+ )
12
+
13
+ QPyDesignerCustomWidgetCollection.addCustomWidget(BECMultiWaveformWidgetPlugin())
14
+
15
+
16
+ if __name__ == "__main__": # pragma: no cover
17
+ main()