Widget system Phase 4a: widget CRUD + grid placement UI
Adds the actual "Android home screen" placement experience: a new Layout tab with a pointer-driven canvas for dragging/resizing widgets and adding new ones from a type picker. Backed by a new routers/api_widgets.py (create/move/delete), which re-validates bounds, minimum footprint, and no-overlap server-side regardless of what the client already checked. A widget added without an explicit position lands in the first open space that fits it (grid.find_open_rect), so users don't have to hunt for empty space themselves. Also fixes a real latent bug this surfaced: changing a frame's orientation swaps the widget grid's long/short axis, which left existing widget placements out of bounds on the new grid with no render-time safeguard. Orientation changes now reset the layout to a single full-panel widget (keeping the first widget's type, dropping the rest), with a client-side confirm before it happens.
This commit is contained in:
@@ -65,6 +65,21 @@ def overlaps(a: Rect, b: Rect) -> bool:
|
||||
return ax < bx + bw and bx < ax + aw and ay < by + bh and by < ay + ah
|
||||
|
||||
|
||||
def find_open_rect(orientation: str, existing: list[Rect], w: int, h: int) -> Rect | None:
|
||||
"""First w x h rect that's in-bounds and doesn't overlap any of
|
||||
`existing`, scanning row-major (top-left first) -- used when creating
|
||||
a widget without an explicit placement (see routers/api_widgets.py),
|
||||
so adding one from a type picker doesn't require the caller to find
|
||||
empty space itself first. None if no such rect fits anywhere."""
|
||||
cols, rows = grid_dims(orientation)
|
||||
for y in range(rows - h + 1):
|
||||
for x in range(cols - w + 1):
|
||||
candidate = (x, y, w, h)
|
||||
if not any(overlaps(candidate, other) for other in existing):
|
||||
return candidate
|
||||
return None
|
||||
|
||||
|
||||
def cell_to_pixels(orientation: str, panel_w: int, panel_h: int, rect: Rect) -> tuple[int, int, int, int]:
|
||||
"""Grid rect -> pixel rect in logical (pre-rotation) canvas space --
|
||||
against image_pipeline.logical_render_size(orientation)'s own
|
||||
|
||||
Reference in New Issue
Block a user