def addExperiment(self): textLabel = QLabel('Experiment:') textLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) textLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) experimentLabel = QLabel('Unknown') experimentLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.toolBarMain.addWidget(textLabel) self.toolBarMain.addWidget(experimentLabel) # if INSTRUMENT is defined add the logo/name of the instrument experiment = os.getenv('EXPERIMENT') if experiment: experimentLabel.setText(experiment)
def addInstrument(self): textLabel = QLabel('Instrument:') textLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) textLabel.setAlignment(Qt.AlignRight | Qt.AlignVCenter) instrumentLabel = QLabel('Unknown') instrumentLabel.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.toolBarMain.addWidget(textLabel) self.toolBarMain.addWidget(instrumentLabel) instrument = os.getenv('INSTRUMENT') if instrument: instrument = instrument.split('.')[-1] logo = decolor_logo(QPixmap('resources/%s-logo.svg' % instrument), Qt.white) if logo.isNull(): instrumentLabel.setText(instrument.upper()) return instrumentLabel.setPixmap( logo.scaledToHeight(self.toolBarMain.height(), Qt.SmoothTransformation))
class MainWindow(DefaultMainWindow): ui = '%s/main.ui' % uipath def __init__(self, log, gui_conf, viewonly=False, tunnel=''): DefaultMainWindow.__init__(self, log, gui_conf, viewonly, tunnel) self.add_logo() self.set_icons() self.style_file = gui_conf.stylefile # Cheeseburger menu dropdown = QMenu('') dropdown.addAction(self.actionConnect) dropdown.addAction(self.actionViewOnly) dropdown.addAction(self.actionPreferences) dropdown.addAction(self.actionExpert) dropdown.addSeparator() dropdown.addAction(self.actionExit) self.actionUser.setMenu(dropdown) self.actionUser.setIconVisibleInMenu(True) self.dropdown = dropdown self.actionExpert.setEnabled(self.client.isconnected) self.actionEmergencyStop.setEnabled(self.client.isconnected) self._init_instrument_name() self._init_experiment_name() def _init_toolbar(self): self.statusLabel = QLabel('', self, pixmap=QPixmap(':/disconnected'), margin=5, minimumSize=QSize(30, 10)) self.statusLabel.setStyleSheet('color: white') self.toolbar = self.toolBarRight self.toolbar.addWidget(self.statusLabel) self.setStatus('disconnected') def _init_experiment_name(self): self.experiment_text = QLabel() self.experiment_text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.experiment_text.setStyleSheet( 'font-size: 17pt; font-weight: bold') self.toolBarMain.addWidget(self.experiment_text) self.experiment_label = QLabel() self.experiment_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.experiment_label.setStyleSheet('font-size: 17pt') self.toolBarMain.addWidget(self.experiment_label) def _init_instrument_name(self): self.instrument_text = QLabel() self.instrument_text.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.instrument_text.setStyleSheet( 'font-size: 17pt; font-weight: bold') self.toolBarMain.addWidget(self.instrument_text) self.instrument_label = QLabel() self.instrument_label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred) self.instrument_label.setStyleSheet('font-size: 17pt') self.toolBarMain.addWidget(self.instrument_label) def set_icons(self): self.actionUser.setIcon(get_icon('settings_applications-24px.svg')) self.actionEmergencyStop.setIcon( get_icon('emergency_stop_cross-24px.svg')) self.actionConnect.setIcon(get_icon('power-24px.svg')) self.actionExit.setIcon(get_icon('exit_to_app-24px.svg')) self.actionViewOnly.setIcon(get_icon('lock-24px.svg')) self.actionPreferences.setIcon(get_icon('tune-24px.svg')) self.actionExpert.setIcon(get_icon('fingerprint-24px.svg')) def add_logo(self): logo_label = QLabel() pxr = decolor_logo( QPixmap(path.join(root_path, 'resources', 'logo-icon.png')), Qt.white) logo_label.setPixmap( pxr.scaledToHeight(self.toolBarMain.height(), Qt.SmoothTransformation)) logo_label.setMargin(5) self.toolBarMain.insertWidget(self.toolBarMain.actions()[0], logo_label) nicos_label = QLabel() pxr = decolor_logo( QPixmap(path.join(root_path, 'resources', 'nicos-logo-high.svg')), Qt.white) nicos_label.setPixmap( pxr.scaledToHeight(self.toolBarMain.height(), Qt.SmoothTransformation)) self.toolBarMain.insertWidget(self.toolBarMain.actions()[1], nicos_label) def update_instrument_text(self): instrument = self.client.eval('session.instrument', None) self.instrument_text.setText('Instrument:') if instrument: logo = decolor_logo( QPixmap( path.join(root_path, 'resources', f'{instrument}-logo.svg')), Qt.white) if logo.isNull(): self.instrument_label.setText(instrument.upper()) return self.instrument_label.setPixmap( logo.scaledToHeight(self.toolBarMain.height(), Qt.SmoothTransformation)) else: self.instrument_label.setText('UNKNOWN') def update_experiment_text(self): max_text_length = 50 experiment = self.client.eval('session.experiment.title', None) if experiment is not None: self.experiment_text.setText(" Experiment:") self.experiment_label.setText(experiment[0:max_text_length]) def remove_experiment_and_instrument(self): self.experiment_label.clear() self.experiment_text.clear() self.instrument_label.clear() self.instrument_text.clear() def reloadQSS(self): self.setQSS(self.stylefile) def selectQSS(self): style_file = QFileDialog.getOpenFileName( self, filter="Qt Stylesheet Files (*.qss)")[0] if style_file: self.style_file = style_file self.setQSS(self.style_file) @staticmethod def setQSS(style_file): with open(style_file, 'r', encoding='utf-8') as fd: try: QApplication.instance().setStyleSheet(fd.read()) except Exception as e: print(e) def setStatus(self, status, exception=False): if status == self.current_status: return if self.client.last_action_at and \ self.current_status == 'running' and \ status in ('idle', 'paused') and \ current_time() - self.client.last_action_at > 20: # show a visual indication of what happened if status == 'paused': msg = 'Script is now paused.' elif exception: msg = 'Script has exited with an error.' else: msg = 'Script has finished.' self.trayIcon.showMessage(self.instrument, msg) self.client.last_action_at = 0 self.current_status = status is_connected = status != 'disconnected' if is_connected: self.actionConnect.setText('Disconnect') self.statusLabel.setText('\u2713 Connected') self.update_instrument_text() self.update_experiment_text() else: self.actionConnect.setText('Connect to server...') self.statusLabel.setText('Disconnected') self.setTitlebar(False) # new status icon pixmap = QPixmap(':/' + status + ('exc' if exception else '')) new_icon = QIcon() new_icon.addPixmap(pixmap, QIcon.Disabled) self.trayIcon.setIcon(new_icon) self.trayIcon.setToolTip('%s status: %s' % (self.instrument, status)) if self.showtrayicon: self.trayIcon.show() if self.promptWindow and status != 'paused': self.promptWindow.close() # propagate to panels for panel in self.panels: panel.updateStatus(status, exception) for window in self.windows.values(): for panel in window.panels: panel.updateStatus(status, exception) def on_client_connected(self): DefaultMainWindow.on_client_connected(self) self.actionConnect.setIcon(get_icon("power_off-24px.svg")) self.actionExpert.setEnabled(True) self.actionEmergencyStop.setEnabled(not self.client.viewonly) def on_client_disconnected(self): DefaultMainWindow.on_client_disconnected(self) self.remove_experiment_and_instrument() self.actionConnect.setIcon(get_icon("power-24px.svg")) self.actionExpert.setEnabled(False) self.actionExpert.setChecked(False) self.actionEmergencyStop.setEnabled(False) def on_actionViewOnly_toggled(self, on): DefaultMainWindow.on_actionViewOnly_toggled(self, on) if self.client.isconnected: self.actionEmergencyStop.setEnabled(not self.client.viewonly) else: self.actionEmergencyStop.setEnabled(False) @pyqtSlot(bool) def on_actionConnect_triggered(self, _): # connection or disconnection request? connection_req = self.current_status == "disconnected" super().on_actionConnect_triggered(connection_req) @pyqtSlot() def on_actionUser_triggered(self): w = self.toolBarRight.widgetForAction(self.actionUser) self.dropdown.popup(w.mapToGlobal(QPoint(0, w.height()))) @pyqtSlot() def on_actionEmergencyStop_triggered(self): self.client.tell_action('emergency')
def initGui(self): def log_unhandled(*exc_info): traceback.print_exception(*exc_info) self.log.exception('unhandled exception in QT callback', exc_info=exc_info) sys.excepthook = log_unhandled self._qtapp = QApplication(['qtapp'], organizationName='nicos', applicationName='gui') self._master = master = MonitorWindow() if self._geometry == 'fullscreen': master.showFullScreen() master._wantFullScreen = True # In some Qt5 versions, showFullScreen is buggy and doesn't # actually resize the window (but hides decoration etc). # So, explicitly set the geometry of the first screen. master.setGeometry(QApplication.screens()[0].geometry()) QCursor.setPos(master.geometry().bottomRight()) elif isinstance(self._geometry, tuple): w, h, x, y = self._geometry master.setGeometry(x, y, w, h) # colors used for the display of watchdog warnings, not for the # individual value displays self._bgcolor = QColor('gray') self._black = QColor('black') self._red = QColor('red') self._gray = QColor('gray') master.setWindowTitle(self.title) self._bgcolor = master.palette().color(QPalette.Window) timefont = QFont(self.font, self._timefontsize) blockfont = QFont(self.font, self._fontsizebig) warnfont = QFont(self.font, self._fontsizebig) warnfont.setBold(True) labelfont = QFont(self.font, self._fontsize) stbarfont = QFont(self.font, int(self._fontsize * 0.8)) valuefont = QFont(self.valuefont or self.font, self._fontsize) blheight = QFontMetrics(blockfont).height() tiheight = QFontMetrics(timefont).height() # split window into to panels/frames below each other: # one displays time, the other is divided further to display blocks. # first the timeframe: masterframe = QFrame(master) masterlayout = QVBoxLayout() if self.title: self._titlelabel = QLabel( '', master, font=timefont, autoFillBackground=True, alignment=Qt.AlignHCenter) pal = self._titlelabel.palette() pal.setColor(QPalette.WindowText, self._gray) self._titlelabel.setPalette(pal) self._titlelabel.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) self._master.updateTitle.connect(self._titlelabel.setText) masterlayout.addWidget(self._titlelabel) masterlayout.addSpacing(0.2 * tiheight) else: self._titlelabel = None self._warnpanel = QFrame(master) self._warnpanel.setVisible(False) warningslayout = QVBoxLayout() lbl = QLabel('Warnings', self._warnpanel, font=warnfont) lbl.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Fixed) warningslayout.addWidget(lbl) self._warnlabel = SqueezedLabel('', self._warnpanel, font=blockfont) warningslayout.addWidget(self._warnlabel) self._warnpanel.setLayout(warningslayout) masterlayout.addWidget(self._warnpanel) master.switchWarnPanel.connect(self._switch_warnpanel) displayframe = QFrame(master) self._plots = {} colorScheme = lightColorScheme if self.colors == 'light' else None fontCache = {1.0: valuefont} def _create_field(groupframe, field): def _setup(widget): fontscale = field.get('fontscale', 1.0) if fontscale not in fontCache: fontCache[fontscale] = scaledFont(valuefont, fontscale) widget.valueFont = fontCache[fontscale] widget.setFont(labelfont) for key in field: if key in widget.properties: setattr(widget, key, field[key]) widget.setSource(self) if hasattr(widget, 'widgetInfo'): widget.widgetInfo.connect(self.newWidgetInfo) return widget if isinstance(field, str): field = {'dev': field} if 'min' in field: field['min'] = repr(field['min']) if 'max' in field: field['max'] = repr(field['max']) setups = field.get('setups', None) if 'gui' in field: resource = findResource(field.pop('gui')) try: instance = uic.loadUi(resource) except Exception as err: self.log.exception('could not load .ui file %r, ignoring', resource) instance = QLabel('%r could not be loaded:\n%s' % (resource, err)) else: for child in instance.findChildren(NicosWidget): _setup(child) instance.setups = setups return instance elif 'widget' in field: widget_class = self._class_import(field.pop('widget')) widget = widget_class(groupframe) if isinstance(widget, NicosWidget): _setup(widget) for child in widget.findChildren(NicosWidget): _setup(child) widget.setups = setups return widget elif 'plot' in field and plot_available: # XXX make this more standard plotwidget = self._plots.get(field['plot']) if plotwidget: plotwidget.devices += [field.get('dev', field.get('key', ''))] plotwidget.names += [field.get('name', field.get('dev', field.get('key', '')))] return None plotwidget = TrendPlot(groupframe) _setup(plotwidget) plotwidget.legend = field.get('legend', True) plotwidget.plotwindow = field.get('plotwindow', 3600) plotwidget.plotinterval = field.get('plotinterval', 2) self._plots[field['plot']] = plotwidget plotwidget.devices = [field.get('dev', field.get('key', ''))] plotwidget.names = [field.get('name', field.get('dev', field.get('key', '')))] plotwidget.setups = setups return plotwidget elif 'picture' in field: picwidget = PictureDisplay(groupframe) picwidget.filepath = field['picture'] picwidget.setups = setups return _setup(picwidget) else: display = ValueDisplay(groupframe, colorScheme=colorScheme, showExpiration=self.noexpired) display.setups = setups return _setup(display) # now iterate through the layout and create the widgets to display it displaylayout = QVBoxLayout(spacing=20) for superrow in self.layout: boxlayout = QHBoxLayout(spacing=20) boxlayout.setContentsMargins(10, 10, 10, 10) for column in superrow: columnlayout = QVBoxLayout(spacing=0.8*blheight) for block in column: block = self._resolve_block(block) blocklayout_outer = QHBoxLayout() blocklayout_outer.addStretch() blocklayout = QVBoxLayout() blocklayout.addSpacing(0.5 * blheight) blockbox = BlockBox(displayframe, block._title, blockfont, block._options) for row in block: if row in (None, '---'): blocklayout.addSpacing(12) else: rowlayout = QHBoxLayout() rowlayout.addStretch() rowlayout.addSpacing(self._padding) for field in row: fieldwidget = _create_field(blockbox, field) if fieldwidget: rowlayout.addWidget(fieldwidget) rowlayout.addSpacing(self._padding) if fieldwidget.setups: if blockbox.setups: blockbox._onlyfields.append(fieldwidget) else: self._onlyfields.append(fieldwidget) # start hidden fieldwidget.setHidden(True) rowlayout.addStretch() blocklayout.addLayout(rowlayout) if blockbox.setups: self._onlyblocks.append((blocklayout_outer, blockbox)) blockbox.setHidden(True) # start hidden blocklayout.addSpacing(0.3 * blheight) blockbox.setLayout(blocklayout) blocklayout_outer.addWidget(blockbox) blocklayout_outer.addStretch() columnlayout.addLayout(blocklayout_outer) columnlayout.addStretch() boxlayout.addLayout(columnlayout) displaylayout.addLayout(boxlayout) displayframe.setLayout(displaylayout) for plot in self._plots.values(): plot.setSource(self) masterlayout.addWidget(displayframe) masterframe.setLayout(masterlayout) master.setCentralWidget(masterframe) # initialize status bar self._statuslabel = QLabel(font=stbarfont) master.statusBar().addWidget(self._statuslabel) self._statustimer = None master.show()