Files
statusbartweak/python/playground.py
T

187 lines
6.4 KiB
Python

"""Editable status-bar layout playground.
Run from this directory with ``python3 playground.py``. Everything below is
intended to be edited freely; the model and renderer live in separate files.
Coordinates use the same convention as the module's layout solver:
horizontal zero is the status bar's left edge and vertical zero is its bottom.
"""
from statusbar_lab import StatusBarLab, containers_overlap, vertically_overlaps
from statusbar_renderer import render
# ---------------------------------------------------------------------------
# Virtual status-bar settings
# ---------------------------------------------------------------------------
STATUSBAR_WIDTH = 1200
STATUSBAR_HEIGHT = 100
# These are inputs for the algorithm you will write. The playground itself
# does not apply them automatically.
EDGE_PADDING = 0
CONTAINER_PADDING = 8
CAMERA_PADDING = 0
TEXT_HORIZONTAL_PADDING = 6
ICON_DOT_GAP = 0
DOT_WIDTH_FACTOR = 0.75
# Keep these in the same terms as the module settings. They are intentionally
# passive until the positioning/truncation algorithm below uses them.
CONTAINER_ORDER = ["clock", "chip", "carrier", "notification", "status"]
SHRINK_ORDER = ["notification", "status", "chip", "carrier"]
# Rendering scale only affects the visualizer, never the simulated geometry.
RENDER_SCALE = 1.0
VERTICAL_RENDER_SCALE = 2.0
# ---------------------------------------------------------------------------
# Scenario API
# ---------------------------------------------------------------------------
LAB = StatusBarLab()
# These lists remain valid when items are added. Clock text lines belong to
# one CLOCK group because the group moves them by their relative x offsets.
CLOCK = LAB.clock
CLOCK_LINES = CLOCK.lines
NOTIFICATIONS = LAB.notifications
STATUSES = LAB.statuses
CHIPS = LAB.chips
CARRIERS = LAB.carriers
CAMERAS = LAB.cameras
def _sync_settings() -> None:
LAB.text_horizontal_padding = TEXT_HORIZONTAL_PADDING
LAB.icon_dot_gap = ICON_DOT_GAP
LAB.dot_width_factor = DOT_WIDTH_FACTOR
def AddClock(
text: str,
height: float,
vertical_offset: float = 0,
horizontal_offset: float = 0,
position: str = "left",
cutout_side: str = "left",
):
"""Add one text line to the single movable CLOCK group.
Horizontal offsets are normalized relative to all clock lines. Therefore
offsets ``5, 10, -20`` produce the same clock geometry as ``105, 110, 80``.
``position`` is ``left``, ``middle`` or ``right``; ``cutout_side`` is the
fallback side for a middle clock when a camera splits the status bar.
"""
_sync_settings()
return CLOCK.add_line(text, height, vertical_offset, horizontal_offset, position, cutout_side)
def AddNotification(
height: float,
vertical_offset: float = 0,
position: str = "left",
cutout_side: str = "left",
direction: str = "right",
):
_sync_settings()
return LAB.add_notification(height, vertical_offset, position, cutout_side, direction)
def SetNotificationIcons(number_of_notifications: int) -> None:
"""Replace the notification-icon pool and empty every notification container."""
LAB.configure_notification_icons(number_of_notifications)
def AddStatus(
height: float,
vertical_offset: float = 0,
position: str = "right",
cutout_side: str = "right",
direction: str = "left",
):
_sync_settings()
return LAB.add_status(height, vertical_offset, position, cutout_side, direction)
def SetStatusIcons(number_of_icons: int, widths: list[float] | None = None) -> None:
"""Replace the status-icon pool and empty every status container.
Missing widths are padded using the first status container's height. Add
status containers before calling this function when relying on that default.
"""
LAB.configure_status_icons(number_of_icons, widths or [])
def AddChip(
text: str,
height: float,
vertical_offset: float = 0,
position: str = "left",
cutout_side: str = "left",
):
_sync_settings()
return LAB.add_chip(text, height, vertical_offset, position, cutout_side)
def AddCarrier(
text: str,
height: float,
vertical_offset: float = 0,
position: str = "left",
cutout_side: str = "left",
):
_sync_settings()
return LAB.add_carrier(text, height, vertical_offset, position, cutout_side)
def AddCamera(width: float, height: float, horizontal_position: float, vertical_position: float):
return LAB.add_camera(width, height, horizontal_position, vertical_position)
# ---------------------------------------------------------------------------
# Simulated app settings: add or remove as many containers as you need.
# ---------------------------------------------------------------------------
AddClock("12:34:56", height=40, vertical_offset=0, horizontal_offset=0)
AddClock("Mon, 1 Jan", height=24, vertical_offset=42, horizontal_offset=10)
AddNotification(height=32, vertical_offset=0)
AddNotification(height=32, vertical_offset=40)
SetNotificationIcons(8)
AddStatus(height=30, vertical_offset=0)
AddStatus(height=30, vertical_offset=38)
SetStatusIcons(6, [20, 30, 30, 45])
AddChip("Navigation 12:34", height=38, vertical_offset=0)
AddCarrier("Example carrier", height=30, vertical_offset=45)
AddCamera(width=90, height=100, horizontal_position=555, vertical_position=0)
# ---------------------------------------------------------------------------
# Positioning and truncation algorithm
# ---------------------------------------------------------------------------
# All containers currently start at horizontal position zero. Add your layout
# algorithm here. Useful operations include:
#
# CLOCK.set_left(EDGE_PADDING)
# NOTIFICATIONS[0].set_right(STATUSBAR_WIDTH - EDGE_PADDING)
# CHIPS[0].set_width(120) # clock widths cannot be overridden
# NOTIFICATIONS[0].add_icons(3) # takes IDs from the shared pool
# NOTIFICATIONS[0].return_icons(1) # returns the newest assigned ID
# NOTIFICATIONS[0].set_dot(True)
# CLOCK.right_edge_between(10, 50) # ignores clock lines outside this band
# containers_overlap(CLOCK, CHIPS[0])
# vertically_overlaps(NOTIFICATIONS[0].bounds, CHIPS[0].bounds)
# Keep the renderer call at the end so the editable scenario and algorithm stay
# together above it.
_sync_settings()
render(LAB, STATUSBAR_WIDTH, STATUSBAR_HEIGHT, RENDER_SCALE, VERTICAL_RENDER_SCALE)