Commit Graph
157 Commits
Author SHA1 Message Date
aiongg 17744430be docking: a divider drag keeps the split's fixed or ratio size (#291) 2026-10-24 16:18:39 -04:00
aiongg 96f8ae3d5a docking: a double-click on a minimized group's active tab leaves it expanded (#289)
* docking: keep a minimized group expanded when its active tab is double-clicked

* docking: no extra SetMinimized for a click on the active tab
2026-10-24 16:15:20 -04:00
aiongg 5a371c978e docking: cancel the OS close of a native window that may not close (#288) 2026-10-24 16:14:58 -04:00
aiongg a0679c1dfc docking: dock column groups give way to the filler from their default heights (DockContent::dock_heights) (#287)
* 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
2026-10-24 16:14:38 -04:00
aiongg 16fb3d46e1 docking: the window under the pointer draws the undock hint (#285) 2026-10-24 14:49:29 -04:00
aiongg 72ca5ea0eb docking: windows sharing the dragged window's title stay faded on macOS 2026-10-24 13:12:58 +00:00
aiongg 6680968a83 docking: DockArea::locked draws a locked workspace; a lock still records native windows 2026-10-24 13:12:58 +00:00
aiongg 5bbf45a20a panes: a bottom pane dragged to a side previews the width it docks at 2026-10-24 13:12:49 +00:00
aiongg 3ddbb0b181 docking: Placement::Split's doc describes the half split 2026-10-24 13:07:07 +00:00
aiongg 1564d54959 docking: a native window moved by its only tab or group joins a body's center
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.
2026-10-24 04:49:32 +00:00
aiongg a22c6d0c63 docking: a native window fades to half opacity while it is dragged, on macOS 2026-10-24 04:32:17 +00:00
aiongg bbaa61e64a docking: the resize band test runs off macOS only, where the bands are 2026-10-24 04:13:41 +00:00
aiongg 3250dd2305 docking: the macOS × sits 8 pt from the corner, its hit area reaching away from it
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.
2026-10-24 03:53:42 +00:00
aiongg ba00e9fd9e craft-ui: end drags and resizes on a focus loss, not while a window reports no focus
egui-winit starts RawInput::focused false and only a winit Focused event
sets it. A window that egui never heard was focused cancelled every tab,
group and window drag and every resize on its first frame. Gestures now
end on a focused-to-unfocused transition (or Escape); a window that
never reported focus still drags while the pointer is pressed in it.
2026-10-24 03:45:08 +00:00
aiongg 09e14347d3 Merge branch 'docking' into dock-windows 2026-10-24 03:44:56 +00:00
aiongg 2f90228e10 docking: a narrow group splits when its neighbours have room for both halves
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.
2026-10-24 03:41:27 +00:00
aiongg 308163bcb5 docking: macOS resizes native windows itself, bands elsewhere are 6 pt with 16 pt corners
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.
2026-10-24 03:40:17 +00:00
aiongg 2cad4d2bec docking: clippy, a type for a split's children and one argument for a node and its rect 2026-10-24 03:13:34 +00:00
aiongg 1c24845a17 Merge branch 'docking' into dock-windows 2026-10-24 03:13:34 +00:00
aiongg 1ccdad9512 docking: Floating::with_id for layouts built in code; debug builds warn about rebuilt layouts
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.
2026-10-24 03:09:14 +00:00
aiongg cb352b39ff docking: all four drop zones of a group share one depth
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.
2026-10-24 03:06:11 +00:00
aiongg 99d8fe537e docking: a dragged divider shrinks the groups beyond it in turn
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.
2026-10-24 03:05:32 +00:00
aiongg b892ec92e2 docking: native window bar buttons win over the resize bands, corners are 4 pt Ls
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.
2026-10-24 03:05:03 +00:00
aiongg 1546cef8d9 docking: Escape in a native window that doesn't own a drag cancels it, whichever window owns it 2026-10-24 00:33:17 +00:00
aiongg 0008f89212 Merge branch 'docking' into dock-windows
Native windows draw a frame's drop zones through the destination window's
painter, and the bar-docking test aims inside the 40 pt right band.
2026-10-24 00:00:43 +00:00
aiongg e6c76f5151 docking: drop zones are 40 pt bands below the tab strip, all outlined while dragging
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.
2026-10-23 23:57:43 +00:00
aiongg 46a49971c7 docking: format 2026-10-23 18:06:20 +00:00
aiongg e2b452482a docking: an example with native floating windows 2026-10-23 18:05:09 +00:00
aiongg 37b6a0dc25 docking: native windows move only on a pointer move of their frame
- A bar drag reads this frame's pointer moves only. egui keeps the last
  pointer position, measured against where the window was then; reused
  after the window moved, it crept the window on.
- Escape pressed in any of the application's windows cancels a drag a
  native window owns.
- DockContent::allow_native defaults to true: the feature is the opt-in.
- DockOutput::forwarded_modifiers tells Cmd/Ctrl+C, X and V, which
  egui-winit sends as Copy, Cut and Paste, from those keys.
2026-10-23 18:05:09 +00:00
aiongg 98e05997a0 docking: native windows place by their content and follow the layout
- A window made this session opens at its computed rect; only windows of a
  loaded layout are restored onto a connected monitor.
- The content (inner rect) is each native window's desktop origin; only
  OuterPosition converts to the outer position.
- A bar drag places the window from its reported position, so late moves
  do not overshoot. The layout follows once the drag ends, and a window
  left with its bar off every monitor goes back onto the nearest.
- A changed Floating::native (undo, reset, reload) moves the OS window
  instead of being overwritten by its next report.
- Dragging a native window's only tab or group docks it whatever
  title_bar_docks says.
- Escape that cancels a drag is consumed; nothing is forwarded while a
  widget of the window has focus.
- A bar drag whose window goes away ends.
- An embedded fallback keeps its drop targets; floating windows get no
  taskbar entry.
- The test host can give windows a frame inset and land moves a frame late.
2026-10-23 17:55:03 +00:00
aiongg 0ac8f80f64 docking: a loaded layout's monitor and monitor size are validated 2026-10-23 17:55:03 +00:00
aiongg e19b1b684d docking: a restored native window opens where its bar can be grabbed 2026-10-23 17:48:12 +00:00
aiongg 137845d6f4 docking: clamping a native window onto a fractional monitor origin cannot panic 2026-10-23 17:42:37 +00:00
aiongg b46b9dd5c1 docking: a native window's bar docks it at the main window's frame edges
The window docks as its groups at a frame's edge zones, as a group drag would; a body's
center still takes no whole window. Tests for Escape during a bar drag and for the
window focused last being in front.
2026-10-23 17:31:11 +00:00
aiongg 84b42eacc9 docking: tabs, groups and windows drag between OS windows
The window where a drag starts owns it and writes its pointer with its desktop origin.
The window under that point shows the preview with its own targets, and the release
docks there, or floats a new window over the desktop. Leaving a window is no release
with native viewports. Dragging the only tab or group of a window moves it, and its
bar docks the whole window.
2026-10-23 17:24:25 +00:00
aiongg 141ddc92f6 docking: which window lies under a desktop point 2026-10-23 17:24:19 +00:00
aiongg 48272d3932 docking: the host stand-in needs no expect, and the label count drops with New Window 2026-10-23 16:42:36 +00:00
aiongg 0ecc7d2d39 Merge remote-tracking branch 'ao/docking' into dock-windows 2026-10-23 16:42:21 +00:00
aiongg e350bfdb01 docking: the undock hint test uses contains, as clippy asks 2026-10-23 16:40:17 +00:00
aiongg e23e447f32 Merge remote-tracking branch 'ao/docking' into dock-windows 2026-10-23 16:35:58 +00:00
aiongg 53947dbfe8 docking: the undock hint test expects the platform's key 2026-10-23 16:35:35 +00:00
aiongg 06c1fc8825 docking: DockDriver stands in for OS windows, and native window tests
with_native_host draws native windows as their own egui frames with a
desktop rect, focus, close requests and the commands they receive. Tests
cover each way into a native window, closing, stable ids, place and
monitor, restore, the bar drag, hiding and forwarded keys.
2026-10-23 08:27:19 +00:00
aiongg 799ab4e691 docking: every float opens in its own OS window
With native-windows on a backend with viewports, each floating window
whose panels allow it is native: in-window floats open over their place
in the app window, and restored windows go back to their monitor or onto
the main window's. Windows stay on top and hide while the app is
inactive. A thin bar with title and close replaces the OS title bar and
moves the window; closing the window closes its panels. Keys a native
window leaves unused come back in DockOutput::forwarded_events, and
DockArea::monitors takes the monitor list. Move Panel to New Window goes,
since every float is native.
2026-10-23 08:27:13 +00:00
aiongg 9c869166e8 docking: floating windows keep a stable id and store their monitor
Floating::id names a window across panel moves: fresh from Floating::new
and on load, unique within a loaded layout, kept by a whole window that
moves and by the receiver of a merge. Floating::monitor and monitor_size
record where a native window is; Action::SetMonitor sets them. Equality
ignores the id.
2026-10-23 08:26:56 +00:00
aiongg 01ce7162a4 docking: Floating::stack is public, and four-way handles take the pointer only
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.
2026-10-23 06:11:03 +00:00
aiongg 50f9c06aa7 Merge remote-tracking branch 'upstream/main' into docking
# Conflicts:
#	crates/ui/src/docking/surface.rs
2026-10-23 05:06:13 +00:00
Dylan M. Taylor c67b1e16b8 Merge pull request #236 from dylanmtaylor/security/docking-group-move-permission
security: require every floating-group member to be movable for MoveFloating (CodeRabbit)
2026-10-22 22:42:36 -04:00
Dylan M. Taylor fd9cf54c48 ui: test that a protected member blocks the floating group's resize grip
Drags the resize grip of sample()'s floating group: a movable group emits MoveFloating,
one with a protected member emits none. Fails without the surface.rs check (CodeRabbit
review nitpick).
2026-10-22 22:23:27 -04:00
Dylan M. Taylor 4f85efb2b9 security: bound print dialog name resolution, PPD labels, lpstat merge and inherited geometry
- craft-ui shown_names resolves label collisions with hash-map counts and a worklist, so a
  crafted cascade is linear instead of cubic (CodeRabbit CWE-407, ui/src/printing.rs:32)
- parse_ppd caps group, option and choice labels at 256 characters before each option copies
  its group (CodeRabbit CWE-400, print/src/lib.rs:232)
- printers_parsed tracks seen destinations in a HashSet (CodeRabbit CWE-407, lib.rs:417)
- sheets::Reader::rect checks an inline array's length before reading it and borrows direct
  objects instead of deep-cloning the inherited MediaBox/CropBox/Rotate for every page
  (CodeRabbit CWE-400, print/src/sheets.rs:774)
2026-10-22 21:49:46 -04:00
Dylan M. Taylor d66e345cc7 security: require every floating-group member to be movable for MoveFloating
MoveFloating checked only the panel it named, but changes the rectangle shared by that
panel's whole floating group, so naming a movable sibling moved a panel whose policy forbids
it. The model now refuses the action unless every member is movable, and the floating
window's resize grip no longer emits it for such a group.

CodeRabbit CWE-863, crates/ui/src/docking/model.rs:392
2026-10-22 21:46:25 -04:00