bec-widgets 2.6.0__py3-none-any.whl → 2.7.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.
- CHANGELOG.md +38 -0
- PKG-INFO +1 -1
- bec_widgets/cli/client.py +116 -4
- bec_widgets/tests/utils.py +7 -1
- bec_widgets/utils/crosshair.py +35 -11
- bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py +6 -3
- bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py +4 -0
- bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py +20 -2
- bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py +3 -0
- bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py +30 -4
- bec_widgets/widgets/plots/image/image.py +147 -11
- bec_widgets/widgets/plots/image/image_roi_plot.py +37 -0
- bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py +4 -3
- bec_widgets/widgets/plots/toolbar_bundles/mouse_interactions.py +1 -1
- {bec_widgets-2.6.0.dist-info → bec_widgets-2.7.1.dist-info}/METADATA +1 -1
- {bec_widgets-2.6.0.dist-info → bec_widgets-2.7.1.dist-info}/RECORD +20 -19
- pyproject.toml +1 -1
- {bec_widgets-2.6.0.dist-info → bec_widgets-2.7.1.dist-info}/WHEEL +0 -0
- {bec_widgets-2.6.0.dist-info → bec_widgets-2.7.1.dist-info}/entry_points.txt +0 -0
- {bec_widgets-2.6.0.dist-info → bec_widgets-2.7.1.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,6 +1,44 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v2.7.1 (2025-05-26)
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
- **signal-combobox**: Bug fix in signal combobox that crashed upon switching from device to signal
|
9
|
+
input
|
10
|
+
([`1a4eb1d`](https://github.com/bec-project/bec_widgets/commit/1a4eb1db67ff6cfc45ce91cd264ae2818a57230a))
|
11
|
+
|
12
|
+
- **signal-line-edit**: Fix signal_line_edit validity check; closes #610
|
13
|
+
([`ec740d3`](https://github.com/bec-project/bec_widgets/commit/ec740d31fdea561f1ed9274ea79b7be3b6ecba11))
|
14
|
+
|
15
|
+
### Refactoring
|
16
|
+
|
17
|
+
- Add rpc interface to signal_line_edit/combobox; add user access methods
|
18
|
+
([`a8811c9`](https://github.com/bec-project/bec_widgets/commit/a8811c9d914feacf08f2f1f1aaf16302cd320ba3))
|
19
|
+
|
20
|
+
### Testing
|
21
|
+
|
22
|
+
- **input-widgets**: Add e2e tests to test widget inputs with demo config of bec.
|
23
|
+
([`f57950c`](https://github.com/bec-project/bec_widgets/commit/f57950c4e3b0b5eab7bc303eaead89f7e50e2804))
|
24
|
+
|
25
|
+
|
26
|
+
## v2.7.0 (2025-05-26)
|
27
|
+
|
28
|
+
### Bug Fixes
|
29
|
+
|
30
|
+
- **image/image_selecetion**: Toolbar selection tool size adjusted
|
31
|
+
([`e12e9e5`](https://github.com/bec-project/bec_widgets/commit/e12e9e534d6913223b741bff31bed6674ae4c0e6))
|
32
|
+
|
33
|
+
- **plot_base/mouse_interactions.py**: Fixed parent
|
34
|
+
([`66e9445`](https://github.com/bec-project/bec_widgets/commit/66e9445760f2796c008d08feba54c3d48e4a9cfb))
|
35
|
+
|
36
|
+
### Features
|
37
|
+
|
38
|
+
- **image**: Roi plots with crosshair cuts added
|
39
|
+
([`ce88787`](https://github.com/bec-project/bec_widgets/commit/ce88787e881d12384dd3a25b75fadda1f2280c81))
|
40
|
+
|
41
|
+
|
4
42
|
## v2.6.0 (2025-05-26)
|
5
43
|
|
6
44
|
### Bug Fixes
|
PKG-INFO
CHANGED
bec_widgets/cli/client.py
CHANGED
@@ -51,6 +51,8 @@ _Widgets = {
|
|
51
51
|
"RingProgressBar": "RingProgressBar",
|
52
52
|
"ScanControl": "ScanControl",
|
53
53
|
"ScatterWaveform": "ScatterWaveform",
|
54
|
+
"SignalComboBox": "SignalComboBox",
|
55
|
+
"SignalLineEdit": "SignalLineEdit",
|
54
56
|
"StopButton": "StopButton",
|
55
57
|
"TextBox": "TextBox",
|
56
58
|
"VSCodeEditor": "VSCodeEditor",
|
@@ -939,9 +941,22 @@ class DeviceComboBox(RPCBase):
|
|
939
941
|
"""Combobox widget for device input with autocomplete for device names."""
|
940
942
|
|
941
943
|
@rpc_call
|
942
|
-
def
|
944
|
+
def set_device(self, device: "str"):
|
943
945
|
"""
|
944
|
-
|
946
|
+
Set the device.
|
947
|
+
|
948
|
+
Args:
|
949
|
+
device (str): Default name.
|
950
|
+
"""
|
951
|
+
|
952
|
+
@property
|
953
|
+
@rpc_call
|
954
|
+
def devices(self) -> "list[str]":
|
955
|
+
"""
|
956
|
+
Get the list of devices for the applied filters.
|
957
|
+
|
958
|
+
Returns:
|
959
|
+
list[str]: List of devices.
|
945
960
|
"""
|
946
961
|
|
947
962
|
|
@@ -959,9 +974,32 @@ class DeviceLineEdit(RPCBase):
|
|
959
974
|
"""Line edit widget for device input with autocomplete for device names."""
|
960
975
|
|
961
976
|
@rpc_call
|
962
|
-
def
|
977
|
+
def set_device(self, device: "str"):
|
963
978
|
"""
|
964
|
-
|
979
|
+
Set the device.
|
980
|
+
|
981
|
+
Args:
|
982
|
+
device (str): Default name.
|
983
|
+
"""
|
984
|
+
|
985
|
+
@property
|
986
|
+
@rpc_call
|
987
|
+
def devices(self) -> "list[str]":
|
988
|
+
"""
|
989
|
+
Get the list of devices for the applied filters.
|
990
|
+
|
991
|
+
Returns:
|
992
|
+
list[str]: List of devices.
|
993
|
+
"""
|
994
|
+
|
995
|
+
@property
|
996
|
+
@rpc_call
|
997
|
+
def _is_valid_input(self) -> bool:
|
998
|
+
"""
|
999
|
+
Check if the current value is a valid device name.
|
1000
|
+
|
1001
|
+
Returns:
|
1002
|
+
bool: True if the current value is a valid device name, False otherwise.
|
965
1003
|
"""
|
966
1004
|
|
967
1005
|
|
@@ -3347,6 +3385,80 @@ class ScatterWaveform(RPCBase):
|
|
3347
3385
|
"""
|
3348
3386
|
|
3349
3387
|
|
3388
|
+
class SignalComboBox(RPCBase):
|
3389
|
+
"""Line edit widget for device input with autocomplete for device names."""
|
3390
|
+
|
3391
|
+
@rpc_call
|
3392
|
+
def set_signal(self, signal: str):
|
3393
|
+
"""
|
3394
|
+
Set the signal.
|
3395
|
+
|
3396
|
+
Args:
|
3397
|
+
signal (str): signal name.
|
3398
|
+
"""
|
3399
|
+
|
3400
|
+
@rpc_call
|
3401
|
+
def set_device(self, device: str | None):
|
3402
|
+
"""
|
3403
|
+
Set the device. If device is not valid, device will be set to None which happens
|
3404
|
+
|
3405
|
+
Args:
|
3406
|
+
device(str): device name.
|
3407
|
+
"""
|
3408
|
+
|
3409
|
+
@property
|
3410
|
+
@rpc_call
|
3411
|
+
def signals(self) -> list[str]:
|
3412
|
+
"""
|
3413
|
+
Get the list of device signals for the applied filters.
|
3414
|
+
|
3415
|
+
Returns:
|
3416
|
+
list[str]: List of device signals.
|
3417
|
+
"""
|
3418
|
+
|
3419
|
+
|
3420
|
+
class SignalLineEdit(RPCBase):
|
3421
|
+
"""Line edit widget for device input with autocomplete for device names."""
|
3422
|
+
|
3423
|
+
@property
|
3424
|
+
@rpc_call
|
3425
|
+
def _is_valid_input(self) -> bool:
|
3426
|
+
"""
|
3427
|
+
Check if the current value is a valid device name.
|
3428
|
+
|
3429
|
+
Returns:
|
3430
|
+
bool: True if the current value is a valid device name, False otherwise.
|
3431
|
+
"""
|
3432
|
+
|
3433
|
+
@rpc_call
|
3434
|
+
def set_signal(self, signal: str):
|
3435
|
+
"""
|
3436
|
+
Set the signal.
|
3437
|
+
|
3438
|
+
Args:
|
3439
|
+
signal (str): signal name.
|
3440
|
+
"""
|
3441
|
+
|
3442
|
+
@rpc_call
|
3443
|
+
def set_device(self, device: str | None):
|
3444
|
+
"""
|
3445
|
+
Set the device. If device is not valid, device will be set to None which happens
|
3446
|
+
|
3447
|
+
Args:
|
3448
|
+
device(str): device name.
|
3449
|
+
"""
|
3450
|
+
|
3451
|
+
@property
|
3452
|
+
@rpc_call
|
3453
|
+
def signals(self) -> list[str]:
|
3454
|
+
"""
|
3455
|
+
Get the list of device signals for the applied filters.
|
3456
|
+
|
3457
|
+
Returns:
|
3458
|
+
list[str]: List of device signals.
|
3459
|
+
"""
|
3460
|
+
|
3461
|
+
|
3350
3462
|
class StopButton(RPCBase):
|
3351
3463
|
"""A button that stops the current scan."""
|
3352
3464
|
|
bec_widgets/tests/utils.py
CHANGED
@@ -200,7 +200,13 @@ class DMMock:
|
|
200
200
|
self.devices = DeviceContainer()
|
201
201
|
self.enabled_devices = [device for device in self.devices if device.enabled]
|
202
202
|
|
203
|
-
def
|
203
|
+
def add_devices(self, devices: list):
|
204
|
+
"""
|
205
|
+
Add devices to the DeviceContainer.
|
206
|
+
|
207
|
+
Args:
|
208
|
+
devices (list): List of device instances to add.
|
209
|
+
"""
|
204
210
|
for device in devices:
|
205
211
|
self.devices[device.name] = device
|
206
212
|
|
bec_widgets/utils/crosshair.py
CHANGED
@@ -85,7 +85,8 @@ class Crosshair(QObject):
|
|
85
85
|
self.items = []
|
86
86
|
self.marker_moved_1d = {}
|
87
87
|
self.marker_clicked_1d = {}
|
88
|
-
self.
|
88
|
+
self.marker_2d_row = None
|
89
|
+
self.marker_2d_col = None
|
89
90
|
self.update_markers()
|
90
91
|
self.check_log()
|
91
92
|
self.check_derivatives()
|
@@ -195,13 +196,23 @@ class Crosshair(QObject):
|
|
195
196
|
marker_clicked_list.append(marker_clicked)
|
196
197
|
self.marker_clicked_1d[name] = marker_clicked_list
|
197
198
|
elif isinstance(item, pg.ImageItem): # 2D plot
|
198
|
-
if self.
|
199
|
+
if self.marker_2d_row is not None and self.marker_2d_col is not None:
|
199
200
|
continue
|
200
|
-
|
201
|
-
|
201
|
+
# Create horizontal ROI for row highlighting
|
202
|
+
if item.image is None:
|
203
|
+
continue
|
204
|
+
self.marker_2d_row = pg.ROI(
|
205
|
+
[0, 0], size=[item.image.shape[0], 1], pen=pg.mkPen("r", width=2), movable=False
|
206
|
+
)
|
207
|
+
self.marker_2d_row.skip_auto_range = True
|
208
|
+
self.plot_item.addItem(self.marker_2d_row)
|
209
|
+
|
210
|
+
# Create vertical ROI for column highlighting
|
211
|
+
self.marker_2d_col = pg.ROI(
|
212
|
+
[0, 0], size=[1, item.image.shape[1]], pen=pg.mkPen("r", width=2), movable=False
|
202
213
|
)
|
203
|
-
self.
|
204
|
-
self.plot_item.addItem(self.
|
214
|
+
self.marker_2d_col.skip_auto_range = True
|
215
|
+
self.plot_item.addItem(self.marker_2d_col)
|
205
216
|
|
206
217
|
def snap_to_data(
|
207
218
|
self, x: float, y: float
|
@@ -243,6 +254,8 @@ class Crosshair(QObject):
|
|
243
254
|
elif isinstance(item, pg.ImageItem): # 2D plot
|
244
255
|
name = item.config.monitor or str(id(item))
|
245
256
|
image_2d = item.image
|
257
|
+
if image_2d is None:
|
258
|
+
continue
|
246
259
|
# Clip the x and y values to the image dimensions to avoid out of bounds errors
|
247
260
|
y_values[name] = int(np.clip(y, 0, image_2d.shape[1] - 1))
|
248
261
|
x_values[name] = int(np.clip(x, 0, image_2d.shape[0] - 1))
|
@@ -330,7 +343,10 @@ class Crosshair(QObject):
|
|
330
343
|
x, y = x_snap_values[name], y_snap_values[name]
|
331
344
|
if x is None or y is None:
|
332
345
|
continue
|
333
|
-
|
346
|
+
# Set position of horizontal ROI (row)
|
347
|
+
self.marker_2d_row.setPos([0, y])
|
348
|
+
# Set position of vertical ROI (column)
|
349
|
+
self.marker_2d_col.setPos([x, 0])
|
334
350
|
coordinate_to_emit = (name, x, y)
|
335
351
|
self.coordinatesChanged2D.emit(coordinate_to_emit)
|
336
352
|
else:
|
@@ -384,7 +400,10 @@ class Crosshair(QObject):
|
|
384
400
|
x, y = x_snap_values[name], y_snap_values[name]
|
385
401
|
if x is None or y is None:
|
386
402
|
continue
|
387
|
-
|
403
|
+
# Set position of horizontal ROI (row)
|
404
|
+
self.marker_2d_row.setPos([0, y])
|
405
|
+
# Set position of vertical ROI (column)
|
406
|
+
self.marker_2d_col.setPos([x, 0])
|
388
407
|
coordinate_to_emit = (name, x, y)
|
389
408
|
self.coordinatesClicked2D.emit(coordinate_to_emit)
|
390
409
|
else:
|
@@ -428,6 +447,8 @@ class Crosshair(QObject):
|
|
428
447
|
for item in self.items:
|
429
448
|
if isinstance(item, pg.ImageItem):
|
430
449
|
image = item.image
|
450
|
+
if image is None:
|
451
|
+
continue
|
431
452
|
ix = int(np.clip(x, 0, image.shape[0] - 1))
|
432
453
|
iy = int(np.clip(y, 0, image.shape[1] - 1))
|
433
454
|
intensity = image[ix, iy]
|
@@ -450,9 +471,12 @@ class Crosshair(QObject):
|
|
450
471
|
self.clear_markers()
|
451
472
|
|
452
473
|
def cleanup(self):
|
453
|
-
if self.
|
454
|
-
self.plot_item.removeItem(self.
|
455
|
-
self.
|
474
|
+
if self.marker_2d_row is not None:
|
475
|
+
self.plot_item.removeItem(self.marker_2d_row)
|
476
|
+
self.marker_2d_row = None
|
477
|
+
if self.marker_2d_col is not None:
|
478
|
+
self.plot_item.removeItem(self.marker_2d_col)
|
479
|
+
self.marker_2d_col = None
|
456
480
|
self.plot_item.removeItem(self.v_line)
|
457
481
|
self.plot_item.removeItem(self.h_line)
|
458
482
|
self.plot_item.removeItem(self.coord_label)
|
@@ -79,7 +79,7 @@ class DeviceSignalInputBase(BECWidget):
|
|
79
79
|
@Slot(str)
|
80
80
|
def set_device(self, device: str | None):
|
81
81
|
"""
|
82
|
-
Set the device. If device is not valid, device will be set to None which
|
82
|
+
Set the device. If device is not valid, device will be set to None which happens
|
83
83
|
|
84
84
|
Args:
|
85
85
|
device(str): device name.
|
@@ -112,9 +112,12 @@ class DeviceSignalInputBase(BECWidget):
|
|
112
112
|
# See above convention for Signals and ComputedSignals
|
113
113
|
if isinstance(device, Signal):
|
114
114
|
self._signals = [self._device]
|
115
|
-
|
115
|
+
self._hinted_signals = [self._device]
|
116
|
+
self._normal_signals = []
|
117
|
+
self._config_signals = []
|
118
|
+
FilterIO.set_selection(widget=self, selection=self._signals)
|
116
119
|
return
|
117
|
-
device_info = device._info
|
120
|
+
device_info = device._info.get("signals", {})
|
118
121
|
|
119
122
|
def _update(kind: Kind):
|
120
123
|
return [
|
@@ -22,10 +22,14 @@ class DeviceComboBox(DeviceInputBase, QComboBox):
|
|
22
22
|
config: Device input configuration.
|
23
23
|
gui_id: GUI ID.
|
24
24
|
device_filter: Device filter, name of the device class from BECDeviceFilter and BECReadoutPriority. Check DeviceInputBase for more details.
|
25
|
+
readout_priority_filter: Readout priority filter, name of the readout priority class from BECDeviceFilter and BECReadoutPriority. Check DeviceInputBase for more details.
|
26
|
+
available_devices: List of available devices, if passed, it sets apply filters to false and device/readout priority filters will not be applied.
|
25
27
|
default: Default device name.
|
26
28
|
arg_name: Argument name, can be used for the other widgets which has to call some other function in bec using correct argument names.
|
27
29
|
"""
|
28
30
|
|
31
|
+
USER_ACCESS = ["set_device", "devices"]
|
32
|
+
|
29
33
|
ICON_NAME = "list_alt"
|
30
34
|
PLUGIN = True
|
31
35
|
|
@@ -24,11 +24,15 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
|
|
24
24
|
client: BEC client object.
|
25
25
|
config: Device input configuration.
|
26
26
|
gui_id: GUI ID.
|
27
|
-
device_filter: Device filter, name of the device class from BECDeviceFilter and
|
27
|
+
device_filter: Device filter, name of the device class from BECDeviceFilter and BECReadoutPriority. Check DeviceInputBase for more details.
|
28
|
+
readout_priority_filter: Readout priority filter, name of the readout priority class from BECDeviceFilter and BECReadoutPriority. Check DeviceInputBase for more details.
|
29
|
+
available_devices: List of available devices, if passed, it sets apply filters to false and device/readout priority filters will not be applied.
|
28
30
|
default: Default device name.
|
29
31
|
arg_name: Argument name, can be used for the other widgets which has to call some other function in bec using correct argument names.
|
30
32
|
"""
|
31
33
|
|
34
|
+
USER_ACCESS = ["set_device", "devices", "_is_valid_input"]
|
35
|
+
|
32
36
|
device_selected = Signal(str)
|
33
37
|
device_config_update = Signal()
|
34
38
|
|
@@ -51,7 +55,7 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
|
|
51
55
|
**kwargs,
|
52
56
|
):
|
53
57
|
self._callback_id = None
|
54
|
-
self.
|
58
|
+
self.__is_valid_input = False
|
55
59
|
self._accent_colors = get_accent_colors()
|
56
60
|
super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
|
57
61
|
self.completer = QCompleter(self)
|
@@ -95,6 +99,20 @@ class DeviceLineEdit(DeviceInputBase, QLineEdit):
|
|
95
99
|
self.textChanged.connect(self.check_validity)
|
96
100
|
self.check_validity(self.text())
|
97
101
|
|
102
|
+
@property
|
103
|
+
def _is_valid_input(self) -> bool:
|
104
|
+
"""
|
105
|
+
Check if the current value is a valid device name.
|
106
|
+
|
107
|
+
Returns:
|
108
|
+
bool: True if the current value is a valid device name, False otherwise.
|
109
|
+
"""
|
110
|
+
return self.__is_valid_input
|
111
|
+
|
112
|
+
@_is_valid_input.setter
|
113
|
+
def _is_valid_input(self, value: bool) -> None:
|
114
|
+
self.__is_valid_input = value
|
115
|
+
|
98
116
|
def on_device_update(self, action: str, content: dict) -> None:
|
99
117
|
"""
|
100
118
|
Callback for device update events. Triggers the device_update signal.
|
@@ -23,8 +23,11 @@ class SignalComboBox(DeviceSignalInputBase, QComboBox):
|
|
23
23
|
arg_name: Argument name, can be used for the other widgets which has to call some other function in bec using correct argument names.
|
24
24
|
"""
|
25
25
|
|
26
|
+
USER_ACCESS = ["set_signal", "set_device", "signals"]
|
27
|
+
|
26
28
|
ICON_NAME = "list_alt"
|
27
29
|
PLUGIN = True
|
30
|
+
RPC = True
|
28
31
|
|
29
32
|
device_signal_changed = Signal(str)
|
30
33
|
|
@@ -24,9 +24,12 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
|
|
24
24
|
arg_name: Argument name, can be used for the other widgets which has to call some other function in bec using correct argument names.
|
25
25
|
"""
|
26
26
|
|
27
|
+
USER_ACCESS = ["_is_valid_input", "set_signal", "set_device", "signals"]
|
28
|
+
|
27
29
|
device_signal_changed = Signal(str)
|
28
30
|
|
29
31
|
PLUGIN = True
|
32
|
+
RPC = True
|
30
33
|
ICON_NAME = "vital_signs"
|
31
34
|
|
32
35
|
def __init__(
|
@@ -41,7 +44,7 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
|
|
41
44
|
arg_name: str | None = None,
|
42
45
|
**kwargs,
|
43
46
|
):
|
44
|
-
self.
|
47
|
+
self.__is_valid_input = False
|
45
48
|
super().__init__(parent=parent, client=client, gui_id=gui_id, config=config, **kwargs)
|
46
49
|
self._accent_colors = get_accent_colors()
|
47
50
|
self.completer = QCompleter(self)
|
@@ -65,8 +68,22 @@ class SignalLineEdit(DeviceSignalInputBase, QLineEdit):
|
|
65
68
|
self.set_device(device)
|
66
69
|
if default is not None:
|
67
70
|
self.set_signal(default)
|
68
|
-
self.textChanged.connect(self.
|
69
|
-
self.
|
71
|
+
self.textChanged.connect(self.check_validity)
|
72
|
+
self.check_validity(self.text())
|
73
|
+
|
74
|
+
@property
|
75
|
+
def _is_valid_input(self) -> bool:
|
76
|
+
"""
|
77
|
+
Check if the current value is a valid device name.
|
78
|
+
|
79
|
+
Returns:
|
80
|
+
bool: True if the current value is a valid device name, False otherwise.
|
81
|
+
"""
|
82
|
+
return self.__is_valid_input
|
83
|
+
|
84
|
+
@_is_valid_input.setter
|
85
|
+
def _is_valid_input(self, value: bool) -> None:
|
86
|
+
self.__is_valid_input = value
|
70
87
|
|
71
88
|
def get_current_device(self) -> object:
|
72
89
|
"""
|
@@ -131,6 +148,9 @@ if __name__ == "__main__": # pragma: no cover
|
|
131
148
|
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
132
149
|
|
133
150
|
from bec_widgets.utils.colors import set_theme
|
151
|
+
from bec_widgets.widgets.control.device_input.device_combobox.device_combobox import (
|
152
|
+
DeviceComboBox,
|
153
|
+
)
|
134
154
|
|
135
155
|
app = QApplication([])
|
136
156
|
set_theme("dark")
|
@@ -138,6 +158,12 @@ if __name__ == "__main__": # pragma: no cover
|
|
138
158
|
widget.setFixedSize(200, 200)
|
139
159
|
layout = QVBoxLayout()
|
140
160
|
widget.setLayout(layout)
|
141
|
-
|
161
|
+
device_line_edit = DeviceComboBox()
|
162
|
+
device_line_edit.filter_to_positioner = True
|
163
|
+
signal_line_edit = SignalLineEdit()
|
164
|
+
device_line_edit.device_selected.connect(signal_line_edit.set_device)
|
165
|
+
|
166
|
+
layout.addWidget(device_line_edit)
|
167
|
+
layout.addWidget(signal_line_edit)
|
142
168
|
widget.show()
|
143
169
|
app.exec_()
|
@@ -13,8 +13,10 @@ from qtpy.QtWidgets import QDialog, QVBoxLayout, QWidget
|
|
13
13
|
from bec_widgets.utils import ConnectionConfig
|
14
14
|
from bec_widgets.utils.colors import Colors
|
15
15
|
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot
|
16
|
+
from bec_widgets.utils.side_panel import SidePanel
|
16
17
|
from bec_widgets.utils.toolbar import MaterialIconAction, SwitchableToolBarAction
|
17
18
|
from bec_widgets.widgets.plots.image.image_item import ImageItem
|
19
|
+
from bec_widgets.widgets.plots.image.image_roi_plot import ImageROIPlot
|
18
20
|
from bec_widgets.widgets.plots.image.setting_widgets.image_roi_tree import ROIPropertyTree
|
19
21
|
from bec_widgets.widgets.plots.image.toolbar_bundles.image_selection import (
|
20
22
|
MonitorSelectionToolbarBundle,
|
@@ -123,6 +125,7 @@ class Image(PlotBase):
|
|
123
125
|
"rois",
|
124
126
|
]
|
125
127
|
sync_colorbar_with_autorange = Signal()
|
128
|
+
image_updated = Signal()
|
126
129
|
|
127
130
|
def __init__(
|
128
131
|
self,
|
@@ -139,6 +142,8 @@ class Image(PlotBase):
|
|
139
142
|
self._color_bar = None
|
140
143
|
self._main_image = ImageItem()
|
141
144
|
self.roi_controller = ROIController(colormap="viridis")
|
145
|
+
self.x_roi = None
|
146
|
+
self.y_roi = None
|
142
147
|
super().__init__(
|
143
148
|
parent=parent, config=config, client=client, gui_id=gui_id, popups=popups, **kwargs
|
144
149
|
)
|
@@ -150,24 +155,60 @@ class Image(PlotBase):
|
|
150
155
|
# Default Color map to plasma
|
151
156
|
self.color_map = "plasma"
|
152
157
|
|
158
|
+
# Initialize ROI plots and side panels
|
159
|
+
self._add_roi_plots()
|
160
|
+
|
153
161
|
self.roi_manager_dialog = None
|
154
162
|
|
163
|
+
# Refresh theme for ROI plots
|
164
|
+
self._update_theme()
|
165
|
+
|
155
166
|
################################################################################
|
156
167
|
# Widget Specific GUI interactions
|
157
168
|
################################################################################
|
169
|
+
def apply_theme(self, theme: str):
|
170
|
+
super().apply_theme(theme)
|
171
|
+
if self.x_roi is not None and self.y_roi is not None:
|
172
|
+
self.x_roi.apply_theme(theme)
|
173
|
+
self.y_roi.apply_theme(theme)
|
174
|
+
|
158
175
|
def _init_toolbar(self):
|
159
176
|
|
160
177
|
# add to the first position
|
161
178
|
self.selection_bundle = MonitorSelectionToolbarBundle(
|
162
179
|
bundle_id="selection", target_widget=self
|
163
180
|
)
|
164
|
-
self.toolbar.add_bundle(self.selection_bundle, self)
|
181
|
+
self.toolbar.add_bundle(bundle=self.selection_bundle, target_widget=self)
|
165
182
|
|
166
183
|
super()._init_toolbar()
|
167
184
|
|
168
185
|
# Image specific changes to PlotBase toolbar
|
169
186
|
self.toolbar.widgets["reset_legend"].action.setVisible(False)
|
170
187
|
|
188
|
+
# ROI Bundle replacement with switchable crosshair
|
189
|
+
self.toolbar.remove_bundle("roi")
|
190
|
+
crosshair = MaterialIconAction(
|
191
|
+
icon_name="point_scan", tooltip="Show Crosshair", checkable=True
|
192
|
+
)
|
193
|
+
crosshair_roi = MaterialIconAction(
|
194
|
+
icon_name="my_location",
|
195
|
+
tooltip="Show Crosshair with ROI plots",
|
196
|
+
checkable=True,
|
197
|
+
parent=self,
|
198
|
+
)
|
199
|
+
crosshair_roi.action.toggled.connect(self.toggle_roi_panels)
|
200
|
+
crosshair.action.toggled.connect(self.toggle_crosshair)
|
201
|
+
switch_crosshair = SwitchableToolBarAction(
|
202
|
+
actions={"crosshair_simple": crosshair, "crosshair_roi": crosshair_roi},
|
203
|
+
initial_action="crosshair_simple",
|
204
|
+
tooltip="Crosshair",
|
205
|
+
checkable=True,
|
206
|
+
parent=self,
|
207
|
+
)
|
208
|
+
self.toolbar.add_action(
|
209
|
+
action_id="switch_crosshair", action=switch_crosshair, target_widget=self
|
210
|
+
)
|
211
|
+
|
171
212
|
# Lock aspect ratio button
|
172
213
|
self.lock_aspect_ratio_action = MaterialIconAction(
|
173
214
|
icon_name="aspect_ratio", tooltip="Lock Aspect Ratio", checkable=True, parent=self
|
@@ -216,11 +257,8 @@ class Image(PlotBase):
|
|
216
257
|
parent=self,
|
217
258
|
)
|
218
259
|
|
219
|
-
self.toolbar.
|
220
|
-
|
221
|
-
action_id="autorange_image",
|
222
|
-
action=self.autorange_switch,
|
223
|
-
target_widget=self,
|
260
|
+
self.toolbar.add_action(
|
261
|
+
action_id="autorange_image", action=self.autorange_switch, target_widget=self
|
224
262
|
)
|
225
263
|
|
226
264
|
self.autorange_mean_action.action.toggled.connect(
|
@@ -252,11 +290,8 @@ class Image(PlotBase):
|
|
252
290
|
parent=self,
|
253
291
|
)
|
254
292
|
|
255
|
-
self.toolbar.
|
256
|
-
|
257
|
-
action_id="switch_colorbar",
|
258
|
-
action=self.colorbar_switch,
|
259
|
-
target_widget=self,
|
293
|
+
self.toolbar.add_action(
|
294
|
+
action_id="switch_colorbar", action=self.colorbar_switch, target_widget=self
|
260
295
|
)
|
261
296
|
|
262
297
|
self.simple_colorbar_action.action.toggled.connect(
|
@@ -430,6 +465,101 @@ class Image(PlotBase):
|
|
430
465
|
else:
|
431
466
|
raise ValueError("roi must be an int index or str name")
|
432
467
|
|
468
|
+
def _add_roi_plots(self):
|
469
|
+
"""
|
470
|
+
Initialize the ROI plots and side panels.
|
471
|
+
"""
|
472
|
+
# Create ROI plot widgets
|
473
|
+
self.x_roi = ImageROIPlot(parent=self)
|
474
|
+
self.y_roi = ImageROIPlot(parent=self)
|
475
|
+
self.x_roi.apply_theme("dark")
|
476
|
+
self.y_roi.apply_theme("dark")
|
477
|
+
|
478
|
+
# Set titles for the plots
|
479
|
+
self.x_roi.plot_item.setTitle("X ROI")
|
480
|
+
self.y_roi.plot_item.setTitle("Y ROI")
|
481
|
+
|
482
|
+
# Create side panels
|
483
|
+
self.side_panel_x = SidePanel(
|
484
|
+
parent=self, orientation="bottom", panel_max_width=200, show_toolbar=False
|
485
|
+
)
|
486
|
+
self.side_panel_y = SidePanel(
|
487
|
+
parent=self, orientation="left", panel_max_width=200, show_toolbar=False
|
488
|
+
)
|
489
|
+
|
490
|
+
# Add ROI plots to side panels
|
491
|
+
self.x_panel_index = self.side_panel_x.add_menu(widget=self.x_roi)
|
492
|
+
self.y_panel_index = self.side_panel_y.add_menu(widget=self.y_roi)
|
493
|
+
|
494
|
+
# # Add side panels to the layout
|
495
|
+
self.layout_manager.add_widget_relative(
|
496
|
+
self.side_panel_x, self.round_plot_widget, position="bottom", shift_direction="down"
|
497
|
+
)
|
498
|
+
self.layout_manager.add_widget_relative(
|
499
|
+
self.side_panel_y, self.round_plot_widget, position="left", shift_direction="right"
|
500
|
+
)
|
501
|
+
|
502
|
+
def toggle_roi_panels(self, checked: bool):
|
503
|
+
"""
|
504
|
+
Show or hide the ROI panels based on the test action toggle state.
|
505
|
+
|
506
|
+
Args:
|
507
|
+
checked (bool): Whether the test action is checked.
|
508
|
+
"""
|
509
|
+
if checked:
|
510
|
+
# Show the ROI panels
|
511
|
+
self.hook_crosshair()
|
512
|
+
self.side_panel_x.show_panel(self.x_panel_index)
|
513
|
+
self.side_panel_y.show_panel(self.y_panel_index)
|
514
|
+
self.crosshair.coordinatesChanged2D.connect(self.update_image_slices)
|
515
|
+
self.image_updated.connect(self.update_image_slices)
|
516
|
+
else:
|
517
|
+
self.unhook_crosshair()
|
518
|
+
# Hide the ROI panels
|
519
|
+
self.side_panel_x.hide_panel()
|
520
|
+
self.side_panel_y.hide_panel()
|
521
|
+
self.image_updated.disconnect(self.update_image_slices)
|
522
|
+
|
523
|
+
@SafeSlot()
|
524
|
+
def update_image_slices(self, coordinates: tuple[int, int, int] = None):
|
525
|
+
"""
|
526
|
+
Update the image slices based on the crosshair position.
|
527
|
+
|
528
|
+
Args:
|
529
|
+
coordinates(tuple): The coordinates of the crosshair.
|
530
|
+
"""
|
531
|
+
if coordinates is None:
|
532
|
+
# Try to get coordinates from crosshair position (like in crosshair mouse_moved)
|
533
|
+
if (
|
534
|
+
hasattr(self, "crosshair")
|
535
|
+
and hasattr(self.crosshair, "v_line")
|
536
|
+
and hasattr(self.crosshair, "h_line")
|
537
|
+
):
|
538
|
+
x = int(round(self.crosshair.v_line.value()))
|
539
|
+
y = int(round(self.crosshair.h_line.value()))
|
540
|
+
else:
|
541
|
+
return
|
542
|
+
else:
|
543
|
+
x = coordinates[1]
|
544
|
+
y = coordinates[2]
|
545
|
+
image = self._main_image.image
|
546
|
+
if image is None:
|
547
|
+
return
|
548
|
+
max_row, max_col = image.shape[0] - 1, image.shape[1] - 1
|
549
|
+
row, col = x, y
|
550
|
+
if not (0 <= row <= max_row and 0 <= col <= max_col):
|
551
|
+
return
|
552
|
+
# Horizontal slice
|
553
|
+
h_slice = image[:, col]
|
554
|
+
x_axis = np.arange(h_slice.shape[0])
|
555
|
+
self.x_roi.plot_item.clear()
|
556
|
+
self.x_roi.plot_item.plot(x_axis, h_slice, pen=pg.mkPen(self.x_roi.curve_color, width=3))
|
557
|
+
# Vertical slice
|
558
|
+
v_slice = image[row, :]
|
559
|
+
y_axis = np.arange(v_slice.shape[0])
|
560
|
+
self.y_roi.plot_item.clear()
|
561
|
+
self.y_roi.plot_item.plot(v_slice, y_axis, pen=pg.mkPen(self.y_roi.curve_color, width=3))
|
562
|
+
|
433
563
|
################################################################################
|
434
564
|
# Widget Specific Properties
|
435
565
|
################################################################################
|
@@ -984,6 +1114,7 @@ class Image(PlotBase):
|
|
984
1114
|
self._main_image.set_data(image_buffer)
|
985
1115
|
if self._color_bar is not None:
|
986
1116
|
self._color_bar.blockSignals(False)
|
1117
|
+
self.image_updated.emit()
|
987
1118
|
|
988
1119
|
def adjust_image_buffer(self, image: ImageItem, new_data: np.ndarray) -> np.ndarray:
|
989
1120
|
"""
|
@@ -1035,6 +1166,7 @@ class Image(PlotBase):
|
|
1035
1166
|
self._main_image.set_data(data)
|
1036
1167
|
if self._color_bar is not None:
|
1037
1168
|
self._color_bar.blockSignals(False)
|
1169
|
+
self.image_updated.emit()
|
1038
1170
|
|
1039
1171
|
################################################################################
|
1040
1172
|
# Clean up
|
@@ -1090,6 +1222,10 @@ class Image(PlotBase):
|
|
1090
1222
|
self.toolbar.widgets["monitor"].widget.close()
|
1091
1223
|
self.toolbar.widgets["monitor"].widget.deleteLater()
|
1092
1224
|
|
1225
|
+
# ROI plots cleanup
|
1226
|
+
self.x_roi.cleanup_pyqtgraph()
|
1227
|
+
self.y_roi.cleanup_pyqtgraph()
|
1228
|
+
|
1093
1229
|
super().cleanup()
|
1094
1230
|
|
1095
1231
|
|
@@ -0,0 +1,37 @@
|
|
1
|
+
import pyqtgraph as pg
|
2
|
+
|
3
|
+
from bec_widgets.utils.round_frame import RoundedFrame
|
4
|
+
from bec_widgets.widgets.plots.plot_base import BECViewBox
|
5
|
+
|
6
|
+
|
7
|
+
class ImageROIPlot(RoundedFrame):
|
8
|
+
"""
|
9
|
+
A widget for displaying an image with a region of interest (ROI) overlay.
|
10
|
+
"""
|
11
|
+
|
12
|
+
def __init__(self, parent=None):
|
13
|
+
super().__init__(parent=parent)
|
14
|
+
|
15
|
+
self.content_widget = pg.GraphicsLayoutWidget(self)
|
16
|
+
self.layout.addWidget(self.content_widget)
|
17
|
+
self.plot_item = pg.PlotItem(viewBox=BECViewBox(enableMenu=True))
|
18
|
+
self.content_widget.addItem(self.plot_item)
|
19
|
+
self.curve_color = "w"
|
20
|
+
|
21
|
+
self.apply_plot_widget_style()
|
22
|
+
|
23
|
+
def apply_theme(self, theme: str):
|
24
|
+
if theme == "dark":
|
25
|
+
self.curve_color = "w"
|
26
|
+
else:
|
27
|
+
self.curve_color = "k"
|
28
|
+
for curve in self.plot_item.curves:
|
29
|
+
curve.setPen(pg.mkPen(self.curve_color, width=3))
|
30
|
+
super().apply_theme(theme)
|
31
|
+
|
32
|
+
def cleanup_pyqtgraph(self):
|
33
|
+
"""Cleanup pyqtgraph items."""
|
34
|
+
self.plot_item.vb.menu.close()
|
35
|
+
self.plot_item.vb.menu.deleteLater()
|
36
|
+
self.plot_item.ctrlMenu.close()
|
37
|
+
self.plot_item.ctrlMenu.deleteLater()
|
@@ -35,19 +35,20 @@ class MonitorSelectionToolbarBundle(ToolbarBundle):
|
|
35
35
|
self.device_combo_box.addItem("", None)
|
36
36
|
self.device_combo_box.setCurrentText("")
|
37
37
|
self.device_combo_box.setToolTip("Select Device")
|
38
|
+
self.device_combo_box.setFixedWidth(150)
|
38
39
|
self.device_combo_box.setItemDelegate(NoCheckDelegate(self.device_combo_box))
|
39
40
|
|
40
|
-
self.add_action("monitor", WidgetAction(widget=self.device_combo_box, adjust_size=
|
41
|
+
self.add_action("monitor", WidgetAction(widget=self.device_combo_box, adjust_size=False))
|
41
42
|
|
42
43
|
# 2) Dimension combo box
|
43
44
|
self.dim_combo_box = QComboBox(parent=self.target_widget)
|
44
45
|
self.dim_combo_box.addItems(["auto", "1d", "2d"])
|
45
46
|
self.dim_combo_box.setCurrentText("auto")
|
46
47
|
self.dim_combo_box.setToolTip("Monitor Dimension")
|
47
|
-
self.dim_combo_box.setFixedWidth(
|
48
|
+
self.dim_combo_box.setFixedWidth(100)
|
48
49
|
self.dim_combo_box.setItemDelegate(NoCheckDelegate(self.dim_combo_box))
|
49
50
|
|
50
|
-
self.add_action("dim_combo", WidgetAction(widget=self.dim_combo_box, adjust_size=
|
51
|
+
self.add_action("dim_combo", WidgetAction(widget=self.dim_combo_box, adjust_size=False))
|
51
52
|
|
52
53
|
# Connect slots, a device will be connected upon change of any combobox
|
53
54
|
self.device_combo_box.currentTextChanged.connect(lambda: self.connect_monitor())
|
@@ -2,11 +2,11 @@
|
|
2
2
|
.gitlab-ci.yml,sha256=1nMYldzVk0tFkBWYTcUjumOrdSADASheWOAc0kOFDYs,9509
|
3
3
|
.pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
|
4
4
|
.readthedocs.yaml,sha256=ivqg3HTaOxNbEW3bzWh9MXAkrekuGoNdj0Mj3SdRYuw,639
|
5
|
-
CHANGELOG.md,sha256=
|
5
|
+
CHANGELOG.md,sha256=6YbGceWS4rhFIeqFqswxqovoHKYmVEiYv9MUjt9L_OI,287860
|
6
6
|
LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=Y_57lRMl_nuLmuqg18CxTycbI32aOzdupElg65WqfSQ,1273
|
8
8
|
README.md,sha256=oY5Jc1uXehRASuwUJ0umin2vfkFh7tHF-LLruHTaQx0,3560
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=g_0rYxfWFe_V6RoaJwQtEAEz8MlETNPBzBRvlywaFf8,2902
|
10
10
|
.git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
|
11
11
|
.github/pull_request_template.md,sha256=F_cJXzooWMFgMGtLK-7KeGcQt0B4AYFse5oN0zQ9p6g,801
|
12
12
|
.github/ISSUE_TEMPLATE/bug_report.yml,sha256=WdRnt7HGxvsIBLzhkaOWNfg8IJQYa_oV9_F08Ym6znQ,1081
|
@@ -35,7 +35,7 @@ bec_widgets/assets/app_icons/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqg
|
|
35
35
|
bec_widgets/assets/app_icons/ui_loader_tile.png,sha256=qSK3XHqvnAVGV9Q0ulORcGFbXJ9LDq2uz8l9uTtMsNk,1812476
|
36
36
|
bec_widgets/assets/app_icons/widget_launch_tile.png,sha256=bWsICHFfSe9-ESUj3AwlE95dDOea-f6M-s9fBapsxB4,2252911
|
37
37
|
bec_widgets/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
-
bec_widgets/cli/client.py,sha256=
|
38
|
+
bec_widgets/cli/client.py,sha256=GOlZajpUb1yMhAJgpsw8kjMFYIudA83l4jN7-XMSsvA,93483
|
39
39
|
bec_widgets/cli/client_utils.py,sha256=F2hyt--jL53bN8NoWifNUMqwwx5FbpS6I1apERdTRzM,18114
|
40
40
|
bec_widgets/cli/generate_cli.py,sha256=xcPNyJoa3IjddX1yEDY45tT-Cs4jO5cQLUmcEubKs44,10976
|
41
41
|
bec_widgets/cli/server.py,sha256=bhI5qj5vhg3qy4tkL1R2Bk_wcf-gjprTIAbVFH6BKXQ,5695
|
@@ -58,7 +58,7 @@ bec_widgets/examples/plugin_example_pyside/tictactoe.py,sha256=s3rCurXloVcmMdzZi
|
|
58
58
|
bec_widgets/examples/plugin_example_pyside/tictactoeplugin.py,sha256=MFMwONn4EZ3V8DboEG4I3BXpURE9JDbKB7XTzzfZl5w,1978
|
59
59
|
bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py,sha256=SiJaoX3OYA8YMkSwU1d7KEfSUjQQUsQgpRAxSSlr8oQ,2376
|
60
60
|
bec_widgets/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
|
-
bec_widgets/tests/utils.py,sha256
|
61
|
+
bec_widgets/tests/utils.py,sha256=DSzi6Z70fospjfyx0Uz5bWIDwaAzKbzcHfWPW0YyxzQ,7102
|
62
62
|
bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
|
63
63
|
bec_widgets/utils/bec_connector.py,sha256=ATOSyZqryn1QHPc7aotiDnUtzFhlj_gmcukMT_pqjHQ,19272
|
64
64
|
bec_widgets/utils/bec_designer.py,sha256=ehNl_i743rijmhPiIGNd1bihE7-l4oJzTVoa4yjPjls,5426
|
@@ -71,7 +71,7 @@ bec_widgets/utils/collapsible_panel_manager.py,sha256=tvv77-9YTfYpsU6M_Le3bHR6wt
|
|
71
71
|
bec_widgets/utils/colors.py,sha256=4Oms3kcstf7-WddGMB2TZXPqJwFMGVjFyBO8tHZHnxk,18308
|
72
72
|
bec_widgets/utils/compact_popup.py,sha256=xVK_lQqL5Hy1ZnUzHXB8GU-Ru-mXevKcdM8ync3ssiA,10269
|
73
73
|
bec_widgets/utils/container_utils.py,sha256=J8YXombOlAPa3M8NGZdhntp2NirBu4raDEQZOgP4elM,3791
|
74
|
-
bec_widgets/utils/crosshair.py,sha256=
|
74
|
+
bec_widgets/utils/crosshair.py,sha256=zWz4rkVD_HQYWhYzX8asjjb1z_G0V3QqyrOXx6f4xXI,20106
|
75
75
|
bec_widgets/utils/entry_validator.py,sha256=lwT8HP0RDG1FXENIeZ3IDEF2DQmD8KXGkRxPoMXbryk,1817
|
76
76
|
bec_widgets/utils/error_popups.py,sha256=UBAmD1YlAgKodpihudyf0VWtI59KGFiLgnjiKmKGjgk,13254
|
77
77
|
bec_widgets/utils/expandable_frame.py,sha256=VV4mgwz4lXbO3r-dNCX2QFUguwWCCXSUkXyjDSTJHbU,2345
|
@@ -177,14 +177,14 @@ bec_widgets/widgets/control/device_control/positioner_group/register_positioner_
|
|
177
177
|
bec_widgets/widgets/control/device_input/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
178
178
|
bec_widgets/widgets/control/device_input/base_classes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
179
179
|
bec_widgets/widgets/control/device_input/base_classes/device_input_base.py,sha256=r4DwWQz2wwNQ3Uswzdy12MGycV7pFrE_Zv4h_2G5IRA,15915
|
180
|
-
bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py,sha256=
|
180
|
+
bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.py,sha256=oylgVQ2XyN7CWrI_Aj4xtKT5tac41JRpGvccaY0SUHw,9271
|
181
181
|
bec_widgets/widgets/control/device_input/device_combobox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
182
182
|
bec_widgets/widgets/control/device_input/device_combobox/device_combo_box.pyproject,sha256=wI2eXR5ky_IM9-BCHJnH_9CEqYcZwIuLcgitSEr8OJU,40
|
183
183
|
bec_widgets/widgets/control/device_input/device_combobox/device_combo_box_plugin.py,sha256=E8LD9T4O2w621q25uHqBqZLDiQ6zpMR25ZDuf51jrPw,1434
|
184
|
-
bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py,sha256=
|
184
|
+
bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py,sha256=babUAPI8St58FV13b4RZJ10DXcj-2mlYcNKKsdpB7Hs,6507
|
185
185
|
bec_widgets/widgets/control/device_input/device_combobox/register_device_combo_box.py,sha256=elw4M4xfIFWe8C0MkdqqqyfnyOVrdl0g0j6bqwOU1GE,526
|
186
186
|
bec_widgets/widgets/control/device_input/device_line_edit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
187
|
-
bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py,sha256=
|
187
|
+
bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py,sha256=k87NtUD2TUB4c6-Ks-eZgafWbjTwbk0RKiqf9-OkjMk,7415
|
188
188
|
bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.pyproject,sha256=tqAYXRbxsHR41MwqmAxvfq1CFeZ1IRv84whUG67HjjE,41
|
189
189
|
bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit_plugin.py,sha256=LoG1VyO21pZ9dbnDVU03xzqgP8P1oEmdeotlkYs_pE8,1466
|
190
190
|
bec_widgets/widgets/control/device_input/device_line_edit/register_device_line_edit.py,sha256=NTB3HghW5S7NvUlPe_k_uFYQLWPYgjgln2bAYipfkpM,527
|
@@ -192,10 +192,10 @@ bec_widgets/widgets/control/device_input/signal_combobox/__init__.py,sha256=47DE
|
|
192
192
|
bec_widgets/widgets/control/device_input/signal_combobox/register_signal_combo_box.py,sha256=VEdFRUfLph7JE2arcnzHw8etsE-4wZkwyzlNLMJBsZk,526
|
193
193
|
bec_widgets/widgets/control/device_input/signal_combobox/signal_combo_box.pyproject,sha256=xod6iyRD-WD0Uk6LWXjSxFJCQy-831pvTkKcw2FAdnM,33
|
194
194
|
bec_widgets/widgets/control/device_input/signal_combobox/signal_combo_box_plugin.py,sha256=sstqm2KtyR5wwOIYJRbzOqHMq5_9ExKP-YS5qV5ACrA,1373
|
195
|
-
bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py,sha256=
|
195
|
+
bec_widgets/widgets/control/device_input/signal_combobox/signal_combobox.py,sha256=NCT0ql6KCe-YspoYKSv2py7JeqKBGJFU97q6UoG-Oxg,4641
|
196
196
|
bec_widgets/widgets/control/device_input/signal_line_edit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
197
197
|
bec_widgets/widgets/control/device_input/signal_line_edit/register_signal_line_edit.py,sha256=aQLTy_3gbji0vq5VvvAddHFimpwGGaMYJy5iGgX23aM,527
|
198
|
-
bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py,sha256
|
198
|
+
bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.py,sha256=-y_Oy8A7pQVQbzjvHznGxTX-wCisP-4l5py7WOm1_EY,6008
|
199
199
|
bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit.pyproject,sha256=3NBnjBB6JRuF2W9-SR6x09KO1C2oB1IEV3VW__miIgI,34
|
200
200
|
bec_widgets/widgets/control/device_input/signal_line_edit/signal_line_edit_plugin.py,sha256=t2VBGsbysCL6154Z5Ny5Nk2UWcURMGS-ibVKiRvYs6Y,1384
|
201
201
|
bec_widgets/widgets/control/scan_control/__init__.py,sha256=IOfHl15vxb_uC6KN62-PeUzbBha_vQyqkkXbJ2HU674,38
|
@@ -259,16 +259,17 @@ bec_widgets/widgets/games/register_minesweeper.py,sha256=8fgMBD3yB-5_eGqhG_qxpj3
|
|
259
259
|
bec_widgets/widgets/plots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
260
260
|
bec_widgets/widgets/plots/plot_base.py,sha256=NliWkXihJIPHRJHe-CNIrdjgxONk7uExG_3SsIpyoRQ,33848
|
261
261
|
bec_widgets/widgets/plots/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
262
|
-
bec_widgets/widgets/plots/image/image.py,sha256=
|
262
|
+
bec_widgets/widgets/plots/image/image.py,sha256=FA2a583iWkDi_zydw_OYi4NEiGHXtM_O0PxxSmdgUiY,42042
|
263
263
|
bec_widgets/widgets/plots/image/image.pyproject,sha256=_sRCIu4MNgToaB4D7tUMWq3xKX6T2VoRS3UzGNIseHQ,23
|
264
264
|
bec_widgets/widgets/plots/image/image_item.py,sha256=2bn9H5YLmo7ohQnnf1mLlL24TASnlZNzMvF7buMutmI,8728
|
265
265
|
bec_widgets/widgets/plots/image/image_plugin.py,sha256=R0Hzh2GgYlfZLPZwOMgqLKKIA5DxEnTcSrbI7zTe-tI,1204
|
266
266
|
bec_widgets/widgets/plots/image/image_processor.py,sha256=0qsQIyB__xxBwNIoXhFbB0wSiB8n7n_oX4cvfFsUzOs,4304
|
267
|
+
bec_widgets/widgets/plots/image/image_roi_plot.py,sha256=5CWy_eC-GS2ZLJTj2ItrVCoKhPN2g3fx6L4ktf5yVFQ,1191
|
267
268
|
bec_widgets/widgets/plots/image/register_image.py,sha256=0rvFyAMGRZcknc7nMVwsMGSfY8L2j9cdtQhbO5TMzeM,455
|
268
269
|
bec_widgets/widgets/plots/image/setting_widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
269
270
|
bec_widgets/widgets/plots/image/setting_widgets/image_roi_tree.py,sha256=nlllg-yTNCjG5DxCEDSGzCNabNSTJ3TZn9mawzIiAq4,14255
|
270
271
|
bec_widgets/widgets/plots/image/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
271
|
-
bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py,sha256=
|
272
|
+
bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py,sha256=gJhDAdHB4cAsPw7E6W6Y2iR3nF_3n_v-ElGqj4TgIGo,2646
|
272
273
|
bec_widgets/widgets/plots/image/toolbar_bundles/processing.py,sha256=A_8_8oDogypmRv8NCDwjO524LJAjgZ7viE1Nz5U__y8,3052
|
273
274
|
bec_widgets/widgets/plots/motor_map/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
274
275
|
bec_widgets/widgets/plots/motor_map/motor_map.py,sha256=pcQStrIJJOsxC2sW3FDMDIFmFXM94uXQVdAjPi-vBvM,29209
|
@@ -307,7 +308,7 @@ bec_widgets/widgets/plots/setting_menus/axis_settings.py,sha256=v-esAvJG8SeVv3hW
|
|
307
308
|
bec_widgets/widgets/plots/setting_menus/axis_settings_horizontal.ui,sha256=v8jJfPLnhORVfJukhRmygrPobMmJLufA4e3C08QeO-o,9526
|
308
309
|
bec_widgets/widgets/plots/setting_menus/axis_settings_vertical.ui,sha256=k4vsQgZyKZkK3JiOXaQmvgR3IHy90mb4upGAtIwBOsA,9104
|
309
310
|
bec_widgets/widgets/plots/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
310
|
-
bec_widgets/widgets/plots/toolbar_bundles/mouse_interactions.py,sha256=
|
311
|
+
bec_widgets/widgets/plots/toolbar_bundles/mouse_interactions.py,sha256=gdQ6Ggdq0rhELncCCUBXwi_k16xXWAgHOtgNmND58cA,4169
|
311
312
|
bec_widgets/widgets/plots/toolbar_bundles/plot_export.py,sha256=43JnNwmp0lAVvSArZ0qa8SWwEAHwrZWBUse0nhlqMkA,3049
|
312
313
|
bec_widgets/widgets/plots/toolbar_bundles/roi_bundle.py,sha256=tBJOhdfbg70uAcLruEdTIUTB7_qbKcswwinsI2tZNDc,1256
|
313
314
|
bec_widgets/widgets/plots/toolbar_bundles/save_state.py,sha256=H3fu-bRzNIycCUFb2wDQU7BRrN8M56P961sZ7vwzrEo,1734
|
@@ -403,8 +404,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=O
|
|
403
404
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
|
404
405
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
|
405
406
|
bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
|
406
|
-
bec_widgets-2.
|
407
|
-
bec_widgets-2.
|
408
|
-
bec_widgets-2.
|
409
|
-
bec_widgets-2.
|
410
|
-
bec_widgets-2.
|
407
|
+
bec_widgets-2.7.1.dist-info/METADATA,sha256=Y_57lRMl_nuLmuqg18CxTycbI32aOzdupElg65WqfSQ,1273
|
408
|
+
bec_widgets-2.7.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
409
|
+
bec_widgets-2.7.1.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
|
410
|
+
bec_widgets-2.7.1.dist-info/licenses/LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
|
411
|
+
bec_widgets-2.7.1.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|
File without changes
|