bec-widgets 2.12.2__py3-none-any.whl → 2.12.4__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.
- .github/workflows/stale-issues.yml +15 -0
- CHANGELOG.md +33 -0
- PKG-INFO +3 -3
- bec_widgets/cli/client.py +2 -2
- bec_widgets/utils/crosshair.py +1 -1
- bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py +19 -0
- bec_widgets/widgets/plots/image/image.py +100 -44
- bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py +53 -6
- bec_widgets/widgets/plots/roi/image_roi.py +31 -18
- {bec_widgets-2.12.2.dist-info → bec_widgets-2.12.4.dist-info}/METADATA +3 -3
- {bec_widgets-2.12.2.dist-info → bec_widgets-2.12.4.dist-info}/RECORD +15 -14
- pyproject.toml +6 -6
- {bec_widgets-2.12.2.dist-info → bec_widgets-2.12.4.dist-info}/WHEEL +0 -0
- {bec_widgets-2.12.2.dist-info → bec_widgets-2.12.4.dist-info}/entry_points.txt +0 -0
- {bec_widgets-2.12.2.dist-info → bec_widgets-2.12.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
name: 'Close stale issues and PRs'
|
2
|
+
on:
|
3
|
+
schedule:
|
4
|
+
- cron: '00 10 * * *'
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
stale:
|
8
|
+
runs-on: ubuntu-latest
|
9
|
+
steps:
|
10
|
+
- uses: actions/stale@v9
|
11
|
+
with:
|
12
|
+
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
13
|
+
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
14
|
+
days-before-stale: 60
|
15
|
+
days-before-close: 7
|
CHANGELOG.md
CHANGED
@@ -1,6 +1,39 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v2.12.4 (2025-06-10)
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
- **image_roi**: Coordinates are emitted correctly when handles are inverted; closes #672
|
9
|
+
([`9ef418b`](https://github.com/bec-project/bec_widgets/commit/9ef418bf5597d4be77adc3c0c88c1c1619c9aa2f))
|
10
|
+
|
11
|
+
### Continuous Integration
|
12
|
+
|
13
|
+
- Add stale issue job
|
14
|
+
([`b3ce680`](https://github.com/bec-project/bec_widgets/commit/b3ce68070d58cdd76559cbd7db04cdbcc6c1f075))
|
15
|
+
|
16
|
+
|
17
|
+
## v2.12.3 (2025-06-05)
|
18
|
+
|
19
|
+
### Bug Fixes
|
20
|
+
|
21
|
+
- **crosshair**: Use objectName instead of config for retrieving the monitor name
|
22
|
+
([`edfac87`](https://github.com/bec-project/bec_widgets/commit/edfac87868605b4b755f7732b2841673de53bc3f))
|
23
|
+
|
24
|
+
- **device_combobox**: Tuple entries of preview signals are checked in DeviceComboBoxes just for the
|
25
|
+
relevant device
|
26
|
+
([`12f5233`](https://github.com/bec-project/bec_widgets/commit/12f523374586d55499f80baf56a50b6ef486cd43))
|
27
|
+
|
28
|
+
- **image**: Preview signals can be used in Image widget; update logic adjusted; closes #683
|
29
|
+
([`2711164`](https://github.com/bec-project/bec_widgets/commit/271116453d1ef5316b19457d04613b6ddc939cdb))
|
30
|
+
|
31
|
+
### Build System
|
32
|
+
|
33
|
+
- Update min dependency of bec to 3.38
|
34
|
+
([`3740ac8`](https://github.com/bec-project/bec_widgets/commit/3740ac8e325a489d59faca648896ffcea29e1a02))
|
35
|
+
|
36
|
+
|
4
37
|
## v2.12.2 (2025-06-05)
|
5
38
|
|
6
39
|
### Bug Fixes
|
PKG-INFO
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bec_widgets
|
3
|
-
Version: 2.12.
|
3
|
+
Version: 2.12.4
|
4
4
|
Summary: BEC Widgets
|
5
5
|
Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
|
6
6
|
Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
|
@@ -9,8 +9,8 @@ Classifier: Development Status :: 3 - Alpha
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Topic :: Scientific/Engineering
|
11
11
|
Requires-Python: >=3.10
|
12
|
-
Requires-Dist: bec-ipython-client<=4.0,>=
|
13
|
-
Requires-Dist: bec-lib<=4.0,>=3.
|
12
|
+
Requires-Dist: bec-ipython-client<=4.0,>=3.38
|
13
|
+
Requires-Dist: bec-lib<=4.0,>=3.38
|
14
14
|
Requires-Dist: bec-qthemes>=0.7,~=0.7
|
15
15
|
Requires-Dist: black~=25.0
|
16
16
|
Requires-Dist: isort>=5.13.2,~=5.13
|
bec_widgets/cli/client.py
CHANGED
@@ -1459,12 +1459,12 @@ class Image(RPCBase):
|
|
1459
1459
|
@rpc_call
|
1460
1460
|
def image(
|
1461
1461
|
self,
|
1462
|
-
monitor: "str | None" = None,
|
1462
|
+
monitor: "str | tuple | None" = None,
|
1463
1463
|
monitor_type: "Literal['auto', '1d', '2d']" = "auto",
|
1464
1464
|
color_map: "str | None" = None,
|
1465
1465
|
color_bar: "Literal['simple', 'full'] | None" = None,
|
1466
1466
|
vrange: "tuple[int, int] | None" = None,
|
1467
|
-
) -> "ImageItem":
|
1467
|
+
) -> "ImageItem | None":
|
1468
1468
|
"""
|
1469
1469
|
Set the image source and update the image.
|
1470
1470
|
|
bec_widgets/utils/crosshair.py
CHANGED
@@ -458,7 +458,7 @@ class Crosshair(QObject):
|
|
458
458
|
)
|
459
459
|
self.coordinatesClicked1D.emit(coordinate_to_emit)
|
460
460
|
elif isinstance(item, pg.ImageItem):
|
461
|
-
name = item.
|
461
|
+
name = item.objectName() or str(id(item))
|
462
462
|
x, y = x_snap_values[name], y_snap_values[name]
|
463
463
|
if x is None or y is None:
|
464
464
|
continue
|
@@ -149,6 +149,25 @@ class DeviceComboBox(DeviceInputBase, QComboBox):
|
|
149
149
|
self._is_valid_input = False
|
150
150
|
self.update()
|
151
151
|
|
152
|
+
def validate_device(self, device: str) -> bool: # type: ignore[override]
|
153
|
+
"""
|
154
|
+
Extend validation so that preview‑signal pseudo‑devices (labels like
|
155
|
+
``"eiger_preview"``) are accepted as valid choices.
|
156
|
+
|
157
|
+
The validation run only on device not on the preview‑signal.
|
158
|
+
|
159
|
+
Args:
|
160
|
+
device: The text currently entered/selected.
|
161
|
+
|
162
|
+
Returns:
|
163
|
+
True if the device is a genuine BEC device *or* one of the
|
164
|
+
whitelisted preview‑signal entries.
|
165
|
+
"""
|
166
|
+
idx = self.findText(device)
|
167
|
+
if idx >= 0 and isinstance(self.itemData(idx), tuple):
|
168
|
+
device = self.itemData(idx)[0] # type: ignore[assignment]
|
169
|
+
return super().validate_device(device)
|
170
|
+
|
152
171
|
|
153
172
|
if __name__ == "__main__": # pragma: no cover
|
154
173
|
# pylint: disable=import-outside-toplevel
|
@@ -35,7 +35,7 @@ class ImageConfig(ConnectionConfig):
|
|
35
35
|
|
36
36
|
|
37
37
|
class ImageLayerConfig(BaseModel):
|
38
|
-
monitor: str | None = Field(None, description="The name of the monitor.")
|
38
|
+
monitor: str | tuple | None = Field(None, description="The name of the monitor.")
|
39
39
|
monitor_type: Literal["1d", "2d", "auto"] = Field("auto", description="The type of monitor.")
|
40
40
|
source: Literal["device_monitor_1d", "device_monitor_2d", "auto"] = Field(
|
41
41
|
"auto", description="The source of the image data."
|
@@ -179,12 +179,12 @@ class Image(ImageBase):
|
|
179
179
|
@SafeSlot(popup_error=True)
|
180
180
|
def image(
|
181
181
|
self,
|
182
|
-
monitor: str | None = None,
|
182
|
+
monitor: str | tuple | None = None,
|
183
183
|
monitor_type: Literal["auto", "1d", "2d"] = "auto",
|
184
184
|
color_map: str | None = None,
|
185
185
|
color_bar: Literal["simple", "full"] | None = None,
|
186
186
|
vrange: tuple[int, int] | None = None,
|
187
|
-
) -> ImageItem:
|
187
|
+
) -> ImageItem | None:
|
188
188
|
"""
|
189
189
|
Set the image source and update the image.
|
190
190
|
|
@@ -201,21 +201,13 @@ class Image(ImageBase):
|
|
201
201
|
|
202
202
|
if self.subscriptions["main"].monitor:
|
203
203
|
self.disconnect_monitor(self.subscriptions["main"].monitor)
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
if
|
208
|
-
self.
|
209
|
-
|
210
|
-
|
211
|
-
self.subscriptions["main"].source = "device_monitor_2d"
|
212
|
-
self.subscriptions["main"].monitor_type = "2d"
|
213
|
-
elif monitor_type == "auto":
|
214
|
-
self.subscriptions["main"].source = "auto"
|
215
|
-
logger.warning(
|
216
|
-
f"Updates for '{monitor}' will be fetch from both 1D and 2D monitor endpoints."
|
217
|
-
)
|
218
|
-
self.subscriptions["main"].monitor_type = "auto"
|
204
|
+
if monitor is None or monitor == "":
|
205
|
+
logger.warning(f"No monitor specified, cannot set image, old monitor is unsubscribed")
|
206
|
+
return None
|
207
|
+
if isinstance(monitor, tuple):
|
208
|
+
self.entry_validator.validate_monitor(monitor[0])
|
209
|
+
else:
|
210
|
+
self.entry_validator.validate_monitor(monitor)
|
219
211
|
|
220
212
|
self.set_image_update(monitor=monitor, type=monitor_type)
|
221
213
|
if color_map is not None:
|
@@ -240,7 +232,12 @@ class Image(ImageBase):
|
|
240
232
|
self.selection_bundle.dim_combo_box,
|
241
233
|
):
|
242
234
|
combo.blockSignals(True)
|
243
|
-
|
235
|
+
if isinstance(config.monitor, tuple):
|
236
|
+
self.selection_bundle.device_combo_box.setCurrentText(
|
237
|
+
f"{config.monitor[0]}_{config.monitor[1]}"
|
238
|
+
)
|
239
|
+
else:
|
240
|
+
self.selection_bundle.device_combo_box.setCurrentText(config.monitor)
|
244
241
|
self.selection_bundle.dim_combo_box.setCurrentText(config.monitor_type)
|
245
242
|
for combo in (
|
246
243
|
self.selection_bundle.device_combo_box,
|
@@ -340,7 +337,8 @@ class Image(ImageBase):
|
|
340
337
|
########################################
|
341
338
|
# Connections
|
342
339
|
|
343
|
-
|
340
|
+
@SafeSlot()
|
341
|
+
def set_image_update(self, monitor: str | tuple, type: Literal["1d", "2d", "auto"]):
|
344
342
|
"""
|
345
343
|
Set the image update method for the given monitor.
|
346
344
|
|
@@ -350,37 +348,95 @@ class Image(ImageBase):
|
|
350
348
|
"""
|
351
349
|
|
352
350
|
# TODO consider moving connecting and disconnecting logic to Image itself if multiple images
|
353
|
-
if
|
354
|
-
self.
|
355
|
-
|
356
|
-
)
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
)
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
351
|
+
if isinstance(monitor, tuple):
|
352
|
+
device = self.dev[monitor[0]]
|
353
|
+
signal = monitor[1]
|
354
|
+
if len(monitor) == 3:
|
355
|
+
signal_config = monitor[2]
|
356
|
+
else:
|
357
|
+
signal_config = device._info["signals"][signal]
|
358
|
+
signal_class = signal_config.get("signal_class", None)
|
359
|
+
if signal_class != "PreviewSignal":
|
360
|
+
logger.warning(f"Signal '{monitor}' is not a PreviewSignal.")
|
361
|
+
return
|
362
|
+
|
363
|
+
ndim = signal_config.get("describe", None).get("signal_info", None).get("ndim", None)
|
364
|
+
if ndim is None:
|
365
|
+
logger.warning(
|
366
|
+
f"Signal '{monitor}' does not have a valid 'ndim' in its signal_info."
|
367
|
+
)
|
368
|
+
return
|
369
|
+
|
370
|
+
if ndim == 1:
|
371
|
+
self.bec_dispatcher.connect_slot(
|
372
|
+
self.on_image_update_1d, MessageEndpoints.device_preview(device.name, signal)
|
373
|
+
)
|
374
|
+
self.subscriptions["main"].source = "device_monitor_1d"
|
375
|
+
self.subscriptions["main"].monitor_type = "1d"
|
376
|
+
elif ndim == 2:
|
377
|
+
self.bec_dispatcher.connect_slot(
|
378
|
+
self.on_image_update_2d, MessageEndpoints.device_preview(device.name, signal)
|
379
|
+
)
|
380
|
+
self.subscriptions["main"].source = "device_monitor_2d"
|
381
|
+
self.subscriptions["main"].monitor_type = "2d"
|
382
|
+
|
383
|
+
else: # FIXME old monitor 1d/2d endpoint handling, present for backwards compatibility, will be removed in future versions
|
384
|
+
if type == "1d":
|
385
|
+
self.bec_dispatcher.connect_slot(
|
386
|
+
self.on_image_update_1d, MessageEndpoints.device_monitor_1d(monitor)
|
387
|
+
)
|
388
|
+
self.subscriptions["main"].source = "device_monitor_1d"
|
389
|
+
self.subscriptions["main"].monitor_type = "1d"
|
390
|
+
elif type == "2d":
|
391
|
+
self.bec_dispatcher.connect_slot(
|
392
|
+
self.on_image_update_2d, MessageEndpoints.device_monitor_2d(monitor)
|
393
|
+
)
|
394
|
+
self.subscriptions["main"].source = "device_monitor_2d"
|
395
|
+
self.subscriptions["main"].monitor_type = "2d"
|
396
|
+
elif type == "auto":
|
397
|
+
self.bec_dispatcher.connect_slot(
|
398
|
+
self.on_image_update_1d, MessageEndpoints.device_monitor_1d(monitor)
|
399
|
+
)
|
400
|
+
self.bec_dispatcher.connect_slot(
|
401
|
+
self.on_image_update_2d, MessageEndpoints.device_monitor_2d(monitor)
|
402
|
+
)
|
403
|
+
self.subscriptions["main"].source = "auto"
|
404
|
+
logger.warning(
|
405
|
+
f"Updates for '{monitor}' will be fetch from both 1D and 2D monitor endpoints."
|
406
|
+
)
|
407
|
+
self.subscriptions["main"].monitor_type = "auto"
|
408
|
+
|
368
409
|
logger.info(f"Connected to {monitor} with type {type}")
|
369
410
|
self.subscriptions["main"].monitor = monitor
|
370
411
|
|
371
|
-
def disconnect_monitor(self, monitor: str):
|
412
|
+
def disconnect_monitor(self, monitor: str | tuple):
|
372
413
|
"""
|
373
414
|
Disconnect the monitor from the image update signals, both 1D and 2D.
|
374
415
|
|
375
416
|
Args:
|
376
|
-
monitor(str): The name of the monitor to disconnect.
|
377
|
-
"""
|
378
|
-
|
379
|
-
self.
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
417
|
+
monitor(str|tuple): The name of the monitor to disconnect, or a tuple of (device, signal) for preview signals.
|
418
|
+
"""
|
419
|
+
if isinstance(monitor, tuple):
|
420
|
+
if self.subscriptions["main"].source == "device_monitor_1d":
|
421
|
+
self.bec_dispatcher.disconnect_slot(
|
422
|
+
self.on_image_update_1d, MessageEndpoints.device_preview(monitor[0], monitor[1])
|
423
|
+
)
|
424
|
+
elif self.subscriptions["main"].source == "device_monitor_2d":
|
425
|
+
self.bec_dispatcher.disconnect_slot(
|
426
|
+
self.on_image_update_2d, MessageEndpoints.device_preview(monitor[0], monitor[1])
|
427
|
+
)
|
428
|
+
else:
|
429
|
+
logger.warning(
|
430
|
+
f"Cannot disconnect monitor {monitor} with source {self.subscriptions['main'].source}"
|
431
|
+
)
|
432
|
+
return
|
433
|
+
else: # FIXME old monitor 1d/2d endpoint handling, present for backwards compatibility, will be removed in future versions
|
434
|
+
self.bec_dispatcher.disconnect_slot(
|
435
|
+
self.on_image_update_1d, MessageEndpoints.device_monitor_1d(monitor)
|
436
|
+
)
|
437
|
+
self.bec_dispatcher.disconnect_slot(
|
438
|
+
self.on_image_update_2d, MessageEndpoints.device_monitor_2d(monitor)
|
439
|
+
)
|
384
440
|
self.subscriptions["main"].monitor = None
|
385
441
|
self._sync_device_selection()
|
386
442
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from bec_lib.device import ReadoutPriority
|
2
|
-
from qtpy.QtCore import Qt
|
2
|
+
from qtpy.QtCore import Qt, QTimer
|
3
3
|
from qtpy.QtWidgets import QComboBox, QStyledItemDelegate
|
4
4
|
|
5
5
|
from bec_widgets.utils.error_popups import SafeSlot
|
@@ -50,11 +50,58 @@ class MonitorSelectionToolbarBundle(ToolbarBundle):
|
|
50
50
|
|
51
51
|
self.add_action("dim_combo", WidgetAction(widget=self.dim_combo_box, adjust_size=False))
|
52
52
|
|
53
|
-
|
54
|
-
self.
|
55
|
-
|
53
|
+
self.device_combo_box.currentTextChanged.connect(self.connect_monitor)
|
54
|
+
self.dim_combo_box.currentTextChanged.connect(self.connect_monitor)
|
55
|
+
|
56
|
+
QTimer.singleShot(0, self._adjust_and_connect)
|
57
|
+
|
58
|
+
def _adjust_and_connect(self):
|
59
|
+
"""
|
60
|
+
Adjust the size of the device combo box and populate it with preview signals.
|
61
|
+
Has to be done with QTimer.singleShot to ensure the UI is fully initialized, needed for testing.
|
62
|
+
"""
|
63
|
+
self._populate_preview_signals()
|
64
|
+
self._reverse_device_items()
|
65
|
+
self.device_combo_box.setCurrentText("") # set again default to empty string
|
66
|
+
|
67
|
+
def _populate_preview_signals(self) -> None:
|
68
|
+
"""
|
69
|
+
Populate the device combo box with preview‑signal devices in the
|
70
|
+
format '<device>_<signal>' and store the tuple(device, signal) in
|
71
|
+
the item's userData for later use.
|
72
|
+
"""
|
73
|
+
preview_signals = self.target_widget.client.device_manager.get_bec_signals("PreviewSignal")
|
74
|
+
for device, signal, signal_config in preview_signals:
|
75
|
+
label = signal_config.get("obj_name", f"{device}_{signal}")
|
76
|
+
self.device_combo_box.addItem(label, (device, signal, signal_config))
|
77
|
+
|
78
|
+
def _reverse_device_items(self) -> None:
|
79
|
+
"""
|
80
|
+
Reverse the current order of items in the device combo box while
|
81
|
+
keeping their userData and restoring the previous selection.
|
82
|
+
"""
|
83
|
+
current_text = self.device_combo_box.currentText()
|
84
|
+
items = [
|
85
|
+
(self.device_combo_box.itemText(i), self.device_combo_box.itemData(i))
|
86
|
+
for i in range(self.device_combo_box.count())
|
87
|
+
]
|
88
|
+
self.device_combo_box.clear()
|
89
|
+
for text, data in reversed(items):
|
90
|
+
self.device_combo_box.addItem(text, data)
|
91
|
+
if current_text:
|
92
|
+
self.device_combo_box.setCurrentText(current_text)
|
56
93
|
|
57
94
|
@SafeSlot()
|
58
|
-
def connect_monitor(self):
|
95
|
+
def connect_monitor(self, *args, **kwargs):
|
96
|
+
"""
|
97
|
+
Connect the target widget to the selected monitor based on the current device and dimension.
|
98
|
+
|
99
|
+
If the selected device is a preview-signal device, it will use the tuple (device, signal) as the monitor.
|
100
|
+
"""
|
59
101
|
dim = self.dim_combo_box.currentText()
|
60
|
-
|
102
|
+
data = self.device_combo_box.currentData()
|
103
|
+
|
104
|
+
if isinstance(data, tuple):
|
105
|
+
self.target_widget.image(monitor=data, monitor_type="auto")
|
106
|
+
else:
|
107
|
+
self.target_widget.image(monitor=self.device_combo_box.currentText(), monitor_type=dim)
|
@@ -437,6 +437,23 @@ class RectangularROI(BaseROI, pg.RectROI):
|
|
437
437
|
self.hoverPen = fn.mkPen(color=(255, 0, 0), width=3, style=QtCore.Qt.DashLine)
|
438
438
|
self.handleHoverPen = fn.mkPen("lime", width=4)
|
439
439
|
|
440
|
+
def _normalized_edges(self) -> tuple[float, float, float, float]:
|
441
|
+
"""
|
442
|
+
Return rectangle edges as (left, bottom, right, top) with consistent
|
443
|
+
ordering even when the ROI has been inverted by its scale handles.
|
444
|
+
|
445
|
+
Returns:
|
446
|
+
tuple: A tuple containing the left, bottom, right, and top edges
|
447
|
+
of the ROI rectangle in normalized coordinates.
|
448
|
+
"""
|
449
|
+
x0, y0 = self.pos().x(), self.pos().y()
|
450
|
+
w, h = self.state["size"]
|
451
|
+
x_left = min(x0, x0 + w)
|
452
|
+
x_right = max(x0, x0 + w)
|
453
|
+
y_bottom = min(y0, y0 + h)
|
454
|
+
y_top = max(y0, y0 + h)
|
455
|
+
return x_left, y_bottom, x_right, y_top
|
456
|
+
|
440
457
|
def add_scale_handle(self):
|
441
458
|
"""
|
442
459
|
Add scale handles at every corner and edge of the ROI.
|
@@ -465,17 +482,15 @@ class RectangularROI(BaseROI, pg.RectROI):
|
|
465
482
|
|
466
483
|
def _on_region_changed(self):
|
467
484
|
"""
|
468
|
-
Handles ROI region
|
485
|
+
Handles changes to the ROI's region.
|
469
486
|
|
470
487
|
This method is called whenever the ROI's position or size changes.
|
471
488
|
It calculates the new corner coordinates and emits the edgesChanged signal
|
472
489
|
with the updated coordinates.
|
473
490
|
"""
|
474
|
-
|
475
|
-
|
476
|
-
self.
|
477
|
-
viewBox = self.parent_plot_item.vb
|
478
|
-
viewBox.update()
|
491
|
+
x_left, y_bottom, x_right, y_top = self._normalized_edges()
|
492
|
+
self.edgesChanged.emit(x_left, y_bottom, x_right, y_top)
|
493
|
+
self.parent_plot_item.vb.update()
|
479
494
|
|
480
495
|
def mouseDragEvent(self, ev):
|
481
496
|
"""
|
@@ -489,9 +504,8 @@ class RectangularROI(BaseROI, pg.RectROI):
|
|
489
504
|
"""
|
490
505
|
super().mouseDragEvent(ev)
|
491
506
|
if ev.isFinish():
|
492
|
-
|
493
|
-
|
494
|
-
self.edgesReleased.emit(x0, y0, x0 + w, y0 + h)
|
507
|
+
x_left, y_bottom, x_right, y_top = self._normalized_edges()
|
508
|
+
self.edgesReleased.emit(x_left, y_bottom, x_right, y_top)
|
495
509
|
|
496
510
|
def get_coordinates(self, typed: bool | None = None) -> dict | tuple:
|
497
511
|
"""
|
@@ -510,17 +524,16 @@ class RectangularROI(BaseROI, pg.RectROI):
|
|
510
524
|
if typed is None:
|
511
525
|
typed = self.description
|
512
526
|
|
513
|
-
|
514
|
-
|
515
|
-
x1, y1 = x0 + w, y0 + h
|
527
|
+
x_left, y_bottom, x_right, y_top = self._normalized_edges()
|
528
|
+
|
516
529
|
if typed:
|
517
530
|
return {
|
518
|
-
"bottom_left": (
|
519
|
-
"bottom_right": (
|
520
|
-
"top_left": (
|
521
|
-
"top_right": (
|
531
|
+
"bottom_left": (x_left, y_bottom),
|
532
|
+
"bottom_right": (x_right, y_bottom),
|
533
|
+
"top_left": (x_left, y_top),
|
534
|
+
"top_right": (x_right, y_top),
|
522
535
|
}
|
523
|
-
return (
|
536
|
+
return (x_left, y_bottom), (x_right, y_bottom), (x_left, y_top), (x_right, y_top)
|
524
537
|
|
525
538
|
def _lookup_scene_image(self):
|
526
539
|
"""
|
@@ -654,7 +667,7 @@ class CircularROI(BaseROI, pg.CircleROI):
|
|
654
667
|
if typed is None:
|
655
668
|
typed = self.description
|
656
669
|
|
657
|
-
d = self.state["size"][0]
|
670
|
+
d = abs(self.state["size"][0])
|
658
671
|
cx = self.pos().x() + d / 2
|
659
672
|
cy = self.pos().y() + d / 2
|
660
673
|
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: bec_widgets
|
3
|
-
Version: 2.12.
|
3
|
+
Version: 2.12.4
|
4
4
|
Summary: BEC Widgets
|
5
5
|
Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
|
6
6
|
Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
|
@@ -9,8 +9,8 @@ Classifier: Development Status :: 3 - Alpha
|
|
9
9
|
Classifier: Programming Language :: Python :: 3
|
10
10
|
Classifier: Topic :: Scientific/Engineering
|
11
11
|
Requires-Python: >=3.10
|
12
|
-
Requires-Dist: bec-ipython-client<=4.0,>=
|
13
|
-
Requires-Dist: bec-lib<=4.0,>=3.
|
12
|
+
Requires-Dist: bec-ipython-client<=4.0,>=3.38
|
13
|
+
Requires-Dist: bec-lib<=4.0,>=3.38
|
14
14
|
Requires-Dist: bec-qthemes>=0.7,~=0.7
|
15
15
|
Requires-Dist: black~=25.0
|
16
16
|
Requires-Dist: isort>=5.13.2,~=5.13
|
@@ -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=On772_xBp6UXL4xD4-avtvUKnrHAn_WkDG54pbO8faw,298414
|
6
6
|
LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=yGts5s4Gww_NSvVRgwxfZ4qy9VcGBEFgtvYb3GwhVFE,1252
|
8
8
|
README.md,sha256=oY5Jc1uXehRASuwUJ0umin2vfkFh7tHF-LLruHTaQx0,3560
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=J2FCGRnxVqdJMydJh53r1De16ht1tmpzMqa-I5v1FEM,2827
|
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
|
@@ -23,6 +23,7 @@ pyproject.toml,sha256=fmTjR-mLrzWuJj1LqBPC9hVL4MNj_cmbjVd9AIhsGjg,2835
|
|
23
23
|
.github/workflows/pytest-matrix.yml,sha256=0gL5wNPJKJF1JapqstlYNYiJ44ko05uaTD7epa7smVw,1834
|
24
24
|
.github/workflows/pytest.yml,sha256=hYOB7XK_79MaiELaTH7zDT-WRw-pRDe4mHyB_WfcGDc,1747
|
25
25
|
.github/workflows/semantic_release.yml,sha256=pdkv1rVG3YgG7yu4nNWvbGZifH4bqO1eh3pM0KHRK04,3720
|
26
|
+
.github/workflows/stale-issues.yml,sha256=Q1n-RO1FjEtuWJFRXpqzWnl7Y6EUn0T2ZSRdZQadJA4,568
|
26
27
|
.github/workflows/sync-issues-pr.yml,sha256=Wn68mK8h0xhwIX1VZPEqHEJmku2BRPOrQ6zQsuCIBJk,1039
|
27
28
|
bec_widgets/__init__.py,sha256=mZhbU6zfFt8-A7q_do74ie89budSevwpKZ6FKtEBdmo,170
|
28
29
|
bec_widgets/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -35,7 +36,7 @@ bec_widgets/assets/app_icons/bec_widgets_icon.png,sha256=K8dgGwIjalDh9PRHUsSQBqg
|
|
35
36
|
bec_widgets/assets/app_icons/ui_loader_tile.png,sha256=qSK3XHqvnAVGV9Q0ulORcGFbXJ9LDq2uz8l9uTtMsNk,1812476
|
36
37
|
bec_widgets/assets/app_icons/widget_launch_tile.png,sha256=bWsICHFfSe9-ESUj3AwlE95dDOea-f6M-s9fBapsxB4,2252911
|
37
38
|
bec_widgets/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
38
|
-
bec_widgets/cli/client.py,sha256=
|
39
|
+
bec_widgets/cli/client.py,sha256=MIHk1aBnopQ9qc9QIEldvbO2C5xW4I6U7WYjyOvaMZw,97953
|
39
40
|
bec_widgets/cli/client_utils.py,sha256=F2hyt--jL53bN8NoWifNUMqwwx5FbpS6I1apERdTRzM,18114
|
40
41
|
bec_widgets/cli/generate_cli.py,sha256=K_wMxo2XBUn92SnY3dSrlyUn8ax6Y20QBGCuP284DsQ,10986
|
41
42
|
bec_widgets/cli/server.py,sha256=h7QyBOOGjyrP_fxJIIOSEMc4E06cLG0JyaofjNV6oCA,5671
|
@@ -72,7 +73,7 @@ bec_widgets/utils/collapsible_panel_manager.py,sha256=tvv77-9YTfYpsU6M_Le3bHR6wt
|
|
72
73
|
bec_widgets/utils/colors.py,sha256=i1DuwwdXzRs7HVq9m5wXSaZOJwLX5mJPvV6GAqylZhM,18341
|
73
74
|
bec_widgets/utils/compact_popup.py,sha256=xVK_lQqL5Hy1ZnUzHXB8GU-Ru-mXevKcdM8ync3ssiA,10269
|
74
75
|
bec_widgets/utils/container_utils.py,sha256=J8YXombOlAPa3M8NGZdhntp2NirBu4raDEQZOgP4elM,3791
|
75
|
-
bec_widgets/utils/crosshair.py,sha256=
|
76
|
+
bec_widgets/utils/crosshair.py,sha256=nqBPQqWzoTLZ-sPBR6ONm7M1TtGGD2EpRwm2iSNpoFo,22304
|
76
77
|
bec_widgets/utils/entry_validator.py,sha256=lwT8HP0RDG1FXENIeZ3IDEF2DQmD8KXGkRxPoMXbryk,1817
|
77
78
|
bec_widgets/utils/error_popups.py,sha256=UBAmD1YlAgKodpihudyf0VWtI59KGFiLgnjiKmKGjgk,13254
|
78
79
|
bec_widgets/utils/expandable_frame.py,sha256=ynqRFwXsd6jWT5C6qjNwmmHY9Rm9UCALeL32OPQkYgw,3785
|
@@ -183,7 +184,7 @@ bec_widgets/widgets/control/device_input/base_classes/device_signal_input_base.p
|
|
183
184
|
bec_widgets/widgets/control/device_input/device_combobox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
184
185
|
bec_widgets/widgets/control/device_input/device_combobox/device_combo_box.pyproject,sha256=wI2eXR5ky_IM9-BCHJnH_9CEqYcZwIuLcgitSEr8OJU,40
|
185
186
|
bec_widgets/widgets/control/device_input/device_combobox/device_combo_box_plugin.py,sha256=E8LD9T4O2w621q25uHqBqZLDiQ6zpMR25ZDuf51jrPw,1434
|
186
|
-
bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py,sha256=
|
187
|
+
bec_widgets/widgets/control/device_input/device_combobox/device_combobox.py,sha256=8ANCTgPtO_Fhhy1ZBUfr9Yx_aArnePgkNORYwnXE-Fw,7251
|
187
188
|
bec_widgets/widgets/control/device_input/device_combobox/register_device_combo_box.py,sha256=elw4M4xfIFWe8C0MkdqqqyfnyOVrdl0g0j6bqwOU1GE,526
|
188
189
|
bec_widgets/widgets/control/device_input/device_line_edit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
189
190
|
bec_widgets/widgets/control/device_input/device_line_edit/device_line_edit.py,sha256=k87NtUD2TUB4c6-Ks-eZgafWbjTwbk0RKiqf9-OkjMk,7415
|
@@ -256,7 +257,7 @@ bec_widgets/widgets/games/register_minesweeper.py,sha256=8fgMBD3yB-5_eGqhG_qxpj3
|
|
256
257
|
bec_widgets/widgets/plots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
257
258
|
bec_widgets/widgets/plots/plot_base.py,sha256=GETUsx51BE_Tuop8bC-KiFVrkR82TJ5S0cr7siouSWM,35848
|
258
259
|
bec_widgets/widgets/plots/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
259
|
-
bec_widgets/widgets/plots/image/image.py,sha256=
|
260
|
+
bec_widgets/widgets/plots/image/image.py,sha256=wrI9C2xNEoQmCWoKjlSdRHroWHffIg_DFT4fNDTgAyE,20299
|
260
261
|
bec_widgets/widgets/plots/image/image.pyproject,sha256=_sRCIu4MNgToaB4D7tUMWq3xKX6T2VoRS3UzGNIseHQ,23
|
261
262
|
bec_widgets/widgets/plots/image/image_base.py,sha256=_c4rYRX2AwGyy0WWUhaAJl3gNfXSq1ts99MG8rsa-6w,36104
|
262
263
|
bec_widgets/widgets/plots/image/image_item.py,sha256=rkL1o35Pgs1zhvv2wpSG1gt_bjP5kO4Z1oy6d2q-Yls,8577
|
@@ -267,7 +268,7 @@ bec_widgets/widgets/plots/image/register_image.py,sha256=0rvFyAMGRZcknc7nMVwsMGS
|
|
267
268
|
bec_widgets/widgets/plots/image/setting_widgets/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
268
269
|
bec_widgets/widgets/plots/image/setting_widgets/image_roi_tree.py,sha256=nlllg-yTNCjG5DxCEDSGzCNabNSTJ3TZn9mawzIiAq4,14255
|
269
270
|
bec_widgets/widgets/plots/image/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
270
|
-
bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py,sha256=
|
271
|
+
bec_widgets/widgets/plots/image/toolbar_bundles/image_selection.py,sha256=ezs2TWZCz-3npbIFEiYuHNiuSvJptJznTEZWD_CX3po,4705
|
271
272
|
bec_widgets/widgets/plots/image/toolbar_bundles/processing.py,sha256=99hgd1q86ZUhQYTTsFCk3Ml8oAEeZJy-WqdmsMO4bzA,3367
|
272
273
|
bec_widgets/widgets/plots/motor_map/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
273
274
|
bec_widgets/widgets/plots/motor_map/motor_map.py,sha256=pcQStrIJJOsxC2sW3FDMDIFmFXM94uXQVdAjPi-vBvM,29209
|
@@ -290,7 +291,7 @@ bec_widgets/widgets/plots/multi_waveform/settings/multi_waveform_controls.ui,sha
|
|
290
291
|
bec_widgets/widgets/plots/multi_waveform/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
291
292
|
bec_widgets/widgets/plots/multi_waveform/toolbar_bundles/monitor_selection.py,sha256=lGreAkRBd-A4X_wqYZiKyGDmb_3uzLunjSju9A2PjWw,2532
|
292
293
|
bec_widgets/widgets/plots/roi/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
293
|
-
bec_widgets/widgets/plots/roi/image_roi.py,sha256=
|
294
|
+
bec_widgets/widgets/plots/roi/image_roi.py,sha256=EobZDeUV3l9O08tKwFGZEvkGNOMnVp0hHWNodYce9I0,32998
|
294
295
|
bec_widgets/widgets/plots/scatter_waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
295
296
|
bec_widgets/widgets/plots/scatter_waveform/register_scatter_waveform.py,sha256=KttVjlAK3PfP9tyMfLnqEm6kphap8NZyqyaRry8oebY,514
|
296
297
|
bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py,sha256=nCyZ_6EunS1m5XkLB-CwfBV9L4IX04D9SpHlHc8zG_I,6763
|
@@ -407,8 +408,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=O
|
|
407
408
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
|
408
409
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
|
409
410
|
bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
|
410
|
-
bec_widgets-2.12.
|
411
|
-
bec_widgets-2.12.
|
412
|
-
bec_widgets-2.12.
|
413
|
-
bec_widgets-2.12.
|
414
|
-
bec_widgets-2.12.
|
411
|
+
bec_widgets-2.12.4.dist-info/METADATA,sha256=yGts5s4Gww_NSvVRgwxfZ4qy9VcGBEFgtvYb3GwhVFE,1252
|
412
|
+
bec_widgets-2.12.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
413
|
+
bec_widgets-2.12.4.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
|
414
|
+
bec_widgets-2.12.4.dist-info/licenses/LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
|
415
|
+
bec_widgets-2.12.4.dist-info/RECORD,,
|
pyproject.toml
CHANGED
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "bec_widgets"
|
7
|
-
version = "2.12.
|
7
|
+
version = "2.12.4"
|
8
8
|
description = "BEC Widgets"
|
9
9
|
requires-python = ">=3.10"
|
10
10
|
classifiers = [
|
@@ -13,15 +13,15 @@ classifiers = [
|
|
13
13
|
"Topic :: Scientific/Engineering",
|
14
14
|
]
|
15
15
|
dependencies = [
|
16
|
-
"bec_ipython_client>=
|
17
|
-
"bec_lib>=3.
|
16
|
+
"bec_ipython_client>=3.38, <=4.0", # needed for jupyter console
|
17
|
+
"bec_lib>=3.38, <=4.0",
|
18
18
|
"bec_qthemes~=0.7, >=0.7",
|
19
|
-
"black~=25.0",
|
20
|
-
"isort~=5.13, >=5.13.2",
|
19
|
+
"black~=25.0", # needed for bw-generate-cli
|
20
|
+
"isort~=5.13, >=5.13.2", # needed for bw-generate-cli
|
21
21
|
"pydantic~=2.0",
|
22
22
|
"pyqtgraph~=0.13",
|
23
23
|
"PySide6~=6.8.2",
|
24
|
-
"qtconsole~=5.5, >=5.5.1",
|
24
|
+
"qtconsole~=5.5, >=5.5.1", # needed for jupyter console
|
25
25
|
"qtpy~=2.4",
|
26
26
|
]
|
27
27
|
|
File without changes
|
File without changes
|
File without changes
|