class TriggeredAcquisition(BaseWidget): def __init__(self, parent=None, prefix='', bpm=''): super().__init__(parent=parent, prefix=prefix, bpm=bpm) self.setupui() mode = SiriusConnectionSignal(self.get_pvname('ACQBPMMode-Sts')) mode.new_value_signal[int].connect(self.toggle_multi_single) self._chans.append(mode) def setupui(self): vbl = QGridLayout(self) lab = QLabel('<h2>' + self.bpm + ' Triggered Acquisitions</h2>') lab.setAlignment(Qt.AlignCenter) vbl.addWidget(lab, 0, 0, 1, 2) self.stack = QStackedLayout() multi_pass = MultiTurnData(parent=self, acq_type='ACQ', prefix=self.prefix, bpm=self.bpm) multi_pass.setObjectName('multi_pass') single_pass = SinglePassData(parent=self, prefix=self.prefix, bpm=self.bpm) single_pass.setObjectName('single_pass') self.stack.addWidget(multi_pass) self.stack.addWidget(single_pass) vbl.addLayout(self.stack, 1, 0) config = ACQTrigConfigs(parent=self, prefix=self.prefix, bpm=self.bpm, data_prefix='ACQ') config.setObjectName('config') vbl.addWidget(config, 1, 1) self.setStyleSheet(""" #multi_pass{ min-width:50em; min-height:48em;} #single_pass{ min-width:50em; min-height:48em;} #config{ min-height:21em;}""") def toggle_multi_single(self, modeidx): self.stack.setCurrentIndex(modeidx)
class MainApp(QWidget): LANDSCAPE = 0 PORTRAIT = 1 stop_signal = Signal() quality_changed = Signal(str) style_changed = Signal(object) last_frame_changed = Signal(object) def __init__(self): QWidget.__init__(self) self.styles = load_styles() self.image = StyledCapture(QImage(256, 256, QImage.Format_RGB888), '') # placeholder self.freeze = None if isinstance(settings.CAPTURE_HANDLER, string_types): self.capture_handler = locate(settings.CAPTURE_HANDLER) else: self.capture_handler = settings.CAPTURE_HANDLER self.setup_ui() self.frame_grabber = FrameGrabber(settings.SIZES[0]) self.frame_thread = QThread() # self.frame_grabber.image_signal.connect(self.display_frame) self.frame_grabber.last_frame_signal.connect(self.last_frame) self.frame_grabber.moveToThread(self.frame_thread) self.frame_thread.started.connect(self.frame_grabber.grab) self.stop_signal.connect(self.frame_grabber.stop_work) self.quality_changed.connect(self.frame_grabber.change_size) self.frame_thread.start() self.image_processor = ImageProcessor(self.styles[0]) self.image_thread = QThread() self.image_processor.image_signal.connect(self.display_frame) self.image_processor.moveToThread(self.image_thread) self.image_thread.started.connect(self.image_processor.monitor_images) self.stop_signal.connect(self.image_processor.stop_work) self.style_changed.connect(self.image_processor.change_style) self.last_frame_changed.connect(self.image_processor.change_last_frame) self.image_thread.start() def closeEvent(self, event): self.stop_signal.emit() self.frame_thread.quit() self.image_thread.quit() self.frame_thread.wait() self.image_thread.wait() def setup_ui(self): """Initialize widgets.""" def switch_style(i): view = self.landscape_view if self.view_mode == MainApp.LANDSCAPE else self.portrait_view self.style_changed.emit(self.styles[i]) view.selected_style = self.styles[i] for i in range(min(len(self.styles), len(settings.STYLE_SHORTCUTS))): QShortcut(QKeySequence(settings.STYLE_SHORTCUTS[i]), self, lambda x=i: switch_style(x)) self.landscape_view = LandscapeView(self.styles) self.landscape_view.style_changed.connect(self.style_button_clicked) self.landscape_view.toggle_fullscreen_signal.connect( self.toggle_fullscreen) self.landscape_view.quality_changed.connect(self.quality_choice) self.portrait_view = PortraitView(self.styles) self.portrait_view.style_changed.connect(self.style_button_clicked) self.portrait_view.toggle_fullscreen_signal.connect( self.toggle_fullscreen) self.portrait_view.quality_changed.connect(self.quality_choice) self.main_layout = QStackedLayout() self.main_layout.addWidget(self.landscape_view) self.main_layout.addWidget(self.portrait_view) self.setLayout(self.main_layout) self.view_mode = MainApp.LANDSCAPE self.setStyleSheet('background-color:black;' 'font-family: Arial;' 'font-style: normal;' 'font-size: 12pt;' 'font-weight: bold;' 'color:white;') self.setWindowTitle('Stylize') def keyPressEvent(self, event): if event.key() == Qt.Key_Escape and not settings.KIOSK: if self.windowState() & Qt.WindowFullScreen: self.showNormal() elif event.key() == Qt.Key_Enter or event.key() == Qt.Key_Return: self.image_capture() def last_frame(self, frame): self.last_frame_changed.emit(frame) def display_frame(self, image): self.image = image if not self.freeze: if self.view_mode == MainApp.LANDSCAPE: self.landscape_view.set_image(self.image.image) else: self.portrait_view.set_image(self.image.image) def resizeEvent(self, event): super(MainApp, self).resizeEvent(event) new_view_mode = MainApp.LANDSCAPE if self.width() >= self.height( ) else MainApp.PORTRAIT if self.view_mode != new_view_mode: old_view = self.portrait_view if new_view_mode == MainApp.LANDSCAPE else self.landscape_view new_view = self.landscape_view if new_view_mode == MainApp.LANDSCAPE else self.portrait_view new_view.quality = old_view.quality new_view.selected_style = old_view.selected_style self.view_mode = new_view_mode self.main_layout.setCurrentIndex(self.view_mode) def style_button_clicked(self, style): self.style_changed.emit(style) def toggle_fullscreen(self): if self.windowState() & Qt.WindowFullScreen: self.showNormal() else: self.showFullScreen() def quality_choice(self, quality): self.quality_changed.emit(quality) def image_capture(self): self.freeze = self.image.copy() # prevent background update try: self.capture_handler(self, self.freeze) except Exception: msg = QMessageBox(self) msg.setIcon(QMessageBox.Critical) msg.setText('Error during capture.') msg.setWindowFlags(Qt.FramelessWindowHint | Qt.Popup) msg.exec_() self.freeze = None
class PSDiag(SiriusMainWindow): """Power Supply Diagnostic.""" def __init__(self, parent=None, prefix=VACA_PREFIX): """Init.""" super().__init__(parent) self._prefix = prefix self.setWindowTitle('PS Diagnostics') self.setObjectName('ASApp') cor = _get_appropriate_color(section='AS') self.setWindowIcon(qta.icon('mdi.stethoscope', color=cor)) self._setupUi() self._initialized = False def _setupUi(self): # Leds Panel cw = QWidget(self) panel = QWidget(cw) panel_lay = QGridLayout() panel_lay.setVerticalSpacing(0) panel_lay.setHorizontalSpacing(5) panel.setLayout(panel_lay) # # Leds Header for i, lab in enumerate([ '', 'PS\nConn?', 'Power\nState', 'Interlock', 'OpMode\nSlowRef?', 'Current\nDiff']): label = QLabel(lab, panel, alignment=Qt.AlignCenter) label.setStyleSheet('min-width:3.4em; max-width:3.4em;') panel_lay.addWidget(label, 0, i) # # Leds panel _on = _PSConst.PwrStateSts.On _slowref = _PSConst.States.SlowRef _rmpwfm = _PSConst.States.RmpWfm i = 2 for sec in ['LI', 'TB', 'BO', 'TS', 'SI']: seclabel = QLabel('<h3>'+sec+'</h3>', panel) panel_lay.addWidget(seclabel, i, 0) i += 1 if sec == 'LI': for label, filt in lips2filters.items(): ps_label = QLabel( label, panel, alignment=Qt.AlignRight | Qt.AlignVCenter) psnames = PSSearch.get_psnames(filters=filt) ps_c2v = dict() ilk_c2v = dict() conn_chs = list() for name in psnames: pvn = _PVName(name).substitute(prefix=self._prefix) conn_chs.append(pvn.substitute(propty='PwrState-Sts')) ps_c2v[pvn.substitute(propty='PwrState-Sts')] = 1 ilk_c2v[pvn.substitute(propty='StatusIntlk-Mon')] = \ {'value': _PS_LI_INTLK, 'comp': 'lt'} f = 'LI-.*:PS-'+filt['dev'] conn_led = MyLedMultiConnection( filters=f, parent=panel, channels=conn_chs) ps_led = MyLedMultiChannel( filters=f, parent=panel, channels2values=ps_c2v) if 'Spect' in filt['dev']: intlk_led = LISpectIntlkLed(panel, filters=f) else: intlk_led = MyLedMultiChannel( filters=f, parent=panel, channels2values=ilk_c2v) suf = sec+filt['dev'].strip('.*')+'_led' conn_led.setObjectName('conn' + suf) ps_led.setObjectName('ps' + suf) intlk_led.setObjectName('intlk' + suf) panel_lay.addWidget(ps_label, i, 0) panel_lay.addWidget(conn_led, i, 1) panel_lay.addWidget(ps_led, i, 2) panel_lay.addWidget(intlk_led, i, 3) i += 1 else: l2f = sips2filters if sec == 'SI' else asps2filters for label, filt in l2f.items(): filt['sec'] = sec psnames = PSSearch.get_psnames(filters=filt) if not psnames: continue psconn_chs = list() ps_c2v = dict() ilk_c2v = dict() opm_c2v = dict() df_c2v = dict() for name in psnames: pvn = _PVName(name).substitute(prefix=self._prefix) ps_c2v[pvn.substitute(propty='PwrState-Sts')] = _on if name.dis == 'PS': psconn_chs.append( pvn.substitute(propty='Version-Cte')) ilk_c2v[pvn.substitute(propty='IntlkSoft-Mon')] = 0 ilk_c2v[pvn.substitute(propty='IntlkHard-Mon')] = 0 opm_pvn = pvn.substitute(propty='OpMode-Sts') if sec == 'BO': opm_c2v[opm_pvn] = { 'value': [_slowref, _rmpwfm], 'comp': 'in'} else: opm_c2v[opm_pvn] = _slowref df_c2v[pvn.substitute(propty='DiagStatus-Mon')] = \ {'value': 0, 'bit': 5} elif name.dis == 'PU': psconn_chs.append( pvn.substitute(propty='PwrState-Sts')) intlkcount = 7 if 'Sept' in name.dev else 8 for idx in range(1, intlkcount+1): ppty = 'Intlk'+str(idx)+'-Mon' pvn = pvn.substitute(propty=ppty) ilk_c2v[pvn] = 1 f = sec+'-'+filt['sub']+':'+psnames[0].dis+'-'+filt['dev'] ps_label = QLabel( label, panel, alignment=Qt.AlignRight | Qt.AlignVCenter) psconn_led = MyLedMultiConnection( filters=f, parent=panel, channels=psconn_chs) ps_led = MyLedMultiChannel( filters=f, parent=panel, channels2values=ps_c2v) intlk_led = MyLedMultiChannel( filters=f, parent=panel, channels2values=ilk_c2v) suf = sec+filt['dev'].strip('.*')+'_led' psconn_led.setObjectName('psconn' + suf) ps_led.setObjectName('ps' + suf) intlk_led.setObjectName('intlk' + suf) panel_lay.addWidget(ps_label, i, 0) panel_lay.addWidget(psconn_led, i, 1) panel_lay.addWidget(ps_led, i, 2) panel_lay.addWidget(intlk_led, i, 3) if psnames[0].dis == 'PS': opm_led = MyLedMultiChannel( filters=f, parent=panel, channels2values=opm_c2v) opm_led.setOnColor(PyDMLed.LightGreen) opm_led.setOffColor(PyDMLed.Yellow) diff_led = MyLedMultiChannel( filters=f, parent=panel, channels2values=df_c2v) opm_led.setObjectName('opm' + suf) diff_led.setObjectName('diff' + suf) panel_lay.addWidget(opm_led, i, 4) panel_lay.addWidget(diff_led, i, 5) i += 1 panel_lay.addItem(QSpacerItem(1, 10, QSzPlcy.Ignored, QSzPlcy.MinimumExpanding), i, 0) i += 1 # Current State and Log Tables table_label2px = { 'Date': 110, 'Time': 85, 'Type': 70, 'PS Name': 145, 'Property': 85, 'Value': 120} channels = list() for ps in PSSearch.get_psnames(filters={'dis': 'PS'}): channels.append(_PVName(ps).substitute( prefix=self._prefix, propty='DiagCurrentDiff-Mon')) channels.append(_PVName(ps).substitute( prefix=self._prefix, propty='OpMode-Sts')) self._status = LogTable(cw, channels, table_label2px, is_status=True) self._status.setObjectName('status_table') self._status.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self._status.updated.connect(self._filter_table) self._log = LogTable(cw, channels, table_label2px) self._log.setObjectName('log_table') self._log.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn) self._tables_stack = QStackedLayout() self._tables_stack.addWidget(self._status) self._tables_stack.addWidget(self._log) self._rb_status = QRadioButton('Status', self) self._rb_status.setObjectName('rb_status') self._rb_status.setChecked(True) self._visible_table = self._status self._rb_status.toggled.connect(_partial(self._toggle_table, 0)) self._rb_log = QRadioButton('Log', self) self._rb_log.setObjectName('rb_log') self._rb_log.toggled.connect(_partial(self._toggle_table, 1)) for name, width in table_label2px.items(): attr = '_search_'+name.replace(' ', '').lower() setattr(self, attr, QLineEdit()) le = getattr(self, attr) le.setObjectName(name) le.setPlaceholderText(name + '...') le.editingFinished.connect(self._filter_table) width = str(width-1) if name == 'Value': le.setStyleSheet( '#'+name+'{min-width:'+width+'px;}') le.setSizePolicy(QSzPlcy.Expanding, QSzPlcy.Maximum) else: le.setStyleSheet( '#'+name+'{min-width:'+width+'px; max-width:'+width+'px;}') le.setSizePolicy(QSzPlcy.Maximum, QSzPlcy.Maximum) self._scrollup_pb = QPushButton('↟', cw) self._scrollup_pb.setObjectName('scrollup_pb') self._scrollup_pb.clicked.connect(self._arrange_table) self._scrolldown_pb = QPushButton('↡', cw) self._scrolldown_pb.setObjectName('scrolldown_pb') self._scrolldown_pb.clicked.connect(self._arrange_table) tables_lay = QGridLayout() tables_lay.setVerticalSpacing(2) tables_lay.setHorizontalSpacing(0) tables_lay.addWidget(self._search_date, 0, 0) tables_lay.addWidget(self._search_time, 0, 1) tables_lay.addWidget(self._search_type, 0, 2) tables_lay.addWidget(self._search_psname, 0, 3) tables_lay.addWidget(self._search_property, 0, 4) tables_lay.addWidget(self._search_value, 0, 5) tables_lay.addWidget(self._scrollup_pb, 0, 6, alignment=Qt.AlignRight) tables_lay.addLayout(self._tables_stack, 1, 0, 1, 7) tables_lay.addWidget(self._rb_status, 2, 0, alignment=Qt.AlignLeft) tables_lay.addWidget(self._rb_log, 2, 1, alignment=Qt.AlignLeft) tables_lay.addWidget(self._scrolldown_pb, 2, 6, alignment=Qt.AlignRight) tables = QWidget(cw) tables.setObjectName('tables') tables.setLayout(tables_lay) # Connect signals for led in self.findChildren(QLed): led.shape = PyDMLed.ShapeMap.Round led.filterlog.connect(self._filter_table) led.warning.connect(self._log.add_log_slot) led.warning.connect(self._status.add_log_slot) led.normal.connect(self._status.remove_log_slot) # Layout window_title = QLabel('<h2>Power Supplies Diagnostics</h2>', cw, alignment=Qt.AlignCenter) layout = QGridLayout() layout.setVerticalSpacing(20) layout.setHorizontalSpacing(5) layout.addWidget(window_title, 0, 0, 1, 2) layout.addWidget(panel, 1, 0) layout.addWidget(tables, 1, 1) cw.setStyleSheet(""" #scrollup_pb, #scrolldown_pb{ max-height: 1em; max-width: 0.7em; color: #464646; } QLineEdit{ max-height: 1em; } #status_table, #log_table{ border: 1px solid #bebebe; } #tables{ min-width: 700px; } #rb_status, #rb_log{ min-width: 5em; max-width: 5em; max-height: 1em; }""") cw.setLayout(layout) self.setCentralWidget(cw) def _arrange_table(self): text = self.sender().text() if '↟' in text: self._visible_table.scrollToTop() elif '↡' in text: self._visible_table.scrollToBottom() def _filter_table(self, text=''): # identify first user interaction if isinstance(self.sender(), (QLineEdit, QLed)): self._initialized = True # ignore initializing if not self._initialized: return # set led's filter if isinstance(self.sender(), QLed): self.blockSignals(True) self._search_psname.setText(text) self.blockSignals(False) # get search filters pats = list() date_txt = self._search_date.text() time_txt = self._search_time.text() logtype_txt = self._search_type.text() psname_txt = self._search_psname.text() property_txt = self._search_property.text() value_txt = self._search_value.text() try: if date_txt: pats.append([_re.compile(date_txt, _re.I), 0]) if time_txt: pats.append([_re.compile(time_txt, _re.I), 1]) if logtype_txt: pats.append([_re.compile(logtype_txt, _re.I), 2]) if psname_txt: pats.append([_re.compile(psname_txt, _re.I), 3]) if property_txt: pats.append([_re.compile(property_txt, _re.I), 4]) if value_txt: pats.append([_re.compile(value_txt, _re.I), 5]) except Exception: return m = self._visible_table.model() for row in range(m.rowCount()): for pat, col in pats: if not pat.search(m.data(m.index(row, col))): self._visible_table.setRowHidden( row, self._visible_table.rootIndex(), True) break else: self._visible_table.setRowHidden( row, self._visible_table.rootIndex(), False) def _toggle_table(self, i, toggle): if not toggle: return self._tables_stack.setCurrentIndex(i) if i == 0: self._log.updated.disconnect(self._filter_table) self._status.updated.connect(self._filter_table) self._visible_table = self._status else: self._status.updated.disconnect(self._filter_table) self._log.updated.connect(self._filter_table) self._visible_table = self._log self._filter_table()