Swatches: add right-click context menu to swatch items

This commit is contained in:
ruchirguitar
2026-11-15 07:26:16 +05:30
parent 9f91f96f18
commit 6f4a651c00
8 changed files with 228 additions and 8 deletions
+33
View File
@@ -211,6 +211,39 @@ pub fn show(app: &mut VectorcraftApp, ui: &mut Ui) {
body(app, ui, TILE);
}
/// Item actions target the clicked swatch, independently of the paint or other selected chips.
fn item_context_menu(app: &mut VectorcraftApp, ui: &Ui, resp: &Response, e: &Entry) {
if e.is_folder() {
return;
}
let name = e.name();
if resp.secondary_clicked() {
let selected = dnd::selection(app, ui);
if selected.last().map(String::as_str) != Some(name) {
set_pstate(ui.ctx(), "swatch-selected", vec![name.to_string()]);
set_pstate(ui.ctx(), "swatch-anchor", name.to_string());
}
}
resp.context_menu(|ui| {
// Recheck the document each frame: a swatch can be deleted while its menu is open.
let enabled = app.session.active().and_then(|st| st.doc.swatch(name)).is_some_and(|s| !s.is_reserved());
let command = if menu_item(ui, tl!("Swatch Options…"), enabled, false) {
Some("ui.swatchOptions")
} else if menu_item(ui, tl!("Duplicate Swatch"), enabled, false) {
Some("swatch.duplicate")
} else if menu_item(ui, tl!("Delete Swatch"), enabled, false) {
Some("swatch.delete")
} else {
None
};
if let Some(command) = command {
// run reports failures through the app's status message.
let _ = app.run(command, json!({"name": name}));
ui.close();
}
});
}
/// The panel in a Fill/Stroke chip popover (the Control bar's and Properties'): the same body, its
/// tiles under their own ids so it can be open beside the panel.
pub(crate) fn popover(app: &mut VectorcraftApp, ui: &mut Ui) {
+4 -2
View File
@@ -48,8 +48,8 @@ pub(super) fn body(app: &mut VectorcraftApp, ui: &mut Ui, salt: &'static str) {
// Without a selection the swatch of the active paint is highlighted.
let fallback: Vec<String> = if selected.is_empty() { active_swatch.into_iter().collect() } else { vec![] };
let sel = if selected.is_empty() { &fallback } else { &selected };
let lit = app.session.active().map(|st| highlighted(&st.doc, sel)).unwrap_or_default();
let is_sel = |name: &str| lit.contains(&name);
let lit: Vec<String> = app.session.active().map(|st| highlighted(&st.doc, sel).into_iter().map(str::to_string).collect()).unwrap_or_default();
let is_sel = |name: &str| lit.iter().any(|n| n == name);
let mut ev = TileEvents::default();
// In a sized panel the list fills the space above the footer (#1638), as the Artboards list
// does; elsewhere it keeps its 150 pt (200 pt for large thumbnails).
@@ -80,6 +80,7 @@ pub(super) fn body(app: &mut VectorcraftApp, ui: &mut Ui, salt: &'static str) {
Entry::Folder(_) => draw_folder(ui, chip),
}
list_row_name(ui, r, chip, crate::i18n::t_name("swatch", name));
super::item_context_menu(app, ui, &resp, e);
tile_input(ui, resp, e, &items, sel, true, &mut ev);
}
} else {
@@ -100,6 +101,7 @@ pub(super) fn body(app: &mut VectorcraftApp, ui: &mut Ui, salt: &'static str) {
}
Entry::Folder(_) => folder_tile(ui, cell, is_sel(name)),
}
super::item_context_menu(app, ui, &resp, e);
tile_input(ui, resp, e, &items, sel, false, &mut ev);
}
}
@@ -4,6 +4,8 @@ use egui::{Event, Modifiers, PointerButton, Pos2};
use vectorcraft_color::Color;
use vectorcraft_engine::Session;
mod context_menu;
fn app() -> VectorcraftApp {
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
@@ -0,0 +1,164 @@
//! Actual secondary-button events on the panel's grid cells and list rows.
use super::*;
use egui_kittest::Harness;
use egui_kittest::kittest::{NodeT, Queryable};
fn harness(view: View) -> Harness<'static, VectorcraftApp> {
let mut first = true;
let builder = Harness::builder().with_size(vec2(300.0, 700.0)).with_accessibility_check(false);
// Optional local visual QA, following the Image Trace harness; captures stay untracked.
let builder = if std::env::var_os("VECTORCRAFT_SWATCHES_CAPTURE_DIR").is_some() { builder.wgpu() } else { builder };
let mut h = builder.build_ui_state(
move |ui, app: &mut VectorcraftApp| {
if std::mem::replace(&mut first, false) {
egui_extras::install_image_loaders(ui.ctx());
crate::theme::install_fonts(ui.ctx());
set_pstate(ui.ctx(), "swatch-view", view);
return;
}
show(app, ui);
},
app(),
);
h.run_steps(4);
h
}
fn right_click(h: &mut Harness<'static, VectorcraftApp>, name: &str) {
let pos = h.ctx.read_response(egui::Id::unique((TILE, name))).expect("swatch response").rect.center();
h.event(Event::PointerMoved(pos));
h.run_steps(1);
for pressed in [true, false] {
h.event(Event::PointerButton { pos, button: PointerButton::Secondary, pressed, modifiers: Modifiers::NONE });
h.run_steps(1);
}
h.run_steps(2);
}
#[test]
fn right_click_selects_without_painting_and_dispatches_item_commands() {
for (view, _) in View::ALL {
for command in ["Swatch Options…", "Duplicate Swatch", "Delete Swatch"] {
let mut h = harness(view);
set_pstate(&h.ctx, "swatch-selected", vec!["Black".to_string()]);
let before = h.state().session.doc().unwrap().doc.clone();
let paint = h.state().session.paint.fill.clone();
let undo = h.state().session.doc().unwrap().history.undo.len();
right_click(&mut h, "Red");
assert_eq!(selected(&h.ctx), ["Red"], "{view:?}");
assert_eq!(h.state().session.doc().unwrap().doc, before, "opening the menu leaves art unchanged");
assert_eq!(h.state().session.paint.fill, paint, "selecting a context target does not apply its paint");
assert_eq!(h.state().session.doc().unwrap().history.undo.len(), undo);
for label in [" Swatch Options…", " Duplicate Swatch", " Delete Swatch"] {
assert!(!h.get_by_label(label).accesskit_node().is_disabled(), "{view:?}: {label}");
}
if command == "Swatch Options…"
&& let Some(dir) = std::env::var_os("VECTORCRAFT_SWATCHES_CAPTURE_DIR")
{
let dir = std::path::PathBuf::from(dir);
std::fs::create_dir_all(&dir).unwrap();
h.render().unwrap().save(dir.join(format!("{view:?}.png"))).unwrap();
}
h.get_by_label(&format!(" {command}")).click();
h.run_steps(3);
match command {
"Swatch Options…" => {
let dialog = h.state().ui.dialog.as_ref().expect("Swatch Options opened");
assert_eq!(dialog.kind, KIND);
assert_eq!(dialog.str("__swatch"), "Red");
assert_eq!(h.state().session.doc().unwrap().history.undo.len(), undo);
}
"Duplicate Swatch" => {
let doc = &h.state().session.doc().unwrap().doc;
assert_eq!(doc.swatch("Red copy").unwrap().paint, doc.swatch("Red").unwrap().paint);
assert!(doc.swatch("Black copy").is_none());
assert_eq!(h.state().session.doc().unwrap().history.undo.len(), undo + 1);
h.state_mut().run("edit.undo", json!({})).unwrap();
assert_eq!(h.state().session.doc().unwrap().doc, before);
}
"Delete Swatch" => {
let doc = &h.state().session.doc().unwrap().doc;
assert!(doc.swatch("Red").is_none());
assert!(doc.swatch("Black").is_some());
assert_eq!(h.state().session.doc().unwrap().history.undo.len(), undo + 1);
h.state_mut().run("edit.undo", json!({})).unwrap();
assert_eq!(h.state().session.doc().unwrap().doc, before);
}
other => panic!("unexpected menu action: {other}"),
}
}
}
}
#[test]
fn reserved_swatches_have_disabled_item_actions() {
for (view, _) in View::ALL {
for name in ["[None]", REGISTRATION] {
let mut h = harness(view);
let before = h.state().session.doc().unwrap().doc.clone();
let undo = h.state().session.doc().unwrap().history.undo.len();
right_click(&mut h, name);
assert_eq!(selected(&h.ctx), [name]);
for label in [" Swatch Options…", " Duplicate Swatch", " Delete Swatch"] {
assert!(h.get_by_label(label).accesskit_node().is_disabled(), "{view:?}: {name}: {label}");
}
// egui closes a context menu even when the clicked item is disabled.
h.get_by_label(" Delete Swatch").click();
h.run_steps(2);
assert!(h.state().ui.dialog.is_none());
assert_eq!(h.state().session.doc().unwrap().doc, before);
assert_eq!(h.state().session.doc().unwrap().history.undo.len(), undo);
}
}
}
#[test]
fn right_clicking_the_active_panel_item_preserves_its_selection() {
for (view, _) in View::ALL {
let mut h = harness(view);
let names = vec!["Black".to_string(), "Red".to_string()];
set_pstate(&h.ctx, "swatch-selected", names.clone());
right_click(&mut h, "Red");
assert_eq!(selected(&h.ctx), names);
h.get_by_label(" Delete Swatch").click();
h.run_steps(3);
let doc = &h.state().session.doc().unwrap().doc;
assert!(doc.swatch("Black").is_some(), "only the clicked item is deleted");
assert!(doc.swatch("Red").is_none());
}
}
#[test]
fn a_swatch_deleted_while_its_menu_is_open_disables_actions() {
let mut first = true;
// Keep the original response alive to exercise the stale-entry guard after external deletion.
let mut h = Harness::builder().with_size(vec2(300.0, 300.0)).with_accessibility_check(false).build_ui_state(
move |ui, app: &mut VectorcraftApp| {
if std::mem::replace(&mut first, false) {
crate::theme::install_fonts(ui.ctx());
return;
}
let e = Entry::Swatch { name: "Red".into(), paint: Paint::solid(Color::BLACK), global: false, spot: false };
let resp = ui.button("Target");
item_context_menu(app, ui, &resp, &e);
},
app(),
);
h.run_steps(4);
h.get_by_label("Target").click_secondary();
h.run_steps(3);
assert!(!h.get_by_label(" Duplicate Swatch").accesskit_node().is_disabled());
h.state_mut().run("swatch.delete", json!({"name": "Red"})).unwrap();
let before = h.state().session.doc().unwrap().doc.clone();
let undo = h.state().session.doc().unwrap().history.undo.len();
h.run_steps(3);
for label in [" Swatch Options…", " Duplicate Swatch", " Delete Swatch"] {
assert!(h.get_by_label(label).accesskit_node().is_disabled(), "{label}");
}
h.get_by_label(" Duplicate Swatch").click();
h.run_steps(2);
assert!(h.state().ui.dialog.is_none());
assert_eq!(h.state().session.doc().unwrap().doc, before);
assert_eq!(h.state().session.doc().unwrap().history.undo.len(), undo);
}
+7 -1
View File
File diff suppressed because one or more lines are too long
+5 -2
View File
@@ -1,6 +1,6 @@
# Roadmap: milestones and what's next
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-13 · **Change:** minor (Graphic Styles list fills a taller panel, #2992; scores and estimates unchanged; previously: PDF import: glyphs in a span with an empty ActualText come in as outlines, #6971; scores and estimates unchanged; previously: library panels' lists fill a taller panel, #2992; scores and estimates unchanged; previously: Swatches list fills a taller panel, #1638; scores and estimates unchanged; previously: icon-strip flyouts also resize from the top edge and the canvas-side top corner, keeping the moved top in workspaces (storytold/craft-libs#1094); scores and estimates unchanged; previously: #6865: explicitly requested oversized editing artboard; Live Paint Bucket fills faces crossed in one drag (#6373); previously: #6404: transform-aware Eyedropper character copying; scores and estimates unchanged; previously: M10/G5: Energy Beams brush library; MCP docs list Energy Beams; previously minor: M10/G5: Skill Icons symbol library; MCP docs list Skill Icons; previously minor: M10/G5: Status Effects graphic style library; MCP docs catch-up for symbol libraries; previously minor: M10/G5: Inventory Icons built-in symbol library; previously minor: Edit › Edit Custom Dictionary…: its dialog adds, deletes and changes the custom dictionary's words, #4936; previously minor: M10/G5: Game HUD graphic style library; previously minor: resizable icon-strip flyouts and bottom-aligned panel footers, #5713; previously minor: M10/G5: Map Markers built-in symbol library; previously minor: right-click on type: Spelling › Auto Spell Check, with its check mark, #4936; previously minor: right-click on a word Auto Spell Check underlined: its suggestions, Ignore All and Add to Dictionary, #4936; previously minor: G2: Effect Gallery thumbnails and in-dialog preview are in; Auto Spell Check: `edit.autoSpellCheck` underlines the unknown words, #4936; previously minor: PDF editable import preserves authored ActualText once, including empty/nested spans and authored ordering (#6165); cross-line/style layout remains approximate; scores and estimates unchanged; PDF marked-text export (#6309): compatible glyphs stay on one layout line with per-glyph offsets; scores and estimates unchanged; interim macOS cursor delivery, #2292; native validation pending; scores and estimates unchanged; Control bar › Snapping includes the existing Snap to Glyph and Alignment Guides toggles (#6164); scores and estimates unchanged; custom dictionary and Ignore All: `text.spelling.addWord`, `removeWord`, `changeWord`, `dictionary` and `ignoreAll`, #4936; previously minor: EPS import: embedded fonts (composite, Type 42, CID-keyed, Type 1, CFF FontSet) draw their glyphs; spell check engine: `text.spelling.check` and `text.spelling.suggest` on craft-proof, #4936; previously minor: floating tab groups collapse into the side icon rail and opened rail panels fold back into it, #5925 in part; M4/M7: `.ai`/EPS type keeps its tab stops, and right-aligned lines with tabs lay out as the file's page, #6147; M4/M7: `.ai`/EPS type from the text document lays its lines out closer to the file's page, within limits, #6137; numeric fields step on wheel hover without taking keyboard focus, #5949; Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen; Selection QoL: marquee modes and visible feedback, #5313; SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts; #3380 deletion-only review follow-up: independent survivors keep gradient placement, owned subpaths avoid discarded copies, and contracts/status/evidence are clarified; endpoint highlighting remains open; scores and estimates unchanged; Indian-language hyphenation review and license allowlist, #4947; Hindi catalog and contributor loanword preferences; full wording review in progress; Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; shape tools move the selection from its centre point and turn it from the zone outside a box corner, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-15 · **Change:** minor (G12: Swatches item menus tested and rendered; Linux full CI passed; Windows engine baseline failures noted; scores and estimates unchanged; previously: Graphic Styles list fills a taller panel, #2992; scores and estimates unchanged; previously: PDF import: glyphs in a span with an empty ActualText come in as outlines, #6971; scores and estimates unchanged; previously: library panels' lists fill a taller panel, #2992; scores and estimates unchanged; previously: Swatches list fills a taller panel, #1638; scores and estimates unchanged; previously: icon-strip flyouts also resize from the top edge and the canvas-side top corner, keeping the moved top in workspaces (storytold/craft-libs#1094); scores and estimates unchanged; previously: #6865: explicitly requested oversized editing artboard; Live Paint Bucket fills faces crossed in one drag (#6373); previously: #6404: transform-aware Eyedropper character copying; scores and estimates unchanged; previously: M10/G5: Energy Beams brush library; MCP docs list Energy Beams; previously minor: M10/G5: Skill Icons symbol library; MCP docs list Skill Icons; previously minor: M10/G5: Status Effects graphic style library; MCP docs catch-up for symbol libraries; previously minor: M10/G5: Inventory Icons built-in symbol library; previously minor: Edit › Edit Custom Dictionary…: its dialog adds, deletes and changes the custom dictionary's words, #4936; previously minor: M10/G5: Game HUD graphic style library; previously minor: resizable icon-strip flyouts and bottom-aligned panel footers, #5713; previously minor: M10/G5: Map Markers built-in symbol library; previously minor: right-click on type: Spelling › Auto Spell Check, with its check mark, #4936; previously minor: right-click on a word Auto Spell Check underlined: its suggestions, Ignore All and Add to Dictionary, #4936; previously minor: G2: Effect Gallery thumbnails and in-dialog preview are in; Auto Spell Check: `edit.autoSpellCheck` underlines the unknown words, #4936; previously minor: PDF editable import preserves authored ActualText once, including empty/nested spans and authored ordering (#6165); cross-line/style layout remains approximate; scores and estimates unchanged; PDF marked-text export (#6309): compatible glyphs stay on one layout line with per-glyph offsets; scores and estimates unchanged; interim macOS cursor delivery, #2292; native validation pending; scores and estimates unchanged; Control bar › Snapping includes the existing Snap to Glyph and Alignment Guides toggles (#6164); scores and estimates unchanged; custom dictionary and Ignore All: `text.spelling.addWord`, `removeWord`, `changeWord`, `dictionary` and `ignoreAll`, #4936; previously minor: EPS import: embedded fonts (composite, Type 42, CID-keyed, Type 1, CFF FontSet) draw their glyphs; spell check engine: `text.spelling.check` and `text.spelling.suggest` on craft-proof, #4936; previously minor: floating tab groups collapse into the side icon rail and opened rail panels fold back into it, #5925 in part; M4/M7: `.ai`/EPS type keeps its tab stops, and right-aligned lines with tabs lay out as the file's page, #6147; M4/M7: `.ai`/EPS type from the text document lays its lines out closer to the file's page, within limits, #6137; numeric fields step on wheel hover without taking keyboard focus, #5949; Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen; Selection QoL: marquee modes and visible feedback, #5313; SVG CSS classes survive export and repeated import in all four styling modes (#2480); current-main integration retains event attributes and scripts; #3380 deletion-only review follow-up: independent survivors keep gradient placement, owned subpaths avoid discarded copies, and contracts/status/evidence are clarified; endpoint highlighting remains open; scores and estimates unchanged; Indian-language hyphenation review and license allowlist, #4947; Hindi catalog and contributor loanword preferences; full wording review in progress; Effect dialogs: a colour swatch beside a hex colour opens the Color Picker, #5365; shape tools move the selection from its centre point and turn it from the zone outside a box corner, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x)
>
> Oversized artboard import update (2026-11-12): Explicit editing-data import retains a single artboard beyond a capped 14,400 pt PDF page (#6865).
>
@@ -56,6 +56,7 @@ M7 type: Touch Type moves a right-to-left character along its line and up from i
| Date | Change | Summary |
|---|---|---|
| 2026-11-15 | minor | G12: Swatches item menus validated in all five views: 39 focused tests passed, regression fails without the menu hooks, rendered list/thumbnail layouts inspected, and fresh local deep CodeRabbit review found zero issues. Full workspace CI passed on Linux/WSL (all 13 gates); native Windows full CI has two unchanged engine-test failures. Scores and estimates unchanged. |
| 2026-11-13 | minor | Graphic Styles: in a panel made taller the list fills the space above the footer instead of stopping at 220 pt (#2992; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/graphic_styles.rs`). Scores and estimates unchanged. |
| 2026-11-13 | minor | PDF import: glyphs inside a marked-content span with an empty `ActualText` come in as outlines in their fill and stroke instead of being left out, adding no text (#6971; `empty_actual_text_keeps_the_glyphs_art` in `crates/pdf/src/tests/actual_text.rs`). Scores and estimates unchanged. |
| 2026-11-13 | minor | Library panels (swatch, Color Book, brush, symbol and graphic style libraries): in a panel made taller the list fills the space above the footer instead of scrolling inside 220 or 280 pt (#2992; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/library_panel/tests.rs`). Scores and estimates unchanged. |
@@ -169,7 +170,7 @@ Gujarati interface follow-up (2026-11-14): the catalog and zero/one plural rule
| M11 | Artboards & views (selected-set deletion shared by Artboards menu, trash and Properties, retaining artboard 1 when all are selected; Artboard deletion keys keep the first of an all-selected set and protect artwork; history prunes invalid indices while preserving valid multiselection (history tests and full workspace CI pass); click-to-fit objects with the Artboard tool (#1227), artboard escape routing and document setup modal handoff done; artboard panel/tool with Move Artwork for X/Y fields and Artboard Options, Trim View, middle-button pan, print tiling and the status bar's artboard navigator with synchronized Artboard tool selection done; Window › Arrange › Tile and Consolidate All Windows done; multiple windows, presentation polish) (cached canvas reprojection preserves scale during resize, rotation and DPI changes; regression-tested and contributor-confirmed 2026-10-19; estimates unchanged) (cached canvas dimensions match the renderer limit before cache-key creation, view construction and worker submission; regression-tested; estimates unchanged); status-bar pointer coordinates follow the active ruler origin and General units | 🟡; Artboard Options shares existing presets and orientation controls and can fit artwork without moving it; artwork fitting includes all drawn document art across artboards and off-board; artwork bounds are cached by active document and revision, and selection uses the shared bounds cache across artboards | 15–25 |
| M12 | Advanced color & art (CMYK/ICC, separations, Gradient Mesh, Live Paint, Image Trace, Graphs) | 🟡 Gradient Mesh, Live Paint, Image Trace (junction-returning pieces retain their positioned boundaries; a simpler contour walk with identical output; an edge's sub-pixel shift is the same from either side; notches read only their own piece; collapsed loops keep few segments; large images trace with a warning; Auto Color keeps rare distinct colours; quick presets trace at once and the Image Trace button opens the adjustment controls; Properties reopens them; tiny fitted contours retain islands and holes; Create Strokes: exact crop EDT, Guo–Hall thinning and maximal-disc graph simplification; 15 presets, the 14 documented ones each with an enhanced version; Ignore Color, Shapes, Auto Grouping and Gradients options; measured in `image-trace-quality.md`; closed outlines retain their interior after straightening; the Flat Logo mode places edges to a fraction of a pixel, restores sharp corners, snaps lines and circles, and refuses gradients; live trace result bounds and selection highlights exclude the retained bitmap except in source-image views), Recolor Artwork, colour management (ICC, soft proofing, separations preview), Graphs (all 9 tools, Graph Data/Type, group-selected series colours persist through regenerate/save/open) done; Graph Design and Marker designs, Transpose and Switch x/y, `\|` label line breaks, the pie options, drop shadows, the legend across the top, overlapping widths, First Row/Column in Front, filled lines, kept label formatting and the Graph Data worksheet done; graph Column designs pending; Vector Halftone Preview keeps the selection box without drawing dot selection marks (#6369); Live Paint Bucket fills faces crossed in one drag (#6373) | 6–10 |
| M13 | Automation (Actions ✅ record/playback, persisted; variables, scripting, batch) | 🟡 MCP `add_text` exposes existing vertical point, area and path type; `script.run` and File › Scripts › Other Script… run JavaScript files, and Window › Script Console shows their output; the script document model and batch work remain | 18–27 |
| M14 | 1.0 polish (preferences, shortcut editor, workspaces, accessibility, packaging for all OSes) (status messages and readouts use stable responsive allocations sized for localized labels and ordinary coordinates; sample widths cached by language/unit/DPI; regression-tested and contributor-confirmed 2026-10-19; estimates unchanged) | 🟡 Icon-strip flyouts resize on their free edges and retain sizes (#5713); interim macOS cursor delivery (#2292) uses existing artwork and host-owned AppKit cursors; headless coverage only, native menu/focus/handback and display validation pending. Dock groups collapse to their tabs by a double-click on a tab (UI.8); Preferences › General › Constrain Angle acts for the arrow keys, Shift drags and new objects (#394, 2026-10-21); numeric-field pointer selection and focus regression-tested (#1326; a release more than 1 pt from the press keeps the caret, a tap within 1 pt selects all, #6659); RPM runtime capabilities and glibc floor checked (#1275; real-distro install/start-up pending), Eyedropper cursor with precise-setting checks (#1269), Preferences, shortcut editor (chords with Shift and a punctuation key fire as typed; other apps' text shortcut sets imported), workspaces (each keeps its layout changes until Reset <name>, UI.7), Window › Help Bar shown or hidden apart from the status bar and kept in saved workspaces, panels docked by dragging into any dock group (as tabs or a top/bottom split) or into the icon column, and closed from a dock tab's context menu (UI.6), a custom title bar on Windows/Linux with a Home button, content-sized dialogs, menus that scroll when longer than the window and macOS native menu dismissal done (M14.8), and native macOS save sheets with a Format menu (#866); titled PDF exports set `DisplayDocTitle` for viewers and accessibility checkers (#3646); accessibility and broader Windows/Linux packaging/QA pending; floating tab groups collapse into the side icon rail and opened rail panels fold back into it (#5925, in part), with pointer and native-window regression coverage; estimates unchanged; numeric spinner arrows keep repeating while held with the mouse (#6307) | 18–28 |
| M14 | 1.0 polish (preferences, shortcut editor, workspaces, accessibility, packaging for all OSes) (status messages and readouts use stable responsive allocations sized for localized labels and ordinary coordinates; sample widths cached by language/unit/DPI; regression-tested and contributor-confirmed 2026-10-19; estimates unchanged) | 🟡 Icon-strip flyouts resize on their free edges and retain sizes (#5713); interim macOS cursor delivery (#2292) uses existing artwork and host-owned AppKit cursors; headless coverage only, native menu/focus/handback and display validation pending. Dock groups collapse to their tabs by a double-click on a tab (UI.8); Preferences › General › Constrain Angle acts for the arrow keys, Shift drags and new objects (#394, 2026-10-21); numeric-field pointer selection and focus regression-tested (#1326; a release more than 1 pt from the press keeps the caret, a tap within 1 pt selects all, #6659); RPM runtime capabilities and glibc floor checked (#1275; real-distro install/start-up pending), Eyedropper cursor with precise-setting checks (#1269), Preferences, shortcut editor (chords with Shift and a punctuation key fire as typed; other apps' text shortcut sets imported), workspaces (each keeps its layout changes until Reset <name>, UI.7), Window › Help Bar shown or hidden apart from the status bar and kept in saved workspaces, panels docked by dragging into any dock group (as tabs or a top/bottom split) or into the icon column, and closed from a dock tab's context menu (UI.6), a custom title bar on Windows/Linux with a Home button, content-sized dialogs, menus that scroll when longer than the window and macOS native menu dismissal done (M14.8), and native macOS save sheets with a Format menu (#866); titled PDF exports set `DisplayDocTitle` for viewers and accessibility checkers (#3646); accessibility and broader Windows/Linux packaging/QA pending; floating tab groups collapse into the side icon rail and opened rail panels fold back into it (#5925, in part), with pointer and native-window regression coverage; estimates unchanged; numeric spinner arrows keep repeating while held with the mouse (#6307); Swatches item context menus tested in all five views and rendered layouts inspected; Linux full CI passed, Windows engine baseline limitations documented (G12) | 18–28 |
| — | Interaction fidelity pass (every tool's modifiers, Properties panel per context, isolation, nuance; width-point creation and adjoining adjustment regression-tested; dialog layout reviewed) | ⬜ (new ruler-guide Alt orientation implemented; existing-guide Escape cancellation regression-tested; broader pass remains) | 60–90 |
| — | Hardening at scale (big-file corpus, fuzzing, cross-platform + browser QA) | 🟡 PngSuite integrity and bounded fetching verified (#1729); real-world corpus/manual QA remain | 50–80 |
| M14 follow-up | Color Picker layout (#2008) | ✅ Compact controls, centered header, stacked actions, aligned fields and screen sampling; narrow windows scroll vertically | Included above |
@@ -207,6 +208,8 @@ separate. Scores and hours unchanged. [Behavior and command details](development
| Date | Change | Summary |
|---|---|---|
| 2026-11-15 | minor | G12: Swatches item menus validated in all five views: 39 focused tests passed, regression fails without the menu hooks, rendered list/thumbnail layouts inspected, and fresh local deep CodeRabbit review found zero issues. Full workspace CI passed on Linux/WSL (all 13 gates); native Windows full CI has two unchanged engine-test failures. Scores and estimates unchanged. |
| 2026-11-14 | minor | G12: Swatches item context menus implemented in list and thumbnail views, with clicked-item actions and reserved/missing-swatch guards. Harness tests added; execution and visual verification pending. Scores and estimates unchanged. |
| 2026-11-14 | minor | Gujarati (#6613): contributor proofreading completed for all 387 additions, with 11 wording corrections; 4,673 reviewed catalog rows. Status/error messages remain partial; web selection requires a bundled Gujarati face. Scores and estimates unchanged. |
| 2026-11-12 | minor | Gujarati (`gu`): 4,286-row machine-assisted catalog reviewed by a native speaker, zero/one singular plurals, desktop font fallback and optional Gujarati craft-fonts fallback; all 72 translation tests pass; a web font and about 2,600 untranslated messages remain; scores and estimates unchanged |
| 2026-11-12 | minor | Explicit editing-data import keeps a single artboard beyond a capped 14,400 pt PDF page (#6865), with a warning; automatic mode stays unchanged. Scores and estimates unchanged. |
File diff suppressed because one or more lines are too long
+5 -1
View File
@@ -1,6 +1,6 @@
# UI and interaction parity
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-13 · **Change:** minor (Graphic Styles list fills a taller panel, #2992; scores and estimates unchanged; previously: library panels' lists fill a taller panel, #2992; scores and estimates unchanged; previously: Swatches list fills a taller panel, #1638; scores and estimates unchanged; previously: icon-strip flyouts also resize from the top edge and the canvas-side top corner, keeping the moved top in workspaces (storytold/craft-libs#1094); scores and estimates unchanged; previously: macOS: the canvas cursor stays after the pointer moves, #6362; scores and estimates unchanged; previously minor: Remove Background in the Contextual Task Bar, Properties › Quick Actions and the Control bar; previously minor: Ruler origin: the corner drag snaps as a drawn point does; previously minor: Live Paint Bucket fills faces crossed in one drag (#6373); previously: #6404: transform-aware Eyedropper character copying; scores and estimates unchanged; previously: Outline view: images and gradient meshes are picked on what Outline draws, so a click inside them reaches the path behind, #6437; previously minor: a middle-click on a document tab closes it, #6506; previously minor: Blob Brush: a round tip's preview is the outline of the area it adds, round at both ends, as the stroke it commits (#4343); scores and estimates unchanged; previously:; ruler double-click adds a guide at the pointer, #5239; G5: Inventory Icons built-in symbol library (four built-ins); previously minor: files that record no units open in Preferences › Units › General, #5820; previously minor: interim macOS cursor delivery, #2292; native validation pending; scores and estimates unchanged; Control bar › Snapping includes the existing Snap to Glyph and Alignment Guides toggles (#6164); scores and estimates unchanged; floating tab groups collapse into the side icon rail and opened rail panels fold back into it, #5925 in part; numeric fields step on wheel hover without taking keyboard focus, #5949; Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen; Selection QoL: marquee modes and visible feedback, #5313; #3380 deletion-only review follow-up: independent survivors keep gradient placement, owned subpaths avoid discarded copies, and contracts/status/evidence are clarified; endpoint highlighting remains open; scores and estimates unchanged; Drop Shadow and glow dialogs: spinner arrows, #5367, #5368; Stroke Weight Up and Down shortcuts, #5797; Layers: Rename (`ui.rename`) opens the name field of the selected layer, group or object, #5324; Properties in Edit Artboards: Transform section above the Artboards section, #5219; scrubby labels: the Control bar's Stroke: and Opacity: links and the Properties panel's Stroke link scrub their fields, #4088; Properties: Quick Actions has Repeat Options for one selected repeat, #5181; Direct Selection: Shift-click picks several blend spine points, which drag together, #5285; Direct Selection: Cmd/Ctrl held lends the Selection tool and shows its bounding box, #3901; Join tool trims two crossing open paths and joins them at the crossing, #5844; Control bar: Paragraph: link and Align left/center/right while type is selected, #5372; shape tools: a press on the selection's centre point moves it and one in the rotate zone outside a box corner turns it, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
> **Last reviewed:** 2026-10-10 · **Last updated:** 2026-11-15 · **Change:** minor (G12: Swatches item menus tested and rendered; Linux full CI passed; Windows engine baseline failures noted; scores and estimates unchanged; previously: Graphic Styles list fills a taller panel, #2992; scores and estimates unchanged; previously: library panels' lists fill a taller panel, #2992; scores and estimates unchanged; previously: Swatches list fills a taller panel, #1638; scores and estimates unchanged; previously: icon-strip flyouts also resize from the top edge and the canvas-side top corner, keeping the moved top in workspaces (storytold/craft-libs#1094); scores and estimates unchanged; previously: macOS: the canvas cursor stays after the pointer moves, #6362; scores and estimates unchanged; previously minor: Remove Background in the Contextual Task Bar, Properties › Quick Actions and the Control bar; previously minor: Ruler origin: the corner drag snaps as a drawn point does; previously minor: Live Paint Bucket fills faces crossed in one drag (#6373); previously: #6404: transform-aware Eyedropper character copying; scores and estimates unchanged; previously: Outline view: images and gradient meshes are picked on what Outline draws, so a click inside them reaches the path behind, #6437; previously minor: a middle-click on a document tab closes it, #6506; previously minor: Blob Brush: a round tip's preview is the outline of the area it adds, round at both ends, as the stroke it commits (#4343); scores and estimates unchanged; previously:; ruler double-click adds a guide at the pointer, #5239; G5: Inventory Icons built-in symbol library (four built-ins); previously minor: files that record no units open in Preferences › Units › General, #5820; previously minor: interim macOS cursor delivery, #2292; native validation pending; scores and estimates unchanged; Control bar › Snapping includes the existing Snap to Glyph and Alignment Guides toggles (#6164); scores and estimates unchanged; floating tab groups collapse into the side icon rail and opened rail panels fold back into it, #5925 in part; numeric fields step on wheel hover without taking keyboard focus, #5949; Character Styles panel: a double-click on a style's row opens its Character Style Options; the dialog keeps a fixed width and scrolls its sections, so its buttons stay on screen; Selection QoL: marquee modes and visible feedback, #5313; #3380 deletion-only review follow-up: independent survivors keep gradient placement, owned subpaths avoid discarded copies, and contracts/status/evidence are clarified; endpoint highlighting remains open; scores and estimates unchanged; Drop Shadow and glow dialogs: spinner arrows, #5367, #5368; Stroke Weight Up and Down shortcuts, #5797; Layers: Rename (`ui.rename`) opens the name field of the selected layer, group or object, #5324; Properties in Edit Artboards: Transform section above the Artboards section, #5219; scrubby labels: the Control bar's Stroke: and Opacity: links and the Properties panel's Stroke link scrub their fields, #4088; Properties: Quick Actions has Repeat Options for one selected repeat, #5181; Direct Selection: Shift-click picks several blend spine points, which drag together, #5285; Direct Selection: Cmd/Ctrl held lends the Selection tool and shows its bounding box, #3901; Join tool trims two crossing open paths and joins them at the crossing, #5844; Control bar: Paragraph: link and Align left/center/right while type is selected, #5372; shape tools: a press on the selection's centre point moves it and one in the rotate zone outside a box corner turns it, #5477; scores and estimates unchanged) · **Target:** Adobe Illustrator 2026 (30.x; Units › East Asian Type acts, with Q and Ha units; scores unchanged)
>
> Vector Halftone preview update (2026-11-10): temporary dot selection marks are hidden, and the bounding box stays available (#6369).
>
@@ -51,6 +51,7 @@ Artboard Options forwards the active Artboard tool's Scale Artwork with Artboard
| Date | Change | Summary |
|---|---|---|
| 2026-11-15 | minor | G12: Swatches item menus validated in all five views: 39 focused tests passed, regression fails without the menu hooks, rendered list/thumbnail layouts inspected, and fresh local deep CodeRabbit review found zero issues. Full workspace CI passed on Linux/WSL (all 13 gates); native Windows full CI has two unchanged engine-test failures. Scores and estimates unchanged. |
| 2026-11-14 | minor | Layers panel: right-clicking a layer/group/object row shows a context menu with Options…, Duplicate, Delete, Lock/Hide Others, Locate Object, and Collect for Export — matching standard desktop layer panel conventions. Scores unchanged. |
| 2026-11-13 | minor | Graphic Styles: in a panel made taller the list fills the space above the footer instead of stopping at 220 pt (#2992; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/graphic_styles.rs`). Scores and estimates unchanged. |
| 2026-11-13 | minor | Library panels (swatch, Color Book, brush, symbol and graphic style libraries): in a panel made taller the list fills the space above the footer instead of scrolling inside 220 or 280 pt (#2992; `the_list_fills_a_tall_panel_above_its_footer` in `crates/ui-egui/src/panels/library_panel/tests.rs`). Scores and estimates unchanged. |
@@ -438,6 +439,7 @@ next unit in the order a right-click on a ruler lists them, from Feet back to Po
| Pathfinder panel: compound shapes (Make, Release and Expand Compound Shape in the panel menu, Alt-click a Shape Mode, a Shape Mode for selected members, the Expand button) | partial | #4522; `object.compoundShape.make`/`setMode`/`release`/`expand`; members stay editable, the area draws, exports and saves; the button of the members' shared mode is lit; blends, envelopes and warped objects are members as they draw; [spec](https://helpx.adobe.com/illustrator/desktop/manage-objects/reshape-transform-objects/create-compound-shapes-with-pathfinder.html); missing: question marks for mixed modes, hit-testing by the area |
| Canvas context menu | done | Right-clicking type opens the canvas menu, with Bullets and Numbering and Spelling. Artboard rows, library groups and items, the rulers and floating toolbar grips have menus too. Gaps: guide and blend spine rows have no menu, and other panels have none |
| Layers panel row context menu | done | Right-clicking a layer/group/object row shows a context menu with Options…, Duplicate, Delete, Lock/Hide Others, Locate Object, and Collect for Export — matching standard desktop layer panel conventions. |
| Swatches item context menu (G12) | done | List and thumbnail items offer Swatch Options…, Duplicate Swatch and Delete Swatch for the clicked item. Right-click selects without applying paint; reserved/missing items disable actions. All 39 Swatches tests pass, including all five views and Undo; the regression fails with the menu hooks removed. Rendered headless menus inspected. Full workspace CI passed on Linux/WSL (all 13 gates); native Windows full CI has two unchanged engine-test failures. |
| SVG Interactivity panel: JavaScript for each object's events and the document's linked JavaScript files, written to SVG and read back as text | done | `svgInteractivity.*`, `ui.javascriptFilesDialog` |
| Retype, Comments, Version History panels | missing | the last two are cloud features (out of scope) |
| Blend panel (30.7) | partial | Window › Blend provides Type (Ease In, Ease Out, Ease In Out, Ease Out In), Ramp 0–100% and independent color Shift, alongside the existing blend controls. Easing is disabled without a spine. Original polynomial distributions approximate the publicly documented behavior. On-canvas Appearance and Easing widgets set Shift and Ramp; a blend without a spine shows the Appearance widget alone. [Public source](https://helpx.adobe.com/illustrator/desktop/manage-colors/apply-transparency-and-blending/blend-panel-overview.html) |
@@ -538,6 +540,8 @@ before release (#6373). [Paint faces and edges](https://helpx.adobe.com/illustra
| Date | Change | Summary |
|---|---|---|
| 2026-11-15 | minor | G12: Swatches item menus validated in all five views: 39 focused tests passed, regression fails without the menu hooks, rendered list/thumbnail layouts inspected, and fresh local deep CodeRabbit review found zero issues. Full workspace CI passed on Linux/WSL (all 13 gates); native Windows full CI has two unchanged engine-test failures. Scores and estimates unchanged. |
| 2026-11-14 | minor | G12: Swatches item context menus implemented in list and thumbnail views, with clicked-item actions and reserved/missing-swatch guards. Harness tests added; execution and visual verification pending. Scores and estimates unchanged. |
| 2026-11-12 | minor | Numeric fields: a focus click released more than 1 pt from its press keeps the caret; a tap within 1 pt still selects the whole value (#6659, follow-up to #1326). Scores and estimates unchanged. |
| 2026-11-12 | minor | Remove Background for a selected image in the Contextual Task Bar, Properties › Quick Actions and the Control bar, which runs at once with its defaults. Scores and estimates unchanged. |
| 2026-11-12 | minor | Live Paint Bucket fills faces crossed in one drag (#6373). Scores and estimates unchanged. |