Ejemplo n.º 1
0
Archivo: qt.py Proyecto: ess-dmsc/nicos
 def enableDisplay(self, layout, isvis):
     QFrame.setVisible(self, isvis)
     if self._label:
         self._label.setVisible(isvis)
     if not isvis:
         layout.removeWidget(self)
     else:
         layout.insertWidget(1, self)
     self.updateGeometry()
Ejemplo n.º 2
0
class ToftofProfileWindow(DlgUtils, QMainWindow):
    def __init__(self, parent):
        QMainWindow.__init__(self, parent)
        DlgUtils.__init__(self, 'Live data')
        self.panel = parent
        layout1 = QVBoxLayout()
        self.plot = QwtPlot(self)
        layout1.addWidget(self.plot)
        self.curve = QwtPlotCurve()
        self.curve.setRenderHint(QwtPlotCurve.RenderAntialiased)
        self.curve.attach(self.plot)
        self.marker = QwtPlotMarker()
        self.marker.attach(self.plot)
        self.markerpen = QPen(Qt.red)
        self.marker.setSymbol(
            QwtSymbol(QwtSymbol.Ellipse, QBrush(), self.markerpen, QSize(7,
                                                                         7)))
        self.zoomer = QwtPlotZoomer(self.plot.canvas())
        self.zoomer.setMousePattern(QwtPlotZoomer.MouseSelect3, Qt.NoButton)
        self.picker = QwtPlotPicker(self.plot.canvas())
        self.picker.setSelectionFlags(QwtPlotPicker.PointSelection
                                      | QwtPlotPicker.ClickSelection)
        self.picker.setMousePattern(QwtPlotPicker.MouseSelect1, Qt.MidButton)
        self.picker.selected.connect(self.pickerSelected)
        layout2 = QHBoxLayout()
        layout2.addWidget(QLabel('Scale:', self))
        self.scale = QComboBox(self)
        self.scale.addItems([
            'Single detectors, sorted by angle',
            'Scattering angle 2theta (deg)', 'Q value (A-1)'
        ])
        self.scale.currentIndexChanged[int].connect(self.scaleChanged)
        layout2.addWidget(self.scale)
        layout2.addStretch()
        self.scaleframe = QFrame(self)
        self.scaleframe.setLayout(layout2)
        self.scaleframe.setVisible(False)
        layout1.addWidget(self.scaleframe)
        mainframe = QFrame(self)
        mainframe.setLayout(layout1)
        self.setCentralWidget(mainframe)
        self.setContentsMargins(6, 6, 6, 6)
        plotfont = scaledFont(self.font(), 0.7)
        self.plot.setAxisFont(QwtPlot.xBottom, plotfont)
        self.plot.setAxisFont(QwtPlot.yLeft, plotfont)
        self.plot.setCanvasBackground(Qt.white)
        self.resize(800, 200)

        self._detinfo = None
        self._anglemap = None
        self._infowindow = None
        self._infolabel = None
        self._xs = self._ys = None
        self._type = None

    def _retrieve_detinfo(self):
        if self._detinfo is None:
            info = self.panel.client.eval(
                'det._detinfo_parsed, '
                'det._anglemap', None)
            if not info:
                return self.showError('Cannot retrieve detector info.')
            self._lambda = self.panel.client.eval('chWL()', None)
            if not self._lambda:
                return self.showError('Cannot retrieve wavelength.')
            self._detinfo, self._anglemap = info
            self._inverse_anglemap = 0
            self._infowindow = QMainWindow(self)
            self._infolabel = QLabel(self._infowindow)
            self._infolabel.setTextFormat(Qt.RichText)
            self._infowindow.setCentralWidget(self._infolabel)
            self._infowindow.setContentsMargins(10, 10, 10, 10)
            self._inv_anglemap = [[
                entry for entry in self._detinfo[1:]
                if entry[12] == self._anglemap[detnr] + 1
            ][0] for detnr in range(len(self._xs))]

    def scaleChanged(self, scale):
        self.update(self._type, self._orig_nbins, self._orig_x, self._orig_y)

    def update(self, proftype, nbins, x, y):
        self._orig_x = x
        self._orig_y = y
        self._orig_nbins = nbins
        x.setsize(8 * nbins)
        y.setsize(8 * nbins)
        xs = struct.unpack('d' * nbins, x)
        ys = struct.unpack('d' * nbins, y)
        if proftype == 0:
            if self.scale.currentIndex() == 0:
                xs = xs
            elif self.scale.currentIndex() == 1:
                self._retrieve_detinfo()
                xs = [self._inv_anglemap[int(xi)][5] for xi in xs]
            else:
                self._retrieve_detinfo()
                if self._lambda is None:
                    self.showError('Could not determine wavelength.')
                    self.scale.setCurrentIndex(1)
                    return
                xs = [
                    4 * pi / self._lambda *
                    sin(radians(self._inv_anglemap[int(xi)][5] / 2.))
                    for xi in xs
                ]
        self._xs = xs
        self._ys = ys
        self.curve.setData(xs, ys)
        self.plot.setAxisAutoScale(QwtPlot.xBottom)
        self.plot.setAxisAutoScale(QwtPlot.yLeft)
        self.marker.setVisible(False)
        self.zoomer.setZoomBase(True)
        self._type = proftype
        if proftype == 0:
            self.setWindowTitle(
                'Single detector view (time-channel integrated)')
            self.scaleframe.setVisible(True)
        elif proftype == 1:
            self.setWindowTitle('Time channel view (detector integrated)')
            self.scaleframe.setVisible(False)
        else:
            self.scaleframe.setVisible(False)

    def pickerSelected(self, point):
        if self._type != 0:
            return
        self._retrieve_detinfo()
        index = self.curve.closestPoint(self.picker.transform(point))[0]
        detentry = self._inv_anglemap[index][:]
        detentry.append(self._xs[index])
        detentry.append(self._ys[index])
        self.marker.setXValue(self._xs[index])
        self.marker.setYValue(self._ys[index])
        self.marker.setVisible(True)
        self.plot.replot()
        self._infowindow.show()
        entrynames = [
            'EntryNr', 'Rack', 'Plate', 'Pos', 'RPos', '2Theta', 'CableNr',
            'CableType', 'CableLen', 'CableEmpty', 'Card', 'Chan', 'Total',
            'DetName', 'BoxNr', 'BoxChan', 'XValue', 'Counts'
        ]
        formats = [
            '%s', '%d', '%d', '%d', '%d', '%.3f', '%d', '%d', '%.2f', '%d',
            '%d', '%d', '%d', '%r', '%d', '%d', '%s', '%d'
        ]
        empties = [1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0]
        self._infolabel.setText('Detector info:<br><table>' + ''.join(
            '<tr><td>%s</td><td></td><td>%s</td></tr>%s' %
            (name, format % value, '<tr></tr>' if empty else '')
            for (name, format, empty,
                 value) in zip(entrynames, formats, empties, detentry)) +
                                '</table>')

    def closeEvent(self, event):
        if self._infowindow:
            self._infowindow.close()
Ejemplo n.º 3
0
Archivo: qt.py Proyecto: ess-dmsc/nicos
class Monitor(BaseMonitor):
    """Qt specific implementation of instrument monitor."""

    parameters = {
        'noexpired': Param('If true, show expired values as "n/a"', type=bool)
    }

    _master = None

    def mainLoop(self):
        self._qtapp.exec_()

    def closeGui(self):
        if self._master:
            self._master.close()

    def _class_import(self, clsname):
        modname, member = clsname.rsplit('.', 1)
        mod = __import__(modname, None, None, [member])
        return getattr(mod, member)

    # pylint: disable=too-many-statements
    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()

    def signalKeyChange(self, obj, *args):
        self._master.keyChange.emit(obj, args)

    def newWidgetInfo(self, info):
        self._statuslabel.setText(info)

    def updateTitle(self, title):
        self._master.updateTitle.emit(title)

    def switchWarnPanel(self, on):
        self._master.switchWarnPanel.emit(on)

    def _switch_warnpanel(self, on):
        if on:
            if self._titlelabel:
                pal = self._titlelabel.palette()
                pal.setColor(QPalette.WindowText, self._black)
                pal.setColor(QPalette.Window, self._red)
                self._titlelabel.setPalette(pal)
            self._warnlabel.setText(self._currwarnings)
            self._warnpanel.setVisible(True)
            self._master.update()
        else:
            self._warnpanel.setVisible(False)
            if self._titlelabel:
                pal = self._titlelabel.palette()
                pal.setColor(QPalette.WindowText, self._gray)
                pal.setColor(QPalette.Window, self._bgcolor)
                self._titlelabel.setPalette(pal)
            # resize to minimum
            self.reconfigureBoxes()
            # self._master.update()

    def reconfigureBoxes(self):
        emitdict = {}
        fields = []
        for (layout, box) in self._onlyblocks:
            emitdict[layout, box] = checkSetupSpec(box.setups, self._setups,
                                                   log=self.log)
            # check fields inside the block, if the block isn't invisible
            if emitdict[layout, box]:
                fields.extend(box._onlyfields)
        # always check fields not in a setup controlled group
        fields.extend(self._onlyfields)
        for field in fields:
            emitdict[None, field] = checkSetupSpec(field.setups, self._setups,
                                                   log=self.log)
        self._master.reconfigure.emit(emitdict)