Commit Graph
872 Commits
Author SHA1 Message Date
BFlat a92993daf9 Merge pull request #7582 from dotCooCoo/fix/clip-effects-hit-test
Selection: clicks in a clip group follow the region its clipping path's effects give it
2026-11-15 06:16:57 +07:00
BFlat c0ce77a912 Merge pull request #7663 from dotCooCoo/feat/perspective-auto-plane-positioning
Perspective: Perspective Grid Options has Automatic Plane Positioning
2026-11-15 05:30:40 +07:00
BFlat 35bf3a7412 Merge pull request #7625 from dotCooCoo/fix/shape-builder-open-path-drawn-fill
Shape Builder: an open path counts as filled by the fill rows that draw
2026-11-15 05:29:46 +07:00
ncic d3213cf5b2 Merge remote-tracking branch 'upstream/main' into pencil-no-guides 2026-11-14 22:02:14 +01:00
dotCooCoo cf8b88b0ea Merge main into fix/clip-effects-hit-test 2026-11-14 12:59:50 -08:00
dotCooCoo ec5472f726 Merge main into fix/shape-builder-open-path-drawn-fill 2026-11-14 12:38:20 -08:00
BFlat 85ce363b93 Merge pull request #7548 from dotCooCoo/fix/objects-on-path-widgets-flatten-once
Objects on Path: the widgets flatten the group's path once per lookup
2026-11-15 03:22:27 +07:00
dotCooCoo b7678494a2 Merge main into fix/clip-effects-hit-test 2026-11-14 12:18:53 -08:00
dotCooCoo 163f256418 Perspective: Perspective Grid Options has Automatic Plane Positioning
Perspective Grid Options gets the two Automatic Plane Positioning
checkboxes, Anchor Point of Perspective Artwork and Intersection of
Gridlines. With the Perspective Selection tool, Shift held over an
anchor point of art in perspective, or over a gridline intersection,
with no button down, moves the active plane through that point and
hides the other planes. A plane made active then passes through the
same point. The plane goes back to its place once an object is drawn
on it or attached to it, when the grid hides or no plane is active,
when the file is opened again, and with Escape.

- perspective.plane.infer {at?, tolerance?, clear?} positions, reads
  and clears the held point, which is view state, not an undo step.
- perspective.widget.options takes anchorPoint and gridlineIntersection,
  both on by default and kept with the preferences.
- perspective.plane.move moves a held plane from where it is held.
2026-11-14 12:11:36 -08:00
dotCooCoo 9d0a4eb731 Shape Builder: rewrap the shape_builder_shapes doc comment 2026-11-14 11:47:28 -08:00
ncic badf89be39 Merge remote-tracking branch 'upstream/main' into pencil-no-guides
# Conflicts:
#	docs/mcp.md
#	docs/target-app-parity.md
2026-11-14 20:32:09 +01:00
dotCooCoo f0c920fa8e Shape Builder: leave out Live Paint faces and edges with an opacity of 0
A visible, unlocked Live Paint face or edge whose own opacity is 0 draws
nothing, as Expand and the edge stroke check already treat it, but the
Shape Builder still took it as an input. It now leaves such faces and
edges out; hidden and locked parts keep their current handling.
2026-11-14 11:15:41 -08:00
dotCooCoo 924aa258d0 Merge main into fix/shape-builder-open-path-drawn-fill 2026-11-14 10:29:06 -08:00
BFlat 8c5494bccc Merge pull request #7342 from dotCooCoo/feat/live-paint-selection-double-click
Live Paint: a Live Paint Selection double-click selects the connected faces or edges
2026-11-15 00:40:41 +07:00
BFlat 01e66f0a19 Merge pull request #7477 from dotCooCoo/fix/dimension-second-point-guides
Dimension tool: no construction guides through a first point off the anchors
2026-11-15 00:39:29 +07:00
BFlat d89f593bfa Merge pull request #7380 from ncic/pencil-cursors
Pencil: shows where a stroke continues, connects and closes
2026-11-15 00:38:01 +07:00
dotCooCoo 1d94c97425 Selection: symbol parts count the Preview of the instance's layers
Direct Selection on a dynamic symbol's instance below a layer whose
Preview is off tested and outlined the art in Preview, where the canvas
draws it in outline with the plain clipping paths. When a clipping
path's effects left no region, a selected object in its clip group kept
an outline cut to the plain clipping path.

- `hit::symbol_part_at` and `hit::symbol_part_outline_in_view` count the
  layers around the instance, the isolated container and the layers
  around it apart, as clicks outside symbols do.
  `symbol_part_outline_in_view` takes the click options in place of the
  outline flag.
- The outline of an object is empty when the effects of a clipping path
  around it leave no region.
2026-11-14 09:30:12 -08:00
dotCooCoo 11bd1659f5 Selection: symbol parts follow the region a clipping path's effects give it
Direct Selection on a dynamic symbol's instance picked an object in the
region its clipping path's effects give it, but cut the object's outline
to the plain clipping path, so the outline came out empty or cut short.
In a layer of the art whose Preview is off, it tested the effect-shaped
region and the fills, where the canvas draws the plain clipping path and
outlines.

- `hit::symbol_part_outline` cuts to the bounds of the effect-shaped
  region. The new `hit::symbol_part_outline_in_view` takes the view's
  outline state, and the Direct Selection overlay passes it.
- `hit::symbol_part_at` tests art in a layer whose Preview is off in
  outline.
2026-11-14 08:51:22 -08:00
dotCooCoo bbe9480656 Shape Builder: an open path counts as filled by the fill rows that draw
Consider Open Filled Paths as Closed decided whether an open path was
filled from its top fill row only. A path whose top fill is None over a
painted lower fill stayed open, and one whose only painted fill was
hidden or at 0% opacity closed. The region map, merge inputs and the
Clicking Stroke Splits the Path cut now use Appearance::has_drawn_fill,
so any shown, painted fill row above 0% opacity counts, as the canvas
paints it.

The Shape Builder's Live Paint face and edge filters had the same
top-row check; they now use has_drawn_fill and has_drawn_stroke, so a
face or edge is taken when one of its rows draws.
2026-11-14 08:00:35 -08:00
dotCooCoo c7cd768399 Merge main into fix/clip-effects-hit-test 2026-11-14 07:42:26 -08:00
FredApps 676f0524cc Merge pull request #1203 from FredApps/fix/spiral-decay-setting-20261011
Keep Spiral decay settings consistent with drawn geometry
2026-11-14 16:22:35 +01:00
BFlat 6e3ec907de Merge pull request #7592 from dotCooCoo/fix/brush-freehand-unknown-brush
Brushes: brush.freehand refuses a brush or style it cannot use
2026-11-14 21:52:42 +07:00
dotCooCoo f6ad3ecc01 Merge main into feat/live-paint-selection-double-click
# Conflicts:
#	docs/target-app-parity.md
2026-11-14 06:28:52 -08:00
ncic cd89999939 Merge remote-tracking branch 'upstream/main' into pencil-cursors
# Conflicts:
#	docs/target-app-parity.md
2026-11-14 14:42:23 +01:00
dotCooCoo f37c5c293e Brushes: brush.freehand refuses a brush or style it cannot use
brush.freehand drew the plain path when `brush` named no brush in the
document or was not a string, and drew a pencil stroke for any `style`
other than "brush". It now refuses an unknown name with "no brush named
`<name>`", as brush.apply and brush.setCurrent do, a `brush` that is not
a string, and a `style` other than "pencil" or "brush". The document does
not change and no undo step is recorded. A `brush` left out or null still
draws the plain path.

The Paintbrush skips a tool brush or current brush that has been deleted
and paints with the other, or draws the plain path when neither is in the
document, so a stroke after a brush is deleted is not refused.
2026-11-14 04:41:02 -08:00
ncic fc47e4782b Pencil: Use Precise Cursors shows the plain crosshair again; a far close is a straight segment 2026-11-14 13:23:22 +01:00
FredApps c9a199ff91 Merge branch 'main' into fix/spiral-decay-setting-20261011 2026-11-14 13:15:33 +01:00
dotCooCoo 8fa551e173 Selection: clicks in a clip group follow the region its clipping path's effects give it
The canvas clips a clip group by its clipping path with the path's live
geometry effects applied, but clicks, hovers and marquees still tested
the plain clipping path. A click where a Transform effect had moved the
clip selected nothing, and a click on the clipping path's own place
selected art that was not drawn there.

- The engine registers the effect-shaped region with the doc crate
  (`hit::set_clip_region`), as it does for image paint and live art. It
  gives a region only when the clipping path holds a visible geometry
  effect; otherwise clicks keep the plain shapes, and type keeps
  counting by its frame.
- Clicks, `objects_at`, the hidden art of a selected object, the Unlock
  submenu's list and marquees inside a clip group or a clipping layer
  use that region. Outline view and layers with Preview off draw no
  effects and keep the plain shapes; the Selection, Direct Selection
  and Enclosing Lasso marquees pass the view's outline state
  (`hit::marquee_in_view`). Each container around a selected object
  tests its clipping path in the outline state a click has there.
- A marquee touches the clipping path itself by its own geometry, as a
  click on its outline finds it, and also on the edge of the region, so
  a marquee around a clipping path that an effect moved into large art
  still selects it. `hit::marquee_in` keeps the plain shapes for the
  Color Theme Picker, which clips by them.
- The region is kept per thread until the clipping path or the live
  inputs change. A clip group's reach takes in the region's box, so
  culling does not skip art the region moved past the plain clipping
  path. Up to 4096 boxes are kept; when they are full, a new box
  replaces only as many others as it needs room for.

Docs: docs/target-app-parity.md.
2026-11-14 04:08:03 -08:00
dotCooCoo 5803d2da4a Fix #7411: a selection grabbed by an anchor snaps it onto other paths
With Smart Guides on, a selection the Selection tool grabbed by one of
its anchors only landed that anchor on other anchors and centers, or
lined its bounds up. The anchor now also lands on the other objects'
paths ("path"), and where a path crosses another path or a ruler guide
("intersect"), in the order Direct Selection uses for a dragged anchor.
When the anchor lands on a path, the bounds do not also line up with
other objects, and a ruler guide nearby does not pull it off the path.
A selection grabbed anywhere else keeps lining its bounds up.

- Targets::for_move_by_anchor gathers the other art's path segments as
  well, and Targets::snap_onto_path lands a point on them or on their
  crossings with each other and with the ruler guides.
- MoveSnap::by_anchor uses those targets; the Selection tool picks it
  when the press grabbed an anchor.

Reported by pivot-al.

Docs: docs/target-app-parity.md.
2026-11-14 03:42:08 -08:00
ncic bdaaff534c Merge remote-tracking branch 'upstream/main' into pencil-cursors
# Conflicts:
#	docs/ui-parity.md
2026-11-14 12:31:28 +01:00
dotCooCoo fc562960ec Merge main into fix/dimension-second-point-guides 2026-11-14 03:02:44 -08:00
dotCooCoo cde9a27b4f Objects on Path: the widgets flatten the group's path once per lookup
Finding where the Rotate All, Space, Move All and Select/Move widgets
go and testing whether the pointer is over one flattened the group's
path two to three times per widget. Starting a Space, Move All or
Select/Move drag flattened it five times, and one pointer move over the
group could flatten it eleven times. Each lookup now flattens the path
once and shares that measurement across the widgets:

- vectorcraft-doc makes `Measured` public with `stop` and `stops`, and
  adds `attachable`, which returns the path with its measurement.
- `Widgets::of` gives all four widgets for the canvas, `widget_at` gives
  the widget under the pointer, and `WidgetDrag::hit` gives the drag a
  press starts, each from one flattening. The Selection and Objects on
  Path tools and the canvas use them.
- A Space, Move All or Select/Move drag keeps its measurement and
  measures again only when the group's path changes.

Widget places, hits, cursors and drag results are unchanged. The new
`spine-count` feature of vectorcraft-doc exposes the flattening counter
to vectorcraft-tools' tests; it is enabled only as a dev-dependency and
leaves Cargo.lock unchanged.
2026-11-14 03:01:29 -08:00
FredApps 4552915aae Tests: spiral decay is per full wind on main, so four segments give the decay 2026-11-14 11:35:04 +01:00
BFlat 868a86ddff Merge pull request #7494 from dotCooCoo/fix/gradient-vector-snap-draw
Gradient tool: a vector drawn on the art snaps as other drawn points do
2026-11-14 16:51:12 +07:00
ncic 77070d29a7 Pencil: the continuation cursor follows the snapped release; Precise Cursors tests keep the badges 2026-11-14 09:22:18 +01:00
ncic cbd1c142dc Merge remote-tracking branch 'upstream/main' into pencil-cursors
# Conflicts:
#	docs/target-app-parity.md
2026-11-14 09:05:01 +01:00
ncic 3789bc27bc Merge remote-tracking branch 'upstream/main' into pencil-no-guides
# Conflicts:
#	docs/mcp.md
#	docs/target-app-parity.md
2026-11-14 08:54:32 +01:00
BFlat 6beeb9e2a4 Merge pull request #7262 from dotCooCoo/feat/smooth-cursor-without-path
Smooth: the cursor shows Not Allowed when no path is selected to smooth
2026-11-14 13:43:44 +07:00
BFlat 508ff987f5 Merge pull request #7374 from dotCooCoo/fix/shape-builder-hover-ended
Shape Builder, Live Paint Selection: hover highlights go when the pointer leaves the canvas
2026-11-14 13:43:20 +07:00
BFlat d3ac2434f5 Merge pull request #7397 from dotCooCoo/fix/dimension-first-preview
Dimension tool: the first preview of a drag-out is drawn at the pointer
2026-11-14 13:43:03 +07:00
BFlat aa5b635b32 Merge pull request #7388 from dotCooCoo/fix/snap-glyph-parametric-slice
Smart Guides: Parametric Shape and Slice tools snap as the drawing tools do
2026-11-14 13:42:31 +07:00
BFlat 7fd4564c0c Merge pull request #7390 from dotCooCoo/fix/hyphenation-exceptions-relayout
Type: hyphenated type lays out again when the hyphenation exceptions change
2026-11-14 13:41:57 +07:00
dotCooCoo 58bc03a3e7 Gradient tool: a vector drawn on the art snaps as other drawn points do
A gradient vector drawn on the art, a click that applies one, and the
dragged start and end handles snapped through snap_draw, which gathers
the bounds and anchors of the art only. Path segments, View › Snap to
Glyph's guides and the construction guides through the vector's start
did not pull them, and a click applied the gradient from the pointer
rather than from the snapped point. They now snap through DrawSnap, as
the Pen and Line Segment tools do:

- The press gathers the targets, for a vector drawn on the art and the
  start and end handles only, and the drag keeps them. A click applies
  the gradient from the snapped press.
- A dragged end or handle leaves its start as a Line Segment's end does:
  it lands on the construction guides through the start, and with Shift
  it keeps to 45° steps from the Constrain Angle and snaps along them.
- The pointer hovering where a press would draw a vector (anywhere with
  art selected, over art with nothing selected), and not over the
  annotator, shows the guides of the point the vector would start on.

A press that snaps onto a nearby target no longer starts the drag
early: the 3 px drag threshold counts from where the pointer was
pressed, not from the snapped start.
2026-11-13 22:25:34 -08:00
dotCooCoo a903feb870 Dimension tool: no construction guides through a first point off the anchors
With Smart Guides on, the Dimension tool's second point snapped onto the
construction guides through the first point (Smart Guides › Construction
Guides), so a click beside a segment straight below a first point that
was not on an anchor stayed on the vertical guide instead of landing on
the segment.

The second point now has no construction guides through a first point
that is not on an anchor. After a first point picked on an anchor, the
construction guides through it still apply. The second point still snaps
to anchors, centers and alignment lines, and with Snap to Perpendicular
or Snap to Tangent on it lands where the line from the first point meets
a segment square or grazes a curve.

Docs: docs/dimensions.md, docs/target-app-parity.md.
2026-11-13 21:26:04 -08:00
dotCooCoo dea57b348b Dimension tool: the first preview of a drag-out is drawn at the pointer
Dragging out a dimension from a segment (Linear) or a corner (Angular)
drew its first preview frame at the wrong distance. The preview placed
the dimension at the pointer before reading the segment's end points or
the corner from the art, and measured the offset from the placeholder
points the dimension starts with. A drag from the top edge of a
rectangle to 40 pt above it showed an offset of 60 instead of -40.

The preview now clears the offset, reads the art's points, places the
dimension at the pointer and checks the result. Clearing the offset
keeps an out-of-range offset from the last pointer position from
failing the read.

Tests: the segment and corner drag-out tests fail without the change.
placement_recovers_after_a_position_out_of_range also passes on main;
it fails when only the offset clear is removed.
2026-11-13 19:08:02 -08:00
dotCooCoo 1dc8b72bbf Type: hyphenated type lays out again when the hyphenation exceptions change
Changing Preferences › Hyphenation › Exceptions bumped each open
document's revision, but the caches of laid-out type outside the text
crate were keyed on the font generation alone. The renderer kept the
glyph geometry, raster-effect pixels, live-effect and envelope art,
pattern tiles and placed symbol art of unchanged type objects, so
hyphenated area type kept its old line breaks on the canvas. The
hit-test art of blends and envelopes, the Fit to Artwork Bounds answer,
the layout caches of the Type and Touch Type tools and the out port's
overflow mark were keyed the same way.

vectorcraft_text::layout_inputs() returns a number that changes with
the fonts and with the hyphenation exceptions. Every one of those
caches now keys on it instead of FontDb::generation(), and envelope ink
uses it in place of the private envelope_ink_inputs(). The hit-test key
hashes it together with the plug-in revision.

Tests: a renderer that drew hyphenated area type, alone, with a drop
shadow, in a group with a Transform effect, in a symbol instance and in
an envelope, draws it as a new renderer does after the exceptions
change; the out port of selected area type shows the overflow that the
new exceptions cause. The render test helpers that run a step again
when the fonts change during it now also run it again when the
exceptions change.
2026-11-13 18:56:48 -08:00
dotCooCoo fecf724501 Smart Guides: Parametric Shape and Slice tools snap as the drawing tools do
The Parametric Shape tool's center and the Slice tool's corners snapped
with Smart Guides to the bounds of the art only, so View › Snap to Glyph
had no effect on them, and neither did the anchors and segments of
paths that the other drawing tools snap to. The point dragged out from a
Parametric Shape's center did not snap at all, and neither tool showed
Smart Guides while hovering before a press.

Both tools now snap through the drawing tools' shared snapping
(DrawSnap). A Parametric Shape's center (from a drag or a double-click),
the point dragged out from it, and a slice's corners land on glyph
guides and on path anchors and segments. The guides show while hovering
and during the drag. When a ruler guide then takes a slice corner, the
Smart Guides are no longer shown. A click with the Parametric Shape tool
still draws nothing when its center snaps a few pixels from the pointer.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 18:50:03 -08:00
dotCooCoo 89bbca79e8 Shape Builder, Live Paint Selection: hover highlights go when the pointer leaves the canvas
The Shape Builder had no hover_ended, so when the pointer left the canvas
(for a panel, out of the window, under a menu or dialog), the region or
stroke highlight and the Cursor Swatch Preview chips stayed where the
pointer was last seen. A map of a large selection that arrived afterwards
also highlighted the region under that old point again. When the hover
ends, the tool now drops the highlight, the stroke a click would split and
the preview, and forgets the point.

The Live Paint Selection tool had the same gap: its face or edge
highlight now goes too.
2026-11-13 18:20:59 -08:00
ncic 5a55fdce0e Merge upstream main into pencil-cursors
# Conflicts:
#	docs/mcp.md
#	docs/target-app-parity.md
2026-11-14 03:17:11 +01:00
dotCooCoo 270e58a461 Live Paint: the Bucket's swatch preview and highlight go when the pointer leaves the canvas 2026-11-13 17:24:40 -08:00