From eb9fad82fd5a7d441afd48e591dab66096feaaa1 Mon Sep 17 00:00:00 2001 From: wyzula-jan Date: Sun, 1 Mar 2026 18:20:24 +0100 Subject: [PATCH] fix(bec_widgets): client RPC api generation --- csaxs_bec/bec_widgets/widgets/client.py | 85 ++------------- .../bec_widgets/widgets/xray_eye/x_ray_eye.py | 103 +++++++++++------- 2 files changed, 75 insertions(+), 113 deletions(-) diff --git a/csaxs_bec/bec_widgets/widgets/client.py b/csaxs_bec/bec_widgets/widgets/client.py index ec2d37c..dd54e1d 100644 --- a/csaxs_bec/bec_widgets/widgets/client.py +++ b/csaxs_bec/bec_widgets/widgets/client.py @@ -13,69 +13,10 @@ logger = bec_logger.logger _Widgets = { - "OmnyAlignment": "OmnyAlignment", "XRayEye": "XRayEye", } -class OmnyAlignment(RPCBase): - @property - @rpc_call - def enable_live_view(self): - """ - None - """ - - @enable_live_view.setter - @rpc_call - def enable_live_view(self): - """ - None - """ - - @property - @rpc_call - def user_message(self): - """ - None - """ - - @user_message.setter - @rpc_call - def user_message(self): - """ - None - """ - - @property - @rpc_call - def sample_name(self): - """ - None - """ - - @sample_name.setter - @rpc_call - def sample_name(self): - """ - None - """ - - @property - @rpc_call - def enable_move_buttons(self): - """ - None - """ - - @enable_move_buttons.setter - @rpc_call - def enable_move_buttons(self): - """ - None - """ - - class XRayEye(RPCBase): @rpc_call def active_roi(self) -> "BaseROI | None": @@ -83,20 +24,6 @@ class XRayEye(RPCBase): Return the currently active ROI, or None if no ROI is active. """ - @property - @rpc_call - def enable_live_view(self): - """ - Get or set the live view enabled state. - """ - - @enable_live_view.setter - @rpc_call - def enable_live_view(self): - """ - Get or set the live view enabled state. - """ - @property @rpc_call def user_message(self): @@ -146,3 +73,15 @@ class XRayEye2DControl(RPCBase): """ Cleanup the BECConnector """ + + @rpc_call + def attach(self): + """ + None + """ + + @rpc_call + def detach(self): + """ + Detach the widget from its parent dock widget (if widget is in the dock), making it a floating widget. + """ 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 2ba48e7..67bb2fc 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 @@ -33,46 +33,48 @@ class XRayEye2DControl(BECWidget, QWidget): self.get_bec_shortcuts() self._step_size = step_size self.root_layout = QGridLayout(self) - self.setStyleSheet(""" + 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.move_up_button.setIcon(material_icon("keyboard_double_arrow_up")) 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.move_up_tweak_button.setIcon(material_icon("keyboard_arrow_up")) 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.move_left_button.setIcon(material_icon("keyboard_double_arrow_left")) 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.move_left_tweak_button.setIcon(material_icon("keyboard_arrow_left")) 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.move_right_button.setIcon(material_icon("keyboard_double_arrow_right")) 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.move_right_tweak_button.setIcon(material_icon("keyboard_arrow_right")) 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.move_down_button.setIcon(material_icon("keyboard_double_arrow_down")) 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.move_down_tweak_button.setIcon(material_icon("keyboard_arrow_down")) self.root_layout.addWidget(self.move_down_tweak_button, 3, 2) # Connections @@ -124,8 +126,15 @@ 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", + "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): @@ -136,7 +145,9 @@ 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() self.resize(800, 600) QTimer.singleShot(0, self._init_gui_trigger) @@ -145,7 +156,9 @@ class XRayEye(BECWidget, QWidget): 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.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) # #TODO Invert y axis to match logic of LabView GUI @@ -156,8 +169,9 @@ 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) @@ -230,7 +244,9 @@ 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): @@ -248,12 +264,14 @@ 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'] + """Checks one of the possible motors for flomni, omny and lamni setup.""" + 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}") ################################################################################ @@ -341,7 +359,7 @@ class XRayEye(BECWidget, QWidget): @SafeSlot(bool, bool) def on_tomo_angle_readback(self, data: dict, meta: dict): - #TODO implement if needed + # TODO implement if needed print(f"data: {data}") print(f"meta: {meta}") @@ -355,25 +373,25 @@ class XRayEye(BECWidget, QWidget): meta(dict): metadata from device """ - 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') + 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)) # Signals from epics gui device # send message - user_message = signals.get("omny_xray_gui_send_message").get('value') + user_message = signals.get("omny_xray_gui_send_message").get("value") self.user_message = user_message # sample name - sample_message = signals.get("omny_xray_gui_sample_name").get('value') + sample_message = signals.get("omny_xray_gui_sample_name").get("value") self.sample_name = sample_message # enable frame acquisition - update_frame_acq = signals.get("omny_xray_gui_update_frame_acq").get('value') + update_frame_acq = signals.get("omny_xray_gui_update_frame_acq").get("value") self.on_live_view_enabled(bool(update_frame_acq)) # enable submit button - enable_submit_button = signals.get("omny_xray_gui_submit").get('value') + enable_submit_button = signals.get("omny_xray_gui_submit").get("value") self.enable_submit_button(enable_submit_button) @SafeSlot() @@ -383,35 +401,40 @@ class XRayEye(BECWidget, QWidget): logger.warning("No active ROI") return roi_coordinates = self.roi_manager.single_active_roi.get_coordinates() - roi_center_x = roi_coordinates['center_x'] - roi_center_y = roi_coordinates['center_y'] + 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): - roi_width = roi_coordinates['width'] - roi_height = roi_coordinates['height'] + 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'] + roi_width = roi_coordinates["diameter"] + roi_height = roi_coordinates["radius"] else: logger.warning("Unsupported ROI type for submit action.") return - print(f"current roi: x:{roi_center_x}, y:{roi_center_y}, w:{roi_width},h:{roi_height}") #TODO remove when will be not needed for debugging + print( + f"current roi: x:{roi_center_x}, y:{roi_center_y}, w:{roi_width},h:{roi_height}" + ) # TODO remove when will be not needed for debugging # submit roi coordinates - step = int(self.dev.omny_xray_gui.step.read().get("omny_xray_gui_step").get('value')) + 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) self.dev.omny_xray_gui.submit.set(1) - + def cleanup(self): """Cleanup connections on widget close -> disconnect slots and stop live mode of camera.""" - self.bec_dispatcher.disconnect_slot(self.device_updates, MessageEndpoints.device_readback("omny_xray_gui")) - getattr(self.dev,CAMERA[0]).live_mode = False + self.bec_dispatcher.disconnect_slot( + self.device_updates, MessageEndpoints.device_readback("omny_xray_gui") + ) + getattr(self.dev, CAMERA[0]).live_mode = False super().cleanup() + if __name__ == "__main__": import sys