class CompassWidget(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) self.compass = QSvgRenderer("compassBody.svg") self.needle = QSvgRenderer("compassNeedle.svg") self.angle = 0 def paintEvent(self, event): painter = QPainter(self) margin = 10 length = min(self.width(), self.height()) - 2 * margin xpos = (self.width() - length) / 2 ypos = (self.height() - length) / 2 bounds = QRectF(xpos, ypos, length, length) #painter.setBrush(Qt.NoBrush) #painter.drawRect(bounds) self.compass.render(painter, bounds) painter.translate(self.width() / 2, self.height() / 2) painter.rotate(self.angle) painter.translate(-self.width() / 2, -self.height() / 2) #painter.translate(xrad/2, yrad/2) self.needle.render(painter, bounds) def setDirection(self, angle): self.angle = angle self.repaint()
class BasicSvgPage(page.AbstractPage): """A page that can display a SVG document.""" paperColor = QColor(Qt.white) def __init__(self, load_file=None): self._svg_r = QSvgRenderer() if load_file: self.load(load_file) def load(self, load_file): """Load filename or QByteArray.""" success = self._svg_r.load(load_file) if success: self.pageWidth = self._svg_r.defaultSize().width() self.pageHeight = self._svg_r.defaultSize().height() return success def paint(self, painter, rect, callback=None): painter.fillRect(rect, self.paperColor) page = QRect(0, 0, self.width, self.height) painter.translate(page.center()) painter.rotate(self.computedRotation * 90) if self.computedRotation & 1: page.setSize(page.size().transposed()) painter.translate(-page.center()) self._svg_r.render(painter, QRectF(page))
def generate_qr_code(text): qr = qrcode.QRCode(version=None, error_correction=qrcode.constants.ERROR_CORRECT_H, border=4, box_size=10) qr.add_data(text) qr.make(fit=True) qr_img = qr.make_image(image_factory=qrcode.image.svg.SvgPathImage) stream = io.BytesIO() qr_img.save(stream) renderer = QSvgRenderer() renderer.load(stream.getvalue()) final_img = QImage(600, 600, QImage.Format_ARGB32) final_img.fill(QColor(0xF4, 0xF4, 0xF4)) painter = QPainter() painter.begin(final_img) painter.setCompositionMode(QPainter.CompositionMode_SourceOver) renderer.render( painter, QRectF(0, 0, final_img.rect().width(), final_img.rect().height())) painter.end() pix = QPixmap.fromImage(final_img) return pix
class CompassWidget(QWidget): def __init__(self, parent): QWidget.__init__(self, parent) self.compass = QSvgRenderer("compassBody.svg") self.needle = QSvgRenderer("compassNeedle.svg") self.angle = 0 def paintEvent(self, event): painter = QPainter(self) margin = 10 length = min(self.width(), self.height()) - 2*margin xpos = (self.width() - length)/2 ypos = (self.height() - length)/2 bounds = QRectF( xpos, ypos, length, length) #painter.setBrush(Qt.NoBrush) #painter.drawRect(bounds) self.compass.render(painter, bounds) painter.translate(self.width() / 2, self.height() / 2) painter.rotate(self.angle) painter.translate(-self.width() / 2, -self.height() / 2) #painter.translate(xrad/2, yrad/2) self.needle.render(painter, bounds) def setDirection(self, angle): self.angle = angle self.repaint()
class ShadowWidget(QWidget): def __init__(self, parentWidget): QWidget.__init__(self, parentWidget) self.texture = QImage("ui/gras.png") self.tree = QSvgRenderer("ui/tree.svg") self.compass = QSvgRenderer("ui/compass2.svg") # set the gras texture as the background image self.setAutoFillBackground(True) pal = self.palette() pal.setBrush(QPalette.Window, QBrush(self.texture)) self.setPalette(pal) self.angle = 0 self.shadowLength = 10 def setAngle(self, value): self.angle = value self.repaint() def setShadowLength(self, value): if (value < 0): value = 0 self.shadowLength = value self.repaint() def paintEvent(self, event): radius = 50 treeSize = QSizeF(2 * radius, 2 * radius) bounds = QRectF( (self.width() - treeSize.height()) / 2, (self.height() - treeSize.width()) / 2, treeSize.width(), treeSize.height()) painter = QPainter(self) # draw the shadow painter.setBrush(Qt.black) painter.setPen(Qt.NoPen) painter.setOpacity(0.5) xrad = 95 yrad = self.shadowLength * 20 rect = QRectF(-xrad, -yrad, xrad, yrad) painter.translate(self.width() / 2, self.height() / 2) painter.rotate(self.angle) painter.translate(xrad/2, yrad/2) painter.drawChord(rect, 0, 180*16) painter.resetTransform() # draw the tree painter.setOpacity(1) self.tree.render(painter, bounds) # draw the compass bounds = QRectF( 10, 10, 50, 50) self.compass.render(painter, bounds)
def load_svg_sized_pixmap(path, w=100, h=100): svg_renderer = QSvgRenderer(path) image = QImage(w, h, QImage.Format_ARGB32) painter = QPainter(image) painter.eraseRect(0, 0, w, h) svg_renderer.render(painter) painter.end() return QPixmap.fromImage(image)
def from_svg_bytes(self, svg_bytes): """Paints an svg from a bytes object""" renderer = QSvgRenderer(svg_bytes) painter = QPainter(self) painter.eraseRect(self.rect()) renderer.render(painter) painter.end()
class ShadowWidget(QWidget): def __init__(self, parentWidget): QWidget.__init__(self, parentWidget) self.texture = QImage("ui/gras.png") self.tree = QSvgRenderer("ui/tree.svg") self.compass = QSvgRenderer("ui/compass2.svg") # set the gras texture as the background image self.setAutoFillBackground(True) pal = self.palette() pal.setBrush(QPalette.Window, QBrush(self.texture)) self.setPalette(pal) self.angle = 0 self.shadowLength = 10 def setAngle(self, value): self.angle = value self.repaint() def setShadowLength(self, value): if (value < 0): value = 0 self.shadowLength = value self.repaint() def paintEvent(self, event): radius = 50 treeSize = QSizeF(2 * radius, 2 * radius) bounds = QRectF((self.width() - treeSize.height()) / 2, (self.height() - treeSize.width()) / 2, treeSize.width(), treeSize.height()) painter = QPainter(self) # draw the shadow painter.setBrush(Qt.black) painter.setPen(Qt.NoPen) painter.setOpacity(0.5) xrad = 95 yrad = self.shadowLength * 20 rect = QRectF(-xrad, -yrad, xrad, yrad) painter.translate(self.width() / 2, self.height() / 2) painter.rotate(self.angle) painter.translate(xrad / 2, yrad / 2) painter.drawChord(rect, 0, 180 * 16) painter.resetTransform() # draw the tree painter.setOpacity(1) self.tree.render(painter, bounds) # draw the compass bounds = QRectF(10, 10, 50, 50) self.compass.render(painter, bounds)
class NorthArrow(QgsMapCanvasItem): def __init__(self, proj, canvas): super(NorthArrow, self).__init__(canvas) self.proj = proj self.canvas = canvas self.map_pos = QgsPointXY(0.0, 0.0) self.svg = QSvgRenderer(":/resources/arrow.svg") self.size = QSize(42, 64) self.corner = 1 def paint(self, painter, xxx, xxx2): """Paint north arrow on painter""" if self.svg.isValid(): pos = self.set_position(self.corner, painter.device().width(), painter.device().height()) rotation = QgsBearingUtils.bearingTrueNorth( self.canvas.mapSettings().destinationCrs(), self.canvas.mapSettings().transformContext(), self.canvas.extent().center()) rotation += self.canvas.rotation() painter.save() painter.rotate(-rotation) # To translate correctly painter.translate(pos.x(), pos.y()) painter.rotate( rotation ) # To rotate north arrow along with canvas, always pointing north # do the drawing, and draw a smooth north arrow even when rotated rectangle = QRectF(-self.size.width() / 2, -self.size.height() / 2, self.size.width(), self.size.height()) self.svg.render(painter, rectangle) painter.restore() def set_position(self, corner, width, height): """ Returns the position of the specified corner with a concrete width and height :param corner: can be 1, 2, 3 or 4. top left, top right, bot left and bot right respectively :param width: width of the paint space :param height: height of the paint space :return: QgsPointXY of the specified corner """ if corner == 1: # top left corner return QgsPointXY(0 + self.size.height() / 2, 0 + self.size.height() / 2) elif corner == 2: # top right corner return QgsPointXY(width - self.size.height() / 2, 0 + self.size.height() / 2) elif corner == 3: # bottom left corner return QgsPointXY(0 + self.size.height() / 2, height - self.size.height() / 2) elif corner == 4: # bottom right corner return QgsPointXY(width - self.size.height() / 2, height - self.size.height() / 2)
class SVGEngine: """ Renders SVG data on Qt paint devices. """ def __init__(self, *, render_hints=QPainter.Antialiasing) -> None: self._data = b"" # Current XML SVG binary data. self._renderer = QSvgRenderer() # Qt SVG renderer. self._render_hints = render_hints # SVG rendering quality hints (such as anti-aliasing). def loads(self, data: QtSVGData) -> None: """ Load the renderer with SVG data. """ if isinstance(data, str): data = data.encode('utf-8') self._data = data self._renderer.load(data) def load(self, filename: str) -> None: """ Load SVG data directly from disk. """ with open(filename) as fp: data = fp.read() self.loads(data) def viewbox_size(self) -> QSize: """ If no valid viewbox is defined, 100x100 is a typical default. """ size = self._renderer.viewBox().size() if size.isEmpty(): size = QSize(100, 100) return size def render(self, target: QPaintDevice, bounds: QRectF = None) -> None: """ Render the current SVG data on <target> with optional <bounds> on the area. """ args = () if bounds is None else (bounds, ) with QPainter(target) as p: p.setRenderHints(self._render_hints) self._renderer.render(p, *args) def render_fit(self, target: QPaintDevice) -> None: """ Render the current SVG data on <target>, centered at maximum scale while preserving aspect ratio. """ width = target.width() height = target.height() v_size = self.viewbox_size() vw = v_size.width() vh = v_size.height() scale = min(width / vw, height / vh) rw = vw * scale rh = vh * scale rx = (width - rw) / 2 ry = (height - rh) / 2 bounds = QRectF(rx, ry, rw, rh) self.render(target, bounds) def dumps(self) -> str: """ Return the current SVG data as a string. """ return self._data.decode('utf-8') def dump(self, filename: str) -> None: """ Save the current SVG data directly to disk. """ with open(filename, 'wb') as fp: fp.write(self._data)
def _render(self, data: XMLIconData) -> QIcon: """ Create a template image, render the XML data in place, and convert it to an icon. Use the viewbox dimensions as pixel sizes. """ svg = QSvgRenderer(data) viewbox = svg.viewBox().size() im = QImage(viewbox, QImage.Format_ARGB32) im.fill(self._bg_color) with QPainter(im) as p: p.setRenderHints(self._render_hints) svg.render(p) return QIcon(QPixmap.fromImage(im))
def update_board(self) -> None: self._image.fill(0) painter = QPainter() painter.begin(self._image) renderer = QSvgRenderer() renderer.load(self._game_view._repr_svg_().encode("utf-8")) renderer.render(painter) painter.end() self._label.setPixmap(QPixmap.fromImage(self._image)) self.setMinimumSize( QSize(self._image.width() + 10, self._image.height() + 10))
def foo(percent=0, size=32): """Returns QIcon""" svgstr = svgFactory(svgExamples[0], percent, size) svg_bytes = bytearray(svgstr, encoding="utf-8") r = QSvgRenderer(svg_bytes) i = QImage(32, 32, QImage.Format_ARGB32) i.fill(0xffffffff) p = QPainter(i) r.render(p) a = QPixmap.fromImage(i) p.end() return a
def svg_to_png(svg_path, png_path): """ inspired by https://stackoverflow.com/questions/8551690/how-to-render-a-scaled-svg-to-a-qimage """ renderer = QSvgRenderer(svg_path) print(renderer) print(renderer.viewBoxF()) print(renderer.defaultSize()) image = QImage(width, height, QImage.Format_ARGB32) painter = QPainter(image) renderer.render(painter) image.save(png_path) painter.end()
def updateUiSvg(self,color_list): svgXmlStreamReader = QXmlStreamReader('<svg xmlns=\"http://www.w3.org/2000/svg\" version=\"1.1\">\n' + self.svgBoxArraySrc(10,10,40,5,24,4,color_list) + '</svg>\n') svgRender = QSvgRenderer() svgRender.load(svgXmlStreamReader) svgPixmap = QPixmap(480,80) svgPixmap.fill(QtCore.Qt.transparent) svgPainter = QPainter(svgPixmap) svgRender.render(svgPainter) self.ui.label_8.setPixmap(svgPixmap) self.ui.label_8.setAlignment(QtCore.Qt.AlignCenter) svgPainter.end()
class SVGButton(QGraphicsObject): def __init__(self, fname, parent=None): super(SVGButton, self).__init__(parent) self.svg = QSvgRenderer(fname) def paint(self, painter, options, widget): self.svg.render(painter, self.boundingRect()) def boundingRect(self): return self.svg.viewBoxF() clicked = pyqtSignal() def mousePressEvent(self, event): self.clicked.emit()
def load_icon(name: AutoKeyIcon) -> QIcon: file_path = ICON_PATH_PREFIX + "/" + name.value icon = QIcon(file_path) if not icon.availableSizes() and file_path.endswith(".svg"): # FIXME: Work around Qt Bug: https://bugreports.qt.io/browse/QTBUG-63187 # Manually render the SVG to some common icon sizes. icon = QIcon() # Discard the bugged QIcon renderer = QSvgRenderer(file_path) for size in (16, 22, 24, 32, 64, 128): pixmap = QPixmap(QSize(size, size)) pixmap.fill(QColor(255, 255, 255, 0)) renderer.render(QPainter(pixmap)) icon.addPixmap(pixmap) return icon
def _render(self, svg_data: str) -> QImage: """ Create a new raster image with the current background color and render an SVG image to it. Pixel dimensions will fit the viewbox at maximum scale. """ svg = QSvgRenderer(svg_data.encode("utf-8")) v_size = svg.viewBox().size() vw = v_size.width() vh = v_size.height() scale = min(self._w_max / vw, self._h_max / vh) w = round(vw * scale) h = round(vh * scale) im = QImage(w, h, QImage.Format_ARGB32) im.fill(self._bg_color) with QPainter(im) as p: p.setRenderHints(QPainter.Antialiasing) svg.render(p, QRectF(0, 0, w, h)) return im
def getIcon(self, icon_name, base_color, hover_color): root = QFileInfo(__file__).absolutePath() svg_files = os.listdir(root + "/../../styles/assets/icons/svg/") filename = "appbar." + icon_name + ".svg" if filename in svg_files: f = QFile(root + '/../../styles/assets/icons/svg/' + filename) if f.open(QFile.ReadOnly | QFile.Text): textStream = QTextStream(f) svgData = textStream.readAll().replace( 'fill="#000000"', 'fill="{}"'.format(base_color)) svgData_hover = svgData.replace( 'fill="{}"'.format(base_color), 'fill="{}"'.format(hover_color)) f.close() svg = QSvgRenderer(QByteArray().append(svgData)) svg_hover = QSvgRenderer(QByteArray().append(svgData_hover)) qim = QImage(76, 76, QImage.Format_RGBA8888) qim.fill(0) painter = QPainter() painter.begin(qim) svg.render(painter) painter.end() qim_hover = QImage(76, 76, QImage.Format_ARGB32) qim_hover.fill(0) painter = QPainter() painter.begin(qim_hover) svg_hover.render(painter) painter.end() self.icon = QIcon(QPixmap.fromImage(qim)) self.hovericon = QIcon(QPixmap.fromImage(qim_hover)) self.setIcon(self.icon) else: qim = QImage(76, 76, QImage.Format_RGBA8888) qim.fill(0) self.icon = QPixmap.fromImage(qim) self.hovericon = QPixmap.fromImage(qim) self.setIcon(self.icon)
def __getitem__(key): if key not in IconCache.icons: if not key.endswith('.svg') and not key.endswith('.svgz'): image = QImage(key).scaled(24, 24) else: svg = QSvgRenderer(key) image = QImage(24, 24, QImage.Format_ARGB32) image.fill(0) painter = QPainter(image) svg.render(painter) painter.end() bytes = QByteArray() buff = QBuffer(bytes) buff.open(QIODevice.WriteOnly) image.save(buff, 'png') IconCache.icons[key] = bytes return QIcon(QPixmap.fromImage(QImage.fromData(IconCache.icons[key])))
def svg2png(fName, width=600, app=None, oFilename=""): """ Smart convertion to PNG files; stroke widths are widened when necessary, so traces on an oscilloscope screen will be visible even if it is downscaled. A PNG file is written. :param fname: file name of a SVG drawing :param width: the width of the wanted PNG drawing; its height will be :param app: the current application :param oFilename: facultative file name for the output PNG file calculated automatically :returns: the effective file name of the written PNG file """ from xml.dom import minidom from PyQt5.QtSvg import QSvgRenderer from PyQt5.QtGui import QImage, QPainter, QColor, QGuiApplication from math import sqrt if not app: app = QGuiApplication([]) doc = minidom.parse(open(fName)) svg = doc.getElementsByTagName("svg")[0] sizeMatch = re.match(r"(\d+) (\d+) (\d+) (\d+)", svg.getAttribute("viewBox")) w, h = int(sizeMatch.group(3)), int(sizeMatch.group(3)) groups = svg.getElementsByTagName("g") scale = width / w for g in groups: if "stroke-width" in g.attributes: g.setAttribute( "stroke-width", str(float(g.getAttribute("stroke-width")) / sqrt(scale))) qsr = QSvgRenderer(svg.toxml().encode("utf-8")) # I do not know why, but without the correction, the height of the # PNG image is too big. Are the viewport units misleading? correction = 1.33 img = QImage(int(w * scale), int(h * scale / correction), QImage.Format_ARGB32) img.fill(QColor("white")) p = QPainter(img) qsr.render(p) p.end() if not oFilename: oFilename = re.sub(r"\.svg$", f"-{width}px.png", fName) img.save(oFilename) return oFilename
def SvgToPixmap(svg_data: Union[str, bytes], size: QSize): if size.isNull(): return QPixmap() svg_renderer = QSvgRenderer() if isinstance(svg_data, bytes): svg_renderer.load(svg_data) else: svg_renderer.load(svg_data.encode('utf-8')) pixmap = QPixmap(size) painter = QPainter() pixmap.fill(Qt.transparent) painter.begin(pixmap) svg_renderer.render(painter) painter.end() return pixmap
def load_icon(name: str) -> QIcon: """ Load a QIcon with the given file name. Files are loaded from the ICON_PATH_PREFIX, which depends on the installation style. """ file_path = ICON_PATH_PREFIX + "/" + name icon = QIcon(file_path) if not icon.availableSizes() and file_path.endswith(".svg"): # FIXME: Work around Qt Bug: https://bugreports.qt.io/browse/QTBUG-63187 # Manually render the SVG to some common icon sizes. icon = QIcon() # Discard the bugged QIcon renderer = QSvgRenderer(file_path) for size in (16, 22, 24, 32, 64, 128): pixmap = QPixmap(QSize(size, size)) pixmap.fill(QColor(255, 255, 255, 0)) renderer.render(QPainter(pixmap)) icon.addPixmap(pixmap) return icon
class NetArchitecture(QObject): def __init__(self, parent=None): # TODO should know its name super(NetArchitecture, self).__init__() self.renderer = QSvgRenderer() self.source_url = QUrl("") self.settings = QSettings('dt', 'DeepThought') self.graph = None self.update_source() def source_setting_changed(self): return not self.settings.value('protofile') == self.source_url def update_source(self): if self.settings.contains('protofile'): source_url = QUrl(self.settings.value('protofile')) source = source_url.toDisplayString(QUrl.RemoveScheme) if os.path.isfile(source): self.source_url = source_url self.set_source(source) return not self.source_url.isEmpty() def set_source(self, caffeproto_file): net = caffe_pb2.NetParameter() text_format.Merge(open(caffeproto_file).read(), net) self.graph = caffe.draw.draw_net(net, 'LR', 'svg') # self.sourceChanged.emit('network_architecture') def get_image(self, size): if self.source_setting_changed(): self.update_source() image = QImage(size.width(), size.height(), QImage.Format_ARGB32) painter = QPainter(image) if self.graph is None: if self.settings.contains('protofile'): url = QUrl(self.settings.value('protofile')) self.set_source(url.toDisplayString(QUrl.RemoveScheme)) else: image.fill(QColor(200, 200, 200)) return image self.renderer.load(QByteArray(self.graph)) self.renderer.render(painter) return image
def __init__(self, xy, parent=None, extra=None): super().__init__(xy, parent, extra) self.setwh((1, 1)) self.color = extra[0] if self.color == '': self.color = '(0, 180, 0)' self.setcolort(self.color) ico = extra[1] icon = None if ico.split('.')[-1] == 'svg' or ico.split('.')[-1] == 'svgz': icon = QImage(int(self.w * UNIT / 2), int(self.h * UNIT / 2), QImage.Format_ARGB32) icon.fill(QColor(120, 120, 120, 0)) renderer = QSvgRenderer(ico) painter = QPainter(icon) renderer.render(painter) del painter else: icon = QImage(ico) self.setPixmap(QPixmap(icon).scaledToHeight(self.height(), Qt.SmoothTransformation))
def paint( self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex ): value = index.data().thumbnail renderer = QSvgRenderer() renderer.load(value) bounds = QRectF( float(option.rect.x()), float(option.rect.y()), float(option.rect.width()), float(option.rect.height()) ) renderer.render(painter, bounds)
def _draw_plate(self, background_path, font_path, target_template, symbols): if background_path.suffix == '.svg': renderer = QSvgRenderer(str(background_path)) assert renderer.isValid() width = target_template['width'] w, h = renderer.viewBox().width(), renderer.viewBox().height() aspect_ratio = w / h w, h = width, width / aspect_ratio image = QImage(w, h, QImage.Format_ARGB32) image.fill(Qt.transparent) # workaround for clean image painter = QPainter(image) painter.setRenderHint(QPainter.Antialiasing, True) painter.setRenderHint(QPainter.TextAntialiasing, True) painter.setRenderHint(QPainter.SmoothPixmapTransform, True) renderer.render(painter) else: image = QPixmap(str(background_path)) assert not image.isNull() width = target_template['width'] w, h = image.width(), image.height() aspect_ratio = w / h w, h = width, width / aspect_ratio image.scaled(w, h, Qt.KeepAspectRatio) image = image.toImage() painter = QPainter(image) font = get_font(font_path) pen = QPen(QColor.fromRgb(int(target_template['font_color'], base=16)), 2, Qt.SolidLine) painter.setPen(pen) for _, sym in symbols.items(): rect = QRect(sym.x, sym.y, sym.w, sym.h) font.setPointSizeF(sym.font_size) painter.setFont(font) painter.drawText(rect, Qt.AlignCenter, sym.sym) painter.end() return qimage_to_nparr(image)
def __init__(self, xy, parent=None, extra=None): super().__init__(xy, parent, extra) if len(self.extra) == 4: self.d, self.exe, self.ico, self.name = self.extra elif len(self.extra) == 3: self.d, self.exe, self.ico = self.extra self.name = self.exe.split()[0] self.setwh((self.d, self.d)) icon = None if self.ico.split('.')[-1] == 'svg' or self.ico.split('.')[-1] == 'svgz': icon = QImage(int(self.d * UNIT / 2), int(self.d * UNIT / 2), QImage.Format_ARGB32) icon.fill(QColor(120, 120, 120, 0)) renderer = QSvgRenderer(self.ico) painter = QPainter(icon) renderer.render(painter) del painter else: icon = QImage(self.ico) iconm = icon.scaled(2, 2) b1 = (QColor(iconm.pixel(0, 0)).getRgb(), QColor(iconm.pixel(0, 1)).getRgb(), QColor(iconm.pixel(1, 0)).getRgb(), QColor(iconm.pixel(1, 1)).getRgb(),) b = (0, 0, 0) for c in b1: b = (b[0] + c[0] // 4, b[1] + c[1] // 4, b[2] + c[2] // 4) self.setcolor(b) scale = min(icon.height(), icon.width(), self.d * UNIT / 2) self.setPixmap(QPixmap(icon).scaledToHeight(scale, Qt.SmoothTransformation)) if self.d > 1: font = QFont('sans') # font.setStretch(QFont.SemiExpanded) font.setPixelSize(UNIT / 4) nametext = QLabel(parent=self) nametext.setFont(font) nametext.move(UNIT / 10, self.height() - UNIT / 10 - nametext.height() / 2) nametext.setAlignment(Qt.AlignBottom | Qt.AlignCenter) nametext.setIndent(self.d * UNIT / 20) nametext.setText('<font color=white>%s</font>' % self.name)
class PixmapGenerator(QObject): """Renders the SVG image and applies the color.""" def __init__(self, path: str, color: Optional[QColor] = None, parent=None): super(PixmapGenerator, self).__init__(parent=parent) self._path = path self._color: Optional[QColor] = color self._svg_renderer = QSvgRenderer(self._path) def path(self) -> str: return self._path def color(self) -> Optional[QColor]: return self._color def pixmap(self, size: QSize) -> QPixmap: """ Render the svg file to a QPixmap, applying the color override if applicable. """ # Create a blank canvas image = QImage(size, QImage.Format_ARGB32_Premultiplied) image.fill(Qt.transparent) # Use the QSvgRenderer to draw the image painter = QPainter(image) self._svg_renderer.render(painter) painter.end() if self._color: # Create a second canvas solidly filled with the color then mask it with the original image colorImage = QImage(size, QImage.Format_ARGB32_Premultiplied) colorImage.fill(QColor(self._color)) painter = QPainter(colorImage) painter.setCompositionMode(QPainter.CompositionMode_DestinationIn) painter.drawImage(0, 0, image) painter.end() image = colorImage return QPixmap.fromImage(image)
def __init__(self): root = QFileInfo(__file__).absolutePath() svg_files = os.listdir(root + "/icons/svg/") self.images = {} for filename in svg_files: f = QFile(root + '/icons/svg/' + filename) if f.open(QFile.ReadOnly | QFile.Text): textStream = QTextStream(f) svgData = textStream.readAll().replace('fill="#000000"', 'fill="#eeeeee"') svgData_hover = svgData.replace('fill="#eeeeee"', 'fill="#3daee9"') f.close() svg = QSvgRenderer(QByteArray().append(svgData)) svg_hover = QSvgRenderer(QByteArray().append(svgData_hover)) qim = QImage(76, 76, QImage.Format_RGBA8888) qim.fill(0) painter = QPainter() painter.begin(qim) svg.render(painter) painter.end() qim_hover = QImage(76, 76, QImage.Format_ARGB32) qim_hover.fill(0) painter = QPainter() painter.begin(qim_hover) svg_hover.render(painter) painter.end() self.images[filename.replace("appbar.", "").replace( ".svg", "")] = (QIcon(QPixmap.fromImage(qim)), QIcon(QPixmap.fromImage(qim_hover)))
def svg2png(fName, width=600, app=None, oFilename=""): """ Smart convertion to PNG files; stroke widths are widened when necessary, so traces on an oscilloscope screen will be visible even if it is downscaled. A PNG file is written. :param fname: file name of a SVG drawing :param width: the width of the wanted PNG drawing; its height will be :param app: the current application :param oFilename: facultative file name for the output PNG file calculated automatically :returns: the effective file name of the written PNG file """ from PyQt5.QtSvg import QSvgRenderer from PyQt5.QtGui import QImage, QPainter, QColor, QGuiApplication from math import sqrt if not app: app = QGuiApplication([]) svg, w, h = openSVG(fName) groups = svg.getElementsByTagName("g") scale = width / w for g in groups: if "stroke-width" in g.attributes: g.setAttribute( "stroke-width", str(float(g.getAttribute("stroke-width")) / sqrt(scale))) qsr = QSvgRenderer(svg.toxml().encode("utf-8")) img = QImage(int(w * scale), int(h * scale), QImage.Format_ARGB32) img.fill(QColor("white")) p = QPainter(img) qsr.render(p) p.end() if not oFilename: oFilename = re.sub(r"\.svg$", f"-{width}px.png", fName) img.save(oFilename) return oFilename
class BasicSvgPage(page.AbstractPage): """A page that can display a SVG document.""" def __init__(self, load_file=None): self._svg_r = QSvgRenderer() if load_file: self.load(load_file) def load(self, load_file): """Load filename or QByteArray.""" success = self._svg_r.load(load_file) if success: self.pageWidth = self._svg_r.defaultSize().width() self.pageHeight = self._svg_r.defaultSize().height() return success def paint(self, painter, rect, callback=None): painter.fillRect(rect, self.paperColor or QColor(Qt.white)) page = QRect(0, 0, self.width, self.height) painter.translate(page.center()) painter.rotate(self.computedRotation * 90) if self.computedRotation & 1: page.setSize(page.size().transposed()) painter.translate(-page.center()) self._svg_r.render(painter, QRectF(page))
def drawObject(self, painter, rect, doc, posInDocument, format): renderer = QSvgRenderer(format.property(Window.SvgData)) renderer.render(painter, rect)
def _createBarcode(self): if self.barcode["value"] == "": return if self.barcode["type"] == BARCODE_ANY: logger.warning("Usando %s por defecto" % self.typeToName(BARCODE_128)) self.barcode["type"] = BARCODE_128 type_ = self.typeToName(self.barcode["type"]) value_ = self.barcode["value"] bg_ = self.barcode["bg"] fg_ = self.barcode["fg"] if not isinstance(self.barcode["bg"], str): bg_ = QColor(self.barcode["bg"]).name() if not isinstance(self.barcode["fg"], str): fg_ = QColor(self.barcode["fg"]).name() margin_ = self.barcode["margin"] / 10 render_options = {} render_options['module_width'] = 0.6 render_options['module_height'] = 10 render_options['background'] = bg_.lower() render_options['foreground'] = fg_.lower() render_options['font_size'] = 8 render_options['write_text'] = self.barcode["text"] render_options['text_distance'] = 35 render_options['quiet_zone'] = margin_ if self.barcode["text"]: render_options['text'] = value_ else: render_options['text'] = " " import barcode from barcode.writer import ImageWriter from PyQt5.QtSvg import QSvgRenderer barC = barcode.get_barcode_class(type_.lower()) try: bar_ = barC(u'%s' % value_) except Exception: bar_ = barC('000000000000') svg = bar_.render(render_options) xml_svg = load2xml(svg.decode("utf-8")) svg_w = (3.779 * float(xml_svg.get("width")[0:6])) svg_h = (3.779 * float(xml_svg.get("height")[0:6])) self.p = QPixmap(svg_w, svg_h) render = QSvgRenderer(svg) self.p.fill(QtCore.Qt.transparent) painter = Qt.QPainter(self.p) render.render(painter, QRectF(0,0,svg_w * 3.4 , svg_h * 3.4)) if self.p.isNull(): self.barcode["valid"] = False else: if self.barcode["scale"] != 1.0: wS_ = self.barcode["x"] * self.barcode["scale"] hS_ = self.barcode["y"] * self.barcode["scale"] self.p = self.p.scaled(wS_, hS_) self.barcode["x"] = self.p.width() self.barcode["y"] = self.p.height() self.barcode["valid"] = True
def drawGraphSymbo(self, renderContext): painter = renderContext.painter() mapToPixel = renderContext.mapToPixel() crs = QgsCoordinateReferenceSystem( 4326, QgsCoordinateReferenceSystem.PostgisCrsId) xform = QgsCoordinateTransform(self.crs(), crs, QgsProject.instance()) xml = self.symbo_reader.read(utils.resolve('render.xml')) pen = QPen() brush = QBrush() diameter = 0 nodes = self.readGraph().getListNode() edges = self.readGraph().getListEdge() #Dessin des arcs for edge in edges: start = nodes[edge.getNodeA()] end = nodes[edge.getNodeB()] #Gestion des configurations de propriétés graphiques """ Le fichier xml correspond à un dictionnaire de dictionnaire de rules: graphrenderer = {"node_rules": GraphRules, "edge_rules": GraphRules} """ if 'edge_rules' in xml: #Récupération de la valeur par défaut de la rule du xml #Cas où il n'y a pas de ruleunit pour la rule en question for key, val in xml['edge_rules'].items(): rule_prop = key graphRule = val attribute_name = graphRule.getName() default_prop = graphRule.getDefaultProp().value() list_ruleunit = graphRule.getRule() if (len(list_ruleunit) == 0): if (rule_prop == "fgcolor"): color = default_prop pen.setColor(color) elif (rule_prop == "linewidth"): variant = default_prop pen.setWidth(variant) elif (rule_prop == "linestyle"): variant = default_prop pen.setStyle(Qt.PenStyle(variant)) #Cas où il y a une ou plusieurs ruleunit dans le xml dict_features = edge.getFeatures() for edge_att_name, edge_att_val in dict_features.items(): if 'edge_rules' in xml: for key, val in xml['edge_rules'].items(): rule_prop = key graphRule = val attribute_name = graphRule.getName() default_prop = graphRule.getDefaultProp().value() list_ruleunit = graphRule.getRule() if (attribute_name == edge_att_name): if (len(list_ruleunit) != 0): #Permet d'affecter la prop_val à l'attr_val correspondant du fichier graph flag = 0 for index in range(len(list_ruleunit)): attribute_val = list_ruleunit[ index].attr_val.value() prop_val = list_ruleunit[ index].prop_val.value() if (str(edge_att_val) == str(attribute_val) ): if (rule_prop == "fgcolor"): color = prop_val pen.setColor(color) elif (rule_prop == "linewidth"): variant = prop_val pen.setWidth(variant) elif (rule_prop == "linestyle"): variant = prop_val pen.setStyle(Qt.PenStyle(variant)) flag = 1 break #Affecte la valeur par défaut à toutes les autres attr_val n'étant pas présentent dans la liste des rule_unit if (flag == 0): if (rule_prop == "fgcolor"): color = default_prop pen.setColor(color) elif (rule_prop == "linewidth"): variant = default_prop pen.setWidth(variant) elif (rule_prop == "linestyle"): variant = default_prop pen.setStyle(Qt.PenStyle(variant)) painter.setPen(pen) painter.setBrush(brush) pointA = mapToPixel.transform( xform.transform((QgsPointXY(int(start.getX()), int(start.getY()))))) pointB = mapToPixel.transform( xform.transform((QgsPointXY(int(end.getX()), int(end.getY()))))) painter.drawLine(pointA.x(), pointA.y(), pointB.x(), pointB.y()) #Même chose pour le dessin des noeuds, avec des rule_prop différentes for id in nodes: x = nodes[id].getX() y = nodes[id].getY() if 'node_rules' in xml: #Récupération de la valeur par défaut de la rule du xml #Cas où il n'y a pas de ruleunit pour la rule en question for key, val in xml['node_rules'].items(): rule_prop = key graphRule = val attribute_name = graphRule.getName() default_prop = graphRule.getDefaultProp().value() list_ruleunit = graphRule.getRule() if (len(list_ruleunit) == 0): if (rule_prop == "bgcolor"): color = default_prop brush.setColor(color) brush.setStyle(Qt.SolidPattern) elif (rule_prop == "fgcolor"): color = default_prop pen.setColor(color) elif (rule_prop == "linewidth"): variant = default_prop pen.setWidth(variant) elif (rule_prop == "size"): diameter = default_prop elif (rule_prop == "shape"): shape = default_prop #Cas où il y a une ou plusieurs ruleunit dans le xml dict_features = nodes[id].getFeatures() for node_att_name, node_att_val in dict_features.items(): if 'node_rules' in xml: for key, val in xml['node_rules'].items(): rule_prop = key graphRule = val attribute_name = graphRule.getName() default_prop = graphRule.getDefaultProp().value() list_ruleunit = graphRule.getRule() if (attribute_name == node_att_name): if (len(list_ruleunit) != 0): #Permet d'affecter la prop_val à l'attr_val correspondant du fichier graph flag = 0 for index in range(len(list_ruleunit)): attribute_val = list_ruleunit[ index].attr_val.value() prop_val = list_ruleunit[ index].prop_val.value() if (str(node_att_val) == str(attribute_val) ): if (rule_prop == "bgcolor"): color = prop_val brush.setColor(color) brush.setStyle(Qt.SolidPattern) elif (rule_prop == "fgcolor"): color = prop_val pen.setColor(color) elif (rule_prop == "linewidth"): variant = prop_val pen.setWidth(variant) elif (rule_prop == "size"): diameter = prop_val elif (rule_prop == "shape"): shape = prop_val flag = 1 break #Affecte la valeur par défaut à toutes les autres attr_val n'étant pas présentent dans la liste des rule_unit if (flag == 0): if (rule_prop == "bgcolor"): color = default_prop brush.setColor(color) brush.setStyle(Qt.SolidPattern) elif (rule_prop == "fgcolor"): color = default_prop pen.setColor(color) elif (rule_prop == "linewidth"): variant = default_prop pen.setWidth(variant) elif (rule_prop == "size"): diameter = default_prop elif (rule_prop == "shape"): shape = default_prop painter.setPen(pen) painter.setBrush(brush) point = mapToPixel.transform(xform.transform((QgsPointXY(x, y)))) #Différentes formes possibles pour la rule shape if (shape != ""): if (shape == "circle"): painter.drawEllipse(point.x() - diameter / 2, point.y() - diameter / 2, diameter, diameter) elif (shape == "rectangle"): painter.drawRect(point.x() - diameter / 2, point.y() - diameter / 2, diameter, diameter) elif (shape == "cross"): painter.drawLine(point.x() - diameter / 2, point.y() - diameter / 2, point.x() + diameter / 2, point.y() + diameter / 2) painter.drawLine(point.x() - diameter / 2, point.y() + diameter / 2, point.x() + diameter / 2, point.y() - diameter / 2) else: #Draw SVG Node svgr = QSvgRenderer(shape) if (svgr.isValid()): svgr.render( painter, QRectF(point.x() - diameter / 2, point.y() - diameter / 2, diameter, diameter)) else: painter.drawEllipse(point.x() - diameter / 2, point.y() - diameter / 2, diameter, diameter) else: #default is circle painter.drawEllipse(point.x() - diameter / 2, point.y() - diameter / 2, diameter, diameter)
class DWaterProgress(QProgressBar): def __init__(self, *args, **kwargs): super(DWaterProgress, self).__init__(*args, **kwargs) self.waterFrontImage = QImage() self.waterBackImage = QImage() self.waterFrontSvg = QSvgRenderer(WATER_FRONT.encode()) self.waterBackSvg = QSvgRenderer(WATER_BACK.encode()) self.pops = [] self.initPops() self.setTextVisible(True) self.interval = 33 self.timer = QTimer(self) self.timer.setInterval(self.interval) self.timer.timeout.connect(self.onTimerOut) self.resizePixmap(self.size()) self.frontXOffset = self.width() self.backXOffset = 0 effect = QGraphicsDropShadowEffect(self) effect.setOffset(0, 6) effect.setColor(QColor(1, 153, 248, 255 * 5 / 20)) effect.setBlurRadius(12) self.setGraphicsEffect(effect) def initPops(self): self.pops = [Pop(7, -1.8, 0.6), Pop(8, 1.2, 1.0), Pop(11, 0.8, 1.6)] @pyqtSlot() def start(self): self.timer.start() @pyqtSlot() def stop(self): self.timer.stop() def resizePixmap(self, sz): # https://github.com/linuxdeepin/dtkwidget/blob/master/src/widgets/dwaterprogress.cpp#L192 # resize water waterWidth = 500 * sz.width() / 100 waterHeight = 110 * sz.height() / 100 waterSize = QSizeF(waterWidth, waterHeight).toSize() if self.waterFrontImage.size() != waterSize: image = QImage(waterWidth, waterHeight, QImage.Format_ARGB32) image.fill(Qt.transparent) waterPainter = QPainter(image) self.waterFrontSvg.render(waterPainter) self.waterFrontImage = image if self.waterBackImage.size() != waterSize: image = QImage(waterWidth, waterHeight, QImage.Format_ARGB32) image.fill(Qt.transparent) # partly transparent red-ish background waterPainter = QPainter(image) self.waterBackSvg.render(waterPainter) self.waterBackImage = image def onTimerOut(self): # interval can not be zero, and limit to 1 self.interval = max(1, self.interval) # move 60% per second frontXDeta = 40.0 / (1000.0 / self.interval) # move 90% per second backXDeta = 60.0 / (1000.0 / self.interval) canvasWidth = int(self.width() * self.devicePixelRatioF()) self.frontXOffset -= frontXDeta * canvasWidth / 100 self.backXOffset += backXDeta * canvasWidth / 100 if self.frontXOffset > canvasWidth: self.frontXOffset = canvasWidth if self.frontXOffset < -(self.waterFrontImage.width() - canvasWidth): self.frontXOffset = canvasWidth if self.backXOffset > self.waterBackImage.width(): self.backXOffset = 0 # update pop # move 25% per second default speed = 25 / (1000.0 / self.interval) # 100 / self.height() for pop in self.pops: # yOffset 0 ~ 100 pop.yOffset += speed * pop.ySpeed if pop.yOffset < 0: pass if pop.yOffset > self.value(): pop.yOffset = 0 pop.xOffset = math.sin( (pop.yOffset / 100) * 2 * 3.14) * 18 * pop.xSpeed + 50 self.update() def paint(self, painter): painter.setRenderHint(QPainter.Antialiasing) pixelRatio = self.devicePixelRatioF() rect = QRectF(0, 0, self.width() * pixelRatio, self.height() * pixelRatio) sz = QSizeF(self.width() * pixelRatio, self.height() * pixelRatio).toSize() self.resizePixmap(sz) yOffset = rect.toRect().topLeft().y() + (100 - self.value() - 10) * sz.height() / 100 # draw water waterImage = QImage(sz, QImage.Format_ARGB32_Premultiplied) waterPainter = QPainter() waterPainter.begin(waterImage) waterPainter.setRenderHint(QPainter.Antialiasing) waterPainter.setCompositionMode(QPainter.CompositionMode_Source) pointStart = QPointF(sz.width() / 2, 0) pointEnd = QPointF(sz.width() / 2, sz.height()) linear = QLinearGradient(pointStart, pointEnd) startColor = QColor('#1F08FF') startColor.setAlphaF(1) endColor = QColor('#50FFF7') endColor.setAlphaF(0.28) linear.setColorAt(0, startColor) linear.setColorAt(1, endColor) linear.setSpread(QGradient.PadSpread) waterPainter.setPen(Qt.NoPen) waterPainter.setBrush(linear) waterPainter.drawEllipse(waterImage.rect().center(), sz.width() / 2 + 1, sz.height() / 2 + 1) waterPainter.setCompositionMode(QPainter.CompositionMode_SourceOver) waterPainter.drawImage(int(self.backXOffset), yOffset, self.waterBackImage) waterPainter.drawImage( int(self.backXOffset) - self.waterBackImage.width(), yOffset, self.waterBackImage) waterPainter.drawImage(int(self.frontXOffset), yOffset, self.waterFrontImage) waterPainter.drawImage( int(self.frontXOffset) - self.waterFrontImage.width(), yOffset, self.waterFrontImage) # draw pop if self.value() > 30: for pop in self.pops: popPath = QPainterPath() popPath.addEllipse(pop.xOffset * sz.width() / 100, (100 - pop.yOffset) * sz.height() / 100, pop.size * sz.width() / 100, pop.size * sz.height() / 100) waterPainter.fillPath(popPath, QColor(255, 255, 255, 255 * 0.3)) if self.isTextVisible(): font = waterPainter.font() rectValue = QRect() progressText = self.text().strip('%') if progressText == '100': font.setPixelSize(sz.height() * 35 / 100) waterPainter.setFont(font) rectValue.setWidth(sz.width() * 60 / 100) rectValue.setHeight(sz.height() * 35 / 100) rectValue.moveCenter(rect.center().toPoint()) waterPainter.setPen(Qt.white) waterPainter.drawText(rectValue, Qt.AlignCenter, progressText) else: font.setPixelSize(sz.height() * 40 / 100) waterPainter.setFont(font) rectValue.setWidth(sz.width() * 45 / 100) rectValue.setHeight(sz.height() * 40 / 100) rectValue.moveCenter(rect.center().toPoint()) rectValue.moveLeft(rect.left() + rect.width() * 0.45 * 0.5) waterPainter.setPen(Qt.white) waterPainter.drawText(rectValue, Qt.AlignCenter, progressText) font.setPixelSize(font.pixelSize() / 2) waterPainter.setFont(font) rectPerent = QRect( QPoint(rectValue.right(), rectValue.bottom() - rect.height() * 20 / 100), QPoint(rectValue.right() + rect.width() * 20 / 100, rectValue.bottom())) waterPainter.drawText(rectPerent, Qt.AlignCenter, '%') waterPainter.end() maskPixmap = QPixmap(sz) maskPixmap.fill(Qt.transparent) path = QPainterPath() path.addEllipse(QRectF(0, 0, sz.width(), sz.height())) maskPainter = QPainter() maskPainter.begin(maskPixmap) maskPainter.setRenderHint(QPainter.Antialiasing) maskPainter.setPen(QPen(Qt.white, 1)) maskPainter.fillPath(path, QBrush(Qt.white)) maskPainter.end() mode = QPainter.CompositionMode_SourceIn contentImage = QImage(sz, QImage.Format_ARGB32_Premultiplied) contentPainter = QPainter() contentPainter.begin(contentImage) contentPainter.setCompositionMode(QPainter.CompositionMode_Source) contentPainter.fillRect(contentImage.rect(), Qt.transparent) contentPainter.setCompositionMode(QPainter.CompositionMode_SourceOver) contentPainter.drawImage(0, 0, maskPixmap.toImage()) contentPainter.setCompositionMode(mode) contentPainter.drawImage(0, 0, waterImage) contentPainter.setCompositionMode( QPainter.CompositionMode_DestinationOver) contentPainter.end() contentImage.setDevicePixelRatio(pixelRatio) painter.drawImage(self.rect(), contentImage) def paintEvent(self, event): painter = QPainter(self) self.paint(painter) def sizeHint(self): return QSize(100, 100)
class GraphViewer(QWidget): def __init__(self, parent): super().__init__(parent) self._y = 0 self._width = 1 self._height = 1 self.dot = Digraph(format='svg', strict=True) self._declared_count = 1 self._declared = dict() self._renderer = QSvgRenderer(self.dot.pipe(), self) self.scrollbar = QScrollBar(self.parent()) self.scrollbar.setRange(0, 0) self.parent().wheelEvent = self.wheelEvent def wheelEvent(self, event): if event.x() > self.getScrollWidth(): return if event.y() > self._height: return self.scrollbar.wheelEvent(event) def add(self, data): # is variable if data in self._declared.keys(): return self._declared[data] if data.is_variable: name = data.name self._declared[data] = name self.dot.node(name) if data.toward is not None: toward = self.add(data.toward) self.dot.edge(toward, name) return name # is constant if data.is_constant: name = data.symbol self._declared[data] = name self.dot.node(name) return name # is operator if data.is_operator: name = '[%d] %s' % (self._declared_count, data.name) self._declared_count += 1 self._declared[data] = name self.dot.node(name) args = [data.sub, data.obj, data.step] if data.args is not None: args += data.args args = [arg for arg in args if arg is not None] for arg in args: arg = self.add(arg) self.dot.edge(arg, name) return name def paintEvent(self, event): self._width = self.width() self._height = self.height() self.scrollbar.setGeometry(self.getScrollWidth(), 0, 20, self._height) self.resize(self._renderer.defaultSize()) painter = QPainter(self) painter.restore() drawRect = QRectF(self.rect()) if self.scrollbar.maximum() == 0: draw_y = 0 else: draw_y = drawRect.height() - self._height draw_y *= self.scrollbar.value() / self.scrollbar.maximum() drawRect.setY(-draw_y) drawRect.setHeight(drawRect.y() + drawRect.height()) self._renderer.render(painter, drawRect) def flush(self): self._renderer = QSvgRenderer(self.dot.pipe()) max_h = self._renderer.defaultSize().height() / self._height if max_h <= 1: max_h = 0 max_h = int(self.delta() * max_h) self.scrollbar.setMaximum(max_h) def clear(self): self._declared_count = 1 self._declared = dict() self.dot.clear() def getScrollWidth(self): return self._width - 20 def delta(self): return 3.14
class QrReaderVideoOverlay(QWidget): """ Overlays the QR scanner results over the video """ BG_RECT_PADDING = 10 BG_RECT_CORNER_RADIUS = 10.0 BG_RECT_OPACITY = 0.75 QR_FINDER_OPACITY = 0.25 QR_FINDER_SIZE = 0.5 def __init__(self, parent: QWidget = None): super().__init__(parent) self.results = [] self.flip_x = False self.validator_results = None self.crop = None self.resolution = None self.qr_outline_pen = QPen() self.qr_outline_pen.setColor(Qt.red) self.qr_outline_pen.setWidth(3) self.qr_outline_pen.setStyle(Qt.DotLine) self.text_pen = QPen() self.text_pen.setColor(Qt.black) self.bg_rect_pen = QPen() self.bg_rect_pen.setColor(Qt.black) self.bg_rect_pen.setStyle(Qt.DotLine) self.bg_rect_fill = QColor(255, 255, 255, 255 * self.BG_RECT_OPACITY) self.qr_finder = QSvgRenderer(":icons/qr_finder.svg") def set_results(self, results: List[QrCodeResult], flip_x: bool, validator_results: QrReaderValidatorResult): self.results = results self.flip_x = flip_x self.validator_results = validator_results self.update() def set_crop(self, crop: QRect): self.crop = crop def set_resolution(self, resolution: QSize): self.resolution = resolution def paintEvent(self, _event: QPaintEvent): if not self.crop or not self.resolution: return painter = QPainter(self) # Keep a backup of the transform and create a new one transform = painter.worldTransform() # Set scaling transform transform = transform.scale(self.width() / self.resolution.width(), self.height() / self.resolution.height()) # Compute the transform to flip the coordinate system on the x axis transform_flip = QTransform() if self.flip_x: transform_flip = transform_flip.translate(self.resolution.width(), 0.0) transform_flip = transform_flip.scale(-1.0, 1.0) # Small helper for tuple to QPoint def toqp(point): return QPoint(point[0], point[1]) # Starting from here we care about AA painter.setRenderHint(QPainter.Antialiasing) # Draw the QR code finder overlay painter.setWorldTransform(transform_flip * transform, False) painter.setOpacity(self.QR_FINDER_OPACITY) qr_finder_size = self.crop.size() * self.QR_FINDER_SIZE tmp = (self.crop.size() - qr_finder_size) / 2 qr_finder_pos = QPoint(tmp.width(), tmp.height()) + self.crop.topLeft() qr_finder_rect = QRect(qr_finder_pos, qr_finder_size) self.qr_finder.render(painter, QRectF(qr_finder_rect)) painter.setOpacity(1.0) # Draw all the QR code results for res in self.results: painter.setWorldTransform(transform_flip * transform, False) # Draw lines between all of the QR code points pen = QPen(self.qr_outline_pen) if res in self.validator_results.result_colors: pen.setColor(self.validator_results.result_colors[res]) painter.setPen(pen) num_points = len(res.points) for i in range(0, num_points): i_n = i + 1 line_from = toqp(res.points[i]) line_from += self.crop.topLeft() line_to = toqp(res.points[i_n] if i_n < num_points else res.points[0]) line_to += self.crop.topLeft() painter.drawLine(line_from, line_to) # Draw the QR code data # Note that we reset the world transform to only the scaled transform # because otherwise the text could be flipped. We only use transform_flip # to map the center point of the result. painter.setWorldTransform(transform, False) font_metrics = painter.fontMetrics() data_metrics = QSize(font_metrics.horizontalAdvance(res.data), font_metrics.capHeight()) center_pos = toqp(res.center) center_pos += self.crop.topLeft() center_pos = transform_flip.map(center_pos) text_offset = QPoint(data_metrics.width(), data_metrics.height()) text_offset = text_offset / 2 text_offset.setX(-text_offset.x()) center_pos += text_offset padding = self.BG_RECT_PADDING bg_rect_pos = center_pos - QPoint(padding, data_metrics.height() + padding) bg_rect_size = data_metrics + (QSize(padding, padding) * 2) bg_rect = QRect(bg_rect_pos, bg_rect_size) bg_rect_path = QPainterPath() radius = self.BG_RECT_CORNER_RADIUS bg_rect_path.addRoundedRect(QRectF(bg_rect), radius, radius, Qt.AbsoluteSize) painter.setPen(self.bg_rect_pen) painter.fillPath(bg_rect_path, self.bg_rect_fill) painter.drawPath(bg_rect_path) painter.setPen(self.text_pen) painter.drawText(center_pos, res.data)
class QLed(QWidget): Circle = 1 Round = 2 Square = 3 Triangle = 4 Red = 1 Green = 2 Yellow = 3 Grey = 4 Orange = 5 Purple = 6 Blue = 7 shapes={ Circle:""" <svg height="50.000000px" id="svg9493" width="50.000000px" xmlns="http://www.w3.org/2000/svg"> <defs id="defs9495"> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient6650" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient6494"> <stop id="stop6496" offset="0.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> <stop id="stop6498" offset="1.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient6648" x1="23.213980" x2="23.201290" xlink:href="#linearGradient6494" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient6646" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient6644" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient id="linearGradient6506"> <stop id="stop6508" offset="0.0000000" style="stop-color:#ffffff;stop-opacity:0.0000000;"/> <stop id="stop6510" offset="1.0000000" style="stop-color:#ffffff;stop-opacity:0.87450981;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7498" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient7464"> <stop id="stop7466" offset="0.0000000" style="stop-color:#00039a;stop-opacity:1.0000000;"/> <stop id="stop7468" offset="1.0000000" style="stop-color:#afa5ff;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7496" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient id="linearGradient5756"> <stop id="stop5758" offset="0.0000000" style="stop-color:#828282;stop-opacity:1.0000000;"/> <stop id="stop5760" offset="1.0000000" style="stop-color:#929292;stop-opacity:0.35294119;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9321" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient id="linearGradient5742"> <stop id="stop5744" offset="0.0000000" style="stop-color:#adadad;stop-opacity:1.0000000;"/> <stop id="stop5746" offset="1.0000000" style="stop-color:#f0f0f0;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7492" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9527" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9529" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9531" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9533" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> </defs> <g id="layer1"> <g id="g9447" style="overflow:visible" transform="matrix(31.25000,0.000000,0.000000,31.25000,-625.0232,-1325.000)"> <path d="M 24.000001,43.200001 C 24.000001,43.641601 23.641601,44.000001 23.200001,44.000001 C 22.758401,44.000001 22.400001,43.641601 22.400001,43.200001 C 22.400001,42.758401 22.758401,42.400001 23.200001,42.400001 C 23.641601,42.400001 24.000001,42.758401 24.000001,43.200001 z " id="path6596" style="fill:url(#linearGradient6644);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible" transform="translate(-2.399258,-1.000000e-6)"/> <path d="M 23.906358,43.296204 C 23.906358,43.625433 23.639158,43.892633 23.309929,43.892633 C 22.980700,43.892633 22.713500,43.625433 22.713500,43.296204 C 22.713500,42.966975 22.980700,42.699774 23.309929,42.699774 C 23.639158,42.699774 23.906358,42.966975 23.906358,43.296204 z " id="path6598" style="fill:url(#linearGradient6646);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible" transform="matrix(1.082474,0.000000,0.000000,1.082474,-4.431649,-3.667015)"/> <path d="M 23.906358,43.296204 C 23.906358,43.625433 23.639158,43.892633 23.309929,43.892633 C 22.980700,43.892633 22.713500,43.625433 22.713500,43.296204 C 22.713500,42.966975 22.980700,42.699774 23.309929,42.699774 C 23.639158,42.699774 23.906358,42.966975 23.906358,43.296204 z " id="path6600" style="fill:url(#linearGradient6648);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible" transform="matrix(0.969072,0.000000,0.000000,0.969072,-1.788256,1.242861)"/> <path d="M 23.906358,43.296204 C 23.906358,43.625433 23.639158,43.892633 23.309929,43.892633 C 22.980700,43.892633 22.713500,43.625433 22.713500,43.296204 C 22.713500,42.966975 22.980700,42.699774 23.309929,42.699774 C 23.639158,42.699774 23.906358,42.966975 23.906358,43.296204 z " id="path6602" style="fill:url(#linearGradient6650);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible" transform="matrix(0.773196,0.000000,0.000000,0.597938,2.776856,17.11876)"/> </g> </g> </svg> """, Round:""" <svg height="50.000000px" id="svg9493" width="100.00000px" xmlns="http://www.w3.org/2000/svg"> <defs id="defs9495"> <linearGradient gradientTransform="matrix(0.928127,0.000000,0.000000,0.639013,13.55634,12.87587)" gradientUnits="userSpaceOnUse" id="linearGradient13424" x1="21.593750" x2="21.593750" xlink:href="#linearGradient6506" y1="47.917328" y2="46.774261"/> <linearGradient id="linearGradient6494"> <stop id="stop6496" offset="0.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> <stop id="stop6498" offset="1.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientTransform="translate(12.00000,-4.000002)" gradientUnits="userSpaceOnUse" id="linearGradient13427" x1="21.591305" x2="21.593750" xlink:href="#linearGradient6494" y1="46.617390" y2="47.781250"/> <linearGradient gradientTransform="translate(12.00000,-4.000002)" gradientUnits="userSpaceOnUse" id="linearGradient13430" x1="21.408695" x2="21.834784" xlink:href="#linearGradient5756" y1="46.556522" y2="47.843750"/> <linearGradient gradientTransform="translate(12.00000,-4.000002)" gradientUnits="userSpaceOnUse" id="linearGradient13433" x1="21.594427" x2="21.600000" xlink:href="#linearGradient5742" y1="46.376728" y2="48.000000"/> <linearGradient gradientTransform="matrix(0.928127,0.000000,0.000000,0.639013,21.55634,15.27587)" gradientUnits="userSpaceOnUse" id="linearGradient13472" x1="21.593750" x2="21.593750" xlink:href="#linearGradient6506" y1="47.917328" y2="46.774261"/> <linearGradient gradientTransform="translate(20.00000,-1.600002)" gradientUnits="userSpaceOnUse" id="linearGradient13475" x1="21.591305" x2="21.593750" xlink:href="#linearGradient9163" y1="46.617390" y2="47.781250"/> <linearGradient gradientTransform="translate(20.00000,-1.600002)" gradientUnits="userSpaceOnUse" id="linearGradient13478" x1="21.408695" x2="21.834784" xlink:href="#linearGradient5756" y1="46.556522" y2="47.843750"/> <linearGradient gradientTransform="translate(20.00000,-1.600002)" gradientUnits="userSpaceOnUse" id="linearGradient13481" x1="21.594427" x2="21.600000" xlink:href="#linearGradient5742" y1="46.376728" y2="48.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9199" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient9163"> <stop id="stop9165" offset="0.0000000" style="stop-color:#000000;stop-opacity:1.0000000;"/> <stop id="stop9167" offset="1.0000000" style="stop-color:#8c8c8c;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9197" x1="23.213980" x2="23.201290" xlink:href="#linearGradient9163" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9195" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9193" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient id="linearGradient6506"> <stop id="stop6508" offset="0.0000000" style="stop-color:#ffffff;stop-opacity:0.0000000;"/> <stop id="stop6510" offset="1.0000000" style="stop-color:#ffffff;stop-opacity:0.87450981;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7498" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient7464"> <stop id="stop7466" offset="0.0000000" style="stop-color:#00039a;stop-opacity:1.0000000;"/> <stop id="stop7468" offset="1.0000000" style="stop-color:#afa5ff;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7496" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient id="linearGradient5756"> <stop id="stop5758" offset="0.0000000" style="stop-color:#828282;stop-opacity:1.0000000;"/> <stop id="stop5760" offset="1.0000000" style="stop-color:#929292;stop-opacity:0.35294119;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9321" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient id="linearGradient5742"> <stop id="stop5744" offset="0.0000000" style="stop-color:#adadad;stop-opacity:1.0000000;"/> <stop id="stop5746" offset="1.0000000" style="stop-color:#f0f0f0;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7492" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9527" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9529" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9531" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9533" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient gradientTransform="matrix(24.16238,0.000000,0.000000,18.68556,-538.2464,-790.0391)" gradientUnits="userSpaceOnUse" id="linearGradient1336" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient gradientTransform="matrix(30.28350,0.000000,0.000000,30.28350,-680.9062,-1286.161)" gradientUnits="userSpaceOnUse" id="linearGradient1339" x1="23.213980" x2="23.201290" xlink:href="#linearGradient9163" y1="42.754631" y2="43.892632"/> <linearGradient gradientTransform="matrix(33.82731,0.000000,0.000000,33.82731,-763.5122,-1439.594)" gradientUnits="userSpaceOnUse" id="linearGradient1342" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientTransform="matrix(31.25000,0.000000,0.000000,31.25000,-700.0000,-1325.000)" gradientUnits="userSpaceOnUse" id="linearGradient1345" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> </defs> <g id="layer1"> <g id="g13543" style="overflow:visible" transform="matrix(31.25000,0.000000,0.000000,31.25000,-999.9999,-1325.000)"> <path d="M 32.799998,42.400000 L 34.399998,42.400000 C 34.843198,42.400000 35.199998,42.756800 35.199998,43.200000 C 35.199998,43.643200 34.843198,44.000000 34.399998,44.000000 L 32.799998,44.000000 C 32.356798,44.000000 31.999998,43.643200 31.999998,43.200000 C 31.999998,42.756800 32.356798,42.400000 32.799998,42.400000 z " id="path13335" style="fill:url(#linearGradient13433);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> <path d="M 32.812498,42.562498 C 32.447387,42.562498 32.156248,42.829606 32.156248,43.187498 C 32.156248,43.545390 32.454607,43.843750 32.812498,43.843748 L 34.406248,43.843748 C 34.764141,43.843748 35.031248,43.552611 35.031248,43.187498 C 35.031248,42.822387 34.771358,42.562498 34.406248,42.562498 L 32.812498,42.562498 z " id="path13337" style="fill:url(#linearGradient13430);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> <path d="M 32.812498,42.624998 C 32.485887,42.624998 32.218748,42.871665 32.218748,43.187498 C 32.218748,43.503332 32.496667,43.781249 32.812498,43.781248 L 34.406248,43.781248 C 34.722082,43.781248 34.968748,43.514111 34.968748,43.187498 C 34.968748,42.860887 34.732858,42.624998 34.406248,42.624998 L 32.812498,42.624998 z " id="path13339" style="fill:url(#linearGradient13427);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> <path d="M 32.872983,42.669849 C 32.569847,42.669849 32.321908,42.827473 32.321908,43.029294 C 32.321908,43.231116 32.579852,43.408709 32.872983,43.408708 L 34.352185,43.408708 C 34.645320,43.408708 34.874257,43.238004 34.874257,43.029294 C 34.874257,42.820585 34.655321,42.669849 34.352185,42.669849 L 32.872983,42.669849 z " id="path13341" style="fill:url(#linearGradient13424);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> </g> </g> </svg> """, Square:""" <svg height="50.000000px" id="svg9493" width="50.000000px" xmlns="http://www.w3.org/2000/svg"> <defs id="defs9495"> <linearGradient gradientTransform="matrix(0.388435,0.000000,0.000000,0.618097,2.806900,2.626330)" gradientUnits="userSpaceOnUse" id="linearGradient31681" x1="21.593750" x2="21.593750" xlink:href="#linearGradient6506" y1="47.917328" y2="46.774261"/> <linearGradient id="linearGradient6494"> <stop id="stop6496" offset="0.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> <stop id="stop6498" offset="1.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient31704" x1="18.390625" x2="18.390625" xlink:href="#linearGradient6494" y1="43.400002" y2="44.593750"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient31624" x1="17.728125" x2="19.031250" xlink:href="#linearGradient5756" y1="43.337502" y2="44.656250"/> <linearGradient gradientTransform="matrix(0.500000,0.000000,0.000000,1.000000,-3.600000,-8.800000)" gradientUnits="userSpaceOnUse" id="linearGradient31686" x1="29.600000" x2="29.600000" xlink:href="#linearGradient5742" y1="39.991302" y2="41.599998"/> <linearGradient gradientTransform="matrix(0.388435,0.000000,0.000000,0.618097,7.606900,5.026330)" gradientUnits="userSpaceOnUse" id="linearGradient31649" x1="21.593750" x2="21.593750" xlink:href="#linearGradient6506" y1="47.917328" y2="46.774261"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient31710" x1="18.390625" x2="18.390625" xlink:href="#linearGradient9163" y1="43.400002" y2="44.593750"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient31570" x1="17.728125" x2="19.031250" xlink:href="#linearGradient5756" y1="43.337502" y2="44.656250"/> <linearGradient gradientTransform="matrix(0.500000,0.000000,0.000000,1.000000,1.200000,-6.400000)" gradientUnits="userSpaceOnUse" id="linearGradient31654" x1="29.600000" x2="29.600000" xlink:href="#linearGradient5742" y1="39.991302" y2="41.599998"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9199" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient9163"> <stop id="stop9165" offset="0.0000000" style="stop-color:#000000;stop-opacity:1.0000000;"/> <stop id="stop9167" offset="1.0000000" style="stop-color:#8c8c8c;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9197" x1="23.213980" x2="23.201290" xlink:href="#linearGradient9163" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9195" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9193" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient id="linearGradient6506"> <stop id="stop6508" offset="0.0000000" style="stop-color:#ffffff;stop-opacity:0.0000000;"/> <stop id="stop6510" offset="1.0000000" style="stop-color:#ffffff;stop-opacity:0.87450981;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7498" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient7464"> <stop id="stop7466" offset="0.0000000" style="stop-color:#00039a;stop-opacity:1.0000000;"/> <stop id="stop7468" offset="1.0000000" style="stop-color:#afa5ff;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7496" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient id="linearGradient5756"> <stop id="stop5758" offset="0.0000000" style="stop-color:#828282;stop-opacity:1.0000000;"/> <stop id="stop5760" offset="1.0000000" style="stop-color:#929292;stop-opacity:0.35294119;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9321" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient id="linearGradient5742"> <stop id="stop5744" offset="0.0000000" style="stop-color:#adadad;stop-opacity:1.0000000;"/> <stop id="stop5746" offset="1.0000000" style="stop-color:#f0f0f0;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7492" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9527" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9529" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9531" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9533" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient gradientTransform="matrix(24.16238,0.000000,0.000000,18.68556,-538.2464,-790.0391)" gradientUnits="userSpaceOnUse" id="linearGradient1336" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient gradientTransform="matrix(30.28350,0.000000,0.000000,30.28350,-680.9062,-1286.161)" gradientUnits="userSpaceOnUse" id="linearGradient1339" x1="23.213980" x2="23.201290" xlink:href="#linearGradient9163" y1="42.754631" y2="43.892632"/> <linearGradient gradientTransform="matrix(33.82731,0.000000,0.000000,33.82731,-763.5122,-1439.594)" gradientUnits="userSpaceOnUse" id="linearGradient1342" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientTransform="matrix(31.25000,0.000000,0.000000,31.25000,-700.0000,-1325.000)" gradientUnits="userSpaceOnUse" id="linearGradient1345" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> </defs> <g id="layer1"> <g id="g31718" style="overflow:visible" transform="matrix(31.25000,0.000000,0.000000,31.25000,-325.0000,-975.0000)"> <path d="M 10.400000,31.200000 L 12.000000,31.200000 L 12.000000,32.800000 L 10.400000,32.800000 L 10.400000,31.200000 z " id="path31614" style="fill:url(#linearGradient31686);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> <path d="M 17.750000,43.343750 L 17.750000,44.656250 L 19.031250,44.656250 L 19.031250,43.343750 L 17.750000,43.343750 z " id="path31616" style="fill:url(#linearGradient31624);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible" transform="translate(-7.190625,-12.00000)"/> <path d="M 17.812500,43.406250 L 17.812500,44.593750 L 18.968750,44.593750 L 18.968750,43.406250 L 17.812500,43.406250 z " id="path31618" style="fill:url(#linearGradient31704);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible" transform="translate(-7.190625,-12.00000)"/> <path d="M 10.891195,31.445120 C 10.630356,31.445967 10.660563,31.393294 10.660563,31.792800 C 10.660563,31.988016 10.768517,32.159796 10.891195,32.159795 L 11.510263,32.159795 C 11.632945,32.159795 11.728757,31.994678 11.728757,31.792800 C 11.728757,31.389990 11.754584,31.441761 11.510263,31.445120 L 10.891195,31.445120 z " id="path31620" sodipodi:nodetypes="csccscc" style="fill:url(#linearGradient31681);fill-opacity:1.0000000;stroke:none;stroke-width:0.80000001;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> </g> </g> </svg> """, Triangle:""" <svg height="50.000000px" id="svg9493" width="50.000000px" xmlns="http://www.w3.org/2000/svg" > <defs id="defs9495"> <linearGradient gradientTransform="matrix(0.389994,0.000000,0.000000,0.403942,4.557010,29.83582)" gradientUnits="userSpaceOnUse" id="linearGradient28861" x1="23.187498" x2="23.187498" xlink:href="#linearGradient6506" y1="28.449617" y2="26.670279"/> <linearGradient id="linearGradient6494"> <stop id="stop6496" offset="0.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> <stop id="stop6498" offset="1.0000000" style="stop-color:%s;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientTransform="translate(-9.587500,13.60000)" gradientUnits="userSpaceOnUse" id="linearGradient28864" x1="23.181250" x2="23.187500" xlink:href="#linearGradient6494" y1="26.793751" y2="27.843750"/> <linearGradient gradientTransform="translate(-9.587500,13.60000)" gradientUnits="userSpaceOnUse" id="linearGradient28867" x1="22.762501" x2="23.812500" xlink:href="#linearGradient5756" y1="26.687500" y2="27.906250"/> <linearGradient gradientTransform="translate(-9.600000,13.60000)" gradientUnits="userSpaceOnUse" id="linearGradient28870" x1="23.187500" x2="23.200001" xlink:href="#linearGradient5742" y1="26.400000" y2="28.000000"/> <linearGradient gradientTransform="matrix(0.389994,0.000000,0.000000,0.403942,9.357010,32.23582)" gradientUnits="userSpaceOnUse" id="linearGradient28801" x1="23.187498" x2="23.187498" xlink:href="#linearGradient6506" y1="28.449617" y2="26.670279"/> <linearGradient gradientTransform="translate(-4.787500,16.00000)" gradientUnits="userSpaceOnUse" id="linearGradient28804" x1="23.181250" x2="23.187500" xlink:href="#linearGradient9163" y1="26.793751" y2="27.843750"/> <linearGradient gradientTransform="translate(-4.787500,16.00000)" gradientUnits="userSpaceOnUse" id="linearGradient28807" x1="22.762501" x2="23.812500" xlink:href="#linearGradient5756" y1="26.687500" y2="27.906250"/> <linearGradient gradientTransform="translate(-4.800000,16.00000)" gradientUnits="userSpaceOnUse" id="linearGradient28810" x1="23.187500" x2="23.200001" xlink:href="#linearGradient5742" y1="26.400000" y2="28.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9199" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient9163"> <stop id="stop9165" offset="0.0000000" style="stop-color:#000000;stop-opacity:1.0000000;"/> <stop id="stop9167" offset="1.0000000" style="stop-color:#8c8c8c;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9197" x1="23.213980" x2="23.201290" xlink:href="#linearGradient9163" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9195" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9193" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient id="linearGradient6506"> <stop id="stop6508" offset="0.0000000" style="stop-color:#ffffff;stop-opacity:0.0000000;"/> <stop id="stop6510" offset="1.0000000" style="stop-color:#ffffff;stop-opacity:0.87450981;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7498" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient id="linearGradient7464"> <stop id="stop7466" offset="0.0000000" style="stop-color:#00039a;stop-opacity:1.0000000;"/> <stop id="stop7468" offset="1.0000000" style="stop-color:#afa5ff;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7496" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient id="linearGradient5756"> <stop id="stop5758" offset="0.0000000" style="stop-color:#828282;stop-opacity:1.0000000;"/> <stop id="stop5760" offset="1.0000000" style="stop-color:#929292;stop-opacity:0.35294119;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9321" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient id="linearGradient5742"> <stop id="stop5744" offset="0.0000000" style="stop-color:#adadad;stop-opacity:1.0000000;"/> <stop id="stop5746" offset="1.0000000" style="stop-color:#f0f0f0;stop-opacity:1.0000000;"/> </linearGradient> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient7492" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9527" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9529" x1="22.935030" x2="23.662106" xlink:href="#linearGradient5756" y1="42.699776" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9531" x1="23.213980" x2="23.201290" xlink:href="#linearGradient7464" y1="42.754631" y2="43.892632"/> <linearGradient gradientUnits="userSpaceOnUse" id="linearGradient9533" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient gradientTransform="matrix(24.16238,0.000000,0.000000,18.68556,-538.2464,-790.0391)" gradientUnits="userSpaceOnUse" id="linearGradient1336" x1="23.402565" x2="23.389874" xlink:href="#linearGradient6506" y1="44.066776" y2="42.883698"/> <linearGradient gradientTransform="matrix(30.28350,0.000000,0.000000,30.28350,-680.9062,-1286.161)" gradientUnits="userSpaceOnUse" id="linearGradient1339" x1="23.213980" x2="23.201290" xlink:href="#linearGradient9163" y1="42.754631" y2="43.892632"/> <linearGradient gradientTransform="matrix(33.82731,0.000000,0.000000,33.82731,-763.5122,-1439.594)" gradientUnits="userSpaceOnUse" id="linearGradient1342" x1="23.349695" x2="23.440580" xlink:href="#linearGradient5756" y1="42.767944" y2="43.710873"/> <linearGradient gradientTransform="matrix(31.25000,0.000000,0.000000,31.25000,-700.0000,-1325.000)" gradientUnits="userSpaceOnUse" id="linearGradient1345" x1="23.193102" x2="23.200001" xlink:href="#linearGradient5742" y1="42.429230" y2="44.000000"/> </defs> <g id="layer1"> <g id="g28884" style="overflow:visible" transform="matrix(31.25000,0.000000,0.000000,31.25000,-400.0000,-1250.000)"> <path d="M 14.400000,41.600000 L 12.800000,41.600000 L 13.600000,40.000000 L 14.400000,41.600000 z " id="path28664" sodipodi:nodetypes="cccc" style="fill:url(#linearGradient28870);fill-opacity:1.0000000;stroke:none;stroke-width:0.064000003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"/> <path d="M 13.600000,40.256250 L 12.975000,41.506250 L 14.225000,41.506250 L 13.600000,40.256250 z " id="path28666" style="fill:url(#linearGradient28867);fill-opacity:1.0000000;stroke:none;stroke-width:0.064000003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> <path d="M 13.600000,40.381250 L 13.068750,41.443750 L 14.131250,41.443750 L 13.600000,40.381250 z " id="path28668" style="fill:url(#linearGradient28864);fill-opacity:1.0000000;stroke:none;stroke-width:0.064000003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> <path d="M 13.575621,40.552906 C 13.555816,40.559679 13.538695,40.572979 13.526872,40.590776 C 13.522451,40.594595 13.518372,40.598819 13.514685,40.603399 L 13.307500,41.032587 C 13.299161,41.047990 13.294953,41.065424 13.295313,41.083080 C 13.296850,41.096430 13.300996,41.109315 13.307500,41.120950 C 13.310377,41.129925 13.314481,41.138427 13.319688,41.146196 C 13.323375,41.150775 13.327454,41.155000 13.331875,41.158819 C 13.339376,41.164212 13.347584,41.168462 13.356250,41.171442 C 13.367483,41.178179 13.379923,41.182474 13.392812,41.184066 L 13.807180,41.184066 C 13.835802,41.183428 13.862639,41.169530 13.880304,41.146196 C 13.884725,41.142377 13.888804,41.138152 13.892491,41.133573 C 13.898995,41.121938 13.903142,41.109053 13.904679,41.095703 C 13.905039,41.078047 13.900831,41.060614 13.892491,41.045211 C 13.892751,41.041007 13.892751,41.036791 13.892491,41.032587 L 13.685307,40.603399 C 13.681620,40.598819 13.677541,40.594595 13.673120,40.590776 C 13.650701,40.559305 13.612491,40.544463 13.575621,40.552906 z " id="path28670" style="fill:url(#linearGradient28861);fill-opacity:1.0000000;stroke:none;stroke-width:0.064000003;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;overflow:visible"/> </g> </g> </svg> """ } colours={Red : (0xCF, 0x00, 0x00), Green : (0x0f, 0x69, 0x00), Yellow : (0xd2, 0xcd, 0x00), Grey : (0x5a, 0x5a, 0x5a), Orange : (0xda, 0x46, 0x15), Purple : (0x87, 0x00, 0x83), Blue : (0x00, 0x03, 0x9a)} clicked=pyqtSignal() def __init__(self, parent=None, **kwargs): self.m_value=False self.m_onColour=QLed.Red self.m_offColour=QLed.Grey self.m_shape=QLed.Circle QWidget.__init__(self, parent, **kwargs) self._pressed=False self.renderer=QSvgRenderer() def value(self): return self.m_value def setValue(self, value): self.m_value=value self.update() value=pyqtProperty(bool, value, setValue) def onColour(self): return self.m_onColour def setOnColour(self, newColour): self.m_onColour=newColour self.update() onColour=pyqtProperty(int, onColour, setOnColour) def offColour(self): return self.m_offColour def setOffColour(self, newColour): self.m_offColour=newColour self.update() offColour=pyqtProperty(int, offColour, setOffColour) def shape(self): return self.m_shape def setShape(self, newShape): self.m_shape=newShape self.update() shape=pyqtProperty(int, shape, setShape) def sizeHint(self): if self.m_shape==QLed.Triangle: return QSize(64,48) elif self.m_shape==QLed.Round: return QSize(96, 48) return QSize(48,48) def adjust(self, r, g, b): def normalise(x): return x/255.0 def denormalise(x): return int(x*255.0) (h,l,s)=rgb_to_hls(normalise(r),normalise(g),normalise(b)) (nr,ng,nb)=hls_to_rgb(h,l*1.5,s) return (denormalise(nr),denormalise(ng),denormalise(nb)) def paintEvent(self, event): option=QStyleOption() option.initFrom(self) h=option.rect.height() w=option.rect.width() if self.m_shape in (QLed.Triangle, QLed.Round): aspect=(4/3.0) if self.m_shape==QLed.Triangle else 2.0 ah=w/aspect aw=w if ah>h: ah=h aw=h*aspect x=abs(aw-w)/2.0 y=abs(ah-h)/2.0 bounds=QRectF(x,y,aw,ah) else: size=min(w,h) x=abs(size-w)/2.0 y=abs(size-h)/2.0 bounds=QRectF(x,y,size,size) painter=QPainter(self); painter.setRenderHint(QPainter.Antialiasing, True); (dark_r,dark_g,dark_b)=self.colours[self.m_onColour if self.m_value else self.m_offColour] dark_str="rgb(%d,%d,%d)" % (dark_r,dark_g,dark_b) light_str="rgb(%d,%d,%d)" % self.adjust(dark_r,dark_g,dark_b) shape = self.shapes[self.m_shape] % (dark_str, light_str) shape = shape.encode('utf-8') self.renderer.load(QByteArray(shape)) self.renderer.render(painter, bounds) def mousePressEvent(self, event): self._pressed=True QWidget.mousePressEvent(self, event) def mouseReleaseEvent(self, event): if self._pressed: self._pressed=False self.clicked.emit() QWidget.mouseReleaseEvent(self, event) def toggleValue(self): self.m_value=not self.m_value; self.update()