Commit Graph
198 Commits
Author SHA1 Message Date
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
aiongg d91e5f6aea docking: paint panel icons in code with DockContent::paint_icon 2026-10-19 13:04:52 +00:00
aiongg f4f9e5b206 docking: one drop preview painter for docking and panes
chrome::drop_preview draws the accent outline, filled or not, for every
docking destination and drag ghost and for the pane host's drop preview.
2026-10-19 12:26:31 +00:00
aiongg 6820f98109 panes: reserve the exact pane size, clip the body and name each title bar
A docked pane draws its body in a child ui clipped to the pane, so a body
wider than the pane no longer shifts a right or bottom pane's reserved
rect into the document. PaneLabels::move_pane takes {title}, so each
title bar's accessible name includes its pane ("Move Styles pane").
Pane title bars mirror with .rtl(true).
2026-10-19 12:25:49 +00:00
aiongg 8a0df8c12f docking: fixes from DesignCraft trial step 2
- Permissions::accepts_splits; PROTECTED takes no side splits, so a
  group dropped on a protected canvas floats.
- A press of any pointer button in a panel body, stripless panels
  included, reports the panel in DockOutput::focused.
- Right to left, tab strips, their header and drag bar, insertion slots
  (DropTarget::right_to_left), accordion headers and chrome::TitleBar
  (ChromeStyle::right_to_left) mirror. TitleBar truncates galley titles
  like tab labels.
- DockStyle::close_menu_items and close_button hide the built-in close
  controls without changing Permissions::closable.
- Menu labels say what moves: Move Panel to Group (move_panel_to_label)
  and Move Group to (move_group_to_label).
- The column bar's button has its own accessibility labels
  (collapse_column_label, expand_column_label).
- Placement::for_zone maps zones onto what the anchor's container takes;
  DockCommand uses it and takes right_to_left.
- Layout::apply, apply_with_permissions and apply_all return the closed
  panels.
- Placement::Group takes an optional preferred height.
2026-10-19 12:24:38 +00:00
aiongg 9c909dba7f docking: merge iconic columns, DockCommand, hit rects, the test driver and the guide
Adds the auto-collapse label to the keyed label hook and returns closed panels from DockCommand::apply through Workspace::apply_all.
2026-10-19 12:12:40 +00:00
aiongg b98ef89921 docking: rewrite the docking guide for the current API
docs/ui-docking.md covers the Dock and Frame profiles, the model and
actions, Workspace, the renderer and DockContent, gestures, DockCommand,
DockStyle::localized, hit rects and the DockDriver test driver, and links
the task-pane guide.

Also: ui.dock open, close and activate map in one place, the command tests
build as a cfg(test) module, the hit-kind table gets a type alias, the
testing example uses public API, and rustfmt.
2026-10-19 12:07:14 +00:00
aiongg 0d350d8e11 docking: DockCommand for the shared command ids and the ui.dock operations
DockCommand<P> deserializes a control command's params, with its id under
"command", and maps it to layout actions applied all or none. It covers the
window.panel.* and window.workspace.* ids, the raw {action} form, and the
ui.dock {operation, …} shape of LightCraft, PDFCraft, CADCraft and
SoundCraft (open, close, activate, float, moveFloating, move, setStackOpen,
resizeStack, resizeSplit), so their parsers can go without a protocol change.
Named workspaces and Reset stay with the application.

tests/docking_workflows.rs loads every v1 fixture, docks groups by their bars
into a new dock, a bottom band and a seam, collapses and expands the column,
floats it by command, drags it back, and checks the layout reads back as
written.
2026-10-19 11:59:33 +00:00
aiongg 0c140eb65b docking: iconic columns with flyouts, hit rects and a test driver
An iconic column draws one icon per panel, a grip above each group and a
separator between groups (M3). Widened past `DockStyle::iconic_label_width`
it shows panel names (M4). Clicking an icon opens its group as a flyout on
the canvas side; another icon switches, the same icon closes, and with
Auto-Collapse Iconic Panels (default on) Escape or a press outside closes
it (M5). Dragging a flyout's strip floats its group (M6), an icon drags its
panel (S7) and the grip its group (S8). A drop into an iconic column makes
a new icon group, previewed by the column outline and an insertion line
(P9). `raise_panel` on an iconic panel opens its flyout (U3), and the
column menu has the Auto-Collapse toggle as `DockEvent::ToggleAutoCollapse`.

Iconic widths move to `DockStyle` (`icon_size`, `iconic_width`,
`iconic_max_width`). `DockArea::hit_rects` names every gesture source the
area drew last frame, and `docking::testing::DockDriver` (feature
`testing`) drives an area with real egui input for application tests.

Behaviour follows vectorcraft crates/ui-egui/src/dock.rs (icon column,
flyout placement, names when widened) and photocraft dock.rs
(auto-collapse).
2026-10-19 05:40:26 +00:00
aiongg c94ab4d313 docking: merge craft_ui::panes, the task-pane host for document apps 2026-10-19 05:38:27 +00:00
aiongg 3893c590b0 docking: group float size, elided tab labels, filled ghost, drag bar grip, tab focus and double-click fixes
A floated group or column keeps its width and takes the tallest member's floating size, else the docked height capped at 320 pt. Tab labels from pre-laid-out galleys are cut with an ellipsis and drawn left-aligned inside the tab, active tabs included. The group drag ghost has a translucent fill, a 2 pt outline and the members' labels. The drag bar draws a grip mark at rest. A click that expands a minimized group does not start a double-click that minimizes it again. A tab focused by the pointer shows no focus outline; keyboard focus still does.

Found in the DesignCraft trial
2026-10-19 05:38:00 +00:00
aiongg 418344c5ad docking: keyed label hook, closed panels from Workspace::apply, borrowed Floating::contains
DockStyle::localized translates every *_label field through one keyed function. Workspace::apply and apply_all return the panels they closed. Floating::contains takes any borrowed form of the panel id.

Found in the DesignCraft trial
2026-10-19 05:38:00 +00:00
aiongg a09aa016e3 panes: docs with adoption steps for WordCraft, DeckCraft, GridCraft 2026-10-19 05:36:18 +00:00
aiongg 484717644c panes: task-pane host for document apps
PaneHost draws the open panes as egui side and bottom panels before the app's
CentralPanel, or as floating frames, each with a title, a ▾ menu (app items,
Move to Start/End, Float, Close), × and a resize edge. Edges are logical
(Start/End) with an RTL flag. Columns shows every pane side by side; OneSlot
shows one closable pane per edge. The app owns open state and pane state: the
host returns Close, Place, Resize, FloatRect and Focus requests, the focused
pane, and cycles focus with F6.

Drag-out-to-float and edge snap follow wordcraft#2584.
2026-10-19 05:36:18 +00:00
aiongg 87e6562a5e ui: chrome live_move for title-bar moves
Moves a rect with a title-bar drag from the rect and press position kept at
drag start, so the window follows the pointer without drift. Escape or window
focus loss ends the move and returns the start rect.
2026-10-19 05:36:18 +00:00
aiongg 315fde3ed8 docking: test window title drags onto dock seams and new-dock bands 2026-10-19 05:27:17 +00:00
aiongg d37d9aeff3 docking: merge floating windows, frame profile and native windows
Merge the docking-t4 track (floating title bars and stacks, frame
profile, native windows, public chrome) into the dock profile track.

Integration:
- DockStyle keeps two edge bands: `edge_band` (8) is the outer edge
  band that splits at the root; `new_dock_band` (12) is the band along
  the docked area's left and right edges that makes a new dock. One
  `seam_band` serves dock seams and floating stack seams.
- New-dock targets are offered in the dock profile rather than only in
  layouts that already have a dock.
- Window title bar drags take the dock targets: a column edge makes a
  new column, a seam or group band stacks the window's groups there,
  the new-dock band makes a dock. They still never split a frame or
  join a body centre. Tab drags check dock targets before floating
  stack and outer edge targets.
- One group_action maps column, window and group gestures to
  MoveColumn, MoveWindow and MoveGroup.
- The unused stacked_groups renderer is gone; docks and floating
  windows each draw their own stacks.
2026-10-19 05:27:17 +00:00
aiongg a842d330e0 docking: test that hidden panels map split resizes to layout paths 2026-10-19 05:22:03 +00:00
aiongg e235c4c183 docking: rustfmt and clippy for the floating and frame changes 2026-10-19 05:21:35 +00:00
aiongg 40fefd9c7b docking: floating title bars and stacks, frame profile, native windows
Floating windows:
- A title bar (TITLE 14) drags the whole window live; Escape and focus
  loss put it back. A release over a tab strip, a floating stack's band
  or seam, or the outer edge emits MoveWindow; elsewhere the window
  stays and hosts get group_drop. Double-click minimizes or expands
  every group; the close button closes every panel (CloseWindow).
- Stacked groups with a 3 pt bar between them and dividers that resize
  both neighbours (ResizeGroup). The top and bottom quarter of a group
  and the seam between two groups insert a new group there, with a line
  preview (P3, P4). The title bar occludes what lies behind it.
- The only group of a window carries the window rect when dragged by its
  bar, so floating it again keeps the window's size.

Frame profile (DockStyle::profile):
- Ctrl/Cmd held at the start of a tab drag undocks the panel (S9).
- The outer edge band splits at the root: top and bottom in both
  profiles, left and right in the frame profile (P8).
- Menu tail: Undock Panel, Close Panel Group, Undock Panel Group, Close
  Other Panels in Group and Maximize Frame (DockEvent::ToggleMaximize).

DockArea::maximized draws only the docked frame holding the panel;
other frames and floating windows do not render or take input.
DockArea::hide_panels leaves out every panel, or every panel except a
host-chosen set; protected panels stay and the layout is unchanged.

Feature native-windows: a floating window with a native rect gets its
own OS window through show_viewport_immediate when the backend does not
embed viewports, and stays in-window otherwise. Closing it emits
SetNative None, so the group returns to its in-window rect; moves and
resizes are read back as SetNative with bounded sizes and positions.
Tabs and groups do not drag between OS windows. Move Panel to New Window
is in the menu tail where native windows are available.

A floating panel whose window closed as a whole restores at its last
rect.

Behaviour follows vectorcraft floating.rs (show_set, draw_groups, track),
effectcraft dock_ui.rs (panel_window, set_panel_window, toggle_maximize)
and dock.rs (PanelWindow::sanitized), filmcraft dock_ui.rs (workspace_edge,
EDGE_BAND, maximized) and storytold/filmcraft#2118 (saved_native_rect,
bounded_inner_size).
2026-10-19 05:19:44 +00:00
aiongg 17cf8cd07b docking: public floating window chrome
docking::chrome holds the parts of a floating window that hosts other
than DockArea need, such as office task panes: FloatingFrame (opaque
frame on its own layer, anchored resize from both sides, the bottom and
both bottom corners, arrow keys on a focused handle) and TitleBar (two
grip lines or a title, an optional menu button, and a close button 10 pt
in from the right). They return responses and requested rects; the
caller turns them into its own commands.

Behaviour follows vectorcraft floating.rs (show_set: TITLE 14, grip
lines, close position).
2026-10-19 05:19:33 +00:00
aiongg c07a0debb4 docking: test dock columns, seams, column drags and RTL docks
Behaviour tests with real egui input: seam, band, column edge and new
dock drops with their line previews, tab drops, a column taking groups
anywhere, scrolling, column bar drags and their cancellation, dividers,
minimize, iconic toggles, occlusion by floating windows and the mirrored
right-to-left layout.

Behaviour follows vectorcraft crates/ui-egui/src/floating.rs tests.
2026-10-19 05:15:14 +00:00
aiongg f1a3683cc9 docking: dock profile with columns, column bars, seams and dock targets
Node::Dock renders as side docks: columns from the window edge inwards,
each with a column bar (drag, »/« button, double-click and menu toggle
iconic) above stacked groups. A split beside a dock gives the dock its
columns' width. Every column's inner edge resizes it; dividers between
open groups save both heights; minimized groups keep theirs. A column
whose groups' minimum heights do not fit scrolls.

Drops resolve dock targets before group targets: column edges (new
column), seams and the top or bottom quarter of a group body (new group),
the room under a minimized column (below its last group) and the left or
right edge of the docked area without a dock (new dock, offered once the
layout has a dock). They show a horizontal or full-height vertical line.
Floating windows and host overlays occlude them. Tab drags use the same
targets with Move. A column bar drag moves the column with a ghost and
floats its groups away from a dock; Escape, focus loss, pointer exit and
cancel_drag cancel it like a group drag.

Side::Start maps to the left edge, or the right with
DockStyle::right_to_left. New DockStyle fields: column_bar_height,
seam_band, edge_band, right_to_left and the column labels.

Behaviour follows vectorcraft crates/ui-egui/src/floating.rs (drop
geometry, column layout and scrolling) and photocraft
crates/ui-egui/src/dock.rs (group heights).
2026-10-19 05:15:14 +00:00
aiongg 954ad06d25 docking: Placement::Edge splits the layout's outer edge
A frame along one edge of the docked layout, a quarter of its size. In a
layout with docks the split wraps the part between them, so a bottom
Timeline or top bar stays inside the docks.

Behaviour follows filmcraft dock_ui.rs (workspace_edge).
2026-10-19 05:05:42 +00:00
aiongg 4bf11647ad docking: test tearing a group out of a floating stack 2026-10-19 04:56:52 +00:00
aionggandZenodeon 1b091edefb docking: drag tab groups by their drag bar and top border
Every group with a tab strip has a drag bar between its tabs and the
host's header, at least drag_bar_width wide: tabs shrink and overflow
before it narrows. The bar and the 4 pt top border move the whole group
with its order and active tab. While dragging, a ghost outline follows
the pointer and one destination preview paints on the Tooltip layer. On
release DockArea resolves the target and emits one MoveGroup: joined as
tabs, split beside a frame, or floated at the group's own size.
group_drop is filled only for releases without a target. Ctrl or Cmd
held at release always floats, for tab drags too. Escape, focus loss,
leaving the window and cancel_drag end the drag without a change. A
release over the group's own docked position is a no-op; a floating
group released over itself moves there.

Double-clicking a tab or the bar of a floating or dock-column group
minimizes it to its strip; clicking another tab expands it. The bar is
focusable; its menu (right-click, Enter or Space) and the tab menu end
with Close Tab Group, Minimize or Expand, Float Tab Group and Group
with. Floating windows paint floating_background and floating_stroke
under their groups, so they stay opaque over a transparent host. A lone
bare panel, like a lone protected one, draws no strip and no bar.

The group handles and their tests build on storytold/craft-libs#110 by
@Zenodeon.

Co-authored-by: Zenodeon <aswinmani2001@gmail.com>
2026-10-19 04:55:27 +00:00
aionggandZenodeon 9777c291c3 docking: anchored floating resize, no-op drops and the host drop hook
Floating windows resize from both side edges, the bottom edge and both
bottom corners; the opposite edges stay fixed and a resize past the
viewport waits for the pointer to come back. A release over a tab's
current slot or its own group body is a no-op instead of a float.
Insertion markers stay inside their strip. Previews paint on the
Tooltip layer, and a reorder inside the source strip shows only the
insertion line. resolve_drag lets the host own a gesture. A panel
floated from a dock uses floating_size or its limits instead of the
column height. ResizeHandle gives focus back after a pointer drag.
node_limits is a free function for the render modules. is_dragging and
tab_insertion_marker are public.

Ported from storytold/craft-libs#110 by @Zenodeon.

Co-authored-by: Zenodeon <aswinmani2001@gmail.com>
2026-10-19 04:45:52 +00:00
aionggandZenodeon 0784873c06 docking: per-panel policy on DockContent and DockArea::show_content
DockContent gains default methods for the logical label, permissions,
limits, floating size, icon, native-window permission, bare panels and a
host drop hook. show_content reads all of them from the content; the
closures passed to the older show functions override the label,
permission and limit defaults.

floating_size, resolve_drag, DropRequest and DropFeedback are ported
from storytold/craft-libs#110 by @Zenodeon.

Co-authored-by: Zenodeon <aswinmani2001@gmail.com>
2026-10-19 04:42:54 +00:00
aiongg 87ddebd73a docking: split the renderer into render modules
DockArea, DockContent, DockStyle, DockOutput and the drag state stay in
surface.rs. The Renderer moves to docking/render: the node tree, limits
and helpers in mod.rs, groups and tabs in group.rs, floating windows in
floating.rs, and drop resolution and previews in preview.rs.
2026-10-19 04:41:18 +00:00
aiongg 69a1adf699 docking: model, workspace and v1 fixture tests
Group, column and window moves, close and restore round trips, dock validation, Lock Workspace, reconcile and reset, the random action sequence over dock layouts, and one v1 fixture per app shape that must parse and write back unchanged.
2026-10-19 04:35:58 +00:00
aiongg 0ea5f8200c docking: Workspace with hidden locations, lock, reconcile and reset
Workspace<P> keeps the current layout, where hidden panels go back, the
user's saved arrangement and Lock Workspace. It reads the {layout,
hidden} files lightcraft, pdfcraft, cadcraft and soundcraft write today.
Close actions record a location per closed panel; set_visible follows
hidden anchors when a panel's own anchor is hidden too. reconcile moves
panels the app does not register now to hidden and places missing
registered panels at their default place; reset returns to the saved or
default arrangement.
2026-10-19 04:35:58 +00:00
aiongg 0ae7cddbb5 docking: docks, columns, groups and floating stacks in the layout model
Node::Dock holds columns of groups on a logical window edge (Side::Start
or Side::End). Floating windows hold a stack of groups and an optional
native rect; the v1 {panels, active, rect} shape still parses, and a
window with one plain group writes it. Placement gains Group and Column,
Target names where a group, column or window goes, and the new actions
move, close, minimize, collapse and resize groups, columns and windows
atomically. Location records group and column state so a panel closed
from a dock or floating stack restores to the same group, seam, column
or dock. Layout gains apply_all, closed_by and panel_state; Permissions
gains locked. Node, Action, Placement and DockError are non_exhaustive.

The renderer draws each floating window's groups stacked and a dock's
columns side by side until the dock and floating-stack profiles land.
2026-10-19 04:35:58 +00:00
NibrasAz7 c4b007706d Docking: hide 'Move to group' when no panel accepts the move (lightcraft#1768)
A movable panel's context menu always offered 'Move to group', even
when the layout held no other panel that accepts tabs — one open panel
showed an empty submenu. Layout gains move_targets() (the same filter
the menu applies: every other panel that accepts_tabs), the menu renders
only when it is non-empty, and a test pins the lone-panel and
protected-anchor cases.

(cherry picked from commit 671463c1af)
2026-10-19 04:17:34 +00:00
Marco Arnulfo 5ac5d26be1 Truncate dock tab labels that do not fit their tab
A tab squeezed below its natural width painted its whole label centred and only clipped it, so long names ran over the tab's edges and under its neighbours. The label is now cut with '…' inside the same padding the natural width is measured with, and a cut tab names its panel in full on hover.

(cherry picked from commit 5c28add6cf)
2026-10-19 04:17:34 +00:00
euisuh 9cbc0888ce fix(ui): end floating group drags on pointer exit
Discard a renderer-owned group gesture when its pointer disappears so a
missing outside release cannot resume dragging, while retaining touch drops.

Closes #95

Co-Authored-By: OpenAI Codex <noreply@openai.com>
(cherry picked from commit 9a6f159fc5)
2026-10-19 04:17:34 +00:00