Commit Graph
232 Commits
Author SHA1 Message Date
aiongg d30c207c8d docking: one model; profile differences are style data
Remove `Profile`. What it switched is now a `DockStyle` setting with the
dock-and-canvas behaviour as the default: `side_edge_zones`,
`new_dock_zones`, `maximize_item`, `close_others_item`,
`command_press_floats`, `float_hint`, and plain bools for
`wheel_selects_tabs` and `middle_click_closes_tabs`. The undock and
Close Panel Group labels go; an app sets `float_label`,
`float_group_label` and `close_group_label` instead.

Remove the size machinery that made frames stick: `DockContent::bare`,
`FixedSlot` and the split that took a parent's or sibling's half beside
a fixed-size frame, and the gap snapping to the nearest frame. A tab
group takes the largest maximum of its panels, so a panel without one
lifts the cap of the group it joins. A dragged divider stores a ratio
whatever mode it was saved with.

Sizes follow the reference rules: a divider resizes only the groups
that touch it and stops at their minimums; a four-way handle where a
divider ends on another moves both (`Divider::Intersection`); a split or
outer-edge drop that would leave a group without `min_pane` is not
offered, and a group too small to halve takes the drop as a tab.

Tests: one per rule, the stuck cases from the FilmCraft map, and a
property test over random drops checking minimums and divider travel.
2026-10-22 20:01:31 +00:00
aiongg 958c5ada58 docking: the Frame profile's drop hint says undock, as its menus do 2026-10-21 16:46:50 +00:00
aiongg 7d786e5108 docking: the Frame profile drop preview says which key floats
While a drag offers a docking target, a hint under the pointer reads
"Hold Ctrl to float" ("Hold ⌘ to float" on macOS), from the
localizable float_hint_label (key dock.floatHint).
2026-10-21 16:45:29 +00:00
aiongg 899807ff19 docking: a split beside a fixed-size frame keeps that frame's size
A side split replaced the anchor frame in place, so a split beside a
fixed-width frame such as a tool strip took the frame's fixed slot:
the two frames shared its width, and the parent's divider resized both.
The frame now keeps its size: on its outer side the new split wraps the
parent, on its inner side it halves the parent's other child. The drop
preview shows the half the new frame takes.
2026-10-21 16:44:06 +00:00
aiongg 40c59bb577 docking: narrow frames keep usable side drop zones, and seams split
A side zone is a quarter of the frame deep, at least 32 pt and at most
half the frame, so a 64 pt tool strip offers its left and right edges
past the outer edge band. A pointer in the gap between frames resolves
to the nearest frame's edge instead of floating.
2026-10-21 16:40:59 +00:00
aiongg 2fa4ad79d7 docking: floating windows stay inside the app's float bounds
DockArea::float_bounds sets where floating windows, flyouts and drag ghosts may go; the default is the whole viewport. An app with its own title bar under a transparent macOS title bar passes the viewport below it, so a floating window can't be dropped, dragged or restored where pressing it moves the app window.
2026-10-21 16:19:25 +00:00
aiongg a0b923ac1e docking: icon groups reserve no drag strip
An icon group's drag band covers the separator above it and the top 4 pt of its first icon, so icons are spaced only by the separators between groups.
2026-10-21 04:40:33 +00:00
aiongg 592cba1ca1 docking: drag areas draw no grip marks
The drag strip beside the tabs, the column bar, the floating title bar and the strip above an icon group stay draggable, with the grab cursor and the hover outline, but paint no grip lines.
2026-10-21 04:12:09 +00:00
aiongg 352a8308c5 docking: rustfmt and clippy 2026-10-20 15:32:26 +00:00
aiongg 5f48f1e1eb docking: per-frame lookups scale with the panel count
The renderer looked up each panel's place with a tree walk, found
recorded content heights by linear search and named every possible
control of every panel to record hit rects. Places come from one
traversal per frame, content heights through an index, and hit rects
are named only when hit_rects asks.
2026-10-20 15:32:26 +00:00
aiongg 0fe98b3be9 docking: Target, Side, ResizeEdge, Profile and DockStyle are non_exhaustive
New variants and style fields can then be added without breaking apps.
DockStyle gains from_visuals and Default for building a style without a Ui.
2026-10-20 15:26:57 +00:00
aiongg bc4addb8d4 docking: opening works when locked, and hiding respects closable
OpenAt checked the opened panel's movable, so a locked workspace refused
OpenAt while Open worked. It checks movable only for a panel already
shown. Workspace::set_visible takes the app's permissions, so hiding
cannot close a protected canvas.
2026-10-20 15:21:51 +00:00
aiongg b19b2638a1 docking: validate rejects empty frames and accordions
No action leaves a Tabs or Stack node without panels, and no app
fixture has one; a file that does is invalid, as an empty group is.
2026-10-20 15:21:51 +00:00
aiongg 0781c48870 docking: screen-reader resize values follow the column width on either edge
On a dock at the right edge the column handle passed accessibility
values through the physical axis, so SetValue 300 gave width 180 and
Increment shrank the column. ResizeHandle::reversed applies
accessibility actions in value space; the pointer and arrow keys stay
physical.
2026-10-20 15:21:46 +00:00
aiongg c084db9c78 docking: a pointer drag on a divider or resize grip leaves no focus behind
Keeping focus on the handle after a pointer drag broke app shortcuts
that defer to a focused widget (egui_wants_keyboard_input), and arrow
keys moved both the canvas selection and the divider. A handle focused
by the pointer gives the focus up on release; one reached with Tab or
F6 keeps it, and arrow keys resize it.
2026-10-20 15:21:46 +00:00
aiongg 41a14168ea docking: reconcile and restore keep a protected canvas shown
Restoring beside a sibling subtree needed the exact same set of panels,
so a migrated layout without the canvas put the canvas in hidden. Restore
splits the anchor alone when the subtree changed. reconcile takes the
panels' permissions and never leaves a registered panel that cannot
close in hidden: it goes back to its recorded or default place, else to
the outer edge of the docked area.
2026-10-20 15:12:06 +00:00
aiongg 4310fc72a1 docking: window.panel.dock to a side never anchors on what moves
On the first panel of the last column, the command picked that panel as
its own anchor and failed with InvalidPlacement. The anchor is a panel of
the last column outside the moving unit; when the unit already is that
column, the command does nothing.
2026-10-20 15:09:34 +00:00
aiongg 37374d06c0 docking: a dock wider than its area shrinks its columns to fit
A layout saved on a larger screen drew its outer columns 0 wide with no
hit rect and resized them to width 0, which the model rejects. Columns
shrink in proportion down to their minimum width; resizing one fixes the
others at their drawn widths so the divider follows the pointer.
2026-10-20 15:08:51 +00:00
aiongg 95d5cddb5f docking: a canvas that accepts splits stays protected
Hiding panels and dropping the tab strip tested for exactly
Permissions::PROTECTED, so a canvas set up as the docs describe
(accepts_splits on) was hidden and got a tab strip. Permissions::is_protected
decides from what the panel allows.
2026-10-20 15:07:24 +00:00
aionggandfilipessmedeiros-collab 07585888d6 docking: floating windows resize from the top edge and corners
A resizable FloatingFrame keeps a 4 pt band above its contents for the
Top, TopLeft and TopRight handles, so they take no title bar moves or
button clicks. They keep the opposite edges in place, respect the size
limits and the screen, take arrow keys when focused, and have hit ids.
Moves carry the whole frame rect, band included.

Ported from #189.

Co-authored-by: filipessmedeiros-collab <343926472+filipessmedeiros-collab@users.noreply.github.com>
2026-10-20 03:51:38 +00:00
aiongg 72a0a4dc78 docking: rustfmt 2026-10-20 03:51:13 +00:00
aiongg 46f2ffd654 docking: a press in a group header focuses the shown panel
Host widgets in the header, such as a menu button or the host's own tabs,
focus the panel the way a press on its tab or body does.
2026-10-20 03:47:12 +00:00
aiongg 91e8cf401e docking: chrome_has_focus recognizes every control a Hit names
It checks the same widget ids as hit_rects and hit_id, which adds icons and
icon grips.
2026-10-20 03:46:31 +00:00
aiongg 815d648016 docking: split divider hits name the layout path while panels are hidden
A split's handle id and its Hit::Divider use the layout path that
ResizeSplit takes, also when hiding panels collapses a split in the drawn
tree.
2026-10-20 03:45:18 +00:00
aiongg ae0c19b49b docking: hidden floating windows do not cover dock targets
Dock targets check the floating windows drawn this frame instead of every
window's last egui area rect. floating_layer says that an undrawn window
keeps its last area rect.
2026-10-20 03:44:25 +00:00
aiongg a55cbe870e docking: a huge wheel delta over a tab strip stops at the last tab
The step count saturates instead of overflowing the index subtraction.
2026-10-20 03:42:52 +00:00
aiongg cef258a356 docking: a column's first tab docks beside its own column
A dock target named by the dragged panel itself anchors on another panel
of the same group or column, or leaves the panel in place when it is alone
there, instead of failing with InvalidPlacement.
2026-10-20 03:42:36 +00:00
aiongg ceb75f965e ui: use US spelling 2026-10-20 03:24:45 +00:00
aiongg 3600104e76 docking: rustfmt the new tests 2026-10-20 01:00:56 +00:00
aiongg 95c81fa6de docking: say that the drag bar's menu opens on a right click
A left click on the drag bar focuses it and opens nothing, as designed;
the Hit::DragBar docs said otherwise.
2026-10-20 01:00:30 +00:00
aiongg a76d196b80 docking: dividers and resize grips keep focus after a pointer drag
Arrow keys resize the handle right after a drag. Focus that came from
the pointer draws no highlight until a key is pressed, and hovering
still focuses nothing.
2026-10-20 01:00:22 +00:00
aiongg 877f676e19 docking: menu item labels in title case
Float Panel, Close Panel and Move Group To match the other menu items.
Control names that only screen readers announce stay in sentence case.
2026-10-20 00:59:33 +00:00
aiongg 38e2b27a30 docking: window.panel.dock with an edge zone and no anchor docks at that edge
A left, right, top or bottom zone without anchor or side maps to
Placement::Edge, anchored on any docked panel that does not move. A
hidden panel is shown and moved in one step, all or nothing.
2026-10-20 00:59:02 +00:00
aiongg 89849272a0 docking: public widget ids and floating window layers
DockArea::hit_id gives the egui id of the control a Hit names, and
DockArea::floating_layer the layer of a floating window, so apps and
their tests stop rebuilding internal ids. The divider between stacked
groups has one id in docks and floating windows.
2026-10-20 00:58:10 +00:00
aiongg 30cebdc0f2 docking: content that fills its body floats at floating_size or 320
A panel body that reaches the bottom of its rect has no height of its
own, so a floated panel or group falls back to floating_size, else 320
points, instead of the whole frame height. A body in a window fitted to
its recorded height keeps that height. Panels leaving a frame fit their
content like panels leaving a dock.
2026-10-20 00:57:14 +00:00
aiongg b94df6c8b6 docking: wheel selects tabs and middle click closes a tab
Both are on in the Frame profile and off by default in the Dock profile;
DockStyle::wheel_selects_tabs and middle_click_closes_tabs set them. A
middle click closes only a closable panel.
2026-10-20 00:55:43 +00:00
aiongg d3079230da docking: group_header_width gets the tab strip width
A header that draws its own tabs, such as a timeline's open sequences,
sizes them to the room the strip has.
2026-10-20 00:54:23 +00:00
aiongg 787b706274 docs: say when a tab is cut and that the drag bar keeps its width 2026-10-19 15:37:00 +00:00
aiongg 13be52fbaa docking: focus only follows the user's input 2026-10-19 14:06:37 +00:00
aiongg a014337eb2 docking: a floated group takes its content height 2026-10-19 14:06:37 +00:00
aiongg e1b7733a1d docking: tabs keep their names and the rest go to the overflow menu 2026-10-19 14:02:05 +00:00
aiongg bfda13d2af docking: a tab dragged to an edge without a dock makes one
A tab that shares its group moves alone into the new dock with Action::MovePanel, as
window.panel.dock does (P6).
2026-10-19 13:32:15 +00:00
aiongg 9359332fd7 panes: the API example gives the document focus on to_document 2026-10-19 13:30:02 +00:00
aiongg 4325b9ccc1 docking: move_targets skips the panel's own group
Moving a panel to a tab of its own group only reorders it, so a panel whose only other tabs are
in its group gets no "Move Panel to Group" menu.
2026-10-19 13:30:02 +00:00
aiongg b64cc4eac6 docking: window.panel.minimize toggles an accordion entry both ways
Without minimized the command read only dock and floating groups, so a closed accordion entry
stayed closed.
2026-10-19 13:30:02 +00:00
aiongg 5d5d11f854 docking: window.panel.dock to a side without a dock moves one panel of a shared group
Action::MovePanel moves one panel to a Target; NewDock and Float give it a group of its own.
DockCommand::Dock with a side that has no dock used to fail with InvalidPlacement for a panel
that shares its group.
2026-10-19 13:30:02 +00:00
aiongg c715d3f25f docking: hosts seed a FloatSpace with panel sizes 2026-10-19 13:22:34 +00:00
aiongg 6261d9d39a docking: DockCommand takes the float space 2026-10-19 13:11:07 +00:00
aiongg 3aded979b5 docking: report flyout changes with DockEvent::FlyoutChanged 2026-10-19 13:07:52 +00:00
aiongg f46828ea48 docking: float commands without a rect at the drag size inside the dock area 2026-10-19 13:07:03 +00:00