bec-widgets 0.55.0__py3-none-any.whl → 0.56.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 (44) hide show
  1. .gitlab-ci.yml +113 -8
  2. CHANGELOG.md +34 -28
  3. PKG-INFO +3 -1
  4. bec_widgets/examples/jupyter_console/jupyter_console_window.py +28 -38
  5. bec_widgets/examples/motor_movement/motor_control_compilations.py +1 -7
  6. bec_widgets/utils/__init__.py +1 -0
  7. bec_widgets/utils/crosshair.py +13 -9
  8. bec_widgets/utils/ui_loader.py +58 -0
  9. bec_widgets/widgets/motor_control/motor_table/motor_table.py +44 -43
  10. bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +25 -23
  11. bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +51 -48
  12. bec_widgets/widgets/spiral_progress_bar/ring.py +5 -5
  13. {bec_widgets-0.55.0.dist-info → bec_widgets-0.56.1.dist-info}/METADATA +3 -1
  14. {bec_widgets-0.55.0.dist-info → bec_widgets-0.56.1.dist-info}/RECORD +22 -43
  15. docs/user/apps.md +1 -26
  16. pyproject.toml +2 -1
  17. tests/end-2-end/test_bec_dock_rpc_e2e.py +1 -1
  18. tests/unit_tests/test_client_utils.py +2 -2
  19. tests/unit_tests/test_crosshair.py +5 -5
  20. tests/unit_tests/test_motor_control.py +49 -45
  21. bec_widgets/examples/eiger_plot/__init__.py +0 -0
  22. bec_widgets/examples/eiger_plot/eiger_plot.py +0 -307
  23. bec_widgets/examples/eiger_plot/eiger_plot.ui +0 -207
  24. bec_widgets/examples/mca_readout/__init__.py +0 -0
  25. bec_widgets/examples/mca_readout/mca_plot.py +0 -159
  26. bec_widgets/examples/mca_readout/mca_sim.py +0 -28
  27. bec_widgets/examples/modular_app/___init__.py +0 -0
  28. bec_widgets/examples/modular_app/modular.ui +0 -92
  29. bec_widgets/examples/modular_app/modular_app.py +0 -197
  30. bec_widgets/examples/motor_movement/config_example.yaml +0 -17
  31. bec_widgets/examples/motor_movement/csax_bec_config.yaml +0 -10
  32. bec_widgets/examples/motor_movement/csaxs_config.yaml +0 -17
  33. bec_widgets/examples/motor_movement/motor_example.py +0 -1344
  34. bec_widgets/examples/stream_plot/__init__.py +0 -0
  35. bec_widgets/examples/stream_plot/line_plot.ui +0 -155
  36. bec_widgets/examples/stream_plot/stream_plot.py +0 -337
  37. docs/user/apps/modular_app.md +0 -6
  38. docs/user/apps/motor_app.md +0 -34
  39. docs/user/apps/motor_app_10fps.gif +0 -0
  40. docs/user/apps/plot_app.md +0 -6
  41. tests/unit_tests/test_eiger_plot.py +0 -115
  42. tests/unit_tests/test_stream_plot.py +0 -158
  43. {bec_widgets-0.55.0.dist-info → bec_widgets-0.56.1.dist-info}/WHEEL +0 -0
  44. {bec_widgets-0.55.0.dist-info → bec_widgets-0.56.1.dist-info}/licenses/LICENSE +0 -0
@@ -16,6 +16,7 @@ from qtpy.QtWidgets import (
16
16
  QTableWidgetItem,
17
17
  )
18
18
 
19
+ from bec_widgets.utils import UILoader
19
20
  from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
20
21
 
21
22
 
@@ -37,25 +38,25 @@ class MotorCoordinateTable(MotorControlWidget):
37
38
  def _load_ui(self):
38
39
  """Load the UI for the coordinate table."""
39
40
  current_path = os.path.dirname(__file__)
40
- uic.loadUi(os.path.join(current_path, "motor_table.ui"), self)
41
+ self.ui = UILoader().load_ui(os.path.join(current_path, "motor_table.ui"), self)
41
42
 
42
43
  def _init_ui(self):
43
44
  """Initialize the UI"""
44
45
  # Setup table behaviour
45
46
  self._setup_table()
46
- self.table.setSelectionBehavior(QTableWidget.SelectRows)
47
+ self.ui.table.setSelectionBehavior(QTableWidget.SelectRows)
47
48
 
48
49
  # for tag columns default tag
49
50
  self.tag_counter = 1
50
51
 
51
52
  # Connect signals and slots
52
- self.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
53
- self.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
53
+ self.ui.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
54
+ self.ui.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
54
55
 
55
56
  # Keyboard shortcuts for deleting a row
56
- self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.table)
57
+ self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.ui.table)
57
58
  self.delete_shortcut.activated.connect(self.delete_selected_row)
58
- self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.table)
59
+ self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.ui.table)
59
60
  self.backspace_shortcut.activated.connect(self.delete_selected_row)
60
61
 
61
62
  # Warning message for mode switch enable/disable
@@ -83,13 +84,13 @@ class MotorCoordinateTable(MotorControlWidget):
83
84
  self.mode = self.config["motor_control"].get("mode", "Individual")
84
85
 
85
86
  # Set combobox to default mode
86
- self.comboBox_mode.setCurrentText(self.mode)
87
+ self.ui.comboBox_mode.setCurrentText(self.mode)
87
88
 
88
89
  self._init_ui()
89
90
 
90
91
  def _setup_table(self):
91
92
  """Setup the table with appropriate headers and configurations."""
92
- mode = self.comboBox_mode.currentText()
93
+ mode = self.ui.comboBox_mode.currentText()
93
94
 
94
95
  if mode == "Individual":
95
96
  self._setup_individual_mode()
@@ -101,14 +102,14 @@ class MotorCoordinateTable(MotorControlWidget):
101
102
 
102
103
  def _setup_individual_mode(self):
103
104
  """Setup the table for individual mode."""
104
- self.table.setColumnCount(5)
105
- self.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
106
- self.table.verticalHeader().setVisible(False)
105
+ self.ui.table.setColumnCount(5)
106
+ self.ui.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
107
+ self.ui.table.verticalHeader().setVisible(False)
107
108
 
108
109
  def _setup_start_stop_mode(self):
109
110
  """Setup the table for start/stop mode."""
110
- self.table.setColumnCount(8)
111
- self.table.setHorizontalHeaderLabels(
111
+ self.ui.table.setColumnCount(8)
112
+ self.ui.table.setHorizontalHeaderLabels(
112
113
  [
113
114
  "Show",
114
115
  "Move [start]",
@@ -120,15 +121,15 @@ class MotorCoordinateTable(MotorControlWidget):
120
121
  "Y [end]",
121
122
  ]
122
123
  )
123
- self.table.verticalHeader().setVisible(False)
124
+ self.ui.table.verticalHeader().setVisible(False)
124
125
  # Set flag to track if the coordinate is stat or the end of the entry
125
126
  self.is_next_entry_end = False
126
127
 
127
128
  def mode_switch(self):
128
129
  """Switch between individual and start/stop mode."""
129
- last_selected_index = self.comboBox_mode.currentIndex()
130
+ last_selected_index = self.ui.comboBox_mode.currentIndex()
130
131
 
131
- if self.table.rowCount() > 0 and self.warning_message is True:
132
+ if self.ui.table.rowCount() > 0 and self.warning_message is True:
132
133
  msgBox = QMessageBox()
133
134
  msgBox.setIcon(QMessageBox.Critical)
134
135
  msgBox.setText(
@@ -138,9 +139,9 @@ class MotorCoordinateTable(MotorControlWidget):
138
139
  returnValue = msgBox.exec()
139
140
 
140
141
  if returnValue is QMessageBox.Cancel:
141
- self.comboBox_mode.blockSignals(True) # Block signals
142
- self.comboBox_mode.setCurrentIndex(last_selected_index)
143
- self.comboBox_mode.blockSignals(False) # Unblock signals
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
144
145
  return
145
146
 
146
147
  # Wipe table
@@ -170,7 +171,7 @@ class MotorCoordinateTable(MotorControlWidget):
170
171
  y(float): Y coordinate.
171
172
  """
172
173
 
173
- mode = self.comboBox_mode.currentText()
174
+ mode = self.ui.comboBox_mode.currentText()
174
175
  if mode == "Individual":
175
176
  checkbox_pos = 0
176
177
  button_pos = 1
@@ -181,8 +182,8 @@ class MotorCoordinateTable(MotorControlWidget):
181
182
  color = "green"
182
183
 
183
184
  # Add new row -> new entry
184
- row_count = self.table.rowCount()
185
- self.table.insertRow(row_count)
185
+ row_count = self.ui.table.rowCount()
186
+ self.ui.table.insertRow(row_count)
186
187
 
187
188
  # Add Widgets
188
189
  self._add_widgets(
@@ -213,8 +214,8 @@ class MotorCoordinateTable(MotorControlWidget):
213
214
  color = "blue"
214
215
 
215
216
  # Add new row -> new entry
216
- row_count = self.table.rowCount()
217
- self.table.insertRow(row_count)
217
+ row_count = self.ui.table.rowCount()
218
+ self.ui.table.insertRow(row_count)
218
219
 
219
220
  # Add Widgets
220
221
  self._add_widgets(
@@ -236,7 +237,7 @@ class MotorCoordinateTable(MotorControlWidget):
236
237
 
237
238
  elif self.is_next_entry_end is True: # It is the end position of the entry
238
239
  print("End position")
239
- row_count = self.table.rowCount() - 1 # Current row
240
+ row_count = self.ui.table.rowCount() - 1 # Current row
240
241
  button_pos = 2
241
242
  x_pos = 6
242
243
  y_pos = 7
@@ -294,7 +295,7 @@ class MotorCoordinateTable(MotorControlWidget):
294
295
  # Add widgets
295
296
  self._add_checkbox(row, checkBox_pos, x_pos, y_pos)
296
297
  self._add_move_button(row, button_pos, x_pos, y_pos)
297
- self.table.setItem(row, tag_pos, QTableWidgetItem(tag))
298
+ self.ui.table.setItem(row, tag_pos, QTableWidgetItem(tag))
298
299
  self._add_line_edit(x, row, x_pos, x_pos, y_pos, coordinate_reference, color)
299
300
  self._add_line_edit(y, row, y_pos, x_pos, y_pos, coordinate_reference, color)
300
301
 
@@ -302,10 +303,10 @@ class MotorCoordinateTable(MotorControlWidget):
302
303
  self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
303
304
 
304
305
  # Connect item edit to emit coordinates
305
- self.table.itemChanged.connect(
306
+ self.ui.table.itemChanged.connect(
306
307
  lambda: print(f"item changed from {coordinate_reference} slot \n {x}-{y}-{color}")
307
308
  )
308
- self.table.itemChanged.connect(
309
+ self.ui.table.itemChanged.connect(
309
310
  lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
310
311
  )
311
312
 
@@ -321,7 +322,7 @@ class MotorCoordinateTable(MotorControlWidget):
321
322
  show_checkbox = QCheckBox()
322
323
  show_checkbox.setChecked(True)
323
324
  show_checkbox.stateChanged.connect(lambda: self.emit_plot_coordinates(x_pos, y_pos))
324
- self.table.setCellWidget(row, checkBox_pos, show_checkbox)
325
+ self.ui.table.setCellWidget(row, checkBox_pos, show_checkbox)
325
326
 
326
327
  def _add_move_button(self, row: int, button_pos: int, x_pos: int, y_pos: int) -> None:
327
328
  """
@@ -334,7 +335,7 @@ class MotorCoordinateTable(MotorControlWidget):
334
335
  """
335
336
  move_button = QPushButton("Move")
336
337
  move_button.clicked.connect(lambda: self.handle_move_button_click(x_pos, y_pos))
337
- self.table.setCellWidget(row, button_pos, move_button)
338
+ self.ui.table.setCellWidget(row, button_pos, move_button)
338
339
 
339
340
  def _add_line_edit(
340
341
  self,
@@ -367,7 +368,7 @@ class MotorCoordinateTable(MotorControlWidget):
367
368
  edit.setAlignment(Qt.AlignmentFlag.AlignCenter)
368
369
 
369
370
  # Add line edit to the table
370
- self.table.setCellWidget(row, line_pos, edit)
371
+ self.ui.table.setCellWidget(row, line_pos, edit)
371
372
  edit.textChanged.connect(
372
373
  lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
373
374
  )
@@ -375,10 +376,10 @@ class MotorCoordinateTable(MotorControlWidget):
375
376
  def wipe_motor_map_coordinates(self):
376
377
  """Wipe the motor map coordinates."""
377
378
  try:
378
- self.table.itemChanged.disconnect() # Disconnect all previous connections
379
+ self.ui.table.itemChanged.disconnect() # Disconnect all previous connections
379
380
  except TypeError:
380
381
  print("No previous connections to disconnect")
381
- self.table.setRowCount(0)
382
+ self.ui.table.setRowCount(0)
382
383
  reference_tags = ["Individual", "Start", "Stop"]
383
384
  for reference_tag in reference_tags:
384
385
  self.plot_coordinates_signal.emit([], reference_tag, "green")
@@ -391,7 +392,7 @@ class MotorCoordinateTable(MotorControlWidget):
391
392
  y_pos(int): Y position of the coordinate.
392
393
  """
393
394
  button = self.sender()
394
- row = self.table.indexAt(button.pos()).row()
395
+ row = self.ui.table.indexAt(button.pos()).row()
395
396
 
396
397
  x = self.get_coordinate(row, x_pos)
397
398
  y = self.get_coordinate(row, y_pos)
@@ -410,8 +411,8 @@ class MotorCoordinateTable(MotorControlWidget):
410
411
  f"Emitting plot coordinates: x_pos={x_pos}, y_pos={y_pos}, reference_tag={reference_tag}, color={color}"
411
412
  )
412
413
  coordinates = []
413
- for row in range(self.table.rowCount()):
414
- show = self.table.cellWidget(row, 0).isChecked()
414
+ for row in range(self.ui.table.rowCount()):
415
+ show = self.ui.table.cellWidget(row, 0).isChecked()
415
416
  x = self.get_coordinate(row, x_pos)
416
417
  y = self.get_coordinate(row, y_pos)
417
418
 
@@ -427,27 +428,27 @@ class MotorCoordinateTable(MotorControlWidget):
427
428
  Returns:
428
429
  float: Value of the coordinate.
429
430
  """
430
- edit = self.table.cellWidget(row, column)
431
+ edit = self.ui.table.cellWidget(row, column)
431
432
  value = float(edit.text()) if edit and edit.text() != "" else None
432
433
  if value:
433
434
  return value
434
435
 
435
436
  def delete_selected_row(self):
436
437
  """Delete the selected row from the table."""
437
- selected_rows = self.table.selectionModel().selectedRows()
438
+ selected_rows = self.ui.table.selectionModel().selectedRows()
438
439
  for row in selected_rows:
439
- self.table.removeRow(row.row())
440
- if self.comboBox_mode.currentText() == "Start/Stop":
440
+ self.ui.table.removeRow(row.row())
441
+ if self.ui.comboBox_mode.currentText() == "Start/Stop":
441
442
  self.emit_plot_coordinates(x_pos=4, y_pos=5, reference_tag="Start", color="blue")
442
443
  self.emit_plot_coordinates(x_pos=6, y_pos=7, reference_tag="Stop", color="red")
443
444
  self.is_next_entry_end = False
444
- elif self.comboBox_mode.currentText() == "Individual":
445
+ elif self.ui.comboBox_mode.currentText() == "Individual":
445
446
  self.emit_plot_coordinates(x_pos=3, y_pos=4, reference_tag="Individual", color="green")
446
447
 
447
448
  def resize_table_auto(self):
448
449
  """Resize the table to fit the contents."""
449
- if self.checkBox_resize_auto.isChecked():
450
- self.table.resizeColumnsToContents()
450
+ if self.ui.checkBox_resize_auto.isChecked():
451
+ self.ui.table.resizeColumnsToContents()
451
452
 
452
453
  def move_motor(self, x: float, y: float) -> None:
453
454
  """
@@ -3,8 +3,10 @@ import os
3
3
  from qtpy import uic
4
4
  from qtpy.QtCore import Signal as pyqtSignal
5
5
  from qtpy.QtCore import Slot as pyqtSlot
6
+ from qtpy.QtWidgets import QWidget
6
7
 
7
- from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
8
+ from bec_widgets.utils import UILoader
9
+ from bec_widgets.widgets.motor_control.motor_control import MotorControlErrors, MotorControlWidget
8
10
 
9
11
 
10
12
  class MotorControlAbsolute(MotorControlWidget):
@@ -23,26 +25,26 @@ class MotorControlAbsolute(MotorControlWidget):
23
25
  def _load_ui(self):
24
26
  """Load the UI from the .ui file."""
25
27
  current_path = os.path.dirname(__file__)
26
- uic.loadUi(os.path.join(current_path, "movement_absolute.ui"), self)
28
+ self.ui = UILoader().load_ui(os.path.join(current_path, "movement_absolute.ui"), self)
27
29
 
28
30
  def _init_ui(self):
29
31
  """Initialize the UI."""
30
32
 
31
33
  # Check if there are any motors connected
32
34
  if self.motor_x is None or self.motor_y is None:
33
- self.motorControl_absolute.setEnabled(False)
35
+ self.ui.motorControl_absolute.setEnabled(False)
34
36
  return
35
37
 
36
38
  # Move to absolute coordinates
37
- self.pushButton_go_absolute.clicked.connect(
39
+ self.ui.pushButton_go_absolute.clicked.connect(
38
40
  lambda: self.move_motor_absolute(
39
- self.spinBox_absolute_x.value(), self.spinBox_absolute_y.value()
41
+ self.ui.spinBox_absolute_x.value(), self.ui.spinBox_absolute_y.value()
40
42
  )
41
43
  )
42
44
 
43
- self.pushButton_set.clicked.connect(self.save_absolute_coordinates)
44
- self.pushButton_save.clicked.connect(self.save_current_coordinates)
45
- self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
45
+ self.ui.pushButton_set.clicked.connect(self.save_absolute_coordinates)
46
+ self.ui.pushButton_save.clicked.connect(self.save_current_coordinates)
47
+ self.ui.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
46
48
 
47
49
  # Enable/Disable GUI
48
50
  self.motor_thread.lock_gui.connect(self.enable_motor_controls)
@@ -80,11 +82,11 @@ class MotorControlAbsolute(MotorControlWidget):
80
82
  """
81
83
 
82
84
  # Disable or enable all controls within the motorControl_absolute group box
83
- for widget in self.motorControl_absolute.findChildren(QWidget):
85
+ for widget in self.ui.motorControl_absolute.findChildren(QWidget):
84
86
  widget.setEnabled(enable)
85
87
 
86
88
  # Enable the pushButton_stop if the motor is moving
87
- self.pushButton_stop.setEnabled(True)
89
+ self.ui.pushButton_stop.setEnabled(True)
88
90
 
89
91
  @pyqtSlot(str, str)
90
92
  def change_motors(self, motor_x: str, motor_y: str):
@@ -109,8 +111,8 @@ class MotorControlAbsolute(MotorControlWidget):
109
111
  """
110
112
  self.precision = precision
111
113
  self.config["motor_control"]["precision"] = precision
112
- self.spinBox_absolute_x.setDecimals(precision)
113
- self.spinBox_absolute_y.setDecimals(precision)
114
+ self.ui.spinBox_absolute_x.setDecimals(precision)
115
+ self.ui.spinBox_absolute_y.setDecimals(precision)
114
116
 
115
117
  def move_motor_absolute(self, x: float, y: float) -> None:
116
118
  """
@@ -122,32 +124,32 @@ class MotorControlAbsolute(MotorControlWidget):
122
124
  # self._enable_motor_controls(False)
123
125
  target_coordinates = (x, y)
124
126
  self.motor_thread.move_absolute(self.motor_x, self.motor_y, target_coordinates)
125
- if self.checkBox_save_with_go.isChecked():
127
+ if self.ui.checkBox_save_with_go.isChecked():
126
128
  self.save_absolute_coordinates()
127
129
 
128
130
  def _init_keyboard_shortcuts(self):
129
131
  """Initialize the keyboard shortcuts."""
130
132
  # Go absolute button
131
- self.pushButton_go_absolute.setShortcut("Ctrl+G")
132
- self.pushButton_go_absolute.setToolTip("Ctrl+G")
133
+ self.ui.pushButton_go_absolute.setShortcut("Ctrl+G")
134
+ self.ui.pushButton_go_absolute.setToolTip("Ctrl+G")
133
135
 
134
136
  # Set absolute coordinates
135
- self.pushButton_set.setShortcut("Ctrl+D")
136
- self.pushButton_set.setToolTip("Ctrl+D")
137
+ self.ui.pushButton_set.setShortcut("Ctrl+D")
138
+ self.ui.pushButton_set.setToolTip("Ctrl+D")
137
139
 
138
140
  # Save Current coordinates
139
- self.pushButton_save.setShortcut("Ctrl+S")
140
- self.pushButton_save.setToolTip("Ctrl+S")
141
+ self.ui.pushButton_save.setShortcut("Ctrl+S")
142
+ self.ui.pushButton_save.setToolTip("Ctrl+S")
141
143
 
142
144
  # Stop Button
143
- self.pushButton_stop.setShortcut("Ctrl+X")
144
- self.pushButton_stop.setToolTip("Ctrl+X")
145
+ self.ui.pushButton_stop.setShortcut("Ctrl+X")
146
+ self.ui.pushButton_stop.setToolTip("Ctrl+X")
145
147
 
146
148
  def save_absolute_coordinates(self):
147
149
  """Emit the setup coordinates from the spinboxes"""
148
150
 
149
- x, y = round(self.spinBox_absolute_x.value(), self.precision), round(
150
- self.spinBox_absolute_y.value(), self.precision
151
+ x, y = round(self.ui.spinBox_absolute_x.value(), self.precision), round(
152
+ self.ui.spinBox_absolute_y.value(), self.precision
151
153
  )
152
154
  self.coordinates_signal.emit((x, y))
153
155
 
@@ -7,6 +7,7 @@ from qtpy.QtCore import Slot as pyqtSlot
7
7
  from qtpy.QtGui import QKeySequence
8
8
  from qtpy.QtWidgets import QDoubleSpinBox, QShortcut, QWidget
9
9
 
10
+ from bec_widgets.utils import UILoader
10
11
  from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
11
12
 
12
13
 
@@ -27,7 +28,7 @@ class MotorControlRelative(MotorControlWidget):
27
28
  """Load the UI from the .ui file."""
28
29
  # Loading UI
29
30
  current_path = os.path.dirname(__file__)
30
- uic.loadUi(os.path.join(current_path, "movement_relative.ui"), self)
31
+ self.ui = UILoader().load_ui(os.path.join(current_path, "movement_relative.ui"), self)
31
32
 
32
33
  def _init_ui(self):
33
34
  """Initialize the UI."""
@@ -51,15 +52,15 @@ class MotorControlRelative(MotorControlWidget):
51
52
 
52
53
  # Update step precision
53
54
  self.precision = self.config["motor_control"]["precision"]
54
- self.spinBox_precision.setValue(self.precision)
55
+ self.ui.spinBox_precision.setValue(self.precision)
55
56
 
56
57
  # Update step sizes
57
- self.spinBox_step_x.setValue(self.config["motor_control"]["step_size_x"])
58
- self.spinBox_step_y.setValue(self.config["motor_control"]["step_size_y"])
58
+ self.ui.spinBox_step_x.setValue(self.config["motor_control"]["step_size_x"])
59
+ self.ui.spinBox_step_y.setValue(self.config["motor_control"]["step_size_y"])
59
60
 
60
61
  # Checkboxes for keyboard shortcuts and x/y step size link
61
- self.checkBox_same_xy.setChecked(self.config["motor_control"]["step_x_y_same"])
62
- self.checkBox_enableArrows.setChecked(self.config["motor_control"]["move_with_arrows"])
62
+ self.ui.checkBox_same_xy.setChecked(self.config["motor_control"]["step_x_y_same"])
63
+ self.ui.checkBox_enableArrows.setChecked(self.config["motor_control"]["move_with_arrows"])
63
64
 
64
65
  self._init_ui()
65
66
 
@@ -67,30 +68,32 @@ class MotorControlRelative(MotorControlWidget):
67
68
  """Initialize the motor control elements"""
68
69
 
69
70
  # Connect checkbox and spinBoxes
70
- self.checkBox_same_xy.stateChanged.connect(self._sync_step_sizes)
71
- self.spinBox_step_x.valueChanged.connect(self._update_step_size_x)
72
- self.spinBox_step_y.valueChanged.connect(self._update_step_size_y)
71
+ self.ui.checkBox_same_xy.stateChanged.connect(self._sync_step_sizes)
72
+ self.ui.spinBox_step_x.valueChanged.connect(self._update_step_size_x)
73
+ self.ui.spinBox_step_y.valueChanged.connect(self._update_step_size_y)
73
74
 
74
- self.toolButton_right.clicked.connect(
75
+ self.ui.toolButton_right.clicked.connect(
75
76
  lambda: self.move_motor_relative(self.motor_x, "x", 1)
76
77
  )
77
- self.toolButton_left.clicked.connect(
78
+ self.ui.toolButton_left.clicked.connect(
78
79
  lambda: self.move_motor_relative(self.motor_x, "x", -1)
79
80
  )
80
- self.toolButton_up.clicked.connect(lambda: self.move_motor_relative(self.motor_y, "y", 1))
81
- self.toolButton_down.clicked.connect(
81
+ self.ui.toolButton_up.clicked.connect(
82
+ lambda: self.move_motor_relative(self.motor_y, "y", 1)
83
+ )
84
+ self.ui.toolButton_down.clicked.connect(
82
85
  lambda: self.move_motor_relative(self.motor_y, "y", -1)
83
86
  )
84
87
 
85
88
  # Switch between key shortcuts active
86
- self.checkBox_enableArrows.stateChanged.connect(self._update_arrow_key_shortcuts)
89
+ self.ui.checkBox_enableArrows.stateChanged.connect(self._update_arrow_key_shortcuts)
87
90
  self._update_arrow_key_shortcuts()
88
91
 
89
92
  # Enable/Disable GUI
90
93
  self.motor_thread.lock_gui.connect(self.enable_motor_controls)
91
94
 
92
95
  # Precision update
93
- self.spinBox_precision.valueChanged.connect(lambda x: self._update_precision(x))
96
+ self.ui.spinBox_precision.valueChanged.connect(lambda x: self._update_precision(x))
94
97
 
95
98
  # Error messages
96
99
  self.motor_thread.motor_error.connect(
@@ -98,7 +101,7 @@ class MotorControlRelative(MotorControlWidget):
98
101
  )
99
102
 
100
103
  # Stop Button
101
- self.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
104
+ self.ui.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
102
105
 
103
106
  def _init_keyboard_shortcuts(self) -> None:
104
107
  """Initialize the keyboard shortcuts"""
@@ -107,42 +110,42 @@ class MotorControlRelative(MotorControlWidget):
107
110
  increase_x_shortcut = QShortcut(QKeySequence("Ctrl+A"), self)
108
111
  decrease_x_shortcut = QShortcut(QKeySequence("Ctrl+Z"), self)
109
112
  increase_x_shortcut.activated.connect(
110
- lambda: self._change_step_size(self.spinBox_step_x, 2)
113
+ lambda: self._change_step_size(self.ui.spinBox_step_x, 2)
111
114
  )
112
115
  decrease_x_shortcut.activated.connect(
113
- lambda: self._change_step_size(self.spinBox_step_x, 0.5)
116
+ lambda: self._change_step_size(self.ui.spinBox_step_x, 0.5)
114
117
  )
115
- self.spinBox_step_x.setToolTip("Increase step size: Ctrl+A\nDecrease step size: Ctrl+Z")
118
+ self.ui.spinBox_step_x.setToolTip("Increase step size: Ctrl+A\nDecrease step size: Ctrl+Z")
116
119
 
117
120
  # Increase/decrease step size for Y motor
118
121
  increase_y_shortcut = QShortcut(QKeySequence("Alt+A"), self)
119
122
  decrease_y_shortcut = QShortcut(QKeySequence("Alt+Z"), self)
120
123
  increase_y_shortcut.activated.connect(
121
- lambda: self._change_step_size(self.spinBox_step_y, 2)
124
+ lambda: self._change_step_size(self.ui.spinBox_step_y, 2)
122
125
  )
123
126
  decrease_y_shortcut.activated.connect(
124
- lambda: self._change_step_size(self.spinBox_step_y, 0.5)
127
+ lambda: self._change_step_size(self.ui.spinBox_step_y, 0.5)
125
128
  )
126
- self.spinBox_step_y.setToolTip("Increase step size: Alt+A\nDecrease step size: Alt+Z")
129
+ self.ui.spinBox_step_y.setToolTip("Increase step size: Alt+A\nDecrease step size: Alt+Z")
127
130
 
128
131
  # Stop Button
129
- self.pushButton_stop.setShortcut("Ctrl+X")
130
- self.pushButton_stop.setToolTip("Ctrl+X")
132
+ self.ui.pushButton_stop.setShortcut("Ctrl+X")
133
+ self.ui.pushButton_stop.setToolTip("Ctrl+X")
131
134
 
132
135
  def _update_arrow_key_shortcuts(self) -> None:
133
136
  """Update the arrow key shortcuts based on the checkbox state."""
134
- if self.checkBox_enableArrows.isChecked():
137
+ if self.ui.checkBox_enableArrows.isChecked():
135
138
  # Set the arrow key shortcuts for motor movement
136
- self.toolButton_right.setShortcut(Qt.Key_Right)
137
- self.toolButton_left.setShortcut(Qt.Key_Left)
138
- self.toolButton_up.setShortcut(Qt.Key_Up)
139
- self.toolButton_down.setShortcut(Qt.Key_Down)
139
+ self.ui.toolButton_right.setShortcut(Qt.Key_Right)
140
+ self.ui.toolButton_left.setShortcut(Qt.Key_Left)
141
+ self.ui.toolButton_up.setShortcut(Qt.Key_Up)
142
+ self.ui.toolButton_down.setShortcut(Qt.Key_Down)
140
143
  else:
141
144
  # Clear the shortcuts
142
- self.toolButton_right.setShortcut("")
143
- self.toolButton_left.setShortcut("")
144
- self.toolButton_up.setShortcut("")
145
- self.toolButton_down.setShortcut("")
145
+ self.ui.toolButton_right.setShortcut("")
146
+ self.ui.toolButton_left.setShortcut("")
147
+ self.ui.toolButton_up.setShortcut("")
148
+ self.ui.toolButton_down.setShortcut("")
146
149
 
147
150
  def _update_precision(self, precision: int) -> None:
148
151
  """
@@ -150,8 +153,8 @@ class MotorControlRelative(MotorControlWidget):
150
153
  Args:
151
154
  precision(int): Precision of the coordinates.
152
155
  """
153
- self.spinBox_step_x.setDecimals(precision)
154
- self.spinBox_step_y.setDecimals(precision)
156
+ self.ui.spinBox_step_x.setDecimals(precision)
157
+ self.ui.spinBox_step_y.setDecimals(precision)
155
158
  self.precision_signal.emit(precision)
156
159
 
157
160
  def _change_step_size(self, spinBox: QDoubleSpinBox, factor: float) -> None:
@@ -167,21 +170,21 @@ class MotorControlRelative(MotorControlWidget):
167
170
 
168
171
  def _sync_step_sizes(self):
169
172
  """Sync step sizes based on checkbox state."""
170
- if self.checkBox_same_xy.isChecked():
171
- value = self.spinBox_step_x.value()
172
- self.spinBox_step_y.setValue(value)
173
+ if self.ui.checkBox_same_xy.isChecked():
174
+ value = self.ui.spinBox_step_x.value()
175
+ self.ui.spinBox_step_y.setValue(value)
173
176
 
174
177
  def _update_step_size_x(self):
175
178
  """Update step size for x if checkbox is checked."""
176
- if self.checkBox_same_xy.isChecked():
177
- value = self.spinBox_step_x.value()
178
- self.spinBox_step_y.setValue(value)
179
+ if self.ui.checkBox_same_xy.isChecked():
180
+ value = self.ui.spinBox_step_x.value()
181
+ self.ui.spinBox_step_y.setValue(value)
179
182
 
180
183
  def _update_step_size_y(self):
181
184
  """Update step size for y if checkbox is checked."""
182
- if self.checkBox_same_xy.isChecked():
183
- value = self.spinBox_step_y.value()
184
- self.spinBox_step_x.setValue(value)
185
+ if self.ui.checkBox_same_xy.isChecked():
186
+ value = self.ui.spinBox_step_y.value()
187
+ self.ui.spinBox_step_x.setValue(value)
185
188
 
186
189
  @pyqtSlot(str, str)
187
190
  def change_motors(self, motor_x: str, motor_y: str):
@@ -206,11 +209,11 @@ class MotorControlRelative(MotorControlWidget):
206
209
  """
207
210
 
208
211
  # Disable or enable all controls within the motorControl_absolute group box
209
- for widget in self.motorControl.findChildren(QWidget):
212
+ for widget in self.ui.motorControl.findChildren(QWidget):
210
213
  widget.setEnabled(disable)
211
214
 
212
215
  # Enable the pushButton_stop if the motor is moving
213
- self.pushButton_stop.setEnabled(True)
216
+ self.ui.pushButton_stop.setEnabled(True)
214
217
 
215
218
  def move_motor_relative(self, motor, axis: str, direction: int) -> None:
216
219
  """
@@ -221,7 +224,7 @@ class MotorControlRelative(MotorControlWidget):
221
224
  direction(int): Direction to move. 1 for positive, -1 for negative.
222
225
  """
223
226
  if axis == "x":
224
- step = direction * self.spinBox_step_x.value()
227
+ step = direction * self.ui.spinBox_step_x.value()
225
228
  elif axis == "y":
226
- step = direction * self.spinBox_step_y.value()
229
+ step = direction * self.ui.spinBox_step_y.value()
227
230
  self.motor_thread.move_relative(motor, step)
@@ -17,16 +17,16 @@ class RingConnections(BaseModel):
17
17
  @field_validator("endpoint")
18
18
  def validate_endpoint(cls, v, values):
19
19
  slot = values.data["slot"]
20
- endpoint = v.endpoint if isinstance(v, EndpointInfo) else v
20
+ v = v.endpoint if isinstance(v, EndpointInfo) else v
21
21
  if slot == "on_scan_progress":
22
- if endpoint != "scans/scan_progress":
22
+ if v != "scans/scan_progress":
23
23
  raise PydanticCustomError(
24
24
  "unsupported endpoint",
25
25
  "For slot 'on_scan_progress', endpoint must be MessageEndpoint.scan_progress or 'scans/scan_progress'.",
26
26
  {"wrong_value": v},
27
27
  )
28
28
  elif slot == "on_device_readback":
29
- if not endpoint.startswith("internal/devices/readback/"):
29
+ if not v.startswith("internal/devices/readback/"):
30
30
  raise PydanticCustomError(
31
31
  "unsupported endpoint",
32
32
  "For slot 'on_device_readback', endpoint must be MessageEndpoint.device_readback(device) or 'internal/devices/readback/{device}'.",
@@ -54,8 +54,8 @@ class RingConfig(ConnectionConfig):
54
54
  description="Start position for the progress bars in degrees. Default is 90 degrees - corespons to "
55
55
  "the top of the ring.",
56
56
  )
57
- min_value: int | None = Field(0, description="Minimum value for the progress bars.")
58
- max_value: int | None = Field(100, description="Maximum value for the progress bars.")
57
+ min_value: int | float | None = Field(0, description="Minimum value for the progress bars.")
58
+ max_value: int | float | None = Field(100, description="Maximum value for the progress bars.")
59
59
  precision: int | None = Field(3, description="Precision for the progress bars.")
60
60
  update_behaviour: Literal["manual", "auto"] | None = Field(
61
61
  "auto", description="Update behaviour for the progress bars."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: bec_widgets
3
- Version: 0.55.0
3
+ Version: 0.56.1
4
4
  Summary: BEC Widgets
5
5
  Project-URL: Bug Tracker, https://gitlab.psi.ch/bec/bec_widgets/issues
6
6
  Project-URL: Homepage, https://gitlab.psi.ch/bec/bec_widgets
@@ -31,3 +31,5 @@ Provides-Extra: pyqt5
31
31
  Requires-Dist: pyqt5>=5.9; extra == 'pyqt5'
32
32
  Provides-Extra: pyqt6
33
33
  Requires-Dist: pyqt6>=6.7; extra == 'pyqt6'
34
+ Provides-Extra: pyside6
35
+ Requires-Dist: pyside6>=6.7; extra == 'pyside6'