Commit Graph
362 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 50bb3b2693 Merge #676 2026-10-09 11:43:41 +07:00
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
fastmikey99andClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
fastmikey99andClaude Opus 5.5 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
fastmikey99andClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 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
bflatasticandClaude Opus 5.5 d5e6be1565 Part of #372: SVG import keeps wrapped layers and round-trips sublayers
Top-level groups already opened as layers named from data-name, else their
id. Now that also holds when one more id-less group wraps them (a transform
on all the art, or a <switch>'s chosen group), and hidden objects inside a
<switch> are kept (hidden) instead of dropped.

Nested groups stay groups unless something marks them as layers: the SVG
export now writes data-vc-layer="sublayer" on layers inside layers, and
import makes such a group (or an Inkscape layer group) a sublayer of the
layer holding it, in that layer's colour. A marked group anywhere else
stays a group.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 07:36:21 +07:00
heojunfoandClaude Opus 5.5 53b4845f6f View › Pixel Preview: show the document pixels the art rasterizes to
Pixel Preview only switched the pixel grid on from 600%: the art was still
rendered for the screen and drawn with linear filtering, so curves and
strokes stayed smooth vectors. Now, while a document pixel is bigger than a
screen pixel, the canvas renders the visible document pixels one per point
(anti-aliased by coverage), uploads them with nearest filtering and places
them over the document rect they cover, turning with a rotated view.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 08:49:18 +09:00
bflatastic 2b10c15d7a Merge #632: Add French (fr) interface translation
# Conflicts:
#	ROADMAP.md
2026-10-09 06:24:09 +07:00
bflatastic 712f4316e0 Merge #631: Type: Character Alignment on the ICF top and bottom (ideographic character face)
# Conflicts:
#	ROADMAP.md
#	crates/text/src/layout.rs
2026-10-09 06:24:04 +07:00
Simon LeblancandClaude Opus 5.5 e22d22a4ce Order the French code and docs alphabetically by language code
French now sits between Spanish and Italian (es, fr, it, ru): the
plural rule, the LANGUAGES registry entry (so the Language menu lists
Français before Italiano), the locale tests, the fr() helper and
french_reads_as_french. README, ROADMAP and docs/development.md list
the languages in the same order.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 01:18:25 +02:00
Simon LeblancandClaude Opus 5.5 9ec940222b Add French (fr) interface translation
Add fr.tsv with the full interface coverage: every menu string, every
tl! literal, the plurals and the status/error messages (@msg).
Registered as complete_menus with the French plural rule (0 and 1 are
singular); every fr-* locale (fr-FR, fr-BE, fr-CA, fr-CH …) resolves
to it. Keeps the product, workspace and perspective preset names in
English like the other complete catalogs.

Tests: french_reads_as_french; fr added to KEEPS_MENU_NAMES and
COMPLETE_MESSAGES; the Latin-script glyph test covers French letters
and the no-break space; locale tests use de-DE as the unsupported case.

Clean-room: written from the meaning of the English labels in the
vocabulary French-speaking users of vector illustration software know
(Plan de travail, Nuancier, Contour, Fond, Tracé, Calque). No other
application's localisation was copied.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-09 01:18:14 +02:00
imachusandClaude Opus 5.5 4411688b3d Type: Character Alignment on the ICF top and bottom (ideographic character face)
Character panel menu › Character Alignment gains ICF Top/Right and ICF Bottom/Left, and
`charAlign` takes `icfTop` / `icfBottom`: a character smaller than the largest on its line lines
up its ideographic character face's top (right, vertical) or bottom (left) with the big one's.

`FontFace::icf_margins` places the ICF inside the em box as the OpenType baseline tags define it
(https://learn.microsoft.com/en-us/typography/opentype/spec/baselinetags): `icfb` / `icft` of the
BASE table's horizontal and vertical axes against `ideo` / `idtp` (else the OS/2 typographic
descender and one em), for Han ideographs (else kana, else the first script). Without them, as that
page allows, the average ink box of some ideographs and kana; a face without ideographs uses its
em box.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 08:14:17 +09:00
bflatastic f365dc1c74 Merge #627: M7: inline symbols in text 2026-10-09 06:02:59 +07:00
bflatastic f3b90fb93f Merge #623: Part of #579: vectorcraft-cli lists the fonts font services load too
# Conflicts:
#	ROADMAP.md
2026-10-09 05:48:40 +07:00
bflatastic fc052cb001 Merge #570: Fix #530: Edit Artboards adds, deletes and leaves artboards from Properties
# Conflicts:
#	ROADMAP.md
2026-10-09 05:48:30 +07:00
bflatastic 896f8efea8 Merge #568: Fix #563: the font menu's live preview no longer flickers
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/src/tests_font_menu.rs
2026-10-09 05:48:00 +07:00
haven b843fe8af3 M7: inline symbols in text
Document symbols placed inline in a run of type (beyond Illustrator; like
InDesign inline anchored objects): TextRun.inline holds the symbol, scale and
shift; the run is one U+FFFC laid out as a glyph sized to the art, centred on
the cap height. text.insertInline and Type > Insert Inline Symbol; editing
keeps the graphic whole; canvas, SVG (<use>) and PDF draw the art; Create
Outlines turns it into a symbol instance.
2026-10-08 15:45:34 -07:00
bflatasticandClaude Opus 5.5 aa5e8f46e9 Part of #579: vectorcraft-cli lists the fonts font services load too
The DirectWrite font lister (#594) was installed in the desktop app only:
`vectorcraft-cli` (convert, run, MCP) didn't see fonts that font services
such as Adobe Fonts load on Windows, so its exports set such type in a
fallback font.

- The CLI shares the app's `system_fonts.rs` and installs it first thing
  on Windows (not the win7 build). The text crate stays free of unsafe
  code; the CLI denies unsafe code instead of forbidding it, so the
  shared module's own allowance applies.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 05:43:13 +07:00
bflatastic 9dec49ed03 Merge #621: Fix #585: a two-finger tap undoes, a three-finger tap redoes
# Conflicts:
#	ROADMAP.md
2026-10-09 05:42:35 +07:00
bflatasticandClaude Opus 5.5 aa125bfff1 Fix #585: a two-finger tap undoes, a three-finger tap redoes
Preferences › Devices › Enable Touch Gestures (on by default) was stored
but nothing read it: no touch gesture was implemented.

- `touch::Taps` follows the fingers egui reports (winit reads them from
  the system: WM_POINTER on Windows): fingers down together and lifted
  within half a second, none moved more than 16 points, is a tap. Two
  fingers undo, three redo, with the preference on.
- egui makes the first finger the pointer too, so it has pressed on the
  canvas by the time a second lands: that press is dropped then (its tool
  interaction rolled back), and the rest of the gesture presses nothing.
  The tap so undoes what came before it, not the first finger's mark.
- A pen is one contact, so pen strokes and taps are unaffected; pinch zoom
  is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 05:39:47 +07:00
bflatastic 22008b4e68 Merge #619: Fix #598: the Free Transform widget
# Conflicts:
#	ROADMAP.md
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
2026-10-09 05:36:53 +07:00
bflatasticandClaude Opus 5.5 2497713779 Fix #598: the Free Transform widget
While the Free Transform tool (E) is active, a small box at the canvas's
top left holds Constrain over the tool's three modes: Free Transform,
Perspective Distort and Free Distort. Before, the modes were reachable
only by modifier keys or `tool.setOption`.

- The buttons set the tool's `constrain` and `mode` options through
  `tool.setOption`, as agents do. Constrain acts as Shift held and is
  greyed in the distort modes, where it does nothing. The modifier keys
  keep working while dragging.
- Theme tokens; Constrain shows the link icon, Free Transform the tool's
  own icon, the distort modes are drawn in code. Tooltips translated
  (cs, es, it, ja, pt-br, ru, zh-hans, zh-hant).
- `ui.inspect` reports where it shows (`freeTransformWidget`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 05:31:43 +07:00
bflatastic 564a3ae662 Merge #616: Fix #597: an image copied in a browser pastes as the picture, not its address
# Conflicts:
#	ROADMAP.md
2026-10-09 05:26:43 +07:00
bflatasticandClaude Opus 5.5 54eed6ec4c Fix #597: an image copied in a browser pastes as the picture, not its address
A browser's Copy Image puts the picture on the clipboard with the image's
address as text (and HTML). Paste takes text before bitmaps, as word
processors offer a picture of copied text, so it pasted the address.

- `clipboard::is_address`: text that is only an address (http, https,
  file, ftp, data or blob).
- Desktop paste (Windows, macOS, Linux): such text gives way to the
  clipboard's bitmap when it has one. An address alone pastes as text, as
  before; nothing is fetched.
- Web: a paste whose text is only an address takes its picture file.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 05:22:09 +07:00
dotCooCoo e0b1f55250 Swatches: swatch exchange (.ase) files open as swatch libraries
File › Open, Other Library… and the User Defined library folder read
.ase files. Colors keep their model, global and spot colors stay global
and spot, and color groups stay groups. The library readers take a
file's bytes. On the web, File › Open passes a swatch library file to
swatch.library.load as dataBase64 instead of as lossy UTF-8 text.

Swatch and group names in a library are now unique, in .gpl files too.
Add to Swatches puts each color group of a library into one document
group when the document already has a swatch with the group's name.
The library fuzz helpers fail when a command panics.
2026-10-08 15:18:57 -07:00
bflatastic 8d5b52965c Merge #611: M7: per-paragraph paragraph attributes 2026-10-09 05:13:59 +07:00
bflatastic 33f38cef08 Merge #610: Fix Shaper recognition and add editable Shaper groups
# Conflicts:
#	crates/ui-egui/src/i18n/cs.tsv
#	crates/ui-egui/src/i18n/es.tsv
#	crates/ui-egui/src/i18n/it.tsv
#	crates/ui-egui/src/i18n/ja.tsv
#	crates/ui-egui/src/i18n/pt-br.tsv
#	crates/ui-egui/src/i18n/ru.tsv
#	crates/ui-egui/src/i18n/zh-hans.tsv
#	crates/ui-egui/src/i18n/zh-hant.tsv
2026-10-09 05:13:59 +07:00
bflatastic 8a18a74daf Merge #612: Fix #593: anchors and handle ends are easier to grab than the segments through them
# Conflicts:
#	ROADMAP.md
2026-10-09 05:13:43 +07:00
bflatasticandClaude Opus 5.5 a0d5d72d90 Fix #593: anchors and handle ends are easier to grab than the segments through them
An anchor was picked within the selection tolerance (3 px), the same reach
as its segments: a press a little off the anchor's 5 px square took the
curve instead.

- `ToolContext::point_tol`: anchors and direction handle ends are picked
  within the selection tolerance, but at least 2 px past the drawn point
  (4.5 px at the default Size 3, more with a larger Size). Anchors are
  tested before segments, so where both are within reach the anchor wins.
- Direct Selection (presses, Highlight anchors on mouse over, blend spine
  points and handles), the Anchor Point, Delete Anchor Point and Scissors
  tools, and the Pen (its Alt conversions; its close/continue reach stays
  5 px unless the points are drawn larger) use it. Segments, objects and
  frame edges keep the selection tolerance.
- Of the topmost path with anchors in reach, the nearest anchor is picked.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 05:09:31 +07:00