def loadUserStyle(window, settings): window.user_font = QFont(settings.value('font', QFont('Monospace'))) color = QColor(settings.value('color')) if color.isValid(): window.user_color = color else: window.user_color = QColor(Qt.white)
def setCustomStyle(self, font, back): self.user_font = font self.user_color = back for plot in self.setplots.values(): plot.setBackgroundColor(back) plot.update() bold = QFont(font) bold.setBold(True) larger = scaledFont(font, 1.6) for plot in self.setplots.values(): plot.setFonts(font, bold, larger)
def __init__(self, parent, view, tb): QDialog.__init__(self, parent) loadUi(self, 'dialogs/traceback.ui') self.tb = tb self.view = view self.client = parent.client assert tb.startswith('Traceback') # split into frames and message frames = [] message = '' curframe = [] for line in tb.splitlines(): if line.startswith(' '): try: name, v = line.split('=', 1) except ValueError: pass # most probably the "^" line of a SyntaxError else: if curframe: curframe[2][name.strip()] = v.strip() elif line.startswith(' '): if curframe: curframe[1] = line.strip() elif line.startswith(' '): curframe = [line.strip(), '', {}] frames.append(curframe) elif not line.startswith('Traceback'): message += line button = QPushButton('To clipboard', self) self.buttonBox.addButton(button, QDialogButtonBox.ActionRole) def copy(): QApplication.clipboard().setText(tb+'\n', QClipboard.Selection) QApplication.clipboard().setText(tb+'\n', QClipboard.Clipboard) button.clicked.connect(copy) self.message.setText(message[:200]) self.tree.setFont(view.font()) boldfont = QFont(view.font()) boldfont.setBold(True) for filename, line, bindings in frames: item = QTreeWidgetItem(self.tree, [filename]) item.setFirstColumnSpanned(True) item = QTreeWidgetItem(self.tree, [line]) item.setFirstColumnSpanned(True) item.setFont(0, boldfont) for var, value in iteritems(bindings): QTreeWidgetItem(item, ['', var, value])
def setCustomStyle(self, font, back): self.user_font = font self.user_color = back for view in self.views: if view.plot: view.plot.setBackgroundColor(back) view.plot.update() bold = QFont(font) bold.setBold(True) larger = scaledFont(font, 1.6) for view in self.views: if view.plot: view.plot.setFonts(font, bold, larger)
def _add_time_point(self, center_x, center_y, time_point): """Add a single time point item.""" x = center_x - (self.TIMEPOINT_DIAMETER / 2) y = center_y - (self.TIMEPOINT_DIAMETER / 2) # Create the acutal time point item time_point_item = QGraphicsEllipseItem(0, 0, self.TIMEPOINT_DIAMETER, self.TIMEPOINT_DIAMETER) # The used color is the strongest one of the FRM II colors. time_point_item.setBrush(QBrush(QColor(0x00, 0x71, 0xbb))) time_point_item.setPen(QPen(0)) self.scene().addItem(time_point_item) time_point_item.setPos(x, y) # place the time point item above the timeline and the selection item time_point_item.setZValue(2) # Create the label of the time point showing the time in the # defined strftime format on the right side of the time point item. label = QGraphicsTextItem(time_point.strftime(self.STRFTIME_FMT)) label.setFont(QFont('Monospace')) label_height = label.boundingRect().height() # minor height adjustment label_y = y - label_height / 6 self.scene().addItem(label) label.setPos(x + self.SELECTION_DIAMETER + self.LABEL_SPACING, label_y) # store references to the item and the timepoint in the same dict # to be able to use it for forward and reverse lookup self._time_point_items[time_point] = time_point_item self._time_point_items[time_point_item] = time_point
def _updateStyle(self, editor): if self.custom_font is None: return bold = QFont(self.custom_font) bold.setBold(True) if has_scintilla: lexer = editor.lexer() lexer.setDefaultFont(self.custom_font) for i in range(16): lexer.setFont(self.custom_font, i) # make keywords bold lexer.setFont(bold, 5) else: editor.setFont(self.custom_font) if has_scintilla: lexer.setPaper(self.custom_back) else: setBackgroundColor(editor, self.custom_back)
def __init__(self, window, timeaxis=False): DlgUtils.__init__(self, 'Plot') self.window = window self.plotcurves = [] self.show_all = False self.timeaxis = timeaxis self.hasSymbols = False self.hasLines = True # currently selected normalization column self.normalized = None self.fitter = None font = self.window.user_font bold = QFont(font) bold.setBold(True) larger = scaledFont(font, 1.6) self.setFonts(font, bold, larger)
def __init__(self, ps1='>>> ', ps2='... ', startup_message='', parent=None): QPlainTextEdit.__init__(self, parent) self.ps1, self.ps2 = ps1, ps2 self.history = [] self.namespace = {} self.construct = [] self.compiler = codeop.CommandCompiler() self.stdout = StdoutProxy(self.appendPlainText) self.setWordWrapMode(QTextOption.WrapAnywhere) self.setUndoRedoEnabled(False) self.document().setDefaultFont(QFont('Monospace', 10, QFont.Normal)) self.showMessage(startup_message)
def viewTextFile(self, fname): with open(fname) as f: contents = f.read() qd = QDialog(self, 'PreviewDlg', True) qd.setCaption('File preview') qd.resize(QSize(500, 500)) lay = QVBoxLayout(qd, 11, 6, 'playout') lb = QLabel(qd, 'label') lb.setText('Viewing %s:' % fname) lay.addWidget(lb) tx = QTextEdit(qd, 'preview') tx.setReadOnly(1) tx.setText(contents) font = QFont(tx.font()) font.setFamily('monospace') tx.setFont(font) lay.addWidget(tx) btn = QPushButton(qd, 'ok') btn.setAutoDefault(1) btn.setDefault(1) btn.setText('Close') btn.clicked.connect(qd.accept) lay.addWidget(btn, 0, QWidget.AlignRight) qd.show()
def __init__(self, parent, client, options): Panel.__init__(self, parent, client, options) loadUi(self, 'panels/scans.ui') ArbitraryFitter.arby_functions.update(options.get('fit_functions', {})) self.statusBar = QStatusBar(self, sizeGripEnabled=False) policy = self.statusBar.sizePolicy() policy.setVerticalPolicy(QSizePolicy.Fixed) self.statusBar.setSizePolicy(policy) self.layout().addWidget(self.statusBar) self.x_menu = QMenu(self) self.x_menu.aboutToShow.connect(self.on_x_menu_aboutToShow) self.actionXAxis.setMenu(self.x_menu) self.y_menu = QMenu(self) self.y_menu.aboutToShow.connect(self.on_y_menu_aboutToShow) self.actionYAxis.setMenu(self.y_menu) self.actionAutoDisplay.setChecked(True) self.norm_menu = QMenu(self) self.norm_menu.aboutToShow.connect(self.on_norm_menu_aboutToShow) self.actionNormalized.setMenu(self.norm_menu) quickfit = QShortcut(QKeySequence("G"), self) quickfit.activated.connect(self.on_quickfit) self.user_color = Qt.white self.user_font = QFont('Monospace') self.bulk_adding = False self.no_openset = False self.last_norm_selection = None self.fitclass = GaussFitter self.fitfuncmap = {} self.menus = None self.bars = None self.data = self.mainwindow.data # maps set uid -> plot self.setplots = {} # maps set uid -> list item self.setitems = {} # current plot object self.currentPlot = None # stack of set uids self.setUidStack = [] # uids of automatically combined datasets -> uid of combined one self.contSetUids = {} self.splitter.setSizes([20, 80]) self.splitter.restoreState(self.splitterstate) if self.tablecolwidth0 > 0: self.metaTable.setColumnWidth(0, self.tablecolwidth0) self.metaTable.setColumnWidth(1, self.tablecolwidth1) self.data.datasetAdded.connect(self.on_data_datasetAdded) self.data.pointsAdded.connect(self.on_data_pointsAdded) self.data.fitAdded.connect(self.on_data_fitAdded) client.experiment.connect(self.on_client_experiment) self.setCurrentDataset(None) self.updateList()
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): 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 scaledFont(font, scale): new = QFont(font) new.setPointSizeF(font.pointSizeF() * scale) return new
def convert(value): if isinstance(value, QFont): # QFont doesn't like to be copied with copy()... return QFont(value) return copy(value)
# keys: (expired, fixed) valueBrush = { (False, False): QBrush(), (False, True): QBrush(Qt.blue), (True, False): QBrush(QColor('#aaaaaa')), (True, True): QBrush(QColor('#aaaaaa')), } lowlevelBrush = { False: QBrush(Qt.black), True: QBrush(QColor('#666666')), } lowlevelFont = { False: QFont(), True: QFont(QFont().family(), -1, -1, True), } # QTreeWidgetItem types SETUP_TYPE = QTreeWidgetItem.UserType DEVICE_TYPE = SETUP_TYPE + 1 PARAM_TYPE = SETUP_TYPE + 2 def setBackgroundBrush(widget, color): palette = widget.palette() palette.setBrush(QPalette.Window, color) widget.setBackgroundRole(QPalette.Window) widget.setPalette(palette)
class NicosWidget(NicosListener): """Base mixin class for a widget that can receive cache events. This class can't inherit directly from QObject because Python classes can only derive from one PyQt base class, and that base class will be different for different widgets. """ # source for cache keys _source = None # daemon-client object, only present when used in the GUI client _client = None # set this to a description of the widget for the Qt designer designer_description = '' # set this to an icon name for the Qt designer designer_icon = None # define properties valueFont = PropDef('valueFont', 'QFont', QFont('Monospace'), 'Font used for displaying values') # collects all properties of self's class @lazy_property def properties(self): props = {} for attrname in dir(self.__class__): attr = getattr(self.__class__, attrname) if isinstance(attr, pyqtProperty): props[attrname] = attr return props # dictionary for storing current property values @lazy_property def props(self): return {} def __init__(self): for prop, pdef in iteritems(self.properties): if prop not in self.props: if callable(pdef.default): self.props[prop] = PropDef.convert(pdef.default(self)) else: self.props[prop] = PropDef.convert(pdef.default) self._scale = QFontMetrics(self.valueFont).width('0') self.initUi() def initUi(self): """Create user interface if necessary.""" def propertyUpdated(self, pname, value): """Called when a property in self.properties has been updated.""" if pname == 'valueFont': self._scale = QFontMetrics(value).width('0') self.update() def setClient(self, client): self.setSource(client) self._client = client # refresh all keys at widget creation time to get an initial value for key in self._devmap: ret = self._client.getCacheKey(key) if ret: self.on_keyChange(ret[0], ret[1], 0, False) # auto-connect client signal handlers for signal in DAEMON_EVENTS: handler = getattr(self, 'on_client_' + signal, None) if handler: getattr(self._client, signal).connect(handler)
def __init__(self, parent, view, tb): QDialog.__init__(self, parent) loadUi(self, 'dialogs/traceback.ui') self.tb = tb self.view = view self.client = parent.client assert tb.startswith(TB_HEADER) # split into frames and message frames = [] message = '' curframe = [] for line in tb.splitlines(): if line.startswith(' '): # frame local variable try: name, v = line.split('=', 1) except ValueError: pass # most probably the "^" line of a SyntaxError else: if curframe: curframe[2][name.strip()] = v.strip() elif line.startswith(' '): # frame source code if curframe: curframe[1] = line elif line.startswith(' '): # frame file/line curframe = [line.strip(), '', {}, None, None] frames.append(curframe) elif line.startswith(TB_CAUSE_MSG): curframe[-2] = message elif line.startswith(TB_CONTEXT_MSG): curframe[-1] = message elif line.startswith(TB_HEADER): message = '' # only collect the message of the final exc else: message += line button = QPushButton('To clipboard', self) self.buttonBox.addButton(button, QDialogButtonBox.ActionRole) def copy(): QApplication.clipboard().setText(tb+'\n', QClipboard.Selection) QApplication.clipboard().setText(tb+'\n', QClipboard.Clipboard) button.clicked.connect(copy) def line_item(msg): item = QTreeWidgetItem(self.tree, [msg]) item.setFirstColumnSpanned(True) return item self.message.setText(message[:200]) self.tree.setFont(view.font()) boldfont = QFont(view.font()) boldfont.setBold(True) for filename, line, bindings, cause, context in frames: line_item(filename) code_item = line_item(line) code_item.setFont(0, boldfont) for var, value in bindings.items(): QTreeWidgetItem(code_item, ['', var, value]) if cause: line_item(cause) line_item('') line_item(TB_CAUSE_MSG).setFont(0, boldfont) line_item('') elif context: line_item(context) line_item('') line_item(TB_CONTEXT_MSG).setFont(0, boldfont) line_item('') line_item(message)
def drawText(self, event, qp): qp.setPen(self.textColor()) qp.setFont(QFont('Arial', 10)) qp.drawText(event.rect(), Qt.AlignLeft, str(self.main.start())) qp.drawText(event.rect(), Qt.AlignRight, str(self.main.end()))