bec-widgets 2.8.2__py3-none-any.whl → 2.8.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.
@@ -12,6 +12,7 @@ jobs:
12
12
  CHILD_PIPELINE_BRANCH: main # Set the branch you want for ophyd_devices
13
13
  BEC_CORE_BRANCH: main # Set the branch you want for bec
14
14
  OPHYD_DEVICES_BRANCH: main # Set the branch you want for ophyd_devices
15
+ PLUGIN_REPO_BRANCH: main # Set the branch you want for the plugin repo
15
16
  PROJECT_PATH: ${{ github.repository }}
16
17
  QTWEBENGINE_DISABLE_SANDBOX: 1
17
18
  QT_QPA_PLATFORM: "offscreen"
@@ -39,10 +40,11 @@ jobs:
39
40
  echo -e "\033[35;1m Using branch $OPHYD_DEVICES_BRANCH of OPHYD_DEVICES \033[0;m";
40
41
  git clone --branch $OPHYD_DEVICES_BRANCH https://github.com/bec-project/ophyd_devices.git
41
42
  export OHPYD_DEVICES_PATH=$PWD/ophyd_devices
43
+ echo -e "\033[35;1m Using branch $PLUGIN_REPO_BRANCH of bec_testing_plugin \033[0;m";
44
+ git clone --branch $PLUGIN_REPO_BRANCH https://github.com/bec-project/bec_testing_plugin.git
42
45
  cd ./bec
43
46
  conda create -q -n test-environment python=3.11
44
47
  source ./bin/install_bec_dev.sh -t
45
48
  cd ../
46
- pip install -e ./ophyd_devices
47
- pip install -e .[dev,pyside6]
49
+ pip install -e ./ophyd_devices -e .[dev,pyside6] -e ./bec_testing_plugin
48
50
  pytest -v --files-path ./ --start-servers --random-order ./tests/end-2-end
CHANGELOG.md CHANGED
@@ -1,6 +1,33 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v2.8.4 (2025-05-30)
5
+
6
+ ### Bug Fixes
7
+
8
+ - **crosshair**: Label decimal precision is dynamically scaled with the plot zoom; API of all
9
+ affected widgets adjusted; option added to PlotBase; closes #637
10
+ ([`c8128fa`](https://github.com/bec-project/bec_widgets/commit/c8128faf79c43487921aada9dbf1869ef5bda93c))
11
+
12
+
13
+ ## v2.8.3 (2025-05-30)
14
+
15
+ ### Bug Fixes
16
+
17
+ - Guard plugin repo import in e2e test
18
+ ([`bf172b8`](https://github.com/bec-project/bec_widgets/commit/bf172b8431ec207f39206d2a0446908f7186858a))
19
+
20
+ ### Refactoring
21
+
22
+ - Store modules with widget search
23
+ ([`b225a7c`](https://github.com/bec-project/bec_widgets/commit/b225a7cc90b55697211c28d9411b6f85c8077217))
24
+
25
+ ### Testing
26
+
27
+ - **e2e**: Add tests involving plugin repo
28
+ ([`05329ab`](https://github.com/bec-project/bec_widgets/commit/05329ab50fe10ffc3c19ef3eb408912bb9068de3))
29
+
30
+
4
31
  ## v2.8.2 (2025-05-27)
5
32
 
6
33
  ### Bug Fixes
PKG-INFO CHANGED
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bec_widgets
3
- Version: 2.8.2
3
+ Version: 2.8.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
@@ -242,7 +242,7 @@ class LaunchWindow(BECMainWindow):
242
242
  )
243
243
 
244
244
  # plugin widgets
245
- self.available_widgets: dict[str, BECWidget] = get_all_plugin_widgets()
245
+ self.available_widgets: dict[str, type[BECWidget]] = get_all_plugin_widgets().as_dict()
246
246
  if self.available_widgets:
247
247
  plugin_repo_name = next(iter(self.available_widgets.values())).__module__.split(".")[0]
248
248
  plugin_repo_name = plugin_repo_name.removesuffix("_bec").upper()
bec_widgets/cli/client.py CHANGED
@@ -63,7 +63,7 @@ _Widgets = {
63
63
 
64
64
 
65
65
  try:
66
- _plugin_widgets = get_all_plugin_widgets()
66
+ _plugin_widgets = get_all_plugin_widgets().as_dict()
67
67
  plugin_client = get_plugin_client_module()
68
68
  Widgets = _WidgetsEnumType("Widgets", {name: name for name in _plugin_widgets} | _Widgets)
69
69
 
@@ -1221,6 +1221,20 @@ class Image(RPCBase):
1221
1221
  Set auto range for the y-axis.
1222
1222
  """
1223
1223
 
1224
+ @property
1225
+ @rpc_call
1226
+ def minimal_crosshair_precision(self) -> "int":
1227
+ """
1228
+ Minimum decimal places for crosshair when dynamic precision is enabled.
1229
+ """
1230
+
1231
+ @minimal_crosshair_precision.setter
1232
+ @rpc_call
1233
+ def minimal_crosshair_precision(self) -> "int":
1234
+ """
1235
+ Minimum decimal places for crosshair when dynamic precision is enabled.
1236
+ """
1237
+
1224
1238
  @property
1225
1239
  @rpc_call
1226
1240
  def color_map(self) -> "str":
@@ -2350,6 +2364,20 @@ class MultiWaveform(RPCBase):
2350
2364
  The font size of the legend font.
2351
2365
  """
2352
2366
 
2367
+ @property
2368
+ @rpc_call
2369
+ def minimal_crosshair_precision(self) -> "int":
2370
+ """
2371
+ Minimum decimal places for crosshair when dynamic precision is enabled.
2372
+ """
2373
+
2374
+ @minimal_crosshair_precision.setter
2375
+ @rpc_call
2376
+ def minimal_crosshair_precision(self) -> "int":
2377
+ """
2378
+ Minimum decimal places for crosshair when dynamic precision is enabled.
2379
+ """
2380
+
2353
2381
  @property
2354
2382
  @rpc_call
2355
2383
  def highlighted_index(self):
@@ -3315,6 +3343,20 @@ class ScatterWaveform(RPCBase):
3315
3343
  The font size of the legend font.
3316
3344
  """
3317
3345
 
3346
+ @property
3347
+ @rpc_call
3348
+ def minimal_crosshair_precision(self) -> "int":
3349
+ """
3350
+ Minimum decimal places for crosshair when dynamic precision is enabled.
3351
+ """
3352
+
3353
+ @minimal_crosshair_precision.setter
3354
+ @rpc_call
3355
+ def minimal_crosshair_precision(self) -> "int":
3356
+ """
3357
+ Minimum decimal places for crosshair when dynamic precision is enabled.
3358
+ """
3359
+
3318
3360
  @property
3319
3361
  @rpc_call
3320
3362
  def main_curve(self) -> "ScatterCurve":
@@ -3789,6 +3831,20 @@ class Waveform(RPCBase):
3789
3831
  The font size of the legend font.
3790
3832
  """
3791
3833
 
3834
+ @property
3835
+ @rpc_call
3836
+ def minimal_crosshair_precision(self) -> "int":
3837
+ """
3838
+ Minimum decimal places for crosshair when dynamic precision is enabled.
3839
+ """
3840
+
3841
+ @minimal_crosshair_precision.setter
3842
+ @rpc_call
3843
+ def minimal_crosshair_precision(self) -> "int":
3844
+ """
3845
+ Minimum decimal places for crosshair when dynamic precision is enabled.
3846
+ """
3847
+
3792
3848
  @property
3793
3849
  @rpc_call
3794
3850
  def curves(self) -> "list[Curve]":
@@ -111,7 +111,7 @@ _Widgets = {
111
111
  self.content += """
112
112
 
113
113
  try:
114
- _plugin_widgets = get_all_plugin_widgets()
114
+ _plugin_widgets = get_all_plugin_widgets().as_dict()
115
115
  plugin_client = get_plugin_client_module()
116
116
  Widgets = _WidgetsEnumType("Widgets", {name: name for name in _plugin_widgets} | _Widgets)
117
117
 
@@ -31,10 +31,9 @@ class RPCWidgetHandler:
31
31
  Returns:
32
32
  None
33
33
  """
34
- clss = get_custom_classes("bec_widgets")
35
- self._widget_classes = get_all_plugin_widgets() | {
36
- cls.__name__: cls for cls in clss.widgets if cls.__name__ not in IGNORE_WIDGETS
37
- }
34
+ self._widget_classes = (
35
+ get_custom_classes("bec_widgets") + get_all_plugin_widgets()
36
+ ).as_dict(IGNORE_WIDGETS)
38
37
 
39
38
  def create_widget(self, widget_type, **kwargs) -> BECWidget:
40
39
  """
@@ -3,12 +3,17 @@ from __future__ import annotations
3
3
  import importlib.metadata
4
4
  import inspect
5
5
  import pkgutil
6
+ import traceback
6
7
  from importlib import util as importlib_util
7
8
  from importlib.machinery import FileFinder, ModuleSpec, SourceFileLoader
8
9
  from types import ModuleType
9
10
  from typing import Generator
10
11
 
11
- from bec_widgets.utils.bec_widget import BECWidget
12
+ from bec_lib.logger import bec_logger
13
+
14
+ from bec_widgets.utils.plugin_utils import BECClassContainer, BECClassInfo
15
+
16
+ logger = bec_logger.logger
12
17
 
13
18
 
14
19
  def _submodule_specs(module: ModuleType) -> tuple[ModuleSpec | None, ...]:
@@ -30,7 +35,12 @@ def _loaded_submodules_from_specs(
30
35
  assert isinstance(
31
36
  submodule.__loader__, SourceFileLoader
32
37
  ), "Module found from FileFinder should have SourceFileLoader!"
33
- submodule.__loader__.exec_module(submodule)
38
+ try:
39
+ submodule.__loader__.exec_module(submodule)
40
+ except Exception as e:
41
+ logger.error(
42
+ f"Error loading plugin {submodule}: \n{''.join(traceback.format_exception(e))}"
43
+ )
34
44
  yield submodule
35
45
 
36
46
 
@@ -41,27 +51,29 @@ def _submodule_by_name(module: ModuleType, name: str):
41
51
  return None
42
52
 
43
53
 
44
- def _get_widgets_from_module(module: ModuleType) -> dict[str, "type[BECWidget]"]:
45
- """Find any BECWidget subclasses in the given module and return them with their names."""
54
+ def _get_widgets_from_module(module: ModuleType) -> BECClassContainer:
55
+ """Find any BECWidget subclasses in the given module and return them with their info."""
46
56
  from bec_widgets.utils.bec_widget import BECWidget # avoid circular import
47
57
 
48
- return dict(
49
- inspect.getmembers(
50
- module,
51
- predicate=lambda item: inspect.isclass(item)
52
- and issubclass(item, BECWidget)
53
- and item is not BECWidget,
54
- )
58
+ classes = inspect.getmembers(
59
+ module,
60
+ predicate=lambda item: inspect.isclass(item)
61
+ and issubclass(item, BECWidget)
62
+ and item is not BECWidget,
63
+ )
64
+ return BECClassContainer(
65
+ BECClassInfo(name=k, module=module.__name__, file=module.__loader__.get_filename(), obj=v)
66
+ for k, v in classes
55
67
  )
56
68
 
57
69
 
58
- def _all_widgets_from_all_submods(module):
70
+ def _all_widgets_from_all_submods(module) -> BECClassContainer:
59
71
  """Recursively load submodules, find any BECWidgets, and return them all as a flat dict."""
60
72
  widgets = _get_widgets_from_module(module)
61
73
  if not hasattr(module, "__path__"):
62
74
  return widgets
63
75
  for submod in _loaded_submodules_from_specs(_submodule_specs(module)):
64
- widgets.update(_all_widgets_from_all_submods(submod))
76
+ widgets += _all_widgets_from_all_submods(submod)
65
77
  return widgets
66
78
 
67
79
 
@@ -75,15 +87,16 @@ def get_plugin_client_module() -> ModuleType | None:
75
87
  return _submodule_by_name(plugin, "client") if (plugin := user_widget_plugin()) else None
76
88
 
77
89
 
78
- def get_all_plugin_widgets() -> dict[str, "type[BECWidget]"]:
90
+ def get_all_plugin_widgets() -> BECClassContainer:
79
91
  """If there is a plugin repository installed, load all widgets from it."""
80
92
  if plugin := user_widget_plugin():
81
93
  return _all_widgets_from_all_submods(plugin)
82
94
  else:
83
- return {}
95
+ return BECClassContainer()
84
96
 
85
97
 
86
98
  if __name__ == "__main__": # pragma: no cover
87
- # print(get_all_plugin_widgets())
99
+
88
100
  client = get_plugin_client_module()
101
+ print(get_all_plugin_widgets())
89
102
  ...
@@ -34,13 +34,21 @@ class Crosshair(QObject):
34
34
  coordinatesChanged2D = Signal(tuple)
35
35
  coordinatesClicked2D = Signal(tuple)
36
36
 
37
- def __init__(self, plot_item: pg.PlotItem, precision: int = 3, parent=None):
37
+ def __init__(
38
+ self,
39
+ plot_item: pg.PlotItem,
40
+ precision: int | None = None,
41
+ *,
42
+ min_precision: int = 2,
43
+ parent=None,
44
+ ):
38
45
  """
39
46
  Crosshair for 1D and 2D plots.
40
47
 
41
48
  Args:
42
49
  plot_item (pyqtgraph.PlotItem): The plot item to which the crosshair will be attached.
43
- precision (int, optional): Number of decimal places to round the coordinates to. Defaults to None.
50
+ precision (int | None, optional): Fixed number of decimal places to display. If *None*, precision is chosen dynamically from the current view range.
51
+ min_precision (int, optional): The lower bound (in decimal places) used when dynamic precision is enabled. Defaults to 2.
44
52
  parent (QObject, optional): Parent object for the QObject. Defaults to None.
45
53
  """
46
54
  super().__init__(parent)
@@ -48,7 +56,9 @@ class Crosshair(QObject):
48
56
  self.is_log_x = None
49
57
  self.is_derivative = None
50
58
  self.plot_item = plot_item
51
- self.precision = precision
59
+ self._precision = precision
60
+ self._min_precision = max(0, int(min_precision)) # ensure non‑negative
61
+
52
62
  self.v_line = pg.InfiniteLine(angle=90, movable=False)
53
63
  self.v_line.skip_auto_range = True
54
64
  self.h_line = pg.InfiniteLine(angle=0, movable=False)
@@ -93,6 +103,56 @@ class Crosshair(QObject):
93
103
 
94
104
  self._connect_to_theme_change()
95
105
 
106
+ @property
107
+ def precision(self) -> int | None:
108
+ """Fixed number of decimals; ``None`` enables dynamic mode."""
109
+ return self._precision
110
+
111
+ @precision.setter
112
+ def precision(self, value: int | None):
113
+ """
114
+ Set the fixed number of decimals to display.
115
+
116
+ Args:
117
+ value(int | None): The number of decimals to display. If `None`, dynamic precision is used based on the view range.
118
+ """
119
+ self._precision = value
120
+
121
+ @property
122
+ def min_precision(self) -> int:
123
+ """Lower bound on decimals when dynamic precision is used."""
124
+ return self._min_precision
125
+
126
+ @min_precision.setter
127
+ def min_precision(self, value: int):
128
+ """
129
+ Set the lower bound on decimals when dynamic precision is used.
130
+
131
+ Args:
132
+ value(int): The minimum number of decimals to display. Must be non-negative.
133
+ """
134
+ self._min_precision = max(0, int(value))
135
+
136
+ def _current_precision(self) -> int:
137
+ """
138
+ Get the current precision based on the view range or fixed precision.
139
+ """
140
+ if self._precision is not None:
141
+ return self._precision
142
+
143
+ # Dynamically choose precision from the smaller visible span
144
+ view_range = self.plot_item.vb.viewRange()
145
+ x_span = abs(view_range[0][1] - view_range[0][0])
146
+ y_span = abs(view_range[1][1] - view_range[1][0])
147
+
148
+ # Ignore zero spans that can appear during initialisation
149
+ spans = [s for s in (x_span, y_span) if s > 0]
150
+ span = min(spans) if spans else 1.0
151
+
152
+ exponent = np.floor(np.log10(span)) # order of magnitude
153
+ decimals = max(0, int(-exponent) + 1)
154
+ return max(self._min_precision, decimals)
155
+
96
156
  def _connect_to_theme_change(self):
97
157
  """Connect to the theme change signal."""
98
158
  qapp = QApplication.instance()
@@ -324,6 +384,7 @@ class Crosshair(QObject):
324
384
  # not sure how we got here, but just to be safe...
325
385
  return
326
386
 
387
+ precision = self._current_precision()
327
388
  for item in self.items:
328
389
  if isinstance(item, pg.PlotDataItem):
329
390
  name = item.name() or str(id(item))
@@ -334,8 +395,8 @@ class Crosshair(QObject):
334
395
  x_snapped_scaled, y_snapped_scaled = self.scale_emitted_coordinates(x, y)
335
396
  coordinate_to_emit = (
336
397
  name,
337
- round(x_snapped_scaled, self.precision),
338
- round(y_snapped_scaled, self.precision),
398
+ round(x_snapped_scaled, precision),
399
+ round(y_snapped_scaled, precision),
339
400
  )
340
401
  self.coordinatesChanged1D.emit(coordinate_to_emit)
341
402
  elif isinstance(item, pg.ImageItem):
@@ -380,6 +441,7 @@ class Crosshair(QObject):
380
441
  # not sure how we got here, but just to be safe...
381
442
  return
382
443
 
444
+ precision = self._current_precision()
383
445
  for item in self.items:
384
446
  if isinstance(item, pg.PlotDataItem):
385
447
  name = item.name() or str(id(item))
@@ -391,8 +453,8 @@ class Crosshair(QObject):
391
453
  x_snapped_scaled, y_snapped_scaled = self.scale_emitted_coordinates(x, y)
392
454
  coordinate_to_emit = (
393
455
  name,
394
- round(x_snapped_scaled, self.precision),
395
- round(y_snapped_scaled, self.precision),
456
+ round(x_snapped_scaled, precision),
457
+ round(y_snapped_scaled, precision),
396
458
  )
397
459
  self.coordinatesClicked1D.emit(coordinate_to_emit)
398
460
  elif isinstance(item, pg.ImageItem):
@@ -443,7 +505,8 @@ class Crosshair(QObject):
443
505
  """
444
506
  x, y = pos
445
507
  x_scaled, y_scaled = self.scale_emitted_coordinates(x, y)
446
- text = f"({x_scaled:.{self.precision}g}, {y_scaled:.{self.precision}g})"
508
+ precision = self._current_precision()
509
+ text = f"({x_scaled:.{precision}f}, {y_scaled:.{precision}f})"
447
510
  for item in self.items:
448
511
  if isinstance(item, pg.ImageItem):
449
512
  image = item.image
@@ -452,7 +515,7 @@ class Crosshair(QObject):
452
515
  ix = int(np.clip(x, 0, image.shape[0] - 1))
453
516
  iy = int(np.clip(y, 0, image.shape[1] - 1))
454
517
  intensity = image[ix, iy]
455
- text += f"\nIntensity: {intensity:.{self.precision}g}"
518
+ text += f"\nIntensity: {intensity:.{precision}f}"
456
519
  break
457
520
  # Update coordinate label
458
521
  self.coord_label.setText(text)
@@ -4,7 +4,7 @@ import importlib
4
4
  import inspect
5
5
  import os
6
6
  from dataclasses import dataclass
7
- from typing import TYPE_CHECKING
7
+ from typing import TYPE_CHECKING, Iterable
8
8
 
9
9
  from bec_lib.plugin_helper import _get_available_plugins
10
10
  from qtpy.QtWidgets import QGraphicsWidget, QWidget
@@ -90,15 +90,15 @@ class BECClassInfo:
90
90
  name: str
91
91
  module: str
92
92
  file: str
93
- obj: type
93
+ obj: type[BECWidget]
94
94
  is_connector: bool = False
95
95
  is_widget: bool = False
96
96
  is_plugin: bool = False
97
97
 
98
98
 
99
99
  class BECClassContainer:
100
- def __init__(self):
101
- self._collection: list[BECClassInfo] = []
100
+ def __init__(self, initial: Iterable[BECClassInfo] = []):
101
+ self._collection: list[BECClassInfo] = list(initial)
102
102
 
103
103
  def __repr__(self):
104
104
  return str(list(cl.name for cl in self.collection))
@@ -106,6 +106,16 @@ class BECClassContainer:
106
106
  def __iter__(self):
107
107
  return self._collection.__iter__()
108
108
 
109
+ def __add__(self, other: BECClassContainer):
110
+ return BECClassContainer((*self, *(c for c in other if c.name not in self.names)))
111
+
112
+ def as_dict(self, ignores: list[str] = []) -> dict[str, type[BECWidget]]:
113
+ """get a dict of {name: Type} for all the entries in the collection.
114
+
115
+ Args:
116
+ ignores(list[str]): a list of class names to exclude from the dictionary."""
117
+ return {c.name: c.obj for c in self if c.name not in ignores}
118
+
109
119
  def add_class(self, class_info: BECClassInfo):
110
120
  """
111
121
  Add a class to the collection.
@@ -115,53 +125,44 @@ class BECClassContainer:
115
125
  """
116
126
  self.collection.append(class_info)
117
127
 
128
+ @property
129
+ def names(self):
130
+ """Return a list of class names"""
131
+ return [c.name for c in self]
132
+
118
133
  @property
119
134
  def collection(self):
120
- """
121
- Get the collection of classes.
122
- """
135
+ """Get the collection of classes."""
123
136
  return self._collection
124
137
 
125
138
  @property
126
139
  def connector_classes(self):
127
- """
128
- Get all connector classes.
129
- """
140
+ """Get all connector classes."""
130
141
  return [info.obj for info in self.collection if info.is_connector]
131
142
 
132
143
  @property
133
144
  def top_level_classes(self):
134
- """
135
- Get all top-level classes.
136
- """
145
+ """Get all top-level classes."""
137
146
  return [info.obj for info in self.collection if info.is_plugin]
138
147
 
139
148
  @property
140
149
  def plugins(self):
141
- """
142
- Get all plugins. These are all classes that are on the top level and are widgets.
143
- """
150
+ """Get all plugins. These are all classes that are on the top level and are widgets."""
144
151
  return [info.obj for info in self.collection if info.is_widget and info.is_plugin]
145
152
 
146
153
  @property
147
154
  def widgets(self):
148
- """
149
- Get all widgets. These are all classes inheriting from BECWidget.
150
- """
155
+ """Get all widgets. These are all classes inheriting from BECWidget."""
151
156
  return [info.obj for info in self.collection if info.is_widget]
152
157
 
153
158
  @property
154
159
  def rpc_top_level_classes(self):
155
- """
156
- Get all top-level classes that are RPC-enabled. These are all classes that users can choose from.
157
- """
160
+ """Get all top-level classes that are RPC-enabled. These are all classes that users can choose from."""
158
161
  return [info.obj for info in self.collection if info.is_plugin and info.is_connector]
159
162
 
160
163
  @property
161
164
  def classes(self):
162
- """
163
- Get all classes.
164
- """
165
+ """Get all classes."""
165
166
  return [info.obj for info in self.collection]
166
167
 
167
168
 
@@ -197,7 +198,7 @@ def get_custom_classes(repo_name: str) -> BECClassContainer:
197
198
  if not hasattr(obj, "__module__") or obj.__module__ != module.__name__:
198
199
  continue
199
200
  if isinstance(obj, type):
200
- class_info = BECClassInfo(name=name, module=module_name, file=path, obj=obj)
201
+ class_info = BECClassInfo(name=name, module=module.__name__, file=path, obj=obj)
201
202
  if issubclass(obj, BECConnector):
202
203
  class_info.is_connector = True
203
204
  if issubclass(obj, BECWidget):
@@ -31,12 +31,9 @@ class UILoader:
31
31
  def __init__(self, parent=None):
32
32
  self.parent = parent
33
33
 
34
- widgets = get_custom_classes("bec_widgets").classes
35
-
36
- self.custom_widgets = {widget.__name__: widget for widget in widgets}
37
-
38
- plugin_widgets = get_all_plugin_widgets()
39
- self.custom_widgets.update(plugin_widgets)
34
+ self.custom_widgets = (
35
+ get_custom_classes("bec_widgets") + get_all_plugin_widgets()
36
+ ).as_dict()
40
37
 
41
38
  if PYSIDE6:
42
39
  self.loader = self.load_ui_pyside6
@@ -88,6 +88,8 @@ class Image(PlotBase):
88
88
  "auto_range_x.setter",
89
89
  "auto_range_y",
90
90
  "auto_range_y.setter",
91
+ "minimal_crosshair_precision",
92
+ "minimal_crosshair_precision.setter",
91
93
  # ImageView Specific Settings
92
94
  "color_map",
93
95
  "color_map.setter",
@@ -91,6 +91,8 @@ class MultiWaveform(PlotBase):
91
91
  "y_log.setter",
92
92
  "legend_label_size",
93
93
  "legend_label_size.setter",
94
+ "minimal_crosshair_precision",
95
+ "minimal_crosshair_precision.setter",
94
96
  # MultiWaveform Specific RPC Access
95
97
  "highlighted_index",
96
98
  "highlighted_index.setter",
@@ -116,6 +116,7 @@ class PlotBase(BECWidget, QWidget):
116
116
  self._user_y_label = ""
117
117
  self._y_label_suffix = ""
118
118
  self._y_axis_units = ""
119
+ self._minimal_crosshair_precision = 3
119
120
 
120
121
  # Plot Indicator Items
121
122
  self.tick_item = BECTickItem(parent=self, plot_item=self.plot_item)
@@ -978,7 +979,9 @@ class PlotBase(BECWidget, QWidget):
978
979
  def hook_crosshair(self) -> None:
979
980
  """Hook the crosshair to all plots."""
980
981
  if self.crosshair is None:
981
- self.crosshair = Crosshair(self.plot_item, precision=3)
982
+ self.crosshair = Crosshair(
983
+ self.plot_item, min_precision=self._minimal_crosshair_precision
984
+ )
982
985
  self.crosshair.crosshairChanged.connect(self.crosshair_position_changed)
983
986
  self.crosshair.crosshairClicked.connect(self.crosshair_position_clicked)
984
987
  self.crosshair.coordinatesChanged1D.connect(self.crosshair_coordinates_changed)
@@ -1006,6 +1009,29 @@ class PlotBase(BECWidget, QWidget):
1006
1009
 
1007
1010
  self.unhook_crosshair()
1008
1011
 
1012
+ @SafeProperty(
1013
+ int, doc="Minimum decimal places for crosshair when dynamic precision is enabled."
1014
+ )
1015
+ def minimal_crosshair_precision(self) -> int:
1016
+ """
1017
+ Minimum decimal places for crosshair when dynamic precision is enabled.
1018
+ """
1019
+ return self._minimal_crosshair_precision
1020
+
1021
+ @minimal_crosshair_precision.setter
1022
+ def minimal_crosshair_precision(self, value: int):
1023
+ """
1024
+ Set the minimum decimal places for crosshair when dynamic precision is enabled.
1025
+
1026
+ Args:
1027
+ value(int): The minimum decimal places to set.
1028
+ """
1029
+ value_int = max(0, int(value))
1030
+ self._minimal_crosshair_precision = value_int
1031
+ if self.crosshair is not None:
1032
+ self.crosshair.min_precision = value_int
1033
+ self.property_changed.emit("minimal_crosshair_precision", value_int)
1034
+
1009
1035
  @SafeSlot()
1010
1036
  def reset(self) -> None:
1011
1037
  """Reset the plot widget."""
@@ -82,6 +82,8 @@ class ScatterWaveform(PlotBase):
82
82
  "y_log.setter",
83
83
  "legend_label_size",
84
84
  "legend_label_size.setter",
85
+ "minimal_crosshair_precision",
86
+ "minimal_crosshair_precision.setter",
85
87
  # Scatter Waveform Specific RPC Access
86
88
  "main_curve",
87
89
  "color_map",
@@ -60,6 +60,7 @@ class AxisSettings(SettingWidget):
60
60
  self.ui.y_grid,
61
61
  self.ui.inner_axes,
62
62
  self.ui.outer_axes,
63
+ self.ui.minimal_crosshair_precision,
63
64
  ]:
64
65
  WidgetIO.connect_widget_change_signal(widget, self.set_property)
65
66
 
@@ -121,6 +122,7 @@ class AxisSettings(SettingWidget):
121
122
  self.ui.y_max,
122
123
  self.ui.y_log,
123
124
  self.ui.y_grid,
125
+ self.ui.minimal_crosshair_precision,
124
126
  ]:
125
127
  property_name = widget.objectName()
126
128
  value = getattr(self.target_widget, property_name)
@@ -144,6 +146,7 @@ class AxisSettings(SettingWidget):
144
146
  self.ui.y_grid,
145
147
  self.ui.outer_axes,
146
148
  self.ui.inner_axes,
149
+ self.ui.minimal_crosshair_precision,
147
150
  ]:
148
151
  property_name = widget.objectName()
149
152
  value = WidgetIO.get_value(widget)
@@ -14,21 +14,78 @@
14
14
  <string>Form</string>
15
15
  </property>
16
16
  <layout class="QGridLayout" name="gridLayout">
17
- <item row="1" column="0">
18
- <widget class="QLabel" name="label">
19
- <property name="text">
20
- <string>Inner Axes</string>
21
- </property>
22
- </widget>
23
- </item>
24
- <item row="1" column="1">
25
- <widget class="ToggleSwitch" name="inner_axes"/>
26
- </item>
27
- <item row="1" column="2">
28
- <widget class="QLabel" name="label_outer_axes">
29
- <property name="text">
30
- <string>Outer Axes</string>
17
+ <item row="2" column="2" colspan="2">
18
+ <widget class="QGroupBox" name="y_axis_box">
19
+ <property name="title">
20
+ <string>Y Axis</string>
31
21
  </property>
22
+ <layout class="QGridLayout" name="gridLayout_5">
23
+ <item row="1" column="0" colspan="2">
24
+ <widget class="QLabel" name="y_min_label">
25
+ <property name="text">
26
+ <string>Min</string>
27
+ </property>
28
+ </widget>
29
+ </item>
30
+ <item row="0" column="2">
31
+ <widget class="QLineEdit" name="y_label"/>
32
+ </item>
33
+ <item row="3" column="0">
34
+ <widget class="QLabel" name="y_scale_label">
35
+ <property name="text">
36
+ <string>Log</string>
37
+ </property>
38
+ </widget>
39
+ </item>
40
+ <item row="0" column="0">
41
+ <widget class="QLabel" name="y_label_label">
42
+ <property name="text">
43
+ <string>Label</string>
44
+ </property>
45
+ </widget>
46
+ </item>
47
+ <item row="2" column="0">
48
+ <widget class="QLabel" name="y_max_label">
49
+ <property name="text">
50
+ <string>Max</string>
51
+ </property>
52
+ </widget>
53
+ </item>
54
+ <item row="4" column="0">
55
+ <widget class="QLabel" name="y_grid_label">
56
+ <property name="text">
57
+ <string>Grid</string>
58
+ </property>
59
+ </widget>
60
+ </item>
61
+ <item row="3" column="2">
62
+ <widget class="ToggleSwitch" name="y_log">
63
+ <property name="checked" stdset="0">
64
+ <bool>false</bool>
65
+ </property>
66
+ </widget>
67
+ </item>
68
+ <item row="4" column="2">
69
+ <widget class="ToggleSwitch" name="y_grid">
70
+ <property name="checked" stdset="0">
71
+ <bool>false</bool>
72
+ </property>
73
+ </widget>
74
+ </item>
75
+ <item row="1" column="2">
76
+ <widget class="BECSpinBox" name="y_min">
77
+ <property name="alignment">
78
+ <set>Qt::AlignmentFlag::AlignCenter</set>
79
+ </property>
80
+ <property name="buttonSymbols">
81
+ <enum>QAbstractSpinBox::ButtonSymbols::UpDownArrows</enum>
82
+ </property>
83
+ </widget>
84
+ </item>
85
+ <item row="2" column="2">
86
+ <widget class="BECSpinBox" name="y_max"/>
87
+ </item>
88
+ </layout>
32
89
  </widget>
33
90
  </item>
34
91
  <item row="1" column="3">
@@ -38,6 +95,13 @@
38
95
  </property>
39
96
  </widget>
40
97
  </item>
98
+ <item row="1" column="0">
99
+ <widget class="QLabel" name="label">
100
+ <property name="text">
101
+ <string>Inner Axes</string>
102
+ </property>
103
+ </widget>
104
+ </item>
41
105
  <item row="2" column="0" colspan="2">
42
106
  <widget class="QGroupBox" name="x_axis_box">
43
107
  <property name="title">
@@ -105,80 +169,6 @@
105
169
  </layout>
106
170
  </widget>
107
171
  </item>
108
- <item row="2" column="2" colspan="2">
109
- <widget class="QGroupBox" name="y_axis_box">
110
- <property name="title">
111
- <string>Y Axis</string>
112
- </property>
113
- <layout class="QGridLayout" name="gridLayout_5">
114
- <item row="1" column="0" colspan="2">
115
- <widget class="QLabel" name="y_min_label">
116
- <property name="text">
117
- <string>Min</string>
118
- </property>
119
- </widget>
120
- </item>
121
- <item row="0" column="2">
122
- <widget class="QLineEdit" name="y_label"/>
123
- </item>
124
- <item row="3" column="0">
125
- <widget class="QLabel" name="y_scale_label">
126
- <property name="text">
127
- <string>Log</string>
128
- </property>
129
- </widget>
130
- </item>
131
- <item row="0" column="0">
132
- <widget class="QLabel" name="y_label_label">
133
- <property name="text">
134
- <string>Label</string>
135
- </property>
136
- </widget>
137
- </item>
138
- <item row="2" column="0">
139
- <widget class="QLabel" name="y_max_label">
140
- <property name="text">
141
- <string>Max</string>
142
- </property>
143
- </widget>
144
- </item>
145
- <item row="4" column="0">
146
- <widget class="QLabel" name="y_grid_label">
147
- <property name="text">
148
- <string>Grid</string>
149
- </property>
150
- </widget>
151
- </item>
152
- <item row="3" column="2">
153
- <widget class="ToggleSwitch" name="y_log">
154
- <property name="checked" stdset="0">
155
- <bool>false</bool>
156
- </property>
157
- </widget>
158
- </item>
159
- <item row="4" column="2">
160
- <widget class="ToggleSwitch" name="y_grid">
161
- <property name="checked" stdset="0">
162
- <bool>false</bool>
163
- </property>
164
- </widget>
165
- </item>
166
- <item row="1" column="2">
167
- <widget class="BECSpinBox" name="y_min">
168
- <property name="alignment">
169
- <set>Qt::AlignmentFlag::AlignCenter</set>
170
- </property>
171
- <property name="buttonSymbols">
172
- <enum>QAbstractSpinBox::ButtonSymbols::UpDownArrows</enum>
173
- </property>
174
- </widget>
175
- </item>
176
- <item row="2" column="2">
177
- <widget class="BECSpinBox" name="y_max"/>
178
- </item>
179
- </layout>
180
- </widget>
181
- </item>
182
172
  <item row="0" column="0" colspan="4">
183
173
  <layout class="QHBoxLayout" name="horizontalLayout">
184
174
  <item>
@@ -191,8 +181,41 @@
191
181
  <item>
192
182
  <widget class="QLineEdit" name="title"/>
193
183
  </item>
184
+ <item>
185
+ <widget class="QLabel" name="label_2">
186
+ <property name="text">
187
+ <string>Precision</string>
188
+ </property>
189
+ </widget>
190
+ </item>
191
+ <item>
192
+ <widget class="QSpinBox" name="minimal_crosshair_precision">
193
+ <property name="toolTip">
194
+ <string>Minimal Crosshair Precision</string>
195
+ </property>
196
+ <property name="alignment">
197
+ <set>Qt::AlignmentFlag::AlignCenter</set>
198
+ </property>
199
+ <property name="maximum">
200
+ <number>20</number>
201
+ </property>
202
+ <property name="value">
203
+ <number>3</number>
204
+ </property>
205
+ </widget>
206
+ </item>
194
207
  </layout>
195
208
  </item>
209
+ <item row="1" column="2">
210
+ <widget class="QLabel" name="label_outer_axes">
211
+ <property name="text">
212
+ <string>Outer Axes</string>
213
+ </property>
214
+ </widget>
215
+ </item>
216
+ <item row="1" column="1">
217
+ <widget class="ToggleSwitch" name="inner_axes"/>
218
+ </item>
196
219
  </layout>
197
220
  </widget>
198
221
  <customwidgets>
@@ -6,15 +6,84 @@
6
6
  <rect>
7
7
  <x>0</x>
8
8
  <y>0</y>
9
- <width>241</width>
10
- <height>526</height>
9
+ <width>250</width>
10
+ <height>612</height>
11
11
  </rect>
12
12
  </property>
13
13
  <property name="windowTitle">
14
14
  <string>Form</string>
15
15
  </property>
16
- <layout class="QGridLayout" name="gridLayout">
17
- <item row="4" column="0" colspan="2">
16
+ <layout class="QVBoxLayout" name="verticalLayout">
17
+ <item>
18
+ <widget class="QGroupBox" name="general_box">
19
+ <property name="title">
20
+ <string>General</string>
21
+ </property>
22
+ <layout class="QGridLayout" name="gridLayout_2">
23
+ <item row="4" column="0">
24
+ <widget class="QLabel" name="label_outer_axes">
25
+ <property name="text">
26
+ <string>Outer Axes</string>
27
+ </property>
28
+ </widget>
29
+ </item>
30
+ <item row="4" column="1">
31
+ <widget class="ToggleSwitch" name="outer_axes">
32
+ <property name="checked" stdset="0">
33
+ <bool>false</bool>
34
+ </property>
35
+ </widget>
36
+ </item>
37
+ <item row="1" column="1">
38
+ <widget class="QLineEdit" name="title"/>
39
+ </item>
40
+ <item row="3" column="0">
41
+ <widget class="QLabel" name="label">
42
+ <property name="text">
43
+ <string>Inner Axes</string>
44
+ </property>
45
+ </widget>
46
+ </item>
47
+ <item row="1" column="0">
48
+ <widget class="QLabel" name="plot_title_label">
49
+ <property name="text">
50
+ <string>Plot Title</string>
51
+ </property>
52
+ </widget>
53
+ </item>
54
+ <item row="3" column="1">
55
+ <widget class="ToggleSwitch" name="inner_axes"/>
56
+ </item>
57
+ <item row="2" column="0">
58
+ <widget class="QLabel" name="label_2">
59
+ <property name="toolTip">
60
+ <string>Minimal Crosshair Precision</string>
61
+ </property>
62
+ <property name="text">
63
+ <string>Precision</string>
64
+ </property>
65
+ </widget>
66
+ </item>
67
+ <item row="2" column="1">
68
+ <widget class="QSpinBox" name="minimal_crosshair_precision">
69
+ <property name="toolTip">
70
+ <string>Minimal Crosshair Precision</string>
71
+ </property>
72
+ <property name="alignment">
73
+ <set>Qt::AlignmentFlag::AlignCenter</set>
74
+ </property>
75
+ <property name="maximum">
76
+ <number>20</number>
77
+ </property>
78
+ <property name="value">
79
+ <number>3</number>
80
+ </property>
81
+ </widget>
82
+ </item>
83
+ </layout>
84
+ </widget>
85
+ </item>
86
+ <item>
18
87
  <widget class="QGroupBox" name="x_axis_box">
19
88
  <property name="title">
20
89
  <string>X Axis</string>
@@ -81,28 +150,7 @@
81
150
  </layout>
82
151
  </widget>
83
152
  </item>
84
- <item row="0" column="0" colspan="2">
85
- <layout class="QHBoxLayout" name="horizontalLayout">
86
- <item>
87
- <widget class="QLabel" name="plot_title_label">
88
- <property name="text">
89
- <string>Plot Title</string>
90
- </property>
91
- </widget>
92
- </item>
93
- <item>
94
- <widget class="QLineEdit" name="title"/>
95
- </item>
96
- </layout>
97
- </item>
98
- <item row="2" column="0">
99
- <widget class="QLabel" name="label_outer_axes">
100
- <property name="text">
101
- <string>Outer Axes</string>
102
- </property>
103
- </widget>
104
- </item>
105
- <item row="5" column="0" colspan="2">
153
+ <item>
106
154
  <widget class="QGroupBox" name="y_axis_box">
107
155
  <property name="title">
108
156
  <string>Y Axis</string>
@@ -169,23 +217,6 @@
169
217
  </layout>
170
218
  </widget>
171
219
  </item>
172
- <item row="2" column="1">
173
- <widget class="ToggleSwitch" name="outer_axes">
174
- <property name="checked" stdset="0">
175
- <bool>false</bool>
176
- </property>
177
- </widget>
178
- </item>
179
- <item row="1" column="0">
180
- <widget class="QLabel" name="label">
181
- <property name="text">
182
- <string>Inner Axes</string>
183
- </property>
184
- </widget>
185
- </item>
186
- <item row="1" column="1">
187
- <widget class="ToggleSwitch" name="inner_axes"/>
188
- </item>
189
220
  </layout>
190
221
  </widget>
191
222
  <customwidgets>
@@ -86,6 +86,8 @@ class Waveform(PlotBase):
86
86
  "y_log.setter",
87
87
  "legend_label_size",
88
88
  "legend_label_size.setter",
89
+ "minimal_crosshair_precision",
90
+ "minimal_crosshair_precision.setter",
89
91
  # Waveform Specific RPC Access
90
92
  "curves",
91
93
  "x_mode",
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bec_widgets
3
- Version: 2.8.2
3
+ Version: 2.8.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
@@ -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=YGfWQy_ddqWGu9GqJDJf0BPzoBedxfKWxPry0uy06ZQ,289047
5
+ CHANGELOG.md,sha256=zrzPgv4SdkfI87Bynz1AKCww3iy1vOyt7iaEzOy2M4Q,289871
6
6
  LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
7
- PKG-INFO,sha256=NhCIQmecYV7pDH3iYVHEpx1aI2g9IsnWWGUwkuiu45Q,1273
7
+ PKG-INFO,sha256=i_3fowZja6vwAtG6rabvccdxkcoUynup_6DHrxGLYuw,1273
8
8
  README.md,sha256=oY5Jc1uXehRASuwUJ0umin2vfkFh7tHF-LLruHTaQx0,3560
9
- pyproject.toml,sha256=iSn7wp1hoYioNcBgHcMH86J2MBkCKCTj52r-BLVT18Q,2902
9
+ pyproject.toml,sha256=s2v1q74HdC09fmE082F9bwYEDALJFrH_W0PPKu7Ykgo,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
@@ -17,7 +17,7 @@ pyproject.toml,sha256=iSn7wp1hoYioNcBgHcMH86J2MBkCKCTj52r-BLVT18Q,2902
17
17
  .github/scripts/pr_issue_sync/requirements.txt,sha256=bFVVn4_gJjJ-BCykMhfQZLPaG2cthrKwM_skcG9wJkU,17
18
18
  .github/workflows/check_pr.yml,sha256=jKMtYBJTNRAdw_MAS4JzdKVSoNrv8nxUQMqobsYFAXw,903
19
19
  .github/workflows/ci.yml,sha256=OVZt0UxN4wQInuMucuQcKsvHDiz27sLeuQRskxjtkY0,1863
20
- .github/workflows/end2end-conda.yml,sha256=N7q_sOZL1Mcivdkb8YIdvqbkkaG79rjHDQRpR2xPdtM,1794
20
+ .github/workflows/end2end-conda.yml,sha256=S9EyUoc084J0sUBg2_jgDAbvPZ9jrzEHOLZS91JF9Xc,2076
21
21
  .github/workflows/formatter.yml,sha256=CdUVrRxWyVes9y-Ez3jiCJXqANPJtl6kfpGQxeWMhcQ,1694
22
22
  .github/workflows/generate-cli-check.yml,sha256=b6TcK8F5Hy0sFjgXpk0w3BO9eMDZw9WysTl3P7zEPuQ,1742
23
23
  .github/workflows/pytest-matrix.yml,sha256=0gL5wNPJKJF1JapqstlYNYiJ44ko05uaTD7epa7smVw,1834
@@ -27,7 +27,7 @@ pyproject.toml,sha256=iSn7wp1hoYioNcBgHcMH86J2MBkCKCTj52r-BLVT18Q,2902
27
27
  bec_widgets/__init__.py,sha256=mZhbU6zfFt8-A7q_do74ie89budSevwpKZ6FKtEBdmo,170
28
28
  bec_widgets/applications/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
29
29
  bec_widgets/applications/bw_launch.py,sha256=4lngXb8Ht_cvQtCwjjbAoqPNuE2V0Ja5WIPHpwgjcRI,687
30
- bec_widgets/applications/launch_window.py,sha256=vKuGNv47jBYlkydk5NrDcrlZhU9wehIYfu7s-IOh7ks,21862
30
+ bec_widgets/applications/launch_window.py,sha256=bYvgFqg1bw3obV7ETKhpqy5QFTEiAaBAAWfh25Yuzm4,21878
31
31
  bec_widgets/assets/app_icons/BEC-General-App.png,sha256=hc2ktly53DZAbl_rE3cb-vdRa5gtdCmBEjfwm2y5P4g,447581
32
32
  bec_widgets/assets/app_icons/alignment_1d.png,sha256=5VouaWieb4lVv3wUBNHaO5ovUW2Fk25aTKYQzOWy0mg,2071069
33
33
  bec_widgets/assets/app_icons/auto_update.png,sha256=YKoAJTWAlWzreYvOm0BttDRFr29tulolZgKirRhAFlA,2197066
@@ -35,14 +35,14 @@ 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=GOlZajpUb1yMhAJgpsw8kjMFYIudA83l4jN7-XMSsvA,93483
38
+ bec_widgets/cli/client.py,sha256=qtAdEDsNub66VLi0uInX4RUQnSaFW86a-I_0bj4um_A,95077
39
39
  bec_widgets/cli/client_utils.py,sha256=F2hyt--jL53bN8NoWifNUMqwwx5FbpS6I1apERdTRzM,18114
40
- bec_widgets/cli/generate_cli.py,sha256=xcPNyJoa3IjddX1yEDY45tT-Cs4jO5cQLUmcEubKs44,10976
40
+ bec_widgets/cli/generate_cli.py,sha256=K_wMxo2XBUn92SnY3dSrlyUn8ax6Y20QBGCuP284DsQ,10986
41
41
  bec_widgets/cli/server.py,sha256=h7QyBOOGjyrP_fxJIIOSEMc4E06cLG0JyaofjNV6oCA,5671
42
42
  bec_widgets/cli/rpc/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  bec_widgets/cli/rpc/rpc_base.py,sha256=lqRr3IUqEKNLS_wHYrFbIr824kj6OYH6ky0Lwb-NovU,11130
44
44
  bec_widgets/cli/rpc/rpc_register.py,sha256=2XBqPdMhJyWPsbV0ZVhl7YL6Yk6gh-VA8BOYi9jistM,5820
45
- bec_widgets/cli/rpc/rpc_widget_handler.py,sha256=-i_jLIclfmIae7vatuvMBRMOg1w7jiKUQiTWaEQXqkc,1746
45
+ bec_widgets/cli/rpc/rpc_widget_handler.py,sha256=U_GhpWs8rHXGRVkdYHNeOXBV2pY2yrYAWgnivi4kc2c,1675
46
46
  bec_widgets/examples/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
47
47
  bec_widgets/examples/general_app/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
48
48
  bec_widgets/examples/general_app/general_app.py,sha256=PoFCTuA_1yqrpgthASpYFgH7JDUZTcXAPZ5h0e3XZfc,3053
@@ -63,7 +63,7 @@ bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U
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
65
65
  bec_widgets/utils/bec_dispatcher.py,sha256=y9EFIgU3JqIs7R10XnLh0I1_Skts9sbPe3ijOVJumYs,9837
66
- bec_widgets/utils/bec_plugin_helper.py,sha256=efg97QDAqhZYeqE1wk3vEgkFuhNewg4rvJrtB7mRCAE,3139
66
+ bec_widgets/utils/bec_plugin_helper.py,sha256=tLXEyzh0LWuRp-1XhJg32m-hUSLfRStC0YRUWKdhY5Q,3565
67
67
  bec_widgets/utils/bec_signal_proxy.py,sha256=Yc08fdBEDABrowwNPSngT9-28R8FD4ml7oTL6BoMyEE,3263
68
68
  bec_widgets/utils/bec_table.py,sha256=nA2b8ukSeUfquFMAxGrUVOqdrzMoDYD6O_4EYbOG2zk,717
69
69
  bec_widgets/utils/bec_widget.py,sha256=jS888GioWKIJafMq5r1YhJ4vgORqiw0qHbxeSbE0Aec,4119
@@ -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=zWz4rkVD_HQYWhYzX8asjjb1z_G0V3QqyrOXx6f4xXI,20106
74
+ bec_widgets/utils/crosshair.py,sha256=UZNM4GQnpYD6arN6CAgM9CTQ4LX6t24NoHozPU244Fc,22310
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
@@ -84,7 +84,7 @@ bec_widgets/utils/name_utils.py,sha256=VEHq6lRty1yif3h1EK2nBRNQquGK-l_p-6H9Fmp6B
84
84
  bec_widgets/utils/ophyd_kind_util.py,sha256=3azqxajYZY4crM04NqDqbEx7zPkWzZGYtWeCzfJu6UE,603
85
85
  bec_widgets/utils/palette_viewer.py,sha256=9FEkDy4sDkVpgazGyk149_Qv1DzJdXX6SpzlIPKoHqc,6304
86
86
  bec_widgets/utils/plot_indicator_items.py,sha256=d3NwWGMUiTJzab1w4dv0YZBJZza8ZMAVea9zdsOL7oM,9687
87
- bec_widgets/utils/plugin_utils.py,sha256=4Ne5ls891jZY6tpDe9Fq_w_Vaog6BZ7f6YSONhTUBP4,7265
87
+ bec_widgets/utils/plugin_utils.py,sha256=EF2ICP9yb9S0xSc_lq5nyBly1sbZJjSOGrocPDJg0H0,7801
88
88
  bec_widgets/utils/redis_message_waiter.py,sha256=fvL_QgC0cTDv_FPJdRyp5AKjf401EJU4z3r38p47ydY,1745
89
89
  bec_widgets/utils/reference_utils.py,sha256=8pq06TOvZBZdim0G6hvPJXzVDib7ve4o-Ptvfp563nk,2859
90
90
  bec_widgets/utils/round_frame.py,sha256=SLtoPi8sfJvjfK7G_a4_sRBMGivF5fTHNwMLq93-cVM,4920
@@ -95,7 +95,7 @@ bec_widgets/utils/settings_dialog.py,sha256=1z6noC9k6BSIGAw12DvHHiW3LmvPquaGMjWS
95
95
  bec_widgets/utils/side_panel.py,sha256=enxcQOwJOMfD3MxgPA9mQSKSX_F6Omy2zePncYDW1FA,14193
96
96
  bec_widgets/utils/thread_checker.py,sha256=rDNuA3X6KQyA7JPb67mccTg0z8YkInynLAENQDQpbuE,1607
97
97
  bec_widgets/utils/toolbar.py,sha256=nQM2h5WqTmQDxlU4GMk6OyRJr-0_4VAKSbug7yOUwWY,40769
98
- bec_widgets/utils/ui_loader.py,sha256=1PtGW36FWxEaHq0_T0ECLANisFyZcMDQJezEKgSwwIg,5118
98
+ bec_widgets/utils/ui_loader.py,sha256=E1tAprb5Vqc3gttANwuCaAx07paGMH6ezGbEDbb1-kE,5002
99
99
  bec_widgets/utils/validator_delegate.py,sha256=Emj1WF6W8Ke1ruBWUfmHdVJpmOSPezuOt4zvQTay_44,442
100
100
  bec_widgets/utils/widget_io.py,sha256=afR7i59fw2WrEQCmkH5dwhz1uNjfMPnJTIhE8NWVBsU,21552
101
101
  bec_widgets/utils/widget_state_manager.py,sha256=tzrxVmnGa6IHSEdeh-R68aQ934BsuS9nLQbwYQ78J90,7651
@@ -257,9 +257,9 @@ bec_widgets/widgets/games/minesweeper.pyproject,sha256=wHrLKY3H8uNiVgb9BIrj4S0Je
257
257
  bec_widgets/widgets/games/minesweeper_plugin.py,sha256=oPEjSTpdIIkvuGThHxhVS8Rp47DWiaXHROtm8NJWYwo,1255
258
258
  bec_widgets/widgets/games/register_minesweeper.py,sha256=8fgMBD3yB-5_eGqhG_qxpj3igXDK9WZfHrdYcA1aqz8,467
259
259
  bec_widgets/widgets/plots/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
260
- bec_widgets/widgets/plots/plot_base.py,sha256=l8qzLybw6PEBZI5gRXaLY0AX_v81e50TFxOO1Muh774,34872
260
+ bec_widgets/widgets/plots/plot_base.py,sha256=GETUsx51BE_Tuop8bC-KiFVrkR82TJ5S0cr7siouSWM,35848
261
261
  bec_widgets/widgets/plots/image/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
262
- bec_widgets/widgets/plots/image/image.py,sha256=FA2a583iWkDi_zydw_OYi4NEiGHXtM_O0PxxSmdgUiY,42042
262
+ bec_widgets/widgets/plots/image/image.py,sha256=4PamL6EqwpmLMpSagYsBS7ZpU0fXVlzMg7518Tqo5EI,42127
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
@@ -282,7 +282,7 @@ bec_widgets/widgets/plots/motor_map/settings/motor_map_settings.ui,sha256=lEKjDU
282
282
  bec_widgets/widgets/plots/motor_map/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
283
283
  bec_widgets/widgets/plots/motor_map/toolbar_bundles/motor_selection.py,sha256=rho8gUGs7cL0YkVYwFFy2FzquB81g5PljpDizfkDTKI,2714
284
284
  bec_widgets/widgets/plots/multi_waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
285
- bec_widgets/widgets/plots/multi_waveform/multi_waveform.py,sha256=vSjjE5TOfvVAIG7qpPr2vBzvvyT9Nr14CvOA6ULN-dI,17536
285
+ bec_widgets/widgets/plots/multi_waveform/multi_waveform.py,sha256=Zwtbv1rgDAbZNtwMM76_KLr0Sy4CyaCegRIsdKWqnHM,17621
286
286
  bec_widgets/widgets/plots/multi_waveform/multi_waveform.pyproject,sha256=DnGmG0HymVvUPLFlOYleIW_pJpDrLIbSne5jrI1Gdfk,32
287
287
  bec_widgets/widgets/plots/multi_waveform/multi_waveform_plugin.py,sha256=pSds2QM6VI5BuCNUIZTzFUd0B0beHBe1dcdBgb1AoGY,1296
288
288
  bec_widgets/widgets/plots/multi_waveform/register_multi_waveform.py,sha256=rP9SfyTwmrX-UXcr6Mk73r8jf8s75-1GX2sNh04QHvU,489
@@ -296,7 +296,7 @@ bec_widgets/widgets/plots/roi/image_roi.py,sha256=HIDlsRJtsZf2Iu09tHQuRXI0jFUiBJ
296
296
  bec_widgets/widgets/plots/scatter_waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
297
297
  bec_widgets/widgets/plots/scatter_waveform/register_scatter_waveform.py,sha256=KttVjlAK3PfP9tyMfLnqEm6kphap8NZyqyaRry8oebY,514
298
298
  bec_widgets/widgets/plots/scatter_waveform/scatter_curve.py,sha256=nCyZ_6EunS1m5XkLB-CwfBV9L4IX04D9SpHlHc8zG_I,6763
299
- bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py,sha256=8d6MF5ud8HzqPGQmYNhWpEp8ac9eDRRM5Z4T5Zq77Fk,19794
299
+ bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.py,sha256=kan90pUjfEeJ4z85ZBWnUfEM9XwV6Ehk4XgSD1jMgD0,19879
300
300
  bec_widgets/widgets/plots/scatter_waveform/scatter_waveform.pyproject,sha256=Z_bnXkjDCBJPBCh1_wX3TyCn75aNBYU8SXxxu6DAj0Q,34
301
301
  bec_widgets/widgets/plots/scatter_waveform/scatter_waveform_plugin.py,sha256=3hpAk08kWSi6eE8NB-_vpHbYjBjGOHiCd42MJzmvFw0,1318
302
302
  bec_widgets/widgets/plots/scatter_waveform/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -304,9 +304,9 @@ bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_setting.py,sha
304
304
  bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_horizontal.ui,sha256=UdUbOWRMonvsfXSH-NQenDGh3Of4xcirU4kXMniENgY,5013
305
305
  bec_widgets/widgets/plots/scatter_waveform/settings/scatter_curve_settings_vertical.ui,sha256=68BUUYkMd6fBQlAcV1Co1FRCSDrJ0m8OAsUj_qxoZqU,7814
306
306
  bec_widgets/widgets/plots/setting_menus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
307
- bec_widgets/widgets/plots/setting_menus/axis_settings.py,sha256=v-esAvJG8SeVv3hWf5L8jyF03jRjd0WvJ9fzbffHY7s,5233
308
- bec_widgets/widgets/plots/setting_menus/axis_settings_horizontal.ui,sha256=v8jJfPLnhORVfJukhRmygrPobMmJLufA4e3C08QeO-o,9526
309
- bec_widgets/widgets/plots/setting_menus/axis_settings_vertical.ui,sha256=k4vsQgZyKZkK3JiOXaQmvgR3IHy90mb4upGAtIwBOsA,9104
307
+ bec_widgets/widgets/plots/setting_menus/axis_settings.py,sha256=REGperW9vSS_ZtZH_zXhId_t4-qax0dFFbHgK84HX88,5380
308
+ bec_widgets/widgets/plots/setting_menus/axis_settings_horizontal.ui,sha256=rXUyB6ciPtYRWBk9-SJpiBl80akCst3U3Nly3_TZiEg,10632
309
+ bec_widgets/widgets/plots/setting_menus/axis_settings_vertical.ui,sha256=-5SYn_o4-EuhG2zaBFVbB5lWs2CpWzB2cYaWXuw-rns,11017
310
310
  bec_widgets/widgets/plots/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
311
311
  bec_widgets/widgets/plots/toolbar_bundles/mouse_interactions.py,sha256=gdQ6Ggdq0rhELncCCUBXwi_k16xXWAgHOtgNmND58cA,4169
312
312
  bec_widgets/widgets/plots/toolbar_bundles/plot_export.py,sha256=43JnNwmp0lAVvSArZ0qa8SWwEAHwrZWBUse0nhlqMkA,3049
@@ -315,7 +315,7 @@ bec_widgets/widgets/plots/toolbar_bundles/save_state.py,sha256=H3fu-bRzNIycCUFb2
315
315
  bec_widgets/widgets/plots/waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
316
316
  bec_widgets/widgets/plots/waveform/curve.py,sha256=KlcGbd60lPO9BYcca08fMhWkfx5qu4O9IbSNTwvajGM,10401
317
317
  bec_widgets/widgets/plots/waveform/register_waveform.py,sha256=pdcLCYKkLkSb-5DqbJdC6M3JyoXQBRVAKf7BZVCto80,467
318
- bec_widgets/widgets/plots/waveform/waveform.py,sha256=tNoeqcPPv0nsJT87qSwJFv2jGATvRayxQQjAoaaLKmQ,68552
318
+ bec_widgets/widgets/plots/waveform/waveform.py,sha256=g4aAaeRgvOrwMW6Ju1cx-OKc0lXqN21Xo0rxbAcGBgk,68637
319
319
  bec_widgets/widgets/plots/waveform/waveform.pyproject,sha256=X2T6d4JGt9YSI28e-myjXh1YkUM4Yr3kNb0-F84KvUA,26
320
320
  bec_widgets/widgets/plots/waveform/waveform_plugin.py,sha256=2AZPtBHs75l9cdhwQnY3jpIMRPUUqK3RNvQbTvrFyvg,1237
321
321
  bec_widgets/widgets/plots/waveform/settings/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -404,8 +404,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=O
404
404
  bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
405
405
  bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
406
406
  bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
407
- bec_widgets-2.8.2.dist-info/METADATA,sha256=NhCIQmecYV7pDH3iYVHEpx1aI2g9IsnWWGUwkuiu45Q,1273
408
- bec_widgets-2.8.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
409
- bec_widgets-2.8.2.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
410
- bec_widgets-2.8.2.dist-info/licenses/LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
411
- bec_widgets-2.8.2.dist-info/RECORD,,
407
+ bec_widgets-2.8.4.dist-info/METADATA,sha256=i_3fowZja6vwAtG6rabvccdxkcoUynup_6DHrxGLYuw,1273
408
+ bec_widgets-2.8.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
409
+ bec_widgets-2.8.4.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
410
+ bec_widgets-2.8.4.dist-info/licenses/LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
411
+ bec_widgets-2.8.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.8.2"
7
+ version = "2.8.4"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [