Commit Graph
426 Commits
Author SHA1 Message Date
bflatasticandClaude Opus 5.5 7578787392 Canvas grid: turn with a rotated view, no per-frame vectors (review of #478)
The pixel grid draws through the document grid's `grid()`, which assumed an
unrotated view: with Rotate View its lines stayed upright on screen, in the
wrong places, or vanished. It now spans the box round the canvas's corners in
document space and draws each line through the view, so the pixel grid and
the document grid (lines and dots) turn with the art. The lines are iterated
rather than collected, capped, and computed by multiplication instead of
accumulating a step.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:00:03 +07:00
wstockandClaude Fable 5.1 aa8e77d09a Part of #394: Show Pixel Grid (Above 600% Zoom)
Preferences › Guides & Grid › Show Pixel Grid (Above 600% Zoom) was stored and
never read. On (the default), in View › Pixel Preview at 600% zoom and above the
canvas draws a translucent line at every document pixel over the art, so the
pixels the art rasterizes to can be seen; nothing below 600%, out of Pixel
Preview, or with the option off. Drawn by the same `grid()` as the document
grid, at a 1 pt spacing.

A headless frame test counts the pixel grid's lines at 800%, 500% and 600%, in
and out of Pixel Preview and with the option off, and checks they are drawn
over the art.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 19:00:03 +07:00
wstockandClaude Fable 5.1 349e1eac3c Part of #394: Anti-aliased Artwork
Preferences › General › Anti-aliased Artwork was stored and never read. Off, the
canvas renders the art with `AntiAlias::None` — a pixel is painted when the art
covers at least half of it, raster effects and pattern tiles staying smooth — and
on (the default) with `AntiAlias::Art`, as before. The preference is part of the
canvas's cache key, so changing it re-renders. Exports keep their own
Anti-aliasing option.

A headless frame test reads the art's raster back out of the frame's texture
upload: edge pixels partly covered with the option on, none off, and smooth
again once it is back on.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 18:59:51 +07:00
wstockandClaude Fable 5.1 beea693ee1 Part of #394: Type Object Selection by Path Only
Preferences › Type › Type Object Selection by Path Only was stored and never read.
On, the Selection tools pick type on its type path only — point type's baseline
(the line the selection marks under it, across its layout's width), area type's
frame, type on a path's path — within the selection tolerance; a click among the
glyphs or inside the frame selects nothing. Off (the default), anywhere in the
type's bounds selects it, as before.

`HitOptions` gains `type_path_only`, set by the tools' context (`hit_options()`)
and the canvas's `hit_at` from the preference, so the Selection tools, Cmd-click
behind, object highlighting and the context menu agree. Tests at the hit-test
level (point, area and on-path type) and through the Selection tool with
`prefs.set`.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 18:59:47 +07:00
bflatasticandClaude Opus 5.5 6dc6b8600b Fix #487: Keyboard Shortcuts records chords with modifiers
egui reports a modifier's own key press (ShiftLeft, ControlLeft…) as a key event, and the
recorder took the first key press it saw, so pressing Shift+A saved `ShiftLeft` as the chord: a
shortcut that can never fire. The recorder now skips modifier key presses, so the chord completes
on the first other key with the modifiers held (Esc still cancels). A modifier is never a chord's
key in the shortcut parser either, so `shortcuts.set` refuses one, and overrides saved that way by
older versions are dropped on start, giving the default back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:55:02 +07:00
bflatasticandClaude Opus 5.5 9f3b992ecc EPS import: other apps' EPS open as vectors, a preview that stands in says why
Discord feedback: "EPS files are always rasterized: they open as bitmaps, in
other programs as vectors". Every EPS saved by Illustrator 2026 fell back to
its TIFF preview (`gcheck` was unknown), and cairo/Inkscape files stopped at
their first image (`status`), dropped masked images (ImageType 3) and failed
on mesh gradients; the warning didn't say where the program failed.

Fallback never silent:
- The warning names the PostScript error, the operator that raised it and
  the named procedures it ran in, innermost first ("a PostScript error
  (typecheck in `add`), in `inner` in `outer`"); errors caught by `stopped`
  aren't reported. It reaches the status bar, document.open, app.open and
  file.open (which now return document.open's result, so MCP's open_file over
  the control channel gets it), and `vectorcraft-cli info` ("warnings").
- A file whose PostScript can't be read opens as its TIFF preview, else its
  Windows metafile preview (as vectors, scaled to the bounding box), else its
  EPSI bitmap. es @msg rows for the new messages.

Interpreter:
- Operators programs probe or use: gcheck/scheck, rootfont,
  currentcolorrendering, currenthsbcolor, status, token, read,
  bytesavailable, fileposition/setfileposition, resetfile, write*, pdfmark
  (marks dropped, as Ghostscript does), execform, nulldevice, strokepath,
  pathforall, user paths (ufill/ueofill/ustroke/uappend/upath/setbbox, the
  encoded form too), setcachedevice2, findcolorrendering, cache, device and
  VM queries, revision; (%stdout) (w) file gives a sink.
- `//name` is replaced by its value when read, inside procedures too.
- Tiling patterns become pattern swatches (their PaintProc drawn in pattern
  space, one cell; uncoloured ones in the colour under them; makepattern
  copies share one swatch); nested patterns stop at 8 levels.
- Type 3 fonts draw their glyphs (BuildGlyph/BuildChar, widths from
  setcachedevice/setcharwidth) as outlines grouped per string, spaced by
  ashow/widthshow/awidthshow/xshow/yshow/xyshow/kshow; glyphshow and
  stringwidth/cshow use them.
- Shadings of types 1 and 4-7 become gradient meshes (data from arrays,
  strings or files, packed or not, flags sharing edges), as fills through a
  shading pattern too; sampled functions (type 0) are evaluated;
  GradientMesh::coons/triangle are shared with PDF import.
- ImageType 3 masked images, interleaved by sample, by row or in separate
  sources; ReusableStreamDecode reads its data when made; Flate/LZW PNG and
  TIFF predictors.
- Bounded: DeviceN at 32 inks, sampled functions at 2^24 samples and 32
  outputs, 4096 patches a shading, strokepath ignores dashes finer than 1e5
  pieces, Type 3 glyphs nest 8 deep (a glyph that shows itself overflowed the
  stack before the limit), 64-bit index maths for 32-bit targets.

Tests: a synthetic program per generator (cairo/Inkscape, its Type 3 fonts,
matplotlib, CorelDRAW, Affinity, LibreOffice, Ghostscript eps2write,
Illustrator procsets), meshes and function shadings, masked images, fault
messages, probing operators, metafile/EPSI previews, `//name`, user paths,
hostile patterns/glyphs/shadings (run against main, 12 of the 14 generator
and feature tests fail; CorelDRAW- and LibreOffice-style programs already
read there). The import fuzz vocabulary covers the new operators. Checked
against real files made here with Inkscape 1.4 (cairo) and Illustrator 2026
(its own format and the CS-to-CC compatibility formats; all fell back or
stopped early on main and open as vectors now; its Illustrator 8 format
needs the next commit); those files aren't committed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:23:36 +07:00
bflatasticandClaude Opus 5.5 13d5645052 Fix #479: Add/Delete Anchor Point tool icons drawn from the Pen tool's
The two tools had hand-drawn nibs that didn't match the Pen tool's icon and read as distorted
next to it. They now use Lucide's pen-tool (the Pen tool's own icon) with a plus or minus badge,
so the Pen group reads as one family; the Remove Anchor Points buttons pick up the minus one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:17:59 +07:00
bflatasticandClaude Opus 5.5 e98a880e75 Part of #472: Escape leaves Presentation Mode; dropped documents open as tabs; .ai off-artboard note
Presentation Mode hides the menus and panels, had no Escape and was saved with the
preferences, so it came back on every restart with no way out. Escape now leaves it (as in
Illustrator), F from it goes back to Normal Screen Mode, and the screen mode is no longer
saved: the app always starts in Normal Screen Mode, and preferences saved in Presentation
Mode by older versions open normally. ui.inspect reports `screenMode` on its own.

Desktop file drags carry no pointer position or modifiers (winit 0.30 on Windows, macOS
and X11), so every drop on a window with a document open was taken for the middle of the
canvas and placed. Where the platform doesn't say, a dropped document (native, SVG, PDF,
.ai, EPS, DXF, EMF/WMF) now opens as a tab of its own and a picture or text is placed in
the middle of the view; pictures dropped together with documents are placed first, so the
last document opened is shown. The web, whose drag events give the position, keeps
Illustrator's choice: placed on the canvas, opened off it (the tab bar).

Illustrator's PDF-compatible part leaves out art outside the artboards (it lives in the
private data alone, which isn't read), so it can't open; importing a file with that
private data now says so in a note. Off-page art a PDF does draw already opens on the
pasteboard; a test keeps it so.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 18:01:12 +07:00
bflatasticandClaude Opus 5.5 10a87311d3 Type: burasagari labels Regular/Force, full-width commas and full stops hang, MCP docs (review of #463)
- The Paragraph panel menu's Burasagari submenu reads None / Regular / Force, as the reference
  app's help names them (`text.setFormat` keeps "none"/"standard"/"forced", its scripting names);
  Reset Panel goes back to new type's Regular.
- The full-width ,.and half-width 、。 hang too; Latin commas and full stops never do, so Latin
  text keeps its breaks and composer with new type's default (tested). The spaces after a hanging
  mark stay on its line.
- docs/mcp.md: a Burasagari section. ROADMAP: wording, Last updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:34:05 +07:00
imachusandClaude Opus 5.5 08e7a4f713 Type: burasagari — a Japanese comma or full stop ending a line may hang outside it
Paragraph panel menu › Burasagari › None / Standard / Forced (with the East Asian options) and
`text.setFormat {burasagari}`:

- None: a comma or full stop that doesn't fit goes to the next line with the character before it.
- Standard: one that doesn't fit hangs outside the line; one that fits stays inside.
- Forced: one ending an area type line always hangs, and the rest of the line fills the measure.

Only 、 and 。 hang (closing brackets don't), in the width their mojikumi gives them. Horizontal
and vertical. Saved only when not None; new type keeps None. Paragraphs with burasagari are
composed line by line.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:34:05 +07:00
bflatasticandClaude Opus 5.5 253249717b Pen and anchors: Alt edits one handle, cut and convert selected anchors from the Control bar
Discord feedback: Alt with the Pen didn't move a direction handle on its own, and there was no
way to break a path at an anchor and pull the ends apart.

- Pen: Alt held over a handle end or an anchor of a selected path (the one being drawn too) hands
  the gesture to the Anchor Point tool, with the convert cursor: dragging a handle moves it alone,
  clicking a smooth anchor makes it a corner, dragging an anchor pulls out symmetric handles.
  Drawing goes on afterwards. Handles hidden by a partial anchor selection aren't grabbed.
- path.cutAtAnchors cuts at the direct-selected anchors in one undo step: a closed path opens
  there, an open one becomes one path per piece, and one anchor of each cut stays selected so a
  drag pulls the path apart. It answers {ids} and refuses (no undo step) when only open ends are
  selected. path.convertAnchors checks `to`, skips stale anchor refs instead of indexing past
  them, and keeps a smooth anchor's handles when converting to smooth.
- SubPath::cut_at and SubPath::smooth_anchor (geom) now back path.split, path.cutAtAnchors,
  path.convertAnchor and path.convertAnchors, replacing three copies of that logic.
- Control bar and Properties panel: "Convert:" corner/smooth and "Anchors:" remove, connect
  (Join), cut buttons when anchors are selected; Cut Path on the task bar and the context menu.
  New original icon dc-anchor-smooth.svg (ASSETS.md row).
- ja, zh-hans, zh-hant and es strings (cs for the context menu item), es @msg rows; docs/mcp.md
  section; ROADMAP.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:16:12 +07:00
bflatasticandClaude Opus 5.5 d6f8cc879f Control bar: image controls (Image Trace, Embed, Crop, Mask) when an image is selected
Discord feedback: Image Trace and the other image options were hidden when an image was
selected; copy, paste, Image Trace should work from the Control bar as in Illustrator.

- Control bar, one image selected: Linked File/Embedded, file name, colour mode and PPI, then
  Embed (+ Edit Original) or Unembed…, an Image Trace split button (click: Default preset;
  arrow: trace with any preset), Mask and Crop Image, in place of Fill and Stroke.
- Control bar, one Image Trace object selected: "Image Tracing", its Preset (choosing another
  traces it again), the Image Trace panel and Expand.
- Properties panel: Image Trace (split), Crop Image and Mask in Quick Actions for an image; an
  Image Trace section (Preset, Expand, Release) for an Image Trace object. Embed/Unembed buttons
  are shared with the Control bar (place::link_buttons).
- New engine command object.maskImage ("Mask"): clips the selected image with a clipping path
  on its outline (rotated with it) and selects that path so its handles crop; one undo step.
- widgets::split_button (flat button with a menu arrow).
- Translations for the new strings (es, ja, zh-hans, zh-hant; "Mask" also pt-br, cs).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 17:15:48 +07:00
bflatasticandClaude Opus 5.5 940285dd9e Type: the point/area type widget converts between them; area type made by dragging resizes
Discord feedback: type in a frame dragged with the Type tool could not be resized or switched
between area and point type the way the reference app allows.

- The Selection tool shows the type widget beside a single selected point or area type object:
  a small circle outside the middle of its bounding box's right side, hollow on point type and
  filled on area type (vectorcraft_tools::typewidget, drawn by the canvas from the same geometry).
  Hovering it shows the arrow with a type badge; its clicks neither drag nor deselect, and a
  double-click runs type.convertToAreaType / type.convertToPointType (the Type menu's commands),
  keeping the text and its styles in place, one undo step, reachable over MCP.
- Resizing area type made by dragging already works on main (#252): the bounding box resizes the
  type area and the text reflows. A regression test now covers the reported flow.
- docs/mcp.md and ROADMAP.md describe the widget.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:54:12 +07:00
bflatasticandClaude Opus 5.5 c5b5dbb6ad Properties: Fill and Stroke; Shift+F7 opens Align; Alt+wheel zooms
Discord feedback.

- Properties panel: the Appearance section's Fill and Stroke rows now use the
  Control bar's widgets: the chips with their chevron and swatch/mixer
  popover, the underlined Stroke link that opens the Stroke panel as a
  popover (stroke::link, shared with the Control bar) and the weight spinner
  with its presets (stroke::weight_field, which also follows the Type tool's
  selected characters). With nothing selected the Document view shows them
  too, as the Control bar does: they set up the next object drawn.
- Window menu panel keys as in Illustrator: Brushes F5, Layers F7, Align
  Shift+F7, Transform Shift+F8, Info Cmd+F8, Pathfinder Cmd+Shift+F9,
  Symbols Cmd+Shift+F11, Character Cmd+T, Paragraph Cmd+Alt+T, Tabs
  Cmd+Shift+T, OpenType Cmd+Alt+Shift+T (beside the existing Color, Color
  Guide, Appearance, Graphic Styles, Stroke, Gradient, Transparency and
  Attributes keys). The dock's tabs (Properties, Layers, Libraries) join the
  panel shortcut table and the Keyboard Shortcuts editor through
  state::all_panels, which window.panel's name lookup and the catalog's
  label list use too.
- Alt-wheel (Option on the Mac) zooms about the pointer whatever General >
  Zoom with Mouse Wheel says: egui spreads a notch over a few frames, and the
  rest of an Alt turn scrolled once Alt was up (also over the control
  channel's ui.wheel); the turn's own modifiers now decide. Pinch zoom is
  covered by the test too.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:46:34 +07:00
bflatasticandClaude Opus 5.5 8f771faa9e Fix #457: paste screenshots from the clipboard on macOS, Windows and the web
A screenshot on the clipboard didn't paste everywhere:
- macOS: the Paste menu item (which takes Cmd+V there) was enabled for text
  only, so with nothing copied in the app Cmd+V did nothing; and arboard
  reads the pasteboard's TIFF only. The pasteboard's types now enable Paste,
  and its PNG, else TIFF, pastes as it is.
- Windows: bitmaps came through CF_BITMAP and GetDIBits, which drops alpha.
  Paste now reads PNG, else CF_DIBV5, else CF_DIB, decoded with their colour
  masks and tables (a BMP file header in front, which image's headerless
  decoder gets wrong for masks after a BITMAPINFOHEADER), opaque when the
  alpha is zero throughout as screenshots leave it, capped at 32768 px a side.
- Web: only SVG text pasted. The page's paste event now hands the first
  picture or file that is art to the app (VectorcraftApp::paste_from_host),
  pasted with the chord held, like the desktop's paste keys.
- Linux reads image/png already; its Paste menu item still waits for text
  (no cheap way to ask arboard for a bitmap), the paste keys take one.

Bitmaps paste as embedded images at the view centre, as before.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:15:20 +07:00
bflatasticandClaude Opus 5.5 0c4df274aa Fix #458: Font Size and Leading combo boxes in the Character and Properties panels and the Control bar
The Properties panel's Font Size and Leading were plain typed fields and the
Control bar had no type controls. All three places now use the shared
editable combo (`widgets::spin_field`: typing, arrow and spinner stepping,
label scrubbing, a preset dropdown in the type unit):

- Character panel: the size and leading grid is shared with the Properties
  panel (`character::metrics_grid`), which now shows the font style, Font
  Size, Leading, Kerning and Tracking as combos and applies them to the
  Type tool's selected characters as the Character panel does.
- Control bar: with type selected or edited, a Character link (the Character
  panel in a popover), the font family and style menus and the Font Size combo.
- Presets as Illustrator lists them: sizes 6-72 pt; Leading has Auto first
  (`widgets::spin_field_auto`, `text.setStyle {leading: "auto"}`) and then
  the size ladder instead of 120% values; Kerning and Tracking -100...200.
- Font Size, Leading, Kerning and Tracking show blank where the selected
  text's values differ (`character::shared`); the spinner does nothing on a
  blank field instead of jumping to the step size.

Each pick is one `text.setStyle` / `text.setRangeStyle` step, so MCP and the
control channel are unchanged. Translations for the two new strings.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 16:10:14 +07:00
wstockandClaude Fable 5.1 14d7b3ddce Part of #394: Smart Guides display options and Snapping Tolerance
Color, Alignment Guides, Anchor/Path Labels, Measurement Labels,
Transform Tools, Object Highlighting and Snapping Tolerance are read:

- tools: `guides::GuideStyle` on `Targets` (`styled(cx)`) colours the
  lines and labels and leaves them out when their option is off, the
  snap itself unchanged; `ToolContext` gains the six fields and
  `snap_tol()`, replacing the 5 px literal for every smart guide snap
  (drawn points, moves, bounding-box handles, ruler guides, artboards,
  reference points). The tools gate their `Overlay::Measure` readouts on
  Measurement Labels (drawing, moving, ruler guides, artboards) or
  Transform Tools (scaling, rotating, Free Transform, transform tools).
- engine: `with_tool_cx` fills them from `Prefs` (the colour parsed, magenta
  as fallback); the colour's default is `#ff3dfc`, what the tools drew.
- ui-egui: the hover outline needs Object Highlighting and Smart Guides.
- Tests in tools (guides, select), engine (tests_prefs) and the canvas;
  docs/mcp.md and ROADMAP.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-08 15:46:15 +07:00
bflatasticandClaude Opus 5.5 297f6e93d3 Fix #455: the toolbar's double arrow and Window › Toolbars switch one/two columns
The toolbar went to two columns whenever the window was shorter than the
single column (about 990 pt for Basic, more for Advanced), so on most
screens it was always double and the double arrow and the Window menu item
flipped a flag nothing read. The column count is now the user's choice
alone; a window too short for the tools scrolls them (#84).

- window.toolbarColumns takes {double?: bool} (set or toggle, returns the
  new state) and reports `checked`; the double arrow runs it.
- The Window › Toolbars item reads "Double Column" with a check mark;
  catalogs updated (cs, es, ja, pt-br, zh-hans, zh-hant) and an es @msg row
  for the new error.
- Headless tests: the arrow and the command toggle the column count in a
  700 pt window (both fail on main).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:38:54 +07:00
bflatasticandClaude Opus 5.5 5d65699043 Part of #451: guides dragged out of the rulers snap, artboard guides
Guides dragged out of a ruler did not snap at all (only Shift to the ruler's
ticks): they now go through the engine (`Session::ruler_guide`, a
`NewGuide` previewing `guide.add`, one undo step) and snap as a moved guide
does: with Smart Guides to the edges, centres (so the sides' midpoints) and
anchors of the art and of the artboards, labelled; with Smart Guides off,
View > Snap to Point pulls new and moved guides onto anchors. Moving art
with the Selection tool already snapped flush to artboard edges and centres
with Smart Guides on; a test now covers it.

Artboard guides: `Guide.artboard` holds an artboard id (written only when
set, so canvas guides save as before and older files open unchanged).
`guide.add {artboard}` makes one, `guide.list` reports it; a guide dragged
out of a ruler with the Artboard tool belongs to the active artboard. It is
drawn, picked and snapped to across its artboard only, moves with it
(`artboard.move`, a pure move in `artboard.setProps`, `artboard.rearrange`),
is copied with it (`artboard.duplicate`, Alt-drag copy) and deleted with it
(`artboard.delete`, the guide selection kept in step).

Guides as Layers rows with their own lock and hide (part d) stay open: ruler
guides are not layer nodes; Lock Guides locks them all, and Make Guides
paths are Layers rows already. Listed in the ROADMAP parity row.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:23:18 +07:00
bflatasticandClaude Opus 5.5 a0819151a0 Fix #446: copy and paste artboards with their art
With the Artboard tool chosen, Copy and Cut take its artboard together with
the art fully inside it (when Move/Copy Artwork with Artboard is on), and
Paste brings both back in one undo step: Paste right of the last artboard,
Paste in Place / in Front / in Back where it was, into this or another
document, the art going back into the layers it came from (Paste on All
Artboards pastes the art alone). The clipboard carries the artboard
(Clipboard::artboard); a pasted artboard keeps its name when it is free.

Duplicate Artboards (the Artboards panel menu, and now a row dragged onto
New Artboard) copies the art too: artboard.duplicate {index?, art?} defaults
to the Artboard tool's artboard and moveArt option and reports the copies.
It shares copy_artboard with the Alt-drag copy (artboard.move {copy}).

New commands reachable over MCP: artboard.copy and artboard.cut
{index?, art?}; edit.copy / edit.cut run them while the Artboard tool is
chosen (and are enabled then with nothing selected). Docs (mcp.md), the
tool and panel docs, translations of the new labels and the ROADMAP follow.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 15:02:33 +07:00
bflatasticandClaude Opus 5.5 f46527e0bd Fix #444: tool cursors are OS cursors, so the pointer no longer trails over the canvas
Over the canvas the window hid the system cursor and painted the tool's
cursor glyph into its own frame. That glyph reached the screen only after
the frame was rendered, queued (two frames by default) and composited, so
on Windows it visibly trailed the real pointer, on any GPU: the "sluggish
mouse" of the report. Frame times were not the cause (0.4 ms empty,
1.5 ms median on a 20 000-path document, and no repaints while idle).

- cursors: the glyphs are collected as shapes, tessellated by egui and
  rasterized into straight-alpha RGBA bitmaps (anti-aliased, hotspot on a
  pixel corner), cached per cursor and display scale so the same Arc is
  handed over every frame and egui-winit keeps its OS cursor.
- canvas: on Windows and Linux the tool cursor goes to the OS through
  ctx.set_cursor_image; the system moves it itself. macOS (bitmaps sized
  in points) and the web (no bitmap cursors in eframe) keep painting it.
- app: the wgpu surface queues one frame instead of two (LOW_LATENCY):
  the GPU only composites the CPU-rendered canvas, so everything drawn in
  the window follows the pointer a frame sooner.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:41:22 +07:00
bflatasticandClaude Opus 5.5 7c7ce7f4fb i18n: Spanish messages say aplicación and match the UI's wording (review of #441)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:34:20 +07:00
Eliezer Hernandez f44155e098 i18n: Spanish translations for error and status-bar messages 2026-10-08 14:34:20 +07:00
bflatasticandClaude Opus 5.5 64cbee2a96 Fix #443: installed fonts outside the font folders and fonts installed while the app runs reach the font menus
The scan read only the platform's font folders, once per session (or on
Character panel menu > Refresh Font List). Fonts Windows registers outside
its font folders (installed as shortcuts, or by programs into their own
folders) never listed, nor did fonts installed while the app was open.

- Windows: the font files registered under the local machine's and the
  user's Fonts registry keys outside the scanned folders are scanned too
  (windows-registry, the windows-rs project's safe registry API).
- Linux/BSD: the XDG data folders' fonts (XDG_DATA_HOME, XDG_DATA_DIRS:
  Flatpak, Snap, NixOS, Guix) and a Flatpak sandbox's host fonts
  (/run/host/fonts, local-fonts, user-fonts); macOS: /Network/Library/Fonts.
- The global database looks the platform's paths up again at each scan,
  and a scan's roots may be font files as well as folders.
- FontDb::installed_fonts_changed compares the folders the last scan read
  (their modification times, and the paths it started from); the app
  checks it when its window comes back to the front and rescans
  (text.rescanFonts) only when fonts were installed or removed meanwhile.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 14:03:53 +07:00
bflatasticandClaude Opus 5.5 17f66003cf Fix #439: Shape Builder erase mode deletes edges, shows what will go and follows Alt live
Alt already deleted regions and pieces of open lines, but erase mode had
no edges of closed shapes, no distinct pointer, highlighted regions in the
merge-mode grey, only noticed Alt on a mouse move, and an erase drag could
flip mode at release. Like the reference app's erase mode:

- pathops::shape_builder(shapes, edges) returns a BuilderArrangement; with
  `edges` it also cuts the outlines of closed (and filled open) paths
  wherever other paths meet them. pathops::cut_out removes such a piece
  from a path: a closed subpath opens there, an open one splits or
  shortens, a piece all the way round takes its subpath, and a filled open
  path's invisible closing edge never comes back as a visible segment.
  Specks where paths only touch cut nothing; a zero-length input is no
  longer the source of edges running through it. encloses_area is shared
  with the tool's closing of filled open paths.
- BuilderMap (with_edges) hit-tests edges like line pieces (nearest wins);
  an erase gesture that crosses an edge into a region deletes the region,
  not the edge (erased_edges).
- shapeBuilder.merge {erase}: deletes the edges touched within tolerance
  (from every shape along them), after the regions; returns `edges`.
  shapeBuilder.regions lists `edges` (bounds, source). One undo step.
- Shape Builder tool: Alt held switches to erase mode and back on release:
  red mesh/edge highlights of what will be deleted, a minus pointer
  (Cursor::ShapeBuilder / ShapeBuilderErase, a plus in merge mode); a drag
  keeps the mode it started in. The canvas re-hovers the tool when a
  modifier changes, so the highlight follows Alt without a mouse move.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:37:35 +07:00
bflatasticandClaude Opus 5.5 97906f2104 Toolbar: a click on the tear-off bar floats the group, window.floatTools, strips in workspaces (review of #437)
- A click on a flyout's tear-off bar, or the release of the long press
  that opened it over the bar, tears the flyout off too, as in
  Illustrator; dragging it still does.
- window.floatTools {tool, floating?} floats or puts back the group
  holding a tool, for the control channel and MCP's invoke_menu.
- Floating strips are part of user workspaces; the built-in ones float
  none, so Reset puts them back.
- Loaded preferences keep one strip per group, of known tools.
- No per-frame clone of the strips or copy of the active tool's id.
- docs/control-protocol.md, ROADMAP, Float Tool Group translations.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:01:40 +07:00
Michael GiesonandClaude Opus 5.5 dcc8a24f66 Toolbar: tool flyouts tear off into floating toolbars
A grab bar runs down the right side of a tool group's flyout. Dragging it
tears the flyout off: the group floats as a strip of its tools' buttons
(the active one lit, each tool's name and shortcut in its tool tip), with
the bar on its right. The same bar moves the strip, and the × at the top
of the bar puts the group back in the toolbar. While a group floats, the
presses that would open its flyout (right, long or corner press) raise
the strip and flash its border instead, so a group is never both a
flyout and a floating strip. Floating strips are kept with the UI
preferences and kept on screen.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 13:01:25 +07:00
bflatasticandClaude Opus 5.5 b08188e5a5 Toolbar: only tool groups' buttons check for a flyout press, ROADMAP (review of #436)
A press on a single tool's button no longer schedules the repaint that
would open a flyout it doesn't have. The ROADMAP's UI list and Last
updated line name the right and corner press.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 13:01:25 +07:00
Michael GiesonandClaude Opus 5.5 e80b3543d3 Toolbar: a right press or a corner press opens a tool group's flyout at once
A right press opens the flyout on the press instead of on the release,
including on the active tool's button, and the release leaves it open. A
primary press on the button's corner triangle opens it at once without
picking the tool; a plain click in the middle still picks it. The long
press keeps scheduling the frame where it becomes long.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 13:01:13 +07:00
bflatasticandClaude Opus 5.5 a32aed7e81 Layers: only the trash and New Layer take dropped rows (review of #435)
Illustrator documents two drop targets in the Layers panel's bottom bar:
dragging items to Create New Layer duplicates them, to the Delete icon
deletes them. Dropping rows on New Sublayer or Make/Release Clipping
Mask no longer creates a sublayer or clips the row's layer; those
buttons only act on a click, and the new test checks a drop on New
Sublayer changes nothing. The trash and New Layer share one drop loop,
and the drag ghost paints its colour bar and thumbnail with the row's
own helpers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:58:21 +07:00
Michael GiesonandClaude Opus 5.5 a216c36779 Layers: drag ghost, drops on the bottom-bar buttons, trash deletes again
Dragging a row shows a dimmed copy of it (colour bar, thumbnail, name)
under the pointer. A row dropped on Delete, New Layer, New Sublayer or
Make/Release Clipping Mask runs that button on the row's layer, as a
click would: Delete removes the row itself and New Layer duplicates it,
as in Illustrator.

Rows dragged onto the trash weren't deleted. The trash took the drop as
a target-circle payload first, and egui's take discards a payload of
another type, so the rows reached the second check as nothing. It now
peeks at the type before taking. The trash is also outlined while rows
or a target circle are over it, like the other drop buttons.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 12:58:04 +07:00
Michael GiesonandClaude Opus 5.5 80f4de1a5e Layers: Layer Options' Color list shows a chip of each colour
Each preset in the Color dropdown has a chip of its colour before its
name; Custom has none, its name aligned with the others.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 12:58:04 +07:00
bflatasticandClaude Opus 5.5 1706e84829 Fix #429: Type on a path brackets, flip and Type on a Path Options that keep the type in place
Type on a path could only be repositioned by Type on a Path Options, whose menu item sent
`{start: 0}`, so OK threw the text to the start of its path; nothing showed or dragged its
brackets. Now, as in Illustrator:

- Type on a path flows between a start and an end bracket (`TextKind::OnPath { end }`, None:
  the end of the path or once round a closed one; `TextKind::path_span`). Flipping
  (`TextObject::flip_on_path`) reverses the path keeping a closed path's first anchor and swaps
  the brackets, so the type keeps its stretch of the path.
- Type on a Path Options gains Align to Path (ascender, descender, center, baseline) and
  Spacing (glyphs spaced as if set that far above the path: closed up round the outside of
  curves, opened up round the inside), laid out by the text engine.
- `type.pathOptions {start?, end?, flip?, effect?, alignToPath?, spacing?, ids?}` sets them in
  one undo step; with none of them it queries. The menu item opens the dialog with the selected
  type's Effect, Flip, Align to Path and Spacing (dropdowns for the choices) and leaves the
  brackets alone, so OK as opened changes nothing.
- The Selection and Direct Selection tools show selected type on a path's path and its start,
  centre and end brackets (`tools::pathtype`, with a bracket cursor): dragging the start or end
  bracket sets where the type runs, dragging the centre bracket slides it along the path and,
  across the path, flips it (Cmd/Ctrl held: it only slides). Each drag is one undo step.
- Arc-length measuring moved to `vectorcraft_geom::ArcPath` (layout, the tools and
  `text.createInPath` share it). SVG export outlines path type whose end bracket, alignment or
  spacing `<textPath>` can't express.
- docs/mcp.md documents the command and the drags; ROADMAP updated; dialog strings translated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:50:25 +07:00
bflatasticandClaude Opus 5.5 b86d19feed Appearance: the popover closes when its anchor isn't shown (review of #430)
The popover kept its open flag while its anchor was hidden (panel closed, selection changed), so
it came back open the next time the row was drawn. It now remembers the last frame it was open in
and counts as closed after a frame without it, as egui's remembered popups do. ROADMAP: the
Appearance panel's Opacity popup.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:27:26 +07:00
Michael GiesonandClaude Opus 5.5 e6914861f1 Appearance: the Opacity popup's blend list and slider work
egui remembers one open popup at a time, so opening the blend-mode
dropdown or the opacity slider inside the Opacity popup closed the popup,
and the dropdown or slider with it. A new widgets::popover keeps its own
open state and closes only on Escape, its anchor, or a click outside it
and the popups it opened. The Opacity popup and the Stroke popover (which
holds dropdowns too) use it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-08 12:27:06 +07:00
bflatasticandClaude Opus 5.5 f155bc5514 Stroke: keep the pt ladder, fix the fallback units and per-unit decimals (review of #426)
- The pt ladder stays 0.25 … 10, 20, 30 … 100 pt (the dropdown's documented 20/30/40 pt steps).
- Feet, yards and meters returned the pt ladder converted as if it were in that unit (a 100 m
  stroke); they now get the pt ladder in points.
- weight_presets returns a fixed array (no allocation per frame); the pica ladder is stored in
  points; 0.325 in is 0.375 in (the eighths ladder).
- Fields keep three decimals in points, pixels and picas (595.276 pt) and show four in mm, cm,
  inches and larger units (8.2677 in, 0.0078 in).
- ROADMAP: the Stroke panel's per-unit presets.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 12:27:06 +07:00
raytheengineerandClaude Opus 4.7 60439d88b9 Stroke: per-unit weight presets so mm/cm/in dropdowns show clean numbers
The Stroke panel weight dropdown converted one pt-based preset list into
whatever Units > Stroke was set to, which produced ugly rounded values like
0.088 mm, 0.265 mm, 10.583 mm from the pt ladder. Each unit now has its own
native ladder (observed from Illustrator's running dropdowns and typed in),
converted to pt once at use. Points, Millimeters, Centimeters, Inches,
Pixels and Picas each get Illustrator's actual values; the exotic Unit
variants (Feet & Inches, Meters, Yards, Feet) fall back to the pt ladder.

Picas round-trip to exact pt weights (1 pt, 12 pt, 60 pt …) but display as
decimal picas until Unit::number learns 0p1 / 1p3 notation; that is a
system-wide formatter change left for a separate PR.

Also bumps Unit::number precision from 3 to 4 decimals so Illustrator's
sub-eighth-inch strokes (0.0078, 0.0156, 0.0313, 0.0625 in) show their
authored values instead of rounding to 0.008 / 0.016 / 0.031 / 0.063.
Trailing zeros are still trimmed, so 1 pt stays "1".

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-10-08 12:26:47 +07:00
bflatasticandClaude Opus 5.5 b71d877a0a Fix #400: Scrub numeric fields by dragging their label
Dragging a numeric field's label left or right steps the field's value,
as Photoshop's scrubby labels do (beyond Illustrator): one unit every
2 points, ten with Shift, a tenth with Ctrl/Cmd (counts stay whole), in
the field's unit and precision. The panels apply each value as they
apply a typed one, so the art follows live and the caller's limits
hold (dragging back from a limit changes the value at once).

- scrub.rs: the label zone over the label noted just before a field
  (dim_label, label_row, widgets::field_label, the Character and
  Paragraph panels' icons, the Transform and Properties rotate/shear
  icons), the ↔ cursor on hover, a click on the label focuses the
  field. The text box itself never scrubs; a field without a label
  doesn't. num_field, plain_field, mixed_field (and the spin fields)
  and opt_field take part.
- Engine: undo groups (Session::begin_undo_group / end_undo_group). The
  edits made in a group, commands and committed live drags alike, are
  one undo step, journaled one by one; a cancelled group is undone and
  dropped from the journal. The app opens one while a label is dragged,
  so a scrub is one undo step whichever path the panel applies values
  by (app.run, session.execute, live_run), and Escape cancels it
  (shortcuts leave Escape to the drag, so it doesn't close a dialog or
  deselect).
- Preferences > General > Scrub Numeric Fields by Dragging
  (`scrubNumericFields`, on by default), translated in ja, es, zh-hans,
  zh-hant and pt-br.
- Tests: label drags with Shift/Ctrl, limits, counts and units, Escape,
  the preference, the cursor, click-to-focus, no scrub on the box or
  without a label, and in the app one undo step for a W drag.
- ROADMAP and docs/mcp.md.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 11:33:57 +07:00
bflatasticandClaude Opus 5.5 e04385e950 Fix #423: Movable dialogs and Offset Path's Joins dropdown
The modal dialogs were anchored to the window's centre, so none of them
could be moved. They now share one modal frame (dialogs/modal.rs): the
band from the window's top edge down to its heading moves it, as a title
bar would, with a grab cursor; it stays on screen and keeps where it was
moved (per dialog, for the session). The shared dialog frame, New
Document (and More Settings), Preferences, Keyboard Shortcuts,
Workspaces and Find Font all use it; About moves by its title bar.

The form dialogs drew every string field as a text box, so Offset
Path's Joins had to be typed. Their choice fields are now dropdowns
(Joins: Miter, Round, Bevel; Average's axis; Shear's and Reflect's
axis), the fields follow the dialog's order (Offset, Joins, Miter Limit;
Rows, Columns, Gutter) instead of alphabetical, and Offset Path has a
Preview that Cancel rolls back.

The axis labels are translated in a new "axis" catalog context: the
plain Horizontal and Vertical rows mean writing direction in Japanese.
ja, es, zh-hans and zh-hant get the axis rows (Horizontal, Vertical,
Both) and Joins, Miter, Bevel, Offset and Axis.

Headless tests drag the heading of four dialog windows (moves, a drag
below the heading doesn't, kept on screen, reopens where it was left),
open the Joins dropdown and choose Round (same result as the command
with round joins), and check the axis dropdowns and the preview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 10:52:05 +07:00
bflatasticandClaude Opus 5.5 8e3dbd5369 Part of #394: Preferences for snapping, handles, rubber bands, pattern tiles, tints and type
Fourteen more Preferences options that were stored but read by nothing now
act, for the mouse and for agents (prefs.set, then pointer_gesture,
press_key or the commands):

- Selection & Anchor Display: Snap to Point and its distance (with Smart
  Guides off, View > Snap to Point lands a dragged selection's grabbed
  point, drawn points and reference points on anchors and ruler guides);
  Move Locked and Hidden Artwork with Artboard (artboard.move, the Artboard
  tool and Rearrange; off, hidden art now stays too); Enable Rubber Band for
  the Pen and Curvature tools; Handles (solid, hollow, large);
  Show handles when multiple anchors are selected (canvas and Direct
  Selection's handle picking); Hide Corner Widget for angles greater than.
- General: Transform Pattern Tiles is the default of a new `patterns`
  param on object.transform/move/rotate/scale/reflect/shear/transformEach
  (journalled when the art uses a pattern), and the transform dialogs get a
  Transform Patterns checkbox; Select Same Tint % (off, Select > Same
  Fill/Stroke Color takes every tint of a global or spot swatch).
- Type: new type.step {attribute, by} steps size, leading, tracking, kerning
  and baseline shift by the Size/Leading, Tracking and Baseline Shift
  increments; Increase/Decrease Font Size (Cmd+Shift+. and Cmd+Shift+,);
  the Type tool's Alt+arrows (kerning at a caret or tracking, leading,
  Shift for baseline shift, Cmd/Ctrl for five steps). Enable Missing Glyph
  Protection keeps characters a new font lacks in the font that had them
  (text.setStyle, text.setRangeStyle). Fill New Type Objects With
  Placeholder Text: type the Type tools place starts with placeholder text,
  selected (text.create / text.createInPath take `placeholder`).

Units > General, Stroke and Type were already the single source of truth
(units.rs). Auto Size New Area Type, Show Font Names in English and
Highlight Alternate Glyphs need subsystems the app doesn't have yet and
stay open with the rest of #394.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:43:12 +07:00
bflatasticandClaude Opus 5.5 9a5429a325 MCP: inspect_document slices too, stricter find filters (review of #416)
- The inspect_document tool (and the control channel's document.inspect)
  take {depth?, childLimit?}, so MCP clients get the skeleton without
  going through run_command; the tool description points at the
  drill-down path.
- document.find rejects a filter of the wrong type instead of dropping
  it (which widened the search); one opt_u64 helper parses limit, depth
  and childLimit.
- docs/mcp.md spells out find's matching rules; control-protocol.md
  and ROADMAP updated; MCP and engine tests cover the new paths.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 09:17:06 +07:00
Fahri Meral e278ccf44d MCP: skeleton reads and find for large documents
document.inspect takes the same {depth?, childLimit?} slicing as
document.node (a depth-0 read is the layer skeleton), and document.find
{name?|kind?|text?, limit?} locates nodes across the tree with their
ancestor paths and a total. docs/mcp.md documents the drill-down recipe;
the CLI stdio sweep covers both.
2026-10-08 09:17:06 +07:00
bflatasticandClaude Opus 5.5 2f710d3acc Fix #414: select, move and delete ruler guides with the selection tools
Guides dragged out of the rulers could not be touched again: no tool hit-tested
them, so a click on a guide went to the art under it.

- The Selection, Direct Selection and Group Selection tools pick a ruler guide
  within the selection tolerance (over the art; Direct Selection takes an
  anchor on it first) through a shared tools::rulerguide::GuideEdit. A drag
  moves the selected guides in one undo step (Alt copies them, Shift snaps the
  dragged one to the ruler's ticks, otherwise it snaps to pixels, the grid or,
  with Smart Guides, the art's edges, centres and anchors); dropped off the
  canvas onto its ruler, the guide is deleted. Hidden or locked guides can't be
  picked; the pointer shows which way a guide moves.
- Selection::guides holds the selected guides (on their own, like slices); the
  canvas draws them in the selection colour. Delete/Backspace (edit.clear)
  delete them, the arrow keys (object.nudge) nudge them, Lock Guides and Hide
  Guides deselect them.
- Commands for agents: guide.list, guide.select {indexes, toggle?},
  guide.move {dx?, dy?, copy?} (besides {index, pos}) and guide.remove {index?};
  guide positions out of range are refused. Documented in docs/mcp.md.
- Shift while dragging a new guide out of a ruler snaps it to the ticks too
  (Unit::ruler_step, shared with the rulers' drawing).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:55:51 +07:00
bflatasticandClaude Opus 5.5 47bed05ff4 Part of #394: Preferences that act on selection, the wheel, tool tips and the grid
Fifteen Preferences options were stored but read by nothing. They now act,
through the existing plumbing (ToolContext for the tools, the prefs read by the
canvas for the view), and reach agents through prefs.set:

- General: Show Tool Tips (off: no widget's tool tip comes due), Double Click
  To Isolate, Zoom with Mouse Wheel (the wheel zooms about the pointer,
  Shift-wheel scrolls up and down, Cmd/Ctrl-wheel sideways), Use Precise
  Cursors (Pen, Eyedropper, Slice and Blend pointers become a crosshair).
- Selection & Anchor Display: Tolerance (objects, anchors and handles, in
  place of the fixed 3 and 4 px), Object Selection by Path Only (compound
  paths too), Command Click to Select Objects Behind (cycles down the objects
  under the pointer; not when Cmd only borrows the selection tool), Zoom to
  Selection (Zoom In/Out centre the selection), anchor Size, Highlight anchors
  on mouse over (Direct Selection).
- Type: Number of Recent Fonts (up to 15 Recent Fonts slots).
- Guides & Grid: guide and grid Color and Style (lines or dots), Grids In Back.

The canvas's context menu, panel drops and hover highlight pick objects like
the selection tools. The control channel gets ui.wheel (with modifiers held
like ui.click) so agents can turn the wheel. The rest of #394 stays open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 08:22:24 +07:00
Brandon ThomasandClaude Opus 5.5 f7a03160d6 About: contributor and model credits compiled in (grab bag + table, self-submitted names) (#411)
* About: contributors compiled in from contributors.json (grab bag + table, sortable, name toggle)

Help > About VectorCraft gains Contributors and Models tabs next to the existing About
content, following the craftrules standard (standards/contributors.md):
contributors/contributors.json is generated by craftrules/scripts/contributors.py and baked
into the binary by crates/ui-egui/build.rs as static tables (credits.rs). Each contributor
line: @username, opt-in display/real name, PRs, commits, lines +/-/delta, binary assets +/-,
first/last commit. Sortable by every column; alphabetical ignores case and the leading @.
Labels are translated (ja, zh-hant, pt-br catalog rows).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors docs: craftrules is two levels up (../../craftrules)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: self-submitted names in contributors/people.toml; AGENTS.md credit-yourself section

build.rs reads contributors/people.toml next to the generated contributors.json and shows a name only
for entries the generator verified as written by that person (craftrules standards/contributors.md).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* i18n: credits labels for catalogs added on main since this branch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate after rebase onto main

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Contributors: regenerate (verified people.toml entries)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 21:22:04 -04:00
bflatasticandClaude Opus 5.5 4767ec7113 Fix #398: Linux/Wayland bitmap paste, copied files paste as art
Under Wayland the window is native but arboard was built without its
data-control backend, so it read the X11 clipboard through XWayland,
which only holds what X11 apps copied: Paste found nothing and reported
an empty clipboard (egui's text paste into fields uses smithay-clipboard,
which is why that worked). arboard now has `wayland-data-control`, the
same as PhotoCraft; it falls back to X11 where the compositor lacks the
protocol (GNOME's Mutter).

The reporter's clipboard also held text/uri-list: with a file copied in a
file manager, Paste would have taken the path as text before the bitmap.
Copied files now paste first, as the first one that is art (SVG, PDF,
EMF/WMF or a bitmap), told from its first 4 KiB by the engine's format
detection (`clipboard::file_flavour`): text/uri-list through arboard on
Linux and macOS (a trailing CR from CRLF lists trimmed), CF_HDROP on
Windows, read with the clipboard closed again.

Dropping files on the window can't work under Wayland yet: winit 0.30,
which eframe 0.36 runs on, has no Wayland drag and drop (winit#1881,
added in 0.31), so no dropped_files arrive. docs/development.md documents
it and the workarounds (copy and paste the files, File > Place, or run
under XWayland with `WAYLAND_DISPLAY=`).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:44:23 +07:00
bflatasticandClaude Opus 5.5 d324138bc1 Fonts: drop the plain font dropdown now that no picker uses it (review of #397)
Find Font and the Glyphs panel were widgets::font_dropdown's last
callers; the font menu's own tests cover searching and Enter. ROADMAP:
the Glyphs panel and Find Font's Replace With use the font menu, without
its live preview.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:32:12 +07:00
DWAA1660andClaude Opus 5.5 1d5e9cb239 Find Font and Glyphs: pick fonts from the font menu (#358 follow-up)
Both switch from widgets::font_dropdown to font_menu::font_menu, so they
get the same samples, favourites and filters as the Character and
Properties panels. They only pick a font: the new font_menu::picked
returns the choice and toggles stars, and never previews on the document.

Follow-up to #339 as suggested in #364.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BRE8ZD3p8QgYctENhnJDz3
2026-10-08 07:32:11 +07:00
bflatasticandClaude Opus 5.5 18cbe007b8 Character Alignment: on a character range too, with the East Asian options (review of #389)
text.setRangeStyle takes charAlign, so the panel menu works on the
characters selected with the Type tool (it routes there while text is
edited, and charAlign alone was answered with "nothing to change").
One char_align_param parses it for both commands. The menu shows with
Preferences › Type › Show East Asian Options, like Mojikumi Set and
Top-to-Top Leading. Rows in the Simplified Chinese, Spanish and
Brazilian Portuguese catalogs; the Japanese Em Box Center names the em
box. ROADMAP: the gating, the range command, and ICF top/bottom still
missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:32:11 +07:00
imachusandClaude Opus 5.5 178ca03eba Type: Character Alignment — where smaller characters line up with a line's largest
Characters of different sizes on one line all sat on the Roman baseline.
Japanese layout usually lines them up by their ideographic em boxes
instead (a 16 pt 第一回 next to 32 pt 雅楽 centred on it, not sitting on
its baseline). The Character panel menu now has Character Alignment:

- `CharStyle.char_align`: Roman Baseline (as before, the default), or the
  em box Top/Right, Center or Bottom/Left: a character smaller than the
  line's largest moves so that its em box top, centre or bottom lines up
  with the largest's (the em box from the font's vertical metrics, else
  0.12 em below the baseline to 0.88 em above it). Vertical type the
  same across the column (top → right). Written only when not Roman
  Baseline.
- `text.setFormat {charAlign: "romanBaseline"|"emBoxTop"|"emBoxCenter"|
  "emBoxBottom"}`; the menu shows the selection's setting; catalog rows
  in ja and zh-hant.
- Not yet: aligning on the ICF (average character face) top and bottom.

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