def __init__(self, parent, client, options): LokiPanelBase.__init__(self, parent, client, options) loadUi(self, findResource('nicos_ess/loki/gui/ui_files/sampleconf.ui')) self.sampleGroup.setEnabled(False) self.frame.setLayout(QVBoxLayout()) self.sample_frame = QFrame(self) loadUi( self.sample_frame, findResource('nicos_ess/loki/gui/ui_files/sampleconf_summary.ui')) layout = self.frame.layout() layout.addWidget(self.sample_frame) self.sample_frame.hide() self.sample_frame.posTbl.setEnabled(False) for box in self.sample_frame.findChildren(QLineEdit): box.setEnabled(False) menu = QMenu(self) menu.addAction(self.actionEmpty) menu.addAction(self.actionGenerate) self.createBtn.setMenu(menu) self.configs = [] self.holder_info = options.get('holder_info', []) self.instrument = options.get('instrument', 'loki') self.unapplied_changes = False self.applyBtn.setEnabled(False) self.initialise_connection_status_listeners()
def setPanelToolbar(self): bar = QToolBar('History viewer') bar.addAction(self.actionNew) bar.addAction(self.actionEditView) bar.addSeparator() bar.addAction(self.actionSavePlot) bar.addAction(self.actionPrint) bar.addAction(self.actionSaveData) bar.addSeparator() bar.addAction(self.actionUnzoom) bar.addAction(self.actionLogScale) bar.addSeparator() bar.addAction(self.actionAutoScale) bar.addAction(self.actionScaleX) bar.addAction(self.actionScaleY) bar.addSeparator() bar.addAction(self.actionResetView) bar.addAction(self.actionDeleteView) bar.addSeparator() bar.addAction(self.actionFitPeak) wa = QWidgetAction(bar) self.fitPickCheckbox = QCheckBox(bar) self.fitPickCheckbox.setText('Pick') self.fitPickCheckbox.setChecked(True) self.actionPickInitial.setChecked(True) self.fitPickCheckbox.toggled.connect(self.actionPickInitial.setChecked) self.actionPickInitial.toggled.connect(self.fitPickCheckbox.setChecked) layout = QHBoxLayout() layout.setContentsMargins(10, 0, 10, 0) layout.addWidget(self.fitPickCheckbox) frame = QFrame(bar) frame.setLayout(layout) wa.setDefaultWidget(frame) bar.addAction(wa) ag = QActionGroup(bar) ag.addAction(self.actionFitPeakGaussian) ag.addAction(self.actionFitPeakLorentzian) ag.addAction(self.actionFitPeakPV) ag.addAction(self.actionFitPeakPVII) ag.addAction(self.actionFitTc) ag.addAction(self.actionFitCosine) ag.addAction(self.actionFitSigmoid) ag.addAction(self.actionFitLinear) ag.addAction(self.actionFitExponential) wa = QWidgetAction(bar) self.fitComboBox = QComboBox(bar) for a in ag.actions(): itemtext = a.text().replace('&', '') self.fitComboBox.addItem(itemtext) self.fitfuncmap[itemtext] = a self.fitComboBox.currentIndexChanged.connect( self.on__fitComboBox_currentIndexChanged) wa.setDefaultWidget(self.fitComboBox) bar.addAction(wa) bar.addSeparator() bar.addAction(self.actionFitArby) self.bar = bar self.actionFitLinear.trigger() return bar
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()
def __init__(self, parent, name, selections, preselect): QFrame.__init__(self, parent) self.name = name self.selections = selections layout = QHBoxLayout() layout.addWidget(QLabel(name, self)) self.combo = QComboBox(self) self.combo.addItems(selections) if preselect in selections: self.combo.setCurrentIndex(selections.index(preselect)) else: self.combo.setCurrentIndex(0) layout.addWidget(self.combo) layout.setContentsMargins(0, 0, 0, 0) self.setLayout(layout)
def __init__(self, parent, text, font, config): if config.get('frames', True): QFrame.__init__(self, parent, frameShape=QFrame.Panel, frameShadow=QFrame.Raised, lineWidth=2) else: QFrame.__init__(self, parent, frameShape=QFrame.NoFrame) self._label = None if text: self._label = QLabel(' ' + text + ' ', parent, autoFillBackground=True, font=font) self._label.resize(self._label.sizeHint()) self._label.show() self._onlyfields = [] self.setups = config.get('setups', None)
def __init__(self, parent, client, instrument, configs, config=None): QDialog.__init__(self, parent) self.instrument = instrument self.configs = configs self.client = client self.setWindowTitle('Sample configuration') layout = QVBoxLayout() self.frm = QFrame(self) loadUi(self.frm, findResource('nicos_ess/loki/gui/ui_files/sampleconf_one.ui')) self.frm.addDevBtn.clicked.connect(self.on_addDevBtn_clicked) self.frm.delDevBtn.clicked.connect(self.on_delDevBtn_clicked) self.frm.readDevsBtn.clicked.connect(self.on_readDevsBtn_clicked) box = QDialogButtonBox(self) box.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) box.accepted.connect(self.maybeAccept) box.rejected.connect(self.reject) layout.addWidget(self.frm) layout.addWidget(box) self.setLayout(layout) self.frm.thickBox.setValidator(DoubleValidator(self)) if config is not None: configToFrame(self.frm, config) # Apply local customisations to the stylesheet self.setStyleSheet(ConfigEditDialog_QSS) if not config: self.frm.whatLbl.setText('New sample configuration')
def __init__(self, parent, client, instrument, configs, config=None): QDialog.__init__(self, parent) self.instrument = instrument self.configs = configs self.client = client self.setWindowTitle('Sample configuration') layout = QVBoxLayout() self.frm = QFrame(self) loadUi(self.frm, findResource('nicos_mlz/kws1/gui/sampleconf_one.ui')) self.frm.addDevBtn.clicked.connect(self.on_addDevBtn_clicked) self.frm.delDevBtn.clicked.connect(self.on_delDevBtn_clicked) self.frm.readDevsBtn.clicked.connect(self.on_readDevsBtn_clicked) self.frm.readApBtn.clicked.connect(self.on_readApBtn_clicked) box = QDialogButtonBox(self) box.setStandardButtons(QDialogButtonBox.Ok | QDialogButtonBox.Cancel) box.accepted.connect(self.maybeAccept) box.rejected.connect(self.reject) layout.addWidget(self.frm) layout.addWidget(box) self.setLayout(layout) for box in [self.frm.offsetBox, self.frm.thickBox, self.frm.factorBox, self.frm.apXBox, self.frm.apYBox, self.frm.apWBox, self.frm.apHBox]: box.setValidator(DoubleValidator(self)) if config is not None: configToFrame(self.frm, config)
def addWidget(self, which): which.setContentsMargins(10, 0, 0, 0) self.scrollLayout.addRow(which) l = QFrame() l.setLineWidth(1) # l.setMidLineWidth(4) l.setFrameShape(QFrame.HLine) l.setContentsMargins(10, 0, 10, 0) self.scrollLayout.addRow(l)
def __init__(self, parent, nmin, allow_enter=False): QScrollArea.__init__(self, parent) self.setWidgetResizable(True) self.frame = QFrame(self) self.layout = QVBoxLayout() self.layout.setContentsMargins(2, 2, 2, 2) self.addBtn = QPushButton(QIcon(':/add'), '', self.frame) self.addBtn.clicked.connect(self.on_addBtn_clicked) self.addBtn.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)) self.layout.addWidget(self.addBtn) self.layout.addStretch() self.frame.setLayout(self.layout) self.setWidget(self.frame) self.items = [] self.nmin = nmin self.allow_enter = allow_enter
def on_list_itemClicked(self, item): self._clearDisplay() index = self.list.row(item) frm = QFrame(self) loadUi(frm, findResource('nicos_mlz/kws1/gui/sampleconf_one.ui')) frm.whatLbl.setText('Sample configuration') configToFrame(frm, self.configs[index]) frm.addDevBtn.setVisible(False) frm.delDevBtn.setVisible(False) frm.readApBtn.setVisible(False) frm.readDevsBtn.setVisible(False) # frm.posTbl.setEditTriggers(QTableWidget.NoEditTriggers) frm.posTbl.setEnabled(False) for box in frm.findChildren(QLineEdit): # box.setReadOnly(True) box.setEnabled(False) layout = self.frame.layout() layout.addWidget(frm)
def __init__(self, main): QDialog.__init__(self, main) loadUi(self, 'dialogs/watchdog.ui') self.frame = QFrame(self) self.scrollArea.setWidget(self.frame) self.frame.setLayout(QVBoxLayout()) self.frame.layout().setContentsMargins(0, 0, 10, 0) self.frame.layout().addStretch() def btn(button): if self.buttonBox.buttonRole(button) == QDialogButtonBox.ResetRole: for w in self.frame.children(): if isinstance(w, QWidget): w.hide() else: self.close() self.buttonBox.clicked.connect(btn)
class WatchdogDialog(QDialog): def __init__(self, main): QDialog.__init__(self, main) loadUi(self, 'dialogs/watchdog.ui') self.frame = QFrame(self) self.scrollArea.setWidget(self.frame) self.frame.setLayout(QVBoxLayout()) self.frame.layout().setContentsMargins(0, 0, 10, 0) self.frame.layout().addStretch() def btn(button): if self.buttonBox.buttonRole(button) == QDialogButtonBox.ResetRole: for w in self.frame.children(): if isinstance(w, QWidget): w.hide() else: self.close() self.buttonBox.clicked.connect(btn) def addEvent(self, data): # data: [event type, timestamp, message, watchdog entry id] layout = self.frame.layout() if data[0] == 'resolved': for i in range(layout.count()): widget = layout.itemAt(i).widget() if getattr(widget, 'entry_id', None) == data[3]: widget.datelabel.setText(widget.datelabel.text() + ' [RESOLVED]') return w = QWidget(self.frame) loadUi(w, 'dialogs/watchdog_item.ui') if len(data) > 3: # compatibility for older watchdogs w.entry_id = data[3] layout.insertWidget(self.frame.layout().count() - 1, w) timestamp = time.strftime('%Y-%m-%d %H:%M', time.localtime(data[1])) if data[0] == 'warning': w.datelabel.setText('Watchdog alert - ' + timestamp) w.messagelabel.setText(data[2]) elif data[0] == 'action': w.datelabel.setText('Watchdog action - ' + timestamp) w.messagelabel.setText('Executing action:\n' + data[2])
def __init__(self, parent, measdef, client): self.measdef = measdef self.client = client QDialog.__init__(self, parent) loadUi(self, findResource('nicos_ess/loki/gui/ui_files/devices.ui')) self.frame = QFrame(self) self.scrollArea.setWidget(self.frame) self.frame.setLayout(QVBoxLayout()) self.frame.layout().setContentsMargins(0, 0, 10, 0) self.frame.layout().addStretch() devlist = client.getDeviceList('nicos.core.device.Moveable') for dev in devlist: if dev not in DEV_NOT_ALLOWED: QListWidgetItem(dev, self.devList) self._widgets = [] for group in measdef.devices: devs = group[0].keys() w = self._addWidget(devs) for entry in group: w.addRow([entry[x] for x in devs])
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
class DevicesDialog(QDialog): def __init__(self, parent, measdef, client): self.measdef = measdef self.client = client QDialog.__init__(self, parent) loadUi(self, findResource('nicos_ess/loki/gui/ui_files/devices.ui')) self.frame = QFrame(self) self.scrollArea.setWidget(self.frame) self.frame.setLayout(QVBoxLayout()) self.frame.layout().setContentsMargins(0, 0, 10, 0) self.frame.layout().addStretch() devlist = client.getDeviceList('nicos.core.device.Moveable') for dev in devlist: if dev not in DEV_NOT_ALLOWED: QListWidgetItem(dev, self.devList) self._widgets = [] for group in measdef.devices: devs = group[0].keys() w = self._addWidget(devs) for entry in group: w.addRow([entry[x] for x in devs]) def toDefs(self): return [w.getDef() for w in self._widgets] def _addWidget(self, devs): w = DevicesWidget(self.frame, self.client, devs) self.frame.layout().insertWidget(self.frame.layout().count() - 1, w) w.remove.connect(self.on_removeWidget) self._widgets.append(w) return w @pyqtSlot() def on_addBtn_clicked(self): devs = [] for item in self.devList.selectedItems(): devs.append(item.text()) if not devs: return self.devList.clearSelection() w = self._addWidget(devs) w.addRow() def on_removeWidget(self, widget): self.frame.layout().removeWidget(widget) self._widgets.remove(widget) widget.deleteLater()
def resizeEvent(self, event): self._repos() return QFrame.resizeEvent(self, event)
def moveEvent(self, event): self._repos() return QFrame.moveEvent(self, event)
def __init__(self, model, name, addr): super(BaseDev, self).__init__() self.name = name self.model = model self.addr = addr self._namelabel = QLabel(name) self._namelabel.setMinimumWidth(120) self._namelabel.setMaximumWidth(120) # self._groupbox = QGroupBox(name) self._groupbox = QFrame() # self._groupbox.setFlat(False) # self._groupbox.setCheckable(False) self._hlayout = QHBoxLayout() self._hlayout.addWidget(self._namelabel) self._hlayout.addWidget(self._groupbox) self._hlayout.setSpacing(0) # inside of the groupbox there is a vbox with 1 or 2 hboxes self._inner_vbox = QVBoxLayout() self._groupbox.setLayout(self._inner_vbox) # upper inner hbox self._inner_hbox1 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox1) # fill upper hbox self.valueWidget = QLineEdit('0b123456789abcdef0') self.valueWidget.setMaximumWidth(120) self._inner_hbox1.addWidget(self.valueWidget) if self.has_target: self.targetWidget = QLineEdit() self.targetWidget.setPlaceholderText('') self.targetWidget.setMaximumWidth(120) self.targetWidget.returnPressed.connect(self._go_clicked) self._inner_hbox1.addWidget(self.targetWidget) self.goButton = QPushButton('Go') self.goButton.clicked.connect(self._go_clicked) self._inner_hbox1.addWidget(self.goButton) self.stopButton = QPushButton('Stop') self.stopButton.clicked.connect(self._stop_clicked) self._inner_hbox1.addWidget(self.stopButton) # now (conditionally) the second hbox if self.has_status: self._inner_hbox2 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox2) self.statvalueWidget = QLineEdit('statval') self.statvalueWidget.setMaximumWidth(120) self._inner_hbox2.addWidget(self.statvalueWidget) self.statusWidget = QLineEdit('Statusstring if available') self.statusWidget.setMaximumWidth(10000) self._inner_hbox2.addWidget(self.statusWidget) self.resetButton = QPushButton('Reset') self.resetButton.clicked.connect(self._reset_clicked) self._inner_hbox1.addWidget(self.resetButton) # self._inner_hbox2.addStretch(0.1) # allow space for resizing self._inner_hbox1.addStretch(1) self._inner_vbox.setSpacing(0) self._inner_vbox.setContentsMargins(0, 0, 0, 0) self._hlayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self._hlayout) self.show()
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 __init__(self, model, name, index, addr, has_status=False, target=None, value_offset=1): QWidget.__init__(self) self.index = index self.name = name self.model = model self.offset = value_offset self.has_status = has_status self.has_target = target is not None self.base_address = addr self._namelabel = QLabel(name) self._namelabel.setMinimumWidth(120) self._namelabel.setMaximumWidth(120) # self._groupbox = QGroupBox(name) self._groupbox = QFrame() # self._groupbox.setFlat(False) # self._groupbox.setCheckable(False) self._hlayout = QHBoxLayout() self._hlayout.addWidget(self._namelabel) self._hlayout.addWidget(self._groupbox) self._hlayout.setSpacing(0) # inside of the groupbox there is a vbox with 1 or 2 hboxes self._inner_vbox = QVBoxLayout() self._groupbox.setLayout(self._inner_vbox) # upper inner hbox self._inner_hbox1 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox1) # fill upper hbox self.valueWidget = QLineEdit('0b123456789abcdef0') self.valueWidget.setMaximumWidth(120) self._inner_hbox1.addWidget(self.valueWidget) if self.has_target: self.targetWidget = QLineEdit() self.targetWidget.setPlaceholderText(target) self.targetWidget.setMaximumWidth(120) self.targetWidget.returnPressed.connect(lambda *a: model.targeter( index, (self.targetWidget.text(), self.targetWidget.setText(''))[0])) self._inner_hbox1.addWidget(self.targetWidget) self.goButton = QPushButton('Go') self.goButton.clicked.connect(lambda *a: model.targeter( index, (self.targetWidget.text(), self.targetWidget.setText(''))[0])) self._inner_hbox1.addWidget(self.goButton) self.stopButton = QPushButton('Stop') self.stopButton.clicked.connect(lambda *a: model.stopper(index)) self._inner_hbox1.addWidget(self.stopButton) # now (conditionally) the second hbox if has_status: self._inner_hbox2 = QHBoxLayout() self._inner_vbox.addLayout(self._inner_hbox2) self.statvalueWidget = QLineEdit('statval') self.statvalueWidget.setMaximumWidth(120) self._inner_hbox2.addWidget(self.statvalueWidget) self.statusWidget = QLineEdit('Statusstring if available') self.statusWidget.setMaximumWidth(10000) self._inner_hbox2.addWidget(self.statusWidget) self.resetButton = QPushButton('Reset') self.resetButton.clicked.connect(lambda *a: model.resetter(index)) self._inner_hbox1.addWidget(self.resetButton) # self._inner_hbox2.addStretch(0.1) # allow space for resizing self._inner_hbox1.addStretch(1) self._inner_vbox.setSpacing(0) self._inner_vbox.setContentsMargins(0, 0, 0, 0) self._hlayout.setContentsMargins(0, 0, 0, 0) self.setLayout(self._hlayout) self.show()
class LokiSamplePanel(LokiPanelBase): panelName = 'LoKI sample setup' def __init__(self, parent, client, options): LokiPanelBase.__init__(self, parent, client, options) loadUi(self, findResource('nicos_ess/loki/gui/ui_files/sampleconf.ui')) self.sampleGroup.setEnabled(False) self.frame.setLayout(QVBoxLayout()) self.sample_frame = QFrame(self) loadUi( self.sample_frame, findResource('nicos_ess/loki/gui/ui_files/sampleconf_summary.ui')) layout = self.frame.layout() layout.addWidget(self.sample_frame) self.sample_frame.hide() self.sample_frame.posTbl.setEnabled(False) for box in self.sample_frame.findChildren(QLineEdit): box.setEnabled(False) menu = QMenu(self) menu.addAction(self.actionEmpty) menu.addAction(self.actionGenerate) self.createBtn.setMenu(menu) self.configs = [] self.holder_info = options.get('holder_info', []) self.instrument = options.get('instrument', 'loki') self.unapplied_changes = False self.applyBtn.setEnabled(False) self.initialise_connection_status_listeners() def setViewOnly(self, viewonly): for control in [ self.createBtn, self.retrieveBtn, self.openFileBtn, self.saveBtn, self.newBtn, self.editBtn, self.delBtn, self.frame, self.list ]: control.setEnabled(not viewonly) # Handle apply button separately. if viewonly: self.unapplied_changes = self.applyBtn.isEnabled() self.applyBtn.setEnabled(False) # If one toggles view only mode without applying changes, upon exiting # view-only mode, following ensures apply button is enabled. elif self.unapplied_changes: self.applyBtn.setEnabled(True) @pyqtSlot() def on_actionEmpty_triggered(self): self._clear_samples() self.sample_frame.hide() self.sampleGroup.setEnabled(True) self.on_newBtn_clicked() @pyqtSlot() def on_actionGenerate_triggered(self): def read_axes(): ax1, ax2 = dlg._info[2], dlg._info[4] for (ax, box) in [(ax1, dlg.ax1Box), (ax2, dlg.ax2Box)]: if not ax: continue x = self.client.eval('%s.read()' % ax, None) if x is None: QMessageBox.warning(dlg, 'Error', f'Could not read {ax}.') return box.setText(f'x:.1f') def btn_toggled(checked): if checked: dlg._info = dlg.sender()._info ax1, ax2 = dlg._info[2], dlg._info[4] for ax, lbl, box, revbox in [ (ax1, dlg.ax1Lbl, dlg.ax1Box, dlg.ax1RevBox), (ax2, dlg.ax2Lbl, dlg.ax2Box, None) ]: if ax: lbl.setText(ax) lbl.show() box.show() if revbox: revbox.show() revbox.setText(f'{ax} starts at far end') else: lbl.hide() box.hide() if revbox: revbox.hide() if not self.holder_info: self.showError('Cannot auto-generate sample list as no sample ' 'changers are defined') return dlg = dialogFromUi( self, findResource('nicos_ess/loki/gui/ui_files/sampleconf_gen.ui')) dlg.ax1Box.setValidator(DoubleValidator(self)) dlg.ax2Box.setValidator(DoubleValidator(self)) dlg.readBtn.clicked.connect(read_axes) n_rows = int(math.ceil(len(self.holder_info) / 2.0)) row, col = 0, 0 for name, info in self.holder_info: btn = QRadioButton(name, dlg) btn._info = info btn.toggled.connect(btn_toggled) dlg.optionFrame.layout().addWidget(btn, row, col) if (row, col) == (0, 0): btn.setChecked(True) row += 1 if row == n_rows: row = 0 col += 1 if dlg.exec_() != QDialog.Accepted: return self._generate_configs(dlg) first_item = None for config in self.configs: new_item = QListWidgetItem(config['name'], self.list) first_item = first_item or new_item # select the first item self.list.setCurrentItem(first_item) self.on_list_itemClicked(first_item) self.sampleGroup.setEnabled(True) self.applyBtn.setEnabled(True) def _generate_configs(self, dlg): rows, levels, ax1, dax1, ax2, dax2 = dlg._info sax1 = float(dlg.ax1Box.text()) if ax1 else 0 sax2 = float(dlg.ax2Box.text()) if ax2 else 0 if dlg.ax1RevBox.isChecked(): dax1 = -dax1 self._clear_samples() n = 0 for i in range(levels): for j in range(rows): n += 1 position = {} if ax1: position[ax1] = round(sax1 + j * dax1, 1) if ax2: position[ax2] = round(sax2 + i * dax2, 1) config = dict( name=str(n), comment='', detoffset=-335.0, thickness=1.0, aperture=(0, 0, 10, 10), position=position, ) self.configs.append(config) def _clear_samples(self): self.list.clear() self.configs.clear() @pyqtSlot() def on_retrieveBtn_clicked(self): sampleconf = self.client.eval('Exp.sample.samples', []) sampleconf = sorted(sampleconf.items()) self.configs = [dict(c[1]) for c in sampleconf if 'thickness' in c[1]] # convert read-only dict to normal dict for config in self.configs: config['position'] = dict(config['position'].items()) self.list.clear() last_item = None for config in self.configs: last_item = QListWidgetItem(config['name'], self.list) # select the last item if last_item: self.list.setCurrentItem(last_item) self.sampleGroup.setEnabled(True) self.applyBtn.setEnabled(False) @pyqtSlot() def on_openFileBtn_clicked(self): initial_dir = self.client.eval('session.experiment.scriptpath', '') filename = QFileDialog.getOpenFileName(self, 'Open sample file', initial_dir, 'Sample files (*.py)')[0] if not filename: return try: self.configs = parse_sampleconf(filename) except Exception as err: self.showError(f'Could not read file: {err}\n\n' 'Are you sure this is a sample file?') else: self.list.clear() self.sampleGroup.setEnabled(True) new_item = None for config in self.configs: new_item = QListWidgetItem(config['name'], self.list) # select the last item if new_item: self.list.setCurrentItem(new_item) self.on_list_itemClicked(new_item) self.applyBtn.setEnabled(True) @pyqtSlot() def on_applyBtn_clicked(self): script = self._generate_script() self.client.run(script) self.showInfo('Sample info has been transferred to the daemon.') self.applyBtn.setEnabled(False) @pyqtSlot() def on_saveBtn_clicked(self): initial_dir = self.client.eval('session.experiment.scriptpath', '') filename = QFileDialog.getSaveFileName(self, 'Save sample file', initial_dir, 'Sample files (*.py)')[0] if not filename: return False if not filename.endswith('.py'): filename += '.py' try: self._save_script(filename, self._generate_script()) except Exception as err: self.showError(f'Could not write file: {err}') def on_list_currentItemChanged(self, item): self.on_list_itemClicked(item) def on_list_itemClicked(self, item): if not item: return if self.sample_frame.isHidden(): self.sample_frame.show() index = self.list.row(item) configToFrame(self.sample_frame, self.configs[index]) def on_list_itemDoubleClicked(self): self.on_editBtn_clicked() @pyqtSlot() def on_newBtn_clicked(self): dlg = ConfigEditDialog(self, self.client, self.instrument, self.configs) if not dlg.exec_(): return self.applyBtn.setEnabled(True) config = configFromFrame(dlg.frm) self.configs.append(config) new_item = QListWidgetItem(config['name'], self.list) self.list.setCurrentItem(new_item) @pyqtSlot() def on_editBtn_clicked(self): index = self.list.currentRow() if index < 0: return dlg = ConfigEditDialog( self, self.client, self.instrument, [config for (i, config) in enumerate(self.configs) if i != index], self.configs[index]) if not dlg.exec_(): return self.applyBtn.setEnabled(True) config = configFromFrame(dlg.frm) self.configs[index] = config list_item = self.list.item(index) list_item.setText(config['name']) self.on_list_itemClicked(list_item) @pyqtSlot() def on_delBtn_clicked(self): index = self.list.currentRow() if index < 0: return self.applyBtn.setEnabled(True) self.list.takeItem(index) del self.configs[index] if self.list.currentRow() != -1: self.on_list_itemClicked(self.list.item(self.list.currentRow())) else: self.sample_frame.hide() def _generate_script(self): script = [ f'# LoKI sample file for NICOS\n', f'# Written: {time.asctime()}\n\n', f'ClearSamples()\n' ] for (i, config) in enumerate(self.configs, start=1): script.append(f"SetSample({i}, {repr(config['name'])}, ") for key in SAMPLE_KEYS: script.append(f"{key}={repr(config[key])}") script.append(', ') del script[-1] # remove last comma script.append(')\n') return ''.join(script) @staticmethod def _save_script(filename, script): with open(filename, 'w') as fp: fp.writelines(script)
def getToolbars(self): if not self.bars: bar = QToolBar('Scans') bar.addAction(self.actionSavePlot) bar.addAction(self.actionPrint) bar.addSeparator() bar.addAction(self.actionXAxis) bar.addAction(self.actionYAxis) bar.addAction(self.actionNormalized) bar.addSeparator() bar.addAction(self.actionLogXScale) bar.addAction(self.actionLogScale) bar.addAction(self.actionUnzoom) bar.addSeparator() bar.addAction(self.actionAutoScale) bar.addAction(self.actionScaleX) bar.addAction(self.actionScaleY) bar.addAction(self.actionLegend) bar.addAction(self.actionErrors) bar.addAction(self.actionResetPlot) bar.addAction(self.actionDeletePlot) bar.addSeparator() bar.addAction(self.actionAutoDisplay) bar.addAction(self.actionCombine) fitbar = QToolBar('Scan fitting') fitbar.addAction(self.actionFitPeak) wa = QWidgetAction(fitbar) self.fitPickCheckbox = QCheckBox(fitbar) self.fitPickCheckbox.setText('Pick') self.fitPickCheckbox.setChecked(True) self.actionPickInitial.setChecked(True) self.fitPickCheckbox.toggled.connect(self.actionPickInitial.setChecked) self.actionPickInitial.toggled.connect(self.fitPickCheckbox.setChecked) layout = QHBoxLayout() layout.setContentsMargins(10, 0, 10, 0) layout.addWidget(self.fitPickCheckbox) frame = QFrame(fitbar) frame.setLayout(layout) wa.setDefaultWidget(frame) fitbar.addAction(wa) ag = QActionGroup(fitbar) ag.addAction(self.actionFitPeakGaussian) ag.addAction(self.actionFitPeakLorentzian) ag.addAction(self.actionFitPeakPV) ag.addAction(self.actionFitPeakPVII) ag.addAction(self.actionFitTc) ag.addAction(self.actionFitCosine) ag.addAction(self.actionFitSigmoid) ag.addAction(self.actionFitLinear) ag.addAction(self.actionFitExponential) wa = QWidgetAction(fitbar) self.fitComboBox = QComboBox(fitbar) for a in ag.actions(): itemtext = a.text().replace('&', '') self.fitComboBox.addItem(itemtext) self.fitfuncmap[itemtext] = a self.fitComboBox.currentIndexChanged.connect( self.on_fitComboBox_currentIndexChanged) wa.setDefaultWidget(self.fitComboBox) fitbar.addAction(wa) fitbar.addSeparator() fitbar.addAction(self.actionFitArby) self.bars = [bar, fitbar] return self.bars
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()
class ItemsWidget(QScrollArea): valueModified = pyqtSignal() valueChosen = pyqtSignal(object) allow_reorder = True def __init__(self, parent, nmin, allow_enter=False): QScrollArea.__init__(self, parent) self.setWidgetResizable(True) self.frame = QFrame(self) self.layout = QVBoxLayout() self.layout.setContentsMargins(2, 2, 2, 2) self.addBtn = QPushButton(QIcon(':/add'), '', self.frame) self.addBtn.clicked.connect(self.on_addBtn_clicked) self.addBtn.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)) self.layout.addWidget(self.addBtn) self.layout.addStretch() self.frame.setLayout(self.layout) self.setWidget(self.frame) self.items = [] self.nmin = nmin self.allow_enter = allow_enter def insertItem(self, *widgets): item = QWidget(self.frame) item._widgets = widgets layout = QHBoxLayout() layout.setContentsMargins(0, 0, 0, 0) for widget in widgets: layout.addWidget(widget) if self.allow_reorder: btn = QPushButton(QIcon(':/up'), '', item) btn._item = item btn.clicked.connect(self.on_upBtn_clicked) layout.addWidget(btn) btn = QPushButton(QIcon(':/down'), '', item) btn._item = item btn.clicked.connect(self.on_downBtn_clicked) layout.addWidget(btn) btn = QPushButton(QIcon(':/remove'), '', item) btn._item = item btn.clicked.connect(self.on_removeBtn_clicked) layout.addWidget(btn) item.setLayout(layout) self.layout.insertWidget(self.layout.count() - 2, item) self.items.append(item) def on_addBtn_clicked(self): self.insertItem(*self.createItem()) self.valueModified.emit() def on_removeBtn_clicked(self): if len(self.items) <= self.nmin: return item = self.sender()._item index = self.items.index(item) del self.items[index] self.layout.takeAt(index).widget().deleteLater() self.valueModified.emit() def on_upBtn_clicked(self): item = self.sender()._item index = self.items.index(item) if index <= 0: return self._swapItems(index - 1) def on_downBtn_clicked(self): item = self.sender()._item index = self.items.index(item) if index >= len(self.items) - 1: return self._swapItems(index) def _swapItems(self, firstindex): item1 = self.items[firstindex] item2 = self.items[firstindex + 1] self.layout.takeAt(firstindex) self.layout.takeAt(firstindex) # moved up one self.items[firstindex:firstindex + 2] = [item2, item1] self.layout.insertWidget(firstindex, item2) self.layout.insertWidget(firstindex + 1, item1) self.valueModified.emit()