Replace Python layout prototype with editable playground

This commit is contained in:
ajp_anton
2026-08-20 23:27:42 +00:00
parent 1d5bcb4e39
commit 07c3444642
6 changed files with 753 additions and 0 deletions
+139
View File
@@ -0,0 +1,139 @@
"""Tk renderer for the status-bar layout playground."""
from __future__ import annotations
import tkinter as tk
from tkinter import font as tkfont
from typing import Iterable
from statusbar_lab import CameraCutout, Container, IconContainer, StatusBarLab, rectangles_overlap
TYPE_COLOURS = {
"clock": "#9fd7ff",
"notification": "#a7efaa",
"status": "#ffd596",
"chip": "#e2b0ff",
"carrier": "#ffb4c4",
}
def render(
lab: StatusBarLab,
statusbar_width: float,
statusbar_height: float,
render_scale: float = 1.0,
vertical_scale: float = 2.0,
margin: int = 40,
) -> None:
root = tk.Tk()
root.title("StatusBarTweak layout playground")
width = int(statusbar_width * render_scale + margin * 2)
height = int(statusbar_height * vertical_scale + margin * 2)
canvas = tk.Canvas(root, width=width, height=height, bg="#242424", highlightthickness=0)
canvas.pack()
def point(x: float, y: float) -> tuple[float, float]:
return margin + x * render_scale, margin + (statusbar_height - y) * vertical_scale
left, bottom = point(0, 0)
right, top = point(statusbar_width, statusbar_height)
canvas.create_rectangle(left, top, right, bottom, fill="white", outline="#4a4a4a", width=5)
containers = lab.render_containers()
for container in containers:
_draw_container(canvas, point, container, render_scale, vertical_scale)
_draw_overlaps(canvas, point, containers)
for camera in lab.cameras:
_draw_camera(canvas, point, camera)
root.mainloop()
def _draw_container(canvas: tk.Canvas, point, container: Container, render_scale: float, vertical_scale: float) -> None:
if isinstance(container, IconContainer):
_draw_icons(canvas, point, container)
return
x1, y1 = point(container.left, container.bottom)
x2, y2 = point(container.right, container.top)
canvas.create_rectangle(x1, y2, x2, y1, fill=TYPE_COLOURS[container.kind], outline="black", width=1)
_draw_clipped_text(canvas, container.text, x1 + 3, (y1 + y2) / 2, max(0, x2 - x1 - 6), container.height * vertical_scale)
def _draw_icons(canvas: tk.Canvas, point, container: IconContainer) -> None:
colour = TYPE_COLOURS[container.kind]
if not container.segments():
x, y1 = point(container.left, container.bottom)
_, y2 = point(container.left, container.top)
canvas.create_line(x, y1, x, y2, fill="black", width=1)
return
cursor = container.left
for segment_kind, icon_id, segment_width in container.segments():
x1, y1 = point(cursor, container.bottom)
x2, y2 = point(cursor + segment_width, container.top)
if segment_kind == "gap":
cursor += segment_width
continue
if segment_kind == "dot":
canvas.create_rectangle(x1, y2, x2, y1, fill=colour, outline="black", width=1)
radius = min(abs(x2 - x1), abs(y1 - y2)) * 0.24
cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
canvas.create_oval(cx - radius, cy - radius, cx + radius, cy + radius, fill="black", outline="black")
else:
canvas.create_rectangle(x1, y2, x2, y1, fill=colour, outline="black", width=1)
_draw_clipped_text(canvas, str(icon_id), (x1 + x2) / 2, (y1 + y2) / 2, abs(x2 - x1) - 2, abs(y1 - y2), anchor="center")
cursor += segment_width
def _draw_camera(canvas: tk.Canvas, point, camera: CameraCutout) -> None:
x1, y1 = point(camera.left, camera.bottom)
x2, y2 = point(camera.right, camera.top)
canvas.create_rectangle(x1, y2, x2, y1, fill="black", outline="black")
def _draw_overlaps(canvas: tk.Canvas, point, containers: Iterable[Container]) -> None:
items = list(containers)
for index, first in enumerate(items):
for second in items[index + 1:]:
if first.kind == "clock" and second.kind == "clock":
continue
if not rectangles_overlap(first.bounds, second.bounds):
continue
left = max(first.left, second.left)
right = min(first.right, second.right)
bottom = max(first.bottom, second.bottom)
top = min(first.top, second.top)
x1, y1 = point(left, bottom)
x2, y2 = point(right, top)
canvas.create_rectangle(x1, y2, x2, y1, fill="red", outline="red")
radius = max(abs(x2 - x1), abs(y1 - y2)) / 2 + 12
cx, cy = (x1 + x2) / 2, (y1 + y2) / 2
canvas.create_oval(cx - radius, cy - radius, cx + radius, cy + radius, outline="red", width=3)
def _draw_clipped_text(
canvas: tk.Canvas,
text: str,
x: float,
y: float,
width: float,
height: float,
anchor: str = "w",
) -> None:
if width <= 0:
return
size = max(7, int(height * 0.42))
text_font = tkfont.Font(family="TkDefaultFont", size=size)
clipped = _clip_text(text_font, text, width)
canvas.create_text(x, y, text=clipped, font=text_font, fill="black", anchor=anchor)
def _clip_text(text_font: tkfont.Font, text: str, width: float) -> str:
if text_font.measure(text) <= width:
return text
ellipsis = "..."
while text and text_font.measure(text + ellipsis) > width:
text = text[:-1]
return text + ellipsis if text else ""