def modifyData(self): visible_curves = self.visibleCurves() # get input from the user: which curves should be modified how dlg = dialogFromUi(self, 'panels/modify.ui') def checkAll(): for i in range(dlg.list.count()): dlg.list.item(i).setCheckState(Qt.Checked) dlg.selectall.clicked.connect(checkAll) for i, descr in visible_curves: li = QListWidgetItem(descr, dlg.list) if len(visible_curves) == 1: li.setCheckState(Qt.Checked) dlg.operation.setFocus() else: li.setCheckState(Qt.Unchecked) if dlg.exec_() != QDialog.Accepted: return # evaluate selection op = dlg.operation.text() curves = [] for i in range(dlg.list.count()): li = dlg.list.item(i) if li.checkState() == Qt.Checked: curves.append(i) # modify curve data for i in curves: curve = self.plotcurves[visible_curves[i][0]] self._modifyCurve(curve, op) self.update()
def __init__(self, parent): QDialog.__init__(self, parent) loadUi(self, 'panels/fit_arby.ui') self.presets = DlgPresets('fit_arby', [(self.function, ''), (self.fitparams, ''), (self.xfrom, ''), (self.xto, '')]) self.presets.load() for name in sorted(ArbitraryFitter.arby_functions): QListWidgetItem(name, self.oftenUsed)
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)
def __init__(self, setups, typ, parent=None): QDialog.__init__(self, parent) uic.loadUi( path.abspath( path.join(path.dirname(__file__), '..', 'ui', 'dialogs', 'addxcludedialog.ui')), self) self.setWindowTitle('New %s ... ' % typ) self.labelHeader.setText('Add new %s:' % typ) for setup in setups: QListWidgetItem(setup, self.listWidgetSetups)
def __init__(self, parameters, existingParameters, parent=None): QDialog.__init__(self, parent) uic.loadUi( path.abspath( path.join(path.dirname(__file__), '..', 'ui', 'dialogs', 'addparameterdialog.ui')), self) self.lineEditCustomParameter.setHidden(True) missingParameters = [ key for key in parameters.keys() if key not in existingParameters.keys() and not key.startswith('_') ] if missingParameters: for key in sorted(missingParameters): listItem = QListWidgetItem(key, self.listWidgetSelectParameter) listItem.setToolTip(parameters[key].description) self.listWidgetSelectParameter.addItem(listItem) else: self.checkBoxCustomParameter.setChecked(True) self.checkBoxCustomParameter.setEnabled(False) self.lineEditCustomParameter.setEnabled(True)
def on_newBtn_clicked(self): dlg = ConfigEditDialog(self, self.client, self.instrument, self.configs) if not dlg.exec_(): return self.dirty = True config = configFromFrame(dlg.frm) dlg.frm.whatLbl.setText('New sample configuration') self.configs.append(config) newitem = QListWidgetItem(config['name'], self.list) self.list.setCurrentItem(newitem) self.on_list_itemClicked(newitem)
def __init__(self, parent, measdef, client): self.measdef = measdef self.samplefile = None self.client = client DlgUtils.__init__(self, 'Sample selection') QDialog.__init__(self, parent) loadUi(self, findResource('nicos_ess/loki/gui/ui_files/samples.ui')) self._init_samplefile = False self.samplefile = measdef.samplefile if self.samplefile is not None: self._init_samplefile = True self.on_sampleFileBtn_toggled(True) self._init_samplefile = False else: self.on_currentSamplesBtn_toggled(True) if self.measdef.samples: for sam in self.measdef.samples[0]: newitem = QListWidgetItem(sam['sample'].getValue(), self.selList) newitem.setData(SAMPLE_NUM, sam['sample'].extra[0])
def on_settingAdd_clicked(self): dlg = dialogFromUi(self, 'dialogs/settings_conn.ui') if dlg.exec_() != QDialog.Accepted: return if not dlg.name.text(): return name = dlg.name.text() while name in self.connpresets: name += '_' cdata = ConnectionData(dlg.host.text(), dlg.port.value(), dlg.login.text(), None, dlg.viewonly.isChecked()) self.connpresets[name] = cdata QListWidgetItem(name + ' (%s:%s)' % (cdata.host, cdata.port), self.settinglist).setData(32, name)
def add_to_flist(self, filename, fformat, scroll=True): shortname = path.basename(filename) if self.fileList.count() > 2 and \ self.fileList.item(self.fileList.count()-2).text() == shortname: return item = QListWidgetItem(shortname) item.setData(32, filename) item.setData(33, fformat) self.fileList.insertItem(self.fileList.count()-1, item) if scroll: self.fileList.scrollToBottom()
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 readonlydict to normal dict for config in self.configs: config['position'] = dict(config['position'].items()) newitem = None for config in self.configs: newitem = QListWidgetItem(config['name'], self.list) # select the last item if newitem: self.list.setCurrentItem(newitem) self.on_list_itemClicked(newitem) self.fileGroup.setEnabled(False) self.sampleGroup.setEnabled(True)
def setScript(self, script): self.traceView.clear() lines = script.splitlines() longest = len(str(len(lines))) padding = ' ' * (longest + 3) height = QFontMetrics(self.traceView.font()).height() for (i, line) in enumerate(lines): item = QListWidgetItem(self.otherlineicon, padding + line, self.traceView) item.setSizeHint(QSize(-1, height)) item.setData(Qt.UserRole, '%*d |' % (longest, i+1)) self.traceView.addItem(item) self.current_line = -1
def setLiveItems(self, n): nitems = len(self.liveitems) if n < nitems: nfiles = self.fileList.count() for i in range(nitems - 1, n - 1, -1): self.liveitems.pop(i) self.fileList.takeItem(nfiles - nitems + i) if self._livechannel > n: self._livechannel = 0 if n > 0 else None else: for i in range(nitems, n): item = QListWidgetItem('<Live #%d>' % (i + 1)) item.setData(FILENAME, i) item.setData(FILEFORMAT, '') item.setData(FILETAG, 'live') self.fileList.insertItem(self.fileList.count(), item) self.liveitems.append(item) if n == 1: self.liveitems[0].setText('<Live>') else: self.liveitems[0].setText('<Live #1>')
def selectCurve(self): """Let the user select a visible plot curve. If there is only one curve, return it directly. """ visible_curves = self.visibleDataCurves() if not visible_curves: return if len(visible_curves) > 1: dlg = dialogFromUi(self, 'panels/selector.ui') dlg.setWindowTitle('Select curve to fit') dlg.label.setText('Select a curve:') for _, descr in visible_curves: QListWidgetItem(descr, dlg.list) dlg.list.setCurrentRow(0) if dlg.exec_() != QDialog.Accepted: return fitcurve = visible_curves[dlg.list.currentRow()][0] else: fitcurve = visible_curves[0][0] return self.plotcurves[fitcurve]
def setScript(self, script): self.traceView.clear() lines = script.splitlines() longest = len(str(len(lines))) padding = ' ' * (longest + 3) metrics = QFontMetrics(self.traceView.font()) height = metrics.height() lineno_width = metrics.size(0, ' ' * (longest + 2)).width() self.traceView.itemDelegate()._margin_offset = lineno_width for (i, line) in enumerate(lines): item = QListWidgetItem(self.otherlineicon, padding + line, self.traceView) item.setSizeHint(QSize(-1, height)) item.setData(Qt.UserRole, '%*d' % (longest, i + 1)) self.traceView.addItem(item) self.current_line = -1
def on_openFileBtn_clicked(self): initialdir = self.client.eval('session.experiment.scriptpath', '') fn = QFileDialog.getOpenFileName(self, 'Open sample file', initialdir, 'Sample files (*.py)')[0] if not fn: return try: self.configs = parse_sampleconf(fn) except Exception as err: self.showError('Could not read file: %s\n\n' 'Are you sure this is a sample file?' % err) else: self.fileGroup.setEnabled(False) self.sampleGroup.setEnabled(True) newitem = None for config in self.configs: newitem = QListWidgetItem(config['name'], self.list) # select the last item if newitem: self.list.setCurrentItem(newitem) self.on_list_itemClicked(newitem) self.filename = fn
def add_to_flist(self, filename, filetype, tag, uid=None, scroll=True): # liveonly mode doesn't display a filelist if self._liveOnlyIndex is not None: return shortname = path.basename(filename) item = QListWidgetItem(shortname) item.setData(FILENAME, filename) item.setData(FILETYPE, filetype) item.setData(FILETAG, tag) item.setData(FILEUID, uid) self.fileList.insertItem(self.fileList.count(), item) if uid: self.remove_obsolete_cached_files() if scroll: self.fileList.scrollToBottom() return item
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])
class LiveDataPanel(Panel): panelName = 'Live data view' def __init__(self, parent, client, options): Panel.__init__(self, parent, client, options) loadUi(self, findResource('nicos_mlz/mira/gui/live.ui')) self._format = None self._runtime = 0 self._no_direct_display = False self._range_active = False self.statusBar = QStatusBar(self) policy = self.statusBar.sizePolicy() policy.setVerticalPolicy(QSizePolicy.Fixed) self.statusBar.setSizePolicy(policy) self.statusBar.setSizeGripEnabled(False) self.layout().addWidget(self.statusBar) if CascadeWidget: self.widget = CascadeWidget(self) self.widget.setContextMenuPolicy(Qt.CustomContextMenu) self.widgetLayout.addWidget(self.widget) else: raise RuntimeError('The Cascade live widget is not available') self.rangeFrom = QDoubleSpinBox(self) self.rangeTo = QDoubleSpinBox(self) for ctrl in [self.rangeFrom, self.rangeTo]: ctrl.setRange(0, 100000000) ctrl.setEnabled(False) ctrl.setMaximumWidth(90) ctrl.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) ctrl.valueChanged.connect(self.on_rangeChanged) self.liveitem = QListWidgetItem('<Live>', self.fileList) self.liveitem.setData(32, '') self.liveitem.setData(33, '') self.splitter.setSizes([20, 80]) self.splitter.restoreState(self.splitterstate) client.livedata.connect(self.on_client_livedata) if client.isconnected: self.on_client_connected() client.connected.connect(self.on_client_connected) client.setup.connect(self.on_client_connected) self.actionLogScale.toggled.connect(self.widget.SetLog10) self.actionSelectChannels.triggered.connect(self.widget.showSumDlg) self.widget.customContextMenuRequested.connect( self.on_widget_customContextMenuRequested) def loadSettings(self, settings): self.splitterstate = settings.value('splitter', '', QByteArray) def saveSettings(self, settings): settings.setValue('splitter', self.splitter.saveState()) def getMenus(self): self.menu = menu = QMenu('&Live data', self) menu.addAction(self.actionLoadTOF) menu.addAction(self.actionLoadPAD) menu.addSeparator() menu.addAction(self.actionWriteXml) menu.addAction(self.actionPrint) menu.addSeparator() menu.addAction(self.actionSetAsROI) menu.addAction(self.actionUnzoom) menu.addAction(self.actionLogScale) menu.addAction(self.actionNormalized) menu.addAction(self.actionLegend) return [menu] def getToolbars(self): bar = QToolBar('Live data') bar.addAction(self.actionWriteXml) bar.addAction(self.actionPrint) bar.addSeparator() bar.addAction(self.actionLogScale) bar.addSeparator() bar.addAction(self.actionUnzoom) bar.addAction(self.actionSetAsROI) bar.addSeparator() bar.addAction(self.actionSelectChannels) bar.addSeparator() bar.addAction(self.actionCustomRange) bar.addWidget(self.rangeFrom) bar.addWidget(QLabel(' to ')) bar.addWidget(self.rangeTo) bar.addSeparator() bar.addAction(self.actionOverviewMode) bar.addAction(self.actionPhaseMode) bar.addAction(self.actionContrastMode) return [bar] def on_widget_customContextMenuRequested(self, point): self.menu.popup(self.mapToGlobal(point)) def on_client_connected(self): self.client.tell('eventunmask', ['livedata']) datapath = self.client.eval('session.experiment.datapath', '') if not datapath: return caspath = path.join(datapath, 'cascade') if path.isdir(caspath): for fn in sorted(os.listdir(caspath)): if fn.endswith('.pad'): self.add_to_flist(path.join(caspath, fn), 'pad', False) elif fn.endswith('tof'): self.add_to_flist(path.join(caspath, fn), 'tof', False) def on_client_livedata(self, params, blobs): tag, _uid, _det, filename, dtype, nx, ny, nt, runtime = params # TODO: remove compatibility code if not isinstance(filename, str): filename, nx, ny, nt = filename[0], nx[0], ny[0], nt[0] if dtype == '<u4' and nx == 128 and ny == 128 and tag != 'MiraXML': if nt == 1: self._format = 'pad' elif nt == 128: self._format = 'tof' self._runtime = runtime self._filename = filename else: if filename and tag != 'MiraXML': self._filename = filename self._format = filename[-3:] else: # print 'Unsupported live data format:', params self._format = None for blob in blobs: self._process_livedata(blob) def _process_livedata(self, data): if self._format not in ('pad', 'tof'): return if data: self._last_data = data if not self._no_direct_display and data: runtime = self._runtime or 1e-6 if self._format == 'pad': self.widget.LoadPadMem(data, 128*128*4) cts = self.widget.GetPad().GetCounts() self.statusBar.showMessage('cps: %.2f | total: %s' % (cts/runtime, cts)) else: self.widget.LoadTofMem(data, 128*128*128*4) cts = self.widget.GetTof().GetCounts() self.statusBar.showMessage('cps: %.2f | total: %s' % (cts/runtime, cts)) self.updateRange() if self._filename and not self._filename.startswith(('live@', '<Live>@')): # and path.isfile(self._filename): if 'mira_cas' not in self._filename: self.add_to_flist(self._filename, self._format) def on_fileList_itemClicked(self, item): if item is None: return fname = item.data(32) fformat = item.data(33) if not fname: if self._no_direct_display: self._no_direct_display = False if self._format == 'pad': self.widget.LoadPadMem(self._last_data, 128*128*4) cts = self.widget.GetPad().GetCounts() self.statusBar.showMessage('total: %s' % cts) elif self._format == 'tof': self.widget.LoadTofMem(self._last_data, 128*128*128*4) cts = self.widget.GetTof().GetCounts() self.statusBar.showMessage('total: %s' % cts) self.updateRange() else: self._no_direct_display = True if fformat == 'pad': self.widget.LoadPadFile(fname) cts = self.widget.GetPad().GetCounts() self.statusBar.showMessage('total: %s' % cts) elif fformat == 'tof': self.widget.LoadTofFile(fname) cts = self.widget.GetTof().GetCounts() self.statusBar.showMessage('total: %s' % cts) self.updateRange() def on_fileList_currentItemChanged(self, item, previous): self.on_fileList_itemClicked(item) @pyqtSlot() def on_actionLoadTOF_triggered(self): filename = QFileDialog.getOpenFileName(self, 'Open TOF File', '', 'TOF File (*.tof *.TOF);;All files (*)')[0] if filename: self.widget.LoadTofFile(filename) self.add_to_flist(filename, 'tof') @pyqtSlot() def on_actionLoadPAD_triggered(self): filename = QFileDialog.getOpenFileName(self, 'Open PAD File', '', 'PAD File (*.pad *.PAD);;All files (*)')[0] if filename: self.widget.LoadPadFile(filename) self.updateRange() self.add_to_flist(filename, 'pad') def add_to_flist(self, filename, fformat, scroll=True): shortname = path.basename(filename) if self.fileList.count() > 2 and \ self.fileList.item(self.fileList.count()-2).text() == shortname: return item = QListWidgetItem(shortname) item.setData(32, filename) item.setData(33, fformat) self.fileList.insertItem(self.fileList.count()-1, item) if scroll: self.fileList.scrollToBottom() @pyqtSlot() def on_actionWriteXml_triggered(self): pad = self.widget.GetPad() if pad is None: return self.showError('No 2-d image is shown.') filename = str(QFileDialog.getSaveFileName( self, 'Select file name', '', 'XML files (*.xml)')[0]) if not filename: return if not filename.endswith('.xml'): filename += '.xml' if TmpImage: tmpimg = TmpImage() tmpimg.ConvertPAD(pad) tmpimg.WriteXML(filename) @pyqtSlot() def on_actionSetAsROI_triggered(self): zoom = self.widget.GetPlot().GetZoomer().zoomRect() self.client.run('psd_channel.roi = (%s, %s, %s, %s)' % (int(zoom.left()), int(zoom.top()), int(zoom.right()), int(zoom.bottom()))) @pyqtSlot() def on_actionUnzoom_triggered(self): self.widget.GetPlot().GetZoomer().zoom(0) @pyqtSlot() def on_actionPrint_triggered(self): printer = QPrinter(QPrinter.HighResolution) printer.setColorMode(QPrinter.Color) printer.setOrientation(QPrinter.Landscape) printer.setOutputFileName('') if QPrintDialog(printer, self).exec_() == QDialog.Accepted: self.widget.GetPlot().print_(printer) self.statusBar.showMessage('Plot successfully printed to %s.' % str(printer.printerName())) def on_actionCustomRange_toggled(self, on): self.rangeFrom.setEnabled(on) self.rangeTo.setEnabled(on) self.widget.SetAutoCountRange(not on) self._range_active = on if on: self.on_rangeChanged(0) else: self.updateRange() def on_rangeChanged(self, val): if self._range_active: self.widget.SetCountRange(self.rangeFrom.value(), self.rangeTo.value()) def updateRange(self): if not self.actionCustomRange.isChecked(): crange = self.widget.GetData2d().range() self.rangeFrom.setValue(crange.minValue()) self.rangeTo.setValue(crange.maxValue()) def closeEvent(self, event): with self.sgroup as settings: settings.setValue('geometry', self.saveGeometry()) event.accept() @pyqtSlot() def on_actionOverviewMode_triggered(self): self.widget.viewOverview() @pyqtSlot() def on_actionPhaseMode_triggered(self): self.widget.SetFoil(7) self.widget.viewPhases() @pyqtSlot() def on_actionContrastMode_triggered(self): self.widget.SetFoil(7) self.widget.viewContrasts()
def on_rightBtn_clicked(self): for item in self.allList.selectedItems(): newitem = QListWidgetItem(item.text(), self.selList) newitem.setData(SAMPLE_NUM, item.data(SAMPLE_NUM))
def __init__(self, parent, client): Cmdlet.__init__(self, parent, client, findResource('nicos_mlz/kws3/gui/restore.ui')) for devname in self._getDeviceList(): item = QListWidgetItem(devname, self.devList) item.setCheckState(Qt.Unchecked)
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', 'Could not read %s.' % ax) return box.setText('%.1f' % x) 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('%s starts at far end' % ax) else: lbl.hide() box.hide() if revbox: revbox.hide() dlg = dialogFromUi(self, findResource( 'nicos_mlz/kws1/gui/sampleconf_gen.ui')) dlg.ax1Box.setValidator(DoubleValidator(self)) dlg.ax2Box.setValidator(DoubleValidator(self)) dlg.readBtn.clicked.connect(read_axes) nrows = 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 == nrows: row = 0 col += 1 if not dlg.exec_(): return 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 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, timefactor = 1.0, aperture = (0, 0, 10, 10), position = position, ) self.configs.append(config) firstitem = None for config in self.configs: newitem = QListWidgetItem(config['name'], self.list) firstitem = firstitem or newitem # select the first item self.list.setCurrentItem(firstitem) self.on_list_itemClicked(firstitem) self.fileGroup.setEnabled(False) self.sampleGroup.setEnabled(True) self.dirty = True
class LiveDataPanel(Panel): panelName = 'Live data view' def __init__(self, parent, client, options): Panel.__init__(self, parent, client, options) loadUi(self, findResource('nicos_mlz/antares/gui/live.ui')) self._format = None self._runtime = 0 self._no_direct_display = False self._range_active = False self.statusBar = QStatusBar(self) policy = self.statusBar.sizePolicy() policy.setVerticalPolicy(QSizePolicy.Fixed) self.statusBar.setSizePolicy(policy) self.statusBar.setSizeGripEnabled(False) self.layout().addWidget(self.statusBar) self.widget = LWWidget(self) self.widget.setContextMenuPolicy(Qt.CustomContextMenu) self.widgetLayout.addWidget(self.widget) self.rangeFrom = QDoubleSpinBox(self) self.rangeTo = QDoubleSpinBox(self) for ctrl in [self.rangeFrom, self.rangeTo]: ctrl.setEnabled(False) ctrl.setMaximumWidth(90) ctrl.setSizePolicy( QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)) ctrl.valueChanged.connect(self.on_rangeChanged) self.liveitem = QListWidgetItem('<Live>', self.fileList) self.liveitem.setData(32, '') self.liveitem.setData(33, '') self.splitter.setSizes([20, 80]) self.splitter.restoreState(self.splitterstate) client.livedata.connect(self.on_client_livedata) client.liveparams.connect(self.on_client_liveparams) if client.isconnected: self.on_client_connected() client.connected.connect(self.on_client_connected) client.setup.connect(self.on_client_connected) self.actionLogScale.toggled.connect(self.widget.setLog10) self.widget.customContextMenuRequested.connect( self.on_widget_customContextMenuRequested) def loadSettings(self, settings): self.splitterstate = settings.value('splitter', '', QByteArray) def saveSettings(self, settings): settings.setValue('splitter', self.splitter.saveState()) def getMenus(self): self.menu = menu = QMenu('&Live data', self) # menu.addAction(self.actionLoadTOF) # menu.addAction(self.actionLoadPAD) # menu.addSeparator() # menu.addAction(self.actionWriteXml) menu.addAction(self.actionPrint) menu.addSeparator() menu.addAction(self.actionSetAsROI) menu.addAction(self.actionUnzoom) menu.addAction(self.actionLogScale) menu.addAction(self.actionNormalized) menu.addAction(self.actionLegend) return [menu] def getToolbars(self): bar = QToolBar('Live data') # bar.addAction(self.actionWriteXml) bar.addAction(self.actionPrint) bar.addSeparator() bar.addAction(self.actionLogScale) bar.addSeparator() bar.addAction(self.actionUnzoom) bar.addAction(self.actionSetAsROI) # bar.addSeparator() # bar.addAction(self.actionSelectChannels) return [bar] def on_widget_customContextMenuRequested(self, point): self.menu.popup(self.mapToGlobal(point)) def on_client_connected(self): self.client.tell('eventunmask', ['livedata', 'liveparams']) datapath = self.client.eval('session.experiment.datapath', '') if not datapath: return caspath = path.join(datapath, 'cascade') if path.isdir(caspath): for fn in sorted(os.listdir(caspath)): if fn.endswith('.pad'): self.add_to_flist(path.join(caspath, fn), 'pad', False) elif fn.endswith('tof'): self.add_to_flist(path.join(caspath, fn), 'tof', False) def on_client_liveparams(self, params): _tag, _uid, _det, _fname, dtype, nx, ny, nz, runtime = params # TODO: remove compatibility code if not isinstance(nx, integer_types): nx, ny, nz = nx[0], ny[0], nz[0] self._runtime = runtime if dtype not in DATATYPES: self._format = None self.log.warning('Unsupported live data format: %r', params) return self._format = dtype self._nx = nx self._ny = ny self._nz = nz def on_client_livedata(self, data): if self._format: self.widget.setData( LWData(self._nx, self._ny, self._nz, self._format, data)) @pyqtSlot() def on_actionSetAsROI_triggered(self): zoom = self.widget.plot().getZoomer().zoomRect() # XXX this is detector specific! self.client.run('det.setRelativeRoi(%s, %s, %s, %s)' % (int(zoom.left()), int(zoom.top()), int( zoom.right()), int(zoom.bottom()))) @pyqtSlot() def on_actionUnzoom_triggered(self): self.widget.plot().getZoomer().zoom(0) @pyqtSlot() def on_actionPrint_triggered(self): printer = QPrinter(QPrinter.HighResolution) printer.setColorMode(QPrinter.Color) printer.setOrientation(QPrinter.Landscape) printer.setOutputFileName('') if QPrintDialog(printer, self).exec_() == QDialog.Accepted: self.widget.plot().print_(printer) def on_actionCustomRange_toggled(self, on): self.rangeFrom.setEnabled(on) self.rangeTo.setEnabled(on) self.widget.SetAutoCountRange(not on) self._range_active = on if on: self.on_rangeChanged(0) else: self.updateRange() def on_rangeChanged(self, val): if self._range_active: self.widget.SetCountRange(self.rangeFrom.value(), self.rangeTo.value()) def updateRange(self): if not self.actionCustomRange.isChecked(): crange = self.widget.GetData2d().range() self.rangeFrom.setValue(crange.minValue()) self.rangeTo.setValue(crange.maxValue()) def closeEvent(self, event): with self.sgroup as settings: settings.setValue('geometry', self.saveGeometry()) event.accept()
def _createViewFromDialog(self, info, row=None): if not info['devices'].strip(): return keys_indices = [ extractKeyAndIndex(d.strip()) for d in info['devices'].split(',') ] if self.client is not None: meta = self._getMetainfo(keys_indices) else: meta = ({}, {}) name = info['name'] if not name: name = info['devices'] if info['simpleTime']: name += ' (%s)' % info['simpleTimeSpec'] window = None if info['simpleTime']: try: itime, _ = get_time_and_interval(info['simpleTimeSpec']) except ValueError: return fromtime = currenttime() - itime totime = None if info['slidingWindow']: window = itime else: if info['frombox']: fromtime = mktime(localtime(info['fromdate'])) else: fromtime = None if info['tobox']: totime = mktime(localtime(info['todate'])) else: totime = None try: interval = float(info['interval']) except ValueError: interval = 5.0 if info['customY']: try: yfrom = float(info['customYFrom']) except ValueError: return try: yto = float(info['customYTo']) except ValueError: return else: yfrom = yto = None view = View(self, name, keys_indices, interval, fromtime, totime, yfrom, yto, window, meta, info, self.gethistory_callback) self.views.append(view) view.listitem = QListWidgetItem(view.name) if row is not None: self.viewList.insertItem(row, view.listitem) else: self.viewList.addItem(view.listitem) self.openView(view) if view.totime is None: for key in view.uniq_keys: self.keyviews.setdefault(key, []).append(view) return view
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 __init__(self): loadUi(self, 'panels/history.ui') self.user_color = Qt.white self.user_font = QFont('Monospace') self.views = [] # stack of views to display self.viewStack = [] # maps watched keys to their views self.keyviews = {} # current plot object self.currentPlot = None self.fitclass = LinearFitter self.fitfuncmap = {} self.enablePlotActions(False) self.presetmenu = QMenu('&Presets', self) for (name, view) in self.last_views: item = QListWidgetItem(name, self.viewList) item.setForeground(QBrush(QColor('#aaaaaa'))) item.setData(Qt.UserRole, view) self.menus = None self.bar = None # NOTE: for this class, automatic connections don't work on PyQt4 >= # 4.12 since this class is not derived from QObject. But on older PyQt4 # and PyQt5, they do work, so we change use the usual naming scheme # slightly to avoid double connections. self.viewList.currentItemChanged.connect( self.on__viewList_currentItemChanged) self.viewList.itemClicked.connect(self.on__viewList_itemClicked) self.viewList.itemDoubleClicked.connect( self.on__viewList_itemDoubleClicked) self.actionNew.triggered.connect(self.on__actionNew_triggered) self.actionEditView.triggered.connect( self.on__actionEditView_triggered) self.actionCloseView.triggered.connect( self.on__actionCloseView_triggered) self.actionResetView.triggered.connect( self.on__actionResetView_triggered) self.actionDeleteView.triggered.connect( self.on__actionDeleteView_triggered) self.actionSavePlot.triggered.connect( self.on__actionSavePlot_triggered) self.actionPrint.triggered.connect(self.on__actionPrint_triggered) self.actionUnzoom.triggered.connect(self.on__actionUnzoom_triggered) self.actionLogScale.toggled.connect(self.on__actionLogScale_toggled) self.actionAutoScale.toggled.connect(self.on__actionAutoScale_toggled) self.actionScaleX.toggled.connect(self.on__actionScaleX_toggled) self.actionScaleY.toggled.connect(self.on__actionScaleY_toggled) self.actionLegend.toggled.connect(self.on__actionLegend_toggled) self.actionSymbols.toggled.connect(self.on__actionSymbols_toggled) self.actionLines.toggled.connect(self.on__actionLines_toggled) self.actionSaveData.triggered.connect( self.on__actionSaveData_triggered) self.actionFitPeak.triggered.connect(self.on__actionFitPeak_triggered) self.actionFitArby.triggered.connect(self.on__actionFitArby_triggered) self.actionFitPeakGaussian.triggered.connect( self.on__actionFitPeakGaussian_triggered) self.actionFitPeakLorentzian.triggered.connect( self.on__actionFitPeakLorentzian_triggered) self.actionFitPeakPV.triggered.connect( self.on__actionFitPeakPV_triggered) self.actionFitPeakPVII.triggered.connect( self.on__actionFitPeakPVII_triggered) self.actionFitTc.triggered.connect(self.on__actionFitTc_triggered) self.actionFitCosine.triggered.connect( self.on__actionFitCosine_triggered) self.actionFitSigmoid.triggered.connect( self.on__actionFitSigmoid_triggered) self.actionFitLinear.triggered.connect( self.on__actionFitLinear_triggered) self.actionFitExponential.triggered.connect( self.on__actionFitExponential_triggered)
def on_client_connected(self): self.detectors.clear() self.sampleenv.clear() default_flags = Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | \ Qt.ItemIsEnabled # fill detectors detectors = self.client.getDeviceList( 'nicos.core.device.Measurable', exclude_class='nicos.devices.generic.detector.PassiveChannel') self._orig_detlist = self.client.eval('session.experiment.detlist', []) for detname in detectors: item = QListWidgetItem(detname, self.detectors) item.setFlags(default_flags) item.setCheckState(Qt.Checked if detname in self._orig_detlist else Qt.Unchecked) # fill environment envdevs = self.client.getDeviceList( 'nicos.core.device.Readable', exclude_class='nicos.core.device.Measurable') self._orig_envlist = self.client.eval('session.experiment.envlist', []) for devname in envdevs: item = QListWidgetItem(devname, self.sampleenv) item.setFlags(default_flags) item.setCheckState(Qt.Checked if devname in self._orig_envlist else Qt.Unchecked) if self.client.viewonly: self.buttonBox.setStandardButtons(QDialogButtonBox.Close) else: self.buttonBox.setStandardButtons(QDialogButtonBox.Apply | QDialogButtonBox.Close)
def on_client_connected(self): # fill setups self._setupinfo = self.client.eval('session.readSetupInfo()', {}) all_loaded = self.client.eval('session.loaded_setups', set()) self._prev_aliases = self.client.eval( '{d.name: d.alias for d in session.devices.values() ' 'if "alias" in d.parameters}', {}) self._loaded = set() self._loaded_basic = None self.basicSetup.clear() self.optSetups.clear() self.errorLabel.hide() default_flags = Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | \ Qt.ItemIsEnabled keep = QListWidgetItem('<keep current>', self.basicSetup) if self._setupinfo is not None: for name, info in sorted(self._setupinfo.items()): if info is None: self.errorLabel.show() continue if info['group'] == 'basic': QListWidgetItem(name, self.basicSetup) if name in all_loaded: self._loaded_basic = name self._loaded.add(name) elif info['group'] == 'optional': item = QListWidgetItem(name, self.optSetups) item.setFlags(default_flags) item.setData(Qt.UserRole, 0) if name in all_loaded: self._loaded.add(name) item.setCheckState(Qt.Checked if name in all_loaded else Qt.Unchecked) elif info['group'] == 'plugplay': item = QListWidgetItem(name, self.optSetups) item.setFlags(default_flags) item.setData(Qt.UserRole, 1) if name in all_loaded: self._loaded.add(name) elif not self.showPnpBox.isChecked(): item.setHidden(True) item.setCheckState(Qt.Checked if name in all_loaded else Qt.Unchecked) self.basicSetup.setCurrentItem(keep) self._prev_alias_config = self._alias_config if self.client.viewonly: self.buttonBox.setStandardButtons(QDialogButtonBox.Close) self.buttonBox.removeButton(self._reload_btn) else: self.buttonBox.setStandardButtons(QDialogButtonBox.Apply | QDialogButtonBox.Close) self.buttonBox.addButton(self._reload_btn, QDialogButtonBox.ResetRole)
class LiveDataPanel(Panel): """Provides a generic "detector live view" for 2-D images. For most instruments, a specific panel must be implemented that takes care of the individual live display needs. Options: * ``instrument`` -- the instrument name that is passed on to the livewidget module. * ``filetypes`` default[] - List of filename extensions whose content should be displayed. This list extends the list of 'fits', 'raw', 'tiff', and 'TIFF'. * ``cachesize`` (default 20) - Number of entries in the live data cache. The live data cache allows to display of previous taken data. * ``showcached`` (default False) - If True the taken live data will be cached. """ panelName = 'Live data view' bar = None menu = None def __init__(self, parent, client, options): Panel.__init__(self, parent, client, options) loadUi(self, 'panels/live.ui') self._allowed_tags = set() self._last_tag = None self._last_fname = None self._last_format = None self._runtime = 0 self._no_direct_display = False self._range_active = False self._cachesize = 20 self._datacache = BoundedOrderedDict(maxlen=self._cachesize) self._datapathok = False self.statusBar = QStatusBar(self, sizeGripEnabled=False) policy = self.statusBar.sizePolicy() policy.setVerticalPolicy(QSizePolicy.Fixed) self.statusBar.setSizePolicy(policy) self.statusBar.setSizeGripEnabled(False) self.layout().addWidget(self.statusBar) self.widget = LWWidget(self) self.widget.setContextMenuPolicy(Qt.CustomContextMenu) self.widget.setControls(Logscale | MinimumMaximum | BrightnessContrast | Integrate | Histogram) self.widgetLayout.addWidget(self.widget) self.liveitem = QListWidgetItem('<Live>', self.fileList) self.liveitem.setData(32, '') self.liveitem.setData(33, '') self.splitter.setSizes([20, 80]) self.splitter.restoreState(self.splitterstate) # configure instrument specific behavior self._instrument = options.get('instrument', '') self.widget.setInstrumentOption(self._instrument) if self._instrument == 'toftof': self.widget.setAxisLabels('time channels', 'detectors') elif self._instrument == 'imaging': self.widget.setControls(ShowGrid | Logscale | Grayscale | Normalize | Darkfield | Despeckle | CreateProfile | Histogram | MinimumMaximum) elif self._instrument == 'laue': self.widget.setControls(ShowGrid | Grayscale | Darkfield | Despeckle | CreateProfile | Histogram | MinimumMaximum) self.widget.setStandardColorMap(True, False) elif self._instrument == 'poli': self.widget.setControls(ShowGrid | Logscale | Grayscale | Despeckle | CreateProfile | Histogram | MinimumMaximum | BrightnessContrast) if self._instrument in ('dns', 'dnspsd'): self.widget.setKeepAspect(False) else: self.widget.setKeepAspect(True) # configure allowed file types opt_filetypes = options.get('filetypes', list(FILETYPES)) self._allowed_tags = set(opt_filetypes) & set(FILETYPES) # configure caching self._showcached = options.get('showcached', False) self._cachesize = options.get('cachesize', 20) if self._cachesize < 1: self._cachesize = 1 # always cache the last live image self._datacache = BoundedOrderedDict(maxlen=self._cachesize) client.livedata.connect(self.on_client_livedata) client.liveparams.connect(self.on_client_liveparams) client.connected.connect(self.on_client_connected) client.setup.connect(self.on_client_connected) self.actionLogScale.toggled.connect(self.widget.setLog10) self.widget.profileUpdate.connect(self.on_widget_profileUpdate) self.widget.customContextMenuRequested.connect( self.on_widget_customContextMenuRequested) self._toftof_profile = None def loadSettings(self, settings): self.splitterstate = settings.value('splitter', '', QByteArray) def saveSettings(self, settings): settings.setValue('splitter', self.splitter.saveState()) settings.setValue('geometry', self.saveGeometry()) if self._toftof_profile: self._toftof_profile.close() def getMenus(self): if not self.menu: menu = QMenu('&Live data', self) menu.addAction(self.actionPrint) menu.addSeparator() menu.addAction(self.actionUnzoom) menu.addAction(self.actionLogScale) self.menu = menu return [self.menu] def getToolbars(self): if not self.bar: bar = QToolBar('Live data') bar.addAction(self.actionPrint) bar.addSeparator() bar.addAction(self.actionLogScale) bar.addSeparator() bar.addAction(self.actionUnzoom) self.bar = bar return [self.bar] def on_widget_customContextMenuRequested(self, point): self.menu.popup(self.mapToGlobal(point)) def on_widget_profileUpdate(self, proftype, nbins, x, y): if self._instrument != 'toftof': return if self._toftof_profile is None: self._toftof_profile = ToftofProfileWindow(self) self._toftof_profile.update(proftype, nbins, x, y) self._toftof_profile.show() def on_client_connected(self): self.client.tell('eventunmask', ['livedata', 'liveparams']) datapath = self.client.eval('session.experiment.datapath', '') if not datapath or not path.isdir(datapath): self._showcached = True # always show cached data if datapath is not accessible return if self._instrument == 'imaging': for fn in sorted(os.listdir(datapath)): if fn.endswith('.fits'): self.add_to_flist(path.join(datapath, fn), '', 'fits', False) def on_client_liveparams(self, params): tag, _uid, det, fname, dtype, nx, ny, nz, runtime = params if (self._instrument == 'dns' and det != 'det') or \ (self._instrument == 'dnspsd' and det != 'qm_det'): self._last_tag = self._last_fname = '' return if not isinstance(fname, string_types): fname, nx, ny, nz = fname[0], nx[0], ny[0], nz[0] self._runtime = runtime normalized_type = numpy.dtype(dtype).str if dtype != '' else '' # pylint: disable=compare-to-empty-string if not fname and normalized_type not in DATATYPES: self._last_format = self._last_fname = None self.log.warning('Unsupported live data format: %s', params) return self._last_tag = tag.lower() self._last_fname = fname self._last_format = normalized_type self._nx = nx self._ny = ny self._nz = nz def on_client_livedata(self, data): # pylint: disable=len-as-condition d = None if self._last_fname: if path.isfile( self._last_fname) and self._last_tag in self._allowed_tags: # in the case of a filename, we add it to the list self.add_to_flist(self._last_fname, self._last_format, self._last_tag) d = LWData(self._last_fname) elif len( data ) and self._last_format and self._last_tag in self._allowed_tags or self._last_tag == 'live': d = LWData(self._nx, self._ny, self._nz, self._last_format, data) self._datacache[self._last_fname] = (self._nx, self._ny, self._nz, self._last_format, data) if self._showcached: self.add_to_flist(self._last_fname, self._last_format, self._last_tag, cached=True) # always allow live data if self._last_tag == 'live': if len(data) and self._last_format: # we got live data with a specified format d = LWData(self._nx, self._ny, self._nz, self._last_format, data) # but display it right now only if on <Live> setting if self._no_direct_display or not d: return self.widget.setData(d) def add_to_flist(self, filename, fformat, ftag, cached=False, scroll=True): shortname = path.basename(filename) item = QListWidgetItem(shortname) item.setData(32, filename) item.setData(33, fformat) item.setData(34, ftag) item.setData(35, cached) self.fileList.insertItem(self.fileList.count() - 1, item) if cached: self.del_obsolete_cached_data() if scroll: self.fileList.scrollToBottom() def del_obsolete_cached_data(self): cached_item_rows = list() for row in range(self.fileList.count()): item = self.fileList.item(row) if item.data(35): cached_item_rows.append(row) if len(cached_item_rows) > self._cachesize: for row in cached_item_rows[0:-self._cachesize]: self.fileList.takeItem(row) def on_fileList_itemClicked(self, item): if item is None: return fname = item.data(32) ftag = item.data(34) cached = item.data(35) if fname == '': # pylint: disable=compare-to-empty-string # show always latest live image if self._no_direct_display: self._no_direct_display = False d = None if self._last_fname and path.isfile(self._last_fname) and \ self._last_tag in self._allowed_tags: d = LWData(self._last_fname) elif self._datacache: val = self._datacache.getlast() d = LWData(*val) if d: self.widget.setData(d) else: # show image from file self._no_direct_display = True if fname and str(ftag) in self._allowed_tags or str( ftag) == 'live': if cached: d = self._datacache.get(fname, None) if d: self.widget.setData(LWData(*d)) else: self.widget.setData(LWData(fname)) def on_fileList_currentItemChanged(self, item, previous): self.on_fileList_itemClicked(item) @pyqtSlot() def on_actionUnzoom_triggered(self): self.widget.plot().getZoomer().zoom(0) @pyqtSlot() def on_actionPrint_triggered(self): printer = QPrinter(QPrinter.HighResolution) printer.setColorMode(QPrinter.Color) printer.setOrientation(QPrinter.Landscape) printer.setOutputFileName('') if QPrintDialog(printer, self).exec_() == QDialog.Accepted: self.widget.plot().print_(printer) self.statusBar.showMessage('Plot successfully printed to %s.' % str(printer.printerName()))
def __init__(self, parent, client, options): Panel.__init__(self, parent, client, options) loadUi(self, 'panels/live.ui') self._allowed_tags = set() self._last_tag = None self._last_fname = None self._last_format = None self._runtime = 0 self._no_direct_display = False self._range_active = False self._cachesize = 20 self._datacache = BoundedOrderedDict(maxlen=self._cachesize) self._datapathok = False self.statusBar = QStatusBar(self, sizeGripEnabled=False) policy = self.statusBar.sizePolicy() policy.setVerticalPolicy(QSizePolicy.Fixed) self.statusBar.setSizePolicy(policy) self.statusBar.setSizeGripEnabled(False) self.layout().addWidget(self.statusBar) self.widget = LWWidget(self) self.widget.setContextMenuPolicy(Qt.CustomContextMenu) self.widget.setControls(Logscale | MinimumMaximum | BrightnessContrast | Integrate | Histogram) self.widgetLayout.addWidget(self.widget) self.liveitem = QListWidgetItem('<Live>', self.fileList) self.liveitem.setData(32, '') self.liveitem.setData(33, '') self.splitter.setSizes([20, 80]) self.splitter.restoreState(self.splitterstate) # configure instrument specific behavior self._instrument = options.get('instrument', '') self.widget.setInstrumentOption(self._instrument) if self._instrument == 'toftof': self.widget.setAxisLabels('time channels', 'detectors') elif self._instrument == 'imaging': self.widget.setControls(ShowGrid | Logscale | Grayscale | Normalize | Darkfield | Despeckle | CreateProfile | Histogram | MinimumMaximum) elif self._instrument == 'laue': self.widget.setControls(ShowGrid | Grayscale | Darkfield | Despeckle | CreateProfile | Histogram | MinimumMaximum) self.widget.setStandardColorMap(True, False) elif self._instrument == 'poli': self.widget.setControls(ShowGrid | Logscale | Grayscale | Despeckle | CreateProfile | Histogram | MinimumMaximum | BrightnessContrast) if self._instrument in ('dns', 'dnspsd'): self.widget.setKeepAspect(False) else: self.widget.setKeepAspect(True) # configure allowed file types opt_filetypes = options.get('filetypes', list(FILETYPES)) self._allowed_tags = set(opt_filetypes) & set(FILETYPES) # configure caching self._showcached = options.get('showcached', False) self._cachesize = options.get('cachesize', 20) if self._cachesize < 1: self._cachesize = 1 # always cache the last live image self._datacache = BoundedOrderedDict(maxlen=self._cachesize) client.livedata.connect(self.on_client_livedata) client.liveparams.connect(self.on_client_liveparams) client.connected.connect(self.on_client_connected) client.setup.connect(self.on_client_connected) self.actionLogScale.toggled.connect(self.widget.setLog10) self.widget.profileUpdate.connect(self.on_widget_profileUpdate) self.widget.customContextMenuRequested.connect( self.on_widget_customContextMenuRequested) self._toftof_profile = None