M14: distinguish qualification from publication (#4173)

This commit is contained in:
skylar taylor-barrick
2026-10-25 23:47:58 -04:00
committed by GitHub
parent 3ce284cda3
commit 581c79dcb1
27 changed files with 298 additions and 50 deletions
+3 -1
View File
@@ -1,5 +1,6 @@
# Development
> **Last updated:** 2026-10-25 · **Change:** Linux Wayland drag-and-drop note names eframe 0.37 (still on winit 0.30).
> **Last updated:** 2026-10-23 · **Change:** Tests: cargo xtask test, one integration-test binary per crate, the dev profile's debug info.
> **Last updated:** 2026-10-21 · **Change:** the interface faces as vectorcraft-ui-egui's `interface-fonts` feature, and `theme::install_fonts` for an embedder that draws the panels itself.
> **Last updated:** 2026-10-21 · **Change:** leaving out the bundled fonts with the egui panels (vectorcraft-ui-egui's and vectorcraft-mcp's `bundled-fonts` features).
@@ -115,7 +116,7 @@ The window runs natively on Wayland (eframe's `wayland` feature) and on X11. On
- **Clipboard:** under Wayland arboard talks to the compositor through the data-control protocol (wlroots compositors such as Sway and Hyprland, KDE Plasma), so bitmaps (`image/png`), SVG markup and text copied in any app paste (#398). Where the compositor lacks the protocol (GNOME's Mutter, [arboard#223](https://github.com/1Password/arboard/issues/223)), arboard falls back to the X11 clipboard through XWayland, which only holds what X11 apps copied. egui's own text paste into fields goes through smithay-clipboard and works either way.
- **Clipboard owners that never answer (#510):** reading the clipboard waits on the app that owns it: arboard gives up on an X11 owner after 4 s, and a Wayland read waits for the owner to send its data. So on Linux the check that enables the Paste menu items runs on a background thread with a second clipboard handle (`crates/ui-egui/src/clipboard_probe.rs`, installed as `Services::clipboard_probe`), only while nothing is copied in the app and a document is open, and the window keeps drawing. A paste itself still reads on the UI thread, so pasting from such an owner waits for it once. Windows and macOS keep the check on the UI thread: Windows only asks which formats the clipboard holds, macOS asks the pasteboard server.
- **Copied files:** files copied in a file manager (`text/uri-list`; `CF_HDROP` on Windows, file URLs on macOS) paste as the first one that is art (SVG, PDF, EPS, EMF/WMF or a bitmap; a `.ai` or `.ait` file from the editing data it holds, else as the PDF or PostScript it holds), before the clipboard's other formats (which include the files' paths as text).
- **Dropping files on the window does not work under Wayland:** winit 0.30, which eframe 0.36 runs on, has no Wayland drag and drop ([winit#1881](https://github.com/rust-windowing/winit/issues/1881), added in winit 0.31; [egui#1563](https://github.com/emilk/egui/issues/1563)), so no `dropped_files` arrive. Until eframe moves to winit 0.31: copy the files in the file manager and paste them, use File › Place or Open, or open the window through XWayland, where drops work: set **Preferences › Performance › Linux Display Server** to **X11 (XWayland)** and restart (#1151), or start the app with `WAYLAND_DISPLAY= vectorcraft`. The preference (`linuxDisplayServer`, read at startup in `apps/vectorcraft/src/main.rs`, shown on Linux only) has winit open the window on X11 (`EventLoopBuilderExtX11::with_x11`) when the session is Wayland, `DISPLAY` is set and the X11 libraries winit loads are installed (`apps/vectorcraft/src/xwayland.rs` reads `ldconfig -p` and the usual library directories); otherwise the window opens on Wayland and the log says why. Unlike clearing `WAYLAND_DISPLAY`, it leaves the clipboard on the compositor's own.
- **Dropping files on the window does not work under Wayland:** winit 0.30, which eframe 0.37 runs on, has no Wayland drag and drop ([winit#1881](https://github.com/rust-windowing/winit/issues/1881), added in winit 0.31; [egui#1563](https://github.com/emilk/egui/issues/1563)), so no `dropped_files` arrive. Until eframe moves to winit 0.31: copy the files in the file manager and paste them, use File › Place or Open, or open the window through XWayland, where drops work: set **Preferences › Performance › Linux Display Server** to **X11 (XWayland)** and restart (#1151), or start the app with `WAYLAND_DISPLAY= vectorcraft`. The preference (`linuxDisplayServer`, read at startup in `apps/vectorcraft/src/main.rs`, shown on Linux only) has winit open the window on X11 (`EventLoopBuilderExtX11::with_x11`) when the session is Wayland, `DISPLAY` is set and the X11 libraries winit loads are installed (`apps/vectorcraft/src/xwayland.rs` reads `ldconfig -p` and the usual library directories); otherwise the window opens on Wayland and the log says why. Unlike clearing `WAYLAND_DISPLAY`, it leaves the clipboard on the compositor's own.
- **Pens and pen displays under Wayland (#491, #2028):** winit 0.30 doesn't bind the Wayland tablet protocol (`zwp_tablet_v2`; tablet input arrives in winit 0.31, [winit#4318](https://github.com/rust-windowing/winit/pull/4318), [egui#7731](https://github.com/emilk/egui/pull/7731)). Since Plasma 6.3, KWin no longer turns tablet input into pointer input for such apps ([kwin!6336](https://invent.kde.org/plasma/kwin/-/merge_requests/6336), commit [25c65abd](https://invent.kde.org/plasma/kwin/-/commit/25c65abddd95eb87fb892a8594faccbf509ff62f)), and GNOME's Mutter does not turn it into pointer input either (that commit's message): on KWin the pen moves the compositor's cursor over the window, but the app gets no motion or presses and shows none of its own cursors. Until eframe moves to winit 0.31, either run the app under XWayland, which supports the tablet protocol and hands the pen to X11 apps as a pointer (Preferences › Performance › Linux Display Server › X11 (XWayland); X11 (XWayland) When a Pen Is Attached (`x11WithPen`), which opens the window through XWayland only when `/proc/bus/input/devices` lists a pen as the app starts, a device with the `BTN_TOOL_PEN` key and the `ABS_X` and `ABS_Y` axes, and logs `pen found: opening the window through XWayland`; `WAYLAND_DISPLAY= vectorcraft`, or `env -u WAYLAND_DISPLAY vectorcraft`; for a desktop launcher, put `env WAYLAND_DISPLAY=` before the command in its `Exec=` line), or turn KWin's deprecated emulation back on for the whole session by setting `KWIN_WAYLAND_EMULATE_TABLET=1` in KWin's environment (for example in a file under `~/.config/environment.d/` or in `/etc/environment`) and logging in again. The pen then works as a mouse. Under XWayland the app also reads the pen's pressure (next item); with KWin's emulation on native Wayland the pen has no pressure. Other compositors that don't emulate a pointer for tablets behave the same way.
- **Pen pressure under X11 and XWayland (#764):** winit 0.30 hands a pen to an X11 window as a mouse, without its pressure. When the window is on X11, XWayland included, the desktop app opens a second X connection (x11rb's `RustConnection`) and reads XInput2 raw events for every device (`apps/vectorcraft/src/tablet.rs`, from PhotoCraft's `crates/tablet`). A device with an `Abs Pressure` valuator is a pen, unless its XInput type is `TOUCHPAD` or `TOUCHSCREEN`. While a pen is the pointer that moved last, its pressure, scaled from the valuator's range to 0..1, reaches the tools that use pressure: the Paintbrush's pressure-sensitive brushes and the Liquify tools' Use Pressure Pen. A pen device whose name or XInput type contains `eraser` (in any case) is the pen's eraser end: while the pointer is over the window, the canvas selects the Eraser tool when the eraser end moves, and it selects the tool used before when the tip moves again (`crates/ui-egui/src/stylus.rs`). The X server needs XInput 2.1 or later; otherwise the log has a `tablet pressure:` warning with the reason, and the pen draws at full pressure.
@@ -490,6 +491,7 @@ Scores and hour estimates are unchanged.
| Date | Change | Summary |
|---|---|---|
| 2026-10-25 | minor | Linux Wayland drag-and-drop note names eframe 0.37 (still on winit 0.30); behavior unchanged. |
| 2026-10-23 | minor | Tests: `cargo xtask test` (nextest, then doctests), one integration-test binary per crate and the files that keep their own, the dev profile's debug info. |
| 2026-10-21 | minor | Fonts › Leaving out the bundled fonts: vectorcraft-ui-egui's `interface-fonts` feature, and `theme::install_fonts` for an embedder that draws the panels without `VectorcraftApp::logic`. |
| 2026-10-21 | minor | M3: highlighted-text Eyedropper sampling preserves ranges and rejects unsupported source/target transparency atomically; regression-tested; scores and estimates unchanged. |
+67 -49
View File
@@ -1,11 +1,15 @@
# VectorCraft — egui 0.37 migration plan
**Status (2026-10-25):** reconciled main `8bf090b25389b48aa6f9d7415de57c9ce7ccf8cb` and passed all 12 mandatory CI stages. Managed job `egui037-vectorcraft-artboard-green-ci-20261025-0589` recorded 10,197 passing test executions, zero failures and 14 ignored. This includes the artboard-name geometry regression, demonstrated failing before the explicit inset repair; input/IME fixtures, no-bundled-font checks and the web app build passed. Native/platform GUI and IME workflows, final packages and paired app performance remain open. Earlier source identities and counts below are historical.
**Status (2026-10-25, shared-docking reconciliation):** the published qualification remains checkpoint `83d6dd2d6603845978f949523e6da2b4945dcffb`, tested with post-PR-4113 `main` `6e7854967d6b8a094bfed809643bd957aa3ba66f` and the two `Id::unique` edits at `crates/ui-egui/src/dialogs/recolor.rs:384,725`; managed job `egui037-vector-postmerge-ci-20261025-1381` passed all 12 mandatory CI stages for that working tree, and publication commit `1072d0e263623882da68d8115934630abbef33ae` records it in PR #4173. The reviewed recolor code is already in `main`: `HEAD` and `origin/main` resolve the same blob `6050af15a3bf7b9a056df6dff347bda7690ad251` for that file.
This checkout, at documentation-only follow-up `12fee85c9cbf9f7f1609a53bc67327b12e4f4dd1` (`M14: distinguish qualification from publication`), is locally reconciling upstream `main` `714434527e1a3e03c4b49096e30dd92b258aab50` (PR #4135: panels on craft-ui's shared docking, floating panels in OS windows). The four conflicted files were resolved by taking upstream's `dock.rs`, `panel_docking.rs` and `panel_docking_tests.rs` and deleting `floating.rs`; `git diff` against `714434527…` is empty for those three files, and no `crate::floating` or `mod floating` path remains. Managed CI job 1422 passed all 12 mandatory stages on the pre-merge tree (`12fee85c9…`); managed job `egui037-vector-combined-ci1443` subsequently passed all 12 mandatory CI stages on the combined working tree, including WASM. Independent integration reviews accepted the conflict resolutions and shared-library pins. This qualification covers the executable source and lockfile; the qualification prose was updated afterward to record that result. Native/platform GUI and IME workflows, final packages and paired app performance remain open.
**Historical status (superseded, not current acceptance):** the earlier reconciliation against `main` `8bf090b25389b48aa6f9d7415de57c9ce7ccf8cb` and managed job `egui037-vectorcraft-artboard-green-ci-20261025-0589` recorded 10,197 passing test executions, zero failures and 14 ignored, including the artboard-name geometry regression, input/IME fixtures, no-bundled-font checks and the web app build. The 0.36.2 lock table and the plan-time local craft-libs/CL-2F statements below are historical planning state. Current dependency pins (read from this checkout's `Cargo.toml` and `Cargo.lock` on 2026-10-25): `egui`, `eframe`, `egui-winit`, `egui-wgpu`, `egui_glow`, `egui_extras`, `egui_kittest`, `epaint`, `emath`, `ecolor`, `epaint_default_fonts` are `0.37.0` from `storytold/egui` rev `6d518fc799681571963842f95b55a6b68431b15a`; `egui_system_font_provider` has an unused patch at that same revision and is not in the resolved dependency graph; `winit` is `0.30.13` from `storytold/winit` rev `a517b3846ee8457d84ee4975110bfda6797c44dc`; `wgpu` is `30.0.1`; `kittest` is `0.5.0`; `accesskit`/`accesskit_winit` are `0.25.1`/`0.34.1`; `craft-ui`, `craft-window`, `craft-keymap`, `craft-print`, `craft-pdf` and `craft-docpath` use published `storytold/craft-libs` rev `a0916808f7d78bed8c7b90cdf937176015454a7f`, as do the `hayro-*` and `krilla` patches.
**Earlier status (historical):** implementation revision 4, 2026-10-24. The VectorCraft migration is implemented in the
`vectorcraft-implementation` worktree; this revision incorporates the final upstream-review repairs. The exact
current tree still needs a fresh managed build/test/lint run before publication; earlier managed evidence
(`tests-12`, `lints-13`) is not claimed for these later edits. Every claim below remains source-grounded in the
`vectorcraft-implementation` worktree; this revision incorporates the final upstream-review repairs. At revision 4
the exact tree still needed a fresh managed build/test/lint run before publication; earlier managed evidence
(`tests-12`, `lints-13`) is not claimed for those later edits. Every claim below remains source-grounded in the
checkouts named here; historical compiler diagnostics and reviewer findings are clues, not acceptance evidence.
**Assigned source:** `/home/codex/work/CraftApps/egui037-migration-20261022/vectorcraft-implementation` — the
@@ -24,6 +28,15 @@ implementation worktree. The earlier pinned review checkout was `vectorcraft` at
`/home/codex/work/ssd2/task-evidence/egui037-migration-20261022/remote-plan-bases-20261023-0632.json`.
**Clean-room note:** this plan uses only public specifications, public documentation and source code. It does not use, inspect or compare against any Adobe application, asset or output.
### Shared-docking integration (current, 2026-10-25)
This subsection records the current code after PR #4135; §§2–5 below remain the original planning record and are marked historical where the merged code replaced them.
- **Desktop versus web/Wayland:** on the desktop, floating panels open in OS windows of their own through craft-ui's target-gated `native-windows` feature (`crates/ui-egui/Cargo.toml`, `crates/ui-egui/src/panel_docking.rs` module docs, `apps/vectorcraft/src/main.rs::native_input_hook`). On the web and on Wayland they float inside the app window (`panel_docking.rs`; `docs/control-protocol.md`).
- **Removed app-side floating:** `crates/ui-egui/src/floating.rs` is deleted. `dock.rs` is now 137 lines and holds `panel_body` plus two scroll-bar tests; `panel_docking.rs` draws the canvas and panels through `craft_ui::docking::DockArea`, with the session-only `Runtime`, `inspect`, `hit_rects`, `known` and `valid`. The old `apply_pending_dock_width`, `cancel_legacy_drag`, `seed_dock_panel_width`, `note_dock_width`, `legacy_dock_default_width`, `shared_dock_default_width` and `dock_width_pending` symbols are gone. `tools_float.rs` keeps the Tools panel's own move state.
- **Dock-width persistence:** `UiState::dock_width` is the app-owned preference. `panel_docking::main_width` clamps it into the default layout, `default_flags`/`Transaction::commit` writes a resized width back, `workspaces::Workspace` captures and applies it (test `saved_workspaces_restore_dock_width`), and `layout_migration` carries it across older preference files. No `PanelState` seeding is used for dock width.
- **Tests:** `panel_docking_tests.rs` covers pointer/keyboard docking; `panel_docking_native_tests.rs` covers desktop OS windows (keyboard, drops, modal focus and `ui.docking` hit-rect filtering); `layout_migration_tests.rs` covers conversion of layouts saved before the canvas joined the shared dock; `dock.rs` retains two scroll-bar accessibility tests; `workspaces.rs` covers saved-width restore. These test surfaces are included in the combined-tree CI qualification recorded above; native GUI workflows remain a separate open gate.
This plan is deliberately app-specific. The suite-wide dependency order and shared acceptance contract are in the
local planning draft `craft-libs/docs/egui-037-suite-rollout.md` (not yet published at the time of writing); this
document only records what VectorCraft must do, what it must prove and what remains unresolved. The shared
@@ -34,8 +47,8 @@ lifecycle, capture-slot, performance and font-fixture contracts in that rollout
## 1. Executive decision
Migrate VectorCraft from the coherent egui **0.36.2** family (currently resolved from crates.io, with `craft-ui` and
`craft-window` pinned to 0.36-era craft-libs revisions) to the selected **egui 0.37.0** family and the suite's
Migrate VectorCraft from its pre-migration coherent egui **0.36.2** family (then resolved from crates.io, with
`craft-ui` and `craft-window` pinned to 0.36-era craft-libs revisions) to the selected **egui 0.37.0** family and the suite's
`winit 0.30.13` language fork, in a sequence that never leaves `main` with a mixed or unbuildable dependency graph.
The migration is not a version-string bump:
@@ -94,7 +107,7 @@ publishing a mixed or reduced graph.
| storytold egui 0.36.2 | `767b1cad294120689a514bb4bd68c077e46679b9` (`craft/0.36.2`) | Existing published fork for comparison |
| aiongg winit candidate | `8b35388bd719e8cc86a95971ba0bc026c9a8f058` (`aiongg/winit craft/0.30.13-lang`) | **Research input only**, not a production pin; missing W15P and W27 lifecycle revisions |
| Published storytold winit | `ffae5198770d7730e718043f035a772b7dbc3b1b` (`craft/0.30.13`) | Old coherent comparator |
| craft-libs implementation base | `3832c47ef68a0e6214f2c1e85f3526b6adcb686e` | Current local shared-library tree and the base for the implemented port; it already carries PR 199's egui 0.37 update, while the CL-2F capture helper remains uncommitted and is a publication gate |
| craft-libs planning base (historical) | `3832c47ef68a0e6214f2c1e85f3526b6adcb686e` | Local shared-library tree used to prepare the port; it carries PR 199's egui 0.37 update. It is not the current pin. The current workspace uses published craft-libs `a0916808f7d78bed8c7b90cdf937176015454a7f`, which includes the CL-2F capture helper |
| craft-libs PR 199 head | `b68de8c5f4f1c060904d211a7b1320aa0f7bce78` | **Stale tree; do not merge.** Reuse selected port hunks only (§3.7) |
| craft-libs PR 199 API commit | `8614e4a04fae516fba16c22b31ff1008cb6be10b` | Historical source of the egui API-port hunks already contained in the `3832c47…` base |
| craft-libs PR 199 README commit | `1764bca` | README/`scope_id` example hunk to review and apply separately |
@@ -103,7 +116,7 @@ publishing a mixed or reduced graph.
| Adversarial plan review, revision 2 | `plan-reviews/vectorcraft-v2.md` | Reviewed document `d8c6a7594015919751d2b83bbe0e44ee9fdb4696b4e5c90fb1f8ecbdf7335f83`; findings resolved in §8.2 |
| Remote bases snapshot | `remote-plan-bases-20261023-0632.json` | Records all suite heads and the two-commit VectorCraft drift above |
Current VectorCraft lock identities (from `Cargo.lock`):
Historical pre-migration VectorCraft lock identities (from `Cargo.lock` at the pinned `890607…` baseline; the 0.36 comparison arm, not the current lock):
| Package | Version | Source |
|---|---|---|
@@ -144,12 +157,15 @@ Root workspace (`Cargo.toml`):
- `resolver = "3"`, members `crates/*`, `apps/*`, `xtask`; default members include `apps/vectorcraft`,
`apps/vectorcraft-cli` and `xtask`.
- Workspace UI dependencies at lines 102–105: `egui = "0.36"`, `egui_extras = { version = "0.36",
default-features = false, features = ["svg"] }`, `eframe = { version = "0.36", default-features = false }`,
`egui_kittest = "0.36"`.
- `craft-ui` rev `5c874d…` with `serde`; `craft-window` rev `1f805…` with `egui`.
- Root `[patch.crates-io]` currently patches `hayro-syntax`, `hayro-interpret`, `hayro-jbig2` and `krilla` to the
same craft-libs rev `ca50d63b…`. These are unrelated to egui and must remain unless a separate comparison proves
- Current workspace UI dependencies: `egui = "0.37"`, `egui_extras = { version = "0.37",
default-features = false, features = ["svg"] }`, `eframe = { version = "0.37", default-features = false }`,
`egui_kittest = "0.37"`.
- Current `craft-ui`, `craft-window` and `craft-keymap` pins are published craft-libs rev `a0916808…`
(`craft-ui` with `serde` and target-gated `native-windows`; `craft-window` with `egui`); `craft-print`,
`craft-pdf` and `craft-docpath` use the same revision.
- Root `[patch.crates-io]` maps the egui family (including `eframe` and `egui_kittest`) to `storytold/egui` rev
`6d518fc7…`, `winit` to `storytold/winit` rev `a517b384…`, and `hayro-*`/`krilla` to craft-libs rev
`a0916808…`. The hayro/krilla patches are unrelated to egui and must remain unless a separate comparison proves
replacement.
- `vendor/windows-link` is the only vendored package. `vendor/windows-link/VECTORCRAFT-PATCH.md` records the
provenance (Microsoft windows-link 0.2.1, crates.io, MIT OR Apache-2.0), the sole change (`CoTaskMemFree` from
@@ -160,9 +176,9 @@ Root workspace (`Cargo.toml`):
example; no egui). `crates/plugins/example/Cargo.lock` is separate and must not acquire egui.
- `crates/affinity/fuzz` has no lockfile in the checkout. Do not create one merely for this migration.
Manifests that participate in the egui graph:
Manifests that participate in the egui graph (the table records the plan-time declarations and required changes; current declarations are listed above):
| Manifest | Current UI declaration | Required change |
| Manifest | Plan-time UI declaration | Required change |
|---|---|---|
| `crates/ui-egui/Cargo.toml` | `egui` workspace + `bytemuck`; `egui_extras`; dev `egui_kittest` `wgpu`,`snapshot` | `egui` must also enable `default_fonts` for library tests/embedders and for downstream kittest tests, which do not inherit kittest's own dev-dependency fonts; `egui_extras`/`egui_kittest` to 0.37; no feature rename assumed |
| `apps/vectorcraft/Cargo.toml` | `eframe` features `default_fonts`, `wayland`, `x11`; default features `wgpu`, `accessibility`; `windows7 = ["eframe/glow"]`; direct `winit 0.30` | add **`eframe/clipboard`**; keep `links` off (existing native `open_url` service); keep `system_fonts` off; retain winit feature set |
@@ -205,15 +221,15 @@ Entry-point details that must remain true:
- The canvas is CPU-rasterized by `vectorcraft_render` and composited by wgpu; egui only uploads the raster texture.
UI-frame work and document rendering are separate measurements.
### 2.4 Current lifecycle (the facts, not the desired design)
### 2.4 Historical 0.36.2 lifecycle (planning snapshot, not current acceptance)
The current app already has:
The 0.36.2 baseline already had:
- `App::logic(&mut self, ctx, frame)` and `App::ui(&mut self, ui, frame)` in both hosts.
- `VectorcraftApp::logic(ctx)` called from the host logic, guarded by `vectorcraft_engine::guard::catch_panic`.
- `VectorcraftApp::ui(ui)` called from the host UI, also guarded.
- A root `Ui` in `App::ui`; panels are already shown with `egui::Panel::…::show(ui, …)`.
- Custom `Area`/`Window` dialogs and floating panels; no `show_viewport_deferred`/child native viewports.
- Custom `Area`/`Window` dialogs and floating panels in the 0.36.2 baseline; at planning time the app had no `show_viewport_deferred`/child native viewports. The shared-docking integration now opens desktop floating panels as craft-ui OS windows, while the web and Wayland keep them in-page (see “Shared-docking integration (current)” above).
- `ctx.run_ui` in many tests; `ctx.run_ui` in test helpers draws either the whole app or one panel/dialog.
What 0.37 makes explicit:
@@ -252,7 +268,7 @@ numbers will drift; symbols are authoritative.
| Class | Historical diagnostic examples | Source anchors in VectorCraft | Required migration |
|---|---|---|---|
| `Event::MouseWheel` gained `source: MouseWheelSource` | `canvas.rs:6226`, `chrome.rs:1691`, `stroke.rs:634`, tests | 21 `Event::MouseWheel` literals; production matches use `..` | Add `source: MouseWheelSource::Unknown` in tests/synthetic input; production events come from egui-winit. Preserve `unit`, `phase`, `delta`, `modifiers`. |
| `WidgetType` is now a deprecated alias for `accesskit::Role`, and variants were renamed | `chrome.rs:640`, `dock.rs:122`, `edit_toolbar.rs:533`, `panel_docking.rs:1241`, `widgets.rs:192/1535/1536/2487` | 54 `WidgetType` call sites | Map per §3.2 to the renamed `Role` variants. Do not hide all roles behind `Role::Unknown`. |
| `WidgetType` is now a deprecated alias for `accesskit::Role`, and variants were renamed | Historical anchors `chrome.rs:640`, `dock.rs:122`, `edit_toolbar.rs:533`, `panel_docking.rs:1241`, `widgets.rs:192/1535/1536/2487`; symbols are authoritative, not these line positions | 54 `WidgetType` call sites at planning time; the current tree has none | Map per §3.2 to the renamed `Role` variants. Do not hide all roles behind `Role::Unknown`. |
| `Id` is not an `IdSalt` | `dialogs/layer_options.rs:129/130`, `menus.rs:3482/3484` | `Atom::custom(chip, …)`; `Panel::right(Id::new(...))`; `ComboBox::from_id_salt(id)` | `IdSalt::new(...)` only for a parameter typed exactly `IdSalt` (`Atom::custom`); pass the original source to `impl AsIdSalt` APIs (`Panel`, `ComboBox`, `ScrollArea`, `make_persistent_id`). `Id::unique(...)` for root ids. Never pass an `Id` as a salt. |
| `WidgetInfo.typ` removed | `dialogs/tests_warp.rs:509` | one test | Use `info.role`. |
| `scroll_area::State.offset` private | `font_menu.rs:507`, `panels/layers.rs:650`, `tests_numfields.rs:614` | 3 sites | Use the public `offset()` method. |
@@ -297,16 +313,16 @@ names.
- Exact `IdSalt` parameters (`Atom::custom`, `Id::with_salt`) take `IdSalt::new(source)`.
- `Id` still satisfies the blanket `AsIdSalt` impl (`Hash + Debug`), so some wrong calls compile while hashing an
`Id` as a salt. That is the wrong identity even when it compiles; `Atom::custom` rejects `Id` outright.
- Dynamic dock columns (`floating.rs`: `Panel::right(Id::new(("dock-column", first)))`) must become
`Panel::right(("dock-column", first))`.
- Historical planning (pre-#4135): dynamic dock columns in the then-existing app `floating.rs` used `Panel::right(Id::new(("dock-column", first)))` and were to become `Panel::right(("dock-column", first))`. The app `floating` module is now deleted; craft-ui's shared docking owns dock columns and their layout in `panel_docking.rs`.
- Do not mechanically wrap an existing `Id` in `IdSalt::new(...)` just to satisfy a signature. Audit the few
`make_persistent_id`/`with`/`Atom::custom` sites individually and preserve the intended key with a focus/state
test. `ComboBox::from_id_salt` in `widgets::combo`, `Panel::right` in `floating.rs`, and `Atom::custom` in
`dialogs/layer_options`/`menus` are the concrete sites to review.
test. `ComboBox::from_id_salt` in `widgets::combo`, `Panel::right` in the deleted `floating.rs` (historical), and `Atom::custom` in `dialogs/layer_options`/`menus` were the concrete sites to review.
- `Id::NULL` and `Id::with(...)` remain valid.
- `Id::unique` also registers debug id sources; do not let debug-only memory growth become a concern.
### 3.4 Panel identity/persistence
### 3.4 Panel identity/persistence (historical planning; superseded by shared docking)
> **Historical planning (pre-#4135; not current code).** The text below describes the old app-owned `PanelState` width path and is retained as planning evidence. The current tree has none of `seed_dock_panel_width`, `note_dock_width`, `apply_pending_dock_width`, `legacy_dock_default_width`, `shared_dock_default_width` or `dock_width_pending`. Width now persists through `UiState::dock_width`: `panel_docking::main_width` clamps it into the default layout, `default_flags`/`Transaction::commit` writes the resized width back, `workspaces::Workspace` captures and applies it (`saved_workspaces_restore_dock_width`), and `layout_migration` carries it across older files. The layout itself is craft-ui `DockArea`/`craft_ui::docking::Layout`.
`crates/ui-egui/src/dock.rs::seed_dock_panel_width` and `note_dock_width` read/write
`egui::containers::panel::PanelState` under `Id::new(panel)`. In 0.37 `Panel` internally derives its bar id from
@@ -456,10 +472,10 @@ historical audit tree `ec8840a` is likewise unsafe. Never merge either tree:
group is movable;
- `crates/ui/src/docking/surface.rs`: resizing a floating group no longer requires all members movable.
- These checks are present in current craft-libs security work (for example #236, docking group move permission). Do not merge that tree.
- Keep the egui-related `8614e4a`/`1764bca` shape already in the `3832c47…` base and the uncommitted capture
helper, preserving the current permission
checks, `craft-platform`, settings, docking, printing and tests. Record the new commit, its parent and the diff.
Publish a new immutable final craft-libs revision only after the shared tests and an adversarial review pass.
- Keep the egui-related `8614e4a`/`1764bca` shape already in the `3832c47…` base and the CL-2F capture helper
(later published in `25da131…`), preserving the permission checks, `craft-platform`, settings, docking, printing
and tests. Record the new commit, its parent and the diff. Publish a new immutable final craft-libs revision only
after the shared tests and an adversarial review pass.
That final revision comes **after** the final reviewed storytold egui/winit revisions (which include E21b and
W15P), so no provisional craft-libs commit pretends to be final.
- The final craft-libs revision also carries the CL-2F frozen capture-slot helper; VectorCraft's final app lock
@@ -679,8 +695,9 @@ craft-window (final craft-libs rev) ── egui 0.37
`accesskit 0.25.1`, `accesskit_consumer 0.39.1`, `accesskit_winit 0.34.1`, `accesskit_atspi_common 0.21.0`,
`accesskit_unix 0.24.0`, `accesskit_macos 0.27.1`, `accesskit_windows 0.35.1` and `accesskit_ios 0.2.1`; the
workspace manifest's requirement strings are lower (`accesskit 0.25.0`, `accesskit_consumer 0.39.0`,
`accesskit_winit 0.34.0`). VectorCraft currently locks `kittest 0.4.0`, `accesskit 0.24.1`,
`accesskit_winit 0.32.2`. The gate checks resolved registry source, compatible version and a single identity; it
`accesskit_winit 0.34.0`). At the pre-migration baseline VectorCraft locked `kittest 0.4.0`, `accesskit 0.24.1`,
`accesskit_winit 0.32.2`; the current pins are in the status block above. The gate checks resolved registry source,
compatible version and a single identity; it
must **not** reject them for not being egui-git packages.
- Keep version requirements at `0.37` in `[workspace.dependencies]`, and add root `[patch.crates-io]` entries for
every fork-source crate used **and** `winit` to the final immutable revisions. This makes transitive
@@ -830,16 +847,12 @@ deadlines and background scheduling. Keep egui's `i.time` for UI animation/gestu
- Pass the existing `&mut Ui` from `App::ui` to panels; never call `Context::root_ui` inside `App::ui`, tests that
use `run_ui`, or any code that already holds the root. `root_ui` is only for a `Context`-only integration, which
VectorCraft does not have.
- Keep `egui::Area`/`Window::show(ctx)` for floating panels/dialogs: they create their own `Ui` and do not borrow
the root. Do not convert them to `root_ui` calls.
- Dialogs keep `egui::Area`/`Window::show(ctx)`: they create their own `Ui` and do not borrow the root. Floating panels are drawn by `craft_ui::docking::DockArea`; on the desktop craft-ui's `native-windows` feature gives them OS windows of their own, and on the web and Wayland they float inside the app window.
- Panel order remains app bar / control bar / status+hint / toolbar / dock / central canvas / floating / dialogs.
The new `Panel` id-salt behavior must not change the order or clip; assert `response.rect`, `ui.clip_rect()` and
hit positions after resize/DPI changes.
- VectorCraft has no `show_viewport_deferred`/child native viewport. Do not add one. Screenshot/root behavior is
single-viewport; still test two queued screenshot requests (issued one at a time) and hidden-window paint because
the callback contract is new.
- Docking/floating use `craft_ui::docking` and app `floating`; keep their layout model and permissions. The
`craft-ui` rebase must preserve the current `MoveFloating` group permission checks.
- VectorCraft does not call `show_viewport_deferred` itself. The only child native viewports are the desktop floating-panel windows that craft-ui's `native-windows` feature creates; the web and Wayland stay in one window. Floating windows' controls are excluded from `ui.docking`'s `hitRects` and from control-channel pointer input (`panel_docking_native_tests.rs`, `docs/control-protocol.md`). Retest screenshot/root behavior for the main viewport with the native child windows present; still test two queued screenshot requests (issued one at a time) and hidden-window paint because the callback contract is new.
- Docking/floating use `craft_ui::docking`; the app `floating` module is deleted. `panel_docking::Runtime` keeps only session-only space/raise/focus state, and `panel_docking::valid`/`known` plus `Permissions` preserve the layout model and the `MoveFloating` group permission checks.
- Test: panels open/close/reorder, dock width restore, floating panel drag/dock, popup/flyout focus, window resize
and 1x/1.5x/2x scale; screenshots and geometry agree.
@@ -1002,7 +1015,7 @@ Start with the tests that already encode behaviour:
| Area | Existing tests/files | What to add |
|---|---|---|
| Whole-window frame | `crates/ui-egui/src/graphics.rs` `frame`, texture tests | tick/ui split, multi-pass, hidden paint, texture counts |
| Panels/dock | `panel_docking.rs`, `panel_docking_tests.rs`, `dock.rs` tests | dock width restore, panel order/clip, 1x/1.5x/2x, floating |
| Panels/dock | `panel_docking_tests.rs` (pointer/keyboard docking), `panel_docking_native_tests.rs` (desktop OS windows), `layout_migration_tests.rs` (older layouts), `dock.rs` (2 scroll-bar tests), `workspaces.rs` (saved dock width) | dock width restore, panel order/clip, 1x/1.5x/2x, floating, native-window focus/keyboard/drops, layout conversion |
| Tabs/menus | `panels/tabs.rs` tests, `menus.rs` | keyboard/accessibility tree, menu geometry |
| Fields | `tests_numfields.rs`, `widgets.rs` tests | wheel, focus, names, roles, click-away selection |
| Canvas | `canvas.rs` tests, `tests_rotateview.rs`, `tests_scrub.rs` | wheel source, zoom/pan, multi-pass, IME |
@@ -1173,7 +1186,7 @@ time or CLI throughput to UI latency.
### 6.2 Paired comparison
- **Performance control:** the pre-migration control is current main `4a7cba0…` (the two-commit DXF delta) with its
- **Performance control:** the pre-migration control is the then-current main `4a7cba0…` (the two-commit DXF delta) with its
coherent 0.36 lock, not `8906073…` alone. The candidate is the migration branch rebased onto `4a7cba0…` (or a
later main after the same gate). This keeps `crates/cad/src/import/curve.rs` identical on both sides and isolates
the egui migration. `8906073…` remains the historical planning baseline and rollback identity, not the paired
@@ -1297,11 +1310,13 @@ These are not “future work”; they block calling the migration done:
P7c, complete). Record exact full SHAs and tree hashes, preserve fork authorship/PATCHES, and prove a clean
`cargo fetch --locked`. No intermediate fork stage is a production pin; candidate aiongg revisions remain
research inputs; no final SHA is invented in this plan.
2. **Final craft-libs revision.** Finish the CL-1/CL-2F delta on the `3832c47…` base (which already carries the
selected `8614e4a`/`1764bca` changes), preserving `craft-platform`, security/settings/docking/printing fixes;
pin D1b and pass `craft-ui` visual regression. Do not merge PR199 head `b68de8c` or audit tree `ec8840a` as
trees. L1 (CL-1) and L2 (CL-2F) precede V2; publish only after shared gates and the capture-helper adapter
review.
2. **Final craft-libs revision (resolved by the published pin).** The CL-1/CL-2F delta is published in
craft-libs `25da131…`; the current workspace pins `craft-ui`, `craft-window`, `craft-keymap` and
`craft-print` to descendant `a0916808…`, retaining that delta and upstream shared docking. The plan-time requirement was to finish that delta on the `3832c47…` base (which already
carries the selected `8614e4a`/`1764bca` changes), preserving `craft-platform`,
security/settings/docking/printing fixes, pin D1b and pass `craft-ui` visual regression. Do not merge PR199
head `b68de8c` or audit tree `ec8840a` as trees. L1 (CL-1) and L2 (CL-2F) preceded V2; publication waited for
the shared gates and the capture-helper adapter review.
3. **`default_fonts`/font provider.** `ui-egui` library tests and no-default-feature builds must bind non-empty
families; production `Tofu` would otherwise draw synthetic boxes, and downstream kittest tests do not inherit
kittest's own dev-dependency fonts. `system_fonts` remains off unless measured and approved; the shared
@@ -1322,7 +1337,7 @@ These are not “future work”; they block calling the migration done:
precise char/byte contract and one undo step, plus the E21b model/preedit/UTF-8 payload producer and the
complete egui P7b/W27 lifecycle (owner identity, `Available` empty vs `Unavailable`, committed clear boundary,
latest-`None` authority, current-epoch mismatch and old-epoch rejection). UI `TextEdit` behavior is separate.
8. **Upstream rebase gate.** Current main is `4a7cba0…`, two commits ahead of the pinned review baseline, touching
8. **Upstream rebase gate.** At plan time, main was `4a7cba0…`, two commits ahead of the pinned review baseline, touching
only `crates/cad/src/import/curve.rs` (DXF spline). Rebase before V2, preserve that fix, rerun its import tests,
and isolate it from performance comparisons (§6.2). Recheck if main advanced further.
9. **macOS evidence.** No macOS host/display is available here. Keyboard layouts, IME (including press-and-hold),
@@ -1399,8 +1414,9 @@ Primary sources inspected (read-only):
- `/home/codex/work/CraftApps/egui037-migration-20261022/vectorcraft` (assigned checkout)
- `/home/codex/work/CraftApps/egui037-migration-20261022/egui` at `0.37.0` and `aiongg/craft/0.37`
- `/home/codex/work/CraftApps/egui037-migration-20261022/winit` at `8b35388…`/`ffae519…`
- `/home/codex/work/CraftApps/egui037-migration-20261022/craft-libs-implementation` at `3832c47…` (the local
implementation base, with the uncommitted CL-2F helper) and the historical PR 199/audit branches
- `/home/codex/work/CraftApps/egui037-migration-20261022/craft-libs-implementation` at `3832c47…` (the historical
local planning base; the CL-2F helper later landed in published craft-libs `25da131…`) and the historical PR
199/audit branches
- `craft-libs/docs/egui-037-suite-rollout.md` and `craft-libs/docs/egui-037-migration-plan.md`
- `egui/docs/egui-037-migration-plan.md` (E21b, W15P, family pins, §10.6 font fixtures)
- `/home/codex/work/ssd2/task-evidence/egui037-migration-20261022/` (upstream discussions, text-input research,
@@ -1478,7 +1494,9 @@ These are decisions this plan recommends but does not silently make:
| 2026-10-23 | Initial source-grounded planning draft. No implementation, build, test or GUI run. |
| 2026-10-23 | Revision 2: resolved every `vectorcraft-v1` finding (§8.1); corrected the lifecycle model (`raw_input_hook` in both hosts, separate host/accepted-frame counters, host-ordered test driver); added E21b and W15P/E4 prerequisites; moved the weak capture slot to the shared craft-ui contract; fixed final-fork → final craft-libs/CL-2F → app ordering; enumerated family and external registry identities; corrected `row_label` and the `Id::new` inventory; recorded the pinned review baseline, `4a7cba0…` drift/rebase gate and same-engine performance control. Static documentation only; no build/test run. |
| 2026-10-23 | Revision 3: resolved every `vectorcraft-v2` finding (§8.2) by replacing contradictory prose: stock-0.37 third arm in visual/performance; shared 4/128/256 MiB capture admission with epoch-bound geometry and hidden paint request; W27 old-epoch invalidation and complete E21b contract; P7c owns #8763/#8748; corrected production `Tofu` vs kittest `Panic` and non-propagating kittest dev-dependency fonts; craft-ui exact-pixel visual regressions; split `ui-deps` ledger; split D1a winit / D1b egui P8; per-stage rollback; removed the dead provisional capture slot and app-local adapter; corrected clipboard scope; added W15P synchronous claims and bounded transfers; set 5% median/10% p95/5% RSS gates with no tolerance widening. Static documentation only; no build/test run. |
| 2026-10-24 | Revision 4: implementation status; repaired the final upstream-review defects (path+data capture downgrade, image-paste repaint and paste-time chord, monotonic hidden tick, IME context invalidation and unavailable revisions, per-viewport exact-once input, Artboard and Split Grid accessible names, fail-closed stale synthetic input); moved the shared-library base reference to the local `3832c47…` implementation base. The exact tree still needs fresh managed verification before publication. |
| 2026-10-24 | Revision 4: implementation status; repaired the final upstream-review defects (path+data capture downgrade, image-paste repaint and paste-time chord, monotonic hidden tick, IME context invalidation and unavailable revisions, per-viewport exact-once input, Artboard and Split Grid accessible names, fail-closed stale synthetic input); moved the shared-library base reference to the local `3832c47…` implementation base. At that revision the exact tree still needed fresh managed verification before publication. |
| 2026-10-25 | Documentation reconciliation after PR 4113 and managed job `egui037-vector-postmerge-ci-20261025-1381`: recorded the current merge tree and pass result, marked the `8bf090b…`/`0589` status and 0.36.2 lock table historical, listed current pins from `Cargo.toml`/`Cargo.lock`, and corrected the plan-time local CL-2F base description to the published craft-libs `25da131…`. Documentation only; no build/test run. |
| 2026-10-25 | Shared-docking reconciliation: recorded the local merge of upstream `main` `714434527…` (PR #4135), the upstream/delete resolution of the four conflicts, the reviewed recolor code already in `main`, and CI 1422's pre-merge pass; corrected current docking claims (desktop OS windows, web/Wayland in-page, deleted `floating.rs` and width helpers, `UiState::dock_width` persistence, new native and layout-migration tests) while retaining the earlier planning sections as historical. The combined executable source and lockfile were subsequently qualified by managed job `egui037-vector-combined-ci1443` (all 12 stages passed); the status text was updated after that run. |
## Local implementation update — 2026-10-23