def _create_pixmap(self, path, color): """ Internal function that creates a new item pixmap from the given path :param path: str :param color: str or QColor :return: QPixmap """ if not path: return QPixmap() dpi = self.treeWidget().dpi() key = path + color + 'DPI-' + str(dpi) item_pixmap = self._PIXMAP_CACHE.get(key) if not item_pixmap: width = 20 * dpi height = 18 * dpi if '/' not in path and '\\' not in path: path = resources.get('icons', path) if not path or not os.path.exists(path): path = self.default_icon_path() pixmap2 = pixmap.Pixmap(path) pixmap2.set_color(color) pixmap2 = pixmap2.scaled(16 * dpi, 16 * dpi, Qt.KeepAspectRatio, Qt.SmoothTransformation) x = (width - pixmap2.width()) / 2 y = (height - pixmap2.height()) / 2 item_pixmap = QPixmap(QSize(width, height)) item_pixmap.fill(Qt.transparent) painter = QPainter(item_pixmap) painter.drawPixmap(x, y, pixmap2) painter.end() self._PIXMAP_CACHE[key] = item_pixmap return item_pixmap
def create_empty_image(output=None, resolution_x=1920, resolution_y=1080, background_color=None): """ Creates an empty image and stores it in the given path :param output: str :param resolution_x: int :param resolution_y: int :param background_color: list(int, int, int) :return: str or QImage """ if background_color is None: background_color = [0, 0, 0] pixmap = QPixmap(resolution_x, resolution_y) pixmap.fill(QColor(*background_color)) if output: output_path = path_utils.clean_path(output) output_dir = os.path.dirname(output_path) if os.access(output_dir, os.W_OK): pixmap.save(output_path) return output_path return QImage(pixmap)
def tint_pixmap(pixmap, tint_color=(255, 255, 255, 100), composition_mode=QPainter.CompositionMode_Plus): """ Composite one pixmap on top of another :param pixmap: :param tint_color: :param composition_mode: :return: """ tint_color = QColor(*tint_color) over_pixmap = QPixmap(pixmap.width(), pixmap.height()) over_pixmap.fill(tint_color) over_pixmap.setMask(pixmap.mask()) painter = QPainter(pixmap) painter.setCompositionMode(composition_mode) painter.drawPixmap(0, 0, over_pixmap.width(), over_pixmap.height(), over_pixmap) painter.end()
def _render_svg(self, svg_path, replace_color=None): if issubclass(self._cls, QIcon) and not replace_color: return QIcon(svg_path) with open(svg_path, 'r+') as f: data_content = f.read() if replace_color is not None: data_content = data_content.replace('#555555', replace_color) self._render.load(QByteArray(data_content)) pix = QPixmap(128, 128) pix.fill(Qt.transparent) painter = QPainter(pix) self._render.render(painter) painter.end() if issubclass(self._cls, QPixmap): return pix else: return self._cls(pix)
def _setup_general_tab(self): general_widget = QWidget() general_layout = layouts.VerticalLayout(spacing=2, margins=(2, 2, 2, 2)) general_widget.setLayout(general_layout) self._themes_combobox = combobox.BaseComboBox(parent=self) all_themes = resources.get_all_resources_of_type( resources.ResourceTypes.THEME) for i, theme in enumerate(all_themes): accent_color_hex = theme.accent_color accent_color = color.Color.hex_to_qcolor( accent_color_hex[1:] if accent_color_hex. startswith('#') else accent_color_hex) background_color_hex = theme.background_color background_color = color.Color.hex_to_qcolor( background_color_hex[1:] if accent_color_hex. startswith('#') else background_color_hex) accent_color_pixmap = QPixmap(25, 25) background_color_pixmap = QPixmap(25, 25) accent_color_pixmap.fill(accent_color) background_color_pixmap.fill(background_color) color_pixmap = QPixmap(50, 25) painter = QPainter(color_pixmap) painter.drawPixmap(0, 0, 25, 25, accent_color_pixmap) painter.drawPixmap(25, 0, 25, 25, background_color_pixmap) painter.end() color_icon = QIcon(color_pixmap) self._themes_combobox.addItem(color_icon, theme.name()) general_layout.addWidget(self._themes_combobox) general_layout.addStretch() return general_widget
def pixmap(self, size, mode, state): pm = QPixmap(size) pm.fill(Qt.transparent) self.paint(QPainter(pm), QRect(QPoint(0, 0), size), mode, state) return pm
def create_drop_indicator_pixmap(palette, size, drop_area): border_color = palette.color(QPalette.Active, QPalette.Highlight) background_color = palette.color(QPalette.Active, QPalette.Base) area_background_color = palette.color(QPalette.Active, QPalette.Highlight).lighter(150) pm = QPixmap(size.width(), size.height()) pm.fill(QColor(0, 0, 0, 0)) painter = QPainter(pm) pen = painter.pen() base_rect = QRectF(pm.rect()) painter.fillRect(base_rect, background_color) painter.save() area_rect = QRectF() area_line = QLineF() gradient = QLinearGradient() if drop_area == DropArea.TopDropArea: area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width(), base_rect.height() * 0.5) area_line = QLineF(area_rect.bottomLeft(), area_rect.bottomRight()) gradient.setStart(area_rect.topLeft()) gradient.setFinalStop(area_rect.bottomLeft()) gradient.setColorAt(0, area_background_color) gradient.setColorAt(1, area_background_color.lighter(120)) elif drop_area == DropArea.RightDropArea: area_rect = QRectF(base_rect.width() * 0.5, base_rect.y(), base_rect.width() * 0.5, base_rect.height()) area_line = QLineF(area_rect.topLeft(), area_rect.bottomLeft()) gradient.setStart(area_rect.topLeft()) gradient.setFinalStop(area_rect.topRight()) gradient.setColorAt(0, area_background_color.lighter(120)) gradient.setColorAt(1, area_background_color) elif drop_area == DropArea.BottomDropArea: area_rect = QRectF(base_rect.x(), base_rect.height() * 0.5, base_rect.width(), base_rect.height() * 0.5) area_line = QLineF(area_rect.topLeft(), area_rect.topRight()) gradient.setStart(area_rect.topLeft()) gradient.setFinalStop(area_rect.bottomLeft()) gradient.setColorAt(0, area_background_color.lighter(120)) gradient.setColorAt(1, area_background_color) elif drop_area == DropArea.LeftDropArea: area_rect = QRectF(base_rect.x(), base_rect.y(), base_rect.width() * 0.5, base_rect.height()) area_line = QLineF(area_rect.topRight(), area_rect.bottomRight()) gradient.setStart(area_rect.topLeft()) gradient.setFinalStop(area_rect.topRight()) gradient.setColorAt(0, area_background_color) gradient.setColorAt(1, area_background_color.lighter(120)) if area_rect.isValid(): painter.fillRect(area_rect, gradient) pen = painter.pen() pen.setColor(border_color) pen.setStyle(Qt.DashLine) painter.setPen(pen) painter.drawLine(area_line) painter.restore() painter.save() pen = painter.pen() pen.setColor(border_color) pen.setWidth(1) painter.setPen(pen) painter.drawRect(base_rect.adjusted(0, 0, -pen.width(), -pen.width())) painter.restore() return pm
def paintEvent(self, event: QPaintEvent) -> None: p = QPainter(self) self.m_normalMap.render(p, event.rect()) p.setPen(Qt.black) p.drawText( self.rect(), Qt.AlignBottom | Qt.TextWordWrap, "Map data CCBYSA 2009 OpenStreetMap.org contributors", ) p.end() if self.zoomed: dim = min(self.width(), self.height()) magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3) radius = magnifierSize / 2 ring = radius - 15 box = QSize(magnifierSize, magnifierSize) if self.maskPixmap.size() != box: self.maskPixmap = QPixmap(box) self.maskPixmap.fill(Qt.transparent) g = QRadialGradient() g.setCenter(radius, radius) g.setFocalPoint(radius, radius) g.setRadius(radius) g.setColorAt(1.0, QColor(255, 255, 255, 0)) g.setColorAt(0.5, QColor(128, 128, 128, 255)) mask = QPainter(self.maskPixmap) mask.setRenderHint(QPainter.Antialiasing) mask.setCompositionMode(QPainter.CompositionMode_Source) mask.setBrush(g) mask.setPen(Qt.NoPen) mask.drawRect(self.maskPixmap.rect()) mask.setBrush(QColor(Qt.transparent)) mask.drawEllipse(g.center(), ring, ring) mask.end() center = self.dragPos - QPoint(0, radius) center = center + QPoint(0, radius / 2) corner = center - QPoint(radius, radius) xy = center * 2 - QPoint(radius, radius) # only set the dimension to the magnified portion if self.zoomPixmap.size() != box: zoomPixmap = QPixmap(box) zoomPixmap.fill(Qt.lightGray) if True: p = QPainter(zoomPixmap) p.translate(-xy) self.m_largeMap.render(p, QRect(xy, box)) p.end() clipPath = QPainterPath() clipPath.addEllipse(center, ring, ring) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) p.setClipPath(clipPath) p.drawPixmap(corner, zoomPixmap) p.setClipping(False) p.drawPixmap(corner, self.maskPixmap) p.setPen(Qt.gray) p.drawPath(clipPath) if self.invert: p = QPainter(self) p.setCompositionMode(QPainter.CompositionMode_Difference) p.fillRect(event.rect(), Qt.white) p.end()
class LightMaps(QWidget): def __init__(self, parent: QWidget = None) -> None: super().__init__(parent) self.m_normalMap = SlippyMap(self) self.m_largeMap = SlippyMap(self) self.m_normalMap.updated.connect(self.updateMap) self.m_largeMap.updated.connect(self.update) self.pressed = False self.snapped = False self.pressPos = QPoint() self.dragPos = QPoint() self.tapTimer = QBasicTimer() self.zoomed = False self.zoomPixmap = QPixmap() self.maskPixmap = QPixmap() self.invert = False def setCenter(self, lat: float, lng: float): self.m_normalMap.latitude = lat self.m_normalMap.longitude = lng self.m_normalMap.invalidate() self.m_largeMap.latitude = lat self.m_largeMap.longitude = lng self.m_largeMap.invalidate() @Slot() def toggleNightMode(self) -> None: self.invert = not self.invert self.update() def activateZoom(self) -> None: self.zoomed = True self.tapTimer.stop() self.m_largeMap.zoom = self.m_normalMap.zoom + 1 self.m_largeMap.width = self.m_normalMap.width * 2 self.m_largeMap.height = self.m_normalMap.height * 2 self.m_largeMap.latitude = self.m_normalMap.latitude self.m_largeMap.longitude = self.m_normalMap.longitude self.m_largeMap.invalidate() self.update() def resizeEvent(self, event: QResizeEvent) -> None: self.m_normalMap.width = self.width() self.m_normalMap.height = self.height() self.m_normalMap.invalidate() self.m_largeMap.width = self.m_normalMap.width * 2 self.m_largeMap.height = self.m_normalMap.height * 2 self.m_largeMap.invalidate() def paintEvent(self, event: QPaintEvent) -> None: p = QPainter(self) self.m_normalMap.render(p, event.rect()) p.setPen(Qt.black) p.drawText( self.rect(), Qt.AlignBottom | Qt.TextWordWrap, "Map data CCBYSA 2009 OpenStreetMap.org contributors", ) p.end() if self.zoomed: dim = min(self.width(), self.height()) magnifierSize = min(MAX_MAGNIFIER, dim * 2 / 3) radius = magnifierSize / 2 ring = radius - 15 box = QSize(magnifierSize, magnifierSize) if self.maskPixmap.size() != box: self.maskPixmap = QPixmap(box) self.maskPixmap.fill(Qt.transparent) g = QRadialGradient() g.setCenter(radius, radius) g.setFocalPoint(radius, radius) g.setRadius(radius) g.setColorAt(1.0, QColor(255, 255, 255, 0)) g.setColorAt(0.5, QColor(128, 128, 128, 255)) mask = QPainter(self.maskPixmap) mask.setRenderHint(QPainter.Antialiasing) mask.setCompositionMode(QPainter.CompositionMode_Source) mask.setBrush(g) mask.setPen(Qt.NoPen) mask.drawRect(self.maskPixmap.rect()) mask.setBrush(QColor(Qt.transparent)) mask.drawEllipse(g.center(), ring, ring) mask.end() center = self.dragPos - QPoint(0, radius) center = center + QPoint(0, radius / 2) corner = center - QPoint(radius, radius) xy = center * 2 - QPoint(radius, radius) # only set the dimension to the magnified portion if self.zoomPixmap.size() != box: zoomPixmap = QPixmap(box) zoomPixmap.fill(Qt.lightGray) if True: p = QPainter(zoomPixmap) p.translate(-xy) self.m_largeMap.render(p, QRect(xy, box)) p.end() clipPath = QPainterPath() clipPath.addEllipse(center, ring, ring) p = QPainter(self) p.setRenderHint(QPainter.Antialiasing) p.setClipPath(clipPath) p.drawPixmap(corner, zoomPixmap) p.setClipping(False) p.drawPixmap(corner, self.maskPixmap) p.setPen(Qt.gray) p.drawPath(clipPath) if self.invert: p = QPainter(self) p.setCompositionMode(QPainter.CompositionMode_Difference) p.fillRect(event.rect(), Qt.white) p.end() def timerEvent(self, event: QTimerEvent) -> None: if not self.zoomed: self.activateZoom() self.update() def mousePressEvent(self, event: QMouseEvent) -> None: if event.buttons() != Qt.LeftButton: return self.pressed = self.snapped = True self.pressPos = self.dragPos = event.pos() self.tapTimer.stop() self.tapTimer.start(HOLD_TIME, self) def mouseMoveEvent(self, event: QMouseEvent) -> None: if not event.buttons(): return if not self.zoomed: if not self.pressed or not self.snapped: delta = event.pos() - self.pressPos self.pressPos = event.pos() self.m_normalMap.pan(delta) return else: threshold = 10 delta = event.pos() - self.pressPos if self.snapped: self.snapped &= delta.x() < threshold self.snapped &= delta.y() < threshold self.snapped &= delta.x() > -threshold self.snapped &= delta.y() > -threshold if not self.snapped: self.tapTimer.stop() else: self.dragPos = event.pos() self.update() def mouseReleaseEvent(self, event: QMouseEvent) -> None: self.zoomed = False self.update() def keyPressEvent(self, event: QKeyEvent) -> None: if not self.zoomed: if event.key() == Qt.Key_Left: self.m_normalMap.pan(QPoint(20, 0)) if event.key() == Qt.Key_Right: self.m_normalMap.pan(QPoint(-20, 0)) if event.key() == Qt.Key_Up: self.m_normalMap.pan(QPoint(0, 20)) if event.key() == Qt.Key_Down: self.m_normalMap.pan(QPoint(0, -20)) if event.key() == Qt.Key_Z or event.key() == Qt.Key_Select: self.dragPos = QPoint(self.width() / 2, self.height() / 2) self.activateZoom() else: if event.key() == Qt.Key_Z or event.key() == Qt.Key_Select: self.zoomed = False self.update() delta = QPoint(0, 0) if event.key() == Qt.Key_Left: delta = QPoint(-15, 0) if event.key() == Qt.Key_Right: delta = QPoint(15, 0) if event.key() == Qt.Key_Up: delta = QPoint(0, -15) if event.key() == Qt.Key_Down: delta = QPoint(0, 15) if delta != QPoint(0, 0): self.dragPos += delta self.update() @Slot(QRect) def updateMap(self, r): self.update(r)
class SlippyMap(QObject): def __init__(self, parent: QObject = None) -> None: super().__init__(parent) self.width: int = 400 self.height: int = 300 self.zoom: int = 15 self.latitude: float = 59.9138204 self.longitude: float = 10.7387413 self.m_offset = QPoint() self.m_tilesRect = QRect() self.m_emptyTile = QPixmap(tdim, tdim) self.m_emptyTile.fill(Qt.lightGray) self.m_tilePixmaps: typing.Dict[QPointH, QPixmap] = dict() self.m_manager = QNetworkAccessManager() self.m_url = QUrl() cache = QNetworkDiskCache() cache.setCacheDirectory( QStandardPaths.writableLocation(QStandardPaths.CacheLocation)) self.m_manager.setCache(cache) self.m_manager.finished.connect(self.handleNetworkData) def invalidate(self) -> None: if self.width <= 0 or self.height <= 0: return ct = tileForCoordinate(self.latitude, self.longitude, self.zoom) tx = ct.x() ty = ct.y() # top-left corner of the center tile xp = self.width / 2 - (tx - math.floor(tx)) * tdim yp = self.height / 2 - (ty - math.floor(ty)) * tdim xa = (xp + tdim - 1) / tdim ya = (yp + tdim - 1) / tdim xs = int(tx) - xa ys = int(ty) - ya # offset for top-left tile self.m_offset = QPoint(xp - xa * tdim, yp - ya * tdim) # last tile vertical and horizontal xe = int(tx) + (self.width - xp - 1) / tdim ye = int(ty) + (self.height - yp - 1) / tdim # build a rect self.m_tilesRect = QRect(xs, ys, xe - xs + 1, ye - ys + 1) if self.m_url.isEmpty(): self.download() self.updated.emit(QRect(0, 0, self.width, self.height)) def render(self, painter: QPainter, rect: QRect) -> None: for x in range(self.m_tilesRect.width() + 1): for y in range(self.m_tilesRect.height() + 1): tp = QPoint(x + self.m_tilesRect.left(), y + self.m_tilesRect.top()) box = self.tileRect(tp) if rect.intersects(box): painter.drawPixmap( box, self.m_tilePixmaps.get(QPointH(tp), self.m_emptyTile)) def pan(self, delta: QPoint) -> None: dx = QPointF(delta) / float(tdim) center = tileForCoordinate(self.latitude, self.longitude, self.zoom) - dx self.latitude = latitudeFromTile(center.y(), self.zoom) self.longitude = longitudeFromTile(center.x(), self.zoom) self.invalidate() updated = Signal(QRect) @Slot(QNetworkReply) def handleNetworkData(self, reply: QNetworkReply) -> None: img = QImage() tp = reply.request().attribute(QNetworkRequest.User) if not reply.error(): if not img.load(reply, ""): img = QImage() reply.deleteLater() self.m_tilePixmaps[QPointH(tp)] = (self.m_emptyTile if img.isNull() else QPixmap.fromImage(img)) self.updated.emit(self.tileRect(tp)) # purge unused spaces bound = self.m_tilesRect.adjusted(-2, -2, 2, 2) self.m_tilePixmaps = { tp: pixmap for tp, pixmap in self.m_tilePixmaps.items() if bound.contains(tp) } self.download() @Slot() def download(self): grab = QPoint(0, 0) for x in range(self.m_tilesRect.width() + 1): for y in range(self.m_tilesRect.height() + 1): tp = self.m_tilesRect.topLeft() + QPoint(x, y) if QPointH(tp) not in self.m_tilePixmaps: grab = tp break if grab == QPoint(0, 0): self.m_url = QUrl() return path = "http://tile.openstreetmap.org/%d/%d/%d.png" self.m_url = QUrl(path % (self.zoom, grab.x(), grab.y())) request = QNetworkRequest() request.setUrl(self.m_url) request.setRawHeader(b"User-Agent", b"The Qt Company (Qt) Graphics Dojo 1.0") request.setAttribute(QNetworkRequest.User, grab) self.m_manager.get(request) def tileRect(self, tp: QPoint): t = tp - self.m_tilesRect.topLeft() x = t.x() * tdim + self.m_offset.x() y = t.y() * tdim + self.m_offset.y() return QRect(x, y, tdim, tdim)