Holding Alt over a selection the Shape Builder had already mapped built
the planar map a second time, to add the outline edges that erasing
hits. A merge, and a Live Paint Bucket fill of a plain selection, also
dropped the map, so a gesture that left the document unchanged was
followed by another full build.
The Shape Builder now builds its map with the outline edges the first
time, and both tools keep the map until the document, its revision or
the selection changes.
When the inputs have more than 128 segments, a hover with the Shape
Builder or the Live Paint Bucket now builds the map on another thread
and highlights no region until it arrives, instead of holding up the
frame; the canvas checks for it each frame. A press waits for the map,
and the headless MCP host waits for it after a move. The web build has
no threads and builds the map at once. The Live Paint Selection tool's
hover no longer builds a map of the selection, which it did not use.
One rule for the hover's context (PR review follow-ups): the target is
recomputed where the pointer is, or cleared, whenever what lies under it
can change while Alt is held.
- The tool hovers only where the pointer is on the canvas itself
(`on_canvas`): under a floating panel, a menu, a popup or a dialog
its hover ends (Tool::hover_ended), as when the pointer leaves the
canvas or a pan, zoom or view-rotation press starts.
- The canvas keeps the hover's context: its rect, the view's centre,
zoom and rotation, and the active document's id and revision (which
moves with every edit, undo and selection change). When it changes
under a still pointer, a tool that asks (Tool::wants_rehover; the
Selection tool after an Alt hover) is hovered again at the pointer,
so wheel, gesture, key or command scrolling and zooming, tab
switches, edits and undos re-measure.
- Coming back onto the canvas re-hovers the tool.
canvas::tests::distance_guides_follow_what_lies_under_a_still_pointer:
a floating window over the pointer (fails without the on_canvas filter),
a 150 pt scroll that leaves empty artboard under it (fails without the
re-hover), a square made under it. select::tests::distance_guides_need_
alt_a_selection_and_smart_guides checks wants_rehover.
An Alt+Space pan press went to Drag::Pan and never reached the tool, so the Distance Guides stayed through the pan until the pointer left the canvas (PR review follow-up). One rule now covers all three cases: the tool's hover ends (Tool::hover_ended, renamed from pointer_left; Session::tool_hover_ended) when the pointer leaves the canvas with no press the tool holds, and when a press starts any drag that doesn't reach the tool (pan, middle-button pan, zoom box or scrub, view rotation, touch gesture). canvas::tests::distance_guides_go_when_the_hover_ends asserts they go at an Alt+Space press and stay gone panning out over a panel.
The pointer-left check skipped every drag, so Alt+Space panning out over a panel kept the measurements (PR review follow-up). Only a press the tool holds (Drag::Tool, Drag::Art) keeps its state now; pan, zoom box, zoom scrub, view rotation, gesture and presentation drags never reach the tool. canvas::tests::distance_guides_go_when_the_pointer_leaves_the_canvas pans out with Alt+Space; it fails with the old drag.is_none() check.
Leaving the canvas (for a panel, or out of the window) sent the tool no
hover event, so the Selection tool kept its Alt-hover target and went
on drawing the measurements (PR review finding).
- Tool::pointer_left: the pointer left the canvas with no button held;
the Selection tool drops its Distance Guides target and its Smart
Guides hover label. Session::tool_pointer_left reaches it.
- The canvas remembers whether the pointer was over it last frame: on
leaving with no drag it calls tool_pointer_left; on coming back it
re-hovers the tool even after a single jump egui doesn't count as
moving, so the guides show again.
Tests: canvas::tests::distance_guides_go_when_the_pointer_leaves_the_
canvas (fails before: the label stayed over a panel with Alt held),
select::tests::distance_guides_need_alt_a_selection_and_smart_guides
(pointer_left clears them).
Distance Guides, from the public "Use Distance Guides for accurate
placement" and "Smart Guides options" (Invoke Distance Guides) pages:
with Smart Guides on, something selected and the Selection tool,
holding Alt/Option over another object shows the horizontal and
vertical distances between the selection and it, and over an empty
part of an artboard the selection's distances from the artboard's left,
right, top and bottom edges.
- guides::distance_guides measures the selection's bounds to a box: on
an axis on which they lie apart, the gap between their facing edges;
otherwise the offsets of both pairs of matching edges. Each line runs
across the middle of the overlap on the other axis (else the
selection's middle), with a dashed line out to the target's edge when
it passes beside it. An artboard is always measured edge to edge.
Labels are in the General unit, in the smart guide colour.
- The Selection tool keeps what its Alt hover points at and draws the
guides while idle; letting Alt go (the canvas re-hovers on a modifier
change), a press or moving off clears them.
- Overlay::Distance: the line with end ticks and its length in a pill;
the canvas draws it.
- Preferences › Smart Guides › Invoke Distance Guides (`distanceGuides`,
on by default), with i18n rows; View › Smart Guides gates it too.
- Hover only, as the pages describe: nothing while moving or nudging.
Tests: select::tests::alt_over_* (gap and edges beside and below,
artboard edges in pt and mm), distance_guides_need_alt_a_selection_and_
smart_guides, tests_prefs::invoke_distance_guides_measures_the_selection_
to_the_object_under_alt, canvas::tests::alt_over_another_object_draws_
the_distance_guide_label (frame test of the drawn label and line).
A file opened or placed off the UI thread waited while the active tool
reported busy. The Dimension tool also reports busy between its clicks,
so after one click a ready file stayed queued with its spinner until
the dimension was finished or canceled. Files also waited between the
clicks of the Blend tool.
The session now records whether the pointer button is held. A file
waits for a busy tool only while the button is held. A file that
opens between a tool's clicks resets the tool, as a switch of
documents does; a file placed in the active document leaves the
tool's clicks in place. Files still wait while a dialog is open, a
drag is under way or a preview is open, and a tool's preview between
its clicks counts as one (the Flare tool after its center drag, the
Dimension tool's line once the pointer moves after its second click).
With the Artboard tool, File › Revert kept the active artboard, but a
command.batch with a file.revert step made artboard 1 the active one.
A batch that switched to another document and back, and the Actions
panel menu's Batch… over a folder whose files it closes or over data
sets with a Revert step, did the same. Each of them starts the tool
afresh and ends in the document it started in, and the app moved the
view to the fresh tool's artboard 1. Only a plain file.revert was
handled, by its command id.
The engine now counts the times switching or closing documents, or
replacing the active one, starts the tool afresh (Session::tool_resets),
and records whether the tool's options were set after that
(Session::tool_set_since_reset). When the count changes during a
command and nothing set the tool's options after it, the app starts
the tool on the active artboard, as it does when a command chooses
another document. When a later step chose the tool's artboards (a
Paste or Cut after the revert), the artboard the tool then has active
becomes the active one.
Docs: docs/mcp.md, docs/target-app-parity.md.
Pen Cmd-borrow keeps Direct Selection when Alt is held so guide copy and other Alt modifiers on the lent tool still work.
Co-authored-by: Cursor <cursoragent@cursor.com>
When Direct Selection was last used or is active, Cmd+Alt borrows Group Selection for pointer presses, matching the documented modifier chord.
Co-authored-by: Cursor <cursoragent@cursor.com>
With Use Preview Bounds on, every hover frame's cursor and every
pointer move measured the selection again, and with Smart Guides on
each selected object too, evaluating their geometry effects each time.
The session now keeps a PreviewMemo, which ToolContext::preview_memo
passes to the tools. selection_bounds, selection_box and the object
bounds that Smart Guides find centers in while hovering read it. The
memo holds the measurements for one key: the document's uid and
revision, the selected objects and Use Preview Bounds. A new key
replaces them. VectorcraftApp::selection_box in the UI keys on the
uid, the revision and Use Preview Bounds. A ToolContext without a
memo measures on every call.
Wire the View menu toggle and add glyph baselines and bounds to drawing snap targets so point type placement lines up with existing text when Smart Guides are on.
Co-authored-by: Cursor <cursoragent@cursor.com>
Keyboard increment (Shift ×10) moves the active glyph through text.touchType, with vertical type remapping like the Type tool.
Co-authored-by: Cursor <cursoragent@cursor.com>
Object > Rasterize, Crop Image, Flatten Transparency, Expand
Appearance of raster effects and Vector Halftone draw the art with the
renderer and replace it with the result. When the art held an image
that could not be decoded, the renderer drew nothing for it, and the
result lacked the image with no message. A raster export of the same
art warns that "an image couldn't be decoded and is missing from the
picture".
These five commands now compare decode_failures before and after they
draw, as raster exports do, and their replies carry that text as
`warning`. They still make their result in one undo step. The app
shows a command's `warning` in the status bar: after a menu command,
after OK in a dialog with a preview, and after a tool runs a command
(Crop Image's Apply).
Docs: docs/mcp.md (Flatten Transparency, Expand Appearance, Document
Raster Effects Settings, Vector halftone).
View › Rulers › Change to Global Rulers (Cmd+Alt+R) was a disabled
stub: the rulers always counted from one document zero point. The
reference app's public help describes two modes: artboard rulers, the
default, count from the active artboard's top-left corner, and each
artboard can have its own zero point; global rulers keep one zero point
for the whole document whichever artboard is active.
https://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/about-rulers.htmlhttps://helpx.adobe.com/illustrator/desktop/measure-and-align/grids-and-guides/use-rulers.html
`view.globalRulers {global?}` switches the mode (toggle by default),
undoable and saved with the document (`rulers`). The menu item reads
Change to Artboard Rulers while global rulers are on. A new document has
artboard rulers; a file saved before the mode existed has no `rulers`
key and opens with global rulers, so it measures as it did.
With artboard rulers, dragging the ruler corner sets the active
artboard's zero point, kept as an offset from its corner
(`artboard_ruler_origins`, by artboard id) so it moves with the
artboard, and double-clicking the corner resets it. The global zero
point (`ruler_origin`) stays separate. `document.rulerOrigin`,
`document.setRulerOrigin` and `document.resetRulerOrigin` take
`artboard`; `Document::ruler_origin_for` is the zero point with an
artboard active, falling back to the corner or the global one when a
stored value is out of range.
The rulers, the Transform, Properties and Control bar X/Y, the Info
panel's X/Y (which ignored the zero point before), ruler-guide
readouts and Shift ruler-tick snapping all count from that zero point:
the view's active artboard reaches the tools through `ViewInfo` and
`ToolContext::ruler_origin`. Command coordinates stay absolute.
Tests: engine/tests/ruler_origin.rs (default mode, per-artboard origin
following its artboard, global origin apart, toggle and undo, save and
legacy files, out-of-range values), ui-egui/src/tests_ruler_origin.rs
(position fields and corner drag on the active artboard, menu label and
shortcut), tools/src/rulerguide.rs (guide readouts and tick snapping).
Tests written for the single global zero point now turn global rulers
on first. "Change to Artboard Rulers" is translated in every catalog.
Docs: docs/ui-parity.md, docs/gaps.md (G7), docs/target-app-parity.md,
docs/mcp.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01U2JbUtM4MkzWLm9FgYiEsq
The overflow marker was drawn by the Type tools only, so with the Selection tool a text box smaller than its text showed no sign that text was hidden. Session::overlays now adds the marker of every selected area type and type on a path that overflows, unless a Type tool is active (it draws its own). The verdict is cached per object and font generation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
In Draw Inside, a double-click with the Selection, Direct Selection or
Group Selection tool outside the object being drawn into now sets the
drawing mode to Draw Normal (view.drawMode {mode: "normal"}), as
Shift+D does. The object's geometric bounds, grown by the selection
tolerance, count as inside, and a double-click after the object was
deleted also returns to Draw Normal. The tool then takes the
double-click as before: with the Selection tool, a double-click on the
empty canvas still exits isolation mode, and one on another object
still isolates that object. Other tools leave Draw Inside on.
Docs: docs/target-app-parity.md.
Drag out from a segment, corner, circle or arc to place a dimension; plain clicks pick two points or two lines. Radial dimensions on perfect arcs, picas, Away/Between and Left/Center/Right text placement. The Properties panel edits a selected dimension, with Apply to All (dimension.applyToAll) and Set as Default. Dimension Selected Paths, the Arc/R/Ø prefixes and the custom defaults are left out. The refresh returns at once in documents without dimensions (Document::dimensions); a linked dimension moved on its own keeps its place; modes, units, line types, arrows and text placement are enums; the tool has its own icon.
With the Type tool editing, a press with Ctrl (Cmd on the Mac) lends the
Selection tool for the drag. Its drag joined the open typing session, so its
preview started from the document before the typing: the type moved or
scaled and lost what had just been typed. The typing is now kept as its own
undo step before the lent tool takes the press, as Undo already does, and
typing goes on after the drag.
During a Selection-tool drag the bounding box and its handles stayed on
screen while the art moved, so the content looked as if it slid inside
a box of its own. The box now hides once a drag moves, scales or
rotates the selection, as in Illustrator, and comes back on release. A
press that hasn't moved, and a marquee, keep it. Tools gain
`transforming()` (Session::tool_transforming) for this.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A selection moved with the Selection or Direct Selection tool that lines
up with nothing along an axis lands as far from its neighbour as two
other objects of its row (or column) are apart, or halfway between its
two neighbours, within the snapping tolerance; the equal gaps are marked
with a line and end ticks in the Smart Guides colour. The objects are
taken as wholes on their layers (groups too), and inside a group holding
the selection, its other objects. Off, moves only line up as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An anchor was picked within the selection tolerance (3 px), the same reach
as its segments: a press a little off the anchor's 5 px square took the
curve instead.
- `ToolContext::point_tol`: anchors and direction handle ends are picked
within the selection tolerance, but at least 2 px past the drawn point
(4.5 px at the default Size 3, more with a larger Size). Anchors are
tested before segments, so where both are within reach the anchor wins.
- Direct Selection (presses, Highlight anchors on mouse over, blend spine
points and handles), the Anchor Point, Delete Anchor Point and Scissors
tools, and the Pen (its Alt conversions; its close/continue reach stays
5 px unless the points are drawn larger) use it. Segments, objects and
frame edges keep the selection tolerance.
- Of the topmost path with anchors in reach, the nearest anchor is picked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every drawing tool now asks one snapper (guides::DrawSnap) for the points it
places: the Pen's and Curvature tool's anchors, the Pencil's ends, the shape
tools' start and dragged corner or radius (Rectangle, Rounded Rectangle,
Ellipse, Polygon, Star, Line Segment, Arc, Spiral, the grids), the Type tool's
click and frame and a new artboard's corners. Points land on other objects'
anchors, centres and paths ("anchor", "center", "path") or line up with their
anchors, edges and centres ("align"); hovering shows it before the press, the
Pen's guides end its rubber band, and the Pen lands on the path being drawn
too. Shift keeps a point to its 45-degree step (from Constrain Angle) or a
box's diagonal and slides it along that way into line with a target.
Preferences > Smart Guides > Construction Guides and Angles now act: a drawn
point near a guide through the point it leaves from lands on it.
Before, the Pen snapped only its press and showed nothing, and the shape tools
re-gathered targets on every drag step from the document showing their own
preview, so the dragged corner stuck to where the last step left it.
Performance: targets are gathered once per document state (keyed on the
document's uid and revision, now in ToolContext), from the art in the window,
and sorted, so the anchors, centres and lines near the pointer are found by
bisection. Leaving objects out of the targets no longer looks up each node's
ancestry (quadratic in the document's size): one pruned walk does it, which
also speeds up the Selection tool's moves and resizes.
The direction handles' HandleSnap (#494) is now a DrawSnap holding its own
targets (Targets::for_handle) for the drag: one cache, one lookup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Reported: with the Pen there was no way to edit curves in place as Ctrl does in Illustrator on
Windows (Cmd on the Mac), segments couldn't be grabbed, and the curve-editing tools felt slow and
sometimes didn't take a handle.
- Cmd/Ctrl held at a press with any tool but a selection tool now borrows the selection tool in the
engine (Session::pointer), not in the canvas: the selection tool chosen last, or Direct Selection
for the Pen, Curvature and anchor tools until one is chosen. The tool lent to isn't deactivated,
so the Pen goes on drawing its path after the release while that path stays selected; it no
longer draws on another open path selected meanwhile. Agents reach it with pointer_gesture
mods.cmd. With Cmd held the pointer is the borrowed tool's. Choosing a tool or switching
documents mid-gesture gives the tool back first.
- Pen + Alt over a segment of a selected path reshapes it, as the Anchor Point tool does.
- The handles shown are the handles that drag (one helper for Direct Selection, the Anchor Point
tool and Pen + Alt): Direct Selection now drags the handles of a path selected as a whole (as
the Pen leaves it, so Cmd + drag of a handle while drawing works), the Anchor Point tool no
longer grabs handles that Show handles when multiple anchors are selected hides, the nearest
handle wins, and a handle shorter than the tolerance leaves its anchor to be picked. The anchor
tools pick within Selection & Anchor Display > Tolerance instead of a fixed 4 px.
- path.reshapeSegment keeps a smooth anchor at either end smooth (its other handle turns with the
moved one) instead of kinking it.
- A dragged handle gathered its smart guide targets from the whole document on every pointer move
(21 ms per move on 20,000 paths): HandleSnap now gathers them once per drag (1 ms).
vectorcraft-cli perf measures handle and segment drags on a 5,000-anchor path.
- catalog::is_selection_tool and catalog::edits_anchors replace the UI's own lists.
- Tests in tools, engine and MCP (headless pointer_gesture); docs/mcp.md, control-protocol.md,
ROADMAP.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Preferences › Type › Type Object Selection by Path Only was stored and never read.
On, the Selection tools pick type on its type path only — point type's baseline
(the line the selection marks under it, across its layout's width), area type's
frame, type on a path's path — within the selection tolerance; a click among the
glyphs or inside the frame selects nothing. Off (the default), anywhere in the
type's bounds selects it, as before.
`HitOptions` gains `type_path_only`, set by the tools' context (`hit_options()`)
and the canvas's `hit_at` from the preference, so the Selection tools, Cmd-click
behind, object highlighting and the context menu agree. Tests at the hit-test
level (point, area and on-path type) and through the Selection tool with
`prefs.set`.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Color, Alignment Guides, Anchor/Path Labels, Measurement Labels,
Transform Tools, Object Highlighting and Snapping Tolerance are read:
- tools: `guides::GuideStyle` on `Targets` (`styled(cx)`) colours the
lines and labels and leaves them out when their option is off, the
snap itself unchanged; `ToolContext` gains the six fields and
`snap_tol()`, replacing the 5 px literal for every smart guide snap
(drawn points, moves, bounding-box handles, ruler guides, artboards,
reference points). The tools gate their `Overlay::Measure` readouts on
Measurement Labels (drawing, moving, ruler guides, artboards) or
Transform Tools (scaling, rotating, Free Transform, transform tools).
- engine: `with_tool_cx` fills them from `Prefs` (the colour parsed, magenta
as fallback); the colour's default is `#ff3dfc`, what the tools drew.
- ui-egui: the hover outline needs Object Highlighting and Smart Guides.
- Tests in tools (guides, select), engine (tests_prefs) and the canvas;
docs/mcp.md and ROADMAP.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Guides dragged out of a ruler did not snap at all (only Shift to the ruler's
ticks): they now go through the engine (`Session::ruler_guide`, a
`NewGuide` previewing `guide.add`, one undo step) and snap as a moved guide
does: with Smart Guides to the edges, centres (so the sides' midpoints) and
anchors of the art and of the artboards, labelled; with Smart Guides off,
View > Snap to Point pulls new and moved guides onto anchors. Moving art
with the Selection tool already snapped flush to artboard edges and centres
with Smart Guides on; a test now covers it.
Artboard guides: `Guide.artboard` holds an artboard id (written only when
set, so canvas guides save as before and older files open unchanged).
`guide.add {artboard}` makes one, `guide.list` reports it; a guide dragged
out of a ruler with the Artboard tool belongs to the active artboard. It is
drawn, picked and snapped to across its artboard only, moves with it
(`artboard.move`, a pure move in `artboard.setProps`, `artboard.rearrange`),
is copied with it (`artboard.duplicate`, Alt-drag copy) and deleted with it
(`artboard.delete`, the guide selection kept in step).
Guides as Layers rows with their own lock and hide (part d) stay open: ruler
guides are not layer nodes; Lock Guides locks them all, and Make Guides
paths are Layers rows already. Listed in the ROADMAP parity row.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fourteen more Preferences options that were stored but read by nothing now
act, for the mouse and for agents (prefs.set, then pointer_gesture,
press_key or the commands):
- Selection & Anchor Display: Snap to Point and its distance (with Smart
Guides off, View > Snap to Point lands a dragged selection's grabbed
point, drawn points and reference points on anchors and ruler guides);
Move Locked and Hidden Artwork with Artboard (artboard.move, the Artboard
tool and Rearrange; off, hidden art now stays too); Enable Rubber Band for
the Pen and Curvature tools; Handles (solid, hollow, large);
Show handles when multiple anchors are selected (canvas and Direct
Selection's handle picking); Hide Corner Widget for angles greater than.
- General: Transform Pattern Tiles is the default of a new `patterns`
param on object.transform/move/rotate/scale/reflect/shear/transformEach
(journalled when the art uses a pattern), and the transform dialogs get a
Transform Patterns checkbox; Select Same Tint % (off, Select > Same
Fill/Stroke Color takes every tint of a global or spot swatch).
- Type: new type.step {attribute, by} steps size, leading, tracking, kerning
and baseline shift by the Size/Leading, Tracking and Baseline Shift
increments; Increase/Decrease Font Size (Cmd+Shift+. and Cmd+Shift+,);
the Type tool's Alt+arrows (kerning at a caret or tracking, leading,
Shift for baseline shift, Cmd/Ctrl for five steps). Enable Missing Glyph
Protection keeps characters a new font lacks in the font that had them
(text.setStyle, text.setRangeStyle). Fill New Type Objects With
Placeholder Text: type the Type tools place starts with placeholder text,
selected (text.create / text.createInPath take `placeholder`).
Units > General, Stroke and Type were already the single source of truth
(units.rs). Auto Size New Area Type, Show Font Names in English and
Highlight Alternate Glyphs need subsystems the app doesn't have yet and
stay open with the rest of #394.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Guides dragged out of the rulers could not be touched again: no tool hit-tested
them, so a click on a guide went to the art under it.
- The Selection, Direct Selection and Group Selection tools pick a ruler guide
within the selection tolerance (over the art; Direct Selection takes an
anchor on it first) through a shared tools::rulerguide::GuideEdit. A drag
moves the selected guides in one undo step (Alt copies them, Shift snaps the
dragged one to the ruler's ticks, otherwise it snaps to pixels, the grid or,
with Smart Guides, the art's edges, centres and anchors); dropped off the
canvas onto its ruler, the guide is deleted. Hidden or locked guides can't be
picked; the pointer shows which way a guide moves.
- Selection::guides holds the selected guides (on their own, like slices); the
canvas draws them in the selection colour. Delete/Backspace (edit.clear)
delete them, the arrow keys (object.nudge) nudge them, Lock Guides and Hide
Guides deselect them.
- Commands for agents: guide.list, guide.select {indexes, toggle?},
guide.move {dx?, dy?, copy?} (besides {index, pos}) and guide.remove {index?};
guide positions out of range are refused. Documented in docs/mcp.md.
- Shift while dragging a new guide out of a ruler snaps it to the ticks too
(Unit::ruler_step, shared with the rulers' drawing).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Fifteen Preferences options were stored but read by nothing. They now act,
through the existing plumbing (ToolContext for the tools, the prefs read by the
canvas for the view), and reach agents through prefs.set:
- General: Show Tool Tips (off: no widget's tool tip comes due), Double Click
To Isolate, Zoom with Mouse Wheel (the wheel zooms about the pointer,
Shift-wheel scrolls up and down, Cmd/Ctrl-wheel sideways), Use Precise
Cursors (Pen, Eyedropper, Slice and Blend pointers become a crosshair).
- Selection & Anchor Display: Tolerance (objects, anchors and handles, in
place of the fixed 3 and 4 px), Object Selection by Path Only (compound
paths too), Command Click to Select Objects Behind (cycles down the objects
under the pointer; not when Cmd only borrows the selection tool), Zoom to
Selection (Zoom In/Out centre the selection), anchor Size, Highlight anchors
on mouse over (Direct Selection).
- Type: Number of Recent Fonts (up to 15 Recent Fonts slots).
- Guides & Grid: guide and grid Color and Style (lines or dots), Grids In Back.
The canvas's context menu, panel drops and hover highlight pick objects like
the selection tools. The control channel gets ui.wheel (with modifiers held
like ui.click) so agents can turn the wheel. The rest of #394 stays open.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Choosing a perspective tool shows the grid, but the canvas also re-selected the tool after a
Cmd-drag with the borrowed Selection tool, so a grid hidden with the tool chosen came back after
any Cmd-drag. `Session::switch_tool` (and the app's `restore_tool`) switch without choosing; the
temporary-tool return uses it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The grid was drawn whenever its `visible` flag was set or a perspective
tool was active, and choosing the Perspective Grid tool (Shift+P) didn't set
the flag. So with the tool chosen, View > Perspective Grid > Hide Grid
(perspective.grid.show) turned the hidden flag on instead of off and the
grid stayed on screen however it was toggled.
Choosing a perspective tool now shows the grid (sets `visible`, view state,
no undo step), and the grid, its widget and the Perspective Grid tool's
handles are drawn only while it is visible. Hide Grid hides it with the
tool still chosen; choosing the tool again shows it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Between paths, the Pen now adds an anchor where a click lands on a
segment of a selected path and deletes the anchor a click lands on,
with the add and delete cursors while hovering, as in the reference
app. The ends of a selected open path still continue it. Shift held,
or General > Disable Auto Add/Delete (a stored preference nothing read
until now, passed to tools as ToolContext::auto_add_delete), starts a
new path instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Typing with an input method (the macOS Japanese IME and the like) used to
insert the raw keys (romaji came in as ASCII): egui's Ime events weren't
handled.
- Tools gain `ime_preedit` / `composing` / `ime_caret`; the Type tool lays
the marked text out in place inside its typing session, underlined (the
clause being converted thicker), and commits it through `text_input`.
Character ranges from the IME convert to byte ranges in one place. A
cancelled composition leaves no empty undo step; an empty clear with
nothing marked never deletes the selection.
- The UI sends Text and Ime events to the tool in order, sends IMEOutput
every frame while text is edited (what lets egui-winit enable the IME
and place its candidate window at the caret, or the converting clause),
and holds back keys, Enter/Escape, clipboard, single-key shortcuts and
menu commands (Undo, Cut, Select All… also from the native menu) while
composing. A click, a tool switch or a style change ends the
composition with the marked text kept as typed; on macOS the IME is
told to discard it (NSTextInputContext.discardMarkedText) so it doesn't
come back in the next input.
- Undo during a typing session also ends the Type tool's session, so its
caret and marked text follow the document.
- Tests: tools (char → byte ranges, underlines and candidate position),
engine (compose → commit is one step, cancel leaves no step, a click
commits, Undo mid-composition is safe), ui-egui (synthetic Ime events:
compose, commit, ⌘Z held back, IME output, click and app switch).
Checked by hand on macOS 27 with the Japanese IME (romaji input, convert,
commit, cancel, Undo/Redo after commit, click away, Latin mode, app
switch). Not checked: Windows and Linux IMEs, the web build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Perspective Grid tool's left and right ground-level points move the whole
grid; the left and right extents are separate (extentRight; Alt drags both,
Shift goes by whole cells); a cell size widget sits up the line where the planes
meet; Shift keeps a vanishing point on the horizon and the ground points and
origin on one axis. The Plane Switching Widget stays put in a corner of the
document window (ViewInfo/ToolContext carry the window as a ScreenFrame), takes
its clicks with any tool while the grid shows (the Perspective Selection tool
too while it's hidden), and 1-4 pick the left, horizontal, right and no plane.
Double-clicking the Perspective Grid tool opens Perspective Grid Options
(show the widget, its corner; perspective.widget.options, kept with the
preferences).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Holding the brush still keeps Twirl, Pucker and Bloat applying, scaled by the
time held: a new Tool::tick (time supplied by the host: canvas frames, or
`holdMs` on ui.pointer / pointer_gesture events) repeats the last point every
0.1 s, one more dab there. Liquify never touches graphs, meshes, type, symbols,
images, or envelopes, repeats and blends with their contents, nor guides in
selection mode; those under the brush come back in `skipped` with a `warning`
that the status bar shows (UiRequest::Status). A drag applies only the dabs
each new sample adds (the stroke's state is kept between previews), giving the
same result as the whole stroke, so journal replay still reproduces it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Each tool keeps its options (a table in vectorcraft_tools::settings) when another
tool is chosen, across document switches, and in the saved preferences
(Prefs::tool_settings). The 7 Liquify tools share one set of Global Brush
Dimensions; the Symbolism tools share their brush. tool.setOption takes
{values} and a `tool` (another tool's options are stored for later), returns
the options, and works headless (MCP host command).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Clicking with the Type tool runs text.create at once, and ending the edit
(Escape, another tool, a click elsewhere) only stopped editing, so every stray
click left an invisible empty text object and a "Type" history step.
The Type tool now remembers the point type its click placed and, when editing
ends with it still empty, runs the new text.discardEmpty command: it removes
the text and, when nothing else changed since the step that created it, drops
those steps so neither the document nor the history keeps a trace. A command
from outside the tool that takes the edited text out of the selection
(Deselect, a Layers panel pick) or removes it now ends the edit too
(Tool::after_command). Dragged area-type frames and type in or on a path keep
their frame.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Slice tool (Shift+K) drags out a user slice (Shift square, Alt from the
centre, snapping to ruler guides) as one undo step through
object.slice.create. The Slice Selection tool selects slices (Shift
toggles, object.slice.select), moves them (object.slice.move; object
slices move their objects), resizes a user slice by its handles
(object.slice.setRect), opens Slice Options on a double click and deletes
with Delete (object.slice.delete). Hidden or locked slices can't be
picked. Both tools have cursors drawn in code.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>