Commit Graph
104 Commits
Author SHA1 Message Date
BFlat c79a21c8b7 Merge pull request #7320 from dotCooCoo/fix/graph-design-art-appearance
Graphs: Appearance and effect commands leave a design's art in a series out
2026-11-14 07:33:59 +07:00
BFlat 6fa41d4f76 Merge pull request #7304 from dotCooCoo/fix/graph-series-object-opacity-other-commands
Graphs: Global Edit, Randomize Opacity and Sort Objects keep what they give a series
2026-11-14 06:26:22 +07:00
dotCooCoo 0d26724a7c Graphs: Appearance and effect commands leave a design's art in a series out
A graph draws the art of a column or marker design inside a series again
from the stored design. Rows, effects and graphic styles that a command
gave that art were lost the next time the graph's data, type or size
changed. The paint commands already left the art out.

- The appearance.* row and whole-appearance commands, effect.apply,
  appearance.addEffect and the effect.* commands that edit, move or
  remove an effect, threeD.mapGraphic, graphicStyle.apply,
  graphicStyle.addFromLibrary with apply, transparency.set with a fill
  or stroke item, and appearance.copyFrom (as the target) leave out any
  object inside a series group other than a path directly in it, given
  by id, selected or reached through target: "contents". They edit the
  other objects given, and a command whose objects are all design art
  is an error.
- appearance.transfer with design art as its target, or as its source
  without copy, is an error.
- A Pathfinder effect no longer groups selected design art.
- The paint commands given a design's copy with a fill or stroke item
  leave it out as well.

docs/mcp.md states the rule, and the Graphs line in
docs/target-app-parity.md names it.
2026-11-13 14:51:31 -08:00
BFlat 2fe70b2483 Merge pull request #7258 from dotCooCoo/fix/graph-label-appearance-kept
Graphs: Appearance edits on a label are kept for every label of its kind
2026-11-14 05:42:08 +07:00
dotCooCoo 6e308c4e54 Graphs: Global Edit, Randomize Opacity and Sort Objects keep what they give a series
A path directly in a graph series lost what these commands gave it when
the graph was drawn again, for example after graph.setData:

- While Global Edit is on in an isolated graph, a match that is a series
  path, or a series group whose paths take the edit, now has what
  changed on its paths stored for their series: the paint, weight,
  opacity and blend mode of the topmost visible fill and stroke, and the
  object's opacity and blend mode. The edited match is stored by its own
  command as before.
- addon.arrange.randomizeOpacity and addon.arrange.sort with apply
  "opacity" now store the object opacity, with the blend mode, of the
  series paths whose opacity they change. When they change several
  paths of one series, the frontmost of them sets what the graph
  stores, as for the other commands.

The graph stores them in the same undo step as the edit. The params
text of addon.arrange.randomizeOpacity and addon.arrange.sort,
docs/mcp.md and docs/target-app-parity.md describe the new behavior.
2026-11-13 13:53:55 -08:00
BFlat 4558196e16 Merge pull request #7053 from dotCooCoo/feat/warichu
Type: Warichu stacks selected characters on lines inside their line
2026-11-14 04:32:40 +07:00
dotCooCoo fdedfb0e59 Merge main into feat/warichu 2026-11-13 11:59:22 -08:00
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 3c434a7e90 Merge main into fix/graph-series-paint-visible-rows 2026-11-13 10:02:14 -08:00
dotCooCoo 5d31439e46 Merge main into fix/graph-series-paint-other-commands 2026-11-13 09:57:15 -08:00
dotCooCoo 87ad60ec42 Merge main into fix/graph-series-group-appearance 2026-11-13 08:15:48 -08:00
dotCooCoo 9a1d36c57e Merge main into fix/graph-series-paint-visible-rows 2026-11-13 08:14:30 -08:00
dotCooCoo b8ab31ff50 Merge main into fix/graph-series-paint-other-commands 2026-11-13 08:13:53 -08:00
dotCooCoo b6aaea6c97 Graphs: Appearance commands and graphic styles given a series group edit its marks
A graph draws its series groups again with no rows of their own, so a
fill, stroke, opacity or graphic style that a command put on a series
group was lost the next time the graph's data, type or size changed,
and the graph stored nothing. paint.setFill and paint.setStroke already
pass a series group's id on to the paths directly inside it.

- appearance.addFill, addStroke, setItem, removeItem, duplicateItem and
  moveItem, graphicStyle.apply and transparency.set with a fill or
  stroke item now edit the paths directly in a series group given by id
  or picked with Group Selection, and the graph stores what they change.
  A series group with no such path, or with a fill or stroke row of its
  own, is still edited itself, and appearance.moveItem from "contents"
  still moves the group's own Contents row.
- appearance.clear, appearance.reduceToBasic, appearance.showAllHidden
  and graphicStyle.breakLink edit the group as well as its paths.
- graphicStyle.apply without add and appearance.transfer onto a series
  group clear the group's own opacity, blend mode, isolation, knockout,
  effects and style link, and graphicStyle.apply with add unlinks the
  group. A transfer source that is one of the group's paths keeps its
  look, and a source that is the group's only path is an error.
- graphicStyle.redefine passes the style to the paths of a linked series
  group, other than the source and the linked paths whose look was
  edited, and clears and unlinks the group.
- graphicStyle.new, graphicStyle.redefine and appearance.transfer read a
  series group that holds no row, effect, opacity, blend mode,
  isolation, knockout or style link of its own through the topmost path
  directly in it, and a move clears each of those paths. A series group
  that holds one of them is read itself, as before.
- The Graphic Styles panel reads the style link of such a selected
  series group from that path.

Docs: docs/mcp.md, docs/target-app-parity.md. Not yet: the Appearance
panel and appearance.setActiveItem still read the selected group's own
rows, and the effect commands and the paint, stroke and gradient
commands with an item still edit the group itself.

Follows #5501.
2026-11-13 07:25:03 -08:00
dotCooCoo 2343e0e8b0 Graphs: paint commands store a series' paint only from the row a mark shows
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke, Apply
Stroke to Fill and a library gradient or pattern applied with library.use
stored the topmost fill or stroke row of a graph series mark on the graph
even when that row was hidden, and stored a stroke set on a Filled Lines
band. When the graph was drawn again, every mark of the series took a
paint that the edited mark never showed, and a band took the stroke color
as its fill.

These commands now follow the rules of the Appearance commands:

- The graph stores the paint only when the row the command wrote is the
  topmost visible row of its kind, or when the command changed what the
  mark shows. With `item`, that is the named row.
- A series that draws Filled Lines bands stores no stroke paint or
  weight; the band keeps its own outline.
- A row without paint before and after the command keeps what the graph
  stores, so None on a marker without a stroke no longer removes the
  line's stored stroke.
- When one command writes several marks of a series, the frontmost mark
  sets what the graph stores, whatever the order of the ids.
- Apply Fill to Stroke and Apply Stroke to Fill on a mark whose row
  already has the paint store it, as paint.setFill does.

A document without graph series marks among the edited objects skips the
comparison of paints.

Docs: docs/mcp.md and the params text of the paint commands.
2026-11-13 06:20:05 -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 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 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
dotCooCoo 226ac437b9 Type: Warichu stacks selected characters on lines inside their line
The Character panel menu has Warichu and Warichu Settings… with Show East
Asian Options. Warichu characters are set at a percentage of their size
and stacked on 1 to 6 lines inside their line: one above the other in
horizontal type and side by side in vertical type. Warichu Settings sets
Lines, Line Gap, Scale and Alignment.

- text.setFormat and text.setRangeStyle take warichu, warichuLines,
  warichuGap, warichuScale and warichuAlign; ui.warichuSettings opens
  the dialog.
- A stretch of warichu characters is one block that stays whole on one
  line. The canvas and every export draw the stacked lines; SVG, PDF and
  the .ai writers write such type as outlines, as they do ruby. Type on a
  path sets the characters at their own size.
- The attributes are saved natively, carried by character styles and
  translated in every complete catalog.

Docs: docs/mcp.md, docs/type-parity.md.
2026-11-12 21:13:21 -08:00
BFlat 81247fdae9 Merge pull request #6666 from dotCooCoo/fix/malformed-id-not-missing
MCP: a malformed object id is refused as such, not reported as missing
2026-11-12 19:14:06 +07:00
Sven Lafebre ab17837cba Merge remote-tracking branch 'origin/main' into fix/5111-kern-paragraph-start
# Conflicts:
#	docs/target-app-parity.md
2026-11-12 09:24:22 +01:00
dotCooCoo 19d2778337 Merge main into fix/malformed-id-not-missing 2026-11-11 23:31:01 -08:00
Christian Lappin f6dbc82e6e M3: validate paragraph-only Eyedropper bounds (#6404)
Paragraph justification can move point text past the canvas limit even when character copying is disabled. Check those targets before keeping the edit or remembered sample, and cover the explicit-target case with a regression.
2026-11-11 21:40:10 -05:00
Christian Lappin 4e3ebb2810 M3: preserve effective text dimensions in Eyedropper picks (#6404) 2026-11-11 21:40:10 -05:00
dotCooCoo 5c2e182388 MCP: a malformed object id is refused as such, not reported as missing
Commands that need an object id read it with `id_param`, which returns
None for a value that is not a non-negative integer, so `{"id": "5"}` or
`{"id": -1}` was refused with "missing id". They now read it with
`object_param`, which refuses such a value with "`id` must be a whole
number", naming the key. This covers `document.node`, the `path.*` anchor
and handle commands, the `text.*` range and path commands, the mesh,
envelope and slice point commands, `layer.target`, `layer.move`,
`node.move`, `select.magicWand`, and the `source`, `target`, `group` and
`path` keys of `appearance.transfer`, `appearance.copyFrom`, the
`livePaint.*` commands and `text.createInPath`.

The optional `group` of `livePaint.fill` and `parent` of `node.move` are
refused the same way when given. Before, a malformed `parent` moved the
object to the top level and a malformed `group` fell back to the
selection.
2026-11-11 12:47:49 -08:00
Sven Lafebre 6ae7051e4e Fix #5111: kerning at the caret before a line's first character moves it
At the Type tool's caret, kerning goes on the character before the caret.
At the start of the text there is none, so Alt+arrows, the Kerning field
and Reset Tracking and Kerning did nothing; at a later paragraph's start
the kerning landed on the invisible line break.

CharStyle::kerning_before (kerningBefore) is the space before a character
that starts a line by itself: the first character of the text, of a
paragraph, or after a forced line break. Shaping gives its cluster the
space and draws it that much later along the line (right to left the
space is at its right; in vertical type it moves down the column). The
caret at such a line's start sets it (edit::caret_kerning_target), in
type.step, type.resetTracking and the Character panel; text.setRangeStyle
takes it. SVG export starts the line where the character is drawn. The
Eyedropper and character styles leave it alone.
2026-11-11 21:43:31 +01:00
dotCooCoo 5ac7d97d85 Guides: ruler guides are document objects on their layers
Ruler guides were a list kept beside the layers. Each guide is now an
object of its layer or sublayer, always directly in it and above the
layer's art. These behave as on main:

- Guides draw on screen only. Exports (SVG, PDF, PNG, PSD), Fit All,
  Select All, the art bounds, clicks and marquees, and a layer's
  Pathfinder and Transform effects leave them out. The Layers panel
  lists them as guide rows of their layer, the highest guide.list
  index first.
- Deleting a layer deletes its guides, and merging layers keeps their
  guides in the merged layer.
- The guide commands number guides as guide.list does, in the order
  they were made.

New: each guide takes an id from the document's object ids. An object
command given a guide's id fails with an error, and node.move cannot
put a guide into a group or out of its layers. A guide made while an
opacity mask, a symbol or a pattern is edited moves to the top
visible, unlocked layer when editing ends.

File format: native files still save the guides in the document's
guides list, in every file version, so older builds read them. Each
entry may now also carry the guide's id, name, locked and hidden
flags; older builds ignore those fields. Opening a file puts each
saved guide on its layer (on the top visible, unlocked layer when the
file names none or a layer it does not have), and each saved guide
counts against the object limit for opening a file. A ruler guide node
that a file holds below a layer's art moves up to the layer's guides,
and one anywhere else (in a group or another object, beside the
layers, or in a symbol) is removed. Ruler guides read from an .ai file
become guide objects on the layer they were on, numbered in the order
the file lists them.
2026-11-11 09:52:28 -08:00
dotCooCoo 99b7fb0ab8 Appearance: aligned Remove Item and Duplicate Item keep the active row
After an aligned Remove Item or Duplicate Item, the active row was
re-pointed by the indices of the first object in paint order. When the
first selected object paints above the others, its own rows that changed
are different ones, so the active row could be dropped or land on the
wrong row, and a later paint edit changed that row instead.

The active row now follows the rows removed or copied in the first
selected object's own stack.

Follows #5591.
2026-11-10 23:58:23 -08:00
Fabio William Conceição 0216bd58c5 G5: document gradient, pattern, opacity and blend on a picked part
The MCP guide and the Eyedropper spec still said those were refused for a Direct Selection of a dynamic symbol part.
2026-11-09 13:12:49 +00:00
Fabio William Conceição 1e278a3dff G5: dynamic symbol parts take opacity, blend and non-solid paint
Direct Selection of a path, compound path or type inside a dynamic instance now applies transparency and gradient or pattern fills through the usual paint commands, and the G5 docs catch up on Overlap and Pattern auto corners.
2026-11-09 12:14:14 +00:00
dotCooCoo f88815abd9 Merge main into fix/graph-series-object-opacity 2026-11-08 14:02:59 -08:00
dotCooCoo 1f38a16329 Commands: an ids list with an entry that is not an id is refused instead of dropping the entry
Squashed from #6179 onto main.
2026-11-09 02:54:32 +07:00
dotCooCoo 581ced3213 Transform: Align to Pixel Grid keeps an object's horizontal and vertical edges on the pixel grid
Squashed from #6169 onto main.
2026-11-09 00:29:28 +07:00
dotCooCoo c0a8ebb70f Graphs: graphic styles and Default and Swap Fill and Stroke update a series' stored paint
Squashed from #6094 onto main.
2026-11-09 00:26:44 +07:00
dotCooCoo 434c032f9e Symbols: Direct Selection sets the solid fill and stroke of one object in a dynamic instance
Squashed from #5962 onto main.
2026-11-09 00:26:11 +07:00
dotCooCoo 76bb829e3a Graphs: a style that removes a mark's painted row resets the stored opacity
Applying or redefining a graphic style on a series mark whose fill or
stroke had paint, when the style leaves that row without paint, now
stores the row's opacity and blend mode on the graph. Before, the
opacity and blend mode another mark of the series left stayed, so a
Filled Lines band's outline kept a stroke opacity after a style without
a stroke went on a stroked marker. A row with no paint before and after
the edit still keeps what the graph stores.
2026-11-08 06:50:03 -08:00
dotCooCoo 32abbfdb8f Merge main into fix/graph-series-object-opacity 2026-11-08 00:05:18 -08:00
dotCooCoo 90cd4797ea Graphs: an added or duplicated top row sets the series' stored paint
appearance.addFill, appearance.addStroke and appearance.duplicateItem can
put a new topmost row on a series mark with the paint the mark already
shows. When another mark of the series had set a different stored paint,
the mark's top paint did not change, so the graph kept the other mark's
paint and drew it again. A new topmost visible row now stores its paint,
as an Eyedropper append already does.
2026-11-08 12:01:39 +07:00
dotCooCoo d136ddb0cc Graphs: Appearance commands' params text names the stored opacity
The params text of the Appearance commands that update a series' stored
paint said the graph stores the paint and weight of the topmost visible
fill and stroke. Each of them also stores that row's opacity, as
docs/mcp.md says. The text now names the opacity too.
2026-11-08 12:01:39 +07:00
dotCooCoo 9a08f64a04 Graphs: Appearance commands and the Eyedropper update a series' stored paint
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke and Apply
Stroke to Fill stored a series' paint on the graph. appearance.setItem, the
Eyedropper, appearance.transfer, Clear Appearance, Reduce to Basic Appearance
and the add, remove, move and duplicate row commands stored no paint or weight.
An Eyedropper pick of a blue fill at 40% onto a red column drew red at 40%
after the next redraw.

These commands and Show All Hidden Attributes now store the paint and weight
of the topmost visible fill and stroke of a path directly in a series group,
in the same undo step. A color, weight or opacity that a command writes to that
row replaces the stored value even when the mark's own value does not change. A
row that has no paint before and after the command does not change the stored
paint. These commands store no stroke for a series that draws Filled Lines
bands, and a band no longer takes its color from an empty stored stroke.

The stored opacity also comes from the topmost visible row: hiding a top row
stores the row under it, and an opacity set on a hidden top row is not stored.

Follows #5501.
2026-11-08 12:01:39 +07:00
dotCooCoo b6fdecc2e0 Graphs: Appearance, Default Fill and Stroke and graphic style help names the stored opacity and blend mode
The help text of appearance.addFill, addStroke, clear, reduceToBasic,
removeItem, duplicateItem, moveItem, copyFrom, showAllHidden and transfer,
paint.default, and graphicStyle.apply and redefine said the graph stores
only the paint and weight of the topmost visible fill and stroke. These
commands also store that row's opacity and blend mode, as
appearance.setItem's help and docs/mcp.md already say.
2026-11-07 19:42:24 -08:00
dotCooCoo 5a9a08fcb1 Graphs: a series keeps the object opacity and blend modes set on one of its marks
An object opacity or blend mode set on a path directly in a graph series, and
the blend mode of its topmost visible fill or stroke, were lost when the graph
was drawn again. The graph now stores them per series next to the row opacity
it already stores, and puts them on every path directly in the series when it
draws the series again.

- transparency.set and object.setProps store the object's opacity and blend
  mode. A value the mark already has still replaces the value another mark of
  the series stored.
- appearance.clear, appearance.transfer, appearance.copyFrom with Transparency
  picked up, graphicStyle.apply without add and graphicStyle.redefine store
  the object's opacity and blend mode they leave on the mark.
- The other Appearance and style commands store them when they change them
  on a mark.
- Every command that stores the opacity of the topmost visible fill or stroke
  also stores its blend mode. A Filled Lines band's outline takes the stored
  stroke opacity and blend mode and keeps its black 0.25 pt stroke.
- An opacity and blend mode are stored as a pair from the edited mark:
  setting only the opacity of one mark also stores that mark's blend mode.
- A graph design's copy in a series keeps its own values.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-07 04:28:27 -08:00
dotCooCoo 434cf3e692 Graphs: graphic styles and Default and Swap Fill and Stroke update a series' stored paint
Applying a graphic style, Redefine Graphic Style, Default Fill and Stroke
and Swap Fill and Stroke on a path in a graph series changed the path
but not the paint the graph stores for the series. When the graph was
drawn again, the series went back to its earlier paint.

These commands now store the mark's topmost visible fill and stroke on
the graph, in the same undo step as the command:

- graphicStyle.apply stores the paint, weight and opacity of both kinds
  of row. With `add` it stores only the kinds of row that are visible
  in the style.
- graphicStyle.redefine stores the paint, weight and opacity of the
  marks still linked to the style.
- paint.default stores the white fill and the 1 pt black stroke, both
  opaque.
- paint.swap stores the swapped paints and the stroke weight and keeps
  the stored opacity. It swaps the topmost rows even when they are
  hidden, and a hidden row it swaps is not stored.

The rule for each kind of mark is the one docs/mcp.md gives for the
Appearance commands. docs/mcp.md also says what the graph does not
store from a graphic style and that a series group given to a graphic
style command is not stored. The params text, docs/mcp.md and the
Graphs line in docs/target-app-parity.md list the commands.
2026-11-07 02:54:42 -08:00
dotCooCoo 9fe7aec49c Graphs: Appearance commands and the Eyedropper update a series' stored paint
paint.setFill, paint.setStroke, paint.none, Apply Fill to Stroke and Apply
Stroke to Fill stored a series' paint on the graph. appearance.setItem, the
Eyedropper, appearance.transfer, Clear Appearance, Reduce to Basic Appearance
and the add, remove, move and duplicate row commands stored no paint or weight.
An Eyedropper pick of a blue fill at 40% onto a red column drew red at 40%
after the next redraw.

These commands and Show All Hidden Attributes now store the paint and weight
of the topmost visible fill and stroke of a path directly in a series group,
in the same undo step. A color, weight or opacity that a command writes to that
row replaces the stored value even when the mark's own value does not change. A
row that has no paint before and after the command does not change the stored
paint. These commands store no stroke for a series that draws Filled Lines
bands, and a band no longer takes its color from an empty stored stroke.

The stored opacity also comes from the topmost visible row: hiding a top row
stores the row under it, and an opacity set on a hidden top row is not stored.

Follows #5501.
2026-11-07 00:07:40 -08:00
dotCooCoo c969b7857d Type: an Eyedropper pick on a selected story styles every frame
appearance.copyFrom and a fill or stroke change on a story selected by
Select All no longer skip locked frames, hidden frames and frames on a
locked artboard. They apply to every frame of the story, as the Character
panel's story edits do. appearance.copyFrom still leaves out a frame that
is its source.
2026-11-07 05:15:11 +07:00
dotCooCoo f534b0061a Type: switching to the Eyedropper keeps a whole-story selection
With a threaded story selected by Select All, switching to the Eyedropper kept
only the edited frame's selection, so a pick styled one frame. The selection now
carries the story's frames, a pick or Shift-click applies to the text of every
frame as one undo step, and switching back to a Type tool restores the story
selection. A selection inside one frame and unthreaded type behave as before.

A pick and a fill or stroke change on a selected story leave locked and hidden
frames and frames on a locked artboard as they are. appearance.copyFrom leaves
out a frame that is its source.

Typing over a selected story no longer removes the text of a frame whose thread
was removed after Select All.
2026-11-07 05:15:10 +07:00
dotCooCoo b5da39d7b5 Commands: true/false flags reject other values everywhere
The remaining flags under crates/engine/src/cmd that read a boolean with
get(..).and_then(Value::as_bool).unwrap_or(..) now go through switch_or,
so a value such as "false" or 1 is an error instead of the default.
Omitting a flag or giving null keeps the old behavior.

- effect.move: copy
- aligned on the appearance.*, stroke.set, transparency.set and effect.*
  commands, checked before any early return
- transparency.viewOpacityMask: on
- view.printTiling: on
- plugin.install: replace and allowHeavy, checked for every plug-in
- edit.clear: guides, and path.deleteAnchors' read of it
- text.create and text.createInPath: vertical (already refused by
  check_switches, so their behavior is unchanged)
2026-11-06 13:47:16 +07:00
dotCooCoo af74427ef4 Appearance: edits to the active row reach the matching row in each selected object
Paint and effect edits matched the active row across all selected
objects at once, so one object without an equal row made every object
edit the row at the raw index. ItemTarget::per_target and
effect_targets now match each object against the first one on its own,
as items_per_target does. effect_targets also looks up the row in the
stack it belongs to when deciding whether an effect edit is
object-level, so an effect on a row that sits lower in another object's
stack no longer fails with "no appearance item".
2026-11-05 03:55:55 +07:00
dotCooCoo a9eae3a333 Appearance: Add New Fill and Add New Stroke comment names the paint they take
The comment in add_item said a new fill or stroke is a copy of the top
one. The code takes only the top item's paint, and for a stroke its
weight. The comment now says so, as the params text does.
2026-11-04 23:44:58 +07:00
dotCooCoo 535d423d6c Appearance: Add New Fill and Add New Stroke params text match the code
appearance.addFill copies the active fill row only when the call has no
`ids`, no `id` and no `target: "contents"`; the params text now names
`id` too. appearance.addStroke gives the new stroke at least 1 pt, so a
0.5 pt top stroke gives a 1 pt stroke; the params text now says so.

Tests pin both: `id` alone leaves the active row alone and puts the new
fill on top, and Add New Stroke on a 0.5 pt stroke adds a 1 pt one.
2026-11-04 20:51:07 +07:00