* docking: default, compact and fill heights for dock column groups
DockContent::dock_heights gives a panel's body heights in a dock column while the
user has not resized its group. Groups at their default give way down to their
compact heights so the filling group gets its fill height; then every group gives
way down to its minimum. Saved heights stay. Without it, layouts are unchanged.
* docking: dock column defaults give way nearest the filler first
The group nearest the filling group shrinks to its compact height before the next
one gives way, so groups further up keep their defaults.
* docking: shared groups with different minimums split the rest evenly above their minimums
* docking: a group asking for a fill height fills the column beside groups without dock heights
Dragging a native window's only tab, or its only group, moves the
window and docks it on release. It took a frame's edges and its tab
strip but not its body's center, a rule meant for the bar, so the
center rectangle was neither a target nor filled under the pointer.
Such a move now joins the center as the tab or group drag would; the
bar still does not.
The ×'s glyph inset, size and hit area are set in one place (MACOS_CLOSE,
OTHER_CLOSE in render/native.rs). On macOS the glyph sits where macOS puts its
close button, and the hit area reaches 10 pt toward the leading edge and down
to the bar's bottom, past AppKit's corner resize area. Elsewhere the layout is
the same as before. CRAFT_DOCK_DEBUG_CLOSE=1 outlines the hit area and AppKit's
resize areas.
A side split that leaves a half at its minimum is taken when the
dividers along that half can still travel, the groups beyond giving
way as they do for a dragged divider. An 80 pt group, whose halves
need 84, splits on all four sides and takes the rest from its
neighbour; only when the groups beyond are at their minimums too does
the drop join the group's tabs.
On macOS the native window is resizable by AppKit again, with its own areas
and cursors. The bar's buttons sit 19 pt in from the trailing edge, clear of
AppKit's corner area (about 15 pt into the window, a 19 pt square measured on
macOS 26), and the window sets no cursor of its own over AppKit's areas.
Elsewhere the bands are 6 pt deep with 16 pt corner Ls, and hand the resize
to the window system; the manual resize path is gone.
Floating::new, single and stack draw a fresh id on each call, so a layout
built anew each frame opened a new OS window each frame. with_id gives such
a layout the same windows every frame. Debug builds log a warning once when
three frames running replace every native window with new ones holding the
same panels.
Each side zone reaches zone_depth into the body, or a quarter of the
body's smaller side when that is less. A tall narrow group's top and
bottom zones are no deeper than its left and right ones.
A divider dragged past the minimum of the group it shrinks moves on to
the next group along the axis, and so on until every group on that side
is at its minimum. The line follows same-axis splits up the tree and
ends at a split across the axis or beside a dock. Groups touching the
divider on the other side grow, up to their maximums, as before.
Stacked panels and the groups of a dock column cascade the same way.
The bands along a native window's edges leave out the bar's buttons, which
sit 4 pt in from the window's edge. Each corner is an L, 4 pt deep and 12 pt
along both edges. macOS windows are not resizable by AppKit, whose resize
areas reach over the ×; the bands resize them by InnerSize and OuterPosition,
since winit has no BeginResize there.
A frame's side zones reach DockStyle::zone_depth (40 pt) into the body below
the tab strip, or a third of a smaller body, so a frame keeps its center.
drop_zone, zone_shape and resolve_drop take the depth. In the Frame style a
drag over a frame outlines every zone a drop there would change something in
and fills the one under the pointer, without the outline of the resulting rect.
Floating::stack builds a window from groups stacked top to bottom, so an
app's own stacked layouts migrate without building the split chain. The
four-way handle no longer takes keyboard focus: it has no label or key
action, and the two dividers it joins take arrow keys.
With side_edge_zones, a drop on a group fills the zone the pointer is in
(a side's trapezoid, or the center rectangle with the tab strip) and
outlines the rect the drop gives what moves. zone_shape gives a zone's
outline; DockDriver::filled_polygon checks it. The dock-and-canvas
arrangement keeps its filled half and insertion lines.
Floating::root replaces the stack of groups. A floating window takes
splits in any direction, tab groups and accordions; its groups split,
join and resize like frames, with the Sizer, four-way handles
(Divider::WindowSplit, Divider::WindowIntersection,
Action::ResizeWindowSplit) and the room check. Tabs and drag bars inside
it show the targets of every window and dock; Undock Panel Group floats
one group of a window that has several. Floating::minimized replaces
per-group minimizing in a window.
Saved layouts keep loading: a stored stack of groups becomes a vertical
split sized by the groups' heights. Placement::Group on a floating anchor
splits its group above or below. A window moved onto a dock keeps its
groups as stacked groups.
Two DockStyle settings, on by default so the dock-and-canvas arrangement
keeps its behaviour. Without float_on_empty_drop, a tab or group released
over no target inside the app window (the gap between groups, a menu bar,
a status bar) cancels the drag; Ctrl/Cmd or a release outside the window
floats it. Without title_bar_docks, dragging a floating window's title bar
only moves the window.
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.
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).
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.
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.
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.
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.
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.
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.
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.
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.
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>
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.
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.
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.
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.
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.
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.