wip formatting
This commit is contained in:
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user