"""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)