chat: dockable-panel layout foundation (mouse resize/dock — RFC, coordinating with your interface work)#419
Conversation
|
yeah, i would love to test this new idea, so if its not a problem, pls do the follow up of 1 and 2 for now:
|
The load-bearing core for a mouse-driven, dockable home layout: a pure,
fully-tested model with no UI wiring yet.
- DockPanel (room rail + visualizer/music/bonsai/lobby), DockSide, and a
PanelSlot { side, weight, enabled }; DockLayout holds the ordered slots
plus the two column widths, with a default matching today's layout.
- frame(area) computes the left/centre/right column rects and stacks each
side's panels by weight; columns clamp to a min/max and never eat the
centre.
- hit(point) classifies a mouse point as a column divider, a panel header
(drag to move), or a panel body; drop_zone(point) picks the side + the
panel a drag would land above; resize()/dock() apply clamped edits.
Seven unit tests cover the geometry, resize clamps, cross-side docking,
hit-testing, and drop-zone selection. Nothing renders from it yet, so it's
additive and safe. cargo test / clippy / fmt green.
Signed-off-by: Tony Hosaroygard <tasmaniamate@gmail.com>
Wire the tested dock layout (common/dock.rs) into the live home screen, the follow-up asked for on mpiorowski#419: 1. The home's two side columns now take their widths from DockLayout instead of the hardcoded 24. The default is 24/24, so the render is byte-identical until a divider is moved. 2. A drag state machine on the existing MouseEventKind::{Down,Drag,Up} path: pressing a column border grabs its divider, dragging resizes the column live (clamped so the centre chat is never squeezed away), and release ends it. Reuses the model's hit()/resize(); the column rects are recorded each frame like the pet-strip click targets. Session-only for now - per-user persistence (step 3) is still to come. Signed-off-by: Tony Hosaroygard <tasmaniamate@gmail.com>
329e58d to
fbf03e6
Compare
|
Thanks Mat — pushed the follow-up for 1 and 2 (rebased onto current 1. The home now renders from 2. A drag state machine on the existing Scope note (so nothing surprises you): this slice is the column-resize half of the drag. I deliberately held back cross-side panel docking (dragging the bonsai header over to the left) — the right sidebar's contents come from your configurable Session-only for now; per-user persistence (3) is still to come whenever you want it.
|
Step 3 of the dockable-panel work (mpiorowski#419): the resized layout now survives reconnects. - late-core stores the layout under a home_dock_layout settings key (extract_home_dock_layout / set_home_dock_layout); the blob is opaque to the core, keyed by the SSH client. - DockLayout gains to_value()/from_value() using the stable panel/side keys, so the JSON survives enum reordering. from_value() is defensive: unknown panels are skipped, missing ones are filled from the default (so a new panel is never hidden by an old save), bad widths fall back. - The layout is seeded from the user's settings at session start and persisted fire-and-forget when a resize drag settles. - Render now clamps the column widths to the live area, so a layout saved on a wide terminal can never squeeze the centre chat on a narrow one (the default 24 is unchanged on normal widths). Signed-off-by: Tony Hosaroygard <tasmaniamate@gmail.com>
|
And 3 — per-user persistence is in too, so the whole thing round-trips now:
|
Thanks @mpiorowski! Opened this early to coordinate — I saw you mention your next PR is interface-related, and I'm building mouse-driven dockable panels for the home screen (drag a divider to resize a column; later, drag a panel's header to move it to the other side / reorder — including sending the bonsai over to the left). It started as just the tested model; per your steer below it now also renders from that model and does live divider-resize (steps 1 & 2).
What's here
A pure, self-contained layout model —
late-ssh/src/app/common/dock.rs— now wired into the live home screen:DockLayout= the movable panels (room rail + visualizer / music / bonsai / lobby), each with a side, a height weight, and enabled — plus the two column widths. Itsdefault()matches today's layout exactly.frame(area)computes the left/centre/right column rects and stacks each side's panels by weight; columns clamp to a min/max and can never squeeze the centre chat away.hit(point)classifies a mouse point as a column divider (→ resize), a panel header (→ drag to move), or a body;drop_zone(point)picks the side + the panel a drag would land above;resize()/dock()apply clamped edits.Now wired (steps 1 & 2)
DockLayout. The two side columns take their widths from the model instead of the hardcoded24; default is 24/24, so the render is byte-identical until a divider is dragged — zero behaviour change out of the box.MouseEventKind::{Down,Drag,Up}path. Grab a column border and drag to resize the room rail or the right sidebar live, clamped so the centre chat can never be squeezed away. Reuses the model'shit()/resize(); the column rects are recorded each frame like the existing pet-strip click targets.Scope note: this is the column-resize half of the drag. Cross-side panel docking (dragging the bonsai header over to the left) is held back on purpose — the right sidebar's contents come from your configurable
right_sidebar_componentslist, so making panels physically movable means reconciling that with the dock model, and I didn't want to change sidebar behaviour under your interface work. It's the natural next slice.users.settingsunder one opaquehome_dock_layoutkey (no migration);DockLayout::to_value()/from_value()use the stable panel/side keys and defensively fill any missing panel from the default. Seeded at session start, saved fire-and-forget when a resize settles. Render also clamps widths to the live area so a wide-terminal save can't squeeze the centre on a narrow one.Still to come
right_sidebar_componentsreconciliation is agreed.Tests
The dock model has 10 unit tests covering the geometry, resize clamps + the drag-resize math, cross-side docking, hit-testing, drop-zone selection, and the JSON persistence round-trip + malformed-blob fallback.
Rebased onto current
main. Totally fine to hold or reshape this if it overlaps what you're already doing — I'd rather build it the way that fits your interface work than duplicate it.