bec-widgets 1.21.4__py3-none-any.whl → 1.23.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.
- CHANGELOG.md +40 -0
- PKG-INFO +1 -1
- bec_widgets/qt_utils/toolbar.py +364 -81
- bec_widgets/widgets/utility/spinbox/__init__.py +0 -0
- bec_widgets/widgets/utility/spinbox/bec_spin_box.pyproject +1 -0
- bec_widgets/widgets/utility/spinbox/bec_spin_box_plugin.py +54 -0
- bec_widgets/widgets/utility/spinbox/decimal_spinbox.py +83 -0
- bec_widgets/widgets/utility/spinbox/register_bec_spin_box.py +15 -0
- {bec_widgets-1.21.4.dist-info → bec_widgets-1.23.0.dist-info}/METADATA +1 -1
- {bec_widgets-1.21.4.dist-info → bec_widgets-1.23.0.dist-info}/RECORD +14 -9
- pyproject.toml +1 -1
- {bec_widgets-1.21.4.dist-info → bec_widgets-1.23.0.dist-info}/WHEEL +0 -0
- {bec_widgets-1.21.4.dist-info → bec_widgets-1.23.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-1.21.4.dist-info → bec_widgets-1.23.0.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,6 +1,46 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v1.23.0 (2025-02-24)
|
5
|
+
|
6
|
+
### Features
|
7
|
+
|
8
|
+
- **bec_spin_box**: Double spin box with setting inside for defining decimals
|
9
|
+
([`f19d948`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/f19d9485df403cb755315ac1a0ff4402d7a85f77))
|
10
|
+
|
11
|
+
|
12
|
+
## v1.22.0 (2025-02-19)
|
13
|
+
|
14
|
+
### Bug Fixes
|
15
|
+
|
16
|
+
- **modular_toolbar**: Add action to an already existing bundle
|
17
|
+
([`4c4f159`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4c4f1592c29974bb095c3c8325e93a1383efa289))
|
18
|
+
|
19
|
+
- **toolbar**: Qmenu Icons are visible
|
20
|
+
([`c2c0221`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c2c022154bddc15d81eb55aad912d8fe1e34c698))
|
21
|
+
|
22
|
+
- **toolbar**: Update_separators logic updated, there cannot be two separators next to each other
|
23
|
+
([`facb8c3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/facb8c30ffa3b12a97c7c68f8594b0354372ca17))
|
24
|
+
|
25
|
+
- **toolbar**: Widget actions are more compact
|
26
|
+
([`ef36a71`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ef36a7124d54319c2cd592433c95e4f7513e982e))
|
27
|
+
|
28
|
+
### Features
|
29
|
+
|
30
|
+
- **toolbar**: Switchabletoolbarbutton
|
31
|
+
([`333570b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/333570ba2fe67cb51fdbab17718003dfdb7f7b55))
|
32
|
+
|
33
|
+
### Refactoring
|
34
|
+
|
35
|
+
- **toolbar**: Added dark mode button for testing appearance for the toolbar example
|
36
|
+
([`6b08f7c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6b08f7cfb2115609a6dc6f681631ecfae23fa899))
|
37
|
+
|
38
|
+
### Testing
|
39
|
+
|
40
|
+
- **toolbar**: Blocking tests fixed
|
41
|
+
([`6ae33a2`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6ae33a23a62eafb7c820e1fde9d6d91ec1796e55))
|
42
|
+
|
43
|
+
|
4
44
|
## v1.21.4 (2025-02-19)
|
5
45
|
|
6
46
|
### Bug Fixes
|
PKG-INFO
CHANGED
bec_widgets/qt_utils/toolbar.py
CHANGED
@@ -8,7 +8,7 @@ from collections import defaultdict
|
|
8
8
|
from typing import Dict, List, Literal, Tuple
|
9
9
|
|
10
10
|
from bec_qthemes._icon.material_icons import material_icon
|
11
|
-
from qtpy.QtCore import QSize, Qt
|
11
|
+
from qtpy.QtCore import QSize, Qt, QTimer
|
12
12
|
from qtpy.QtGui import QAction, QColor, QIcon
|
13
13
|
from qtpy.QtWidgets import (
|
14
14
|
QApplication,
|
@@ -18,15 +18,54 @@ from qtpy.QtWidgets import (
|
|
18
18
|
QMainWindow,
|
19
19
|
QMenu,
|
20
20
|
QSizePolicy,
|
21
|
+
QStyle,
|
21
22
|
QToolBar,
|
22
23
|
QToolButton,
|
24
|
+
QVBoxLayout,
|
23
25
|
QWidget,
|
24
26
|
)
|
25
27
|
|
26
28
|
import bec_widgets
|
29
|
+
from bec_widgets.utils.colors import set_theme
|
30
|
+
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
|
27
31
|
|
28
32
|
MODULE_PATH = os.path.dirname(bec_widgets.__file__)
|
29
33
|
|
34
|
+
# Ensure that icons are shown in menus (especially on macOS)
|
35
|
+
QApplication.setAttribute(Qt.AA_DontShowIconsInMenus, False)
|
36
|
+
|
37
|
+
|
38
|
+
class LongPressToolButton(QToolButton):
|
39
|
+
def __init__(self, *args, long_press_threshold=500, **kwargs):
|
40
|
+
super().__init__(*args, **kwargs)
|
41
|
+
self.long_press_threshold = long_press_threshold
|
42
|
+
self._long_press_timer = QTimer(self)
|
43
|
+
self._long_press_timer.setSingleShot(True)
|
44
|
+
self._long_press_timer.timeout.connect(self.handleLongPress)
|
45
|
+
self._pressed = False
|
46
|
+
self._longPressed = False
|
47
|
+
|
48
|
+
def mousePressEvent(self, event):
|
49
|
+
self._pressed = True
|
50
|
+
self._longPressed = False
|
51
|
+
self._long_press_timer.start(self.long_press_threshold)
|
52
|
+
super().mousePressEvent(event)
|
53
|
+
|
54
|
+
def mouseReleaseEvent(self, event):
|
55
|
+
self._pressed = False
|
56
|
+
if self._longPressed:
|
57
|
+
self._longPressed = False
|
58
|
+
self._long_press_timer.stop()
|
59
|
+
event.accept() # Prevent normal click action after a long press
|
60
|
+
return
|
61
|
+
self._long_press_timer.stop()
|
62
|
+
super().mouseReleaseEvent(event)
|
63
|
+
|
64
|
+
def handleLongPress(self):
|
65
|
+
if self._pressed:
|
66
|
+
self._longPressed = True
|
67
|
+
self.showMenu()
|
68
|
+
|
30
69
|
|
31
70
|
class ToolBarAction(ABC):
|
32
71
|
"""
|
@@ -84,6 +123,21 @@ class IconAction(ToolBarAction):
|
|
84
123
|
toolbar.addAction(self.action)
|
85
124
|
|
86
125
|
|
126
|
+
class QtIconAction(ToolBarAction):
|
127
|
+
def __init__(self, standard_icon, tooltip=None, checkable=False, parent=None):
|
128
|
+
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
|
129
|
+
self.standard_icon = standard_icon
|
130
|
+
self.icon = QApplication.style().standardIcon(standard_icon)
|
131
|
+
self.action = QAction(self.icon, self.tooltip, parent)
|
132
|
+
self.action.setCheckable(self.checkable)
|
133
|
+
|
134
|
+
def add_to_toolbar(self, toolbar, target):
|
135
|
+
toolbar.addAction(self.action)
|
136
|
+
|
137
|
+
def get_icon(self):
|
138
|
+
return self.icon
|
139
|
+
|
140
|
+
|
87
141
|
class MaterialIconAction(ToolBarAction):
|
88
142
|
"""
|
89
143
|
Action with a Material icon for the toolbar.
|
@@ -111,7 +165,7 @@ class MaterialIconAction(ToolBarAction):
|
|
111
165
|
self.icon_name = icon_name
|
112
166
|
self.filled = filled
|
113
167
|
self.color = color
|
114
|
-
# Generate the icon
|
168
|
+
# Generate the icon using the material_icon helper
|
115
169
|
self.icon = material_icon(
|
116
170
|
self.icon_name,
|
117
171
|
size=(20, 20),
|
@@ -119,7 +173,6 @@ class MaterialIconAction(ToolBarAction):
|
|
119
173
|
filled=self.filled,
|
120
174
|
color=self.color,
|
121
175
|
)
|
122
|
-
# Immediately create an QAction with the given parent
|
123
176
|
self.action = QAction(self.icon, self.tooltip, parent=parent)
|
124
177
|
self.action.setCheckable(self.checkable)
|
125
178
|
|
@@ -152,7 +205,7 @@ class DeviceSelectionAction(ToolBarAction):
|
|
152
205
|
device_combobox (DeviceComboBox): The combobox for selecting the device.
|
153
206
|
"""
|
154
207
|
|
155
|
-
def __init__(self, label: str, device_combobox):
|
208
|
+
def __init__(self, label: str | None = None, device_combobox=None):
|
156
209
|
super().__init__()
|
157
210
|
self.label = label
|
158
211
|
self.device_combobox = device_combobox
|
@@ -161,15 +214,99 @@ class DeviceSelectionAction(ToolBarAction):
|
|
161
214
|
def add_to_toolbar(self, toolbar, target):
|
162
215
|
widget = QWidget()
|
163
216
|
layout = QHBoxLayout(widget)
|
164
|
-
|
165
|
-
layout.
|
166
|
-
|
167
|
-
|
217
|
+
layout.setContentsMargins(0, 0, 0, 0)
|
218
|
+
layout.setSpacing(0)
|
219
|
+
if self.label is not None:
|
220
|
+
label = QLabel(f"{self.label}")
|
221
|
+
layout.addWidget(label)
|
222
|
+
if self.device_combobox is not None:
|
223
|
+
layout.addWidget(self.device_combobox)
|
224
|
+
toolbar.addWidget(widget)
|
168
225
|
|
169
226
|
def set_combobox_style(self, color: str):
|
170
227
|
self.device_combobox.setStyleSheet(f"QComboBox {{ background-color: {color}; }}")
|
171
228
|
|
172
229
|
|
230
|
+
class SwitchableToolBarAction(ToolBarAction):
|
231
|
+
"""
|
232
|
+
A split toolbar action that combines a main action and a drop-down menu for additional actions.
|
233
|
+
|
234
|
+
The main button displays the currently selected action's icon and tooltip. Clicking on the main button
|
235
|
+
triggers that action. Clicking on the drop-down arrow displays a menu with alternative actions. When an
|
236
|
+
alternative action is selected, it becomes the new default and its callback is immediately executed.
|
237
|
+
|
238
|
+
This design mimics the behavior seen in Adobe Photoshop or Affinity Designer toolbars.
|
239
|
+
|
240
|
+
Args:
|
241
|
+
actions (dict): A dictionary mapping a unique key to a ToolBarAction instance.
|
242
|
+
initial_action (str, optional): The key of the initial default action. If not provided, the first action is used.
|
243
|
+
tooltip (str, optional): An optional tooltip for the split action; if provided, it overrides the default action's tooltip.
|
244
|
+
checkable (bool, optional): Whether the action is checkable. Defaults to True.
|
245
|
+
parent (QWidget, optional): Parent widget for the underlying QAction.
|
246
|
+
"""
|
247
|
+
|
248
|
+
def __init__(
|
249
|
+
self,
|
250
|
+
actions: Dict[str, ToolBarAction],
|
251
|
+
initial_action: str = None,
|
252
|
+
tooltip: str = None,
|
253
|
+
checkable: bool = True,
|
254
|
+
parent=None,
|
255
|
+
):
|
256
|
+
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
|
257
|
+
self.actions = actions
|
258
|
+
self.current_key = initial_action if initial_action is not None else next(iter(actions))
|
259
|
+
self.parent = parent
|
260
|
+
self.checkable = checkable
|
261
|
+
self.main_button = None
|
262
|
+
self.menu_actions: Dict[str, QAction] = {}
|
263
|
+
|
264
|
+
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
265
|
+
"""
|
266
|
+
Adds the split action to the toolbar.
|
267
|
+
|
268
|
+
Args:
|
269
|
+
toolbar (QToolBar): The toolbar to add the action to.
|
270
|
+
target (QWidget): The target widget for the action.
|
271
|
+
"""
|
272
|
+
self.main_button = LongPressToolButton(toolbar)
|
273
|
+
self.main_button.setPopupMode(QToolButton.MenuButtonPopup)
|
274
|
+
self.main_button.setCheckable(self.checkable)
|
275
|
+
default_action = self.actions[self.current_key]
|
276
|
+
self.main_button.setIcon(default_action.get_icon())
|
277
|
+
self.main_button.setToolTip(default_action.tooltip)
|
278
|
+
self.main_button.clicked.connect(self._trigger_current_action)
|
279
|
+
menu = QMenu(self.main_button)
|
280
|
+
self.menu_actions = {}
|
281
|
+
for key, action_obj in self.actions.items():
|
282
|
+
menu_action = QAction(action_obj.get_icon(), action_obj.tooltip, self.main_button)
|
283
|
+
menu_action.setIconVisibleInMenu(True)
|
284
|
+
menu_action.setCheckable(self.checkable)
|
285
|
+
menu_action.setChecked(key == self.current_key)
|
286
|
+
menu_action.triggered.connect(lambda checked, k=key: self._set_default_action(k))
|
287
|
+
menu.addAction(menu_action)
|
288
|
+
self.menu_actions[key] = menu_action
|
289
|
+
self.main_button.setMenu(menu)
|
290
|
+
toolbar.addWidget(self.main_button)
|
291
|
+
|
292
|
+
def _trigger_current_action(self):
|
293
|
+
action_obj = self.actions[self.current_key]
|
294
|
+
action_obj.action.trigger()
|
295
|
+
|
296
|
+
def _set_default_action(self, key: str):
|
297
|
+
self.current_key = key
|
298
|
+
new_action = self.actions[self.current_key]
|
299
|
+
self.main_button.setIcon(new_action.get_icon())
|
300
|
+
self.main_button.setToolTip(new_action.tooltip)
|
301
|
+
# Update check state of menu items
|
302
|
+
for k, menu_act in self.menu_actions.items():
|
303
|
+
menu_act.setChecked(k == key)
|
304
|
+
new_action.action.trigger()
|
305
|
+
|
306
|
+
def get_icon(self) -> QIcon:
|
307
|
+
return self.actions[self.current_key].get_icon()
|
308
|
+
|
309
|
+
|
173
310
|
class WidgetAction(ToolBarAction):
|
174
311
|
"""
|
175
312
|
Action for adding any widget to the toolbar.
|
@@ -180,15 +317,23 @@ class WidgetAction(ToolBarAction):
|
|
180
317
|
"""
|
181
318
|
|
182
319
|
def __init__(self, label: str | None = None, widget: QWidget = None, parent=None):
|
183
|
-
super().__init__(
|
320
|
+
super().__init__(icon_path=None, tooltip=label, checkable=False)
|
184
321
|
self.label = label
|
185
322
|
self.widget = widget
|
323
|
+
self.container = None
|
186
324
|
|
187
325
|
def add_to_toolbar(self, toolbar: QToolBar, target: QWidget):
|
188
|
-
|
189
|
-
|
326
|
+
"""
|
327
|
+
Adds the widget to the toolbar.
|
328
|
+
|
329
|
+
Args:
|
330
|
+
toolbar (QToolBar): The toolbar to add the widget to.
|
331
|
+
target (QWidget): The target widget for the action.
|
332
|
+
"""
|
333
|
+
self.container = QWidget()
|
334
|
+
layout = QHBoxLayout(self.container)
|
190
335
|
layout.setContentsMargins(0, 0, 0, 0)
|
191
|
-
layout.setSpacing(
|
336
|
+
layout.setSpacing(0)
|
192
337
|
|
193
338
|
if self.label is not None:
|
194
339
|
label_widget = QLabel(f"{self.label}")
|
@@ -209,19 +354,12 @@ class WidgetAction(ToolBarAction):
|
|
209
354
|
|
210
355
|
layout.addWidget(self.widget)
|
211
356
|
|
212
|
-
toolbar.addWidget(container)
|
357
|
+
toolbar.addWidget(self.container)
|
358
|
+
# Store the container as the action to allow toggling visibility.
|
359
|
+
self.action = self.container
|
213
360
|
|
214
361
|
@staticmethod
|
215
362
|
def calculate_minimum_width(combo_box: QComboBox) -> int:
|
216
|
-
"""
|
217
|
-
Calculate the minimum width required to display the longest item in the combo box.
|
218
|
-
|
219
|
-
Args:
|
220
|
-
combo_box (QComboBox): The combo box to calculate the width for.
|
221
|
-
|
222
|
-
Returns:
|
223
|
-
int: The calculated minimum width in pixels.
|
224
|
-
"""
|
225
363
|
font_metrics = combo_box.fontMetrics()
|
226
364
|
max_width = max(font_metrics.width(combo_box.itemText(i)) for i in range(combo_box.count()))
|
227
365
|
return max_width + 60
|
@@ -261,12 +399,15 @@ class ExpandableMenuAction(ToolBarAction):
|
|
261
399
|
menu = QMenu(button)
|
262
400
|
for action_id, action in self.actions.items():
|
263
401
|
sub_action = QAction(action.tooltip, target)
|
264
|
-
|
402
|
+
sub_action.setIconVisibleInMenu(True)
|
403
|
+
if action.icon_path:
|
265
404
|
icon = QIcon()
|
266
405
|
icon.addFile(action.icon_path, size=QSize(20, 20))
|
267
406
|
sub_action.setIcon(icon)
|
268
|
-
elif hasattr(action, "get_icon"):
|
269
|
-
|
407
|
+
elif hasattr(action, "get_icon") and callable(action.get_icon):
|
408
|
+
sub_icon = action.get_icon()
|
409
|
+
if sub_icon and not sub_icon.isNull():
|
410
|
+
sub_action.setIcon(sub_icon)
|
270
411
|
sub_action.setCheckable(action.checkable)
|
271
412
|
menu.addAction(sub_action)
|
272
413
|
self.widgets[action_id] = sub_action
|
@@ -289,7 +430,6 @@ class ToolbarBundle:
|
|
289
430
|
self.bundle_id = bundle_id
|
290
431
|
self._actions: dict[str, ToolBarAction] = {}
|
291
432
|
|
292
|
-
# If you passed in a list of tuples, load them into the dictionary
|
293
433
|
if actions is not None:
|
294
434
|
for action_id, action in actions:
|
295
435
|
self._actions[action_id] = action
|
@@ -331,7 +471,7 @@ class ModularToolBar(QToolBar):
|
|
331
471
|
actions (dict, optional): A dictionary of action creators to populate the toolbar. Defaults to None.
|
332
472
|
target_widget (QWidget, optional): The widget that the actions will target. Defaults to None.
|
333
473
|
orientation (Literal["horizontal", "vertical"], optional): The initial orientation of the toolbar. Defaults to "horizontal".
|
334
|
-
background_color (str, optional): The background color of the toolbar. Defaults to "rgba(0, 0, 0, 0)"
|
474
|
+
background_color (str, optional): The background color of the toolbar. Defaults to "rgba(0, 0, 0, 0)".
|
335
475
|
"""
|
336
476
|
|
337
477
|
def __init__(
|
@@ -378,7 +518,7 @@ class ModularToolBar(QToolBar):
|
|
378
518
|
Sets the background color and other appearance settings.
|
379
519
|
|
380
520
|
Args:
|
381
|
-
color(str): The background color of the toolbar.
|
521
|
+
color (str): The background color of the toolbar.
|
382
522
|
"""
|
383
523
|
self.setIconSize(QSize(20, 20))
|
384
524
|
self.setMovable(False)
|
@@ -402,100 +542,133 @@ class ModularToolBar(QToolBar):
|
|
402
542
|
|
403
543
|
def update_material_icon_colors(self, new_color: str | tuple | QColor):
|
404
544
|
"""
|
405
|
-
Updates the color of all MaterialIconAction icons
|
545
|
+
Updates the color of all MaterialIconAction icons.
|
406
546
|
|
407
547
|
Args:
|
408
|
-
new_color (str | tuple | QColor): The new color
|
548
|
+
new_color (str | tuple | QColor): The new color.
|
409
549
|
"""
|
410
550
|
for action in self.widgets.values():
|
411
551
|
if isinstance(action, MaterialIconAction):
|
412
552
|
action.color = new_color
|
413
|
-
# Refresh the icon
|
414
553
|
updated_icon = action.get_icon()
|
415
554
|
action.action.setIcon(updated_icon)
|
416
555
|
|
417
556
|
def add_action(self, action_id: str, action: ToolBarAction, target_widget: QWidget):
|
418
557
|
"""
|
419
|
-
Adds a new standalone action
|
558
|
+
Adds a new standalone action dynamically.
|
420
559
|
|
421
560
|
Args:
|
422
|
-
action_id (str): Unique identifier
|
423
|
-
action (ToolBarAction): The action to add
|
424
|
-
target_widget (QWidget): The target widget
|
561
|
+
action_id (str): Unique identifier.
|
562
|
+
action (ToolBarAction): The action to add.
|
563
|
+
target_widget (QWidget): The target widget.
|
425
564
|
"""
|
426
565
|
if action_id in self.widgets:
|
427
566
|
raise ValueError(f"Action with ID '{action_id}' already exists.")
|
428
567
|
action.add_to_toolbar(self, target_widget)
|
429
568
|
self.widgets[action_id] = action
|
430
569
|
self.toolbar_items.append(("action", action_id))
|
431
|
-
self.update_separators()
|
570
|
+
self.update_separators()
|
432
571
|
|
433
572
|
def hide_action(self, action_id: str):
|
434
573
|
"""
|
435
|
-
Hides a specific action
|
574
|
+
Hides a specific action.
|
436
575
|
|
437
576
|
Args:
|
438
|
-
action_id (str): Unique identifier
|
577
|
+
action_id (str): Unique identifier.
|
439
578
|
"""
|
440
579
|
if action_id not in self.widgets:
|
441
580
|
raise ValueError(f"Action with ID '{action_id}' does not exist.")
|
442
581
|
action = self.widgets[action_id]
|
443
|
-
if hasattr(action, "action") and
|
582
|
+
if hasattr(action, "action") and action.action is not None:
|
444
583
|
action.action.setVisible(False)
|
445
|
-
self.update_separators()
|
584
|
+
self.update_separators()
|
446
585
|
|
447
586
|
def show_action(self, action_id: str):
|
448
587
|
"""
|
449
|
-
Shows a specific action
|
588
|
+
Shows a specific action.
|
450
589
|
|
451
590
|
Args:
|
452
|
-
action_id (str): Unique identifier
|
591
|
+
action_id (str): Unique identifier.
|
453
592
|
"""
|
454
593
|
if action_id not in self.widgets:
|
455
594
|
raise ValueError(f"Action with ID '{action_id}' does not exist.")
|
456
595
|
action = self.widgets[action_id]
|
457
|
-
if hasattr(action, "action") and
|
596
|
+
if hasattr(action, "action") and action.action is not None:
|
458
597
|
action.action.setVisible(True)
|
459
|
-
self.update_separators()
|
598
|
+
self.update_separators()
|
460
599
|
|
461
600
|
def add_bundle(self, bundle: ToolbarBundle, target_widget: QWidget):
|
462
601
|
"""
|
463
|
-
Adds a bundle of actions
|
602
|
+
Adds a bundle of actions, separated by a separator.
|
464
603
|
|
465
604
|
Args:
|
466
|
-
bundle (ToolbarBundle): The bundle
|
467
|
-
target_widget (QWidget): The target widget
|
605
|
+
bundle (ToolbarBundle): The bundle.
|
606
|
+
target_widget (QWidget): The target widget.
|
468
607
|
"""
|
469
608
|
if bundle.bundle_id in self.bundles:
|
470
609
|
raise ValueError(f"ToolbarBundle with ID '{bundle.bundle_id}' already exists.")
|
471
610
|
|
472
|
-
# Add a separator before the bundle (but not to first one)
|
473
611
|
if self.toolbar_items:
|
474
612
|
sep = SeparatorAction()
|
475
613
|
sep.add_to_toolbar(self, target_widget)
|
476
614
|
self.toolbar_items.append(("separator", None))
|
477
615
|
|
478
|
-
# Add each action in the bundle
|
479
616
|
for action_id, action_obj in bundle.actions.items():
|
480
617
|
action_obj.add_to_toolbar(self, target_widget)
|
481
618
|
self.widgets[action_id] = action_obj
|
482
619
|
|
483
|
-
# Register the bundle
|
484
620
|
self.bundles[bundle.bundle_id] = list(bundle.actions.keys())
|
485
621
|
self.toolbar_items.append(("bundle", bundle.bundle_id))
|
622
|
+
self.update_separators()
|
623
|
+
|
624
|
+
def add_action_to_bundle(self, bundle_id: str, action_id: str, action, target_widget: QWidget):
|
625
|
+
"""
|
626
|
+
Dynamically adds an action to an existing bundle.
|
627
|
+
|
628
|
+
Args:
|
629
|
+
bundle_id (str): The bundle ID.
|
630
|
+
action_id (str): Unique identifier.
|
631
|
+
action (ToolBarAction): The action to add.
|
632
|
+
target_widget (QWidget): The target widget.
|
633
|
+
"""
|
634
|
+
if bundle_id not in self.bundles:
|
635
|
+
raise ValueError(f"Bundle '{bundle_id}' does not exist.")
|
636
|
+
if action_id in self.widgets:
|
637
|
+
raise ValueError(f"Action with ID '{action_id}' already exists.")
|
638
|
+
|
639
|
+
action.add_to_toolbar(self, target_widget)
|
640
|
+
new_qaction = action.action
|
641
|
+
self.removeAction(new_qaction)
|
642
|
+
|
643
|
+
bundle_action_ids = self.bundles[bundle_id]
|
644
|
+
if bundle_action_ids:
|
645
|
+
last_bundle_action = self.widgets[bundle_action_ids[-1]].action
|
646
|
+
actions_list = self.actions()
|
647
|
+
try:
|
648
|
+
index = actions_list.index(last_bundle_action)
|
649
|
+
except ValueError:
|
650
|
+
self.addAction(new_qaction)
|
651
|
+
else:
|
652
|
+
if index + 1 < len(actions_list):
|
653
|
+
before_action = actions_list[index + 1]
|
654
|
+
self.insertAction(before_action, new_qaction)
|
655
|
+
else:
|
656
|
+
self.addAction(new_qaction)
|
657
|
+
else:
|
658
|
+
self.addAction(new_qaction)
|
486
659
|
|
487
|
-
self.
|
660
|
+
self.widgets[action_id] = action
|
661
|
+
self.bundles[bundle_id].append(action_id)
|
662
|
+
self.update_separators()
|
488
663
|
|
489
664
|
def contextMenuEvent(self, event):
|
490
665
|
"""
|
491
|
-
Overrides the context menu event to show
|
666
|
+
Overrides the context menu event to show toolbar actions with checkboxes and icons.
|
492
667
|
|
493
668
|
Args:
|
494
|
-
event(QContextMenuEvent): The context menu event.
|
669
|
+
event (QContextMenuEvent): The context menu event.
|
495
670
|
"""
|
496
671
|
menu = QMenu(self)
|
497
|
-
|
498
|
-
# Iterate through the toolbar items in order
|
499
672
|
for item_type, identifier in self.toolbar_items:
|
500
673
|
if item_type == "separator":
|
501
674
|
menu.addSeparator()
|
@@ -503,18 +676,16 @@ class ModularToolBar(QToolBar):
|
|
503
676
|
self.handle_bundle_context_menu(menu, identifier)
|
504
677
|
elif item_type == "action":
|
505
678
|
self.handle_action_context_menu(menu, identifier)
|
506
|
-
|
507
|
-
# Connect the triggered signal after all actions are added
|
508
679
|
menu.triggered.connect(self.handle_menu_triggered)
|
509
680
|
menu.exec_(event.globalPos())
|
510
681
|
|
511
682
|
def handle_bundle_context_menu(self, menu: QMenu, bundle_id: str):
|
512
683
|
"""
|
513
|
-
Adds
|
684
|
+
Adds bundle actions to the context menu.
|
514
685
|
|
515
686
|
Args:
|
516
|
-
menu (QMenu): The context menu
|
517
|
-
bundle_id (str): The identifier
|
687
|
+
menu (QMenu): The context menu.
|
688
|
+
bundle_id (str): The bundle identifier.
|
518
689
|
"""
|
519
690
|
action_ids = self.bundles.get(bundle_id, [])
|
520
691
|
for act_id in action_ids:
|
@@ -535,7 +706,6 @@ class ModularToolBar(QToolBar):
|
|
535
706
|
# Set the icon if available
|
536
707
|
if qaction.icon() and not qaction.icon().isNull():
|
537
708
|
menu_action.setIcon(qaction.icon())
|
538
|
-
|
539
709
|
menu.addAction(menu_action)
|
540
710
|
|
541
711
|
def handle_action_context_menu(self, menu: QMenu, action_id: str):
|
@@ -565,73 +735,95 @@ class ModularToolBar(QToolBar):
|
|
565
735
|
menu.addAction(menu_action)
|
566
736
|
|
567
737
|
def handle_menu_triggered(self, action):
|
568
|
-
"""
|
738
|
+
"""
|
739
|
+
Handles the triggered signal from the context menu.
|
740
|
+
|
741
|
+
Args:
|
742
|
+
action: Action triggered.
|
743
|
+
"""
|
569
744
|
action_id = action.data()
|
570
745
|
if action_id:
|
571
746
|
self.toggle_action_visibility(action_id, action.isChecked())
|
572
747
|
|
573
748
|
def toggle_action_visibility(self, action_id: str, visible: bool):
|
574
749
|
"""
|
575
|
-
Toggles the visibility of a specific action
|
750
|
+
Toggles the visibility of a specific action.
|
576
751
|
|
577
752
|
Args:
|
578
|
-
action_id(str): Unique identifier
|
579
|
-
visible(bool): Whether the action should be visible.
|
753
|
+
action_id (str): Unique identifier.
|
754
|
+
visible (bool): Whether the action should be visible.
|
580
755
|
"""
|
581
756
|
if action_id not in self.widgets:
|
582
757
|
return
|
583
|
-
|
584
758
|
tool_action = self.widgets[action_id]
|
585
|
-
if hasattr(tool_action, "action") and
|
759
|
+
if hasattr(tool_action, "action") and tool_action.action is not None:
|
586
760
|
tool_action.action.setVisible(visible)
|
587
761
|
self.update_separators()
|
588
762
|
|
589
763
|
def update_separators(self):
|
590
764
|
"""
|
591
|
-
Hide separators that are adjacent to another separator or have no actions
|
765
|
+
Hide separators that are adjacent to another separator or have no non-separator actions between them.
|
592
766
|
"""
|
593
767
|
toolbar_actions = self.actions()
|
594
|
-
|
768
|
+
# First pass: set visibility based on surrounding non-separator actions.
|
595
769
|
for i, action in enumerate(toolbar_actions):
|
596
770
|
if not action.isSeparator():
|
597
771
|
continue
|
598
|
-
# Find the previous visible action
|
599
772
|
prev_visible = None
|
600
773
|
for j in range(i - 1, -1, -1):
|
601
774
|
if toolbar_actions[j].isVisible():
|
602
775
|
prev_visible = toolbar_actions[j]
|
603
776
|
break
|
604
|
-
|
605
|
-
# Find the next visible action
|
606
777
|
next_visible = None
|
607
778
|
for j in range(i + 1, len(toolbar_actions)):
|
608
779
|
if toolbar_actions[j].isVisible():
|
609
780
|
next_visible = toolbar_actions[j]
|
610
781
|
break
|
611
|
-
|
612
|
-
# Determine if the separator should be hidden
|
613
|
-
# Hide if both previous and next visible actions are separators or non-existent
|
614
782
|
if (prev_visible is None or prev_visible.isSeparator()) and (
|
615
783
|
next_visible is None or next_visible.isSeparator()
|
616
784
|
):
|
617
785
|
action.setVisible(False)
|
618
786
|
else:
|
619
787
|
action.setVisible(True)
|
788
|
+
# Second pass: ensure no two visible separators are adjacent.
|
789
|
+
prev = None
|
790
|
+
for action in toolbar_actions:
|
791
|
+
if action.isVisible() and action.isSeparator():
|
792
|
+
if prev and prev.isSeparator():
|
793
|
+
action.setVisible(False)
|
794
|
+
else:
|
795
|
+
prev = action
|
796
|
+
else:
|
797
|
+
if action.isVisible():
|
798
|
+
prev = action
|
620
799
|
|
621
800
|
|
622
801
|
class MainWindow(QMainWindow): # pragma: no cover
|
623
802
|
def __init__(self):
|
624
803
|
super().__init__()
|
625
804
|
self.setWindowTitle("Toolbar / ToolbarBundle Demo")
|
626
|
-
|
627
805
|
self.central_widget = QWidget()
|
628
806
|
self.setCentralWidget(self.central_widget)
|
807
|
+
self.test_label = QLabel(text="This is a test label.")
|
808
|
+
self.central_widget.layout = QVBoxLayout(self.central_widget)
|
809
|
+
self.central_widget.layout.addWidget(self.test_label)
|
629
810
|
|
630
|
-
# Create a modular toolbar
|
631
811
|
self.toolbar = ModularToolBar(parent=self, target_widget=self)
|
632
812
|
self.addToolBar(self.toolbar)
|
633
813
|
|
634
|
-
|
814
|
+
self.add_switchable_button_checkable()
|
815
|
+
self.add_switchable_button_non_checkable()
|
816
|
+
self.add_widget_actions()
|
817
|
+
self.add_bundles()
|
818
|
+
self.add_menus()
|
819
|
+
|
820
|
+
# For theme testing
|
821
|
+
|
822
|
+
self.dark_button = DarkModeButton(toolbar=True)
|
823
|
+
dark_mode_action = WidgetAction(label=None, widget=self.dark_button)
|
824
|
+
self.toolbar.add_action("dark_mode", dark_mode_action, self)
|
825
|
+
|
826
|
+
def add_bundles(self):
|
635
827
|
home_action = MaterialIconAction(
|
636
828
|
icon_name="home", tooltip="Home", checkable=True, parent=self
|
637
829
|
)
|
@@ -651,12 +843,11 @@ class MainWindow(QMainWindow): # pragma: no cover
|
|
651
843
|
)
|
652
844
|
self.toolbar.add_bundle(main_actions_bundle, target_widget=self)
|
653
845
|
|
654
|
-
# Another bundle
|
655
846
|
search_action = MaterialIconAction(
|
656
|
-
icon_name="search", tooltip="Search", checkable=
|
847
|
+
icon_name="search", tooltip="Search", checkable=False, parent=self
|
657
848
|
)
|
658
849
|
help_action = MaterialIconAction(
|
659
|
-
icon_name="help", tooltip="Help", checkable=
|
850
|
+
icon_name="help", tooltip="Help", checkable=False, parent=self
|
660
851
|
)
|
661
852
|
second_bundle = ToolbarBundle(
|
662
853
|
bundle_id="secondary_actions",
|
@@ -664,9 +855,101 @@ class MainWindow(QMainWindow): # pragma: no cover
|
|
664
855
|
)
|
665
856
|
self.toolbar.add_bundle(second_bundle, target_widget=self)
|
666
857
|
|
858
|
+
new_action = MaterialIconAction(
|
859
|
+
icon_name="counter_1", tooltip="New Action", checkable=True, parent=self
|
860
|
+
)
|
861
|
+
self.toolbar.add_action_to_bundle(
|
862
|
+
"main_actions", "new_action", new_action, target_widget=self
|
863
|
+
)
|
864
|
+
|
865
|
+
def add_menus(self):
|
866
|
+
menu_material_actions = {
|
867
|
+
"mat1": MaterialIconAction(
|
868
|
+
icon_name="home", tooltip="Material Home", checkable=True, parent=self
|
869
|
+
),
|
870
|
+
"mat2": MaterialIconAction(
|
871
|
+
icon_name="settings", tooltip="Material Settings", checkable=True, parent=self
|
872
|
+
),
|
873
|
+
"mat3": MaterialIconAction(
|
874
|
+
icon_name="info", tooltip="Material Info", checkable=True, parent=self
|
875
|
+
),
|
876
|
+
}
|
877
|
+
menu_qt_actions = {
|
878
|
+
"qt1": QtIconAction(
|
879
|
+
standard_icon=QStyle.SP_FileIcon, tooltip="Qt File", checkable=True, parent=self
|
880
|
+
),
|
881
|
+
"qt2": QtIconAction(
|
882
|
+
standard_icon=QStyle.SP_DirIcon, tooltip="Qt Directory", checkable=True, parent=self
|
883
|
+
),
|
884
|
+
"qt3": QtIconAction(
|
885
|
+
standard_icon=QStyle.SP_TrashIcon, tooltip="Qt Trash", checkable=True, parent=self
|
886
|
+
),
|
887
|
+
}
|
888
|
+
expandable_menu_material = ExpandableMenuAction(
|
889
|
+
label="Material Menu", actions=menu_material_actions
|
890
|
+
)
|
891
|
+
expandable_menu_qt = ExpandableMenuAction(label="Qt Menu", actions=menu_qt_actions)
|
892
|
+
|
893
|
+
self.toolbar.add_action("material_menu", expandable_menu_material, self)
|
894
|
+
self.toolbar.add_action("qt_menu", expandable_menu_qt, self)
|
895
|
+
|
896
|
+
def add_switchable_button_checkable(self):
|
897
|
+
action1 = MaterialIconAction(
|
898
|
+
icon_name="counter_1", tooltip="Action 1", checkable=True, parent=self
|
899
|
+
)
|
900
|
+
action2 = MaterialIconAction(
|
901
|
+
icon_name="counter_2", tooltip="Action 2", checkable=True, parent=self
|
902
|
+
)
|
903
|
+
|
904
|
+
switchable_action = SwitchableToolBarAction(
|
905
|
+
actions={"action1": action1, "action2": action2},
|
906
|
+
initial_action="action1",
|
907
|
+
tooltip="Switchable Action",
|
908
|
+
checkable=True,
|
909
|
+
parent=self,
|
910
|
+
)
|
911
|
+
self.toolbar.add_action("switchable_action", switchable_action, self)
|
912
|
+
|
913
|
+
action1.action.toggled.connect(
|
914
|
+
lambda checked: self.test_label.setText(f"Action 1 triggered, checked = {checked}")
|
915
|
+
)
|
916
|
+
action2.action.toggled.connect(
|
917
|
+
lambda checked: self.test_label.setText(f"Action 2 triggered, checked = {checked}")
|
918
|
+
)
|
919
|
+
|
920
|
+
def add_switchable_button_non_checkable(self):
|
921
|
+
action1 = MaterialIconAction(
|
922
|
+
icon_name="counter_1", tooltip="Action 1", checkable=False, parent=self
|
923
|
+
)
|
924
|
+
action2 = MaterialIconAction(
|
925
|
+
icon_name="counter_2", tooltip="Action 2", checkable=False, parent=self
|
926
|
+
)
|
927
|
+
|
928
|
+
switchable_action = SwitchableToolBarAction(
|
929
|
+
actions={"action1": action1, "action2": action2},
|
930
|
+
initial_action="action1",
|
931
|
+
tooltip="Switchable Action",
|
932
|
+
checkable=False,
|
933
|
+
parent=self,
|
934
|
+
)
|
935
|
+
self.toolbar.add_action("switchable_action_no_toggle", switchable_action, self)
|
936
|
+
|
937
|
+
action1.action.triggered.connect(
|
938
|
+
lambda checked: self.test_label.setText(f"Action 1 triggered, checked = {checked}")
|
939
|
+
)
|
940
|
+
action2.action.triggered.connect(
|
941
|
+
lambda checked: self.test_label.setText(f"Action 2 triggered, checked = {checked}")
|
942
|
+
)
|
943
|
+
|
944
|
+
def add_widget_actions(self):
|
945
|
+
combo = QComboBox()
|
946
|
+
combo.addItems(["Option 1", "Option 2", "Option 3"])
|
947
|
+
self.toolbar.add_action("device_combo", WidgetAction(label="Device:", widget=combo), self)
|
948
|
+
|
667
949
|
|
668
950
|
if __name__ == "__main__": # pragma: no cover
|
669
951
|
app = QApplication(sys.argv)
|
952
|
+
set_theme("light")
|
670
953
|
main_window = MainWindow()
|
671
954
|
main_window.show()
|
672
955
|
sys.exit(app.exec_())
|
File without changes
|
@@ -0,0 +1 @@
|
|
1
|
+
{'files': ['decimal_spinbox.py']}
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# Copyright (C) 2022 The Qt Company Ltd.
|
2
|
+
# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
|
3
|
+
|
4
|
+
from qtpy.QtDesigner import QDesignerCustomWidgetInterface
|
5
|
+
|
6
|
+
from bec_widgets.utils.bec_designer import designer_material_icon
|
7
|
+
from bec_widgets.widgets.utility.spinbox.decimal_spinbox import BECSpinBox
|
8
|
+
|
9
|
+
DOM_XML = """
|
10
|
+
<ui language='c++'>
|
11
|
+
<widget class='BECSpinBox' name='bec_spin_box'>
|
12
|
+
</widget>
|
13
|
+
</ui>
|
14
|
+
"""
|
15
|
+
|
16
|
+
|
17
|
+
class BECSpinBoxPlugin(QDesignerCustomWidgetInterface): # pragma: no cover
|
18
|
+
def __init__(self):
|
19
|
+
super().__init__()
|
20
|
+
self._form_editor = None
|
21
|
+
|
22
|
+
def createWidget(self, parent):
|
23
|
+
t = BECSpinBox(parent)
|
24
|
+
return t
|
25
|
+
|
26
|
+
def domXml(self):
|
27
|
+
return DOM_XML
|
28
|
+
|
29
|
+
def group(self):
|
30
|
+
return ""
|
31
|
+
|
32
|
+
def icon(self):
|
33
|
+
return designer_material_icon(BECSpinBox.ICON_NAME)
|
34
|
+
|
35
|
+
def includeFile(self):
|
36
|
+
return "bec_spin_box"
|
37
|
+
|
38
|
+
def initialize(self, form_editor):
|
39
|
+
self._form_editor = form_editor
|
40
|
+
|
41
|
+
def isContainer(self):
|
42
|
+
return False
|
43
|
+
|
44
|
+
def isInitialized(self):
|
45
|
+
return self._form_editor is not None
|
46
|
+
|
47
|
+
def name(self):
|
48
|
+
return "BECSpinBox"
|
49
|
+
|
50
|
+
def toolTip(self):
|
51
|
+
return "BECSpinBox"
|
52
|
+
|
53
|
+
def whatsThis(self):
|
54
|
+
return self.toolTip()
|
@@ -0,0 +1,83 @@
|
|
1
|
+
import sys
|
2
|
+
|
3
|
+
from bec_qthemes import material_icon
|
4
|
+
from qtpy.QtGui import Qt
|
5
|
+
from qtpy.QtWidgets import (
|
6
|
+
QApplication,
|
7
|
+
QDoubleSpinBox,
|
8
|
+
QInputDialog,
|
9
|
+
QSizePolicy,
|
10
|
+
QToolButton,
|
11
|
+
QWidget,
|
12
|
+
)
|
13
|
+
|
14
|
+
from bec_widgets.utils import ConnectionConfig
|
15
|
+
from bec_widgets.utils.bec_widget import BECWidget
|
16
|
+
|
17
|
+
|
18
|
+
class BECSpinBox(BECWidget, QDoubleSpinBox):
|
19
|
+
PLUGIN = True
|
20
|
+
RPC = False
|
21
|
+
ICON_NAME = "123"
|
22
|
+
|
23
|
+
def __init__(
|
24
|
+
self,
|
25
|
+
parent: QWidget | None = None,
|
26
|
+
config: ConnectionConfig | None = None,
|
27
|
+
client=None,
|
28
|
+
gui_id: str | None = None,
|
29
|
+
) -> None:
|
30
|
+
if config is None:
|
31
|
+
config = ConnectionConfig(widget_class=self.__class__.__name__)
|
32
|
+
super().__init__(client=client, gui_id=gui_id, config=config)
|
33
|
+
QDoubleSpinBox.__init__(self, parent=parent)
|
34
|
+
|
35
|
+
self.setObjectName("BECSpinBox")
|
36
|
+
# Make the widget as compact as possible horizontally.
|
37
|
+
self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Fixed)
|
38
|
+
self.setAlignment(Qt.AlignHCenter)
|
39
|
+
|
40
|
+
# Configure default QDoubleSpinBox settings.
|
41
|
+
self.setRange(-2147483647, 2147483647)
|
42
|
+
self.setDecimals(2)
|
43
|
+
|
44
|
+
# Create an embedded settings button.
|
45
|
+
self.setting_button = QToolButton(self)
|
46
|
+
self.setting_button.setIcon(material_icon("settings"))
|
47
|
+
self.setting_button.setToolTip("Set number of decimals")
|
48
|
+
self.setting_button.setCursor(Qt.PointingHandCursor)
|
49
|
+
self.setting_button.setFocusPolicy(Qt.NoFocus)
|
50
|
+
self.setting_button.setStyleSheet("QToolButton { border: none; padding: 0px; }")
|
51
|
+
|
52
|
+
self.setting_button.clicked.connect(self.change_decimals)
|
53
|
+
|
54
|
+
self._button_size = 12
|
55
|
+
self._arrow_width = 20
|
56
|
+
|
57
|
+
def resizeEvent(self, event):
|
58
|
+
super().resizeEvent(event)
|
59
|
+
arrow_width = self._arrow_width
|
60
|
+
|
61
|
+
# Position the settings button inside the spin box, to the left of the arrow buttons.
|
62
|
+
x = self.width() - arrow_width - self._button_size - 2 # 2px margin
|
63
|
+
y = (self.height() - self._button_size) // 2
|
64
|
+
self.setting_button.setFixedSize(self._button_size, self._button_size)
|
65
|
+
self.setting_button.move(x, y)
|
66
|
+
|
67
|
+
def change_decimals(self):
|
68
|
+
"""
|
69
|
+
Change the number of decimals in the spin box.
|
70
|
+
"""
|
71
|
+
current = self.decimals()
|
72
|
+
new_decimals, ok = QInputDialog.getInt(
|
73
|
+
self, "Set Decimals", "Number of decimals:", current, 0, 10, 1
|
74
|
+
)
|
75
|
+
if ok:
|
76
|
+
self.setDecimals(new_decimals)
|
77
|
+
|
78
|
+
|
79
|
+
if __name__ == "__main__": # pragma: no cover
|
80
|
+
app = QApplication(sys.argv)
|
81
|
+
window = BECSpinBox()
|
82
|
+
window.show()
|
83
|
+
sys.exit(app.exec())
|
@@ -0,0 +1,15 @@
|
|
1
|
+
def main(): # pragma: no cover
|
2
|
+
from qtpy import PYSIDE6
|
3
|
+
|
4
|
+
if not PYSIDE6:
|
5
|
+
print("PYSIDE6 is not available in the environment. Cannot patch designer.")
|
6
|
+
return
|
7
|
+
from PySide6.QtDesigner import QPyDesignerCustomWidgetCollection
|
8
|
+
|
9
|
+
from bec_widgets.widgets.utility.spinbox.bec_spin_box_plugin import BECSpinBoxPlugin
|
10
|
+
|
11
|
+
QPyDesignerCustomWidgetCollection.addCustomWidget(BECSpinBoxPlugin())
|
12
|
+
|
13
|
+
|
14
|
+
if __name__ == "__main__": # pragma: no cover
|
15
|
+
main()
|
@@ -2,11 +2,11 @@
|
|
2
2
|
.gitlab-ci.yml,sha256=PuL-FmkTHm7qs467Mh9D8quWcEj4tgEA-UUGDieMuWk,8774
|
3
3
|
.pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
|
4
4
|
.readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
|
5
|
-
CHANGELOG.md,sha256
|
5
|
+
CHANGELOG.md,sha256=areIe8x_CISa3v2AYaePk8DGFWijiSCy-ILBAZGrYdA,230584
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=WcdVimfKWBYa3l0ifogd51I_0VM7a9qy1uAOAj4oeEU,1173
|
8
8
|
README.md,sha256=KgdKusjlvEvFtdNZCeDMO91y77MWK2iDcYMDziksOr4,2553
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=BUpfPrJNoboBinXX3OGzf4SD1ImSX6TqmS179jRRMXI,2540
|
10
10
|
.git_hooks/pre-commit,sha256=n3RofIZHJl8zfJJIUomcMyYGFi_rwq4CC19z0snz3FI,286
|
11
11
|
.gitlab/issue_templates/bug_report_template.md,sha256=gAuyEwl7XlnebBrkiJ9AqffSNOywmr8vygUFWKTuQeI,386
|
12
12
|
.gitlab/issue_templates/documentation_update_template.md,sha256=FHLdb3TS_D9aL4CYZCjyXSulbaW5mrN2CmwTaeLPbNw,860
|
@@ -55,7 +55,7 @@ bec_widgets/qt_utils/redis_message_waiter.py,sha256=fvL_QgC0cTDv_FPJdRyp5AKjf401
|
|
55
55
|
bec_widgets/qt_utils/round_frame.py,sha256=ldLQ4BaWygFRrRv1s0w--5qZ4sj8MAqhdXuzho50xMg,4860
|
56
56
|
bec_widgets/qt_utils/settings_dialog.py,sha256=NhtzTer_xzlB2lLLrGklkI1QYLJEWQpJoZbCz4o5daI,3645
|
57
57
|
bec_widgets/qt_utils/side_panel.py,sha256=H2Ko7FPYwQ2Nemrud-q-rmqzHGO8vly_pzE_ySEfoGQ,12569
|
58
|
-
bec_widgets/qt_utils/toolbar.py,sha256=
|
58
|
+
bec_widgets/qt_utils/toolbar.py,sha256=AizwnTiY2RkRJfouJu4nCiFoWd0wEgS_nDF36EiUQjk,35779
|
59
59
|
bec_widgets/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
60
60
|
bec_widgets/tests/utils.py,sha256=GbQtN7qf9n-8FoAfNddZ4aAqA7oBo_hGAlnKELd6Xzw,6943
|
61
61
|
bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
|
@@ -325,6 +325,11 @@ bec_widgets/widgets/utility/logpanel/log_panel.pyproject,sha256=2ncs1bsu-wICstR1
|
|
325
325
|
bec_widgets/widgets/utility/logpanel/log_panel_plugin.py,sha256=KY7eS1uGZzLYtDAdBv6S2mw8UjcDGVt3UklN_D5M06A,1250
|
326
326
|
bec_widgets/widgets/utility/logpanel/logpanel.py,sha256=jMQKn5O7qUFkN-2YnQ3HY7vSf8LIH5ox-T1E_lL3zfQ,19675
|
327
327
|
bec_widgets/widgets/utility/logpanel/register_log_panel.py,sha256=LFUE5JzCYvIwJQtTqZASLVAHYy3gO1nrHzPVH_kpCEY,470
|
328
|
+
bec_widgets/widgets/utility/spinbox/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
329
|
+
bec_widgets/widgets/utility/spinbox/bec_spin_box.pyproject,sha256=RIg1SZuCltuZZuK1O4Djg0TpCInhoCw8KeqNaf1_K0A,33
|
330
|
+
bec_widgets/widgets/utility/spinbox/bec_spin_box_plugin.py,sha256=-XNrUAz1LZQPhJrH1sszfGrpBfpHUIfNO4bw7MPcc3k,1255
|
331
|
+
bec_widgets/widgets/utility/spinbox/decimal_spinbox.py,sha256=JhTh4Iz_7Hv69G4kksdpa1QZihtAzqaYlkWf3v-SGN8,2671
|
332
|
+
bec_widgets/widgets/utility/spinbox/register_bec_spin_box.py,sha256=_whARPM42TCYV_rUBtThGUK7XC1VoIwRn8fVHzxI2pc,476
|
328
333
|
bec_widgets/widgets/utility/spinner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
329
334
|
bec_widgets/widgets/utility/spinner/register_spinner_widget.py,sha256=96A13dEcyTgXfc9G0sTdlXYCDcVav8Z2P2eDC95bESQ,484
|
330
335
|
bec_widgets/widgets/utility/spinner/spinner.py,sha256=6c0fN7mdGzELg4mf_yG08ubses3svb6w0EqMeHDFkIw,2651
|
@@ -356,8 +361,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=Z
|
|
356
361
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
|
357
362
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
|
358
363
|
bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
|
359
|
-
bec_widgets-1.
|
360
|
-
bec_widgets-1.
|
361
|
-
bec_widgets-1.
|
362
|
-
bec_widgets-1.
|
363
|
-
bec_widgets-1.
|
364
|
+
bec_widgets-1.23.0.dist-info/METADATA,sha256=WcdVimfKWBYa3l0ifogd51I_0VM7a9qy1uAOAj4oeEU,1173
|
365
|
+
bec_widgets-1.23.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
366
|
+
bec_widgets-1.23.0.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
|
367
|
+
bec_widgets-1.23.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
368
|
+
bec_widgets-1.23.0.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|
File without changes
|