Commit Graph
83 Commits
Author SHA1 Message Date
aiongg 732d4ded79 refactor(tools): move select.rs tests to select/tests.rs 2026-10-26 18:18:16 +00:00
Taha-Mahmoodi de151f849a Type: the thread-break comments describe the behaviour in our own words
Review follow-up (CodeRabbit, clean-room): two doc comments quoted the
cited help page. Comments only.
2026-10-26 16:00:39 +07:00
Taha-Mahmoodi 54d9fbc162 Type: a double-click on a threaded port breaks the thread there 2026-10-26 16:00:39 +07:00
Taha-Mahmoodi 5b91057dca Repeat: a selected Grid Repeat has on-canvas handles for its rows, columns and spacing
With the Selection tool, a single selected grid repeat shows a handle below the grid (rows), one right of it (columns), one past its bottom-right corner (both) and sliders between its first two columns and rows (horizontal and vertical spacing), as the public Set grid repeat options page describes. Each drag previews object.repeat.options and commits as one Repeat Options undo step; Escape cancels, and a drag that ends where it began leaves no step. Bounding-box handles keep priority where they overlap, and the controls hide with the edges or the bounding box. Before, a drag there scaled the source or started a marquee.

Part of #2691.
2026-10-26 13:44:06 +07:00
Marco Arnulfo ec97ee2c80 Direct Selection: an anchor of type on a path's path drags and the type reflows along it (part of #3980) 2026-10-24 22:06:20 +02:00
Gabriel Luís da Silva f0ec1c8506 Fix #3716: a click near an anchor selects without moving the object
A Selection tool press within reach of an anchor or the centre grabs the
object by that point, but the drag threshold was measured from that point
instead of from the press. A press 3-6 px from it was already past the
threshold, so the first pointer wobble started a move and jumped the
object by the offset. The threshold now counts from where the pointer
went down; a real drag still moves the object by the grabbed point.
2026-10-24 04:49:07 +07:00
bflatastic f247772042 Type: selected type shows its in and out ports, and the in port threads backwards
Squashed from #3817 onto main.
2026-10-24 03:09:10 +07:00
Taha-Mahmoodi 7693aeb508 Smart Guides: Distance Guides follow what lies under a still pointer
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.
2026-10-24 03:09:09 +07:00
Taha-Mahmoodi 26bf324c81 Smart Guides: a pan, zoom or view-rotation press ends the Distance Guides hover
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.
2026-10-24 03:09:09 +07:00
Taha-Mahmoodi 822effa384 Smart Guides: Distance Guides go when the pointer leaves the canvas with Alt held
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).
2026-10-24 03:09:09 +07:00
Taha-Mahmoodi d0b62e56fb Smart Guides: the Distance Guides tests pass clippy's type-complexity lint 2026-10-24 03:09:09 +07:00
Taha-Mahmoodi a301760aa6 Smart Guides: Alt over another object or the artboard shows the selection's distances to it
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).
2026-10-24 03:09:09 +07:00
Angelo Bernardini ef1fa1d228 G12: Constrain Angle for the arrow keys, Shift drags and new objects (#394)
Squashed from #3363 onto main.
2026-10-23 08:54:57 +07:00
Taha-Mahmoodi 970e62f27d Fix: a path moved by its stroke or edge lands exactly on a ruler guide
Cause: with Snap to Point, the point of a moved selection that snaps to a
ruler guide is the grabbed point (#1534). Away from an anchor or center
that was the raw pressed spot (select.rs: `grab` fell back to `p`;
direct.rs: a straight segment's `grab: p`, MoveObject's `start`). A press
on a stroke or within the pick tolerance of an edge lies a few pixels
beside the path, so the pressed spot landed on the guide, "align" showed,
and the path stopped that far beside it: 0.096 pt at 3,891% and 0.0099 pt
at 28,757% in the #3701 screenshots, visible only when zoomed in.

Change: `guides::hold_on_path` finds the nearest point of the path (on a
straight segment exactly on its line). `select::hold_point` uses it for a
press on the stroke or outline, or within 6 px of it. The Selection tool
(`State::Moving::hold`), Direct and Group Selection moves
(`State::MoveObject::hold`) and Direct Selection's straight-segment drag
(`grab`) snap that point. The move delta still runs from the press, so
nothing jumps. A press in the middle of a fill still snaps the pressed
spot, as Snap to Point is documented to.

Verification: tests_prefs::a_move_held_by_a_paths_stroke_lands_the_path_on_a_ruler_guide
and tests_prefs::a_straight_segment_dragged_by_direct_selection_lands_on_a_ruler_guide
fail without the change (edge 0.0257 pt and anchors -0.0052 pt off the
guide) and pass with it (|gap| < 1e-9 pt). A headless egui/wgpu render at
3,891% and 28,757% puts the guide, the selection outline and the centre of
the 1 pt stroke band in the same pixel column. cargo xtask ci: all 10
steps passed; 9429 tests passed, 0 failed.
2026-10-23 06:13:02 +07:00
nrq6993-a11yandCursor ab0ddf0eae G1: Live Corners relative rounding (#1144)
Store corner radii as fractions of each corner's max so rounding scales with the shape; expose via Corners dialog and object.setLiveShape relativeRadii.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-21 23:38:03 +07:00
Jürg Lehni af2618c9e4 Threaded text: type on a path threads, mixed with area type
Illustrator links type in an area or along a path (https://helpx.adobe.com/illustrator/using/manage-text-area.html); until now only area type threaded here. Type on a path that overflows ends its line where its text stops fitting, so a story flows on from it, and its red out port, just past its end bracket, loads the Selection tool with the text as area type's does. A new frame threaded from it at a point is type on a path of its shape.
2026-10-21 23:15:45 +07:00
dotCooCoo a5ea3a8002 Use Preview Bounds: a handle drag keeps the opposite visible edge in place
With Use Preview Bounds on, a bounding-box handle drag scaled the art by
the ratio of the visual box, so margins that stay (a stroke with Scale
Strokes & Effects off, an Offset Path reach) or scale by another factor
moved the opposite visible edge: dragging the right edge of a square with
Offset Path 10 from 210 to 310 left its left edge at 98.33 instead of 90.

The Selection tool now previews object.setBounds with the dragged visual
size and the opposite handle (with Alt, the center) as the reference
point, so the scale is solved from the geometric box and the margins the
visual box adds, for strokes with Scale Strokes & Effects on or off and
for geometry effects. Shift and Alt drags follow the same rule; a drag
that flips the box, and one with anchors selected, still scale by the
matrix. A previewed object.setBounds runs as object.transform with the
transform it finds, so Transform Again repeats the drag and the journal
holds that transform. The drag transforms a path of a compound path
selected on its own, as object.transform does, and leaves the art at
least 1e-4 of its width and height.
2026-10-21 17:11:08 +07:00
dotCooCoo 9f31471042 Use Preview Bounds: the selection tools measure the selection once per revision
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.
2026-10-21 17:11:08 +07:00
dotCooCoo 1267efbcf9 Use Preview Bounds: objects are measured with their geometry effects
With Use Preview Bounds on, the bounding box, the Transform panel,
Align, Distribute, Distribute Spacing and object.setBounds measured
each object without its geometry effects. A square with Offset Path
10 measured as the square, and type with Outline Object measured by
its layout box instead of its glyphs.

The new vectorcraft_effects::preview module measures objects as they
are drawn. A path is measured by its effected shape, with the
geometry effects of each fill and stroke that paints. Type, images,
live objects and symbol instances are measured by their reshaped art.
A group or layer with geometry or Pathfinder effects, or with a fill
or stroke of its own that has geometry effects or paints members with
geometry effects, is measured by its evaluated art. A blend, envelope
or repeat whose objects have geometry effects is measured by its
evaluated art, with those objects measured after their effects. Raster
effects are not measured. In one object, the art of at most 4,096 symbol
instances is measured with its geometry effects, and the other
instances are measured without them. With Use Preview Bounds off, the
measures are unchanged.

object.setBounds sizes objects with geometry effects by measuring
them after each scale it tries, so type with Outline Object set to
100 pt wide gets a glyph box 100 pt wide.

Selection::anchors_box is split out of Selection::anchor_bounds. The
doc comment of VectorcraftApp::selection_bounds said that it includes
effects; it now says that it leaves them out.
2026-10-21 17:11:08 +07:00
dotCooCoo 6a1c8eda46 Part of #1816: Snap to Grid lands a moved object by its nearest edge and no longer snaps its center
With View › Snap to Grid on, a whole object moved with the Selection,
Group Selection or Direct Selection tool landed on the grid by
whichever of its two edges or its center was nearest a gridline on
each axis. An object on the grid whose width is an odd number of grid
steps has its center half a step between gridlines, so a short drag
could pull it half a step off the grid: on a 20 pt grid, a 100 pt
square at (100, 100) dragged by (8, 8) moved by (10, 10).

A move now lands the nearer of the two edges on a gridline on each
axis, as the reference app's help describes, and the center no longer
snaps. The square above stays at (100, 100). This changes the rule #769
chose for #740. The plain move and the Shift-constrained one both use
grid_pull, so both change.

Docs: docs/target-app-parity.md (Drawing aids).
2026-10-21 16:55:17 +07:00
Drew DibbleandClaude Opus 5.5 5fd553cc8b G1: loaded text, double-clicks and guide release take what is drawn
The selection tools' clipping-path outline hit was also used where the
Selection and Direct Selection tools act on what is drawn rather than
select. Near a layer's clipping mask edge, with art drawn over it:
loaded text threaded into the unpainted mask instead of the art, a
double-click on type entered isolation on the mask instead of editing
the type (Selection) or did nothing (Direct Selection), and Cmd/Ctrl+
Shift double-click could not release a guide path there. These now
take the ordinary hit (ToolContext::hit_options); a press or hover
that selects keeps the outline hit.

Tests (each fails with the selection hit options):
select::tests::loaded_text_threads_into_the_art_on_a_layer_masks_edge,
a_double_click_on_type_at_a_layer_masks_edge_edits_it (Selection and
Direct Selection) and a_guide_on_a_layer_masks_edge_is_released, over
the new testutil helpers add_masked_layer and
doc_with_type_on_a_layer_masks_edge. Recorded in
docs/target-app-parity.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 15:44:27 +07:00
Drew DibbleandClaude Opus 5.5 061e905724 G1: selection tools take a clipping path on its outline
A clip group answered a press only strictly inside its clipping path,
and there the art above the path came first in the hit test, so where
the clipped art extends past the mask's edge the clipping path's
segments could not be reached on the canvas.

With the new HitOptions::clip_outlines, which the Selection, Direct
Selection and Group Selection tools set
(ToolContext::selection_hit_options), a press within the selection
tolerance of a clipping path's outline, inside or just outside it,
hits the clipping path (HitKind::Outline) before the art it clips:
Direct Selection takes its segments and the Selection tool the clip
group. It applies to a clip group's clipping path and to a layer's
clipping mask, and only to one a click may hit (may_hit: visible,
editable, within reach). Inside the mask the art is hit as before.

The other tools, which act on what is drawn (the eyedropper, type,
gradients...), leave the option off, and hit_test_visible never
applies it, so they still take the art at the mask's edge rather
than the mask's empty appearance. Select Behind's one-pass walk takes
a layer mask's outline first too, so it lists what the repeated hit
test finds. Object Highlighting and a right-click's selection in the
canvas (selection_hit_at) take what those tools take; dropping a
swatch on art still hits what is drawn.

The reference app reshapes a clipping path with Direct Selection:
https://helpx.adobe.com/illustrator/desktop/manage-objects/edit-objects/edit-clipping-masks.html

Tests in doc: a_clipping_path_is_hit_on_its_outline_before_its_art,
only_the_selection_tools_hit_a_clipping_path_on_its_outline and
select_behind_takes_a_layer_masks_outline_first; the random Select
Behind test now clips layers and sublayers and sets clip_outlines,
and fails without the Select Behind change. In tools,
a_press_on_a_clipping_path_takes_its_segment_over_the_art fails
without the change; select::a_press_on_a_masks_edge_selects_its_clip_group
fails when the Selection tool uses the plain options; the eyedropper
copies the art on the edge. Recorded in docs/ui-parity.md,
docs/gaps.md and docs/target-app-parity.md.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-21 15:42:37 +07:00
Dan Green 7852f363a1 Fix #2143: selected ruler guides align to a key object
A lone object selected with ruler guides can be the key (the Selection
tool's click on it), and Align to the key moves the other selected
guides to its edge or centre: vertical guides to left, centre or right,
horizontal ones to top, centre or bottom. Parallel guides line up on a
key guide. Aligning to the selection or the artboard leaves guides alone.
2026-10-20 05:56:59 +07:00
nrq6993-a11yandCursor fd53416de3 G1: honor Show Measurement Labels on pie, corners, width, and tiling readouts
Tools that showed distance or angle overlays during drags now respect the
Units preference, consistent with shape and selection tools.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor 99aa4e6a7c G1: hide bounding box while dragging type-on-path brackets.
Match corner-radius and pie-widget drags: the Selection tool reports a transforming drag so the canvas drops the sharp selection box during bracket moves.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 02:23:33 +07:00
nrq6993-a11yandCursor d41af02637 G1: Spacing Guides snap bounding-box resizes to equal gaps
Smart Guides spacing now applies when scaling with the Selection and Free Transform tools, not only on moves.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-10-20 01:48:35 +07:00
NetterSilverandClaude Haiku 5.5 3eed3be8e6 Stop locked guide objects from blocking marquee selection
Fixes #3036

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-19 22:19:42 +07:00
AJ Richardson 411f5f7680 prioritize bounding-box handles over mirror axis 2026-10-18 19:02:44 +07:00
AJ Richardson 63cebd392a Add interactive Mirror Repeat axis controls 2026-10-18 19:02:44 +07:00
dotCooCoo 034ef916ad Selection: a Shift-constrained move that snaps stays on its line
A move that Shift kept level, upright or on a diagonal left that line
when it snapped. With View › Snap to Grid on, a level Shift-drag also
moved the selection up or down onto a gridline, and Snap to Pixel,
Smart Guides and Snap to Point moved it off the line in the same way.
Each axis snapped on its own after Shift had constrained the move.

With the Selection tool, and with Group Selection and Direct Selection
moving whole objects, a Shift-constrained move now slides along its
line until it snaps. With Snap to Grid or Snap to Pixel, the move
slides along the line by the shorter of the two distances that put it
on a gridline or a whole pixel on either axis. The bounds line up with
the other objects, or space evenly with them, only on the axes the line
runs along, and the grabbed point stops where the line passes an anchor
or crosses a ruler guide. A level or upright move snaps along its own
axis only. Moves without Shift snap as before.

Docs: docs/target-app-parity.md.
2026-10-18 12:40:10 +07:00
dotCooCoo 23dd9a1f2a Fix #2054: bounding-box resize handles snap to the grid, pixels, points and ruler guides
A bounding-box handle dragged with the Selection or Free Transform tool
snapped only with Smart Guides on, and then only to the other objects
and the artboards. View > Snap to Grid, Snap to Pixel, Snap to Point
with Smart Guides off and the ruler guides did not move it, while a
move snaps to all of them.

The corner or side a handle moves now snaps as a dragged point does.
With Snap to Grid on it lines up with the nearest gridline, and with
Snap to Pixel on it lines up with whole pixels. With Smart Guides off,
Snap to Point lands it on the other objects' anchors and on ruler
guides within its distance. With Smart Guides and Snap to Point both
on, it lines up with the ruler guides as well as with the other
objects. Shift still keeps the proportions. Without Alt the opposite
side stays put, and with Alt the box still scales about its center.

Docs: docs/target-app-parity.md.
2026-10-18 01:27:14 +07:00
bflatastic 88567ee46c Part of #2572: clicking an area type's out port threads its text into a path or a new frame 2026-10-17 19:13:22 +07:00
dotCooCoo a12af589aa Rotate View: resize and rotate cursors turn with the view
In a rotated view the resize and rotate cursors were the ones for an
unturned view. With the view turned 90°, the right-middle handle of a
selection's bounding box shows at the middle of the box's bottom edge
and drags up and down, but its cursor was the left-right arrow. This
affected the Selection, Free Transform, Artboard, Slice Selection, Crop
Image, Perspective Grid and Perspective Selection tools, ruler guides,
and the spread handle of a freeform gradient.

Now each of these cursors turns with the view to the nearest 45°. The
Selection tool and the Perspective Selection tool turn the handle's
direction by the view's angle before they round it to a cursor.
ToolContext::view_angle reads the view's angle from the screen frame,
and Cursor::turned turns a resize or rotate cursor by it. The new
Cursor::rotate_about_in_view turns the pointer's direction from the
center by the view before it picks one of the rotate cursor's eight
directions. Cursor::rotate_about keeps its signature and behavior. At
0° every cursor is as it was.

Docs: docs/target-app-parity.md.
2026-10-17 16:18:28 +07:00
dotCooCoo b275eb04d0 Guides: a Cmd/Ctrl+Shift double-click releases the guide under the pointer
A double-click on a ruler guide with the Selection, Direct Selection or
Group Selection tool did nothing, whatever keys were held. A guide could
be released only with View › Guides › Release Guides.

With the Selection, Direct Selection or Group Selection tool, a
double-click with Cmd/Ctrl and Shift held now runs view.guides.release
on the ruler guide under the pointer (index) or, when no ruler guide
is there, on the guide path under it (ids). Nothing is released while
guides are hidden or locked, and a double-click without both keys does
what it did before.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-17 14:43:13 +07:00
Michael GiesonandClaude Opus 5.5 2d0da1472f Cursors: 36 more tool states get cursors of their own, listed in cursors.toml
Node editing as the public manual describes it: Direct Selection's anchor squares (hollow
or filled), Reshape Segment over a curved segment, Group Selection's plus (also Direct
Selection with Alt), the arrow hollow while a drag snaps, and Alt-copy arrowheads. The
Anchor Point caret, the Curvature pen and Free Transform's side-shear arrows (ShearH,
ShearV) are drawn in code. Lasso, the freehand, symbolism and other tools return cursors
of their own that borrow their old look until drawn (Cursor::stand_in).

crates/tools/src/cursors.toml lists every Cursor value, when it shows and its hotspot,
for whoever draws them; `cargo xtask cursors` (in ci) warns about a missing, unknown,
repeated or incomplete entry and never fails. The busy cursor is listed as missing (G1).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-17 12:26:12 +07:00
dotCooCoo 3b683bbeec Ellipse: dragging a pie widget on the canvas sets its pie angle
The Selection tool shows two pie widgets just outside a selected live
ellipse while the bounding box shows: one at the Pie Start Angle and
one at the Pie End Angle. Dragging one sets its angle to the angle of
the outline's point that lies in the direction of the pointer from the
ellipse's center, in one undo step, through `object.setLiveShape`'s
`pieStart` or `pieEnd`. Double-clicking one makes the ellipse whole
again (0° to 360°). Where the two widgets coincide, as on a whole
ellipse, a press takes the End widget.

Docs: docs/target-app-parity.md, docs/ui-parity.md.
2026-10-16 15:27:53 +07:00
dotCooCoo 5527418234 Selection: pressing E while dragging a marquee selects only the objects inside it
A Selection tool marquee selected every object it touched, a Group
Selection marquee selected the anchors inside it, and E pressed during
the drag did nothing. Now E switches either marquee to selecting only
the objects that lie entirely inside it, measured by their geometric
bounds, and E pressed again switches it back. Each marquee starts in
the default mode.

- The Selection tool selects a group only when the whole group lies
  inside. Group Selection selects the objects inside groups, each as a
  whole object. Shift still toggles. Direct Selection does not take E.
- The ruler guides the marquee selects with the art are limited the same
  way: an artboard guide is selected when its whole length lies inside,
  and a canvas guide is not selected.
- Tools receive letter keys as ToolKey::Letter. While a tool is busy, the
  desktop app sends it each press of a letter it claims, without Cmd,
  Ctrl or Alt and without key repeats, and headless press_key sends a
  claimed letter the same way. With nothing dragged, press_key {key: "e"}
  still chooses the tool bound to E.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-16 15:27:53 +07:00
dotCooCoo 21b4e70150 Shaper: an arrow widget switches a Shaper Group between Face Selection and Construction mode
A Shaper Group had no arrow widget for switching between Face Selection
and Construction mode.

With the Shaper or Selection tool active, a selected Shaper Group, or a
group with one of its faces selected, now shows an arrow beside the
middle of the right side of its source shapes' bounds. A click on it
isolates the source shapes (object.isolate). A second click leaves
isolation with the group selected (object.exitIsolation). The arrow
points right in Face Selection mode and left in Construction mode.

In Construction mode a Shaper click selects an original shape of the
isolated group. Before, it selected the whole group outside the
isolation, and shaper.select with source could pick an original of
another Shaper Group lying above it.

Docs: docs/shaper.md, docs/target-app-parity.md.
2026-10-16 15:00:07 +07:00
sanyamsingh001andCodex 74573d6bad G1: Cancel existing-guide drags with Escape
Co-authored-by: Codex <noreply@openai.com>
2026-10-16 04:44:59 +07:00
bflatastic 2843687ef4 Text: leave out the bottom-handle Auto Size double-click until its behaviour is settled (#1947) 2026-10-16 04:44:31 +07:00
Marco Arnulfo a69371656b Text: Ctrl+Shift+C aligns centre off the Mac, a double-click on area type's bottom handle turns on Auto Size (fixes #1940) 2026-10-16 04:44:29 +07:00
dotCooCoo a14abc3177 Control bar: buttons isolate the selected object and exit isolation mode
The Control bar had no isolation controls. In isolation mode it now
shows an Exit Isolation Mode button (`object.exitIsolation`), except
while a pattern is edited: the isolation bar's Done and Cancel end
that edit. Outside isolation mode, with one group, compound path,
path, image, mesh or placed file selected, it shows an Isolate
Selected Object button (`object.isolate`). After a Direct Selection
click on a path inside a group, the button isolates that path. An
envelope's contents get no button: for them the Control bar shows the
envelope's Edit Envelope and Edit Contents buttons.

The button offers the kinds of object that the Selection tool's
double-click isolates. The double-click's check moves unchanged into
`vectorcraft_tools::select::isolates`, and both use it.

Docs: docs/target-app-parity.md.
2026-10-16 02:25:49 +07:00
bflatastic ed96b2ff65 Marquee guide selection: one shared helper for both selection tools 2026-10-14 08:01:50 +07:00
Murat Vural 8796aa9d85 feat: marquee selection selects unlocked ruler guides 2026-10-14 08:01:50 +07:00
bflatastic 50911d8608 Fix #1534: a dragged selection snaps to ruler guides with Smart Guides on too 2026-10-13 08:51:43 +07:00
Vikram Bhaskaran bf2b5643dc Hide the selection bounds while a corner-radius drag is underway.
The sharp outer box stayed on screen because a corner drag was not treated as a transform.
2026-10-12 19:50:12 +07:00
Ayberk A. 3073f0ab03 Isolation mode: double-clicking a single object isolates it
With Double Click To Isolate on, the Selection tool isolated groups only. A
double-click on a single path, compound path, image, mesh or placed file now
isolates it too, as the public documentation describes. Type still switches to
the Type tool; blends, envelopes, repeats and symbol instances keep their own
editing modes.

While a single object is isolated only it is hit, marqueed and taken by Select
All, new art goes beside it in its group or layer, and a double-click on the
empty canvas leaves with it selected. object.isolate accepts any object except
type.
2026-10-12 18:56:41 +07:00
arhammusheer 5beac4f122 #1244: smaller objects: Node 352 -> 152 bytes, NodeKind 200 -> 80, and a cheaper undo estimate
Rarely set fields move into one optional boxed NodeExtras, and large NodeKind payloads (images,
live shapes, blends, envelopes) are boxed. Every object, and every undo step that copies it,
shrinks: a 50k-path move keeps ~24.5 MB per step instead of ~40 MB. Files stay byte-identical
(Node keeps its flat JSON through a borrowed Serialize and a from-wire Deserialize, no flatten),
and loading is slightly faster. Undo and redo reuse their step's size estimate instead of
walking the document again (8.3 -> 5.6 ms for a 50k-path move).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VmMmc1J8XeNLxhRihWv9cc

# Conflicts:
#	crates/engine/src/cmd/graph.rs
#	crates/svg/src/export.rs
2026-10-12 11:02:32 +07:00
Fabio LussiandClaude Opus 5.5 8b839dd50f Snap to Point: drag a selection by the anchor pressed near
With Smart Guides off, the Selection tool grabbed the selection by the
pressed spot, so Snap to Point brought the pointer onto another anchor
while the object's own anchor stayed a few pixels off. A press within
reach of an anchor now grabs the object by that anchor (Smart Guides on
or off, also without a hover event first), and the arrow turns hollow
over such an anchor while Snap to Point is on.

Fixes #1274

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 07:49:47 +07:00
bflatastic 4ab69b877e Tests and Czech: select.key's new error is translated in cs, and the select tool test sets a shared appearance 2026-10-12 00:34:57 +07:00