Commit Graph

1267 Commits

Author SHA1 Message Date
bflatastic 2b91d7effd Merge #679 2026-10-09 11:43:42 +07:00
bflatastic b062d625cf Merge #678 2026-10-09 11:43:42 +07:00
bflatastic ee7be83ee0 Merge #677 2026-10-09 11:43:41 +07:00
bflatastic 50bb3b2693 Merge #676 2026-10-09 11:43:41 +07:00
bflatastic 2f81b4437b Merge #674 2026-10-09 11:43:40 +07:00
BFlat 23b7c68d90
Merge pull request #680 from storytold/fix/671-artboard-orientation
Fix #671: Edit Artboards' Properties picks a size preset and flips the orientation
2026-10-09 11:42:03 +07:00
bflatastic 4176c0f297 Fix #671: Edit Artboards' Properties picks a size preset and flips the orientation
With the Artboard tool, the Properties panel showed the active artboard's name,
position and size but no quick way to turn it between portrait and landscape.
It now has a row with:
- Preset: New Document's saved and built-in presets, by category, matched in
  either orientation (Custom when none matches); choosing one sizes the
  artboard in its current orientation;
- Portrait and Landscape (the New Document toggle): the other one swaps the
  artboard's width and height.
The artboard's top-left corner stays put, so no art moves with it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:37:05 +07:00
BFlat 349668a1e6
Merge pull request #672 from storytold/pr/land-394
Land #664, #669: Animated Zoom, Large Tabs, Scale Cursor, anti-aliased bitmaps, Spacing Guides (part of #394)
2026-10-09 11:32:46 +07:00
bflatastic ea07805fdf ROADMAP: Spacing Guides wired (#669) beside #664's preferences
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:26:01 +07:00
bflatastic e29e558810 Merge fix/394-spacing-guides
# Conflicts:
#	ROADMAP.md
2026-10-09 11:25:41 +07:00
bflatastic cc627c75e3 Merge fix/394-prefs-batch
# Conflicts:
#	ROADMAP.md
2026-10-09 11:25:38 +07:00
BFlat 5f4e03f3b3
Merge pull request #670 from storytold/fix/661-touch-bar-quit-int
Fix #661: quitting no longer crashes on Macs with a Touch Bar
2026-10-09 11:24:59 +07:00
fastmikey99 f767403673 Crop Image: trim an image to its pixels that aren't fully transparent
object.cropImage {trim: true} cuts the selected image to the box of its pixels
with any alpha, copying them as they are (no re-render, no resampling) and
placing them where they were. An image with nothing to cut is left as it is
and isn't an error (trimmed: false), so a script can trim every image it
opens. Print-ready PNGs usually carry transparent padding; with this, Fit to
Artwork Bounds can size to the art.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:24:04 +13:00
bflatastic 90d6785eb5 Part of #394: Animated Zoom, Large Tabs, Scale Cursor and anti-aliased bitmaps act
- Performance › Animated Zoom (with GPU Performance, which dims it when
  off): the Zoom tool dragged sideways zooms about the press (right in,
  left out) and held still zooms on (Alt: out); a click still steps. Off,
  a drag zooms to the area dragged across, now drawn as a marquee. The
  hint bar says which.
- User Interface › Large Tabs: taller document tabs with larger titles.
- User Interface › Scale Cursor Proportional to UI: off, the tool cursors
  keep their size whatever the UI Scaling (OS and painted cursors alike).
- File Handling › Display Bitmaps as Anti-aliased Images in Pixel
  Preview: off (the default), Pixel Preview samples images nearest-pixel
  (`RenderOptions::smooth_images`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:22:43 +07:00
bflatastic 1575b14294 Part of #394: Smart Guides › Spacing Guides space a moved selection evenly
A selection moved with the Selection or Direct Selection tool that lines
up with nothing along an axis lands as far from its neighbour as two
other objects of its row (or column) are apart, or halfway between its
two neighbours, within the snapping tolerance; the equal gaps are marked
with a line and end ticks in the Smart Guides colour. The objects are
taken as wholes on their layers (groups too), and inside a group holding
the selection, its other objects. Off, moves only line up as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:22:22 +07:00
bflatastic f17bac2c64 Fix #661: quitting no longer crashes on Macs with a Touch Bar
On every quit (Cmd+Q, VectorCraft > Quit, the close button) on a MacBook Pro
with a Touch Bar, AppKit threw from -[_NSTouchBarFinderObservation invalidate]
and macOS reported a crash. AccessKit's macOS adapter subclasses the window's
content view and gives it back its own class when the window is torn down;
AppKit's Touch Bar support observes the view under the subclass, so removing
that observation throws (the same cause Zed fixed in zed-industries/zed#65186).

On macOS with accessibility, the app now ends the process at the end of
on_exit, once the preferences are saved, before eframe tears the window down.
Nothing after the window is needed on a normal quit. While the window is still
starting up it doesn't, so a graphics failure still starts the app again on
another adapter (#651).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:20:40 +07:00
BFlat 01ad745e86
Merge pull request #668 from storytold/fix/663-recent-and-preset-dblclick
Part of #663: Home screen Recent Files; a double-clicked preset creates the document
2026-10-09 11:20:12 +07:00
bflatastic d8f6bacddb Part of #663: Home screen Recent Files; a double-clicked preset creates the document
- The Home screen lists the first six of File > Open Recent Files, each by name
  (a click opens it) and folder; one that can't be opened says so in the status
  bar. With none, there is no section.
- In New Document, a double-click on a preset card creates the document from
  it; a click still only chooses it. The Create buttons no longer overwrite a
  create asked for earlier in the frame.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 11:17:35 +07:00
fastmikey99 2cdf4e3de0 Colour: ICC CMYK converts straight into the RGB profile, with black-point compensation
CMYK went to RGB through display sRGB: CMYK -> sRGB (clamped) -> working RGB.
Into a wider space (Wide Gamut RGB, the 1998 primaries) that clipped every
colour sRGB can't hold - CMYK cyan's red channel landed at 99 instead of 0 -
and the black-point compensation setting had no effect (moxcms leaves it
unimplemented). An ICC CMYK profile now converts directly into the RGB
profile: into its primaries with linear curves, where compensation is a
linear remap from the profile's black (found by sending black through the
profile and reading it back), then onto its own curves. The canvas uses the
same conversion into sRGB, so what shows is what an RGB export writes.

Checked against Ghostscript with the same profiles (relative colorimetric,
compensation on and off): exports into Wide Gamut RGB and the sRGB display
agree within 1 level in 255. The built-in CMYK spaces are unchanged (Generic
CMYK compensates in its own model).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:11:34 +13:00
fastmikey99 088495ee17 PDF import: masked CMYK images stay CMYK, their mask an opacity mask
A CMYK image with an /SMask, /Mask or colour key was handed to the
interpreter and stored as an RGB PNG, converted with hayro's own bundled
profile (Perceptual) rather than the working CMYK, so it showed 10-30 levels
lighter than other CMYK images and lost its ink amounts. It now keeps its
inks as other CMYK images do (#320), and its alpha becomes a greyscale
opacity mask. PDF export already writes that as a DeviceCMYK image under a
soft mask, so a round trip keeps the inks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:11:34 +13:00
fastmikey99 43db1cdbbf Open CMYK TIFFs with an alpha channel, and rasters past 512 MB
The image decoder can't read a CMYK TIFF with an alpha channel at all
("color type Unknown(0)"); it is now read with the tiff crate, associated
alpha divided back out and the inks converted in the active colour settings.
And a 60 in sheet at 300 ppi (18000 x 6600 px) hit the decoder's 512 MB
default allocation limit; up to 2 GB is now allowed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:11:08 +13:00
fastmikey99 ed17166343 Open raster images at the size their resolution declares
An image opened as a document took 1 px = 1 pt whatever its pHYs, JFIF or
EXIF resolution said, so a 300 ppi print file opened at four times its
physical size. It now opens the way Place already sizes it (pt_per_px):
at the resolution it declares, 72 ppi when it declares none.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 17:11:07 +13:00
BFlat fc74389b5a
Merge pull request #660 from Haven-King/fix/text-engine-integration
Fix/text engine integration
2026-10-09 10:45:11 +07:00
BFlat 0891ffbf51
Merge pull request #659 from storytold/fix/449-two-finger-pan
Part of #449: two fingers dragged on a touch screen pan the canvas
2026-10-09 10:37:26 +07:00
bflatastic 861a0759b0 Part of #449: two fingers dragged on a touch screen pan the canvas
A pinch already zoomed the canvas and a second finger already cancelled the
first finger's press, but dragging two fingers together did nothing: the
canvas only read wheel scrolls, and a touch screen sends touches. The fingers'
movement (egui's multi-touch translation) now scrolls the canvas under either
Zoom with Mouse Wheel setting, and zoom and scroll apply in the same frame, so
a pinch that also slides pans too. Trackpads send scrolls, so nothing counts
twice.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:34:22 +07:00
haven 992f6a0a4d M7: tests for the text engine features combined
Layout (vectorcraft-text tests_combos): every pair of ligatures under tracking,
the paragraph composer, vertical alignment, Shrink Text to Fit, per-paragraph
attributes and inline graphics, and all six at once. Commands
(vectorcraft-engine tests_textcombos): Auto Size and Shrink Text with inline
art, paragraphs, composer and alignment; editing and undo across them; a save
round trip with everything on.
2026-10-08 20:30:14 -07:00
haven 53e39884fc M7: Auto Size measures vertically aligned area type from the top
auto_height lays the text out in a very tall probe frame; with Center, Bottom
or Justify the lines moved down inside it and the frame grew to tens of
thousands of points.
2026-10-08 20:30:14 -07:00
haven abdc26d8d1 M7: Shrink Text to Fit scales inline art's baseline shift
The fit scaled each run's size, leading and baseline shift but not an inline
graphic's own shift (points), so shrunk symbols sat off the cap-height centre.
2026-10-08 20:30:14 -07:00
haven 56c975465c M7: inline art follows vertically aligned lines
align_vertically moved lines and glyphs but not TextLayout::inlines, so inline
symbols in a centred or bottom-aligned area stayed where top alignment put them.
The reflow path for non-rectangular frames also kept the previous pass's
inlines, drawing each symbol twice.
2026-10-08 20:30:14 -07:00
BFlat 2dcac5b48b
Merge pull request #658 from storytold/fix/651-gpu-fallback-int
Fix #651: a dual-GPU Mac falls back to its other GPU
2026-10-09 10:29:33 +07:00
bflatastic dc39146d0d Fix #651: a dual-GPU Mac falls back to its other GPU
Metal reports no PCI ids, so both GPUs of a dual-GPU Mac had the adapter key
Metal:0000:0000. When the integrated GPU failed at start-up, the restart left
out both and the app quit, although the discrete GPU works. An adapter without
ids is now keyed by its name, so the restart leaves out only the one that
failed.

The failure itself was wgpu's indirect-call validation compute shader, which
OCLP-patched Metal on an Iris Pro can't compile. Nothing in VectorCraft or
egui draws indirectly, so that validation is off (WGPU_VALIDATION_INDIRECT_CALL=1
turns it back on).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:26:55 +07:00
BFlat 147fc113c3
Merge pull request #657 from storytold/pr/land-641
Land #653, #654, #656: Image Trace View modes, Palette and Create Strokes (part of #641)
2026-10-09 10:25:04 +07:00
bflatastic 66a5363629 Merge #656: Image Trace: Create Strokes
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/buildcmds.rs
#	crates/engine/src/tests_build.rs
#	crates/mcp/src/prompts.rs
#	crates/trace/src/tests.rs
#	crates/ui-egui/src/panels/image_trace.rs
2026-10-09 10:16:02 +07:00
bflatastic eea4fe9e58 Merge #654: Image Trace: Palette (Limited, Full Tone, Automatic, Document Library)
# Conflicts:
#	ROADMAP.md
#	crates/engine/src/cmd/buildcmds.rs
#	crates/ui-egui/src/panels/image_trace.rs
2026-10-09 10:14:35 +07:00
bflatastic 13c37e0bf4 Merge #653: Image Trace: Advanced as a section that stays open, and View modes
# Conflicts:
#	ROADMAP.md
2026-10-09 10:13:04 +07:00
bflatastic 438f90c751 Part of #641: Image Trace: Create Strokes
Advanced › Create: Fills and/or Strokes, with Stroke (the widest line, px).
With Strokes, each colour's 8-connected parts no wider than the stroke width
(chamfer distance transform) trace as open centre lines instead of filled
outlines: the line is thinned to one pixel (Zhang-Suen with each removal
re-checked, so two-pixel lines survive; staircase corners dropped), its
skeleton becomes runs between ends and junctions (junction pixels merged,
spurs pruned, runs through two-way junctions joined, rings closed), and each
run is simplified and fitted with curves. The stroke width is the line's mean
width (pixels over length). Traced lines get round caps and joins in the
document. Without Fills, wider areas become 1 px stroked outlines.
`imageTrace.make` takes fills, strokes and strokeWidth, and refuses neither
fills nor strokes and a non-positive width.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 10:11:09 +07:00
bflatastic 4a81e549a2 Part of #641: Image Trace: Palette (Limited, Full Tone, Automatic, Document Library)
Color mode's colours now come from a Palette (`palette` in imageTrace.make's
params), shown in the Image Trace panel under Mode:
- Limited: the `colors` best colours (what Color did before; the default).
- Full Tone: median cut until no colour box spans more than 96 (Less) … 8
  (More) levels per channel, up to 256 colours, set by `colorDetail` 0-100
  (the panel's Colors slider for this palette).
- Automatic: flat art (90% of the pixels in a few tight colours) traces with
  exactly its colours, anything else as Full Tone.
- Document Library: the most used (at most `colors`) colours of the
  document's swatches or of a swatch library (`library`: "document" or a
  library id or name, chosen in the panel's Library list), used as they are;
  traced shapes fill with the swatch's own colour, its colour model kept.
  The library's colours are looked up at every trace, not saved.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:51:49 +07:00
bflatastic 5be583d1f7 Part of #641: Image Trace: Advanced as a section that stays open, and View modes
- The Image Trace panel's Advanced options sit under a full-width collapsible
  header (widgets::section_toggle, also used by New Document's Advanced
  Options); whether it is open is kept with the UI preferences.
- View: Tracing Result, Tracing Result with Outlines, Outlines, Outlines with
  Source Image and Source Image, in the panel, the Control bar and the
  Properties panel. The view is saved in the Image Trace object's settings
  (`trace.view`), kept when it is traced again, set with the new
  `imageTrace.setView` command (or `view` on imageTrace.make) and drawn by the
  canvas only (RenderOptions::trace_views): exports, printing and Expand keep
  the tracing result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:33:22 +07:00
BFlat 11fceda13e
Merge pull request #650 from mateususa/fix/artboard-tool-delete-key
Artboard tool: Delete and Backspace delete the active artboard
2026-10-09 09:31:38 +07:00
BFlat ea814b3fac
Merge pull request #652 from storytold/fix/649-dock-drop-zone
Fix #649: a panel dropped on the dock lights up where it goes
2026-10-09 09:27:11 +07:00
bflatastic b5e39048df Fix #649: a panel dropped on the dock lights up where it goes
Panels other than Properties, Layers and Libraries live in the dock's icon
column, not as tabs. Dragging one onto the dock lit up the whole dock, tabs
included, and the drop put it back as an icon, so it seemed to vanish. The
drop zone now lights up the icon column for such panels (the whole dock still
for the tabbed ones), and the dropped panel pops out of its icon.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:23:30 +07:00
mateususa 762bd6b927 Artboard tool: Delete and Backspace delete the active artboard
The Artboard tool handled Delete/Backspace in Tool::key, but never claimed
the keys through Tool::claims_key. The UI only routes Delete/Backspace to a
tool that claims them, so the keypress went to the Clear shortcut instead
and the artboard stayed. The existing tests called the tool directly and
missed it.

The tool now claims Delete/Backspace while no drag is in progress and more
than one artboard exists. With only one artboard left, the keys stay with
the shortcut.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:19:59 -07:00
BFlat 033ceaff41
Merge pull request #648 from storytold/fix/svg-root-layer-name
Part of #372: SVG import names the one layer from the root element
2026-10-09 09:05:21 +07:00
bflatastic a2e4206155 Part of #372: SVG import names the one layer from the root element
Other editors export a document with a single layer without a layer group:
the layer's name goes on the root <svg> (id, or data-name) and its art sits
directly inside. Such a file opened as "Layer 1"; now its one layer takes the
root's name. Files whose top-level groups are the layers are unchanged, and an
Inkscape root's generated id (with inkscape:version) isn't taken as a name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 09:00:24 +07:00
BFlat 771981e2b1
Merge pull request #644 from dotCooCoo/feat/ase-import
Swatches: swatch exchange (.ase) files open as swatch libraries
2026-10-09 08:50:50 +07:00
BFlat c7aeaa637f
Merge pull request: land #643 (fix #638)
Land #643 (fix #638: Layers panel lays out only rows in view, keeps open rows in the file)
2026-10-09 08:40:24 +07:00
bflatastic 965fc449e1 Merge #643: Fix #638: Layers panel lays out only the rows in view and keeps open rows in the file 2026-10-09 08:31:13 +07:00
bflatastic 977e5d1967 Fix #638: Layers panel lays out only the rows in view and keeps open rows in the file
The panel laid out a row (with its thumbnail and several whole-document
lookups) for every open row each frame. A layer of 5,000 groups of 10 paths,
all open, took about 29 s a frame headless. Now the rows shown are listed once
per document change (with their layer colour and dimming worked out on the
way down) and ScrollArea::show_rows lays out only those in view: 0.4 ms a
frame. A row highlighted out of view is scrolled to.

The open rows move from UI state into the document's state
(DocState::layers_open, OpenRows): a document opens with only its top-level
layers open, and native files save the open rows (Document::layers_open,
written only when not the default, at save time like the view, so opening or
closing rows never marks the document modified).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:19:49 +07:00
BFlat b73e19eef2
Merge pull request: land #639 (part of #372)
Land #639 (part of #372: SVG import keeps wrapped layers, round-trips sublayers)
2026-10-09 07:45:18 +07:00
bflatastic 4792bd82a2 Merge #639: Part of #372: SVG import keeps wrapped layers and round-trips sublayers 2026-10-09 07:41:02 +07:00