bec-widgets 2.15.1__py3-none-any.whl → 2.16.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,254 @@
1
+ from ast import literal_eval
2
+
3
+ from bec_lib.atlas_models import Device as DeviceConfigModel
4
+ from bec_lib.config_helper import CONF as DEVICE_CONF_KEYS
5
+ from bec_lib.config_helper import ConfigHelper
6
+ from bec_lib.logger import bec_logger
7
+ from qtpy.QtCore import QObject, QRunnable, QSize, Qt, QThreadPool, Signal
8
+ from qtpy.QtWidgets import (
9
+ QApplication,
10
+ QDialog,
11
+ QDialogButtonBox,
12
+ QLabel,
13
+ QStackedLayout,
14
+ QVBoxLayout,
15
+ QWidget,
16
+ )
17
+
18
+ from bec_widgets.utils.bec_widget import BECWidget
19
+ from bec_widgets.utils.error_popups import SafeSlot
20
+ from bec_widgets.widgets.services.device_browser.device_item.device_config_form import (
21
+ DeviceConfigForm,
22
+ )
23
+ from bec_widgets.widgets.utility.spinner.spinner import SpinnerWidget
24
+
25
+ logger = bec_logger.logger
26
+
27
+
28
+ class _CommSignals(QObject):
29
+ error = Signal(Exception)
30
+ done = Signal()
31
+
32
+
33
+ class _CommunicateUpdate(QRunnable):
34
+
35
+ def __init__(self, config_helper: ConfigHelper, device: str, config: dict) -> None:
36
+ super().__init__()
37
+ self.config_helper = config_helper
38
+ self.device = device
39
+ self.config = config
40
+ self.signals = _CommSignals()
41
+
42
+ @SafeSlot()
43
+ def run(self):
44
+ try:
45
+ timeout = self.config_helper.suggested_timeout_s(self.config)
46
+ RID = self.config_helper.send_config_request(
47
+ action="update", config={self.device: self.config}, wait_for_response=False
48
+ )
49
+ logger.info("Waiting for config reply")
50
+ reply = self.config_helper.wait_for_config_reply(RID, timeout=timeout)
51
+ self.config_helper.handle_update_reply(reply, RID, timeout)
52
+ logger.info("Done updating config!")
53
+ except Exception as e:
54
+ self.signals.error.emit(e)
55
+ finally:
56
+ self.signals.done.emit()
57
+
58
+
59
+ class DeviceConfigDialog(BECWidget, QDialog):
60
+ RPC = False
61
+ applied = Signal()
62
+
63
+ def __init__(
64
+ self,
65
+ parent=None,
66
+ device: str | None = None,
67
+ config_helper: ConfigHelper | None = None,
68
+ **kwargs,
69
+ ):
70
+ super().__init__(parent=parent, **kwargs)
71
+ self._config_helper = config_helper or ConfigHelper(
72
+ self.client.connector, self.client._service_name
73
+ )
74
+ self.threadpool = QThreadPool()
75
+ self._device = device
76
+ self.setWindowTitle(f"Edit config for: {device}")
77
+ self._container = QStackedLayout()
78
+ self._container.setStackingMode(QStackedLayout.StackAll)
79
+
80
+ self._layout = QVBoxLayout()
81
+ user_warning = QLabel(
82
+ "Warning: edit items here at your own risk - minimal validation is applied to the entered values.\n"
83
+ "Items in the deviceConfig dictionary should correspond to python literals, e.g. numbers, lists, strings (including quotes), etc."
84
+ )
85
+ user_warning.setWordWrap(True)
86
+ user_warning.setStyleSheet("QLabel { color: red; }")
87
+ self._layout.addWidget(user_warning)
88
+ self._add_form()
89
+ self._add_overlay()
90
+ self._add_buttons()
91
+
92
+ self.setLayout(self._container)
93
+ self._overlay_widget.setVisible(False)
94
+
95
+ def _add_form(self):
96
+ self._form_widget = QWidget()
97
+ self._form_widget.setLayout(self._layout)
98
+ self._form = DeviceConfigForm()
99
+ self._layout.addWidget(self._form)
100
+
101
+ for row in self._form.enumerate_form_widgets():
102
+ if row.label.property("_model_field_name") in DEVICE_CONF_KEYS.NON_UPDATABLE:
103
+ row.widget._set_pretty_display()
104
+
105
+ self._fetch_config()
106
+ self._fill_form()
107
+ self._container.addWidget(self._form_widget)
108
+
109
+ def _add_overlay(self):
110
+ self._overlay_widget = QWidget()
111
+ self._overlay_widget.setStyleSheet("background-color:rgba(128,128,128,128);")
112
+ self._overlay_widget.setAutoFillBackground(True)
113
+ self._overlay_layout = QVBoxLayout()
114
+ self._overlay_layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
115
+ self._overlay_widget.setLayout(self._overlay_layout)
116
+
117
+ self._spinner = SpinnerWidget(parent=self)
118
+ self._spinner.setMinimumSize(QSize(100, 100))
119
+ self._overlay_layout.addWidget(self._spinner)
120
+ self._container.addWidget(self._overlay_widget)
121
+
122
+ def _add_buttons(self):
123
+ button_box = QDialogButtonBox(
124
+ QDialogButtonBox.Apply | QDialogButtonBox.Ok | QDialogButtonBox.Cancel
125
+ )
126
+ button_box.button(QDialogButtonBox.Apply).clicked.connect(self.apply)
127
+ button_box.accepted.connect(self.accept)
128
+ button_box.rejected.connect(self.reject)
129
+ self._layout.addWidget(button_box)
130
+
131
+ def _fetch_config(self):
132
+ self._initial_config = {}
133
+ if (
134
+ self.client.device_manager is not None
135
+ and self._device in self.client.device_manager.devices
136
+ ):
137
+ self._initial_config = self.client.device_manager.devices.get(self._device)._config
138
+
139
+ def _fill_form(self):
140
+ self._form.set_data(DeviceConfigModel.model_validate(self._initial_config))
141
+
142
+ def updated_config(self):
143
+ new_config = self._form.get_form_data()
144
+ diff = {
145
+ k: v for k, v in new_config.items() if self._initial_config.get(k) != new_config.get(k)
146
+ }
147
+ if diff.get("deviceConfig") is not None:
148
+ # TODO: special cased in some parts of device manager but not others, should
149
+ # be removed in config update as with below issue
150
+ diff["deviceConfig"].pop("device_access", None)
151
+ # TODO: replace when https://github.com/bec-project/bec/issues/528 is resolved
152
+ diff["deviceConfig"] = {
153
+ k: literal_eval(str(v)) for k, v in diff["deviceConfig"].items()
154
+ }
155
+ return diff
156
+
157
+ @SafeSlot()
158
+ def apply(self):
159
+ self._process_update_action()
160
+ self.applied.emit()
161
+
162
+ @SafeSlot()
163
+ def accept(self):
164
+ self._process_update_action()
165
+ return super().accept()
166
+
167
+ def _process_update_action(self):
168
+ updated_config = self.updated_config()
169
+ if (device_name := updated_config.get("name")) == "":
170
+ logger.warning("Can't create a device with no name!")
171
+ elif set(updated_config.keys()) & set(DEVICE_CONF_KEYS.NON_UPDATABLE):
172
+ logger.info(
173
+ f"Removing old device {self._device} and adding new device {device_name or self._device} with modified config: {updated_config}"
174
+ )
175
+ else:
176
+ self._update_device_config(updated_config)
177
+
178
+ def _update_device_config(self, config: dict):
179
+ if self._device is None:
180
+ return
181
+ if config == {}:
182
+ logger.info("No changes made to device config")
183
+ return
184
+ logger.info(f"Sending request to update device config: {config}")
185
+
186
+ self._start_waiting_display()
187
+ communicate_update = _CommunicateUpdate(self._config_helper, self._device, config)
188
+ communicate_update.signals.error.connect(self.update_error)
189
+ communicate_update.signals.done.connect(self.update_done)
190
+ self.threadpool.start(communicate_update)
191
+
192
+ @SafeSlot()
193
+ def update_done(self):
194
+ self._stop_waiting_display()
195
+ self._fetch_config()
196
+ self._fill_form()
197
+
198
+ @SafeSlot(Exception, popup_error=True)
199
+ def update_error(self, e: Exception):
200
+ raise RuntimeError("Failed to update device configuration") from e
201
+
202
+ def _start_waiting_display(self):
203
+ self._overlay_widget.setVisible(True)
204
+ self._spinner.start()
205
+ QApplication.processEvents()
206
+
207
+ def _stop_waiting_display(self):
208
+ self._overlay_widget.setVisible(False)
209
+ self._spinner.stop()
210
+ QApplication.processEvents()
211
+
212
+
213
+ def main(): # pragma: no cover
214
+ import sys
215
+
216
+ from qtpy.QtWidgets import QApplication, QLineEdit, QPushButton, QWidget
217
+
218
+ from bec_widgets.utils.colors import set_theme
219
+
220
+ dialog = None
221
+
222
+ app = QApplication(sys.argv)
223
+ set_theme("light")
224
+ widget = QWidget()
225
+ widget.setLayout(QVBoxLayout())
226
+
227
+ device = QLineEdit()
228
+ widget.layout().addWidget(device)
229
+
230
+ def _destroy_dialog(*_):
231
+ nonlocal dialog
232
+ dialog = None
233
+
234
+ def accept(*args):
235
+ logger.success(f"submitted device config form {dialog} {args}")
236
+ _destroy_dialog()
237
+
238
+ def _show_dialog(*_):
239
+ nonlocal dialog
240
+ if dialog is None:
241
+ dialog = DeviceConfigDialog(device=device.text())
242
+ dialog.accepted.connect(accept)
243
+ dialog.rejected.connect(_destroy_dialog)
244
+ dialog.open()
245
+
246
+ button = QPushButton("Show device dialog")
247
+ widget.layout().addWidget(button)
248
+ button.clicked.connect(_show_dialog)
249
+ widget.show()
250
+ sys.exit(app.exec_())
251
+
252
+
253
+ if __name__ == "__main__":
254
+ main()
@@ -0,0 +1,60 @@
1
+ from __future__ import annotations
2
+
3
+ from bec_lib.atlas_models import Device as DeviceConfigModel
4
+ from pydantic import BaseModel
5
+ from qtpy.QtWidgets import QApplication
6
+
7
+ from bec_widgets.utils.colors import get_theme_name
8
+ from bec_widgets.utils.forms_from_types import styles
9
+ from bec_widgets.utils.forms_from_types.forms import PydanticModelForm
10
+ from bec_widgets.utils.forms_from_types.items import (
11
+ DEFAULT_WIDGET_TYPES,
12
+ BoolFormItem,
13
+ BoolToggleFormItem,
14
+ )
15
+
16
+
17
+ class DeviceConfigForm(PydanticModelForm):
18
+ RPC = False
19
+ PLUGIN = False
20
+
21
+ def __init__(self, parent=None, client=None, pretty_display=False, **kwargs):
22
+ super().__init__(
23
+ parent=parent,
24
+ data_model=DeviceConfigModel,
25
+ pretty_display=pretty_display,
26
+ client=client,
27
+ **kwargs,
28
+ )
29
+ self._widget_types = DEFAULT_WIDGET_TYPES.copy()
30
+ self._widget_types["bool"] = (lambda spec: spec.item_type is bool, BoolToggleFormItem)
31
+ self._widget_types["optional_bool"] = (
32
+ lambda spec: spec.item_type == bool | None,
33
+ BoolFormItem,
34
+ )
35
+ self._validity.setVisible(False)
36
+ self._connect_to_theme_change()
37
+ self.populate()
38
+
39
+ def _post_init(self): ...
40
+
41
+ def set_pretty_display_theme(self, theme: str | None = None):
42
+ if theme is None:
43
+ theme = get_theme_name()
44
+ self.setStyleSheet(styles.pretty_display_theme(theme))
45
+
46
+ def get_form_data(self):
47
+ """Get the entered metadata as a dict."""
48
+ return self._md_schema.model_validate(super().get_form_data()).model_dump()
49
+
50
+ def _connect_to_theme_change(self):
51
+ """Connect to the theme change signal."""
52
+ qapp = QApplication.instance()
53
+ if hasattr(qapp, "theme_signal"):
54
+ qapp.theme_signal.theme_updated.connect(self.set_pretty_display_theme) # type: ignore
55
+
56
+ def set_schema(self, schema: type[BaseModel]):
57
+ raise TypeError("This class doesn't support changing the schema")
58
+
59
+ def set_data(self, data: DeviceConfigModel): # type: ignore # This class locks the type
60
+ super().set_data(data)
@@ -3,49 +3,27 @@ from __future__ import annotations
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from bec_lib.atlas_models import Device as DeviceConfigModel
6
+ from bec_lib.devicemanager import DeviceContainer
6
7
  from bec_lib.logger import bec_logger
8
+ from bec_qthemes import material_icon
7
9
  from qtpy.QtCore import QMimeData, QSize, Qt, Signal
8
10
  from qtpy.QtGui import QDrag
9
- from qtpy.QtWidgets import QApplication, QHBoxLayout, QWidget
11
+ from qtpy.QtWidgets import QApplication, QHBoxLayout, QToolButton, QWidget
10
12
 
11
- from bec_widgets.utils.colors import get_theme_name
12
13
  from bec_widgets.utils.error_popups import SafeSlot
13
14
  from bec_widgets.utils.expandable_frame import ExpandableGroupFrame
14
- from bec_widgets.utils.forms_from_types import styles
15
- from bec_widgets.utils.forms_from_types.forms import PydanticModelForm
16
- from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
15
+ from bec_widgets.widgets.services.device_browser.device_item.device_config_dialog import (
16
+ DeviceConfigDialog,
17
+ )
18
+ from bec_widgets.widgets.services.device_browser.device_item.device_config_form import (
19
+ DeviceConfigForm,
20
+ )
17
21
 
18
22
  if TYPE_CHECKING: # pragma: no cover
19
23
  from qtpy.QtGui import QMouseEvent
20
24
 
21
- logger = bec_logger.logger
22
-
23
-
24
- class DeviceItemForm(PydanticModelForm):
25
- RPC = False
26
- PLUGIN = False
27
-
28
- def __init__(self, parent=None, client=None, pretty_display=False, **kwargs):
29
- super().__init__(
30
- parent=parent,
31
- data_model=DeviceConfigModel,
32
- pretty_display=pretty_display,
33
- client=client,
34
- **kwargs,
35
- )
36
- self._validity.setVisible(False)
37
- self._connect_to_theme_change()
38
-
39
- def set_pretty_display_theme(self, theme: str | None = None):
40
- if theme is None:
41
- theme = get_theme_name()
42
- self.setStyleSheet(styles.pretty_display_theme(theme))
43
25
 
44
- def _connect_to_theme_change(self):
45
- """Connect to the theme change signal."""
46
- qapp = QApplication.instance()
47
- if hasattr(qapp, "theme_signal"):
48
- qapp.theme_signal.theme_updated.connect(self.set_pretty_display_theme) # type: ignore
26
+ logger = bec_logger.logger
49
27
 
50
28
 
51
29
  class DeviceItem(ExpandableGroupFrame):
@@ -53,9 +31,9 @@ class DeviceItem(ExpandableGroupFrame):
53
31
 
54
32
  RPC = False
55
33
 
56
- def __init__(self, parent, device: str, icon: str = "") -> None:
34
+ def __init__(self, parent, device: str, devices: DeviceContainer, icon: str = "") -> None:
57
35
  super().__init__(parent, title=device, expanded=False, icon=icon)
58
-
36
+ self.dev = devices
59
37
  self._drag_pos = None
60
38
  self._expanded_first_time = False
61
39
  self._data = None
@@ -65,17 +43,29 @@ class DeviceItem(ExpandableGroupFrame):
65
43
  self.set_layout(layout)
66
44
 
67
45
  self.adjustSize()
68
- self._title.clicked.connect(self.switch_expanded_state)
69
- self._title_icon.clicked.connect(self.switch_expanded_state)
46
+
47
+ def _create_title_layout(self, title: str, icon: str):
48
+ super()._create_title_layout(title, icon)
49
+ self.edit_button = QToolButton()
50
+ self.edit_button.setIcon(
51
+ material_icon(icon_name="edit", size=(10, 10), convert_to_pixmap=False)
52
+ )
53
+ self._title_layout.insertWidget(self._title_layout.count() - 1, self.edit_button)
54
+ self.edit_button.clicked.connect(self._create_edit_dialog)
55
+
56
+ def _create_edit_dialog(self):
57
+ dialog = DeviceConfigDialog(parent=self, device=self.device)
58
+ dialog.accepted.connect(self._reload_config)
59
+ dialog.applied.connect(self._reload_config)
60
+ dialog.open()
70
61
 
71
62
  @SafeSlot()
72
63
  def switch_expanded_state(self):
73
64
  if not self.expanded and not self._expanded_first_time:
74
65
  self._expanded_first_time = True
75
- self.form = DeviceItemForm(parent=self, pretty_display=True)
66
+ self.form = DeviceConfigForm(parent=self, pretty_display=True)
76
67
  self._contents.layout().addWidget(self.form)
77
- if self._data:
78
- self.form.set_data(self._data)
68
+ self._reload_config()
79
69
  self.broadcast_size_hint.emit(self.sizeHint())
80
70
  super().switch_expanded_state()
81
71
  if self._expanded_first_time:
@@ -86,6 +76,10 @@ class DeviceItem(ExpandableGroupFrame):
86
76
  self.adjustSize()
87
77
  self.broadcast_size_hint.emit(self.sizeHint())
88
78
 
79
+ @SafeSlot(popup_error=True)
80
+ def _reload_config(self, *_):
81
+ self.set_display_config(self.dev[self.device]._config)
82
+
89
83
  def set_display_config(self, config_dict: dict):
90
84
  """Set the displayed information from a device config dict, which must conform to the
91
85
  bec_lib.atlas_models.Device config model."""
@@ -118,29 +112,33 @@ class DeviceItem(ExpandableGroupFrame):
118
112
 
119
113
  if __name__ == "__main__": # pragma: no cover
120
114
  import sys
115
+ from unittest.mock import MagicMock
121
116
 
122
117
  from qtpy.QtWidgets import QApplication
123
118
 
119
+ from bec_widgets.widgets.services.device_browser.device_item.device_config_form import (
120
+ DeviceConfigForm,
121
+ )
122
+ from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
123
+
124
124
  app = QApplication(sys.argv)
125
125
  widget = QWidget()
126
126
  layout = QHBoxLayout()
127
127
  widget.setLayout(layout)
128
- item = DeviceItem("Device")
128
+ mock_config = {
129
+ "name": "Test Device",
130
+ "enabled": True,
131
+ "deviceClass": "FakeDeviceClass",
132
+ "deviceConfig": {"kwarg1": "value1"},
133
+ "readoutPriority": "baseline",
134
+ "description": "A device for testing out a widget",
135
+ "readOnly": True,
136
+ "softwareTrigger": False,
137
+ "deviceTags": {"tag1", "tag2", "tag3"},
138
+ "userParameter": {"some_setting": "some_ value"},
139
+ }
140
+ item = DeviceItem(widget, "Device", {"Device": MagicMock(enabled=True, _config=mock_config)})
129
141
  layout.addWidget(DarkModeButton())
130
142
  layout.addWidget(item)
131
- item.set_display_config(
132
- {
133
- "name": "Test Device",
134
- "enabled": True,
135
- "deviceClass": "FakeDeviceClass",
136
- "deviceConfig": {"kwarg1": "value1"},
137
- "readoutPriority": "baseline",
138
- "description": "A device for testing out a widget",
139
- "readOnly": True,
140
- "softwareTrigger": False,
141
- "deviceTags": ["tag1", "tag2", "tag3"],
142
- "userParameter": {"some_setting": "some_ value"},
143
- }
144
- )
145
143
  widget.show()
146
144
  sys.exit(app.exec_())
@@ -10,6 +10,7 @@ class ToggleSwitch(QWidget):
10
10
  A simple toggle.
11
11
  """
12
12
 
13
+ stateChanged = Signal(bool)
13
14
  enabled = Signal(bool)
14
15
  ICON_NAME = "toggle_on"
15
16
  PLUGIN = True
@@ -42,11 +43,19 @@ class ToggleSwitch(QWidget):
42
43
 
43
44
  @checked.setter
44
45
  def checked(self, state):
46
+ if self._checked != state:
47
+ self.stateChanged.emit(state)
45
48
  self._checked = state
46
49
  self.update_colors()
47
50
  self.set_thumb_pos_to_state()
48
51
  self.enabled.emit(self._checked)
49
52
 
53
+ def setChecked(self, state: bool):
54
+ self.checked = state
55
+
56
+ def isChecked(self):
57
+ return self.checked
58
+
50
59
  @Property(QPointF)
51
60
  def thumb_pos(self):
52
61
  return self._thumb_pos
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: bec_widgets
3
- Version: 2.15.1
3
+ Version: 2.16.0
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=BGd-zRzWE7KTMPqaa3CPc_JyROlDYD5DZ95PQMUjKzQ,301055
5
+ CHANGELOG.md,sha256=_jkBL9IyzlQ1Qeke_iNWW1uyEOUTnub8cOk6L16Th60,303426
6
6
  LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
7
- PKG-INFO,sha256=gTntcRGnhQPrg5vyZPQgQOjlhlKK-Y5r__82UIsiJXA,1252
7
+ PKG-INFO,sha256=Ruu7v-DGBzfToXWxY60FteqGE2djyfYs5FpnQk7oQYE,1252
8
8
  README.md,sha256=oY5Jc1uXehRASuwUJ0umin2vfkFh7tHF-LLruHTaQx0,3560
9
- pyproject.toml,sha256=HMdAYHc2bpPYaYYmgAWgbC3HiiptNXdnHyTMOQmdXg8,2827
9
+ pyproject.toml,sha256=ZeBsXAfaSDFXfcgpGwnAY7zfZm58l6SkdU0AFL1f_uw,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
@@ -59,7 +59,7 @@ bec_widgets/examples/plugin_example_pyside/tictactoe.py,sha256=s3rCurXloVcmMdzZi
59
59
  bec_widgets/examples/plugin_example_pyside/tictactoeplugin.py,sha256=MFMwONn4EZ3V8DboEG4I3BXpURE9JDbKB7XTzzfZl5w,1978
60
60
  bec_widgets/examples/plugin_example_pyside/tictactoetaskmenu.py,sha256=SiJaoX3OYA8YMkSwU1d7KEfSUjQQUsQgpRAxSSlr8oQ,2376
61
61
  bec_widgets/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
62
- bec_widgets/tests/utils.py,sha256=PVVhVrAVGqOI_BWZQRwCrJViIcwVHLZyeqWu8b7nN8k,7151
62
+ bec_widgets/tests/utils.py,sha256=R04KpeQctQoDrtGRd00lrLIHxTbjMelrgIsE-Ea40_s,7151
63
63
  bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
64
64
  bec_widgets/utils/bec_connector.py,sha256=ATOSyZqryn1QHPc7aotiDnUtzFhlj_gmcukMT_pqjHQ,19272
65
65
  bec_widgets/utils/bec_designer.py,sha256=ehNl_i743rijmhPiIGNd1bihE7-l4oJzTVoa4yjPjls,5426
@@ -76,7 +76,7 @@ bec_widgets/utils/container_utils.py,sha256=J8YXombOlAPa3M8NGZdhntp2NirBu4raDEQZ
76
76
  bec_widgets/utils/crosshair.py,sha256=nqBPQqWzoTLZ-sPBR6ONm7M1TtGGD2EpRwm2iSNpoFo,22304
77
77
  bec_widgets/utils/entry_validator.py,sha256=lwT8HP0RDG1FXENIeZ3IDEF2DQmD8KXGkRxPoMXbryk,1817
78
78
  bec_widgets/utils/error_popups.py,sha256=UBAmD1YlAgKodpihudyf0VWtI59KGFiLgnjiKmKGjgk,13254
79
- bec_widgets/utils/expandable_frame.py,sha256=ynqRFwXsd6jWT5C6qjNwmmHY9Rm9UCALeL32OPQkYgw,3785
79
+ bec_widgets/utils/expandable_frame.py,sha256=BvR5kyALWPcOz7l5zarqG_M-EWFY2LMw0jfdDWC5-hI,4025
80
80
  bec_widgets/utils/filter_io.py,sha256=GKO6GOTiKxTuTp_SHp5Ewou54N7wIZXgWWvlFvhbBmw,5114
81
81
  bec_widgets/utils/fps_counter.py,sha256=seuCWwiNP5q2e2OEztloa66pNb3Sygh-0lEHAcYaDfc,2612
82
82
  bec_widgets/utils/generate_designer_plugin.py,sha256=d_-cWQJ2s8Ff-XD_YQUgnVsRCMHBPcszXOAuJSeIWHM,5676
@@ -103,8 +103,8 @@ bec_widgets/utils/widget_io.py,sha256=afR7i59fw2WrEQCmkH5dwhz1uNjfMPnJTIhE8NWVBs
103
103
  bec_widgets/utils/widget_state_manager.py,sha256=tzrxVmnGa6IHSEdeh-R68aQ934BsuS9nLQbwYQ78J90,7651
104
104
  bec_widgets/utils/yaml_dialog.py,sha256=T6UyGNGdmpXW74fa_7Nk6b99T5pp2Wvyw3AOauRc8T8,2407
105
105
  bec_widgets/utils/forms_from_types/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
106
- bec_widgets/utils/forms_from_types/forms.py,sha256=o2BPhegPDI5b6zzLIrFrWja2FkKWcz97iwSrl0j0JSM,10097
107
- bec_widgets/utils/forms_from_types/items.py,sha256=Pt5QWMtbu9Hb6Mcvm0-SR8NUY3-KsSwcjkGDHmdwq-w,13013
106
+ bec_widgets/utils/forms_from_types/forms.py,sha256=UhhuZNz0nZfPF9DERDYCq4Idp70NUcrgfAXpjn2G2Og,10928
107
+ bec_widgets/utils/forms_from_types/items.py,sha256=i9K8uoANKZuPuWPYSdK74UER3LXFf7sWHX1Rl-7ALgc,22458
108
108
  bec_widgets/utils/forms_from_types/styles.py,sha256=PeMx8bLI2PX0--U1QOS-3yuGQiyAX4W3EpL_IA5iIrI,702
109
109
  bec_widgets/utils/plugin_templates/plugin.template,sha256=DWtJdHpdsVtbiTTOniH3zBe5a40ztQ20o_-Hclyu38s,1266
110
110
  bec_widgets/utils/plugin_templates/register.template,sha256=XyL3OZPT_FTArLAM8tHd5qMqv2ZuAbJAZLsNNnHcagU,417
@@ -222,11 +222,11 @@ bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog_compact.ui,sha256=JbdMEPzbA3p2
222
222
  bec_widgets/widgets/dap/lmfit_dialog/lmfit_dialog_vertical.ui,sha256=BVm0XydqbgmIYOs3YPQzQsL4v4gZzourR10dH_2NrVg,5078
223
223
  bec_widgets/widgets/dap/lmfit_dialog/register_lm_fit_dialog.py,sha256=7tB1gsvv310_kVuKf2u4EdSR4F1posm7QCrWH5Kih-Q,480
224
224
  bec_widgets/widgets/editors/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
225
- bec_widgets/widgets/editors/dict_backed_table.py,sha256=fKQ-50QzwqJs4JaFlGDx8OB4HEV1dMn5sVPEb_aDFxI,7244
225
+ bec_widgets/widgets/editors/dict_backed_table.py,sha256=_ukL5J4DkPnGQPUAvPHwU9evv5yBBqwjhSNWrYwU6OI,9170
226
226
  bec_widgets/widgets/editors/jupyter_console/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
227
  bec_widgets/widgets/editors/jupyter_console/jupyter_console.py,sha256=-e7HQOECeH5eDrJYh4BFIzRL78LDkooU4otabyN0aX4,2343
228
228
  bec_widgets/widgets/editors/scan_metadata/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
229
- bec_widgets/widgets/editors/scan_metadata/_util.py,sha256=7bny4A1ZDNAt4ZzkdZclJS3r0jlQvEU2Kyj-G5Synms,2036
229
+ bec_widgets/widgets/editors/scan_metadata/_util.py,sha256=mKc_9y4jeul1jWU1G7fxjLJ4ANmtAAXUUgZUkzsGSyY,2090
230
230
  bec_widgets/widgets/editors/scan_metadata/register_scan_metadata.py,sha256=dGcd8AXM1E9i-N45_CIRdCIyKtHJlq_7neyKHrDx6C0,487
231
231
  bec_widgets/widgets/editors/scan_metadata/scan_metadata.py,sha256=t5sv6AgxxM4-Metgqh5OzOE5g7DNNvNZfBOjBvI8oh8,5445
232
232
  bec_widgets/widgets/editors/scan_metadata/scan_metadata.pyproject,sha256=_4guiQAGxiQ4gSN5i5S160UnFXvPFC1W1nG77PubNYQ,31
@@ -349,14 +349,16 @@ bec_widgets/widgets/services/bec_status_box/bec_status_box_plugin.py,sha256=2tBP
349
349
  bec_widgets/widgets/services/bec_status_box/register_bec_status_box.py,sha256=_1gr5nid6D5ZEvvt-GPyXhEGfacSh_QW0oWKxmZrUmY,490
350
350
  bec_widgets/widgets/services/bec_status_box/status_item.py,sha256=CNhGk6J8iNvlldibcuy4PFQULRHvgqHyot-UJ8xfVJw,5609
351
351
  bec_widgets/widgets/services/device_browser/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
352
- bec_widgets/widgets/services/device_browser/device_browser.py,sha256=ivr6BSjS_MRJujmsE_dvOns3iBXf76LAlnIg_ueJXNs,5298
352
+ bec_widgets/widgets/services/device_browser/device_browser.py,sha256=RHJgOXDChAqy4BPpBVIKJReXXFJB-DpVvt3LhCFR9V8,5231
353
353
  bec_widgets/widgets/services/device_browser/device_browser.pyproject,sha256=s0vM1xYUwyU6Je68_hSCSBLK8ZPfHB-ftt4flfdpkXY,32
354
354
  bec_widgets/widgets/services/device_browser/device_browser.ui,sha256=Dy_3oXArScP-_7hRI6nQ7SKKnihuyYAzJfXiRxxJQBE,1077
355
355
  bec_widgets/widgets/services/device_browser/device_browser_plugin.py,sha256=JS4uYQclT-h0jMTPZ_wZgi5MCert--gjmmBks_EmEoo,1299
356
356
  bec_widgets/widgets/services/device_browser/register_device_browser.py,sha256=OrL6NwN47TMu-ib6vqtnQ3ogePMWVipG3IfEXyq2OqY,509
357
357
  bec_widgets/widgets/services/device_browser/util.py,sha256=aDtRa53L4-CGn4rM9IKqUP80pBYBxh4pssE1Tc46tAo,370
358
358
  bec_widgets/widgets/services/device_browser/device_item/__init__.py,sha256=VGY-uNVCnpcY-q-gijteB2N8KxFNgYR-qQ209MVu1QI,36
359
- bec_widgets/widgets/services/device_browser/device_item/device_item.py,sha256=g8kjFxErwAD_QpxtM-HLYh7DauTuilW-pYoGNshw-vk,5153
359
+ bec_widgets/widgets/services/device_browser/device_item/device_config_dialog.py,sha256=183LABi4767PptQHy8mfV1I6MFlDGmC1vekFqjtkOuk,8748
360
+ bec_widgets/widgets/services/device_browser/device_item/device_config_form.py,sha256=Bw2sxvszs2qPe5WCUV_J4P6iuWSEQc0I37cyr9Wat30,2138
361
+ bec_widgets/widgets/services/device_browser/device_item/device_item.py,sha256=LxkeUphf6BjzQadOlyF080TUoPtFdivO7b7c-SjdK94,5251
360
362
  bec_widgets/widgets/utility/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
361
363
  bec_widgets/widgets/utility/logpanel/__init__.py,sha256=HldSvPLYgrqBjCgIQj0f7Wa4slkSMksk4bsRJOQi__Y,91
362
364
  bec_widgets/widgets/utility/logpanel/_util.py,sha256=GqzHbdOTmWBru9OR4weeYdziWj_cWxqSJhS4_6W3Qjg,1836
@@ -380,7 +382,7 @@ bec_widgets/widgets/utility/spinner/spinner_widget.pyproject,sha256=zzLajGB3DTgV
380
382
  bec_widgets/widgets/utility/spinner/spinner_widget_plugin.py,sha256=kRQCOwxPQsFOrJIkSoqq7xdF_VtoRo_b2vOZEr5eXrA,1363
381
383
  bec_widgets/widgets/utility/toggle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
382
384
  bec_widgets/widgets/utility/toggle/register_toggle_switch.py,sha256=6y9-Cr_qcpEphRK2_wyt6vWY9SnUzw78RHwZCW-xMRw,480
383
- bec_widgets/widgets/utility/toggle/toggle.py,sha256=BotavzAjDcBt6Mk1Fy6eJ-QWceboS18NJMcAvZnXUvM,4516
385
+ bec_widgets/widgets/utility/toggle/toggle.py,sha256=NbbvemzDStIUaspVUUqWWdrpv_XhRbZsAmGJgYy1V_A,4748
384
386
  bec_widgets/widgets/utility/toggle/toggle_switch.pyproject,sha256=Msa-AS5H5XlqW65r8GlX2AxD8FnFnDyDgGnbKcXqKOw,24
385
387
  bec_widgets/widgets/utility/toggle/toggle_switch_plugin.py,sha256=rcazogplQXHu_4K2e9OTvfhOSUe4yi1kaTxN8a1GsXU,1352
386
388
  bec_widgets/widgets/utility/visual/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -409,8 +411,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=O
409
411
  bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
410
412
  bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
411
413
  bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
412
- bec_widgets-2.15.1.dist-info/METADATA,sha256=gTntcRGnhQPrg5vyZPQgQOjlhlKK-Y5r__82UIsiJXA,1252
413
- bec_widgets-2.15.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
414
- bec_widgets-2.15.1.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
415
- bec_widgets-2.15.1.dist-info/licenses/LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
416
- bec_widgets-2.15.1.dist-info/RECORD,,
414
+ bec_widgets-2.16.0.dist-info/METADATA,sha256=Ruu7v-DGBzfToXWxY60FteqGE2djyfYs5FpnQk7oQYE,1252
415
+ bec_widgets-2.16.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
416
+ bec_widgets-2.16.0.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
417
+ bec_widgets-2.16.0.dist-info/licenses/LICENSE,sha256=Daeiu871NcAp8uYi4eB_qHgvypG-HX0ioRQyQxFwjeg,1531
418
+ bec_widgets-2.16.0.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.15.1"
7
+ version = "2.16.0"
8
8
  description = "BEC Widgets"
9
9
  requires-python = ">=3.10"
10
10
  classifiers = [