bec-widgets 0.53.2__py3-none-any.whl → 0.54.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- CHANGELOG.md +24 -25
- PKG-INFO +1 -1
- bec_widgets/cli/client.py +13 -13
- bec_widgets/cli/client_utils.py +0 -4
- bec_widgets/cli/generate_cli.py +7 -5
- bec_widgets/cli/server.py +5 -7
- bec_widgets/examples/jupyter_console/jupyter_console_window.py +7 -3
- bec_widgets/examples/motor_movement/motor_control_compilations.py +17 -16
- bec_widgets/widgets/__init__.py +0 -10
- bec_widgets/widgets/figure/figure.py +40 -23
- bec_widgets/widgets/figure/plots/__init__.py +0 -0
- bec_widgets/widgets/figure/plots/image/__init__.py +0 -0
- bec_widgets/widgets/{plots → figure/plots/image}/image.py +6 -416
- bec_widgets/widgets/figure/plots/image/image_item.py +277 -0
- bec_widgets/widgets/figure/plots/image/image_processor.py +152 -0
- bec_widgets/widgets/figure/plots/motor_map/__init__.py +0 -0
- bec_widgets/widgets/{plots → figure/plots/motor_map}/motor_map.py +2 -2
- bec_widgets/widgets/figure/plots/waveform/__init__.py +0 -0
- bec_widgets/widgets/{plots → figure/plots/waveform}/waveform.py +9 -222
- bec_widgets/widgets/figure/plots/waveform/waveform_curve.py +227 -0
- bec_widgets/widgets/motor_control/__init__.py +0 -7
- bec_widgets/widgets/motor_control/motor_control.py +2 -948
- bec_widgets/widgets/motor_control/motor_table/__init__.py +0 -0
- bec_widgets/widgets/motor_control/motor_table/motor_table.py +483 -0
- bec_widgets/widgets/motor_control/movement_absolute/__init__.py +0 -0
- bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +157 -0
- bec_widgets/widgets/motor_control/movement_relative/__init__.py +0 -0
- bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +227 -0
- bec_widgets/widgets/motor_control/selection/__init__.py +0 -0
- bec_widgets/widgets/motor_control/selection/selection.py +110 -0
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/METADATA +1 -1
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/RECORD +51 -52
- docs/requirements.txt +1 -0
- pyproject.toml +1 -1
- tests/end-2-end/test_bec_dock_rpc_e2e.py +1 -1
- tests/end-2-end/test_bec_figure_rpc_e2e.py +4 -4
- tests/end-2-end/test_rpc_register_e2e.py +1 -1
- tests/unit_tests/test_bec_dock.py +1 -1
- tests/unit_tests/test_bec_figure.py +6 -4
- tests/unit_tests/test_bec_motor_map.py +2 -3
- tests/unit_tests/test_motor_control.py +6 -5
- tests/unit_tests/test_waveform1d.py +13 -1
- bec_widgets/validation/__init__.py +0 -2
- bec_widgets/validation/monitor_config_validator.py +0 -258
- bec_widgets/widgets/monitor/__init__.py +0 -1
- bec_widgets/widgets/monitor/config_dialog.py +0 -574
- bec_widgets/widgets/monitor/config_dialog.ui +0 -210
- bec_widgets/widgets/monitor/example_configs/config_device.yaml +0 -60
- bec_widgets/widgets/monitor/example_configs/config_scans.yaml +0 -92
- bec_widgets/widgets/monitor/monitor.py +0 -845
- bec_widgets/widgets/monitor/tab_template.ui +0 -180
- bec_widgets/widgets/motor_map/__init__.py +0 -1
- bec_widgets/widgets/motor_map/motor_map.py +0 -594
- bec_widgets/widgets/plots/__init__.py +0 -4
- tests/unit_tests/test_bec_monitor.py +0 -220
- tests/unit_tests/test_config_dialog.py +0 -178
- tests/unit_tests/test_motor_map.py +0 -171
- tests/unit_tests/test_validator_errors.py +0 -110
- /bec_widgets/{cli → assets}/bec_widgets_icon.png +0 -0
- /bec_widgets/{examples/jupyter_console → assets}/terminal_icon.png +0 -0
- /bec_widgets/widgets/{plots → figure/plots}/plot_base.py +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_table.ui → motor_table/motor_table.ui} +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_absolute.ui → movement_absolute/movement_absolute.ui} +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_relative.ui → movement_relative/movement_relative.ui} +0 -0
- /bec_widgets/widgets/motor_control/{motor_control_selection.ui → selection/selection.ui} +0 -0
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/WHEEL +0 -0
- {bec_widgets-0.53.2.dist-info → bec_widgets-0.54.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,26 +1,12 @@
|
|
1
1
|
# pylint: disable = no-name-in-module,missing-module-docstring
|
2
|
-
import os
|
3
2
|
from enum import Enum
|
4
3
|
|
5
4
|
from bec_lib.alarm_handler import AlarmBase
|
6
5
|
from bec_lib.device import Positioner
|
7
|
-
from qtpy import
|
8
|
-
from qtpy.QtCore import Qt, QThread
|
6
|
+
from qtpy.QtCore import QThread
|
9
7
|
from qtpy.QtCore import Signal as pyqtSignal
|
10
8
|
from qtpy.QtCore import Slot as pyqtSlot
|
11
|
-
from qtpy.
|
12
|
-
from qtpy.QtWidgets import (
|
13
|
-
QCheckBox,
|
14
|
-
QComboBox,
|
15
|
-
QDoubleSpinBox,
|
16
|
-
QLineEdit,
|
17
|
-
QMessageBox,
|
18
|
-
QPushButton,
|
19
|
-
QShortcut,
|
20
|
-
QTableWidget,
|
21
|
-
QTableWidgetItem,
|
22
|
-
QWidget,
|
23
|
-
)
|
9
|
+
from qtpy.QtWidgets import QMessageBox, QWidget
|
24
10
|
|
25
11
|
from bec_widgets.utils.bec_dispatcher import BECDispatcher
|
26
12
|
|
@@ -77,938 +63,6 @@ class MotorControlWidget(QWidget):
|
|
77
63
|
self._init_ui()
|
78
64
|
|
79
65
|
|
80
|
-
class MotorControlSelection(MotorControlWidget):
|
81
|
-
"""
|
82
|
-
Widget for selecting the motors to control.
|
83
|
-
|
84
|
-
Signals:
|
85
|
-
selected_motors_signal (pyqtSignal(str,str)): Signal to emit the selected motors.
|
86
|
-
Slots:
|
87
|
-
get_available_motors (pyqtSlot): Slot to populate the available motors in the combo boxes and set the index based on the configuration.
|
88
|
-
enable_motor_controls (pyqtSlot(bool)): Slot to enable/disable the motor controls GUI.
|
89
|
-
on_config_update (pyqtSlot(dict)): Slot to update the config dict.
|
90
|
-
"""
|
91
|
-
|
92
|
-
selected_motors_signal = pyqtSignal(str, str)
|
93
|
-
|
94
|
-
def _load_ui(self):
|
95
|
-
"""Load the UI from the .ui file."""
|
96
|
-
current_path = os.path.dirname(__file__)
|
97
|
-
uic.loadUi(os.path.join(current_path, "motor_control_selection.ui"), self)
|
98
|
-
|
99
|
-
def _init_ui(self):
|
100
|
-
"""Initialize the UI."""
|
101
|
-
# Lock GUI while motors are moving
|
102
|
-
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
103
|
-
|
104
|
-
self.pushButton_connecMotors.clicked.connect(self.select_motor)
|
105
|
-
self.get_available_motors()
|
106
|
-
|
107
|
-
# Connect change signals to change color
|
108
|
-
self.comboBox_motor_x.currentIndexChanged.connect(
|
109
|
-
lambda: self.set_combobox_style(self.comboBox_motor_x, "#ffa700")
|
110
|
-
)
|
111
|
-
self.comboBox_motor_y.currentIndexChanged.connect(
|
112
|
-
lambda: self.set_combobox_style(self.comboBox_motor_y, "#ffa700")
|
113
|
-
)
|
114
|
-
|
115
|
-
@pyqtSlot(dict)
|
116
|
-
def on_config_update(self, config: dict) -> None:
|
117
|
-
"""
|
118
|
-
Update config dict
|
119
|
-
Args:
|
120
|
-
config(dict): New config dict
|
121
|
-
"""
|
122
|
-
self.config = config
|
123
|
-
|
124
|
-
# Get motor names
|
125
|
-
self.motor_x, self.motor_y = (
|
126
|
-
self.config["motor_control"]["motor_x"],
|
127
|
-
self.config["motor_control"]["motor_y"],
|
128
|
-
)
|
129
|
-
|
130
|
-
self._init_ui()
|
131
|
-
|
132
|
-
@pyqtSlot(bool)
|
133
|
-
def enable_motor_controls(self, enable: bool) -> None:
|
134
|
-
"""
|
135
|
-
Enable or disable the motor controls.
|
136
|
-
Args:
|
137
|
-
enable(bool): True to enable, False to disable.
|
138
|
-
"""
|
139
|
-
self.motorSelection.setEnabled(enable)
|
140
|
-
|
141
|
-
@pyqtSlot()
|
142
|
-
def get_available_motors(self) -> None:
|
143
|
-
"""
|
144
|
-
Slot to populate the available motors in the combo boxes and set the index based on the configuration.
|
145
|
-
"""
|
146
|
-
# Get all available motors
|
147
|
-
self.motor_list = self.motor_thread.get_all_motors_names()
|
148
|
-
|
149
|
-
# Populate the combo boxes
|
150
|
-
self.comboBox_motor_x.addItems(self.motor_list)
|
151
|
-
self.comboBox_motor_y.addItems(self.motor_list)
|
152
|
-
|
153
|
-
# Set the index based on the config if provided
|
154
|
-
if self.config:
|
155
|
-
index_x = self.comboBox_motor_x.findText(self.motor_x)
|
156
|
-
index_y = self.comboBox_motor_y.findText(self.motor_y)
|
157
|
-
self.comboBox_motor_x.setCurrentIndex(index_x if index_x != -1 else 0)
|
158
|
-
self.comboBox_motor_y.setCurrentIndex(index_y if index_y != -1 else 0)
|
159
|
-
|
160
|
-
def set_combobox_style(self, combobox: QComboBox, color: str) -> None:
|
161
|
-
"""
|
162
|
-
Set the combobox style to a specific color.
|
163
|
-
Args:
|
164
|
-
combobox(QComboBox): Combobox to change the color.
|
165
|
-
color(str): Color to set the combobox to.
|
166
|
-
"""
|
167
|
-
combobox.setStyleSheet(f"QComboBox {{ background-color: {color}; }}")
|
168
|
-
|
169
|
-
def select_motor(self):
|
170
|
-
"""Emit the selected motors"""
|
171
|
-
motor_x = self.comboBox_motor_x.currentText()
|
172
|
-
motor_y = self.comboBox_motor_y.currentText()
|
173
|
-
|
174
|
-
# Reset the combobox color to normal after selection
|
175
|
-
self.set_combobox_style(self.comboBox_motor_x, "")
|
176
|
-
self.set_combobox_style(self.comboBox_motor_y, "")
|
177
|
-
|
178
|
-
self.selected_motors_signal.emit(motor_x, motor_y)
|
179
|
-
|
180
|
-
|
181
|
-
class MotorControlAbsolute(MotorControlWidget):
|
182
|
-
"""
|
183
|
-
Widget for controlling the motors to absolute coordinates.
|
184
|
-
|
185
|
-
Signals:
|
186
|
-
coordinates_signal (pyqtSignal(tuple)): Signal to emit the coordinates.
|
187
|
-
Slots:
|
188
|
-
change_motors (pyqtSlot): Slot to change the active motors.
|
189
|
-
enable_motor_controls (pyqtSlot(bool)): Slot to enable/disable the motor controls.
|
190
|
-
"""
|
191
|
-
|
192
|
-
coordinates_signal = pyqtSignal(tuple)
|
193
|
-
|
194
|
-
def _load_ui(self):
|
195
|
-
"""Load the UI from the .ui file."""
|
196
|
-
current_path = os.path.dirname(__file__)
|
197
|
-
uic.loadUi(os.path.join(current_path, "motor_control_absolute.ui"), self)
|
198
|
-
|
199
|
-
def _init_ui(self):
|
200
|
-
"""Initialize the UI."""
|
201
|
-
|
202
|
-
# Check if there are any motors connected
|
203
|
-
if self.motor_x is None or self.motor_y is None:
|
204
|
-
self.motorControl_absolute.setEnabled(False)
|
205
|
-
return
|
206
|
-
|
207
|
-
# Move to absolute coordinates
|
208
|
-
self.pushButton_go_absolute.clicked.connect(
|
209
|
-
lambda: self.move_motor_absolute(
|
210
|
-
self.spinBox_absolute_x.value(), self.spinBox_absolute_y.value()
|
211
|
-
)
|
212
|
-
)
|
213
|
-
|
214
|
-
self.pushButton_set.clicked.connect(self.save_absolute_coordinates)
|
215
|
-
self.pushButton_save.clicked.connect(self.save_current_coordinates)
|
216
|
-
self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
217
|
-
|
218
|
-
# Enable/Disable GUI
|
219
|
-
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
220
|
-
|
221
|
-
# Error messages
|
222
|
-
self.motor_thread.motor_error.connect(
|
223
|
-
lambda error: MotorControlErrors.display_error_message(error)
|
224
|
-
)
|
225
|
-
|
226
|
-
# Keyboard shortcuts
|
227
|
-
self._init_keyboard_shortcuts()
|
228
|
-
|
229
|
-
@pyqtSlot(dict)
|
230
|
-
def on_config_update(self, config: dict) -> None:
|
231
|
-
"""Update config dict"""
|
232
|
-
self.config = config
|
233
|
-
|
234
|
-
# Get motor names
|
235
|
-
self.motor_x, self.motor_y = (
|
236
|
-
self.config["motor_control"]["motor_x"],
|
237
|
-
self.config["motor_control"]["motor_y"],
|
238
|
-
)
|
239
|
-
|
240
|
-
# Update step precision
|
241
|
-
self.precision = self.config["motor_control"]["precision"]
|
242
|
-
|
243
|
-
self._init_ui()
|
244
|
-
|
245
|
-
@pyqtSlot(bool)
|
246
|
-
def enable_motor_controls(self, enable: bool) -> None:
|
247
|
-
"""
|
248
|
-
Enable or disable the motor controls.
|
249
|
-
Args:
|
250
|
-
enable(bool): True to enable, False to disable.
|
251
|
-
"""
|
252
|
-
|
253
|
-
# Disable or enable all controls within the motorControl_absolute group box
|
254
|
-
for widget in self.motorControl_absolute.findChildren(QWidget):
|
255
|
-
widget.setEnabled(enable)
|
256
|
-
|
257
|
-
# Enable the pushButton_stop if the motor is moving
|
258
|
-
self.pushButton_stop.setEnabled(True)
|
259
|
-
|
260
|
-
@pyqtSlot(str, str)
|
261
|
-
def change_motors(self, motor_x: str, motor_y: str):
|
262
|
-
"""
|
263
|
-
Change the active motors and update config.
|
264
|
-
Can be connected to the selected_motors_signal from MotorControlSelection.
|
265
|
-
Args:
|
266
|
-
motor_x(str): New motor X to be controlled.
|
267
|
-
motor_y(str): New motor Y to be controlled.
|
268
|
-
"""
|
269
|
-
self.motor_x = motor_x
|
270
|
-
self.motor_y = motor_y
|
271
|
-
self.config["motor_control"]["motor_x"] = motor_x
|
272
|
-
self.config["motor_control"]["motor_y"] = motor_y
|
273
|
-
|
274
|
-
@pyqtSlot(int)
|
275
|
-
def set_precision(self, precision: int) -> None:
|
276
|
-
"""
|
277
|
-
Set the precision of the coordinates.
|
278
|
-
Args:
|
279
|
-
precision(int): Precision of the coordinates.
|
280
|
-
"""
|
281
|
-
self.precision = precision
|
282
|
-
self.config["motor_control"]["precision"] = precision
|
283
|
-
self.spinBox_absolute_x.setDecimals(precision)
|
284
|
-
self.spinBox_absolute_y.setDecimals(precision)
|
285
|
-
|
286
|
-
def move_motor_absolute(self, x: float, y: float) -> None:
|
287
|
-
"""
|
288
|
-
Move the motor to the target coordinates.
|
289
|
-
Args:
|
290
|
-
x(float): Target x coordinate.
|
291
|
-
y(float): Target y coordinate.
|
292
|
-
"""
|
293
|
-
# self._enable_motor_controls(False)
|
294
|
-
target_coordinates = (x, y)
|
295
|
-
self.motor_thread.move_absolute(self.motor_x, self.motor_y, target_coordinates)
|
296
|
-
if self.checkBox_save_with_go.isChecked():
|
297
|
-
self.save_absolute_coordinates()
|
298
|
-
|
299
|
-
def _init_keyboard_shortcuts(self):
|
300
|
-
"""Initialize the keyboard shortcuts."""
|
301
|
-
# Go absolute button
|
302
|
-
self.pushButton_go_absolute.setShortcut("Ctrl+G")
|
303
|
-
self.pushButton_go_absolute.setToolTip("Ctrl+G")
|
304
|
-
|
305
|
-
# Set absolute coordinates
|
306
|
-
self.pushButton_set.setShortcut("Ctrl+D")
|
307
|
-
self.pushButton_set.setToolTip("Ctrl+D")
|
308
|
-
|
309
|
-
# Save Current coordinates
|
310
|
-
self.pushButton_save.setShortcut("Ctrl+S")
|
311
|
-
self.pushButton_save.setToolTip("Ctrl+S")
|
312
|
-
|
313
|
-
# Stop Button
|
314
|
-
self.pushButton_stop.setShortcut("Ctrl+X")
|
315
|
-
self.pushButton_stop.setToolTip("Ctrl+X")
|
316
|
-
|
317
|
-
def save_absolute_coordinates(self):
|
318
|
-
"""Emit the setup coordinates from the spinboxes"""
|
319
|
-
|
320
|
-
x, y = round(self.spinBox_absolute_x.value(), self.precision), round(
|
321
|
-
self.spinBox_absolute_y.value(), self.precision
|
322
|
-
)
|
323
|
-
self.coordinates_signal.emit((x, y))
|
324
|
-
|
325
|
-
def save_current_coordinates(self):
|
326
|
-
"""Emit the current coordinates from the motor thread"""
|
327
|
-
x, y = self.motor_thread.get_coordinates(self.motor_x, self.motor_y)
|
328
|
-
self.coordinates_signal.emit((round(x, self.precision), round(y, self.precision)))
|
329
|
-
|
330
|
-
|
331
|
-
class MotorControlRelative(MotorControlWidget):
|
332
|
-
"""
|
333
|
-
Widget for controlling the motors to relative coordinates.
|
334
|
-
|
335
|
-
Signals:
|
336
|
-
precision_signal (pyqtSignal): Signal to emit the precision of the coordinates.
|
337
|
-
Slots:
|
338
|
-
change_motors (pyqtSlot(str,str)): Slot to change the active motors.
|
339
|
-
enable_motor_controls (pyqtSlot): Slot to enable/disable the motor controls.
|
340
|
-
"""
|
341
|
-
|
342
|
-
precision_signal = pyqtSignal(int)
|
343
|
-
|
344
|
-
def _load_ui(self):
|
345
|
-
"""Load the UI from the .ui file."""
|
346
|
-
# Loading UI
|
347
|
-
current_path = os.path.dirname(__file__)
|
348
|
-
uic.loadUi(os.path.join(current_path, "motor_control_relative.ui"), self)
|
349
|
-
|
350
|
-
def _init_ui(self):
|
351
|
-
"""Initialize the UI."""
|
352
|
-
self._init_ui_motor_control()
|
353
|
-
self._init_keyboard_shortcuts()
|
354
|
-
|
355
|
-
@pyqtSlot(dict)
|
356
|
-
def on_config_update(self, config: dict) -> None:
|
357
|
-
"""
|
358
|
-
Update config dict
|
359
|
-
Args:
|
360
|
-
config(dict): New config dict
|
361
|
-
"""
|
362
|
-
self.config = config
|
363
|
-
|
364
|
-
# Get motor names
|
365
|
-
self.motor_x, self.motor_y = (
|
366
|
-
self.config["motor_control"]["motor_x"],
|
367
|
-
self.config["motor_control"]["motor_y"],
|
368
|
-
)
|
369
|
-
|
370
|
-
# Update step precision
|
371
|
-
self.precision = self.config["motor_control"]["precision"]
|
372
|
-
self.spinBox_precision.setValue(self.precision)
|
373
|
-
|
374
|
-
# Update step sizes
|
375
|
-
self.spinBox_step_x.setValue(self.config["motor_control"]["step_size_x"])
|
376
|
-
self.spinBox_step_y.setValue(self.config["motor_control"]["step_size_y"])
|
377
|
-
|
378
|
-
# Checkboxes for keyboard shortcuts and x/y step size link
|
379
|
-
self.checkBox_same_xy.setChecked(self.config["motor_control"]["step_x_y_same"])
|
380
|
-
self.checkBox_enableArrows.setChecked(self.config["motor_control"]["move_with_arrows"])
|
381
|
-
|
382
|
-
self._init_ui()
|
383
|
-
|
384
|
-
def _init_ui_motor_control(self) -> None:
|
385
|
-
"""Initialize the motor control elements"""
|
386
|
-
|
387
|
-
# Connect checkbox and spinBoxes
|
388
|
-
self.checkBox_same_xy.stateChanged.connect(self._sync_step_sizes)
|
389
|
-
self.spinBox_step_x.valueChanged.connect(self._update_step_size_x)
|
390
|
-
self.spinBox_step_y.valueChanged.connect(self._update_step_size_y)
|
391
|
-
|
392
|
-
self.toolButton_right.clicked.connect(
|
393
|
-
lambda: self.move_motor_relative(self.motor_x, "x", 1)
|
394
|
-
)
|
395
|
-
self.toolButton_left.clicked.connect(
|
396
|
-
lambda: self.move_motor_relative(self.motor_x, "x", -1)
|
397
|
-
)
|
398
|
-
self.toolButton_up.clicked.connect(lambda: self.move_motor_relative(self.motor_y, "y", 1))
|
399
|
-
self.toolButton_down.clicked.connect(
|
400
|
-
lambda: self.move_motor_relative(self.motor_y, "y", -1)
|
401
|
-
)
|
402
|
-
|
403
|
-
# Switch between key shortcuts active
|
404
|
-
self.checkBox_enableArrows.stateChanged.connect(self._update_arrow_key_shortcuts)
|
405
|
-
self._update_arrow_key_shortcuts()
|
406
|
-
|
407
|
-
# Enable/Disable GUI
|
408
|
-
self.motor_thread.lock_gui.connect(self.enable_motor_controls)
|
409
|
-
|
410
|
-
# Precision update
|
411
|
-
self.spinBox_precision.valueChanged.connect(lambda x: self._update_precision(x))
|
412
|
-
|
413
|
-
# Error messages
|
414
|
-
self.motor_thread.motor_error.connect(
|
415
|
-
lambda error: MotorControlErrors.display_error_message(error)
|
416
|
-
)
|
417
|
-
|
418
|
-
# Stop Button
|
419
|
-
self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
|
420
|
-
|
421
|
-
def _init_keyboard_shortcuts(self) -> None:
|
422
|
-
"""Initialize the keyboard shortcuts"""
|
423
|
-
|
424
|
-
# Increase/decrease step size for X motor
|
425
|
-
increase_x_shortcut = QShortcut(QKeySequence("Ctrl+A"), self)
|
426
|
-
decrease_x_shortcut = QShortcut(QKeySequence("Ctrl+Z"), self)
|
427
|
-
increase_x_shortcut.activated.connect(
|
428
|
-
lambda: self._change_step_size(self.spinBox_step_x, 2)
|
429
|
-
)
|
430
|
-
decrease_x_shortcut.activated.connect(
|
431
|
-
lambda: self._change_step_size(self.spinBox_step_x, 0.5)
|
432
|
-
)
|
433
|
-
self.spinBox_step_x.setToolTip("Increase step size: Ctrl+A\nDecrease step size: Ctrl+Z")
|
434
|
-
|
435
|
-
# Increase/decrease step size for Y motor
|
436
|
-
increase_y_shortcut = QShortcut(QKeySequence("Alt+A"), self)
|
437
|
-
decrease_y_shortcut = QShortcut(QKeySequence("Alt+Z"), self)
|
438
|
-
increase_y_shortcut.activated.connect(
|
439
|
-
lambda: self._change_step_size(self.spinBox_step_y, 2)
|
440
|
-
)
|
441
|
-
decrease_y_shortcut.activated.connect(
|
442
|
-
lambda: self._change_step_size(self.spinBox_step_y, 0.5)
|
443
|
-
)
|
444
|
-
self.spinBox_step_y.setToolTip("Increase step size: Alt+A\nDecrease step size: Alt+Z")
|
445
|
-
|
446
|
-
# Stop Button
|
447
|
-
self.pushButton_stop.setShortcut("Ctrl+X")
|
448
|
-
self.pushButton_stop.setToolTip("Ctrl+X")
|
449
|
-
|
450
|
-
def _update_arrow_key_shortcuts(self) -> None:
|
451
|
-
"""Update the arrow key shortcuts based on the checkbox state."""
|
452
|
-
if self.checkBox_enableArrows.isChecked():
|
453
|
-
# Set the arrow key shortcuts for motor movement
|
454
|
-
self.toolButton_right.setShortcut(Qt.Key_Right)
|
455
|
-
self.toolButton_left.setShortcut(Qt.Key_Left)
|
456
|
-
self.toolButton_up.setShortcut(Qt.Key_Up)
|
457
|
-
self.toolButton_down.setShortcut(Qt.Key_Down)
|
458
|
-
else:
|
459
|
-
# Clear the shortcuts
|
460
|
-
self.toolButton_right.setShortcut("")
|
461
|
-
self.toolButton_left.setShortcut("")
|
462
|
-
self.toolButton_up.setShortcut("")
|
463
|
-
self.toolButton_down.setShortcut("")
|
464
|
-
|
465
|
-
def _update_precision(self, precision: int) -> None:
|
466
|
-
"""
|
467
|
-
Update the precision of the coordinates.
|
468
|
-
Args:
|
469
|
-
precision(int): Precision of the coordinates.
|
470
|
-
"""
|
471
|
-
self.spinBox_step_x.setDecimals(precision)
|
472
|
-
self.spinBox_step_y.setDecimals(precision)
|
473
|
-
self.precision_signal.emit(precision)
|
474
|
-
|
475
|
-
def _change_step_size(self, spinBox: QDoubleSpinBox, factor: float) -> None:
|
476
|
-
"""
|
477
|
-
Change the step size of the spinbox.
|
478
|
-
Args:
|
479
|
-
spinBox(QDoubleSpinBox): Spinbox to change the step size.
|
480
|
-
factor(float): Factor to change the step size.
|
481
|
-
"""
|
482
|
-
old_step = spinBox.value()
|
483
|
-
new_step = old_step * factor
|
484
|
-
spinBox.setValue(new_step)
|
485
|
-
|
486
|
-
def _sync_step_sizes(self):
|
487
|
-
"""Sync step sizes based on checkbox state."""
|
488
|
-
if self.checkBox_same_xy.isChecked():
|
489
|
-
value = self.spinBox_step_x.value()
|
490
|
-
self.spinBox_step_y.setValue(value)
|
491
|
-
|
492
|
-
def _update_step_size_x(self):
|
493
|
-
"""Update step size for x if checkbox is checked."""
|
494
|
-
if self.checkBox_same_xy.isChecked():
|
495
|
-
value = self.spinBox_step_x.value()
|
496
|
-
self.spinBox_step_y.setValue(value)
|
497
|
-
|
498
|
-
def _update_step_size_y(self):
|
499
|
-
"""Update step size for y if checkbox is checked."""
|
500
|
-
if self.checkBox_same_xy.isChecked():
|
501
|
-
value = self.spinBox_step_y.value()
|
502
|
-
self.spinBox_step_x.setValue(value)
|
503
|
-
|
504
|
-
@pyqtSlot(str, str)
|
505
|
-
def change_motors(self, motor_x: str, motor_y: str):
|
506
|
-
"""
|
507
|
-
Change the active motors and update config.
|
508
|
-
Can be connected to the selected_motors_signal from MotorControlSelection.
|
509
|
-
Args:
|
510
|
-
motor_x(str): New motor X to be controlled.
|
511
|
-
motor_y(str): New motor Y to be controlled.
|
512
|
-
"""
|
513
|
-
self.motor_x = motor_x
|
514
|
-
self.motor_y = motor_y
|
515
|
-
self.config["motor_control"]["motor_x"] = motor_x
|
516
|
-
self.config["motor_control"]["motor_y"] = motor_y
|
517
|
-
|
518
|
-
@pyqtSlot(bool)
|
519
|
-
def enable_motor_controls(self, disable: bool) -> None:
|
520
|
-
"""
|
521
|
-
Enable or disable the motor controls.
|
522
|
-
Args:
|
523
|
-
disable(bool): True to disable, False to enable.
|
524
|
-
"""
|
525
|
-
|
526
|
-
# Disable or enable all controls within the motorControl_absolute group box
|
527
|
-
for widget in self.motorControl.findChildren(QWidget):
|
528
|
-
widget.setEnabled(disable)
|
529
|
-
|
530
|
-
# Enable the pushButton_stop if the motor is moving
|
531
|
-
self.pushButton_stop.setEnabled(True)
|
532
|
-
|
533
|
-
def move_motor_relative(self, motor, axis: str, direction: int) -> None:
|
534
|
-
"""
|
535
|
-
Move the motor relative to the current position.
|
536
|
-
Args:
|
537
|
-
motor: Motor to move.
|
538
|
-
axis(str): Axis to move.
|
539
|
-
direction(int): Direction to move. 1 for positive, -1 for negative.
|
540
|
-
"""
|
541
|
-
if axis == "x":
|
542
|
-
step = direction * self.spinBox_step_x.value()
|
543
|
-
elif axis == "y":
|
544
|
-
step = direction * self.spinBox_step_y.value()
|
545
|
-
self.motor_thread.move_relative(motor, step)
|
546
|
-
|
547
|
-
|
548
|
-
class MotorCoordinateTable(MotorControlWidget):
|
549
|
-
"""
|
550
|
-
Widget to save coordinates from motor, display them in the table and move back to them.
|
551
|
-
There are two modes of operation:
|
552
|
-
- Individual: Each row is a single coordinate.
|
553
|
-
- Start/Stop: Each pair of rows is a start and end coordinate.
|
554
|
-
Signals:
|
555
|
-
plot_coordinates_signal (pyqtSignal(list, str, str)): Signal to plot the coordinates in the MotorMap.
|
556
|
-
Slots:
|
557
|
-
add_coordinate (pyqtSlot(tuple)): Slot to add a coordinate to the table.
|
558
|
-
mode_switch (pyqtSlot): Slot to switch between individual and start/stop mode.
|
559
|
-
"""
|
560
|
-
|
561
|
-
plot_coordinates_signal = pyqtSignal(list, str, str)
|
562
|
-
|
563
|
-
def _load_ui(self):
|
564
|
-
"""Load the UI for the coordinate table."""
|
565
|
-
current_path = os.path.dirname(__file__)
|
566
|
-
uic.loadUi(os.path.join(current_path, "motor_control_table.ui"), self)
|
567
|
-
|
568
|
-
def _init_ui(self):
|
569
|
-
"""Initialize the UI"""
|
570
|
-
# Setup table behaviour
|
571
|
-
self._setup_table()
|
572
|
-
self.table.setSelectionBehavior(QTableWidget.SelectRows)
|
573
|
-
|
574
|
-
# for tag columns default tag
|
575
|
-
self.tag_counter = 1
|
576
|
-
|
577
|
-
# Connect signals and slots
|
578
|
-
self.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
|
579
|
-
self.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
|
580
|
-
|
581
|
-
# Keyboard shortcuts for deleting a row
|
582
|
-
self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.table)
|
583
|
-
self.delete_shortcut.activated.connect(self.delete_selected_row)
|
584
|
-
self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.table)
|
585
|
-
self.backspace_shortcut.activated.connect(self.delete_selected_row)
|
586
|
-
|
587
|
-
# Warning message for mode switch enable/disable
|
588
|
-
self.warning_message = True
|
589
|
-
|
590
|
-
@pyqtSlot(dict)
|
591
|
-
def on_config_update(self, config: dict) -> None:
|
592
|
-
"""
|
593
|
-
Update config dict
|
594
|
-
Args:
|
595
|
-
config(dict): New config dict
|
596
|
-
"""
|
597
|
-
self.config = config
|
598
|
-
|
599
|
-
# Get motor names
|
600
|
-
self.motor_x, self.motor_y = (
|
601
|
-
self.config["motor_control"]["motor_x"],
|
602
|
-
self.config["motor_control"]["motor_y"],
|
603
|
-
)
|
604
|
-
|
605
|
-
# Decimal precision of the table coordinates
|
606
|
-
self.precision = self.config["motor_control"].get("precision", 3)
|
607
|
-
|
608
|
-
# Mode switch default option
|
609
|
-
self.mode = self.config["motor_control"].get("mode", "Individual")
|
610
|
-
|
611
|
-
# Set combobox to default mode
|
612
|
-
self.comboBox_mode.setCurrentText(self.mode)
|
613
|
-
|
614
|
-
self._init_ui()
|
615
|
-
|
616
|
-
def _setup_table(self):
|
617
|
-
"""Setup the table with appropriate headers and configurations."""
|
618
|
-
mode = self.comboBox_mode.currentText()
|
619
|
-
|
620
|
-
if mode == "Individual":
|
621
|
-
self._setup_individual_mode()
|
622
|
-
elif mode == "Start/Stop":
|
623
|
-
self._setup_start_stop_mode()
|
624
|
-
self.start_stop_counter = 0 # TODO: remove this??
|
625
|
-
|
626
|
-
self.wipe_motor_map_coordinates()
|
627
|
-
|
628
|
-
def _setup_individual_mode(self):
|
629
|
-
"""Setup the table for individual mode."""
|
630
|
-
self.table.setColumnCount(5)
|
631
|
-
self.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
|
632
|
-
self.table.verticalHeader().setVisible(False)
|
633
|
-
|
634
|
-
def _setup_start_stop_mode(self):
|
635
|
-
"""Setup the table for start/stop mode."""
|
636
|
-
self.table.setColumnCount(8)
|
637
|
-
self.table.setHorizontalHeaderLabels(
|
638
|
-
[
|
639
|
-
"Show",
|
640
|
-
"Move [start]",
|
641
|
-
"Move [end]",
|
642
|
-
"Tag",
|
643
|
-
"X [start]",
|
644
|
-
"Y [start]",
|
645
|
-
"X [end]",
|
646
|
-
"Y [end]",
|
647
|
-
]
|
648
|
-
)
|
649
|
-
self.table.verticalHeader().setVisible(False)
|
650
|
-
# Set flag to track if the coordinate is stat or the end of the entry
|
651
|
-
self.is_next_entry_end = False
|
652
|
-
|
653
|
-
def mode_switch(self):
|
654
|
-
"""Switch between individual and start/stop mode."""
|
655
|
-
last_selected_index = self.comboBox_mode.currentIndex()
|
656
|
-
|
657
|
-
if self.table.rowCount() > 0 and self.warning_message is True:
|
658
|
-
msgBox = QMessageBox()
|
659
|
-
msgBox.setIcon(QMessageBox.Critical)
|
660
|
-
msgBox.setText(
|
661
|
-
"Switching modes will delete all table entries. Do you want to continue?"
|
662
|
-
)
|
663
|
-
msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
|
664
|
-
returnValue = msgBox.exec()
|
665
|
-
|
666
|
-
if returnValue is QMessageBox.Cancel:
|
667
|
-
self.comboBox_mode.blockSignals(True) # Block signals
|
668
|
-
self.comboBox_mode.setCurrentIndex(last_selected_index)
|
669
|
-
self.comboBox_mode.blockSignals(False) # Unblock signals
|
670
|
-
return
|
671
|
-
|
672
|
-
# Wipe table
|
673
|
-
self.wipe_motor_map_coordinates()
|
674
|
-
|
675
|
-
# Initiate new table with new mode
|
676
|
-
self._setup_table()
|
677
|
-
|
678
|
-
@pyqtSlot(tuple)
|
679
|
-
def add_coordinate(self, coordinates: tuple):
|
680
|
-
"""
|
681
|
-
Add a coordinate to the table.
|
682
|
-
Args:
|
683
|
-
coordinates(tuple): Coordinates (x,y) to add to the table.
|
684
|
-
"""
|
685
|
-
tag = f"Pos {self.tag_counter}"
|
686
|
-
self.tag_counter += 1
|
687
|
-
x, y = coordinates
|
688
|
-
self._add_row(tag, x, y)
|
689
|
-
|
690
|
-
def _add_row(self, tag: str, x: float, y: float) -> None:
|
691
|
-
"""
|
692
|
-
Add a row to the table.
|
693
|
-
Args:
|
694
|
-
tag(str): Tag of the coordinate.
|
695
|
-
x(float): X coordinate.
|
696
|
-
y(float): Y coordinate.
|
697
|
-
"""
|
698
|
-
|
699
|
-
mode = self.comboBox_mode.currentText()
|
700
|
-
if mode == "Individual":
|
701
|
-
checkbox_pos = 0
|
702
|
-
button_pos = 1
|
703
|
-
tag_pos = 2
|
704
|
-
x_pos = 3
|
705
|
-
y_pos = 4
|
706
|
-
coordinate_reference = "Individual"
|
707
|
-
color = "green"
|
708
|
-
|
709
|
-
# Add new row -> new entry
|
710
|
-
row_count = self.table.rowCount()
|
711
|
-
self.table.insertRow(row_count)
|
712
|
-
|
713
|
-
# Add Widgets
|
714
|
-
self._add_widgets(
|
715
|
-
tag,
|
716
|
-
x,
|
717
|
-
y,
|
718
|
-
row_count,
|
719
|
-
checkbox_pos,
|
720
|
-
tag_pos,
|
721
|
-
button_pos,
|
722
|
-
x_pos,
|
723
|
-
y_pos,
|
724
|
-
coordinate_reference,
|
725
|
-
color,
|
726
|
-
)
|
727
|
-
|
728
|
-
if mode == "Start/Stop":
|
729
|
-
# These positions are always fixed
|
730
|
-
checkbox_pos = 0
|
731
|
-
tag_pos = 3
|
732
|
-
|
733
|
-
if self.is_next_entry_end is False: # It is the start position of the entry
|
734
|
-
print("Start position")
|
735
|
-
button_pos = 1
|
736
|
-
x_pos = 4
|
737
|
-
y_pos = 5
|
738
|
-
coordinate_reference = "Start"
|
739
|
-
color = "blue"
|
740
|
-
|
741
|
-
# Add new row -> new entry
|
742
|
-
row_count = self.table.rowCount()
|
743
|
-
self.table.insertRow(row_count)
|
744
|
-
|
745
|
-
# Add Widgets
|
746
|
-
self._add_widgets(
|
747
|
-
tag,
|
748
|
-
x,
|
749
|
-
y,
|
750
|
-
row_count,
|
751
|
-
checkbox_pos,
|
752
|
-
tag_pos,
|
753
|
-
button_pos,
|
754
|
-
x_pos,
|
755
|
-
y_pos,
|
756
|
-
coordinate_reference,
|
757
|
-
color,
|
758
|
-
)
|
759
|
-
|
760
|
-
# Next entry will be the end of the current entry
|
761
|
-
self.is_next_entry_end = True
|
762
|
-
|
763
|
-
elif self.is_next_entry_end is True: # It is the end position of the entry
|
764
|
-
print("End position")
|
765
|
-
row_count = self.table.rowCount() - 1 # Current row
|
766
|
-
button_pos = 2
|
767
|
-
x_pos = 6
|
768
|
-
y_pos = 7
|
769
|
-
coordinate_reference = "Stop"
|
770
|
-
color = "red"
|
771
|
-
|
772
|
-
# Add Widgets
|
773
|
-
self._add_widgets(
|
774
|
-
tag,
|
775
|
-
x,
|
776
|
-
y,
|
777
|
-
row_count,
|
778
|
-
checkbox_pos,
|
779
|
-
tag_pos,
|
780
|
-
button_pos,
|
781
|
-
x_pos,
|
782
|
-
y_pos,
|
783
|
-
coordinate_reference,
|
784
|
-
color,
|
785
|
-
)
|
786
|
-
self.is_next_entry_end = False # Next entry will be the start of the new entry
|
787
|
-
|
788
|
-
# Auto table resize
|
789
|
-
self.resize_table_auto()
|
790
|
-
|
791
|
-
def _add_widgets(
|
792
|
-
self,
|
793
|
-
tag: str,
|
794
|
-
x: float,
|
795
|
-
y: float,
|
796
|
-
row: int,
|
797
|
-
checkBox_pos: int,
|
798
|
-
tag_pos: int,
|
799
|
-
button_pos: int,
|
800
|
-
x_pos: int,
|
801
|
-
y_pos: int,
|
802
|
-
coordinate_reference: str,
|
803
|
-
color: str,
|
804
|
-
) -> None:
|
805
|
-
"""
|
806
|
-
Add widgets to the table.
|
807
|
-
Args:
|
808
|
-
tag(str): Tag of the coordinate.
|
809
|
-
x(float): X coordinate.
|
810
|
-
y(float): Y coordinate.
|
811
|
-
row(int): Row of the QTableWidget where to add the widgets.
|
812
|
-
checkBox_pos(int): Column where to put CheckBox.
|
813
|
-
tag_pos(int): Column where to put Tag.
|
814
|
-
button_pos(int): Column where to put Move button.
|
815
|
-
x_pos(int): Column where to link x coordinate.
|
816
|
-
y_pos(int): Column where to link y coordinate.
|
817
|
-
coordinate_reference(str): Reference to the coordinate for MotorMap.
|
818
|
-
color(str): Color of the coordinate for MotorMap.
|
819
|
-
"""
|
820
|
-
# Add widgets
|
821
|
-
self._add_checkbox(row, checkBox_pos, x_pos, y_pos)
|
822
|
-
self._add_move_button(row, button_pos, x_pos, y_pos)
|
823
|
-
self.table.setItem(row, tag_pos, QTableWidgetItem(tag))
|
824
|
-
self._add_line_edit(x, row, x_pos, x_pos, y_pos, coordinate_reference, color)
|
825
|
-
self._add_line_edit(y, row, y_pos, x_pos, y_pos, coordinate_reference, color)
|
826
|
-
|
827
|
-
# # Emit the coordinates to be plotted
|
828
|
-
self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
829
|
-
|
830
|
-
# Connect item edit to emit coordinates
|
831
|
-
self.table.itemChanged.connect(
|
832
|
-
lambda: print(f"item changed from {coordinate_reference} slot \n {x}-{y}-{color}")
|
833
|
-
)
|
834
|
-
self.table.itemChanged.connect(
|
835
|
-
lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
836
|
-
)
|
837
|
-
|
838
|
-
def _add_checkbox(self, row: int, checkBox_pos: int, x_pos: int, y_pos: int):
|
839
|
-
"""
|
840
|
-
Add a checkbox to the table.
|
841
|
-
Args:
|
842
|
-
row(int): Row of QTableWidget where to add the checkbox.
|
843
|
-
checkBox_pos(int): Column where to put CheckBox.
|
844
|
-
x_pos(int): Column where to link x coordinate.
|
845
|
-
y_pos(int): Column where to link y coordinate.
|
846
|
-
"""
|
847
|
-
show_checkbox = QCheckBox()
|
848
|
-
show_checkbox.setChecked(True)
|
849
|
-
show_checkbox.stateChanged.connect(lambda: self.emit_plot_coordinates(x_pos, y_pos))
|
850
|
-
self.table.setCellWidget(row, checkBox_pos, show_checkbox)
|
851
|
-
|
852
|
-
def _add_move_button(self, row: int, button_pos: int, x_pos: int, y_pos: int) -> None:
|
853
|
-
"""
|
854
|
-
Add a move button to the table.
|
855
|
-
Args:
|
856
|
-
row(int): Row of QTableWidget where to add the move button.
|
857
|
-
button_pos(int): Column where to put move button.
|
858
|
-
x_pos(int): Column where to link x coordinate.
|
859
|
-
y_pos(int): Column where to link y coordinate.
|
860
|
-
"""
|
861
|
-
move_button = QPushButton("Move")
|
862
|
-
move_button.clicked.connect(lambda: self.handle_move_button_click(x_pos, y_pos))
|
863
|
-
self.table.setCellWidget(row, button_pos, move_button)
|
864
|
-
|
865
|
-
def _add_line_edit(
|
866
|
-
self,
|
867
|
-
value: float,
|
868
|
-
row: int,
|
869
|
-
line_pos: int,
|
870
|
-
x_pos: int,
|
871
|
-
y_pos: int,
|
872
|
-
coordinate_reference: str,
|
873
|
-
color: str,
|
874
|
-
) -> None:
|
875
|
-
"""
|
876
|
-
Add a QLineEdit to the table.
|
877
|
-
Args:
|
878
|
-
value(float): Initial value of the QLineEdit.
|
879
|
-
row(int): Row of QTableWidget where to add the QLineEdit.
|
880
|
-
line_pos(int): Column where to put QLineEdit.
|
881
|
-
x_pos(int): Column where to link x coordinate.
|
882
|
-
y_pos(int): Column where to link y coordinate.
|
883
|
-
coordinate_reference(str): Reference to the coordinate for MotorMap.
|
884
|
-
color(str): Color of the coordinate for MotorMap.
|
885
|
-
"""
|
886
|
-
# Adding validator
|
887
|
-
validator = QDoubleValidator()
|
888
|
-
validator.setDecimals(self.precision)
|
889
|
-
|
890
|
-
# Create line edit
|
891
|
-
edit = QLineEdit(str(f"{value:.{self.precision}f}"))
|
892
|
-
edit.setValidator(validator)
|
893
|
-
edit.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
894
|
-
|
895
|
-
# Add line edit to the table
|
896
|
-
self.table.setCellWidget(row, line_pos, edit)
|
897
|
-
edit.textChanged.connect(
|
898
|
-
lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
|
899
|
-
)
|
900
|
-
|
901
|
-
def wipe_motor_map_coordinates(self):
|
902
|
-
"""Wipe the motor map coordinates."""
|
903
|
-
try:
|
904
|
-
self.table.itemChanged.disconnect() # Disconnect all previous connections
|
905
|
-
except TypeError:
|
906
|
-
print("No previous connections to disconnect")
|
907
|
-
self.table.setRowCount(0)
|
908
|
-
reference_tags = ["Individual", "Start", "Stop"]
|
909
|
-
for reference_tag in reference_tags:
|
910
|
-
self.plot_coordinates_signal.emit([], reference_tag, "green")
|
911
|
-
|
912
|
-
def handle_move_button_click(self, x_pos: int, y_pos: int) -> None:
|
913
|
-
"""
|
914
|
-
Handle the move button click.
|
915
|
-
Args:
|
916
|
-
x_pos(int): X position of the coordinate.
|
917
|
-
y_pos(int): Y position of the coordinate.
|
918
|
-
"""
|
919
|
-
button = self.sender()
|
920
|
-
row = self.table.indexAt(button.pos()).row()
|
921
|
-
|
922
|
-
x = self.get_coordinate(row, x_pos)
|
923
|
-
y = self.get_coordinate(row, y_pos)
|
924
|
-
self.move_motor(x, y)
|
925
|
-
|
926
|
-
def emit_plot_coordinates(self, x_pos: float, y_pos: float, reference_tag: str, color: str):
|
927
|
-
"""
|
928
|
-
Emit the coordinates to be plotted.
|
929
|
-
Args:
|
930
|
-
x_pos(float): X position of the coordinate.
|
931
|
-
y_pos(float): Y position of the coordinate.
|
932
|
-
reference_tag(str): Reference tag of the coordinate.
|
933
|
-
color(str): Color of the coordinate.
|
934
|
-
"""
|
935
|
-
print(
|
936
|
-
f"Emitting plot coordinates: x_pos={x_pos}, y_pos={y_pos}, reference_tag={reference_tag}, color={color}"
|
937
|
-
)
|
938
|
-
coordinates = []
|
939
|
-
for row in range(self.table.rowCount()):
|
940
|
-
show = self.table.cellWidget(row, 0).isChecked()
|
941
|
-
x = self.get_coordinate(row, x_pos)
|
942
|
-
y = self.get_coordinate(row, y_pos)
|
943
|
-
|
944
|
-
coordinates.append((x, y, show)) # (x, y, show_flag)
|
945
|
-
self.plot_coordinates_signal.emit(coordinates, reference_tag, color)
|
946
|
-
|
947
|
-
def get_coordinate(self, row: int, column: int) -> float:
|
948
|
-
"""
|
949
|
-
Helper function to get the coordinate from the table QLineEdit cells.
|
950
|
-
Args:
|
951
|
-
row(int): Row of the table.
|
952
|
-
column(int): Column of the table.
|
953
|
-
Returns:
|
954
|
-
float: Value of the coordinate.
|
955
|
-
"""
|
956
|
-
edit = self.table.cellWidget(row, column)
|
957
|
-
value = float(edit.text()) if edit and edit.text() != "" else None
|
958
|
-
if value:
|
959
|
-
return value
|
960
|
-
|
961
|
-
def delete_selected_row(self):
|
962
|
-
"""Delete the selected row from the table."""
|
963
|
-
selected_rows = self.table.selectionModel().selectedRows()
|
964
|
-
for row in selected_rows:
|
965
|
-
self.table.removeRow(row.row())
|
966
|
-
if self.comboBox_mode.currentText() == "Start/Stop":
|
967
|
-
self.emit_plot_coordinates(x_pos=4, y_pos=5, reference_tag="Start", color="blue")
|
968
|
-
self.emit_plot_coordinates(x_pos=6, y_pos=7, reference_tag="Stop", color="red")
|
969
|
-
self.is_next_entry_end = False
|
970
|
-
elif self.comboBox_mode.currentText() == "Individual":
|
971
|
-
self.emit_plot_coordinates(x_pos=3, y_pos=4, reference_tag="Individual", color="green")
|
972
|
-
|
973
|
-
def resize_table_auto(self):
|
974
|
-
"""Resize the table to fit the contents."""
|
975
|
-
if self.checkBox_resize_auto.isChecked():
|
976
|
-
self.table.resizeColumnsToContents()
|
977
|
-
|
978
|
-
def move_motor(self, x: float, y: float) -> None:
|
979
|
-
"""
|
980
|
-
Move the motor to the target coordinates.
|
981
|
-
Args:
|
982
|
-
x(float): Target x coordinate.
|
983
|
-
y(float): Target y coordinate.
|
984
|
-
"""
|
985
|
-
self.motor_thread.move_absolute(self.motor_x, self.motor_y, (x, y))
|
986
|
-
|
987
|
-
@pyqtSlot(str, str)
|
988
|
-
def change_motors(self, motor_x: str, motor_y: str) -> None:
|
989
|
-
"""
|
990
|
-
Change the active motors and update config.
|
991
|
-
Can be connected to the selected_motors_signal from MotorControlSelection.
|
992
|
-
Args:
|
993
|
-
motor_x(str): New motor X to be controlled.
|
994
|
-
motor_y(str): New motor Y to be controlled.
|
995
|
-
"""
|
996
|
-
self.motor_x = motor_x
|
997
|
-
self.motor_y = motor_y
|
998
|
-
self.config["motor_control"]["motor_x"] = motor_x
|
999
|
-
self.config["motor_control"]["motor_y"] = motor_y
|
1000
|
-
|
1001
|
-
@pyqtSlot(int)
|
1002
|
-
def set_precision(self, precision: int) -> None:
|
1003
|
-
"""
|
1004
|
-
Set the precision of the coordinates.
|
1005
|
-
Args:
|
1006
|
-
precision(int): Precision of the coordinates.
|
1007
|
-
"""
|
1008
|
-
self.precision = precision
|
1009
|
-
self.config["motor_control"]["precision"] = precision
|
1010
|
-
|
1011
|
-
|
1012
66
|
class MotorControlErrors:
|
1013
67
|
"""Class for displaying formatted error messages."""
|
1014
68
|
|