"""Draw a rounded border around any widget with a Cairo DrawingArea overlay. This GTK build's renderer does not paint CSS border/background nodes on plain container widgets (Box/Frame) — only on buttons/entries — but it renders Cairo draw funcs and textures fine (the map image proves it). So module 'borders' are drawn explicitly here instead of via CSS. """ from __future__ import annotations import math import gi gi.require_version("Gtk", "4.0") from gi.repository import Gtk # noqa: E402 # CyberQueer accent/violet (matches @accent/@violet / COLOR_HIGHLIGHT/COLOR_DARK # in colors.conf). ACCENT = (0xE4 / 255, 0x00 / 255, 0x46 / 255) VIOLET = (0x50 / 255, 0x18 / 255, 0xDD / 255) # Module fills are translucent violet rather than solid gray/black — lets the # hologram overlay's scanlines/noise (drawn above, on window.py's overlay) and # the desktop behind the panel both read through, so the whole thing looks # like projected light/glass instead of an opaque card. FILL_COLOR = VIOLET FILL_ALPHA = 0.34 def _rounded_rect(cr, x, y, w, h, r) -> None: r = min(r, w / 2, h / 2) cr.new_sub_path() cr.arc(x + w - r, y + r, r, -math.pi / 2, 0) cr.arc(x + w - r, y + h - r, r, 0, math.pi / 2) cr.arc(x + r, y + h - r, r, math.pi / 2, math.pi) cr.arc(x + r, y + r, r, math.pi, 3 * math.pi / 2) cr.close_path() # Soft outer glow around the border ring: Cairo has no native blur, so this is # the usual poor-man's bloom — the same crisp stroke redrawn a few times at # increasing width and decreasing alpha, underneath the final crisp line. _GLOW_LAYERS = [(10, 0.05), (6, 0.09), (3, 0.15)] def _make_draw(border: int, radius: int, color, fill_bg: bool, glow: bool): def draw(_area, cr, w, h, *_a) -> None: inset = border / 2 r, g, b = color if glow: for extra_w, alpha in _GLOW_LAYERS: _rounded_rect(cr, inset, inset, w - border, h - border, radius) cr.set_source_rgba(r, g, b, alpha) cr.set_line_width(border + extra_w) cr.stroke() _rounded_rect(cr, inset, inset, w - border, h - border, radius) if fill_bg: cr.set_source_rgba(*FILL_COLOR, FILL_ALPHA) cr.fill_preserve() cr.set_source_rgb(*color) cr.set_line_width(border) cr.stroke() return draw def bordered(child: Gtk.Widget, border: int = 3, radius: int = 16, color=ACCENT, fill_bg: bool = False, glow: bool = True) -> Gtk.Overlay: """Wrap child in an overlay whose background is a drawn rounded border — with a soft holographic glow around it by default, matching orbit-menu/ horizon-dock's aesthetic. The DrawingArea is the overlay's main child (drawn first, behind); the content is an overlay child on top and drives the size. A small margin keeps the content clear of the drawn border ring. """ overlay = Gtk.Overlay() area = Gtk.DrawingArea() area.set_draw_func(_make_draw(border, radius, color, fill_bg, glow)) overlay.set_child(area) # background: the border ring child.set_margin_start(border + 4) child.set_margin_end(border + 4) child.set_margin_top(border + 4) child.set_margin_bottom(border + 4) overlay.add_overlay(child) # content on top overlay.set_measure_overlay(child, True) # size the overlay to the content return overlay