bec-widgets 0.54.0__py3-none-any.whl → 0.56.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.
Files changed (51) hide show
  1. .gitlab-ci.yml +113 -8
  2. CHANGELOG.md +32 -21
  3. PKG-INFO +3 -1
  4. bec_widgets/cli/client.py +252 -0
  5. bec_widgets/cli/generate_cli.py +4 -1
  6. bec_widgets/cli/rpc_wigdet_handler.py +2 -1
  7. bec_widgets/examples/jupyter_console/jupyter_console_window.py +29 -37
  8. bec_widgets/examples/motor_movement/motor_control_compilations.py +1 -7
  9. bec_widgets/utils/__init__.py +1 -0
  10. bec_widgets/utils/crosshair.py +13 -9
  11. bec_widgets/utils/ui_loader.py +58 -0
  12. bec_widgets/widgets/__init__.py +1 -0
  13. bec_widgets/widgets/motor_control/motor_table/motor_table.py +44 -43
  14. bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py +25 -23
  15. bec_widgets/widgets/motor_control/movement_relative/movement_relative.py +51 -48
  16. bec_widgets/widgets/spiral_progress_bar/__init__.py +1 -0
  17. bec_widgets/widgets/spiral_progress_bar/ring.py +184 -0
  18. bec_widgets/widgets/spiral_progress_bar/spiral_progress_bar.py +594 -0
  19. {bec_widgets-0.54.0.dist-info → bec_widgets-0.56.0.dist-info}/METADATA +3 -1
  20. {bec_widgets-0.54.0.dist-info → bec_widgets-0.56.0.dist-info}/RECORD +29 -46
  21. docs/user/apps.md +1 -26
  22. pyproject.toml +2 -1
  23. tests/end-2-end/test_bec_dock_rpc_e2e.py +81 -0
  24. tests/unit_tests/test_client_utils.py +2 -2
  25. tests/unit_tests/test_crosshair.py +5 -5
  26. tests/unit_tests/test_motor_control.py +49 -45
  27. tests/unit_tests/test_spiral_progress_bar.py +338 -0
  28. bec_widgets/examples/eiger_plot/__init__.py +0 -0
  29. bec_widgets/examples/eiger_plot/eiger_plot.py +0 -307
  30. bec_widgets/examples/eiger_plot/eiger_plot.ui +0 -207
  31. bec_widgets/examples/mca_readout/__init__.py +0 -0
  32. bec_widgets/examples/mca_readout/mca_plot.py +0 -159
  33. bec_widgets/examples/mca_readout/mca_sim.py +0 -28
  34. bec_widgets/examples/modular_app/___init__.py +0 -0
  35. bec_widgets/examples/modular_app/modular.ui +0 -92
  36. bec_widgets/examples/modular_app/modular_app.py +0 -197
  37. bec_widgets/examples/motor_movement/config_example.yaml +0 -17
  38. bec_widgets/examples/motor_movement/csax_bec_config.yaml +0 -10
  39. bec_widgets/examples/motor_movement/csaxs_config.yaml +0 -17
  40. bec_widgets/examples/motor_movement/motor_example.py +0 -1344
  41. bec_widgets/examples/stream_plot/__init__.py +0 -0
  42. bec_widgets/examples/stream_plot/line_plot.ui +0 -155
  43. bec_widgets/examples/stream_plot/stream_plot.py +0 -337
  44. docs/user/apps/modular_app.md +0 -6
  45. docs/user/apps/motor_app.md +0 -34
  46. docs/user/apps/motor_app_10fps.gif +0 -0
  47. docs/user/apps/plot_app.md +0 -6
  48. tests/unit_tests/test_eiger_plot.py +0 -115
  49. tests/unit_tests/test_stream_plot.py +0 -158
  50. {bec_widgets-0.54.0.dist-info → bec_widgets-0.56.0.dist-info}/WHEEL +0 -0
  51. {bec_widgets-0.54.0.dist-info → bec_widgets-0.56.0.dist-info}/licenses/LICENSE +0 -0
@@ -2,15 +2,14 @@ import os
2
2
 
3
3
  import numpy as np
4
4
  import pyqtgraph as pg
5
- from pyqtgraph.Qt import QtWidgets, uic
5
+ import qdarktheme
6
6
  from qtconsole.inprocess import QtInProcessKernelManager
7
7
  from qtconsole.rich_jupyter_widget import RichJupyterWidget
8
8
  from qtpy.QtCore import QSize
9
9
  from qtpy.QtGui import QIcon
10
10
  from qtpy.QtWidgets import QApplication, QVBoxLayout, QWidget
11
11
 
12
- from bec_widgets.cli.rpc_register import RPCRegister
13
- from bec_widgets.utils import BECDispatcher
12
+ from bec_widgets.utils import BECDispatcher, UILoader
14
13
  from bec_widgets.widgets import BECFigure
15
14
  from bec_widgets.widgets.dock.dock_area import BECDockArea
16
15
 
@@ -25,7 +24,6 @@ class JupyterConsoleWidget(RichJupyterWidget): # pragma: no cover:
25
24
  self.kernel_client.start_channels()
26
25
 
27
26
  self.kernel_manager.kernel.shell.push({"np": np, "pg": pg})
28
- # self.set_console_font_size(70)
29
27
 
30
28
  def shutdown_kernel(self):
31
29
  self.kernel_client.stop_channels()
@@ -39,32 +37,28 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
39
37
  super().__init__(parent)
40
38
 
41
39
  current_path = os.path.dirname(__file__)
42
- uic.loadUi(os.path.join(current_path, "jupyter_console_window.ui"), self)
40
+ self.ui = UILoader().load_ui(os.path.join(current_path, "jupyter_console_window.ui"), self)
43
41
 
44
42
  self._init_ui()
45
43
 
46
- self.splitter.setSizes([200, 100])
44
+ self.ui.splitter.setSizes([200, 100])
47
45
  self.safe_close = False
48
- # self.figure.clean_signal.connect(self.confirm_close)
49
-
50
- self.register = RPCRegister()
51
- self.register.add_rpc(self.figure)
52
46
 
53
47
  # console push
54
48
  self.console.kernel_manager.kernel.shell.push(
55
49
  {
56
50
  "fig": self.figure,
57
- "register": self.register,
58
51
  "dock": self.dock,
59
52
  "w1": self.w1,
60
53
  "w2": self.w2,
61
54
  "w3": self.w3,
55
+ "d0": self.d0,
62
56
  "d1": self.d1,
63
57
  "d2": self.d2,
64
- "d3": self.d3,
65
- "b2a": self.button_2_a,
66
- "b2b": self.button_2_b,
67
- "b2c": self.button_2_c,
58
+ "fig0": self.fig0,
59
+ "fig1": self.fig1,
60
+ "fig2": self.fig2,
61
+ "bar": self.bar,
68
62
  "bec": self.figure.client,
69
63
  "scans": self.figure.client.scans,
70
64
  "dev": self.figure.client.device_manager.devices,
@@ -73,11 +67,11 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
73
67
 
74
68
  def _init_ui(self):
75
69
  # Plotting window
76
- self.glw_1_layout = QVBoxLayout(self.glw) # Create a new QVBoxLayout
70
+ self.glw_1_layout = QVBoxLayout(self.ui.glw) # Create a new QVBoxLayout
77
71
  self.figure = BECFigure(parent=self, gui_id="remote") # Create a new BECDeviceMonitor
78
72
  self.glw_1_layout.addWidget(self.figure) # Add BECDeviceMonitor to the layout
79
73
 
80
- self.dock_layout = QVBoxLayout(self.dock_placeholder)
74
+ self.dock_layout = QVBoxLayout(self.ui.dock_placeholder)
81
75
  self.dock = BECDockArea(gui_id="remote")
82
76
  self.dock_layout.addWidget(self.dock)
83
77
 
@@ -87,7 +81,7 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
87
81
  # init dock for testing
88
82
  self._init_dock()
89
83
 
90
- self.console_layout = QVBoxLayout(self.widget_console)
84
+ self.console_layout = QVBoxLayout(self.ui.widget_console)
91
85
  self.console = JupyterConsoleWidget()
92
86
  self.console_layout.addWidget(self.console)
93
87
  self.console.set_default_style("linux")
@@ -109,25 +103,22 @@ class JupyterConsoleWindow(QWidget): # pragma: no cover:
109
103
  self.c1 = self.w1.get_config()
110
104
 
111
105
  def _init_dock(self):
112
- self.button_1 = QtWidgets.QPushButton("Button 1 ")
113
- self.button_2_a = QtWidgets.QPushButton("Button to be added at place 0,0 in d3")
114
- self.button_2_b = QtWidgets.QPushButton("button after without postions specified")
115
- self.button_2_c = QtWidgets.QPushButton("button super late")
116
- self.button_3 = QtWidgets.QPushButton("Button above Figure ")
117
- self.label_1 = QtWidgets.QLabel("some scan info label with useful information")
118
-
119
- self.label_2 = QtWidgets.QLabel("label which is added separately")
120
- self.label_3 = QtWidgets.QLabel("Label above figure")
121
-
122
- self.d1 = self.dock.add_dock(widget=self.button_1, position="left")
123
- self.d1.addWidget(self.label_2)
124
- self.d2 = self.dock.add_dock(widget=self.label_1, position="right")
125
- self.d3 = self.dock.add_dock(name="figure")
126
- self.fig_dock3 = BECFigure()
127
- self.fig_dock3.plot(x_name="samx", y_name="bpm4d")
128
- self.d3.add_widget(self.label_3)
129
- self.d3.add_widget(self.button_3)
130
- self.d3.add_widget(self.fig_dock3)
106
+
107
+ self.d0 = self.dock.add_dock(name="dock_0")
108
+ self.fig0 = self.d0.add_widget_bec("BECFigure")
109
+ self.fig0.image("eiger", vrange=(0, 100))
110
+
111
+ self.d1 = self.dock.add_dock(name="dock_1", position="right")
112
+ self.fig1 = self.d1.add_widget_bec("BECFigure")
113
+ self.fig1.plot(x_name="samx", y_name="bpm4i")
114
+ self.fig1.plot(x_name="samx", y_name="bpm3a")
115
+
116
+ self.d2 = self.dock.add_dock(name="dock_2", position="bottom")
117
+ self.fig2 = self.d2.add_widget_bec("BECFigure", row=0, col=0)
118
+ self.fig2.motor_map(x_name="samx", y_name="samy")
119
+ self.fig2.plot(x_name="samx", y_name="bpm4i")
120
+ self.bar = self.d2.add_widget_bec("SpiralProgressBar", row=0, col=1)
121
+ self.bar.set_diameter(200)
131
122
 
132
123
  self.dock.save_state()
133
124
 
@@ -153,6 +144,7 @@ if __name__ == "__main__": # pragma: no cover
153
144
  app = QApplication(sys.argv)
154
145
  app.setApplicationName("Jupyter Console")
155
146
  app.setApplicationDisplayName("Jupyter Console")
147
+ qdarktheme.setup_theme("auto")
156
148
  icon = QIcon()
157
149
  icon.addFile(os.path.join(module_path, "assets", "terminal_icon.png"), size=QSize(48, 48))
158
150
  app.setWindowIcon(icon)
@@ -151,7 +151,7 @@ class MotorControlPanel(QWidget):
151
151
  self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
152
152
 
153
153
  # Set the window to a fixed size based on its contents
154
- self.layout().setSizeConstraint(layout.SetFixedSize)
154
+ # self.layout().setSizeConstraint(layout.SetFixedSize)
155
155
 
156
156
 
157
157
  class MotorControlPanelAbsolute(QWidget):
@@ -178,9 +178,6 @@ class MotorControlPanelAbsolute(QWidget):
178
178
  # Connecting signals and slots
179
179
  self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
180
180
 
181
- # Set the window to a fixed size based on its contents
182
- self.layout().setSizeConstraint(layout.SetFixedSize)
183
-
184
181
 
185
182
  class MotorControlPanelRelative(QWidget):
186
183
  def __init__(self, parent=None, client=None, config=None):
@@ -206,9 +203,6 @@ class MotorControlPanelRelative(QWidget):
206
203
  # Connecting signals and slots
207
204
  self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
208
205
 
209
- # Set the window to a fixed size based on its contents
210
- self.layout().setSizeConstraint(layout.SetFixedSize)
211
-
212
206
 
213
207
  if __name__ == "__main__": # pragma: no cover
214
208
  import argparse
@@ -7,4 +7,5 @@ from .crosshair import Crosshair
7
7
  from .entry_validator import EntryValidator
8
8
  from .layout_manager import GridLayoutManager
9
9
  from .rpc_decorator import register_rpc_methods, rpc_public
10
+ from .ui_loader import UILoader
10
11
  from .validator_delegate import DoubleValidationDelegate
@@ -8,13 +8,13 @@ from qtpy.QtCore import Signal as pyqtSignal
8
8
 
9
9
  class Crosshair(QObject):
10
10
  # Signal for 1D plot
11
- coordinatesChanged1D = pyqtSignal(float, list)
12
- coordinatesClicked1D = pyqtSignal(float, list)
11
+ coordinatesChanged1D = pyqtSignal(tuple)
12
+ coordinatesClicked1D = pyqtSignal(tuple)
13
13
  # Signal for 2D plot
14
- coordinatesChanged2D = pyqtSignal(float, float)
15
- coordinatesClicked2D = pyqtSignal(float, float)
14
+ coordinatesChanged2D = pyqtSignal(tuple)
15
+ coordinatesClicked2D = pyqtSignal(tuple)
16
16
 
17
- def __init__(self, plot_item: pg.PlotItem, precision: int = None, parent=None):
17
+ def __init__(self, plot_item: pg.PlotItem, precision: int = 3, parent=None):
18
18
  """
19
19
  Crosshair for 1D and 2D plots.
20
20
 
@@ -174,10 +174,11 @@ class Crosshair(QObject):
174
174
  if isinstance(item, pg.PlotDataItem):
175
175
  if x is None or all(v is None for v in y_values):
176
176
  return
177
- self.coordinatesChanged1D.emit(
177
+ coordinate_to_emit = (
178
178
  round(x, self.precision),
179
179
  [round(y_val, self.precision) for y_val in y_values],
180
180
  )
181
+ self.coordinatesChanged1D.emit(coordinate_to_emit)
181
182
  for i, y_val in enumerate(y_values):
182
183
  self.marker_moved_1d[i].setData(
183
184
  [x if not self.is_log_x else np.log10(x)],
@@ -186,7 +187,8 @@ class Crosshair(QObject):
186
187
  elif isinstance(item, pg.ImageItem):
187
188
  if x is None or y_values is None:
188
189
  return
189
- self.coordinatesChanged2D.emit(x, y_values)
190
+ coordinate_to_emit = (x, y_values)
191
+ self.coordinatesChanged2D.emit(coordinate_to_emit)
190
192
 
191
193
  def mouse_clicked(self, event):
192
194
  """Handles the mouse clicked event, updating the crosshair position and emitting signals.
@@ -209,10 +211,11 @@ class Crosshair(QObject):
209
211
  if isinstance(item, pg.PlotDataItem):
210
212
  if x is None or all(v is None for v in y_values):
211
213
  return
212
- self.coordinatesClicked1D.emit(
214
+ coordinate_to_emit = (
213
215
  round(x, self.precision),
214
216
  [round(y_val, self.precision) for y_val in y_values],
215
217
  )
218
+ self.coordinatesClicked1D.emit(coordinate_to_emit)
216
219
  for i, y_val in enumerate(y_values):
217
220
  for marker in self.marker_clicked_1d[i]:
218
221
  marker.setData(
@@ -222,7 +225,8 @@ class Crosshair(QObject):
222
225
  elif isinstance(item, pg.ImageItem):
223
226
  if x is None or y_values is None:
224
227
  return
225
- self.coordinatesClicked2D.emit(x, y_values)
228
+ coordinate_to_emit = (x, y_values)
229
+ self.coordinatesClicked2D.emit(coordinate_to_emit)
226
230
  self.marker_2d.setPos([x, y_values])
227
231
 
228
232
  def check_log(self):
@@ -0,0 +1,58 @@
1
+ from qtpy import QT_VERSION
2
+ from qtpy.QtCore import QFile, QIODevice
3
+
4
+
5
+ class UILoader:
6
+ """Universal UI loader for PyQt5, PyQt6, PySide2, and PySide6."""
7
+
8
+ def __init__(self, parent=None):
9
+ self.parent = parent
10
+ if QT_VERSION.startswith("5"):
11
+ # PyQt5 or PySide2
12
+ from qtpy import uic
13
+
14
+ self.loader = uic.loadUi
15
+ elif QT_VERSION.startswith("6"):
16
+ # PyQt6 or PySide6
17
+ try:
18
+ from PySide6.QtUiTools import QUiLoader
19
+
20
+ self.loader = self.load_ui_pyside6
21
+ except ImportError:
22
+ from PyQt6.uic import loadUi
23
+
24
+ self.loader = loadUi
25
+
26
+ def load_ui_pyside6(self, ui_file, parent=None):
27
+ """
28
+ Specific loader for PySide6 using QUiLoader.
29
+ Args:
30
+ ui_file(str): Path to the .ui file.
31
+ parent(QWidget): Parent widget.
32
+
33
+ Returns:
34
+ QWidget: The loaded widget.
35
+ """
36
+ from PySide6.QtUiTools import QUiLoader
37
+
38
+ loader = QUiLoader(parent)
39
+ file = QFile(ui_file)
40
+ if not file.open(QIODevice.ReadOnly):
41
+ raise IOError(f"Cannot open file: {ui_file}")
42
+ widget = loader.load(file, parent)
43
+ file.close()
44
+ return widget
45
+
46
+ def load_ui(self, ui_file, parent=None):
47
+ """
48
+ Universal UI loader method.
49
+ Args:
50
+ ui_file(str): Path to the .ui file.
51
+ parent(QWidget): Parent widget.
52
+
53
+ Returns:
54
+ QWidget: The loaded widget.
55
+ """
56
+ if parent is None:
57
+ parent = self.parent
58
+ return self.loader(ui_file, parent)
@@ -1,3 +1,4 @@
1
1
  from .dock import BECDock, BECDockArea
2
2
  from .figure import BECFigure, FigureConfig
3
3
  from .scan_control import ScanControl
4
+ from .spiral_progress_bar import SpiralProgressBar
@@ -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
  """