diff --git a/notes.org b/notes.org index bbe3b1c0..de43ba60 100644 --- a/notes.org +++ b/notes.org @@ -4,8 +4,6 @@ of the application. We want to remove this and let the displays work independently of the QApplication. -** TODO [0/1] Ion chambers - - [ ] Respond to clicks of the details button ** TODO [0/2] Component selector - [ ] Pass the app's instrument registry down to the component selector - [ ] Send the registry initially when the component selector is created @@ -51,8 +49,8 @@ - [X] Apps needs to connect queue_status_changed to main_window.update_queue_controls ** TODO [0/1] Queue button - [ ] App needs to pass queue_status_updated signal down to update_queue_style slot -** TODO [1/2] Voltmeters - - [ ] App needs to respond to the voltmeters ``details_window_requested`` signal +** TODO [2/2] Voltmeters + - [X] App needs to respond to the voltmeters ``details_window_requested`` signal - [X] Move functionality from voltmeter.py into voltmeters.py ** TODO [0/2] Camera - [ ] There's still a FireflyApplication.instance() call in camera diff --git a/src/firefly/controller.py b/src/firefly/controller.py index 85c192e4..eeb7d747 100644 --- a/src/firefly/controller.py +++ b/src/firefly/controller.py @@ -270,8 +270,10 @@ def setup_window_actions(self): text="&Voltmeters", display_file=ui_dir / "voltmeters.py", WindowClass=FireflyMainWindow, + shortcut="Ctrl+V", icon=qta.icon("ph.faders-horizontal"), ) + self.actions.voltmeter.window_created.connect(self.finalize_voltmeter_window) # Launch log window self.actions.log = WindowAction( name="show_logs_window_action", @@ -307,6 +309,15 @@ async def finalize_new_window(self, action): self.queue_status_changed.connect(action.window.update_queue_controls) self._queue_client.check_queue_status(force=True) + def finalize_voltmeter_window(self, action): + """Connect up signals that are specific to the voltmeters window.""" + def launch_ion_chamber_window(ic_name): + action = self.actions.ion_chambers[ic_name] + action.trigger() + + display = action.window.display_widget() + display.details_window_requested.connect(launch_ion_chamber_window) + def launch_queuemonitor(self): config = load_config()["queueserver"] zmq_info_addr = f"tcp://{config['info_host']}:{config['info_port']}" diff --git a/src/firefly/main_window.py b/src/firefly/main_window.py index 4b0c01dd..8e85f618 100644 --- a/src/firefly/main_window.py +++ b/src/firefly/main_window.py @@ -364,7 +364,6 @@ def setup_menu_actions(self, actions): def update_queue_controls(self, new_status): """Update the queue controls to match the state of the queueserver.""" - print(new_status) super().update_queue_controls(new_status) self.ui.navbar.setVisible(bool(new_status['in_use'])) diff --git a/src/firefly/tests/test_controller.py b/src/firefly/tests/test_controller.py index 28cf8944..9890df84 100644 --- a/src/firefly/tests/test_controller.py +++ b/src/firefly/tests/test_controller.py @@ -142,6 +142,26 @@ def test_autostart_changed(controller, qtbot): assert autostart_action.isChecked() +@pytest.mark.asyncio +async def test_ion_chamber_details_window(qtbot, sim_registry, I0, controller): + """Check that the controller opens ion chamber windows from voltmeters + display. + + """ + vm_action = controller.actions.voltmeter + ic_action = controller.actions.ion_chambers['I0'] + # Create the ion chamber display + vm_action = controller.actions.voltmeter + with qtbot.waitSignal(vm_action.window_shown, timeout=1): + vm_action.trigger() + vm_display = vm_action.window.display_widget() + qtbot.addWidget(vm_display) + await vm_display.update_devices(sim_registry) + # Click the ion chamber button + details_button = vm_display._ion_chamber_rows[0].details_button + with qtbot.waitSignal(ic_action.window_shown, timeout=1000): + details_button.click() + # ----------------------------------------------------------------------------- # :author: Mark Wolfman # :email: wolfman@anl.gov diff --git a/src/firefly/voltmeters.py b/src/firefly/voltmeters.py index 6c41657f..0096aeea 100644 --- a/src/firefly/voltmeters.py +++ b/src/firefly/voltmeters.py @@ -4,11 +4,14 @@ from functools import partial from qasync import asyncSlot +import qtawesome as qta from bluesky_queueserver_api import BPlan from pydm.widgets import PyDMLabel, PyDMPushButton from pydm.widgets.analog_indicator import PyDMAnalogIndicator +from pydm.widgets.display_format import DisplayFormat from qtpy.QtWidgets import QVBoxLayout, QHBoxLayout, QPushButton, QLabel, QCheckBox, QSpacerItem, QSizePolicy -from qtpy.QtCore import Signal +from qtpy.QtCore import Signal, Qt +from qtpy.QtGui import QFont import haven from firefly import display @@ -26,6 +29,9 @@ def customize_ui(self): # Connect support for running the auto_gain plan self.ui.auto_gain_button.setToolTip(haven.auto_gain.__doc__) self.ui.auto_gain_button.clicked.connect(self.run_auto_gain) + # Adjust layouts + self.ui.voltmeters_layout.setHorizontalSpacing(0) + self.ui.voltmeters_layout.setVerticalSpacing(0) def clear_layout(self, layout): if layout is None: @@ -40,7 +46,6 @@ def clear_layout(self, layout): @asyncSlot(object) async def update_devices(self, registry): - print("Updating voltmeters devices") ion_chambers = registry.findall(label="ion_chambers") self.ion_chambers = sorted(ion_chambers, key=lambda c: c.ch_num) # Clear the voltmeters grid layout @@ -106,35 +111,51 @@ def setup_ui(self): parent=self.parent, init_channel=f"haven://{device_name}.description" ) + self.name_label.setStyleSheet("font: 12pt \"Sans Serif\";\nfont-weight: bold;") self.column_layouts[0].addWidget(self.name_label) # Analog indicator self.voltage_indicator = PyDMAnalogIndicator( parent=self.parent, init_channel=f"haven://{device_name}.voltmeter.volts" ) + self.voltage_indicator.showValue = False + self.voltage_indicator.limitsFromChannel = False + self.voltage_indicator.minorAlarmFromChannel = False + self.voltage_indicator.majorAlarmFromChannel = False + self.voltage_indicator.userLowerLimit = 0.0 + self.voltage_indicator.userUpperLimit = 5.0 + self.voltage_indicator.userUpperMinorAlarm = 4.5 + self.voltage_indicator.userLowerMinorAlarm = 0.5 + self.voltage_indicator.userUpperMajorAlarm = 5.0 + self.voltage_indicator.userLowerMajorAlarm = 0.15 self.column_layouts[1].addWidget(self.voltage_indicator) # Voltage labels self.column_layouts[2].addItem(VSpacer()) self.voltage_label_layout = QHBoxLayout() + self.voltage_label_layout.setSpacing(3) self.column_layouts[2].addLayout(self.voltage_label_layout) self.voltage_label_layout.addItem(HSpacer()) self.voltage_label = PyDMLabel( parent=self.parent, init_channel=f"haven://{device_name}.voltmeter.volts", ) + self.voltage_label.setStyleSheet("font: 12pt \"Sans Serif\";\nfont-weight: bold;") self.voltage_label_layout.addWidget(self.voltage_label) self.voltage_unit_label = QLabel(parent=self.parent) + self.voltage_unit_label.setStyleSheet("font: 12pt \"Sans Serif\";\nfont-weight: bold;") self.voltage_unit_label.setText("V") self.voltage_label_layout.addWidget(self.voltage_unit_label) self.voltage_label_layout.addItem(HSpacer()) # Current labels self.current_label_layout = QHBoxLayout() + self.current_label_layout.setSpacing(3) self.column_layouts[2].addLayout(self.current_label_layout) self.current_label_layout.addItem(HSpacer()) self.current_label = PyDMLabel( parent=self.parent, init_channel=f"haven://{device_name}.voltmeter.amps", ) + self.current_label.displayFormat = DisplayFormat.Exponential self.current_label_layout.addWidget(self.current_label) self.current_unit_label = QLabel(parent=self.parent) self.current_unit_label.setText("A") @@ -145,23 +166,24 @@ def setup_ui(self): self.column_layouts[3].addItem(VSpacer()) self.gain_header_label = QLabel() self.gain_header_label.setText("Gain/Offset") + self.gain_header_label.setAlignment(Qt.AlignCenter) self.column_layouts[3].addWidget(self.gain_header_label) # Gain up/down buttons self.gain_buttons_layout = QHBoxLayout() self.column_layouts[3].addLayout(self.gain_buttons_layout) self.gain_buttons_layout.addItem(HSpacer()) self.gain_down_button = PyDMPushButton( - parent=self.parent, init_channel=f"haven://{device_name}.preamp.gain_level", relative=True, pressValue=-1, + icon=qta.icon("fa5s.arrow-left"), ) self.gain_buttons_layout.addWidget(self.gain_down_button) self.gain_up_button = PyDMPushButton( - parent=self.parent, init_channel=f"haven://{device_name}.preamp.gain_level", relative=True, pressValue=1, + icon=qta.icon("fa5s.arrow-right"), ) self.gain_buttons_layout.addWidget(self.gain_up_button) self.gain_buttons_layout.addItem(HSpacer()) @@ -178,8 +200,12 @@ def setup_ui(self): # Auto-gain and detail window controls self.column_layouts[4].addItem(VSpacer()) self.auto_gain_checkbox = QCheckBox(parent=self.parent) + self.auto_gain_checkbox.setText("Auto-gain") self.column_layouts[4].addWidget(self.auto_gain_checkbox) self.details_button = QPushButton(parent=self.parent) + self.details_button.setText("More") + self.details_button.setIcon(qta.icon("fa5s.cog")) + self.details_button.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Minimum) self.column_layouts[4].addWidget(self.details_button) self.column_layouts[4].addItem(VSpacer()) diff --git a/src/firefly/voltmeters.ui b/src/firefly/voltmeters.ui index 2991e0f0..9bab7c0f 100644 --- a/src/firefly/voltmeters.ui +++ b/src/firefly/voltmeters.ui @@ -6,7 +6,7 @@ 0 0 - 808 + 578 449