Commit Graph
4974 Commits
Author SHA1 Message Date
dotCooCoo 5c0f22b345 Graphs: Appearance edits on a label are kept for every label of its kind
A fill or stroke row that the Appearance commands gave a graph label, its
object opacity, and the characters the Eyedropper gave it lasted only
until the graph was drawn again: the graph stored nothing for a label's
rows, and the Eyedropper's character attributes were not stored.

- The graph keeps, for value axis numbers, category labels and legend
  labels, the paint, weight, opacity and blend mode of a label's topmost
  visible fill and stroke row, their order and place relative to the
  Characters row, and the label's object opacity and blend mode
  (labelStyles valuesRows, categoriesRows, legendRows). Every label of
  the kind gets those rows when the graph is drawn again, with a placed
  gradient fitted to each label.
- Every appearance.* command stores them, and so do graphicStyle.apply
  and redefine and the paint, stroke, gradient and transparency edits
  aimed at a row, even when the label already showed them.
  transparency.set without a row and object.setProps store only the
  object opacity and blend mode. With several labels of a kind, the last
  one edited wins.
- appearance.copyFrom onto all of a label's text stores the character
  attributes it applied and, from type, the paragraph attributes; a
  transparency pick stores the object opacity and blend mode, and
  append stores the rows.
- paint.setFill and paint.setStroke store a character fill or stroke
  only when the characters take the paint (the whole label, or all of
  its text highlighted with the Type tool); aimed at a row, they store
  the row.
- Document Color Mode and swatch edits reach the kept rows.

Docs: docs/mcp.md, the commands' params text, docs/target-app-parity.md.
2026-11-13 11:35:27 -08:00
dotCooCoo b429b2937f Docs: one app.open row after the merge of main 2026-11-13 11:34:50 -08:00
dotCooCoo 1d35e00981 Live Paint and Shape Builder: tool.setOption refuses invalid options
tool.setOption for the Live Paint Bucket, the Live Paint Selection tool
and the Shape Builder used to keep the old value when a switch was not
true or false, a color could not be read or a width or gap length was
not a number, and it set the other values sent with it. It also took
the RGB of a color with an alpha part, and the Shape Builder took any
`pickColorFrom` other than `swatches` as `artwork` and any `selection`
other than `straightLine` as `freeform`.

The command now checks every value before it sets any, whether the tool
is chosen or not: a switch must be true or false, a highlight color
must be an RGB color or a layer color's name without an alpha part, a
width or gap length must be a number, `pickColorFrom` and `selection`
must be one of their names, and an option the tool does not have is an
error. The error names the option, and nothing is set or saved. A width
outside 1 to 20 and a gap length outside 0 to 72 are still clamped, and
saved settings with an invalid value still load.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-13 11:34:44 -08:00
dotCooCoo 18b879a5bc Merge main into fix/graph-series-paint-visible-rows 2026-11-13 11:30:16 -08:00
Drew Dibble 09d5522785 Merge remote-tracking branch 'upstream/main' into seam-round-joins
# Conflicts:
#	docs/effects-parity.md
#	docs/gaps.md
#	docs/target-app-parity.md
2026-11-13 12:29:58 -07:00
dotCooCoo 6326b17b0e Blend: spreading keys along a replaced spine measures it once
Giving the keys of a blend whose spine came from Replace Spine anchors of
their own flattened and measured the whole spine again for every key,
then walked its segments one by one. 1,000 keys on a spine of 4,096
segments flattened it 999 times.

The spine is now flattened once into one buffer. A split flattens only
its two halves and measures the segments after it again, in order, only
as far as the next key, so the arc lengths are summed as before and the
keys get the same anchors. A binary search finds each key's segment.

A spine so large that its length overflows no longer gets an anchor
split at a parameter that is not a number: spreading keys along it
returns nothing and leaves it as it was.
2026-11-13 11:21:31 -08:00
dotCooCoo 69deae55cf .ai import: straight paths twisted past 180° keep the drawn look
A path or compound path with straight segments and nothing stroked was
read with its Twist live at any angle. It is now read live up to 180°
either way, a limit VectorCraft sets, and one twisted further keeps the
file's drawn look, as curves and groups already do past 90°.

The .ai writer keeps a graphic-style link only where the reader reads the
style live, so a straight object twisted past 180° is now written without
the link, with the existing style-link warning.

Docs: docs/file-format-parity.md, docs/target-app-parity.md.
2026-11-13 11:21:08 -08:00
dotCooCoo b7dbb4b59c Merge main into fix/graph-series-paint-other-commands 2026-11-13 11:18:16 -08:00
dotCooCoo af91a37669 Merge main into feat/monitor-profile-windows-linux 2026-11-13 11:12:25 -08:00
dotCooCoo 7dc335b49d Merge main into fix/status-linked-files-keeps-notes 2026-11-13 11:11:31 -08:00
BFlat 630ef6f549 Merge pull request #7129 from dotCooCoo/fix/brush-library-names-translated
Brushes: built-in library panels show brush names in the UI language
2026-11-14 01:55:05 +07:00
BFlat e718e975b6 Merge pull request #7104 from dotCooCoo/feat/actions-record-into-selected
Actions: Begin Recording adds steps to the selected action, and a drag moves a step
2026-11-14 01:54:47 +07:00
BFlat 1664f6de66 Merge pull request #7139 from dotCooCoo/feat/ctb-type-tools-font-fill
Contextual Task Bar: the Type tools show font family, style, size and Fill
2026-11-14 01:54:39 +07:00
BFlat ca8e49e9e2 Merge pull request #7158 from dotCooCoo/fix/export-unused-option-warning
Export: warnings name an option the chosen format doesn't read
2026-11-14 01:54:29 +07:00
BFlat 820b82b8d3 Merge pull request #7188 from dotCooCoo/fix/color-gamut-cache-profile
Color: the out-of-gamut warning updates after a profile change
2026-11-14 01:54:13 +07:00
BFlat a8db64db47 Merge pull request #7208 from dotCooCoo/feat/live-paint-selection-cursors
Live Paint Selection: cursor shows a face, an edge or nothing to select
2026-11-14 01:54:04 +07:00
BFlat 5010861362 Merge pull request #7199 from dotCooCoo/fix/close-background-tab-keeps-front
Documents: closing a background tab keeps the document in front
2026-11-14 01:53:56 +07:00
BFlat 9bad58b73e Merge pull request #7215 from dotCooCoo/fix/new-profile-errors-hide-path
New Document profiles: errors name the profile file by its file name outside the read roots
2026-11-14 01:53:47 +07:00
BFlat 1c1bb2f96e Merge pull request #7191 from dotCooCoo/feat/gradient-hue-blend
Gradients: Hue Clockwise and Hue Counterclockwise mix stops around the hue wheel
2026-11-14 01:53:39 +07:00
BFlat 26869d1754 Merge pull request #7197 from dotCooCoo/fix/item-4498
Arrowheads: keep agents to the arrowheads file inside their read roots
2026-11-14 01:53:29 +07:00
BFlat 2370ad1b21 Merge pull request #7200 from dotCooCoo/fix/free-distort-constrain
Free Transform: Constrain keeps a Free Distort corner on its diagonal
2026-11-14 01:53:20 +07:00
BFlat edc4b712dd Merge pull request #7146 from jmverges/fix/7141-page-check-typed-envelopes
.ai and EPS import: envelopes of type stay live where other art differs from the page
2026-11-14 01:53:11 +07:00
BFlat d533018fd5 Merge pull request #7180 from ruchirguitar/feat/6740-type3-named-groups
feat(pdf): preserve Type 3 font text runs as named groups (#6740)
2026-11-14 01:53:02 +07:00
dotCooCoo 2aa7bbd791 Plug-ins: file-key exemptions name only params a command takes
A command now counts as taking a file or folder when its params
description (with the commands its `…` entries name) or its schema takes
a file key as a param. A word in the description's prose or result no
longer counts; a description whose keys are not known keeps the text
scan. The code of the call-time scan of arguments is unchanged, but it
reads the changed exemption tables. The confined run is unchanged.

- NOT_FILES drops seven entries that named no param of their command
  (object.setLiveShape path, path.reverse paths, object.pathfinder.options
  paths, object.maskImage path, imageTrace.make paths,
  svgInteractivity.info files, addon.cleanup.rejoin paths). A top-level
  `path` to object.setLiveShape or object.maskImage, `paths` to
  path.reverse, imageTrace.make or addon.cleanup.rejoin, and `files` to
  svgInteractivity.info are now refused.
- Image Trace's path fidelity setting is exempt only inside `params` and
  `savedPreset` of imageTrace.make and imageTrace.makeAndExpand, so a
  call with it is no longer refused.
- every_command_is_sorted checks that each exemption names a param its
  command takes, and that each nested exemption starts at one.
- effect.expandAsWireframes is reviewed as allowed and
  stroke.arrowheads.list as refused.
2026-11-13 10:50:53 -08:00
dotCooCoo 444f50a4c4 Objects on Path: each path is flattened once per placement or transform
stops and stop flattened the path twice, once for the points and once
for its length, and stop did both before rejecting an index past the
last object. place validated the path with attachable_path first, and
transform measured the old and new paths up to three times each.

A private Measured value now holds the flattened first subpath with its
length and closed flag, and path_length, stops, stop and transform use
it. stop returns None for an out-of-range index without measuring, and
a move of the group measures no path.

attachable_path now uses path_length, so a path whose length overflows
to infinity is no longer offered as one objects can attach to when
placement cannot measure it.
2026-11-13 10:50:24 -08:00
dotCooCoo d1f76ede8a Smooth: a drag along a segment smooths it when its anchors are out of reach
A Smooth drag along the middle of a curved segment smoothed nothing when
neither of the segment's anchors was within the reach, and paths of two
anchors were never smoothed.

- path.smoothRegion searches each curved segment where it can come
  within the reach, halving it down to pieces no longer than half the
  reach, and adds an anchor in the middle of each stretch in reach; the
  existing reach split then cuts the segment where the drag enters and
  leaves the reach. A drag that only grazes a curve finds the place on
  it nearest the drag. The search is bounded per drag and shared
  equally by the segments in reach.
- Paths of two anchors are smoothed, open or closed.
- Alt with the Paintbrush smooths a selected two-anchor curve; a
  two-anchor straight line still gets the closed stroke. Both sides use
  one segment_is_straight test.

Part of #2224
2026-11-13 10:44:19 -08:00
dotCooCoo e25795f73e Path Precision Tools: Trim at Crossings leaves clipping paths and art outside isolation alone
- The clipping path of a clip group or a clipped layer takes no part,
  the members of a compound clipping path included. Before, only a
  plain clipping path was left out.
- In isolation mode only paths inside the isolated object are trimmed;
  paths outside it still count as crossing.
- A rectangle or line that reaches so many paths that comparing their
  boxes would take more than 50,000,000 tests is refused before any
  work starts.
- A tool drag that goes 3 screen pixels or more from the press stays a
  rectangle or line when it ends near the press. Before, it ran as a
  click and could remove a whole path the final rectangle did not
  touch.

Docs: docs/mcp.md.
2026-11-13 10:44:07 -08:00
dotCooCoo 1dff3264f0 Docs: File formats area rows list the legacy .ai kerning, hyphen and language evidence
The current File formats rows of docs/target-app-parity.md now name the legacy .ai manual kerning, discretionary hyphen and hyphenation language reading and writing, with their tests. Score, gaps and hours are unchanged.
2026-11-13 10:42:02 -08:00
dotCooCoo 9a4e3e6202 Smooth tool: the drag shows the band the tool smooths
While the Smooth tool drags with a path selected that it can smooth, a
dashed outline shows the band its release smooths: every point within
the tool's radius (12 screen pixels) of the drag, round at both ends.
Alt smoothing with the Pencil, Paintbrush and Blob Brush shows the same
band. A selection with no path the tool can change shows none.

- The band is kept in squares eight radii wide, and each step of the
  drag adds its area only to the squares it reaches. A piece of a
  square's outline along a side is left out only where the square
  across holds band area.
- A drag segment too long for the squares (a jump drawn zoomed out and
  viewed zoomed in) keeps its band near each end in the squares and
  shows the rest as the two sides of its band. A step that cannot be
  added whole is added one segment at a time.
- A coarser grid of cells lists the squares and long segments, so a new
  one is checked only against those near it, and an outline is made
  again only where the band near it changed.
- After a zoom change mid-drag the band is outlined again a few hundred
  points per frame, and the work on long segments stops for the frame
  after a fixed budget. Tools report unfinished overlays with
  Tool::overlays_pending, and the canvas then draws again on the next
  frame, so the band covers the whole drag even while the pointer holds
  still.
2026-11-13 10:41:00 -08:00
dotCooCoo b513c631f9 Type: threaded paths and frames aligned off the top measure the paragraphs they need
A threaded story measured each type-on-a-path frame, and each area frame
whose lines align to the center, the bottom or justify vertically, with
the whole rest of the story. A story of 1,500 one-line paragraphs through
40 such frames was laid out over about 2.1 million bytes while the frames
were measured.

- Area type without Shrink Text to Fit now takes the paragraph probe for
  every vertical alignment. A reflow pass that places less text is
  undone, so when the final layout stops before the last paragraph break
  measured, every pass placed the same lines as with the whole rest.
- Type on a path takes it when its line starts at the start bracket: no
  Dynamic Text, Optical Margin Alignment or Roman Hanging Punctuation,
  the first paragraph aligned Left, Justify Left or Auto, and vertical
  type or no right-to-left text in the rest of the story. The story is
  scanned for right-to-left text once per distribution.
- Shrink Text to Fit, the other path settings and a share that ends in
  the story's last paragraph are still measured with the whole rest.

The same 40 frames are now measured over 21,035 bytes (aligned to the
center) and 20,583 bytes (paths aligned Left). Each frame's share is
unchanged: the tests compare every slice with the whole-rest result for
both distribution entry points, across alignments, frame shapes, wraps,
path settings, right-to-left text, styles, lists and seeded stories.
2026-11-13 10:31:42 -08:00
dotCooCoo 78a06865d7 i18n: Hindi uses one word for a variable and जोड़ें for joining paths
The Hindi catalog called a variable चर, परिवर्तनीय, वैरिएबल or
वेरिएबल from one row to the next: the Variables panel, Load and Save
Variable Library, Variable Options and the data-merge messages mixed
them, and so did variable widths, the font technology label and
environment variables. Every such row now says वेरिएबल (plural
वेरिएबल्स).

Close or Join, Join Point Text, Join the lines of each paragraph and
most of the path join messages said शामिल हों, which means joining a
group; the other join messages used जुड़ना, जॉइन or the English word.
They now say जोड़ें, as the Join command already did. The Discord rows
keep शामिल हों, and the stroke corner names and the Join tool keep
जॉइन.

hindi_rows_use_one_term_for_a_variable_and_for_joining_paths checks
both terms in every row. docs/localization-hi.md lists the terms, and
the Hindi row counts in it and in docs/localization-parity.md are
current (8,782 rows, 3,014 @msg).
2026-11-13 10:30:49 -08:00
dotCooCoo db047c000e Docs: Global Edit leaves out groups holding type or images
Global Edit does not take images or text, so a group holding type or an
image is not a missing case. docs/gaps.md drops it from G5's Missing
line and states the exclusion next to the similar-groups entry, with
the help page. docs/ui-parity.md states the same exclusion and no longer
lists highlighting the matches before the start as remaining, since it
ships with a regression test. docs/target-app-parity.md gains an
Evidence line.
2026-11-13 10:29:27 -08:00
dotCooCoo 27ad04dbc1 Documents: closing a modified background tab keeps the document in front
Closing a modified tab that is not in front shows it while the Save
Changes dialog asks about it. After Save or Don't Save, the closed tab's
neighbor became the current document instead of the document that was in
front before the question.

Closing a background tab with its close button, or `file.close` with its
`index`, now remembers the uid of the document in front in the dialog's
protected `__front` field, and once the asked document closes, that
document is made current again while it is still open. The field
survives a Save dialog shown off the UI thread. Cancel keeps the asked
document in front, closing the document in front still brings its
neighbor forward, and Close All and Quit are unchanged.
2026-11-13 10:19:30 -08:00
dotCooCoo 19be0bb880 Type: inline graphics in symbol, mask and pattern art follow their symbols
Type with an inline graphic was resolved only in the layers, so type in
the art of another symbol, a graph design, a pattern tile or an opacity
mask kept the size its graphic had when it was made. The symbol holding
that type, its instances and the inline graphics that show it were
measured from the stale layout.

- Inline graphics are resolved in every tree that holds type. Symbols
  are resolved in dependency order, so a symbol's type is laid out
  before the type that shows that symbol inline. Edits, opening,
  reverting and Refresh Font List use the same pass.
- The pass visits each object once: it resolves the children first and
  copies a node only when something below it changed. It measures each
  symbol's art once per pass.
- An inline graphic of a symbol whose art shows that symbol inline,
  directly or through other symbols, is an empty slot. The symbols on
  such a cycle are found once and cached until the symbols change.
- A changed inline graphic also clears the text's cached baselines.
2026-11-13 10:17:33 -08:00
dotCooCoo c367e8d0f3 Touch: canvas taps, presses and view navigation are ignored while a modal dialog is open
With Enable Touch Gestures on, a two-finger tap on the canvas undid and a
three-finger tap redid even while a modal dialog was open, and in the Touch
workspace a two-finger tap switched modes behind it. Fingers already down
when a dialog opened could still complete a tap when they lifted, during
the dialog or after it closed.

While a modal is open, from the frame it opens:
- no finger tap runs a command and no multi-finger gesture begins; the
  fingers already down are forgotten, so lifting them later runs nothing
- a primary press does not reach the tool, a middle-button press does not
  start a pan, and a double-click does nothing
- a long touch does not drop the canvas press
- a click in Presentation Mode does not step to the next artboard
- a pinch, wheel turn or trackpad rotation does not move the view, and the
  rest of a wheel turn made under the dialog is dropped after it closes;
  a new wheel turn after the dialog closes moves the view at once

Docs: docs/target-app-parity.md, docs/mcp.md.
2026-11-13 10:16:40 -08:00
dotCooCoo 1b935b6d0a Merge main into fix/smooth-fidelity-screen-pixels 2026-11-13 10:13:12 -08:00
dotCooCoo 78d3f6e1a5 PDF/.ai import: legacy type keeps manual kerning, discretionary hyphens and language
Legacy .ai type (version 7) now reads the operators it used to skip:

- `autoKern kernValue Tk` (and `TK` in overflow text) sets the manual
  kerning of the character before the pair, or at the start of a line
  the space before the line's first character; autoKern 1 sets the
  pair back to automatic. Values are kept to -1000..10000.
- `T+` and `T-` (discretionary hyphens) become soft hyphens.
- `languageID XL` sets the characters' language (ids 0 to 11).
- A visible text object read while a line breaking value (`TG`) or
  Japanese layout rules (`Xu`, `Tu`) are set opens with a warning,
  once per file for each.

Final-form positions (Tc, Tw, Tm, Td, T*, TR) stay ignored.

Legacy .ai saves now write manual kerning as `0 value Tk` after each
character that has it and before a paragraph's first character with
space before it, and soft hyphens as `T+`; manual kerning is no longer
listed among the attributes left out. The writer's prolog defines Tk
and T+.

Docs: docs/file-format-parity.md, docs/target-app-parity.md.
2026-11-13 10:12:57 -08:00
dotCooCoo 683dea1c4b Docs: UI chrome rows no longer list SVG Interactivity as missing
The UI chrome rows in target-app-parity.md listed SVG Interactivity and
context menus beyond the canvas as remaining work. The SVG Interactivity
panel ships, and the canvas, Layers rows, artboard rows, libraries,
rulers and toolbar grips have menus, so the rows now name context menus
in the panels that have none. ui-parity.md drops a second checklist row
that listed SVG Interactivity as missing; the row above it already
lists Retype, Comments and Version History.
2026-11-13 10:11:30 -08:00
dotCooCoo c5b20136ae Merge main into fix/trace-blur-rings
# Conflicts:
#	docs/image-trace-quality.md
2026-11-13 10:06:37 -08:00
dotCooCoo b54f357ced Merge main into fix/raster-effects-skipped-transform-budget 2026-11-13 10:06:29 -08:00
dotCooCoo 1f13d1f8b7 Merge main into fix/area-type-band-coverage 2026-11-13 10:04:24 -08:00
dotCooCoo 3c434a7e90 Merge main into fix/graph-series-paint-visible-rows 2026-11-13 10:02:14 -08:00
dotCooCoo 796100e388 Merge main into fix/flatpak-clipboard-images 2026-11-13 09:59:55 -08:00
dotCooCoo 8b0e905586 Docs: Layers row context menu offers Collect for Export
The gap lists and area tables said Layers rows, panels and type have
no context menu. Layer, sublayer, group and object rows offer Collect
for Export for the row or every highlighted row, and right-clicking
type opens the canvas menu. The docs now list what ships and name the
remaining gaps: other row menu commands, guide and blend spine rows,
and panels without a menu. The Layers panel menu list adds Collect for
Export, and SVG Interactivity leaves the missing list.
2026-11-13 09:57:59 -08:00
dotCooCoo 5d31439e46 Merge main into fix/graph-series-paint-other-commands 2026-11-13 09:57:15 -08:00
dotCooCoo 3397b0a534 Docs: keep one Preferences progress bullet with the off default for Highlight Alternate Glyphs
docs/target-app-parity.md listed the "Preferences that act" bullet three
times. Two older copies disagreed on Highlight Alternate Glyphs (one said
on by default, the code sets it off in Prefs::default) and still counted
about 14 stored options. The newest copy is kept, now with the Highlight
Alternate Glyphs clause (off by default), and its count names the two
options still stored only: Scratch Disks and the legacy vector clipboard.

The older of the two "Preferences audit (2026-10-30)" bullets, which still
listed five stored-only options, is removed, and the UI chrome summary row
now says 2 options, matching docs/gaps.md G12.
2026-11-13 09:55:46 -08:00
dotCooCoo 1da59bfb22 Document Info: hidden and clear objects list no brushes or paints
Brushes, Spot Color Objects, Pattern Objects and Gradient Objects left
out a fill or stroke that was hidden or at an opacity of 0, but still
listed an object that was itself hidden or at an opacity of 0, and the
objects inside such a group or layer. They now leave those out, their
characters' paints and colorized images included. With Selection Only,
an object selected inside a hidden group or layer, or one at an
opacity of 0, is left out too. Objects still counts every object.
2026-11-13 09:54:35 -08:00
BFlat 608830d683 Merge pull request #7162 from dotCooCoo/fix/actions-recording-limit-notice
Actions: script runs and tool edits name a recording limit as they end
2026-11-14 00:52:08 +07:00
BFlat 7553c1f679 Merge pull request #7182 from dotCooCoo/feat/objects-on-path-detach
Objects on Path: Detach takes the chosen object off the path
2026-11-14 00:51:59 +07:00
BFlat 88a5b496f2 Merge pull request #7113 from dotCooCoo/fix/tabs-ruler-mixed-selection
Tabs: the ruler shows when a non-text object is first in the selection
2026-11-14 00:51:48 +07:00