def addScaleBarWidget(self, parent): config = createForm("plot_scale.ui", parent) config_params = createForm("plot_scale_config.ui", None) self._scale_config = config self._scale_config_param = config_params config.configuration.clicked.connect(self._showConfig) config.scaleBar.toggled.connect(self.set_scale_show) config_params.selectTextColor.clicked.connect(self._changeScaleTextColor) config_params.selectLineColor.clicked.connect(self._changeScaleLineColor) config_params.selectPosition.highlighted['QString'].connect(self.set_scale_position) config_params.selectFont.clicked.connect(self._changeFont) config_params.lineThickness.valueChanged[int].connect(self._changeScaleLineThickness) config_params.outsideImage.toggled.connect(self._set_scaleBarOutsideImage) config.scaleBar.setChecked(self.scale_show) scaled_font = QFont(self.scale_font) scaled_font.setPointSizeF(config_params.selectFont.font().pointSizeF()) config_params.selectFont.setFont(scaled_font) setColor(config_params.textColor, self.scale_text) setColor(config_params.lineColor, self.scale_line) config_params.outsideImage.setChecked(self.scale_bar_outside_image) for i in range(config_params.selectPosition.count()): txt = config_params.selectPosition.itemText(i) if txt == self.scale_position: config_params.selectPosition.setCurrentIndex(i) break else: self.scale_position = config_params.selectPosition.itemText(0) config_params.selectPosition.setCurrentIndex(0) parent.layout().addWidget(config)
def show(cursor, pos=None, num_lines=6): """Displays a tooltip showing part of the cursor's Document. If the cursor has a selection, those blocks are displayed. Otherwise, num_lines lines are displayed. If pos is not given, the global mouse position is used. """ block = cursor.document().findBlock(cursor.selectionStart()) c2 = QTextCursor(block) if cursor.hasSelection(): c2.setPosition(cursor.selectionEnd(), QTextCursor.KeepAnchor) c2.movePosition(QTextCursor.EndOfBlock, QTextCursor.KeepAnchor) else: c2.movePosition(QTextCursor.NextBlock, QTextCursor.KeepAnchor, num_lines) data = textformats.formatData('editor') doc = QTextDocument() font = QFont(data.font) font.setPointSizeF(font.pointSizeF() * .8) doc.setDefaultFont(font) doc.setPlainText(c2.selection().toPlainText()) if metainfo.info(cursor.document()).highlighting: highlighter.highlight(doc, state=tokeniter.state(block)) size = doc.size().toSize() + QSize(8, -4) pix = QPixmap(size) pix.fill(data.baseColors['background']) doc.drawContents(QPainter(pix)) label = QLabel() label.setPixmap(pix) label.setStyleSheet("QLabel { border: 1px solid #777; }") label.resize(size) widgets.customtooltip.show(label, pos)
def getFontFromCmnd(self, fontinfo): ''' Returns a QFont based on the information in the dictionary fontinfo. Recognized keys in the font dictionary are: "family": font family name (string) "size": text size in points (1/72 inches) "italic": italicize? (False/True) "bold": make bold? (False/True) "underline": underline? (False/True) ''' try: myfont = QFont(fontinfo["family"]) except KeyError: myfont = self.__viewer.font() try: myfont.setPointSizeF(fontinfo["size"]) except KeyError: pass try: myfont.setItalic(fontinfo["italic"]) except KeyError: pass try: myfont.setBold(fontinfo["bold"]) except KeyError: pass try: myfont.setUnderline(fontinfo["underline"]) except KeyError: pass return myfont
def _addLabel(self, v, cnt): label = QLabel(v.name + ':') f = QFont(label.font().family()) f.setPointSizeF(11) label.setFont(f) label.setMinimumWidth(80) label.setAlignment(Qt.AlignRight) self.layout.addWidget(label, cnt, 0)
def _changeFont(self): fnt, ok = QFontDialog.getFont(self.scale_font, self._scale_config_param, "Font for the color scale bar") if ok: self.scale_font = fnt normal_size = self._scale_config_param.selectFont.font().pointSizeF() scaled_font = QFont(fnt) scaled_font.setPointSizeF(normal_size) self._scale_config_param.selectFont.setFont(scaled_font)
def test_partials_labels_disabled(self): # Set Big font size font = QFont(self._TestFont) font.setPointSizeF(84) self.lyr.textFont = font # Disable partials labels self._Pal.setShowingPartialsLabels(False) self._Pal.saveEngineSettings() self.checkTest()
def test_text_size_map_unit(self): # Label text size in map units self.lyr.fontSizeInMapUnits = True font = QFont(self._TestFont) font.setPointSizeF(460) self.lyr.textFont = font self._Mismatches['TestCanvasPoint'] = 776 self._ColorTols['TestComposerPdfPoint'] = 2 self.checkTest()
def loadSettings(self): s = QSettings() s.beginGroup("log") font = QFont(s.value("fontfamily", "monospace")) font.setPointSizeF(float(s.value("fontsize", 9.0))) with qutil.signalsBlocked(self.fontChooser, self.fontSize): self.fontChooser.setCurrentFont(font) self.fontSize.setValue(font.pointSizeF()) self.showlog.setChecked(s.value("show_on_start", True) not in (False, "false")) self.rawview.setChecked(s.value("rawview", True) not in (False, "false"))
def test_partials_labels_enabled(self): # Set Big font size font = QFont(self._TestFont) font.setPointSizeF(84) self.lyr.textFont = font # Enable partials labels self._Pal.setShowingPartialsLabels(True) self._Pal.saveEngineSettings() self._Mismatches['TestCanvasPoint'] = 779 self._ColorTols['TestComposerPdfPoint'] = 2 self.checkTest()
def loadSettings(self): s = QSettings() s.beginGroup("log") font = QFont(s.value("fontfamily", "monospace", type(""))) font.setPointSizeF(s.value("fontsize", 9.0, float)) with qutil.signalsBlocked(self.fontChooser, self.fontSize): self.fontChooser.setCurrentFont(font) self.fontSize.setValue(font.pointSizeF()) self.showlog.setChecked(s.value("show_on_start", True, bool)) self.rawview.setChecked(s.value("rawview", True, bool)) self.hideauto.setChecked(s.value("hide_auto_engrave", False, bool))
def _changeFont(self): fnt, ok = QFontDialog.getFont(self.scale_font, self._scale_config_param, "Font for the color scale bar") if ok: self.scale_font = fnt normal_size = self._scale_config_param.selectFont.font( ).pointSizeF() scaled_font = QFont(fnt) scaled_font.setPointSizeF(normal_size) self._scale_config_param.selectFont.setFont(scaled_font)
def logformats(self): """Returns a dictionary with QTextCharFormats for the different types of messages. Besides the STDOUT, STDERR, NEUTRAL, FAILURE and SUCCESS formats there is also a "link" format, that looks basically the same as the output formats, but blueish and underlined, to make parts of the output (e.g. filenames) look clickable. """ textColor = QApplication.palette().color(QPalette.WindowText) successColor = qutil.addcolor(textColor, 0, 128, 0) # more green failureColor = qutil.addcolor(textColor, 128, 0, 0) # more red linkColor = qutil.addcolor(textColor, 0, 0, 128) # more blue stdoutColor = qutil.addcolor(textColor, 64, 64, 0) # more purple s = QSettings() s.beginGroup("log") outputFont = QFont(s.value("fontfamily", "monospace", type(""))) outputFont.setPointSizeF(s.value("fontsize", 9.0, float)) output = QTextCharFormat() output.setFont(outputFont) # enable zooming the log font size output.setProperty(QTextFormat.FontSizeAdjustment, 0) stdout = QTextCharFormat(output) stdout.setForeground(stdoutColor) stderr = QTextCharFormat(output) link = QTextCharFormat(output) link.setForeground(linkColor) link.setFontUnderline(True) status = QTextCharFormat() status.setFontWeight(QFont.Bold) neutral = QTextCharFormat(status) success = QTextCharFormat(status) success.setForeground(successColor) failure = QTextCharFormat(status) failure.setForeground(failureColor) return { job.STDOUT: stdout, job.STDERR: stderr, job.NEUTRAL: neutral, job.SUCCESS: success, job.FAILURE: failure, 'link': link, }
def importTheme(filename, widget, schemeWidget): """Loads the colors theme from a file""" try: d = ET.parse(filename) root = d.getroot() if root.tag != "frescobaldi-theme": raise ValueError(_("No theme found.")) except Exception as e: QMessageBox.critical( widget, app.caption(_("Error")), _("Can't read from source:\n\n{url}\n\n{error}").format(url=filename, error=e), ) return schemeWidget.scheme.blockSignals(True) key = schemeWidget.addScheme(root.get("name")) schemeWidget.scheme.blockSignals(False) tfd = textformats.TextFormatData(key) fontElt = root.find("font") defaultfont = "Lucida Console" if os.name == "nt" else "monospace" if fontElt.get("fontFamily") in QFontDatabase().families(): fontFamily = fontElt.get("fontFamily") else: fontFamily = defaultfont font = QFont(fontFamily) font.setPointSizeF(float(fontElt.get("fontSize"))) tfd.font = font for elt in root.find("baseColors"): tfd.baseColors[elt.tag] = QColor(elt.get("color")) for elt in root.find("defaultStyles"): tfd.defaultStyles[elt.tag] = eltToStyle(elt) for style in root.find("allStyles"): if not style in tfd.allStyles: tfd.allStyles[style] = {} for elt in style: tfd.allStyles[style.tag][elt.tag] = eltToStyle(elt) widget.addSchemeData(key, tfd) schemeWidget.disableDefault(False) schemeWidget.currentChanged.emit() schemeWidget.changed.emit()
def importTheme(filename, widget, schemeWidget): """Loads the colors theme from a file""" try: d = ET.parse(filename) root = d.getroot() if root.tag != 'frescobaldi-theme': raise ValueError(_("No theme found.")) except Exception as e: QMessageBox.critical( widget, app.caption(_("Error")), _("Can't read from source:\n\n{url}\n\n{error}").format( url=filename, error=e)) return schemeWidget.scheme.blockSignals(True) key = schemeWidget.addScheme(root.get('name')) schemeWidget.scheme.blockSignals(False) tfd = textformats.TextFormatData(key) fontElt = root.find('font') defaultfont = "Lucida Console" if os.name == "nt" else "monospace" if fontElt.get('fontFamily') in QFontDatabase().families(): fontFamily = fontElt.get('fontFamily') else: fontFamily = defaultfont font = QFont(fontFamily) font.setPointSizeF(float(fontElt.get('fontSize'))) tfd.font = font for elt in root.find('baseColors'): tfd.baseColors[elt.tag] = QColor(elt.get('color')) for elt in root.find('defaultStyles'): tfd.defaultStyles[elt.tag] = eltToStyle(elt) for style in root.find('allStyles'): if not style in tfd.allStyles: tfd.allStyles[style] = {} for elt in style: tfd.allStyles[style.tag][elt.tag] = eltToStyle(elt) widget.addSchemeData(key, tfd) schemeWidget.disableDefault(False) schemeWidget.currentChanged.emit() schemeWidget.changed.emit()
def test_background_rect_w_offset(self): # Label rectangular background self._Mismatches['TestComposerImageVsCanvasPoint'] = 800 self._Mismatches['TestComposerImagePoint'] = 800 # verify fix for issues # http://hub.qgis.org/issues/9057 # http://gis.stackexchange.com/questions/86900 self.lyr.fontSizeInMapUnits = True font = QFont(self._TestFont) font.setPointSizeF(460) self.lyr.textFont = font self.lyr.shapeDraw = True self.lyr.shapeOffsetUnits = QgsPalLayerSettings.MapUnits self.lyr.shapeOffset = QPointF(-2900.0, -450.0) self._Mismatches['TestCanvasPoint'] = 774 self._ColorTols['TestComposerPdfPoint'] = 2 self.checkTest()
def test_background_svg(self): # Label SVG background self.lyr.fontSizeInMapUnits = True font = QFont(self._TestFont) font.setPointSizeF(460) self.lyr.textFont = font self.lyr.shapeDraw = True self.lyr.shapeType = QgsPalLayerSettings.ShapeSVG svg = os.path.join( svgSymbolsPath(), 'backgrounds', 'background_square.svg') self.lyr.shapeSVGFile = svg self.lyr.shapeSizeUnits = QgsPalLayerSettings.MapUnits self.lyr.shapeSizeType = QgsPalLayerSettings.SizeBuffer self.lyr.shapeSize = QPointF(100.0, 0.0) self._Mismatches['TestComposerPdfVsComposerPoint'] = 580 self._Mismatches['TestCanvasPoint'] = 776 self._ColorTols['TestComposerPdfPoint'] = 2 self.checkTest()
def test_background_svg(self): # Label SVG background self.lyr.fontSizeInMapUnits = True font = QFont(self._TestFont) font.setPointSizeF(460) self.lyr.textFont = font self.lyr.shapeDraw = True self.lyr.shapeType = QgsPalLayerSettings.ShapeSVG svg = os.path.join(svgSymbolsPath(), 'backgrounds', 'background_square.svg') self.lyr.shapeSVGFile = svg self.lyr.shapeSizeUnits = QgsPalLayerSettings.MapUnits self.lyr.shapeSizeType = QgsPalLayerSettings.SizeBuffer self.lyr.shapeSize = QPointF(100.0, 0.0) self._Mismatches['TestComposerPdfVsComposerPoint'] = 580 self._Mismatches['TestCanvasPoint'] = 776 self._ColorTols['TestComposerPdfPoint'] = 2 self.checkTest()
def paintEvent(self, event): bgcol = QColor('#111') if self.panic: fgcol = QColor('#e11') else: fgcol = QColor('#ddd') # Size and shit w, h = self.width(), self.height() minsize = min(w,h)*self.scale arcwidth = minsize*0.1 minsize *= 0.86 marginx = (w-minsize)/2 marginy = (h-minsize)/2 # Start drawing shit painter = QPainter(self) painter.setRenderHints(QPainter.Antialiasing | QPainter.TextAntialiasing) painter.setPen(QPen(fgcol, arcwidth, cap=Qt.FlatCap)) #font = QFont('sv basic manual') font = QFont('bank gothic') font.setPointSize(get_font_size(font, minsize-2*arcwidth)) smallfont = QFont(font) smallfont.setPointSizeF(font.pointSize()/2) painter.fillRect(QRectF(0,0,w,h), bgcol) # Timer dial thingy painter.setOpacity(0.05) painter.drawArc(marginx,marginy, minsize,minsize, 0, 5760) painter.setOpacity(1) arclength = min(1, self.totalseconds/self.panictime) * 5760 painter.drawArc(marginx,marginy, minsize,minsize, 90*16, -arclength) # Timer text painter.setFont(font) textoptions = QtGui.QTextOption(Qt.AlignCenter) painter.drawText(QRectF(marginx, marginy, minsize, minsize), self.get_text(0), textoptions) painter.setFont(smallfont) painter.setOpacity(0.5) painter.drawText(QRectF(marginx, marginy+minsize*0.4, minsize, minsize/2), self.get_text(1), textoptions) #painter.setOpacity(0.15) #painter.drawText(QRectF(marginx, marginy+minsize*0.05, minsize, minsize/2), # self.get_text(2), textoptions) painter.end()
def addScaleBarWidget(self, parent): config = createForm("plot_scale.ui", parent) config_params = createForm("plot_scale_config.ui", None) self._scale_config = config self._scale_config_param = config_params config.configuration.clicked.connect(self._showConfig) config.scaleBar.toggled.connect(self.set_scale_show) config_params.selectTextColor.clicked.connect( self._changeScaleTextColor) config_params.selectLineColor.clicked.connect( self._changeScaleLineColor) config_params.selectPosition.highlighted['QString'].connect( self.set_scale_position) config_params.selectFont.clicked.connect(self._changeFont) config_params.lineThickness.valueChanged[int].connect( self._changeScaleLineThickness) config_params.outsideImage.toggled.connect( self._set_scaleBarOutsideImage) config.scaleBar.setChecked(self.scale_show) scaled_font = QFont(self.scale_font) scaled_font.setPointSizeF(config_params.selectFont.font().pointSizeF()) config_params.selectFont.setFont(scaled_font) setColor(config_params.textColor, self.scale_text) setColor(config_params.lineColor, self.scale_line) config_params.outsideImage.setChecked(self.scale_bar_outside_image) for i in range(config_params.selectPosition.count()): txt = config_params.selectPosition.itemText(i) if txt == self.scale_position: config_params.selectPosition.setCurrentIndex(i) break else: self.scale_position = config_params.selectPosition.itemText(0) config_params.selectPosition.setCurrentIndex(0) parent.layout().addWidget(config)
class TextFormatData(object): """Encapsulates all settings in the Fonts & Colors page for a scheme.""" def __init__(self, scheme): """Loads the data from scheme.""" self.font = None self.baseColors = {} self.defaultStyles = {} self.allStyles = {} self._inherits = {} self.load(scheme) def load(self, scheme): """Load the settings for the scheme. Called on init.""" s = QSettings() s.beginGroup("fontscolors/" + scheme) # load font defaultfont = "Lucida Console" if os.name == "nt" else "monospace" self.font = QFont(s.value("fontfamily", defaultfont, type(""))) self.font.setPointSizeF(s.value("fontsize", 10.0, float)) # load base colors s.beginGroup("basecolors") for name in baseColors: if s.contains(name): self.baseColors[name] = QColor(s.value(name, "", type(""))) else: self.baseColors[name] = baseColorDefaults[name]() s.endGroup() # get the list of supported styles from ly.colorize all_styles = ly.colorize.default_mapping() default_styles = set() for group, styles in all_styles: d = self._inherits[group] = {} for style in styles: if style.base: default_styles.add(style.base) d[style.name] = style.base default_scheme = ly.colorize.default_scheme # load default styles s.beginGroup("defaultstyles") for name in default_styles: self.defaultStyles[name] = f = QTextCharFormat() css = default_scheme[None].get(name) if css: css2fmt(css, f) s.beginGroup(name) self.loadTextFormat(f, s) s.endGroup() s.endGroup() # load specific styles s.beginGroup("allstyles") for group, styles in all_styles: self.allStyles[group]= {} s.beginGroup(group) for style in styles: self.allStyles[group][style.name] = f = QTextCharFormat() css = default_scheme[group].get(style.name) if css: css2fmt(css, f) s.beginGroup(style.name) self.loadTextFormat(f, s) s.endGroup() s.endGroup() s.endGroup() def save(self, scheme): """Save the settings to the scheme.""" s = QSettings() s.beginGroup("fontscolors/" + scheme) # save font s.setValue("fontfamily", self.font.family()) s.setValue("fontsize", self.font.pointSizeF()) # save base colors for name in baseColors: s.setValue("basecolors/"+name, self.baseColors[name].name()) # save default styles s.beginGroup("defaultstyles") for name in defaultStyles: s.beginGroup(name) self.saveTextFormat(self.defaultStyles[name], s) s.endGroup() s.endGroup() # save all specific styles s.beginGroup("allstyles") for group, styles in ly.colorize.default_mapping(): s.beginGroup(group) for style in styles: s.beginGroup(style.name) self.saveTextFormat(self.allStyles[group][style.name], s) s.endGroup() s.endGroup() s.endGroup() def textFormat(self, group, name): """Return a QTextCharFormat() for the specified group and name.""" inherit = self._inherits[group].get(name) f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat() f.merge(self.allStyles[group][name]) return f def css_scheme(self): """Return a dictionary of css dictionaries representing this scheme. This can be fed to the ly.colorize.format_stylesheet() function. """ scheme = {} # base/default styles d = scheme[None] = {} for name, fmt in self.defaultStyles.items(): d[name] = fmt2css(fmt) # mode/group styles for mode, styles in self.allStyles.items(): d = scheme[mode] = {} for name, fmt in styles.items(): d[name] = fmt2css(fmt) return scheme def palette(self): """Return a basic palette with text, background, selection and selection background filled in.""" p = QApplication.palette() p.setColor(QPalette.Text, self.baseColors['text']) p.setColor(QPalette.Base, self.baseColors['background']) p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext']) p.setColor(QPalette.Highlight, self.baseColors['selectionbackground']) return p def saveTextFormat(self, fmt, settings): """(Internal) Store one QTextCharFormat in the QSettings instance.""" if fmt.hasProperty(QTextFormat.FontWeight): settings.setValue('bold', fmt.fontWeight() >= 70) else: settings.remove('bold') if fmt.hasProperty(QTextFormat.FontItalic): settings.setValue('italic', fmt.fontItalic()) else: settings.remove('italic') if fmt.hasProperty(QTextFormat.TextUnderlineStyle): settings.setValue('underline', fmt.fontUnderline()) else: settings.remove('underline') if fmt.hasProperty(QTextFormat.ForegroundBrush): settings.setValue('textColor', fmt.foreground().color().name()) else: settings.remove('textColor') if fmt.hasProperty(QTextFormat.BackgroundBrush): settings.setValue('backgroundColor', fmt.background().color().name()) else: settings.remove('backgroundColor') if fmt.hasProperty(QTextFormat.TextUnderlineColor): settings.setValue('underlineColor', fmt.underlineColor().name()) else: settings.remove('underlineColor') def loadTextFormat(self, fmt, settings): """(Internal) Merge values from the QSettings instance into the QTextCharFormat.""" if settings.contains('bold'): fmt.setFontWeight(QFont.Bold if settings.value('bold', False, bool) else QFont.Normal) if settings.contains('italic'): fmt.setFontItalic(settings.value('italic', False, bool)) if settings.contains('underline'): fmt.setFontUnderline(settings.value('underline', False, bool)) if settings.contains('textColor'): fmt.setForeground(QColor(settings.value('textColor', '' , type("")))) if settings.contains('backgroundColor'): fmt.setBackground(QColor(settings.value('backgroundColor', '' , type("")))) if settings.contains('underlineColor'): fmt.setUnderlineColor(QColor(settings.value('underlineColor', '' , type(""))))
class TextFormatData(object): """Encapsulates all settings in the Fonts & Colors page for a scheme.""" def __init__(self, scheme): """Loads the data from scheme.""" self.font = None self.baseColors = {} self.defaultStyles = {} self.allStyles = {} self.load(scheme) def load(self, scheme): """Load the settings for the scheme. Called on init.""" s = QSettings() s.beginGroup("fontscolors/" + scheme) # load font self.font = QFont(s.value("fontfamily", "monospace")) self.font.setPointSizeF(float(s.value("fontsize", 10.0))) # load base colors s.beginGroup("basecolors") for name in baseColors: if s.contains(name): self.baseColors[name] = QColor(s.value(name)) else: self.baseColors[name] = baseColorDefaults[name]() s.endGroup() # load default styles s.beginGroup("defaultstyles") for name in defaultStyles: self.defaultStyles[name] = f = QTextCharFormat(defaultStyleDefaults[name]) s.beginGroup(name) self.loadTextFormat(f, s) s.endGroup() s.endGroup() # load specific styles s.beginGroup("allstyles") for group, styles in allStyles: self.allStyles[group]= {} s.beginGroup(group) for name in styles: default = allStyleDefaults[group].get(name) self.allStyles[group][name] = f = QTextCharFormat(default) if default else QTextCharFormat() s.beginGroup(name) self.loadTextFormat(f, s) s.endGroup() s.endGroup() s.endGroup() def save(self, scheme): """Save the settings to the scheme.""" s = QSettings() s.beginGroup("fontscolors/" + scheme) # save font s.setValue("fontfamily", self.font.family()) s.setValue("fontsize", self.font.pointSizeF()) # save base colors for name in baseColors: s.setValue("basecolors/"+name, self.baseColors[name].name()) # save default styles s.beginGroup("defaultstyles") for name in defaultStyles: s.beginGroup(name) self.saveTextFormat(self.defaultStyles[name], s) s.endGroup() s.endGroup() # save all specific styles s.beginGroup("allstyles") for group, styles in allStyles: s.beginGroup(group) for name in styles: s.beginGroup(name) self.saveTextFormat(self.allStyles[group][name], s) s.endGroup() s.endGroup() s.endGroup() def textFormat(self, group, name): """Return a QTextCharFormat() for the specified group and name.""" inherit = inherits[group].get(name) f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat() f.merge(self.allStyles[group][name]) return f def palette(self): """Return a basic palette with text, background, selection and selection background filled in.""" p = QApplication.palette() p.setColor(QPalette.Text, self.baseColors['text']) p.setColor(QPalette.Base, self.baseColors['background']) p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext']) p.setColor(QPalette.Highlight, self.baseColors['selectionbackground']) return p def saveTextFormat(self, fmt, settings): """(Internal) Store one QTextCharFormat in the QSettings instance.""" if fmt.hasProperty(QTextFormat.FontWeight): settings.setValue('bold', fmt.fontWeight() >= 70) else: settings.remove('bold') if fmt.hasProperty(QTextFormat.FontItalic): settings.setValue('italic', fmt.fontItalic()) else: settings.remove('italic') if fmt.hasProperty(QTextFormat.TextUnderlineStyle): settings.setValue('underline', fmt.fontUnderline()) else: settings.remove('underline') if fmt.hasProperty(QTextFormat.ForegroundBrush): settings.setValue('textColor', fmt.foreground().color().name()) else: settings.remove('textColor') if fmt.hasProperty(QTextFormat.BackgroundBrush): settings.setValue('backgroundColor', fmt.background().color().name()) else: settings.remove('backgroundColor') if fmt.hasProperty(QTextFormat.TextUnderlineColor): settings.setValue('underlineColor', fmt.underlineColor().name()) else: settings.remove('underlineColor') def loadTextFormat(self, fmt, settings): """(Internal) Merge values from the QSettings instance into the QTextCharFormat.""" if settings.contains('bold'): fmt.setFontWeight(QFont.Bold if settings.value('bold') in (True, 'true') else QFont.Normal) if settings.contains('italic'): fmt.setFontItalic(settings.value('italic') in (True, 'true')) if settings.contains('underline'): fmt.setFontUnderline(settings.value('underline') in (True, 'true')) if settings.contains('textColor'): fmt.setForeground(QColor(settings.value('textColor'))) if settings.contains('backgroundColor'): fmt.setBackground(QColor(settings.value('backgroundColor'))) if settings.contains('underlineColor'): fmt.setUnderlineColor(QColor(settings.value('underlineColor')))
class CharMap(QWidget): """A widget displaying a table of characters.""" characterSelected = pyqtSignal(str) characterClicked = pyqtSignal(str) def __init__(self, parent=None): super(CharMap, self).__init__(parent) self._showToolTips = True self._showWhatsThis = True self._selected = -1 self._column_count = 32 self._square = 24 self._range = (0, 0) self._font = QFont() def setRange(self, first, last): self._range = (first, last) self._selected = -1 self.adjustSize() self.update() def range(self): return self._range def square(self): """Returns the width of one item (determined by font size).""" return self._square def select(self, charcode): """Selects the specified character (int or str).""" if not isinstance(charcode, int): charcode = ord(charcode) if not self._range[0] <= charcode <= self._range[1]: charcode = -1 if self._selected != charcode: self._selected = charcode self.characterSelected.emit(chr(charcode)) self.update() def character(self): """Returns the currently selected character, if any.""" if self._selected != -1: return chr(self._selected) def setDisplayFont(self, font): self._font.setFamily(font.family()) self.update() def displayFont(self): return QFont(self._font) def setDisplayFontSize(self, size): self._font.setPointSize(size) self._square = max(24, QFontMetrics(self._font).xHeight() * 3) self.adjustSize() self.update() def displayFontSize(self): return self._font.pointSize() def setDisplayFontSizeF(self, size): self._font.setPointSizeF(size) self._square = max(24, QFontMetrics(self._font).xHeight() * 3) self.adjustSize() self.update() def displayFontSizeF(self): return self._font.pointSizeF() def setColumnCount(self, count): """Sets how many columns should be used.""" count = max(1, count) self._column_count = count self.adjustSize() self.update() def columnCount(self): return self._column_count def sizeHint(self): return self.sizeForColumnCount(self._column_count) def paintEvent(self, ev): rect = ev.rect() s = self._square rows = range(rect.top() // s, rect.bottom() // s + 1) cols = range(rect.left() // s, rect.right() // s + 1) painter = QPainter(self) painter.setPen(QPen(self.palette().color(QPalette.Window))) painter.setFont(self._font) metrics = QFontMetrics(self._font) # draw characters on white tiles tile = self.palette().color(QPalette.Base) selected_tile = self.palette().color(QPalette.Highlight) selected_tile.setAlpha(96) selected_box = self.palette().color(QPalette.Highlight) text_pen = QPen(self.palette().text()) disabled_pen = QPen(self.palette().color(QPalette.Disabled, QPalette.Text)) selection_pen = QPen(selected_box) for row in rows: for col in cols: char = row * self._column_count + col + self._range[0] if char > self._range[1]: break printable = self.isprint(char) painter.setClipRect(col * s, row * s, s, s) if char == self._selected: painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, selected_tile) painter.setPen(selection_pen) painter.drawRect(col * s, row * s, s - 1, s - 1) elif printable: painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, tile) painter.setPen(text_pen if printable else disabled_pen) t = chr(char) x = col * s + s // 2 - metrics.width(t) // 2 y = row * s + 4 + metrics.ascent() painter.drawText(x, y, t) else: continue break def sizeForColumnCount(self, count): """Returns the size the widget would have in a certain column count. This can be used in e.g. a resizable scroll area. """ first, last = self._range rows = ((last - first) // count) + 1 return QSize(count, rows) * self._square def columnCountForWidth(self, width): """Returns the number of columns that would fit into the given width.""" return width // self._square def mousePressEvent(self, ev): charcode = self.charcodeAt(ev.pos()) if charcode != -1 and self.isprint(charcode): self.select(charcode) if ev.button() != Qt.RightButton: self.characterClicked.emit(chr(charcode)) def charcodeRect(self, charcode): """Returns the rectangular box around the given charcode, if any.""" if self._range[0] <= charcode <= self._range[1]: row, col = divmod(charcode - self._range[0], self._column_count) s = self._square return QRect(col * s, row * s, s, s) def charcodeAt(self, position): row = position.y() // self._square col = position.x() // self._square if col <= self._column_count: charcode = self._range[0] + row * self._column_count + col if charcode <= self._range[1]: return charcode return -1 def event(self, ev): if ev.type() == QEvent.ToolTip: if self._showToolTips: c = self.charcodeAt(ev.pos()) if c: text = self.getToolTipText(c) if text: rect = self.charcodeRect(c) QToolTip.showText(ev.globalPos(), text, self, rect) ev.accept() return True elif ev.type() == QEvent.QueryWhatsThis: if self._showWhatsThis: ev.accept() return True elif ev.type() == QEvent.WhatsThis: ev.accept() if self._showWhatsThis: c = self.charcodeAt(ev.pos()) text = self.getWhatsThisText(c) if c else None if text: QWhatsThis.showText(ev.globalPos(), text, self) else: QWhatsThis.leaveWhatsThisMode() return True return super(CharMap, self).event(ev) def getToolTipText(self, charcode): try: return unicodedata.name(chr(charcode)) except ValueError: pass def getWhatsThisText(self, charcode): try: name = unicodedata.name(chr(charcode)) except ValueError: return return whatsthis_html.format( self._font.family(), chr(charcode), name, charcode) def setShowToolTips(self, enabled): self._showToolTips = bool(enabled) def showToolTips(self): return self._showToolTips def setShowWhatsThis(self, enabled): self._showWhatsThis = bool(enabled) def showWhatsThis(self): return self._showWhatsThis def isprint(self, charcode): """Returns True if the given charcode is printable.""" return isprint(charcode)
class CharMap(QWidget): """A widget displaying a table of characters.""" characterSelected = pyqtSignal(str) characterClicked = pyqtSignal(str) def __init__(self, parent=None): super(CharMap, self).__init__(parent) self._showToolTips = True self._showWhatsThis = True self._selected = -1 self._column_count = 32 self._square = 24 self._range = (0, 0) self._font = QFont() def setRange(self, first, last): self._range = (first, last) self._selected = -1 self.adjustSize() self.update() def range(self): return self._range def square(self): """Returns the width of one item (determined by font size).""" return self._square def select(self, charcode): """Selects the specified character (int or str).""" if not isinstance(charcode, int): charcode = ord(charcode) if not self._range[0] <= charcode <= self._range[1]: charcode = -1 if self._selected != charcode: self._selected = charcode self.characterSelected.emit(chr(charcode)) self.update() def character(self): """Returns the currently selected character, if any.""" if self._selected != -1: return chr(self._selected) def setDisplayFont(self, font): self._font.setFamily(font.family()) self.update() def displayFont(self): return QFont(self._font) def setDisplayFontSize(self, size): self._font.setPointSize(size) self._square = max(24, QFontMetrics(self._font).xHeight() * 3) self.adjustSize() self.update() def displayFontSize(self): return self._font.pointSize() def setDisplayFontSizeF(self, size): self._font.setPointSizeF(size) self._square = max(24, QFontMetrics(self._font).xHeight() * 3) self.adjustSize() self.update() def displayFontSizeF(self): return self._font.pointSizeF() def setColumnCount(self, count): """Sets how many columns should be used.""" count = max(1, count) self._column_count = count self.adjustSize() self.update() def columnCount(self): return self._column_count def sizeHint(self): return self.sizeForColumnCount(self._column_count) def paintEvent(self, ev): rect = ev.rect() s = self._square rows = range(rect.top() // s, rect.bottom() // s + 1) cols = range(rect.left() // s, rect.right() // s + 1) painter = QPainter(self) painter.setPen(QPen(self.palette().color(QPalette.Window))) painter.setFont(self._font) metrics = QFontMetrics(self._font) # draw characters on white tiles tile = self.palette().color(QPalette.Base) selected_tile = self.palette().color(QPalette.Highlight) selected_tile.setAlpha(96) selected_box = self.palette().color(QPalette.Highlight) text_pen = QPen(self.palette().text()) disabled_pen = QPen(self.palette().color(QPalette.Disabled, QPalette.Text)) selection_pen = QPen(selected_box) for row in rows: for col in cols: char = row * self._column_count + col + self._range[0] if char > self._range[1]: break printable = self.isprint(char) painter.setClipRect(col * s, row * s, s, s) if char == self._selected: painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, selected_tile) painter.setPen(selection_pen) painter.drawRect(col * s, row * s, s - 1, s - 1) elif printable: painter.fillRect(col * s + 1, row * s + 1, s - 2, s - 2, tile) painter.setPen(text_pen if printable else disabled_pen) t = chr(char) x = col * s + s // 2 - metrics.width(t) // 2 y = row * s + 4 + metrics.ascent() painter.drawText(x, y, t) else: continue break def sizeForColumnCount(self, count): """Returns the size the widget would have in a certain column count. This can be used in e.g. a resizable scroll area. """ first, last = self._range rows = ((last - first) // count) + 1 return QSize(count, rows) * self._square def columnCountForWidth(self, width): """Returns the number of columns that would fit into the given width.""" return width // self._square def mousePressEvent(self, ev): charcode = self.charcodeAt(ev.pos()) if charcode != -1 and self.isprint(charcode): self.select(charcode) if ev.button() != Qt.RightButton: self.characterClicked.emit(chr(charcode)) def charcodeRect(self, charcode): """Returns the rectangular box around the given charcode, if any.""" if self._range[0] <= charcode <= self._range[1]: row, col = divmod(charcode - self._range[0], self._column_count) s = self._square return QRect(col * s, row * s, s, s) def charcodeAt(self, position): row = position.y() // self._square col = position.x() // self._square if col <= self._column_count: charcode = self._range[0] + row * self._column_count + col if charcode <= self._range[1]: return charcode return -1 def event(self, ev): if ev.type() == QEvent.ToolTip: if self._showToolTips: c = self.charcodeAt(ev.pos()) if c: text = self.getToolTipText(c) if text: rect = self.charcodeRect(c) QToolTip.showText(ev.globalPos(), text, self, rect) ev.accept() return True elif ev.type() == QEvent.QueryWhatsThis: if self._showWhatsThis: ev.accept() return True elif ev.type() == QEvent.WhatsThis: ev.accept() if self._showWhatsThis: c = self.charcodeAt(ev.pos()) text = self.getWhatsThisText(c) if c else None if text: QWhatsThis.showText(ev.globalPos(), text, self) else: QWhatsThis.leaveWhatsThisMode() return True return super(CharMap, self).event(ev) def getToolTipText(self, charcode): try: return unicodedata.name(chr(charcode)) except ValueError: pass def getWhatsThisText(self, charcode): try: name = unicodedata.name(chr(charcode)) except ValueError: return return whatsthis_html.format(self._font.family(), chr(charcode), name, charcode) def setShowToolTips(self, enabled): self._showToolTips = bool(enabled) def showToolTips(self): return self._showToolTips def setShowWhatsThis(self, enabled): self._showWhatsThis = bool(enabled) def showWhatsThis(self): return self._showWhatsThis def isprint(self, charcode): """Returns True if the given charcode is printable.""" return isprint(charcode)
def draw(self, painter, size = None): """ :Arguments: painter : QPainter Opened painter on which to draw """ bounding_rect = QRectF() position = self.position transfer_function = self.transfer_function font = QFont(self.font) text_color = self.text_color line_color = self.line_color line_thickness = self.line_thickness value_range = self.value_range if size is None: viewport = painter.viewport() # viewport rectangle mat, ok = painter.worldMatrix().inverted() if not ok: raise ValueError("Transformation matrix of painter is singular.") viewport = mat.mapRect(viewport) else: viewport = size # First, prepare the gradient w = viewport.width() h = viewport.height() #print("Size of viewport: {0}x{1}".format(w, h)) gr = QLinearGradient() nb_values = ceil(w/5.0) brush_color = QColor() for i in range(int(nb_values)): brush_color.setRgbF(*transfer_function.rgba(i/nb_values)) gr.setColorAt(i/nb_values, brush_color) # Second, find its position metric = QFontMetricsF(font, painter.device()) font_test = [ str(i)*5 for i in range(10) ] lim_width = 0 lim_height = 0 for t in font_test: rect = metric.boundingRect(t) lim_width = max(lim_width, rect.width()) lim_height = max(lim_height, rect.height()) lim_height *= 3 length = self.scale_length shift_length = (1-length)/2 width = self.scale_width shift_width = self.scale_shift_width delta_value = value_range[1]-value_range[0] if position == "Top": scale_rect = QRectF(shift_length*w, shift_width*h, length*w, width*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.bottomRight() elif position == "Right": scale_rect = QRectF((1-shift_width-width)*w, shift_length*h, width*w, length*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.topLeft() elif position == "Bottom": scale_rect = QRectF(shift_length*w, (1-shift_width-width)*h, length*w, width*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.topLeft() end_pos = scale_rect.topRight() elif position == "Left": scale_rect = QRectF(shift_width*w, shift_length*h, width*w, length*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomRight() end_pos = scale_rect.topRight() else: raise ValueError("Invalid scale position: %s" % position) shift_pos = (end_pos-start_pos)/delta_value if position in ["Left", "Right"]: is_vertical = True length = scale_rect.height() else: is_vertical = False length = scale_rect.width() # Get the ticks ticks = self.selectValues(length, is_vertical, painter) if len(ticks) == 0: return ticks_str, ticks_extra = self._tick2str(ticks) # Figure the shifts dist_to_bar = self.text_to_bar max_width = 0 max_height = 0 for t in ticks_str: rect = metric.boundingRect(t) max_width = max(rect.width(), max_width) max_height = max(rect.height(), max_height) if position == "Left": shift_left = dist_to_bar shift_top = None elif position == "Right": shift_left = -dist_to_bar-max_width shift_top = None elif position == "Top": shift_left = None shift_top = dist_to_bar else: shift_left = None shift_top = -dist_to_bar-max_height painter.save() painter.translate(viewport.topLeft()) #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top())) painter.setBrush(gr) line_pen = QPen(line_color) line_pen.setWidth(line_thickness) painter.setPen(line_pen) painter.drawRect(scale_rect) bounding_rect |= scale_rect #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(), #scale_rect.top(), scale_rect.width(), scale_rect.height())) painter.setFont(font) painter.setPen(text_color) for ts,t in zip(ticks_str, ticks): r = metric.boundingRect(ts) pos = start_pos+shift_pos*(t-value_range[0]) if shift_left is None: pos.setX( pos.x() - r.width()/2 ) else: pos.setX( pos.x() + shift_left ) if shift_top is None: pos.setY( pos.y() - r.height()/2) else: pos.setY( pos.y() + shift_top ) r.moveTo(pos) real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts) bounding_rect |= real_rect if ticks_extra is not None or self.unit: unit = self.unit exp_width = width = space_width = 0 exp_txt = "" r = exp_r = unit_r = QRectF() exp_font = None if ticks_extra is not None: exp_txt = u"×10" r = metric.boundingRect(exp_txt) exp_font = QFont(font) exp_size = self.exp_size if exp_font.pixelSize() != -1: exp_font.setPixelSize(exp_size*exp_font.pixelSize()) else: exp_font.setPointSizeF(exp_size*exp_font.pointSizeF()) exp_metric = QFontMetricsF(exp_font, painter.device()) exp_r = exp_metric.boundingRect(ticks_extra) if unit: unit_r = metric.boundingRect(unit) total_width = r.width()+exp_r.width()+unit_r.width() total_height = max(r.height(),unit_r.height())+exp_r.height()/2 pos = scale_rect.topRight() log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y())) log_debug("Size of image = (%d,%d)" % (w,h)) log_debug("Size of text = (%g,%g)" % (total_width, total_height)) if position == "Bottom": pos.setY(pos.y() + scale_rect.height() + dist_to_bar) pos.setX(pos.x() - total_width) elif position == "Top": pos.setY(pos.y() - dist_to_bar - total_height) pos.setX(pos.x() - total_width) else: # position == "left" or "right" pos.setX(pos.x() - (scale_rect.width() + total_width)/2) if pos.x() < 0: pos.setX(dist_to_bar) elif pos.x()+total_width+dist_to_bar > w: pos.setX(w - total_width - dist_to_bar) pos.setY(pos.y() - dist_to_bar - total_height) log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y())) if ticks_extra is not None: r.moveTo(pos) real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, exp_txt) bounding_rect |= real_rect pos.setX( pos.x() + r.width() ) pos.setY( pos.y() - metric.ascent()/2 ) exp_r.moveTo(pos) painter.setFont(exp_font) real_rect = painter.drawText(exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ticks_extra) bounding_rect |= real_rect pos.setY(pos.y() + metric.ascent()/2) if unit: pos.setX(pos.x() + space_width + exp_r.width()) unit_r.moveTo(pos) painter.setFont(font) real_rect = painter.drawText(unit_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit) bounding_rect |= real_rect # Draw the ticks now painter.setPen(line_pen) tick_size = self.tick_size if is_vertical: width = scale_rect.width()*tick_size else: width = scale_rect.height()*tick_size pen_width = painter.pen().widthF() if pen_width == 0: pen_width = 1.0 for t in ticks: pos1 = start_pos + shift_pos*(t-value_range[0]) pos2 = QPointF(pos1) if is_vertical: pos1.setX(scale_rect.left() + pen_width) pos2.setX(pos1.x() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setX(scale_rect.right() - pen_width) pos2.setX(pos1.x() - width + pen_width) painter.drawLine(pos1, pos2) else: pos1.setY(scale_rect.top() + pen_width) pos2.setY(pos1.y() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setY(scale_rect.bottom() - pen_width) pos2.setY(pos1.y() - width + pen_width) painter.drawLine(pos1, pos2) painter.restore() bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width, pen_width, pen_width) return bounding_rect
class TextFormatData(object): """Encapsulates all settings in the Fonts & Colors page for a scheme.""" def __init__(self, scheme): """Loads the data from scheme.""" self.font = None self.baseColors = {} self.defaultStyles = {} self.allStyles = {} self.load(scheme) def load(self, scheme): s = QSettings() s.beginGroup("fontscolors/" + scheme) # load font self.font = QFont(s.value("fontfamily", "monospace")) self.font.setPointSizeF(float(s.value("fontsize", 10.0))) # load base colors s.beginGroup("basecolors") for name in baseColors: if s.contains(name): self.baseColors[name] = QColor(s.value(name)) else: self.baseColors[name] = baseColorDefaults[name]() s.endGroup() # load default styles s.beginGroup("defaultstyles") for name in defaultStyles: self.defaultStyles[name] = f = QTextCharFormat(defaultStyleDefaults[name]) s.beginGroup(name) loadTextFormat(f, s) s.endGroup() s.endGroup() # load specific styles s.beginGroup("allstyles") for group, styles in allStyles: self.allStyles[group]= {} s.beginGroup(group) for name in styles: default = allStyleDefaults[group].get(name) self.allStyles[group][name] = f = QTextCharFormat(default) if default else QTextCharFormat() s.beginGroup(name) loadTextFormat(f, s) s.endGroup() s.endGroup() s.endGroup() def save(self, scheme): s = QSettings() s.beginGroup("fontscolors/" + scheme) # save font s.setValue("fontfamily", self.font.family()) s.setValue("fontsize", self.font.pointSizeF()) # save base colors for name in baseColors: s.setValue("basecolors/"+name, self.baseColors[name].name()) # save default styles s.beginGroup("defaultstyles") for name in defaultStyles: s.beginGroup(name) saveTextFormat(self.defaultStyles[name], s) s.endGroup() s.endGroup() # save all specific styles s.beginGroup("allstyles") for group, styles in allStyles: s.beginGroup(group) for name in styles: s.beginGroup(name) saveTextFormat(self.allStyles[group][name], s) s.endGroup() s.endGroup() s.endGroup() def textFormat(self, group, name): inherit = inherits[group].get(name) f = QTextCharFormat(self.defaultStyles[inherit]) if inherit else QTextCharFormat() f.merge(self.allStyles[group][name]) return f def palette(self): """Returns a basic palette with text, background, selection and selection background filled in.""" p = QApplication.palette() p.setColor(QPalette.Text, self.baseColors['text']) p.setColor(QPalette.Base, self.baseColors['background']) p.setColor(QPalette.HighlightedText, self.baseColors['selectiontext']) p.setColor(QPalette.Highlight, self.baseColors['selectionbackground']) return p
def draw(self, painter, size=None): """ :Arguments: painter : QPainter Opened painter on which to draw """ bounding_rect = QRectF() position = self.position transfer_function = self.transfer_function font = QFont(self.font) text_color = self.text_color line_color = self.line_color line_thickness = self.line_thickness value_range = self.value_range if size is None: viewport = painter.viewport() # viewport rectangle mat, ok = painter.worldMatrix().inverted() if not ok: raise ValueError( "Transformation matrix of painter is singular.") viewport = mat.mapRect(viewport) else: viewport = size # First, prepare the gradient w = viewport.width() h = viewport.height() #print("Size of viewport: {0}x{1}".format(w, h)) gr = QLinearGradient() nb_values = ceil(w / 5.0) brush_color = QColor() for i in range(int(nb_values)): brush_color.setRgbF(*transfer_function.rgba(i / nb_values)) gr.setColorAt(i / nb_values, brush_color) # Second, find its position metric = QFontMetricsF(font, painter.device()) font_test = [str(i) * 5 for i in range(10)] lim_width = 0 lim_height = 0 for t in font_test: rect = metric.boundingRect(t) lim_width = max(lim_width, rect.width()) lim_height = max(lim_height, rect.height()) lim_height *= 3 length = self.scale_length shift_length = (1 - length) / 2 width = self.scale_width shift_width = self.scale_shift_width delta_value = value_range[1] - value_range[0] if position == "Top": scale_rect = QRectF(shift_length * w, shift_width * h, length * w, width * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.bottomRight() elif position == "Right": scale_rect = QRectF((1 - shift_width - width) * w, shift_length * h, width * w, length * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.topLeft() elif position == "Bottom": scale_rect = QRectF(shift_length * w, (1 - shift_width - width) * h, length * w, width * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.topLeft() end_pos = scale_rect.topRight() elif position == "Left": scale_rect = QRectF(shift_width * w, shift_length * h, width * w, length * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomRight() end_pos = scale_rect.topRight() else: raise ValueError("Invalid scale position: %s" % position) shift_pos = (end_pos - start_pos) / delta_value if position in ["Left", "Right"]: is_vertical = True length = scale_rect.height() else: is_vertical = False length = scale_rect.width() # Get the ticks ticks = self.selectValues(length, is_vertical, painter) if len(ticks) == 0: return ticks_str, ticks_extra = self._tick2str(ticks) # Figure the shifts dist_to_bar = self.text_to_bar max_width = 0 max_height = 0 for t in ticks_str: rect = metric.boundingRect(t) max_width = max(rect.width(), max_width) max_height = max(rect.height(), max_height) if position == "Left": shift_left = dist_to_bar shift_top = None elif position == "Right": shift_left = -dist_to_bar - max_width shift_top = None elif position == "Top": shift_left = None shift_top = dist_to_bar else: shift_left = None shift_top = -dist_to_bar - max_height painter.save() painter.translate(viewport.topLeft()) #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top())) painter.setBrush(gr) line_pen = QPen(line_color) line_pen.setWidth(line_thickness) painter.setPen(line_pen) painter.drawRect(scale_rect) bounding_rect |= scale_rect #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(), #scale_rect.top(), scale_rect.width(), scale_rect.height())) painter.setFont(font) painter.setPen(text_color) for ts, t in zip(ticks_str, ticks): r = metric.boundingRect(ts) pos = start_pos + shift_pos * (t - value_range[0]) if shift_left is None: pos.setX(pos.x() - r.width() / 2) else: pos.setX(pos.x() + shift_left) if shift_top is None: pos.setY(pos.y() - r.height() / 2) else: pos.setY(pos.y() + shift_top) r.moveTo(pos) real_rect = painter.drawText( r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts) bounding_rect |= real_rect if ticks_extra is not None or self.unit: unit = self.unit exp_width = width = space_width = 0 exp_txt = "" r = exp_r = unit_r = QRectF() exp_font = None if ticks_extra is not None: exp_txt = u"×10" r = metric.boundingRect(exp_txt) exp_font = QFont(font) exp_size = self.exp_size if exp_font.pixelSize() != -1: exp_font.setPixelSize(exp_size * exp_font.pixelSize()) else: exp_font.setPointSizeF(exp_size * exp_font.pointSizeF()) exp_metric = QFontMetricsF(exp_font, painter.device()) exp_r = exp_metric.boundingRect(ticks_extra) if unit: unit_r = metric.boundingRect(unit) total_width = r.width() + exp_r.width() + unit_r.width() total_height = max(r.height(), unit_r.height()) + exp_r.height() / 2 pos = scale_rect.topRight() log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y())) log_debug("Size of image = (%d,%d)" % (w, h)) log_debug("Size of text = (%g,%g)" % (total_width, total_height)) if position == "Bottom": pos.setY(pos.y() + scale_rect.height() + dist_to_bar) pos.setX(pos.x() - total_width) elif position == "Top": pos.setY(pos.y() - dist_to_bar - total_height) pos.setX(pos.x() - total_width) else: # position == "left" or "right" pos.setX(pos.x() - (scale_rect.width() + total_width) / 2) if pos.x() < 0: pos.setX(dist_to_bar) elif pos.x() + total_width + dist_to_bar > w: pos.setX(w - total_width - dist_to_bar) pos.setY(pos.y() - dist_to_bar - total_height) log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y())) if ticks_extra is not None: r.moveTo(pos) real_rect = painter.drawText( r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, exp_txt) bounding_rect |= real_rect pos.setX(pos.x() + r.width()) pos.setY(pos.y() - metric.ascent() / 2) exp_r.moveTo(pos) painter.setFont(exp_font) real_rect = painter.drawText( exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ticks_extra) bounding_rect |= real_rect pos.setY(pos.y() + metric.ascent() / 2) if unit: pos.setX(pos.x() + space_width + exp_r.width()) unit_r.moveTo(pos) painter.setFont(font) real_rect = painter.drawText( unit_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit) bounding_rect |= real_rect # Draw the ticks now painter.setPen(line_pen) tick_size = self.tick_size if is_vertical: width = scale_rect.width() * tick_size else: width = scale_rect.height() * tick_size pen_width = painter.pen().widthF() if pen_width == 0: pen_width = 1.0 for t in ticks: pos1 = start_pos + shift_pos * (t - value_range[0]) pos2 = QPointF(pos1) if is_vertical: pos1.setX(scale_rect.left() + pen_width) pos2.setX(pos1.x() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setX(scale_rect.right() - pen_width) pos2.setX(pos1.x() - width + pen_width) painter.drawLine(pos1, pos2) else: pos1.setY(scale_rect.top() + pen_width) pos2.setY(pos1.y() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setY(scale_rect.bottom() - pen_width) pos2.setY(pos1.y() - width + pen_width) painter.drawLine(pos1, pos2) painter.restore() bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width, pen_width, pen_width) return bounding_rect
class LayerWidgetDelegate(QStyledItemDelegate): """ set for a specific column, controls the rendering and editing of items in that column or row of a list or table see QAbstractItemView.setItemDelegateForRow/Column """ _doc: Document = None # document we're representing # _doc: DocumentAsLayerStack = None # document we're representing def layer_prez(self, index: int): cll = self._doc.current_layer_set return cll[index] if index < len(cll) and index >= 0 else None def __init__(self, doc: Document, *args, **kwargs): super(LayerWidgetDelegate, self).__init__(*args, **kwargs) self._doc = doc # self._doc = doc.as_layer_stack fsize = get_font_size(7) self.font = QFont('Andale Mono') self.font.setPointSizeF(fsize) def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex): pz = self.layer_prez(index.row()) # if pz.kind == KIND.RGB: # LOG.debug('triple-sizing composite layer') # return QSize(CELL_WIDTH, CELL_HEIGHT*3) # else: return QSize(CELL_WIDTH, CELL_HEIGHT) def displayText(self, *args, **kwargs): return None def paint(self, painter, option, index): """draw the individual lines in the layers control """ painter.save() color = QColor(187, 213, 255, 255) if index.row() % 2 == 0 else QColor( 177, 223, 255, 255) # color = QColor(187, 213, 255, 255) painter.setPen(QPen(color)) painter.setFont(self.font) value = index.data(Qt.UserRole) text = index.data(Qt.DisplayRole) rect = option.rect # if we have a value, break out the animation order and other info animation_order = None if value: value, animation_order = value # if we have a point probe value, draw the filled bar to represent where it is in that layer's data range if value: value, bar, fmtd_str = value w = bar * float(rect.width()) r = QRect(rect.left(), rect.top(), int(w), rect.height()) painter.fillRect(r, color) super(LayerWidgetDelegate, self).paint(painter, option, index) # if this layer is selected, draw a colored rectangle to highlight it if option.state & QStyle.State_Selected and value: painter.fillRect(r, QColor(213, 187, 255, 96)) # draw the name of the layer painter.setPen(QPen(Qt.black)) painter.setFont(self.font) bounds = painter.drawText( rect.left() + LEFT_OFFSET, rect.top() + TOP_OFFSET, rect.width() - LEFT_OFFSET, CELL_HEIGHT / 2 - TOP_OFFSET, Qt.AlignLeft, text, ) # also draw the animation order if animation_order is not None: painter.setPen(QPen(Qt.white)) ao_rect = QRect( bounds.right(), rect.top() + TOP_OFFSET, rect.width() - bounds.right(), CELL_HEIGHT / 2 - TOP_OFFSET, ) # draw the text once to get the bounding rectangle bounds = painter.drawText( ao_rect, Qt.AlignRight, str(animation_order + 1), ) painter.fillRect(bounds, Qt.black) # draw the text a second time to make sure it appears in the rectangle painter.drawText( ao_rect, Qt.AlignRight, str(animation_order + 1), ) # if we have a point probe value, draw text with it's value if value: painter.setPen(Qt.darkBlue) theight = CELL_HEIGHT / 2 t = rect.top() + rect.height() - theight if w < rect.width( ) / 3: # place the text to the right of the bar instead of inside l = max(int(w), LEFT_OFFSET) r = rect.width() align = Qt.AlignLeft else: l = 0 r = w align = Qt.AlignRight painter.drawText(l, t, r - l, theight, align, fmtd_str) painter.restore()