Commit Graph
18 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 fb41d79f28 Layers: ruler guide rows have their own eye and lock, and go to the trash
The eye and lock on a guide's row in the Layers panel hide or lock that
guide alone, in one undo step, and a drag down either column takes guide
rows along with the other rows it passes. A hidden guide is not drawn and
does not snap, and its row is dimmed; a locked guide is drawn and snaps
but can't be selected, moved or deleted. Both can be changed while the
guide's layer is hidden or locked, and the guide shows or can be edited
only when its layer allows it as well. The state is kept through save
and reopen.

- layer.setProps takes ruler guide node ids; every other command still
  refuses them.
- guide.list rows carry the guide's node id and its own hidden and
  locked state.
- Alt-click and Ctrl/Cmd+Alt-click on a guide row's eye or lock act on
  the other layers, as on any row in that layer.
- Object > Lock > Selection and Object > Hide > Selection lock or hide the
  selected ruler guides with the selected art, in one undo step, outside
  isolation mode. Unlock All and Show All, document scope, also unlock or
  show guides locked or hidden on their own and select them as guides.
- Guide rows dropped on the Layers panel's trash delete their guides
  (guide.remove {indexes}). A click on a guide row clears the highlighted
  rows, so Delete deletes the guide; with no row highlighted the trash
  deletes the selected guides.
- guide.remove and guide.setLayer refuse index together with indexes and
  an indexes value that is not a list, and count a repeated index once.
  guide.select, guide.remove and guide.setLayer refuse an indexes list of
  more than 10,000 entries; guide.setLayer cut such a list short before.
- Moving, deleting or moving to another layer a guide that is hidden or
  locked on its own fails with "the guide is hidden or locked"; a guide
  on a hidden or locked layer still fails with "the guide is on a hidden
  or locked layer".

Docs: docs/mcp.md, docs/target-app-parity.md, docs/ui-parity.md.
2026-11-13 06:07:27 -08:00
HassanKhan 386e405800 Commands: draw_shape and object.reflect say which way they turn; test the notes the key walk misses (#6340)
draw_shape's rotation also turns rectangles and ellipses; object.reflect's numeric axis is counter-clockwise from horizontal. A test covers that axis and the Scatter brush's rotation range, which every_turn_param_says_which_way_it_turns can't reach.
2026-11-12 10:47:06 +05:00
HassanKhan b3860bf7d0 Commands: every angle and rotation param says which way it turns (#6340)
The params docs now state the direction (and the zero) of each angle or
rotation a command takes; behaviour is unchanged. Shape creation, text.create,
the grids, add-on shapes, saved views, Liquify, Puppet Warp pins, Mirror and
Radial Repeat and Vector Halftone turn clockwise; text character rotation,
gradients, the eraser tip and print screen angles turn counter-clockwise.

view.saved.new's rotation note changes its schema, so the API level goes to 3.

A test walks every command's params doc and fails when a param named like an
angle or rotation doesn't say clockwise or counter-clockwise.
2026-11-11 21:40:27 +05:00
dotCooCoo 156613941a Type: glyph bounds take in underline and strikethrough bars
With Measure Type by Glyph Bounds on, point type is measured by its
glyph outlines and its underline and strikethrough bars, as the canvas
draws them. A typed W or H gives what is drawn that size, and underlined
or struck-through spaces are measured by their bars instead of the em
box.

The texts now say that each point type object selected as an object
(not inside a selected group) is measured this way, that moved type
snaps by its ink box, and which Arrange Tools commands follow the
option: Swap Objects, Replace with Top Object, Set Size of Each and
Sort Objects. Arrange in Grid and Group Overlapping Objects keep
measuring visual bounds.
2026-11-09 21:53:22 -08:00
dotCooCoo a1949095c6 Type: an option fits a text object's bounds to its glyph outlines
Measure Type by Glyph Bounds (`typeGlyphBounds`, off by default) is in
Preferences > Type > Glyph Bounds and the Transform panel menu. With it
on, the bounding box, the Transform, Control bar and Properties X, Y, W
and H, `object.setBounds`, the transform tools' reference point and the
Arrange commands measure point type selected on its own by the ink of
its glyphs instead of its em box. A typed W or H scales the live type
until its ink has that size.

- The engine caches each type object's ink in text space with its
  layout bounds; the cache is not saved.
- Use Preview Bounds adds the characters' strokes, and type with
  geometry effects is measured as drawn. Skewed type is measured by its
  outlines.
- Type that draws nothing, area type, type on a path and type inside a
  selected group are measured as before. Align and Distribute keep
  following Align to Glyph Bounds.

Docs: docs/mcp.md, docs/control-protocol.md, docs/target-app-parity.md,
object.setBounds params text.
2026-11-09 21:07:55 -08:00
dotCooCoo f88815abd9 Merge main into fix/graph-series-object-opacity 2026-11-08 14:02:59 -08: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 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 b46cdc4e4d Isolation mode: Lock, Unlock All, Hide and Show All work on the isolated art
Squashed from #4849 onto main.
2026-11-01 01:21:53 +07:00
dotCooCoo a4ca347692 Shaper: dragging a shape out of a Shaper Group's bounds takes it out of the group
Squashed from #4415 onto main.
2026-10-29 15:16:17 +07:00
dotCooCoo dfe201dec3 Transparency: isolation mode and opacity mask editing can't be entered from each other
Enter Isolation Mode worked while an opacity mask was edited, and Edit
Opacity Mask and View Opacity Mask worked in isolation mode, so each
mode replaced the other's isolated art. In the reference app, isolation
mode can't be entered while a mask is edited, and mask editing can't be
entered in isolation mode.

object.isolate and perspective.editText, which shows type in isolation
mode, are now off while an opacity mask is edited, and a call returns
an error that ends "stop editing the opacity mask first". In isolation
mode transparency.editOpacityMask and transparency.viewOpacityMask are
off, and transparency.makeOpacityMask refuses one target, an object or
a layer, which it would take into mask editing; a call returns an error
that ends "exit isolation mode first". Make Opacity Mask with two
objects still masks one with the other. Pattern editing mode does not
count as isolation mode for these commands.

Object > Perspective > Edit Text, the canvas context menu and the
Transparency panel's menu and Make Mask button follow the commands'
enablement. A click or Alt-click on the mask thumbnail in isolation
mode shows the error and does not edit the mask. While a mask is
edited, the Contextual Task Bar leaves out Isolate, and the Properties
panel's Quick Actions leave out Isolate Group.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 11:20:08 +07:00
dotCooCoo 02f2dd8c5a Object: Unlock All and Show All with Shift+Alt act only within the selected object's group
Squashed from #4439 onto main.
2026-10-29 11:18:38 +07:00
dotCooCoo 7b36442f41 Keyboard Shortcuts: Distribute Spacing stays listed, its axis is optional
object.distributeSpacing already spaces horizontally without an axis; its params doc now says so, so the editor keeps listing it.
2026-10-29 10:13:23 +07:00
bflatastic c591331d65 Object: import the isolation predicates in menucmds.rs and object/commands.rs (#4299 made the imports explicit) 2026-10-29 10:13:22 +07:00
dotCooCoo a6a850868c Object: Lock, Hide, Unlock All and Show All are off in isolation mode
The reference app disables its Lock, Hide and Show All menus in
isolation mode. In VectorCraft every item of Object › Lock and
Object › Hide, Unlock All and Show All worked there.

In isolation mode, object.lock, object.lock.above,
object.lock.otherLayers, object.hide, object.hide.above,
object.hide.otherLayers, object.unlockAll and object.showAll are now
off. Their menu items are greyed out, and a call returns an error
that ends "exit isolation mode first". The Contextual Task Bar's
Lock button is greyed out too, and the Properties panel's Quick
Actions leave out Lock. Pattern editing mode and opacity mask editing do not count as
isolation mode for these commands. The check is outside_isolation in
cmd.rs, with has_selection_outside_isolation beside it.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-29 10:12:16 +07:00
Dylan M. Taylor 7043ef6f3d Extract geometry command helpers 2026-10-28 16:44:11 +00:00
aiongg 43ae75d4dc refactor(engine): move cmd/object.rs items to cmd/object/{align,arrange,bounds,commands,compound,props,shape,spans,transform}.rs 2026-10-26 22:01:25 +00:00