Skip to content

visualdynamics.gui.glyphs

glyphs

Glyphs drawn from the package's own SVG files, without Qt's SVG module.

QtSvg is not in the set of Qt modules the project uses (AGENTS.md rule 3), and the one glyph so far, the drawer tab's chevron, is a six-vertex outline that needs no SVG renderer. Its vertices are read from the path and painted as a polygon, in the palette's color, at the screen's pixel ratio. When the design changes, the file is replaced.

The parser accepts only the subset the files are drawn in: absolute M, L and Z commands, straight edges, one path. Anything else raises ValueError instead of being drawn wrong.

Functions:

Name Description
polygon_of

The vertices of the single straight-edged path in an SVG, and the

glyph

An icon of a packaged glyph, filled with color, turned turn

drawer_glyph

The chevron on a drawer tab. It points away from edge

Functions:

polygon_of

polygon_of(svg: str) -> tuple[list[tuple[float, float]], float]

The vertices of the single straight-edged path in an SVG, and the side length of its square viewBox.

Raises ValueError for anything outside that subset: curves, relative commands, more than one path, a viewBox that is not square or not at the origin, or fewer than three vertices.

Source code in src/visualdynamics/gui/glyphs.py
def polygon_of(svg: str) -> tuple[list[tuple[float, float]], float]:
    """The vertices of the single straight-edged path in an SVG, and the
    side length of its square viewBox.

    Raises ValueError for anything outside that subset: curves, relative
    commands, more than one path, a viewBox that is not square or not at
    the origin, or fewer than three vertices.
    """
    box = re.search(r'viewBox="0 0 (\S+) (\S+)"', svg)
    if box is None or box.group(1) != box.group(2):
        raise ValueError('the glyph needs a square viewBox at the origin')
    paths = re.findall(r'<path\b[^>]*\bd="([^"]*)"', svg)
    if len(paths) != 1:
        raise ValueError(f'one path expected, {len(paths)} found')
    tokens = _TOKENS.findall(paths[0])
    vertices: list[tuple[float, float]] = []
    command = None
    while tokens:
        token = tokens.pop(0)
        if token.isalpha():
            if token not in 'MLZ':
                raise ValueError(f'path command {token!r} is not drawn: '
                                 'straight absolute edges only')
            command = token
            continue
        if command not in 'ML' or not tokens:
            raise ValueError('malformed path data')
        vertices.append((float(token), float(tokens.pop(0))))
    if len(vertices) < 3:
        raise ValueError('a polygon needs at least three vertices')
    return vertices, float(box.group(1))

glyph

glyph(name: str, color: QColor, size: int = 16, turn: float = 0) -> QIcon

An icon of a packaged glyph, filled with color, turned turn degrees clockwise about its center, size pixels on a side.

It is rendered at one and two device pixels per point so a Retina screen gets a sharp edge, and the icon uses whichever fits the screen.

Source code in src/visualdynamics/gui/glyphs.py
def glyph(name: str, color: QColor, size: int = 16,
          turn: float = 0) -> QIcon:
    """An icon of a packaged glyph, filled with `color`, turned `turn`
    degrees clockwise about its center, `size` pixels on a side.

    It is rendered at one and two device pixels per point so a Retina
    screen gets a sharp edge, and the icon uses whichever fits the
    screen.
    """
    vertices, side = _load(name)
    polygon = QPolygonF([QPointF(x, y) for x, y in vertices])
    icon = QIcon()
    for ratio in (1, 2):
        pixmap = QPixmap(size * ratio, size * ratio)
        pixmap.fill(Qt.GlobalColor.transparent)
        painter = QPainter(pixmap)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)
        painter.setPen(Qt.PenStyle.NoPen)
        painter.setBrush(color)
        painter.scale(size * ratio / side, size * ratio / side)
        painter.translate(side / 2, side / 2)
        painter.rotate(turn)
        painter.translate(-side / 2, -side / 2)
        painter.drawPolygon(polygon)
        painter.end()
        pixmap.setDevicePixelRatio(ratio)
        icon.addPixmap(pixmap)
    return icon

drawer_glyph

drawer_glyph(edge: str, open_: bool, color: QColor, size: int = 16) -> QIcon

The chevron on a drawer tab. It points away from edge ('bottom', 'top', 'left' or 'right') while the drawer is closed and toward it once open, which is the way a click will move the edge.

Source code in src/visualdynamics/gui/glyphs.py
def drawer_glyph(edge: str, open_: bool, color: QColor,
                 size: int = 16) -> QIcon:
    """The chevron on a drawer tab. It points away from `edge`
    ('bottom', 'top', 'left' or 'right') while the drawer is closed and
    toward it once open, which is the way a click will move the edge."""
    return glyph('drawer-tab', color, size,
                 _CLOSED_TURN[edge] + (180 if open_ else 0))