bec-widgets 0.80.1__py3-none-any.whl → 0.81.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (28) hide show
  1. CHANGELOG.md +12 -12
  2. PKG-INFO +1 -1
  3. bec_widgets/examples/__init__.py +0 -9
  4. bec_widgets/widgets/buttons/color_button/color_button.py +19 -0
  5. {bec_widgets-0.80.1.dist-info → bec_widgets-0.81.1.dist-info}/METADATA +1 -1
  6. {bec_widgets-0.80.1.dist-info → bec_widgets-0.81.1.dist-info}/RECORD +10 -28
  7. pyproject.toml +1 -1
  8. bec_widgets/examples/motor_movement/__init__.py +0 -9
  9. bec_widgets/examples/motor_movement/motor_control_compilations.py +0 -250
  10. bec_widgets/examples/motor_movement/motor_controller.ui +0 -926
  11. bec_widgets/widgets/motor_control/__init__.py +0 -0
  12. bec_widgets/widgets/motor_control/motor_control.py +0 -252
  13. bec_widgets/widgets/motor_control/motor_table/__init__.py +0 -0
  14. bec_widgets/widgets/motor_control/motor_table/motor_table.py +0 -484
  15. bec_widgets/widgets/motor_control/motor_table/motor_table.ui +0 -113
  16. bec_widgets/widgets/motor_control/movement_absolute/__init__.py +0 -0
  17. bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +0 -159
  18. bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.ui +0 -149
  19. bec_widgets/widgets/motor_control/movement_relative/__init__.py +0 -0
  20. bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +0 -230
  21. bec_widgets/widgets/motor_control/movement_relative/movement_relative.ui +0 -298
  22. bec_widgets/widgets/motor_control/selection/__init__.py +0 -0
  23. bec_widgets/widgets/motor_control/selection/selection.py +0 -110
  24. bec_widgets/widgets/motor_control/selection/selection.ui +0 -69
  25. tests/unit_tests/test_motor_control.py +0 -588
  26. {bec_widgets-0.80.1.dist-info → bec_widgets-0.81.1.dist-info}/WHEEL +0 -0
  27. {bec_widgets-0.80.1.dist-info → bec_widgets-0.81.1.dist-info}/entry_points.txt +0 -0
  28. {bec_widgets-0.80.1.dist-info → bec_widgets-0.81.1.dist-info}/licenses/LICENSE +0 -0
@@ -1,484 +0,0 @@
1
- # pylint: disable = no-name-in-module,missing-module-docstring
2
- import os
3
-
4
- from qtpy import uic
5
- from qtpy.QtCore import Qt
6
- from qtpy.QtCore import Signal as pyqtSignal
7
- from qtpy.QtCore import Slot as pyqtSlot
8
- from qtpy.QtGui import QDoubleValidator, QKeySequence
9
- from qtpy.QtWidgets import (
10
- QCheckBox,
11
- QLineEdit,
12
- QMessageBox,
13
- QPushButton,
14
- QShortcut,
15
- QTableWidget,
16
- QTableWidgetItem,
17
- )
18
-
19
- from bec_widgets.utils import UILoader
20
- from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
21
-
22
-
23
- class MotorCoordinateTable(MotorControlWidget):
24
- """
25
- Widget to save coordinates from motor, display them in the table and move back to them.
26
- There are two modes of operation:
27
- - Individual: Each row is a single coordinate.
28
- - Start/Stop: Each pair of rows is a start and end coordinate.
29
- Signals:
30
- plot_coordinates_signal (pyqtSignal(list, str, str)): Signal to plot the coordinates in the MotorMap.
31
- Slots:
32
- add_coordinate (pyqtSlot(tuple)): Slot to add a coordinate to the table.
33
- mode_switch (pyqtSlot): Slot to switch between individual and start/stop mode.
34
- """
35
-
36
- plot_coordinates_signal = pyqtSignal(list, str, str)
37
-
38
- def _load_ui(self):
39
- """Load the UI for the coordinate table."""
40
- current_path = os.path.dirname(__file__)
41
- self.ui = UILoader().load_ui(os.path.join(current_path, "motor_table.ui"), self)
42
-
43
- def _init_ui(self):
44
- """Initialize the UI"""
45
- # Setup table behaviour
46
- self._setup_table()
47
- self.ui.table.setSelectionBehavior(QTableWidget.SelectRows)
48
-
49
- # for tag columns default tag
50
- self.tag_counter = 1
51
-
52
- # Connect signals and slots
53
- self.ui.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
54
- self.ui.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
55
-
56
- # Keyboard shortcuts for deleting a row
57
- self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.ui.table)
58
- self.delete_shortcut.activated.connect(self.delete_selected_row)
59
- self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.ui.table)
60
- self.backspace_shortcut.activated.connect(self.delete_selected_row)
61
-
62
- # Warning message for mode switch enable/disable
63
- self.warning_message = True
64
-
65
- @pyqtSlot(dict)
66
- def on_config_update(self, config: dict) -> None:
67
- """
68
- Update config dict
69
- Args:
70
- config(dict): New config dict
71
- """
72
- self.config = config
73
-
74
- # Get motor names
75
- self.motor_x, self.motor_y = (
76
- self.config["motor_control"]["motor_x"],
77
- self.config["motor_control"]["motor_y"],
78
- )
79
-
80
- # Decimal precision of the table coordinates
81
- self.precision = self.config["motor_control"].get("precision", 3)
82
-
83
- # Mode switch default option
84
- self.mode = self.config["motor_control"].get("mode", "Individual")
85
-
86
- # Set combobox to default mode
87
- self.ui.comboBox_mode.setCurrentText(self.mode)
88
-
89
- self._init_ui()
90
-
91
- def _setup_table(self):
92
- """Setup the table with appropriate headers and configurations."""
93
- mode = self.ui.comboBox_mode.currentText()
94
-
95
- if mode == "Individual":
96
- self._setup_individual_mode()
97
- elif mode == "Start/Stop":
98
- self._setup_start_stop_mode()
99
- self.start_stop_counter = 0 # TODO: remove this??
100
-
101
- self.wipe_motor_map_coordinates()
102
-
103
- def _setup_individual_mode(self):
104
- """Setup the table for individual mode."""
105
- self.ui.table.setColumnCount(5)
106
- self.ui.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
107
- self.ui.table.verticalHeader().setVisible(False)
108
-
109
- def _setup_start_stop_mode(self):
110
- """Setup the table for start/stop mode."""
111
- self.ui.table.setColumnCount(8)
112
- self.ui.table.setHorizontalHeaderLabels(
113
- [
114
- "Show",
115
- "Move [start]",
116
- "Move [end]",
117
- "Tag",
118
- "X [start]",
119
- "Y [start]",
120
- "X [end]",
121
- "Y [end]",
122
- ]
123
- )
124
- self.ui.table.verticalHeader().setVisible(False)
125
- # Set flag to track if the coordinate is stat or the end of the entry
126
- self.is_next_entry_end = False
127
-
128
- def mode_switch(self):
129
- """Switch between individual and start/stop mode."""
130
- last_selected_index = self.ui.comboBox_mode.currentIndex()
131
-
132
- if self.ui.table.rowCount() > 0 and self.warning_message is True:
133
- msgBox = QMessageBox()
134
- msgBox.setIcon(QMessageBox.Critical)
135
- msgBox.setText(
136
- "Switching modes will delete all table entries. Do you want to continue?"
137
- )
138
- msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
139
- returnValue = msgBox.exec()
140
-
141
- if returnValue is QMessageBox.Cancel:
142
- self.ui.comboBox_mode.blockSignals(True) # Block signals
143
- self.ui.comboBox_mode.setCurrentIndex(last_selected_index)
144
- self.ui.comboBox_mode.blockSignals(False) # Unblock signals
145
- return
146
-
147
- # Wipe table
148
- self.wipe_motor_map_coordinates()
149
-
150
- # Initiate new table with new mode
151
- self._setup_table()
152
-
153
- @pyqtSlot(tuple)
154
- def add_coordinate(self, coordinates: tuple):
155
- """
156
- Add a coordinate to the table.
157
- Args:
158
- coordinates(tuple): Coordinates (x,y) to add to the table.
159
- """
160
- tag = f"Pos {self.tag_counter}"
161
- self.tag_counter += 1
162
- x, y = coordinates
163
- self._add_row(tag, x, y)
164
-
165
- def _add_row(self, tag: str, x: float, y: float) -> None:
166
- """
167
- Add a row to the table.
168
- Args:
169
- tag(str): Tag of the coordinate.
170
- x(float): X coordinate.
171
- y(float): Y coordinate.
172
- """
173
-
174
- mode = self.ui.comboBox_mode.currentText()
175
- if mode == "Individual":
176
- checkbox_pos = 0
177
- button_pos = 1
178
- tag_pos = 2
179
- x_pos = 3
180
- y_pos = 4
181
- coordinate_reference = "Individual"
182
- color = "green"
183
-
184
- # Add new row -> new entry
185
- row_count = self.ui.table.rowCount()
186
- self.ui.table.insertRow(row_count)
187
-
188
- # Add Widgets
189
- self._add_widgets(
190
- tag,
191
- x,
192
- y,
193
- row_count,
194
- checkbox_pos,
195
- tag_pos,
196
- button_pos,
197
- x_pos,
198
- y_pos,
199
- coordinate_reference,
200
- color,
201
- )
202
-
203
- if mode == "Start/Stop":
204
- # These positions are always fixed
205
- checkbox_pos = 0
206
- tag_pos = 3
207
-
208
- if self.is_next_entry_end is False: # It is the start position of the entry
209
- print("Start position")
210
- button_pos = 1
211
- x_pos = 4
212
- y_pos = 5
213
- coordinate_reference = "Start"
214
- color = "blue"
215
-
216
- # Add new row -> new entry
217
- row_count = self.ui.table.rowCount()
218
- self.ui.table.insertRow(row_count)
219
-
220
- # Add Widgets
221
- self._add_widgets(
222
- tag,
223
- x,
224
- y,
225
- row_count,
226
- checkbox_pos,
227
- tag_pos,
228
- button_pos,
229
- x_pos,
230
- y_pos,
231
- coordinate_reference,
232
- color,
233
- )
234
-
235
- # Next entry will be the end of the current entry
236
- self.is_next_entry_end = True
237
-
238
- elif self.is_next_entry_end is True: # It is the end position of the entry
239
- print("End position")
240
- row_count = self.ui.table.rowCount() - 1 # Current row
241
- button_pos = 2
242
- x_pos = 6
243
- y_pos = 7
244
- coordinate_reference = "Stop"
245
- color = "red"
246
-
247
- # Add Widgets
248
- self._add_widgets(
249
- tag,
250
- x,
251
- y,
252
- row_count,
253
- checkbox_pos,
254
- tag_pos,
255
- button_pos,
256
- x_pos,
257
- y_pos,
258
- coordinate_reference,
259
- color,
260
- )
261
- self.is_next_entry_end = False # Next entry will be the start of the new entry
262
-
263
- # Auto table resize
264
- self.resize_table_auto()
265
-
266
- def _add_widgets(
267
- self,
268
- tag: str,
269
- x: float,
270
- y: float,
271
- row: int,
272
- checkBox_pos: int,
273
- tag_pos: int,
274
- button_pos: int,
275
- x_pos: int,
276
- y_pos: int,
277
- coordinate_reference: str,
278
- color: str,
279
- ) -> None:
280
- """
281
- Add widgets to the table.
282
- Args:
283
- tag(str): Tag of the coordinate.
284
- x(float): X coordinate.
285
- y(float): Y coordinate.
286
- row(int): Row of the QTableWidget where to add the widgets.
287
- checkBox_pos(int): Column where to put CheckBox.
288
- tag_pos(int): Column where to put Tag.
289
- button_pos(int): Column where to put Move button.
290
- x_pos(int): Column where to link x coordinate.
291
- y_pos(int): Column where to link y coordinate.
292
- coordinate_reference(str): Reference to the coordinate for MotorMap.
293
- color(str): Color of the coordinate for MotorMap.
294
- """
295
- # Add widgets
296
- self._add_checkbox(row, checkBox_pos, x_pos, y_pos)
297
- self._add_move_button(row, button_pos, x_pos, y_pos)
298
- self.ui.table.setItem(row, tag_pos, QTableWidgetItem(tag))
299
- self._add_line_edit(x, row, x_pos, x_pos, y_pos, coordinate_reference, color)
300
- self._add_line_edit(y, row, y_pos, x_pos, y_pos, coordinate_reference, color)
301
-
302
- # # Emit the coordinates to be plotted
303
- self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
304
-
305
- # Connect item edit to emit coordinates
306
- self.ui.table.itemChanged.connect(
307
- lambda: print(f"item changed from {coordinate_reference} slot \n {x}-{y}-{color}")
308
- )
309
- self.ui.table.itemChanged.connect(
310
- lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
311
- )
312
-
313
- def _add_checkbox(self, row: int, checkBox_pos: int, x_pos: int, y_pos: int):
314
- """
315
- Add a checkbox to the table.
316
- Args:
317
- row(int): Row of QTableWidget where to add the checkbox.
318
- checkBox_pos(int): Column where to put CheckBox.
319
- x_pos(int): Column where to link x coordinate.
320
- y_pos(int): Column where to link y coordinate.
321
- """
322
- show_checkbox = QCheckBox()
323
- show_checkbox.setChecked(True)
324
- show_checkbox.stateChanged.connect(lambda: self.emit_plot_coordinates(x_pos, y_pos))
325
- self.ui.table.setCellWidget(row, checkBox_pos, show_checkbox)
326
-
327
- def _add_move_button(self, row: int, button_pos: int, x_pos: int, y_pos: int) -> None:
328
- """
329
- Add a move button to the table.
330
- Args:
331
- row(int): Row of QTableWidget where to add the move button.
332
- button_pos(int): Column where to put move button.
333
- x_pos(int): Column where to link x coordinate.
334
- y_pos(int): Column where to link y coordinate.
335
- """
336
- move_button = QPushButton("Move")
337
- move_button.clicked.connect(lambda: self.handle_move_button_click(x_pos, y_pos))
338
- self.ui.table.setCellWidget(row, button_pos, move_button)
339
-
340
- def _add_line_edit(
341
- self,
342
- value: float,
343
- row: int,
344
- line_pos: int,
345
- x_pos: int,
346
- y_pos: int,
347
- coordinate_reference: str,
348
- color: str,
349
- ) -> None:
350
- """
351
- Add a QLineEdit to the table.
352
- Args:
353
- value(float): Initial value of the QLineEdit.
354
- row(int): Row of QTableWidget where to add the QLineEdit.
355
- line_pos(int): Column where to put QLineEdit.
356
- x_pos(int): Column where to link x coordinate.
357
- y_pos(int): Column where to link y coordinate.
358
- coordinate_reference(str): Reference to the coordinate for MotorMap.
359
- color(str): Color of the coordinate for MotorMap.
360
- """
361
- # Adding validator
362
- validator = QDoubleValidator()
363
- validator.setDecimals(self.precision)
364
-
365
- # Create line edit
366
- edit = QLineEdit(str(f"{value:.{self.precision}f}"))
367
- edit.setValidator(validator)
368
- edit.setAlignment(Qt.AlignmentFlag.AlignCenter)
369
-
370
- # Add line edit to the table
371
- self.ui.table.setCellWidget(row, line_pos, edit)
372
- edit.textChanged.connect(
373
- lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
374
- )
375
-
376
- def wipe_motor_map_coordinates(self):
377
- """Wipe the motor map coordinates."""
378
- try:
379
- self.ui.table.itemChanged.disconnect() # Disconnect all previous connections
380
- except TypeError:
381
- print("No previous connections to disconnect")
382
- self.ui.table.setRowCount(0)
383
- reference_tags = ["Individual", "Start", "Stop"]
384
- for reference_tag in reference_tags:
385
- self.plot_coordinates_signal.emit([], reference_tag, "green")
386
-
387
- def handle_move_button_click(self, x_pos: int, y_pos: int) -> None:
388
- """
389
- Handle the move button click.
390
- Args:
391
- x_pos(int): X position of the coordinate.
392
- y_pos(int): Y position of the coordinate.
393
- """
394
- button = self.sender()
395
- row = self.ui.table.indexAt(button.pos()).row()
396
-
397
- x = self.get_coordinate(row, x_pos)
398
- y = self.get_coordinate(row, y_pos)
399
- self.move_motor(x, y)
400
-
401
- def emit_plot_coordinates(self, x_pos: float, y_pos: float, reference_tag: str, color: str):
402
- """
403
- Emit the coordinates to be plotted.
404
- Args:
405
- x_pos(float): X position of the coordinate.
406
- y_pos(float): Y position of the coordinate.
407
- reference_tag(str): Reference tag of the coordinate.
408
- color(str): Color of the coordinate.
409
- """
410
- print(
411
- f"Emitting plot coordinates: x_pos={x_pos}, y_pos={y_pos}, reference_tag={reference_tag}, color={color}"
412
- )
413
- coordinates = []
414
- for row in range(self.ui.table.rowCount()):
415
- show = self.ui.table.cellWidget(row, 0).isChecked()
416
- x = self.get_coordinate(row, x_pos)
417
- y = self.get_coordinate(row, y_pos)
418
-
419
- coordinates.append((x, y, show)) # (x, y, show_flag)
420
- self.plot_coordinates_signal.emit(coordinates, reference_tag, color)
421
-
422
- def get_coordinate(self, row: int, column: int) -> float:
423
- """
424
- Helper function to get the coordinate from the table QLineEdit cells.
425
- Args:
426
- row(int): Row of the table.
427
- column(int): Column of the table.
428
- Returns:
429
- float: Value of the coordinate.
430
- """
431
- edit = self.ui.table.cellWidget(row, column)
432
- value = float(edit.text()) if edit and edit.text() != "" else None
433
- if value:
434
- return value
435
-
436
- def delete_selected_row(self):
437
- """Delete the selected row from the table."""
438
- selected_rows = self.ui.table.selectionModel().selectedRows()
439
- for row in selected_rows:
440
- self.ui.table.removeRow(row.row())
441
- if self.ui.comboBox_mode.currentText() == "Start/Stop":
442
- self.emit_plot_coordinates(x_pos=4, y_pos=5, reference_tag="Start", color="blue")
443
- self.emit_plot_coordinates(x_pos=6, y_pos=7, reference_tag="Stop", color="red")
444
- self.is_next_entry_end = False
445
- elif self.ui.comboBox_mode.currentText() == "Individual":
446
- self.emit_plot_coordinates(x_pos=3, y_pos=4, reference_tag="Individual", color="green")
447
-
448
- def resize_table_auto(self):
449
- """Resize the table to fit the contents."""
450
- if self.ui.checkBox_resize_auto.isChecked():
451
- self.ui.table.resizeColumnsToContents()
452
-
453
- def move_motor(self, x: float, y: float) -> None:
454
- """
455
- Move the motor to the target coordinates.
456
- Args:
457
- x(float): Target x coordinate.
458
- y(float): Target y coordinate.
459
- """
460
- self.motor_thread.move_absolute(self.motor_x, self.motor_y, (x, y))
461
-
462
- @pyqtSlot(str, str)
463
- def change_motors(self, motor_x: str, motor_y: str) -> None:
464
- """
465
- Change the active motors and update config.
466
- Can be connected to the selected_motors_signal from MotorControlSelection.
467
- Args:
468
- motor_x(str): New motor X to be controlled.
469
- motor_y(str): New motor Y to be controlled.
470
- """
471
- self.motor_x = motor_x
472
- self.motor_y = motor_y
473
- self.config["motor_control"]["motor_x"] = motor_x
474
- self.config["motor_control"]["motor_y"] = motor_y
475
-
476
- @pyqtSlot(int)
477
- def set_precision(self, precision: int) -> None:
478
- """
479
- Set the precision of the coordinates.
480
- Args:
481
- precision(int): Precision of the coordinates.
482
- """
483
- self.precision = precision
484
- self.config["motor_control"]["precision"] = precision
@@ -1,113 +0,0 @@
1
- <?xml version="1.0" encoding="UTF-8"?>
2
- <ui version="4.0">
3
- <class>Form</class>
4
- <widget class="QWidget" name="Form">
5
- <property name="geometry">
6
- <rect>
7
- <x>0</x>
8
- <y>0</y>
9
- <width>676</width>
10
- <height>667</height>
11
- </rect>
12
- </property>
13
- <property name="windowTitle">
14
- <string>Motor Coordinates Table</string>
15
- </property>
16
- <layout class="QVBoxLayout" name="verticalLayout">
17
- <item>
18
- <layout class="QHBoxLayout" name="horizontalLayout_3">
19
- <item>
20
- <spacer name="horizontalSpacer_4">
21
- <property name="orientation">
22
- <enum>Qt::Horizontal</enum>
23
- </property>
24
- <property name="sizeHint" stdset="0">
25
- <size>
26
- <width>40</width>
27
- <height>20</height>
28
- </size>
29
- </property>
30
- </spacer>
31
- </item>
32
- <item>
33
- <widget class="QCheckBox" name="checkBox_resize_auto">
34
- <property name="text">
35
- <string>Resize Auto</string>
36
- </property>
37
- <property name="checked">
38
- <bool>true</bool>
39
- </property>
40
- </widget>
41
- </item>
42
- <item>
43
- <widget class="QPushButton" name="pushButton_editColumns">
44
- <property name="enabled">
45
- <bool>false</bool>
46
- </property>
47
- <property name="text">
48
- <string>Edit Custom Column</string>
49
- </property>
50
- </widget>
51
- </item>
52
- <item>
53
- <widget class="QLabel" name="label">
54
- <property name="text">
55
- <string>Entries Mode:</string>
56
- </property>
57
- </widget>
58
- </item>
59
- <item>
60
- <widget class="QComboBox" name="comboBox_mode">
61
- <property name="enabled">
62
- <bool>true</bool>
63
- </property>
64
- <item>
65
- <property name="text">
66
- <string>Individual</string>
67
- </property>
68
- </item>
69
- <item>
70
- <property name="text">
71
- <string>Start/Stop</string>
72
- </property>
73
- </item>
74
- </widget>
75
- </item>
76
- </layout>
77
- </item>
78
- <item>
79
- <widget class="QTableWidget" name="table">
80
- <property name="gridStyle">
81
- <enum>Qt::SolidLine</enum>
82
- </property>
83
- </widget>
84
- </item>
85
- <item>
86
- <layout class="QHBoxLayout" name="horizontalLayout">
87
- <item>
88
- <widget class="QPushButton" name="pushButton_importCSV">
89
- <property name="enabled">
90
- <bool>false</bool>
91
- </property>
92
- <property name="text">
93
- <string>Import CSV</string>
94
- </property>
95
- </widget>
96
- </item>
97
- <item>
98
- <widget class="QPushButton" name="pushButton_exportCSV">
99
- <property name="enabled">
100
- <bool>false</bool>
101
- </property>
102
- <property name="text">
103
- <string>Export CSV</string>
104
- </property>
105
- </widget>
106
- </item>
107
- </layout>
108
- </item>
109
- </layout>
110
- </widget>
111
- <resources/>
112
- <connections/>
113
- </ui>