diff --git a/mxcubeqt/bricks/aperture_brick.py b/mxcubeqt/bricks/aperture_brick.py index cc7f390b1..3daee4f32 100644 --- a/mxcubeqt/bricks/aperture_brick.py +++ b/mxcubeqt/bricks/aperture_brick.py @@ -134,7 +134,7 @@ def init_aperture(self): aperture_size_list = HWR.beamline.beam.aperture.get_diameter_size_list() self.aperture_diameter_combo.clear() for aperture_size in aperture_size_list: - self.aperture_diameter_combo.addItem("%d%s" % (aperture_size, unichr(956))) + self.aperture_diameter_combo.addItem("%s%s" % (aperture_size, unichr(956))) aperture_position_list = HWR.beamline.beam.aperture.get_position_list() self.aperture_position_combo.clear() diff --git a/mxcubeqt/bricks/desy/digital_zoom_brick.py b/mxcubeqt/bricks/desy/digital_zoom_brick.py index b60500da6..c61e306e8 100644 --- a/mxcubeqt/bricks/desy/digital_zoom_brick.py +++ b/mxcubeqt/bricks/desy/digital_zoom_brick.py @@ -30,7 +30,6 @@ class DigitalZoomBrick(BaseWidget): - STATE_COLORS = ( colors.LIGHT_YELLOW, # INITIALIZING colors.LIGHT_GREEN, # ON @@ -129,16 +128,15 @@ def setToolTip(self, name=None, state=None): self.label.setToolTip(tip) def motor_state_changed(self, state): - # self.positions_combo.setEnabled(self.motor_hwobj.is_ready()) if self.motor_hwobj.is_ready: colors.set_widget_color( - self.positions_combo, colors.LIGHT_GREEN, qt_import.QPalette.Button, + self.positions_combo, colors.LIGHT_GREEN, qt_import.QPalette.Button ) else: colors.set_widget_color( - self.positions_combo, colors.LIGHT_GRAY, qt_import.QPalette.Button, + self.positions_combo, colors.LIGHT_GRAY, qt_import.QPalette.Button ) # self.setToolTip(state=state) @@ -242,7 +240,6 @@ def position_selected(self, index): self.previous_position_button.setEnabled(index >= 0) def predefined_position_changed(self, position, offset): - if self.positions: for index, item in enumerate(self.positions): if position.name == item.name: diff --git a/mxcubeqt/bricks/desy/p11_deice_brick.py b/mxcubeqt/bricks/desy/p11_deice_brick.py deleted file mode 100644 index 029e8d981..000000000 --- a/mxcubeqt/bricks/desy/p11_deice_brick.py +++ /dev/null @@ -1,676 +0,0 @@ -# -# Project: MXCuBE -# https://github.com/mxcube -# -# This file is part of MXCuBE software. -# -# MXCuBE is free software: you can redistribute it and/or modify -# it under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# MXCuBE is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with MXCuBE. If not, see . - -import re - -from mxcubeqt.utils import colors, icons, qt_import -from mxcubeqt.base_components import BaseWidget - -from mxcubeqt.utils import colors, icons, qt_import -from mxcubeqt.bricks.proposal_brick import DuoStateBrick, ProposalGUIEvent -from mxcubecore import HardwareRepository as HWR -import logging -import os - -__category__ = "DESY" - - -class P11DeiceBrick(DuoStateBrick): - - STATES = { - "unknown": (colors.LIGHT_GRAY, True, True, False, False), - "disabled": (colors.LIGHT_GRAY, False, False, False, False), - "noperm": (colors.LIGHT_GRAY, False, False, False, False), - "error": (colors.LIGHT_RED, False, False, False, False), - "out": (colors.LIGHT_GREEN, True, False, False, True), - "closed": (colors.LIGHT_GREEN, True, True, False, True), - "moving": (colors.LIGHT_YELLOW, False, False, None, None), - "in": (colors.LIGHT_GREEN, False, True, True, False), - "opened": (colors.LIGHT_GREEN, True, True, True, False), - "automatic": (colors.WHITE, True, True, False, False), - } - - def __init__(self, *args): - BaseWidget.__init__(self, *args) - - # Hardware objects ---------------------------------------------------- - self.wrapper_hwobj = None - - # Internal values ----------------------------------------------------- - self.__expertMode = False - - # Properties ---------------------------------------------------------- - self.add_property("mnemonic", "string", "") - self.add_property("forceNoControl", "boolean", False) - self.add_property("expertModeControlOnly", "boolean", False) - self.add_property("icons", "string", "") - self.add_property("in", "string", "in") - self.add_property("out", "string", "out") - self.add_property("setin", "string", "Set in") - self.add_property("setout", "string", "Set out") - self.add_property("username", "string", "") - - # Signals ------------------------------------------------------------- - - # Slots --------------------------------------------------------------- - self.define_slot("allowControl", ()) - - # Graphic elements ---------------------------------------------------- - self.main_gbox = qt_import.QGroupBox("none", self) - self.main_gbox.setAlignment(qt_import.Qt.AlignCenter) - self.state_ledit = qt_import.QLineEdit("unknown", self.main_gbox) - - self.buttons_widget = qt_import.QWidget(self.main_gbox) - self.set_in_button = qt_import.QPushButton("Set in", self.buttons_widget) - self.set_in_button.setCheckable(True) - self.set_out_button = qt_import.QPushButton("Set out", self.buttons_widget) - self.set_out_button.setCheckable(True) - - # Layout -------------------------------------------------------------- - _buttons_widget_hlayout = qt_import.QHBoxLayout(self.buttons_widget) - _buttons_widget_hlayout.addWidget(self.set_in_button) - _buttons_widget_hlayout.addWidget(self.set_out_button) - _buttons_widget_hlayout.setSpacing(0) - _buttons_widget_hlayout.setContentsMargins(0, 0, 0, 0) - - _main_gbox_vlayout = qt_import.QVBoxLayout(self.main_gbox) - _main_gbox_vlayout.addWidget(self.state_ledit) - _main_gbox_vlayout.addWidget(self.buttons_widget) - _main_gbox_vlayout.setSpacing(2) - _main_gbox_vlayout.setContentsMargins(4, 4, 4, 4) - - _main_vlayout = qt_import.QVBoxLayout(self) - _main_vlayout.addWidget(self.main_gbox) - _main_vlayout.setSpacing(0) - _main_vlayout.setContentsMargins(0, 0, 0, 0) - - # SizePolicies -------------------------------------------------------- - - # Qt signal/slot connections ------------------------------------------ - self.set_in_button.toggled.connect(self.set_in) - self.set_out_button.toggled.connect(self.set_out) - - # Other --------------------------------------------------------------- - self.state_ledit.setAlignment(qt_import.Qt.AlignCenter) - self.state_ledit.setToolTip("Shows the current control state") - self.state_ledit.setFrame(False) - bold_font = self.state_ledit.font() - bold_font.setBold(True) - self.state_ledit.setFont(bold_font) - self.state_ledit.setFixedHeight(24) - - self.set_in_button.setToolTip("Changes the control state") - self.set_out_button.setToolTip("Changes the control state") - - self.instance_synchronize("state_ledit") - - def setExpertMode(self, expert): - self.__expertMode = expert - self.buttons_widget.show() - - if not expert and self["expertModeControlOnly"]: - self.buttons_widget.hide() - - def set_in(self, state): - if state: - self.set_in_button.setEnabled(False) - self.wrapper_hwobj.setIn() - else: - self.set_in_button.blockSignals(True) - # self.set_in_button.setState(QtGui.QPushButton.On) - self.set_in_button.setDown(True) - self.set_in_button.blockSignals(False) - - def set_out(self, state): - if state: - self.set_out_button.setEnabled(False) - self.wrapper_hwobj.setOut() - else: - self.set_out_button.blockSignals(True) - self.set_out_button.setDown(False) - # self.set_out_button.setState(QtGui.QPushButton.On) - self.set_out_button.blockSignals(False) - - def updateLabel(self, label): - self.main_gbox.setTitle(label) - - def stateChanged(self, state, state_label=""): - self.setEnabled(True) - state = str(state) - try: - color = self.STATES[state][0] - except KeyError: - state = "unknown" - color = self.STATES[state][0] - if color is None: - color = colors.GROUP_BOX_GRAY - - colors.set_widget_color(self.state_ledit, color, qt_import.QPalette.Base) - # self.state_ledit.setPaletteBackgroundColor(QColor(color)) - if len(state_label) > 0: - self.state_ledit.setText("%s" % state_label) - else: - label_str = state - if state == "in": - prop_label = self["in"].strip() - if len(prop_label.strip()): - label_str = prop_label - if state == "out": - prop_label = self["out"].strip() - if prop_label: - label_str = prop_label - self.state_ledit.setText("%s" % label_str) - - if state in self.STATES: - in_enable = self.STATES[state][1] - out_enable = self.STATES[state][2] - else: - in_enable = False - out_enable = False - - self.set_in_button.setEnabled(in_enable) - self.set_out_button.setEnabled(out_enable) - - if state in self.STATES: - in_state = self.STATES[state][3] - out_state = self.STATES[state][4] - else: - in_state = True - out_state = False - if in_state is not None: - self.set_in_button.blockSignals(True) - self.set_in_button.setChecked(in_state) - self.set_in_button.blockSignals(False) - if out_state is not None: - self.set_out_button.blockSignals(True) - self.set_out_button.setChecked(out_state) - self.set_out_button.blockSignals(False) - - """ - if state=='in': - self.duoStateBrickMovingSignal.emit(False) - self.duoStateBrickInSignal.emit(True) - elif state=='out': - self.duoStateBrickMovingSignal.emit(False) - self.duoStateBrickOutSignal.emit(True) - elif state=='moving': - self.duoStateBrickMovingSignal.emit(True) - elif state=='error' or state=='unknown' or state=='disabled': - self.duoStateBrickMovingSignal.emit(False) - self.duoStateBrickInSignal.emit(False) - self.duoStateBrickOutSignal.emit(False) - """ - - def allowControl(self, enable): - if self["forceNoControl"]: - return - if enable: - self.buttons_widget.show() - else: - self.buttons_widget.hide() - - def property_changed(self, property_name, old_value, new_value): - if property_name == "mnemonic": - if self.wrapper_hwobj is not None: - self.wrapper_hwobj.duoStateChangedSignal.disconnect(self.stateChanged) - - h_obj = self.get_hardware_object(new_value) - if h_obj is not None: - self.wrapper_hwobj = WrapperHO(h_obj) - self.main_gbox.show() - - if self["username"] == "": - self["username"] = self.wrapper_hwobj.username - - help_text = self["setin"] + " the " + self["username"].lower() - self.set_in_button.setToolTip(help_text) - help_text = self["setout"] + " the " + self["username"].lower() - self.set_out_button.setToolTip(help_text) - self.main_gbox.setTitle(self["username"]) - self.wrapper_hwobj.duoStateChangedSignal.connect(self.stateChanged) - self.wrapper_hwobj.get_state() - else: - self.wrapper_hwobj = None - # self.main_gbox.hide() - elif property_name == "expertModeControlOnly": - if new_value: - if self.__expertMode: - self.buttons_widget.show() - else: - self.buttons_widget.hide() - else: - self.buttons_widget.show() - elif property_name == "forceNoControl": - if new_value: - self.buttons_widget.hide() - else: - self.buttons_widget.show() - elif property_name == "icons": - # w = self.fontMetrics().width("Set out") - icons_list = new_value.split() - try: - self.set_in_button.setIcon(icons.load_icon(icons_list[0])) - except IndexError: - self.set_in_button.setText(self["setin"]) - # self.set_in_button.setMinimumWidth(w) - try: - self.set_out_button.setIcon(icons.load_icon(icons_list[1])) - except IndexError: - self.set_out_button.setText(self["setout"]) - # self.set_out_button.setMinimumWidth(w) - - # elif property_name=='in': - # if self.wrapper_hwobj is not None: - # self.stateChanged(self.wrapper_hwobj.get_state()) - - # elif property_name=='out': - # if self.wrapper_hwobj is not None: - # self.stateChanged(self.wrapper_hwobj.get_state()) - - elif property_name == "setin": - # w=self.fontMetrics().width("Set out") - icons_list = self["icons"] - try: - i = icons_list[0] - except IndexError: - self.set_in_button.setText(new_value) - # self.set_in_button.setMinimumWidth(w) - help_text = new_value + " the " + self["username"].lower() - self.set_in_button.setToolTip(help_text) - self.set_in_button.setText(self["setin"]) - - elif property_name == "setout": - # w=self.fontMetrics().width("Set out") - icons_list = self["icons"].split() - try: - i = icons_list[1] - except IndexError: - self.set_out_button.setText(new_value) - # self.set_out_button.setMinimumWidth(w) - help_text = new_value + " the " + self["username"].lower() - self.set_out_button.setToolTip(help_text) - self.set_out_button.setText(self["setout"]) - - elif property_name == "username": - if new_value == "": - if self.wrapper_hwobj is not None: - name = self.wrapper_hwobj.username - if name != "": - self["username"] = name - return - help_text = self["setin"] + " the " + new_value.lower() - self.set_in_button.setToolTip(help_text) - help_text = self["setout"] + " the " + new_value.lower() - self.set_out_button.setToolTip(help_text) - self.main_gbox.setTitle(self["username"]) - - else: - BaseWidget.property_changed(self, property_name, old_value, new_value) - - -### -# Wrapper around different hardware objects, to make them have the -# same behavior to the brick -### - - -class WrapperHO(qt_import.QObject): - DEVICE_MAP = { - "Device": "Procedure", - "SOLEILGuillotine": "Shutter", - "SoleilSafetyShutter": "Shutter", - "TangoShutter": "Shutter", - "ShutterEpics": "Shutter", - "MD2v4_FastShutter": "Shutter", - "TempShutter": "Shutter", - "EMBLSafetyShutter": "Shutter", - "MDFastShutter": "Shutter", - "WagoPneu": "WagoPneu", - "Shutter": "WagoPneu", - "SpecMotorWSpecPositions": "WagoPneu", - "Procedure": "WagoPneu", - } - - WAGO_STATE = {"in": "in", "out": "out", "unknown": "unknown"} - - SHUTTER_STATE = { - "fault": "error", - "opened": "in", - "noperm": "noperm", - "closed": "out", - "unknown": "unknown", - "moving": "moving", - "automatic": "automatic", - "disabled": "disabled", - "error": "error", - } - DOOR_INTERLOCK_STATE = { - "locked": "out", - "unlocked": "disabled", - "locked_active": "out", - "locked_inactive": "disabled", - "error": "error", - } - - MOTOR_WPOS = ("out", "in") - MOTOR_WSTATE = ("disabled", "error", None, "moving", "moving", "moving") - - STATES = ( - "unknown", - "disabled", - "closed", - "error", - "out", - "moving", - "in", - "automatic", - "noperm", - ) - - duoStateChangedSignal = qt_import.pyqtSignal(str, str) - - def __init__(self, hardware_obj): - qt_import.QObject.__init__(self) - - # self.setIn = new.instancemethod(lambda self: None, self) - self.setIn = lambda self: None - self.setOut = self.setIn - # self.get-State = new.instancemethod(lambda self: "unknown", self) - self.get_state = lambda self: "unknown" - self.dev = hardware_obj - try: - sClass = str(self.dev.__class__) - i, j = re.search("'.*'", sClass).span() - except BaseException: - dev_class = sClass - else: - dev_class = sClass[i + 1 : j - 1] - self.devClass = dev_class.split(".")[-1] - - self.devClass = WrapperHO.DEVICE_MAP.get(self.devClass, "Shutter") - - initFunc = getattr(self, "init%s" % self.devClass) - initFunc() - self.setIn = getattr(self, "setIn%s" % self.devClass) - self.setOut = getattr(self, "setOut%s" % self.devClass) - self.get_state = getattr(self, "getState%s" % self.devClass) - - def __getstate__(self): - dict = self.__dict__.copy() - del dict["setIn"] - del dict["setOut"] - del dict["getState"] - return dict - - def __setstate__(self, dict): - self.__dict__ = dict.copy() - try: - # Python2 - import new - - self.setIn = new.instancemethod(lambda self: None, self) - self.setOut = self.setIn - self.get_state = new.instancemethod(lambda self: "unknown", self) - except ImportError: - import types - - self.setIn = types.MethodType(lambda self: None, self) - self.setOut = self.setIn - self.get_state = types.MethodType(lambda self: "unknown", self) - - def userName(self): - return self.dev.username - - # WagoPneu HO methods - def initWagoPneu(self): - self.dev.connect(self.dev, "wagoStateChanged", self.stateChangedWagoPneu) - - def setInWagoPneu(self): - self.duoStateChangedSignal.emit("moving") - self.dev.wagoIn() - - def setOutWagoPneu(self): - self.duoStateChangedSignal.emit("moving") - self.dev.wagoOut() - - def stateChangedWagoPneu(self, state): - try: - state = WrapperHO.WAGO_STATE[state] - except KeyError: - state = "error" - self.duoStateChangedSignal.emit(state) - - def getStateWagoPneu(self): - state = self.dev.getWagoState() - try: - state = WrapperHO.WAGO_STATE[state] - except KeyError: - state = "error" - return state - - # Shutter HO methods - def initShutter(self): - self.dev.connect(self.dev, "shutterStateChanged", self.stateChangedShutter) - - def setInShutter(self): - self.dev.openShutter() - - def setOutShutter(self): - self.dev.closeShutter() - - def stateChangedShutter(self, state, state_label=None): - state = WrapperHO.SHUTTER_STATE.get(state, "unknown") - if not state_label: - state_label = "" - self.duoStateChangedSignal.emit(state, state_label) - - def getStateShutter(self): - state = self.dev.getShutterState() - try: - state = WrapperHO.SHUTTER_STATE[state] - except KeyError: - state = "error" - return state - - # SpecMotorWSpecPositions HO methods - def initSpecMotorWSpecPositions(self): - self.positions = None - self.dev.connect( - self.dev, - "predefinedPositionChanged", - self.position_changed_spec_motor_wspec_positions, - ) - self.dev.connect( - self.dev, "stateChanged", self.stateChangedSpecMotorWSpecPositions - ) - self.dev.connect( - self.dev, - "newPredefinedPositions", - self.new_predefined_spec_motor_wspec_positions, - ) - - def setInSpecMotorWSpecPositions(self): - if self.positions is not None: - self.dev.moveToPosition(self.positions[1]) - - def setOutSpecMotorWSpecPositions(self): - if self.positions is not None: - self.dev.moveToPosition(self.positions[0]) - - def stateChangedSpecMotorWSpecPositions(self, state): - # logging.info("stateChangedSpecMotorWSpecPositions %s" % state) - try: - state = WrapperHO.MOTOR_WSTATE[state] - except IndexError: - state = "error" - if state is not None: - self.duoStateChangedSignal.emit(state) - - def position_changed_spec_motor_wspec_positions(self, pos_name, pos): - if self.dev.get_state() != self.dev.READY: - return - state = "error" - if self.positions is not None: - for i in range(len(self.positions)): - if pos_name == self.positions[i]: - state = WrapperHO.MOTOR_WPOS[i] - self.duoStateChangedSignal.emit(state) - - def get_state_spec_motor_wspec_positions(self): - if self.positions is None: - return "error" - curr_pos = self.dev.get_current_position_name() - if curr_pos is None: - state = self.dev.get_state() - try: - state = WrapperHO.MOTOR_WSTATE[state] - except IndexError: - state = "error" - return state - else: - for i in range(len(self.positions)): - if curr_pos == self.positions[i]: - return WrapperHO.MOTOR_WPOS[i] - return "error" - - def new_predefined_spec_motor_wspec_positions(self): - self.positions = self.dev.get_predefined_positions_list() - self.position_changed_spec_motor_wspec_positions( - self.dev.get_current_position_name(), self.dev.get_value() - ) - - # Procedure HO methods - def init_procedure(self): - cmds = self.dev.get_commands() - - self.set_in_cmd = None - self.set_out_cmd = None - - try: - channel = self.dev.get_channel_object("dev_state") - except KeyError: - channel = None - self.stateChannel = channel - if self.stateChannel is not None: - self.state_dict = { - "OPEN": "in", - "CLOSED": "out", - "ERROR": "error", - "1": "in", - "0": "out", - } - self.stateChannel.connect_signal("update", self.channel_update) - else: - self.state_dict = {} - - for cmd in cmds: - if cmd.name() == "set in": - self.set_in_cmd = cmd - if self.stateChannel is not None: - self.set_in_cmd.connect_signal( - "commandReplyArrived", self.procedureSetInEnded - ) - self.set_in_cmd.connect_signal( - "commandBeginWaitReply", self.procedure_started - ) - self.set_in_cmd.connect_signal( - "commandFailed", self.procedure_aborted - ) - self.set_in_cmd.connect_signal( - "commandAborted", self.procedure_aborted - ) - elif cmd.name() == "set out": - self.set_out_cmd = cmd - if self.stateChannel is not None: - self.set_out_cmd.connect_signal( - "commandReplyArrived", self.procedure_set_out_ended - ) - self.set_out_cmd.connect_signal( - "commandBeginWaitReply", self.procedure_started - ) - self.set_out_cmd.connect_signal( - "commandFailed", self.procedure_aborted - ) - self.set_out_cmd.connect_signal( - "commandAborted", self.procedure_aborted - ) - - def channel_update(self, value): - try: - key = self.dev.statekey - except AttributeError: - pass - else: - try: - state = value[key] - except TypeError: - state = "error" - try: - state = self.state_dict[state] - except KeyError: - pass - self.duoStateChangedSignal.emit(state) - - def set_in_procedure(self): - if self.set_in_cmd is not None: - self.set_in_cmd() - - def set_out_procedure(self): - if self.set_out_cmd is not None: - self.set_out_cmd() - - """ - def stateChangedProcedure(self,state): - pass - """ - - def get_state_procedure(self): - if self.stateChannel is not None: - try: - state = self.stateChannel.get_value() - except BaseException: - state = "error" - else: - try: - key = self.dev.statekey - except AttributeError: - pass - else: - try: - state = state[key] - except TypeError: - state = "error" - try: - state = self.state_dict[state] - except KeyError: - pass - return state - return "unknown" - - def procedureSetInEnded(self, *args): - self.duoStateChangedSignal.emit("in") - - def procedure_set_out_ended(self, *args): - self.duoStateChangedSignal.emit("out") - - def procedure_started(self, *args): - self.duoStateChangedSignal.emit("moving") - - def procedure_aborted(self, *args): - self.duoStateChangedSignal.emit("error") diff --git a/mxcubeqt/bricks/desy/p11_machine_info_brick.py b/mxcubeqt/bricks/desy/p11_machine_info_brick.py new file mode 100644 index 000000000..1ac42e9b2 --- /dev/null +++ b/mxcubeqt/bricks/desy/p11_machine_info_brick.py @@ -0,0 +1,150 @@ +# +# Project: MXCuBE +# https://github.com/mxcube +# +# This file is part of MXCuBE software. +# +# MXCuBE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# MXCuBE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with MXCuBE. If not, see . + +from mxcubeqt.base_components import BaseWidget +from mxcubeqt.utils import icons, colors, qt_import +from mxcubeqt.widgets.matplot_widget import TwoAxisPlotWidget + +from mxcubecore import HardwareRepository as HWR +import logging + +from PyQt5.QtWidgets import QLineEdit + +STATES = {"unknown": colors.GRAY, "ready": colors.LIGHT_BLUE, "error": colors.LIGHT_RED} + + +__credits__ = ["MXCuBE collaboration"] +__license__ = "LGPLv3+" +__category__ = "DESY" + +from mxcubeqt.base_components import BaseWidget +from mxcubeqt.utils import qt_import +import logging +from PyQt5.QtCore import QMetaObject, Qt +from PyQt5.QtWidgets import ( + QApplication, + QWidget, + QLabel, + QVBoxLayout, + QFormLayout, + QGroupBox, +) + + +class P11MachineInfoBrick(BaseWidget): + """Brick to display information about synchrotron and beamline as simple text lines.""" + + def __init__(self, *args): + super().__init__(*args) + + self.current_label_text = qt_import.QLabel(self) + self.current_label = qt_import.QLabel(self) + + self.message_label_text = qt_import.QLabel(self) + self.message_label = qt_import.QLabel(self) + + self.lifetime_label_text = qt_import.QLabel(self) + self.lifetime_label = qt_import.QLabel(self) + + self.energy_label_text = qt_import.QLabel(self) + self.energy_label = qt_import.QLabel(self) + + # Set default values + self.current_label_text.setText("Machine current") + self.current_label.setText("N/A mA") + self.current_label.setStyleSheet("background-color: #6cb2f8;") + self.current_label.setAlignment(Qt.AlignCenter) + + self.message_label_text.setText("Machine state") + self.message_label.setStyleSheet("background-color: #6cb2f8;") + self.message_label.setText("N/A") + self.message_label.setAlignment(Qt.AlignCenter) + + self.lifetime_label_text.setText("Lifetime") + self.lifetime_label.setText("N/A hours") + self.lifetime_label.setStyleSheet("background-color: #6cb2f8;") + self.lifetime_label.setAlignment(Qt.AlignCenter) + + self.energy_label_text.setText("Energy") + self.energy_label.setText("N/A GeV") + self.energy_label.setStyleSheet("background-color: #6cb2f8;") + self.energy_label.setAlignment(Qt.AlignCenter) + + # Add labels to layout + self.main_layout = qt_import.QVBoxLayout(self) + + self.main_layout.addWidget(self.current_label_text) + self.main_layout.addWidget(self.current_label) + + self.main_layout.addWidget(self.message_label_text) + self.main_layout.addWidget(self.message_label) + + self.main_layout.addWidget(self.lifetime_label_text) + self.main_layout.addWidget(self.lifetime_label) + + self.main_layout.addWidget(self.energy_label_text) + self.main_layout.addWidget(self.energy_label) + + def update_labels_in_ui_thread(self, current_value): + QMetaObject.invokeMethod( + self.current_label, "setText", Qt.QueuedConnection, f"{current_value} mA" + ) + + def run(self): + """Connect the signal from the hardware object.""" + if HWR.beamline.machine_info is not None: + HWR.beamline.machine_info.valuesChanged.connect(self.set_value) + else: + logging.error("Machine info object not available") + + def set_value(self, values_dict): + """Update the labels in the MachineInfoBrick with machine values.""" + logging.info(f"Received machine info values: {values_dict}") + + current_value = values_dict.get("current", {}).get("value", "N/A") + lifetime_value = values_dict.get("lifetime", {}).get("value", "N/A") + energy_value = values_dict.get("energy", {}).get("value", "N/A") + message_value = values_dict.get("message", {}).get("value", "N/A") + + # Update the UI labels + self.current_label.setText(f"{current_value} mA") + self.lifetime_label.setText(f"{lifetime_value} hours") + self.energy_label.setText(f"{energy_value} GeV") + self.message_label.setText(f"{message_value}") + + # Check if machine current is <= 99, change color + if current_value != "N/A" and float(current_value) <= 99: + self.set_all_labels_color("salmon") + else: + self.reset_all_labels_color() + + def set_all_labels_color(self, color): + """Set all label backgrounds to the specified color.""" + self.current_label.setStyleSheet(f"background-color: {color};") + self.message_label.setStyleSheet(f"background-color: {color};") + self.lifetime_label.setStyleSheet(f"background-color: {color};") + self.energy_label.setStyleSheet(f"background-color: {color};") + + def reset_all_labels_color(self): + """Reset all label backgrounds to their default color.""" + default_color = "#6cb2f8" + self.current_label.setStyleSheet(f"background-color: {default_color};") + self.message_label.setStyleSheet(f"background-color: {default_color};") + self.lifetime_label.setStyleSheet(f"background-color: {default_color};") + self.energy_label.setStyleSheet(f"background-color: {default_color};") diff --git a/mxcubeqt/bricks/desy/p11_proposal_brick.py b/mxcubeqt/bricks/desy/p11_proposal_brick.py index 5e75a356b..519093a0e 100644 --- a/mxcubeqt/bricks/desy/p11_proposal_brick.py +++ b/mxcubeqt/bricks/desy/p11_proposal_brick.py @@ -17,6 +17,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with MXCuBE. If not, see . +__credits__ = ["MXCuBE collaboration"] +__license__ = "LGPLv3+" +__category__ = "DESY" + + import logging import os @@ -24,6 +29,7 @@ from mxcubeqt.bricks.proposal_brick import ProposalBrick, ProposalGUIEvent from mxcubecore import HardwareRepository as HWR + class P11ProposalBrick(ProposalBrick): def __init__(self, *args): super(P11ProposalBrick, self).__init__(*args) @@ -89,25 +95,61 @@ def run(self): qt_import.QApplication.postEvent(self, start_server_event) def p11_login_as_proposal(self): + try: + if HWR.beamline.lims.simulated_proposal == 1: + proposal_code = HWR.beamline.lims.simulated_prop_code + proposal_number = HWR.beamline.lims.simulated_prop_number + else: + proposal_code = HWR.beamline.session.get_current_proposal_code() + proposal_number = HWR.beamline.session.get_current_proposal_number() - if HWR.beamline.lims.simulated_proposal == 1: - proposal_code = HWR.beamline.lims.simulated_prop_code - proposal_number = HWR.beamline.lims.simulated_prop_number - else: - proposal_code = HWR.beamline.session.get_current_proposal_code() - proposal_number = HWR.beamline.session.get_current_proposal_number() + logging.getLogger("HWR").debug( + " PROPOSAL BRICK - code is %s" % proposal_code + ) + logging.getLogger("HWR").debug( + " PROPOSAL BRICK - number is %s" % proposal_number + ) + + # Fetch proposal data + prop = HWR.beamline.lims.get_proposal(proposal_code, proposal_number) - logging.getLogger("HWR").debug(" PROPOSAL BRICK - code is %s" % proposal_code) - logging.getLogger("HWR").debug( - " PROPOSAL BRICK - number is %s" % proposal_number - ) + # Check for ISPyB connection error + if prop["status"]["code"] == "error": + self.message_widget.setText("ISPyB is not connected.") + self.message_widget.show() - self._do_login_as_proposal( - proposal_code, proposal_number, None, HWR.beamline.lims.beamline_name, - ) + # Display the available proposal info + self.show_selected_proposal(prop["Proposal"]) + + except Exception as e: + # Catch any errors and display them as warnings but proceed + logging.getLogger("HWR").error(f"Error logging in as proposal: {str(e)}") + self.message_widget.setText(f"Error: {str(e)}") + self.message_widget.show() + self.show_selected_proposal( + {"code": proposal_code, "number": proposal_number} + ) def show_selected_proposal(self, proposal): + """ + Display the selected proposal information even if incomplete. + """ + try: + beamtime_id = HWR.beamline.session.get_current_beamtime_id() + prop_code = str(proposal.get("code", "Unknown")) + prop_number = str(proposal.get("number", "Unknown")) + + prop_info = f"ID: {prop_code}-{prop_number} - BT_ID: {beamtime_id}" + self.proposal_info.setText(prop_info) + self.proposal_info.show() + + except KeyError as e: + logging.getLogger("HWR").error(f"Missing proposal information: {str(e)}") + self.proposal_info.setText(f"ID: {prop_code}-Unknown - BT_ID: Unknown") + self.proposal_info.show() + + def show_selected_proposal(self, proposal): beamtime_id = HWR.beamline.session.get_current_beamtime_id() prop_number = str(proposal["number"]) prop_code = str(proposal["code"]) diff --git a/mxcubeqt/bricks/desy/p11_sample_changer_brick.py b/mxcubeqt/bricks/desy/p11_sample_changer_brick.py index d41ef1313..aa9c8be99 100644 --- a/mxcubeqt/bricks/desy/p11_sample_changer_brick.py +++ b/mxcubeqt/bricks/desy/p11_sample_changer_brick.py @@ -17,6 +17,11 @@ # You should have received a copy of the GNU Lesser General Public License # along with MXCuBE. If not, see . +__credits__ = ["MXCuBE collaboration"] +__license__ = "LGPLv3+" +__category__ = "DESY" + + from mxcubeqt.bricks.cats_simple_brick import CatsSimpleBrick diff --git a/mxcubeqt/bricks/desy/p11_simple_brick.py b/mxcubeqt/bricks/desy/p11_simple_brick.py index ef55e24cc..673acbf70 100644 --- a/mxcubeqt/bricks/desy/p11_simple_brick.py +++ b/mxcubeqt/bricks/desy/p11_simple_brick.py @@ -34,7 +34,12 @@ from mxcubeqt.base_components import BaseWidget from mxcubeqt.utils import colors, qt_import from mxcubeqt.utils import sample_changer_helper as sc_helper -from mxcubeqt.bricks.sample_changer_brick import SampleChangerBrick, BasketView, VialView, StatusView +from mxcubeqt.bricks.sample_changer_brick import ( + SampleChangerBrick, + BasketView, + VialView, + StatusView, +) from mxcubecore import HardwareRepository as HWR @@ -44,12 +49,10 @@ class P11SCStatusView(qt_import.QWidget): - # statusMsgChangedSignal = qt_import.pyqtSignal(str, qt_import.QColor) # resetSampleChangerSignal = qt_import.pyqtSignal() def __init__(self, parent, brick): - qt_import.QWidget.__init__(self, parent) self._parent = brick @@ -94,7 +97,6 @@ def __init__(self, parent, brick): # Qt signal/slot connections ------------------------------------------ - def set_expert_mode(self, expert): pass @@ -104,7 +106,6 @@ def setStatusMsg(self, status): self.setToolTip(status) def setState(self, state): - color = sc_helper.SC_STATE_COLOR.get(state, None) if color is None: @@ -121,10 +122,10 @@ def setState(self, state): def setIcons(self, *args): pass + class P11SimpleBrick(SampleChangerBrick): def __init__(self, *args): - - super(P11SimpleBrick,self).__init__(*args) + super(P11SimpleBrick, self).__init__(*args) self._powered_on = None self.state = sc_helper.SampleChangerState.Ready @@ -140,18 +141,18 @@ def __init__(self, *args): self.double_click_loads_cbox.hide() self.current_basket_view.hide() - #self.current_sample_view.hide() + # self.current_sample_view.hide() if HWR.beamline.sample_changer is not None: - #self.connect( - #HWR.beamline.sample_changer, - #"runningStateChanged", - #self._updatePathRunning, - #) + # self.connect( + # HWR.beamline.sample_changer, + # "runningStateChanged", + # self._updatePathRunning, + # ) self.connect( HWR.beamline.sample_changer, "powerStateChanged", - self._update_power_state + self._update_power_state, ) self._powered_on = HWR.beamline.sample_changer.is_powered() @@ -159,7 +160,7 @@ def __init__(self, *args): def build_status_view(self, container): return P11SCStatusView(container, self) - #return StatusView(container) + # return StatusView(container) def build_operations_widget(self): self.buttons_layout = qt_import.QHBoxLayout() @@ -168,16 +169,25 @@ def build_operations_widget(self): self.load_button = qt_import.QPushButton("Load", self) self.unload_button = qt_import.QPushButton("Unload", self) self.wash_button = qt_import.QPushButton("Wash", self) + self.home_button = qt_import.QPushButton("Home position", self) + self.cool_button = qt_import.QPushButton("Cool position", self) + self.deice_button = qt_import.QPushButton("Deice", self) self.abort_button = qt_import.QPushButton("Abort", self) self.load_button.clicked.connect(self.load_selected_sample) self.unload_button.clicked.connect(self.unload_sample) self.wash_button.clicked.connect(self.wash_sample) + self.home_button.clicked.connect(self.home_robot) + self.cool_button.clicked.connect(self.cool_robot) + self.deice_button.clicked.connect(self.deice_robot) self.abort_button.clicked.connect(self.abort_mounting) self.buttons_layout.addWidget(self.load_button) self.buttons_layout.addWidget(self.unload_button) self.buttons_layout.addWidget(self.wash_button) + self.buttons_layout.addWidget(self.home_button) + self.buttons_layout.addWidget(self.cool_button) + self.buttons_layout.addWidget(self.deice_button) self.operation_buttons_layout.addLayout(self.buttons_layout) self.operation_buttons_layout.addWidget(self.abort_button) self.operations_widget.setLayout(self.operation_buttons_layout) @@ -217,6 +227,9 @@ def _update_buttons(self): self.load_button.setEnabled(False) self.unload_button.setEnabled(False) self.wash_button.setEnabled(False) + self.home_button.setEnabled(False) + self.cool_button.setEnabled(False) + self.deice_button.setEnabled(False) self.abort_button.setEnabled(False) abort_color = colors.LIGHT_GRAY elif ready: @@ -245,8 +258,8 @@ def load_selected_sample(self): logging.getLogger("GUI").info("Loading sample: %s / %s" % (basket, vial)) if basket is not None and vial is not None: - sample_loc = "%d:%d" % (basket, vial) - HWR.beamline.sample_changer.load(sample_loc, wait=False) + sample_loc = "%d:%d" % (basket, vial) + HWR.beamline.sample_changer.load(sample_loc, wait=False) def unload_sample(self): logging.getLogger("GUI").info("Unloading sample") @@ -256,6 +269,17 @@ def wash_sample(self): logging.getLogger("GUI").info("Washing sample") HWR.beamline.sample_changer.wash() + def home_robot(self): + logging.getLogger("GUI").info("Home robot") + HWR.beamline.sample_changer.home() + + def cool_robot(self): + logging.getLogger("GUI").info("Cool robot") + HWR.beamline.sample_changer.cool() + + def deice_robot(self): + logging.getLogger("GUI").info("Deice robot") + HWR.beamline.sample_changer.deice() def abort_mounting(self): HWR.beamline.sample_changer._do_abort() diff --git a/mxcubeqt/bricks/desy/value_state_brick.py b/mxcubeqt/bricks/desy/value_state_brick.py index f573a4383..c30bf26a9 100644 --- a/mxcubeqt/bricks/desy/value_state_brick.py +++ b/mxcubeqt/bricks/desy/value_state_brick.py @@ -32,7 +32,6 @@ class ValueStateBrick(BaseWidget): - STATE_COLORS = ( colors.LIGHT_RED, # ALARM colors.LIGHT_YELLOW, # WARNING diff --git a/mxcubeqt/bricks/door_interlock_brick.py b/mxcubeqt/bricks/door_interlock_brick.py index 3e1483f7b..bd1d0972a 100644 --- a/mxcubeqt/bricks/door_interlock_brick.py +++ b/mxcubeqt/bricks/door_interlock_brick.py @@ -84,12 +84,8 @@ def __init__(self, *args): self.state_label.setToolTip("Shows the current door state") self.unlock_door_button.setToolTip("Unlocks the doors") - self.connect( - HWR.beamline.hutch_interlock, - "valueChanged", - self.value_changed - ) - + self.connect(HWR.beamline.hutch_interlock, "valueChanged", self.value_changed) + def unlock_doors(self): self.unlock_door_button.setEnabled(False) HWR.beamline.hutch_interlock.unlock() diff --git a/mxcubeqt/bricks/machine_info_brick.py b/mxcubeqt/bricks/machine_info_brick.py index 284c80326..c4604d93e 100644 --- a/mxcubeqt/bricks/machine_info_brick.py +++ b/mxcubeqt/bricks/machine_info_brick.py @@ -169,4 +169,3 @@ def update_info(self, info_dict): self.value_plot.add_new_plot_value(value) def open_history_view(self): - self.value_plot.setVisible(not self.value_plot.isVisible()) diff --git a/mxcubeqt/bricks/multi_state_brick.py b/mxcubeqt/bricks/multi_state_brick.py index e3ed53f36..e45f9c8cd 100644 --- a/mxcubeqt/bricks/multi_state_brick.py +++ b/mxcubeqt/bricks/multi_state_brick.py @@ -56,16 +56,13 @@ from mxcubecore.BaseHardwareObjects import HardwareObjectState - __credits__ = ["MXCuBE collaboration"] __license__ = "LGPLv3+" __category__ = "General" class MultiStateBrick(BaseWidget): - units = { - "micron": u"\u03BC", - } + units = {"micron": "\u03BC"} def __init__(self, *args): @@ -117,38 +114,37 @@ def __init__(self, *args): def property_changed(self, property_name, old_value, new_value): if property_name == "label": - if new_value == "": + if new_value != "": self.label.setText(new_value) else: - self.label.hide() + self.label.show() + elif property_name == "title": if new_value != "": self.main_gbox.setTitle(new_value) + elif property_name == "multibutton": if new_value != "": self.multibutton = new_value - if len(self.positions): + if self.positions is not None and len(self.positions): self.switch_multibutton_mode(self.multibutton) - elif property_name == "mnemonic": - if self.multi_hwobj is not None: - self.disconnect(self.multi_hwobj, "stateChanged", self.state_changed) - self.disconnect( - self.multi_hwobj, "valueChanged", self.value_changed, - ) + elif property_name == "mnemonic": + # Get the new hardware object directly without using callbacks or signals self.multi_hwobj = self.get_hardware_object(new_value) if self.multi_hwobj is not None: - self.connect(self.multi_hwobj, "stateChanged", self.state_changed) - self.connect( - self.multi_hwobj, "valueChanged", self.value_changed, - ) - + # Set up the motor positions and buttons self.fill_positions() + if self.multibutton: self.switch_multibutton_mode(True) - self.state_changed() + + # Manually check the state of the motor and update the UI + self.state_changed(self.multi_hwobj.get_state()) + else: + # Fall back to the base class method for other properties BaseWidget.property_changed(self, property_name, old_value, new_value) def switch_multibutton_mode(self, mode): @@ -161,7 +157,8 @@ def switch_multibutton_mode(self, mode): def get_position_label(self, posidx): pos = self.positions[posidx] - unit = self.multi_hwobj.get_property_value_by_index(posidx, "unit") + # Access the unit directly from self.multi_hwobj._positions + unit = self.multi_hwobj._positions.get(pos, {}).get("unit", "") label = str(pos) if unit: label += self.units.get(unit, unit) @@ -195,47 +192,101 @@ def fill_positions(self): self.value_changed() def change_value(self, index): - if index >= 0: - self.multi_hwobj.set_value(index) + """Change the hardware object to the selected value.""" + # Check if positions is a list or dictionary + if isinstance(self.positions, list): + # If positions is a list, use the index directly + if 0 <= index < len(self.positions): + position_name = self.positions[index] + self.multi_hwobj.set_value(position_name) + else: + logging.error(f"Invalid index: {index}.") + elif isinstance(self.positions, dict): + # If positions is a dictionary, convert keys to a list and use the index + keys_list = list(self.positions.keys()) + if 0 <= index < len(keys_list): + position_name = keys_list[index] + self.multi_hwobj.set_value(position_name) + else: + logging.error(f"Invalid index: {index}.") + else: + logging.error(f"Invalid type for positions: {type(self.positions)}") def state_changed(self, state=None): - + """Update the UI based on the current state of the hardware.""" if state is None: state = self.multi_hwobj.get_state() if state == HardwareObjectState.READY: color = colors.LIGHT_GREEN + self.label.setText("Motor Ready") self.setEnabled(True) elif state == HardwareObjectState.BUSY: color = colors.LIGHT_YELLOW + self.label.setText("Motor Busy") self.setEnabled(False) else: color = colors.LIGHT_GRAY + self.label.setText("Motor Not Ready") self.setEnabled(False) + # Update colors in the UI colors.set_widget_color( self.multi_position_combo, color, qt_import.QPalette.Button ) - - for but in self.multibuttons: - colors.set_widget_color(but, color, qt_import.QPalette.Button) + for button in self.multibuttons: + colors.set_widget_color(button, color, qt_import.QPalette.Button) def value_changed(self, value=None): - + """This method is called when the hardware object's value changes.""" self.multi_position_combo.blockSignals(True) if value is None: + # Get the current value from the hardware object value = self.multi_hwobj.get_value() - if value >= 0 and value < len(self.positions): - self.multi_position_combo.setCurrentIndex(value) + # Check if positions exist and handle both list and dict cases + if isinstance(self.positions, dict): + positions_list = list(self.positions.keys()) + elif isinstance(self.positions, list): + positions_list = self.positions + else: + logging.error(f"Invalid type for positions: {type(self.positions)}") + positions_list = [] + + # Handle string positions and index values + if isinstance(value, str): + if value in positions_list: + # Set the current index to the matching string position + self.multi_position_combo.setCurrentIndex(positions_list.index(value)) + self.label.setText(f"Current Position: {value}") + else: + logging.error(f"Unknown position: {value}") + self.label.setText("Unknown Position") + self.multi_position_combo.setCurrentIndex(-1) else: - self.multi_position_combo.setCurrentIndex(-1) + try: + # If value is an index, convert it to an integer + value = int(value) + except (ValueError, TypeError): + logging.error( + f"Invalid value type: {value}. Expected an integer or string." + ) + value = -1 + + if 0 <= value < len(positions_list): + # Set the current index based on the integer value + self.multi_position_combo.setCurrentIndex(value) + self.label.setText(f"Current Position: {positions_list[value]}") + else: + self.multi_position_combo.setCurrentIndex(-1) + self.label.setText("Unknown Position") self.multi_position_combo.blockSignals(False) - # value is index + # Update button states for button in self.multibuttons: button.setEnabled(True) - self.multibuttons[value].setEnabled(False) + if isinstance(value, int) and 0 <= value < len(self.multibuttons): + self.multibuttons[value].setEnabled(False) diff --git a/mxcubeqt/bricks/progress_bar_brick.py b/mxcubeqt/bricks/progress_bar_brick.py index 931307f78..9835ac55c 100644 --- a/mxcubeqt/bricks/progress_bar_brick.py +++ b/mxcubeqt/bricks/progress_bar_brick.py @@ -76,7 +76,7 @@ def step_progress(self, step, msg=None): # f self.use_dialog: # BaseWidget.set_progress_dialog_step(step) # lse: - self.progress_bar.setValue(step) + self.progress_bar.setValue(int(step)) self.setEnabled(True) # BaseWidget.set_progress_bar_step(step) diff --git a/mxcubeqt/gui_builder.py b/mxcubeqt/gui_builder.py index 76db7a48d..c676d89e7 100644 --- a/mxcubeqt/gui_builder.py +++ b/mxcubeqt/gui_builder.py @@ -1262,7 +1262,7 @@ def __init__(self, *args, **kwargs): self.log_window.setWindowTitle("Log window") sw = qt_import.QApplication.desktop().screen().width() sh = qt_import.QApplication.desktop().screen().height() - self.log_window.resize(qt_import.QSize(sw * 0.8, sh * 0.2)) + self.log_window.resize(qt_import.QSize(int(sw * 0.8), int(sh * 0.2))) self.property_editor_window = PropertyEditorWindow(None) self.gui_preview_window = GUIPreviewWindow(None) self.configuration = self.gui_editor_window.configuration diff --git a/mxcubeqt/utils/gui_display.py b/mxcubeqt/utils/gui_display.py index 5d7c8dd8f..942d57db4 100644 --- a/mxcubeqt/utils/gui_display.py +++ b/mxcubeqt/utils/gui_display.py @@ -477,18 +477,18 @@ def paintEvent(self, event): if self.orientation == "horizontal": height = self.height() / 2 - painter.drawLine(0, height, self.width(), height) - painter.drawLine(0, height, 5, height - 5) - painter.drawLine(0, height, 5, height + 5) - painter.drawLine(self.width(), height, self.width() - 5, height - 5) - painter.drawLine(self.width(), height, self.width() - 5, height + 5) + painter.drawLine(0, int(height), int(self.width()), int(height)) + painter.drawLine(0,int(height), 5, int(height) - 5) + painter.drawLine(0, int(height), 5, int(height) + 5) + painter.drawLine(self.width(), int(height), self.width() - 5, int(height) - 5) + painter.drawLine(self.width(), int(height), self.width() - 5, int(height) + 5) else: width = self.width() / 2 - painter.drawLine(self.width() / 2, 0, self.width() / 2, self.height()) - painter.drawLine(width, 0, width - 5, 5) - painter.drawLine(width, 0, width + 5, 5) - painter.drawLine(width, self.height(), width - 5, self.height() - 5) - painter.drawLine(width, self.height(), width + 5, self.height() - 5) + painter.drawLine(int(self.width() / 2), 0,int(self.width() / 2),int( self.height())) + painter.drawLine(int(width), 0, int(width) - 5, 5) + painter.drawLine(int(width), 0, int(width) + 5, 5) + painter.drawLine(int(width), self.height(), int(width) - 5, self.height() - 5) + painter.drawLine(int(width), self.height(), int(width) + 5, self.height() - 5) class CustomFrame(qt_import.QFrame): def __init__(self, *args, **kwargs): diff --git a/mxcubeqt/widgets/acquisition_ssx_widget.py b/mxcubeqt/widgets/acquisition_ssx_widget.py index f7fbdb8d2..fab973104 100644 --- a/mxcubeqt/widgets/acquisition_ssx_widget.py +++ b/mxcubeqt/widgets/acquisition_ssx_widget.py @@ -339,18 +339,20 @@ def update_energy_limits(self, limits): def update_transmission_limits(self, limits): """ - Updates transmission limits - :param limits: list of two floats - :return: None + Updates transmission limits. + + Args: + limits (tuple): A tuple containing the minimum and maximum transmission limits. """ - if limits: + if limits and limits[0] is not None and limits[1] is not None: self.transmission_validator.setBottom(limits[0]) self.transmission_validator.setTop(limits[1]) self.acq_widget_layout.transmission_ledit.setToolTip( "Transmission limits %0.2f : %0.2f %%\n" % (limits[0], limits[1]) - + "2 digits precision." ) self._acquisition_mib.validate_all() + else: + self.acq_widget_layout.transmission_ledit.setToolTip(r"Invalid transmission limits: {}".format(limits)) def update_resolution_limits(self, limits): """ diff --git a/mxcubeqt/widgets/acquisition_widget.py b/mxcubeqt/widgets/acquisition_widget.py index 27776e84b..2b731bd5b 100644 --- a/mxcubeqt/widgets/acquisition_widget.py +++ b/mxcubeqt/widgets/acquisition_widget.py @@ -498,9 +498,11 @@ def init_limits(self): self.set_tunable_energy(HWR.beamline.tunable_wavelength) has_shutter_less = HWR.beamline.detector.has_shutterless() - self.acq_widget_layout.shutterless_cbx.setEnabled(has_shutter_less) + self.acq_widget_layout.shutterless_cbx.setEnabled(False) self.acq_widget_layout.shutterless_cbx.setChecked(has_shutter_less) + + if HWR.beamline.disable_num_passes: num_passes = self.acq_widget_layout.findChild( qt_import.QLineEdit, "num_passes_ledit" @@ -660,7 +662,13 @@ def update_energy_limits(self, limits): self._acquisition_mib.validate_all() def update_transmission_limits(self, limits): - if limits: + """ + Updates the transmission limits in the validator. + + Args: + limits (tuple): A tuple containing the minimum and maximum transmission limits. + """ + if limits and limits[0] is not None and limits[1] is not None: self.transmission_validator.setBottom(limits[0]) self.transmission_validator.setTop(limits[1]) self.acq_widget_layout.transmission_ledit.setToolTip( @@ -668,6 +676,8 @@ def update_transmission_limits(self, limits): + "2 digits precision." ) self._acquisition_mib.validate_all() + else: + self.acq_widget_layout.transmission_ledit.setToolTip("Invalid transmission limits received: {}".format(limits)) def update_resolution_limits(self, limits): if limits: diff --git a/mxcubeqt/widgets/acquisition_widget_simple.py b/mxcubeqt/widgets/acquisition_widget_simple.py index e67060b2e..15ec06211 100644 --- a/mxcubeqt/widgets/acquisition_widget_simple.py +++ b/mxcubeqt/widgets/acquisition_widget_simple.py @@ -294,13 +294,21 @@ def update_energy_limits(self, limits): self._acquisition_mib.validate_all() def update_transmission_limits(self, limits): - if limits: + """ + Updates the transmission limits in the validator. + + Args: + limits (tuple): A tuple containing the minimum and maximum transmission limits. + """ + if limits and limits[0] is not None and limits[1] is not None: self.transmission_validator.setBottom(limits[0]) self.transmission_validator.setTop(limits[1]) self.acq_widget_layout.transmission_ledit.setToolTip( "Transmission limits %0.3f : %0.3f" % (limits[0], limits[1]) ) self._acquisition_mib.validate_all() + else: + self.acq_widget_layout.transmission_ledit.setToolTip(r"Invalid transmission limits received: {}".format(limits)) def update_resolution_limits(self, limits): if limits: