bec-widgets 1.24.0__py3-none-any.whl → 1.24.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHANGELOG.md +25 -0
- PKG-INFO +1 -1
- bec_widgets/qt_utils/settings_dialog.py +7 -6
- bec_widgets/qt_utils/toolbar.py +6 -3
- bec_widgets/widgets/plots_next_gen/plot_base.py +170 -33
- bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings.py +59 -4
- bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings_horizontal.ui +112 -156
- bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings_vertical.ui +17 -52
- bec_widgets/widgets/plots_next_gen/toolbar_bundles/mouse_interactions.py +31 -18
- bec_widgets/widgets/plots_next_gen/toolbar_bundles/plot_export.py +10 -3
- {bec_widgets-1.24.0.dist-info → bec_widgets-1.24.1.dist-info}/METADATA +1 -1
- {bec_widgets-1.24.0.dist-info → bec_widgets-1.24.1.dist-info}/RECORD +16 -16
- pyproject.toml +1 -1
- {bec_widgets-1.24.0.dist-info → bec_widgets-1.24.1.dist-info}/WHEEL +0 -0
- {bec_widgets-1.24.0.dist-info → bec_widgets-1.24.1.dist-info}/entry_points.txt +0 -0
- {bec_widgets-1.24.0.dist-info → bec_widgets-1.24.1.dist-info}/licenses/LICENSE +0 -0
CHANGELOG.md
CHANGED
@@ -1,6 +1,31 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
3
|
|
4
|
+
## v1.24.1 (2025-02-26)
|
5
|
+
|
6
|
+
### Bug Fixes
|
7
|
+
|
8
|
+
- **plot_base**: Ability to choose between popup or side panel gui mode
|
9
|
+
([`3aa2f22`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/3aa2f2225fba499b648d191ea27553b6db303c18))
|
10
|
+
|
11
|
+
- **toolbar**: Switch Actions for default checked actions fixed
|
12
|
+
([`6d1106e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6d1106e33e1fc3839244b11a601fb71e81a65e61))
|
13
|
+
|
14
|
+
### Refactoring
|
15
|
+
|
16
|
+
- **axis_settings**: Spinbox migrated to new BECSpinBoxes
|
17
|
+
([`90a1846`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/90a184643aaaaabaa4feb02d2f406fe2bb9daecc))
|
18
|
+
|
19
|
+
- **plot_base**: Toolbar buttons adapted for the Switch actions from toolbar; plot export and mouse
|
20
|
+
modes consolidated into one switch button
|
21
|
+
([`6f2c240`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/6f2c2401ac99b2b8a9af9af76854669a248b516b))
|
22
|
+
|
23
|
+
### Testing
|
24
|
+
|
25
|
+
- Extended test coverage for axis settings, plot base and qt toolbar action
|
26
|
+
([`8679b5f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/8679b5f08bef8a4a2b6338d9bee4cd70d564f288))
|
27
|
+
|
28
|
+
|
4
29
|
## v1.24.0 (2025-02-26)
|
5
30
|
|
6
31
|
### Bug Fixes
|
PKG-INFO
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from qtpy.QtWidgets import QDialog, QDialogButtonBox, QHBoxLayout, QPushButton, QVBoxLayout, QWidget
|
2
2
|
|
3
|
-
from bec_widgets.qt_utils.error_popups import SafeSlot
|
3
|
+
from bec_widgets.qt_utils.error_popups import SafeSlot
|
4
4
|
|
5
5
|
|
6
6
|
class SettingWidget(QWidget):
|
@@ -20,14 +20,14 @@ class SettingWidget(QWidget):
|
|
20
20
|
def set_target_widget(self, target_widget: QWidget):
|
21
21
|
self.target_widget = target_widget
|
22
22
|
|
23
|
-
@
|
23
|
+
@SafeSlot()
|
24
24
|
def accept_changes(self):
|
25
25
|
"""
|
26
26
|
Accepts the changes made in the settings widget and applies them to the target widget.
|
27
27
|
"""
|
28
28
|
pass
|
29
29
|
|
30
|
-
@
|
30
|
+
@SafeSlot(dict)
|
31
31
|
def display_current_settings(self, config_dict: dict):
|
32
32
|
"""
|
33
33
|
Displays the current settings of the target widget in the settings widget.
|
@@ -54,12 +54,13 @@ class SettingsDialog(QDialog):
|
|
54
54
|
settings_widget: SettingWidget = None,
|
55
55
|
window_title: str = "Settings",
|
56
56
|
config: dict = None,
|
57
|
+
modal: bool = False,
|
57
58
|
*args,
|
58
59
|
**kwargs,
|
59
60
|
):
|
60
61
|
super().__init__(parent, *args, **kwargs)
|
61
62
|
|
62
|
-
self.setModal(
|
63
|
+
self.setModal(modal)
|
63
64
|
|
64
65
|
self.setWindowTitle(window_title)
|
65
66
|
|
@@ -92,7 +93,7 @@ class SettingsDialog(QDialog):
|
|
92
93
|
ok_button.setDefault(True)
|
93
94
|
ok_button.setAutoDefault(True)
|
94
95
|
|
95
|
-
@
|
96
|
+
@SafeSlot()
|
96
97
|
def accept(self):
|
97
98
|
"""
|
98
99
|
Accept the changes made in the settings widget and close the dialog.
|
@@ -100,7 +101,7 @@ class SettingsDialog(QDialog):
|
|
100
101
|
self.widget.accept_changes()
|
101
102
|
super().accept()
|
102
103
|
|
103
|
-
@
|
104
|
+
@SafeSlot()
|
104
105
|
def apply_changes(self):
|
105
106
|
"""
|
106
107
|
Apply the changes made in the settings widget without closing the dialog.
|
bec_widgets/qt_utils/toolbar.py
CHANGED
@@ -251,6 +251,7 @@ class SwitchableToolBarAction(ToolBarAction):
|
|
251
251
|
initial_action: str = None,
|
252
252
|
tooltip: str = None,
|
253
253
|
checkable: bool = True,
|
254
|
+
default_state_checked: bool = False,
|
254
255
|
parent=None,
|
255
256
|
):
|
256
257
|
super().__init__(icon_path=None, tooltip=tooltip, checkable=checkable)
|
@@ -258,6 +259,7 @@ class SwitchableToolBarAction(ToolBarAction):
|
|
258
259
|
self.current_key = initial_action if initial_action is not None else next(iter(actions))
|
259
260
|
self.parent = parent
|
260
261
|
self.checkable = checkable
|
262
|
+
self.default_state_checked = default_state_checked
|
261
263
|
self.main_button = None
|
262
264
|
self.menu_actions: Dict[str, QAction] = {}
|
263
265
|
|
@@ -283,7 +285,7 @@ class SwitchableToolBarAction(ToolBarAction):
|
|
283
285
|
menu_action.setIconVisibleInMenu(True)
|
284
286
|
menu_action.setCheckable(self.checkable)
|
285
287
|
menu_action.setChecked(key == self.current_key)
|
286
|
-
menu_action.triggered.connect(lambda checked, k=key: self.
|
288
|
+
menu_action.triggered.connect(lambda checked, k=key: self.set_default_action(k))
|
287
289
|
menu.addAction(menu_action)
|
288
290
|
self.menu_actions[key] = menu_action
|
289
291
|
self.main_button.setMenu(menu)
|
@@ -293,7 +295,7 @@ class SwitchableToolBarAction(ToolBarAction):
|
|
293
295
|
action_obj = self.actions[self.current_key]
|
294
296
|
action_obj.action.trigger()
|
295
297
|
|
296
|
-
def
|
298
|
+
def set_default_action(self, key: str):
|
297
299
|
self.current_key = key
|
298
300
|
new_action = self.actions[self.current_key]
|
299
301
|
self.main_button.setIcon(new_action.get_icon())
|
@@ -929,7 +931,7 @@ class MainWindow(QMainWindow): # pragma: no cover
|
|
929
931
|
actions={"action1": action1, "action2": action2},
|
930
932
|
initial_action="action1",
|
931
933
|
tooltip="Switchable Action",
|
932
|
-
checkable=
|
934
|
+
checkable=True,
|
933
935
|
parent=self,
|
934
936
|
)
|
935
937
|
self.toolbar.add_action("switchable_action_no_toggle", switchable_action, self)
|
@@ -940,6 +942,7 @@ class MainWindow(QMainWindow): # pragma: no cover
|
|
940
942
|
action2.action.triggered.connect(
|
941
943
|
lambda checked: self.test_label.setText(f"Action 2 triggered, checked = {checked}")
|
942
944
|
)
|
945
|
+
switchable_action.actions["action1"].action.setChecked(True)
|
943
946
|
|
944
947
|
def add_widget_actions(self):
|
945
948
|
combo = QComboBox()
|
@@ -1,14 +1,18 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from enum import Enum
|
4
|
+
|
5
|
+
import numpy as np
|
3
6
|
import pyqtgraph as pg
|
4
7
|
from bec_lib import bec_logger
|
5
8
|
from qtpy.QtCore import QPoint, QPointF, Qt, Signal
|
6
|
-
from qtpy.QtWidgets import QLabel, QVBoxLayout, QWidget
|
9
|
+
from qtpy.QtWidgets import QHBoxLayout, QLabel, QMainWindow, QVBoxLayout, QWidget
|
7
10
|
|
8
11
|
from bec_widgets.qt_utils.error_popups import SafeProperty, SafeSlot
|
9
12
|
from bec_widgets.qt_utils.round_frame import RoundedFrame
|
13
|
+
from bec_widgets.qt_utils.settings_dialog import SettingsDialog
|
10
14
|
from bec_widgets.qt_utils.side_panel import SidePanel
|
11
|
-
from bec_widgets.qt_utils.toolbar import MaterialIconAction, ModularToolBar,
|
15
|
+
from bec_widgets.qt_utils.toolbar import MaterialIconAction, ModularToolBar, ToolbarBundle
|
12
16
|
from bec_widgets.utils import ConnectionConfig, Crosshair, EntryValidator
|
13
17
|
from bec_widgets.utils.bec_widget import BECWidget
|
14
18
|
from bec_widgets.utils.fps_counter import FPSCounter
|
@@ -20,7 +24,6 @@ from bec_widgets.widgets.plots_next_gen.toolbar_bundles.mouse_interactions impor
|
|
20
24
|
)
|
21
25
|
from bec_widgets.widgets.plots_next_gen.toolbar_bundles.plot_export import PlotExportBundle
|
22
26
|
from bec_widgets.widgets.plots_next_gen.toolbar_bundles.roi_bundle import ROIBundle
|
23
|
-
from bec_widgets.widgets.utility.visual.dark_mode_button.dark_mode_button import DarkModeButton
|
24
27
|
|
25
28
|
logger = bec_logger.logger
|
26
29
|
|
@@ -42,6 +45,12 @@ class BECViewBox(pg.ViewBox):
|
|
42
45
|
self.update()
|
43
46
|
|
44
47
|
|
48
|
+
class UIMode(Enum):
|
49
|
+
NONE = 0
|
50
|
+
POPUP = 1
|
51
|
+
SIDE = 2
|
52
|
+
|
53
|
+
|
45
54
|
class PlotBase(BECWidget, QWidget):
|
46
55
|
PLUGIN = False
|
47
56
|
RPC = False
|
@@ -59,6 +68,7 @@ class PlotBase(BECWidget, QWidget):
|
|
59
68
|
config: ConnectionConfig | None = None,
|
60
69
|
client=None,
|
61
70
|
gui_id: str | None = None,
|
71
|
+
popups: bool = False,
|
62
72
|
) -> None:
|
63
73
|
if config is None:
|
64
74
|
config = ConnectionConfig(widget_class=self.__class__.__name__)
|
@@ -74,6 +84,8 @@ class PlotBase(BECWidget, QWidget):
|
|
74
84
|
self.layout.setContentsMargins(0, 0, 0, 0)
|
75
85
|
self.layout.setSpacing(0)
|
76
86
|
self.layout_manager = LayoutManagerWidget(parent=self)
|
87
|
+
self.layout_manager.layout.setContentsMargins(0, 0, 0, 0)
|
88
|
+
self.layout_manager.layout.setSpacing(0)
|
77
89
|
|
78
90
|
# Property Manager
|
79
91
|
self.state_manager = WidgetStateManager(self)
|
@@ -82,12 +94,14 @@ class PlotBase(BECWidget, QWidget):
|
|
82
94
|
self.entry_validator = EntryValidator(self.dev)
|
83
95
|
|
84
96
|
# Base widgets elements
|
97
|
+
self._ui_mode = UIMode.POPUP if popups else UIMode.SIDE
|
98
|
+
self.axis_settings_dialog = None
|
85
99
|
self.plot_widget = pg.GraphicsLayoutWidget(parent=self)
|
86
100
|
self.plot_item = pg.PlotItem(viewBox=BECViewBox(enableMenu=True))
|
87
101
|
self.plot_widget.addItem(self.plot_item)
|
88
102
|
self.side_panel = SidePanel(self, orientation="left", panel_max_width=280)
|
89
103
|
self.toolbar = ModularToolBar(target_widget=self, orientation="horizontal")
|
90
|
-
self.
|
104
|
+
self._init_toolbar()
|
91
105
|
|
92
106
|
# PlotItem Addons
|
93
107
|
self.plot_item.addLegend()
|
@@ -115,13 +129,14 @@ class PlotBase(BECWidget, QWidget):
|
|
115
129
|
self.layout_manager.add_widget_relative(self.side_panel, self.round_plot_widget, "left")
|
116
130
|
self.layout_manager.add_widget_relative(self.toolbar, self.fps_label, "top")
|
117
131
|
|
118
|
-
self.
|
132
|
+
self.ui_mode = self._ui_mode # to initiate the first time
|
119
133
|
|
120
134
|
# PlotItem ViewBox Signals
|
121
135
|
self.plot_item.vb.sigStateChanged.connect(self.viewbox_state_changed)
|
122
136
|
|
123
|
-
def
|
124
|
-
|
137
|
+
def _init_toolbar(self):
|
138
|
+
self.popup_bundle = None
|
139
|
+
self.performance_bundle = ToolbarBundle("performance")
|
125
140
|
self.plot_export_bundle = PlotExportBundle("plot_export", target_widget=self)
|
126
141
|
self.mouse_bundle = MouseInteractionToolbarBundle("mouse_interaction", target_widget=self)
|
127
142
|
# self.state_export_bundle = SaveStateBundle("state_export", target_widget=self) #TODO ATM disabled, cannot be used in DockArea, which is exposed to the user
|
@@ -133,33 +148,130 @@ class PlotBase(BECWidget, QWidget):
|
|
133
148
|
self.toolbar.add_bundle(self.mouse_bundle, target_widget=self)
|
134
149
|
self.toolbar.add_bundle(self.roi_bundle, target_widget=self)
|
135
150
|
|
136
|
-
self.
|
137
|
-
self.toolbar.add_action(
|
151
|
+
self.performance_bundle.add_action(
|
138
152
|
"fps_monitor",
|
139
|
-
MaterialIconAction(
|
140
|
-
|
153
|
+
MaterialIconAction(
|
154
|
+
icon_name="speed", tooltip="Show FPS Monitor", checkable=True, parent=self
|
155
|
+
),
|
141
156
|
)
|
142
|
-
self.toolbar.
|
157
|
+
self.toolbar.add_bundle(self.performance_bundle, target_widget=self)
|
143
158
|
|
144
159
|
self.toolbar.widgets["fps_monitor"].action.toggled.connect(
|
145
160
|
lambda checked: setattr(self, "enable_fps_monitor", checked)
|
146
161
|
)
|
147
162
|
|
163
|
+
# hide some options by default
|
164
|
+
self.toolbar.toggle_action_visibility("fps_monitor", False)
|
165
|
+
|
148
166
|
def add_side_menus(self):
|
149
167
|
"""Adds multiple menus to the side panel."""
|
150
168
|
# Setting Axis Widget
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
169
|
+
try:
|
170
|
+
axis_setting = AxisSettings(target_widget=self)
|
171
|
+
self.side_panel.add_menu(
|
172
|
+
action_id="axis",
|
173
|
+
icon_name="settings",
|
174
|
+
tooltip="Show Axis Settings",
|
175
|
+
widget=axis_setting,
|
176
|
+
title="Axis Settings",
|
177
|
+
)
|
178
|
+
except ValueError:
|
179
|
+
return
|
180
|
+
|
181
|
+
def add_popups(self):
|
182
|
+
"""
|
183
|
+
Add popups to the toolbar.
|
184
|
+
"""
|
185
|
+
self.popup_bundle = ToolbarBundle("popup_bundle")
|
186
|
+
settings = MaterialIconAction(
|
187
|
+
icon_name="settings", tooltip="Show Axis Settings", checkable=True, parent=self
|
158
188
|
)
|
189
|
+
self.popup_bundle.add_action("axis", settings)
|
190
|
+
self.toolbar.add_bundle(self.popup_bundle, target_widget=self)
|
191
|
+
self.toolbar.widgets["axis"].action.triggered.connect(self.show_axis_settings_popup)
|
192
|
+
|
193
|
+
def show_axis_settings_popup(self):
|
194
|
+
"""
|
195
|
+
Show the axis settings dialog.
|
196
|
+
"""
|
197
|
+
settings_action = self.toolbar.widgets["axis"].action
|
198
|
+
if self.axis_settings_dialog is None or not self.axis_settings_dialog.isVisible():
|
199
|
+
axis_setting = AxisSettings(target_widget=self, popup=True)
|
200
|
+
self.axis_settings_dialog = SettingsDialog(
|
201
|
+
self, settings_widget=axis_setting, window_title="Axis Settings", modal=False
|
202
|
+
)
|
203
|
+
# When the dialog is closed, update the toolbar icon and clear the reference
|
204
|
+
self.axis_settings_dialog.finished.connect(self._axis_settings_closed)
|
205
|
+
self.axis_settings_dialog.show()
|
206
|
+
settings_action.setChecked(True)
|
207
|
+
else:
|
208
|
+
# If already open, bring it to the front
|
209
|
+
self.axis_settings_dialog.raise_()
|
210
|
+
self.axis_settings_dialog.activateWindow()
|
211
|
+
settings_action.setChecked(True) # keep it toggled
|
212
|
+
|
213
|
+
def _axis_settings_closed(self):
|
214
|
+
"""
|
215
|
+
Slot for when the axis settings dialog is closed.
|
216
|
+
"""
|
217
|
+
self.axis_settings_dialog = None
|
218
|
+
self.toolbar.widgets["axis"].action.setChecked(False)
|
159
219
|
|
160
220
|
################################################################################
|
161
221
|
# Toggle UI Elements
|
162
222
|
################################################################################
|
223
|
+
@property
|
224
|
+
def ui_mode(self) -> UIMode:
|
225
|
+
return self._ui_mode
|
226
|
+
|
227
|
+
@ui_mode.setter
|
228
|
+
def ui_mode(self, mode: UIMode):
|
229
|
+
if not isinstance(mode, UIMode):
|
230
|
+
raise ValueError("ui_mode must be an instance of UIMode")
|
231
|
+
self._ui_mode = mode
|
232
|
+
|
233
|
+
# First, clear both UI elements:
|
234
|
+
if self.popup_bundle is not None:
|
235
|
+
for action_id in self.toolbar.bundles["popup_bundle"]:
|
236
|
+
self.toolbar.widgets[action_id].action.setVisible(False)
|
237
|
+
if self.axis_settings_dialog is not None and self.axis_settings_dialog.isVisible():
|
238
|
+
self.axis_settings_dialog.close()
|
239
|
+
self.side_panel.hide()
|
240
|
+
|
241
|
+
# Now, apply the new mode:
|
242
|
+
if mode == UIMode.POPUP:
|
243
|
+
if self.popup_bundle is None:
|
244
|
+
self.add_popups()
|
245
|
+
else:
|
246
|
+
for action_id in self.toolbar.bundles["popup_bundle"]:
|
247
|
+
self.toolbar.widgets[action_id].action.setVisible(True)
|
248
|
+
elif mode == UIMode.SIDE:
|
249
|
+
self.add_side_menus()
|
250
|
+
self.side_panel.show()
|
251
|
+
|
252
|
+
@SafeProperty(bool, doc="Enable popups setting dialogs for the plot widget.")
|
253
|
+
def enable_popups(self):
|
254
|
+
return self.ui_mode == UIMode.POPUP
|
255
|
+
|
256
|
+
@enable_popups.setter
|
257
|
+
def enable_popups(self, value: bool):
|
258
|
+
if value:
|
259
|
+
self.ui_mode = UIMode.POPUP
|
260
|
+
else:
|
261
|
+
if self.ui_mode == UIMode.POPUP:
|
262
|
+
self.ui_mode = UIMode.NONE
|
263
|
+
|
264
|
+
@SafeProperty(bool, doc="Show Side Panel")
|
265
|
+
def enable_side_panel(self) -> bool:
|
266
|
+
return self.ui_mode == UIMode.SIDE
|
267
|
+
|
268
|
+
@enable_side_panel.setter
|
269
|
+
def enable_side_panel(self, value: bool):
|
270
|
+
if value:
|
271
|
+
self.ui_mode = UIMode.SIDE
|
272
|
+
else:
|
273
|
+
if self.ui_mode == UIMode.SIDE:
|
274
|
+
self.ui_mode = UIMode.NONE
|
163
275
|
|
164
276
|
@SafeProperty(bool, doc="Show Toolbar")
|
165
277
|
def enable_toolbar(self) -> bool:
|
@@ -167,15 +279,22 @@ class PlotBase(BECWidget, QWidget):
|
|
167
279
|
|
168
280
|
@enable_toolbar.setter
|
169
281
|
def enable_toolbar(self, value: bool):
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
282
|
+
if value:
|
283
|
+
# Disable popup mode
|
284
|
+
if self._popups:
|
285
|
+
# Directly update the internal flag to avoid recursion
|
286
|
+
self._popups = False
|
287
|
+
# Hide the popup bundle if it exists and close any open dialogs
|
288
|
+
if self.popup_bundle is not None:
|
289
|
+
for action in self.toolbar.bundles["popup_bundle"].actions:
|
290
|
+
action.setVisible(False)
|
291
|
+
if self.axis_settings_dialog is not None and self.axis_settings_dialog.isVisible():
|
292
|
+
self.axis_settings_dialog.close()
|
293
|
+
self.side_panel.show()
|
294
|
+
# Add side menus if not already added
|
295
|
+
self.add_side_menus()
|
296
|
+
else:
|
297
|
+
self.side_panel.hide()
|
179
298
|
|
180
299
|
@SafeProperty(bool, doc="Enable the FPS monitor.")
|
181
300
|
def enable_fps_monitor(self) -> bool:
|
@@ -591,16 +710,34 @@ class PlotBase(BECWidget, QWidget):
|
|
591
710
|
item.ctrlMenu.deleteLater()
|
592
711
|
|
593
712
|
|
713
|
+
class DemoPlotBase(QMainWindow): # pragma: no cover:
|
714
|
+
def __init__(self):
|
715
|
+
super().__init__()
|
716
|
+
self.main_widget = QWidget()
|
717
|
+
self.setCentralWidget(self.main_widget)
|
718
|
+
self.main_widget.layout = QHBoxLayout(self.main_widget)
|
719
|
+
|
720
|
+
self.plot_popup = PlotBase(popups=True)
|
721
|
+
self.plot_popup.title = "PlotBase with popups"
|
722
|
+
self.plot_side_panels = PlotBase(popups=False)
|
723
|
+
self.plot_side_panels.title = "PlotBase with side panels"
|
724
|
+
|
725
|
+
self.plot_popup.plot_item.plot(np.random.rand(100), pen=(255, 0, 0))
|
726
|
+
self.plot_side_panels.plot_item.plot(np.random.rand(100), pen=(0, 255, 0))
|
727
|
+
|
728
|
+
self.main_widget.layout.addWidget(self.plot_side_panels)
|
729
|
+
self.main_widget.layout.addWidget(self.plot_popup)
|
730
|
+
|
731
|
+
self.resize(1400, 600)
|
732
|
+
|
733
|
+
|
594
734
|
if __name__ == "__main__": # pragma: no cover:
|
595
735
|
import sys
|
596
736
|
|
597
737
|
from qtpy.QtWidgets import QApplication
|
598
738
|
|
599
739
|
app = QApplication(sys.argv)
|
600
|
-
|
601
|
-
|
602
|
-
# Just some example data and parameters to test
|
603
|
-
widget.y_grid = True
|
604
|
-
widget.plot_item.plot([1, 2, 3, 4, 5], [1, 2, 3, 4, 5])
|
740
|
+
window = DemoPlotBase()
|
741
|
+
window.show()
|
605
742
|
|
606
743
|
sys.exit(app.exec_())
|
@@ -9,7 +9,7 @@ from bec_widgets.utils.widget_io import WidgetIO
|
|
9
9
|
|
10
10
|
|
11
11
|
class AxisSettings(SettingWidget):
|
12
|
-
def __init__(self, parent=None, target_widget=None, *args, **kwargs):
|
12
|
+
def __init__(self, parent=None, target_widget=None, popup=False, *args, **kwargs):
|
13
13
|
super().__init__(parent=parent, *args, **kwargs)
|
14
14
|
|
15
15
|
# This is a settings widget that depends on the target widget
|
@@ -18,9 +18,15 @@ class AxisSettings(SettingWidget):
|
|
18
18
|
self.setProperty("skip_settings", True)
|
19
19
|
self.setObjectName("AxisSettings")
|
20
20
|
current_path = os.path.dirname(__file__)
|
21
|
-
|
21
|
+
if popup:
|
22
|
+
form = UILoader().load_ui(
|
23
|
+
os.path.join(current_path, "axis_settings_horizontal.ui"), self
|
24
|
+
)
|
25
|
+
else:
|
26
|
+
form = UILoader().load_ui(os.path.join(current_path, "axis_settings_vertical.ui"), self)
|
22
27
|
|
23
28
|
self.target_widget = target_widget
|
29
|
+
self.popup = popup
|
24
30
|
|
25
31
|
# # Scroll area
|
26
32
|
self.scroll_area = QScrollArea(self)
|
@@ -34,10 +40,13 @@ class AxisSettings(SettingWidget):
|
|
34
40
|
# self.layout.addWidget(self.ui)
|
35
41
|
self.ui = form
|
36
42
|
|
37
|
-
self.
|
38
|
-
|
43
|
+
if self.target_widget is not None and self.popup is False:
|
44
|
+
self.connect_all_signals()
|
39
45
|
self.target_widget.property_changed.connect(self.update_property)
|
40
46
|
|
47
|
+
if self.popup is True:
|
48
|
+
self.fetch_all_properties()
|
49
|
+
|
41
50
|
def connect_all_signals(self):
|
42
51
|
for widget in [
|
43
52
|
self.ui.title,
|
@@ -93,3 +102,49 @@ class AxisSettings(SettingWidget):
|
|
93
102
|
was_blocked = widget_to_set.blockSignals(True)
|
94
103
|
WidgetIO.set_value(widget_to_set, value)
|
95
104
|
widget_to_set.blockSignals(was_blocked)
|
105
|
+
|
106
|
+
def fetch_all_properties(self):
|
107
|
+
"""
|
108
|
+
Fetch all properties from the target widget and update the settings widget.
|
109
|
+
"""
|
110
|
+
for widget in [
|
111
|
+
self.ui.title,
|
112
|
+
self.ui.inner_axes,
|
113
|
+
self.ui.outer_axes,
|
114
|
+
self.ui.x_label,
|
115
|
+
self.ui.x_min,
|
116
|
+
self.ui.x_max,
|
117
|
+
self.ui.x_log,
|
118
|
+
self.ui.x_grid,
|
119
|
+
self.ui.y_label,
|
120
|
+
self.ui.y_min,
|
121
|
+
self.ui.y_max,
|
122
|
+
self.ui.y_log,
|
123
|
+
self.ui.y_grid,
|
124
|
+
]:
|
125
|
+
property_name = widget.objectName()
|
126
|
+
value = getattr(self.target_widget, property_name)
|
127
|
+
WidgetIO.set_value(widget, value)
|
128
|
+
|
129
|
+
def accept_changes(self):
|
130
|
+
"""
|
131
|
+
Apply all properties from the settings widget to the target widget.
|
132
|
+
"""
|
133
|
+
for widget in [
|
134
|
+
self.ui.title,
|
135
|
+
self.ui.inner_axes,
|
136
|
+
self.ui.outer_axes,
|
137
|
+
self.ui.x_label,
|
138
|
+
self.ui.x_min,
|
139
|
+
self.ui.x_max,
|
140
|
+
self.ui.x_log,
|
141
|
+
self.ui.x_grid,
|
142
|
+
self.ui.y_label,
|
143
|
+
self.ui.y_min,
|
144
|
+
self.ui.y_max,
|
145
|
+
self.ui.y_log,
|
146
|
+
self.ui.y_grid,
|
147
|
+
]:
|
148
|
+
property_name = widget.objectName()
|
149
|
+
value = WidgetIO.get_value(widget)
|
150
|
+
setattr(self.target_widget, property_name, value)
|
@@ -6,245 +6,201 @@
|
|
6
6
|
<rect>
|
7
7
|
<x>0</x>
|
8
8
|
<y>0</y>
|
9
|
-
<width>
|
10
|
-
<height>
|
9
|
+
<width>486</width>
|
10
|
+
<height>300</height>
|
11
11
|
</rect>
|
12
12
|
</property>
|
13
|
-
<property name="minimumSize">
|
14
|
-
<size>
|
15
|
-
<width>0</width>
|
16
|
-
<height>250</height>
|
17
|
-
</size>
|
18
|
-
</property>
|
19
|
-
<property name="maximumSize">
|
20
|
-
<size>
|
21
|
-
<width>16777215</width>
|
22
|
-
<height>278</height>
|
23
|
-
</size>
|
24
|
-
</property>
|
25
13
|
<property name="windowTitle">
|
26
14
|
<string>Form</string>
|
27
15
|
</property>
|
28
16
|
<layout class="QGridLayout" name="gridLayout">
|
29
|
-
<item row="0" column="0" colspan="2">
|
30
|
-
<layout class="QHBoxLayout" name="horizontalLayout">
|
31
|
-
<item>
|
32
|
-
<widget class="QLabel" name="plot_title_label">
|
33
|
-
<property name="text">
|
34
|
-
<string>Plot Title</string>
|
35
|
-
</property>
|
36
|
-
</widget>
|
37
|
-
</item>
|
38
|
-
<item>
|
39
|
-
<widget class="QLineEdit" name="plot_title"/>
|
40
|
-
</item>
|
41
|
-
</layout>
|
42
|
-
</item>
|
43
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">
|
44
28
|
<widget class="QLabel" name="label_outer_axes">
|
45
29
|
<property name="text">
|
46
30
|
<string>Outer Axes</string>
|
47
31
|
</property>
|
48
32
|
</widget>
|
49
33
|
</item>
|
50
|
-
<item row="
|
51
|
-
<widget class="
|
34
|
+
<item row="1" column="3">
|
35
|
+
<widget class="ToggleSwitch" name="outer_axes">
|
36
|
+
<property name="checked" stdset="0">
|
37
|
+
<bool>false</bool>
|
38
|
+
</property>
|
39
|
+
</widget>
|
40
|
+
</item>
|
41
|
+
<item row="2" column="0" colspan="2">
|
42
|
+
<widget class="QGroupBox" name="x_axis_box">
|
52
43
|
<property name="title">
|
53
|
-
<string>
|
44
|
+
<string>X Axis</string>
|
54
45
|
</property>
|
55
|
-
<layout class="QGridLayout" name="
|
56
|
-
<item row="
|
57
|
-
<widget class="
|
58
|
-
<
|
59
|
-
<
|
60
|
-
|
61
|
-
</property>
|
62
|
-
</item>
|
63
|
-
<item>
|
64
|
-
<property name="text">
|
65
|
-
<string>log</string>
|
66
|
-
</property>
|
67
|
-
</item>
|
46
|
+
<layout class="QGridLayout" name="gridLayout_4">
|
47
|
+
<item row="5" column="0">
|
48
|
+
<widget class="QLabel" name="x_grid_label">
|
49
|
+
<property name="text">
|
50
|
+
<string>Grid</string>
|
51
|
+
</property>
|
68
52
|
</widget>
|
69
53
|
</item>
|
70
|
-
<item row="
|
71
|
-
<widget class="
|
72
|
-
<property name="
|
73
|
-
<
|
74
|
-
</property>
|
75
|
-
<property name="minimum">
|
76
|
-
<double>-9999.000000000000000</double>
|
77
|
-
</property>
|
78
|
-
<property name="maximum">
|
79
|
-
<double>9999.000000000000000</double>
|
54
|
+
<item row="3" column="2">
|
55
|
+
<widget class="ToggleSwitch" name="x_log">
|
56
|
+
<property name="checked" stdset="0">
|
57
|
+
<bool>false</bool>
|
80
58
|
</property>
|
81
59
|
</widget>
|
82
60
|
</item>
|
83
|
-
<item row="
|
84
|
-
<widget class="QLabel" name="
|
61
|
+
<item row="2" column="0">
|
62
|
+
<widget class="QLabel" name="x_max_label">
|
85
63
|
<property name="text">
|
86
|
-
<string>
|
64
|
+
<string>Max</string>
|
87
65
|
</property>
|
88
66
|
</widget>
|
89
67
|
</item>
|
90
|
-
<item row="
|
91
|
-
<widget class="
|
92
|
-
<property name="
|
93
|
-
<
|
94
|
-
</property>
|
95
|
-
<property name="minimum">
|
96
|
-
<double>-9999.000000000000000</double>
|
97
|
-
</property>
|
98
|
-
<property name="maximum">
|
99
|
-
<double>9999.000000000000000</double>
|
68
|
+
<item row="5" column="2">
|
69
|
+
<widget class="ToggleSwitch" name="x_grid">
|
70
|
+
<property name="checked" stdset="0">
|
71
|
+
<bool>false</bool>
|
100
72
|
</property>
|
101
73
|
</widget>
|
102
74
|
</item>
|
103
|
-
<item row="0" column="2">
|
104
|
-
<widget class="QLineEdit" name="y_label"/>
|
105
|
-
</item>
|
106
75
|
<item row="3" column="0">
|
107
|
-
<widget class="QLabel" name="
|
76
|
+
<widget class="QLabel" name="x_scale_label">
|
108
77
|
<property name="text">
|
109
|
-
<string>
|
78
|
+
<string>Log</string>
|
110
79
|
</property>
|
111
80
|
</widget>
|
112
81
|
</item>
|
113
|
-
<item row="
|
114
|
-
<widget class="QLabel" name="
|
82
|
+
<item row="1" column="0" colspan="2">
|
83
|
+
<widget class="QLabel" name="x_min_label">
|
115
84
|
<property name="text">
|
116
|
-
<string>
|
85
|
+
<string>Min</string>
|
117
86
|
</property>
|
118
87
|
</widget>
|
119
88
|
</item>
|
120
|
-
<item row="
|
121
|
-
<widget class="QLabel" name="
|
89
|
+
<item row="0" column="0">
|
90
|
+
<widget class="QLabel" name="x_label_label">
|
122
91
|
<property name="text">
|
123
|
-
<string>
|
92
|
+
<string>Label</string>
|
124
93
|
</property>
|
125
94
|
</widget>
|
126
95
|
</item>
|
127
|
-
<item row="
|
128
|
-
<widget class="
|
129
|
-
<property name="text">
|
130
|
-
<string/>
|
131
|
-
</property>
|
132
|
-
</widget>
|
96
|
+
<item row="0" column="2">
|
97
|
+
<widget class="QLineEdit" name="x_label"/>
|
133
98
|
</item>
|
134
|
-
<item row="
|
135
|
-
<widget class="
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
</widget>
|
99
|
+
<item row="1" column="2">
|
100
|
+
<widget class="BECSpinBox" name="x_min"/>
|
101
|
+
</item>
|
102
|
+
<item row="2" column="2">
|
103
|
+
<widget class="BECSpinBox" name="x_max"/>
|
140
104
|
</item>
|
141
105
|
</layout>
|
142
106
|
</widget>
|
143
107
|
</item>
|
144
|
-
<item row="2" column="
|
145
|
-
<widget class="QGroupBox" name="
|
108
|
+
<item row="2" column="2" colspan="2">
|
109
|
+
<widget class="QGroupBox" name="y_axis_box">
|
146
110
|
<property name="title">
|
147
|
-
<string>
|
111
|
+
<string>Y Axis</string>
|
148
112
|
</property>
|
149
|
-
<layout class="QGridLayout" name="
|
150
|
-
<item row="
|
151
|
-
<widget class="QLabel" name="
|
113
|
+
<layout class="QGridLayout" name="gridLayout_5">
|
114
|
+
<item row="1" column="0" colspan="2">
|
115
|
+
<widget class="QLabel" name="y_min_label">
|
152
116
|
<property name="text">
|
153
|
-
<string>
|
117
|
+
<string>Min</string>
|
154
118
|
</property>
|
155
119
|
</widget>
|
156
120
|
</item>
|
157
|
-
<item row="
|
158
|
-
<widget class="
|
159
|
-
<property name="alignment">
|
160
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
161
|
-
</property>
|
162
|
-
<property name="minimum">
|
163
|
-
<double>-9999.000000000000000</double>
|
164
|
-
</property>
|
165
|
-
<property name="maximum">
|
166
|
-
<double>9999.000000000000000</double>
|
167
|
-
</property>
|
168
|
-
</widget>
|
121
|
+
<item row="0" column="2">
|
122
|
+
<widget class="QLineEdit" name="y_label"/>
|
169
123
|
</item>
|
170
|
-
<item row="
|
171
|
-
<widget class="QLabel" name="
|
124
|
+
<item row="3" column="0">
|
125
|
+
<widget class="QLabel" name="y_scale_label">
|
172
126
|
<property name="text">
|
173
|
-
<string>
|
127
|
+
<string>Log</string>
|
174
128
|
</property>
|
175
129
|
</widget>
|
176
130
|
</item>
|
177
|
-
<item row="
|
178
|
-
<widget class="
|
179
|
-
<property name="
|
180
|
-
<
|
181
|
-
</property>
|
182
|
-
<property name="minimum">
|
183
|
-
<double>-9999.000000000000000</double>
|
184
|
-
</property>
|
185
|
-
<property name="maximum">
|
186
|
-
<double>9999.000000000000000</double>
|
131
|
+
<item row="0" column="0">
|
132
|
+
<widget class="QLabel" name="y_label_label">
|
133
|
+
<property name="text">
|
134
|
+
<string>Label</string>
|
187
135
|
</property>
|
188
136
|
</widget>
|
189
137
|
</item>
|
190
|
-
<item row="3" column="2">
|
191
|
-
<widget class="QComboBox" name="x_scale">
|
192
|
-
<item>
|
193
|
-
<property name="text">
|
194
|
-
<string>linear</string>
|
195
|
-
</property>
|
196
|
-
</item>
|
197
|
-
<item>
|
198
|
-
<property name="text">
|
199
|
-
<string>log</string>
|
200
|
-
</property>
|
201
|
-
</item>
|
202
|
-
</widget>
|
203
|
-
</item>
|
204
138
|
<item row="2" column="0">
|
205
|
-
<widget class="QLabel" name="
|
139
|
+
<widget class="QLabel" name="y_max_label">
|
206
140
|
<property name="text">
|
207
141
|
<string>Max</string>
|
208
142
|
</property>
|
209
143
|
</widget>
|
210
144
|
</item>
|
211
|
-
<item row="
|
212
|
-
<widget class="
|
213
|
-
</item>
|
214
|
-
<item row="0" column="0">
|
215
|
-
<widget class="QLabel" name="x_label_label">
|
145
|
+
<item row="4" column="0">
|
146
|
+
<widget class="QLabel" name="y_grid_label">
|
216
147
|
<property name="text">
|
217
|
-
<string>
|
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>
|
218
156
|
</property>
|
219
157
|
</widget>
|
220
158
|
</item>
|
221
159
|
<item row="4" column="2">
|
222
|
-
<widget class="
|
223
|
-
<property name="
|
224
|
-
<
|
160
|
+
<widget class="ToggleSwitch" name="y_grid">
|
161
|
+
<property name="checked" stdset="0">
|
162
|
+
<bool>false</bool>
|
225
163
|
</property>
|
226
164
|
</widget>
|
227
165
|
</item>
|
228
|
-
<item row="
|
229
|
-
<widget class="
|
230
|
-
<property name="
|
231
|
-
<
|
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>
|
232
173
|
</property>
|
233
174
|
</widget>
|
234
175
|
</item>
|
176
|
+
<item row="2" column="2">
|
177
|
+
<widget class="BECSpinBox" name="y_max"/>
|
178
|
+
</item>
|
235
179
|
</layout>
|
236
180
|
</widget>
|
237
181
|
</item>
|
238
|
-
<item row="
|
239
|
-
<
|
240
|
-
<
|
241
|
-
<
|
242
|
-
|
243
|
-
|
182
|
+
<item row="0" column="0" colspan="4">
|
183
|
+
<layout class="QHBoxLayout" name="horizontalLayout">
|
184
|
+
<item>
|
185
|
+
<widget class="QLabel" name="plot_title_label">
|
186
|
+
<property name="text">
|
187
|
+
<string>Plot Title</string>
|
188
|
+
</property>
|
189
|
+
</widget>
|
190
|
+
</item>
|
191
|
+
<item>
|
192
|
+
<widget class="QLineEdit" name="title"/>
|
193
|
+
</item>
|
194
|
+
</layout>
|
244
195
|
</item>
|
245
196
|
</layout>
|
246
197
|
</widget>
|
247
198
|
<customwidgets>
|
199
|
+
<customwidget>
|
200
|
+
<class>BECSpinBox</class>
|
201
|
+
<extends>QDoubleSpinBox</extends>
|
202
|
+
<header>bec_spin_box</header>
|
203
|
+
</customwidget>
|
248
204
|
<customwidget>
|
249
205
|
<class>ToggleSwitch</class>
|
250
206
|
<extends>QWidget</extends>
|
@@ -20,19 +20,6 @@
|
|
20
20
|
<string>X Axis</string>
|
21
21
|
</property>
|
22
22
|
<layout class="QGridLayout" name="gridLayout_4">
|
23
|
-
<item row="2" column="2">
|
24
|
-
<widget class="QDoubleSpinBox" name="x_max">
|
25
|
-
<property name="alignment">
|
26
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
27
|
-
</property>
|
28
|
-
<property name="minimum">
|
29
|
-
<double>-9999.000000000000000</double>
|
30
|
-
</property>
|
31
|
-
<property name="maximum">
|
32
|
-
<double>9999.000000000000000</double>
|
33
|
-
</property>
|
34
|
-
</widget>
|
35
|
-
</item>
|
36
23
|
<item row="3" column="0">
|
37
24
|
<widget class="QLabel" name="x_scale_label">
|
38
25
|
<property name="text">
|
@@ -64,19 +51,6 @@
|
|
64
51
|
</property>
|
65
52
|
</widget>
|
66
53
|
</item>
|
67
|
-
<item row="1" column="2">
|
68
|
-
<widget class="QDoubleSpinBox" name="x_min">
|
69
|
-
<property name="alignment">
|
70
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
71
|
-
</property>
|
72
|
-
<property name="minimum">
|
73
|
-
<double>-9999.000000000000000</double>
|
74
|
-
</property>
|
75
|
-
<property name="maximum">
|
76
|
-
<double>9999.000000000000000</double>
|
77
|
-
</property>
|
78
|
-
</widget>
|
79
|
-
</item>
|
80
54
|
<item row="1" column="0" colspan="2">
|
81
55
|
<widget class="QLabel" name="x_min_label">
|
82
56
|
<property name="text">
|
@@ -98,6 +72,12 @@
|
|
98
72
|
</property>
|
99
73
|
</widget>
|
100
74
|
</item>
|
75
|
+
<item row="1" column="2">
|
76
|
+
<widget class="BECSpinBox" name="x_min"/>
|
77
|
+
</item>
|
78
|
+
<item row="2" column="2">
|
79
|
+
<widget class="BECSpinBox" name="x_max"/>
|
80
|
+
</item>
|
101
81
|
</layout>
|
102
82
|
</widget>
|
103
83
|
</item>
|
@@ -128,19 +108,6 @@
|
|
128
108
|
<string>Y Axis</string>
|
129
109
|
</property>
|
130
110
|
<layout class="QGridLayout" name="gridLayout_5">
|
131
|
-
<item row="2" column="2">
|
132
|
-
<widget class="QDoubleSpinBox" name="y_max">
|
133
|
-
<property name="alignment">
|
134
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
135
|
-
</property>
|
136
|
-
<property name="minimum">
|
137
|
-
<double>-9999.000000000000000</double>
|
138
|
-
</property>
|
139
|
-
<property name="maximum">
|
140
|
-
<double>9999.000000000000000</double>
|
141
|
-
</property>
|
142
|
-
</widget>
|
143
|
-
</item>
|
144
111
|
<item row="1" column="0" colspan="2">
|
145
112
|
<widget class="QLabel" name="y_min_label">
|
146
113
|
<property name="text">
|
@@ -148,19 +115,6 @@
|
|
148
115
|
</property>
|
149
116
|
</widget>
|
150
117
|
</item>
|
151
|
-
<item row="1" column="2">
|
152
|
-
<widget class="QDoubleSpinBox" name="y_min">
|
153
|
-
<property name="alignment">
|
154
|
-
<set>Qt::AlignmentFlag::AlignCenter</set>
|
155
|
-
</property>
|
156
|
-
<property name="minimum">
|
157
|
-
<double>-9999.000000000000000</double>
|
158
|
-
</property>
|
159
|
-
<property name="maximum">
|
160
|
-
<double>9999.000000000000000</double>
|
161
|
-
</property>
|
162
|
-
</widget>
|
163
|
-
</item>
|
164
118
|
<item row="0" column="2">
|
165
119
|
<widget class="QLineEdit" name="y_label"/>
|
166
120
|
</item>
|
@@ -206,6 +160,12 @@
|
|
206
160
|
</property>
|
207
161
|
</widget>
|
208
162
|
</item>
|
163
|
+
<item row="1" column="2">
|
164
|
+
<widget class="BECSpinBox" name="y_min"/>
|
165
|
+
</item>
|
166
|
+
<item row="2" column="2">
|
167
|
+
<widget class="BECSpinBox" name="y_max"/>
|
168
|
+
</item>
|
209
169
|
</layout>
|
210
170
|
</widget>
|
211
171
|
</item>
|
@@ -229,6 +189,11 @@
|
|
229
189
|
</layout>
|
230
190
|
</widget>
|
231
191
|
<customwidgets>
|
192
|
+
<customwidget>
|
193
|
+
<class>BECSpinBox</class>
|
194
|
+
<extends>QDoubleSpinBox</extends>
|
195
|
+
<header>bec_spin_box</header>
|
196
|
+
</customwidget>
|
232
197
|
<customwidget>
|
233
198
|
<class>ToggleSwitch</class>
|
234
199
|
<extends>QWidget</extends>
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import pyqtgraph as pg
|
2
|
+
from qtpy.QtCore import QTimer
|
2
3
|
|
3
4
|
from bec_widgets.qt_utils.error_popups import SafeSlot
|
4
|
-
from bec_widgets.qt_utils.toolbar import MaterialIconAction, ToolbarBundle
|
5
|
+
from bec_widgets.qt_utils.toolbar import MaterialIconAction, SwitchableToolBarAction, ToolbarBundle
|
5
6
|
|
6
7
|
|
7
8
|
class MouseInteractionToolbarBundle(ToolbarBundle):
|
@@ -15,6 +16,7 @@ class MouseInteractionToolbarBundle(ToolbarBundle):
|
|
15
16
|
def __init__(self, bundle_id="mouse_interaction", target_widget=None, **kwargs):
|
16
17
|
super().__init__(bundle_id=bundle_id, actions=[], **kwargs)
|
17
18
|
self.target_widget = target_widget
|
19
|
+
self.mouse_mode = None
|
18
20
|
|
19
21
|
# Create each MaterialIconAction with a parent
|
20
22
|
# so the signals can fire even if the toolbar isn't added yet.
|
@@ -43,9 +45,16 @@ class MouseInteractionToolbarBundle(ToolbarBundle):
|
|
43
45
|
parent=self.target_widget,
|
44
46
|
)
|
45
47
|
|
48
|
+
self.switch_mouse_action = SwitchableToolBarAction(
|
49
|
+
actions={"drag_mode": drag, "rectangle_mode": rect},
|
50
|
+
initial_action="drag_mode",
|
51
|
+
tooltip="Mouse Modes",
|
52
|
+
checkable=True,
|
53
|
+
parent=self,
|
54
|
+
)
|
55
|
+
|
46
56
|
# Add them to the bundle
|
47
|
-
self.add_action("
|
48
|
-
self.add_action("rectangle_mode", rect)
|
57
|
+
self.add_action("switch_mouse", self.switch_mouse_action)
|
49
58
|
self.add_action("auto_range", auto)
|
50
59
|
self.add_action("aspect_ratio", aspect_ratio)
|
51
60
|
|
@@ -55,33 +64,34 @@ class MouseInteractionToolbarBundle(ToolbarBundle):
|
|
55
64
|
auto.action.triggered.connect(self.autorange_plot)
|
56
65
|
aspect_ratio.action.toggled.connect(self.lock_aspect_ratio)
|
57
66
|
|
58
|
-
|
59
|
-
|
60
|
-
drag.action.setChecked(True)
|
61
|
-
elif mode == "RectMode":
|
62
|
-
rect.action.setChecked(True)
|
67
|
+
# Give some time to check the state
|
68
|
+
QTimer.singleShot(10, self.get_viewbox_mode)
|
63
69
|
|
64
|
-
def get_viewbox_mode(self)
|
70
|
+
def get_viewbox_mode(self):
|
65
71
|
"""
|
66
|
-
Returns the current interaction mode of a PyQtGraph ViewBox.
|
67
|
-
|
68
|
-
Returns:
|
69
|
-
str: "PanMode" if pan is enabled, "RectMode" if zoom is enabled, "Unknown" otherwise.
|
72
|
+
Returns the current interaction mode of a PyQtGraph ViewBox and sets the corresponding action.
|
70
73
|
"""
|
74
|
+
|
71
75
|
if self.target_widget:
|
72
76
|
viewbox = self.target_widget.plot_item.getViewBox()
|
73
77
|
if viewbox.getState()["mouseMode"] == 3:
|
74
|
-
|
78
|
+
self.switch_mouse_action.set_default_action("drag_mode")
|
79
|
+
self.switch_mouse_action.main_button.setChecked(True)
|
80
|
+
self.mouse_mode = "PanMode"
|
75
81
|
elif viewbox.getState()["mouseMode"] == 1:
|
76
|
-
|
77
|
-
|
82
|
+
self.switch_mouse_action.set_default_action("rectangle_mode")
|
83
|
+
self.switch_mouse_action.main_button.setChecked(True)
|
84
|
+
self.mouse_mode = "RectMode"
|
78
85
|
|
79
86
|
@SafeSlot(bool)
|
80
87
|
def enable_mouse_rectangle_mode(self, checked: bool):
|
81
88
|
"""
|
82
89
|
Enable the rectangle zoom mode on the plot widget.
|
83
90
|
"""
|
84
|
-
self.
|
91
|
+
if self.mouse_mode == "RectMode":
|
92
|
+
self.switch_mouse_action.main_button.setChecked(True)
|
93
|
+
return
|
94
|
+
self.actions["switch_mouse"].actions["drag_mode"].action.setChecked(not checked)
|
85
95
|
if self.target_widget and checked:
|
86
96
|
self.target_widget.plot_item.getViewBox().setMouseMode(pg.ViewBox.RectMode)
|
87
97
|
|
@@ -90,7 +100,10 @@ class MouseInteractionToolbarBundle(ToolbarBundle):
|
|
90
100
|
"""
|
91
101
|
Enable the pan mode on the plot widget.
|
92
102
|
"""
|
93
|
-
self.
|
103
|
+
if self.mouse_mode == "PanMode":
|
104
|
+
self.switch_mouse_action.main_button.setChecked(True)
|
105
|
+
return
|
106
|
+
self.actions["switch_mouse"].actions["rectangle_mode"].action.setChecked(not checked)
|
94
107
|
if self.target_widget and checked:
|
95
108
|
self.target_widget.plot_item.getViewBox().setMouseMode(pg.ViewBox.PanMode)
|
96
109
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
from pyqtgraph.exporters import MatplotlibExporter
|
2
2
|
|
3
3
|
from bec_widgets.qt_utils.error_popups import SafeSlot, WarningPopupUtility
|
4
|
-
from bec_widgets.qt_utils.toolbar import MaterialIconAction, ToolbarBundle
|
4
|
+
from bec_widgets.qt_utils.toolbar import MaterialIconAction, SwitchableToolBarAction, ToolbarBundle
|
5
5
|
|
6
6
|
|
7
7
|
class PlotExportBundle(ToolbarBundle):
|
@@ -25,9 +25,16 @@ class PlotExportBundle(ToolbarBundle):
|
|
25
25
|
icon_name="photo_library", tooltip="Open Matplotlib Dialog", parent=self.target_widget
|
26
26
|
)
|
27
27
|
|
28
|
+
switch_export_action = SwitchableToolBarAction(
|
29
|
+
actions={"save": save, "matplotlib": matplotlib},
|
30
|
+
initial_action="save",
|
31
|
+
tooltip="Switchable Action",
|
32
|
+
checkable=False,
|
33
|
+
parent=self,
|
34
|
+
)
|
35
|
+
|
28
36
|
# Add them to the bundle
|
29
|
-
self.add_action("
|
30
|
-
self.add_action("matplotlib", matplotlib)
|
37
|
+
self.add_action("export_switch", switch_export_action)
|
31
38
|
|
32
39
|
# Immediately connect signals
|
33
40
|
save.action.triggered.connect(self.export_dialog)
|
@@ -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=mge3u5uy21sCYWBhbFJ_Fk538ngStkA12NLY5yoesIU,232548
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=c5r-ka79i2PSUeIMx2sHxMvNWO1FTlMK498Jc9WVtCE,1173
|
8
8
|
README.md,sha256=KgdKusjlvEvFtdNZCeDMO91y77MWK2iDcYMDziksOr4,2553
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=x2UUcWiaoe9iv0OT2HqVhz1MHgMcDnR8Ma1EeDYp7NM,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
|
@@ -54,9 +54,9 @@ bec_widgets/qt_utils/expandable_frame.py,sha256=ys2peAfVAK3V2ZZekmp5JlpVovJwLMJG
|
|
54
54
|
bec_widgets/qt_utils/palette_viewer.py,sha256=--B0x7aE7bniHIeuuLY_pH8yBDrTTXaE0IDrC_AM1mo,6326
|
55
55
|
bec_widgets/qt_utils/redis_message_waiter.py,sha256=fvL_QgC0cTDv_FPJdRyp5AKjf401EJU4z3r38p47ydY,1745
|
56
56
|
bec_widgets/qt_utils/round_frame.py,sha256=ldLQ4BaWygFRrRv1s0w--5qZ4sj8MAqhdXuzho50xMg,4860
|
57
|
-
bec_widgets/qt_utils/settings_dialog.py,sha256=
|
57
|
+
bec_widgets/qt_utils/settings_dialog.py,sha256=zST_lq4B3-Dl2mvQ8oma4zxjUFQ6Oms3tlheaBETkj4,3682
|
58
58
|
bec_widgets/qt_utils/side_panel.py,sha256=H2Ko7FPYwQ2Nemrud-q-rmqzHGO8vly_pzE_ySEfoGQ,12569
|
59
|
-
bec_widgets/qt_utils/toolbar.py,sha256=
|
59
|
+
bec_widgets/qt_utils/toolbar.py,sha256=RG9bP2cmbKrIYReJV7yz3G3-LT6mhiRTUBuXaO0nYVc,35949
|
60
60
|
bec_widgets/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
61
61
|
bec_widgets/tests/utils.py,sha256=GbQtN7qf9n-8FoAfNddZ4aAqA7oBo_hGAlnKELd6Xzw,6943
|
62
62
|
bec_widgets/utils/__init__.py,sha256=1930ji1Jj6dVuY81Wd2kYBhHYNV-2R0bN_L4o9zBj1U,533
|
@@ -277,14 +277,14 @@ bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.py,
|
|
277
277
|
bec_widgets/widgets/plots/waveform/waveform_popups/curve_dialog/curve_dialog.ui,sha256=vaOfrygcQp3-H82AkMUHgV2v0Y_TmRO5KLui-bWoado,11056
|
278
278
|
bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
279
279
|
bec_widgets/widgets/plots/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py,sha256=78vAXX_x5vi1XMtncOHvTvfgGnZJNSkRjOAnCOBE26U,1047
|
280
|
-
bec_widgets/widgets/plots_next_gen/plot_base.py,sha256=
|
280
|
+
bec_widgets/widgets/plots_next_gen/plot_base.py,sha256=BjbXOuPobMisM-3h_Kzx-E8yUI-6-fmzzda_ERZTHHM,27428
|
281
281
|
bec_widgets/widgets/plots_next_gen/setting_menus/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
282
|
-
bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings.py,sha256=
|
283
|
-
bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings_horizontal.ui,sha256=
|
284
|
-
bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings_vertical.ui,sha256=
|
282
|
+
bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings.py,sha256=Hp-59LOw8ezaXOBmsZlAKu7kRe5_U-1XaY5cuox1SVY,5270
|
283
|
+
bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings_horizontal.ui,sha256=v8jJfPLnhORVfJukhRmygrPobMmJLufA4e3C08QeO-o,9526
|
284
|
+
bec_widgets/widgets/plots_next_gen/setting_menus/axis_settings_vertical.ui,sha256=k4vsQgZyKZkK3JiOXaQmvgR3IHy90mb4upGAtIwBOsA,9104
|
285
285
|
bec_widgets/widgets/plots_next_gen/toolbar_bundles/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
286
|
-
bec_widgets/widgets/plots_next_gen/toolbar_bundles/mouse_interactions.py,sha256=
|
287
|
-
bec_widgets/widgets/plots_next_gen/toolbar_bundles/plot_export.py,sha256=
|
286
|
+
bec_widgets/widgets/plots_next_gen/toolbar_bundles/mouse_interactions.py,sha256=5yLXPLqFo3FWnkgS1lKgeyBPzPIaADOJVHO3ajfRYDQ,4664
|
287
|
+
bec_widgets/widgets/plots_next_gen/toolbar_bundles/plot_export.py,sha256=6FWU-jbHF0dGa06ItQpuabHjX8kazHHjgmnp4YBltdQ,2620
|
288
288
|
bec_widgets/widgets/plots_next_gen/toolbar_bundles/roi_bundle.py,sha256=kgEPk1MYJ0ighSm5T1ri8Hw1t82J4SKMvJLj_witnoQ,979
|
289
289
|
bec_widgets/widgets/plots_next_gen/toolbar_bundles/save_state.py,sha256=a7yCJQ_8HVAYN2dHcbxAjo3nJOSUUQZ7RJuUuGCXDBU,1740
|
290
290
|
bec_widgets/widgets/progress/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -362,8 +362,8 @@ bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.py,sha256=Z
|
|
362
362
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button.pyproject,sha256=Lbi9zb6HNlIq14k6hlzR-oz6PIFShBuF7QxE6d87d64,34
|
363
363
|
bec_widgets/widgets/utility/visual/dark_mode_button/dark_mode_button_plugin.py,sha256=CzChz2SSETYsR8-36meqWnsXCT-FIy_J_xeU5coWDY8,1350
|
364
364
|
bec_widgets/widgets/utility/visual/dark_mode_button/register_dark_mode_button.py,sha256=rMpZ1CaoucwobgPj1FuKTnt07W82bV1GaSYdoqcdMb8,521
|
365
|
-
bec_widgets-1.24.
|
366
|
-
bec_widgets-1.24.
|
367
|
-
bec_widgets-1.24.
|
368
|
-
bec_widgets-1.24.
|
369
|
-
bec_widgets-1.24.
|
365
|
+
bec_widgets-1.24.1.dist-info/METADATA,sha256=c5r-ka79i2PSUeIMx2sHxMvNWO1FTlMK498Jc9WVtCE,1173
|
366
|
+
bec_widgets-1.24.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
367
|
+
bec_widgets-1.24.1.dist-info/entry_points.txt,sha256=dItMzmwA1wizJ1Itx15qnfJ0ZzKVYFLVJ1voxT7K7D4,214
|
368
|
+
bec_widgets-1.24.1.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
369
|
+
bec_widgets-1.24.1.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|
File without changes
|