Commit Graph
8770 Commits
Author SHA1 Message Date
Don Omondi fc099e849c Direct Selection: with Snap to Grid, a dragged straight segment lands its anchors on the grid (#3835)
A straight segment dragged with Direct Selection or Group Selection snapped the
point it was pressed at to a grid intersection, leaving both of its anchors off
the grid. With Snap to Grid or Snap to Pixel on, the box round the moved anchors
now lands an edge on a gridline on each axis, as a moved object's does; Shift
keeps the move on its line. A dragged anchor still lands on an intersection.
2026-11-07 00:17:16 +07:00
Don Omondi 591fc9b21e Paste: cells copied from a spreadsheet paste as a table of type over gridlines
Tab-separated rows with the same number of cells (quoted cells too)
become a group of point type, one per cell, in columns and rows over
0.5 pt gridlines; other text pastes as before. Fixes #5296.
2026-11-07 00:17:15 +07:00
dotCooCoo 42fe0bead3 Appearance and Eyedropper: reading an object's paint does not measure its bounds
The Eyedropper, the Live Paint check for paint to sample, the Appearance
panel's Characters chips and the colors the Libraries panel adds from
the selection found the paint behind the Fill or Stroke proxy through
Node::proxy_paint, which measures the object's geometric bounds. They
now read it with Node::proxy_paint_only.

- Eyedropper: the test for an empty fill reads the paint without
  measuring. A sample measures the object only for a gradient or a
  pattern, whose color depends on the point; a solid color gives its
  color at once.
- Live Paint: the check for paint to sample reads the paint without
  measuring.
- Appearance panel: the Characters row's two chips read the paint
  without measuring.
- Libraries: adding a color or a pattern from the selection reads the
  paint without measuring; a gradient is still measured for its
  placement.

The paints and colors are the same as before. On an open path of
200,000 anchors, the Live Paint check and the Eyedropper's sample for a
point inside it take 0.004 ms together instead of 26.0 ms in a release
build.

Docs: docs/target-app-parity.md.
2026-11-07 00:17:15 +07:00
Don Omondi b8ec5f4b23 Type: Alt + numeric-keypad codes type their character on Windows; type.insert takes a code (#5108) 2026-11-07 00:17:15 +07:00
bflatastic 7913c481aa Docs: keep the effects status entries 2026-11-07 00:17:14 +07:00
Don Omondi 3f7f743ddb 3D effects: Extrude & Bevel, Inflate and Rotate apply to groups
A 3D effect on a group or layer builds a solid from every path,
compound path and type in it, all turned about one shared axis, as the
public docs describe for groups. Fixes #4506.
2026-11-07 00:17:14 +07:00
Don Omondi 6160d0bd45 Snap to Glyph: glyph bounds give corners and turn with rotated type (#5112) 2026-11-07 00:17:13 +07:00
Hamza 9916857dba Type: pin that a Type-range paste into new point type keeps its formatting
#5929 reports that a styled word copied with the Type tool loses its
formatting when pasted into a new point type object made by a Type
tool click (placeholder text selected): on 0.21.1 the Copy left plain
text on the system clipboard, so the paste could not match it with the
copied runs. #5636 (on main since 0.21.1) publishes the copy through
the clipboard publisher, and the paste keeps the runs. This test pins
that case end to end through the app: copy, two clicks (end editing,
place new type), paste, then font, size and colour of the new text.

Closes #5929
2026-11-07 00:17:12 +07:00
Don Omondi 5019846d08 Perspective grid: a grid dragged off its preset reports no preset name
perspective.grid.get reports define.name only while the grid still has
the preset's fields, as Define Grid's Preset menu shows [Custom]. Part of #5248.
2026-11-07 00:17:12 +07:00
Cursor AgentandAdithya Shankaran 4e11389bf0 Don't write over a library file that changed since it was saved
The name remembered for a user library file stays only while the file still
holds the bytes that were written. A file a device name could make, which can
no longer be read, is kept too, and the save goes to a new file.

Co-authored-by: Adithya Shankaran <adikshan11@users.noreply.github.com>
2026-11-07 00:17:12 +07:00
Adithya Shankaran 850fd620f9 Don't replace an .ase file whose owner isn't known
After a restart an .ase file called COM¹- could have been saved as COM¹ or as
COM¹-, and the same goes for its numbered files. Such a file is kept until it is
saved here, so a library named like that gets a new file, once per run. Other
names go on replacing their own file.
2026-11-06 23:05:29 +07:00
Adithya Shankaran a17efec894 Remember the name a library file was saved under
An .ase file can't say whose it is, so without this COM¹ saved after COM¹- wrote
over it. The app now remembers while it runs. After a restart COM¹ gets a new
file, which costs a copy and loses nothing.
2026-11-06 23:05:29 +07:00
Adithya Shankaran 857ba3972b Don't copy a library on every save when its format keeps no title
An .ase file reads its name from the file name, so COM¹ saved again looked like
another library and got a new numbered file each time.
2026-11-06 23:05:29 +07:00
Don Omondi 6537396ee0 Effects: a Transform effect's copies of a filled and stroked path stack one above another (#5920)
A path whose fills and strokes stack (a fill and a stroke, several of
either, an even-odd fill, or a partly transparent or blended one) drew
its Transform effect's copies as one path, so every copy's stroke lay on
top of every copy's fill. It now draws each copy as an object of its own
above the one before, as Expand Appearance makes them.

Fixes #5920
2026-11-06 23:04:56 +07:00
jayzed80andClaude Opus 5.5 7d465d4fa3 fix(text): a gutter too huge to step past no longer stalls area type layout
Past a gutter of 1e300 a step no longer moves the baseline, so every cell of
a 100 x 100 frame was searched for all MAX_STEPS steps: over 40 s per layout.
AreaOptions::gutter has no limit, so a saved file can do this.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 23:04:37 +07:00
Hamza b474525e4b Find Whole Word: a change of style inside a word is not a word boundary
Find and Replace matched each style run on its own, and the whole-word
test looked only at the characters inside the run, so a run's end read
as a word boundary: with cat coloured red in catfish, a Whole Word
search for cat replaced it. The test now looks past the run's ends at
the characters next to it in the neighbouring runs. Matches still stay
inside one run, as the command documents.

Fixes #5901
2026-11-06 23:04:21 +07:00
Hamza d316edaad9 Find and Replace: type inside a locked or hidden group is left alone
all_texts walked every node of a visible, unlocked layer and checked
only each text object's own lock and visibility, so a text object that
was itself shown and unlocked inside a locked or hidden group was found
and replaced. It now stops at a hidden or locked group, as it stops at
a hidden or locked layer: Find and Replace and Find Next with no ids
leave that type alone, however deep the group is.

Fixes #5900
2026-11-06 23:04:06 +07:00
Don Omondi f482c9c243 Drop Shadow: a swatch beside Color opens the Color Picker (#5364)
Squashed from #5918 onto main.
2026-11-06 23:03:56 +07:00
Don Omondi 6725f24a80 Path booleans: check the windings against the operands' areas and resolve the operands when they don't add up (#5478) 2026-11-06 23:03:25 +07:00
FredApps 36ef34dfdd Merge pull request #5923 from storytold/house-rules
Copy the shared house rules into AGENTS.md
2026-11-06 14:58:56 +01:00
FredApps aabefa3a20 Copy the shared house rules into AGENTS.md.
The blocks come from craft-contrib at dde09ea31e2e457f5b4653a6e76f7cdf55944bdf. CLAUDE.md imports AGENTS.md. The house-rules workflow checks the copy.
2026-11-06 11:50:02 +01:00
BFlat f3d9970f69 Merge pull request #5916 from mockydevs/feat/effect-dialog-spinners
Drop Shadow and Outer Glow: spinner arrows step Opacity, the offsets, Blur and Darkness (#5367, #5368)
2026-11-06 18:27:56 +08:00
BFlat 278c8de572 Merge pull request #5915 from Silvertree2010/fix/5902-cross-document-paste-loses-a-sym
Keep a symbol's options when pasting it into another document
2026-11-06 18:27:41 +08:00
Don Omondi f7135db6e9 Drop Shadow and Outer Glow: spinner arrows step Opacity, the offsets, Blur and Darkness (#5367, #5368) 2026-11-06 17:09:24 +07:00
NetterSilverandClaude Opus 5.5 a76e157de7 Keep a symbol's options when pasting it into another document
Fixes #5902

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 17:08:54 +07:00
BFlat e83bfa5fa1 Merge pull request #5914 from adikshan11/fix/library-file-name-collision
Keep the other library when two names share a file name
2026-11-06 18:04:04 +08:00
Adithya Shankaran 0864db9494 Keep the other library when two names share a file name
A library called COM¹ is saved as COM¹-, which can be the file of a library
really called COM¹-, and the numbered file one of them then gets can be asked
for by a third name. Saving one replaced the other. Each now gets a free file
name, and saving it again goes back to that file.
2026-11-06 16:52:05 +07:00
BFlat 85978cc2e4 Merge pull request #5913 from mockydevs/fix/svg-filter-mask-regions-5876-5875
SVG import: filter and mask regions clip what they declare (#5876, #5875)
2026-11-06 17:51:53 +08:00
Don Omondi f08381df8d SVG import: filter and mask regions clip what they declare (#5876, #5875)
Squashed from #5913 onto main.
2026-11-06 16:39:04 +07:00
BFlat 9195f43901 Merge pull request #5910 from mockydevs/feat/stroke-weight-shortcuts
Stroke Weight Up and Down: Cmd/Ctrl+Alt+. and , step the selected strokes' weight (#5797)
2026-11-06 17:31:49 +08:00
Don Omondi 74b5966bbd Stroke Weight Up and Down: Cmd/Ctrl+Alt+. and , step the selected strokes' weight (#5797) 2026-11-06 16:19:37 +07:00
BFlat f4b56474d4 Merge pull request #5909 from mockydevs/fix/svg-blur-linearrgb-5877
SVG import: Gaussian blurs keep color-interpolation-filters; Gaussian Blur can blur in linear light (#5877)
2026-11-06 17:19:02 +08:00
Don Omondi 41ceaadc7e SVG import: Gaussian blurs keep color-interpolation-filters; Gaussian Blur can blur in linear light (#5877) 2026-11-06 16:05:55 +07:00
BFlat 702f4100fd Merge pull request #5908 from mockydevs/feat/pdf-export-url-links-5785
PDF and .ai export: objects' URLs become clickable links (#5785)
2026-11-06 17:01:56 +08:00
Don Omondi dbbe8a9298 PDF and .ai export: objects' URLs become clickable links (#5785)
Each visible object with a URL (Attributes panel) is written as a Link
annotation with a URI action over its bounds on the page, trimmed to its
clipping groups. Hidden objects, non-printing layers and printed sheets get
none; PDF/X files leave them out with a warning. URIs are percent-encoded
to 7-bit ASCII.
2026-11-06 15:48:02 +07:00
BFlat a0d496251a Merge pull request #5906 from dotCooCoo/fix/legacy-ai-colorized-images
Legacy .ai export: black-and-white colorized images save as image masks
2026-11-06 16:47:09 +08:00
BFlat 8dc5da6d1f Merge pull request #5905 from mockydevs/fix/svg-gradient-linearrgb-5878
SVG import: gradients with color-interpolation="linearRGB" mix their stops in linear light (#5878)
2026-11-06 16:46:52 +08:00
BFlat 54c975a085 Merge pull request #5903 from dotCooCoo/fix/ai-swatch-name-collisions
.ai import: a pattern or color named as another swatch keeps its swatch
2026-11-06 16:46:34 +08:00
BFlat 543762c599 Merge pull request #5904 from mockydevs/fix/blend-spine-review
Blend spine: moveAnchor refuses `with` alongside `handle`; spine built once per overlay and drag
2026-11-06 16:46:18 +08:00
dotCooCoo d58d47312f Legacy .ai export: black-and-white colorized images save as image masks
A colorized image whose pixels are all black or white (or clear) is
written as a 1-bit image mask (ImageMask 1): its color as the fill, a 0
bit for each black pixel and a 1 bit for each white or clear one. The
legacy reader opens it colorized again with the same clear pixels, so
the engine no longer flattens or omits it. Other colorized images are
written with their color in their pixels, over white, with the note
for transparent images.
2026-11-06 15:33:35 +07:00
Don Omondi 427ec0017c SVG import: gradients with color-interpolation="linearRGB" mix their stops in linear light (#5878) 2026-11-06 15:33:02 +07:00
dotCooCoo 968bf1dc48 .ai import: a pattern or color named as another swatch keeps its swatch
Squashed from #5903 onto main.
2026-11-06 15:33:00 +07:00
Don Omondi 149eee2c70 Blend spine: moveAnchor refuses with alongside handle; spine built once per overlay and drag
object.blend.spine.moveAnchor now refuses any supplied `with` (even an
empty list) together with `handle`. Direct Selection builds the blend
spine once when drawing the picked points and once per drag preview,
instead of once per picked point. Part of #5285.
2026-11-06 15:32:52 +07:00
BFlat 07c814597d Merge pull request #5899 from dotCooCoo/fix/tab-stops-string-params
Reject invalid Tab Stop string parameters
2026-11-06 16:32:38 +08:00
BFlat 5788e043d9 Merge pull request #5828 from mockydevs/feat/f2-rename-5324
Layers: F2 renames the selected layer, group or object (#5324)
2026-11-06 16:32:21 +08:00
dotCooCoo 8f81e142a5 Reject invalid Tab Stop string parameters 2026-11-06 15:20:17 +07:00
Don Omondi 00b09002cf Layers: Rename opens the selected layer, group or object's name field (#5324) 2026-11-06 15:14:20 +07:00
BFlat 683ccdf8dc Merge pull request #5897 from dotCooCoo/fix/restyled-empty-frame-keeps-style
Text: a restyled empty frame keeps its style before an unedited empty frame
2026-11-06 16:09:53 +08:00
dotCooCoo f48ac15d08 Text: a restyled empty frame keeps its style before an unedited empty frame
When a frame's text ends with a paragraph break and the next frame is empty, restyling that empty frame was undone on reflow: an unedited empty frame after it gave the story's last paragraph its own style again. A restyled empty frame now keeps its style against unedited empty frames that follow it. Unedited empty frames before it, later frames with text and later restyled frames still give the paragraph their style, as before.
2026-11-06 14:56:28 +07:00
BFlat 5e7c331745 Merge pull request #5896 from adikshan11/fix/automation-superscript-device-names
Automation roots: refuse COM¹ to LPT³ as Windows device names
2026-11-06 15:46:42 +08:00