pymodaq 5.0.0__py3-none-any.whl → 5.0.2__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 +55 -89
- pymodaq/control_modules/daq_move.py +129 -55
- pymodaq/control_modules/daq_move_ui.py +42 -11
- pymodaq/control_modules/daq_viewer.py +32 -13
- pymodaq/control_modules/move_utility_classes.py +346 -79
- pymodaq/control_modules/utils.py +26 -9
- pymodaq/control_modules/viewer_utility_classes.py +51 -14
- pymodaq/daq_utils/daq_utils.py +6 -0
- pymodaq/dashboard.py +532 -263
- pymodaq/examples/qt_less_standalone_module.py +128 -0
- pymodaq/extensions/bayesian/bayesian_optimisation.py +30 -21
- pymodaq/extensions/bayesian/utils.py +6 -3
- pymodaq/extensions/daq_logger/__init__.py +1 -0
- pymodaq/extensions/daq_logger/daq_logger.py +4 -5
- pymodaq/extensions/daq_scan.py +28 -8
- pymodaq/extensions/daq_scan_ui.py +7 -9
- pymodaq/extensions/pid/__init__.py +0 -1
- pymodaq/extensions/pid/actuator_controller.py +13 -0
- pymodaq/extensions/pid/daq_move_PID.py +25 -46
- pymodaq/extensions/pid/pid_controller.py +49 -41
- pymodaq/extensions/pid/utils.py +7 -31
- pymodaq/extensions/utils.py +41 -7
- pymodaq/post_treatment/load_and_plot.py +43 -10
- pymodaq/resources/setup_plugin.py +1 -0
- pymodaq/updater.py +107 -0
- pymodaq/utils/chrono_timer.py +6 -7
- pymodaq/utils/daq_utils.py +6 -3
- pymodaq/utils/data.py +21 -17
- pymodaq/utils/enums.py +6 -0
- pymodaq/utils/gui_utils/loader_utils.py +29 -2
- pymodaq/utils/gui_utils/utils.py +9 -12
- pymodaq/utils/gui_utils/widgets/lcd.py +8 -0
- pymodaq/utils/h5modules/module_saving.py +5 -2
- pymodaq/utils/leco/daq_move_LECODirector.py +22 -16
- pymodaq/utils/leco/daq_xDviewer_LECODirector.py +15 -9
- pymodaq/utils/leco/leco_director.py +4 -3
- pymodaq/utils/leco/pymodaq_listener.py +9 -13
- pymodaq/utils/leco/utils.py +40 -7
- pymodaq/utils/managers/modules_manager.py +22 -12
- pymodaq/utils/managers/overshoot_manager.py +45 -1
- pymodaq/utils/managers/preset_manager.py +22 -46
- pymodaq/utils/managers/preset_manager_utils.py +17 -13
- pymodaq/utils/managers/remote_manager.py +1 -1
- pymodaq/utils/messenger.py +6 -0
- pymodaq/utils/parameter/__init__.py +5 -1
- pymodaq/utils/tcp_ip/mysocket.py +4 -110
- pymodaq/utils/tcp_ip/serializer.py +4 -769
- pymodaq/utils/tcp_ip/tcp_server_client.py +5 -5
- pymodaq-5.0.2.dist-info/METADATA +242 -0
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/RECORD +54 -55
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/WHEEL +1 -1
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/entry_points.txt +1 -0
- pymodaq/examples/custom_app.py +0 -255
- pymodaq/examples/custom_viewer.py +0 -112
- pymodaq/examples/parameter_ex.py +0 -158
- pymodaq/examples/preset_MockCamera.xml +0 -1
- pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.py +0 -142
- pymodaq/post_treatment/daq_measurement/daq_measurement_GUI.ui +0 -232
- pymodaq/post_treatment/daq_measurement/daq_measurement_main.py +0 -391
- pymodaq/post_treatment/daq_measurement/process_from_QtDesigner_DAQ_Measurement_GUI.bat +0 -2
- pymodaq-5.0.0.dist-info/METADATA +0 -166
- /pymodaq/{post_treatment/daq_measurement → daq_utils}/__init__.py +0 -0
- {pymodaq-5.0.0.dist-info → pymodaq-5.0.2.dist-info}/licenses/LICENSE +0 -0
pymodaq/dashboard.py
CHANGED
|
@@ -8,8 +8,12 @@ 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
|
|
12
|
+
|
|
13
|
+
|
|
11
14
|
from qtpy import QtGui, QtWidgets, QtCore
|
|
12
|
-
from qtpy.QtCore import Qt, QObject, Slot, QThread, Signal
|
|
15
|
+
from qtpy.QtCore import Qt, QObject, Slot, QThread, Signal, QSize
|
|
16
|
+
from qtpy.QtWidgets import QTableWidget, QTableWidgetItem, QCheckBox, QWidget, QLabel, QDialogButtonBox, QDialog
|
|
13
17
|
from time import perf_counter
|
|
14
18
|
import numpy as np
|
|
15
19
|
|
|
@@ -20,6 +24,7 @@ from pymodaq_utils.logger import set_logger, get_module_name
|
|
|
20
24
|
from pymodaq_utils import utils
|
|
21
25
|
from pymodaq_utils.utils import get_version, find_dict_in_list_from_key_val
|
|
22
26
|
from pymodaq_utils import config as configmod
|
|
27
|
+
from pymodaq_utils.enums import BaseEnum
|
|
23
28
|
|
|
24
29
|
from pymodaq_gui.parameter import ParameterTree, Parameter
|
|
25
30
|
from pymodaq_gui.utils import DockArea, Dock, select_file
|
|
@@ -27,25 +32,29 @@ import pymodaq_gui.utils.layout as layout_mod
|
|
|
27
32
|
from pymodaq_gui.messenger import messagebox
|
|
28
33
|
from pymodaq_gui.parameter import utils as putils
|
|
29
34
|
from pymodaq_gui.managers.roi_manager import ROISaver
|
|
35
|
+
from pymodaq_gui.utils.custom_app import CustomApp
|
|
30
36
|
|
|
31
37
|
from pymodaq.utils.managers.modules_manager import ModulesManager
|
|
32
38
|
from pymodaq.utils.managers.preset_manager import PresetManager
|
|
33
39
|
from pymodaq.utils.managers.overshoot_manager import OvershootManager
|
|
34
40
|
from pymodaq.utils.managers.remote_manager import RemoteManager
|
|
35
|
-
from pymodaq.utils.exceptions import DetectorError, ActuatorError,
|
|
41
|
+
from pymodaq.utils.exceptions import DetectorError, ActuatorError, MasterSlaveError
|
|
36
42
|
from pymodaq.utils.daq_utils import get_instrument_plugins
|
|
37
43
|
from pymodaq.utils.leco.utils import start_coordinator
|
|
38
44
|
from pymodaq.utils import config as config_mod_pymodaq
|
|
45
|
+
|
|
39
46
|
from pymodaq.control_modules.daq_move import DAQ_Move
|
|
40
47
|
from pymodaq.control_modules.daq_viewer import DAQ_Viewer
|
|
48
|
+
from pymodaq_gui.utils.splash import get_splash_sc
|
|
49
|
+
|
|
41
50
|
from pymodaq import extensions as extmod
|
|
42
51
|
|
|
52
|
+
logger = set_logger(get_module_name(__file__))
|
|
53
|
+
config = configmod.Config()
|
|
43
54
|
|
|
44
55
|
get_instrument_plugins()
|
|
56
|
+
extensions = extmod.get_extensions()
|
|
45
57
|
|
|
46
|
-
logger = set_logger(get_module_name(__file__))
|
|
47
|
-
|
|
48
|
-
config = configmod.Config()
|
|
49
58
|
|
|
50
59
|
local_path = configmod.get_set_local_dir()
|
|
51
60
|
now = datetime.datetime.now()
|
|
@@ -56,16 +65,105 @@ overshoot_path = config_mod_pymodaq.get_set_overshoot_path()
|
|
|
56
65
|
roi_path = config_mod_pymodaq.get_set_roi_path()
|
|
57
66
|
remote_path = config_mod_pymodaq.get_set_remote_path()
|
|
58
67
|
|
|
59
|
-
|
|
68
|
+
|
|
69
|
+
class ManagerEnums(BaseEnum):
|
|
70
|
+
preset = 0
|
|
71
|
+
remote = 1
|
|
72
|
+
overshoot = 2
|
|
73
|
+
roi = 3
|
|
74
|
+
|
|
75
|
+
class PymodaqUpdateTableWidget(QTableWidget):
|
|
76
|
+
'''
|
|
77
|
+
A class to represent PyMoDAQ and its subpackages'
|
|
78
|
+
available updates as a table.
|
|
79
|
+
'''
|
|
80
|
+
def __init__(self):
|
|
81
|
+
super().__init__()
|
|
82
|
+
|
|
83
|
+
self._checkboxes = []
|
|
84
|
+
self._package_versions = []
|
|
85
|
+
|
|
86
|
+
def setHorizontalHeaderLabels(self, labels):
|
|
87
|
+
super().setHorizontalHeaderLabels(labels)
|
|
88
|
+
self.setColumnCount(len(labels))
|
|
89
|
+
|
|
90
|
+
def append_row(self, checkbox, package, current_version, available_version):
|
|
91
|
+
row = len(self._checkboxes)
|
|
92
|
+
|
|
93
|
+
self._checkboxes.append(checkbox)
|
|
94
|
+
self._package_versions.append(f'{package}=={available_version}')
|
|
95
|
+
|
|
96
|
+
checkbox_widget = QWidget()
|
|
97
|
+
|
|
98
|
+
checkbox.setChecked(True)
|
|
99
|
+
checkbox.setToolTip("Check to install update")
|
|
100
|
+
|
|
101
|
+
checkbox_layout = QtWidgets.QHBoxLayout()
|
|
102
|
+
checkbox_layout.addWidget(checkbox)
|
|
103
|
+
checkbox_layout.setAlignment(Qt.AlignCenter)
|
|
104
|
+
checkbox_layout.setContentsMargins(0, 0, 0, 0)
|
|
105
|
+
|
|
106
|
+
checkbox_widget.setLayout(checkbox_layout)
|
|
107
|
+
|
|
108
|
+
# Add the checkbox widget to the table
|
|
109
|
+
self.setCellWidget(row, 0, checkbox_widget)
|
|
110
|
+
|
|
111
|
+
# Add labels in the other columns
|
|
112
|
+
self.setItem(row, 1, QTableWidgetItem(str(package)))
|
|
113
|
+
self.setItem(row, 2, QTableWidgetItem(str(current_version)))
|
|
114
|
+
self.setItem(row, 3, QTableWidgetItem(str(available_version)))
|
|
60
115
|
|
|
61
116
|
|
|
62
|
-
|
|
117
|
+
def get_checked_data(self):
|
|
118
|
+
checked = list(map(lambda c : c.isChecked(), self._checkboxes))
|
|
119
|
+
return list(np.array(self._package_versions)[checked])
|
|
120
|
+
|
|
121
|
+
def sizeHint(self):
|
|
122
|
+
self.resizeColumnsToContents()
|
|
123
|
+
self.resizeRowsToContents()
|
|
124
|
+
|
|
125
|
+
# Compute the size to adapt the window (header + borders + sum of all the elements)
|
|
126
|
+
width = self.verticalHeader().width() \
|
|
127
|
+
+ self.frameWidth() * 2 \
|
|
128
|
+
+ sum([self.columnWidth(i) for i in range(self.columnCount())])
|
|
129
|
+
|
|
130
|
+
height = self.horizontalHeader().height() \
|
|
131
|
+
+ self.frameWidth() * 2 \
|
|
132
|
+
+ sum([self.rowHeight(i) for i in range(self.rowCount())])
|
|
133
|
+
|
|
134
|
+
return QSize(width, height)
|
|
135
|
+
|
|
136
|
+
class DashBoard(CustomApp):
|
|
63
137
|
"""
|
|
64
138
|
Main class initializing a DashBoard interface to display det and move modules and logger """
|
|
65
139
|
status_signal = Signal(str)
|
|
66
140
|
preset_loaded_signal = Signal(bool)
|
|
67
141
|
new_preset_created = Signal()
|
|
68
142
|
|
|
143
|
+
settings_name = 'dashboard_settings'
|
|
144
|
+
_splash_sc = None
|
|
145
|
+
|
|
146
|
+
params = [
|
|
147
|
+
{'title': 'Log level', 'name': 'log_level', 'type': 'list',
|
|
148
|
+
'value': config('general', 'debug_level'),
|
|
149
|
+
'limits': config('general', 'debug_levels')},
|
|
150
|
+
|
|
151
|
+
{'title': 'Loaded presets', 'name': 'loaded_files', 'type': 'group', 'children': [
|
|
152
|
+
{'title': 'Preset file', 'name': 'preset_file', 'type': 'str', 'value': '',
|
|
153
|
+
'readonly': True},
|
|
154
|
+
{'title': 'Overshoot file', 'name': 'overshoot_file', 'type': 'str', 'value': '',
|
|
155
|
+
'readonly': True},
|
|
156
|
+
{'title': 'Layout file', 'name': 'layout_file', 'type': 'str', 'value': '',
|
|
157
|
+
'readonly': True},
|
|
158
|
+
{'title': 'ROI file', 'name': 'roi_file', 'type': 'str', 'value': '',
|
|
159
|
+
'readonly': True},
|
|
160
|
+
{'title': 'Remote file', 'name': 'remote_file', 'type': 'str', 'value': '',
|
|
161
|
+
'readonly': True},
|
|
162
|
+
]},
|
|
163
|
+
{'title': 'Actuators Init.', 'name': 'actuators', 'type': 'group', 'children': []},
|
|
164
|
+
{'title': 'Detectors Init.', 'name': 'detectors', 'type': 'group', 'children': []},
|
|
165
|
+
]
|
|
166
|
+
|
|
69
167
|
def __init__(self, dockarea):
|
|
70
168
|
"""
|
|
71
169
|
|
|
@@ -74,7 +172,8 @@ class DashBoard(QObject):
|
|
|
74
172
|
parent: (dockarea) instance of the modified pyqtgraph Dockarea (see daq_utils)
|
|
75
173
|
"""
|
|
76
174
|
|
|
77
|
-
super().__init__()
|
|
175
|
+
super().__init__(dockarea)
|
|
176
|
+
|
|
78
177
|
logger.info('Initializing Dashboard')
|
|
79
178
|
self.extra_params = []
|
|
80
179
|
self.preset_path = preset_path
|
|
@@ -88,14 +187,10 @@ class DashBoard(QObject):
|
|
|
88
187
|
self.extensions = dict([])
|
|
89
188
|
self.extension_windows = []
|
|
90
189
|
|
|
91
|
-
self.dockarea = dockarea
|
|
92
190
|
self.dockarea.dock_signal.connect(self.save_layout_state_auto)
|
|
93
|
-
|
|
191
|
+
|
|
94
192
|
self.title = ''
|
|
95
|
-
splash_path = Path(__file__).parent.joinpath('splash.png')
|
|
96
193
|
|
|
97
|
-
splash = QtGui.QPixmap(str(splash_path))
|
|
98
|
-
self.splash_sc = QtWidgets.QSplashScreen(splash, Qt.WindowStaysOnTopHint)
|
|
99
194
|
self.overshoot_manager = None
|
|
100
195
|
self.preset_manager = None
|
|
101
196
|
self.roi_saver: ROISaver = None
|
|
@@ -112,12 +207,23 @@ class DashBoard(QObject):
|
|
|
112
207
|
self.preset_file = None
|
|
113
208
|
self.actuators_modules = []
|
|
114
209
|
self.detector_modules = []
|
|
115
|
-
|
|
210
|
+
|
|
211
|
+
self.setup_ui()
|
|
212
|
+
|
|
213
|
+
self.mainwindow.setVisible(True)
|
|
116
214
|
|
|
117
215
|
logger.info('Dashboard Initialized')
|
|
118
216
|
|
|
119
217
|
if config('general', 'check_version'):
|
|
120
|
-
self.
|
|
218
|
+
if self.check_update(show=False):
|
|
219
|
+
sys.exit(0)
|
|
220
|
+
|
|
221
|
+
@classmethod
|
|
222
|
+
@property
|
|
223
|
+
def splash_sc(cls) -> QtWidgets.QSplashScreen:
|
|
224
|
+
if cls._splash_sc is None:
|
|
225
|
+
cls._splash_sc = get_splash_sc()
|
|
226
|
+
return cls._splash_sc
|
|
121
227
|
|
|
122
228
|
def set_preset_path(self, path):
|
|
123
229
|
self.preset_path = path
|
|
@@ -179,6 +285,7 @@ class DashBoard(QObject):
|
|
|
179
285
|
self.scan_module = extmod.DAQScan(dockarea=area, dashboard=self)
|
|
180
286
|
self.extensions['DAQScan'] = self.scan_module
|
|
181
287
|
self.scan_module.status_signal.connect(self.add_status)
|
|
288
|
+
#win.setWindowTitle("DAQScan")
|
|
182
289
|
win.show()
|
|
183
290
|
return self.scan_module
|
|
184
291
|
|
|
@@ -264,7 +371,159 @@ class DashBoard(QObject):
|
|
|
264
371
|
self.extension_windows[-1].show()
|
|
265
372
|
return self.extensions[ext['class_name']]
|
|
266
373
|
|
|
267
|
-
def
|
|
374
|
+
def setup_actions(self):
|
|
375
|
+
self.add_action('log', 'Log File', '', "Show Log File in default editor",
|
|
376
|
+
auto_toolbar=False)
|
|
377
|
+
self.add_action('quit', 'Quit', 'close2', "Quit program")
|
|
378
|
+
self.toolbar.addSeparator()
|
|
379
|
+
self.add_action('config', 'Configuration file', 'tree', "General Settings")
|
|
380
|
+
self.add_action('restart', 'Restart', '', "Restart the Dashboard",
|
|
381
|
+
auto_toolbar=False)
|
|
382
|
+
self.add_action('leco', 'Run Leco Coordinator', '', 'Run a Coordinator on this localhost',
|
|
383
|
+
auto_toolbar=False)
|
|
384
|
+
self.add_action('load_layout', 'Load Layout', '',
|
|
385
|
+
'Load the Saved Docks layout corresponding to the current preset',
|
|
386
|
+
auto_toolbar=False)
|
|
387
|
+
self.add_action('save_layout', 'Save Layout', '',
|
|
388
|
+
'Save the Saved Docks layout corresponding to the current preset',
|
|
389
|
+
auto_toolbar=False)
|
|
390
|
+
self.add_action('log_window', 'Show/hide log window', '', checkable=True,
|
|
391
|
+
auto_toolbar=False)
|
|
392
|
+
self.add_action('new_preset', 'New Preset', '',
|
|
393
|
+
'Create a new experimental setup configuration file: a "preset"',
|
|
394
|
+
auto_toolbar=False)
|
|
395
|
+
self.add_action('modify_preset', 'Modify Preset', '',
|
|
396
|
+
'Modify an existing experimental setup configuration file: a "preset"',
|
|
397
|
+
auto_toolbar=False)
|
|
398
|
+
|
|
399
|
+
self.add_widget('preset_list', QtWidgets.QComboBox, toolbar=self.toolbar,
|
|
400
|
+
signal_str='currentTextChanged', slot=self.update_preset_action)
|
|
401
|
+
self.add_action('load_preset', 'LOAD', 'Open',
|
|
402
|
+
tip='Load the selected Preset: ')
|
|
403
|
+
self.update_preset_action_list()
|
|
404
|
+
|
|
405
|
+
self.add_action('new_overshoot', 'New Overshoot', '',
|
|
406
|
+
'Create a new experimental setup overshoot configuration file',
|
|
407
|
+
auto_toolbar=False)
|
|
408
|
+
self.add_action('modify_overshoot', 'Modify Overshoot', '',
|
|
409
|
+
'Modify an existing experimental setup overshoot configuration file',
|
|
410
|
+
auto_toolbar=False)
|
|
411
|
+
|
|
412
|
+
for ind_file, file in enumerate(config_mod_pymodaq.get_set_overshoot_path().iterdir()):
|
|
413
|
+
if file.suffix == '.xml':
|
|
414
|
+
self.add_action(self.get_action_from_file(file, ManagerEnums.overshoot), file.stem,
|
|
415
|
+
auto_toolbar=False)
|
|
416
|
+
|
|
417
|
+
self.add_action('save_roi', 'Save ROIs as a file', '', auto_toolbar=False)
|
|
418
|
+
self.add_action('modify_roi', 'Modify ROI file', '', auto_toolbar=False)
|
|
419
|
+
|
|
420
|
+
for ind_file, file in enumerate(config_mod_pymodaq.get_set_roi_path().iterdir()):
|
|
421
|
+
if file.suffix == '.xml':
|
|
422
|
+
self.add_action(self.get_action_from_file(file, ManagerEnums.roi), file.stem,
|
|
423
|
+
'', auto_toolbar=False)
|
|
424
|
+
|
|
425
|
+
self.add_action('new_remote', 'Create New Remote', '', auto_toolbar=False)
|
|
426
|
+
self.add_action('modify_remote', 'Modify Remote file', '', auto_toolbar=False)
|
|
427
|
+
for ind_file, file in enumerate(config_mod_pymodaq.get_set_remote_path().iterdir()):
|
|
428
|
+
if file.suffix == '.xml':
|
|
429
|
+
self.add_action(self.get_action_from_file(file, ManagerEnums.remote),
|
|
430
|
+
file.stem, '', auto_toolbar=False)
|
|
431
|
+
self.add_action('activate_overshoot', 'Activate overshoot', 'Error',
|
|
432
|
+
tip='if activated, apply an overshoot if one is configured',
|
|
433
|
+
checkable=True, enabled=False)
|
|
434
|
+
self.toolbar.addSeparator()
|
|
435
|
+
self.add_action('do_scan', 'Do Scans', 'surfacePlot',
|
|
436
|
+
tip='Open the DAQ Scan extension to acquire data as a function of '
|
|
437
|
+
'one or more parameter')
|
|
438
|
+
self.toolbar.addSeparator()
|
|
439
|
+
self.add_action('do_log', 'Log data', '', auto_toolbar=False)
|
|
440
|
+
self.add_action('do_pid', 'PID module', auto_toolbar=False)
|
|
441
|
+
self.add_action('console', 'IPython Console', auto_toolbar=False)
|
|
442
|
+
self.add_action('bayesian', 'Bayesian Optimisation', auto_toolbar=False)
|
|
443
|
+
|
|
444
|
+
self.add_action('about', 'About', 'information2')
|
|
445
|
+
self.add_action('help', 'Help', 'help1')
|
|
446
|
+
self.get_action('help').setShortcut(QtGui.QKeySequence('F1'))
|
|
447
|
+
self.add_action('check_update', 'Check Updates', '', auto_toolbar=False)
|
|
448
|
+
self.toolbar.addSeparator()
|
|
449
|
+
self.add_action('plugin_manager', 'Plugin Manager', '')
|
|
450
|
+
|
|
451
|
+
def update_preset_action_list(self):
|
|
452
|
+
presets = []
|
|
453
|
+
self.get_action('preset_list').clear()
|
|
454
|
+
for ind_file, file in enumerate(self.preset_path.iterdir()):
|
|
455
|
+
if file.suffix == '.xml':
|
|
456
|
+
filestem = file.stem
|
|
457
|
+
if not self.has_action(self.get_action_from_file(file, ManagerEnums.preset)):
|
|
458
|
+
self.add_action(self.get_action_from_file(file, ManagerEnums.preset),
|
|
459
|
+
filestem, '', f'Load the {filestem}.xml preset',
|
|
460
|
+
auto_toolbar=False)
|
|
461
|
+
presets.append(filestem)
|
|
462
|
+
|
|
463
|
+
self.get_action('preset_list').addItems(presets)
|
|
464
|
+
|
|
465
|
+
def update_preset_action(self, preset_name: str):
|
|
466
|
+
self.get_action('load_preset').setToolTip(f'Load the {preset_name}.xml preset file!')
|
|
467
|
+
|
|
468
|
+
def connect_things(self):
|
|
469
|
+
self.status_signal[str].connect(self.add_status)
|
|
470
|
+
self.connect_action('log', self.show_log)
|
|
471
|
+
self.connect_action('config', self.show_config)
|
|
472
|
+
self.connect_action('quit', self.quit_fun)
|
|
473
|
+
self.connect_action('restart', self.restart_fun)
|
|
474
|
+
self.connect_action('leco', start_coordinator)
|
|
475
|
+
self.connect_action('load_layout', self.load_layout_state)
|
|
476
|
+
self.connect_action('save_layout', self.save_layout_state)
|
|
477
|
+
self.connect_action('log_window', self.logger_dock.setVisible)
|
|
478
|
+
self.connect_action('new_preset', self.create_preset)
|
|
479
|
+
self.connect_action('modify_preset', self.modify_preset)
|
|
480
|
+
|
|
481
|
+
for ind_file, file in enumerate(self.preset_path.iterdir()):
|
|
482
|
+
if file.suffix == '.xml':
|
|
483
|
+
self.connect_action(self.get_action_from_file(file, ManagerEnums.preset),
|
|
484
|
+
self.create_menu_slot(self.preset_path.joinpath(file)))
|
|
485
|
+
self.connect_action('load_preset',
|
|
486
|
+
lambda: self.set_preset_mode(
|
|
487
|
+
self.preset_path.joinpath(
|
|
488
|
+
f"{self.get_action('preset_list').currentText()}.xml")))
|
|
489
|
+
self.connect_action('new_overshoot', self.create_overshoot)
|
|
490
|
+
self.connect_action('modify_overshoot', self.modify_overshoot)
|
|
491
|
+
self.connect_action('activate_overshoot', self.activate_overshoot)
|
|
492
|
+
|
|
493
|
+
for ind_file, file in enumerate(config_mod_pymodaq.get_set_overshoot_path().iterdir()):
|
|
494
|
+
if file.suffix == '.xml':
|
|
495
|
+
self.connect_action(self.get_action_from_file(file, ManagerEnums.overshoot),
|
|
496
|
+
self.create_menu_slot_over(
|
|
497
|
+
config_mod_pymodaq.get_set_overshoot_path().joinpath(file)))
|
|
498
|
+
|
|
499
|
+
self.connect_action('save_roi', self.create_roi_file)
|
|
500
|
+
self.connect_action('modify_roi', self.modify_roi)
|
|
501
|
+
|
|
502
|
+
for ind_file, file in enumerate(config_mod_pymodaq.get_set_roi_path().iterdir()):
|
|
503
|
+
if file.suffix == '.xml':
|
|
504
|
+
self.connect_action(self.get_action_from_file(file, ManagerEnums.roi),
|
|
505
|
+
self.create_menu_slot_roi(config_mod_pymodaq.get_set_roi_path().joinpath(file)))
|
|
506
|
+
|
|
507
|
+
self.connect_action('new_remote', self.create_remote)
|
|
508
|
+
self.connect_action('modify_remote', self.modify_remote)
|
|
509
|
+
for ind_file, file in enumerate(config_mod_pymodaq.get_set_remote_path().iterdir()):
|
|
510
|
+
if file.suffix == '.xml':
|
|
511
|
+
self.connect_action(self.get_action_from_file(file, ManagerEnums.remote),
|
|
512
|
+
self.create_menu_slot_remote(
|
|
513
|
+
config_mod_pymodaq.get_set_remote_path().joinpath(file)))
|
|
514
|
+
|
|
515
|
+
self.connect_action('do_scan', lambda: self.load_scan_module())
|
|
516
|
+
self.connect_action('do_log', lambda: self.load_log_module())
|
|
517
|
+
self.connect_action('do_pid', lambda: self.load_pid_module())
|
|
518
|
+
self.connect_action('console', lambda: self.load_console())
|
|
519
|
+
self.connect_action('bayesian', lambda: self.load_bayesian())
|
|
520
|
+
|
|
521
|
+
self.connect_action('about', self.show_about)
|
|
522
|
+
self.connect_action('help', self.show_help)
|
|
523
|
+
self.connect_action('check_update', lambda: self.check_update(True))
|
|
524
|
+
self.connect_action('plugin_manager', self.start_plugin_manager)
|
|
525
|
+
|
|
526
|
+
def setup_menu(self, menubar: QtWidgets.QMenuBar = None):
|
|
268
527
|
"""
|
|
269
528
|
Create the menubar object looking like :
|
|
270
529
|
"""
|
|
@@ -272,128 +531,95 @@ class DashBoard(QObject):
|
|
|
272
531
|
|
|
273
532
|
# %% create Settings menu
|
|
274
533
|
self.file_menu = menubar.addMenu('File')
|
|
275
|
-
self.file_menu.addAction('
|
|
276
|
-
self.file_menu.addAction('
|
|
534
|
+
self.file_menu.addAction(self.get_action('log'))
|
|
535
|
+
self.file_menu.addAction(self.get_action('config'))
|
|
277
536
|
self.file_menu.addSeparator()
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
quit_action.triggered.connect(self.quit_fun)
|
|
281
|
-
restart_action.triggered.connect(self.restart_fun)
|
|
537
|
+
self.file_menu.addAction(self.get_action('quit'))
|
|
538
|
+
self.file_menu.addAction(self.get_action('restart'))
|
|
282
539
|
|
|
283
540
|
self.settings_menu = menubar.addMenu('Settings')
|
|
284
|
-
|
|
285
|
-
action_leco.triggered.connect(start_coordinator)
|
|
541
|
+
self.settings_menu.addAction(self.get_action('leco'))
|
|
286
542
|
docked_menu = self.settings_menu.addMenu('Docked windows')
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
action_load.triggered.connect(self.load_layout_state)
|
|
291
|
-
action_save.triggered.connect(self.save_layout_state)
|
|
543
|
+
docked_menu.addAction(self.get_action('load_layout'))
|
|
544
|
+
docked_menu.addAction(self.get_action('save_layout'))
|
|
292
545
|
|
|
293
546
|
docked_menu.addSeparator()
|
|
294
|
-
|
|
295
|
-
action_show_log.setCheckable(True)
|
|
296
|
-
action_show_log.toggled.connect(self.logger_dock.setVisible)
|
|
547
|
+
docked_menu.addAction(self.get_action('log_window'))
|
|
297
548
|
|
|
298
549
|
self.preset_menu = menubar.addMenu('Preset Modes')
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
action_new_preset.triggered.connect(self.create_preset)
|
|
302
|
-
action_modify_preset = self.preset_menu.addAction('Modify Preset')
|
|
303
|
-
action_modify_preset.triggered.connect(self.modify_preset)
|
|
550
|
+
self.preset_menu.addAction(self.get_action('new_preset'))
|
|
551
|
+
self.preset_menu.addAction(self.get_action('modify_preset'))
|
|
304
552
|
self.preset_menu.addSeparator()
|
|
305
|
-
self.
|
|
553
|
+
self.load_preset_menu = self.preset_menu.addMenu('Load presets')
|
|
306
554
|
|
|
307
|
-
slots = dict([])
|
|
308
555
|
for ind_file, file in enumerate(self.preset_path.iterdir()):
|
|
309
556
|
if file.suffix == '.xml':
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
slots[filestem].triggered.connect(
|
|
313
|
-
self.create_menu_slot(self.preset_path.joinpath(file)))
|
|
557
|
+
self.load_preset_menu.addAction(
|
|
558
|
+
self.get_action(self.get_action_from_file(file, ManagerEnums.preset)))
|
|
314
559
|
|
|
315
560
|
self.overshoot_menu = menubar.addMenu('Overshoot Modes')
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
action_modify_overshoot = self.overshoot_menu.addAction('Modify Overshoot')
|
|
320
|
-
action_modify_overshoot.triggered.connect(self.modify_overshoot)
|
|
561
|
+
self.overshoot_menu.addAction(self.get_action('new_overshoot'))
|
|
562
|
+
self.overshoot_menu.addAction(self.get_action('modify_overshoot'))
|
|
563
|
+
self.overshoot_menu.addAction(self.get_action('activate_overshoot'))
|
|
321
564
|
self.overshoot_menu.addSeparator()
|
|
322
|
-
|
|
565
|
+
load_overshoot_menu = self.overshoot_menu.addMenu('Load Overshoots')
|
|
323
566
|
|
|
324
|
-
slots_over = dict([])
|
|
325
567
|
for ind_file, file in enumerate(config_mod_pymodaq.get_set_overshoot_path().iterdir()):
|
|
326
568
|
if file.suffix == '.xml':
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
slots_over[filestem].triggered.connect(
|
|
330
|
-
self.create_menu_slot_over(
|
|
331
|
-
config_mod_pymodaq.get_set_overshoot_path().joinpath(file)))
|
|
569
|
+
load_overshoot_menu.addAction(
|
|
570
|
+
self.get_action(self.get_action_from_file(file, ManagerEnums.overshoot)))
|
|
332
571
|
|
|
333
572
|
self.roi_menu = menubar.addMenu('ROI Modes')
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
action_modify_roi = self.roi_menu.addAction('Modify roi config')
|
|
337
|
-
action_modify_roi.triggered.connect(self.modify_roi)
|
|
573
|
+
self.roi_menu.addAction(self.get_action('save_roi'))
|
|
574
|
+
self.roi_menu.addAction(self.get_action('modify_roi'))
|
|
338
575
|
self.roi_menu.addSeparator()
|
|
339
|
-
|
|
576
|
+
load_roi_menu = self.roi_menu.addMenu('Load roi configs')
|
|
340
577
|
|
|
341
|
-
slots = dict([])
|
|
342
578
|
for ind_file, file in enumerate(config_mod_pymodaq.get_set_roi_path().iterdir()):
|
|
343
579
|
if file.suffix == '.xml':
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
slots[filestem].triggered.connect(
|
|
347
|
-
self.create_menu_slot_roi(config_mod_pymodaq.get_set_roi_path().joinpath(file)))
|
|
580
|
+
load_roi_menu.addAction(
|
|
581
|
+
self.get_action(self.get_action_from_file(file, ManagerEnums.roi)))
|
|
348
582
|
|
|
349
583
|
self.remote_menu = menubar.addMenu('Remote/Shortcuts Control')
|
|
350
584
|
self.remote_menu.addAction('New remote config.', self.create_remote)
|
|
351
585
|
self.remote_menu.addAction('Modify remote config.', self.modify_remote)
|
|
352
586
|
self.remote_menu.addSeparator()
|
|
353
|
-
|
|
587
|
+
load_remote_menu = self.remote_menu.addMenu('Load remote config.')
|
|
354
588
|
|
|
355
|
-
slots = dict([])
|
|
356
589
|
for ind_file, file in enumerate(config_mod_pymodaq.get_set_remote_path().iterdir()):
|
|
357
590
|
if file.suffix == '.xml':
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
self.
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
action_pid = self.actions_menu.addAction('PID module')
|
|
371
|
-
action_pid.triggered.connect(lambda: self.load_pid_module())
|
|
372
|
-
action_console = self.actions_menu.addAction('IPython Console')
|
|
373
|
-
action_console.triggered.connect(lambda: self.load_console())
|
|
374
|
-
action_bayesian = self.actions_menu.addAction('Bayesian Optimisation')
|
|
375
|
-
action_bayesian.triggered.connect(lambda: self.load_bayesian())
|
|
376
|
-
|
|
591
|
+
load_remote_menu.addAction(
|
|
592
|
+
self.get_action(self.get_action_from_file(file, ManagerEnums.remote)))
|
|
593
|
+
|
|
594
|
+
# extensions menu
|
|
595
|
+
self.extensions_menu = menubar.addMenu('Extensions')
|
|
596
|
+
self.extensions_menu.addAction(self.get_action('do_scan'))
|
|
597
|
+
self.extensions_menu.addAction(self.get_action('do_log'))
|
|
598
|
+
self.extensions_menu.addAction(self.get_action('do_pid'))
|
|
599
|
+
self.extensions_menu.addAction(self.get_action('console'))
|
|
600
|
+
self.extensions_menu.addAction(self.get_action('bayesian'))
|
|
601
|
+
|
|
602
|
+
# extensions from plugins
|
|
377
603
|
extensions_actions = []
|
|
378
604
|
for ext in extensions:
|
|
379
|
-
extensions_actions.append(self.
|
|
605
|
+
extensions_actions.append(self.extensions_menu.addAction(ext['name']))
|
|
380
606
|
extensions_actions[-1].triggered.connect(self.create_menu_slot_ext(ext))
|
|
381
607
|
|
|
382
|
-
|
|
383
608
|
# help menu
|
|
384
609
|
help_menu = menubar.addMenu('?')
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
action_help = help_menu.addAction('Help')
|
|
388
|
-
action_help.triggered.connect(self.show_help)
|
|
389
|
-
action_help.setShortcut(QtGui.QKeySequence('F1'))
|
|
390
|
-
|
|
610
|
+
help_menu.addAction(self.get_action('about'))
|
|
611
|
+
help_menu.addAction(self.get_action('help'))
|
|
391
612
|
help_menu.addSeparator()
|
|
392
|
-
|
|
393
|
-
|
|
613
|
+
help_menu.addAction(self.get_action('check_update'))
|
|
614
|
+
help_menu.addAction(self.get_action('plugin_manager'))
|
|
394
615
|
|
|
395
|
-
|
|
396
|
-
|
|
616
|
+
self.overshoot_menu.setEnabled(False)
|
|
617
|
+
self.roi_menu.setEnabled(False)
|
|
618
|
+
self.remote_menu.setEnabled(False)
|
|
619
|
+
self.extensions_menu.setEnabled(False)
|
|
620
|
+
self.file_menu.setEnabled(True)
|
|
621
|
+
self.settings_menu.setEnabled(True)
|
|
622
|
+
self.preset_menu.setEnabled(True)
|
|
397
623
|
|
|
398
624
|
def start_plugin_manager(self):
|
|
399
625
|
self.win_plug_manager = QtWidgets.QMainWindow()
|
|
@@ -424,7 +650,10 @@ class DashBoard(QObject):
|
|
|
424
650
|
try:
|
|
425
651
|
if self.preset_file is not None:
|
|
426
652
|
self.roi_saver.set_new_roi(self.preset_file.stem)
|
|
427
|
-
self.
|
|
653
|
+
self.add_action(self.get_action_from_file(self.preset_file,
|
|
654
|
+
ManagerEnums.roi),
|
|
655
|
+
self.preset_file.stem, '')
|
|
656
|
+
self.setup_menu(self.menubar)
|
|
428
657
|
|
|
429
658
|
except Exception as e:
|
|
430
659
|
logger.exception(str(e))
|
|
@@ -433,7 +662,10 @@ class DashBoard(QObject):
|
|
|
433
662
|
try:
|
|
434
663
|
if self.preset_file is not None:
|
|
435
664
|
self.remote_manager.set_new_remote(self.preset_file.stem)
|
|
436
|
-
self.
|
|
665
|
+
self.add_action(self.get_action_from_file(self.preset_file,
|
|
666
|
+
ManagerEnums.remote),
|
|
667
|
+
self.preset_file.stem, '')
|
|
668
|
+
self.setup_menu(self.menubar)
|
|
437
669
|
|
|
438
670
|
except Exception as e:
|
|
439
671
|
logger.exception(str(e))
|
|
@@ -442,18 +674,27 @@ class DashBoard(QObject):
|
|
|
442
674
|
try:
|
|
443
675
|
if self.preset_file is not None:
|
|
444
676
|
self.overshoot_manager.set_new_overshoot(self.preset_file.stem)
|
|
445
|
-
self.
|
|
677
|
+
self.add_action(self.get_action_from_file(self.preset_file,
|
|
678
|
+
ManagerEnums.overshoot),
|
|
679
|
+
self.preset_file.stem, '')
|
|
680
|
+
self.setup_menu(self.menubar)
|
|
446
681
|
except Exception as e:
|
|
447
682
|
logger.exception(str(e))
|
|
448
683
|
|
|
449
684
|
def create_preset(self):
|
|
450
685
|
try:
|
|
451
|
-
self.preset_manager.set_new_preset()
|
|
452
|
-
|
|
453
|
-
|
|
686
|
+
status = self.preset_manager.set_new_preset()
|
|
687
|
+
if status:
|
|
688
|
+
self.update_preset_action_list()
|
|
689
|
+
self.setup_menu(self.menubar)
|
|
690
|
+
self.new_preset_created.emit()
|
|
454
691
|
except Exception as e:
|
|
455
692
|
logger.exception(str(e))
|
|
456
693
|
|
|
694
|
+
@staticmethod
|
|
695
|
+
def get_action_from_file(file: Path, manager: ManagerEnums):
|
|
696
|
+
return f'{file.stem}_{manager.name}'
|
|
697
|
+
|
|
457
698
|
def modify_remote(self):
|
|
458
699
|
try:
|
|
459
700
|
path = select_file(start_path=config_mod_pymodaq.get_set_remote_path(), save=False,
|
|
@@ -619,7 +860,7 @@ class DashBoard(QObject):
|
|
|
619
860
|
self.save_layout_state(path)
|
|
620
861
|
|
|
621
862
|
def add_move(self, plug_name, plug_settings, plug_type, move_docks, move_forms,
|
|
622
|
-
actuators_modules):
|
|
863
|
+
actuators_modules) -> DAQ_Move:
|
|
623
864
|
|
|
624
865
|
move_docks.append(Dock(plug_name, size=(150, 250)))
|
|
625
866
|
if len(move_docks) == 1:
|
|
@@ -640,18 +881,51 @@ class DashBoard(QObject):
|
|
|
640
881
|
mssg = f'Could not set this setting: {str(e)}\n' \
|
|
641
882
|
f'The Preset is no more compatible with the plugin {plug_type}'
|
|
642
883
|
logger.warning(mssg)
|
|
643
|
-
self.splash_sc.showMessage(mssg
|
|
884
|
+
self.splash_sc.showMessage(mssg)
|
|
644
885
|
QtWidgets.QApplication.processEvents()
|
|
645
886
|
|
|
646
887
|
mov_mod_tmp.bounds_signal[bool].connect(self.stop_moves)
|
|
647
888
|
move_docks[-1].addWidget(move_forms[-1])
|
|
648
889
|
actuators_modules.append(mov_mod_tmp)
|
|
890
|
+
return mov_mod_tmp
|
|
649
891
|
|
|
650
|
-
def
|
|
651
|
-
|
|
892
|
+
def add_move_from_extension(self, name: str, instrument_name: str,
|
|
893
|
+
instrument_controller: Any):
|
|
894
|
+
""" Specific method to add a DAQ_Move within the Dashboard. This Particular actuator
|
|
895
|
+
should be defined in the plugin of the extension and is used to mimic an actuator while
|
|
896
|
+
move_abs is actually triggering an action on the extension which loaded it
|
|
652
897
|
|
|
653
|
-
|
|
654
|
-
|
|
898
|
+
For an exemple, see the PyMoDAQ builtin PID extension
|
|
899
|
+
|
|
900
|
+
Parameters
|
|
901
|
+
----------
|
|
902
|
+
name: str
|
|
903
|
+
The name to print on the UI title
|
|
904
|
+
instrument_name: str
|
|
905
|
+
The name of the instrument class, for instance PID for the daq_move_PID
|
|
906
|
+
module and the DAQ_Move_PID instrument class
|
|
907
|
+
instrument_controller: object
|
|
908
|
+
whatever object is used to communicate between the instrument module and the extension
|
|
909
|
+
which created it
|
|
910
|
+
"""
|
|
911
|
+
actuator = self.add_move(name, None, instrument_name, [], [], [])
|
|
912
|
+
actuator.controller = instrument_controller
|
|
913
|
+
actuator.master = False
|
|
914
|
+
actuator.init_hardware_ui()
|
|
915
|
+
QtWidgets.QApplication.processEvents()
|
|
916
|
+
self.poll_init(actuator)
|
|
917
|
+
QtWidgets.QApplication.processEvents()
|
|
918
|
+
|
|
919
|
+
# Update actuators modules and module manager
|
|
920
|
+
self.actuators_modules.append(actuator)
|
|
921
|
+
self.update_module_manager()
|
|
922
|
+
|
|
923
|
+
def add_det(self, plug_name, plug_settings, det_docks_settings, det_docks_viewer,
|
|
924
|
+
detector_modules, plug_type: str = None, plug_subtype: str = None) -> DAQ_Viewer:
|
|
925
|
+
if plug_type is None:
|
|
926
|
+
plug_type = plug_settings.child('main_settings', 'DAQ_type').value()
|
|
927
|
+
if plug_subtype is None:
|
|
928
|
+
plug_subtype = plug_settings.child('main_settings', 'detector_type').value()
|
|
655
929
|
det_docks_settings.append(Dock(plug_name + " settings", size=(150, 250)))
|
|
656
930
|
det_docks_viewer.append(Dock(plug_name + " viewer", size=(350, 350)))
|
|
657
931
|
if len(detector_modules) == 0:
|
|
@@ -676,11 +950,54 @@ class DashBoard(QObject):
|
|
|
676
950
|
mssg = f'Could not set this setting: {str(e)}\n' \
|
|
677
951
|
f'The Preset is no more compatible with the plugin {plug_subtype}'
|
|
678
952
|
logger.warning(mssg)
|
|
679
|
-
self.splash_sc.showMessage(mssg
|
|
953
|
+
self.splash_sc.showMessage(mssg)
|
|
680
954
|
|
|
681
955
|
detector_modules.append(det_mod_tmp)
|
|
956
|
+
return det_mod_tmp
|
|
682
957
|
|
|
683
|
-
def
|
|
958
|
+
def add_det_from_extension(self, name: str, daq_type: str, instrument_name: str,
|
|
959
|
+
instrument_controller: Any):
|
|
960
|
+
""" Specific method to add a DAQ_Viewer within the Dashboard. This Particular detector
|
|
961
|
+
should be defined in the plugin of the extension and is used to mimic a grab while data
|
|
962
|
+
are actually coming from the extension which loaded it
|
|
963
|
+
|
|
964
|
+
For an exemple, see the pymodaq_plugins_datamixer plugin and its DataMixer extension
|
|
965
|
+
|
|
966
|
+
Parameters
|
|
967
|
+
----------
|
|
968
|
+
name: str
|
|
969
|
+
The name to print on the UI title
|
|
970
|
+
daq_type: str
|
|
971
|
+
either DAQ0D, DAQ1D, DAQ2D or DAQND depending the type of the instrument
|
|
972
|
+
instrument_name: str
|
|
973
|
+
The name of the instrument class, for instance DataMixer for the daq_0Dviewer_DataMixer
|
|
974
|
+
module and the DAQ_0DViewer_DataMixer instrument class
|
|
975
|
+
instrument_controller: object
|
|
976
|
+
whatever object is used to communicate between the instrument module and the extension
|
|
977
|
+
which created it
|
|
978
|
+
"""
|
|
979
|
+
detector = self.add_det(name, None, [], [], [],
|
|
980
|
+
plug_type=daq_type,
|
|
981
|
+
plug_subtype=instrument_name)
|
|
982
|
+
detector.controller = instrument_controller
|
|
983
|
+
detector.master = False
|
|
984
|
+
detector.init_hardware_ui()
|
|
985
|
+
QtWidgets.QApplication.processEvents()
|
|
986
|
+
self.poll_init(detector)
|
|
987
|
+
QtWidgets.QApplication.processEvents()
|
|
988
|
+
|
|
989
|
+
# Update actuators modules and module manager
|
|
990
|
+
self.detector_modules.append(detector)
|
|
991
|
+
self.update_module_manager()
|
|
992
|
+
|
|
993
|
+
def update_module_manager(self):
|
|
994
|
+
if self.modules_manager is None:
|
|
995
|
+
self.modules_manager = ModulesManager(self.detector_modules, self.actuators_modules)
|
|
996
|
+
else:
|
|
997
|
+
self.modules_manager.actuators_all = self.actuators_modules
|
|
998
|
+
self.modules_manager.detectors_all = self.detector_modules
|
|
999
|
+
|
|
1000
|
+
def set_file_preset(self, filename) -> Tuple[List[DAQ_Move], List[DAQ_Viewer]]:
|
|
684
1001
|
"""
|
|
685
1002
|
Set a file managers from the converted xml file given by the filename parameter.
|
|
686
1003
|
|
|
@@ -718,17 +1035,16 @@ class DashBoard(QObject):
|
|
|
718
1035
|
self.preset_manager.preset_params.child('Detectors').children()]
|
|
719
1036
|
|
|
720
1037
|
for plug in plugins:
|
|
721
|
-
plug['ID'] = plug['value'].child('params', 'main_settings', 'controller_ID').value()
|
|
722
1038
|
if plug["type"] == 'det':
|
|
723
|
-
plug['
|
|
724
|
-
|
|
1039
|
+
plug['ID'] = plug['value']['params', 'detector_settings', 'controller_ID']
|
|
1040
|
+
plug['status'] = plug['value']['params', 'detector_settings',
|
|
1041
|
+
'controller_status']
|
|
725
1042
|
else:
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
'params', 'move_settings', 'multiaxes', 'multi_status'
|
|
730
|
-
|
|
731
|
-
plug['status'] = 'Master'
|
|
1043
|
+
plug['ID'] = plug['value']['params', 'move_settings',
|
|
1044
|
+
'multiaxes', 'controller_ID']
|
|
1045
|
+
plug['status'] = plug['value'][
|
|
1046
|
+
'params', 'move_settings', 'multiaxes', 'multi_status']
|
|
1047
|
+
|
|
732
1048
|
|
|
733
1049
|
IDs = list(set([plug['ID'] for plug in plugins]))
|
|
734
1050
|
# %%
|
|
@@ -750,8 +1066,7 @@ class DashBoard(QObject):
|
|
|
750
1066
|
plug_init = plugin['value'].child('init').value()
|
|
751
1067
|
plug_settings = plugin['value'].child('params')
|
|
752
1068
|
self.splash_sc.showMessage(
|
|
753
|
-
'Loading {:s} module: {:s}'.format(plugin['type'], plug_name)
|
|
754
|
-
color=Qt.white)
|
|
1069
|
+
'Loading {:s} module: {:s}'.format(plugin['type'], plug_name))
|
|
755
1070
|
|
|
756
1071
|
if plugin['type'] == 'move':
|
|
757
1072
|
plug_type = plug_settings.child('main_settings', 'move_type').value()
|
|
@@ -1030,33 +1345,22 @@ class DashBoard(QObject):
|
|
|
1030
1345
|
self.update_status('Overshoot configuration ({}) has been loaded'.format(file),
|
|
1031
1346
|
log_type='log')
|
|
1032
1347
|
self.overshoot_manager.set_file_overshoot(filename, show=False)
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
for det_param in self.overshoot_manager.overshoot_params.child(
|
|
1038
|
-
'Detectors').children():
|
|
1039
|
-
if det_param.child(('trig_overshoot')).value():
|
|
1040
|
-
det_index = det_titles.index(det_param.opts['title'])
|
|
1041
|
-
det_module = self.detector_modules[det_index]
|
|
1042
|
-
det_module.settings.child(
|
|
1043
|
-
'main_settings', 'overshoot', 'stop_overshoot').setValue(True)
|
|
1044
|
-
det_module.settings.child(
|
|
1045
|
-
'main_settings', 'overshoot', 'overshoot_value').setValue(
|
|
1046
|
-
det_param['overshoot_value'])
|
|
1047
|
-
for move_param in det_param.child(('params')).children():
|
|
1048
|
-
if move_param['move_overshoot']:
|
|
1049
|
-
move_index = move_titles.index(move_param.opts['title'])
|
|
1050
|
-
move_module = self.actuators_modules[move_index]
|
|
1051
|
-
det_module.overshoot_signal.connect(
|
|
1052
|
-
self.create_overshoot_fun(
|
|
1053
|
-
move_module, move_param['position']))
|
|
1348
|
+
self.set_action_enabled('activate_overshoot', True)
|
|
1349
|
+
self.set_action_checked('activate_overshoot', False)
|
|
1350
|
+
self.get_action('activate_overshoot').trigger()
|
|
1054
1351
|
|
|
1055
1352
|
except Exception as e:
|
|
1056
1353
|
logger.exception(str(e))
|
|
1057
1354
|
|
|
1058
|
-
def
|
|
1059
|
-
|
|
1355
|
+
def activate_overshoot(self, status: bool):
|
|
1356
|
+
try:
|
|
1357
|
+
self.overshoot_manager.activate_overshoot(self.detector_modules,
|
|
1358
|
+
self.actuators_modules,
|
|
1359
|
+
status)
|
|
1360
|
+
except Exception as e:
|
|
1361
|
+
logger.warning(f'Could not load the overshoot file:\n{str(e)}')
|
|
1362
|
+
self.set_action_checked('activate_overshoot', False)
|
|
1363
|
+
self.set_action_enabled('activate_overshoot', False)
|
|
1060
1364
|
|
|
1061
1365
|
@property
|
|
1062
1366
|
def move_modules(self):
|
|
@@ -1093,6 +1397,9 @@ class DashBoard(QObject):
|
|
|
1093
1397
|
try:
|
|
1094
1398
|
if not isinstance(filename, Path):
|
|
1095
1399
|
filename = Path(filename)
|
|
1400
|
+
|
|
1401
|
+
self.get_action('preset_list').setCurrentText(filename.stem)
|
|
1402
|
+
|
|
1096
1403
|
self.mainwindow.setVisible(False)
|
|
1097
1404
|
for area in self.dockarea.tempAreas:
|
|
1098
1405
|
area.window().setVisible(False)
|
|
@@ -1100,7 +1407,7 @@ class DashBoard(QObject):
|
|
|
1100
1407
|
self.splash_sc.show()
|
|
1101
1408
|
QtWidgets.QApplication.processEvents()
|
|
1102
1409
|
self.splash_sc.raise_()
|
|
1103
|
-
self.splash_sc.showMessage('Loading Modules, please wait'
|
|
1410
|
+
self.splash_sc.showMessage('Loading Modules, please wait')
|
|
1104
1411
|
QtWidgets.QApplication.processEvents()
|
|
1105
1412
|
self.clear_move_det_controllers()
|
|
1106
1413
|
QtWidgets.QApplication.processEvents()
|
|
@@ -1109,7 +1416,7 @@ class DashBoard(QObject):
|
|
|
1109
1416
|
|
|
1110
1417
|
try:
|
|
1111
1418
|
actuators_modules, detector_modules = self.set_file_preset(filename)
|
|
1112
|
-
except (ActuatorError, DetectorError,
|
|
1419
|
+
except (ActuatorError, DetectorError, MasterSlaveError) as error:
|
|
1113
1420
|
self.splash_sc.close()
|
|
1114
1421
|
self.mainwindow.setVisible(True)
|
|
1115
1422
|
for area in self.dockarea.tempAreas:
|
|
@@ -1128,55 +1435,7 @@ class DashBoard(QObject):
|
|
|
1128
1435
|
self.actuators_modules = actuators_modules
|
|
1129
1436
|
self.detector_modules = detector_modules
|
|
1130
1437
|
|
|
1131
|
-
self.
|
|
1132
|
-
|
|
1133
|
-
# Now that we have the module manager, load PID if it is checked in managers
|
|
1134
|
-
try:
|
|
1135
|
-
if self.preset_manager.preset_params.child('use_pid').value():
|
|
1136
|
-
self.load_pid_module()
|
|
1137
|
-
|
|
1138
|
-
self.pid_module.settings.child('models', 'model_class').setValue(
|
|
1139
|
-
self.preset_manager.preset_params.child('pid_models').value())
|
|
1140
|
-
QtWidgets.QApplication.processEvents()
|
|
1141
|
-
self.pid_module.set_model()
|
|
1142
|
-
|
|
1143
|
-
QtWidgets.QApplication.processEvents()
|
|
1144
|
-
|
|
1145
|
-
for child in putils.iter_children_params(
|
|
1146
|
-
self.preset_manager.preset_params.child('model_settings'),
|
|
1147
|
-
[]):
|
|
1148
|
-
preset_path = self.preset_manager.preset_params.child(
|
|
1149
|
-
'model_settings').childPath(child)
|
|
1150
|
-
path = ['models', 'model_params']
|
|
1151
|
-
path.extend(preset_path)
|
|
1152
|
-
self.pid_module.settings.child(*path).setValue(child.value())
|
|
1153
|
-
|
|
1154
|
-
model_class = extmod.get_models(
|
|
1155
|
-
self.preset_manager.preset_params.child('pid_models').value())['class']
|
|
1156
|
-
for setp in model_class.setpoints_names:
|
|
1157
|
-
self.add_move(setp, None, 'PID', [], [], actuators_modules)
|
|
1158
|
-
actuators_modules[-1].controller = dict(
|
|
1159
|
-
curr_point=self.pid_module.curr_points_signal,
|
|
1160
|
-
setpoint=self.pid_module.setpoints_signal,
|
|
1161
|
-
emit_curr_points=self.pid_module.emit_curr_points_sig)
|
|
1162
|
-
actuators_modules[-1].init_hardware_ui()
|
|
1163
|
-
QtWidgets.QApplication.processEvents()
|
|
1164
|
-
self.poll_init(actuators_modules[-1])
|
|
1165
|
-
QtWidgets.QApplication.processEvents()
|
|
1166
|
-
|
|
1167
|
-
# Update actuators modules and module manager
|
|
1168
|
-
self.actuators_modules = actuators_modules
|
|
1169
|
-
self.modules_manager = ModulesManager(self.detector_modules,
|
|
1170
|
-
self.actuators_modules)
|
|
1171
|
-
|
|
1172
|
-
except Exception as e:
|
|
1173
|
-
raise PIDError('Could not load the PID extension and create setpoints actuators'
|
|
1174
|
-
f'{str(e)}')
|
|
1175
|
-
|
|
1176
|
-
#
|
|
1177
|
-
if self.pid_module is not None:
|
|
1178
|
-
self.pid_module.get_action('ini_model').trigger()
|
|
1179
|
-
# #
|
|
1438
|
+
self.update_module_manager()
|
|
1180
1439
|
|
|
1181
1440
|
#####################################################
|
|
1182
1441
|
self.overshoot_manager = OvershootManager(
|
|
@@ -1216,11 +1475,13 @@ class DashBoard(QObject):
|
|
|
1216
1475
|
if self.pid_window is not None:
|
|
1217
1476
|
self.pid_window.show()
|
|
1218
1477
|
|
|
1219
|
-
self.
|
|
1478
|
+
self.load_preset_menu.setEnabled(False)
|
|
1479
|
+
self.set_action_enabled('load_preset', False)
|
|
1480
|
+
self.set_action_enabled('preset_list', False)
|
|
1220
1481
|
self.overshoot_menu.setEnabled(True)
|
|
1221
1482
|
self.roi_menu.setEnabled(True)
|
|
1222
1483
|
self.remote_menu.setEnabled(True)
|
|
1223
|
-
self.
|
|
1484
|
+
self.extensions_menu.setEnabled(True)
|
|
1224
1485
|
self.file_menu.setEnabled(True)
|
|
1225
1486
|
self.settings_menu.setEnabled(True)
|
|
1226
1487
|
self.update_init_tree()
|
|
@@ -1276,40 +1537,18 @@ class DashBoard(QObject):
|
|
|
1276
1537
|
config_tree = TreeFromToml()
|
|
1277
1538
|
config_tree.show_dialog()
|
|
1278
1539
|
|
|
1279
|
-
def
|
|
1540
|
+
def setup_docks(self):
|
|
1280
1541
|
|
|
1281
1542
|
# %% create logger dock
|
|
1282
1543
|
self.logger_dock = Dock("Logger")
|
|
1283
1544
|
self.logger_list = QtWidgets.QListWidget()
|
|
1284
1545
|
self.logger_list.setMinimumWidth(300)
|
|
1285
|
-
|
|
1286
|
-
self.init_tree.setMinimumWidth(300)
|
|
1546
|
+
|
|
1287
1547
|
splitter = QtWidgets.QSplitter(Qt.Vertical)
|
|
1288
|
-
splitter.addWidget(self.
|
|
1548
|
+
splitter.addWidget(self.settings_tree)
|
|
1289
1549
|
splitter.addWidget(self.logger_list)
|
|
1290
1550
|
self.logger_dock.addWidget(splitter)
|
|
1291
1551
|
|
|
1292
|
-
self.settings = Parameter.create(name='init_settings', type='group', children=[
|
|
1293
|
-
{'title': 'Log level', 'name': 'log_level', 'type': 'list',
|
|
1294
|
-
'value': config('general', 'debug_level'),
|
|
1295
|
-
'limits': config('general', 'debug_levels')},
|
|
1296
|
-
|
|
1297
|
-
{'title': 'Loaded presets', 'name': 'loaded_files', 'type': 'group', 'children': [
|
|
1298
|
-
{'title': 'Preset file', 'name': 'preset_file', 'type': 'str', 'value': '',
|
|
1299
|
-
'readonly': True},
|
|
1300
|
-
{'title': 'Overshoot file', 'name': 'overshoot_file', 'type': 'str', 'value': '',
|
|
1301
|
-
'readonly': True},
|
|
1302
|
-
{'title': 'Layout file', 'name': 'layout_file', 'type': 'str', 'value': '',
|
|
1303
|
-
'readonly': True},
|
|
1304
|
-
{'title': 'ROI file', 'name': 'roi_file', 'type': 'str', 'value': '',
|
|
1305
|
-
'readonly': True},
|
|
1306
|
-
{'title': 'Remote file', 'name': 'remote_file', 'type': 'str', 'value': '',
|
|
1307
|
-
'readonly': True},
|
|
1308
|
-
]},
|
|
1309
|
-
{'title': 'Actuators Init.', 'name': 'actuators', 'type': 'group', 'children': []},
|
|
1310
|
-
{'title': 'Detectors Init.', 'name': 'detectors', 'type': 'group', 'children': []},
|
|
1311
|
-
])
|
|
1312
|
-
self.init_tree.setParameters(self.settings, showTop=False)
|
|
1313
1552
|
self.remote_dock = Dock('Remote controls')
|
|
1314
1553
|
self.dockarea.addDock(self.remote_dock, 'top')
|
|
1315
1554
|
self.dockarea.addDock(self.logger_dock, 'above', self.remote_dock)
|
|
@@ -1318,21 +1557,9 @@ class DashBoard(QObject):
|
|
|
1318
1557
|
self.remote_dock.setVisible(False)
|
|
1319
1558
|
self.preset_manager = PresetManager(path=self.preset_path, extra_params=self.extra_params)
|
|
1320
1559
|
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
self.
|
|
1324
|
-
self.overshoot_menu.setEnabled(False)
|
|
1325
|
-
self.roi_menu.setEnabled(False)
|
|
1326
|
-
self.remote_menu.setEnabled(False)
|
|
1327
|
-
self.actions_menu.setEnabled(False)
|
|
1328
|
-
# connecting
|
|
1329
|
-
self.status_signal[str].connect(self.add_status)
|
|
1330
|
-
|
|
1331
|
-
self.file_menu.setEnabled(True)
|
|
1332
|
-
# self.actions_menu.setEnabled(True)
|
|
1333
|
-
self.settings_menu.setEnabled(True)
|
|
1334
|
-
self.preset_menu.setEnabled(True)
|
|
1335
|
-
self.mainwindow.setVisible(True)
|
|
1560
|
+
@property
|
|
1561
|
+
def menubar(self):
|
|
1562
|
+
return self._menubar
|
|
1336
1563
|
|
|
1337
1564
|
def parameter_tree_changed(self, param, changes):
|
|
1338
1565
|
"""
|
|
@@ -1366,36 +1593,76 @@ class DashBoard(QObject):
|
|
|
1366
1593
|
self.splash_sc.showMessage(
|
|
1367
1594
|
f"PyMoDAQ version {get_version('pymodaq')}\n"
|
|
1368
1595
|
f"Modular Acquisition with Python\n"
|
|
1369
|
-
f"Written by Sébastien Weber"
|
|
1370
|
-
|
|
1596
|
+
f"Written by Sébastien Weber")
|
|
1597
|
+
|
|
1598
|
+
def check_update(self, show=True):
|
|
1371
1599
|
|
|
1372
|
-
def check_version(self, show=True):
|
|
1373
1600
|
try:
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1601
|
+
packages = ['pymodaq_utils', 'pymodaq_data', 'pymodaq_gui', 'pymodaq']
|
|
1602
|
+
current_versions = [version_mod.parse(get_version(p)) for p in packages]
|
|
1603
|
+
available_versions = [version_mod.parse(get_pypi_pymodaq(p)['version']) for p in packages]
|
|
1604
|
+
new_versions = np.greater(available_versions, current_versions)
|
|
1605
|
+
# Combine package and version information and select only the ones with a newer version available
|
|
1606
|
+
|
|
1607
|
+
|
|
1608
|
+
packages_data = np.array(list(zip(packages, current_versions, available_versions)))[new_versions]
|
|
1609
|
+
|
|
1610
|
+
#TODO: Remove `or True`
|
|
1611
|
+
if len(packages_data) > 0:
|
|
1612
|
+
#Create a QDialog window and different graphical components
|
|
1613
|
+
dialog = QtWidgets.QDialog()
|
|
1614
|
+
dialog.setWindowTitle("Update check")
|
|
1615
|
+
|
|
1616
|
+
vlayout = QtWidgets.QVBoxLayout()
|
|
1617
|
+
|
|
1618
|
+
message_label = QLabel("New versions of PyMoDAQ packages available!\nPlease select the ones you want to install:")
|
|
1619
|
+
message_label.setAlignment(Qt.AlignCenter)
|
|
1620
|
+
|
|
1621
|
+
|
|
1622
|
+
table = PymodaqUpdateTableWidget()
|
|
1623
|
+
table.setRowCount(len(packages_data))
|
|
1624
|
+
table.setColumnCount(4)
|
|
1625
|
+
table.setHorizontalHeaderLabels(["Select", "Package", "Current version", "New version"])
|
|
1626
|
+
|
|
1627
|
+
for p in packages_data:
|
|
1628
|
+
table.append_row(QCheckBox(), p[0], p[1], p[2])
|
|
1629
|
+
|
|
1630
|
+
button = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
1631
|
+
button.accepted.connect(dialog.accept)
|
|
1632
|
+
button.rejected.connect(dialog.reject)
|
|
1633
|
+
|
|
1634
|
+
# The vlayout contains the message, the table and the buttons
|
|
1635
|
+
# and is connected to the dialog window
|
|
1636
|
+
vlayout.addWidget(message_label)
|
|
1637
|
+
vlayout.addWidget(table)
|
|
1638
|
+
vlayout.addWidget(button)
|
|
1639
|
+
dialog.setLayout(vlayout)
|
|
1640
|
+
|
|
1641
|
+
ret = dialog.exec()
|
|
1642
|
+
|
|
1643
|
+
if ret == QDialog.Accepted:
|
|
1644
|
+
# If the update is accepted, the checked packages are extracted from the table
|
|
1645
|
+
# and send to the updater
|
|
1646
|
+
packages_to_update = table.get_checked_data()
|
|
1647
|
+
if len(packages_to_update) > 0:
|
|
1648
|
+
packages_to_update_str = ', '.join(packages_to_update)
|
|
1649
|
+
logger.info("Trying to update:")
|
|
1650
|
+
logger.info(f"\t {packages_to_update_str}")
|
|
1651
|
+
subprocess.Popen(['pymodaq_updater', '--wait', '--file', __file__] + packages_to_update, stdin=subprocess.PIPE)
|
|
1652
|
+
self.quit_fun()
|
|
1653
|
+
return True
|
|
1654
|
+
logger.info("Update found but no packages checked for update.")
|
|
1391
1655
|
else:
|
|
1392
1656
|
if show:
|
|
1393
|
-
msgBox.
|
|
1394
|
-
|
|
1657
|
+
msgBox = QtWidgets.QMessageBox()
|
|
1658
|
+
msgBox.setWindowTitle("Update check")
|
|
1659
|
+
msgBox.setText("Everything is up to date!")
|
|
1395
1660
|
ret = msgBox.exec()
|
|
1396
1661
|
except Exception as e:
|
|
1397
1662
|
logger.exception("Error while checking the available PyMoDAQ version")
|
|
1398
1663
|
|
|
1664
|
+
return False
|
|
1665
|
+
|
|
1399
1666
|
def show_file_attributes(self, type_info='dataset'):
|
|
1400
1667
|
"""
|
|
1401
1668
|
Switch the type_info value.
|
|
@@ -1465,6 +1732,7 @@ class DashBoard(QObject):
|
|
|
1465
1732
|
|
|
1466
1733
|
def main():
|
|
1467
1734
|
from pymodaq_gui.utils.utils import mkQApp
|
|
1735
|
+
|
|
1468
1736
|
app = mkQApp('Dashboard')
|
|
1469
1737
|
|
|
1470
1738
|
win = QtWidgets.QMainWindow()
|
|
@@ -1473,10 +1741,11 @@ def main():
|
|
|
1473
1741
|
win.resize(1000, 500)
|
|
1474
1742
|
win.setWindowTitle('PyMoDAQ Dashboard')
|
|
1475
1743
|
|
|
1476
|
-
# win.setVisible(False)
|
|
1477
1744
|
prog = DashBoard(area)
|
|
1745
|
+
|
|
1746
|
+
win.show()
|
|
1747
|
+
|
|
1478
1748
|
app.exec()
|
|
1479
|
-
return prog, win
|
|
1480
1749
|
|
|
1481
1750
|
|
|
1482
1751
|
if __name__ == '__main__':
|