pymodaq 5.0.17__py3-none-any.whl → 5.1.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.
Potentially problematic release.
This version of pymodaq might be problematic. Click here for more details.
- pymodaq/__init__.py +23 -11
- pymodaq/control_modules/__init__.py +1 -0
- pymodaq/control_modules/daq_move.py +458 -246
- pymodaq/control_modules/daq_move_ui/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/factory.py +48 -0
- pymodaq/control_modules/{daq_move_ui.py → daq_move_ui/ui_base.py} +168 -210
- pymodaq/control_modules/daq_move_ui/uis/__init__.py +0 -0
- pymodaq/control_modules/daq_move_ui/uis/binary.py +139 -0
- pymodaq/control_modules/daq_move_ui/uis/original.py +120 -0
- pymodaq/control_modules/daq_move_ui/uis/relative.py +124 -0
- pymodaq/control_modules/daq_move_ui/uis/simple.py +126 -0
- pymodaq/control_modules/daq_viewer.py +113 -101
- pymodaq/control_modules/daq_viewer_ui.py +41 -31
- pymodaq/control_modules/mocks.py +2 -2
- pymodaq/control_modules/move_utility_classes.py +113 -41
- pymodaq/control_modules/thread_commands.py +137 -0
- pymodaq/control_modules/ui_utils.py +72 -0
- pymodaq/control_modules/utils.py +107 -63
- pymodaq/control_modules/viewer_utility_classes.py +13 -17
- pymodaq/dashboard.py +1294 -625
- pymodaq/examples/qt_less_standalone_module.py +48 -11
- pymodaq/extensions/__init__.py +8 -3
- pymodaq/extensions/adaptive/__init__.py +2 -0
- pymodaq/extensions/adaptive/adaptive_optimization.py +179 -0
- pymodaq/extensions/adaptive/loss_function/_1d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/_2d_loss_functions.py +73 -0
- pymodaq/extensions/adaptive/loss_function/__init__.py +3 -0
- pymodaq/extensions/adaptive/loss_function/loss_factory.py +110 -0
- pymodaq/extensions/adaptive/utils.py +123 -0
- pymodaq/extensions/bayesian/__init__.py +1 -1
- pymodaq/extensions/bayesian/acquisition/__init__.py +2 -0
- pymodaq/extensions/bayesian/acquisition/acquisition_function_factory.py +80 -0
- pymodaq/extensions/bayesian/acquisition/base_acquisition_function.py +105 -0
- pymodaq/extensions/bayesian/bayesian_optimization.py +143 -0
- pymodaq/extensions/bayesian/utils.py +71 -297
- pymodaq/extensions/daq_logger/daq_logger.py +7 -12
- pymodaq/extensions/daq_logger/h5logging.py +1 -1
- pymodaq/extensions/daq_scan.py +30 -55
- pymodaq/extensions/data_mixer/__init__.py +0 -0
- pymodaq/extensions/data_mixer/daq_0Dviewer_DataMixer.py +97 -0
- pymodaq/extensions/data_mixer/data_mixer.py +262 -0
- pymodaq/extensions/data_mixer/model.py +108 -0
- pymodaq/extensions/data_mixer/models/__init__.py +0 -0
- pymodaq/extensions/data_mixer/models/equation_model.py +91 -0
- pymodaq/extensions/data_mixer/models/gaussian_fit_model.py +65 -0
- pymodaq/extensions/data_mixer/parser.py +53 -0
- pymodaq/extensions/data_mixer/utils.py +23 -0
- pymodaq/extensions/h5browser.py +3 -34
- pymodaq/extensions/optimizers_base/__init__.py +0 -0
- pymodaq/extensions/optimizers_base/optimizer.py +1016 -0
- pymodaq/extensions/optimizers_base/thread_commands.py +22 -0
- pymodaq/extensions/optimizers_base/utils.py +427 -0
- pymodaq/extensions/pid/actuator_controller.py +3 -2
- pymodaq/extensions/pid/daq_move_PID.py +107 -30
- pymodaq/extensions/pid/pid_controller.py +613 -287
- pymodaq/extensions/pid/utils.py +8 -5
- pymodaq/extensions/utils.py +17 -2
- pymodaq/resources/config_template.toml +57 -0
- pymodaq/resources/preset_default.xml +1 -1
- pymodaq/utils/config.py +13 -4
- pymodaq/utils/daq_utils.py +14 -0
- pymodaq/utils/data.py +1 -0
- pymodaq/utils/gui_utils/loader_utils.py +25 -15
- pymodaq/utils/h5modules/module_saving.py +134 -22
- pymodaq/utils/leco/daq_move_LECODirector.py +123 -84
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +84 -97
- pymodaq/utils/leco/director_utils.py +32 -16
- pymodaq/utils/leco/leco_director.py +104 -27
- pymodaq/utils/leco/pymodaq_listener.py +186 -97
- pymodaq/utils/leco/rpc_method_definitions.py +43 -0
- pymodaq/utils/leco/utils.py +25 -25
- pymodaq/utils/managers/batchscan_manager.py +12 -11
- pymodaq/utils/managers/modules_manager.py +74 -33
- pymodaq/utils/managers/overshoot_manager.py +11 -10
- pymodaq/utils/managers/preset_manager.py +100 -64
- pymodaq/utils/managers/preset_manager_utils.py +163 -107
- pymodaq/utils/managers/remote_manager.py +21 -16
- pymodaq/utils/scanner/scan_factory.py +18 -4
- pymodaq/utils/scanner/scan_selector.py +1 -3
- pymodaq/utils/scanner/scanner.py +35 -6
- pymodaq/utils/scanner/scanners/_1d_scanners.py +15 -46
- pymodaq/utils/scanner/scanners/_2d_scanners.py +21 -68
- pymodaq/utils/scanner/scanners/sequential.py +50 -31
- pymodaq/utils/scanner/scanners/tabular.py +45 -28
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/METADATA +7 -6
- pymodaq-5.1.0.dist-info/RECORD +154 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/entry_points.txt +0 -2
- pymodaq/extensions/bayesian/bayesian_optimisation.py +0 -685
- pymodaq/utils/leco/desktop.ini +0 -2
- pymodaq-5.0.17.dist-info/RECORD +0 -121
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/WHEEL +0 -0
- {pymodaq-5.0.17.dist-info → pymodaq-5.1.0.dist-info}/licenses/LICENSE +0 -0
pymodaq/dashboard.py
CHANGED
|
@@ -8,12 +8,19 @@ import logging
|
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from importlib import import_module
|
|
10
10
|
from packaging import version as version_mod
|
|
11
|
-
from typing import Tuple, List, Any, TYPE_CHECKING
|
|
11
|
+
from typing import Tuple, Union, List, Any, TYPE_CHECKING, Sequence
|
|
12
|
+
import argparse
|
|
12
13
|
|
|
13
14
|
|
|
14
15
|
from qtpy import QtGui, QtWidgets, QtCore
|
|
15
|
-
from qtpy.QtCore import Qt,
|
|
16
|
-
from qtpy.QtWidgets import
|
|
16
|
+
from qtpy.QtCore import Qt, QThread, Signal, QSize
|
|
17
|
+
from qtpy.QtWidgets import (
|
|
18
|
+
QTableWidget,
|
|
19
|
+
QTableWidgetItem,
|
|
20
|
+
QLabel,
|
|
21
|
+
QDialogButtonBox,
|
|
22
|
+
QMessageBox,
|
|
23
|
+
)
|
|
17
24
|
from time import perf_counter
|
|
18
25
|
import numpy as np
|
|
19
26
|
|
|
@@ -45,12 +52,17 @@ from pymodaq.utils import config as config_mod_pymodaq
|
|
|
45
52
|
|
|
46
53
|
from pymodaq.control_modules.daq_move import DAQ_Move
|
|
47
54
|
from pymodaq.control_modules.daq_viewer import DAQ_Viewer
|
|
55
|
+
from pymodaq.control_modules.daq_move_ui.factory import ActuatorUIFactory
|
|
48
56
|
from pymodaq_gui.utils.splash import get_splash_sc
|
|
49
|
-
|
|
50
57
|
from pymodaq import extensions as extmod
|
|
58
|
+
from pymodaq.utils.config import Config as ControlModulesConfig
|
|
59
|
+
|
|
51
60
|
|
|
52
61
|
logger = set_logger(get_module_name(__file__))
|
|
53
|
-
|
|
62
|
+
|
|
63
|
+
config_utils = configmod.Config()
|
|
64
|
+
config = ControlModulesConfig()
|
|
65
|
+
|
|
54
66
|
|
|
55
67
|
get_instrument_plugins()
|
|
56
68
|
extensions = extmod.get_extensions()
|
|
@@ -72,11 +84,13 @@ class ManagerEnums(BaseEnum):
|
|
|
72
84
|
overshoot = 2
|
|
73
85
|
roi = 3
|
|
74
86
|
|
|
87
|
+
|
|
75
88
|
class PymodaqUpdateTableWidget(QTableWidget):
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
89
|
+
"""
|
|
90
|
+
A class to represent PyMoDAQ and its subpackages'
|
|
91
|
+
available updates as a table.
|
|
92
|
+
"""
|
|
93
|
+
|
|
80
94
|
def __init__(self):
|
|
81
95
|
super().__init__()
|
|
82
96
|
self._row = 0
|
|
@@ -84,7 +98,7 @@ class PymodaqUpdateTableWidget(QTableWidget):
|
|
|
84
98
|
def setHorizontalHeaderLabels(self, labels):
|
|
85
99
|
super().setHorizontalHeaderLabels(labels)
|
|
86
100
|
self.setColumnCount(len(labels))
|
|
87
|
-
|
|
101
|
+
|
|
88
102
|
def append_row(self, package, current_version, available_version):
|
|
89
103
|
# Add labels
|
|
90
104
|
self.setItem(self._row, 0, QTableWidgetItem(str(package)))
|
|
@@ -96,48 +110,97 @@ class PymodaqUpdateTableWidget(QTableWidget):
|
|
|
96
110
|
def sizeHint(self):
|
|
97
111
|
self.resizeColumnsToContents()
|
|
98
112
|
self.resizeRowsToContents()
|
|
99
|
-
|
|
113
|
+
|
|
100
114
|
# Compute the size to adapt the window (header + borders + sum of all the elements)
|
|
101
|
-
width
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
115
|
+
width = (
|
|
116
|
+
self.verticalHeader().width()
|
|
117
|
+
+ self.frameWidth() * 2
|
|
118
|
+
+ sum([self.columnWidth(i) for i in range(self.columnCount())])
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
height = (
|
|
122
|
+
self.horizontalHeader().height()
|
|
123
|
+
+ self.frameWidth() * 2
|
|
124
|
+
+ sum([self.rowHeight(i) for i in range(self.rowCount())])
|
|
125
|
+
)
|
|
108
126
|
|
|
109
127
|
return QSize(width, height)
|
|
110
128
|
|
|
129
|
+
|
|
111
130
|
class DashBoard(CustomApp):
|
|
112
131
|
"""
|
|
113
|
-
Main class initializing a DashBoard interface to display det and move modules and logger
|
|
132
|
+
Main class initializing a DashBoard interface to display det and move modules and logger"""
|
|
133
|
+
|
|
114
134
|
status_signal = Signal(str)
|
|
115
135
|
preset_loaded_signal = Signal(bool)
|
|
116
136
|
new_preset_created = Signal()
|
|
117
137
|
|
|
118
|
-
settings_name =
|
|
138
|
+
settings_name = "dashboard_settings"
|
|
119
139
|
_splash_sc = None
|
|
120
140
|
|
|
121
141
|
params = [
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
142
|
+
{
|
|
143
|
+
"title": "Log level",
|
|
144
|
+
"name": "log_level",
|
|
145
|
+
"type": "list",
|
|
146
|
+
"value": config_utils("general", "debug_levels")[0],
|
|
147
|
+
"limits": config_utils("general", "debug_levels"),
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
"title": "Loaded presets",
|
|
151
|
+
"name": "loaded_files",
|
|
152
|
+
"type": "group",
|
|
153
|
+
"children": [
|
|
154
|
+
{
|
|
155
|
+
"title": "Preset file",
|
|
156
|
+
"name": "preset_file",
|
|
157
|
+
"type": "str",
|
|
158
|
+
"value": "",
|
|
159
|
+
"readonly": True,
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
"title": "Overshoot file",
|
|
163
|
+
"name": "overshoot_file",
|
|
164
|
+
"type": "str",
|
|
165
|
+
"value": "",
|
|
166
|
+
"readonly": True,
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"title": "Layout file",
|
|
170
|
+
"name": "layout_file",
|
|
171
|
+
"type": "str",
|
|
172
|
+
"value": "",
|
|
173
|
+
"readonly": True,
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"title": "ROI file",
|
|
177
|
+
"name": "roi_file",
|
|
178
|
+
"type": "str",
|
|
179
|
+
"value": "",
|
|
180
|
+
"readonly": True,
|
|
181
|
+
},
|
|
182
|
+
{
|
|
183
|
+
"title": "Remote file",
|
|
184
|
+
"name": "remote_file",
|
|
185
|
+
"type": "str",
|
|
186
|
+
"value": "",
|
|
187
|
+
"readonly": True,
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
"title": "Actuators Init.",
|
|
193
|
+
"name": "actuators",
|
|
194
|
+
"type": "group",
|
|
195
|
+
"children": [],
|
|
196
|
+
},
|
|
197
|
+
{
|
|
198
|
+
"title": "Detectors Init.",
|
|
199
|
+
"name": "detectors",
|
|
200
|
+
"type": "group",
|
|
201
|
+
"children": [],
|
|
202
|
+
},
|
|
203
|
+
]
|
|
141
204
|
|
|
142
205
|
def __init__(self, dockarea):
|
|
143
206
|
"""
|
|
@@ -146,10 +209,10 @@ class DashBoard(CustomApp):
|
|
|
146
209
|
----------
|
|
147
210
|
parent: (dockarea) instance of the modified pyqtgraph Dockarea (see daq_utils)
|
|
148
211
|
"""
|
|
149
|
-
|
|
212
|
+
|
|
150
213
|
super().__init__(dockarea)
|
|
151
214
|
|
|
152
|
-
logger.info(
|
|
215
|
+
logger.info("Initializing Dashboard")
|
|
153
216
|
self.extra_params = []
|
|
154
217
|
self.preset_path = preset_path
|
|
155
218
|
self.wait_time = 1000
|
|
@@ -164,7 +227,7 @@ class DashBoard(CustomApp):
|
|
|
164
227
|
|
|
165
228
|
self.dockarea.dock_signal.connect(self.save_layout_state_auto)
|
|
166
229
|
|
|
167
|
-
self.title =
|
|
230
|
+
self.title = ""
|
|
168
231
|
|
|
169
232
|
self.overshoot_manager = None
|
|
170
233
|
self.preset_manager = None
|
|
@@ -183,22 +246,23 @@ class DashBoard(CustomApp):
|
|
|
183
246
|
self.actuators_modules = []
|
|
184
247
|
self.detector_modules = []
|
|
185
248
|
|
|
249
|
+
self.compact_actuator_dock: Dock = None
|
|
250
|
+
|
|
186
251
|
self.setup_ui()
|
|
187
252
|
|
|
188
253
|
self.mainwindow.setVisible(True)
|
|
189
254
|
|
|
190
|
-
logger.info(
|
|
255
|
+
logger.info("Dashboard Initialized")
|
|
191
256
|
|
|
192
|
-
if
|
|
257
|
+
if config_utils("general", "check_version"):
|
|
193
258
|
if self.check_update(show=False):
|
|
194
259
|
sys.exit(0)
|
|
195
260
|
|
|
196
|
-
@classmethod
|
|
197
261
|
@property
|
|
198
|
-
def splash_sc(
|
|
199
|
-
if
|
|
200
|
-
|
|
201
|
-
return
|
|
262
|
+
def splash_sc(self) -> QtWidgets.QSplashScreen:
|
|
263
|
+
if not hasattr(self, "_splash_sc") or self._splash_sc is None:
|
|
264
|
+
self._splash_sc = get_splash_sc()
|
|
265
|
+
return self._splash_sc
|
|
202
266
|
|
|
203
267
|
def set_preset_path(self, path):
|
|
204
268
|
self.preset_path = path
|
|
@@ -207,47 +271,176 @@ class DashBoard(CustomApp):
|
|
|
207
271
|
|
|
208
272
|
def set_extra_preset_params(self, params, param_options=[]):
|
|
209
273
|
self.extra_params = params
|
|
210
|
-
self.preset_manager = PresetManager(
|
|
211
|
-
|
|
274
|
+
self.preset_manager = PresetManager(
|
|
275
|
+
path=self.preset_path, extra_params=params, param_options=param_options
|
|
276
|
+
)
|
|
212
277
|
|
|
213
278
|
def add_status(self, txt):
|
|
214
279
|
"""
|
|
215
|
-
|
|
216
|
-
|
|
280
|
+
Add the QListWisgetItem initialized with txt informations to the User Interface
|
|
281
|
+
logger_list and to the save_parameters.logger array.
|
|
217
282
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
283
|
+
=============== =========== ======================
|
|
284
|
+
**Parameters** **Type** **Description**
|
|
285
|
+
*txt* string the log info to add.
|
|
286
|
+
=============== =========== ======================
|
|
222
287
|
"""
|
|
223
288
|
try:
|
|
224
289
|
now = datetime.datetime.now()
|
|
225
|
-
new_item = QtWidgets.QListWidgetItem(
|
|
290
|
+
new_item = QtWidgets.QListWidgetItem(
|
|
291
|
+
now.strftime("%Y/%m/%d %H:%M:%S") + ": " + txt
|
|
292
|
+
)
|
|
226
293
|
self.logger_list.addItem(new_item)
|
|
227
294
|
|
|
228
295
|
except Exception as e:
|
|
229
296
|
logger.exception(str(e))
|
|
230
297
|
|
|
298
|
+
def remove_detectors(self, detector_modules: List[DAQ_Viewer] = None):
|
|
299
|
+
"""
|
|
300
|
+
Remove the given list of detectors from the dashboard.
|
|
301
|
+
Parameters
|
|
302
|
+
----------
|
|
303
|
+
detector_modules: List[DAQ_Viewer]
|
|
304
|
+
List of DAQ_Viewer instances to be removed.
|
|
305
|
+
"""
|
|
306
|
+
if detector_modules is None:
|
|
307
|
+
detector_modules = []
|
|
308
|
+
try:
|
|
309
|
+
for detector_module in detector_modules:
|
|
310
|
+
if detector_module in self.detector_modules:
|
|
311
|
+
self.detector_modules.remove(detector_module)
|
|
312
|
+
detector_module.quit_fun()
|
|
313
|
+
dock = self.dockarea.docks.get(
|
|
314
|
+
f"{detector_module.title} settings", None
|
|
315
|
+
)
|
|
316
|
+
if dock:
|
|
317
|
+
dock.close()
|
|
318
|
+
dock = self.dockarea.docks.get(f"{detector_module.title} viewer", None)
|
|
319
|
+
if dock:
|
|
320
|
+
dock.close()
|
|
321
|
+
self.update_module_manager()
|
|
322
|
+
except Exception as e:
|
|
323
|
+
logger.exception(str(e))
|
|
324
|
+
|
|
325
|
+
def remove_actuators(self, actuator_modules: List[DAQ_Move] = None):
|
|
326
|
+
"""
|
|
327
|
+
Remove the given list of actuators from the dashboard.
|
|
328
|
+
Parameters
|
|
329
|
+
----------
|
|
330
|
+
actuator_modules: List[DAQ_Move]
|
|
331
|
+
List of DAQ_Move instances to be removed.
|
|
332
|
+
"""
|
|
333
|
+
if actuator_modules is None:
|
|
334
|
+
actuator_modules = []
|
|
335
|
+
try:
|
|
336
|
+
for actuator_module in actuator_modules:
|
|
337
|
+
if actuator_module in self.actuators_modules:
|
|
338
|
+
self.actuators_modules.remove(actuator_module)
|
|
339
|
+
actuator_module.quit_fun()
|
|
340
|
+
dock = self.dockarea.docks.get(actuator_module.title, None)
|
|
341
|
+
if dock:
|
|
342
|
+
dock.close()
|
|
343
|
+
self.update_module_manager()
|
|
344
|
+
except Exception as e:
|
|
345
|
+
logger.exception(str(e))
|
|
346
|
+
|
|
347
|
+
def get_docks_from_modules(
|
|
348
|
+
self, modules: Sequence[Union["DAQ_Move", "DAQ_Viewer"]]
|
|
349
|
+
) -> List[Dock]:
|
|
350
|
+
"""
|
|
351
|
+
Get a list of Dock instances from the given modules.
|
|
352
|
+
|
|
353
|
+
Parameters
|
|
354
|
+
----------
|
|
355
|
+
modules: Sequence[DAQ_Move/DAQ_Viewer]
|
|
356
|
+
Sequence of DAQ_Move or DAQ_Viewer instances.
|
|
357
|
+
|
|
358
|
+
Returns
|
|
359
|
+
-------
|
|
360
|
+
List[Dock]
|
|
361
|
+
List of Dock instances corresponding to the given modules.
|
|
362
|
+
"""
|
|
363
|
+
docks = []
|
|
364
|
+
for module in modules:
|
|
365
|
+
if hasattr(module, "dock"):
|
|
366
|
+
docks.append(module.dock)
|
|
367
|
+
return docks
|
|
368
|
+
|
|
369
|
+
def remove_modules(
|
|
370
|
+
self, modules: List[Union["DAQ_Move", "DAQ_Viewer", "str"]] = None
|
|
371
|
+
):
|
|
372
|
+
"""
|
|
373
|
+
Remove the given list of actuators/detectors from the dashboard.
|
|
374
|
+
|
|
375
|
+
Parameters
|
|
376
|
+
----------
|
|
377
|
+
modules: List[DAQ_Move/DAQ_Viewer]
|
|
378
|
+
List of DAQ_Move/DAQ_Viewer instances to be removed.
|
|
379
|
+
"""
|
|
380
|
+
if modules is None:
|
|
381
|
+
modules = []
|
|
382
|
+
try:
|
|
383
|
+
actuators_modules = []
|
|
384
|
+
detector_modules = []
|
|
385
|
+
for module in modules:
|
|
386
|
+
if isinstance(
|
|
387
|
+
module, DAQ_Move
|
|
388
|
+
): # Test if module is an instance of DAQ_Move
|
|
389
|
+
actuators_modules.append(module)
|
|
390
|
+
elif isinstance(
|
|
391
|
+
module, DAQ_Viewer
|
|
392
|
+
): # Test if module is an instance of DAQ_Viewer
|
|
393
|
+
detector_modules.append(module)
|
|
394
|
+
if isinstance(
|
|
395
|
+
module, str
|
|
396
|
+
): # Test if module is a string (name of the module)
|
|
397
|
+
actuators_modules.extend(
|
|
398
|
+
self.modules_manager.get_mods_from_names(
|
|
399
|
+
[
|
|
400
|
+
module,
|
|
401
|
+
],
|
|
402
|
+
"act",
|
|
403
|
+
) # For actuators
|
|
404
|
+
)
|
|
405
|
+
detector_modules.extend(
|
|
406
|
+
self.modules_manager.get_mods_from_names(
|
|
407
|
+
[
|
|
408
|
+
module,
|
|
409
|
+
],
|
|
410
|
+
"det",
|
|
411
|
+
) # For detectors
|
|
412
|
+
)
|
|
413
|
+
if (hasattr(self, "actuators_modules")) & (
|
|
414
|
+
self.actuators_modules is not None
|
|
415
|
+
): # Remove actuators
|
|
416
|
+
self.remove_actuators(actuators_modules)
|
|
417
|
+
if (hasattr(self, "detector_modules")) & (
|
|
418
|
+
self.detector_modules is not None
|
|
419
|
+
): # Remove detectors
|
|
420
|
+
self.remove_detectors(detector_modules)
|
|
421
|
+
except Exception as e:
|
|
422
|
+
logger.exception(str(e))
|
|
423
|
+
|
|
231
424
|
def clear_move_det_controllers(self):
|
|
232
425
|
"""
|
|
233
|
-
|
|
426
|
+
Remove all docks containing Moves or Viewers.
|
|
234
427
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
428
|
+
See Also
|
|
429
|
+
--------
|
|
430
|
+
quit_fun, update_status
|
|
238
431
|
"""
|
|
239
432
|
try:
|
|
240
433
|
# remove all docks containing Moves or Viewers
|
|
241
|
-
if hasattr(self,
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
434
|
+
if hasattr(self, "actuators_modules") & (
|
|
435
|
+
self.actuators_modules is not None
|
|
436
|
+
):
|
|
437
|
+
for module in self.actuators_modules:
|
|
438
|
+
module.quit_fun()
|
|
245
439
|
self.actuators_modules = []
|
|
246
440
|
|
|
247
|
-
if hasattr(self,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
module.quit_fun()
|
|
441
|
+
if hasattr(self, "detector_modules") & (self.detector_modules is not None):
|
|
442
|
+
for module in self.detector_modules:
|
|
443
|
+
module.quit_fun()
|
|
251
444
|
self.detector_modules = []
|
|
252
445
|
except Exception as e:
|
|
253
446
|
logger.exception(str(e))
|
|
@@ -256,11 +449,18 @@ class DashBoard(CustomApp):
|
|
|
256
449
|
if win is None:
|
|
257
450
|
win = QtWidgets.QMainWindow()
|
|
258
451
|
area = DockArea()
|
|
452
|
+
win.setWindowFlags(
|
|
453
|
+
Qt.Window
|
|
454
|
+
| Qt.WindowTitleHint
|
|
455
|
+
| Qt.WindowMinimizeButtonHint
|
|
456
|
+
| Qt.WindowMaximizeButtonHint
|
|
457
|
+
)
|
|
259
458
|
win.setCentralWidget(area)
|
|
459
|
+
win.setWindowTitle("Scanner")
|
|
260
460
|
self.scan_module = extmod.DAQScan(dockarea=area, dashboard=self)
|
|
261
|
-
self.extensions[
|
|
461
|
+
self.extensions["DAQScan"] = self.scan_module
|
|
262
462
|
self.scan_module.status_signal.connect(self.add_status)
|
|
263
|
-
#win.setWindowTitle("DAQScan")
|
|
463
|
+
# win.setWindowTitle("DAQScan")
|
|
264
464
|
win.show()
|
|
265
465
|
return self.scan_module
|
|
266
466
|
|
|
@@ -268,9 +468,16 @@ class DashBoard(CustomApp):
|
|
|
268
468
|
if win is None:
|
|
269
469
|
win = QtWidgets.QMainWindow()
|
|
270
470
|
area = DockArea()
|
|
471
|
+
win.setWindowFlags(
|
|
472
|
+
Qt.Window
|
|
473
|
+
| Qt.WindowTitleHint
|
|
474
|
+
| Qt.WindowMinimizeButtonHint
|
|
475
|
+
| Qt.WindowMaximizeButtonHint
|
|
476
|
+
)
|
|
271
477
|
win.setCentralWidget(area)
|
|
478
|
+
win.setWindowTitle("Logger")
|
|
272
479
|
self.log_module = extmod.DAQ_Logger(dockarea=area, dashboard=self)
|
|
273
|
-
self.extensions[
|
|
480
|
+
self.extensions["DAQ_Logger"] = self.log_module
|
|
274
481
|
self.log_module.status_signal.connect(self.add_status)
|
|
275
482
|
win.show()
|
|
276
483
|
return self.log_module
|
|
@@ -280,22 +487,30 @@ class DashBoard(CustomApp):
|
|
|
280
487
|
self.pid_window = QtWidgets.QMainWindow()
|
|
281
488
|
else:
|
|
282
489
|
self.pid_window = win
|
|
490
|
+
self.pid_window.setWindowFlags(
|
|
491
|
+
Qt.Window
|
|
492
|
+
| Qt.WindowTitleHint
|
|
493
|
+
| Qt.WindowMinimizeButtonHint
|
|
494
|
+
| Qt.WindowMaximizeButtonHint
|
|
495
|
+
)
|
|
283
496
|
dockarea = DockArea()
|
|
284
497
|
self.pid_window.setCentralWidget(dockarea)
|
|
285
|
-
self.pid_window.setWindowTitle(
|
|
498
|
+
self.pid_window.setWindowTitle("PID Controller")
|
|
286
499
|
self.pid_module = extmod.DAQ_PID(dockarea=dockarea, dashboard=self)
|
|
287
|
-
self.extensions[
|
|
500
|
+
self.extensions["DAQ_PID"] = self.pid_module
|
|
288
501
|
self.pid_window.show()
|
|
289
502
|
return self.pid_module
|
|
290
503
|
|
|
291
504
|
def load_console(self):
|
|
292
|
-
dock_console = Dock(
|
|
293
|
-
self.dockarea.addDock(dock_console,
|
|
294
|
-
qtconsole = extmod.QtConsole(
|
|
295
|
-
|
|
296
|
-
|
|
505
|
+
dock_console = Dock("QTConsole")
|
|
506
|
+
self.dockarea.addDock(dock_console, "bottom")
|
|
507
|
+
qtconsole = extmod.QtConsole(
|
|
508
|
+
style_sheet=config_utils("style", "syntax_highlighting"),
|
|
509
|
+
syntax_style=config_utils("style", "syntax_highlighting"),
|
|
510
|
+
custom_banner=extmod.console.BANNER,
|
|
511
|
+
)
|
|
297
512
|
dock_console.addWidget(qtconsole)
|
|
298
|
-
self.extensions[
|
|
513
|
+
self.extensions["qtconsole"] = qtconsole
|
|
299
514
|
|
|
300
515
|
qtconsole.push_variables(dict(dashboard=self, mods=self.modules_manager, np=np))
|
|
301
516
|
|
|
@@ -306,19 +521,108 @@ class DashBoard(CustomApp):
|
|
|
306
521
|
self.bayesian_window = QtWidgets.QMainWindow()
|
|
307
522
|
else:
|
|
308
523
|
self.bayesian_window = win
|
|
524
|
+
self.bayesian_window.setWindowFlags(
|
|
525
|
+
Qt.Window
|
|
526
|
+
| Qt.WindowTitleHint
|
|
527
|
+
| Qt.WindowMinimizeButtonHint
|
|
528
|
+
| Qt.WindowMaximizeButtonHint
|
|
529
|
+
)
|
|
309
530
|
dockarea = DockArea()
|
|
310
531
|
self.bayesian_window.setCentralWidget(dockarea)
|
|
311
|
-
self.bayesian_window.setWindowTitle(
|
|
312
|
-
self.bayesian_module = extmod.
|
|
313
|
-
|
|
314
|
-
|
|
532
|
+
self.bayesian_window.setWindowTitle("Bayesian Optimiser")
|
|
533
|
+
self.bayesian_module = extmod.BayesianOptimization(
|
|
534
|
+
dockarea=dockarea, dashboard=self
|
|
535
|
+
)
|
|
536
|
+
self.extensions["bayesian"] = self.bayesian_module
|
|
537
|
+
|
|
538
|
+
if self.bayesian_module.validate_config():
|
|
539
|
+
self.bayesian_window.show()
|
|
540
|
+
else:
|
|
541
|
+
messagebox(
|
|
542
|
+
severity="critical",
|
|
543
|
+
title="Bayesian Optimisation error",
|
|
544
|
+
text=f"""
|
|
545
|
+
<p>Saved Bayesian Optimisation configuration file is not compatible anymore.</p>
|
|
546
|
+
<p>Please delete the file at <b>{self.bayesian_module.config_path}</b>.</p>
|
|
547
|
+
""",
|
|
548
|
+
)
|
|
549
|
+
self.bayesian_module.quit()
|
|
315
550
|
return self.bayesian_module
|
|
316
551
|
|
|
552
|
+
def load_adaptive(self, win=None):
|
|
553
|
+
if win is None:
|
|
554
|
+
self.adaptive_window = QtWidgets.QMainWindow()
|
|
555
|
+
else:
|
|
556
|
+
self.adaptive_window = win
|
|
557
|
+
self.adaptive_window.setWindowFlags(
|
|
558
|
+
Qt.Window
|
|
559
|
+
| Qt.WindowTitleHint
|
|
560
|
+
| Qt.WindowMinimizeButtonHint
|
|
561
|
+
| Qt.WindowMaximizeButtonHint
|
|
562
|
+
)
|
|
563
|
+
dockarea = DockArea()
|
|
564
|
+
self.adaptive_window.setCentralWidget(dockarea)
|
|
565
|
+
self.adaptive_window.setWindowTitle("Adaptive Scan")
|
|
566
|
+
self.adaptive_module = extmod.AdaptiveOptimisation(
|
|
567
|
+
dockarea=dockarea, dashboard=self
|
|
568
|
+
)
|
|
569
|
+
self.extensions["adaptive"] = self.adaptive_module
|
|
570
|
+
|
|
571
|
+
if self.adaptive_module.validate_config():
|
|
572
|
+
self.adaptive_window.show()
|
|
573
|
+
else:
|
|
574
|
+
messagebox(
|
|
575
|
+
severity="critical",
|
|
576
|
+
title="Adaptive Optimisation error",
|
|
577
|
+
text=f"""
|
|
578
|
+
<p>Saved Adaptive Optimisation configuration file is not compatible anymore.</p>
|
|
579
|
+
<p>Please delete the file at <b>{self.adaptive_module.config_path}</b>.</p>
|
|
580
|
+
""",
|
|
581
|
+
)
|
|
582
|
+
self.adaptive_module.quit()
|
|
583
|
+
return self.adaptive_module
|
|
584
|
+
|
|
585
|
+
def load_datamixer(self, win=None):
|
|
586
|
+
if win is None:
|
|
587
|
+
self.datamixer_window = QtWidgets.QMainWindow()
|
|
588
|
+
else:
|
|
589
|
+
self.datamixer_window = win
|
|
590
|
+
self.datamixer_window.setWindowFlags(
|
|
591
|
+
Qt.Window
|
|
592
|
+
| Qt.WindowTitleHint
|
|
593
|
+
| Qt.WindowMinimizeButtonHint
|
|
594
|
+
| Qt.WindowMaximizeButtonHint
|
|
595
|
+
)
|
|
596
|
+
dockarea = DockArea()
|
|
597
|
+
self.datamixer_window.setCentralWidget(dockarea)
|
|
598
|
+
self.datamixer_window.setWindowTitle("DataMixer")
|
|
599
|
+
self.datamixer_module = extmod.DataMixer(
|
|
600
|
+
parent=dockarea, dashboard=self
|
|
601
|
+
)
|
|
602
|
+
self.extensions["datamixer"] = self.datamixer_module
|
|
603
|
+
|
|
604
|
+
if self.datamixer_module.validate_config():
|
|
605
|
+
self.datamixer_window.show()
|
|
606
|
+
else:
|
|
607
|
+
messagebox(
|
|
608
|
+
severity="critical",
|
|
609
|
+
title="DataMixer error",
|
|
610
|
+
text=f"""
|
|
611
|
+
<p>Saved DataMixer configuration file is not compatible anymore.</p>
|
|
612
|
+
<p>Please delete the file at <b>{self.datamixer_module.config_path}</b>.</p>
|
|
613
|
+
""",
|
|
614
|
+
)
|
|
615
|
+
self.datamixer_module.quit()
|
|
616
|
+
return self.datamixer_module
|
|
617
|
+
|
|
618
|
+
|
|
317
619
|
def load_extension_from_name(self, name: str) -> dict:
|
|
318
|
-
return self.load_extensions_module(
|
|
620
|
+
return self.load_extensions_module(
|
|
621
|
+
find_dict_in_list_from_key_val(extensions, "name", name)
|
|
622
|
+
)
|
|
319
623
|
|
|
320
624
|
def load_extensions_module(self, ext: dict):
|
|
321
|
-
"""
|
|
625
|
+
"""Init and load an extension from a plugin package
|
|
322
626
|
|
|
323
627
|
ext: dict
|
|
324
628
|
dictionary containing info on the extension plugin package and class to be loaded,
|
|
@@ -339,266 +643,395 @@ class DashBoard(CustomApp):
|
|
|
339
643
|
area = DockArea()
|
|
340
644
|
self.extension_windows[-1].setCentralWidget(area)
|
|
341
645
|
self.extension_windows[-1].resize(1000, 500)
|
|
342
|
-
self.extension_windows[-1].setWindowTitle(ext[
|
|
646
|
+
self.extension_windows[-1].setWindowTitle(ext["name"])
|
|
343
647
|
module = import_module(f"{ext['pkg']}.extensions.{ext['module']}")
|
|
344
|
-
klass = getattr(module, ext[
|
|
345
|
-
self.extensions[ext[
|
|
648
|
+
klass = getattr(module, ext["class_name"])
|
|
649
|
+
self.extensions[ext["class_name"]] = klass(area, dashboard=self)
|
|
346
650
|
self.extension_windows[-1].show()
|
|
347
|
-
return self.extensions[ext[
|
|
651
|
+
return self.extensions[ext["class_name"]]
|
|
348
652
|
|
|
349
653
|
def setup_actions(self):
|
|
350
|
-
self.add_action(
|
|
351
|
-
|
|
352
|
-
|
|
654
|
+
self.add_action(
|
|
655
|
+
"log", "Log File", "", "Show Log File in default editor", auto_toolbar=False
|
|
656
|
+
)
|
|
657
|
+
self.add_action("quit", "Quit", "close2", "Quit program")
|
|
353
658
|
self.toolbar.addSeparator()
|
|
354
|
-
self.add_action(
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
self.add_action(
|
|
377
|
-
|
|
659
|
+
self.add_action(
|
|
660
|
+
"config_utils",
|
|
661
|
+
"Utils Config.",
|
|
662
|
+
"tree",
|
|
663
|
+
tip="Show utility configuration file",
|
|
664
|
+
)
|
|
665
|
+
self.add_action(
|
|
666
|
+
"config",
|
|
667
|
+
"Controls/Extensions Config.",
|
|
668
|
+
"tree",
|
|
669
|
+
tip="Show Control Modules and Extensions configuration file",
|
|
670
|
+
)
|
|
671
|
+
self.add_action(
|
|
672
|
+
"restart", "Restart", "", "Restart the Dashboard", auto_toolbar=False
|
|
673
|
+
)
|
|
674
|
+
self.add_action(
|
|
675
|
+
"leco",
|
|
676
|
+
"Run Leco Coordinator",
|
|
677
|
+
"",
|
|
678
|
+
"Run a Coordinator on this localhost",
|
|
679
|
+
auto_toolbar=False,
|
|
680
|
+
)
|
|
681
|
+
self.add_action(
|
|
682
|
+
"load_layout",
|
|
683
|
+
"Load Layout",
|
|
684
|
+
"",
|
|
685
|
+
"Load the Saved Docks layout corresponding to the current preset",
|
|
686
|
+
auto_toolbar=False,
|
|
687
|
+
)
|
|
688
|
+
self.add_action(
|
|
689
|
+
"save_layout",
|
|
690
|
+
"Save Layout",
|
|
691
|
+
"",
|
|
692
|
+
"Save the Saved Docks layout corresponding to the current preset",
|
|
693
|
+
auto_toolbar=False,
|
|
694
|
+
)
|
|
695
|
+
self.add_action(
|
|
696
|
+
"log_window", "Show/hide log window", "", checkable=True, auto_toolbar=False
|
|
697
|
+
)
|
|
698
|
+
self.add_action(
|
|
699
|
+
"new_preset",
|
|
700
|
+
"New Preset",
|
|
701
|
+
"",
|
|
702
|
+
'Create a new experimental setup configuration file: a "preset"',
|
|
703
|
+
auto_toolbar=False,
|
|
704
|
+
)
|
|
705
|
+
self.add_action(
|
|
706
|
+
"modify_preset",
|
|
707
|
+
"Modify Preset",
|
|
708
|
+
"",
|
|
709
|
+
'Modify an existing experimental setup configuration file: a "preset"',
|
|
710
|
+
auto_toolbar=False,
|
|
711
|
+
)
|
|
712
|
+
|
|
713
|
+
self.add_widget(
|
|
714
|
+
"preset_list",
|
|
715
|
+
QtWidgets.QComboBox,
|
|
716
|
+
toolbar=self.toolbar,
|
|
717
|
+
signal_str="currentTextChanged",
|
|
718
|
+
slot=self.update_preset_action,
|
|
719
|
+
)
|
|
720
|
+
self.add_action("load_preset", "LOAD", "Open", tip="Load the selected Preset: ")
|
|
378
721
|
self.update_preset_action_list()
|
|
379
722
|
|
|
380
|
-
self.add_action(
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
for ind_file, file in enumerate(
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
self.add_action(
|
|
407
|
-
|
|
408
|
-
|
|
723
|
+
self.add_action(
|
|
724
|
+
"new_overshoot",
|
|
725
|
+
"New Overshoot",
|
|
726
|
+
"",
|
|
727
|
+
"Create a new experimental setup overshoot configuration file",
|
|
728
|
+
auto_toolbar=False,
|
|
729
|
+
)
|
|
730
|
+
self.add_action(
|
|
731
|
+
"modify_overshoot",
|
|
732
|
+
"Modify Overshoot",
|
|
733
|
+
"",
|
|
734
|
+
"Modify an existing experimental setup overshoot configuration file",
|
|
735
|
+
auto_toolbar=False,
|
|
736
|
+
)
|
|
737
|
+
|
|
738
|
+
for ind_file, file in enumerate(
|
|
739
|
+
config_mod_pymodaq.get_set_overshoot_path().iterdir()
|
|
740
|
+
):
|
|
741
|
+
if file.suffix == ".xml":
|
|
742
|
+
self.add_action(
|
|
743
|
+
self.get_action_from_file(file, ManagerEnums.overshoot),
|
|
744
|
+
file.stem,
|
|
745
|
+
auto_toolbar=False,
|
|
746
|
+
)
|
|
747
|
+
|
|
748
|
+
self.add_action("save_roi", "Save ROIs as a file", "", auto_toolbar=False)
|
|
749
|
+
self.add_action("modify_roi", "Modify ROI file", "", auto_toolbar=False)
|
|
750
|
+
|
|
751
|
+
for ind_file, file in enumerate(
|
|
752
|
+
config_mod_pymodaq.get_set_roi_path().iterdir()
|
|
753
|
+
):
|
|
754
|
+
if file.suffix == ".xml":
|
|
755
|
+
self.add_action(
|
|
756
|
+
self.get_action_from_file(file, ManagerEnums.roi),
|
|
757
|
+
file.stem,
|
|
758
|
+
"",
|
|
759
|
+
auto_toolbar=False,
|
|
760
|
+
)
|
|
761
|
+
|
|
762
|
+
self.add_action("new_remote", "Create New Remote", "", auto_toolbar=False)
|
|
763
|
+
self.add_action("modify_remote", "Modify Remote file", "", auto_toolbar=False)
|
|
764
|
+
for ind_file, file in enumerate(
|
|
765
|
+
config_mod_pymodaq.get_set_remote_path().iterdir()
|
|
766
|
+
):
|
|
767
|
+
if file.suffix == ".xml":
|
|
768
|
+
self.add_action(
|
|
769
|
+
self.get_action_from_file(file, ManagerEnums.remote),
|
|
770
|
+
file.stem,
|
|
771
|
+
"",
|
|
772
|
+
auto_toolbar=False,
|
|
773
|
+
)
|
|
774
|
+
self.add_action(
|
|
775
|
+
"activate_overshoot",
|
|
776
|
+
"Activate overshoot",
|
|
777
|
+
"Error",
|
|
778
|
+
tip="if activated, apply an overshoot if one is configured",
|
|
779
|
+
checkable=True,
|
|
780
|
+
enabled=False,
|
|
781
|
+
)
|
|
409
782
|
self.toolbar.addSeparator()
|
|
410
|
-
self.add_action(
|
|
411
|
-
|
|
412
|
-
|
|
783
|
+
self.add_action(
|
|
784
|
+
"do_scan",
|
|
785
|
+
"Do Scans",
|
|
786
|
+
"surfacePlot",
|
|
787
|
+
tip="Open the DAQ Scan extension to acquire data as a function of "
|
|
788
|
+
"one or more parameter",
|
|
789
|
+
)
|
|
413
790
|
self.toolbar.addSeparator()
|
|
414
|
-
self.add_action(
|
|
415
|
-
self.add_action(
|
|
416
|
-
self.add_action(
|
|
417
|
-
self.add_action(
|
|
418
|
-
|
|
419
|
-
self.add_action(
|
|
420
|
-
|
|
421
|
-
self.
|
|
422
|
-
self.add_action(
|
|
791
|
+
self.add_action("do_log", "Log data", "", auto_toolbar=False)
|
|
792
|
+
self.add_action("do_pid", "PID module", auto_toolbar=False)
|
|
793
|
+
self.add_action("console", "IPython Console", auto_toolbar=False)
|
|
794
|
+
self.add_action("bayesian", "Bayesian Optimisation", auto_toolbar=False)
|
|
795
|
+
self.add_action("adaptive", "Adaptive Scan", auto_toolbar=False)
|
|
796
|
+
self.add_action("datamixer", "DataMixer", auto_toolbar=False)
|
|
797
|
+
|
|
798
|
+
self.add_action("about", "About", "information2")
|
|
799
|
+
self.add_action("help", "Help", "help1")
|
|
800
|
+
self.get_action("help").setShortcut(QtGui.QKeySequence("F1"))
|
|
801
|
+
self.add_action("check_update", "Check Updates", "", auto_toolbar=False)
|
|
423
802
|
self.toolbar.addSeparator()
|
|
424
|
-
self.add_action(
|
|
803
|
+
self.add_action("plugin_manager", "Plugin Manager", "")
|
|
425
804
|
|
|
426
805
|
def update_preset_action_list(self):
|
|
427
806
|
presets = []
|
|
428
|
-
self.get_action(
|
|
807
|
+
self.get_action("preset_list").clear()
|
|
429
808
|
for ind_file, file in enumerate(self.preset_path.iterdir()):
|
|
430
|
-
if file.suffix ==
|
|
809
|
+
if file.suffix == ".xml":
|
|
431
810
|
filestem = file.stem
|
|
432
|
-
if not self.has_action(
|
|
433
|
-
self.
|
|
434
|
-
|
|
435
|
-
|
|
811
|
+
if not self.has_action(
|
|
812
|
+
self.get_action_from_file(file, ManagerEnums.preset)
|
|
813
|
+
):
|
|
814
|
+
self.add_action(
|
|
815
|
+
self.get_action_from_file(file, ManagerEnums.preset),
|
|
816
|
+
filestem,
|
|
817
|
+
"",
|
|
818
|
+
f"Load the {filestem}.xml preset",
|
|
819
|
+
auto_toolbar=False,
|
|
820
|
+
)
|
|
436
821
|
presets.append(filestem)
|
|
437
822
|
|
|
438
|
-
self.get_action(
|
|
823
|
+
self.get_action("preset_list").addItems(presets)
|
|
439
824
|
|
|
440
825
|
def update_preset_action(self, preset_name: str):
|
|
441
|
-
self.get_action(
|
|
826
|
+
self.get_action("load_preset").setToolTip(
|
|
827
|
+
f"Load the {preset_name}.xml preset file!"
|
|
828
|
+
)
|
|
442
829
|
|
|
443
830
|
def connect_things(self):
|
|
444
831
|
self.status_signal[str].connect(self.add_status)
|
|
445
|
-
self.connect_action(
|
|
446
|
-
self.connect_action(
|
|
447
|
-
self.connect_action(
|
|
448
|
-
self.connect_action(
|
|
449
|
-
self.connect_action(
|
|
450
|
-
self.connect_action(
|
|
451
|
-
self.connect_action(
|
|
452
|
-
self.connect_action(
|
|
453
|
-
self.connect_action(
|
|
454
|
-
self.connect_action(
|
|
832
|
+
self.connect_action("log", self.show_log)
|
|
833
|
+
self.connect_action("config_utils", lambda: self.show_config(config_utils))
|
|
834
|
+
self.connect_action("config", lambda: self.show_config(config))
|
|
835
|
+
self.connect_action("quit", self.quit_fun)
|
|
836
|
+
self.connect_action("restart", self.restart_fun)
|
|
837
|
+
self.connect_action("leco", start_coordinator)
|
|
838
|
+
self.connect_action("load_layout", self.load_layout_state)
|
|
839
|
+
self.connect_action("save_layout", self.save_layout_state)
|
|
840
|
+
self.connect_action("log_window", self.logger_dock.setVisible)
|
|
841
|
+
self.connect_action("new_preset", self.create_preset)
|
|
842
|
+
self.connect_action("modify_preset", self.modify_preset)
|
|
455
843
|
|
|
456
844
|
for ind_file, file in enumerate(self.preset_path.iterdir()):
|
|
457
|
-
if file.suffix ==
|
|
458
|
-
self.connect_action(
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
845
|
+
if file.suffix == ".xml":
|
|
846
|
+
self.connect_action(
|
|
847
|
+
self.get_action_from_file(file, ManagerEnums.preset),
|
|
848
|
+
self.create_menu_slot(self.preset_path.joinpath(file)),
|
|
849
|
+
)
|
|
850
|
+
self.connect_action(
|
|
851
|
+
"load_preset",
|
|
852
|
+
lambda: self.set_preset_mode(
|
|
853
|
+
self.preset_path.joinpath(
|
|
854
|
+
f"{self.get_action('preset_list').currentText()}.xml"
|
|
855
|
+
)
|
|
856
|
+
),
|
|
857
|
+
)
|
|
858
|
+
self.connect_action("new_overshoot", self.create_overshoot)
|
|
859
|
+
self.connect_action("modify_overshoot", self.modify_overshoot)
|
|
860
|
+
self.connect_action("activate_overshoot", self.activate_overshoot)
|
|
861
|
+
|
|
862
|
+
for ind_file, file in enumerate(
|
|
863
|
+
config_mod_pymodaq.get_set_overshoot_path().iterdir()
|
|
864
|
+
):
|
|
865
|
+
if file.suffix == ".xml":
|
|
866
|
+
self.connect_action(
|
|
867
|
+
self.get_action_from_file(file, ManagerEnums.overshoot),
|
|
471
868
|
self.create_menu_slot_over(
|
|
472
|
-
config_mod_pymodaq.get_set_overshoot_path().joinpath(file)
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
869
|
+
config_mod_pymodaq.get_set_overshoot_path().joinpath(file)
|
|
870
|
+
),
|
|
871
|
+
)
|
|
872
|
+
|
|
873
|
+
self.connect_action("save_roi", self.create_roi_file)
|
|
874
|
+
self.connect_action("modify_roi", self.modify_roi)
|
|
875
|
+
|
|
876
|
+
for ind_file, file in enumerate(
|
|
877
|
+
config_mod_pymodaq.get_set_roi_path().iterdir()
|
|
878
|
+
):
|
|
879
|
+
if file.suffix == ".xml":
|
|
880
|
+
self.connect_action(
|
|
881
|
+
self.get_action_from_file(file, ManagerEnums.roi),
|
|
882
|
+
self.create_menu_slot_roi(
|
|
883
|
+
config_mod_pymodaq.get_set_roi_path().joinpath(file)
|
|
884
|
+
),
|
|
885
|
+
)
|
|
886
|
+
|
|
887
|
+
self.connect_action("new_remote", self.create_remote)
|
|
888
|
+
self.connect_action("modify_remote", self.modify_remote)
|
|
889
|
+
for ind_file, file in enumerate(
|
|
890
|
+
config_mod_pymodaq.get_set_remote_path().iterdir()
|
|
891
|
+
):
|
|
892
|
+
if file.suffix == ".xml":
|
|
893
|
+
self.connect_action(
|
|
894
|
+
self.get_action_from_file(file, ManagerEnums.remote),
|
|
487
895
|
self.create_menu_slot_remote(
|
|
488
|
-
config_mod_pymodaq.get_set_remote_path().joinpath(file)
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
self.connect_action(
|
|
493
|
-
self.connect_action(
|
|
494
|
-
self.connect_action(
|
|
495
|
-
|
|
496
|
-
self.connect_action(
|
|
497
|
-
self.connect_action(
|
|
498
|
-
self.connect_action(
|
|
499
|
-
|
|
896
|
+
config_mod_pymodaq.get_set_remote_path().joinpath(file)
|
|
897
|
+
),
|
|
898
|
+
)
|
|
899
|
+
|
|
900
|
+
self.connect_action("do_scan", lambda: self.load_scan_module())
|
|
901
|
+
self.connect_action("do_log", lambda: self.load_log_module())
|
|
902
|
+
self.connect_action("do_pid", lambda: self.load_pid_module())
|
|
903
|
+
self.connect_action("console", lambda: self.load_console())
|
|
904
|
+
self.connect_action("bayesian", lambda: self.load_bayesian())
|
|
905
|
+
self.connect_action("adaptive", lambda: self.load_adaptive())
|
|
906
|
+
self.connect_action("datamixer", lambda: self.load_datamixer())
|
|
907
|
+
|
|
908
|
+
self.connect_action("about", self.show_about)
|
|
909
|
+
self.connect_action("help", self.show_help)
|
|
910
|
+
self.connect_action("check_update", lambda: self.check_update(True))
|
|
911
|
+
self.connect_action("plugin_manager", self.start_plugin_manager)
|
|
500
912
|
|
|
501
913
|
def setup_menu(self, menubar: QtWidgets.QMenuBar = None):
|
|
502
914
|
"""
|
|
503
|
-
|
|
915
|
+
Create the menubar object looking like :
|
|
504
916
|
"""
|
|
505
917
|
menubar.clear()
|
|
506
918
|
|
|
507
919
|
# %% create Settings menu
|
|
508
|
-
self.file_menu = menubar.addMenu(
|
|
509
|
-
self.file_menu.addAction(self.get_action(
|
|
510
|
-
self.file_menu.addAction(self.get_action(
|
|
920
|
+
self.file_menu = menubar.addMenu("File")
|
|
921
|
+
self.file_menu.addAction(self.get_action("log"))
|
|
922
|
+
self.file_menu.addAction(self.get_action("config_utils"))
|
|
923
|
+
self.file_menu.addAction(self.get_action("config"))
|
|
511
924
|
self.file_menu.addSeparator()
|
|
512
|
-
self.file_menu.addAction(self.get_action(
|
|
513
|
-
self.file_menu.addAction(self.get_action(
|
|
925
|
+
self.file_menu.addAction(self.get_action("quit"))
|
|
926
|
+
self.file_menu.addAction(self.get_action("restart"))
|
|
514
927
|
|
|
515
|
-
self.settings_menu = menubar.addMenu(
|
|
516
|
-
self.settings_menu.addAction(self.get_action(
|
|
517
|
-
docked_menu = self.settings_menu.addMenu(
|
|
518
|
-
docked_menu.addAction(self.get_action(
|
|
519
|
-
docked_menu.addAction(self.get_action(
|
|
928
|
+
self.settings_menu = menubar.addMenu("Settings")
|
|
929
|
+
self.settings_menu.addAction(self.get_action("leco"))
|
|
930
|
+
docked_menu = self.settings_menu.addMenu("Docked windows")
|
|
931
|
+
docked_menu.addAction(self.get_action("load_layout"))
|
|
932
|
+
docked_menu.addAction(self.get_action("save_layout"))
|
|
520
933
|
|
|
521
934
|
docked_menu.addSeparator()
|
|
522
|
-
docked_menu.addAction(self.get_action(
|
|
935
|
+
docked_menu.addAction(self.get_action("log_window"))
|
|
523
936
|
|
|
524
|
-
self.preset_menu = menubar.addMenu(
|
|
525
|
-
self.preset_menu.addAction(self.get_action(
|
|
526
|
-
self.preset_menu.addAction(self.get_action(
|
|
937
|
+
self.preset_menu = menubar.addMenu("Preset Modes")
|
|
938
|
+
self.preset_menu.addAction(self.get_action("new_preset"))
|
|
939
|
+
self.preset_menu.addAction(self.get_action("modify_preset"))
|
|
527
940
|
self.preset_menu.addSeparator()
|
|
528
|
-
self.load_preset_menu = self.preset_menu.addMenu(
|
|
941
|
+
self.load_preset_menu = self.preset_menu.addMenu("Load presets")
|
|
529
942
|
|
|
530
943
|
for ind_file, file in enumerate(self.preset_path.iterdir()):
|
|
531
|
-
if file.suffix ==
|
|
944
|
+
if file.suffix == ".xml":
|
|
532
945
|
self.load_preset_menu.addAction(
|
|
533
|
-
self.get_action(
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
self.overshoot_menu.
|
|
946
|
+
self.get_action(
|
|
947
|
+
self.get_action_from_file(file, ManagerEnums.preset)
|
|
948
|
+
)
|
|
949
|
+
)
|
|
950
|
+
|
|
951
|
+
self.overshoot_menu = menubar.addMenu("Overshoot Modes")
|
|
952
|
+
self.overshoot_menu.addAction(self.get_action("new_overshoot"))
|
|
953
|
+
self.overshoot_menu.addAction(self.get_action("modify_overshoot"))
|
|
954
|
+
self.overshoot_menu.addAction(self.get_action("activate_overshoot"))
|
|
539
955
|
self.overshoot_menu.addSeparator()
|
|
540
|
-
load_overshoot_menu = self.overshoot_menu.addMenu(
|
|
956
|
+
load_overshoot_menu = self.overshoot_menu.addMenu("Load Overshoots")
|
|
541
957
|
|
|
542
|
-
for ind_file, file in enumerate(
|
|
543
|
-
|
|
958
|
+
for ind_file, file in enumerate(
|
|
959
|
+
config_mod_pymodaq.get_set_overshoot_path().iterdir()
|
|
960
|
+
):
|
|
961
|
+
if file.suffix == ".xml":
|
|
544
962
|
load_overshoot_menu.addAction(
|
|
545
|
-
self.get_action(
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
963
|
+
self.get_action(
|
|
964
|
+
self.get_action_from_file(file, ManagerEnums.overshoot)
|
|
965
|
+
)
|
|
966
|
+
)
|
|
967
|
+
|
|
968
|
+
self.roi_menu = menubar.addMenu("ROI Modes")
|
|
969
|
+
self.roi_menu.addAction(self.get_action("save_roi"))
|
|
970
|
+
self.roi_menu.addAction(self.get_action("modify_roi"))
|
|
550
971
|
self.roi_menu.addSeparator()
|
|
551
|
-
load_roi_menu = self.roi_menu.addMenu(
|
|
972
|
+
load_roi_menu = self.roi_menu.addMenu("Load roi configs")
|
|
552
973
|
|
|
553
|
-
for ind_file, file in enumerate(
|
|
554
|
-
|
|
974
|
+
for ind_file, file in enumerate(
|
|
975
|
+
config_mod_pymodaq.get_set_roi_path().iterdir()
|
|
976
|
+
):
|
|
977
|
+
if file.suffix == ".xml":
|
|
555
978
|
load_roi_menu.addAction(
|
|
556
|
-
self.get_action(self.get_action_from_file(file, ManagerEnums.roi))
|
|
979
|
+
self.get_action(self.get_action_from_file(file, ManagerEnums.roi))
|
|
980
|
+
)
|
|
557
981
|
|
|
558
|
-
self.remote_menu = menubar.addMenu(
|
|
559
|
-
self.remote_menu.addAction(
|
|
560
|
-
self.remote_menu.addAction(
|
|
982
|
+
self.remote_menu = menubar.addMenu("Remote/Shortcuts Control")
|
|
983
|
+
self.remote_menu.addAction("New remote config.", self.create_remote)
|
|
984
|
+
self.remote_menu.addAction("Modify remote config.", self.modify_remote)
|
|
561
985
|
self.remote_menu.addSeparator()
|
|
562
|
-
load_remote_menu = self.remote_menu.addMenu(
|
|
986
|
+
load_remote_menu = self.remote_menu.addMenu("Load remote config.")
|
|
563
987
|
|
|
564
|
-
for ind_file, file in enumerate(
|
|
565
|
-
|
|
988
|
+
for ind_file, file in enumerate(
|
|
989
|
+
config_mod_pymodaq.get_set_remote_path().iterdir()
|
|
990
|
+
):
|
|
991
|
+
if file.suffix == ".xml":
|
|
566
992
|
load_remote_menu.addAction(
|
|
567
|
-
self.get_action(
|
|
993
|
+
self.get_action(
|
|
994
|
+
self.get_action_from_file(file, ManagerEnums.remote)
|
|
995
|
+
)
|
|
996
|
+
)
|
|
568
997
|
|
|
569
998
|
# extensions menu
|
|
570
|
-
self.extensions_menu = menubar.addMenu(
|
|
571
|
-
self.extensions_menu.addAction(self.get_action(
|
|
572
|
-
self.extensions_menu.addAction(self.get_action(
|
|
573
|
-
self.extensions_menu.addAction(self.get_action(
|
|
574
|
-
self.extensions_menu.addAction(self.get_action(
|
|
575
|
-
self.extensions_menu.addAction(self.get_action(
|
|
999
|
+
self.extensions_menu = menubar.addMenu("Extensions")
|
|
1000
|
+
self.extensions_menu.addAction(self.get_action("do_scan"))
|
|
1001
|
+
self.extensions_menu.addAction(self.get_action("do_log"))
|
|
1002
|
+
self.extensions_menu.addAction(self.get_action("do_pid"))
|
|
1003
|
+
self.extensions_menu.addAction(self.get_action("console"))
|
|
1004
|
+
self.extensions_menu.addAction(self.get_action("bayesian"))
|
|
1005
|
+
self.extensions_menu.addAction(self.get_action("adaptive"))
|
|
1006
|
+
self.extensions_menu.addAction(self.get_action("datamixer"))
|
|
576
1007
|
|
|
577
1008
|
# extensions from plugins
|
|
578
1009
|
extensions_actions = []
|
|
579
1010
|
for ext in extensions:
|
|
580
|
-
extensions_actions.append(self.extensions_menu.addAction(ext[
|
|
1011
|
+
extensions_actions.append(self.extensions_menu.addAction(ext["name"]))
|
|
581
1012
|
extensions_actions[-1].triggered.connect(self.create_menu_slot_ext(ext))
|
|
582
1013
|
|
|
583
1014
|
# help menu
|
|
584
|
-
help_menu = menubar.addMenu(
|
|
585
|
-
help_menu.addAction(self.get_action(
|
|
586
|
-
help_menu.addAction(self.get_action(
|
|
1015
|
+
help_menu = menubar.addMenu("?")
|
|
1016
|
+
help_menu.addAction(self.get_action("about"))
|
|
1017
|
+
help_menu.addAction(self.get_action("help"))
|
|
587
1018
|
help_menu.addSeparator()
|
|
588
|
-
help_menu.addAction(self.get_action(
|
|
589
|
-
help_menu.addAction(self.get_action(
|
|
1019
|
+
help_menu.addAction(self.get_action("check_update"))
|
|
1020
|
+
help_menu.addAction(self.get_action("plugin_manager"))
|
|
590
1021
|
|
|
591
|
-
self.
|
|
592
|
-
|
|
593
|
-
self.
|
|
594
|
-
self.
|
|
1022
|
+
status = self.preset_file is None
|
|
1023
|
+
|
|
1024
|
+
self.overshoot_menu.setEnabled(not status)
|
|
1025
|
+
self.roi_menu.setEnabled(not status)
|
|
1026
|
+
self.remote_menu.setEnabled(not status)
|
|
1027
|
+
self.extensions_menu.setEnabled(not status)
|
|
595
1028
|
self.file_menu.setEnabled(True)
|
|
596
1029
|
self.settings_menu.setEnabled(True)
|
|
597
|
-
self.preset_menu.setEnabled(
|
|
1030
|
+
self.preset_menu.setEnabled(status)
|
|
598
1031
|
|
|
599
1032
|
def start_plugin_manager(self):
|
|
600
1033
|
self.win_plug_manager = QtWidgets.QMainWindow()
|
|
601
|
-
self.win_plug_manager.setWindowTitle(
|
|
1034
|
+
self.win_plug_manager.setWindowTitle("PyMoDAQ Plugin Manager")
|
|
602
1035
|
widget = QtWidgets.QWidget()
|
|
603
1036
|
self.win_plug_manager.setCentralWidget(widget)
|
|
604
1037
|
self.plugin_manager = PluginManager(widget)
|
|
@@ -625,10 +1058,19 @@ class DashBoard(CustomApp):
|
|
|
625
1058
|
try:
|
|
626
1059
|
if self.preset_file is not None:
|
|
627
1060
|
self.roi_saver.set_new_roi(self.preset_file.stem)
|
|
628
|
-
self.add_action(
|
|
629
|
-
|
|
630
|
-
|
|
1061
|
+
self.add_action(
|
|
1062
|
+
self.get_action_from_file(self.preset_file, ManagerEnums.roi),
|
|
1063
|
+
self.preset_file.stem,
|
|
1064
|
+
"",
|
|
1065
|
+
)
|
|
631
1066
|
self.setup_menu(self.menubar)
|
|
1067
|
+
self.connect_action(
|
|
1068
|
+
self.get_action_from_file(self.preset_file, ManagerEnums.roi),
|
|
1069
|
+
self.create_menu_slot_roi(
|
|
1070
|
+
config_mod_pymodaq.get_set_roi_path().joinpath(self.preset_file.name)
|
|
1071
|
+
),
|
|
1072
|
+
)
|
|
1073
|
+
|
|
632
1074
|
|
|
633
1075
|
except Exception as e:
|
|
634
1076
|
logger.exception(str(e))
|
|
@@ -637,10 +1079,18 @@ class DashBoard(CustomApp):
|
|
|
637
1079
|
try:
|
|
638
1080
|
if self.preset_file is not None:
|
|
639
1081
|
self.remote_manager.set_new_remote(self.preset_file.stem)
|
|
640
|
-
self.add_action(
|
|
641
|
-
|
|
642
|
-
|
|
1082
|
+
self.add_action(
|
|
1083
|
+
self.get_action_from_file(self.preset_file, ManagerEnums.remote),
|
|
1084
|
+
self.preset_file.stem,
|
|
1085
|
+
"",
|
|
1086
|
+
)
|
|
643
1087
|
self.setup_menu(self.menubar)
|
|
1088
|
+
self.connect_action(
|
|
1089
|
+
self.get_action_from_file(self.preset_file, ManagerEnums.remote),
|
|
1090
|
+
self.create_menu_slot_remote(
|
|
1091
|
+
config_mod_pymodaq.get_set_remote_path().joinpath(self.preset_file.name)
|
|
1092
|
+
),
|
|
1093
|
+
)
|
|
644
1094
|
|
|
645
1095
|
except Exception as e:
|
|
646
1096
|
logger.exception(str(e))
|
|
@@ -649,10 +1099,18 @@ class DashBoard(CustomApp):
|
|
|
649
1099
|
try:
|
|
650
1100
|
if self.preset_file is not None:
|
|
651
1101
|
self.overshoot_manager.set_new_overshoot(self.preset_file.stem)
|
|
652
|
-
self.add_action(
|
|
653
|
-
|
|
654
|
-
|
|
1102
|
+
self.add_action(
|
|
1103
|
+
self.get_action_from_file(self.preset_file, ManagerEnums.overshoot),
|
|
1104
|
+
self.preset_file.stem,
|
|
1105
|
+
"",
|
|
1106
|
+
)
|
|
655
1107
|
self.setup_menu(self.menubar)
|
|
1108
|
+
self.connect_action(
|
|
1109
|
+
self.get_action_from_file(self.preset_file, ManagerEnums.overshoot),
|
|
1110
|
+
self.create_menu_slot_over(
|
|
1111
|
+
config_mod_pymodaq.get_set_overshoot_path().joinpath(self.preset_file.name)
|
|
1112
|
+
),
|
|
1113
|
+
)
|
|
656
1114
|
except Exception as e:
|
|
657
1115
|
logger.exception(str(e))
|
|
658
1116
|
|
|
@@ -668,13 +1126,16 @@ class DashBoard(CustomApp):
|
|
|
668
1126
|
|
|
669
1127
|
@staticmethod
|
|
670
1128
|
def get_action_from_file(file: Path, manager: ManagerEnums):
|
|
671
|
-
return f
|
|
1129
|
+
return f"{file.stem}_{manager.name}"
|
|
672
1130
|
|
|
673
1131
|
def modify_remote(self):
|
|
674
1132
|
try:
|
|
675
|
-
path = select_file(
|
|
676
|
-
|
|
677
|
-
|
|
1133
|
+
path = select_file(
|
|
1134
|
+
start_path=config_mod_pymodaq.get_set_remote_path(),
|
|
1135
|
+
save=False,
|
|
1136
|
+
ext="xml",
|
|
1137
|
+
)
|
|
1138
|
+
if path != "":
|
|
678
1139
|
self.remote_manager.set_file_remote(path)
|
|
679
1140
|
|
|
680
1141
|
else: # cancel
|
|
@@ -684,9 +1145,12 @@ class DashBoard(CustomApp):
|
|
|
684
1145
|
|
|
685
1146
|
def modify_overshoot(self):
|
|
686
1147
|
try:
|
|
687
|
-
path = select_file(
|
|
688
|
-
|
|
689
|
-
|
|
1148
|
+
path = select_file(
|
|
1149
|
+
start_path=config_mod_pymodaq.get_set_overshoot_path(),
|
|
1150
|
+
save=False,
|
|
1151
|
+
ext="xml",
|
|
1152
|
+
)
|
|
1153
|
+
if path != "":
|
|
690
1154
|
self.overshoot_manager.set_file_overshoot(path)
|
|
691
1155
|
|
|
692
1156
|
else: # cancel
|
|
@@ -696,9 +1160,10 @@ class DashBoard(CustomApp):
|
|
|
696
1160
|
|
|
697
1161
|
def modify_roi(self):
|
|
698
1162
|
try:
|
|
699
|
-
path = select_file(
|
|
700
|
-
|
|
701
|
-
|
|
1163
|
+
path = select_file(
|
|
1164
|
+
start_path=config_mod_pymodaq.get_set_roi_path(), save=False, ext="xml"
|
|
1165
|
+
)
|
|
1166
|
+
if path != "":
|
|
702
1167
|
self.roi_saver.set_file_roi(path)
|
|
703
1168
|
|
|
704
1169
|
else: # cancel
|
|
@@ -708,19 +1173,21 @@ class DashBoard(CustomApp):
|
|
|
708
1173
|
|
|
709
1174
|
def modify_preset(self):
|
|
710
1175
|
try:
|
|
711
|
-
path = select_file(start_path=self.preset_path, save=False, ext=
|
|
712
|
-
if path !=
|
|
1176
|
+
path = select_file(start_path=self.preset_path, save=False, ext="xml")
|
|
1177
|
+
if path != "":
|
|
713
1178
|
modified = self.preset_manager.set_file_preset(path)
|
|
714
1179
|
|
|
715
1180
|
if modified:
|
|
716
1181
|
self.remove_preset_related_files(path.name)
|
|
717
1182
|
if self.detector_modules:
|
|
718
|
-
mssg =
|
|
719
|
-
mssg.setText(
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
1183
|
+
mssg = QMessageBox()
|
|
1184
|
+
mssg.setText(
|
|
1185
|
+
"You have to restart the application to take the modifications"
|
|
1186
|
+
" into account!\n\n"
|
|
1187
|
+
"The related files: ROI, Layout, Overshoot and Remote will be"
|
|
1188
|
+
" deleted if existing!\n\n"
|
|
1189
|
+
"Quitting the application..."
|
|
1190
|
+
)
|
|
724
1191
|
mssg.exec()
|
|
725
1192
|
self.restart_fun()
|
|
726
1193
|
|
|
@@ -732,22 +1199,24 @@ class DashBoard(CustomApp):
|
|
|
732
1199
|
def remove_preset_related_files(self, name):
|
|
733
1200
|
config_mod_pymodaq.get_set_roi_path().joinpath(name).unlink(missing_ok=True)
|
|
734
1201
|
config_mod_pymodaq.get_set_layout_path().joinpath(name).unlink(missing_ok=True)
|
|
735
|
-
config_mod_pymodaq.get_set_overshoot_path().joinpath(name).unlink(
|
|
1202
|
+
config_mod_pymodaq.get_set_overshoot_path().joinpath(name).unlink(
|
|
1203
|
+
missing_ok=True
|
|
1204
|
+
)
|
|
736
1205
|
config_mod_pymodaq.get_set_remote_path().joinpath(name).unlink(missing_ok=True)
|
|
737
1206
|
|
|
738
1207
|
def quit_fun(self):
|
|
739
1208
|
"""
|
|
740
|
-
|
|
1209
|
+
Quit the current instance of DAQ_scan and close on cascade move and detector modules.
|
|
741
1210
|
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
1211
|
+
See Also
|
|
1212
|
+
--------
|
|
1213
|
+
quit_fun
|
|
745
1214
|
"""
|
|
746
1215
|
try:
|
|
747
1216
|
self.remote_timer.stop()
|
|
748
1217
|
|
|
749
1218
|
for ext in self.extensions:
|
|
750
|
-
if hasattr(self.extensions[ext],
|
|
1219
|
+
if hasattr(self.extensions[ext], "quit_fun"):
|
|
751
1220
|
self.extensions[ext].quit_fun()
|
|
752
1221
|
for mov in self.actuators_modules:
|
|
753
1222
|
try:
|
|
@@ -784,7 +1253,7 @@ class DashBoard(CustomApp):
|
|
|
784
1253
|
QThread.msleep(1000)
|
|
785
1254
|
QtWidgets.QApplication.processEvents()
|
|
786
1255
|
|
|
787
|
-
if hasattr(self,
|
|
1256
|
+
if hasattr(self, "mainwindow"):
|
|
788
1257
|
self.mainwindow.close()
|
|
789
1258
|
|
|
790
1259
|
if self.pid_window is not None:
|
|
@@ -795,40 +1264,42 @@ class DashBoard(CustomApp):
|
|
|
795
1264
|
|
|
796
1265
|
def restart_fun(self, ask=False):
|
|
797
1266
|
ret = False
|
|
798
|
-
mssg =
|
|
1267
|
+
mssg = QMessageBox()
|
|
799
1268
|
if ask:
|
|
800
|
-
mssg.setText(
|
|
801
|
-
|
|
1269
|
+
mssg.setText(
|
|
1270
|
+
"You have to restart the application to take the"
|
|
1271
|
+
" modifications into account!"
|
|
1272
|
+
)
|
|
802
1273
|
mssg.setInformativeText("Do you want to restart?")
|
|
803
|
-
mssg.setStandardButtons(
|
|
1274
|
+
mssg.setStandardButtons(QMessageBox.StandardButton.Ok | QMessageBox.StandardButton.Cancel)
|
|
804
1275
|
ret = mssg.exec()
|
|
805
1276
|
|
|
806
|
-
if ret ==
|
|
1277
|
+
if ret == QMessageBox.StandardButton.Ok or not ask:
|
|
807
1278
|
self.quit_fun()
|
|
808
1279
|
subprocess.call([sys.executable, __file__])
|
|
809
1280
|
|
|
810
1281
|
def load_layout_state(self, file=None):
|
|
811
1282
|
"""
|
|
812
|
-
|
|
1283
|
+
Load and restore a layout state from the select_file obtained pathname file.
|
|
813
1284
|
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
1285
|
+
See Also
|
|
1286
|
+
--------
|
|
1287
|
+
utils.select_file
|
|
817
1288
|
"""
|
|
818
1289
|
try:
|
|
819
1290
|
file = layout_mod.load_layout_state(self.dockarea, file)
|
|
820
|
-
self.settings.child(
|
|
1291
|
+
self.settings.child("loaded_files", "layout_file").setValue(file)
|
|
821
1292
|
except Exception as e:
|
|
822
1293
|
logger.exception(str(e))
|
|
823
1294
|
|
|
824
1295
|
def save_layout_state(self, file=None):
|
|
825
1296
|
"""
|
|
826
|
-
|
|
827
|
-
|
|
1297
|
+
Save the current layout state in the select_file obtained pathname file.
|
|
1298
|
+
Once done dump the pickle.
|
|
828
1299
|
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1300
|
+
See Also
|
|
1301
|
+
--------
|
|
1302
|
+
utils.select_file
|
|
832
1303
|
"""
|
|
833
1304
|
try:
|
|
834
1305
|
layout_mod.save_layout_state(self.dockarea, file)
|
|
@@ -837,42 +1308,91 @@ class DashBoard(CustomApp):
|
|
|
837
1308
|
|
|
838
1309
|
def save_layout_state_auto(self):
|
|
839
1310
|
if self.preset_file is not None:
|
|
840
|
-
path = layout_path.joinpath(self.preset_file.stem +
|
|
1311
|
+
path = layout_path.joinpath(self.preset_file.stem + ".dock")
|
|
841
1312
|
self.save_layout_state(path)
|
|
842
1313
|
|
|
843
|
-
def add_move(
|
|
844
|
-
|
|
1314
|
+
def add_move(
|
|
1315
|
+
self,
|
|
1316
|
+
plug_name: str = None,
|
|
1317
|
+
plug_settings: Parameter = None,
|
|
1318
|
+
plug_type: str = None,
|
|
1319
|
+
move_docks: list[Dock] = None,
|
|
1320
|
+
move_forms: list[QtWidgets.QWidget] = None,
|
|
1321
|
+
actuators_modules: list[DAQ_Move] = None,
|
|
1322
|
+
ui_identifier: str = None,
|
|
1323
|
+
**kwargs
|
|
1324
|
+
) -> DAQ_Move:
|
|
1325
|
+
if move_docks is None:
|
|
1326
|
+
move_docks = []
|
|
1327
|
+
if move_forms is None:
|
|
1328
|
+
move_forms = []
|
|
1329
|
+
if actuators_modules is None:
|
|
1330
|
+
actuators_modules = []
|
|
845
1331
|
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
1332
|
+
if ui_identifier is not None:
|
|
1333
|
+
pass
|
|
1334
|
+
elif plug_settings is None:
|
|
1335
|
+
ui_identifier = config("actuator", "ui")
|
|
1336
|
+
else:
|
|
1337
|
+
try:
|
|
1338
|
+
ui_identifier = plug_settings["main_settings", "ui_type"]
|
|
1339
|
+
except KeyError:
|
|
1340
|
+
ui_identifier = config("actuator", "ui")
|
|
1341
|
+
|
|
1342
|
+
is_compact = (
|
|
1343
|
+
ActuatorUIFactory.get(ui_identifier).is_compact
|
|
1344
|
+
if ui_identifier is not None
|
|
1345
|
+
else False
|
|
1346
|
+
)
|
|
1347
|
+
|
|
1348
|
+
if is_compact:
|
|
1349
|
+
if self.compact_actuator_dock is None:
|
|
1350
|
+
self.compact_actuator_dock = Dock("Simple Actuators")
|
|
1351
|
+
self.compact_actuator_dock.layout.setSpacing(0)
|
|
1352
|
+
self.compact_actuator_dock.layout.setContentsMargins(0, 0, 0, 0)
|
|
1353
|
+
|
|
1354
|
+
dock = self.compact_actuator_dock
|
|
1355
|
+
self.logger_dock.area.addDock(dock, "bottom")
|
|
849
1356
|
else:
|
|
850
|
-
|
|
1357
|
+
dock = Dock(plug_name, size=(150, 250))
|
|
1358
|
+
move_docks.append(dock)
|
|
1359
|
+
|
|
1360
|
+
if len(move_docks) == 1:
|
|
1361
|
+
self.dockarea.addDock(dock, "right", self.logger_dock)
|
|
1362
|
+
else:
|
|
1363
|
+
self.dockarea.addDock(dock, "above", move_docks[-2])
|
|
1364
|
+
|
|
851
1365
|
move_forms.append(QtWidgets.QWidget())
|
|
852
|
-
mov_mod_tmp = DAQ_Move(move_forms[-1], plug_name)
|
|
1366
|
+
mov_mod_tmp = DAQ_Move(move_forms[-1], plug_name, ui_identifier=ui_identifier)
|
|
853
1367
|
|
|
854
1368
|
mov_mod_tmp.actuator = plug_type
|
|
855
1369
|
QtWidgets.QApplication.processEvents()
|
|
856
|
-
mov_mod_tmp.manage_ui_actions(
|
|
1370
|
+
mov_mod_tmp.manage_ui_actions("quit", "setEnabled", False)
|
|
857
1371
|
|
|
858
1372
|
if plug_settings is not None:
|
|
859
1373
|
try:
|
|
860
1374
|
putils.set_param_from_param(mov_mod_tmp.settings, plug_settings)
|
|
861
1375
|
except KeyError as e:
|
|
862
|
-
mssg =
|
|
863
|
-
|
|
1376
|
+
mssg = (
|
|
1377
|
+
f"Could not set this setting: {str(e)}\n"
|
|
1378
|
+
f"The Preset is no more compatible with the plugin {plug_type}"
|
|
1379
|
+
)
|
|
864
1380
|
logger.warning(mssg)
|
|
865
1381
|
self.splash_sc.showMessage(mssg)
|
|
866
1382
|
QtWidgets.QApplication.processEvents()
|
|
867
1383
|
|
|
868
1384
|
mov_mod_tmp.bounds_signal[bool].connect(self.do_stuff_from_out_bounds)
|
|
869
|
-
|
|
1385
|
+
dock.addWidget(move_forms[-1])
|
|
1386
|
+
|
|
870
1387
|
actuators_modules.append(mov_mod_tmp)
|
|
871
1388
|
return mov_mod_tmp
|
|
872
1389
|
|
|
873
|
-
def add_move_from_extension(
|
|
874
|
-
|
|
875
|
-
|
|
1390
|
+
def add_move_from_extension(
|
|
1391
|
+
self, name: str, instrument_name: str, instrument_controller: Any,
|
|
1392
|
+
ui_identifier = None,
|
|
1393
|
+
**kwargs
|
|
1394
|
+
):
|
|
1395
|
+
"""Specific method to add a DAQ_Move within the Dashboard. This Particular actuator
|
|
876
1396
|
should be defined in the plugin of the extension and is used to mimic an actuator while
|
|
877
1397
|
move_abs is actually triggering an action on the extension which loaded it
|
|
878
1398
|
|
|
@@ -888,8 +1408,13 @@ class DashBoard(CustomApp):
|
|
|
888
1408
|
instrument_controller: object
|
|
889
1409
|
whatever object is used to communicate between the instrument module and the extension
|
|
890
1410
|
which created it
|
|
1411
|
+
ui_identifier: str
|
|
1412
|
+
One of the possible registered UI
|
|
1413
|
+
kwargs: named arguments to be passed to add_move
|
|
891
1414
|
"""
|
|
892
|
-
actuator = self.add_move(name, None, instrument_name, [], [], []
|
|
1415
|
+
actuator = self.add_move(name, None, instrument_name, [], [], [],
|
|
1416
|
+
ui_identifier=ui_identifier,
|
|
1417
|
+
**kwargs)
|
|
893
1418
|
actuator.controller = instrument_controller
|
|
894
1419
|
actuator.master = False
|
|
895
1420
|
actuator.init_hardware_ui()
|
|
@@ -901,48 +1426,83 @@ class DashBoard(CustomApp):
|
|
|
901
1426
|
self.actuators_modules.append(actuator)
|
|
902
1427
|
self.update_module_manager()
|
|
903
1428
|
|
|
904
|
-
def add_det(
|
|
905
|
-
|
|
1429
|
+
def add_det(
|
|
1430
|
+
self,
|
|
1431
|
+
plug_name,
|
|
1432
|
+
plug_settings,
|
|
1433
|
+
det_docks_settings,
|
|
1434
|
+
det_docks_viewer,
|
|
1435
|
+
detector_modules,
|
|
1436
|
+
plug_type: str = None,
|
|
1437
|
+
plug_subtype: str = None,
|
|
1438
|
+
) -> DAQ_Viewer:
|
|
906
1439
|
if plug_type is None:
|
|
907
|
-
plug_type = plug_settings.child(
|
|
1440
|
+
plug_type = plug_settings.child("main_settings", "DAQ_type").value()
|
|
908
1441
|
if plug_subtype is None:
|
|
909
|
-
plug_subtype = plug_settings.child(
|
|
1442
|
+
plug_subtype = plug_settings.child("main_settings", "detector_type").value()
|
|
910
1443
|
det_docks_settings.append(Dock(plug_name + " settings", size=(150, 250)))
|
|
911
1444
|
det_docks_viewer.append(Dock(plug_name + " viewer", size=(350, 350)))
|
|
912
1445
|
if len(detector_modules) == 0:
|
|
913
|
-
self.logger_dock.area.addDock(det_docks_settings[-1],
|
|
1446
|
+
self.logger_dock.area.addDock(det_docks_settings[-1], "bottom")
|
|
914
1447
|
# dockarea of the logger dock
|
|
915
1448
|
else:
|
|
916
|
-
self.dockarea.addDock(
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
1449
|
+
self.dockarea.addDock(
|
|
1450
|
+
det_docks_settings[-1], "right", detector_modules[-1].viewer_docks[-1]
|
|
1451
|
+
)
|
|
1452
|
+
self.dockarea.addDock(det_docks_viewer[-1], "right", det_docks_settings[-1])
|
|
1453
|
+
det_mod_tmp = DAQ_Viewer(
|
|
1454
|
+
self.dockarea,
|
|
1455
|
+
title=plug_name,
|
|
1456
|
+
daq_type=plug_type,
|
|
1457
|
+
dock_settings=det_docks_settings[-1],
|
|
1458
|
+
dock_viewer=det_docks_viewer[-1],
|
|
1459
|
+
)
|
|
922
1460
|
QtWidgets.QApplication.processEvents()
|
|
923
1461
|
det_mod_tmp.detector = plug_subtype
|
|
924
1462
|
QtWidgets.QApplication.processEvents()
|
|
925
|
-
det_mod_tmp.manage_ui_actions(
|
|
1463
|
+
det_mod_tmp.manage_ui_actions("quit", "setEnabled", False)
|
|
926
1464
|
|
|
927
1465
|
if plug_settings is not None:
|
|
928
1466
|
try:
|
|
929
1467
|
putils.set_param_from_param(det_mod_tmp.settings, plug_settings)
|
|
930
1468
|
except KeyError as e:
|
|
931
|
-
mssg =
|
|
932
|
-
|
|
1469
|
+
mssg = (
|
|
1470
|
+
f"Could not set this setting: {str(e)}\n"
|
|
1471
|
+
f"The Preset is no more compatible with the plugin {plug_subtype}"
|
|
1472
|
+
)
|
|
933
1473
|
logger.warning(mssg)
|
|
934
1474
|
self.splash_sc.showMessage(mssg)
|
|
935
1475
|
|
|
936
1476
|
detector_modules.append(det_mod_tmp)
|
|
937
1477
|
return det_mod_tmp
|
|
938
1478
|
|
|
939
|
-
def
|
|
940
|
-
|
|
941
|
-
|
|
1479
|
+
def override_det_from_extension(self, overriden_grabbers: Sequence[str] = None):
|
|
1480
|
+
"""(Experimental) If an extension adding detectors within the Dashboard need to,
|
|
1481
|
+
it could call this method.
|
|
1482
|
+
|
|
1483
|
+
Then if some other extension trigger a grab from it, the request of a grab won't be done twice
|
|
1484
|
+
|
|
1485
|
+
Parameters
|
|
1486
|
+
----------
|
|
1487
|
+
overriden_grabbers: Sequence[str]
|
|
1488
|
+
sequence of detector names whose corresponding modules should set their
|
|
1489
|
+
attribute override_grab_from_extension to True.
|
|
1490
|
+
"""
|
|
1491
|
+
if overriden_grabbers is not None:
|
|
1492
|
+
for mod_name in overriden_grabbers:
|
|
1493
|
+
mod = self.modules_manager.get_mod_from_name(mod_name, "det")
|
|
1494
|
+
if mod is not None:
|
|
1495
|
+
mod.override_grab_from_extension = True
|
|
1496
|
+
|
|
1497
|
+
def add_det_from_extension(
|
|
1498
|
+
self, name: str, daq_type: str, instrument_name: str, instrument_controller: Any
|
|
1499
|
+
):
|
|
1500
|
+
"""Specific method to add a DAQ_Viewer within the Dashboard. This Particular detector
|
|
942
1501
|
should be defined in the plugin of the extension and is used to mimic a grab while data
|
|
943
1502
|
are actually coming from the extension which loaded it
|
|
944
1503
|
|
|
945
1504
|
For an exemple, see the pymodaq_plugins_datamixer plugin and its DataMixer extension
|
|
1505
|
+
or the DAQ_PID extension
|
|
946
1506
|
|
|
947
1507
|
Parameters
|
|
948
1508
|
----------
|
|
@@ -957,9 +1517,9 @@ class DashBoard(CustomApp):
|
|
|
957
1517
|
whatever object is used to communicate between the instrument module and the extension
|
|
958
1518
|
which created it
|
|
959
1519
|
"""
|
|
960
|
-
detector = self.add_det(
|
|
961
|
-
|
|
962
|
-
|
|
1520
|
+
detector = self.add_det(
|
|
1521
|
+
name, None, [], [], [], plug_type=daq_type, plug_subtype=instrument_name
|
|
1522
|
+
)
|
|
963
1523
|
detector.controller = instrument_controller
|
|
964
1524
|
detector.master = False
|
|
965
1525
|
detector.init_hardware_ui()
|
|
@@ -973,33 +1533,35 @@ class DashBoard(CustomApp):
|
|
|
973
1533
|
|
|
974
1534
|
def update_module_manager(self):
|
|
975
1535
|
if self.modules_manager is None:
|
|
976
|
-
self.modules_manager = ModulesManager(
|
|
1536
|
+
self.modules_manager = ModulesManager(
|
|
1537
|
+
self.detector_modules, self.actuators_modules, parent_name="Dashboard"
|
|
1538
|
+
)
|
|
977
1539
|
else:
|
|
978
1540
|
self.modules_manager.actuators_all = self.actuators_modules
|
|
979
1541
|
self.modules_manager.detectors_all = self.detector_modules
|
|
980
1542
|
|
|
981
1543
|
def set_file_preset(self, filename) -> Tuple[List[DAQ_Move], List[DAQ_Viewer]]:
|
|
982
1544
|
"""
|
|
983
|
-
|
|
1545
|
+
Set a file managers from the converted xml file given by the filename parameter.
|
|
984
1546
|
|
|
985
1547
|
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
1548
|
+
=============== =========== ===================================================
|
|
1549
|
+
**Parameters** **Type** **Description**
|
|
1550
|
+
*filename* string the name of the xml file to be converted/treated
|
|
1551
|
+
=============== =========== ===================================================
|
|
990
1552
|
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
1553
|
+
Returns
|
|
1554
|
+
-------
|
|
1555
|
+
(Object list, Object list) tuple
|
|
1556
|
+
The updated (Move modules list, Detector modules list).
|
|
995
1557
|
|
|
996
|
-
|
|
1558
|
+
"""
|
|
997
1559
|
actuators_modules = []
|
|
998
1560
|
detector_modules = []
|
|
999
1561
|
if not isinstance(filename, Path):
|
|
1000
1562
|
filename = Path(filename)
|
|
1001
1563
|
|
|
1002
|
-
if filename.suffix ==
|
|
1564
|
+
if filename.suffix == ".xml":
|
|
1003
1565
|
self.preset_file = filename
|
|
1004
1566
|
self.preset_manager.set_file_preset(filename, show=False)
|
|
1005
1567
|
move_docks = []
|
|
@@ -1010,32 +1572,47 @@ class DashBoard(CustomApp):
|
|
|
1010
1572
|
# ################################################################
|
|
1011
1573
|
# ##### sort plugins by IDs and within the same IDs by Master and Slave status
|
|
1012
1574
|
plugins = []
|
|
1013
|
-
plugins += [
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1575
|
+
plugins += [
|
|
1576
|
+
{"type": "move", "value": child}
|
|
1577
|
+
for child in self.preset_manager.preset_params.child("Moves").children()
|
|
1578
|
+
]
|
|
1579
|
+
plugins += [
|
|
1580
|
+
{"type": "det", "value": child}
|
|
1581
|
+
for child in self.preset_manager.preset_params.child(
|
|
1582
|
+
"Detectors"
|
|
1583
|
+
).children()
|
|
1584
|
+
]
|
|
1018
1585
|
for plug in plugins:
|
|
1019
|
-
if plug["type"] ==
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1586
|
+
if plug["type"] == "det":
|
|
1587
|
+
try:
|
|
1588
|
+
plug["ID"] = plug["value"][
|
|
1589
|
+
"params", "detector_settings", "controller_ID"
|
|
1590
|
+
]
|
|
1591
|
+
plug["status"] = plug["value"][
|
|
1592
|
+
"params", "detector_settings", "controller_status"
|
|
1593
|
+
]
|
|
1594
|
+
except KeyError as e:
|
|
1595
|
+
raise DetectorError
|
|
1023
1596
|
else:
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1597
|
+
try:
|
|
1598
|
+
plug["ID"] = plug["value"][
|
|
1599
|
+
"params", "move_settings", "multiaxes", "controller_ID"
|
|
1600
|
+
]
|
|
1601
|
+
plug["status"] = plug["value"][
|
|
1602
|
+
"params", "move_settings", "multiaxes", "multi_status"
|
|
1603
|
+
]
|
|
1604
|
+
except KeyError as e:
|
|
1605
|
+
raise ActuatorError
|
|
1606
|
+
|
|
1607
|
+
IDs = list(set([plug["ID"] for plug in plugins]))
|
|
1031
1608
|
# %%
|
|
1032
1609
|
plugins_sorted = []
|
|
1033
1610
|
for id in IDs:
|
|
1034
1611
|
plug_Ids = []
|
|
1035
1612
|
for plug in plugins:
|
|
1036
|
-
if plug[
|
|
1613
|
+
if plug["ID"] == id:
|
|
1037
1614
|
plug_Ids.append(plug)
|
|
1038
|
-
plug_Ids.sort(key=lambda status: status[
|
|
1615
|
+
plug_Ids.sort(key=lambda status: status["status"])
|
|
1039
1616
|
plugins_sorted.append(plug_Ids)
|
|
1040
1617
|
#################################################################
|
|
1041
1618
|
#######################
|
|
@@ -1043,37 +1620,50 @@ class DashBoard(CustomApp):
|
|
|
1043
1620
|
ind_det = -1
|
|
1044
1621
|
for plug_IDs in plugins_sorted:
|
|
1045
1622
|
for ind_plugin, plugin in enumerate(plug_IDs):
|
|
1046
|
-
plug_name = plugin[
|
|
1047
|
-
plug_init = plugin[
|
|
1048
|
-
plug_settings = plugin[
|
|
1623
|
+
plug_name = plugin["value"].child("name").value()
|
|
1624
|
+
plug_init = plugin["value"].child("init").value()
|
|
1625
|
+
plug_settings = plugin["value"].child("params")
|
|
1049
1626
|
self.splash_sc.showMessage(
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1627
|
+
"Loading {:s} module: {:s}".format(plugin["type"], plug_name)
|
|
1628
|
+
)
|
|
1629
|
+
|
|
1630
|
+
if plugin["type"] == "move":
|
|
1631
|
+
plug_type = plug_settings.child(
|
|
1632
|
+
"main_settings", "move_type"
|
|
1633
|
+
).value()
|
|
1634
|
+
self.add_move(
|
|
1635
|
+
plug_name,
|
|
1636
|
+
plug_settings,
|
|
1637
|
+
plug_type,
|
|
1638
|
+
move_docks,
|
|
1639
|
+
move_forms,
|
|
1640
|
+
actuators_modules,
|
|
1641
|
+
)
|
|
1056
1642
|
|
|
1057
1643
|
if ind_plugin == 0: # should be a master type plugin
|
|
1058
|
-
if plugin[
|
|
1059
|
-
raise MasterSlaveError(
|
|
1060
|
-
|
|
1644
|
+
if plugin["status"] != "Master":
|
|
1645
|
+
raise MasterSlaveError(
|
|
1646
|
+
f"The instrument {plug_name} should"
|
|
1647
|
+
f" be defined as Master"
|
|
1648
|
+
)
|
|
1061
1649
|
if plug_init:
|
|
1062
1650
|
actuators_modules[-1].init_hardware_ui()
|
|
1063
1651
|
QtWidgets.QApplication.processEvents()
|
|
1064
1652
|
self.poll_init(actuators_modules[-1])
|
|
1065
1653
|
QtWidgets.QApplication.processEvents()
|
|
1066
1654
|
master_controller = actuators_modules[-1].controller
|
|
1067
|
-
elif plugin[
|
|
1655
|
+
elif plugin["status"] == "Master" and len(plug_IDs) > 1:
|
|
1068
1656
|
raise MasterSlaveError(
|
|
1069
|
-
f
|
|
1070
|
-
f
|
|
1071
|
-
f
|
|
1657
|
+
f"The instrument {plug_name} defined as Master has to be "
|
|
1658
|
+
f"initialized (init checked in the preset) in order to init "
|
|
1659
|
+
f"its associated slave instrument"
|
|
1072
1660
|
)
|
|
1073
1661
|
else:
|
|
1074
|
-
if plugin[
|
|
1075
|
-
raise MasterSlaveError(
|
|
1076
|
-
|
|
1662
|
+
if plugin["status"] != "Slave":
|
|
1663
|
+
raise MasterSlaveError(
|
|
1664
|
+
f"The instrument {plug_name} should"
|
|
1665
|
+
f" be defined as slave"
|
|
1666
|
+
)
|
|
1077
1667
|
if plug_init:
|
|
1078
1668
|
actuators_modules[-1].controller = master_controller
|
|
1079
1669
|
actuators_modules[-1].init_hardware_ui()
|
|
@@ -1082,30 +1672,39 @@ class DashBoard(CustomApp):
|
|
|
1082
1672
|
QtWidgets.QApplication.processEvents()
|
|
1083
1673
|
else:
|
|
1084
1674
|
ind_det += 1
|
|
1085
|
-
self.add_det(
|
|
1086
|
-
|
|
1675
|
+
self.add_det(
|
|
1676
|
+
plug_name,
|
|
1677
|
+
plug_settings,
|
|
1678
|
+
det_docks_settings,
|
|
1679
|
+
det_docks_viewer,
|
|
1680
|
+
detector_modules,
|
|
1681
|
+
)
|
|
1087
1682
|
QtWidgets.QApplication.processEvents()
|
|
1088
1683
|
|
|
1089
1684
|
if ind_plugin == 0: # should be a master type plugin
|
|
1090
|
-
if plugin[
|
|
1091
|
-
raise MasterSlaveError(
|
|
1092
|
-
|
|
1685
|
+
if plugin["status"] != "Master":
|
|
1686
|
+
raise MasterSlaveError(
|
|
1687
|
+
f"The instrument {plug_name} should"
|
|
1688
|
+
f" be defined as Master"
|
|
1689
|
+
)
|
|
1093
1690
|
if plug_init:
|
|
1094
1691
|
detector_modules[-1].init_hardware_ui()
|
|
1095
1692
|
QtWidgets.QApplication.processEvents()
|
|
1096
1693
|
self.poll_init(detector_modules[-1])
|
|
1097
1694
|
QtWidgets.QApplication.processEvents()
|
|
1098
1695
|
master_controller = detector_modules[-1].controller
|
|
1099
|
-
elif plugin[
|
|
1696
|
+
elif plugin["status"] == "Master" and len(plug_IDs) > 1:
|
|
1100
1697
|
raise MasterSlaveError(
|
|
1101
|
-
f
|
|
1102
|
-
f
|
|
1103
|
-
f
|
|
1698
|
+
f"The instrument {plug_name} defined as Master has to be "
|
|
1699
|
+
f"initialized (init checked in the preset) in order to init "
|
|
1700
|
+
f"its associated slave instrument"
|
|
1104
1701
|
)
|
|
1105
1702
|
else:
|
|
1106
|
-
if plugin[
|
|
1107
|
-
raise MasterSlaveError(
|
|
1108
|
-
|
|
1703
|
+
if plugin["status"] != "Slave":
|
|
1704
|
+
raise MasterSlaveError(
|
|
1705
|
+
f"The instrument {plug_name} should"
|
|
1706
|
+
f" be defined as Slave"
|
|
1707
|
+
)
|
|
1109
1708
|
if plug_init:
|
|
1110
1709
|
detector_modules[-1].controller = master_controller
|
|
1111
1710
|
detector_modules[-1].init_hardware_ui()
|
|
@@ -1113,23 +1712,27 @@ class DashBoard(CustomApp):
|
|
|
1113
1712
|
self.poll_init(detector_modules[-1])
|
|
1114
1713
|
QtWidgets.QApplication.processEvents()
|
|
1115
1714
|
|
|
1116
|
-
detector_modules[-1].settings.child(
|
|
1117
|
-
|
|
1715
|
+
detector_modules[-1].settings.child(
|
|
1716
|
+
"main_settings", "overshoot"
|
|
1717
|
+
).show()
|
|
1718
|
+
detector_modules[-1].overshoot_signal[bool].connect(
|
|
1719
|
+
self.stop_moves_from_overshoot
|
|
1720
|
+
)
|
|
1118
1721
|
|
|
1119
1722
|
QtWidgets.QApplication.processEvents()
|
|
1120
1723
|
# restore dock state if saved
|
|
1121
1724
|
|
|
1122
1725
|
self.title = self.preset_file.stem
|
|
1123
|
-
path = layout_path.joinpath(self.title +
|
|
1726
|
+
path = layout_path.joinpath(self.title + ".dock")
|
|
1124
1727
|
if path.is_file():
|
|
1125
1728
|
self.load_layout_state(path)
|
|
1126
1729
|
|
|
1127
|
-
self.mainwindow.setWindowTitle(f
|
|
1730
|
+
self.mainwindow.setWindowTitle(f"PyMoDAQ Dashboard: {self.title}")
|
|
1128
1731
|
if self.pid_module is not None:
|
|
1129
1732
|
self.pid_module.set_module_manager(detector_modules, actuators_modules)
|
|
1130
1733
|
return actuators_modules, detector_modules
|
|
1131
1734
|
else:
|
|
1132
|
-
logger.error(
|
|
1735
|
+
logger.error("Invalid file selected")
|
|
1133
1736
|
return actuators_modules, detector_modules
|
|
1134
1737
|
|
|
1135
1738
|
def poll_init(self, module):
|
|
@@ -1147,11 +1750,13 @@ class DashBoard(CustomApp):
|
|
|
1147
1750
|
if not isinstance(filename, Path):
|
|
1148
1751
|
filename = Path(filename)
|
|
1149
1752
|
try:
|
|
1150
|
-
if filename.suffix ==
|
|
1753
|
+
if filename.suffix == ".xml":
|
|
1151
1754
|
file = filename.stem
|
|
1152
|
-
self.settings.child(
|
|
1153
|
-
self.update_status(
|
|
1154
|
-
|
|
1755
|
+
self.settings.child("loaded_files", "roi_file").setValue(file)
|
|
1756
|
+
self.update_status(
|
|
1757
|
+
"ROI configuration ({}) has been loaded".format(file),
|
|
1758
|
+
log_type="log",
|
|
1759
|
+
)
|
|
1155
1760
|
self.roi_saver.set_file_roi(filename, show=False)
|
|
1156
1761
|
|
|
1157
1762
|
except Exception as e:
|
|
@@ -1161,11 +1766,11 @@ class DashBoard(CustomApp):
|
|
|
1161
1766
|
if not isinstance(filename, Path):
|
|
1162
1767
|
filename = Path(filename)
|
|
1163
1768
|
ext = filename.suffix
|
|
1164
|
-
if ext ==
|
|
1769
|
+
if ext == ".xml":
|
|
1165
1770
|
self.remote_file = filename
|
|
1166
1771
|
self.remote_manager.remote_changed.connect(self.activate_remote)
|
|
1167
1772
|
self.remote_manager.set_file_remote(filename, show=False)
|
|
1168
|
-
self.settings.child(
|
|
1773
|
+
self.settings.child("loaded_files", "remote_file").setValue(filename)
|
|
1169
1774
|
self.remote_manager.set_remote_configuration()
|
|
1170
1775
|
self.remote_dock.addWidget(self.remote_manager.remote_settings_tree)
|
|
1171
1776
|
self.remote_dock.setVisible(True)
|
|
@@ -1187,25 +1792,31 @@ class DashBoard(CustomApp):
|
|
|
1187
1792
|
module_name=module, module_type=module_type)
|
|
1188
1793
|
|
|
1189
1794
|
"""
|
|
1190
|
-
if remote_action[
|
|
1191
|
-
if remote_action[
|
|
1192
|
-
self.shortcuts[remote_action[
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1795
|
+
if remote_action["action_type"] == "shortcut":
|
|
1796
|
+
if remote_action["action_name"] not in self.shortcuts:
|
|
1797
|
+
self.shortcuts[remote_action["action_name"]] = QtWidgets.QShortcut(
|
|
1798
|
+
QtGui.QKeySequence(remote_action["action_dict"]["shortcut"]),
|
|
1799
|
+
self.dockarea,
|
|
1800
|
+
)
|
|
1801
|
+
self.activate_shortcut(
|
|
1802
|
+
self.shortcuts[remote_action["action_name"]],
|
|
1803
|
+
remote_action["action_dict"],
|
|
1804
|
+
activate=remote_action["action_dict"]["activated"],
|
|
1805
|
+
)
|
|
1806
|
+
|
|
1807
|
+
elif remote_action["action_type"] == "joystick":
|
|
1200
1808
|
if not self.ispygame_init:
|
|
1201
1809
|
self.init_pygame()
|
|
1202
1810
|
|
|
1203
|
-
if remote_action[
|
|
1204
|
-
self.joysticks[remote_action[
|
|
1811
|
+
if remote_action["action_name"] not in self.joysticks:
|
|
1812
|
+
self.joysticks[remote_action["action_name"]] = remote_action[
|
|
1813
|
+
"action_dict"
|
|
1814
|
+
]
|
|
1205
1815
|
|
|
1206
1816
|
def init_pygame(self):
|
|
1207
1817
|
try:
|
|
1208
1818
|
import pygame
|
|
1819
|
+
|
|
1209
1820
|
self.pygame = pygame
|
|
1210
1821
|
pygame.init()
|
|
1211
1822
|
pygame.joystick.init()
|
|
@@ -1213,15 +1824,15 @@ class DashBoard(CustomApp):
|
|
|
1213
1824
|
self.joysticks_obj = []
|
|
1214
1825
|
for ind in range(joystick_count):
|
|
1215
1826
|
self.joysticks_obj.append(dict(obj=pygame.joystick.Joystick(ind)))
|
|
1216
|
-
self.joysticks_obj[-1][
|
|
1217
|
-
self.joysticks_obj[-1][
|
|
1827
|
+
self.joysticks_obj[-1]["obj"].init()
|
|
1828
|
+
self.joysticks_obj[-1]["id"] = self.joysticks_obj[-1]["obj"].get_id()
|
|
1218
1829
|
|
|
1219
1830
|
self.remote_timer.timeout.connect(self.pygame_loop)
|
|
1220
1831
|
self.ispygame_init = True
|
|
1221
1832
|
self.remote_timer.start(10)
|
|
1222
1833
|
|
|
1223
1834
|
except ImportError as e:
|
|
1224
|
-
logger.warning(
|
|
1835
|
+
logger.warning("No pygame module installed. Needed for joystick control")
|
|
1225
1836
|
|
|
1226
1837
|
def pygame_loop(self):
|
|
1227
1838
|
"""
|
|
@@ -1235,24 +1846,33 @@ class DashBoard(CustomApp):
|
|
|
1235
1846
|
"""
|
|
1236
1847
|
|
|
1237
1848
|
for action_dict in self.joysticks.values():
|
|
1238
|
-
if
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1849
|
+
if (
|
|
1850
|
+
action_dict["activated"]
|
|
1851
|
+
and action_dict["actionner_type"].lower() == "axis"
|
|
1852
|
+
):
|
|
1853
|
+
if action_dict["module_type"] == "act":
|
|
1854
|
+
joy = utils.find_dict_in_list_from_key_val(
|
|
1855
|
+
self.joysticks_obj, "id", action_dict["joystickID"]
|
|
1856
|
+
)
|
|
1857
|
+
val = joy["obj"].get_axis(action_dict["actionnerID"])
|
|
1243
1858
|
if abs(val) > 1e-4:
|
|
1244
1859
|
module = self.modules_manager.get_mod_from_name(
|
|
1245
|
-
action_dict[
|
|
1246
|
-
|
|
1247
|
-
action = getattr(module, action_dict[
|
|
1860
|
+
action_dict["module_name"], mod=action_dict["module_type"]
|
|
1861
|
+
)
|
|
1862
|
+
action = getattr(module, action_dict["action"])
|
|
1248
1863
|
if module.move_done_bool:
|
|
1249
|
-
action(
|
|
1250
|
-
|
|
1864
|
+
action(
|
|
1865
|
+
val
|
|
1866
|
+
* 1
|
|
1867
|
+
* module.settings.child(
|
|
1868
|
+
"move_settings", "epsilon"
|
|
1869
|
+
).value()
|
|
1870
|
+
)
|
|
1251
1871
|
|
|
1252
1872
|
# # For other actions use the event loop
|
|
1253
1873
|
for event in self.pygame.event.get(): # User did something.
|
|
1254
1874
|
selection = dict([])
|
|
1255
|
-
if
|
|
1875
|
+
if "joy" in event.dict:
|
|
1256
1876
|
selection.update(dict(joy=event.joy))
|
|
1257
1877
|
if event.type == self.pygame.JOYBUTTONDOWN:
|
|
1258
1878
|
selection.update(dict(button=event.button))
|
|
@@ -1262,24 +1882,28 @@ class DashBoard(CustomApp):
|
|
|
1262
1882
|
selection.update(dict(hat=event.hat, value=event.value))
|
|
1263
1883
|
if len(selection) > 1:
|
|
1264
1884
|
for action_dict in self.joysticks.values():
|
|
1265
|
-
if action_dict[
|
|
1885
|
+
if action_dict["activated"]:
|
|
1266
1886
|
module = self.modules_manager.get_mod_from_name(
|
|
1267
|
-
action_dict[
|
|
1268
|
-
|
|
1269
|
-
if action_dict[
|
|
1270
|
-
action = getattr(module, action_dict[
|
|
1887
|
+
action_dict["module_name"], mod=action_dict["module_type"]
|
|
1888
|
+
)
|
|
1889
|
+
if action_dict["module_type"] == "det":
|
|
1890
|
+
action = getattr(module, action_dict["action"])
|
|
1271
1891
|
else:
|
|
1272
|
-
action = getattr(module, action_dict[
|
|
1273
|
-
|
|
1274
|
-
if action_dict[
|
|
1275
|
-
if (
|
|
1276
|
-
|
|
1277
|
-
|
|
1892
|
+
action = getattr(module, action_dict["action"])
|
|
1893
|
+
|
|
1894
|
+
if action_dict["joystickID"] == selection["joy"]:
|
|
1895
|
+
if (
|
|
1896
|
+
action_dict["actionner_type"].lower() == "button"
|
|
1897
|
+
and "button" in selection
|
|
1898
|
+
):
|
|
1899
|
+
if action_dict["actionnerID"] == selection["button"]:
|
|
1278
1900
|
action()
|
|
1279
|
-
elif (
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1901
|
+
elif (
|
|
1902
|
+
action_dict["actionner_type"].lower() == "hat"
|
|
1903
|
+
and "hat" in selection
|
|
1904
|
+
):
|
|
1905
|
+
if action_dict["actionnerID"] == selection["hat"]:
|
|
1906
|
+
action(selection["value"])
|
|
1283
1907
|
|
|
1284
1908
|
QtWidgets.QApplication.processEvents()
|
|
1285
1909
|
|
|
@@ -1299,8 +1923,7 @@ class DashBoard(CustomApp):
|
|
|
1299
1923
|
|
|
1300
1924
|
"""
|
|
1301
1925
|
if activate:
|
|
1302
|
-
shortcut.activated.connect(
|
|
1303
|
-
self.create_activated_shortcut(action))
|
|
1926
|
+
shortcut.activated.connect(self.create_activated_shortcut(action))
|
|
1304
1927
|
else:
|
|
1305
1928
|
try:
|
|
1306
1929
|
shortcut.activated.disconnect()
|
|
@@ -1308,40 +1931,43 @@ class DashBoard(CustomApp):
|
|
|
1308
1931
|
pass
|
|
1309
1932
|
|
|
1310
1933
|
def create_activated_shortcut(self, action):
|
|
1311
|
-
module = self.modules_manager.get_mod_from_name(
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1934
|
+
module = self.modules_manager.get_mod_from_name(
|
|
1935
|
+
action["module_name"], mod=action["module_type"]
|
|
1936
|
+
)
|
|
1937
|
+
if action["module_type"] == "det":
|
|
1938
|
+
return lambda: getattr(module, action["action"])()
|
|
1315
1939
|
else:
|
|
1316
|
-
return lambda: getattr(module, action[
|
|
1940
|
+
return lambda: getattr(module, action["action"])()
|
|
1317
1941
|
|
|
1318
1942
|
def set_overshoot_configuration(self, filename):
|
|
1319
1943
|
try:
|
|
1320
1944
|
if not isinstance(filename, Path):
|
|
1321
1945
|
filename = Path(filename)
|
|
1322
1946
|
|
|
1323
|
-
if filename.suffix ==
|
|
1947
|
+
if filename.suffix == ".xml":
|
|
1324
1948
|
file = filename.stem
|
|
1325
|
-
self.settings.child(
|
|
1326
|
-
self.update_status(
|
|
1327
|
-
|
|
1949
|
+
self.settings.child("loaded_files", "overshoot_file").setValue(file)
|
|
1950
|
+
self.update_status(
|
|
1951
|
+
"Overshoot configuration ({}) has been loaded".format(file),
|
|
1952
|
+
log_type="log",
|
|
1953
|
+
)
|
|
1328
1954
|
self.overshoot_manager.set_file_overshoot(filename, show=False)
|
|
1329
|
-
self.set_action_enabled(
|
|
1330
|
-
self.set_action_checked(
|
|
1331
|
-
self.get_action(
|
|
1955
|
+
self.set_action_enabled("activate_overshoot", True)
|
|
1956
|
+
self.set_action_checked("activate_overshoot", False)
|
|
1957
|
+
self.get_action("activate_overshoot").trigger()
|
|
1332
1958
|
|
|
1333
1959
|
except Exception as e:
|
|
1334
1960
|
logger.exception(str(e))
|
|
1335
1961
|
|
|
1336
1962
|
def activate_overshoot(self, status: bool):
|
|
1337
1963
|
try:
|
|
1338
|
-
self.overshoot_manager.activate_overshoot(
|
|
1339
|
-
|
|
1340
|
-
|
|
1964
|
+
self.overshoot_manager.activate_overshoot(
|
|
1965
|
+
self.detector_modules, self.actuators_modules, status
|
|
1966
|
+
)
|
|
1341
1967
|
except Exception as e:
|
|
1342
|
-
logger.warning(f
|
|
1343
|
-
self.set_action_checked(
|
|
1344
|
-
self.set_action_enabled(
|
|
1968
|
+
logger.warning(f"Could not load the overshoot file:\n{str(e)}")
|
|
1969
|
+
self.set_action_checked("activate_overshoot", False)
|
|
1970
|
+
self.set_action_enabled("activate_overshoot", False)
|
|
1345
1971
|
|
|
1346
1972
|
@property
|
|
1347
1973
|
def move_modules(self):
|
|
@@ -1352,34 +1978,34 @@ class DashBoard(CustomApp):
|
|
|
1352
1978
|
|
|
1353
1979
|
def set_preset_mode(self, filename):
|
|
1354
1980
|
"""
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1981
|
+
| Set the managers mode from the given filename.
|
|
1982
|
+
|
|
|
1983
|
+
| In case of "mock" or "canon" move, set the corresponding managers calling
|
|
1984
|
+
set_(*)_preset procedure.
|
|
1985
|
+
|
|
|
1986
|
+
| Else set the managers file using set_file_preset function.
|
|
1987
|
+
| Once done connect the move and detector modules to logger to recipe/transmit
|
|
1988
|
+
informations.
|
|
1989
|
+
|
|
1990
|
+
Finally update DAQ_scan_settings tree with :
|
|
1991
|
+
* Detectors
|
|
1992
|
+
* Move
|
|
1993
|
+
* plot_form.
|
|
1994
|
+
|
|
1995
|
+
=============== =========== =============================================
|
|
1996
|
+
**Parameters** **Type** **Description**
|
|
1997
|
+
*filename* string the name of the managers file to be treated
|
|
1998
|
+
=============== =========== =============================================
|
|
1999
|
+
|
|
2000
|
+
See Also
|
|
2001
|
+
--------
|
|
2002
|
+
set_Mock_preset, set_canon_preset, set_file_preset, add_status, update_status
|
|
1377
2003
|
"""
|
|
1378
2004
|
try:
|
|
1379
2005
|
if not isinstance(filename, Path):
|
|
1380
2006
|
filename = Path(filename)
|
|
1381
2007
|
|
|
1382
|
-
self.get_action(
|
|
2008
|
+
self.get_action("preset_list").setCurrentText(filename.stem)
|
|
1383
2009
|
|
|
1384
2010
|
self.mainwindow.setVisible(False)
|
|
1385
2011
|
for area in self.dockarea.tempAreas:
|
|
@@ -1388,12 +2014,12 @@ class DashBoard(CustomApp):
|
|
|
1388
2014
|
self.splash_sc.show()
|
|
1389
2015
|
QtWidgets.QApplication.processEvents()
|
|
1390
2016
|
self.splash_sc.raise_()
|
|
1391
|
-
self.splash_sc.showMessage(
|
|
2017
|
+
self.splash_sc.showMessage("Loading Modules, please wait")
|
|
1392
2018
|
QtWidgets.QApplication.processEvents()
|
|
1393
2019
|
self.clear_move_det_controllers()
|
|
1394
2020
|
QtWidgets.QApplication.processEvents()
|
|
1395
2021
|
|
|
1396
|
-
logger.info(f
|
|
2022
|
+
logger.info(f"Loading Preset file: {filename}")
|
|
1397
2023
|
|
|
1398
2024
|
try:
|
|
1399
2025
|
actuators_modules, detector_modules = self.set_file_preset(filename)
|
|
@@ -1402,17 +2028,29 @@ class DashBoard(CustomApp):
|
|
|
1402
2028
|
self.mainwindow.setVisible(True)
|
|
1403
2029
|
for area in self.dockarea.tempAreas:
|
|
1404
2030
|
area.window().setVisible(True)
|
|
1405
|
-
messagebox(
|
|
1406
|
-
|
|
2031
|
+
messagebox(
|
|
2032
|
+
severity="critical",
|
|
2033
|
+
title="Preset loading error",
|
|
2034
|
+
text=f"""
|
|
2035
|
+
<p>{error}</p>
|
|
2036
|
+
<p>This error may be related to:</p>
|
|
2037
|
+
<p>Saved preset file is not compatible anymore.</p>
|
|
2038
|
+
<p>Please recreate the preset at <b>{filename}</b>.</p>
|
|
2039
|
+
""",
|
|
2040
|
+
)
|
|
1407
2041
|
logger.exception(str(error))
|
|
1408
2042
|
|
|
1409
2043
|
self.quit_fun()
|
|
1410
2044
|
return
|
|
1411
2045
|
|
|
1412
2046
|
if not (not actuators_modules and not detector_modules):
|
|
1413
|
-
self.update_status(
|
|
1414
|
-
|
|
1415
|
-
|
|
2047
|
+
self.update_status(
|
|
2048
|
+
"Preset mode ({}) has been loaded".format(filename.name),
|
|
2049
|
+
log_type="log",
|
|
2050
|
+
)
|
|
2051
|
+
self.settings.child("loaded_files", "preset_file").setValue(
|
|
2052
|
+
filename.name
|
|
2053
|
+
)
|
|
1416
2054
|
self.actuators_modules = actuators_modules
|
|
1417
2055
|
self.detector_modules = detector_modules
|
|
1418
2056
|
|
|
@@ -1421,7 +2059,8 @@ class DashBoard(CustomApp):
|
|
|
1421
2059
|
#####################################################
|
|
1422
2060
|
self.overshoot_manager = OvershootManager(
|
|
1423
2061
|
det_modules=[det.title for det in detector_modules],
|
|
1424
|
-
actuators_modules=[move.title for move in actuators_modules]
|
|
2062
|
+
actuators_modules=[move.title for move in actuators_modules],
|
|
2063
|
+
)
|
|
1425
2064
|
# load overshoot if present
|
|
1426
2065
|
file = filename.name
|
|
1427
2066
|
path = overshoot_path.joinpath(file)
|
|
@@ -1430,7 +2069,8 @@ class DashBoard(CustomApp):
|
|
|
1430
2069
|
|
|
1431
2070
|
self.remote_manager = RemoteManager(
|
|
1432
2071
|
actuators=[move.title for move in actuators_modules],
|
|
1433
|
-
detectors=[det.title for det in detector_modules]
|
|
2072
|
+
detectors=[det.title for det in detector_modules],
|
|
2073
|
+
)
|
|
1434
2074
|
# load remote file if present
|
|
1435
2075
|
file = filename.name
|
|
1436
2076
|
path = remote_path.joinpath(file)
|
|
@@ -1457,8 +2097,8 @@ class DashBoard(CustomApp):
|
|
|
1457
2097
|
self.pid_window.show()
|
|
1458
2098
|
|
|
1459
2099
|
self.load_preset_menu.setEnabled(False)
|
|
1460
|
-
self.set_action_enabled(
|
|
1461
|
-
self.set_action_enabled(
|
|
2100
|
+
self.set_action_enabled("load_preset", False)
|
|
2101
|
+
self.set_action_enabled("preset_list", False)
|
|
1462
2102
|
self.overshoot_menu.setEnabled(True)
|
|
1463
2103
|
self.roi_menu.setEnabled(True)
|
|
1464
2104
|
self.remote_menu.setEnabled(True)
|
|
@@ -1469,37 +2109,45 @@ class DashBoard(CustomApp):
|
|
|
1469
2109
|
|
|
1470
2110
|
self.preset_loaded_signal.emit(True)
|
|
1471
2111
|
|
|
1472
|
-
logger.info(f
|
|
2112
|
+
logger.info(f"Preset file: {filename} has been loaded")
|
|
1473
2113
|
|
|
1474
2114
|
except Exception as e:
|
|
1475
2115
|
logger.exception(str(e))
|
|
1476
2116
|
|
|
1477
2117
|
def update_init_tree(self):
|
|
1478
2118
|
for act in self.actuators_modules:
|
|
1479
|
-
name =
|
|
1480
|
-
if act.title not in [
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
2119
|
+
name = "".join(act.title.split()) # remove empty spaces
|
|
2120
|
+
if act.title not in [
|
|
2121
|
+
ac.title()
|
|
2122
|
+
for ac in putils.iter_children_params(
|
|
2123
|
+
self.settings.child("actuators"), []
|
|
2124
|
+
)
|
|
2125
|
+
]:
|
|
2126
|
+
self.settings.child("actuators").addChild(
|
|
2127
|
+
{"title": act.title, "name": name, "type": "led", "value": False}
|
|
2128
|
+
)
|
|
1485
2129
|
QtWidgets.QApplication.processEvents()
|
|
1486
|
-
self.settings.child(
|
|
2130
|
+
self.settings.child("actuators", name).setValue(act.initialized_state)
|
|
1487
2131
|
|
|
1488
2132
|
for det in self.detector_modules:
|
|
1489
|
-
name =
|
|
1490
|
-
if det.title not in [
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
2133
|
+
name = "".join(det.title.split()) # remove empty spaces
|
|
2134
|
+
if det.title not in [
|
|
2135
|
+
de.title()
|
|
2136
|
+
for de in putils.iter_children_params(
|
|
2137
|
+
self.settings.child("detectors"), []
|
|
2138
|
+
)
|
|
2139
|
+
]:
|
|
2140
|
+
self.settings.child("detectors").addChild(
|
|
2141
|
+
{"title": det.title, "name": name, "type": "led", "value": False}
|
|
2142
|
+
)
|
|
1494
2143
|
QtWidgets.QApplication.processEvents()
|
|
1495
|
-
self.settings.child(
|
|
2144
|
+
self.settings.child("detectors", name).setValue(det.initialized_state)
|
|
1496
2145
|
|
|
1497
2146
|
def do_stuff_from_out_bounds(self, out_of_bounds: bool):
|
|
1498
|
-
|
|
1499
2147
|
if out_of_bounds:
|
|
1500
|
-
logger.warning(f
|
|
2148
|
+
logger.warning(f"Some actuators reached their bounds")
|
|
1501
2149
|
if self.scan_module is not None:
|
|
1502
|
-
logger.warning(f
|
|
2150
|
+
logger.warning(f"Stopping the DAQScan for out of bounds")
|
|
1503
2151
|
self.scan_module.stop_scan()
|
|
1504
2152
|
|
|
1505
2153
|
def stop_moves_from_overshoot(self, overshoot):
|
|
@@ -1508,11 +2156,11 @@ class DashBoard(CustomApp):
|
|
|
1508
2156
|
|
|
1509
2157
|
def stop_moves(self, *args, **kwargs):
|
|
1510
2158
|
"""
|
|
1511
|
-
|
|
2159
|
+
Foreach module of the move module object list, stop motion.
|
|
1512
2160
|
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
2161
|
+
See Also
|
|
2162
|
+
--------
|
|
2163
|
+
stop_scan, DAQ_Move_main.daq_move.stop_motion
|
|
1516
2164
|
"""
|
|
1517
2165
|
if self.scan_module is not None:
|
|
1518
2166
|
self.scan_module.stop_scan()
|
|
@@ -1522,15 +2170,16 @@ class DashBoard(CustomApp):
|
|
|
1522
2170
|
|
|
1523
2171
|
def show_log(self):
|
|
1524
2172
|
import webbrowser
|
|
1525
|
-
webbrowser.open(logging.getLogger('pymodaq').handlers[0].baseFilename)
|
|
1526
2173
|
|
|
1527
|
-
|
|
2174
|
+
webbrowser.open(logging.getLogger("pymodaq").handlers[0].baseFilename)
|
|
2175
|
+
|
|
2176
|
+
def show_config(self, config):
|
|
1528
2177
|
from pymodaq_gui.utils.widgets.tree_toml import TreeFromToml
|
|
1529
|
-
|
|
2178
|
+
|
|
2179
|
+
config_tree = TreeFromToml(config)
|
|
1530
2180
|
config_tree.show_dialog()
|
|
1531
2181
|
|
|
1532
2182
|
def setup_docks(self):
|
|
1533
|
-
|
|
1534
2183
|
# %% create logger dock
|
|
1535
2184
|
self.logger_dock = Dock("Logger")
|
|
1536
2185
|
self.logger_list = QtWidgets.QListWidget()
|
|
@@ -1541,13 +2190,15 @@ class DashBoard(CustomApp):
|
|
|
1541
2190
|
splitter.addWidget(self.logger_list)
|
|
1542
2191
|
self.logger_dock.addWidget(splitter)
|
|
1543
2192
|
|
|
1544
|
-
self.remote_dock = Dock(
|
|
1545
|
-
self.dockarea.addDock(self.remote_dock,
|
|
1546
|
-
self.dockarea.addDock(self.logger_dock,
|
|
2193
|
+
self.remote_dock = Dock("Remote controls")
|
|
2194
|
+
self.dockarea.addDock(self.remote_dock, "top")
|
|
2195
|
+
self.dockarea.addDock(self.logger_dock, "above", self.remote_dock)
|
|
1547
2196
|
self.logger_dock.setVisible(True)
|
|
1548
2197
|
|
|
1549
2198
|
self.remote_dock.setVisible(False)
|
|
1550
|
-
self.preset_manager = PresetManager(
|
|
2199
|
+
self.preset_manager = PresetManager(
|
|
2200
|
+
path=self.preset_path, extra_params=self.extra_params
|
|
2201
|
+
)
|
|
1551
2202
|
|
|
1552
2203
|
@property
|
|
1553
2204
|
def menubar(self):
|
|
@@ -1555,13 +2206,13 @@ class DashBoard(CustomApp):
|
|
|
1555
2206
|
|
|
1556
2207
|
def parameter_tree_changed(self, param, changes):
|
|
1557
2208
|
"""
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
2209
|
+
Foreach value changed, update :
|
|
2210
|
+
* Viewer in case of **DAQ_type** parameter name
|
|
2211
|
+
* visibility of button in case of **show_averaging** parameter name
|
|
2212
|
+
* visibility of naverage in case of **live_averaging** parameter name
|
|
2213
|
+
* scale of axis **else** (in 2D pymodaq type)
|
|
1563
2214
|
|
|
1564
|
-
|
|
2215
|
+
Once done emit the update settings signal to link the commit.
|
|
1565
2216
|
|
|
1566
2217
|
|
|
1567
2218
|
"""
|
|
@@ -1569,15 +2220,15 @@ class DashBoard(CustomApp):
|
|
|
1569
2220
|
for param, change, data in changes:
|
|
1570
2221
|
path = self.settings.childPath(param)
|
|
1571
2222
|
if path is not None:
|
|
1572
|
-
childName =
|
|
2223
|
+
childName = ".".join(path)
|
|
1573
2224
|
else:
|
|
1574
2225
|
childName = param.name()
|
|
1575
|
-
if change ==
|
|
2226
|
+
if change == "childAdded":
|
|
1576
2227
|
pass
|
|
1577
|
-
elif change ==
|
|
1578
|
-
if param.name() ==
|
|
2228
|
+
elif change == "value":
|
|
2229
|
+
if param.name() == "log_level":
|
|
1579
2230
|
logger.setLevel(param.value())
|
|
1580
|
-
elif change ==
|
|
2231
|
+
elif change == "parent":
|
|
1581
2232
|
pass
|
|
1582
2233
|
|
|
1583
2234
|
def show_about(self):
|
|
@@ -1585,41 +2236,46 @@ class DashBoard(CustomApp):
|
|
|
1585
2236
|
self.splash_sc.showMessage(
|
|
1586
2237
|
f"PyMoDAQ version {get_version('pymodaq')}\n"
|
|
1587
2238
|
f"Modular Acquisition with Python\n"
|
|
1588
|
-
f"Written by Sébastien Weber"
|
|
2239
|
+
f"Written by Sébastien Weber"
|
|
2240
|
+
)
|
|
1589
2241
|
|
|
1590
2242
|
def check_update(self, show=True):
|
|
1591
|
-
|
|
1592
2243
|
try:
|
|
1593
|
-
packages = [
|
|
2244
|
+
packages = ["pymodaq_utils", "pymodaq_data", "pymodaq_gui", "pymodaq"]
|
|
1594
2245
|
current_versions = [version_mod.parse(get_version(p)) for p in packages]
|
|
1595
|
-
available_versions = [
|
|
2246
|
+
available_versions = [
|
|
2247
|
+
version_mod.parse(get_pypi_pymodaq(p)["version"]) for p in packages
|
|
2248
|
+
]
|
|
1596
2249
|
new_versions = np.greater(available_versions, current_versions)
|
|
1597
2250
|
# Combine package and version information and select only the ones with a newer version available
|
|
1598
2251
|
|
|
1599
|
-
|
|
1600
|
-
|
|
2252
|
+
packages_data = np.array(
|
|
2253
|
+
list(zip(packages, current_versions, available_versions))
|
|
2254
|
+
)[new_versions]
|
|
1601
2255
|
|
|
1602
2256
|
if len(packages_data) > 0:
|
|
1603
|
-
#Create a QDialog window and different graphical components
|
|
2257
|
+
# Create a QDialog window and different graphical components
|
|
1604
2258
|
dialog = QtWidgets.QDialog()
|
|
1605
2259
|
dialog.setWindowTitle("Update check")
|
|
1606
|
-
|
|
2260
|
+
|
|
1607
2261
|
vlayout = QtWidgets.QVBoxLayout()
|
|
1608
2262
|
|
|
1609
|
-
message_label = QLabel(
|
|
2263
|
+
message_label = QLabel(
|
|
2264
|
+
"New versions of PyMoDAQ packages available!\nUse your package manager to update."
|
|
2265
|
+
)
|
|
1610
2266
|
message_label.setAlignment(Qt.AlignCenter)
|
|
1611
|
-
|
|
1612
2267
|
|
|
1613
2268
|
table = PymodaqUpdateTableWidget()
|
|
1614
|
-
table.setRowCount(len(packages_data))
|
|
2269
|
+
table.setRowCount(len(packages_data))
|
|
1615
2270
|
table.setColumnCount(3)
|
|
1616
|
-
table.setHorizontalHeaderLabels(
|
|
1617
|
-
|
|
2271
|
+
table.setHorizontalHeaderLabels(
|
|
2272
|
+
["Package", "Current version", "New version"]
|
|
2273
|
+
)
|
|
2274
|
+
|
|
1618
2275
|
for p in packages_data:
|
|
1619
2276
|
table.append_row(p[0], p[1], p[2])
|
|
1620
2277
|
|
|
1621
|
-
|
|
1622
|
-
# The vlayout contains the message, the table and the buttons
|
|
2278
|
+
# The vlayout contains the message, the table and the buttons
|
|
1623
2279
|
# and is connected to the dialog window
|
|
1624
2280
|
vlayout.addWidget(message_label)
|
|
1625
2281
|
vlayout.addWidget(table)
|
|
@@ -1629,7 +2285,7 @@ class DashBoard(CustomApp):
|
|
|
1629
2285
|
|
|
1630
2286
|
else:
|
|
1631
2287
|
if show:
|
|
1632
|
-
msgBox =
|
|
2288
|
+
msgBox = QMessageBox()
|
|
1633
2289
|
msgBox.setWindowTitle("Update check")
|
|
1634
2290
|
msgBox.setText("Everything is up to date!")
|
|
1635
2291
|
ret = msgBox.exec()
|
|
@@ -1638,48 +2294,48 @@ class DashBoard(CustomApp):
|
|
|
1638
2294
|
|
|
1639
2295
|
return False
|
|
1640
2296
|
|
|
1641
|
-
def show_file_attributes(self, type_info=
|
|
2297
|
+
def show_file_attributes(self, type_info="dataset"):
|
|
1642
2298
|
"""
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
2299
|
+
Switch the type_info value.
|
|
2300
|
+
|
|
2301
|
+
In case of :
|
|
2302
|
+
* *scan* : Set parameters showing top false
|
|
2303
|
+
* *dataset* : Set parameters showing top false
|
|
2304
|
+
* *managers* : Set parameters showing top false.
|
|
2305
|
+
Add the save/cancel buttons to the accept/reject dialog
|
|
2306
|
+
(to save managers parameters in a xml file).
|
|
2307
|
+
|
|
2308
|
+
Finally, in case of accepted managers type info,
|
|
2309
|
+
save the managers parameters in a xml file.
|
|
2310
|
+
|
|
2311
|
+
=============== =========== ====================================
|
|
2312
|
+
**Parameters** **Type** **Description**
|
|
2313
|
+
*type_info* string The file type information between
|
|
2314
|
+
* scan
|
|
2315
|
+
* dataset
|
|
2316
|
+
* managers
|
|
2317
|
+
=============== =========== ====================================
|
|
1662
2318
|
"""
|
|
1663
2319
|
dialog = QtWidgets.QDialog()
|
|
1664
2320
|
vlayout = QtWidgets.QVBoxLayout()
|
|
1665
2321
|
tree = ParameterTree()
|
|
1666
2322
|
tree.setMinimumWidth(400)
|
|
1667
2323
|
tree.setMinimumHeight(500)
|
|
1668
|
-
if type_info ==
|
|
2324
|
+
if type_info == "scan":
|
|
1669
2325
|
tree.setParameters(self.scan_attributes, showTop=False)
|
|
1670
|
-
elif type_info ==
|
|
2326
|
+
elif type_info == "dataset":
|
|
1671
2327
|
tree.setParameters(self.dataset_attributes, showTop=False)
|
|
1672
2328
|
|
|
1673
2329
|
vlayout.addWidget(tree)
|
|
1674
2330
|
dialog.setLayout(vlayout)
|
|
1675
|
-
buttonBox =
|
|
1676
|
-
buttonBox.addButton(
|
|
1677
|
-
buttonBox.addButton(
|
|
2331
|
+
buttonBox = QDialogButtonBox(parent=dialog)
|
|
2332
|
+
buttonBox.addButton("Cancel", QDialogButtonBox.ButtonRole.RejectRole)
|
|
2333
|
+
buttonBox.addButton("Apply", QDialogButtonBox.ButtonRole.AcceptRole)
|
|
1678
2334
|
buttonBox.rejected.connect(dialog.reject)
|
|
1679
2335
|
buttonBox.accepted.connect(dialog.accept)
|
|
1680
2336
|
|
|
1681
2337
|
vlayout.addWidget(buttonBox)
|
|
1682
|
-
dialog.setWindowTitle(
|
|
2338
|
+
dialog.setWindowTitle("Fill in information about this {}".format(type_info))
|
|
1683
2339
|
res = dialog.exec()
|
|
1684
2340
|
return res
|
|
1685
2341
|
|
|
@@ -1688,14 +2344,14 @@ class DashBoard(CustomApp):
|
|
|
1688
2344
|
|
|
1689
2345
|
def update_status(self, txt, wait_time=0, log_type=None):
|
|
1690
2346
|
"""
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
2347
|
+
Show the txt message in the status bar with a delay of wait_time ms.
|
|
2348
|
+
|
|
2349
|
+
=============== =========== =======================
|
|
2350
|
+
**Parameters** **Type** **Description**
|
|
2351
|
+
*txt* string The message to show
|
|
2352
|
+
*wait_time* int the delay of showing
|
|
2353
|
+
*log_type* string the type of the log
|
|
2354
|
+
=============== =========== =======================
|
|
1699
2355
|
"""
|
|
1700
2356
|
try:
|
|
1701
2357
|
if log_type is not None:
|
|
@@ -1707,21 +2363,34 @@ class DashBoard(CustomApp):
|
|
|
1707
2363
|
|
|
1708
2364
|
def main():
|
|
1709
2365
|
from pymodaq_gui.utils.utils import mkQApp
|
|
2366
|
+
from pymodaq.utils.gui_utils.loader_utils import load_dashboard_with_preset
|
|
1710
2367
|
|
|
2368
|
+
# Create application and main window
|
|
1711
2369
|
app = mkQApp('Dashboard')
|
|
1712
2370
|
|
|
1713
2371
|
win = QtWidgets.QMainWindow()
|
|
1714
2372
|
area = DockArea()
|
|
1715
2373
|
win.setCentralWidget(area)
|
|
1716
2374
|
win.resize(1000, 500)
|
|
1717
|
-
win.setWindowTitle(
|
|
2375
|
+
win.setWindowTitle("PyMoDAQ Dashboard")
|
|
2376
|
+
|
|
2377
|
+
# Command-line argument parsing
|
|
2378
|
+
parser = argparse.ArgumentParser(prog="dashboard", description="PyMoDAQ dashboard")
|
|
2379
|
+
parser.add_argument("-p", "--preset", metavar="PRESET_NAME", help="preset name to load")
|
|
2380
|
+
args = parser.parse_args()
|
|
1718
2381
|
|
|
1719
|
-
|
|
2382
|
+
# If preset name is supplied, load dashboard with this preset
|
|
2383
|
+
if args.preset:
|
|
2384
|
+
load_dashboard_with_preset(args.preset)
|
|
1720
2385
|
|
|
1721
|
-
|
|
2386
|
+
# If no command-line arguments are supplied, start empty
|
|
2387
|
+
else:
|
|
2388
|
+
prog = DashBoard(area)
|
|
2389
|
+
win.show()
|
|
1722
2390
|
|
|
2391
|
+
# Run application
|
|
1723
2392
|
app.exec()
|
|
1724
2393
|
|
|
1725
2394
|
|
|
1726
|
-
if __name__ ==
|
|
2395
|
+
if __name__ == "__main__":
|
|
1727
2396
|
main()
|