Commit Graph
1765 Commits
Author SHA1 Message Date
bflatastic 54b0c7266c Fix #4826: Artwork Cleanup's Join Point Text stacks one-line type into one object 2026-10-31 20:44:15 +07:00
bflatastic 672a5342a6 Fix #4817: Properties' Quick Actions has Blend Options for a selected blend with any tool 2026-10-31 19:44:50 +07:00
bflatastic 78a68bd8ec Fix #4835: Artwork Cleanup's Duplicate Objects finds type set twice in the same place 2026-10-31 19:43:17 +07:00
Don Omondi 1883e5342d PDF import: find installed fonts named with hyphens or a composite font's CMap
- A composite (Type 0) font is noted by its descendant CIDFont's BaseFont
  (ISO 32000-1 9.7.4.1), not its own BaseFont, which ends in "-" and the
  CMap name (9.7.6.1, e.g. Name-Identity-H); without one, the CMap name is
  taken off the end of the BaseFont.
- A font name's family is the longest part before a hyphen (or the comma of
  Arial,Bold) that names an available family, so Noto-Sans-Bold is Noto
  Sans, Bold and Noto-Sans-CJK-JP is Noto Sans CJK JP; a shorter family
  still matches when no longer one is available.
- A missing font is split only at a comma or before the first part that is a
  style word (Helvetica-BoldOblique); otherwise the whole name is its family
  (MS-PGothic is reported as MS PGothic, not MS).

Synthetic tests (no host fonts): Families::of builds the family list.

# Conflicts:
#	docs/file-format-parity.md
#	docs/gaps.md
#	docs/type-parity.md
2026-10-31 19:43:17 +07:00
Don Omondi 1679318034 Type: lam-alef highlight follow-up: optional features, all marks, exact ligature test (#394)
Highlight Alternate Glyphs no longer drops a lam-alef cluster's glyphs
outright: the ligature is clear when required shaping, or shaping with
liga left on (older fonts), gives it, so an optional feature such as
salt that changes it is highlighted again. is_lam_alef takes any
combining mark by Unicode general category (Arabic Extended-A/B/C
included) instead of a partial list. The test font maps the fatha to a
mark and skips marks in its ligature, so the mark-spanning test checks
the exact ligature glyph and cluster; it gains a salt lookup and test.

Also a one-line equivalent nonminimal_bool repair in pathops'
pathtools that strict Clippy needs on main.
2026-10-31 19:43:17 +07:00
Don Omondi 22b1c6bc2e Fix #3085: DXF LAYOUT objects write only the group codes the DXF Reference defines
The PLOTSETTINGS part of each LAYOUT wrote the paper image origin as a point
(148 and 158), but the origin is two values at 148 (x) and 149 (y), and 158 is
not a PLOTSETTINGS code. Strict readers such as Autodesk Fusion can reject the
file. The ezdxf re-save the reporter found Fusion accepts differs from our export in
these objects, not in the geometry.

- 148/149 for the paper image origin
- shade plot mode, resolution level and DPI (76/77/78) from DXF 2004
- plot flag 1024 (model type) on the Model layout
- the plot style ACDBPLACEHOLDER without a subclass marker

Test r2000_and_later_files_have_the_structure_cad_apps_require checks the
required sections and table entries, handles below $HANDSEED, references
that resolve, and LAYOUT group codes.

# Conflicts:
#	docs/file-format-parity.md
2026-10-31 19:43:17 +07:00
Don Omondi 7403003fb1 fix(eps): an envelope's contents being edited aren't read as art
An envelope whose contents are being edited is written the other way
round from one that isn't: its contents, a group on `%_` lines, then
its dictionary, which holds the mesh that shapes them. Only a group of
meshes was left out before an envelope's dictionary, so those contents
were read as art and their undistorted shapes drew over the distorted
art that follows on plain lines (and that the page draws).

The group on `%_` lines before an envelope's dictionary is now left
out whatever it holds; text in it stays as hidden text, as the
dictionary's own source text does.

# Conflicts:
#	docs/file-format-parity.md
2026-10-31 19:43:17 +07:00
Don Omondi 5b15b3f56b fix(eps): a transparency set in a dictionary's art stays after it
Art inside a dictionary in the editing data, such as an area text's
frame (`/ConfiningPath`) or a mask's art, can set a transparency
(`Xy`). The writer goes on from it: the objects after an area text
whose frame sets one have no `Xy` of their own. The reader dropped
that state when the dictionary closed, so those objects took the
transparency before the dictionary instead; in a user's file a Lighten
glow before an area text made everything after it fade into the light
background.

The last transparency the art inside a dictionary sets is now the
current one after it (and the enclosing dictionary's). Dictionaries
outside the layers (the setup's styles) are left as they were.

# Conflicts:
#	docs/file-format-parity.md
2026-10-31 19:43:17 +07:00
Don Omondi 75d2736a2a fix(eps): area type's first line goes where the file lays it out
Area type made from the editing data's text document was laid out with
its first baseline the font's ascent below the frame's top. The text
document keeps where each of its lines starts, and the file's page draws
them there: for some fonts the first line sits well above the font's
ascent (Oswald's at about its cap height), so headings came in lower
than on the page and the layers were taken to differ from it.

When the file's first line is more than half a point from where it is
laid out here, the first baseline is now fixed where the file has it
(First Baseline: Fixed), measured in the text document's own frame so a
copied object's type moves with its frame.

# Conflicts:
#	docs/file-format-parity.md
2026-10-31 19:43:17 +07:00
Don Omondi 3602bd6ea3 fix(ai-import): type from the text document takes its character style's attributes
Type made from an Illustrator file's text document took each character
attribute its run doesn't set from the document's base attributes, not
from the character style the run names ([Normal Character Style] or
another of the file's). Where the two differ the type came in wrong: a
file whose base fill is white and whose Normal Character Style is black
came in with its text white, invisible, so the layers differed from the
page wherever the page's own type didn't stand in for it.

A run now takes its own attributes, then its character style's (and the
styles that one is based on, up to 16), then the document's.
2026-10-31 19:43:17 +07:00
Taha-Mahmoodi f9a523b55e Docs: Snapping is no longer a main gap in the parity table (#2530)
The tangent and perpendicular case is done for every tool the public pages name; its evidence stays in the revision row and in gaps.md and ui-parity.md.
2026-10-31 19:43:17 +07:00
Taha-Mahmoodi 63b685758f Snapping: a line end dragged with Direct Selection snaps square to straight paths and tangent to curves (#2530) 2026-10-31 19:43:17 +07:00
Taha-Mahmoodi 811ba8727b Fix #3604: automation file access refuses an NTFS alternate data stream name on Windows
With write root ...\out, a save to ...\out\x.svg:evil was accepted: it stays inside the root, but writes a hidden stream no folder listing shows. A ':' in any name after the drive is now refused with the device names. The check is a plain name test, so it is covered on every platform; the check-then-open race (item 1 of the report) is a documented limitation and is not touched.
2026-10-31 19:43:17 +07:00
Taha-Mahmoodi f65d28378f Fix #995: a width-profile stroke keeps its shape when the view zooms out
The canvas keeps a hairline visible by raising a stroke's weight to half a device pixel. A width profile multiplies that weight, so a 1 pt stroke with a 6x width point swelled to twice its size at 25% zoom and shrank back on zooming in. The minimum now goes to the profile's widest point instead; plain strokes are unchanged.
2026-10-31 19:43:16 +07:00
Taha-Mahmoodi 59eb658fd7 Fix #2651: Grid Repeat Options has a Preview checkbox
The grid options' public page lists a Preview option: the repeat on the canvas follows the fields while the dialog is open. Object > Repeat > Options had none, so a change showed only after OK. Now a Grid Repeat's dialog has the checkbox: Cancel puts the original back without a history step, OK keeps the previewed values as one undo step. Radial and Mirror Repeat Options are left as they are, since their public pages list no Preview.
2026-10-31 19:43:16 +07:00
Don Omondi 9259434a89 SVG export: a gradient mesh patch is cut no finer than its colour changes
Each patch of a gradient mesh was cut into 8 x 8 flat quads for SVG export,
Object > Expand and the other outputs that cannot shade a mesh, whatever its
colours, so a patch of one colour became 64 identical pieces. Neighbouring
quads are now joined into square blocks wherever the colour changes by no
more than about one 8-bit step across the block; the block's outline runs
through its quads' corners, and a patch that folds over itself is not joined.
2026-10-31 19:43:16 +07:00
Taha-Mahmoodi a1a3a99104 Fix #3592: a gradient mesh from a file is budgeted at about a million quads
A mesh read from a file can have any number of patches, and the view any zoom: a 150 x 150 mesh from a 3 MB file exported at 20x asked for about 23 million quads (2 GB), and the command's own cap of 50 rows and columns does not apply to a loaded one. One tessellation now makes at most 1,048,576 quads, the subdivision per patch giving way before that, and a mesh with more patches than that is malformed, like a point count that does not fit.
2026-10-31 19:43:16 +07:00
dotCooCoo b13b3260cd Keyboard Shortcuts: a shortcut on the Turkish Q quotation-mark key shows " and runs
Squashed from #4851 onto main.
2026-10-31 19:43:16 +07:00
dotCooCoo c15874ba6e Perspective Selection: Shift constrains each object in its own plane
perspective.move takes constrain: true instead of a plane-space
direction. For each object, the command snaps the move to the nearest
axis or 45-degree diagonal of that object's own plane, so a selection on
several planes keeps every object on a line of its plane. The tool sends
the raw pointer with the flag.

On a diagonal, Snap to Grid now moves along the diagonal by the nearer
per-axis correction, so that edge lands on its gridline.
2026-10-31 19:43:16 +07:00
dotCooCoo 9f64452303 Perspective Selection: Snap to Grid keeps a Shift-constrained move on its axis or diagonal
perspective.move takes an optional constrain: [dx, dy], a plane-space
direction. For an in-plane move, Snap to Grid's correction is projected
onto that direction, so a move the Shift key constrains to a plane axis
or a 45-degree diagonal stays on that line when an object edge lies near
a gridline. The Perspective Selection tool sends the direction for
Shift moves and copies. Moves without the param behave as before.
2026-10-31 19:43:16 +07:00
dotCooCoo f677c60aba Perspective Selection: Shift constrains a move to the plane's axes and diagonals
Holding Shift while dragging objects with the Perspective Selection tool
snaps the move, in the plane's own coordinates, to the nearest plane axis
or 45 degree diagonal. This applies to plain moves and to Alt and
Ctrl+Alt copies. The preview, the final move and the measurement label
use the snapped point. Pressing or releasing Shift, pressing 5 and
pressing 1 to 4 during the drag recompute the preview from the pointer;
a move perpendicular to the plane is not constrained.
2026-10-31 19:43:15 +07:00
dotCooCoo baaffd63e7 Blob Brush: Tool Options set the brush's Angle and Roundness
Blob Brush Tool Options gain Angle (-180 to 180 degrees, 0 by default)
and Roundness (0 to 100 percent, 100 by default), with a preview of the
tip and three dabs; a drag in the preview square sets the Angle. The
elliptical tip keeps its angle on the page along a stroke, a 0 percent
tip is drawn 0.1 percent as wide as it is long, and Size set to
Pressure still varies its size. path.blob takes angle and roundness,
and both values are kept with the tool's options.

While a non-round tip drags, the Blob Brush shows the outline of the
area it covers with its length label, and an Alt drag that smooths
shows the Smooth tool's thin line.
2026-10-31 19:43:15 +07:00
dotCooCoo d318a77560 DXF export: Alter Paths for Appearance outlines only strokes a CAD line can't draw
Alter Paths for Appearance wrote every stroke as its filled outline, so a
1 pt circle became two circles and a hatch, and an open arc became a
closed outline and a hatch: two cut lines where a CAM program expects
one. The option now outlines only the strokes a line can't draw: the ones
Preserve Appearance outlines, strokes wider than the widest lineweight
(2.11 mm, to the hundredth), and every stroke in R13 and R14, which have
no lineweights. Other strokes stay CIRCLE, ARC, SPLINE and LWPOLYLINE
entities with their lineweights; R12 keeps them as POLYLINEs with their
width.

A dashed stroke whose offset starts part way into its pattern is now
outlined with Preserve Appearance and with Alter Paths: a linetype always
starts at the start of its pattern, so the dashes were written in the
wrong place.
2026-10-31 19:43:15 +07:00
dotCooCoo b493e601a9 Docs: leave the DXF row of file-format-parity.md to #4796
The ELLIPSE note stays in docs/gaps.md; the open #4796 rewrites the same file-format-parity.md row.
2026-10-31 19:43:15 +07:00
dotCooCoo d0a903d5d7 DXF export: ellipses and unevenly scaled circles are written as ELLIPSE
A closed path of four cubics that is the four-cubic circle under an
affine map (an ellipse, or a circle scaled out of proportion) is written
as a native ELLIPSE in R13 and later, with its center, major axis and
minor to major ratio. The check maps the path back onto the unit circle
and runs the existing circle recognition on it. R12 keeps the existing
fallback, and ellipses with a ratio under 1e-6 stay splines. The ratio
and end parameter are written in full so that a thin ellipse keeps its
size and a whole turn reads back closed.

Part of #1299.
2026-10-31 19:43:15 +07:00
dotCooCoo 06e8d711ae DXF export: an open path of one straight segment is written as a LINE
An open path with a single straight segment was written as a two-vertex
LWPOLYLINE (POLYLINE before R14). It is now a LINE entity from its start
to its end point. A stroke with a weight in R12, R13 and R14 keeps its
polyline, since a LINE has no width. Closed paths and paths with more
than one segment are unchanged.

Part of #1299.
2026-10-31 19:43:15 +07:00
dotCooCoo ab2426ca15 Swatches: the delete prompt for several swatches uses each language's plural forms
The confirmation for deleting several swatches and groups now goes
through i18n::tn, as the Graphic Styles prompt does, and each catalog
gives the count-dependent forms in an @plural row.
2026-10-31 19:43:15 +07:00
dotCooCoo f6b79c3f50 Docs: the type.underline line in docs/mcp.md no longer repeats the end of the sentence before it 2026-10-31 19:43:14 +07:00
dotCooCoo 8579aa07e3 Shortcuts: in the web build a key-position shortcut uses the key of the same press
eframe's web build sends a keystroke's text before its key press. On a
layout without Latin letters, the one-key shortcuts paired each text with
the last key press before it, so in the web build a lone keystroke had no
key and ran no shortcut, and a second keystroke in the same frame used
the first one's key.

Each text now takes the press right before it, unless an earlier text in
the frame took that press, and otherwise the press right after it. The
one-key shortcuts and the shortcut names a tool sees while it is busy use
the same pairing. The desktop order (key, then text) pairs as before.
2026-10-31 18:44:50 +07:00
aiongg ffad6cc20e docs: tidy wording 2026-10-31 04:25:47 +00:00
aiongg 8ae1f7dae6 docs: tidy agent, contributor and asset docs 2026-10-31 04:17:23 +00:00
dotCooCoo 462b7cca15 Image Trace: Document Library fills are not linked to swatches
With Document Swatches as the library, traced fills and strokes take the
library color without a swatch link. Global, spot and tint swatches no
longer link the trace, so editing a swatch later leaves the trace
unchanged, and swatch order no longer decides whether a fill is linked.
Each region still takes the nearest library color, and a tint traces at
the color the tint swatch shows.
2026-10-31 07:17:08 +07:00
dotCooCoo 830cbbcecb Tabs: the ruler's indent markers set the first-line and left indents
The Tabs panel's ruler shows an upper marker at the first line's position
(left indent plus first-line indent) and a lower marker at the left
indent. Dragging the upper marker sets the first-line indent. Dragging the
lower marker sets the left indent and keeps each paragraph's first line
where it was; Ctrl-dragging it (Command on macOS) moves both markers.
Marker drags land on whole points, or on ruler ticks with Snap to Unit or
Shift, and each release is one undo step through text.setFormat. With a
marker selected, the X (or Y) field shows and sets its position.

When the touched paragraphs have different left indents, only the upper
marker is shown, and its position applies to every touched paragraph.
2026-10-31 07:17:04 +07:00
bflatastic 79f7b393e9 Add-ons: Path Precision Tools — Shared Edge Merge
Path Precision Tools gains the Shared Edge Merge Tool, kept out of the
toolbars (All Tools drawer and Object › Plug-ins › Path Precision Tools,
no shortcut), and Keep Shared Points Together:

- Shared Edge Merge Tool (sharedEdge): over two paths touching at two
  coincident anchors (tolerance 0 to 3 pt) hovering shows the two
  stretches and the merged edge; a click replaces both with it, half way
  between them, or following the upper (Shift) or lower (Alt) path. Both
  paths stay closed or open, anchors either stretch has inside are
  matched on the other, one undo step.
- Making ends: near anchors meet on a click and an anchor one path lacks
  is added to match; Shift+Alt asks for this inside a stretch.
- Keep Shared Points Together: an option that makes Slide Anchor Along
  Path, Extend Path and Set Anchor take coincident anchors along. Nothing
  else in the app changes.
- Shared Edges section in the Anchor Inspector: brush diameter,
  coincidence and the option.
- Commands addon.pathtools.mergeEdge and movePointsTogether, params
  validated and covered by the command sweep.
- Cursor stand-in, catalog rows in every language, docs and tests.
2026-10-31 07:16:22 +07:00
dotCooCoo 82025e57b5 Live Paint: Alt-click and Alt+Shift-click with the Bucket sample with the Eyedropper
With the Live Paint Bucket, Alt-click on vector art samples its fill,
stroke and stroke weight into the paint defaults, and on a placed image
it samples the pixel as a solid fill with no stroke. Alt+Shift-click
samples only the color under the pointer, including an intermediate
gradient color or image pixels, into the active fill or stroke. Neither
click paints or changes the selection or selected art, and the next
Bucket click paints with the sampled paint. While Alt is held, the
Bucket shows the Eyedropper cursor and no face or edge highlight.

appearance.copyFrom takes `defaultsOnly: true` to update only the paint
defaults, and paint.sampleColor takes `clearStroke: true` to clear the
stroke default after an image sample into the fill.
2026-10-31 06:28:46 +07:00
Don Omondi de703fe722 M5: opaque knockout fills draw once in hard-edge and supersampled raster export
A knockout element with one opaque Normal solid fill (a path or
compound, no mask, effects or isolation) is drawn once under
AntiAlias::None, including the internal hard-edge frame of Art
Optimized supersampled exports, instead of being erased and added back
through per-element backdrop layers. Analytical antialiasing keeps the
existing compositor and rounding.

Exact-pixel tests compare against the general knockout path for paths
and compound holes across precision, supersampling, translucent parents
and copied backdrops, and check that the backdrop rasters are skipped;
translucent fills keep their knockout compositing.

# Conflicts:
#	docs/roadmap.md
#	docs/target-app-parity.md
2026-10-31 06:28:42 +07:00
dotCooCoo 51b6bbdd17 Paintbrush: Alt held at the press smooths a selected path
With a path selected that the Smooth tool can change, Alt held at a
Paintbrush press now switches the drag to the Smooth tool: it smooths the
selected paths under the drag with the Smooth tool's radius and Smooth Tool
Options' Fidelity, and the cursor shows the Smooth tool before the press.
Alt pressed after a stroke begins still closes the path on release. With no
such path selected (nothing, only text or an image, or only a two-point
line), Alt at the press draws the closed stroke as before.

The Paintbrush no longer reads the Pencil's "Alt key toggles to Smooth Tool"
setting: its Alt close and Alt smoothing do not depend on it.
2026-10-31 06:11:00 +07:00
bflatastic e13c4bc9d0 Add-ons: Path Precision Tools — live path effects 2026-10-31 06:10:47 +07:00
Don Omondi b0cc17343e fix(pdf-import): take a group's knockout and isolate flags from the interpreter
The import read each form's /Group /I and /K from the file in order and
matched them to the transparency groups the interpreter pushed. The
interpreter draws a group that adds nothing (full opacity, Normal, no
mask, neither flag) straight onto its parent without pushing it, so every
group after one took another group's flags. Blend steps written as a
knockout group of falling opacity then painted over each other and drew
as solid dark shapes instead of light rings.

The interpreter already reports the flags right after pushing a group
(set_knockout, set_isolated); the import now uses those and drops the
file-order list. That list was capped at 10,000 entries, past which a page
failed to import; that limit goes with it.
2026-10-31 05:27:13 +07:00
Don Omondi d4745fe046 fix(eps): a layer's state after its last blend stays the layer's
#4757 gives a blend the Xy written after its record. When the blend is a
layer's last object, the layer's own state block (Xy, Xd, 7 () XW, LB)
went to the blend instead, and the layer stayed opaque. The blend's state
is now tentative like a mesh's (#4748): its own 6 () XW confirms it, the
layer's LB gives it to the layer and the blend keeps what it had.

Also records the .ai/EPS audit fixes under G9, the File formats row and M4.
2026-10-31 05:11:04 +07:00
Don Omondi aa6a960062 fix(ai-import): compare a PDF of some artboards on the artboard its page shows
A PDF saved with Illustrator editing data for only some of its artboards
has pages for those artboards, while the editing data keeps them all. The
layers were compared with the first page on the first artboard, so a page
showing a later artboard never matched and the file came in as its PDF
part, without its layers.

With fewer pages than artboards, the first page is now taken to be the
artboard of its size whose art draws most like it (up to 16 weighed), and
the pages' type goes to that artboard and the ones after it. All the
artboards still come in, and the comparison still decides whether the
layers are used.
2026-10-31 04:55:14 +07:00
Don Omondi c4d2480132 .ai/EPS import: a blend takes the transparency written after its record
Squashed from #4757 onto main.
2026-10-31 04:39:05 +07:00
Don Omondi a1fc3cfdb1 fix(eps): a masked gradient mesh takes the transparency after its mask
A gradient mesh with an opacity mask has its own state (`Xy`) after the
mask's dictionary, not right after its `/End X!`. The operators of the
mask's art, on `%_` lines, cleared the flag that says a mesh just ended,
so the state was read as the next object's and each masked mesh in a
run drew with the blend mode of the one before it.

The flag now goes back to what it was when a dictionary opened once it
closes, as `after_object` does.
2026-10-31 04:21:56 +07:00
bflatastic c9dc4fa857 Add-ons: Path Precision Tools — Corner Tool and Slide Anchor
Path Precision Tools gains two tools, kept out of the toolbars (All Tools
drawer and Object › Plug-ins › Path Precision Tools, no shortcuts):

- Corner Tool (cornerTool): editable corners on any path through the
  existing Live Corners. Hover shows an eligible anchor, a click cuts a
  corner with the tool's radius and kind, a drag sizes it (Shift: whole
  values), a corner's marker selects it and loads its values, resizes it
  and removes it at 0 or on a double-click; a corner never grows past
  what fits; an Alt-marquee cuts every eligible anchor inside.
- Corners section in the Anchor Inspector: radius, kind, selected count,
  Apply to Selected Anchors.
- Slide Anchor Along Path (slideAnchor): a drag runs an anchor along its
  curve, the neighbouring segments refitted by the keep-shape kernel;
  Shift snaps where the tangent is a multiple of 45° from the constrain
  angle.
- Commands addon.pathtools.cornerSet, cornerRemove and slideAnchor, one
  undo step each, params validated and covered by the command sweep.
- Cursor stand-ins, catalog rows in every language, docs and tests.
2026-10-31 04:21:26 +07:00
Don Omondi ff1f721013 fix(eps-import): keep a layer's opacity when its state block has the stroke style
A layer's own state block (Xy, Xd, 7 () XW before LB) can have the
stroke style (J j w M d XR) between its Xy and Xd. Read as the art moving
on, it dropped the layer's opacity, so a layer at 17% drew opaque and the
file came in as its page. The stroke style now keeps the pending layer
state, and the state a mesh before it had; an object's own 6 () XW block
still isn't the layer's.
2026-10-31 04:02:35 +07:00
dotCooCoo 6a034c77c3 Transform tools: backquote drag transforms only the pattern
Holding backquote while dragging with the Selection tool (move, bounding-box
scale or rotate) or the Rotate, Reflect, Scale or Shear tool applies the drag
to the selected objects' pattern fills and strokes and leaves their geometry
in place. The key state at release decides the result: the key may be pressed
after the mouse button goes down, and releasing it before the button comes up
commits an ordinary transform. Objects without pattern paint do not move.

PointerEvent gains a `backquote` flag (false when absent). The desktop canvas
reads it from the held key on every pointer event, and `ui.pointer` and the
`pointer_gesture` tool accept it per event or as a default for the gesture.
2026-10-31 03:34:55 +07:00
dotCooCoo 26ac7799e7 Shortcuts: Shift+Comma and Shift+Period also apply the last color and gradient
Apply Last Color keeps `,` and also gets `Shift+,` as a default key;
Apply Last Gradient keeps `.` and also gets `Shift+.`. The keymap
catalog takes the extra defaults from a small alias table, the
Keyboard Shortcuts dialog lists every default key of a row, and reset
restores both.

A shifted punctuation chord that the active keymap binds now runs from
its key press, once per press, so a user binding such as `Shift+;`
works and layouts where Shift+Period types another character still run
the bound command. Text editing still types the characters.

The toolbar tips read "Color (, or <)" and "Gradient (. or >)", with
rows in every catalog.
2026-10-31 03:34:51 +07:00
dotCooCoo fc7ef3102f Object: Cmd/Ctrl+Alt+Shift+2 locks inside clip groups and isolation, with no menu item
object.lock.unselected is now reached by its key and as a command only:
the Object > Lock > Unselected Artwork menu item is removed, and the
command stays in the registry, the shortcut editor and automation.

In a partly selected clip group or compound path it now locks the
unselected members, the clipping path included, and leaves the container
and the selected members unlocked. It locks unselected guides while Lock
Guides is on. Hidden art and art on a locked layer stay unlocked, and a
selected layer's art counts as selected.

With a selection in isolation mode the command is enabled and locks only
the unselected art inside the isolated group. The other Lock and Hide
items keep their isolation behavior.

Lock and Hide still share one selector. A lock flag on it selects the
clip group, compound path and guide cases above; Hide > Unselected
Artwork keeps its behavior, and a test covers both directions.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-31 03:34:47 +07:00
dotCooCoo a372d39a31 Object: Cmd/Ctrl+Alt+Shift+2 locks every unselected object
The reference app locks all deselected artwork on Cmd/Ctrl+Alt+Shift+2.
VectorCraft had no command for it: Object > Lock held Selection, All
Artwork Above and Other Layers.

The new command, object.lock.unselected (Object > Lock > Unselected
Artwork), locks in one undo step the objects that Hide > Unselected
Artwork hides: every object that Select All takes and that is neither
selected nor holds a selected object. It returns the count. Hidden
objects stay unlocked. The selection stays as it is, Unlock All unlocks
the objects again and selects them, and with nothing to lock the
command records no undo step. Both commands now share one function,
which locks or hides the objects that the existing unselected helper
returns.

In isolation mode the menu item is disabled, and the command returns
the error "not available in isolation mode" that Hide > Unselected
Artwork returns there, and changes nothing.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-10-31 03:34:47 +07:00
Don Omondi 7591e35345 docs: record the .ai/EPS import fixes from a user's file audit
Adds the evidence and revision rows that target-app-parity.md and
roadmap.md expect for the .ai/EPS import changes of 2026-10-30 (#4708,
#4664, #4723, #4742, #4658, #4727, #4738, #4744, #4748, #4743). Scores
and estimates unchanged.
2026-10-31 03:34:43 +07:00