142 Commits
Author SHA1 Message Date
Zinadin ZidanandClaude Opus 5.5 9f68b84897 docs(docking): a label left with a digit keeps its text, not only one with a letter (#410)
A blank name falls back to the default label only when no letter or
digit is left ("{name} 2" gives "2"); the docs and the rustdoc of
labels::named said a letter. A test pins both cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 17:59:40 +06:00
Zinadin ZidanandClaude Opus 5.5 0f2ad92204 docs(docking): a group drawn without a drag bar is moved by its border band (#410)
The accessibility section said a group's top border band is never
announced. Where no drag bar is drawn the band is the group's one move
handle and has the node.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 17:35:37 +06:00
Zinadin ZidanandClaude Opus 5.5 b4bd8e6f70 docking: each move handle has one name, after what it moves (#410)
A group's drag bar and its top border band were both buttons with
move_group_label, so a screen reader heard every group twice, and every
group and column bar had the same name. The band, which only drags, is
now out of the accessibility tree and keyboard focus (unless no bar is
drawn), and a `{name}` in move_group_label or move_column_label stands
for what the handle moves: the logical label of the panel the group
shows, or the titled panels a column's groups show, joined by ", ". A
blank title leaves the placeholder out with the brackets, quotes or
separator around it. Labels without it, today's defaults included, are
used unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 12:44:01 +06:00
aiongg 970fd6fa39 keymap: test the UK ISO key; the Turkish Q item applies to Windows and Linux 2026-11-01 03:31:51 +00:00
dotCooCoo fc37b20235 keymap: the ISO key next to left Shift can be bound to shortcuts
craft_keymap::Key gains IntlBackslash, the key between left Shift and Z
on ISO keyboards (`<` and `>` on Turkish Q). Key::from_egui and to_egui
map it to egui's IntlBackslash, so the shortcut recorder records it and
the dispatcher runs its bindings. Its shortcut text is `IntlBackslash`
(`Cmd+IntlBackslash`, `Shift+IntlBackslash`), read without regard to
case; `<` and `>` still parse as no key.

The key counts as a symbol position: Shift stays in the chord, and once
the layout has typed `<` there, display_for shows `Ctrl+<`.
MAX_CHORD_TEXT goes from 64 to 72 bytes so that the longest canonical
trigger, `Cmd+Ctrl+Alt+Shift+IntlBackslash` pressed twice, reads back.
2026-10-30 23:00:40 -07:00
aiongg a2be97cf8e docs: tidy AGENTS.md and clean-room doc 2026-10-31 04:17:35 +00:00
Dylan M. Taylor b645a09174 Merge pull request #365 from rwoldberg/clean-room-crw-format-decode
Clean room crw format decode
2026-10-30 22:40:13 -04:00
Dylan M. Taylor 04aa1703b3 update: honor pretend versions in app release checks (#436) 2026-10-30 02:12:36 -04:00
Dylan M. Taylor 8829439d68 crw: address the remaining CodeRabbit record findings
- 02 §4: the decoder refuses the G5 with Error::Unsupported; the embedded-JPEG fallback is the
  caller's, not the decoder's.
- 04: the Auto-slot claim holds outside the white-balance preset captures.
- The record README no longer says it holds everything in the order it happened: the derivation
  trail stays at the pinned LightCraft revision.
- docs/clean-room.md allows that split for a derivation done in another repository, so the
  standard and the CRW record agree.
2026-10-28 22:19:44 -04:00
Dylan M. Taylor fea36c4309 Merge branch 'main' into clean-room-crw-format-decode 2026-10-28 22:10:33 -04:00
aiongg bd97cb760c craft-ui: iconic flyouts stay open by default (#384) 2026-10-27 01:49:01 -04:00
RWoldbergandClaude Fable 5.1 a0c8a08020 craft-crw: Canon CRW (CIFF) raw decoder, moved from LightCraft with its clean-room record
The clean-room Canon CRW decoder written in LightCraft (crates/raw/src/vendor/crw.rs,
crw_tables.rs, branch clean-room-crw-format-decode, revision 70c755e4) becomes the shared
crate craft-crw: the CIFF heap container, the entropy coding derived by black-box analysis
(frozen code tables for selectors 0-2), sensor black and white levels, as-shot white
balance, orientation and the make/model/time records. Public types are the crate's own
(Error, Limits, Cfa, Rect, BlackLevel, Header, Image); the capture time is handed on as
Unix seconds so no calendar code lives here; LightCraft's shared plateau estimate is
copied as saturation_plateau. Algorithm, tables and thresholds are unchanged.

Tests: the ported synthetic round-trip, table-structure and hostile-input tests; a
proptest mutation sweep (tests/robust.rs); and tests/samples.rs, which pins the eleven
CC0 raw.pixls.us sample files (tests/samples.json: URL, SHA-256, licence) to the SHA-256
of the verified decode plus levels, white balance and metadata, so the port is proven
byte-identical to the LightCraft decode without redistributing the reference TIFFs.
scripts/fetch-crw-samples.py downloads the files outside the checkout; CRAFT_CRW_SAMPLES
and CRAFT_CRW_ORACLE point the tests at them. The crate builds for wasm32.

The whole derivation record (starting assumptions, plan with the maintainer's decisions,
source log, container and payload notes, derivation log, frozen format, verification,
colour/levels notes, private-corpus and chart notes, scripts, logs and the frozen table
JSON) moves verbatim to crates/crw/clean-room/ with a README that indexes it and maps the
LightCraft paths it cites; tools/gen_tables.py regenerates src/tables.rs from the JSON,
byte for byte.

Repository: .github/workflows/crw.yml (fmt, clippy, tests on Linux, Windows and macOS;
wasm check; the sample-file job with cached downloads), README and ATTRIBUTION rows,
NOTICE source provenance, docs/clean-room.md (the clean-room standard a format crate
follows here), and AGENTS.md expanded with the start-of-session steps, the new-crate
checklist, clean-room, assets and test rules; CLAUDE.md points at it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-26 08:20:01 -06:00
aiongg 4db3dd0117 Merge commit '819fd27f002439df60c2892715bfa322b2e566ea' into docking-native-ime 2026-10-26 03:15:20 +00:00
aiongg 9d0a57ab1c Merge remote-tracking branch 'upstream/main' into lang-2-ui 2026-10-26 03:14:20 +00:00
aiongg d7b9b5618f panes: a pane dropped over a docked pane's outer or inner third docks beside it there (#357)
Dragging a pane (a docked pane's title or a floating pane) over another
pane docked at a side edge offers two dock zones: the outer third docks
it directly outside that pane, the inner third directly inside it. The
middle third is no target. The window-edge strip docks a pane outermost
on that edge. The new PaneRequest::Before(pane, before) asks the app to
move the pane to directly before another in its open list, which sets
its position on the edge; the drop preview is laid out from that order,
so it matches where the pane lands. With one slot per edge, a closable
pane dropped on an edge takes the slot.
2026-10-25 23:13:24 -04:00
aiongg 512b54355c docking: apps can draw extra tabs after a group's panel tabs (#356)
DockContent::group_extra_tabs_width and group_extra_tabs draw host tabs
right after a group's panel tabs, before the drag bar and the header.
They fit with the panel tabs as one more tab that never overflows: both
shrink widest first to min_tab_width, and in a narrower row the panel
tabs overflow while the extra tabs keep that width.
2026-10-25 23:12:14 -04:00
aiongg 28f4036f3b docking: native floating windows publish their IME descriptor
A native floating window is an egui pass of its own, and can draw several
panel bodies. A Composer drawn there records its descriptor, and the dock
area publishes it once, after the window's last body, so a body drawn after
the editor's cannot clear it and end the composition. DockContent::window_drawn
runs at the same point for apps that publish their own descriptor.
2026-10-26 02:21:16 +00:00
aiongg c692b6816d Merge remote-tracking branch 'upstream/main' into docking-native-ime 2026-10-26 02:05:07 +00:00
aiongg f85b11b8e4 docking: AppKit moves a native window for its bar drag on macOS (#341)
* docking: AppKit moves a native window for its bar drag on macOS

Moving a native window with OuterPosition every frame jitters on macOS:
the window's reported place and the pointer events disagree about where
the window is. On macOS the bar press (or the start of a drag of a
window's only tab or group) now sends ViewportCommand::StartDrag, which
winit turns into performWindowDragWithEvent, and the dock area sends no
OuterPosition for that drag.

egui keeps running frames during the move, but the window's reported
place lags it, so each frame takes the window's place as AppKit's
cursor (NSEvent::mouseLocation) less the pressed point. Drop targets,
the drag fade, cross-window routing and the drop use that point. The
drag ends on the first frame where NSEvent::pressedMouseButtons or egui
reports the release, and is resolved once; a desktop drop records
cursor less grab. Ctrl/Cmd is read from AppKit's modifier flags, since
AppKit sends no key events during the move, and Escape does not cancel
the move. A press released within the click distance docks nothing.
Windows, X11 and Wayland keep their paths.

The window system seam (WindowSystem, formerly DesktopCursor) tells the
cursor, the button, the modifiers and whether it moves windows.
NativeHost models AppKit's move (moves_windows, held): the window
follows the cursor at the grab and reports its place late. The
app-driven cursor path from #325 and its stale-pointer model are
removed, since macOS no longer takes that path.

* docs: a cancel during an AppKit bar drag leaves the window moving
2026-10-25 21:58:02 -04:00
aiongg 3c574ddc61 craft-ui: interface fonts, text direction, IME composer, localized widgets and screen testing
craft-fonts-build gains Embed::serve (served faces for web builds) and the coverage module that craft-ui's fonts use.
2026-10-25 19:08:59 +00:00
skylar taylor-barrick 42e30cd5b3 Reconcile native docking fixes with egui 0.37 input routing 2026-10-25 17:41:23 +01:00
skylar taylor-barrick f71bccb65e Merge latest docking preview changes into egui 0.37 migration 2026-10-25 17:24:24 +01:00
aiongg 8b19c44267 docking: a dragged window fades only while it highlights a drop target (#321)
* docking: a dragged native window fades only while a drop target is highlighted

The dragged window stays opaque over empty space and goes to 75% only
while the bar, only-tab or only-tab-row drag shows a drop preview.
paint_group_drag reports whether it highlighted a target; end_cross keeps
that for the next frame, since the dragged window sets its opacity before
the preview is drawn.

* docking: a dragged in-window floating window fades only while a drop target is highlighted

The rule for native windows covers in-window floating windows too. A
title bar drag draws its window at DRAG_OPACITY (75%) while the drag
highlights a drop target, and opaque over empty space and after a drop,
Escape or focus loss. finish_group_drag keeps paint_group_drag's result
for the next frame, since the window draws before the preview.
FloatingFrame takes an opacity for the whole frame, contents included.

* docking: a title-bar drag also fades over a preview the host draws
2026-10-25 12:21:53 -04:00
aiongg da5bc8df94 docking: native palettes stay shown while the app is inactive (#326)
* docking: keep native palettes shown while the app is inactive

Palettes no longer hide when none of the application's windows has focus.
They drop to WindowLevel::Normal while the application is inactive, so
they do not cover other applications, and go back to AlwaysOnTop when it
is active again. Files dragged from another application reach them, OS
sheets attached to them stay open, and they stay shown, dimmed, while an
app modal blocks input.

* docking: on Windows an inactive app's palettes go behind other windows

* docking: the viewer level test expects the inactive palette level
2026-10-25 12:18:10 -04:00
aiongg 200b68fd6a docking: a macOS window bar drag follows AppKit's cursor (#325)
AppKit reports a native window's new place as soon as a move is
commanded, but measures the pointer events it sends against where the
window server had the window, which can be a move behind. Placing the
window from those events made it overshoot and step back while the
cursor moved smoothly.

On macOS the window now goes to NSEvent::mouseLocation, flipped against
the primary screen's height and divided by egui's zoom factor, less the
pressed point; drop targets are hit at the same point. Other platforms
keep placing the window from the frame's pointer move.

The cursor source is a DesktopCursor the test harness fixes. NativeHost
can tell the cursor (tells_cursor) and measure a window's pointer events
against its place some frames back (stale), through window_pointer.
2026-10-25 12:09:34 -04:00
aiongg c74116411d docking: a group drops on its own column's window edge, and window-edge drops preview a line (#324)
A group bar drag to a dock band named by one of the moving panels, such as the window edge of the column the group heads, anchors on another panel of that column, as a tab drag does; with none, the drop is a no-op. Before, the model rejected the move and the drop did nothing.

Drops on the bands along the layout's outer edge (a new dock, a new outermost column, the outer edge band) preview the line along that edge instead of the rect the panels take; drops beside groups keep the rect. The window-edge column line sits inside the window, like the new-dock line.
2026-10-25 12:08:55 -04:00
skylar taylor-barrick e5da4a7a68 M0: reconcile shared UI and updater changes with egui 0.37 2026-10-25 17:07:55 +01:00
aiongg bab74e1f4c docking: a canvas body takes no drop in the docking profile (#323)
With new_dock_zones (and without side_edge_zones), the body of a frame or
floating group that takes no tabs is no drop target, whatever its
accepts_splits. A floating window released there stays floating and a
docked panel floats as over empty space; the outer edge band, dock columns,
new docks and drops beside other groups still dock. Without new_dock_zones
the whole canvas body still goes to the nearest of drop_edges.
2026-10-25 12:07:15 -04:00
aiongg 2ccf7ea3a2 Merge remote-tracking branch 'upstream/main' into dock-result-preview
# Conflicts:
#	crates/ui/src/docking/drop_tests.rs
#	crates/ui/src/docking/render/preview.rs
2026-10-25 14:01:23 +00:00
aiongg 79709a7a70 Merge commit '3e72e33d' into dock-result-preview 2026-10-25 14:00:24 +00:00
aiongg edef7915d2 docking: fixes from the first Mac test round (edge band, drop_edges, no-op drops, narrow frames, pane previews) (#312)
* docking: fade a dragged native window only when the drag can dock

* docking: narrow the outer edge band to the canvas column and add DockStyle::drop_edges

* docking: drop_edges defaults to all sides; the docking profile's outer band takes only its top and bottom

* panes: preview the slot a dragged pane docks in, also while floating

* docking: a drop that changes only sizes is a no-op; a lone floating group's header drag looks through its window

* docking: a drop beside a frame too narrow to halve takes the room from beyond its divider

* panes: the dock preview counts a pane its drop reveals, and a side pane stays inside the host

With SidePolicy::OneSlot a drop can reveal a pane the frame hides, so the landing slot is
worked out from every open pane. A side pane is no wider than the room the panes outside it
leave, as the preview assumes; egui placed a wider one partly beyond the host's edge.

* docking: anchor an outer edge drop on the area it shows

The edge band and window.panel.dock to an outer edge anchor on the canvas only where the edge area narrows to the canvas column, else on a panel that is not protected, so tree order no longer decides the frame. The renderer tries the drop and offers the band only when it wraps the panels the band shows. A top (bottom) edge also narrows a split of rows to its first (last) row when only that row holds the canvas. to_actions takes the permissions, and FloatSpace records side_edge_zones.

* docking: a sized split gives the new frame its minimum or saved width

* docking: keep a native window opaque during a float-only drag

* docking: DockCommand::to_actions keeps its signature; to_actions_with takes the permissions

FilmCraft calls to_actions. Without permissions no panel is protected, so an outer edge dock
wraps the part between the docks, as before.
2026-10-25 09:59:17 -04:00
aiongg ea4c823abb docking: save every floating window's id (#317) 2026-10-25 09:50:13 -04:00
aiongg 3e72e33dae Merge remote-tracking branch 'upstream/main' into mac-b1-edges
# Conflicts:
#	crates/ui/src/panes/mod.rs
2026-10-25 13:49:59 +00:00
aiongg 766f5a01c6 ui: panes::Rail, an icon strip that opens one task pane at a time (#309)
* ui: panes::Rail, an icon strip that opens one task pane at a time

* ui: panes: a docked pane can go without its title bar

* ui: panes::Rail review fixes

* ui: panes: a docked pane's resize edge works on both sides of the line
2026-10-25 09:48:51 -04:00
aiongg cdc6713130 Merge branch 'mac-b1-edges' into dock-result-preview 2026-10-25 07:01:22 +00:00
aiongg 91aaa294d0 docking: anchor an outer edge drop on the area it shows
The edge band and window.panel.dock to an outer edge anchor on the canvas only where the edge area narrows to the canvas column, else on a panel that is not protected, so tree order no longer decides the frame. The renderer tries the drop and offers the band only when it wraps the panels the band shows. A top (bottom) edge also narrows a split of rows to its first (last) row when only that row holds the canvas. to_actions takes the permissions, and FloatSpace records side_edge_zones.
2026-10-25 06:18:34 +00:00
aiongg d004f40c25 docking: preview a drop beside something with the rect the panel takes 2026-10-25 05:56:38 +00:00
aiongg 950b9644e8 docking: a drop beside a frame too narrow to halve takes the room from beyond its divider 2026-10-25 05:34:35 +00:00
aiongg 63b3e4e2e8 docking: a drop that changes only sizes is a no-op; a lone floating group's header drag looks through its window 2026-10-25 05:34:35 +00:00
aiongg f268d21055 panes: preview the slot a dragged pane docks in, also while floating 2026-10-25 05:20:53 +00:00
aiongg 876d2539f9 docking: drop_edges defaults to all sides; the docking profile's outer band takes only its top and bottom 2026-10-25 05:20:27 +00:00
aiongg 889f0367f2 docking: narrow the outer edge band to the canvas column and add DockStyle::drop_edges 2026-10-25 05:18:09 +00:00
skylartaylor f8c6a3d51b E21: reconcile whole-group docking targets from current main 2026-10-25 05:40:42 +01:00
aiongg 8a503cfe79 docking: drop targets follow the pointer over the whole group (#310)
* docking: drop targets follow the pointer over the whole group

Outside side_edge_zones, a group body's outer third on each side docks
beside it and the middle joins as a tab; at a corner the relatively
nearer side wins, and a group that takes no tabs maps its whole body to
its edges. Dock-column groups get the same zones: top and bottom stack,
left and right make a column. Border bands (seam, column edge, new
dock, root edge) are 28 pt and reach only 4 pt into a tab strip that
takes tabs.

Previews are a drop_line_width line along the edge a drop docks to, or
the whole group's outline with a light fill for a tab join, for tab and
group drags alike. side_edge_zones keeps its 40 pt picture-frame zones,
overlay and previews (SIDE_EDGE_ZONE_DEPTH).

DockStyle: side_zone_fraction replaces zone_depth; new column_edge_band
and drop_line_width; edge_band, seam_band and new_dock_band default to
28.

* docking: document the drop zones, bands and previews

* docking: dock groups and the outer edge band keep the split-tree sizes with side edge zones

* docking: drop zones for hosts that resolve drops, lines kept in view, stripless dock groups

resolve_drop_by and DockStyle::zone_rule give hosts the dock area's zones and previews.
A stack line on an edge scrolled out of a dock column shows at the view's edge, and a dock
group without a tab strip takes its zones from the top of its body. A style needs a drop
line wider than zero and a side zone fraction of at most one half.
2026-10-24 23:51:43 -04:00
skylartaylor 6fe4139998 egui037: preserve current docking and printing and prevent input-hook deadlock 2026-10-25 04:00:32 +01:00
aiongg e95bc0d2a2 docking: blocking input hands the keyboard to the main window (#306)
* docking: blocking input hands the keyboard from a native window to the main window

* docking: the keyboard goes to the main window only if a native window still has it after a short wait
2026-10-24 22:10:52 -04:00
aiongg 869928d2a0 docking: app drags in panel bodies reach other native windows (#302)
* docking: route app drags in panel bodies across native windows

While an app's drag that began in a panel body lasts, the owner window's
input hook sends pointer moves over another of the app's windows to that
window in its coordinates (PointerMoved, PointerGone, and the primary
release), and the owner sees the pointer gone there. Drop sites in the
target window see hover and release with no app changes.

* docking: wrap the body-drag docs

* docking: a stopped body-drag route takes back the events it queued

* docking: route only body drags that carry a payload, and hold the owner's release

A body drag reaches other windows only with an egui drag-and-drop
payload or when the app calls docking::route_app_drag that frame or the
last; sliders, scrollbars and other plain drags keep the owner's
pointer. When the release goes to another window, the owner's own
release waits for its next input, so a target drawn before the owner
reads the release while egui's payload still exists. A stop never
withdraws that held release.

* docking: routed and held events come before a window's own input

* docking: a held release waits for the main window's next pass, with the pointer events after it

* docking: the owner sees the pointer go in the pass its release is held
2026-10-24 20:36:23 -04:00
skylartaylor 650b1c0b05 M037: reconcile current libraries and preserve native IME reset acknowledgements 2026-10-25 01:58:55 +02:00
skylartaylor b282cb2d29 egui037: Reconcile shared UI pins with reviewed PDF updates 2026-10-25 01:29:13 +02:00
aiongg 38c4ecab17 docking: native windows ignore input while the app shows a modal (#298)
* docking: native windows ignore input while the app shows a modal

DockArea::input_blocked disables each native floating window's widgets, drops its pointer, key, text and scroll input, covers it with DockStyle::blocked_dim over a layer that takes the pointer, offers no drop targets, forwards no events and cancels its OS close request. Turning it on cancels a drag in progress.

* docking: a blocked native window also drops hovered and dropped files

* docking: blocked palettes drop to the normal window level

* docking: a blocked native window still forwards key releases

* docking: while input is blocked, activation raises the main window last

* docking: blocked palettes stay shown, and the main window comes in front on the app's return
2026-10-24 18:27:19 -04:00