Пример #1
0
    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)
Пример #2
0
    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))
Пример #3
0
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')
Пример #4
0
    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()