Commit Graph
8842 Commits
Author SHA1 Message Date
BFlat afdc490d3a Merge pull request #5971 from slafebre/fix/5964-gradient-dash-corner
Part of #5964: stroke gradients cover an arrowhead to the end of its reach
2026-11-07 09:09:47 +08:00
BFlat 073923ee30 Merge pull request #5969 from dotCooCoo/fix/eyedropper-keeps-story-selection
Type: switching to the Eyedropper keeps a whole-story selection
2026-11-07 09:09:33 +08:00
BFlat 085bbf5495 Merge pull request #5968 from slafebre/fix/5714-smooth-width-profiles
Fix #5714: widths run smoothly between width points
2026-11-07 09:09:19 +08:00
BFlat ee4f711fbe Merge pull request #5967 from dotCooCoo/fix/ai-brushed-paths
.ai import: paths with an Art brush open with the brush on their stroke
2026-11-07 09:09:01 +08:00
BFlat 7adc7fa40c Merge pull request #5966 from dotCooCoo/fix/ai-envelope-stroked-box
.ai import: envelopes map from their stroked box when the file saves its size
2026-11-07 09:08:45 +08:00
BFlat 9950bde2e7 Merge pull request #5963 from dotCooCoo/fix/pdf-export-cost
PDF export: members of a plain group or layer are measured once to leave out off-page art, and the link walk measures only what it reads
2026-11-07 09:08:28 +08:00
BFlat e940a55cb6 Merge pull request #5959 from dotCooCoo/fix/ai-symbol-section-strings
.ai import: ASCII85 data in a section does not hide the section's end
2026-11-07 09:08:13 +08:00
BFlat aeb697c8ea Merge pull request #5958 from FractalEncrypt/fix/shape-tool-centre-and-rotate
Shape tools: move the selection from its centre point and turn it outside a corner
2026-11-07 09:07:57 +08:00
BFlat b59e31203e Merge pull request #5957 from FractalEncrypt/fix/transform-fields-tab-order
Transform fields: Tab moves from one field to the next, one press each
2026-11-07 09:07:42 +08:00
BFlat 5a07696a8e Merge pull request #4732 from SofiaAFigueredo/feat/4684-unify-home-screen-ui
UI: centre the Home screen and use the accent for the Discord button (#4684)
2026-11-07 09:07:26 +08:00
BFlat 4244b96afc Merge pull request #5955 from dotCooCoo/fix/open-text-layout
Type: layout keeps each font face's shaping plans
2026-11-07 09:07:10 +08:00
BFlat 8df48df103 Merge pull request #5953 from mockydevs/fix/legacy-ai-smooth-image-clip-5264
Legacy .ai export: a flattened transparent image's clip follows its edge smoothly
2026-11-07 09:06:50 +08:00
BFlat 4db8bbc97c Merge pull request #5952 from dotCooCoo/feat/ai-pathfinder-effect-commands
.ai import: the other Effect › Pathfinder operations open as live effects on a group
2026-11-07 09:06:14 +08:00
BFlat 3bceade119 Merge pull request #5951 from dotCooCoo/fix/ai-active-artboard
.ai save: the editing copy names the active artboard
2026-11-07 09:05:42 +08:00
BFlat 76eca8e98e Merge pull request #5950 from mockydevs/feat/progress-indicator-5930
Opening a slow file shows a progress window with Cancel and Continue in Background
2026-11-07 09:05:27 +08:00
BFlat b497793902 Merge pull request #5948 from Hamza0101/feat/bulgarian-text-language
Languages: Bulgarian, with its quote marks and the fonts' Bulgarian forms (#5945)
2026-11-07 09:05:15 +08:00
BFlat 98c6e8ab5d Merge pull request #5947 from mockydevs/fix/grid-snap-anchors
Direct Selection: with Snap to Grid, a dragged straight segment lands its anchors on the grid
2026-11-07 09:04:57 +08:00
BFlat 0ebce55584 Merge pull request #5942 from mockydevs/feat/paste-spreadsheet-table
Paste: cells copied from a spreadsheet paste as a table of type over gridlines
2026-11-07 09:04:38 +08:00
BFlat d79c3574af Merge pull request #5940 from dotCooCoo/fix/paint-without-bounds
Appearance and Eyedropper: reading an object's paint does not measure its bounds
2026-11-07 09:04:16 +08:00
BFlat af4f590b6b Merge pull request #5939 from mockydevs/feat/alt-numpad-codes-5108
Type: Alt + numeric-keypad codes (Alt+0176 → °) type their character on Windows; type.insert takes a code
2026-11-07 09:03:59 +08:00
BFlat 84fc4b74ac Merge pull request #5938 from mockydevs/feat/3d-effects-on-groups
3D effects: Extrude & Bevel, Inflate and Rotate apply to groups, turned about one shared axis
2026-11-07 09:03:47 +08:00
BFlat e688fbea0e Merge pull request #5937 from mockydevs/feat/glyph-bounds-corners-5112
Snap to Glyph: each glyph's bounding-box corners are snap points, and the box turns with rotated type
2026-11-07 09:03:27 +08:00
BFlat bc57bdaee3 Merge pull request #5932 from Hamza0101/fix/paste-into-new-type-keeps-formatting
Type: pin that a Type-range paste into new point type keeps its formatting (#5929)
2026-11-07 09:03:09 +08:00
BFlat 8029748283 Merge pull request #5931 from mockydevs/fix/perspective-plane-offsets
Perspective grid: a grid dragged off its preset reports no preset name
2026-11-07 09:02:47 +08:00
BFlat c14ec164a2 Merge pull request #5928 from adikshan11/fix/library-untitled-format-copies
Don't copy a library on every save when its format keeps no title
2026-11-07 09:02:27 +08:00
BFlat d074756192 Merge pull request #5927 from mockydevs/fix/transform-effect-copies-5920
Effects: a Transform effect's copies of a filled and stroked path stack one above another
2026-11-07 09:02:10 +08:00
BFlat 0f0ded95b4 Merge pull request #5924 from jayzed80/fix/text-huge-gutter-stall
fix(text): a gutter too huge to step past no longer stalls area type layout
2026-11-07 09:01:34 +08:00
BFlat 145a10c2db Merge pull request #5922 from Hamza0101/fix/find-whole-word-across-runs
Find Whole Word: a change of style inside a word is not a word boundary (#5901)
2026-11-07 09:01:14 +08:00
BFlat 9ef87c19e5 Merge pull request #5921 from Hamza0101/fix/find-replace-respects-group-lock
Find and Replace: type inside a locked or hidden group is left alone (#5900)
2026-11-07 09:00:51 +08:00
BFlat 4166d31a54 Merge pull request #5918 from mockydevs/feat/drop-shadow-colour-picker
Drop Shadow: a swatch beside Color opens the Color Picker (#5364)
2026-11-07 09:00:28 +08:00
BFlat c0a40216ce Merge pull request #5917 from mockydevs/fix/boolean-area-check
Path booleans: check the windings against the operands' areas and resolve the operands when they don't add up (#5478)
2026-11-07 08:59:49 +08:00
Sven Lafebre a83a0054ea Part of #5964: stroke gradients cover an arrowhead to the end of its reach
With ribs only at the path's corners (an Along gradient), the ribs that reach
across an arrowhead stopped at the last corner inside its reach, so the slice
narrowed from the head's tip towards the next corner and left the corners of
a Triangle head's base outside every slice. Where each arrowhead's reach ends
now gets a rib of its own.
2026-11-07 05:15:12 +07:00
dotCooCoo 18015f3631 Type: a selected story stays selected when its text leaves the edited frame
When a frame threaded in before the edited frame takes all of the story's
text, the edited frame is left with no text while the story stays
selected. The other frames' text is now highlighted, Delete and Backspace
replace the story, an Alt+arrow step changes the tracking of every frame,
and Copy and Cut take the story. A story whose frames hold no text has
nothing to copy, and Delete in it records no undo step.
2026-11-07 05:15:12 +07:00
dotCooCoo 22bb2ac8a6 Type: a selected story's highlight and typing follow its current thread
With a whole story selected, the highlight and typing read the frames saved
at Select All, while a pick, a fill and the other story-wide edits read the
document's thread. A frame added by text.thread.add took a pick without being
highlighted, and typing left its text in place.

Both now read the thread through Document::story_of. A frame threaded in
during the selection is highlighted and takes the edit, and a frame that
leaves the thread is not highlighted and keeps its text.
2026-11-07 05:15:11 +07: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
Sven Lafebre 1b62f86b8c Fix #5714: doc comments on the width profile tests 2026-11-07 05:15:10 +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
Sven Lafebre d208f5da64 Contributors: Sven Lafebre's name 2026-11-07 05:15:10 +07:00
dotCooCoo 0c570dee87 .ai import: paths with an Art brush open with the brush on their stroke
A path with an Art brush comes in as the path, with the brush on its
stroke at its weight, instead of as its drawn look, when the brush
stretches art of solid-filled paths along the path, unflipped, at 100% in
Tints. The art runs on the side of the path the file draws it.

The drawn look stays for other colorizations and widths; Proportional,
between-guides and flipped brushes; type; a path with settings of its own,
a variable width, effects, a swatch stroke or an entry that isn't read;
and art with strokes, gradients, patterns, masks or effects, or no length.

A brushed stroke, Calligraphic ones too, takes the brush the Brushes panel
keeps under its name, and an image with a brush keeps its drawn look.

In every document, Tints and Tints and Shades take art in black ink alone
by its ink amount, and a process or gray stroke color's tints and shades
stay in that color's model.

Place and Expand bring the brushes the art uses, renaming on conflict.

Part of #637.
2026-11-07 05:15:09 +07:00
Sven Lafebre 9da56717a0 Fix #5714: widths run smoothly between width points
The width between two width points was a straight line, so a variable-width
stroke turned a corner at every width point.

- Each side of a width profile now follows a monotone cubic (Fritsch-Carlson)
  through its points: no kink at a point, flat at a point wider or narrower
  than both neighbours, never past either point of a span. Points on one line
  stay on it and two-point tapers are unchanged; stacked points still step.
- widest() counts each span's wider left and wider right, since the two sides
  needn't peak together.
- The outliner samples straight runs between width points closely enough to
  follow the curve to the drawing tolerance (at most 64 samples per span and
  4,096 per piece); straight spans get none.
- Tests that expected straight-line widths now expect the curve. The stroke
  gradient coverage test uses Teardrop instead of Wave until #5964 is fixed.
2026-11-07 05:15:09 +07:00
dotCooCoo ab3ac3d429 .ai import: envelopes map from their stroked box when the file saves its size
When Distort Appearance is on and the size a `.ai` saves for an
envelope's contents (`AIDeformArtWidthKey`, `AIDeformArtHeightKey`)
matches the contents' bounds with strokes, the reader now maps the
contents from that stroked box. It used to map them from the geometric
bounds, half a stroke inside that box, so an envelope of stroked art
could differ from its drawn art and keep the drawn art with a note.

Envelope Options hold the box's margins as `boundsMargin`, shares of the
geometric bounds at the top, bottom, left and right. Native files write
them only when they are not zero, and `object.envelope.info` reports
them then. Leaving Edit Contents measures them again when the strokes
reach differently than when Edit Contents began, and the node holds
what they measured then until it leaves. New envelopes have no
margins, so their results do not change. Contents with no width or no
height, such as one straight line, get no margins.

Docs: docs/mcp.md, docs/target-app-parity.md.
2026-11-07 05:15:08 +07:00
dotCooCoo b50a6bcad4 PDF export: the link walk measures only linked objects and clipping groups
The walk that writes link annotations measured every object at every
level, on every export that can have links, and read the box only for
an object with a URL that opens and for a clipping group. It now
measures only those, so a document with no URLs or clipping groups is
not measured a second time. The link annotations are unchanged.

The output is byte for byte the same on a document of linked objects in
plain and clipping groups on and off the page, with default settings,
with uncompressed text and with PDF layers.
2026-11-07 05:15:08 +07:00
dotCooCoo a3045845c8 PDF export: members of a plain group or layer are measured once to leave out off-page art
The walk measured every object's visual box to leave out what is off
the page. A plain group or layer is measured as the union of its
members, and each member then measured itself again when it was
written, so an object in plain groups was measured once for each level
it sits at.

Measuring a plain group or layer now keeps its members' boxes in a
tree, and each member uses its box when it is written. A container
written whatever its box is (a PDF layer's group, placed symbol art) is
not measured. A knockout group's elements are measured for the group's
box and again for the list of elements on the page, and that second box
is used for the element and for its mask. Objects in a live container
(Blend, Envelope, Repeat, Intertwine) are still measured with the
container and again after it is expanded. Node::visual_of_members holds
the formula that Node::visual also uses, so the boxes and every decision
are unchanged.

The output is byte for byte the same on one open path of 200,000
anchors, 20,000 rectangles in 200 groups of 100, and 5,000 point type
objects, and on a document of plain, see-through, clipping and knockout
groups on and off the page, each exported with default settings, with
uncompressed text and with PDF layers.
2026-11-07 05:15:07 +07:00
dotCooCoo a17907ee7d .ai import: data with no end outside a section does not hide a later section's end
When the scan for swatch names searched data outside a section and found no `~>`, it stopped searching for the end of all later data. Data in a later section then was not skipped, so a `(` on a `%_` line of it opened a string that ran past the section's end marker, and a color named after the section did not reserve its name. The scan now records the search that found nothing per section's end marker, so a search in another section still stops at that section's markers.
2026-11-07 05:15:06 +07:00
dotCooCoo 3e1893d399 .ai import: ASCII85 data without its end does not hide the section's end
Data with no `~>` before the section's end marker was lexed as tokens, so a `(` on a `%_` line of it opened a string that ran past the marker and the section did not end. The scan now skips that data up to the section's end marker, or up to the start of a section of the same kind nested after it. A `%` on the key's own line starts no marker, and a marker line with bytes that are not UTF-8 counts, as the scan reads comments.

When versioned content does not end, the scan for swatch names goes back to where its dictionaries stood at the start of that content, so data in the range it reads again is skipped.
2026-11-07 05:15:06 +07:00
dotCooCoo babbbb9eb0 .ai import: ASCII85 data in a section does not hide the section's end
A section scan lexed a /ForeignObject's /Data, a /Binary dictionary's data and a text document's data as tokens. A `%_` line of that data holding a `(` opened a string, so the section ran past its end marker: the editing data failed to read, or the art after it was misread. Reader::section now skips the data up to its `~>`, as the reader does for art outside a section. Data without its `~>` before the section's end marker is not skipped. The scan for swatch names does the same.
2026-11-07 05:15:06 +07:00
FractalEncrypt d572f3ce71 Shape tools: the tool methods this pull request changes say what they do
The `Tool` implementation's `busy`, `pointer`, `key`, `claims_key`, `overlays`
and `cursor` in shape.rs, and `pointer` and `cursor` in select.rs, are the ones
this pull request edits; each now has a doc comment, so the docstring coverage
of the functions the diff touches is complete.
2026-11-07 05:15:05 +07:00
FractalEncrypt 1c271c776c Shape tools: review follow-ups from CodeRabbit
- The 45° move assertion compares dx and dy with a small tolerance instead of
  exact equality (the matrix's floats are rounded), keeping the non-zero check
  and the message.
- The engine test helpers say what they do, so the docstring coverage of the
  functions this pull request touches is complete.
2026-11-07 05:15:05 +07:00
FractalEncrypt 10724077bc docs: the shape-tool status lines name no other branch's change
The roadmap's status line and revision history now record the shape tools'
centre-point move and corner rotate (#5477), and the parity status line no
longer names the Transform tab-order fix, which is its own pull request.
2026-11-07 05:15:05 +07:00
FractalEncrypt dd160dc768 Selection: Cmd/Ctrl over a centre point selects behind, so the arrow stays plain
The press with Cmd/Ctrl held selects the object behind rather than taking the
centre point; the pointer now agrees.
2026-11-07 05:15:04 +07:00