Example #1
0
class StatusLed(BaseLed):
    designer_description = 'LED showing the status of the device'
    designer_icon = ':/leds/yellow_on'

    dev = PropDef('dev', str, '', 'Device name')
    key = PropDef('key', str, '', 'Key name of the device')

    colors = {
        OK: 'green',
        BUSY: 'yellow',
        WARN: 'orange',
        NOTREACHED: 'red',
        DISABLED: 'gray',
        ERROR: 'red',
        UNKNOWN: 'gray',
    }

    def propertyUpdated(self, pname, value):
        if pname == 'dev':
            if value:
                self.key = value + '.status'
        BaseLed.propertyUpdated(self, pname, value)

    def on_keyChange(self, key, value, time, expired):
        if value is None:
            expired = True
            value = (OK, '')
        if expired:
            self.ledStatus = False
        else:
            self.ledStatus = True
        self.ledColor = self.colors[value[0]]
Example #2
0
class ValueLed(BaseLed):
    designer_description = 'LED showing if the selected value is true'

    dev = PropDef('dev', str, '', 'NICOS device to use the value')
    key = PropDef('key', str, '', 'Key to use as the value')
    goal = PropDef(
        'goal', str, '', 'Comparison value (by default the LED is '
        'green if value is true/nonzero)')

    _goalval = None

    def propertyUpdated(self, pname, value):
        if pname == 'dev':
            if value:
                self.key = value + '.value'
        elif pname == 'goal':
            self._goalval = ast.literal_eval(value) if value else None
        BaseLed.propertyUpdated(self, pname, value)

    def on_keyChange(self, key, value, time, expired):
        if expired:
            self.ledStatus = False
        else:
            self.ledStatus = True
        if self._goalval is not None:
            green = value == self._goalval
        else:
            green = value
        if green:
            self.ledColor = 'green'
        else:
            self.ledColor = 'red'
Example #3
0
class RefsansWidget(NicosWidget, RefsansView):

    tubeangle = PropDef('tubeangle', str, '', 'Inclination of the tube')
    pivot = PropDef('pivot', str, '', 'Mounting point of the tube (pivot)')
    detpos = PropDef('detpos', str, '', 'Detector position inside tube')

    def __init__(self, parent):
        RefsansView.__init__(self, parent=parent)
        NicosWidget.__init__(self)

        self._keymap = {}
        self._statuskeymap = {}
        self._targetkeymap = {}

    def registerKeys(self):
        for dev in ['tubeangle', 'pivot', 'detpos']:
            devname = self.props.get(dev)
            if devname:
                k = self._source.register(self, devname + '/value')
                self._keymap[k] = dev
                k = self._source.register(self, devname + '/status')
                self._statuskeymap[k] = dev
                k = self._source.register(self, devname + '/target')
                self._targetkeymap[k] = dev

    def on_keyChange(self, key, value, time, expired):
        if key in self._keymap and not expired:
            self.values[self._keymap[key]] = value
            self.update()
        elif key in self._statuskeymap and not expired:
            self.status[self._statuskeymap[key]] = value[0]
            self.update()
        elif key in self._targetkeymap and not expired:
            self.targets[self._targetkeymap[key]] = value
            self.update()
Example #4
0
class BeamOption(NicosWidget, QWidget):

    designer_description = 'SANS-1 beam option'

    def __init__(self, parent, designMode=False):
        self._curstr = ''
        self._curstatus = OK
        self._fixed = ''

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    dev = PropDef('dev', str, '', 'NICOS device name')
    height = PropDef('height', int, 4, 'Widget height in characters')
    width = PropDef('width', int, 10, 'Widget width in characters')
    name = PropDef('name', str, '', 'Display name')

    def sizeHint(self):
        return QSize(
            self.props['width'] * self._scale,
            self.props['height'] * self._scale +
            (self.props['name'] and self._scale * 2.5 or 0))

    def registerKeys(self):
        self.registerDevice(self.props['dev'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        self._curstr = unitvalue
        self.update()

    def on_devMetaChange(self, dev, fmtstr, unit, fixed):
        self._fixed = fixed
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        self._curstatus = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setBrush(_magenta)
        painter.setRenderHint(QPainter.Antialiasing)

        w = self.props['width'] * self._scale
        h = self.props['height'] * self._scale

        if self.props['name']:
            painter.setFont(self.font())
            painter.drawText(0, 0, w, self._scale * 2.5, Qt.AlignCenter,
                             self.props['name'])
            yoff = self._scale * 2.5
        else:
            yoff = 0
        painter.setBrush(statusbrush[self._curstatus])
        painter.drawRect(2, 2 + yoff, w - 4, h - 4)
        painter.setFont(self.valueFont)
        painter.drawText(2, 2 + yoff, w - 4, h - 4, Qt.AlignCenter,
                         self._curstr)
Example #5
0
class BaseLed(QLabel, NicosWidget):

    designer_icon = ':/leds/green_on'

    _ledPatternName = ':/leds/{color}_{status}'

    ledStatus = PropDef('ledStatus', bool, True, 'Status to display the '
                        '"On color" (bright)')
    ledInverted = PropDef('ledInverted', bool, False, 'Status to display the '
                          '"Off color" (dark)')
    ledColor = PropDef('ledColor', str, 'green', 'Color of the LED (default '
                       'is green)')

    def __init__(self, parent=None, designMode=False):
        QLabel.__init__(self, parent)
        NicosWidget.__init__(self)
        self._refresh()

    def sizeHint(self):
        if self.layout() is None:
            return QSize(24, 24)
        return QLabel.sizeHint(self)

    def minimumSizeHint(self):
        return QSize(8, 8)

    def _refresh(self):
        status = self.props['ledStatus']
        inverted = self.props['ledInverted']
        color = self.props['ledColor']
        if inverted:
            status = not status
        status = status and "on" or "off"
        ledName = self._ledPatternName.format(color=color, status=status)
        pixmap = QPixmap(ledName).scaled(self.size(), Qt.KeepAspectRatio,
                                         Qt.SmoothTransformation)
        self.setPixmap(pixmap)
        self.setAlignment(Qt.AlignCenter)

    def resizeEvent(self, event):
        self._refresh()
        return QWidget.resizeEvent(self, event)

    def registerKeys(self):
        self.registerKey(self.props['key'])

    def propertyUpdated(self, pname, value):
        self._refresh()
        NicosWidget.propertyUpdated(self, pname, value)
Example #6
0
class SinglePushButton(PushButton):

    designer_description = 'Simulation of a push button with a light and only'\
                           ' one state to swith On or Off'
    designer_icon = ':/leds/yellow_on'

    toState = PropDef('toState', str, '1', 'Target for action')

    def __init__(self, parent=None, designMode=False):
        self._stateTo = 1
        PushButton.__init__(self, parent, designMode)

    def propertyUpdated(self, pname, value):
        PushButton.propertyUpdated(self, pname, value)

        if pname == 'toState':
            if isinstance(value, str):
                self._stateTo = value
            else:
                self._stateTo = ast.literal_eval(value) if value else 1

    def mousePressEvent(self, event):

        if event.button() == Qt.LeftButton:
            self._client.run('move(%s, %r)' % (self.dev, self._stateTo))
        event.accept()
Example #7
0
class ClickableOutputLed(ValueLed):
    designer_description = 'Digital Output Led that changes device state on click'
    designer_icon = ':/leds/orange_on'

    ledColor = PropDef('ledColor', str, 'orange', 'Default led color')
    stateActive = PropDef('stateActive', str, '1', 'Target for active LED '
                          'state (green)')
    stateInactive = PropDef('stateInactive', str, '0', 'Target for inactive '
                            'LED state (red)')

    def __init__(self, parent=None, designMode=False):
        self.current = None
        self._stateActive = 1
        self._stateInactive = 0
        ValueLed.__init__(self, parent, designMode)

    def on_keyChange(self, key, value, time, expired):
        ValueLed.on_keyChange(self, key, value, time, expired)
        self.current = value

    def propertyUpdated(self, pname, value):
        ValueLed.propertyUpdated(self, pname, value)

        if pname == 'stateInactive':
            if isinstance(value, string_types):
                self._stateInactive = value
            else:
                self._stateInactive = ast.literal_eval(value) if value else 0
        if pname == 'stateActive':
            if isinstance(value, string_types):
                self._stateActive = value
            else:
                self._stateActive = ast.literal_eval(value) if value else 1

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.ledColor = 'orange'
            if self.current == self._stateActive:
                self._client.run('move(%s, %r)' %
                                 (self.dev, self._stateInactive))
            else:
                self._client.run('move(%s, %r)' %
                                 (self.dev, self._stateActive))

            event.accept()
        else:
            event.ignore()
Example #8
0
class ValueLabel(SqueezedLabel):
    """Label that just displays a single value."""

    designer_description = 'A label that just displays a single value'
    # designer_icon = ':/'     # XXX add appropriate icons

    dev = PropDef('dev', str, '', 'NICOS device name, if set, display '
                  'value of this device')
    key = PropDef('key', str, '', 'Cache key to display')
    format = PropDef(
        'format', str, '', 'Python format string to use for the '
        'value; if "dev" is given this defaults to the '
        '"fmtstr" set in NICOS')

    def __init__(self, parent, designMode=False, **kwds):
        self._designMode = designMode
        SqueezedLabel.__init__(self, parent, designMode, **kwds)
        if designMode:
            self.setText('(value display)')
        self._callback = lambda value, strvalue: from_maybe_utf8(strvalue)

    def setFormatCallback(self, callback):
        self._callback = callback

    def propertyUpdated(self, pname, value):
        if pname == 'dev':
            if value:
                self.key = value + '.value'
        elif pname == 'key' and self._designMode:
            self.setText('(%s)' % value)
        NicosWidget.propertyUpdated(self, pname, value)

    def registerKeys(self):
        if self.props['dev']:
            self.registerDevice(self.props['dev'], fmtstr=self.props['format'])
        else:
            self.registerKey(self.props['key'], fmtstr=self.props['format'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        if expired:
            setForegroundColor(self, QColor('grey'))
        else:
            setForegroundColor(self, QColor('black'))
            self.setText(self._callback(value, strvalue))
Example #9
0
class DeviceParamEdit(DeviceValueEdit):

    designer_description = 'Editor for a device parameter with the right ' \
        'kind of widget'

    param = PropDef('param', str, '', 'Parameter name')

    def propertyUpdated(self, pname, value):
        if pname in ('dev', 'param'):
            self._reinit()
        NicosWidget.propertyUpdated(self, pname, value)

    def registerKeys(self):
        self.registerKey(self.props['dev'] + '.' + self.props['param'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        if self.props['updateValue']:
            self._reinit(value)

    def _reinit(self, curvalue=None):
        if not self._client:
            return
        devname = str(self.props['dev'])
        parname = str(self.props['param'])
        if devname and parname:
            pvals = self._client.getDeviceParams(devname)
            pinfo = self._client.getDeviceParamInfo(devname) or {}
            mainunit = pvals.get('unit', 'main')
            if parname not in pinfo:
                punit = ''
                valuetype = str
            else:
                punit = (pinfo[parname]['unit']
                         or '').replace('main', mainunit)
                valuetype = pinfo[parname]['type']
            if curvalue is None:
                curvalue = pvals.get(parname)
            if curvalue is None and valuetype is not None:
                curvalue = valuetype()
        else:
            valuetype = str
            curvalue = ''
            punit = ''
        self._inner = create(self,
                             valuetype,
                             curvalue,
                             unit=punit,
                             client=self._client)
        last = self._layout.takeAt(0)
        if last:
            last.widget().deleteLater()
        self._layout.insertWidget(0, self._inner)
        self._inner.valueModified.connect(self.valueModified)
Example #10
0
class BeamPosition(CollimatorTable):

    designer_description = 'REFSANS NOK and slit table'

    key = PropDef('key', str, '', 'Cache key to display')

    def __init__(self, parent, designMode=False):
        CollimatorTable.__init__(self, parent, designMode)

    def registerKeys(self):
        self.registerKey(self.props['key'])
        CollimatorTable.registerKeys(self)
Example #11
0
class DeviceParamTree(NicosWidget, BaseDeviceParamTree):

    designer_description = 'Displays devices and their parameters'

    showparams = PropDef('showparams', bool, True, 'Show parameters as subitems')

    def __init__(self, parent, designMode=False, **kwds):
        BaseDeviceParamTree.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)

    def setClient(self, client):
        NicosWidget.setClient(self, client)
        BaseDeviceParamTree.setClient(self, client)

    def propertyUpdated(self, pname, value):
        if pname == 'showparams':
            self._showparams = value
        NicosWidget.propertyUpdated(self, pname, value)
Example #12
0
class TrendPlot(NicosWidget, QWidget):

    designer_description = 'A trend plotter for one or more devices'
    designer_icon = ':/plotter'

    widgetInfo = pyqtSignal(str)
    timeSeriesUpdate = pyqtSignal(object)

    # colors = [Qt.red, Qt.darkGreen, Qt.blue, Qt.black, Qt.magenta, Qt.cyan,
    #           Qt.darkGray]

    devices = PropDef(
        'devices', 'QStringList', [], '''
List of devices or cache keys that the plot should display.

For devices use device name. For keys use cache key with "." or "/" separator,
e.g. T.heaterpower.

To access items of a sequence, use subscript notation, e.g. T.userlimits[0]
''')
    names = PropDef(
        'names', 'QStringList', [], 'Names for the plot curves, '
        'defaults to the device names/keys.')
    legend = PropDef('legend', bool, False, 'If a legend should be shown.')
    plotwindow = PropDef(
        'plotwindow', int, 3600, 'The range of time in '
        'seconds that should be represented by the plot.')
    plotinterval = PropDef(
        'plotinterval', float, 2, 'The minimum time in '
        'seconds between two points that should be '
        'plotted.')
    height = PropDef(
        'height', int, 10, 'Height of the plot widget in units '
        'of app font character width.')
    width = PropDef(
        'width', int, 30, 'Width of the plot widget in units '
        'of app font character width.')

    # pylint: disable=W0231
    def __init__(self, parent, designMode=False):
        self.ncurves = 0
        self.ctimers = {}
        self.keyindices = {}
        self.plotcurves = {}
        self.series = {}
        self.legendobj = None

        # X label settings, default values for default window of 3600s
        self._showdate = False
        self._showsecs = False

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    def initUi(self):
        # axes setup
        self.widget = InteractiveGRWidget(self)
        self.plot = Plot(viewport=(.1, .95, .25, .95))
        self.axes = NicosTimePlotAxes(self.plot._viewport)
        self.axes.setWindow(0, 1, 0, 1)
        self.plot.addAxes(self.axes)
        self.plot.setLegend(True)
        self.plot.setLegendWidth(0.07)
        self.plot.offsetXLabel = -.2
        self.axes.setXtickCallback(self.xtickCallBack)
        self.widget.addPlot(self.plot)
        layout = QHBoxLayout(self)
        layout.addWidget(self.widget)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self.curves = []

        # event support
        self.widget.cbm.addHandler(LegendEvent.ROI_CLICKED,
                                   self.on_legendItemClicked, LegendEvent)
        self.widget.cbm.addHandler(MouseEvent.MOUSE_MOVE, self.on_mouseMove)

        self.timeSeriesUpdate.connect(self.on_timeSeriesUpdate)

    def xtickCallBack(self, x, y, _svalue, value):
        gr.setcharup(-1., 1.)
        gr.settextalign(gr.TEXT_HALIGN_RIGHT, gr.TEXT_VALIGN_TOP)
        dx = .02
        timeVal = localtime(value)
        if self._showdate:
            gr.text(x + dx, y - 0.01, strftime(DATEFMT, timeVal))
        if self._showsecs:
            gr.text(x - dx, y - 0.01, strftime(TIMEFMT, timeVal))
        else:
            gr.text(x - dx, y - 0.01, strftime(SHORTTIMEFMT, timeVal))
        gr.setcharup(0., 1.)

    def propertyUpdated(self, pname, value):
        if pname == 'plotwindow':
            self._showdate = value > 24 * 3600
            self._showsecs = value < 300
        elif pname in ('width', 'height'):
            self.setMinimumSize(
                QSize(self._scale * (self.props['width'] + .5),
                      self._scale * (self.props['height'] + .5)))
        elif pname == 'legend':
            self.plot.setLegend(value)
        NicosWidget.propertyUpdated(self, pname, value)

    def setFont(self, font):
        pass  # TODO: can't set font for GR right now

    def on_mouseMove(self, event):
        wc = event.getWC(self.plot.viewport)
        ts = strftime(DATEFMT + ' ' + TIMEFMT, localtime(wc.x))
        msg = 't = %s, y = %g' % (ts, wc.y)
        self.widgetInfo.emit(msg)

    def on_legendItemClicked(self, event):
        if event.getButtons() & MouseEvent.LEFT_BUTTON:
            event.curve.visible = not event.curve.visible
            self.update()

    def on_timeSeriesUpdate(self, series):
        curve = self.plotcurves[series]
        curve.x = series.x
        curve.y = series.y
        c = self.axes.getCurves()
        dy = abs(c.ymin - c.ymax) * 0.05
        self.axes.setWindow(c.xmin, c.xmax, c.ymin - dy, c.ymax + dy)
        self.widget.update()
        self.ctimers[curve].start(5000)

    def on_keyChange(self, key, value, time, expired):
        if key not in self.keyindices or value is None:
            return
        for index in self.keyindices[key]:
            series = self.series[key, index]
            # restrict time of value to 1 minute past at
            # maximum, so that it doesn't get culled by the windowing
            time = max(time, currenttime() - 60)
            if index:
                try:
                    fvalue = functools.reduce(operator.getitem, index, value)
                    series.add_value(time, fvalue)
                except Exception:
                    pass
            else:
                series.add_value(time, value)

    def addcurve(self, key, index, title, scale, offset):
        series = TimeSeries(key, self.props['plotinterval'], scale, offset,
                            self.props['plotwindow'], self)
        series.init_empty()
        curve = PlotCurve([currenttime()], [0], legend=title)
        self.plotcurves[series] = curve
        self.ncurves += 1
        self.curves.append(curve)
        self.axes.addCurves(curve)
        self.series[key, index] = series
        self.widget.update()

        # record the current value at least every 5 seconds, to avoid curves
        # not updating if the value doesn't change
        def update():
            series.synthesize_value()

        self.ctimers[curve] = QTimer(singleShot=True)
        self.ctimers[curve].timeout.connect(update)

    def registerKeys(self):
        for key, name in zip_longest(self.props['devices'],
                                     self.props['names']):
            if name is None:
                name = key
            key, index, scale, offset = extractKeyAndIndex(key)
            keyid = self._source.register(self, key)
            self.keyindices.setdefault(keyid, []).append(index)
            self.addcurve(keyid, index, name, scale, offset)
Example #13
0
class VRefsans(NicosWidget, QWidget):

    designer_description = 'Display of the REFSANS NOK configuration'

    nok0dev = PropDef('nok0dev', str, '', 'NOK 0 device')
    shutter_gammadev = PropDef('shutter_gammadev', str, '', 'NOK 1 device')
    nok2dev = PropDef('nok2dev', str, '', 'NOK 2 device')
    nok3dev = PropDef('nok3dev', str, '', 'NOK 3 device')
    nok4dev = PropDef('nok4dev', str, '', 'NOK 4 device')
    nok5adev = PropDef('nok5adev', str, '', 'NOK 5a device')
    nok5bdev = PropDef('nok5bdev', str, '', 'NOK 5b device')
    nok6dev = PropDef('nok6dev', str, '', 'NOK 6 device')
    nok7dev = PropDef('nok7dev', str, '', 'NOK 7 device')
    nok8dev = PropDef('nok8dev', str, '', 'NOK 8 device')
    height = PropDef('height', int, 30, 'Widget height in characters')
    width = PropDef('width', int, 40, 'Widget width in characters')

    def __init__(self, parent, designMode=False):
        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

        # default values (used when no such devices are configured)
        self.values = {
            'nok0': 0,
            'shutter_gamma': 0,
            'nok2': (0, 0),
            'nok3': (0, 0),
            'nok4': (0, 0),
            'nok5a': (0, 0),
            'nok5b': (0, 0),
            'nok6': (0, 0),
            'nok7': (0, 0),
            'nok8': (0, 0),
        }
        self.targets = self.values.copy()
        self.status = {
            'nok0': OK,
            'shutter_gamma': OK,
            'nok2': OK,
            'nok3': OK,
            'nok4': OK,
            'nok5a': OK,
            'nok5b': OK,
            'nok6': OK,
            'nok7': OK,
            'nok8': OK,
        }
        self._keymap = {}
        self._statuskeymap = {}
        self._targetkeymap = {}
        self._lengthkeymap = {}
        self._length = [0, 100, 300, 600, 1000, 1720, 1720, 1720, 1190, 880]
        self._fulllength = sum(self._length)

    def registerKeys(self):
        for dev in [
                'nok0', 'shutter_gamma', 'nok2', 'nok3', 'nok4', 'nok5a',
                'nok5b', 'nok6', 'nok7', 'nok8'
        ]:
            devname = str(self.props[dev + 'dev'])
            if devname:
                k1 = self._source.register(self, devname + '/value')
                self._keymap[k1] = dev
                k2 = self._source.register(self, devname + '/status')
                self._statuskeymap[k2] = dev
                k3 = self._source.register(self, devname + '/target')
                self._targetkeymap[k3] = dev
                k4 = self._source.register(self, devname + '/length')
                self._lengthkeymap[k4] = dev

    def on_keyChange(self, key, value, time, expired):
        if key in self._keymap and not expired:
            self.values[self._keymap[key]] = value
            self.update()
        elif key in self._statuskeymap and not expired:
            self.status[self._statuskeymap[key]] = value[0]
            self.update()
        elif key in self._targetkeymap and not expired:
            self.targets[self._targetkeymap[key]] = value
            self.update()
        elif key in self._lengthkeymap and not expired:
            self.targets[self._lengthkeymap[key]] = value
            self.update()

    def sizeHint(self):
        return QSize(self.props['width'] * self._scale + 2,
                     self.props['height'] * self._scale + 2)

    def _calculatePoint(self, ind, x, y):
        w, h = self.width * self._scale, self.height * self._scale
        x = sum(self._length[0:ind])
        mx = 4 + w * x / self._fulllength
        my = 5 + h * y / 400
        return (mx, my)

    def paintEvent(self, event):
        w, h = self.width * self._scale, self.height * self._scale
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.setPen(QColor('black'))
        painter.setBrush(_white)
        painter.drawRect(1, 1, w, h)

        # determine positions
        beam = QPolygonF([QPointF(4, 5)])
        i = 0
        for k in [
                'nok0', 'shutter_gamma', 'nok2', 'nok3', 'nok4', 'nok5a',
                'nok5b', 'nok6', 'nok7', 'nok8'
        ]:
            v = self.values[k]
            if isinstance(v, (tuple, readonlylist)):
                x, y = v  # pylint: disable=W0633
            elif isinstance(v, int):
                x, y = 0, v
            else:
                raise Exception('%r' % type(v))
            p = self._calculatePoint(i, x, y)
            beam.append(QPointF(p[0], p[1]))
            i += 1
        x, y = self.values['nok8']
        p = self._calculatePoint(i + 1, x, y)

        painter.setPen(beambackgroundpen)
        painter.drawPolyline(beam)

        # draw beam
        painter.setPen(beampen)
        painter.drawPolyline(beam)
Example #14
0
class TimeDistance(NicosWidget, TimeDistanceWidget):

    designer_description = 'REFSANS time distance diagram display'

    chopper1 = PropDef('chopper1', str, 'chopper1', 'Chopper 1 device')
    chopper2 = PropDef('chopper2', str, 'chopper2', 'Chopper 2 device')
    chopper3 = PropDef('chopper3', str, 'chopper3', 'Chopper 3 device')
    chopper4 = PropDef('chopper4', str, 'chopper4', 'Chopper 4 device')
    chopper5 = PropDef('chopper5', str, 'chopper5', 'Chopper 5 device')
    chopper6 = PropDef('chopper6', str, 'chopper6', 'Chopper 6 device')

    disc2_pos = PropDef('disc2_pos', str, 'disc2_pos',
                        'Position of disc2 translation')

    periods = PropDef('periods', int, 2, 'Number of periods to display')
    D = PropDef('D', float, 22.8, 'Beamline length')

    fp = PropDef('flightpath', str, 'real_flight_path', 'Flight path device')

    def __init__(self, parent, designMode=False):
        TimeDistanceWidget.__init__(self, parent)
        NicosWidget.__init__(self)
        self._speed = 0
        self._phases = [0] * 6
        self._disk2_pos = 5
        self._fp = 0

    def registerKeys(self):
        # chopperspeed, chopper phases,a
        for dev in ['chopper1', 'disc2_pos']:
            devname = self.props.get(dev)
            if devname:
                self._source.register(self, devname + '/value')

        for dev in [
                'chopper1', 'chopper2', 'chopper3', 'chopper4', 'chopper5',
                'chopper6'
        ]:
            devname = self.props.get(dev)
            if devname:
                self._source.register(self, devname + '/phase')

        devname = self.props.get('chopper2')
        if devname:
            self._source.register(self, devname + '/pos')

        devname = self.props.get('fp')
        if devname:
            self._source.register(self, devname + '/value')

    def on_keyChange(self, key, value, time, expired):
        _, dev, param = key.split('/')
        devs = [key for key, d in self.props.items() if d == dev]
        if devs:
            devname = devs[0]
            if param == 'value':
                if value is None:
                    return
                if devname == 'chopper1':
                    self._speed = int(value)
                elif devname == 'disc2_pos':
                    self._disk2_pos = int(value)
                elif devname == 'fp':
                    self._fp = int(value)
            elif param == 'phase':
                if devname.startswith('chopper'):
                    if value is not None:
                        index = int(devname[-1]) - 1
                        self._phases[index] = float(value)
            elif param == 'pos' and devname == 'chopper2':
                if value is not None:
                    self._disk2_pos = int(value)
            self.plot(self._speed, self._phases, self.props['periods'],
                      self._disk2_pos, self.props['D'], self._fp)
Example #15
0
class TasWidget(NicosWidget, QWidget):
    """Display of the TAS table configuration."""

    designer_description = __doc__

    mthdev = PropDef('mthdev', str, '', 'Monochromator rocking angle device')
    mttdev = PropDef('mttdev', str, '',
                     'Monochromator scattering angle device')
    sthdev = PropDef('sthdev', str, '', 'Sample rotation device')
    sttdev = PropDef('sttdev', str, '', 'Sample scattering angle device')
    athdev = PropDef('athdev', str, '', 'Analyzer rocking angle device')
    attdev = PropDef('attdev', str, '', 'Analyzer scattering angle device')
    Lmsdev = PropDef('Lmsdev', str, '',
                     'Distance monochromator->sample device')
    Lsadev = PropDef('Lsadev', str, '', 'Distance sample->analyzer device')
    Laddev = PropDef('Laddev', str, '', 'Distance analyzer->detector device')
    height = PropDef('height', int, 30, 'Widget height in characters')
    width = PropDef('width', int, 40, 'Widget width in characters')

    def __init__(self, parent, designMode=False):
        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

        # default values (used when no such devices are configured)
        self.values = {
            'mth': -45,
            'mtt': -90,
            'sth': 30,
            'stt': 60,
            'ath': -45,
            'att': -90,
            'Lms': 1000,
            'Lsa': 580,
            'Lad': 400,
        }
        self.targets = self.values.copy()
        self.status = {
            'mth': OK,
            'mtt': OK,
            'sth': OK,
            'stt': OK,
            'ath': OK,
            'att': OK,
        }
        self._keymap = {}
        self._statuskeymap = {}
        self._targetkeymap = {}

    def registerKeys(self):
        for dev in [
                'mth', 'mtt', 'sth', 'stt', 'ath', 'att', 'Lms', 'Lsa', 'Lad'
        ]:
            devname = str(self.props[dev + 'dev'])
            if devname:
                k1 = self._source.register(self, devname + '/value')
                self._keymap[k1] = dev
                k2 = self._source.register(self, devname + '/status')
                self._statuskeymap[k2] = dev
                k3 = self._source.register(self, devname + '/target')
                self._targetkeymap[k3] = dev

    def on_keyChange(self, key, value, time, expired):
        if key in self._keymap and not expired:
            self.values[self._keymap[key]] = value
            self.update()
        elif key in self._statuskeymap and not expired:
            self.status[self._statuskeymap[key]] = value[0]
            self.update()
        elif key in self._targetkeymap and not expired:
            self.targets[self._targetkeymap[key]] = value
            self.update()

    def sizeHint(self):
        return QSize(self.props['width'] * self._scale + 2,
                     self.props['height'] * self._scale + 2)

    def paintEvent(self, event):
        s = self.size()
        w, h = s.width(), s.height()
        # calculate the maximum length if all elements in a line
        maxL = self.values['Lms'] + self.values['Lsa'] + self.values['Lad']
        # add the size of the Monochromator and detector
        scale = min((w / 2 - anaradius) / float(maxL),
                    (h - monoradius - anaradius) / float(maxL))

        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.setPen(QColor('black'))
        painter.setBrush(_white)
        painter.drawRect(0, 0, w, h)

        # determine positions

        # incoming beam
        if self.values['mth'] < 0:
            bx, by = 3, h - (2 + monoradius)
        else:
            bx, by = 3, 2 + monoradius
        # monochromator
        mx, my = w / 2., by

        # sample
        L = self.values['Lms'] * scale  # length is in mm -- scale down a bit
        mttangle = self.values['mtt'] * deg2rad
        mttangle_t = self.targets['mtt'] * deg2rad
        if self.values['mth'] < 0:
            mttangle = -mttangle
            mttangle_t = -mttangle_t

        sx, sy = mx + L * cos(mttangle), my - L * sin(mttangle)
        sx_t, sy_t = mx + L * cos(mttangle_t), my - L * sin(mttangle_t)

        # analyzer
        L = self.values['Lsa'] * scale  # length is in mm -- scale down a bit
        sttangle = self.values['stt'] * deg2rad
        sttangle_t = self.targets['stt'] * deg2rad
        if self.values['sth'] < 0:
            sttangle = mttangle - sttangle
            sttangle_t = mttangle_t - sttangle_t
        else:
            sttangle = mttangle + sttangle
            sttangle_t = mttangle_t + sttangle_t
        ax, ay = sx + L * cos(sttangle), sy - L * sin(sttangle)
        ax_t, ay_t = sx_t + L * cos(sttangle_t), sy_t - L * sin(sttangle_t)

        # detector
        L = self.values['Lad'] * scale  # length is in mm -- scale down a bit
        attangle = self.values['att'] * deg2rad
        attangle_t = self.targets['att'] * deg2rad
        if self.values['ath'] < 0:
            attangle = sttangle - attangle
            attangle_t = sttangle_t - attangle_t
        else:
            attangle = sttangle + attangle
            attangle_t = sttangle_t + attangle_t

        dx, dy = ax + L * cos(attangle), ay - L * sin(attangle)
        dx_t, dy_t = ax_t + L * cos(attangle_t), ay_t - L * sin(attangle_t)

        # draw table "halos"
        painter.setPen(nopen)
        if self.status['mth'] != OK:
            painter.setBrush(statusbrush[self.status['mth']])
            painter.drawEllipse(QPoint(mx, my), monoradius + halowidth,
                                monoradius + halowidth)
        elif self.status['mtt'] != OK:
            painter.setBrush(statusbrush[self.status['mtt']])
            painter.drawEllipse(QPoint(mx, my), monoradius + halowidth,
                                monoradius + halowidth)
        if self.status['sth'] != OK:
            painter.setBrush(statusbrush[self.status['sth']])
            painter.drawEllipse(QPoint(sx, sy), sampleradius + halowidth,
                                sampleradius + halowidth)
        elif self.status['stt'] != OK:
            painter.setBrush(statusbrush[self.status['stt']])
            painter.drawEllipse(QPoint(sx, sy), sampleradius + halowidth,
                                sampleradius + halowidth)
        if self.status['ath'] != OK:
            painter.setBrush(statusbrush[self.status['ath']])
            painter.drawEllipse(QPoint(ax, ay), anaradius + halowidth,
                                anaradius + halowidth)
        elif self.status['att'] != OK:
            painter.setBrush(statusbrush[self.status['att']])
            painter.drawEllipse(QPoint(ax, ay), anaradius + halowidth,
                                anaradius + halowidth)

        # draw table targets
        painter.setPen(targetpen)
        painter.setBrush(_nobrush)
        painter.drawEllipse(QPoint(sx_t, sy_t), sampleradius - .5,
                            sampleradius - .5)
        painter.drawEllipse(QPoint(ax_t, ay_t), anaradius - .5, anaradius - .5)
        painter.drawEllipse(QPoint(dx_t, dy_t), detradius - .5, detradius - .5)

        # draw the tables
        painter.setPen(defaultpen)
        painter.setBrush(monotablebrush)
        painter.drawEllipse(QPoint(mx, my), monoradius, monoradius)
        painter.setBrush(sampletablebrush)
        painter.drawEllipse(QPoint(sx, sy), sampleradius, sampleradius)
        painter.setBrush(anatablebrush)
        painter.drawEllipse(QPoint(ax, ay), anaradius, anaradius)
        painter.setBrush(dettablebrush)
        painter.drawEllipse(QPoint(dx, dy), detradius, detradius)
        painter.setBrush(_white)
        painter.setPen(nopen)
        painter.drawEllipse(QPoint(mx, my), monoradius / 2, monoradius / 2)
        # painter.drawEllipse(QPoint(sx, sy), 20, 20)
        painter.drawEllipse(QPoint(ax, ay), anaradius / 2, anaradius / 2)
        # painter.drawEllipse(QPoint(dx, dy), 20, 20)

        beam = QPolygonF([
            QPointF(bx, by),
            QPointF(mx, my),
            QPointF(sx, sy),
            QPointF(ax, ay),
            QPointF(dx, dy)
        ])
        painter.setPen(beambackgroundpen)
        painter.drawPolyline(beam)

        # draw mono crystals
        painter.setPen(monopen)
        mthangle = -self.values['mth'] * deg2rad
        painter.drawLine(mx + 10 * cos(mthangle), my - 10 * sin(mthangle),
                         mx - 10 * cos(mthangle), my + 10 * sin(mthangle))

        # draw ana crystals
        athangle = -self.values['ath'] * deg2rad
        alpha = athangle + sttangle
        # TODO if the angle is too small then it could be that the ath value
        # must be turned by 90 deg (PANDA: chair setup) ??
        if attangle < 0 and alpha < attangle:
            alpha += pi_2
        painter.drawLine(ax + 10 * cos(alpha), ay - 10 * sin(alpha),
                         ax - 10 * cos(alpha), ay + 10 * sin(alpha))

        # draw sample
        painter.setPen(samplepen)
        painter.setBrush(samplebrush)
        sthangle = self.values['sth'] * deg2rad
        alpha = sthangle + mttangle + pi_4
        # painter.drawRect(sx - 5, sy - 5, 10, 10)
        sz = 10
        painter.drawPolygon(
            QPolygonF([
                QPointF(sx + sz * cos(alpha), sy - sz * sin(alpha)),
                QPointF(sx + sz * cos(alpha + pi_2),
                        sy - sz * sin(alpha + pi_2)),
                QPointF(sx - sz * cos(alpha), sy + sz * sin(alpha)),
                QPointF(sx - sz * cos(alpha + pi_2),
                        sy + sz * sin(alpha + pi_2)),
                QPointF(sx + sz * cos(alpha), sy - sz * sin(alpha))
            ]))

        painter.setPen(samplecoordpen)
        sr = sampleradius
        for angle in [alpha - pi_4, alpha - 3 * pi_4]:
            painter.drawLine(sx - sr * cos(angle), sy + sr * sin(angle),
                             sx + sr * cos(angle), sy - sr * sin(angle))

        # draw detector
        painter.setPen(monopen)
        painter.setBrush(_white)
        painter.drawEllipse(QPoint(dx, dy), 4, 4)

        # draw beam
        painter.setPen(beampen)
        painter.drawPolyline(beam)
Example #16
0
class Tube(NicosWidget, QWidget):

    designer_description = 'KWS tube'

    devices = PropDef('devices', 'QStringList', [])
    height = PropDef('height', int, 10, 'Widget height in characters')
    width = PropDef('width', int, 30, 'Widget width in characters')
    name = PropDef('name', str, '')
    posscale = PropDef('posscale', float, 20)
    color = PropDef('color', 'QColor', _grey.color())
    beamstop = PropDef('beamstop', bool, False,
                       'Beamstop instead of detector Y/Z')
    smalldet = PropDef(
        'smalldet', float, 0, 'Positioning of small detector, '
        'or zero for no small detector')

    def __init__(self, parent, designMode=False):
        # z, x, y, small_x, small_y
        self._curval = [0, 0, 0, 0, 0]
        self._curstr = ['', '', '', '', '']
        self._curstatus = [OK, OK, OK, OK, OK]

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    def sizeHint(self):
        return QSize(
            self.props['width'] * self._scale + 10,
            self.props['height'] * self._scale +
            (self.props['smalldet'] and 50 or 0) +
            (self.props['name'] and self._scale * 2.5 or 0) + 40)

    def registerKeys(self):
        for dev in self.props['devices']:
            self.registerDevice(str(dev))

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curval[idx] = value
        self._curstr[idx] = unitvalue
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curstatus[idx] = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setBrush(QBrush(self.color))
        painter.setRenderHint(QPainter.Antialiasing)

        fontscale = float(self._scale)
        h = self.props['height'] * fontscale
        w = self.props['width'] * fontscale
        posscale = (w - 100) / self.props['posscale']

        # Draw name above tube
        if self.props['name']:
            painter.setFont(self.font())
            painter.drawText(5, 0, w, fontscale * 2.5, Qt.AlignCenter,
                             self.props['name'])
            yoff = fontscale * 2.5
        elif self.props['smalldet']:
            yoff = 50
        else:
            yoff = 0

        # Draw tube
        painter.setPen(self.color)
        painter.drawEllipse(5, 5 + yoff, 50, h)
        painter.drawRect(30, 5 + yoff, w - 50, h)
        painter.setPen(QColor('black'))
        painter.drawArc(5, 5 + yoff, 50, h, 1440, 2880)
        painter.drawLine(30, 5 + yoff, w - 25, 5 + yoff)
        painter.drawLine(30, 5 + yoff + h, w - 25, 5 + yoff + h)
        painter.drawEllipse(w - 45, 5 + yoff, 50, h)

        if self.props['smalldet']:
            sw = 20
            sx = 30 + self.props['smalldet'] * posscale
            painter.setPen(self.color)
            painter.drawRect(sx - sw, 2, 2 * sw, yoff + 10)
            painter.setPen(QColor('black'))
            painter.drawLine(sx - sw, 5 + yoff, sx - sw, 2)
            painter.drawLine(sx - sw, 2, sx + sw, 2)
            painter.drawLine(sx + sw, 2, sx + sw, 5 + yoff)

        # draw detector
        pos_val = self._curval[0]
        if pos_val is not None:
            pos_status = self._curstatus[0]
            pos_str = self._curstr[0]
            x_val = self._curval[1]
            x_status = self._curstatus[1]
            x_str = '%.1f x' % x_val
            y_val = self._curval[2]
            y_status = self._curstatus[2]
            y_str = '%.1f y' % y_val

            stat = max(pos_status, x_status, y_status)
            painter.setBrush(statusbrush[stat])
            painter.setFont(self.valueFont)
            painter.resetTransform()
            # Translate to detector position
            xp = 30 + pos_val * posscale
            painter.translate(xp + fontscale / 2., 15 + yoff + (h - 20) / 2.)
            painter.drawRect(-fontscale / 2., -(h - 20) / 2., fontscale,
                             h - 20)
            painter.resetTransform()
            # Put X/Y values left or right of detector depending on position
            if pos_val < 14:
                xoff = 2 * fontscale
            else:
                xoff = -8.5 * fontscale
            # X translation
            painter.drawText(xp + xoff, yoff + 2 * fontscale, 7 * fontscale,
                             2 * fontscale, Qt.AlignRight, x_str)
            # Y translation
            painter.drawText(xp + xoff, yoff + 3.5 * fontscale, 7 * fontscale,
                             2 * fontscale, Qt.AlignRight, y_str)
            # Z position
            minx = max(0, xp + 5 - 4 * fontscale)
            painter.drawText(minx, h + 10 + yoff, 8 * fontscale, 30,
                             Qt.AlignCenter, pos_str)

            # draw beamstop
            if self.props['beamstop']:
                painter.setPen(QPen(_blue.color()))
                painter.drawRect(xp - 8,
                                 yoff + 15 + posscale / 350 * (1100 - y_val),
                                 2, 10)

        # draw small detector
        if self.props['smalldet'] and self._curval[4] is not None:
            x_status = self._curstatus[3]
            x_str = '%4.1f x' % self._curval[3]
            y_status = self._curstatus[4]
            y_val = self._curval[4]
            y_str = '%4.0f y' % y_val
            stat = max(x_status, y_status)

            painter.setBrush(statusbrush[stat])
            painter.setPen(QPen(_black.color()))
            painter.setFont(self.valueFont)
            sy = 10 + y_val * posscale / 250
            painter.drawRect(sx - fontscale / 2., sy, fontscale, 30)

            painter.drawText(sx - 10.5 * fontscale, sy, 8 * fontscale,
                             2 * fontscale, Qt.AlignRight, x_str)
            painter.drawText(sx - 10.5 * fontscale, sy + 1.5 * fontscale,
                             8 * fontscale, 2 * fontscale, Qt.AlignRight,
                             y_str)
Example #17
0
class Lenses(NicosWidget, QWidget):

    designer_description = 'KWS lenses'

    def __init__(self, parent, designMode=False):
        # lens_in, lens_out
        self._curval = [0, 0]
        self._curstr = ['', '']
        self._curstatus = [OK, OK]

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    devices = PropDef('devices', 'QStringList', [])
    height = PropDef('height', int, 4)
    width = PropDef('width', int, 10)

    def registerKeys(self):
        for dev in self.props['devices']:
            self.registerDevice(str(dev))

    def sizeHint(self):
        return QSize(self._scale * self.props['width'],
                     self._scale * self.props['height'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curval[idx] = value
        self._curstr[idx] = unitvalue
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curstatus[idx] = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        painter.setPen(QPen(_black.color()))
        painter.setBrush(_grey)

        fontscale = float(self._scale)
        h = self.props['height'] * fontscale
        w = self.props['width'] * fontscale
        painter.drawRect(2, 10, w - 4, h / 2)

        is_in = int(self._curval[0])
        is_out = int(self._curval[1])
        lensheight = h / 2 - 25
        lensw = w / 32
        for (i, n, x) in [(0, 4, 0), (1, 6, 6), (2, 16, 14)]:
            if is_in & (1 << i):
                lensy = 22
            elif is_out & (1 << i):
                lensy = h / 2 + 20
            else:
                lensy = h / 4 + 22
            for j in range(n):
                painter.drawRect((1 + x + j) * lensw, lensy, lensw + 1,
                                 lensheight)
Example #18
0
class PictureDisplay(NicosWidget, QWidget):
    """A display widget to show a picture."""

    designer_description = 'Widget to display a picture file'

    filepath = PropDef('filepath', str, '', 'Path to the picture that should '
                       'be displayed')
    name = PropDef('name', str, '', 'Name (caption) to be displayed above '
                   'the picture')
    refresh = PropDef('refresh', int, 0, 'Interval to check for updates '
                      'in seconds')
    height = PropDef('height', int, 0)
    width = PropDef('width', int, 0)

    def __init__(self, parent=None, designMode=False, **kwds):
        QWidget.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)
        self._last_mtime = None
        self.namelabel = QLabel(self)
        self.namelabel.setAlignment(Qt.AlignHCenter)
        self.piclabel = QLabel(self)
        self.piclabel.setScaledContents(True)
        layout = QVBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.piclabel, 1)
        self.setLayout(layout)

    def registerKeys(self):
        pass

    def setPicture(self):
        size = QSize(self.props['width'] * self._scale,
                     self.props['height'] * self._scale)
        if isfile(self._filePath):
            pixmap = QPixmap(self._filePath)
        else:
            pixmap = QPixmap(size)
            pixmap.fill()
        if size.isEmpty():
            self.piclabel.setPixmap(pixmap)
        else:
            self.piclabel.setPixmap(pixmap.scaled(size))
            self.piclabel.resize(self.piclabel.sizeHint())

    def updatePicture(self):
        if not isfile(self._filePath):
            return

        # on first iteration self._last_mtime is None -> always setPicture()
        mtime = getmtime(self._filePath)
        if self._last_mtime != mtime:
            self._last_mtime = mtime
            self.setPicture()

    def propertyUpdated(self, pname, value):
        NicosWidget.propertyUpdated(self, pname, value)
        if pname == 'filepath':
            self._filePath = findResource(value)
            self.setPicture()
        elif pname == 'name':
            layout = QVBoxLayout()
            if value:
                layout.addWidget(self.namelabel)
                layout.addSpacing(5)
            layout.addWidget(self.piclabel, 1)
            sip.delete(self.layout())
            self.setLayout(layout)
            self.namelabel.setText(value)
        elif pname in ('width', 'height'):
            self.setPicture()
        elif pname == 'refresh':
            if value:
                self._refreshTimer = QTimer()
                self._refreshTimer.setInterval(value * 1000)
                self._refreshTimer.timeout.connect(self.updatePicture)
                self._refreshTimer.start()
Example #19
0
class DeviceValueEdit(NicosWidget, QWidget):

    designer_description = 'Editor for a device value with the right kind ' \
        'of widget'

    valueModified = pyqtSignal()
    valueChosen = pyqtSignal(object)

    dev = PropDef('dev', str, '', 'Device name')
    useButtons = PropDef('useButtons', bool, False,
                         'Use buttons for values with few choices?')
    allowEnter = PropDef('allowEnter', bool, True,
                         'Emit valueChosen signal on pressing Enter?')
    updateValue = PropDef('updateValue', bool, False,
                          'Update the editor when the device value changes?')
    showUnit = PropDef('showUnit', bool, True,
                       'Show the unit next to the input')

    def __init__(self, parent, designMode=False, **kwds):
        self._inner = None
        QWidget.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)
        self._layout = QHBoxLayout()
        self._layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self._layout)
        if designMode:
            self._layout.insertWidget(0, QLabel('(Value Editor)', self))

    def setFocus(self):
        if self._inner is not None:
            self._inner.setFocus()
        else:
            QWidget.setFocus(self)

    def propertyUpdated(self, pname, value):
        if pname == 'dev':
            self._reinit()
        NicosWidget.propertyUpdated(self, pname, value)

    def setClient(self, client):
        NicosWidget.setClient(self, client)
        self._reinit()

    def on_client_connected(self):
        self._reinit()

    def registerKeys(self):
        if self.props['updateValue']:
            self.registerDevice(self.props['dev'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        self._reinit(value)

    def on_devMetaChange(self, dev, fmtstr, unit, fixed):
        self._reinit()

    def _reinit(self, curvalue=None):
        if not self._client or not self._client.isconnected:
            return
        devname = str(self.props['dev'])
        if devname:
            params = self._client.getDeviceParams(devname)
            valuetype = self._client.getDeviceValuetype(devname)
            valueinfo = self._client.eval(
                'session.getDevice(%r).valueInfo()' % devname, None)
            unit = params.get('unit', '') if self.props['showUnit'] else ''
            fmtstr = params.get('fmtstr', '%s')
            if curvalue is None:
                curvalue = params.get('target')
            if curvalue is None and valuetype is not None:
                curvalue = valuetype()
        else:
            valuetype = str
            curvalue = ''
            fmtstr = '%s'
            unit = ''
            valueinfo = None

        self._inner = create(self,
                             valuetype,
                             curvalue,
                             fmtstr,
                             unit,
                             allow_buttons=self.props['useButtons'],
                             allow_enter=self.props['allowEnter'],
                             client=self._client,
                             valinfo=valueinfo)
        last = self._layout.takeAt(0)
        if last:
            last.widget().deleteLater()
        self._layout.insertWidget(0, self._inner)
        self._inner.valueModified.connect(self.valueModified)
        self._inner.valueChosen.connect(self.valueChosen)

    def getValue(self):
        if self._inner:
            return self._inner.getValue()

    def setValue(self, value):
        self._reinit(value)
Example #20
0
class ValueDisplay(NicosWidget, QWidget):
    """Value display widget with two labels."""

    designer_description = 'A widget with name/value labels'
    designer_icon = ':/table'

    widgetInfo = pyqtSignal(str)

    dev = PropDef('dev', str, '', 'NICOS device name, if set, display '
                  'value of this device')
    key = PropDef('key', str, '', 'Cache key to display (without "nicos/"'
                  ' prefix), set either "dev" or this')
    statuskey = PropDef('statuskey', str, '', 'Cache key to extract status '
                        'information  for coloring value, if "dev" is '
                        'given this is set automatically')
    name = PropDef('name', str, '', 'Name of the value to display above/'
                   'left of the value; if "dev" is given this '
                   'defaults to the device name')
    unit = PropDef('unit', str, '', 'Unit of the value to display next to '
                   'the name; if "dev" is given this defaults to '
                   'the unit set in NICOS')
    format = PropDef('format', str, '', 'Python format string to use for the '
                     'value; if "dev" is given this defaults to the '
                     '"fmtstr" set in NICOS')
    maxlen = PropDef('maxlen', int, -1, 'Maximum length of the value string to '
                     'allow; defaults to no limit')
    width = PropDef('width', int, 8, 'Width of the widget in units of the '
                    'width of one character')
    istext = PropDef('istext', bool, False, 'If given, a "text" font will be '
                     'used for the value instead of the monospaced '
                     'font used for numeric values')
    showName = PropDef('showName', bool, True, 'If false, do not display the '
                       'label for the value name')
    showStatus = PropDef('showStatus', bool, True, 'If false, do not display '
                         'the device status as a color of the value text')
    showExpiration = PropDef('showExpiration', bool, True, 'If true, display '
                             'expired cache values as "n/a"')
    horizontal = PropDef('horizontal', bool, False, 'If true, display name '
                         'label left of the value instead of above it')

    def __init__(self, parent, designMode=False, colorScheme=None, **kwds):
        # keys being watched
        self._mainkeyid = None
        self._statuskeyid = None

        # other current values
        self._isfixed = ''
        # XXX could be taken from devinfo
        self._lastvalue = designMode and '1.4' or None
        self._laststatus = (OK, '')
        self._lastchange = 0
        self._mouseover = False
        self._mousetimer = None
        self._expired = True

        self._colorscheme = colorScheme or defaultColorScheme

        QWidget.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)
        self._statuscolors = self._colorscheme['fore'][UNKNOWN], \
            self._colorscheme['back'][UNKNOWN]
        self._labelcolor = None

    def propertyUpdated(self, pname, value):
        if pname == 'dev':
            if value:
                self.key = value + '.value'
                self.statuskey = value + '.status'
        elif pname == 'width':
            if value < 0:
                self.reinitLayout()
            else:
                onechar = QFontMetrics(self.valueFont).width('0')
                self.valuelabel.setMinimumSize(QSize(onechar * (value + .5), 0))
        elif pname == 'istext':
            self.valuelabel.setFont(value and self.font() or self.valueFont)
            self.width = self.width
        elif pname == 'valueFont':
            self.valuelabel.setFont(self.valueFont)
            self.width = self.width  # update char width calculation
        elif pname == 'showName':
            self.namelabel.setVisible(value)
        elif pname == 'showStatus':
            if not value:
                setBothColors(self.valuelabel,
                              (self._colorscheme['fore'][UNKNOWN],
                               self._colorscheme['back'][UNKNOWN]))
        elif pname == 'horizontal':
            self.reinitLayout()
        if pname in ('dev', 'name', 'unit'):
            self.update_namelabel()
        NicosWidget.propertyUpdated(self, pname, value)

    def initUi(self):
        self.namelabel = QLabel(' ', self, textFormat=Qt.RichText)
        self.update_namelabel()

        valuelabel = SensitiveSMLabel('----', self, self._label_entered,
                                      self._label_left)
        valuelabel.setFrameShape(QFrame.Panel)
        valuelabel.setAlignment(Qt.AlignHCenter)
        valuelabel.setFrameShadow(QFrame.Sunken)
        valuelabel.setAutoFillBackground(True)
        setBothColors(valuelabel, (self._colorscheme['fore'][UNKNOWN],
                                   self._colorscheme['back'][UNKNOWN]))
        valuelabel.setLineWidth(2)
        self.valuelabel = valuelabel
        self.width = 8

        self.reinitLayout()

    def reinitLayout(self):
        # reinitialize UI after switching horizontal/vertical layout
        if self.props['horizontal']:
            new_layout = QHBoxLayout()
            new_layout.addWidget(self.namelabel)
            new_layout.addStretch()
            new_layout.addWidget(self.valuelabel)
            self.namelabel.setAlignment(Qt.AlignLeft | Qt.AlignVCenter)
        else:
            new_layout = QVBoxLayout()
            new_layout.addWidget(self.namelabel)
            tmplayout = QHBoxLayout()
            if self.width >= 0:
                tmplayout.addStretch()
            tmplayout.addWidget(self.valuelabel)
            if self.width >= 0:
                tmplayout.addStretch()
            new_layout.addLayout(tmplayout)
            self.namelabel.setAlignment(Qt.AlignHCenter)
        if self.layout():
            sip.delete(self.layout())
        new_layout.setContentsMargins(1, 1, 1, 1)  # save space
        self.setLayout(new_layout)

    def registerKeys(self):
        if self.props['dev']:
            self.registerDevice(self.props['dev'],
                                self.props['unit'], self.props['format'])
        else:
            self.registerKey(self.props['key'], self.props['statuskey'],
                             self.props['unit'], self.props['format'])

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        # check expired values
        self._expired = expired
        self._lastvalue = value
        self._lastchange = currenttime()
        if self.props['maxlen'] > -1:
            self.valuelabel.setText(strvalue[:self.props['maxlen']])
        else:
            self.valuelabel.setText(strvalue)
        if self._expired:
            setBothColors(self.valuelabel, (self._colorscheme['fore'][UNKNOWN],
                                            self._colorscheme['expired']))
            if self.props['showExpiration']:
                self.valuelabel.setText(NOT_AVAILABLE)
        elif not self.props['istext']:
            setBothColors(self.valuelabel, (self._colorscheme['fore'][BUSY],
                                            self._colorscheme['back'][BUSY]))
            QTimer.singleShot(1000, self._applystatuscolor)
        else:
            self._applystatuscolor()

    def _applystatuscolor(self):
        if self._expired:
            setBothColors(self.valuelabel, (self._colorscheme['fore'][UNKNOWN],
                                            self._colorscheme['expired']))
        else:
            setBothColors(self.valuelabel, self._statuscolors)
            if self._labelcolor:
                self.namelabel.setAutoFillBackground(True)
                setBackgroundColor(self.namelabel, self._labelcolor)
            else:
                self.namelabel.setAutoFillBackground(False)

    def on_devStatusChange(self, dev, code, status, expired):
        if self.props['showStatus']:
            self._statuscolors = self._colorscheme['fore'][code], \
                self._colorscheme['back'][code]
            self._labelcolor = self._colorscheme['label'][code]
            self._laststatus = code, status
            self._applystatuscolor()

    def on_devMetaChange(self, dev, fmtstr, unit, fixed):
        self._isfixed = fixed and ' (F)'
        self.format = fmtstr
        self.unit = unit or ''

    def update_namelabel(self):
        name = self.props['name'] or self.props['dev'] or self.props['key']
        self.namelabel.setText(
            html.escape(str(name)) +
            ' <font color="#888888">%s</font><font color="#0000ff">%s</font> '
            % (html.escape(self.props['unit'].strip()), self._isfixed))

    def _label_entered(self, widget, event, from_mouse=True):
        infotext = '%s = %s' % (self.props['name'] or self.props['dev']
                                or self.props['key'], self.valuelabel.text())
        if self.props['unit'].strip():
            infotext += ' %s' % self.props['unit']
        if self.props['statuskey']:
            try:
                const, msg = self._laststatus
            except ValueError:
                const, msg = self._laststatus, ''
            infotext += ', status is %s: %s' % (statuses.get(const, '?'), msg)
        infotext += ', changed %s ago' % (
            nicedelta(currenttime() - self._lastchange))
        self.widgetInfo.emit(infotext)
        if from_mouse:
            self._mousetimer = QTimer(self, timeout=lambda:
                                      self._label_entered(widget, event, False)
                                      )
            self._mousetimer.start(1000)

    def _label_left(self, widget, event):
        if self._mousetimer:
            self._mousetimer.stop()
            self._mousetimer = None
            self.widgetInfo.emit('')
Example #21
0
class TasWidget(NicosWidget, TasView):
    """Display of the TAS table configuration."""

    designer_description = __doc__

    mthdev = PropDef('mthdev', str, '', 'Monochromator rocking angle device')
    mttdev = PropDef('mttdev', str, '',
                     'Monochromator scattering angle device')
    sthdev = PropDef('sthdev', str, '', 'Sample rotation device')
    sttdev = PropDef('sttdev', str, '', 'Sample scattering angle device')
    athdev = PropDef('athdev', str, '', 'Analyzer rocking angle device')
    attdev = PropDef('attdev', str, '', 'Analyzer scattering angle device')
    Lmsdev = PropDef('Lmsdev', str, '',
                     'Distance monochromator->sample device')
    Lsadev = PropDef('Lsadev', str, '', 'Distance sample->analyzer device')
    Laddev = PropDef('Laddev', str, '', 'Distance analyzer->detector device')
    height = PropDef('height', int, 30, 'Widget height in characters')
    width = PropDef('width', int, 40, 'Widget width in characters')

    def __init__(self, parent, designMode=False):
        TasView.__init__(self, parent)
        NicosWidget.__init__(self)

        self._keymap = {}
        self._statuskeymap = {}
        self._targetkeymap = {}

    def registerKeys(self):
        for dev in self.values:
            devname = str(self.props[dev + 'dev'])
            if devname:
                self._keymap[self._source.register(self,
                                                   devname + '/value')] = dev
                self._statuskeymap[self._source.register(
                    self, devname + '/status')] = dev
                self._targetkeymap[self._source.register(
                    self, devname + '/target')] = dev

    def on_keyChange(self, key, value, time, expired):
        if not expired:
            if key in self._keymap:
                # Scale the distances
                if self._keymap[key] in ('Lms', 'Lsa', 'Lad'):
                    value /= 10
                self.values[self._keymap[key]] = value
            elif key in self._statuskeymap:
                self.status[self._statuskeymap[key]] = value[0]
            elif key in self._targetkeymap:
                self.targets[self._targetkeymap[key]] = value
            else:
                return
            self.update()

    def sizeHint(self):
        return QSize(self.props['width'] * self._scale + 2,
                     self.props['height'] * self._scale + 2)
Example #22
0
class Collimation(NicosWidget, QWidget):

    designer_description = 'KWS collimation'

    devices = PropDef('devices', 'QStringList', [])
    height = PropDef('height', int, 4)
    width = PropDef('width', int, 10)
    polarizer = PropDef('polarizer', int, 0,
                        'Number of bits for the polarizer')

    def __init__(self, parent, designMode=False):
        # coll_in, coll_out, ap_20, ap_14, ap_8, ap_4, ap_2, pol_in, pol_out
        self._curval = [0, 0, (0, 0), (0, 0), (0, 0), (0, 0), (0, 0), 0, 0]
        self._curstr = ['', '', '', '', '', '', '', '', '']
        self._curstatus = [OK, OK, OK, OK, OK, OK, OK, OK, OK]

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    def registerKeys(self):
        for dev in self.props['devices']:
            self.registerDevice(str(dev))

    def sizeHint(self):
        return QSize(self._scale * self.props['width'],
                     self._scale * self.props['height'] * 1.2)

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curval[idx] = value
        self._curstr[idx] = unitvalue
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curstatus[idx] = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        pen = painter.pen()

        fontscale = float(self._scale)
        painter.setFont(scaledFont(self.valueFont, 0.9))
        h = self.props['height'] * fontscale
        w = self.props['width'] * fontscale
        elwidth = w / 20.
        elheight = h / 3

        pol_bits = self.props['polarizer']
        is_in = int(self._curval[0] << pol_bits | self._curval[7])
        is_out = int(self._curval[1] << pol_bits | self._curval[8])
        x = elwidth
        y = 2.5 * fontscale
        for i in range(18):
            painter.setPen(QPen(_black.color()))
            painter.setBrush(_grey)
            painter.drawRect(x, y, elwidth - 2, elheight)
            painter.setBrush(_blue)
            if is_in & (1 << (17 - i)):
                ely = 3
            elif is_out & (1 << (17 - i)):
                ely = 2 + elheight / 2
            else:
                ely = 2 + elheight / 4
            painter.drawRect(x + 3, y + ely, elwidth - 8, elheight / 3)
            if i >= 18 - pol_bits:
                painter.setPen(QPen(_white.color()))
                painter.drawText(x + 3, y + ely - 2, elwidth - 8,
                                 elheight / 3 + 2, Qt.AlignHCenter, 'POL')
                painter.setPen(QPen(_black.color()))
            painter.drawText(x, 3, elwidth, 2 * fontscale,
                             Qt.AlignRight | Qt.AlignTop, str(19 - i))
            x += elwidth
        painter.fillRect(0, y + elheight / 3 - 5, w, 3, _yellow)
        painter.setPen(pen)

        x = elwidth + 1
        y += elheight + 4

        slhw = 1.6 * elwidth
        for i, slitpos in enumerate([20, 14, 8, 4, 2]):
            slitw, slith = self._curval[2 + i]
            xmiddle = x + ((20 - slitpos) * elwidth)
            painter.drawLine(xmiddle, y, xmiddle, y + 15)
            painter.setBrush(_white)
            painter.drawRect(xmiddle - 0.5 * slhw, y + 15, slhw, slhw)
            painter.setBrush(collstatusbrush[self._curstatus[2 + i]])
            w = (50 - slitw) * slhw / 100
            h = (50 - slith) * slhw / 100
            painter.drawRect(xmiddle - 0.5 * slhw + w, y + 15 + h,
                             slhw - 2 * w, slhw - 2 * h)
            painter.drawText(xmiddle - 0.8 * elwidth, y + 15, slhw, slhw,
                             Qt.AlignCenter, '%.1f\n%.1f' % (slitw, slith))
Example #23
0
class CollimatorTable(NicosWidget, QWidget):
    """Displays a list of 'beam options' as a vertical stack.

    Options are displayed as vertical stack of named elements drawn on top
    of a centered blue line ('the beam').
    If the device value is in 'options', the correspondig element is drawn
    on top of 'the beam' by moving the whole stack vertically.
    If the device value is in 'disabled_options', the whole
    stack of options is vertically shifted 'out of beam'.
    Other values are ignored as they are considered temporary
    (while moving an option).

    If the device state happens to be in error, the name label is
    displayed in red to indicate the error.
    """

    designer_description = 'SANS-1 collimator table'

    def __init__(self, parent, designMode=False):
        self._curstr = ''
        self._curstatus = OK
        self._fixed = ''
        self.shift = -1

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    dev = PropDef('dev', str, '', 'NICOS device name of a switcher')
    options = PropDef(
        'options', 'QStringList', [], 'list of valid switcher-'
        'values to display in top-down order (first element '
        'will be displayed on top location)')
    disabled_options = PropDef(
        'disabled_options', 'QStringList', [],
        'list of valid switcher values for which '
        'all options are display out-of-beam')
    height = PropDef('height', int, 4, 'Widget height in characters')
    width = PropDef('width', int, 10, 'Widget width in characters')
    name = PropDef('name', str, '', 'Display name')

    def registerKeys(self):
        self.registerDevice(self.props['dev'])

    def sizeHint(self):
        return QSize(
            self._scale * self.props['width'],
            self._scale * 2.5 * self.props['height'] +
            (self.props['name'] and 2.5 * self._scale or 0))

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        self._curstr = strvalue
        self.update()

    def on_devMetaChange(self, dev, fmtstr, unit, fixed):
        self._fixed = fixed
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        self._curstatus = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        h = self._scale * 2.5 * self.props['height']
        w = self._scale * self.props['width']

        # cache pen
        pen = painter.pen()

        if self.props['name']:
            painter.setFont(self.font())
            if self._curstatus != OK:
                painter.fillRect(0, 0, w, self._scale * 2.5,
                                 statusbrush[self._curstatus])
            if self._fixed:
                painter.setPen(QPen(_blue.color()))
            else:
                painter.setPen(QPen(_black.color()))
            painter.drawText(0, 0, w, self._scale * 2.5, Qt.AlignCenter,
                             self.props['name'])
            painter.setPen(pen)
            yoff = self._scale * 2.5
        else:
            yoff = 0

        painter.setPen(QPen(_blue.color()))

        y = h * 0.5 + yoff
        painter.drawLine(0, y, w, y)
        painter.drawLine(0, y + 1, w, y + 1)
        painter.drawLine(0, y + 2, w, y + 2)

        # reset pen
        painter.setPen(pen)

        painter.setBrush(statusbrush[self._curstatus])
        if self._curstr in self.props['options']:
            self.shift = self.props['options'].index(self._curstr)
        if self._curstr in self.props['disabled_options']:
            self.shift = len(self.props['options'])

        painter.setFont(self.valueFont)

        h0 = max(2 * self._scale, 2 * self._scale + 4)
        painter.setClipRect(0, yoff, w, h)
        for i, t in enumerate(self.props['options']):
            y = h * 0.5 + yoff + h0 * (self.shift - i - 0.45)
            b = statusbrush[self._curstatus]
            if t == self._curstr:
                painter.setBrush(b)
            else:
                painter.setBrush(_grey if b == statusbrush[OK] else b)
            painter.drawRect(5, y + 2, w - 10, h0 - 4)
            painter.drawText(5, y + 2, w - 10, h0 - 4, Qt.AlignCenter, t)
Example #24
0
class SampleSlit(NicosWidget, QWidget):

    designer_description = 'KWS sample slit'

    def __init__(self, parent, designMode=False):
        self._curval = [0, 0, 0, 0]
        self._curstatus = OK
        self._opmode = 'offcentered'

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    device = PropDef('device', str, '')
    maxh = PropDef('maxh', float, 30)
    maxw = PropDef('maxw', float, 30)
    height = PropDef('height', int, 4)
    width = PropDef('width', int, 10)

    def registerKeys(self):
        self.registerDevice(str(self.props['device']))
        self.registerKey('%s/opmode' % self.props['device'])

    def sizeHint(self):
        return QSize(self._scale * self.props['width'],
                     self._scale * self.props['height'])

    def on_keyChange(self, key, value, time, expired):
        if key.endswith('/opmode'):
            self._opmode = value
            return
        NicosWidget.on_keyChange(self, key, value, time, expired)

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        self._curval = value
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        self._curstatus = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        fontscale = float(self._scale)
        ww = self.props['width'] * fontscale - 4
        wh = self.props['height'] * fontscale - 4
        sx, sy = self.props['maxw'], self.props['maxh']

        if self._opmode == 'offcentered':
            dx, dy, w, h = self._curval
            x0, x1, y0, y1 = dx - w / 2., dx + w / 2., dy - h / 2., dy + h / 2.
            l1, l2, l3, l4 = '(%.1f, %.1f)' % (dx, dy), '%.1f x %.1f' % (
                w, h), '', ''
        elif self._opmode == 'centered':
            w, h = self._curval
            x0, x1, y0, y1 = -w / 2., w / 2., -h / 2., h / 2.
            l1, l2, l3, l4 = '', '%.1f x %.1f' % (w, h), '', ''
        elif self._opmode.startswith('4blades'):
            x0, x1, y0, y1 = self._curval
            l1, l2, l3, l4 = '%.1f' % y1, '%.1f' % y0, '%.1f' % x0, '%.1f' % x1
            if self._opmode.endswith('opposite'):
                x0 *= -1
                y0 *= -1

        x0 = (x0 + sx / 2) / sx * ww
        x1 = (x1 + sx / 2) / sx * ww
        y0 = wh - (y0 + sy / 2) / sy * wh
        y1 = wh - (y1 + sy / 2) / sy * wh

        painter.setPen(QPen(_black.color()))
        painter.setBrush(_white)
        painter.drawRect(2, 2, ww, wh)
        painter.setBrush(collstatusbrush[self._curstatus])
        painter.drawRect(2 + x0, 2 + y1, x1 - x0, y0 - y1)

        painter.setFont(scaledFont(self.valueFont, 0.8))
        painter.drawText(2, 2, ww, wh, Qt.AlignTop | Qt.AlignHCenter, l1)
        painter.drawText(2, 2, ww, wh, Qt.AlignBottom | Qt.AlignHCenter, l2)
        painter.drawText(2, 2, ww, wh, Qt.AlignVCenter | Qt.AlignLeft, l3)
        painter.drawText(2, 2, ww, wh, Qt.AlignVCenter | Qt.AlignRight, l4)
Example #25
0
class Tube2(NicosWidget, QWidget):
    """Sans1Tube with two detectors..."""

    designer_description = 'SANS-1 tube with two detectors'

    def __init__(self, parent, designMode=False):
        # det1pos, det1shift, det1tilt, det2pos
        self._curval = [0, 0, 0, 0]
        self._curstr = ['', '', '', '']
        self._curstatus = [OK, OK, OK, OK]

        QWidget.__init__(self, parent)
        NicosWidget.__init__(self)

    devices = PropDef('devices', 'QStringList', [], 'position, shift and '
                      'tilt of det1, position of det2')
    height = PropDef('height', int, 10, 'Widget height in characters')
    width = PropDef('width', int, 30, 'Widget width in characters')
    name = PropDef('name', str, '', 'Display name')
    posscale = PropDef('posscale', float, 20000, 'Length of the tube')
    color = PropDef('color', 'QColor', _magenta.color(), 'Color of the tube')

    def sizeHint(self):
        return QSize(
            self.props['width'] * self._scale + 10,
            self.props['height'] * self._scale +
            (self.props['name'] and self._scale * 2.5 or 0) + 40)

    def registerKeys(self):
        for dev in self.props['devices']:
            self.registerDevice(str(dev))

    def on_devValueChange(self, dev, value, strvalue, unitvalue, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curval[idx] = value
        self._curstr[idx] = unitvalue
        self.update()

    def on_devStatusChange(self, dev, code, status, expired):
        try:
            idx = self.props['devices'].index(dev)
        except ValueError:
            return
        self._curstatus[idx] = code
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setBrush(QBrush(self.color))
        painter.setRenderHint(QPainter.Antialiasing)

        fontscale = float(self._scale)
        h = self.props['height'] * fontscale
        w = self.props['width'] * fontscale
        posscale = (w - 120) / self.props['posscale']

        if self.props['name']:
            painter.setFont(self.font())
            painter.drawText(5, 0, w, fontscale * 2.5, Qt.AlignCenter,
                             self.props['name'])
            yoff = fontscale * 2.5
        else:
            yoff = 0

        painter.setPen(self.color)
        painter.drawEllipse(5, 5 + yoff, 50, h)
        painter.drawRect(30, 5 + yoff, w - 50, h)
        painter.setPen(QColor('black'))
        painter.drawArc(5, 5 + yoff, 50, h, 1440, 2880)
        painter.drawLine(30, 5 + yoff, w - 25, 5 + yoff)
        painter.drawLine(30, 5 + yoff + h, w - 25, 5 + yoff + h)
        painter.drawEllipse(w - 45, 5 + yoff, 50, h)

        # draw Detector 1
        minx = 0
        pos_val = self._curval[0]
        if pos_val is not None:
            pos_status = self._curstatus[0]
            pos_str = self._curstr[0]
            shift_val = self._curval[1]
            shift_status = self._curstatus[1]
            shift_str = self._curstr[1]
            if shift_val > 0:
                shift_str += ' ↓'
            elif shift_val < 0:
                shift_str += ' ↑'
            # Not used at the moment, prepared for later use
            tilt_val = self._curval[2]
            tilt_status = self._curstatus[2]
            tilt_str = self._curstr[2]
            if tilt_str.endswith('deg'):
                tilt_str = tilt_str[:-3] + '°'

            stat = max(pos_status, shift_status, tilt_status)
            painter.setBrush(statusbrush[stat])
            # tf = QTransform()
            # tf.rotate(tilt_val)
            painter.resetTransform()
            painter.translate(60 + pos_val * posscale + fontscale / 2.,
                              15 + yoff + shift_val * posscale + (h - 20) / 2.)
            painter.rotate(-tilt_val)
            painter.drawRect(-fontscale / 2., -(h - 20) / 2., fontscale,
                             h - 20)  # XXX tilt ???
            painter.resetTransform()
            painter.setFont(self.valueFont)
            painter.drawText(
                60 + pos_val * posscale - 10.5 * fontscale,
                -5 + yoff + h - fontscale,  # + (shift_val - 4) * posscale,
                9.5 * fontscale,
                2 * fontscale,
                Qt.AlignRight,
                tilt_str)
            painter.drawText(
                60 + pos_val * posscale - 6.5 * fontscale,
                yoff + fontscale,  # + (shift_val - 4) * posscale,
                9.5 * fontscale,
                2 * fontscale,
                Qt.AlignLeft,
                shift_str)
            minx = max(minx, 60 + pos_val * posscale + 5 - 4 * fontscale)
            painter.drawText(minx, h + 10 + yoff, 8 * fontscale, 30,
                             Qt.AlignCenter, pos_str)
            minx = minx + 8 * fontscale
Example #26
0
class MultiList(NicosWidget, QWidget):
    """A list of entries, where each entry is a frame loaded from a UI file."""

    designer_description = 'A list (with add/remove controls) of .ui entries'

    uifile = PropDef('uifile', str, '', 'UI file to use for the entries')

    entryAdded = pyqtSignal(object)
    entryRemoved = pyqtSignal(object)

    def __init__(self, parent, designMode=False, **kwds):
        QWidget.__init__(self, parent, **kwds)
        NicosWidget.__init__(self)
        self._entries = []
        self._vlayout = QVBoxLayout()
        self._vlayout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self._vlayout)
        self._add()
        self._designer = designMode

    def registerKeys(self):
        pass

    def propertyUpdated(self, pname, value):
        if pname == 'uifile':
            self.clear()
        NicosWidget.propertyUpdated(self, pname, value)

    def entry(self, i):
        return self._entries[i].subwidget

    def entries(self):
        return [e.subwidget for e in self._entries]

    def count(self):
        return len(self._entries)

    def clear(self):
        for entry in self._entries[::-1]:
            self._remove(entry)
        self._add()

    def _remove(self, entry):
        self._entries.remove(entry)
        self._vlayout.removeWidget(entry)
        self.entryRemoved.emit(entry.subwidget)
        entry.deleteLater()
        if self._entries:
            self._entries[-1].setButton('+')

    def _add(self):
        new_frame = MultiEntry(self, self._client, self.props['uifile'])
        new_frame.addOrRemove.connect(self._addRemove)
        if self._entries:
            self._entries[-1].setButton('-')
        self._entries.append(new_frame)
        self._vlayout.addWidget(new_frame)
        self.entryAdded.emit(self._entries[-1].subwidget)

    def _addRemove(self):
        if not self._entries or self.sender() is self._entries[-1]:
            self._add()
        else:
            self._remove(self.sender())
Example #27
0
class MultiAnalyzerWidget(NicosWidget, MultiAnalyzerView):

    rd1 = PropDef('rd1', str, 'rd1', 'Detector 1 position')
    rd2 = PropDef('rd2', str, 'rd2', 'Detector 2 position')
    rd3 = PropDef('rd3', str, 'rd3', 'Detector 3 position')
    rd4 = PropDef('rd4', str, 'rd4', 'Detector 4 position')
    rd5 = PropDef('rd5', str, 'rd5', 'Detector 5 position')
    rd6 = PropDef('rd6', str, 'rd6', 'Detector 6 position')
    rd7 = PropDef('rd7', str, 'rd7', 'Detector 7 position')
    rd8 = PropDef('rd8', str, 'rd8', 'Detector 8 position')
    rd9 = PropDef('rd9', str, 'rd9', 'Detector 9 position')
    rd10 = PropDef('rd10', str, 'rd10', 'Detector 10 position')
    rd11 = PropDef('rd11', str, 'rd11', 'Detector 11 position')

    rg1 = PropDef('rg1', str, 'rg1', 'Guide 1 rotation')
    rg2 = PropDef('rg2', str, 'rg2', 'Guide 2 rotation')
    rg3 = PropDef('rg3', str, 'rg3', 'Guide 3 rotation')
    rg4 = PropDef('rg4', str, 'rg4', 'Guide 4 rotation')
    rg5 = PropDef('rg5', str, 'rg5', 'Guide 5 rotation')
    rg6 = PropDef('rg6', str, 'rg6', 'Guide 6 rotation')
    rg7 = PropDef('rg7', str, 'rg7', 'Guide 7 rotation')
    rg8 = PropDef('rg8', str, 'rg8', 'Guide 8 rotation')
    rg9 = PropDef('rg9', str, 'rg9', 'Guide 9 rotation')
    rg10 = PropDef('rg10', str, 'rg10', 'Guide 10 rotation')
    rg11 = PropDef('rg11', str, 'rg11', 'Guide 11 rotation')

    ra1 = PropDef('ra1', str, 'ra1', 'Monochromator crystal 1 rotation')
    ra2 = PropDef('ra2', str, 'ra2', 'Monochromator crystal 2 rotation')
    ra3 = PropDef('ra3', str, 'ra3', 'Monochromator crystal 3 rotation')
    ra4 = PropDef('ra4', str, 'ra4', 'Monochromator crystal 4 rotation')
    ra5 = PropDef('ra5', str, 'ra5', 'Monochromator crystal 5 rotation')
    ra6 = PropDef('ra6', str, 'ra6', 'Monochromator crystal 6 rotation')
    ra7 = PropDef('ra7', str, 'ra7', 'Monochromator crystal 7 rotation')
    ra8 = PropDef('ra8', str, 'ra8', 'Monochromator crystal 8 rotation')
    ra9 = PropDef('ra9', str, 'ra9', 'Monochromator crystal 9 rotation')
    ra10 = PropDef('ra10', str, 'ra10', 'Monochromator crystal 10 rotation')
    ra11 = PropDef('ra11', str, 'ra11', 'Monochromator crystal 11 rotation')

    ta1 = PropDef('ta1', str, 'ta1', 'Monochromator crystal 1 translation')
    ta2 = PropDef('ta2', str, 'ta2', 'Monochromator crystal 2 translation')
    ta3 = PropDef('ta3', str, 'ta3', 'Monochromator crystal 3 translation')
    ta4 = PropDef('ta4', str, 'ta4', 'Monochromator crystal 4 translation')
    ta5 = PropDef('ta5', str, 'ta5', 'Monochromator crystal 5 translation')
    ta6 = PropDef('ta6', str, 'ta6', 'Monochromator crystal 6 translation')
    ta7 = PropDef('ta7', str, 'ta7', 'Monochromator crystal 7 translation')
    ta8 = PropDef('ta8', str, 'ta8', 'Monochromator crystal 8 translation')
    ta9 = PropDef('ta9', str, 'ta9', 'Monochromator crystal 9 translation')
    ta10 = PropDef('ta10', str, 'ta10', 'Monochromator crystal 10 translation')
    ta11 = PropDef('ta11', str, 'ta11', 'Monochromator crystal 11 translation')

    cad = PropDef('cad', str, 'cad', 'CAD device')
    lsa = PropDef('lsa', str, 'lsa', 'Distance sample analyser center')

    height = PropDef('height', int, 30, 'Widget height in characters')
    width = PropDef('width', int, 40, 'Widget width in characters')

    def __init__(self, parent):
        MultiAnalyzerView.__init__(self)
        NicosWidget.__init__(self)

        self._keymap = {}
        self._statuskeymap = {}
        self._targetkeymap = {}

    def registerKeys(self):
        for dev in [
                'ta1', 'ta2', 'ta3', 'ta4', 'ta5', 'ta6', 'ta7', 'ta8', 'ta9',
                'ta10', 'ta11', 'ra1', 'ra2', 'ra3', 'ra4', 'ra5', 'ra6',
                'ra7', 'ra8', 'ra9', 'ra10', 'ra11', 'rd1', 'rd2', 'rd3',
                'rd4', 'rd5', 'rd6', 'rd7', 'rd8', 'rd9', 'rd10', 'rd11',
                'rg1', 'rg2', 'rg3', 'rg4', 'rg5', 'rg6', 'rg7', 'rg8', 'rg9',
                'rg10', 'rg11', 'cad', 'lsa'
        ]:
            devname = self.props.get(dev)
            if devname:
                k = self._source.register(self, devname + '/value')
                self._keymap[k] = dev
                k = self._source.register(self, devname + '/status')
                self._statuskeymap[k] = dev
                k = self._source.register(self, devname + '/target')
                self._targetkeymap[k] = dev

    def on_keyChange(self, key, value, time, expired):
        if key in self._keymap and not expired:
            self.values[self._keymap[key]] = value
            self.update()
        elif key in self._statuskeymap and not expired:
            self.status[self._statuskeymap[key]] = value[0]
            self.update()
        elif key in self._targetkeymap and not expired:
            self.targets[self._targetkeymap[key]] = value
            self.update()

    def sizeHint(self):
        return QSize(self.props['width'] * self._scale + 2,
                     self.props['height'] * self._scale + 2)