""" Gui header for SwissFEL """ from datetime import datetime import random from qtpy.QtCore import Qt, QTimer from qtpy.QtGui import QFont from qtpy.QtWidgets import (QApplication, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QRadioButton, QWidget) from caqtwidgets.pvwidgets import CAQLabel, QHLine, QVLine from pyqtacc.bdbase.enumkind import UserMode class GUIHeader(QWidget): """ GUI Header Class """ def __init__(self, parent, user_mode=UserMode.OPERATION, extended=True): super(GUIHeader, self).__init__() self.parent = parent self.appname = parent.appname self.title = parent.title self.settings = parent.settings self.user_mode = user_mode self.current_user_mode = user_mode self.extended = extended self.cafe = parent.cafe self.cyca = parent.cyca self.input_parameters = parent.input_parameters self.input_labels = parent.input_labels self.expert_parameters = parent.expert_parameters self.expert_labels = parent.expert_labels self.aramis_status = None self.athos_status = None self.porthos_status = None self.font_gui = QFont("sans serif") self.font_gui.setPointSize(11) self.font_pts10 = QFont("sans serif") self.font_pts10.setPointSize(10) self.widget_height = self.settings.data["StyleGuide"]["widgetHeight"] self.extra_height = self.settings.data["StyleGuide"]["extraGroupHeight"] self.aramis_color = self.settings.data["Aramis"]["color"] self.athos_color = self.settings.data["Athos"]["color"] self.porthos_color = self.settings.data["Porthos"]["color"] beamline = ["Aramis", "Athos", "Porthos"] pvlist = [] for item in beamline: if item not in self.settings.data: continue try: pvlist.append(self.settings.data[item]["laser"]) pvlist.append(self.settings.data[item]["freq"]) pvlist.append(self.settings.data[item]["beamStatus"]) pvlist.append(self.settings.data[item]["energy"]) pvlist.append(self.settings.data[item]["charge"]) pvlist.append(self.settings.data[item]["photonEnergy"]) except KeyError as error: print("KeyError in guiheader.py __init__", str(error)) for pv in self.settings.data["OpMsg"].values(): pvlist.append(pv) print(datetime.now()) self.cafe.openPrepare() self.cafe.open(pvlist) self.cafe.openNowAndWait(0.4) print(datetime.now()) self.cafe.printDisconnected() self.station_width = 200 #default self.station_height = 100 self.hor_layout = QHBoxLayout() self.hor_layout.addWidget(self.status_widget()) self.hor_layout.addWidget(self.aramis_widget()) self.hor_layout.addWidget(self.athos_widget()) yr_diff = abs(2032 - datetime.now().year) show_porthos = False try: if self.settings.data["showPorthos"]: show_porthos = True else: if random.randint(2, 12) > yr_diff: show_porthos = True except KeyError as error: print("KeyError in guiheader.py initialization:", str(error)) if random.randint(2, 12) > yr_diff: show_porthos = True if show_porthos: self.hor_layout.addWidget(self.porthos_widget()) self.hor_layout.setSpacing(10) self.hor_layout.setAlignment(Qt.AlignLeft) self.hor_layout.setContentsMargins(5, 0, 5, 0) self.header_wgt = QGroupBox() self.header_wgt.setObjectName(self.user_mode.name) self.header_wgt.setLayout(self.hor_layout) self.header_wgt.setFixedHeight(110) title = "SwissFEL {0}".format(self.user_mode.name) if self.title: title += ": {0}".format(self.title) self.header_wgt.setTitle(title) self.target_beamline = None self.timer = QTimer() self.timer.timeout.connect(self.blink_target_beamline) self.timer.start(500) self.timer_count = 0 def blink_target_beamline(self): self.timer_count += 1 if self.timer_count < 2: return if self.timer_count % 2 == 0: self.reset_beamline() else: self.set_target_beamline(target=self.target_beamline, reset=False) if self.timer_count > 4: self.timer.stop() QApplication.processEvents() def set_target_beamline(self, target, reset=True): """ Select beamline target and modify color scheme accordinly """ if not target: return if target == "Aramis": self.aramis_status.setObjectName("TARGET") self.aramis_status.setTitle("Target: Aramis") self.aramis_status.style().polish(self.aramis_status) elif target == "Athos": self.athos_status.setObjectName("TARGET") self.athos_status.setTitle("Target: Athos") self.athos_status.style().polish(self.athos_status) elif target == "Porthos" and self.porthos_status: if self.porthos_status: self.porthos_status.setObjectName("TARGET") self.porthos_status.setTitle("Target: Porthos") self.porthos_status.style().polish(self.porthos_status) if reset: self.reset_beamline() self.target_beamline = target def reset_beamline(self): """ Reset QGroupBox for previous target to original colors """ if self.target_beamline == "Aramis": self.reset_aramis() elif self.target_beamline == "Athos": self.reset_athos() elif self.target_beamline == "Porthos": self.reset_porthos() def reset_aramis(self): """ Reset Aramis QGroupBox color """ self.aramis_status.setObjectName("ARAMIS") self.aramis_status.setTitle("Aramis") self.aramis_status.style().polish(self.aramis_status) def reset_athos(self): """ Reset Athos QGroupBox color """ self.athos_status.setObjectName("ATHOS") self.athos_status.setTitle("Athos") self.athos_status.style().polish(self.athos_status) def reset_porthos(self): """ Reset Porthos QGroupBox color """ if self.porthos_status: self.porthos_status.setObjectName("PORTHOS") self.porthos_status.setTitle("Porthos") self.porthos_status.style().polish(self.porthos_status) def reset_operation_mode(self): """ Reset header colors to application operation mode """ self.change_operation_mode(user_mode=self.user_mode) def change_operation_mode(self, user_mode=UserMode.OPERATION): """ Different operation modes have different color schemes """ self.header_wgt.setObjectName(user_mode.name) self.header_wgt.setTitle(self.header_wgt.title().replace( self.current_user_mode.name, user_mode.name)) self.header_wgt.style().polish(self.header_wgt) self.current_user_mode = user_mode def beamline_widget(self, beamline="Aramis"): """ QGroupBox template for beamlines """ station = QGroupBox() station.setObjectName(beamline.upper()) station.setAlignment(Qt.AlignHCenter | Qt.AlignTop) station.setFlat(False) station.setTitle(beamline) laser = CAQLabel(self, pv_name=self.settings.data[beamline]["laser"]) laser.setFixedHeight(self.widget_height) freq = CAQLabel(self, pv_name=self.settings.data[beamline]["freq"], show_units=True) freq.setAlignment(Qt.AlignRight) freq.setFixedHeight(self.widget_height) freq.setFixedWidth(84) beamstatus = CAQLabel( self, pv_name=self.settings.data[beamline]["beamStatus"], color_mode="alarm") beamstatus.setFixedHeight(self.widget_height) grid_layout = QGridLayout() grid_layout.addWidget(laser, 0, 0, 1, 1, Qt.AlignCenter) grid_layout.addWidget(freq, 0, 1, 1, 1, Qt.AlignCenter) grid_layout.addWidget(beamstatus, 1, 0, 1, 2, Qt.AlignCenter) if self.extended: grid_layout.addWidget(QVLine(), 0, 2, 2, 1) filtered_energy = CAQLabel( self, pv_name=self.settings.data[beamline]["energy"], show_units=True) filtered_energy.setFixedHeight(self.widget_height) charge = CAQLabel( self, pv_name=self.settings.data[beamline]["charge"], show_units=True, notify_freq_hz=2) charge.setFixedHeight(self.widget_height) charge.setFixedWidth(78) photon_energy = CAQLabel( self, pv_name=self.settings.data[beamline]["photonEnergy"], show_units=False, suffix='\u00B5J') photon_energy.setFixedHeight(self.widget_height) photon_energy.setFixedWidth(66) #So aramis/Athos are the same grid_layout.addWidget(filtered_energy, 0, 3, 1, 2, Qt.AlignCenter) grid_layout.addWidget(charge, 1, 3, 1, 1, Qt.AlignCenter) grid_layout.addWidget(photon_energy, 1, 4, 1, 1, Qt.AlignCenter) grid_layout.setVerticalSpacing(0) grid_layout.setHorizontalSpacing(0) grid_layout.setContentsMargins(0, 10, 0, 0) #print(grid_layout.getContentsMargins()) station.setLayout(grid_layout) self.station_height = laser.height() + freq.height() + self.extra_height station.setFixedHeight(self.station_height) self.station_width = laser.width() + freq.width() + 10 if self.extended: self.station_width += (charge.width() + photon_energy.width()) station.setFixedWidth(self.station_width) station.setAlignment(Qt.AlignCenter) return station def aramis_widget(self): """ QGroupBox encompassing main Aramis parameters """ self.aramis_status = self.beamline_widget(beamline="Aramis") return self.aramis_status def athos_widget(self): """ QGroupBox encompassing main Athos parameters """ self.athos_status = self.beamline_widget(beamline="Athos") return self.athos_status def porthos_widget(self): """ QGroupBox encompassing main Porthos parameters """ #porthos = self.beamline_widget(beamline="Porthos") station = QGroupBox() station.setObjectName("Porthos".upper()) station.setAlignment(Qt.AlignHCenter | Qt.AlignTop) station.setFlat(False) station.setTitle("Porthos") grid_layout = QGridLayout() text = "Honest and extrovert!" \ if random.randint(1, 10) > 9 else "Arriving 2032" qlabel = QLabel(text) qlabel.setFont(self.font_pts10) qlabel.setAlignment(Qt.AlignCenter) grid_layout.addWidget(qlabel, 0, 0) station.setLayout(grid_layout) station.setFixedWidth(self.station_width) station.setFixedHeight(self.station_height) self.porthos_status = station return self.porthos_status def status_widget(self): """ QGroupBox encompassing machine status info """ station = QGroupBox() station.setObjectName("MACHINE") station.setAlignment(Qt.AlignHCenter | Qt.AlignTop) station.setFlat(False) station.setTitle("Status") date = CAQLabel(self, pv_name=self.settings.data["OpMsg"]["pvDate1"]) date.setFixedHeight(self.widget_height) eventno = CAQLabel( self, pv_name=self.settings.data["OpMsg"]["pvEventNo"], notify_freq_hz=10) eventno.setFixedHeight(self.widget_height) eventno.setAlignment(Qt.AlignCenter) message = CAQLabel( self, pv_name=self.settings.data["OpMsg"]["pvMsg1"]) message.setFixedHeight(self.widget_height) message.setFixedWidth(eventno.width() + date.width() + 2) grid_layout = QGridLayout() grid_layout.addWidget(date, 0, 0, 1, 1, Qt.AlignCenter) grid_layout.addWidget(eventno, 0, 1, 1, 1, Qt.AlignCenter) grid_layout.addWidget(message, 1, 0, 1, 2, Qt.AlignCenter) grid_layout.setVerticalSpacing(0) grid_layout.setHorizontalSpacing(0) grid_layout.setContentsMargins(0, 10, 0, 0) station.setLayout(grid_layout) station.setFixedHeight(eventno.height() + date.height() + self.extra_height) station.setFixedWidth(eventno.width() + date.width() + 10) self.machine_status = station return self.machine_status def operator_group_header(self): return self.radio_target_beamline() def radio_target_beamline(self): widget = QWidget() layout = QGridLayout() layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout) target_list = ["Aramis", "Athos"] self.radiobutton = [QRadioButton("Aramis"), QRadioButton("Athos")] try: if self.settings.data["showPorthos"]: target_list.append("Porthos") self.radiobutton.append(QRadioButton("Porthos")) except KeyError as error: print("KeyError in guiheader.py, def radio_target_beamline:", str(error)) color_list = [self.aramis_color, self.athos_color, self.porthos_color] width_list = [70, 64, 84] #width_list = [80, 74, 92] #pts 11 layout.addWidget(QHLine(), 0, 0, 1, 3) for i, (radio, target, color, width) in enumerate( zip(self.radiobutton, target_list, color_list, width_list)): #radio = QRadioButton(target) radio.setFont(self.font_pts10) radio.setStyleSheet("color : {0};".format(color)) radio.target = target radio.toggled.connect(self.on_target_clicked) layout.addWidget(radio, 1, i) radio.setFixedWidth(width) try: target = self.settings.data["Parameters"]["undulator"]["data"][ "value"] except KeyError as error: print("KeyError in guiheader.py, def radio_target_beamline:", str(error)) target = target_list[0] try: idx = target_list.index(target) except ValueError as error: print("ValueError in guiheader.py, def radio_target_beamline:", str(error)) idx = 0 self.radiobutton[idx].setChecked(True) self.radiobutton[idx].toggled.emit(True) layout.addWidget(QHLine(), 2, 0, 1, 3) widget.setLayout(layout) return widget def on_target_clicked(self): radio_button = self.sender() if radio_button.isChecked(): print("Target is {0}".format(radio_button.target)) self.set_target_beamline(radio_button.target) radio_button.setText(radio_button.target.upper()) self.timer.start(500) self.timer_count = 0 self.parent.input_parameters['undulator'] = radio_button.target for radio in self.radiobutton: if not radio.isChecked(): radio.setText(radio.target)