diff --git a/bec_widgets/examples/__init__.py b/bec_widgets/examples/__init__.py
index cdec4903..e69de29b 100644
--- a/bec_widgets/examples/__init__.py
+++ b/bec_widgets/examples/__init__.py
@@ -1,9 +0,0 @@
-from .motor_movement import (
- MotorControlApp,
- MotorControlMap,
- MotorControlPanel,
- MotorControlPanelAbsolute,
- MotorControlPanelRelative,
- MotorCoordinateTable,
- MotorThread,
-)
diff --git a/bec_widgets/examples/motor_movement/__init__.py b/bec_widgets/examples/motor_movement/__init__.py
deleted file mode 100644
index 6e1ea76e..00000000
--- a/bec_widgets/examples/motor_movement/__init__.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from .motor_control_compilations import (
- MotorControlApp,
- MotorControlMap,
- MotorControlPanel,
- MotorControlPanelAbsolute,
- MotorControlPanelRelative,
- MotorCoordinateTable,
- MotorThread,
-)
diff --git a/bec_widgets/examples/motor_movement/motor_control_compilations.py b/bec_widgets/examples/motor_movement/motor_control_compilations.py
deleted file mode 100644
index 21cb8a94..00000000
--- a/bec_widgets/examples/motor_movement/motor_control_compilations.py
+++ /dev/null
@@ -1,250 +0,0 @@
-# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
-
-import qdarktheme
-from qtpy.QtCore import Qt
-from qtpy.QtWidgets import QApplication, QSplitter, QVBoxLayout, QWidget
-
-from bec_widgets.utils.bec_dispatcher import BECDispatcher
-from bec_widgets.widgets.motor_control.motor_control import MotorThread
-from bec_widgets.widgets.motor_control.motor_table.motor_table import MotorCoordinateTable
-from bec_widgets.widgets.motor_control.movement_absolute.movement_absolute import (
- MotorControlAbsolute,
-)
-from bec_widgets.widgets.motor_control.movement_relative.movement_relative import (
- MotorControlRelative,
-)
-from bec_widgets.widgets.motor_control.selection.selection import MotorControlSelection
-
-CONFIG_DEFAULT = {
- "motor_control": {
- "motor_x": "samx",
- "motor_y": "samy",
- "step_size_x": 3,
- "step_size_y": 3,
- "precision": 4,
- "step_x_y_same": False,
- "move_with_arrows": False,
- },
- "plot_settings": {
- "colormap": "Greys",
- "scatter_size": 5,
- "max_points": 1000,
- "num_dim_points": 100,
- "precision": 2,
- "num_columns": 1,
- "background_value": 25,
- },
- "motors": [
- {
- "plot_name": "Motor Map",
- "x_label": "Motor X",
- "y_label": "Motor Y",
- "signals": {
- "x": [{"name": "samx", "entry": "samx"}],
- "y": [{"name": "samy", "entry": "samy"}],
- },
- }
- ],
-}
-
-
-class MotorControlApp(QWidget):
- def __init__(self, parent=None, client=None, config=None):
- super().__init__(parent)
-
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client if client is None else client
- self.config = config
-
- # Widgets
- self.motor_control_panel = MotorControlPanel(client=self.client, config=self.config)
- # Create MotorMap
- # self.motion_map = MotorMap(client=self.client, config=self.config)
- # Create MotorCoordinateTable
- self.motor_table = MotorCoordinateTable(client=self.client, config=self.config)
-
- # Create the splitter and add MotorMap and MotorControlPanel
- splitter = QSplitter(Qt.Horizontal)
- # splitter.addWidget(self.motion_map)
- splitter.addWidget(self.motor_control_panel)
- splitter.addWidget(self.motor_table)
-
- # Set the main layout
- layout = QVBoxLayout(self)
- layout.addWidget(splitter)
- self.setLayout(layout)
-
- # Connecting signals and slots
- # self.motor_control_panel.selection_widget.selected_motors_signal.connect(
- # lambda x, y: self.motion_map.change_motors(x, y, 0)
- # )
- self.motor_control_panel.absolute_widget.coordinates_signal.connect(
- self.motor_table.add_coordinate
- )
- self.motor_control_panel.relative_widget.precision_signal.connect(
- self.motor_table.set_precision
- )
- self.motor_control_panel.relative_widget.precision_signal.connect(
- self.motor_control_panel.absolute_widget.set_precision
- )
-
- # self.motor_table.plot_coordinates_signal.connect(self.motion_map.plot_saved_coordinates)
-
-
-class MotorControlMap(QWidget):
- def __init__(self, parent=None, client=None, config=None):
- super().__init__(parent)
-
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client if client is None else client
- self.config = config
-
- # Widgets
- self.motor_control_panel = MotorControlPanel(client=self.client, config=self.config)
- # Create MotorMap
- # self.motion_map = MotorMap(client=self.client, config=self.config)
-
- # Create the splitter and add MotorMap and MotorControlPanel
- splitter = QSplitter(Qt.Horizontal)
- # splitter.addWidget(self.motion_map)
- splitter.addWidget(self.motor_control_panel)
-
- # Set the main layout
- layout = QVBoxLayout(self)
- layout.addWidget(splitter)
- self.setLayout(layout)
-
- # Connecting signals and slots
- # self.motor_control_panel.selection_widget.selected_motors_signal.connect(
- # lambda x, y: self.motion_map.change_motors(x, y, 0)
- # )
-
-
-class MotorControlPanel(QWidget):
- def __init__(self, parent=None, client=None, config=None):
- super().__init__(parent)
-
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client if client is None else client
- self.config = config
-
- self.motor_thread = MotorThread(client=self.client)
-
- self.selection_widget = MotorControlSelection(
- client=self.client, config=self.config, motor_thread=self.motor_thread
- )
- self.relative_widget = MotorControlRelative(
- client=self.client, config=self.config, motor_thread=self.motor_thread
- )
- self.absolute_widget = MotorControlAbsolute(
- client=self.client, config=self.config, motor_thread=self.motor_thread
- )
-
- layout = QVBoxLayout(self)
-
- layout.addWidget(self.selection_widget)
- layout.addWidget(self.relative_widget)
- layout.addWidget(self.absolute_widget)
-
- # Connecting signals and slots
- self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
- self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
-
- # Set the window to a fixed size based on its contents
- # self.layout().setSizeConstraint(layout.SetFixedSize)
-
-
-class MotorControlPanelAbsolute(QWidget):
- def __init__(self, parent=None, client=None, config=None):
- super().__init__(parent)
-
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client if client is None else client
- self.config = config
-
- self.motor_thread = MotorThread(client=self.client)
-
- self.selection_widget = MotorControlSelection(
- client=client, config=config, motor_thread=self.motor_thread
- )
- self.absolute_widget = MotorControlAbsolute(
- client=client, config=config, motor_thread=self.motor_thread
- )
-
- layout = QVBoxLayout(self)
- layout.addWidget(self.selection_widget)
- layout.addWidget(self.absolute_widget)
-
- # Connecting signals and slots
- self.selection_widget.selected_motors_signal.connect(self.absolute_widget.change_motors)
-
-
-class MotorControlPanelRelative(QWidget):
- def __init__(self, parent=None, client=None, config=None):
- super().__init__(parent)
-
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client if client is None else client
- self.config = config
-
- self.motor_thread = MotorThread(client=self.client)
-
- self.selection_widget = MotorControlSelection(
- client=client, config=config, motor_thread=self.motor_thread
- )
- self.relative_widget = MotorControlRelative(
- client=client, config=config, motor_thread=self.motor_thread
- )
-
- layout = QVBoxLayout(self)
- layout.addWidget(self.selection_widget)
- layout.addWidget(self.relative_widget)
-
- # Connecting signals and slots
- self.selection_widget.selected_motors_signal.connect(self.relative_widget.change_motors)
-
-
-if __name__ == "__main__": # pragma: no cover
- import argparse
- import sys
-
- parser = argparse.ArgumentParser(description="Run various Motor Control Widgets compositions.")
- parser.add_argument(
- "-v",
- "--variant",
- type=str,
- choices=["app", "map", "panel", "panel_abs", "panel_rel"],
- help="Select the variant of the motor control to run. "
- "'app' for the full application, "
- "'map' for MotorMap, "
- "'panel' for the MotorControlPanel, "
- "'panel_abs' for MotorControlPanel with absolute control, "
- "'panel_rel' for MotorControlPanel with relative control.",
- )
-
- args = parser.parse_args()
-
- bec_dispatcher = BECDispatcher()
- client = bec_dispatcher.client
- client.start()
-
- app = QApplication([])
- qdarktheme.setup_theme("auto")
-
- if args.variant == "app":
- window = MotorControlApp(client=client) # , config=CONFIG_DEFAULT)
- elif args.variant == "map":
- window = MotorControlMap(client=client) # , config=CONFIG_DEFAULT)
- elif args.variant == "panel":
- window = MotorControlPanel(client=client) # , config=CONFIG_DEFAULT)
- elif args.variant == "panel_abs":
- window = MotorControlPanelAbsolute(client=client) # , config=CONFIG_DEFAULT)
- elif args.variant == "panel_rel":
- window = MotorControlPanelRelative(client=client) # , config=CONFIG_DEFAULT)
- else:
- print("Please specify a valid variant to run. Use -h for help.")
- print("Running the full application by default.")
- window = MotorControlApp(client=client) # , config=CONFIG_DEFAULT)
-
- window.show()
- sys.exit(app.exec())
diff --git a/bec_widgets/examples/motor_movement/motor_controller.ui b/bec_widgets/examples/motor_movement/motor_controller.ui
deleted file mode 100644
index 6134093f..00000000
--- a/bec_widgets/examples/motor_movement/motor_controller.ui
+++ /dev/null
@@ -1,926 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 1561
- 748
-
-
-
-
- 1409
- 748
-
-
-
- Motor Controller
-
-
- -
-
-
- true
-
-
-
- -
-
-
-
- 221
- 471
-
-
-
-
- 1
-
-
- QLayout::SetMinimumSize
-
-
-
-
-
-
- 261
- 145
-
-
-
- Motor Selection
-
-
-
-
-
-
- Motor Y
-
-
-
- -
-
-
- -
-
-
- -
-
-
- Motor X
-
-
-
- -
-
-
- Connect Motors
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Minimum
-
-
-
- 20
- 18
-
-
-
-
- -
-
-
-
- 261
- 339
-
-
-
- Motor Relative
-
-
-
-
-
-
- Move with arrow keys
-
-
-
- -
-
-
- Step [X] = Step [Y]
-
-
-
- -
-
-
-
-
-
-
- 111
- 19
-
-
-
- Step [Y]
-
-
-
- -
-
-
-
- 111
- 19
-
-
-
- Decimal
-
-
-
- -
-
-
-
- 110
- 19
-
-
-
- Qt::AlignCenter
-
-
- 0.000000000000000
-
-
- 99.000000000000000
-
-
- 0.100000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
-
- 111
- 19
-
-
-
- Step [X]
-
-
-
- -
-
-
-
- 110
- 19
-
-
-
- Qt::AlignCenter
-
-
- 0.000000000000000
-
-
- 99.000000000000000
-
-
- 0.100000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
-
- 110
- 19
-
-
-
- Qt::AlignCenter
-
-
- 8
-
-
- 2
-
-
-
-
-
- -
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::UpArrow
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::DownArrow
-
-
-
- -
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::LeftArrow
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::RightArrow
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
- QSizePolicy::Minimum
-
-
-
- 20
- 18
-
-
-
-
- -
-
-
-
- 261
- 195
-
-
-
- Move Absolute
-
-
-
-
-
-
- Save position with Go
-
-
-
- -
-
-
-
-
-
- Qt::AlignCenter
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- Y
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- X
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
-
-
- Save
-
-
-
- -
-
-
- Set
-
-
-
- -
-
-
- Go
-
-
-
-
-
- -
-
-
- Stop Movement
-
-
-
-
-
-
-
-
-
- -
-
-
- true
-
-
- 0
-
-
-
- Coordinates
-
-
-
-
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Entries Mode:
-
-
-
- -
-
-
-
-
- Individual
-
-
- -
-
- Start/Stop
-
-
-
-
-
-
- -
-
-
- QAbstractItemView::MultiSelection
-
-
- QAbstractItemView::SelectRows
-
-
-
- Show
-
-
-
-
- Move
-
-
-
-
- Tag
-
-
-
-
- X
-
-
-
-
- Y
-
-
-
-
- -
-
-
-
-
-
- Resize Table
-
-
-
- -
-
-
- Resize Auto
-
-
- true
-
-
-
- -
-
-
- Import CSV
-
-
-
- -
-
-
- Export CSV
-
-
-
- -
-
-
- Help
-
-
-
- -
-
-
- Duplicate Last Entry
-
-
-
-
-
-
-
-
-
- Settings
-
-
- -
-
-
- false
-
-
- Motor Limits
-
-
-
-
-
-
- Update
-
-
-
- -
-
-
- + Y
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- - Y
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- - X
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- + X
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- -1000.000000000000000
-
-
- 1000.000000000000000
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- -1000.000000000000000
-
-
- 1000.000000000000000
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- -1000.000000000000000
-
-
- 1000.000000000000000
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- -1000.000000000000000
-
-
- 1000.000000000000000
-
-
-
-
-
-
- -
-
-
- Plotting Options
-
-
-
-
-
-
- Qt::AlignCenter
-
-
- 100
-
-
- 10000
-
-
- 100
-
-
- 5000
-
-
-
- -
-
-
- Max Points
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- 1
-
-
- 15
-
-
- 5
-
-
-
- -
-
-
- Scatter Size
-
-
-
- -
-
-
- Update Settings
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- 10
-
-
- 1000
-
-
- 10
-
-
- 100
-
-
-
- -
-
-
- N dim
-
-
-
- -
-
-
- Enable Control GUI
-
-
-
-
-
-
-
-
-
-
- Queue
-
-
- -
-
-
- Work in progress
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- false
-
-
- Reset Queue
-
-
-
- -
-
-
- false
-
-
-
- queueID
-
-
-
-
- scan_id
-
-
-
-
- is_scan
-
-
-
-
- type
-
-
-
-
- scan_number
-
-
-
-
- IQ status
-
-
-
-
-
-
-
-
-
-
-
-
- GraphicsLayoutWidget
- QGraphicsView
-
-
-
-
-
-
diff --git a/bec_widgets/widgets/motor_control/__init__.py b/bec_widgets/widgets/motor_control/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/motor_control/motor_control.py b/bec_widgets/widgets/motor_control/motor_control.py
deleted file mode 100644
index 45aa334a..00000000
--- a/bec_widgets/widgets/motor_control/motor_control.py
+++ /dev/null
@@ -1,252 +0,0 @@
-# pylint: disable = no-name-in-module,missing-module-docstring
-from enum import Enum
-
-from bec_lib.alarm_handler import AlarmBase
-from bec_lib.device import Positioner
-from qtpy.QtCore import QThread
-from qtpy.QtCore import Signal as pyqtSignal
-from qtpy.QtCore import Slot as pyqtSlot
-from qtpy.QtWidgets import QMessageBox, QWidget
-
-from bec_widgets.utils.bec_dispatcher import BECDispatcher
-
-CONFIG_DEFAULT = {
- "motor_control": {
- "motor_x": "samx",
- "motor_y": "samy",
- "step_size_x": 3,
- "step_size_y": 50,
- "precision": 4,
- "step_x_y_same": False,
- "move_with_arrows": False,
- }
-}
-
-
-class MotorControlWidget(QWidget):
- """Base class for motor control widgets."""
-
- def __init__(self, parent=None, client=None, motor_thread=None, config=None):
- super().__init__(parent)
- self.client = client
- self.motor_thread = motor_thread
- self.config = config
-
- self.motor_x = None
- self.motor_y = None
-
- if not self.client:
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client
-
- if not self.motor_thread:
- self.motor_thread = MotorThread(client=self.client)
-
- self._load_ui()
-
- if self.config is None:
- print(f"No initial config found for {self.__class__.__name__}")
- self._init_ui()
- else:
- self.on_config_update(self.config)
-
- def _load_ui(self):
- """Load the UI from the .ui file."""
-
- def _init_ui(self):
- """Initialize the UI components specific to the widget."""
-
- @pyqtSlot(dict)
- def on_config_update(self, config):
- """Handle configuration updates."""
- self.config = config
- self._init_ui()
-
-
-class MotorControlErrors:
- """Class for displaying formatted error messages."""
-
- @staticmethod
- def display_error_message(error_message: str) -> None:
- """
- Display a critical error message.
- Args:
- error_message(str): Error message to display.
- """
- # Create a QMessageBox
- msg = QMessageBox()
- msg.setIcon(QMessageBox.Critical)
- msg.setWindowTitle("Critical Error")
-
- # Format the message
- formatted_message = MotorControlErrors._format_error_message(error_message)
- msg.setText(formatted_message)
-
- # Display the message box
- msg.exec_()
-
- @staticmethod
- def _format_error_message(error_message: str) -> str:
- """
- Format the error message.
- Args:
- error_message(str): Error message to format.
-
- Returns:
- str: Formatted error message.
- """
- # Split the message into lines
- lines = error_message.split("\n")
- formatted_lines = [
- f"{line.strip()}" if i == 0 else line.strip()
- for i, line in enumerate(lines)
- if line.strip()
- ]
-
- # Join the lines with double breaks for empty lines in between
- formatted_message = "
".join(formatted_lines)
-
- return formatted_message
-
-
-class MotorActions(Enum):
- """Enum for motor actions."""
-
- MOVE_ABSOLUTE = "move_absolute"
- MOVE_RELATIVE = "move_relative"
-
-
-class MotorThread(QThread):
- """
- QThread subclass for controlling motor actions asynchronously.
-
- Signals:
- coordinates_updated (pyqtSignal): Signal to emit current coordinates.
- motor_error (pyqtSignal): Signal to emit when there is an error with the motors.
- lock_gui (pyqtSignal): Signal to lock/unlock the GUI.
- """
-
- coordinates_updated = pyqtSignal(float, float) # Signal to emit current coordinates
- motor_error = pyqtSignal(str) # Signal to emit when there is an error with the motors
- lock_gui = pyqtSignal(bool) # Signal to lock/unlock the GUI
-
- def __init__(self, parent=None, client=None):
- super().__init__(parent)
-
- bec_dispatcher = BECDispatcher()
- self.client = bec_dispatcher.client if client is None else client
- self.dev = self.client.device_manager.devices
- self.scans = self.client.scans
- self.queue = self.client.queue
- self.action = None
-
- self.motor = None
- self.motor_x = None
- self.motor_y = None
- self.target_coordinates = None
- self.value = None
-
- def get_all_motors_names(self) -> list:
- """
- Get all the motors names.
- Returns:
- list: List of all the motors names.
- """
- all_devices = self.client.device_manager.devices.enabled_devices
- all_motors_names = [motor.name for motor in all_devices if isinstance(motor, Positioner)]
- return all_motors_names
-
- def get_coordinates(self, motor_x: str, motor_y: str) -> tuple:
- """
- Get the current coordinates of the motors.
- Args:
- motor_x(str): Motor X to get positions from.
- motor_y(str): Motor Y to get positions from.
-
- Returns:
- tuple: Current coordinates of the motors.
- """
- x = self.dev[motor_x].readback.get()
- y = self.dev[motor_y].readback.get()
- return x, y
-
- def move_absolute(self, motor_x: str, motor_y: str, target_coordinates: tuple) -> None:
- """
- Wrapper for moving the motor to the target coordinates.
- Args:
- motor_x(str): Motor X to move.
- motor_y(str): Motor Y to move.
- target_coordinates(tuple): Target coordinates.
- """
- self.action = MotorActions.MOVE_ABSOLUTE
- self.motor_x = motor_x
- self.motor_y = motor_y
- self.target_coordinates = target_coordinates
- self.start()
-
- def move_relative(self, motor: str, value: float) -> None:
- """
- Wrapper for moving the motor relative to the current position.
- Args:
- motor(str): Motor to move.
- value(float): Value to move.
- """
- self.action = MotorActions.MOVE_RELATIVE
- self.motor = motor
- self.value = value
- self.start()
-
- def run(self):
- """
- Run the thread.
- Possible actions:
- - Move to coordinates
- - Move relative
- """
- if self.action == MotorActions.MOVE_ABSOLUTE:
- self._move_motor_absolute(self.motor_x, self.motor_y, self.target_coordinates)
- elif self.action == MotorActions.MOVE_RELATIVE:
- self._move_motor_relative(self.motor, self.value)
-
- def _move_motor_absolute(self, motor_x: str, motor_y: str, target_coordinates: tuple) -> None:
- """
- Move the motor to the target coordinates.
- Args:
- motor_x(str): Motor X to move.
- motor_y(str): Motor Y to move.
- target_coordinates(tuple): Target coordinates.
- """
- self.lock_gui.emit(False)
- try:
- status = self.scans.mv(
- self.dev[motor_x],
- target_coordinates[0],
- self.dev[motor_y],
- target_coordinates[1],
- relative=False,
- )
- status.wait()
- except AlarmBase as e:
- self.motor_error.emit(str(e))
- finally:
- self.lock_gui.emit(True)
-
- def _move_motor_relative(self, motor, value: float) -> None:
- """
- Move the motor relative to the current position.
- Args:
- motor(str): Motor to move.
- value(float): Value to move.
- """
- self.lock_gui.emit(False)
- try:
- status = self.scans.mv(self.dev[motor], value, relative=True)
- status.wait()
- except AlarmBase as e:
- self.motor_error.emit(str(e))
- finally:
- self.lock_gui.emit(True)
-
- def stop_movement(self):
- self.queue.request_scan_abortion()
- self.queue.request_queue_reset()
diff --git a/bec_widgets/widgets/motor_control/motor_table/__init__.py b/bec_widgets/widgets/motor_control/motor_table/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/motor_control/motor_table/motor_table.py b/bec_widgets/widgets/motor_control/motor_table/motor_table.py
deleted file mode 100644
index 5fbc439f..00000000
--- a/bec_widgets/widgets/motor_control/motor_table/motor_table.py
+++ /dev/null
@@ -1,484 +0,0 @@
-# pylint: disable = no-name-in-module,missing-module-docstring
-import os
-
-from qtpy import uic
-from qtpy.QtCore import Qt
-from qtpy.QtCore import Signal as pyqtSignal
-from qtpy.QtCore import Slot as pyqtSlot
-from qtpy.QtGui import QDoubleValidator, QKeySequence
-from qtpy.QtWidgets import (
- QCheckBox,
- QLineEdit,
- QMessageBox,
- QPushButton,
- QShortcut,
- QTableWidget,
- QTableWidgetItem,
-)
-
-from bec_widgets.utils import UILoader
-from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
-
-
-class MotorCoordinateTable(MotorControlWidget):
- """
- Widget to save coordinates from motor, display them in the table and move back to them.
- There are two modes of operation:
- - Individual: Each row is a single coordinate.
- - Start/Stop: Each pair of rows is a start and end coordinate.
- Signals:
- plot_coordinates_signal (pyqtSignal(list, str, str)): Signal to plot the coordinates in the MotorMap.
- Slots:
- add_coordinate (pyqtSlot(tuple)): Slot to add a coordinate to the table.
- mode_switch (pyqtSlot): Slot to switch between individual and start/stop mode.
- """
-
- plot_coordinates_signal = pyqtSignal(list, str, str)
-
- def _load_ui(self):
- """Load the UI for the coordinate table."""
- current_path = os.path.dirname(__file__)
- self.ui = UILoader().load_ui(os.path.join(current_path, "motor_table.ui"), self)
-
- def _init_ui(self):
- """Initialize the UI"""
- # Setup table behaviour
- self._setup_table()
- self.ui.table.setSelectionBehavior(QTableWidget.SelectRows)
-
- # for tag columns default tag
- self.tag_counter = 1
-
- # Connect signals and slots
- self.ui.checkBox_resize_auto.stateChanged.connect(self.resize_table_auto)
- self.ui.comboBox_mode.currentIndexChanged.connect(self.mode_switch)
-
- # Keyboard shortcuts for deleting a row
- self.delete_shortcut = QShortcut(QKeySequence(Qt.Key_Delete), self.ui.table)
- self.delete_shortcut.activated.connect(self.delete_selected_row)
- self.backspace_shortcut = QShortcut(QKeySequence(Qt.Key_Backspace), self.ui.table)
- self.backspace_shortcut.activated.connect(self.delete_selected_row)
-
- # Warning message for mode switch enable/disable
- self.warning_message = True
-
- @pyqtSlot(dict)
- def on_config_update(self, config: dict) -> None:
- """
- Update config dict
- Args:
- config(dict): New config dict
- """
- self.config = config
-
- # Get motor names
- self.motor_x, self.motor_y = (
- self.config["motor_control"]["motor_x"],
- self.config["motor_control"]["motor_y"],
- )
-
- # Decimal precision of the table coordinates
- self.precision = self.config["motor_control"].get("precision", 3)
-
- # Mode switch default option
- self.mode = self.config["motor_control"].get("mode", "Individual")
-
- # Set combobox to default mode
- self.ui.comboBox_mode.setCurrentText(self.mode)
-
- self._init_ui()
-
- def _setup_table(self):
- """Setup the table with appropriate headers and configurations."""
- mode = self.ui.comboBox_mode.currentText()
-
- if mode == "Individual":
- self._setup_individual_mode()
- elif mode == "Start/Stop":
- self._setup_start_stop_mode()
- self.start_stop_counter = 0 # TODO: remove this??
-
- self.wipe_motor_map_coordinates()
-
- def _setup_individual_mode(self):
- """Setup the table for individual mode."""
- self.ui.table.setColumnCount(5)
- self.ui.table.setHorizontalHeaderLabels(["Show", "Move", "Tag", "X", "Y"])
- self.ui.table.verticalHeader().setVisible(False)
-
- def _setup_start_stop_mode(self):
- """Setup the table for start/stop mode."""
- self.ui.table.setColumnCount(8)
- self.ui.table.setHorizontalHeaderLabels(
- [
- "Show",
- "Move [start]",
- "Move [end]",
- "Tag",
- "X [start]",
- "Y [start]",
- "X [end]",
- "Y [end]",
- ]
- )
- self.ui.table.verticalHeader().setVisible(False)
- # Set flag to track if the coordinate is stat or the end of the entry
- self.is_next_entry_end = False
-
- def mode_switch(self):
- """Switch between individual and start/stop mode."""
- last_selected_index = self.ui.comboBox_mode.currentIndex()
-
- if self.ui.table.rowCount() > 0 and self.warning_message is True:
- msgBox = QMessageBox()
- msgBox.setIcon(QMessageBox.Critical)
- msgBox.setText(
- "Switching modes will delete all table entries. Do you want to continue?"
- )
- msgBox.setStandardButtons(QMessageBox.Ok | QMessageBox.Cancel)
- returnValue = msgBox.exec()
-
- if returnValue is QMessageBox.Cancel:
- self.ui.comboBox_mode.blockSignals(True) # Block signals
- self.ui.comboBox_mode.setCurrentIndex(last_selected_index)
- self.ui.comboBox_mode.blockSignals(False) # Unblock signals
- return
-
- # Wipe table
- self.wipe_motor_map_coordinates()
-
- # Initiate new table with new mode
- self._setup_table()
-
- @pyqtSlot(tuple)
- def add_coordinate(self, coordinates: tuple):
- """
- Add a coordinate to the table.
- Args:
- coordinates(tuple): Coordinates (x,y) to add to the table.
- """
- tag = f"Pos {self.tag_counter}"
- self.tag_counter += 1
- x, y = coordinates
- self._add_row(tag, x, y)
-
- def _add_row(self, tag: str, x: float, y: float) -> None:
- """
- Add a row to the table.
- Args:
- tag(str): Tag of the coordinate.
- x(float): X coordinate.
- y(float): Y coordinate.
- """
-
- mode = self.ui.comboBox_mode.currentText()
- if mode == "Individual":
- checkbox_pos = 0
- button_pos = 1
- tag_pos = 2
- x_pos = 3
- y_pos = 4
- coordinate_reference = "Individual"
- color = "green"
-
- # Add new row -> new entry
- row_count = self.ui.table.rowCount()
- self.ui.table.insertRow(row_count)
-
- # Add Widgets
- self._add_widgets(
- tag,
- x,
- y,
- row_count,
- checkbox_pos,
- tag_pos,
- button_pos,
- x_pos,
- y_pos,
- coordinate_reference,
- color,
- )
-
- if mode == "Start/Stop":
- # These positions are always fixed
- checkbox_pos = 0
- tag_pos = 3
-
- if self.is_next_entry_end is False: # It is the start position of the entry
- print("Start position")
- button_pos = 1
- x_pos = 4
- y_pos = 5
- coordinate_reference = "Start"
- color = "blue"
-
- # Add new row -> new entry
- row_count = self.ui.table.rowCount()
- self.ui.table.insertRow(row_count)
-
- # Add Widgets
- self._add_widgets(
- tag,
- x,
- y,
- row_count,
- checkbox_pos,
- tag_pos,
- button_pos,
- x_pos,
- y_pos,
- coordinate_reference,
- color,
- )
-
- # Next entry will be the end of the current entry
- self.is_next_entry_end = True
-
- elif self.is_next_entry_end is True: # It is the end position of the entry
- print("End position")
- row_count = self.ui.table.rowCount() - 1 # Current row
- button_pos = 2
- x_pos = 6
- y_pos = 7
- coordinate_reference = "Stop"
- color = "red"
-
- # Add Widgets
- self._add_widgets(
- tag,
- x,
- y,
- row_count,
- checkbox_pos,
- tag_pos,
- button_pos,
- x_pos,
- y_pos,
- coordinate_reference,
- color,
- )
- self.is_next_entry_end = False # Next entry will be the start of the new entry
-
- # Auto table resize
- self.resize_table_auto()
-
- def _add_widgets(
- self,
- tag: str,
- x: float,
- y: float,
- row: int,
- checkBox_pos: int,
- tag_pos: int,
- button_pos: int,
- x_pos: int,
- y_pos: int,
- coordinate_reference: str,
- color: str,
- ) -> None:
- """
- Add widgets to the table.
- Args:
- tag(str): Tag of the coordinate.
- x(float): X coordinate.
- y(float): Y coordinate.
- row(int): Row of the QTableWidget where to add the widgets.
- checkBox_pos(int): Column where to put CheckBox.
- tag_pos(int): Column where to put Tag.
- button_pos(int): Column where to put Move button.
- x_pos(int): Column where to link x coordinate.
- y_pos(int): Column where to link y coordinate.
- coordinate_reference(str): Reference to the coordinate for MotorMap.
- color(str): Color of the coordinate for MotorMap.
- """
- # Add widgets
- self._add_checkbox(row, checkBox_pos, x_pos, y_pos)
- self._add_move_button(row, button_pos, x_pos, y_pos)
- self.ui.table.setItem(row, tag_pos, QTableWidgetItem(tag))
- self._add_line_edit(x, row, x_pos, x_pos, y_pos, coordinate_reference, color)
- self._add_line_edit(y, row, y_pos, x_pos, y_pos, coordinate_reference, color)
-
- # # Emit the coordinates to be plotted
- self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
-
- # Connect item edit to emit coordinates
- self.ui.table.itemChanged.connect(
- lambda: print(f"item changed from {coordinate_reference} slot \n {x}-{y}-{color}")
- )
- self.ui.table.itemChanged.connect(
- lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
- )
-
- def _add_checkbox(self, row: int, checkBox_pos: int, x_pos: int, y_pos: int):
- """
- Add a checkbox to the table.
- Args:
- row(int): Row of QTableWidget where to add the checkbox.
- checkBox_pos(int): Column where to put CheckBox.
- x_pos(int): Column where to link x coordinate.
- y_pos(int): Column where to link y coordinate.
- """
- show_checkbox = QCheckBox()
- show_checkbox.setChecked(True)
- show_checkbox.stateChanged.connect(lambda: self.emit_plot_coordinates(x_pos, y_pos))
- self.ui.table.setCellWidget(row, checkBox_pos, show_checkbox)
-
- def _add_move_button(self, row: int, button_pos: int, x_pos: int, y_pos: int) -> None:
- """
- Add a move button to the table.
- Args:
- row(int): Row of QTableWidget where to add the move button.
- button_pos(int): Column where to put move button.
- x_pos(int): Column where to link x coordinate.
- y_pos(int): Column where to link y coordinate.
- """
- move_button = QPushButton("Move")
- move_button.clicked.connect(lambda: self.handle_move_button_click(x_pos, y_pos))
- self.ui.table.setCellWidget(row, button_pos, move_button)
-
- def _add_line_edit(
- self,
- value: float,
- row: int,
- line_pos: int,
- x_pos: int,
- y_pos: int,
- coordinate_reference: str,
- color: str,
- ) -> None:
- """
- Add a QLineEdit to the table.
- Args:
- value(float): Initial value of the QLineEdit.
- row(int): Row of QTableWidget where to add the QLineEdit.
- line_pos(int): Column where to put QLineEdit.
- x_pos(int): Column where to link x coordinate.
- y_pos(int): Column where to link y coordinate.
- coordinate_reference(str): Reference to the coordinate for MotorMap.
- color(str): Color of the coordinate for MotorMap.
- """
- # Adding validator
- validator = QDoubleValidator()
- validator.setDecimals(self.precision)
-
- # Create line edit
- edit = QLineEdit(str(f"{value:.{self.precision}f}"))
- edit.setValidator(validator)
- edit.setAlignment(Qt.AlignmentFlag.AlignCenter)
-
- # Add line edit to the table
- self.ui.table.setCellWidget(row, line_pos, edit)
- edit.textChanged.connect(
- lambda: self.emit_plot_coordinates(x_pos, y_pos, coordinate_reference, color)
- )
-
- def wipe_motor_map_coordinates(self):
- """Wipe the motor map coordinates."""
- try:
- self.ui.table.itemChanged.disconnect() # Disconnect all previous connections
- except TypeError:
- print("No previous connections to disconnect")
- self.ui.table.setRowCount(0)
- reference_tags = ["Individual", "Start", "Stop"]
- for reference_tag in reference_tags:
- self.plot_coordinates_signal.emit([], reference_tag, "green")
-
- def handle_move_button_click(self, x_pos: int, y_pos: int) -> None:
- """
- Handle the move button click.
- Args:
- x_pos(int): X position of the coordinate.
- y_pos(int): Y position of the coordinate.
- """
- button = self.sender()
- row = self.ui.table.indexAt(button.pos()).row()
-
- x = self.get_coordinate(row, x_pos)
- y = self.get_coordinate(row, y_pos)
- self.move_motor(x, y)
-
- def emit_plot_coordinates(self, x_pos: float, y_pos: float, reference_tag: str, color: str):
- """
- Emit the coordinates to be plotted.
- Args:
- x_pos(float): X position of the coordinate.
- y_pos(float): Y position of the coordinate.
- reference_tag(str): Reference tag of the coordinate.
- color(str): Color of the coordinate.
- """
- print(
- f"Emitting plot coordinates: x_pos={x_pos}, y_pos={y_pos}, reference_tag={reference_tag}, color={color}"
- )
- coordinates = []
- for row in range(self.ui.table.rowCount()):
- show = self.ui.table.cellWidget(row, 0).isChecked()
- x = self.get_coordinate(row, x_pos)
- y = self.get_coordinate(row, y_pos)
-
- coordinates.append((x, y, show)) # (x, y, show_flag)
- self.plot_coordinates_signal.emit(coordinates, reference_tag, color)
-
- def get_coordinate(self, row: int, column: int) -> float:
- """
- Helper function to get the coordinate from the table QLineEdit cells.
- Args:
- row(int): Row of the table.
- column(int): Column of the table.
- Returns:
- float: Value of the coordinate.
- """
- edit = self.ui.table.cellWidget(row, column)
- value = float(edit.text()) if edit and edit.text() != "" else None
- if value:
- return value
-
- def delete_selected_row(self):
- """Delete the selected row from the table."""
- selected_rows = self.ui.table.selectionModel().selectedRows()
- for row in selected_rows:
- self.ui.table.removeRow(row.row())
- if self.ui.comboBox_mode.currentText() == "Start/Stop":
- self.emit_plot_coordinates(x_pos=4, y_pos=5, reference_tag="Start", color="blue")
- self.emit_plot_coordinates(x_pos=6, y_pos=7, reference_tag="Stop", color="red")
- self.is_next_entry_end = False
- elif self.ui.comboBox_mode.currentText() == "Individual":
- self.emit_plot_coordinates(x_pos=3, y_pos=4, reference_tag="Individual", color="green")
-
- def resize_table_auto(self):
- """Resize the table to fit the contents."""
- if self.ui.checkBox_resize_auto.isChecked():
- self.ui.table.resizeColumnsToContents()
-
- def move_motor(self, x: float, y: float) -> None:
- """
- Move the motor to the target coordinates.
- Args:
- x(float): Target x coordinate.
- y(float): Target y coordinate.
- """
- self.motor_thread.move_absolute(self.motor_x, self.motor_y, (x, y))
-
- @pyqtSlot(str, str)
- def change_motors(self, motor_x: str, motor_y: str) -> None:
- """
- Change the active motors and update config.
- Can be connected to the selected_motors_signal from MotorControlSelection.
- Args:
- motor_x(str): New motor X to be controlled.
- motor_y(str): New motor Y to be controlled.
- """
- self.motor_x = motor_x
- self.motor_y = motor_y
- self.config["motor_control"]["motor_x"] = motor_x
- self.config["motor_control"]["motor_y"] = motor_y
-
- @pyqtSlot(int)
- def set_precision(self, precision: int) -> None:
- """
- Set the precision of the coordinates.
- Args:
- precision(int): Precision of the coordinates.
- """
- self.precision = precision
- self.config["motor_control"]["precision"] = precision
diff --git a/bec_widgets/widgets/motor_control/motor_table/motor_table.ui b/bec_widgets/widgets/motor_control/motor_table/motor_table.ui
deleted file mode 100644
index 52aa059a..00000000
--- a/bec_widgets/widgets/motor_control/motor_table/motor_table.ui
+++ /dev/null
@@ -1,113 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 676
- 667
-
-
-
- Motor Coordinates Table
-
-
- -
-
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Resize Auto
-
-
- true
-
-
-
- -
-
-
- false
-
-
- Edit Custom Column
-
-
-
- -
-
-
- Entries Mode:
-
-
-
- -
-
-
- true
-
-
-
-
- Individual
-
-
- -
-
- Start/Stop
-
-
-
-
-
-
- -
-
-
- Qt::SolidLine
-
-
-
- -
-
-
-
-
-
- false
-
-
- Import CSV
-
-
-
- -
-
-
- false
-
-
- Export CSV
-
-
-
-
-
-
-
-
-
-
diff --git a/bec_widgets/widgets/motor_control/movement_absolute/__init__.py b/bec_widgets/widgets/motor_control/movement_absolute/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py b/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py
deleted file mode 100644
index 72f6a7af..00000000
--- a/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.py
+++ /dev/null
@@ -1,159 +0,0 @@
-import os
-
-from qtpy import uic
-from qtpy.QtCore import Signal as pyqtSignal
-from qtpy.QtCore import Slot as pyqtSlot
-from qtpy.QtWidgets import QWidget
-
-from bec_widgets.utils import UILoader
-from bec_widgets.widgets.motor_control.motor_control import MotorControlErrors, MotorControlWidget
-
-
-class MotorControlAbsolute(MotorControlWidget):
- """
- Widget for controlling the motors to absolute coordinates.
-
- Signals:
- coordinates_signal (pyqtSignal(tuple)): Signal to emit the coordinates.
- Slots:
- change_motors (pyqtSlot): Slot to change the active motors.
- enable_motor_controls (pyqtSlot(bool)): Slot to enable/disable the motor controls.
- """
-
- coordinates_signal = pyqtSignal(tuple)
-
- def _load_ui(self):
- """Load the UI from the .ui file."""
- current_path = os.path.dirname(__file__)
- self.ui = UILoader().load_ui(os.path.join(current_path, "movement_absolute.ui"), self)
-
- def _init_ui(self):
- """Initialize the UI."""
-
- # Check if there are any motors connected
- if self.motor_x is None or self.motor_y is None:
- self.ui.motorControl_absolute.setEnabled(False)
- return
-
- # Move to absolute coordinates
- self.ui.pushButton_go_absolute.clicked.connect(
- lambda: self.move_motor_absolute(
- self.ui.spinBox_absolute_x.value(), self.ui.spinBox_absolute_y.value()
- )
- )
-
- self.ui.pushButton_set.clicked.connect(self.save_absolute_coordinates)
- self.ui.pushButton_save.clicked.connect(self.save_current_coordinates)
- self.ui.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
-
- # Enable/Disable GUI
- self.motor_thread.lock_gui.connect(self.enable_motor_controls)
-
- # Error messages
- self.motor_thread.motor_error.connect(
- lambda error: MotorControlErrors.display_error_message(error)
- )
-
- # Keyboard shortcuts
- self._init_keyboard_shortcuts()
-
- @pyqtSlot(dict)
- def on_config_update(self, config: dict) -> None:
- """Update config dict"""
- self.config = config
-
- # Get motor names
- self.motor_x, self.motor_y = (
- self.config["motor_control"]["motor_x"],
- self.config["motor_control"]["motor_y"],
- )
-
- # Update step precision
- self.precision = self.config["motor_control"]["precision"]
-
- self._init_ui()
-
- @pyqtSlot(bool)
- def enable_motor_controls(self, enable: bool) -> None:
- """
- Enable or disable the motor controls.
- Args:
- enable(bool): True to enable, False to disable.
- """
-
- # Disable or enable all controls within the motorControl_absolute group box
- for widget in self.ui.motorControl_absolute.findChildren(QWidget):
- widget.setEnabled(enable)
-
- # Enable the pushButton_stop if the motor is moving
- self.ui.pushButton_stop.setEnabled(True)
-
- @pyqtSlot(str, str)
- def change_motors(self, motor_x: str, motor_y: str):
- """
- Change the active motors and update config.
- Can be connected to the selected_motors_signal from MotorControlSelection.
- Args:
- motor_x(str): New motor X to be controlled.
- motor_y(str): New motor Y to be controlled.
- """
- self.motor_x = motor_x
- self.motor_y = motor_y
- self.config["motor_control"]["motor_x"] = motor_x
- self.config["motor_control"]["motor_y"] = motor_y
-
- @pyqtSlot(int)
- def set_precision(self, precision: int) -> None:
- """
- Set the precision of the coordinates.
- Args:
- precision(int): Precision of the coordinates.
- """
- self.precision = precision
- self.config["motor_control"]["precision"] = precision
- self.ui.spinBox_absolute_x.setDecimals(precision)
- self.ui.spinBox_absolute_y.setDecimals(precision)
-
- def move_motor_absolute(self, x: float, y: float) -> None:
- """
- Move the motor to the target coordinates.
- Args:
- x(float): Target x coordinate.
- y(float): Target y coordinate.
- """
- # self._enable_motor_controls(False)
- target_coordinates = (x, y)
- self.motor_thread.move_absolute(self.motor_x, self.motor_y, target_coordinates)
- if self.ui.checkBox_save_with_go.isChecked():
- self.save_absolute_coordinates()
-
- def _init_keyboard_shortcuts(self):
- """Initialize the keyboard shortcuts."""
- # Go absolute button
- self.ui.pushButton_go_absolute.setShortcut("Ctrl+G")
- self.ui.pushButton_go_absolute.setToolTip("Ctrl+G")
-
- # Set absolute coordinates
- self.ui.pushButton_set.setShortcut("Ctrl+D")
- self.ui.pushButton_set.setToolTip("Ctrl+D")
-
- # Save Current coordinates
- self.ui.pushButton_save.setShortcut("Ctrl+S")
- self.ui.pushButton_save.setToolTip("Ctrl+S")
-
- # Stop Button
- self.ui.pushButton_stop.setShortcut("Ctrl+X")
- self.ui.pushButton_stop.setToolTip("Ctrl+X")
-
- def save_absolute_coordinates(self):
- """Emit the setup coordinates from the spinboxes"""
-
- x, y = round(self.ui.spinBox_absolute_x.value(), self.precision), round(
- self.ui.spinBox_absolute_y.value(), self.precision
- )
- self.coordinates_signal.emit((x, y))
-
- def save_current_coordinates(self):
- """Emit the current coordinates from the motor thread"""
- x, y = self.motor_thread.get_coordinates(self.motor_x, self.motor_y)
- self.coordinates_signal.emit((round(x, self.precision), round(y, self.precision)))
diff --git a/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.ui b/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.ui
deleted file mode 100644
index ea4ec863..00000000
--- a/bec_widgets/widgets/motor_control/movement_absolute/movement_absolute.ui
+++ /dev/null
@@ -1,149 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 285
- 220
-
-
-
-
- 285
- 220
-
-
-
-
- 285
- 220
-
-
-
- Move Movement Absolute
-
-
- -
-
-
-
- 261
- 195
-
-
-
-
- 261
- 195
-
-
-
- Move Movement Absolute
-
-
-
-
-
-
- Save position with Go
-
-
-
- -
-
-
-
-
-
- Qt::AlignCenter
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- Qt::AlignCenter
-
-
- -500.000000000000000
-
-
- 500.000000000000000
-
-
- 0.100000000000000
-
-
-
- -
-
-
- Y
-
-
- Qt::AlignCenter
-
-
-
- -
-
-
- X
-
-
- Qt::AlignCenter
-
-
-
-
-
- -
-
-
-
-
-
- Save
-
-
-
- -
-
-
- Set
-
-
-
- -
-
-
- Go
-
-
-
-
-
- -
-
-
- Stop Movement
-
-
-
-
-
-
-
-
-
-
-
diff --git a/bec_widgets/widgets/motor_control/movement_relative/__init__.py b/bec_widgets/widgets/motor_control/movement_relative/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/motor_control/movement_relative/movement_relative.py b/bec_widgets/widgets/motor_control/movement_relative/movement_relative.py
deleted file mode 100644
index 80a60ae6..00000000
--- a/bec_widgets/widgets/motor_control/movement_relative/movement_relative.py
+++ /dev/null
@@ -1,230 +0,0 @@
-import os
-
-from qtpy import uic
-from qtpy.QtCore import Qt
-from qtpy.QtCore import Signal as pyqtSignal
-from qtpy.QtCore import Slot as pyqtSlot
-from qtpy.QtGui import QKeySequence
-from qtpy.QtWidgets import QDoubleSpinBox, QShortcut, QWidget
-
-from bec_widgets.utils import UILoader
-from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
-
-
-class MotorControlRelative(MotorControlWidget):
- """
- Widget for controlling the motors to relative coordinates.
-
- Signals:
- precision_signal (pyqtSignal): Signal to emit the precision of the coordinates.
- Slots:
- change_motors (pyqtSlot(str,str)): Slot to change the active motors.
- enable_motor_controls (pyqtSlot): Slot to enable/disable the motor controls.
- """
-
- precision_signal = pyqtSignal(int)
-
- def _load_ui(self):
- """Load the UI from the .ui file."""
- # Loading UI
- current_path = os.path.dirname(__file__)
- self.ui = UILoader().load_ui(os.path.join(current_path, "movement_relative.ui"), self)
-
- def _init_ui(self):
- """Initialize the UI."""
- self._init_ui_motor_control()
- self._init_keyboard_shortcuts()
-
- @pyqtSlot(dict)
- def on_config_update(self, config: dict) -> None:
- """
- Update config dict
- Args:
- config(dict): New config dict
- """
- self.config = config
-
- # Get motor names
- self.motor_x, self.motor_y = (
- self.config["motor_control"]["motor_x"],
- self.config["motor_control"]["motor_y"],
- )
-
- # Update step precision
- self.precision = self.config["motor_control"]["precision"]
- self.ui.spinBox_precision.setValue(self.precision)
-
- # Update step sizes
- self.ui.spinBox_step_x.setValue(self.config["motor_control"]["step_size_x"])
- self.ui.spinBox_step_y.setValue(self.config["motor_control"]["step_size_y"])
-
- # Checkboxes for keyboard shortcuts and x/y step size link
- self.ui.checkBox_same_xy.setChecked(self.config["motor_control"]["step_x_y_same"])
- self.ui.checkBox_enableArrows.setChecked(self.config["motor_control"]["move_with_arrows"])
-
- self._init_ui()
-
- def _init_ui_motor_control(self) -> None:
- """Initialize the motor control elements"""
-
- # Connect checkbox and spinBoxes
- self.ui.checkBox_same_xy.stateChanged.connect(self._sync_step_sizes)
- self.ui.spinBox_step_x.valueChanged.connect(self._update_step_size_x)
- self.ui.spinBox_step_y.valueChanged.connect(self._update_step_size_y)
-
- self.ui.toolButton_right.clicked.connect(
- lambda: self.move_motor_relative(self.motor_x, "x", 1)
- )
- self.ui.toolButton_left.clicked.connect(
- lambda: self.move_motor_relative(self.motor_x, "x", -1)
- )
- self.ui.toolButton_up.clicked.connect(
- lambda: self.move_motor_relative(self.motor_y, "y", 1)
- )
- self.ui.toolButton_down.clicked.connect(
- lambda: self.move_motor_relative(self.motor_y, "y", -1)
- )
-
- # Switch between key shortcuts active
- self.ui.checkBox_enableArrows.stateChanged.connect(self._update_arrow_key_shortcuts)
- self._update_arrow_key_shortcuts()
-
- # Enable/Disable GUI
- self.motor_thread.lock_gui.connect(self.enable_motor_controls)
-
- # Precision update
- self.ui.spinBox_precision.valueChanged.connect(lambda x: self._update_precision(x))
-
- # Error messages
- self.motor_thread.motor_error.connect(
- lambda error: MotorControlErrors.display_error_message(error)
- )
-
- # Stop Button
- self.ui.pushButton_stop.clicked.connect(self.motor_thread.stop_movement)
-
- def _init_keyboard_shortcuts(self) -> None:
- """Initialize the keyboard shortcuts"""
-
- # Increase/decrease step size for X motor
- increase_x_shortcut = QShortcut(QKeySequence("Ctrl+A"), self)
- decrease_x_shortcut = QShortcut(QKeySequence("Ctrl+Z"), self)
- increase_x_shortcut.activated.connect(
- lambda: self._change_step_size(self.ui.spinBox_step_x, 2)
- )
- decrease_x_shortcut.activated.connect(
- lambda: self._change_step_size(self.ui.spinBox_step_x, 0.5)
- )
- self.ui.spinBox_step_x.setToolTip("Increase step size: Ctrl+A\nDecrease step size: Ctrl+Z")
-
- # Increase/decrease step size for Y motor
- increase_y_shortcut = QShortcut(QKeySequence("Alt+A"), self)
- decrease_y_shortcut = QShortcut(QKeySequence("Alt+Z"), self)
- increase_y_shortcut.activated.connect(
- lambda: self._change_step_size(self.ui.spinBox_step_y, 2)
- )
- decrease_y_shortcut.activated.connect(
- lambda: self._change_step_size(self.ui.spinBox_step_y, 0.5)
- )
- self.ui.spinBox_step_y.setToolTip("Increase step size: Alt+A\nDecrease step size: Alt+Z")
-
- # Stop Button
- self.ui.pushButton_stop.setShortcut("Ctrl+X")
- self.ui.pushButton_stop.setToolTip("Ctrl+X")
-
- def _update_arrow_key_shortcuts(self) -> None:
- """Update the arrow key shortcuts based on the checkbox state."""
- if self.ui.checkBox_enableArrows.isChecked():
- # Set the arrow key shortcuts for motor movement
- self.ui.toolButton_right.setShortcut(Qt.Key_Right)
- self.ui.toolButton_left.setShortcut(Qt.Key_Left)
- self.ui.toolButton_up.setShortcut(Qt.Key_Up)
- self.ui.toolButton_down.setShortcut(Qt.Key_Down)
- else:
- # Clear the shortcuts
- self.ui.toolButton_right.setShortcut("")
- self.ui.toolButton_left.setShortcut("")
- self.ui.toolButton_up.setShortcut("")
- self.ui.toolButton_down.setShortcut("")
-
- def _update_precision(self, precision: int) -> None:
- """
- Update the precision of the coordinates.
- Args:
- precision(int): Precision of the coordinates.
- """
- self.ui.spinBox_step_x.setDecimals(precision)
- self.ui.spinBox_step_y.setDecimals(precision)
- self.precision_signal.emit(precision)
-
- def _change_step_size(self, spinBox: QDoubleSpinBox, factor: float) -> None:
- """
- Change the step size of the spinbox.
- Args:
- spinBox(QDoubleSpinBox): Spinbox to change the step size.
- factor(float): Factor to change the step size.
- """
- old_step = spinBox.value()
- new_step = old_step * factor
- spinBox.setValue(new_step)
-
- def _sync_step_sizes(self):
- """Sync step sizes based on checkbox state."""
- if self.ui.checkBox_same_xy.isChecked():
- value = self.ui.spinBox_step_x.value()
- self.ui.spinBox_step_y.setValue(value)
-
- def _update_step_size_x(self):
- """Update step size for x if checkbox is checked."""
- if self.ui.checkBox_same_xy.isChecked():
- value = self.ui.spinBox_step_x.value()
- self.ui.spinBox_step_y.setValue(value)
-
- def _update_step_size_y(self):
- """Update step size for y if checkbox is checked."""
- if self.ui.checkBox_same_xy.isChecked():
- value = self.ui.spinBox_step_y.value()
- self.ui.spinBox_step_x.setValue(value)
-
- @pyqtSlot(str, str)
- def change_motors(self, motor_x: str, motor_y: str):
- """
- Change the active motors and update config.
- Can be connected to the selected_motors_signal from MotorControlSelection.
- Args:
- motor_x(str): New motor X to be controlled.
- motor_y(str): New motor Y to be controlled.
- """
- self.motor_x = motor_x
- self.motor_y = motor_y
- self.config["motor_control"]["motor_x"] = motor_x
- self.config["motor_control"]["motor_y"] = motor_y
-
- @pyqtSlot(bool)
- def enable_motor_controls(self, disable: bool) -> None:
- """
- Enable or disable the motor controls.
- Args:
- disable(bool): True to disable, False to enable.
- """
-
- # Disable or enable all controls within the motorControl_absolute group box
- for widget in self.ui.motorControl.findChildren(QWidget):
- widget.setEnabled(disable)
-
- # Enable the pushButton_stop if the motor is moving
- self.ui.pushButton_stop.setEnabled(True)
-
- def move_motor_relative(self, motor, axis: str, direction: int) -> None:
- """
- Move the motor relative to the current position.
- Args:
- motor: Motor to move.
- axis(str): Axis to move.
- direction(int): Direction to move. 1 for positive, -1 for negative.
- """
- if axis == "x":
- step = direction * self.ui.spinBox_step_x.value()
- elif axis == "y":
- step = direction * self.ui.spinBox_step_y.value()
- self.motor_thread.move_relative(motor, step)
diff --git a/bec_widgets/widgets/motor_control/movement_relative/movement_relative.ui b/bec_widgets/widgets/motor_control/movement_relative/movement_relative.ui
deleted file mode 100644
index 78fed89b..00000000
--- a/bec_widgets/widgets/motor_control/movement_relative/movement_relative.ui
+++ /dev/null
@@ -1,298 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 285
- 405
-
-
-
-
- 285
- 405
-
-
-
- Motor Control Relative
-
-
- -
-
-
-
- 261
- 394
-
-
-
- Motor Control Relative
-
-
-
-
-
-
- Move with arrow keys
-
-
-
- -
-
-
- Step [X] = Step [Y]
-
-
-
- -
-
-
-
-
-
-
- 111
- 19
-
-
-
- Step [Y]
-
-
-
- -
-
-
-
- 111
- 19
-
-
-
- Decimal
-
-
-
- -
-
-
-
- 110
- 19
-
-
-
- Qt::AlignCenter
-
-
- 0.000000000000000
-
-
- 99.000000000000000
-
-
- 0.100000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
-
- 111
- 19
-
-
-
- Step [X]
-
-
-
- -
-
-
-
- 110
- 19
-
-
-
- Qt::AlignCenter
-
-
- 0.000000000000000
-
-
- 99.000000000000000
-
-
- 0.100000000000000
-
-
- 1.000000000000000
-
-
-
- -
-
-
-
- 110
- 19
-
-
-
- Qt::AlignCenter
-
-
- 8
-
-
- 2
-
-
-
-
-
- -
-
-
- QLayout::SetDefaultConstraint
-
-
-
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::UpArrow
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::DownArrow
-
-
-
- -
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::LeftArrow
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
- -
-
-
-
- 26
- 26
-
-
-
- ...
-
-
- Qt::RightArrow
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Qt::Vertical
-
-
-
- 20
- 40
-
-
-
-
-
-
- -
-
-
- Stop Movement
-
-
-
-
-
-
-
-
-
-
-
diff --git a/bec_widgets/widgets/motor_control/selection/__init__.py b/bec_widgets/widgets/motor_control/selection/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/bec_widgets/widgets/motor_control/selection/selection.py b/bec_widgets/widgets/motor_control/selection/selection.py
deleted file mode 100644
index 1f48c1a1..00000000
--- a/bec_widgets/widgets/motor_control/selection/selection.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# pylint: disable = no-name-in-module,missing-module-docstring
-import os
-
-from qtpy import uic
-from qtpy.QtCore import Signal as pyqtSignal
-from qtpy.QtCore import Slot as pyqtSlot
-from qtpy.QtWidgets import QComboBox
-
-from bec_widgets.widgets.motor_control.motor_control import MotorControlWidget
-
-
-class MotorControlSelection(MotorControlWidget):
- """
- Widget for selecting the motors to control.
-
- Signals:
- selected_motors_signal (pyqtSignal(str,str)): Signal to emit the selected motors.
- Slots:
- get_available_motors (pyqtSlot): Slot to populate the available motors in the combo boxes and set the index based on the configuration.
- enable_motor_controls (pyqtSlot(bool)): Slot to enable/disable the motor controls GUI.
- on_config_update (pyqtSlot(dict)): Slot to update the config dict.
- """
-
- selected_motors_signal = pyqtSignal(str, str)
-
- def _load_ui(self):
- """Load the UI from the .ui file."""
- current_path = os.path.dirname(__file__)
- uic.loadUi(os.path.join(current_path, "selection.ui"), self)
-
- def _init_ui(self):
- """Initialize the UI."""
- # Lock GUI while motors are moving
- self.motor_thread.lock_gui.connect(self.enable_motor_controls)
-
- self.pushButton_connecMotors.clicked.connect(self.select_motor)
- self.get_available_motors()
-
- # Connect change signals to change color
- self.comboBox_motor_x.currentIndexChanged.connect(
- lambda: self.set_combobox_style(self.comboBox_motor_x, "#ffa700")
- )
- self.comboBox_motor_y.currentIndexChanged.connect(
- lambda: self.set_combobox_style(self.comboBox_motor_y, "#ffa700")
- )
-
- @pyqtSlot(dict)
- def on_config_update(self, config: dict) -> None:
- """
- Update config dict
- Args:
- config(dict): New config dict
- """
- self.config = config
-
- # Get motor names
- self.motor_x, self.motor_y = (
- self.config["motor_control"]["motor_x"],
- self.config["motor_control"]["motor_y"],
- )
-
- self._init_ui()
-
- @pyqtSlot(bool)
- def enable_motor_controls(self, enable: bool) -> None:
- """
- Enable or disable the motor controls.
- Args:
- enable(bool): True to enable, False to disable.
- """
- self.motorSelection.setEnabled(enable)
-
- @pyqtSlot()
- def get_available_motors(self) -> None:
- """
- Slot to populate the available motors in the combo boxes and set the index based on the configuration.
- """
- # Get all available motors
- self.motor_list = self.motor_thread.get_all_motors_names()
-
- # Populate the combo boxes
- self.comboBox_motor_x.addItems(self.motor_list)
- self.comboBox_motor_y.addItems(self.motor_list)
-
- # Set the index based on the config if provided
- if self.config:
- index_x = self.comboBox_motor_x.findText(self.motor_x)
- index_y = self.comboBox_motor_y.findText(self.motor_y)
- self.comboBox_motor_x.setCurrentIndex(index_x if index_x != -1 else 0)
- self.comboBox_motor_y.setCurrentIndex(index_y if index_y != -1 else 0)
-
- def set_combobox_style(self, combobox, color: str) -> None:
- """
- Set the combobox style to a specific color.
- Args:
- combobox(QComboBox): Combobox to change the color.
- color(str): Color to set the combobox to.
- """
- combobox.setStyleSheet(f"QComboBox {{ background-color: {color}; }}")
-
- def select_motor(self):
- """Emit the selected motors"""
- motor_x = self.comboBox_motor_x.currentText()
- motor_y = self.comboBox_motor_y.currentText()
-
- # Reset the combobox color to normal after selection
- self.set_combobox_style(self.comboBox_motor_x, "")
- self.set_combobox_style(self.comboBox_motor_y, "")
-
- self.selected_motors_signal.emit(motor_x, motor_y)
diff --git a/bec_widgets/widgets/motor_control/selection/selection.ui b/bec_widgets/widgets/motor_control/selection/selection.ui
deleted file mode 100644
index 406363df..00000000
--- a/bec_widgets/widgets/motor_control/selection/selection.ui
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
- Form
-
-
-
- 0
- 0
- 285
- 156
-
-
-
-
- 285
- 156
-
-
-
- Motor Control Selection
-
-
- -
-
-
-
- 261
- 145
-
-
-
- Motor Selection
-
-
-
-
-
-
- Motor X
-
-
-
- -
-
-
- -
-
-
- Motor Y
-
-
-
- -
-
-
- Connect Motors
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/unit_tests/test_motor_control.py b/tests/unit_tests/test_motor_control.py
deleted file mode 100644
index c0bcec3a..00000000
--- a/tests/unit_tests/test_motor_control.py
+++ /dev/null
@@ -1,588 +0,0 @@
-# pylint: disable = no-name-in-module,missing-class-docstring, missing-module-docstring
-from unittest.mock import MagicMock, patch
-
-import pytest
-from bec_lib.devicemanager import DeviceContainer
-
-from bec_widgets.examples import (
- MotorControlApp,
- MotorControlMap,
- MotorControlPanel,
- MotorControlPanelAbsolute,
- MotorControlPanelRelative,
-)
-from bec_widgets.widgets.motor_control.motor_control import MotorActions, MotorThread
-from bec_widgets.widgets.motor_control.motor_table.motor_table import MotorCoordinateTable
-from bec_widgets.widgets.motor_control.movement_absolute.movement_absolute import (
- MotorControlAbsolute,
-)
-from bec_widgets.widgets.motor_control.movement_relative.movement_relative import (
- MotorControlRelative,
-)
-from bec_widgets.widgets.motor_control.selection.selection import MotorControlSelection
-
-from .client_mocks import mocked_client
-
-CONFIG_DEFAULT = {
- "motor_control": {
- "motor_x": "samx",
- "motor_y": "samy",
- "step_size_x": 3,
- "step_size_y": 3,
- "precision": 4,
- "step_x_y_same": False,
- "move_with_arrows": False,
- },
- "plot_settings": {
- "colormap": "Greys",
- "scatter_size": 5,
- "max_points": 1000,
- "num_dim_points": 100,
- "precision": 2,
- "num_columns": 1,
- "background_value": 25,
- },
- "motors": [
- {
- "plot_name": "Motor Map",
- "x_label": "Motor X",
- "y_label": "Motor Y",
- "signals": {
- "x": [{"name": "samx", "entry": "samx"}],
- "y": [{"name": "samy", "entry": "samy"}],
- },
- }
- ],
-}
-
-
-#######################################################
-# Motor Thread
-#######################################################
-@pytest.fixture
-def motor_thread(mocked_client):
- """Fixture for MotorThread with a mocked client."""
- return MotorThread(client=mocked_client)
-
-
-def test_motor_thread_initialization(mocked_client):
- motor_thread = MotorThread(client=mocked_client)
- assert motor_thread.client == mocked_client
- assert isinstance(motor_thread.dev, DeviceContainer)
-
-
-def test_get_all_motors_names(mocked_client):
- motor_thread = MotorThread(client=mocked_client)
- motor_names = motor_thread.get_all_motors_names()
- expected_names = ["samx", "samy", "samz", "aptrx", "aptry"]
- assert sorted(motor_names) == sorted(expected_names)
- assert all(name in motor_names for name in expected_names)
- assert len(motor_names) == len(expected_names) # Ensure only these motors are returned
-
-
-def test_get_coordinates(mocked_client):
- motor_thread = MotorThread(client=mocked_client)
- motor_x, motor_y = "samx", "samy"
- x, y = motor_thread.get_coordinates(motor_x, motor_y)
-
- assert x == mocked_client.device_manager.devices[motor_x].readback.get()
- assert y == mocked_client.device_manager.devices[motor_y].readback.get()
-
-
-def test_move_motor_absolute_by_run(mocked_client):
- motor_thread = MotorThread(client=mocked_client)
- motor_thread.motor_x = "samx"
- motor_thread.motor_y = "samy"
- motor_thread.target_coordinates = (5.0, -3.0)
- motor_thread.action = MotorActions.MOVE_ABSOLUTE
- motor_thread.run()
-
- assert mocked_client.device_manager.devices["samx"].read_value == 5.0
- assert mocked_client.device_manager.devices["samy"].read_value == -3.0
-
-
-def test_move_motor_relative_by_run(mocked_client):
- motor_thread = MotorThread(client=mocked_client)
-
- initial_value = motor_thread.dev["samx"].read()["samx"]["value"]
- move_value = 2.0
- expected_value = initial_value + move_value
- motor_thread.motor = "samx"
- motor_thread.value = move_value
- motor_thread.action = MotorActions.MOVE_RELATIVE
- motor_thread.run()
-
- assert mocked_client.device_manager.devices["samx"].read_value == expected_value
-
-
-def test_motor_thread_move_absolute(motor_thread):
- motor_x = "samx"
- motor_y = "samy"
- target_x = 5.0
- target_y = -3.0
-
- motor_thread.move_absolute(motor_x, motor_y, (target_x, target_y))
- motor_thread.wait()
-
- assert motor_thread.dev[motor_x].read()["samx"]["value"] == target_x
- assert motor_thread.dev[motor_y].read()["samy"]["value"] == target_y
-
-
-def test_motor_thread_move_relative(motor_thread):
- motor_name = "samx"
- move_value = 2.0
-
- initial_value = motor_thread.dev[motor_name].read()["samx"]["value"]
- motor_thread.move_relative(motor_name, move_value)
- motor_thread.wait()
-
- expected_value = initial_value + move_value
- assert motor_thread.dev[motor_name].read()["samx"]["value"] == expected_value
-
-
-#######################################################
-# Motor Control Widgets - MotorControlSelection
-#######################################################
-@pytest.fixture(scope="function")
-def motor_selection_widget(qtbot, mocked_client, motor_thread):
- """Fixture for creating a MotorControlSelection widget with a mocked client."""
- widget = MotorControlSelection(
- client=mocked_client, config=CONFIG_DEFAULT, motor_thread=motor_thread
- )
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- return widget
-
-
-def test_initialization_and_population(motor_selection_widget):
- assert motor_selection_widget.comboBox_motor_x.count() == 5
- assert motor_selection_widget.comboBox_motor_x.itemText(0) == "samx"
- assert motor_selection_widget.comboBox_motor_y.itemText(1) == "samy"
- assert motor_selection_widget.comboBox_motor_y.itemText(2) == "samz"
- assert motor_selection_widget.comboBox_motor_x.itemText(3) == "aptrx"
- assert motor_selection_widget.comboBox_motor_y.itemText(4) == "aptry"
-
-
-def test_selection_and_signal_emission(motor_selection_widget):
- # Connect signal to a custom slot to capture the emitted values
- emitted_values = []
-
- def capture_emitted_values(motor_x, motor_y):
- emitted_values.append((motor_x, motor_y))
-
- motor_selection_widget.selected_motors_signal.connect(capture_emitted_values)
-
- # Select motors
- motor_selection_widget.comboBox_motor_x.setCurrentIndex(0) # Select 'samx'
- motor_selection_widget.comboBox_motor_y.setCurrentIndex(1) # Select 'samy'
- motor_selection_widget.pushButton_connecMotors.click() # Emit the signal
-
- # Verify the emitted signal
- assert emitted_values == [
- ("samx", "samy")
- ], "The emitted signal did not match the expected values"
-
-
-def test_configuration_update(motor_selection_widget):
- new_config = {"motor_control": {"motor_x": "samy", "motor_y": "samx"}}
- motor_selection_widget.on_config_update(new_config)
- assert motor_selection_widget.comboBox_motor_x.currentText() == "samy"
- assert motor_selection_widget.comboBox_motor_y.currentText() == "samx"
-
-
-def test_enable_motor_controls(motor_selection_widget):
- motor_selection_widget.enable_motor_controls(False)
- assert not motor_selection_widget.comboBox_motor_x.isEnabled()
- assert not motor_selection_widget.comboBox_motor_y.isEnabled()
-
- motor_selection_widget.enable_motor_controls(True)
- assert motor_selection_widget.comboBox_motor_x.isEnabled()
- assert motor_selection_widget.comboBox_motor_y.isEnabled()
-
-
-#######################################################
-# Motor Control Widgets - MotorControlAbsolute
-#######################################################
-
-
-@pytest.fixture(scope="function")
-def motor_absolute_widget(qtbot, mocked_client, motor_thread):
- widget = MotorControlAbsolute(
- client=mocked_client, config=CONFIG_DEFAULT, motor_thread=motor_thread
- )
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- return widget
-
-
-def test_absolute_initialization(motor_absolute_widget):
- motor_absolute_widget.change_motors("samx", "samy")
- motor_absolute_widget.on_config_update(CONFIG_DEFAULT)
- assert motor_absolute_widget.motor_x == "samx", "Motor X not initialized correctly"
- assert motor_absolute_widget.motor_y == "samy", "Motor Y not initialized correctly"
- assert motor_absolute_widget.precision == CONFIG_DEFAULT["motor_control"]["precision"]
-
-
-def test_absolute_save_current_coordinates(motor_absolute_widget):
- motor_x_value = motor_absolute_widget.client.device_manager.devices["samx"].read()["samx"][
- "value"
- ]
- motor_y_value = motor_absolute_widget.client.device_manager.devices["samy"].read()["samy"][
- "value"
- ]
- motor_absolute_widget.change_motors("samx", "samy")
-
- emitted_coordinates = []
-
- def capture_emit(x_y):
- emitted_coordinates.append(x_y)
-
- motor_absolute_widget.coordinates_signal.connect(capture_emit)
-
- # Trigger saving current coordinates
- motor_absolute_widget.ui.pushButton_save.click()
-
- assert emitted_coordinates == [(motor_x_value, motor_y_value)]
-
-
-def test_absolute_set_absolute_coordinates(motor_absolute_widget):
- motor_absolute_widget.ui.spinBox_absolute_x.setValue(5)
- motor_absolute_widget.ui.spinBox_absolute_y.setValue(10)
-
- # Connect to the coordinates_signal to capture emitted values
- emitted_values = []
-
- def capture_coordinates(x_y):
- emitted_values.append(x_y)
-
- motor_absolute_widget.coordinates_signal.connect(capture_coordinates)
-
- # Simulate button click for absolute movement
- motor_absolute_widget.ui.pushButton_set.click()
-
- assert emitted_values == [(5, 10)]
-
-
-def test_absolute_go_absolute_coordinates(motor_absolute_widget):
- motor_absolute_widget.change_motors("samx", "samy")
-
- motor_absolute_widget.ui.spinBox_absolute_x.setValue(5)
- motor_absolute_widget.ui.spinBox_absolute_y.setValue(10)
-
- with patch(
- "bec_widgets.widgets.motor_control.motor_control.MotorThread.move_absolute",
- new_callable=MagicMock,
- ) as mock_move_absolute:
- motor_absolute_widget.ui.pushButton_go_absolute.click()
- mock_move_absolute.assert_called_once_with("samx", "samy", (5, 10))
-
-
-def test_change_motor_absolute(motor_absolute_widget):
- motor_absolute_widget.change_motors("aptrx", "aptry")
-
- assert motor_absolute_widget.motor_x == "aptrx"
- assert motor_absolute_widget.motor_y == "aptry"
-
- motor_absolute_widget.change_motors("samx", "samy")
-
- assert motor_absolute_widget.motor_x == "samx"
- assert motor_absolute_widget.motor_y == "samy"
-
-
-def test_set_precision(motor_absolute_widget):
- motor_absolute_widget.on_config_update(CONFIG_DEFAULT)
- motor_absolute_widget.set_precision(2)
-
- assert motor_absolute_widget.ui.spinBox_absolute_x.decimals() == 2
- assert motor_absolute_widget.ui.spinBox_absolute_y.decimals() == 2
-
-
-#######################################################
-# Motor Control Widgets - MotorControlRelative
-#######################################################
-@pytest.fixture(scope="function")
-def motor_relative_widget(qtbot, mocked_client, motor_thread):
- widget = MotorControlRelative(
- client=mocked_client, config=CONFIG_DEFAULT, motor_thread=motor_thread
- )
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- return widget
-
-
-def test_initialization_and_config_update(motor_relative_widget):
- motor_relative_widget.on_config_update(CONFIG_DEFAULT)
-
- assert motor_relative_widget.motor_x == CONFIG_DEFAULT["motor_control"]["motor_x"]
- assert motor_relative_widget.motor_y == CONFIG_DEFAULT["motor_control"]["motor_y"]
- assert motor_relative_widget.precision == CONFIG_DEFAULT["motor_control"]["precision"]
-
- # Simulate a configuration update
- new_config = {
- "motor_control": {
- "motor_x": "new_motor_x",
- "motor_y": "new_motor_y",
- "precision": 2,
- "step_size_x": 5,
- "step_size_y": 5,
- "step_x_y_same": True,
- "move_with_arrows": True,
- }
- }
- motor_relative_widget.on_config_update(new_config)
-
- assert motor_relative_widget.motor_x == "new_motor_x"
- assert motor_relative_widget.motor_y == "new_motor_y"
- assert motor_relative_widget.precision == 2
-
-
-def test_move_motor_relative(motor_relative_widget):
- motor_relative_widget.on_config_update(CONFIG_DEFAULT)
- # Set step sizes
- motor_relative_widget.ui.spinBox_step_x.setValue(1)
- motor_relative_widget.ui.spinBox_step_y.setValue(1)
-
- # Mock the move_relative method
- motor_relative_widget.motor_thread.move_relative = MagicMock()
-
- # Simulate button clicks
- motor_relative_widget.ui.toolButton_right.click()
- motor_relative_widget.motor_thread.move_relative.assert_called_with(
- motor_relative_widget.motor_x, 1
- )
-
- motor_relative_widget.ui.toolButton_left.click()
- motor_relative_widget.motor_thread.move_relative.assert_called_with(
- motor_relative_widget.motor_x, -1
- )
-
- motor_relative_widget.ui.toolButton_up.click()
- motor_relative_widget.motor_thread.move_relative.assert_called_with(
- motor_relative_widget.motor_y, 1
- )
-
- motor_relative_widget.ui.toolButton_down.click()
- motor_relative_widget.motor_thread.move_relative.assert_called_with(
- motor_relative_widget.motor_y, -1
- )
-
-
-def test_precision_update(motor_relative_widget):
- # Capture emitted precision values
- emitted_values = []
-
- def capture_precision(precision):
- emitted_values.append(precision)
-
- motor_relative_widget.precision_signal.connect(capture_precision)
-
- # Update precision
- motor_relative_widget.ui.spinBox_precision.setValue(1)
-
- assert emitted_values == [1]
- assert motor_relative_widget.ui.spinBox_step_x.decimals() == 1
- assert motor_relative_widget.ui.spinBox_step_y.decimals() == 1
-
-
-def test_sync_step_sizes(motor_relative_widget):
- motor_relative_widget.on_config_update(CONFIG_DEFAULT)
- motor_relative_widget.ui.checkBox_same_xy.setChecked(True)
-
- # Change step size for X
- motor_relative_widget.ui.spinBox_step_x.setValue(2)
-
- assert motor_relative_widget.ui.spinBox_step_y.value() == 2
-
-
-def test_change_motor_relative(motor_relative_widget):
- motor_relative_widget.on_config_update(CONFIG_DEFAULT)
- motor_relative_widget.change_motors("aptrx", "aptry")
-
- assert motor_relative_widget.motor_x == "aptrx"
- assert motor_relative_widget.motor_y == "aptry"
-
-
-#######################################################
-# Motor Control Widgets - MotorCoordinateTable
-#######################################################
-@pytest.fixture(scope="function")
-def motor_coordinate_table(qtbot, mocked_client, motor_thread):
- widget = MotorCoordinateTable(
- client=mocked_client, config=CONFIG_DEFAULT, motor_thread=motor_thread
- )
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- return widget
-
-
-def test_delete_selected_row(motor_coordinate_table):
- # Add a coordinate
- motor_coordinate_table.add_coordinate((1.0, 2.0))
- motor_coordinate_table.add_coordinate((3.0, 4.0))
-
- # Select the row
- motor_coordinate_table.ui.table.selectRow(0)
-
- # Delete the selected row
- motor_coordinate_table.delete_selected_row()
- assert motor_coordinate_table.ui.table.rowCount() == 1
-
-
-def test_add_coordinate_and_table_update(motor_coordinate_table):
- # Disable Warning message popups for test
- motor_coordinate_table.warning_message = False
-
- # Add coordinate in Individual mode
- motor_coordinate_table.add_coordinate((1.0, 2.0))
- assert motor_coordinate_table.ui.table.rowCount() == 1
-
- # Check if the coordinates match
- x_item_individual = motor_coordinate_table.ui.table.cellWidget(
- 0, 3
- ) # Assuming X is in column 3
- y_item_individual = motor_coordinate_table.ui.table.cellWidget(
- 0, 4
- ) # Assuming Y is in column 4
- assert float(x_item_individual.text()) == 1.0
- assert float(y_item_individual.text()) == 2.0
-
- # Switch to Start/Stop and add coordinates
- motor_coordinate_table.ui.comboBox_mode.setCurrentIndex(1) # Switch mode
-
- motor_coordinate_table.add_coordinate((3.0, 4.0))
- motor_coordinate_table.add_coordinate((5.0, 6.0))
- assert motor_coordinate_table.ui.table.rowCount() == 1
-
-
-def test_plot_coordinates_signal(motor_coordinate_table):
- # Connect to the signal
- def signal_emitted(coordinates, reference_tag, color):
- nonlocal received
- received = True
- assert len(coordinates) == 1 # Assuming one coordinate was added
- assert reference_tag in ["Individual", "Start", "Stop"]
- assert color in ["green", "blue", "red"]
-
- received = False
- motor_coordinate_table.plot_coordinates_signal.connect(signal_emitted)
-
- # Add a coordinate and check signal
- motor_coordinate_table.add_coordinate((1.0, 2.0))
- assert received
-
-
-# def test_move_motor_action(motor_coordinate_table,qtbot):#TODO enable again after table refactor
-# # Add a coordinate
-# motor_coordinate_table.add_coordinate((1.0, 2.0))
-#
-# # Mock the motor thread move_absolute function
-# motor_coordinate_table.motor_thread.move_absolute = MagicMock()
-#
-# # Trigger the move action
-# move_button = motor_coordinate_table.table.cellWidget(0, 1)
-# move_button.click()
-#
-# motor_coordinate_table.motor_thread.move_absolute.assert_called_with(
-# motor_coordinate_table.motor_x, motor_coordinate_table.motor_y, (1.0, 2.0)
-# )
-
-
-def test_plot_coordinates_signal_individual(motor_coordinate_table, qtbot):
- motor_coordinate_table.warning_message = False
- motor_coordinate_table.set_precision(3)
- motor_coordinate_table.ui.comboBox_mode.setCurrentIndex(0)
-
- # This list will store the signals emitted during the test
- emitted_signals = []
-
- def signal_emitted(coordinates, reference_tag, color):
- emitted_signals.append((coordinates, reference_tag, color))
-
- motor_coordinate_table.plot_coordinates_signal.connect(signal_emitted)
-
- # Add new coordinates
- motor_coordinate_table.add_coordinate((1.0, 2.0))
- qtbot.wait(100)
-
- # Verify the signals
- assert len(emitted_signals) > 0, "No signals were emitted."
-
- for coordinates, reference_tag, color in emitted_signals:
- assert len(coordinates) > 0, "Coordinates list is empty."
- assert reference_tag == "Individual"
- assert color == "green"
- assert motor_coordinate_table.ui.table.cellWidget(0, 3).text() == "1.000"
- assert motor_coordinate_table.ui.table.cellWidget(0, 4).text() == "2.000"
-
-
-#######################################################
-# MotorControl examples compilations
-#######################################################
-@pytest.fixture(scope="function")
-def motor_app(qtbot, mocked_client):
- widget = MotorControlApp(config=CONFIG_DEFAULT, client=mocked_client)
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- yield widget
-
-
-def test_motor_app_initialization(motor_app):
- assert isinstance(motor_app, MotorControlApp)
- assert motor_app.client is not None
- assert motor_app.config == CONFIG_DEFAULT
-
-
-@pytest.fixture(scope="function")
-def motor_control_map(qtbot, mocked_client):
- widget = MotorControlMap(config=CONFIG_DEFAULT, client=mocked_client)
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- yield widget
-
-
-def test_motor_control_map_initialization(motor_control_map):
- assert isinstance(motor_control_map, MotorControlMap)
- assert motor_control_map.client is not None
- assert motor_control_map.config == CONFIG_DEFAULT
-
-
-@pytest.fixture(scope="function")
-def motor_control_panel(qtbot, mocked_client):
- widget = MotorControlPanel(config=CONFIG_DEFAULT, client=mocked_client)
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- yield widget
-
-
-def test_motor_control_panel_initialization(motor_control_panel):
- assert isinstance(motor_control_panel, MotorControlPanel)
- assert motor_control_panel.client is not None
- assert motor_control_panel.config == CONFIG_DEFAULT
-
-
-@pytest.fixture(scope="function")
-def motor_control_panel_absolute(qtbot, mocked_client):
- widget = MotorControlPanelAbsolute(config=CONFIG_DEFAULT, client=mocked_client)
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- yield widget
-
-
-def test_motor_control_panel_absolute_initialization(motor_control_panel_absolute):
- assert isinstance(motor_control_panel_absolute, MotorControlPanelAbsolute)
- assert motor_control_panel_absolute.client is not None
- assert motor_control_panel_absolute.config == CONFIG_DEFAULT
-
-
-@pytest.fixture(scope="function")
-def motor_control_panel_relative(qtbot, mocked_client):
- widget = MotorControlPanelRelative(config=CONFIG_DEFAULT, client=mocked_client)
- qtbot.addWidget(widget)
- qtbot.waitExposed(widget)
- yield widget
-
-
-def test_motor_control_panel_relative_initialization(motor_control_panel_relative):
- assert isinstance(motor_control_panel_relative, MotorControlPanelRelative)
- assert motor_control_panel_relative.client is not None
- assert motor_control_panel_relative.config == CONFIG_DEFAULT