Commit Graph
13399 Commits
Author SHA1 Message Date
dotCooCoo 73a9c22361 Actions: Insert Menu Item adds Object › Align and View menu commands
Insert Menu Item… now lists the Object › Align items and the View menu
commands the app runs itself (Outline, Pixel Preview, Trim View,
Presentation Mode, Screen Mode, zoom, fit, Rotate View, and the show,
hide and snap items).

- An Align step holds the params its click sends at insertion, so a
  later Align To choice does not change it. A step that aligns to the
  key object stops the playback when the selection has no key.
- A View menu step plays in its place at every speed and adds no undo
  step. At Accelerated the steps on each side of it are one undo step
  each. Playing it while recording records it.
- Batch… refuses an action with an included View menu step.
- An action set file with a View menu step is version 6.
- The steps before a stop now play as saved steps, as other playback
  does, so a key that an older version recorded no longer fails there.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 05:17:40 -08:00
dotCooCoo 54b4addceb Actions: a command that changes a dragged step's action ends the drag
A drag of a step row kept the action's id and the step's index. A
command that ran while the pointer was held could put another step at
that index, and the release then moved that step.

The drag now keeps the action's steps and excluded steps as they were
when it started. It ends without a move when a command changes either,
or deletes the action. A command on another action leaves the drag as
it is.
2026-11-13 05:12:09 -08:00
dotCooCoo cf4d27c38e Graphs: stroke, gradient and recolor commands update a series' stored paint
A stroke weight set with stroke.set or stroke.weightUp/weightDown, a
gradient made, placed or edited with paint.editGradient,
paint.setGradientGeom or the freeform gradient edits, and colors changed
by paint.invert, paint.complement, the Edit Colors recolor and Blend
commands, recolor.apply, addon.color.filter,
addon.color.applyNearestSwatch or the ink limit of
addon.color.printFixes changed a series mark but not the paint the graph
stores, so the mark went back to the old paint when the graph was drawn
again.

appearance::edit_items now stores what its edit changes on the topmost
visible fill and stroke of series marks, as the Appearance commands do,
and the recolor pass does the same for the series marks it reaches,
including those inside a series group or a graph it is given. When one
command changes several marks of a series, the frontmost one sets the
stored paint. A gradient is stored with its placement.

These commands do not store the colors they give a graph's axes and
labels. docs/mcp.md, the params text and the Graphs line in
docs/target-app-parity.md say what is stored.
2026-11-13 05:08:19 -08:00
dotCooCoo 1517c81262 3D and Materials: wrap graphics around the side of Revolve objects
The Materials tab and threeD.mapGraphic now map graphics onto
Revolve's swept side, unrolled flat: x runs around the axis (the
angle times the profile's distance from the axis at that point) and
y along the profile. A graphic keeps its size at every distance from
the axis, so it reaches farther around where the profile comes nearer
the axis. Each face of the side draws the part that falls on it: a
graphic narrows toward the silhouette, follows the profile along its
length, is shaded with the surface (several lights included) and is
hidden where the side faces away. A part that runs past the end of
the profile reaches the curved rim and stops there. The middle of the
side faces the viewer with the axis on either edge. On a compound
profile or a group the graphics go on the longest contour.

- three-d: with Revolve::map_surface set, side faces carry a
  SurfaceCell (corners on the page and on the unrolled side, whether
  the outside faces the viewer) and a closed profile off the axis
  takes an anchor where its side is cut; without it the faces are as
  before. revolve_surface_size gives the side's size for a new
  graphic's fit.
- effects: Revolve takes `graphics` (front only); surface_parts cuts
  and maps them per face; curves are cut into straight pieces one at
  a time, and commands refuse graphics past the point limits;
  switching between Extrude, Plane and Revolve keeps the front's
  graphics.
- The Materials tab hides Face for Revolve; params text, docs/mcp.md,
  docs/three-d.md and the progress docs describe the change.
- i18n: the complete-message catalogs translate the three new
  refusals in place of the planar-faces refusal they replace, and ja,
  es, zh-hans and zh-hant translate the Materials tab's label.
2026-11-13 05:06:03 -08:00
dotCooCoo 3aa7ea2f78 Recolor Artwork: a weighed color recolors with the row it moved to
- recolor.weigh drops another row's entry for a color that moved, so
  recolor.apply recolors it with the row it moved to and the shares
  describe the recolor. A color that the first color of another row
  with a new color also lists stays where it is.
- Linked swatch colors are grouped through a map, so a row with many
  unlinked colors no longer compares each one with every group.
- The Prominent Colors bar reads the shares again when a row gains or
  loses a new color, since that changes which row takes a shared color.
2026-11-13 04:58:39 -08:00
dotCooCoo aa5654ec2d Tests: Smooth Tool Options reports its Fidelity slider in px
dialog_sliders_report_the_numbers_their_fields_show still expected the Smooth
tool's Fidelity slider to read "0.25pt". The dialog shows that Fidelity in
screen pixels, so the test expects "0.25px", and it now also checks that the
Blob Brush's Fidelity slider reads in points.
2026-11-13 04:54:52 -08:00
dotCooCoo 7232875e9f Layers: rows held at the list's edge scroll it at the same speed at every frame rate
A row held in the 28-point band at the list's top or bottom edge scrolled
the list by a fixed distance each frame, so the list moved farther in the
same time on a display that redraws more often.

`scroll_at_edges` now scrolls by the time each frame took: 60 points a
second at the band's inner side and 340 at the edge. A stalled frame counts
a tenth of a second at most. The scroll is applied without the scroll
animation. The Libraries panel's list uses the same function.

Test: `panels::layers` test
`a_held_row_scrolls_the_list_as_far_in_the_same_time_at_any_frame_rate`
holds a row for half a second in 15 frames and in 60 frames and compares
where the rows come to rest.

Docs: docs/target-app-parity.md.
2026-11-13 04:53:01 -08:00
dotCooCoo 6b55d7ca3e Eyedropper: a whole pick that removes a series mark's painted row replaces the stored transparency
A whole pick from a source with no fill row, or no stroke row, removes
that row from the target. When the target is a graph series mark whose
row had paint, the pick now replaces the row opacity and blend mode the
graph keeps for that kind of row in the series. A row that had no paint
before the pick still leaves the kept values as they are, and a pick of
some attributes from such a source is unchanged.
2026-11-13 04:50:59 -08:00
dotCooCoo ba2a6fc1f3 Type: a further span beside a wrap object is measured across its line's height
Text wrap can split a line into spans that share a baseline. The spans
after the first were measured across the height of the line set in the
first one, so a taller line set in a later span could run into a wrap
object the shorter line stayed clear of. Each further span is now
measured again across the height of the line that goes in it. The line
gets the part that is free, and a span with no free part, or with a part
narrowed to less than the line's first word, is left empty. The
Every-line Composer and the line loop both place lines through
`Pen::place`, so they agree.

The Every-line Composer also keeps a line start whose line found no room
while a longer line from it would be taller. A taller line steps down
the frame by its own leading and can find room the shorter line's steps
missed.

Tests: a_further_span_is_measured_across_the_height_of_its_line,
composition_tries_a_longer_line_after_one_that_cannot_be_set.
2026-11-13 04:48:43 -08:00
dotCooCoo 349034dda2 Smooth tool: each drag smooths the path under it, and repeated drags keep smoothing
Part of #2224.

A Smooth tool drag only refitted the anchors in its reach within
Fidelity, so a wobble wider than Fidelity stayed, and a second drag over
the same place changed nothing. Repeated refits also drifted away from
the path, and a drag over a whole closed path left a corner at its first
anchor.

- path.smoothRegion now smooths the stretch in reach along its length
  with a Gaussian whose spread is a third of the reach, then refits it
  within Fidelity. The run's outer end points and handles stay fixed.
- Each refit stays within twice the distance the smoothing moved the
  path (at least a tenth of Fidelity), so repeated drags do not drift
  (SimplifyOptions::smooth_moved_only).
- A whole closed path is smoothed across its start as a loop, so a
  bump at the first anchor is smoothed like any other and no corner is
  left. Object > Path > Smooth smooths a closed path across its start
  the same way.
2026-11-13 04:44:12 -08:00
dotCooCoo 39f66f3870 Effects: a later painted effect runs on every fill and stroke a piece returns
When a painted live effect on a fill or stroke returned several fills or
strokes, the next effect in that stack ran only on the first of them and
the others took its geometry. A later live-effect plug-in, and a later
geometry effect on strokes, now runs once on each of them in paint order,
given the piece's fills and strokes and its own `_context.item`. Each
run's pieces replace only that fill or stroke; a run that fails, is
refused, is deferred or would pass the effects' budget leaves only its own
fill or stroke as it was. Fills and strokes that keep the same path stay
on one path, and a deferred run is listed at the source fill's or
stroke's place.

The results that are kept share the effects' budget, and each run's
result is kept or left out whole. They are first placed with all the
room the art leaves, and placed again with room kept for the piece's path
when a fill or stroke left on that path finds no room. A result on the
path before it costs nothing and is taken whatever room is left; a
built-in effect that finds no room is built again with all the room the
art leaves, and that result is taken only when it is on the path before
it. A plug-in result is held only while it is placed: one that does not
fit, or that moves onto the path before it, is let go at once, so the
results held at one time stay within the budget however many fills and
strokes the piece has. A result kept in the first placing is reused in
the second without running the plug-in again. A painted piece's share of
the budget is counted once at each later effect.
2026-11-13 04:44:11 -08:00
jmvergesandClaude Opus 5.5 6ed3935e59 Envelopes: a top object's side split at a cusp still follows its curve
Split where the curve stops (a cusp), both handles at the split lie on
the anchor, so their lengths say nothing of how the curve's parameter
divides between the two pieces, and the side fell back to the polygon
shares. When both handles lie within ONE_CURVE of the anchor, the
spans now come from how far each piece bends away from it (the second
derivatives, in proportion to the squares of the spans). The existing
check of every piece against the rebuilt curve is unchanged.

Test: a_split_curve_keeps_the_top_object_patch_when_split_at_a_cusp.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 12:43:47 +00:00
dotCooCoo e8c3dace32 Effects: a group's geometry effects reshape what its members draw
A group's or layer's geometry effects now run after its members' own:
the geometry effects of each visible path and compound path in it and
of their fills and strokes, and a nested group's geometry and
Pathfinder effects, are applied first, at any depth, and the group's
effects reshape the result. A symbol instance's geometry effects run
after those of its symbol's members in the same way. Before, the group
reshaped the members' outlines and their own effects ran afterwards:
a 100 pt square with its own 10 pt Offset Path in a group with a 50%
Transform drew 70 pt wide, and it now draws 60 pt wide. Existing
documents with such groups draw differently.

The canvas, export (including groups that keep their type), Expand
Appearance and the art that Pathfinder operations and compound shapes
take from such a group use the same order. The reply of
effect.expandAppearance names such a group and no longer names the
members whose effects the group's art already holds.

The renderer now drops the art it keeps for a group when a plug-in is
installed or removed and a member of the group has a plug-in effect.

Docs: docs/target-app-parity.md. Not yet: the own geometry effects of
images, symbol instances, paths with a linked opacity mask or a 3D
effect, and nested groups with a 3D effect in a group still run after
the group's.
2026-11-13 04:41:58 -08:00
dotCooCoo 51eea7ecfb Tabs: the ruler shows when a non-text object is first in the selection
With the Selection tool, the Tabs panel showed "No text selected" when
the first selected object was a shape, or a group holding text, even
with text selected. It now shows the ruler and stops of the first
paragraph of the first selected text object, looking into selected
groups as the Character and Paragraph panels do. A stop set on that
ruler goes to every selected text object, as text.tabs.set already did;
other objects are left as they were. A selection without text still
shows the empty state.
2026-11-13 04:37:30 -08:00
dotCooCoo f918c91c13 Edit: settling an interaction keeps the warning of the preview it applies
With Real-time Drawing off, a command that ends a drag first (Undo, Redo,
Clear History, a plug-in command and the others) applies the drag's
deferred preview, but dropped the warning that preview gave, which
releasing the drag shows in the status bar.

- The applied preview's warning is now kept while a top-level command or
  the tool's actions run. A command's result carries it as
  `previewWarning`, and as `warning` when the command has no warning of
  its own, so the status bar shows it.
- Typing kept as its own step when a tool's drag begins, or when Cmd
  lends the Selection tool, shows the warning in the status bar.
- The Cmd-lend path no longer ignores an error from keeping the typing.

Docs: docs/mcp.md (undo/redo row), docs/target-app-parity.md.
2026-11-13 04:36:38 -08:00
dotCooCoo 6e361b0bec Pencil: Fidelity keeps its screen size at low zoom
The Pencil and the Paintbrush send their Fidelity in points at the
current zoom, but path.freehand read at most 100 pt. At 3.13% zoom a
20 px Fidelity (639 pt) was fitted at 100 pt, the same as 3.13 px on
screen, so a stroke drawn zoomed out kept far more anchors than the
same stroke at 100%.

- path.freehand, and brush.freehand, which runs it, take a Fidelity
  from MIN_FIT_TOLERANCE to MAX_FIT_TOLERANCE (100 / 0.0313 pt, the
  100 px field maximum at the lowest zoom). A value outside that range
  is now rejected with an error instead of being read as the nearer
  end. The default stays 1.5 pt and path.blob keeps its 100 pt bound.
- The Pencil and the Paintbrush keep the value they send within that
  range, so a stroke draws at any zoom.
- An extending stroke still closes the path within four Fidelities of
  its other end, at most 400 pt, as before.

It conflicts with open #7089 in crates/tools/src/draw2.rs.

Docs: docs/mcp.md, docs/target-app-parity.md, path.freehand params.
2026-11-13 04:35:29 -08:00
dotCooCoo d747f5b365 Learn: Back to skills and the Quick skill guide card run learn.skills
learn.skills {} shows the Learn panel on its Skills tab with the list of
skills, with no skill and no tutorial open, and returns what learn.list
returns. Back to skills after a skill's last tutorial and the Quick skill
guide card on the For you tab now run it, so the control channel and MCP
can reach the same view.

- The command is listed in both UI command catalogs, and its label has a
  row in every catalog.
- Docs: docs/mcp.md, docs/target-app-parity.md, docs/ui-parity.md.
2026-11-13 04:34:35 -08:00
dotCooCoo 0fd757c6b8 Clipboard: the window closes at once and quitting waits up to 27 s for the Paste check
On Linux the Paste menu's background check holds its own clipboard
handle. When the app quit while that check's X11 text read was still
unanswered, quitting stopped waiting for the check's thread after 5 s,
but the handle's read worker holds arboard's handle until 25 s after the
read was sent. The app's own handle was then dropped first, so it was
not the last one alive to hand what was copied to a clipboard manager.

- CLIPBOARD_PROBE_STOP_WAIT (27 s, exported from vectorcraft-ui-egui)
  replaces the 5 s bound: the 25 s X11 read limit plus LOAD_WAIT, the
  2 s limit on waiting for a reader to stop. Quitting still ends after
  it when a host's handle never lets go.
- On Linux and the BSDs, on_exit hides the main window before eframe
  drops the app, so the window closes at once while the process waits
  for the clipboard handles. The window is hidden, not closed, and the
  connection the clipboards use stays open. winit hides X11 windows,
  XWayland ones included; it cannot hide a native Wayland window, which
  stays on screen until the wait ends. macOS and Windows are unchanged.
- Probe's Drop waits through an injectable function, so a test drives
  the wait with a controllable clock while the probe's handle is still
  being dropped and checks that it is dropped before the app's.
- A Linux test in the app checks the bound against X11_READ_LIMIT and
  LOAD_WAIT, so raising either fails it.
- Comments and docs/development.md describe the wait.
2026-11-13 04:33:41 -08:00
dotCooCoo ab75b67f85 Simplify: the join at the start of a smoothed loop turns by at most 0.5°
A smoothed loop with no corner is refitted along one direction across
its start. The first and the last fitted curve were each compared with
that direction, so when both became lines, the two lines could turn by
up to 1° where they meet at the loop's start.

`refit_part` now compares the last curve of such a loop with the
direction the loop's first segment leaves along. When the line would
turn by more than 0.5° from it, the last piece stays a flat curve.

Test: `simplify_keeps_the_join_at_the_start_of_a_smoothed_loop_smooth`
(`crates/pathops/tests/it/ops.rs`).
2026-11-13 04:33:23 -08:00
dotCooCoo d956d2165f SVG: an absolutely placed right-to-left chunk is anchored by the edges of its glyphs
A text chunk placed by an absolute x was measured from the pen of its
first character to the farthest glyph end. The first character of a
right-to-left chunk is drawn at its right, so a chunk of several such
characters was measured as that one character: anchored by middle or
end, or starting a line beside absolutely placed characters, it opened
off its position by the width of its other characters.

- A chunk's left and right edges are the smallest glyph start and the
  largest glyph end over all its characters, as SVG 2 anchors a chunk
  (https://www.w3.org/TR/SVG2/text.html#TextLayoutAlgorithm). The first
  character's pen is placed at its own distance from the left edge.
- The layout that measures the chunks has the direction the imported
  text gets: left to right unless the text's direction is rtl. Text
  starting with a digit and holding right-to-left letters was measured
  right to left.
- The chunks are measured in the first of the layouts that kern the
  characters onto their x, so anchored text is laid out once less.
2026-11-13 04:32:32 -08:00
dotCooCoo 88c02aa293 Effects: culling a painted piece leaves room for its own brush art
A live-effect plug-in that paints its pieces draws each piece's brushed
stroke along the piece's path at the piece's stroke width. Culling left
room for brush art from the object's own stroke width around the
pieces, so brush art of a moved or wider piece was cut off at the edge
of the view. Culling now leaves 16 x the piece's stroke width + 8 pt
past each brushed piece, and does so for a symbol instance whose art
holds such a path (measured once per symbol) and for a blend, envelope
or repeat that holds one. Object > Rasterize measures the brush art
drawn along each piece and leaves out the object's own brush art, which
is not drawn.

Groups and layers now leave room for their members' brush art. The
cull bounds of a group or layer united its members' bounds without the
room each brushed member leaves, so the painted bounds of a group, and
the area redrawn when it changes, left out brush art past its members'
strokes. That applied to plain brushed paths as well as painted pieces.
Each member is now measured as the renderer measures it when it draws
the group, in the members of a group with a fill, stroke or adjustment
of its own and in a group with crop marks or Vector Halftone too.
2026-11-13 04:31:38 -08:00
dotCooCoo 3990c748bd Toolbars: toolbars made with New Toolbar dock along the window's edges
A toolbar made with New Toolbar now docks in a lane along the window's
left or right edge (on the left, right of the Tools panel docked there).
Dropping its title bar on an edge docks it, with the target lit while
the title bar is dragged over it; dragging it out of its lane floats it
under the pointer, and Escape or losing the window's focus during the
drag puts it back. The title bar's context menu has Dock to Left, Dock
to Right and Float Toolbar.

- Toolbars docked at one edge stack from the top, each with an equal
  share of the lane's height, and the lane is as wide as its widest
  toolbar. A lane too short for its stack wraps it into more columns,
  up to half the width beside it; past that the toolbars show only
  their title bars, a lone toolbar included, and a column too short
  for those scrolls with the mouse wheel.
- With Keep Tools Beside the Canvas on and Tools docked on the left,
  the left lane is laid out inside the canvas panel right of Tools, and
  the canvas keeps room for one column of it and its 200 points.
- A release in the frame the pointer leaves the lane floats the toolbar
  with its corner where the drag put it.
- window.toolbar.dock {name, side?, order?} and window.toolbar.float
  {name, x?, y?} do the same from the control protocol; bad params are
  errors and change nothing. window.toolbar.list reports floating, side
  and order.
- CustomToolbar keeps dock (place in the edge's stack) and dock_right;
  both default, so toolbars saved before load floating. Workspaces and
  preferences keep the placement; New Toolbar still starts floating, a
  copy floats, and deleting a docked toolbar closes up its stack.
- Dock to Left, Dock to Right, Dock Toolbar and Float Toolbar have rows
  in every catalog.

Part of #1759
2026-11-13 04:29:55 -08:00
dotCooCoo 2bd02ecb2a Paths: a quadratic segment whose points coincide measures zero length instead of NaN
measured_arclen returned kurbo's arc length unchecked. For a quadratic
segment whose three points coincide, kurbo 0.13.1's QuadBez::arclen
multiplies 0 by infinity and returns NaN. measured_arclen now returns 0
when the measurement is not finite, the same value it gives a segment it
does not measure. Finite results are unchanged.
2026-11-13 04:29:09 -08:00
dotCooCoo 727a26d5a6 Path ops: Offset Path sweeps long, low paths along their length
Offset Path now turns the overlap sweep the way Outline Stroke and
Unite do. When the estimate for its fill, the ring stroked around it
and the outline of its open subpaths is under two thirds as large for
the parts turned a quarter turn, the faces are found on the turned
parts, the faces within the offset distance of the path are dropped by
testing their points turned back, and the result is turned back.

On an open path of 10,000 anchors in rows of 1,000, offsetting by 2 pt
takes 1.0 s of processor time instead of 1.8 s in a release build.
The offset of a long, low path has as many subpaths as the offset of
the same path stood on end, and the area where the two differ is no
larger than the refit precision times the outline's length.
2026-11-13 04:26:14 -08:00
dotCooCoo cf10a77594 Actions: Begin Recording adds steps to the selected action, and a drag moves a step
With an action selected, Begin Recording records into it: Stop puts the
recorded commands after the selected step, or after the action's last
step, and the steps after them keep whether they are excluded. With no
action selected it still adds a new Action N.

- ui.action.record takes {set?, action?, after?}; action needs set.
  The place stays between the same steps while a step is inserted,
  deleted or moved in that action during the recording, and the selected
  step and an open Record Stop dialog follow their step when Stop adds
  the recorded steps before them.
- New ui.action.moveStep {set, action, step, toSet?, toAction?, before}
  moves a step within its action or into another action, also an empty
  one or one in another set. The step keeps its params and exclusion,
  the selected step and an open Record Stop dialog follow their step,
  and a move past 10,000 steps or 8 MiB is an error that changes
  nothing.
- In the Actions panel a step row drags: a line shows where the step
  goes, the release moves it once, and a release off the actions' rows
  leaves it where it was. The list scrolls near its edges.

Help page: https://helpx.adobe.com/illustrator/desktop/automate-visualize-data/automate-actions/add-commands-to-actions.html

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 04:17:59 -08:00
dotCooCoo 7b30424538 Merge main into feat/warichu 2026-11-13 04:06:56 -08:00
dotCooCoo 5e33ab2a61 Merge main into fix/nested-link-ids 2026-11-13 04:06:39 -08:00
dotCooCoo 2170ddcac4 Eyedropper: a pick that leaves a series mark's row without paint replaces the stored transparency
An Eyedropper pick that includes transparency now counts a fill or stroke
row that had paint before the pick and has none after it when it stores
the series' row opacity and blend mode on the graph, as graphic styles
already do. Before, such a pick left the opacity and blend mode another
mark of the series had stored, and the series was drawn with them again
after its data changed. A row that had no paint before the pick still
leaves the stored values as they are.
2026-11-13 04:05:56 -08:00
jmvergesandClaude Opus 5.5 728fd9ef14 Envelopes: a top object's side that is one split curve follows its parameter
A top-object envelope gives each piece of a side a share of the content
in proportion to its control polygon's length. When anchors split a
curve without changing its shape, the pieces' polygons don't divide the
side where the curve's own parameter does, so the envelope bent its
contents differently although its outline was the same: Add Anchor
Points on a top object moved the art, and a top object whose .ai mesh
saves each side's curve split into thirds drew its type up to about
half a point off its drawn art, which follows the whole curve's
parameter.

Coons::from_top_object now checks whether a side's pieces, from corner
to corner, are all pieces of one cubic. The pieces' spans of that
curve's parameter come from the handle lengths either side of each
split, the curve from the outer ends and handles, and every piece must
lie within 0.02 pt of the curve's piece over its span (each control
point). Such a side runs along that curve, by its parameter. Any other
side keeps the polygon shares, including a side only partly made of one
curve and a smooth side drawn in many pieces that isn't one curve as a
whole. Corners found from the outline can still move when anchors are
added, as before. Gradient meshes made from a path are unchanged.

Existing top-object envelopes with such sides redraw.
a_split_curve_moves_the_top_object_share_to_its_new_anchor, which
pinned the earlier behaviour, becomes a_split_curve_keeps_the_top_object_patch.

Tests: a_split_curve_keeps_the_top_object_patch,
a_top_object_joins_a_split_curve_saved_with_rounded_coordinates,
a_top_object_keeps_smoothly_joined_curves_apart,
a_top_object_side_partly_of_one_curve_keeps_the_polygon_shares and
a_top_object_side_of_many_arcs_stays_on_them (vectorcraft-doc),
envelope_top_object_keeps_its_look_when_anchors_are_added
(vectorcraft-engine) and
a_top_object_whose_top_is_one_curve_split_in_thirds_opens_live
(vectorcraft-eps).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-13 11:18:40 +00:00
dotCooCoo dc7b0d0c90 Layers: layer and object rows held near the list's top or bottom edge scroll a long list
While layer or object rows are dragged in the Layers panel, holding the
pointer within 28 points of the list's top or bottom edge scrolls the
list that way, faster nearer the edge, and it keeps scrolling while the
pointer stays still, so a row out of view can take the drop (a move, or
a copy with Alt). The Libraries panel's edge-scroll helper moves to
panels.rs and both panels use it. Scrolling stops on release, when the
pointer leaves the list's width, and for other drags such as the eye or
lock column.
2026-11-13 02:31:55 -08:00
dotCooCoo 6bf988a0e1 Clipboard: the Flatpak on GNOME copies and pastes pictures and SVG with other apps
Where arboard has neither data-control nor X11 (the Flatpak on a GNOME
Wayland session), Copy and Paste used smithay-clipboard on the window's
connection, which carries text only. They now use a core wl_data_device
client on that connection.

- One Copy offers the PNG as image/png, the SVG as image/svg+xml (with
  Include SVG Code on) and the text as text/plain;charset=utf-8,
  UTF8_STRING and text/plain. A format with no data is not offered.
- Paste reads SVG, then text, then PNG. Blank text, or text that only
  names a picture, gives way to the PNG, and a failed or empty SVG read
  falls back to the types after it. The Paste menu item is enabled by the
  types offered, without reading any data.
- The clipboard holds VectorCraft's Copy while its data source is not
  canceled and the offer has the Copy's types.
- A read takes 64 MiB at most. Text waits 2 s, SVG and PNG 10 s off the
  UI thread. Another app's paste is sent on its own thread, 8 at once.

smithay-clipboard is no longer a dependency of the app.
2026-11-13 02:31:04 -08:00
dotCooCoo 737d9bc5b8 PDF/.ai save: envelopes stay editable when the file is reopened
A PDF-compatible .ai saved with Include Editing Data for Other Apps now
writes warp, mesh and top-object envelopes as live envelope records in
its editing copy: the grid or contents, Envelope Options, Fidelity,
Edit Contents, a warp's settings and the contents' box, beside the
distorted art, in the form the .ai envelope reader reads. The file
opens with the same live envelopes.

Envelopes the reader would open in another shape or with other
settings are written as their distorted art with a warning: type in
the contents, a turned frame, an old warp map, a mesh laid out another
way round, a top object whose sides do not pair up, a Fidelity that is
not a whole number, bounds margins kept with Distort Appearance off,
envelopes in opacity masks, pattern tiles, clipped art or another
envelope's contents, on a large canvas, and after the first 256.
2026-11-13 02:28:11 -08:00
HassanKhan c6b22ad891 Merge remote-tracking branch 'upstream/main' into feat-6304-font-height-icons
# Conflicts:
#	docs/target-app-parity.md
2026-11-13 15:12:02 +05:00
BFlat 1dbdbce91f Merge pull request #7080 from dotCooCoo/feat/trace-create-strokes
Image Trace: Create Strokes makes a wide shape's thin features strokes and keeps its body a fill
2026-11-13 17:03:37 +07:00
BFlat 54f0c1b99b Merge pull request #7003 from mockydevs/fix/graphic-styles-list-height-2992
Graphic Styles: the list fills a taller panel above its footer
2026-11-13 17:03:22 +07:00
dotCooCoo 2129d00868 Dimension tool: a point on a Smart Guide stays on the guide
A Linear pick that the Smart Guides left where the pointer already was,
for example straight below the first point on the vertical construction
guide through it, or exactly in line with an object's center, was taken
as not snapped. The pick then moved to the closest point of a segment
within 8 pixels while the guide still showed it on the guide. The same
happened to a point already on a grid crossing with Snap to Grid on, or
on a whole pixel with Snap to Pixel on.

The pick now keeps the snapped point whenever the snap shows guides or
grid or pixel snapping is on. With Snap to Grid or Snap to Pixel on, a
pick off an anchor is no longer moved from the grid or the whole pixel
onto a segment. A point that no
anchor, guide, grid or pixel snapping places still lands on the closest
point of a segment. An anchor within 8 pixels, a segment within the
Smart Guides snapping tolerance and a nearby guide crossing still take
the point as before.

Docs: docs/dimensions.md, docs/target-app-parity.md.
2026-11-13 01:48:09 -08:00
dotCooCoo f81793d671 View: Pixel Snapping Options choose whether Snap to Pixel snaps drawing, moving and scaling
Control bar > Snapping > Pixel Snapping Options... opens a dialog with
three checkboxes: Snap to Pixel While Drawing, While Moving and While
Scaling. OK sets them; Cancel leaves them as they were. While View >
Snap to Pixel is off, the dialog notes that the options take effect once
it is on.

- view.snapToPixel.options {drawing?, moving?, scaling?} reads and sets
  them. They are kept in the preferences as the pixelSnap group, all on
  by default, so turning Snap to Pixel on behaves as before. An unknown
  key or a value that is not a boolean is refused and changes nothing.
  The command has a parameter schema, which raises the API level to 4.
- Drawing covers points the drawing tools place, the Knife's straight
  cut, the Measure tool and the rulers' origin. Moving covers Selection
  and Direct Selection moves, ruler guides, artboard moves and the
  Rotate, Reflect and Shear tools' drags. Scaling covers bounding-box,
  Free Transform, artboard and slice handles and the Scale tool's drag.
  An edit whose option is off snaps as it does with Snap to Pixel off.
- Align New Objects to Pixel Grid and the objects' pixel-aligned
  property do not depend on these options.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 01:38:58 -08:00
dotCooCoo 6c773585fa Type: the Every-line Composer sets mixed sizes in shaped and wrapped area type
A paragraph whose characters differ in line metrics (type size, font,
leading, vertical scale, or an inline graphic taller than the text) was
broken with the Single-line Composer in area type of a shape other than
a rectangle, or with text wrap. The every-line composer now composes it
there too.

- The composer takes each line's width from a measure that follows
  where the lines above it went (`composer::Measure`,
  `compose_with`). The fixed widths by line number are one such measure.
- In a frame whose lines are not all as wide, each line the composer
  tries is placed from the pen the lines above it left, at its own
  tallest metrics, as the line loop places it (`layout/shaped.rs`).
  Starts with the same placement are shared, and each start keeps the
  placements it was tried with.
- A line too long for its room does not end the search from its start
  while a glyph after it could make the line taller and set it lower,
  where the frame may be wider.
- The line loop places a composed line in such a frame at the line's
  tallest metrics, so it gets the room the composer measured for it.
- The search for one paragraph stops after 1,000,000 lines tried or
  2,000,000 baseline steps. The searches of all the paragraphs of one
  frame share a budget of 2,000,000 lines and 4,000,000 steps, kept
  apart from the line loop's own steps. A paragraph whose search stops
  is broken line by line. A paragraph the frame has no room for is
  broken line by line too, and overflows as before.

Tests: crates/text/src/tests/combos.rs (a stepped frame, a frame that
widens, text wrap with two spans on a baseline, overflow, a long
paragraph) and crates/text/src/layout/wrapping_tests.rs (the composer
with a measure, and the shared search budget).
2026-11-13 01:24:33 -08:00
dotCooCoo 345cd021dc i18n: Dutch translates status and error messages
Dutch was not in COMPLETE_MESSAGES, so with the interface in Dutch
script errors, plug-in manifest and permission errors, parameter
schema errors, 3D effect refusals, file-reader errors and data-set
messages showed in English.

- nl.tsv gains 557 `@msg` rows and one `@msgplural` row: the messages
  the German catalog translates and Dutch lacked. Most are one block
  with a header comment on their conventions, in the order de.tsv
  holds them; the rest sit next to the related existing rows.
  Backticked names, command ids, double-quoted values and bare true,
  false and null stay as the English writes them.
- nl joins COMPLETE_MESSAGES, so the message tests that iterate the
  list check Dutch too, and the untranslated report lists Dutch's
  missing messages. It lists the same set for Dutch as for German.
- The registry comment, docs/development.md, the Dutch row and
  introduction of docs/localization-parity.md, and the interface
  languages line of docs/target-app-parity.md list Dutch among the
  languages that translate messages.
2026-11-13 01:23:19 -08:00
dotCooCoo 78ee4d04b6 Panels: item drags start only with the primary button, as Layers does
A right or middle drag on a swatch or color group, a brush, a symbol, a
graphic style, a library item or group, a character or paragraph style,
an Appearance row or thumbnail, the Fill and Stroke squares, a Recent
Colors chip or the Gradient panel's thumbnail started the same drag as
the primary button, so it could reorder, copy, delete or apply the item.
These drags now start only with the primary button, as Layers rows
(#7016) and Artboards rows (#7005) do: `widgets::drag_source`, the
Swatches tiles, library panel items, text style rows and Appearance rows
check `drag_started_by(Primary)`, and the Appearance thumbnail shows the
grabbing hand only for a primary drag. Right-click menus and the Graphic
Styles panel's held right-button preview are unchanged.
2026-11-13 01:22:30 -08:00
dotCooCoo 7805479dad Libraries: a character style's menu offers Apply, Add to Character Styles, Rename and Delete
A right-click on a character style in the Libraries panel now opens Apply
Character Style, Add to Character Styles, Move to Group, Rename… and
Delete. Apply is enabled only with type selected. Opening the menu applies
nothing, and the paragraph style menu is unchanged.

- library.addToCharacterStyles adds the style to the document's character
  styles without applying it, so no type needs to be selected. A document
  style with the same name and attributes is reused with no undo step, and
  a name taken by other attributes gets a number.
- library.renameItem renames a library item in place and keeps its group.
  The name is trimmed and has 1 to 256 characters. Another item of the same
  kind with that name is an error, the item's own name writes nothing, and
  a rename is not a document undo step.
- library.use and library.addToCharacterStyles compare a library style
  with the document's in the form the document stores it in. A whole
  number size from a library file no longer adds a numbered copy.
- A character style color linked to a swatch that is not a global or spot
  swatch of the document keeps the color it shows without the link.
  Before, adding or applying such a style failed with "no swatch".

Help page: https://helpx.adobe.com/illustrator/desktop/design-with-text/fonts-and-scripts/add-and-use-text-and-character-styles-in-libraries.html
2026-11-13 01:22:29 -08:00
HassanKhan b219decd75 Character panel: the highlighted font height icon keeps its contrast (#6304)
On the open list's row of the current reference, drawn on the
accent-tinted selection fill, the icon draws its measure in the name's
colour instead of the accent, which lost its contrast there. The other
rows and the closed field keep the accent.
2026-11-13 14:19:58 +05:00
dotCooCoo 1c0310a1d5 Smooth: Fidelity is in screen pixels, so a drag smooths as much at any zoom
The Smooth tool, and an Alt smoothing drag with the Pencil, Paintbrush or
Blob Brush, now send path.smoothRegion their Fidelity divided by the zoom,
as the Pencil and the Paintbrush do since #5748. Smooth Tool Options shows
Fidelity in px. A saved Fidelity keeps its number, so it smooths as before
at 100% zoom.

path.smoothRegion now refits at tolerances from 0.05 px at the highest zoom
to 100 px at the lowest (0.000078125 to about 3195 pt) instead of clamping
to 0.05 to 100 pt, so the setting keeps scaling across the whole zoom range.
2026-11-13 01:18:06 -08:00
dotCooCoo bc92def89e Smooth tool: smoothing a path deselects its direct-selected anchors
path.smoothRegion replaced the anchors of each path it smoothed but left
the selection alone, so anchor and segment refs selected with Direct
Selection still named the old indices: after a smooth that removed
anchors, a ref could point past the end of the path or at another
anchor. The edit now drops those refs for each path it changes, so the
path stays selected whole. Selected paths the drag does not change keep
their anchors, and undo restores the earlier selection.
2026-11-13 01:12:38 -08:00
dotCooCoo eee96556e6 Simplify: a refitted curve becomes a line only when its joins stay smooth
Simplify, Object > Path > Smooth, the Smooth tool and freehand strokes
turned every refitted curve whose handles lay near its chord into a
straight line. A short curve whose end directions were off the chord
passed that test, and the anchor between it and the next curve became a
corner the path did not have: a Smooth tool drag along a line jagged by
up to 6 pt left corners of 7.7 to 40.6 degrees.

A curve now becomes a line only when the line runs within 0.5 degrees
of the directions the path arrives and leaves along. A nearly straight
piece that would turn more stays a flat curve. Convert to Straight Lines
is unchanged.
2026-11-13 01:09:38 -08:00
dotCooCoo 6e2fe9fddf SVG: right-to-left text with text-anchor start or end opens at its directional edge
SVG 2 defines text-anchor start for right-to-left text as placing the
right side of the text at its position, and end as placing the left
side there (https://www.w3.org/TR/SVG2/text.html#TextAnchoringProperties).
Import placed start at the left edge and end at the right edge whatever
the direction.

- Point type and type on a path swap start and end when the effective
  direction is rtl. On a path, right-to-left text anchored by start now
  ends at startOffset and text anchored by end begins there. Vertical
  type keeps its anchoring.
- Each line and each absolutely placed chunk is anchored by the
  text-anchor and direction of the element holding its first
  character, a tspan's own included. A later chunk no longer takes the
  first chunk's anchor.
- Each line of point type starts at its own x, also when it has the
  same anchor as the line before it or another line holds absolutely
  placed characters. Such lines were drawn at the first line's x.
- A test covers letter-spaced right-to-left lines: the layout keeps the
  tracking of every letter in such a line, so the whole advance sits
  on its anchor.
2026-11-13 01:06:53 -08:00
BFlat 3b48070751 Merge pull request #7061 from dotCooCoo/fix/dcs-transparency-clip
Place: DCS transparency interactions look only at what clipping paths show
2026-11-13 16:04:49 +07:00
BFlat d118fcb17c Merge pull request #7046 from dotCooCoo/fix/issue-3349
.ai import: graphic styles of one paint open with their fill and stroke
2026-11-13 16:04:36 +07:00
BFlat f0653da969 Merge pull request #7072 from kler/swedish-ui-2026-11-13
i18n(sv): translate 37 new strings, use the agreed terms in 9
2026-11-13 16:04:26 +07:00
dotCooCoo 093f04952c Image Trace: Create Strokes makes a wide shape's thin features strokes and keeps its body a fill
Stroke is the widest feature that can be stroked, and it was applied to
each connected shape as a whole: a thick body with thin arms stayed one
filled area. Now a shape wider than Stroke somewhere keeps as its area
every disc wider than Stroke that fits in it, and each piece outside
those discs that reaches out of them at least one and a half times its
own width (and 3 px) is traced as a stroked center line. A line's end at
the area goes to the cut, so the line's cap closes the join. Corners and
edge slivers stay in the area, and a piece that cannot be traced stays
in it too. Shapes no wider than Stroke trace as before.

Each line keeps one width; without Fills, the area is still a 1 px
outline.

Docs: docs/target-app-parity.md.
2026-11-13 01:01:59 -08:00