def _get_color(self, color: Color) -> qg.QColor: qt_color = self._color_cache.get(color, None) if qt_color is None: if len(color) == 7: qt_color = qg.QColor(color) # '#RRGGBB' elif len(color) == 9: rgb = color[1:7] alpha = color[7:9] qt_color = qg.QColor(f"#{alpha}{rgb}") # '#AARRGGBB' else: raise TypeError(color) self._color_cache[color] = qt_color return qt_color
def _get_brush(self, properties: Properties) -> qg.QBrush: filling = properties.filling if filling: if filling.type == filling.PATTERN: if ( self.config.hatch_policy == HatchPolicy.SHOW_APPROXIMATE_PATTERN ): # Default pattern scaling is not supported by PyQt: key: PatternKey = (filling.name, filling.angle) qt_pattern = self._pattern_cache.get(key) # type: ignore if qt_pattern is None: qt_pattern = self._get_qt_pattern(filling.pattern) self._pattern_cache[key] = qt_pattern elif self.config.hatch_policy == HatchPolicy.SHOW_SOLID: qt_pattern = qc.Qt.SolidPattern # type: ignore elif self.config.hatch_policy == HatchPolicy.SHOW_OUTLINE: return self._no_fill else: raise ValueError(self.config.hatch_policy) else: qt_pattern = qc.Qt.SolidPattern # type: ignore return qg.QBrush(self._get_color(properties.color), qt_pattern) # type: ignore else: return self._no_fill
def draw_path(self, path: Path, properties: Properties, z=0): qt_path = qg.QPainterPath() _extend_qt_path(qt_path, path) return self.scene.addPath( qt_path, self.get_pen(properties), self.no_fill, )
def drawForeground(self, painter: qg.QPainter, rect: qc.QRectF) -> None: if self._is_loading and self._loading_overlay: painter.save() painter.fillRect(rect, qg.QColor("#aa000000")) painter.setWorldMatrixEnabled(False) r = self.viewport().rect() painter.setBrush(qc.Qt.NoBrush) painter.setPen(qc.Qt.white) painter.drawText(r.center(), "Loading...") painter.restore()
def _get_qfont(font: fonts.FontFace) -> Optional[qg.QFont]: qfont = None if font: family = font.family italic = "italic" in font.style.lower() weight = _map_weight(font.weight) qfont = qg.QFont(family, weight=weight, italic=italic) # INFO: setting the stretch value makes results worse! # qfont.setStretch(_map_stretch(font.stretch)) return qfont
def _matrix_to_qtransform(matrix: Matrix44) -> qg.QTransform: """Qt also uses row-vectors so the translation elements are placed in the bottom row. This is only a simple conversion which assumes that although the transformation is 4x4,it does not involve the z axis. A more correct transformation could be implemented like so: https://stackoverflow.com/questions/10629737/convert-3d-4x4-rotation-matrix-into-2d """ return qg.QTransform(*matrix.get_2d_transformation())
def draw_filled_polygon( self, points: Iterable[Vec3], properties: Properties ) -> None: brush = self._get_brush(properties) polygon = qg.QPolygonF() for p in points: polygon.append(qc.QPointF(p.x, p.y)) item = _CosmeticPolygon(polygon) item.setPen(self._no_line) item.setBrush(brush) self._scene.addItem(item) self._set_item_data(item)
def set_app_icon(app): from ezdxf.addons.xqt import QtGui, QtCore app_icon = QtGui.QIcon() p = resources_path() app_icon.addFile(str(p / "16x16.png"), QtCore.QSize(16, 16)) app_icon.addFile(str(p / "24x24.png"), QtCore.QSize(24, 24)) app_icon.addFile(str(p / "32x32.png"), QtCore.QSize(32, 32)) app_icon.addFile(str(p / "48x48.png"), QtCore.QSize(48, 48)) app_icon.addFile(str(p / "64x64.png"), QtCore.QSize(64, 64)) app_icon.addFile(str(p / "256x256.png"), QtCore.QSize(256, 256)) app.setWindowIcon(app_icon)
def get_text_path(self, text: str, font: qg.QFont) -> qg.QPainterPath: # None is the default font key = font.key() if font is not None else None cache = self._text_path_cache[key] # defaultdict(dict) path = cache.get(text, None) if path is None: if font is None: font = self._default_font path = qg.QPainterPath() path.addText(0, 0, font, text) if self._use_cache: cache[text] = path return path
def __init__( self, scene: Optional[qw.QGraphicsScene] = None, *, use_text_cache: bool = True, debug_draw_rect: bool = False, extra_lineweight_scaling: float = 2.0, ): """ Args: extra_lineweight_scaling: compared to other backends, PyQt draws lines which appear thinner """ super().__init__() self._scene = scene or qw.QGraphicsScene() # avoids many type errors self._color_cache: Dict[Color, qg.QColor] = {} self._pattern_cache: Dict[PatternKey, int] = {} self._no_line = qg.QPen(qc.Qt.NoPen) self._no_fill = qg.QBrush(qc.Qt.NoBrush) self._text_renderer = TextRenderer(qg.QFont(), use_text_cache) self._line_renderer: PyQtLineRenderer self._extra_lineweight_scaling = extra_lineweight_scaling self._debug_draw_rect = debug_draw_rect
def _get_pen(self, properties: Properties) -> qg.QPen: """Returns a cosmetic pen with applied lineweight but without line type support. """ px = ( properties.lineweight / 0.3527 * self.config.lineweight_scaling * self._extra_lineweight_scaling ) pen = qg.QPen(self._get_color(properties.color), px) # Use constant width in pixel: pen.setCosmetic(True) pen.setJoinStyle(qc.Qt.RoundJoin) return pen
def make_action( self, name, slot, *, shortcut: str = "", icon_name: str = "", tip: str = "", ) -> QAction: action = QAction(name, self) if shortcut: action.setShortcut(shortcut) if icon_name: icon = QtGui.QIcon(str(self.resource_path / icon_name)) action.setIcon(icon) if tip: action.setToolTip(tip) action.triggered.connect(slot) return action
def draw_path(self, path, properties: Properties, z=0): pattern = self.pattern(properties) pen = self.get_pen(properties) if len(pattern) < 2: qt_path = qg.QPainterPath() _extend_qt_path(qt_path, path) return self.scene.addPath(qt_path, pen, self.no_fill) else: add_line = self.scene.addLine renderer = EzdxfLineTypeRenderer(pattern) segments = renderer.line_segments( path.flattening( self._config.max_flattening_distance, segments=16 ) ) return [ add_line(s.x, s.y, e.x, e.y, pen) for s, e in segments # PyQt has problems with very short lines: if not s.isclose(e) ]
def draw_filled_paths( self, paths: Iterable[Path], holes: Iterable[Path], properties: Properties, ) -> None: qt_path = qg.QPainterPath() for path in paths: try: path = path.counter_clockwise() except ValueError: # cannot detect path orientation continue _extend_qt_path(qt_path, path) for path in holes: try: path = path.clockwise() except ValueError: # cannot detect path orientation continue _extend_qt_path(qt_path, path) item = _CosmeticPath(qt_path) item.setPen(self._get_pen(properties)) item.setBrush(self._get_brush(properties)) self._scene.addItem(item) self._set_item_data(item)
def drawForeground(self, painter: qg.QPainter, rect: qc.QRectF) -> None: super().drawForeground(painter, rect) if self._selected_items: item = self._selected_items[self._selected_index] r = item.sceneTransform().mapRect(item.boundingRect()) painter.fillRect(r, qg.QColor(0, 255, 0, 100))
def set_background(self, color: Color): self._scene.setBackgroundBrush(qg.QBrush(self._get_color(color)))
def draw_point(self, pos: Vec3, properties: Properties) -> None: """Draw a real dimensionless point.""" brush = qg.QBrush(self._get_color(properties.color), qc.Qt.SolidPattern) item = _Point(pos.x, pos.y, brush) self._set_item_data(item) self._scene.addItem(item)
def __init__(self, x: float, y: float, brush: qg.QBrush): super().__init__() self.location = qc.QPointF(x, y) self.radius = 1.0 self.setPen(qg.QPen(qc.Qt.NoPen)) self.setBrush(brush)