From 08c49b8f51d5d27fb51f79bdb44d1e8ce8dd8090 Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Wed, 22 Oct 2025 14:23:50 +0200 Subject: [PATCH] wip formatting --- .../bec_widgets/widgets/xray_eye/x_ray_eye.py | 177 ++++++++++-------- 1 file changed, 94 insertions(+), 83 deletions(-) diff --git a/csaxs_bec/bec_widgets/widgets/xray_eye/x_ray_eye.py b/csaxs_bec/bec_widgets/widgets/xray_eye/x_ray_eye.py index 61f6f1e..969a7cd 100644 --- a/csaxs_bec/bec_widgets/widgets/xray_eye/x_ray_eye.py +++ b/csaxs_bec/bec_widgets/widgets/xray_eye/x_ray_eye.py @@ -1,107 +1,119 @@ from __future__ import annotations -from PySide6.QtWidgets import QToolButton, QSpinBox -from qtpy.QtCore import Qt, QTimer -from qtpy.QtWidgets import QDoubleSpinBox -from qtpy.QtWidgets import QPushButton -from qtpy.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QGridLayout, QLabel, QLineEdit, QSizePolicy, QFrame - from bec_lib import bec_logger +from bec_lib.endpoints import MessageEndpoints from bec_qthemes import material_icon -from bec_widgets import BECWidget, SafeSlot, SafeProperty -from bec_widgets.widgets.control.device_control.positioner_box import PositionerBox2D +from bec_widgets import BECWidget, SafeProperty, SafeSlot from bec_widgets.widgets.plots.image.image import Image from bec_widgets.widgets.plots.image.setting_widgets.image_roi_tree import ROIPropertyTree -from bec_widgets.widgets.plots.roi.image_roi import BaseROI, RectangularROI, CircularROI, EllipticalROI +from bec_widgets.widgets.plots.roi.image_roi import BaseROI, CircularROI, RectangularROI from bec_widgets.widgets.utility.toggle.toggle import ToggleSwitch - -from bec_lib.endpoints import MessageEndpoints +from qtpy.QtCore import Qt, QTimer +from qtpy.QtWidgets import ( + QFrame, + QGridLayout, + QHBoxLayout, + QLabel, + QLineEdit, + QPushButton, + QSizePolicy, + QSpinBox, + QToolButton, + QVBoxLayout, + QWidget, +) logger = bec_logger.logger -#TODO replace with actual device names, these are just placeholders from simulation framework +# TODO replace with actual device names, these are just placeholders from simulation framework DEVICE_HORIZONTAL = "samx" DEVICE_VERTICAL = "samy" -CAMERA = ("cam_flomni_overview","preview") +CAMERA = ("cam_flomni_overview", "preview") -class XRayEye2DControl(BECWidget,QWidget): - def __init__(self, parent=None,step_size:int=100,*arg,**kwargs): - super().__init__(parent=parent,*arg,**kwargs) + +class XRayEye2DControl(BECWidget, QWidget): + def __init__(self, parent=None, step_size: int = 100, *arg, **kwargs): + super().__init__(parent=parent, *arg, **kwargs) self.get_bec_shortcuts() self._step_size = step_size self.root_layout = QGridLayout(self) - + self.setStyleSheet(""" + QToolButton { + border: 1px solid; + border-radius: 4px; + } + """) # Up self.move_up_button = QToolButton(parent=self) self.move_up_button.setIcon(material_icon('keyboard_double_arrow_up')) - self.root_layout.addWidget(self.move_up_button,0,2) + self.root_layout.addWidget(self.move_up_button, 0, 2) # Up tweak button self.move_up_tweak_button = QToolButton(parent=self) self.move_up_tweak_button.setIcon(material_icon('keyboard_arrow_up')) - self.root_layout.addWidget(self.move_up_tweak_button,1,2) + self.root_layout.addWidget(self.move_up_tweak_button, 1, 2) # Left self.move_left_button = QToolButton(parent=self) self.move_left_button.setIcon(material_icon('keyboard_double_arrow_left')) - self.root_layout.addWidget(self.move_left_button,2,0) + self.root_layout.addWidget(self.move_left_button, 2, 0) # Left tweak button self.move_left_tweak_button = QToolButton(parent=self) self.move_left_tweak_button.setIcon(material_icon('keyboard_arrow_left')) - self.root_layout.addWidget(self.move_left_tweak_button,2,1) + self.root_layout.addWidget(self.move_left_tweak_button, 2, 1) # Right self.move_right_button = QToolButton(parent=self) self.move_right_button.setIcon(material_icon('keyboard_double_arrow_right')) - self.root_layout.addWidget(self.move_right_button,2,4) + self.root_layout.addWidget(self.move_right_button, 2, 4) # Right tweak button self.move_right_tweak_button = QToolButton(parent=self) self.move_right_tweak_button.setIcon(material_icon('keyboard_arrow_right')) - self.root_layout.addWidget(self.move_right_tweak_button,2,3) + self.root_layout.addWidget(self.move_right_tweak_button, 2, 3) # Down self.move_down_button = QToolButton(parent=self) self.move_down_button.setIcon(material_icon('keyboard_double_arrow_down')) - self.root_layout.addWidget(self.move_down_button,4,2) + self.root_layout.addWidget(self.move_down_button, 4, 2) # Down tweak button self.move_down_tweak_button = QToolButton(parent=self) self.move_down_tweak_button.setIcon(material_icon('keyboard_arrow_down')) - self.root_layout.addWidget(self.move_down_tweak_button,3,2) + self.root_layout.addWidget(self.move_down_tweak_button, 3, 2) # Connections - self.move_up_button.clicked.connect(lambda : self.move("up",tweak=False)) - self.move_up_tweak_button.clicked.connect(lambda : self.move("up",tweak=True)) - self.move_down_button.clicked.connect(lambda : self.move("down",tweak=False)) - self.move_down_tweak_button.clicked.connect(lambda : self.move("down",tweak=True)) - self.move_left_button.clicked.connect(lambda : self.move("left",tweak=False)) - self.move_left_tweak_button.clicked.connect(lambda : self.move("left",tweak=True)) - self.move_right_button.clicked.connect(lambda : self.move("right",tweak=False)) - self.move_right_tweak_button.clicked.connect(lambda : self.move("right",tweak=True)) + self.move_up_button.clicked.connect(lambda: self.move("up", tweak=False)) + self.move_up_tweak_button.clicked.connect(lambda: self.move("up", tweak=True)) + self.move_down_button.clicked.connect(lambda: self.move("down", tweak=False)) + self.move_down_tweak_button.clicked.connect(lambda: self.move("down", tweak=True)) + self.move_left_button.clicked.connect(lambda: self.move("left", tweak=False)) + self.move_left_tweak_button.clicked.connect(lambda: self.move("left", tweak=True)) + self.move_right_button.clicked.connect(lambda: self.move("right", tweak=False)) + self.move_right_tweak_button.clicked.connect(lambda: self.move("right", tweak=True)) @SafeProperty(int) - def step_size(self)->int: + def step_size(self) -> int: return self._step_size @step_size.setter - def step_size(self,step_size:int): + def step_size(self, step_size: int): self._step_size = step_size @SafeSlot(bool) - def enable_controls_hor(self,enable:bool): + def enable_controls_hor(self, enable: bool): self.move_left_button.setEnabled(enable) self.move_left_tweak_button.setEnabled(enable) self.move_right_button.setEnabled(enable) self.move_right_tweak_button.setEnabled(enable) @SafeSlot(bool) - def enable_controls_ver(self,enable:bool): + def enable_controls_ver(self, enable: bool): self.move_up_button.setEnabled(enable) self.move_up_tweak_button.setEnabled(enable) self.move_down_button.setEnabled(enable) self.move_down_tweak_button.setEnabled(enable) - def move(self,direction:str,tweak:bool=False): + def move(self, direction: str, tweak: bool = False): step = self._step_size if tweak: - step = int(self._step_size/5) + step = int(self._step_size / 5) if direction == "up": self.dev.omny_xray_gui.mvy.set(step) elif direction == "down": @@ -115,7 +127,8 @@ class XRayEye2DControl(BECWidget,QWidget): class XRayEye(BECWidget, QWidget): - USER_ACCESS = ["active_roi","enable_live_view", "enable_live_view.setter", "user_message", "user_message.setter","sample_name", "sample_name.setter", "enable_move_buttons", "enable_move_buttons.setter"] + USER_ACCESS = ["active_roi", "enable_live_view", "enable_live_view.setter", "user_message", "user_message.setter", + "sample_name", "sample_name.setter", "enable_move_buttons", "enable_move_buttons.setter"] PLUGIN = True def __init__(self, parent=None, **kwargs): @@ -126,17 +139,18 @@ class XRayEye(BECWidget, QWidget): self._make_connections() # Connection to redis endpoints - self.bec_dispatcher.connect_slot(self.device_updates,MessageEndpoints.device_readback("omny_xray_gui")) + self.bec_dispatcher.connect_slot(self.device_updates, MessageEndpoints.device_readback("omny_xray_gui")) self.connect_motors() - QTimer.singleShot(0,self._init_gui_trigger) - + self.resize(800, 600) + QTimer.singleShot(0, self._init_gui_trigger) + def _init_ui(self): self.core_layout = QHBoxLayout(self) self.image = Image(parent=self) - self.image.enable_toolbar = False # Disable default toolbar to not allow to user set anything - self.image.inner_axes = False # Disable inner axes to maximize image area - self.image.plot_item.vb.invertY(True) # Invert y axis to match logic of LabView GUI + self.image.enable_toolbar = False # Disable default toolbar to not allow to user set anything + self.image.inner_axes = False # Disable inner axes to maximize image area + self.image.plot_item.vb.invertY(True) # Invert y axis to match logic of LabView GUI # Control panel on the right: vertical layout inside a fixed-width widget self.control_panel = QWidget(parent=self) @@ -145,7 +159,8 @@ class XRayEye(BECWidget, QWidget): self.control_panel_layout.setSpacing(10) # ROI toolbar + Live toggle (header row) - self.roi_manager = ROIPropertyTree(parent=self, image_widget=self.image, compact=True, compact_orientation="horizontal") + self.roi_manager = ROIPropertyTree(parent=self, image_widget=self.image, compact=True, + compact_orientation="horizontal") header_row = QHBoxLayout() header_row.setContentsMargins(0, 0, 0, 0) header_row.setSpacing(8) @@ -163,14 +178,14 @@ class XRayEye(BECWidget, QWidget): # 2D Positioner (fixed size) self.motor_control_2d = XRayEye2DControl(parent=self) - self.control_panel_layout.addWidget(self.motor_control_2d, 0, Qt.AlignTop | Qt.AlignRight) + self.control_panel_layout.addWidget(self.motor_control_2d, 0, Qt.AlignTop | Qt.AlignCenter) # separator self.control_panel_layout.addWidget(self._create_separator()) # Step size label step_size_form = QGridLayout() - #General Step size + # General Step size self.step_size = QSpinBox(parent=self) self.step_size.setRange(10, 100) self.step_size.setSingleStep(10) @@ -178,10 +193,10 @@ class XRayEye(BECWidget, QWidget): # Submit button self.submit_button = QPushButton("Submit", parent=self) # Add to layout form - step_size_form.addWidget(QLabel("Horizontal", parent=self),0,0) + step_size_form.addWidget(QLabel("Horizontal", parent=self), 0, 0) step_size_form.addWidget(self.step_size, 0, 1) - step_size_form.addWidget(QLabel("Vertical", parent=self),1,0) - step_size_form.addWidget(self.submit_button,2,0,1,2) + step_size_form.addWidget(QLabel("Vertical", parent=self), 1, 0) + step_size_form.addWidget(self.submit_button, 2, 0, 1, 2) # Add form to control panel self.control_panel_layout.addLayout(step_size_form) @@ -193,12 +208,12 @@ class XRayEye(BECWidget, QWidget): form = QGridLayout() self.sample_name_line_edit = QLineEdit(parent=self) self.sample_name_line_edit.setReadOnly(True) - form.addWidget(QLabel("Sample", parent=self),0,0) - form.addWidget(self.sample_name_line_edit,0,1) + form.addWidget(QLabel("Sample", parent=self), 0, 0) + form.addWidget(self.sample_name_line_edit, 0, 1) self.message_line_edit = QLineEdit(parent=self) self.message_line_edit.setReadOnly(True) - form.addWidget(QLabel("Message", parent=self),1,0) - form.addWidget(self.message_line_edit,1,1) + form.addWidget(QLabel("Message", parent=self), 1, 0) + form.addWidget(self.message_line_edit, 1, 1) self.control_panel_layout.addLayout(form) # Fix panel width and allow vertical expansion @@ -218,7 +233,7 @@ class XRayEye(BECWidget, QWidget): # Make connections self.live_preview_toggle.enabled.connect(self.on_live_view_enabled) - self.step_size.valueChanged.connect(lambda x: self.motor_control_2d.setProperty("step_size",x)) + self.step_size.valueChanged.connect(lambda x: self.motor_control_2d.setProperty("step_size", x)) self.submit_button.clicked.connect(self.submit) def _create_separator(self): @@ -237,11 +252,11 @@ class XRayEye(BECWidget, QWidget): def connect_motors(self): """ Checks one of the possible motors for flomni, omny and lamni setup.""" - possible_motors = ['osamroy','lsamrot','fsamroy'] + possible_motors = ['osamroy', 'lsamrot', 'fsamroy'] for motor in possible_motors: if motor in self.dev: - self.bec_dispatcher.connect_slot(self.on_tomo_angle_readback,MessageEndpoints.device_readback(motor)) + self.bec_dispatcher.connect_slot(self.on_tomo_angle_readback, MessageEndpoints.device_readback(motor)) logger.info(f"Succesfully connected to {motor}") ################################################################################ @@ -280,11 +295,10 @@ class XRayEye(BECWidget, QWidget): def enable_move_buttons(self, enabled: bool): self.motor_control_2d.setEnabled(enabled) - def active_roi(self)->BaseROI|None: + def active_roi(self) -> BaseROI | None: """Return the currently active ROI, or None if no ROI is active.""" return self.roi_manager.single_active_roi - ################################################################################ # Slots ported from the original OmnyAlignment, can be adjusted as needed ################################################################################ @@ -299,7 +313,6 @@ class XRayEye(BECWidget, QWidget): logger.info(f"Active ROI coordinates: {roi.get_coordinates()}") return roi.get_coordinates() - @SafeSlot(bool) def on_live_view_enabled(self, enabled: bool): logger.info(f"Live view is enabled: {enabled}") @@ -314,8 +327,8 @@ class XRayEye(BECWidget, QWidget): self.live_preview_toggle.checked = enabled self.live_preview_toggle.blockSignals(False) - @SafeSlot(bool,bool) - def on_motors_enable(self,x_enable:bool,y_enable:bool): + @SafeSlot(bool, bool) + def on_motors_enable(self, x_enable: bool, y_enable: bool): self.motor_control_2d.enable_controls_hor(x_enable) self.motor_control_2d.enable_controls_ver(y_enable) @@ -333,23 +346,22 @@ class XRayEye(BECWidget, QWidget): if enable == -1: self.submit_button.setEnabled(False) else: - self.submit_button.setEnabled(True) + self.submit_button.setEnabled(True) - @SafeSlot(bool,bool) - def on_tomo_angle_readback(self,data:dict,meta:dict): + @SafeSlot(bool, bool) + def on_tomo_angle_readback(self, data: dict, meta: dict): print(f"data: {data}") print(f"meta: {meta}") - @SafeSlot(dict,dict) - def device_updates(self,data:dict,meta:dict): + @SafeSlot(dict, dict) + def device_updates(self, data: dict, meta: dict): signals = data.get('signals') enable_live_preview = signals.get("omny_xray_gui_update_frame_acq").get('value') enable_x_motor = signals.get("omny_xray_gui_enable_mv_x").get('value') enable_y_motor = signals.get("omny_xray_gui_enable_mv_y").get('value') self.on_live_view_enabled(bool(enable_live_preview)) - self.on_motors_enable(bool(enable_x_motor),bool(enable_y_motor)) - + self.on_motors_enable(bool(enable_x_motor), bool(enable_y_motor)) # Signals from epics gui device # send message @@ -365,7 +377,6 @@ class XRayEye(BECWidget, QWidget): enable_submit_button = signals.get("omny_xray_gui_submit").get('value') self.enable_submit_button(enable_submit_button) - @SafeSlot() def submit(self): """Execute submit action by submit button.""" @@ -376,32 +387,32 @@ class XRayEye(BECWidget, QWidget): roi_center_x = roi_coordinates['center_x'] roi_center_y = roi_coordinates['center_y'] # Case of rectangular ROI - if isinstance(self.roi_manager.single_active_roi,RectangularROI): + if isinstance(self.roi_manager.single_active_roi, RectangularROI): roi_width = roi_coordinates['width'] roi_height = roi_coordinates['height'] - elif isinstance(self.roi_manager.single_active_roi,CircularROI): - roi_width = roi_coordinates['diameter'] - roi_height =roi_coordinates['radius'] + elif isinstance(self.roi_manager.single_active_roi, CircularROI): + roi_width = roi_coordinates['diameter'] + roi_height = roi_coordinates['radius'] else: logger.warning("Unsupported ROI type for submit action.") return - + print(f"current roi: {roi_center_x},{roi_center_y}, {roi_width},{roi_height}") # submit roi coordinates step = int(self.dev.omny_xray_gui.step.read().get("omny_xray_gui_step").get('value')) - xval_x = getattr(self.dev.omny_xray_gui.xval_x,f"xval_x_{step}").set(roi_center_x) - xval_y = getattr(self.dev.omny_xray_gui.yval_y,f"yval_y_{step}").set(roi_center_y) - width_x = getattr(self.dev.omny_xray_gui.width_x,f"width_x_{step}").set(roi_width) - width_y = getattr(self.dev.omny_xray_gui.width_y,f"width_y_{step}").set(roi_height) + xval_x = getattr(self.dev.omny_xray_gui.xval_x, f"xval_x_{step}").set(roi_center_x) + xval_y = getattr(self.dev.omny_xray_gui.yval_y, f"yval_y_{step}").set(roi_center_y) + width_x = getattr(self.dev.omny_xray_gui.width_x, f"width_x_{step}").set(roi_width) + width_y = getattr(self.dev.omny_xray_gui.width_y, f"width_y_{step}").set(roi_height) self.dev.omny_xray_gui.submit.set(1) - if __name__ == "__main__": - import sys + from qtpy.QtWidgets import QApplication + app = QApplication(sys.argv) win = XRayEye()