bec-widgets 0.102.0__py3-none-any.whl → 0.104.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.
- .gitlab-ci.yml +6 -2
- CHANGELOG.md +52 -54
- PKG-INFO +1 -1
- bec_widgets/utils/bec_widget.py +8 -2
- bec_widgets/widgets/scan_control/scan_control.py +183 -21
- bec_widgets/widgets/scan_control/scan_group_box.py +34 -12
- bec_widgets/widgets/toggle/toggle.py +3 -3
- bec_widgets/widgets/vscode/vscode.py +17 -1
- bec_widgets/widgets/website/website.py +15 -1
- {bec_widgets-0.102.0.dist-info → bec_widgets-0.104.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.102.0.dist-info → bec_widgets-0.104.0.dist-info}/RECORD +15 -15
- pyproject.toml +1 -1
- {bec_widgets-0.102.0.dist-info → bec_widgets-0.104.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.102.0.dist-info → bec_widgets-0.104.0.dist-info}/entry_points.txt +0 -0
- {bec_widgets-0.102.0.dist-info → bec_widgets-0.104.0.dist-info}/licenses/LICENSE +0 -0
.gitlab-ci.yml
CHANGED
@@ -5,8 +5,12 @@ image: $CI_DEPENDENCY_PROXY_GROUP_IMAGE_PREFIX/python:3.11
|
|
5
5
|
#commands to run in the Docker container before starting each job.
|
6
6
|
variables:
|
7
7
|
DOCKER_TLS_CERTDIR: ""
|
8
|
-
BEC_CORE_BRANCH:
|
9
|
-
|
8
|
+
BEC_CORE_BRANCH:
|
9
|
+
description: bec branch
|
10
|
+
value: main
|
11
|
+
OPHYD_DEVICES_BRANCH:
|
12
|
+
description: ophyd_devices branch
|
13
|
+
value: main
|
10
14
|
CHILD_PIPELINE_BRANCH: $CI_DEFAULT_BRANCH
|
11
15
|
|
12
16
|
workflow:
|
CHANGELOG.md
CHANGED
@@ -1,5 +1,57 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## v0.104.0 (2024-09-04)
|
4
|
+
|
5
|
+
### Documentation
|
6
|
+
|
7
|
+
* docs(scan_control): docs extended ([`730e25f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/730e25fd3a8be156603005982bfd2a2c2b16dff1))
|
8
|
+
|
9
|
+
### Feature
|
10
|
+
|
11
|
+
* feat(scan_control): scan control remember the previously set parameters and shares kwarg settings across scans ([`d28f9b0`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d28f9b04c45385179353cc247221ec821dcaa29b))
|
12
|
+
|
13
|
+
### Fix
|
14
|
+
|
15
|
+
* fix(scan_control): SafeSlot applied to run_scan to avoid faulty scan requests ([`9047916`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/90479167fb5cae393c884e71a80fcfdb48a76427))
|
16
|
+
|
17
|
+
* fix(scan_control): scan parameters can be loaded from the last executed scan from redis ([`ec3bc8b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ec3bc8b5194c680b847d3306c41eef4638ccfcc7))
|
18
|
+
|
19
|
+
* fix(toggle): state can be determined with the widget initialisation ([`2cd9c7f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/2cd9c7f5854f158468e53b5b29ec31b1ff1e00e6))
|
20
|
+
|
21
|
+
### Refactor
|
22
|
+
|
23
|
+
* refactor(scan_control): scan control layout adjusted ([`85dcbda`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/85dcbdaa88fe77aeea7012bfc16f10c4f873f75e))
|
24
|
+
|
25
|
+
* refactor(scan_control): basic pydantic config added ([`fe8dc55`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/fe8dc55eb102c51c34bf9606690914da53b5ac02))
|
26
|
+
|
27
|
+
### Test
|
28
|
+
|
29
|
+
* test(scan_control): tests extended for getting kwargs between scan switching and getting parameters from redis ([`b07e677`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/b07e67715c9284e9bf36056ba4ba8068f60cbaf3))
|
30
|
+
|
31
|
+
* test(conftest): only run cleanup checks if test passed ([`26920f8`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/26920f8482bdb35ece46df37232af50ab9cab463))
|
32
|
+
|
33
|
+
## v0.103.0 (2024-09-04)
|
34
|
+
|
35
|
+
### Ci
|
36
|
+
|
37
|
+
* ci: prefill variables for manual pipeline start ([`158c19e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/158c19eda771562a325fd59405f9fd4cb9a17ed6))
|
38
|
+
|
39
|
+
### Feature
|
40
|
+
|
41
|
+
* feat(vscode): open vscode on a free port ([`52da835`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/52da835803f2453096a8b7df23bee5fdf93ae2bb))
|
42
|
+
|
43
|
+
* feat(website): added method to wait until the webpage is loaded ([`9be19d4`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9be19d4abebad08c5fc6bea936dd97475fe8f628))
|
44
|
+
|
45
|
+
### Fix
|
46
|
+
|
47
|
+
* fix(theme): fixed segfault for webengineview for auto updates ([`9866075`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9866075100577948755b563dc7b7dc4cdc60d040))
|
48
|
+
|
49
|
+
### Test
|
50
|
+
|
51
|
+
* test(webview): fixed tests after refactoring ([`d5eb30c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/d5eb30cd7df4cb0dc3275dd362768afc211eaf2d))
|
52
|
+
|
53
|
+
* test(vscode): popen call does not have to be the only one ([`39f98ec`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/39f98ec223ba8b59e478ac788c08c59ffe886b4e))
|
54
|
+
|
3
55
|
## v0.102.0 (2024-09-04)
|
4
56
|
|
5
57
|
### Documentation
|
@@ -103,57 +155,3 @@
|
|
103
155
|
### Refactor
|
104
156
|
|
105
157
|
* refactor(stop_button): stop button changed to QWidget and adapted for toolbar ([`097946f`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/097946fd688b8faf770e7cc0e689ea668206bc7a))
|
106
|
-
|
107
|
-
* refactor: added hide option for device selection button ([`cdd1752`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/cdd175207e922904b2efbb2d9ecf7c556c617f2e))
|
108
|
-
|
109
|
-
## v0.99.9 (2024-08-28)
|
110
|
-
|
111
|
-
### Fix
|
112
|
-
|
113
|
-
* fix: fixed build process and excluded docs and tests from tarballs and wheels ([`719254c`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/719254cf0a48e1fc4bd541edba239570778bcfea))
|
114
|
-
|
115
|
-
## v0.99.8 (2024-08-28)
|
116
|
-
|
117
|
-
### Fix
|
118
|
-
|
119
|
-
* fix(website): fixed designer integration for website widget ([`5f37e86`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/5f37e862c95ac7173b6918ad39bcaef938dad698))
|
120
|
-
|
121
|
-
### Refactor
|
122
|
-
|
123
|
-
* refactor(website): changed inheritance of website widget to simple qwidget; closes #325 ([`9925bbd`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/9925bbdb48b55eacbbce9fd6a1555a21b84221f9))
|
124
|
-
|
125
|
-
## v0.99.7 (2024-08-28)
|
126
|
-
|
127
|
-
### Fix
|
128
|
-
|
129
|
-
* fix(toolbar): material icons can accept color as kwarg ([`ffc871e`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/ffc871ebbd3b68abc3e151bb8f5849e6c50e775e))
|
130
|
-
|
131
|
-
## v0.99.6 (2024-08-28)
|
132
|
-
|
133
|
-
### Documentation
|
134
|
-
|
135
|
-
* docs: various bugs fixed ([`c31e9a3`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c31e9a3aff3ee8e984674dee0965ee7f1b6e2b8f))
|
136
|
-
|
137
|
-
### Fix
|
138
|
-
|
139
|
-
* fix(toolbar): use of native qt separators ([`09c6c93`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/09c6c93c397ce4a21c293f6c79106c74b2db65ca))
|
140
|
-
|
141
|
-
## v0.99.5 (2024-08-28)
|
142
|
-
|
143
|
-
### Documentation
|
144
|
-
|
145
|
-
* docs(index): index page is centered ([`02239de`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/02239de0a36fcd6cbf97990b0dec1ddf7ecf6ba6))
|
146
|
-
|
147
|
-
### Fix
|
148
|
-
|
149
|
-
* fix(dock_area): dark button added ([`e6f204b`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/e6f204b6aa295747a68769f43af2e549149b401a))
|
150
|
-
|
151
|
-
## v0.99.4 (2024-08-28)
|
152
|
-
|
153
|
-
### Documentation
|
154
|
-
|
155
|
-
* docs(buttons): added missing buttons docs ([`4e5520a`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/4e5520aee2115d2fc0cebb3865433478a5ec8253))
|
156
|
-
|
157
|
-
### Fix
|
158
|
-
|
159
|
-
* fix(theme): apply theme to all pyqtgraph widgets on manual updates ([`c550186`](https://gitlab.psi.ch/bec/bec_widgets/-/commit/c5501860e8e07a53f4bce144d44ed39eda6290ef))
|
PKG-INFO
CHANGED
bec_widgets/utils/bec_widget.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
import darkdetect
|
3
4
|
from qtpy.QtCore import Slot
|
4
5
|
from qtpy.QtWidgets import QApplication, QWidget
|
5
6
|
|
@@ -40,12 +41,17 @@ class BECWidget(BECConnector):
|
|
40
41
|
"""
|
41
42
|
if not isinstance(self, QWidget):
|
42
43
|
raise RuntimeError(f"{repr(self)} is not a subclass of QWidget")
|
43
|
-
super().__init__(client, config, gui_id)
|
44
|
+
super().__init__(client=client, config=config, gui_id=gui_id)
|
44
45
|
|
45
46
|
# Set the theme to auto if it is not set yet
|
46
47
|
app = QApplication.instance()
|
47
48
|
if not hasattr(app, "theme"):
|
48
|
-
|
49
|
+
# DO NOT SET THE THEME TO AUTO! Otherwise, the qwebengineview will segfault
|
50
|
+
# Instead, we will set the theme to the system setting on startup
|
51
|
+
if darkdetect.isDark():
|
52
|
+
set_theme("dark")
|
53
|
+
else:
|
54
|
+
set_theme("light")
|
49
55
|
|
50
56
|
if theme_update:
|
51
57
|
self._connect_to_theme_change()
|
@@ -1,21 +1,39 @@
|
|
1
|
+
from collections import defaultdict
|
2
|
+
from typing import Optional
|
3
|
+
|
1
4
|
from bec_lib.endpoints import MessageEndpoints
|
5
|
+
from pydantic import BaseModel, Field
|
2
6
|
from qtpy.QtCore import Property, Signal, Slot
|
3
7
|
from qtpy.QtWidgets import (
|
4
8
|
QApplication,
|
5
9
|
QComboBox,
|
6
|
-
QGridLayout,
|
7
10
|
QGroupBox,
|
8
11
|
QHBoxLayout,
|
12
|
+
QLabel,
|
9
13
|
QPushButton,
|
10
14
|
QSizePolicy,
|
11
15
|
QVBoxLayout,
|
12
16
|
QWidget,
|
13
17
|
)
|
14
18
|
|
19
|
+
from bec_widgets.qt_utils.error_popups import SafeSlot
|
20
|
+
from bec_widgets.utils import ConnectionConfig
|
15
21
|
from bec_widgets.utils.bec_widget import BECWidget
|
16
|
-
from bec_widgets.utils.colors import apply_theme
|
17
22
|
from bec_widgets.widgets.scan_control.scan_group_box import ScanGroupBox
|
18
23
|
from bec_widgets.widgets.stop_button.stop_button import StopButton
|
24
|
+
from bec_widgets.widgets.toggle.toggle import ToggleSwitch
|
25
|
+
|
26
|
+
|
27
|
+
class ScanParameterConfig(BaseModel):
|
28
|
+
name: str
|
29
|
+
args: Optional[list] = Field(None)
|
30
|
+
kwargs: Optional[dict] = Field(None)
|
31
|
+
|
32
|
+
|
33
|
+
class ScanControlConfig(ConnectionConfig):
|
34
|
+
default_scan: Optional[str] = Field(None)
|
35
|
+
allowed_scans: Optional[list] = Field(None)
|
36
|
+
scans: Optional[dict[str, ScanParameterConfig]] = defaultdict(dict)
|
19
37
|
|
20
38
|
|
21
39
|
class ScanControl(BECWidget, QWidget):
|
@@ -26,9 +44,20 @@ class ScanControl(BECWidget, QWidget):
|
|
26
44
|
scan_selected = Signal(str)
|
27
45
|
|
28
46
|
def __init__(
|
29
|
-
self,
|
47
|
+
self,
|
48
|
+
parent=None,
|
49
|
+
client=None,
|
50
|
+
config: ScanControlConfig | dict | None = None,
|
51
|
+
gui_id: str | None = None,
|
52
|
+
allowed_scans: list | None = None,
|
53
|
+
default_scan: str | None = None,
|
30
54
|
):
|
31
|
-
|
55
|
+
|
56
|
+
if config is None:
|
57
|
+
config = ScanControlConfig(
|
58
|
+
widget_class=self.__class__.__name__, allowed_scans=allowed_scans
|
59
|
+
)
|
60
|
+
super().__init__(client=client, gui_id=gui_id, config=config)
|
32
61
|
QWidget.__init__(self, parent=parent)
|
33
62
|
|
34
63
|
# Client from BEC + shortcuts to device manager and scans
|
@@ -36,12 +65,16 @@ class ScanControl(BECWidget, QWidget):
|
|
36
65
|
|
37
66
|
# Main layout
|
38
67
|
self.layout = QVBoxLayout(self)
|
68
|
+
self.layout.setContentsMargins(5, 5, 5, 5)
|
39
69
|
self.arg_box = None
|
40
70
|
self.kwarg_boxes = []
|
41
71
|
self.expert_mode = False # TODO implement in the future versions
|
72
|
+
self.previous_scan = None
|
73
|
+
self.last_scan_found = None
|
42
74
|
|
43
|
-
#
|
44
|
-
self.
|
75
|
+
# Widget Default Parameters
|
76
|
+
self.config.default_scan = default_scan
|
77
|
+
self.config.allowed_scans = allowed_scans
|
45
78
|
|
46
79
|
# Create and set main layout
|
47
80
|
self._init_UI()
|
@@ -56,7 +89,12 @@ class ScanControl(BECWidget, QWidget):
|
|
56
89
|
self.scan_selection_group.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed)
|
57
90
|
self.layout.addWidget(self.scan_selection_group)
|
58
91
|
|
92
|
+
# Default scan from config
|
93
|
+
if self.config.default_scan is not None:
|
94
|
+
self.comboBox_scan_selection.setCurrentText(self.config.default_scan)
|
95
|
+
|
59
96
|
# Connect signals
|
97
|
+
self.comboBox_scan_selection.view().pressed.connect(self.save_current_scan_parameters)
|
60
98
|
self.comboBox_scan_selection.currentIndexChanged.connect(self.on_scan_selection_changed)
|
61
99
|
self.button_run_scan.clicked.connect(self.run_scan)
|
62
100
|
|
@@ -89,18 +127,35 @@ class ScanControl(BECWidget, QWidget):
|
|
89
127
|
"""
|
90
128
|
|
91
129
|
scan_selection_group = QGroupBox("Scan Selection", self)
|
92
|
-
self.scan_selection_layout =
|
130
|
+
self.scan_selection_layout = QVBoxLayout(scan_selection_group)
|
93
131
|
self.comboBox_scan_selection = QComboBox(scan_selection_group)
|
94
132
|
|
95
|
-
#
|
133
|
+
# Buttons
|
134
|
+
self.button_layout = QHBoxLayout()
|
135
|
+
## Run button
|
96
136
|
self.button_run_scan = QPushButton("Start", scan_selection_group)
|
97
137
|
self.button_run_scan.setStyleSheet("background-color: #559900; color: white")
|
98
|
-
|
138
|
+
## Stop button
|
99
139
|
self.button_stop_scan = StopButton(parent=scan_selection_group)
|
100
|
-
|
101
|
-
self.
|
102
|
-
self.
|
103
|
-
|
140
|
+
## Add buttons to layout
|
141
|
+
self.button_layout.addWidget(self.button_run_scan)
|
142
|
+
self.button_layout.addWidget(self.button_stop_scan)
|
143
|
+
|
144
|
+
# Label to reload the last scan parameters
|
145
|
+
self.toggle_layout = QHBoxLayout()
|
146
|
+
## Label
|
147
|
+
self.last_scan_label = QLabel("Restore last scan parameters", scan_selection_group)
|
148
|
+
## Switch toggle button
|
149
|
+
self.toggle = ToggleSwitch(parent=scan_selection_group, checked=False)
|
150
|
+
self.toggle.enabled.connect(self.request_last_executed_scan_parameters)
|
151
|
+
## Add label and switch to layout
|
152
|
+
self.toggle_layout.addWidget(self.last_scan_label)
|
153
|
+
self.toggle_layout.addWidget(self.toggle)
|
154
|
+
|
155
|
+
# Add widgets to layout
|
156
|
+
self.scan_selection_layout.addWidget(self.comboBox_scan_selection)
|
157
|
+
self.scan_selection_layout.addLayout(self.button_layout)
|
158
|
+
self.scan_selection_layout.addLayout(self.toggle_layout)
|
104
159
|
|
105
160
|
return scan_selection_group
|
106
161
|
|
@@ -109,7 +164,7 @@ class ScanControl(BECWidget, QWidget):
|
|
109
164
|
self.available_scans = self.client.connector.get(
|
110
165
|
MessageEndpoints.available_scans()
|
111
166
|
).resource
|
112
|
-
if self.allowed_scans is None:
|
167
|
+
if self.config.allowed_scans is None:
|
113
168
|
supported_scans = ["ScanBase", "SyncFlyScanBase", "AsyncFlyScanBase"]
|
114
169
|
allowed_scans = [
|
115
170
|
scan_name
|
@@ -118,13 +173,50 @@ class ScanControl(BECWidget, QWidget):
|
|
118
173
|
]
|
119
174
|
|
120
175
|
else:
|
121
|
-
allowed_scans = self.allowed_scans
|
176
|
+
allowed_scans = self.config.allowed_scans
|
122
177
|
self.comboBox_scan_selection.addItems(allowed_scans)
|
123
178
|
|
124
179
|
def on_scan_selection_changed(self, index: int):
|
125
180
|
"""Callback for scan selection combo box"""
|
126
181
|
selected_scan_name = self.comboBox_scan_selection.currentText()
|
127
182
|
self.scan_selected.emit(selected_scan_name)
|
183
|
+
self.request_last_executed_scan_parameters()
|
184
|
+
self.restore_scan_parameters(selected_scan_name)
|
185
|
+
|
186
|
+
@Slot()
|
187
|
+
def request_last_executed_scan_parameters(self):
|
188
|
+
"""
|
189
|
+
Requests the last executed scan parameters from BEC and restores them to the scan control widget.
|
190
|
+
"""
|
191
|
+
enabled = self.toggle.checked
|
192
|
+
current_scan = self.comboBox_scan_selection.currentText()
|
193
|
+
if enabled:
|
194
|
+
history = self.client.connector.lrange(MessageEndpoints.scan_queue_history(), 0, -1)
|
195
|
+
|
196
|
+
for scan in history:
|
197
|
+
scan_name = scan.content["info"]["request_blocks"][-1]["msg"].content["scan_type"]
|
198
|
+
if scan_name == current_scan:
|
199
|
+
args_dict = scan.content["info"]["request_blocks"][-1]["msg"].content[
|
200
|
+
"parameter"
|
201
|
+
]["args"]
|
202
|
+
args_list = []
|
203
|
+
for key, value in args_dict.items():
|
204
|
+
args_list.append(key)
|
205
|
+
args_list.extend(value)
|
206
|
+
if len(args_list) > 1 and self.arg_box is not None:
|
207
|
+
self.arg_box.set_parameters(args_list)
|
208
|
+
kwargs = scan.content["info"]["request_blocks"][-1]["msg"].content["parameter"][
|
209
|
+
"kwargs"
|
210
|
+
]
|
211
|
+
if kwargs and self.kwarg_boxes:
|
212
|
+
for box in self.kwarg_boxes:
|
213
|
+
box.set_parameters(kwargs)
|
214
|
+
self.last_scan_found = True
|
215
|
+
break
|
216
|
+
else:
|
217
|
+
self.last_scan_found = False
|
218
|
+
else:
|
219
|
+
self.last_scan_found = False
|
128
220
|
|
129
221
|
@Property(str)
|
130
222
|
def current_scan(self):
|
@@ -151,6 +243,29 @@ class ScanControl(BECWidget, QWidget):
|
|
151
243
|
"""
|
152
244
|
self.current_scan = scan_name
|
153
245
|
|
246
|
+
@Property(bool)
|
247
|
+
def hide_scan_remember_toggle(self):
|
248
|
+
"""Property to hide the scan remember toggle."""
|
249
|
+
return not self.toggle.isVisible()
|
250
|
+
|
251
|
+
@hide_scan_remember_toggle.setter
|
252
|
+
def hide_scan_remember_toggle(self, hide: bool):
|
253
|
+
"""Setter for the hide_scan_remember_toggle property.
|
254
|
+
|
255
|
+
Args:
|
256
|
+
hide(bool): Hide or show the scan remember toggle.
|
257
|
+
"""
|
258
|
+
self.show_scan_remember_toggle(not hide)
|
259
|
+
|
260
|
+
@Slot(bool)
|
261
|
+
def show_scan_remember_toggle(self, show: bool):
|
262
|
+
"""Shows or hides the scan control buttons."""
|
263
|
+
self.toggle.setVisible(show)
|
264
|
+
self.last_scan_label.setVisible(show)
|
265
|
+
|
266
|
+
show_group = show or self.button_run_scan.isVisible()
|
267
|
+
self.scan_selection_group.setVisible(show_group)
|
268
|
+
|
154
269
|
@Property(bool)
|
155
270
|
def hide_scan_control_buttons(self):
|
156
271
|
"""Property to hide the scan control buttons."""
|
@@ -294,17 +409,64 @@ class ScanControl(BECWidget, QWidget):
|
|
294
409
|
box.deleteLater()
|
295
410
|
self.kwarg_boxes = []
|
296
411
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
412
|
+
def get_scan_parameters(self, bec_object: bool = True):
|
413
|
+
"""
|
414
|
+
Returns the scan parameters for the selected scan.
|
415
|
+
|
416
|
+
Args:
|
417
|
+
bec_object(bool): If True, returns the BEC object for the scan parameters such as device objects.
|
418
|
+
"""
|
301
419
|
args = []
|
302
420
|
kwargs = {}
|
303
421
|
if self.arg_box is not None:
|
304
|
-
args = self.arg_box.get_parameters()
|
422
|
+
args = self.arg_box.get_parameters(bec_object)
|
305
423
|
for box in self.kwarg_boxes:
|
306
|
-
box_kwargs = box.get_parameters()
|
424
|
+
box_kwargs = box.get_parameters(bec_object)
|
307
425
|
kwargs.update(box_kwargs)
|
426
|
+
return args, kwargs
|
427
|
+
|
428
|
+
def restore_scan_parameters(self, scan_name: str):
|
429
|
+
"""
|
430
|
+
Restores the scan parameters for the given scan name
|
431
|
+
|
432
|
+
Args:
|
433
|
+
scan_name(str): Name of the scan to restore the parameters for.
|
434
|
+
"""
|
435
|
+
if self.last_scan_found is True:
|
436
|
+
return
|
437
|
+
scan_params = self.config.scans.get(scan_name, None)
|
438
|
+
if scan_params is None and self.previous_scan is None:
|
439
|
+
return
|
440
|
+
|
441
|
+
if scan_params is None and self.previous_scan is not None:
|
442
|
+
previous_scan_params = self.config.scans.get(self.previous_scan, None)
|
443
|
+
self._restore_kwargs(previous_scan_params.kwargs)
|
444
|
+
return
|
445
|
+
|
446
|
+
if scan_params.args is not None and self.arg_box is not None:
|
447
|
+
self.arg_box.set_parameters(scan_params.args)
|
448
|
+
|
449
|
+
self._restore_kwargs(scan_params.kwargs)
|
450
|
+
|
451
|
+
def _restore_kwargs(self, scan_kwargs: dict):
|
452
|
+
"""Restores the kwargs for the given scan parameters."""
|
453
|
+
if scan_kwargs is not None and self.kwarg_boxes is not None:
|
454
|
+
for box in self.kwarg_boxes:
|
455
|
+
box.set_parameters(scan_kwargs)
|
456
|
+
|
457
|
+
def save_current_scan_parameters(self):
|
458
|
+
"""Saves the current scan parameters to the scan control config for further use."""
|
459
|
+
scan_name = self.comboBox_scan_selection.currentText()
|
460
|
+
self.previous_scan = scan_name
|
461
|
+
args, kwargs = self.get_scan_parameters(False)
|
462
|
+
scan_params = ScanParameterConfig(name=scan_name, args=args, kwargs=kwargs)
|
463
|
+
self.config.scans[scan_name] = scan_params
|
464
|
+
|
465
|
+
@SafeSlot(popup_error=True)
|
466
|
+
def run_scan(self):
|
467
|
+
"""Starts the selected scan with the given parameters."""
|
468
|
+
self.scan_started.emit()
|
469
|
+
args, kwargs = self.get_scan_parameters()
|
308
470
|
scan_function = getattr(self.scans, self.comboBox_scan_selection.currentText())
|
309
471
|
if callable(scan_function):
|
310
472
|
scan_function(*args, **kwargs)
|
@@ -230,32 +230,35 @@ class ScanGroupBox(QGroupBox):
|
|
230
230
|
widget.deleteLater()
|
231
231
|
self.widgets = self.widgets[: -len(self.inputs)]
|
232
232
|
|
233
|
-
def get_parameters(self):
|
233
|
+
def get_parameters(self, device_object: bool = True):
|
234
234
|
"""
|
235
235
|
Returns the parameters from the widgets in the scan control layout formated to run scan from BEC.
|
236
236
|
"""
|
237
237
|
if self.box_type == "args":
|
238
|
-
return self._get_arg_parameterts()
|
238
|
+
return self._get_arg_parameterts(device_object=device_object)
|
239
239
|
elif self.box_type == "kwargs":
|
240
|
-
return self._get_kwarg_parameters()
|
240
|
+
return self._get_kwarg_parameters(device_object=device_object)
|
241
241
|
|
242
|
-
def _get_arg_parameterts(self):
|
242
|
+
def _get_arg_parameterts(self, device_object: bool = True):
|
243
243
|
args = []
|
244
244
|
for i in range(1, self.layout.rowCount()):
|
245
245
|
for j in range(self.layout.columnCount()):
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
246
|
+
try: # In case that the bundle size changes
|
247
|
+
widget = self.layout.itemAtPosition(i, j).widget()
|
248
|
+
if isinstance(widget, DeviceLineEdit) and device_object:
|
249
|
+
value = widget.get_device()
|
250
|
+
else:
|
251
|
+
value = WidgetIO.get_value(widget)
|
252
|
+
args.append(value)
|
253
|
+
except AttributeError:
|
254
|
+
continue
|
252
255
|
return args
|
253
256
|
|
254
|
-
def _get_kwarg_parameters(self):
|
257
|
+
def _get_kwarg_parameters(self, device_object: bool = True):
|
255
258
|
kwargs = {}
|
256
259
|
for i in range(self.layout.columnCount()):
|
257
260
|
widget = self.layout.itemAtPosition(1, i).widget()
|
258
|
-
if isinstance(widget, DeviceLineEdit):
|
261
|
+
if isinstance(widget, DeviceLineEdit) and device_object:
|
259
262
|
value = widget.get_device()
|
260
263
|
else:
|
261
264
|
value = WidgetIO.get_value(widget)
|
@@ -273,3 +276,22 @@ class ScanGroupBox(QGroupBox):
|
|
273
276
|
if isinstance(widget, DeviceLineEdit):
|
274
277
|
widget_rows += 1
|
275
278
|
return widget_rows
|
279
|
+
|
280
|
+
def set_parameters(self, parameters: list | dict):
|
281
|
+
if self.box_type == "args":
|
282
|
+
self._set_arg_parameters(parameters)
|
283
|
+
elif self.box_type == "kwargs":
|
284
|
+
self._set_kwarg_parameters(parameters)
|
285
|
+
|
286
|
+
def _set_arg_parameters(self, parameters: list):
|
287
|
+
while len(parameters) != len(self.widgets):
|
288
|
+
self.add_widget_bundle()
|
289
|
+
for i, parameter in enumerate(parameters):
|
290
|
+
WidgetIO.set_value(self.widgets[i], parameter)
|
291
|
+
|
292
|
+
def _set_kwarg_parameters(self, parameters: dict):
|
293
|
+
for widget in self.widgets:
|
294
|
+
for key, value in parameters.items():
|
295
|
+
if widget.arg_name == key:
|
296
|
+
WidgetIO.set_value(widget, value)
|
297
|
+
break
|
@@ -13,7 +13,7 @@ class ToggleSwitch(QWidget):
|
|
13
13
|
enabled = Signal(bool)
|
14
14
|
ICON_NAME = "toggle_on"
|
15
15
|
|
16
|
-
def __init__(self, parent=None):
|
16
|
+
def __init__(self, parent=None, checked=True):
|
17
17
|
super().__init__(parent)
|
18
18
|
self.setFixedSize(40, 21)
|
19
19
|
|
@@ -23,14 +23,14 @@ class ToggleSwitch(QWidget):
|
|
23
23
|
self._inactive_track_color = QColor(200, 200, 200)
|
24
24
|
self._inactive_thumb_color = QColor(255, 255, 255)
|
25
25
|
|
26
|
-
self._checked =
|
26
|
+
self._checked = checked
|
27
27
|
self._track_color = self.inactive_track_color
|
28
28
|
self._thumb_color = self.inactive_thumb_color
|
29
29
|
|
30
30
|
self._animation = QPropertyAnimation(self, b"thumb_pos")
|
31
31
|
self._animation.setDuration(200)
|
32
32
|
self._animation.setEasingCurve(QEasingCurve.Type.OutBack)
|
33
|
-
self.setProperty("checked",
|
33
|
+
self.setProperty("checked", checked)
|
34
34
|
|
35
35
|
@Property(bool)
|
36
36
|
def checked(self):
|
@@ -2,12 +2,27 @@ import os
|
|
2
2
|
import select
|
3
3
|
import shlex
|
4
4
|
import signal
|
5
|
+
import socket
|
5
6
|
import subprocess
|
6
7
|
import sys
|
7
8
|
|
8
9
|
from bec_widgets.widgets.website.website import WebsiteWidget
|
9
10
|
|
10
11
|
|
12
|
+
def get_free_port():
|
13
|
+
"""
|
14
|
+
Get a free port on the local machine.
|
15
|
+
|
16
|
+
Returns:
|
17
|
+
int: The free port number
|
18
|
+
"""
|
19
|
+
sock = socket.socket()
|
20
|
+
sock.bind(("", 0))
|
21
|
+
port = sock.getsockname()[1]
|
22
|
+
sock.close()
|
23
|
+
return port
|
24
|
+
|
25
|
+
|
11
26
|
class VSCodeEditor(WebsiteWidget):
|
12
27
|
"""
|
13
28
|
A widget to display the VSCode editor.
|
@@ -15,7 +30,6 @@ class VSCodeEditor(WebsiteWidget):
|
|
15
30
|
|
16
31
|
token = "bec"
|
17
32
|
host = "127.0.0.1"
|
18
|
-
port = 7000
|
19
33
|
|
20
34
|
USER_ACCESS = []
|
21
35
|
ICON_NAME = "developer_mode_tv"
|
@@ -23,6 +37,7 @@ class VSCodeEditor(WebsiteWidget):
|
|
23
37
|
def __init__(self, parent=None, config=None, client=None, gui_id=None):
|
24
38
|
|
25
39
|
self.process = None
|
40
|
+
self.port = get_free_port()
|
26
41
|
self._url = f"http://{self.host}:{self.port}?tkn={self.token}"
|
27
42
|
super().__init__(parent=parent, config=config, client=client, gui_id=gui_id)
|
28
43
|
self.start_server()
|
@@ -49,6 +64,7 @@ class VSCodeEditor(WebsiteWidget):
|
|
49
64
|
if output and f"available at {self._url}" in output:
|
50
65
|
break
|
51
66
|
self.set_url(self._url)
|
67
|
+
self.wait_until_loaded()
|
52
68
|
|
53
69
|
def cleanup_vscode(self):
|
54
70
|
"""
|
@@ -1,5 +1,5 @@
|
|
1
1
|
from qtpy.QtCore import Property, QUrl, Slot, qInstallMessageHandler
|
2
|
-
from qtpy.QtWebEngineWidgets import QWebEngineView
|
2
|
+
from qtpy.QtWebEngineWidgets import QWebEngineSettings, QWebEngineView
|
3
3
|
from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
|
4
4
|
|
5
5
|
from bec_widgets.utils.bec_widget import BECWidget
|
@@ -32,6 +32,19 @@ class WebsiteWidget(BECWidget, QWidget):
|
|
32
32
|
self.setLayout(layout)
|
33
33
|
self.set_url(url)
|
34
34
|
|
35
|
+
self._loaded = False
|
36
|
+
self.website.loadFinished.connect(self._on_load_finished)
|
37
|
+
|
38
|
+
def wait_until_loaded(self):
|
39
|
+
while not self._loaded:
|
40
|
+
QApplication.processEvents()
|
41
|
+
|
42
|
+
def _on_load_finished(self):
|
43
|
+
"""
|
44
|
+
Callback when the website has finished loading
|
45
|
+
"""
|
46
|
+
self._loaded = True
|
47
|
+
|
35
48
|
@Property(str)
|
36
49
|
def url(self) -> str:
|
37
50
|
"""
|
@@ -64,6 +77,7 @@ class WebsiteWidget(BECWidget, QWidget):
|
|
64
77
|
return
|
65
78
|
if not isinstance(url, str):
|
66
79
|
return
|
80
|
+
self._loaded = False
|
67
81
|
self.website.setUrl(QUrl(url))
|
68
82
|
|
69
83
|
def get_url(self) -> str:
|
@@ -1,12 +1,12 @@
|
|
1
1
|
.gitignore,sha256=cMQ1MLmnoR88aMCCJwUyfoTnufzl4-ckmHtlFUqHcT4,3253
|
2
|
-
.gitlab-ci.yml,sha256=
|
2
|
+
.gitlab-ci.yml,sha256=Dc1iDjsc72UxdUtihx4uSZU0lrTQeR8hZwGx1MQBfKE,8432
|
3
3
|
.pylintrc,sha256=eeY8YwSI74oFfq6IYIbCqnx3Vk8ZncKaatv96n_Y8Rs,18544
|
4
4
|
.readthedocs.yaml,sha256=aSOc277LqXcsTI6lgvm_JY80lMlr69GbPKgivua2cS0,603
|
5
|
-
CHANGELOG.md,sha256=
|
5
|
+
CHANGELOG.md,sha256=56BXszrhvVmZ-ko-vL6XvL-n404_pI3WPFat9QBsGKw,7391
|
6
6
|
LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
7
|
-
PKG-INFO,sha256=
|
7
|
+
PKG-INFO,sha256=5uieac1rLNLfxfbqXF9q2AyKsrEM34ZR7Mp_zjJOcLg,1334
|
8
8
|
README.md,sha256=Od69x-RS85Hph0-WwWACwal4yUd67XkEn4APEfHhHFw,2649
|
9
|
-
pyproject.toml,sha256=
|
9
|
+
pyproject.toml,sha256=2KA4GlcKlp8NhsbCE5skdf7xye1F8SaNHRy11G7Ikfs,2544
|
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
|
@@ -52,7 +52,7 @@ bec_widgets/utils/bec_connector.py,sha256=SivHKXVyNVqeu3kCXYEPpbleTVw8g1cW0FKq1Q
|
|
52
52
|
bec_widgets/utils/bec_designer.py,sha256=Z3MeMju-KmTz8POtm23VQfp4rvtD2sF6eIOKQkl2F7w,4729
|
53
53
|
bec_widgets/utils/bec_dispatcher.py,sha256=NkObWO_gRO9Uobz-fy0gVTZqQsbFRaKj6fbjYZoErFI,6400
|
54
54
|
bec_widgets/utils/bec_table.py,sha256=nA2b8ukSeUfquFMAxGrUVOqdrzMoDYD6O_4EYbOG2zk,717
|
55
|
-
bec_widgets/utils/bec_widget.py,sha256=
|
55
|
+
bec_widgets/utils/bec_widget.py,sha256=7KmIdWCa7skN1jTsQQkhOpu2PZmKMr98AMB1f_MZfv4,3179
|
56
56
|
bec_widgets/utils/colors.py,sha256=N3GbVBpExfC1m_dnYFDoua-iRLM90E5kTKVOIkZVmDM,12372
|
57
57
|
bec_widgets/utils/container_utils.py,sha256=0wr3ZfuMiAFKCrQHVjxjw-Vuk8wsHdridqcjy2eY840,1531
|
58
58
|
bec_widgets/utils/crosshair.py,sha256=8lik9k69WI2WMj5FGLbrKtny9duxqXUJAhpX8tHoyp0,11543
|
@@ -199,10 +199,10 @@ bec_widgets/widgets/ring_progress_bar/ring_progress_bar.pyproject,sha256=ZNYDnKD
|
|
199
199
|
bec_widgets/widgets/ring_progress_bar/ring_progress_bar_plugin.py,sha256=-rw9ZSThgAH0Ubbr3X-L5x-ZqMXUGnauyFb4OmfUvD4,1394
|
200
200
|
bec_widgets/widgets/scan_control/__init__.py,sha256=IOfHl15vxb_uC6KN62-PeUzbBha_vQyqkkXbJ2HU674,38
|
201
201
|
bec_widgets/widgets/scan_control/register_scan_control.py,sha256=xUX2yR0-MaIMg9_y9qe50yDDphzsh2x1b5PMrF90yPM,475
|
202
|
-
bec_widgets/widgets/scan_control/scan_control.py,sha256=
|
202
|
+
bec_widgets/widgets/scan_control/scan_control.py,sha256=PVy_gqivO_Nut6ZxdOhgXfRyRPcQ92wSGOGY8duxXlE,18074
|
203
203
|
bec_widgets/widgets/scan_control/scan_control.pyproject,sha256=eTgVDFKToIH8_BbJjM2RvbOLr7HnYoidX0SAHx640DM,30
|
204
204
|
bec_widgets/widgets/scan_control/scan_control_plugin.py,sha256=7GaqmaRgbwIPjVoXcyKVDl8UpfqC2weViup-YFfzUsM,1270
|
205
|
-
bec_widgets/widgets/scan_control/scan_group_box.py,sha256=
|
205
|
+
bec_widgets/widgets/scan_control/scan_group_box.py,sha256=ZGF5alvw4vK---6-zsVUzW-6dt7-V68EbzrGp5EL_RE,10377
|
206
206
|
bec_widgets/widgets/spinner/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
207
207
|
bec_widgets/widgets/spinner/register_spinner_widget.py,sha256=_zCPjLh4M7NTSHP1Atdn6yu33zJ3LJkcBy3KOJ5eSVY,476
|
208
208
|
bec_widgets/widgets/spinner/spinner.py,sha256=5LoRGuRvQmY1hUCt06P3DJjXqOVkFCszbNAXRmPzqlo,2628
|
@@ -220,14 +220,14 @@ bec_widgets/widgets/text_box/text_box.pyproject,sha256=XohO1BIe2hrpU-z_KHKRgjcUk
|
|
220
220
|
bec_widgets/widgets/text_box/text_box_plugin.py,sha256=rjRxqqovggpiI3gfQrXU-uc7TEjugIameQBrFD6s9hY,1302
|
221
221
|
bec_widgets/widgets/toggle/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
222
222
|
bec_widgets/widgets/toggle/register_toggle_switch.py,sha256=8pVtkeEeiDOjV4OPoZq1I30F9JDzl4nQE7e7xoWyWBs,472
|
223
|
-
bec_widgets/widgets/toggle/toggle.py,sha256=
|
223
|
+
bec_widgets/widgets/toggle/toggle.py,sha256=cLKWXH5vLG6VcycN_EgwdFsMPS65EbqoS0dfKE1S5kk,4498
|
224
224
|
bec_widgets/widgets/toggle/toggle_switch.pyproject,sha256=Msa-AS5H5XlqW65r8GlX2AxD8FnFnDyDgGnbKcXqKOw,24
|
225
225
|
bec_widgets/widgets/toggle/toggle_switch_plugin.py,sha256=1snX-mKw_K3oPqUApGRPDnNRnLMZjqnmQOzuIJ9MOT4,1344
|
226
226
|
bec_widgets/widgets/vscode/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
227
227
|
bec_widgets/widgets/vscode/register_vs_code_editor.py,sha256=JATKBkTEuReeQ2Jj402xasjgVRMFI8uUOAAwmnFOWRA,473
|
228
228
|
bec_widgets/widgets/vscode/vs_code_editor.pyproject,sha256=bxx0jZlSfBo-Em7p15W1QIJ9lFr9jqTqGynUQG01ocU,24
|
229
229
|
bec_widgets/widgets/vscode/vs_code_editor_plugin.py,sha256=exFR6HTVdLLPfn2U6BMDugPoxZaebcHTnHWMrX2n_d4,1338
|
230
|
-
bec_widgets/widgets/vscode/vscode.py,sha256=
|
230
|
+
bec_widgets/widgets/vscode/vscode.py,sha256=3HDWYJZPi4lNr7gW4IabTYyivMdhZGhq5ETGlJihqlc,2579
|
231
231
|
bec_widgets/widgets/waveform/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
232
232
|
bec_widgets/widgets/waveform/bec_waveform_widget.pyproject,sha256=GLD8GN9dXx9wNbtnevrxqqcwk7vKV-Uv8QYSycdaoaI,33
|
233
233
|
bec_widgets/widgets/waveform/bec_waveform_widget_plugin.py,sha256=qSQTeCzIUn8rgDkjIM47Rr3-fqg1uk8rDf_lCoY9gZw,1402
|
@@ -241,11 +241,11 @@ bec_widgets/widgets/waveform/waveform_popups/dap_summary_dialog/__init__.py,sha2
|
|
241
241
|
bec_widgets/widgets/waveform/waveform_popups/dap_summary_dialog/dap_summary_dialog.py,sha256=XOHppMcONwfhAYpqIc51VOrpunWmPSn50sT3I0MjW2c,1173
|
242
242
|
bec_widgets/widgets/website/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
243
243
|
bec_widgets/widgets/website/register_website_widget.py,sha256=LIQJpV9uqcBiPR9cEAiDjaUS_l7JroYVdsotnLpD9H0,476
|
244
|
-
bec_widgets/widgets/website/website.py,sha256=
|
244
|
+
bec_widgets/widgets/website/website.py,sha256=42pncCc_zI2eqeMArIurVmPUukRo5bTxa2h1Skah-io,3012
|
245
245
|
bec_widgets/widgets/website/website_widget.pyproject,sha256=scOiV3cV1_BjbzpPzy2N8rIJL5P2qIZz8ObTJ-Uvdtg,25
|
246
246
|
bec_widgets/widgets/website/website_widget_plugin.py,sha256=pz38_C2cZ0yvPPS02wdIPcmhFo_yiwUhflsASocAPQQ,1341
|
247
|
-
bec_widgets-0.
|
248
|
-
bec_widgets-0.
|
249
|
-
bec_widgets-0.
|
250
|
-
bec_widgets-0.
|
251
|
-
bec_widgets-0.
|
247
|
+
bec_widgets-0.104.0.dist-info/METADATA,sha256=5uieac1rLNLfxfbqXF9q2AyKsrEM34ZR7Mp_zjJOcLg,1334
|
248
|
+
bec_widgets-0.104.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
|
249
|
+
bec_widgets-0.104.0.dist-info/entry_points.txt,sha256=3otEkCdDB9LZJuBLzG4pFLK5Di0CVybN_12IsZrQ-58,166
|
250
|
+
bec_widgets-0.104.0.dist-info/licenses/LICENSE,sha256=YRKe85CBRyP7UpEAWwU8_qSIyuy5-l_9C-HKg5Qm8MQ,1511
|
251
|
+
bec_widgets-0.104.0.dist-info/RECORD,,
|
pyproject.toml
CHANGED
File without changes
|
File without changes
|
File without changes
|