Icon in document tree

This commit is contained in:
2026-07-27 15:15:13 +02:00
parent 54788583a4
commit a4daaa8798
5 changed files with 191 additions and 23 deletions

View File

@@ -1,10 +1,13 @@
from __future__ import annotations
from PySide6.QtCore import QRectF
from PySide6.QtCore import QRectF, QSize, Qt
from PySide6.QtGui import QBrush, QColor, QFont, QIcon, QPainter, QPen, QPixmap
from bedit_gui.models import Icon, Line, Rectangle, Text
from bedit_core.models import Port, PortID, SignalDirection
from bedit_gui.models import Icon, Line, LineType, Rectangle, Text
PORT_SIZE = 16
DEFAULT_ICON_SIZE = QSize(48, 48)
def get_bounding_box(icon: Icon) -> QRectF:
@@ -30,3 +33,64 @@ def get_bounding_box(icon: Icon) -> QRectF:
right = max(point[0] for point in points)
bottom = max(point[1] for point in points)
return QRectF(left, top, right - left, bottom - top)
def render_icon(icon: Icon, ports: dict[PortID, Port], size: QSize = DEFAULT_ICON_SIZE, render_ports: bool = False) -> QIcon:
pixmap = QPixmap(size)
pixmap.fill(Qt.GlobalColor.transparent)
bounds = get_bounding_box(icon)
if not icon.shapes and not icon.port_positions:
return QIcon(pixmap)
available_width = max(1, size.width() - 4)
available_height = max(1, size.height() - 4)
scale = min(available_width / max(1, bounds.width()), available_height / max(1, bounds.height()))
painter = QPainter(pixmap)
painter.setRenderHint(QPainter.RenderHint.Antialiasing)
painter.translate(size.width() / 2, size.height() / 2)
painter.scale(scale, scale)
painter.translate(-bounds.center())
for shape in sorted(icon.shapes.values(), key=lambda item: item.layer):
if isinstance(shape, Rectangle):
painter.setPen(_line_pen(shape.line_type, shape.line_thickness, shape.line_color))
painter.setBrush(QBrush(_color(shape.fill_color)))
painter.drawRoundedRect(QRectF(shape.pos[0], shape.pos[1], shape.width, shape.height), shape.corner_radius, shape.corner_radius)
elif isinstance(shape, Text):
font = QFont()
font.setPixelSize(max(1, round(shape.size)))
font.setBold(shape.bold)
font.setItalic(shape.italic)
painter.setFont(font)
painter.setPen(_color(shape.color))
painter.drawText(QRectF(shape.pos[0], shape.pos[1], shape.width, shape.height), Qt.AlignmentFlag.AlignCenter | Qt.TextFlag.TextWordWrap, shape.text)
elif isinstance(shape, Line):
painter.setPen(_line_pen(shape.line_type, shape.line_thickness, shape.line_color))
painter.drawLine(shape.pos[0], shape.pos[1], shape.end[0], shape.end[1])
if render_ports:
painter.setPen(QPen(QColor("#000000")))
for port_id, position in icon.port_positions.items():
port = ports.get(port_id)
if port is None:
continue
color = QColor("#000000") if port.direction is SignalDirection.INPUT else QColor("#ffffff")
painter.setBrush(QBrush(color))
painter.drawRect(position[0], position[1], PORT_SIZE, PORT_SIZE)
painter.end()
return QIcon(pixmap)
def _line_pen(line_type: LineType, thickness: float, color: str) -> QPen:
styles = {LineType.SOLID: Qt.PenStyle.SolidLine, LineType.DASHED: Qt.PenStyle.DashLine, LineType.DOTTED: Qt.PenStyle.DotLine, LineType.DASH_DOT: Qt.PenStyle.DashDotLine}
if line_type is LineType.NONE:
return QPen(Qt.PenStyle.NoPen)
return QPen(_color(color), thickness, styles[line_type])
def _color(value: str) -> QColor:
color = value.removeprefix("#")
if len(color) == 8:
return QColor(int(color[0:2], 16), int(color[2:4], 16), int(color[4:6], 16), int(color[6:8], 16))
return QColor(value)