Commit Graph
1127 Commits
Author SHA1 Message Date
bflatastic 2f0369a7ad Merge #372: fix(engine): new text is readable on the frame it is drawn in (#362) (@vxMacDev) 2026-10-15 15:07:17 +07:00
bflatastic 457c688872 Merge #293: M1: a press on a corner handle resizes instead of picking the corner-radius handle (@marcoarnulfo) 2026-10-15 15:07:14 +07:00
bflatastic 0b364ae1fe Merge #271: M7: double-clicking a page in the Pages list no longer closes the app (@marcoarnulfo) 2026-10-15 15:07:11 +07:00
Andrii VolkovandClaude Opus 5.5 9eadb37622 perf(ui): look for CJK names in edits, not on every pan
Each frame checks the active document's names for CJK scripts, to install
faces for them. The check was keyed on the revision, which pans and zooms
bump too, so every frame of a pan read every layer name. In a 900 000-layer
file that was ~70 ms a frame: panning ran at ~14 fps whatever the canvas cost.

It now keeps the document version it read: the same version (a pan, a zoom)
is skipped, and a new one reads only the layers that changed since
(`Document::changed_ids`, sized by the edit), or every name past 10 000
changes. On that file the UI frame while panning went from ~71 ms to ~3 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YQxjkNSUJhTkTfY74aNeki
2026-10-15 10:47:23 +03:00
Reva Doni AprilioandClaude Opus 5.5 627933ae06 M9: Indonesian draft catalog
Adds crates/ui-egui/locales/id.toml, a draft Indonesian catalog covering
every UI string (1,577 keys), command label (557) and menu wording (31),
machine-drafted and marked "draft — needs native review".

Indonesian keeps a noun unchanged after a count, so plural entries give
only `other` and plural_one needs no change. Preferences ▸ Language lists
Bahasa Indonesia; System maps id / id_ID to it (new assertion in
i18n_tests.rs) and `id` joins the cjk can-show list. Docs updated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 14:39:08 +07:00
Andrey 8c74c72b50 Merge branch 'main' into fix/261-startup-failure-dialog 2026-10-15 10:15:53 +03:00
Andrey 17a3e2b6d6 Merge branch 'main' into fix/224-variables-collection-crash 2026-10-15 10:15:49 +03:00
Andrey e4126949bf Merge branch 'main' into fix/255-shadow-behind-blur 2026-10-15 10:15:46 +03:00
Andrey 15ca8d4881 Merge branch 'main' into fix/203-189-image-memory-budgets 2026-10-15 10:15:42 +03:00
Andrey 704831830e Merge branch 'main' into fix/210-deep-nesting-stack 2026-10-15 10:15:39 +03:00
Andrey de30e34538 Merge branch 'main' into fix/187-keep-recovery-until-recopied 2026-10-15 10:15:36 +03:00
Andrey 4e5ff2bd46 Merge branch 'main' into fix/style-folder-rename-focus 2026-10-15 10:15:32 +03:00
Andrey 6fbf3ca9aa Merge branch 'main' into fix/333-engine-tests-scan-fonts 2026-10-15 10:15:29 +03:00
Andrey e41e12324d Merge branch 'main' into fix/183-compaction-keeps-edits 2026-10-15 10:15:26 +03:00
NetterSilverandClaude Haiku 5.5 7f2f8ee09a Refuse negative or fractional indexes in page.select and doc.switch
Found while testing crates/engine/src/cmd/page.rs:50

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 08:02:06 +02:00
IanHollow 611fb324b9 M7: find Unix user fonts under XDG_DATA_HOME
Assisted-by: GPT-6
Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-14 22:59:17 -07:00
Rob Coenen 1b67ac1e6d Merge remote-tracking branch 'origin/main' into claude/wonderful-neumann-adc42b 2026-10-15 01:15:53 -04:00
LosminekandClaude Opus 5.5 49a2c643c6 i18n: add Czech (cs) UI catalog as a draft
Adds crates/ui-egui/locales/cs.toml with all 2165 entries (ui, commands,
menu), marked "draft — needs native review" and kept out of COMPLETE.
Plurals use one/other only; the other form is worded count-neutral so it
reads correctly for 2-4 as well. Lists cs in the pref.language help text,
adds a cs_CZ.UTF-8 detection test and updates the localization docs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 07:01:27 +02:00
Rob CoenenandClaude Opus 5.5 996852d15c M4: hanging punctuation test holds for fonts that kern with x offsets
On macOS without craft-fonts the default face is Helvetica Neue, whose
kerning comes out of the shaper partly as an x offset (e.g. on the "e" of
"here."), so a glyph's x + advance is not its pen end. The layout was
right (the full stop's pen sits exactly on the edge); the test assumed no
offsets. Each hanging line is now compared with the same line set flush:
every glyph must move by exactly the hanging mark's advance, and the flush
right line must end on the edge.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 00:55:43 -04:00
NetterSilverandClaude Haiku 5.5 1199f690ad Fix Send to back leaving layers above siblings across frames
Found while testing crates/engine/src/cmd/arrange.rs:327-330

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 06:12:21 +02:00
Rob Coenen 099465212e Merge remote-tracking branch 'origin/main' into vector-edit-canvas-stays-put
# Conflicts:
#	crates/ui-egui/src/home_tests.rs
2026-10-14 23:57:57 -04:00
Andrey 8482c3e85b M7: home tests wait for the recent files reader instead of a fixed frame count (#351) (#354) 2026-10-15 05:53:18 +02:00
skylar taylor-barrickandskylartaylor 3a1aeb7a4b ci: add comfortable runtime limits to unbounded jobs (#397)
Co-authored-by: skylartaylor <26588250+skylartaylor@users.noreply.github.com>
2026-10-15 05:15:58 +02:00
Edivan TeixeiraandClaude Opus 5.5 13691c1cc0 Let batch steps reference ids created by earlier steps
Inside command.batch, `{"$step": n}` anywhere in a step's params is
replaced by the `id` in step n's result before the step runs
(`{"$step": n, "field": "..."}` picks another field). A nested tree,
such as a frame with children, now takes one batch and one undo step,
not one round-trip per level with ids copied between calls by hand.

Malformed references (forward or self, negative or fractional index,
missing or non-string field, extra keys) fail the batch with BadParams
naming the step, and the existing group machinery rolls it back. The
params walk is depth-capped. Steps are journalled with resolved params.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 23:43:31 -03:00
NetterSilverandClaude Haiku 5.5 d1430e3054 Keep text selection highlight inside the box at the end of the text
Fixes #365

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:56:27 +02:00
NetterSilverandClaude Haiku 5.5 fc6f52e852 Keep corner resize cursors diagonal on wide and tall layers
Fixes #370

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:50:00 +02:00
NetterSilverandClaude Haiku 5.5 3c00ea6440 Outline stroke on every selected layer, not just the first
Fixes #378

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:41:17 +02:00
NetterSilverandClaude Haiku 5.5 3d90d8edfe Keep View toggles such as Rulers in the preferences
Fixes #379

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 03:33:28 +02:00
NetterSilverandClaude Haiku 5.5 87b9a3a9ce Reject negative or fractional index in effect.set, export.update and export.remove
Found while testing crates/engine/src/cmd/edit.rs:256 (effect.set), :305 (export.update), :317 (export.remove)

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-15 01:08:36 +00:00
vxMacDev 12d4dbfbc9 fix(engine): new text is readable on the frame it is drawn in (#362)
The colour of new text in the app was chosen from the page alone, so
on a dark page text drawn in a white frame (a new frame's default) was
white and invisible. readable_text_fills now looks at what the text is
drawn on: the nearest layer from its parent out whose top visible fill
is a mostly opaque solid colour, else the page. The Text tool and
text.create / node.create pass the text's parent.

The two tests that asserted the page-only rule in a frame now expect
black text in a white frame; new cases cover dark, unfilled, nested,
faint and stacked fills, and the Text tool.
2026-10-14 18:35:21 -05:00
Mateus Villain 3edb15c417 M1: copy and paste through the system clipboard in the browser
The web build's Services never wrote to the clipboard, so Cmd+V after
Cmd+C got the paste event with whatever text the clipboard held before
and made a text layer of it instead of pasting the copied layers.
WebServices now writes copies (text and PNG) through egui's output,
which eframe hands to the browser clipboard during the copy event.
2026-10-14 20:26:18 -03:00
Ahmed5Emad 93a75a4720 M1: adding auto layout to an existing frame keeps its size instead of hugging 2026-10-15 02:02:00 +03:00
Mateus Villain 01a0f4f332 M3: variables export as a download in the browser
The web build has no save dialogs, so Export… ▸ Variables JSON / CSS
custom properties returned silently. Services gains downloads() and
download(name, bytes); the browser hands the file over through a Blob
link, and the variables panel uses it where the platform saves by
downloads.
2026-10-14 20:01:53 -03:00
vxMacDev b87d2e476f fix(engine): drag with the Text tool to make a fixed-width text box (#360)
The Text tool made its text on the press and ignored the drag, so a
drag gave auto-width text like a click. The new text now stays in a
TextBox gesture while pressed: past the drag slop it becomes a box as
wide as the drag, its top-left at the drag's, with a fixed width and a
height that follows its text. A click, or a drag within the slop, still
makes auto-width text.
2026-10-14 17:29:09 -05:00
NetterSilverandClaude Haiku 5.5 2aa3ca3c45 Make edit.findReplace replace case-insensitive matches
Found while testing crates/engine/src/cmd/edit.rs:962-977

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 22:26:37 +00:00
Skyfuller1303 39d0f2d872 M7: show windowed text and sidebar sharpness close-ups 2026-10-15 00:15:01 +02:00
Skyfuller1303 7a8e5373b1 M7: keep Windows windowed UI and canvas text sharp 2026-10-15 00:02:41 +02:00
NetterSilverandClaude Haiku 5.5 c02e864873 Replace every occurrence in edit.findReplace when replacement contains find
Found while testing crates/engine/src/cmd/edit.rs:975-981

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-10-14 21:22:29 +00:00
Rob CoenenandClaude Opus 5.5 3c03f370f9 M1: Cmd+R rename test sends Ctrl+R only where Ctrl is the command key
On macOS egui never sends `ctrl` together with `command`; Ctrl comes alone there
and Ctrl+R isn't a shortcut (rename is Cmd+R or F2), so case 1 failed on every
macOS run. The keymap is right; the test now presses Ctrl+R only off macOS.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-14 17:07:05 -04:00
vxMacDev 8efb66ba19 fix(ui): step through the font picker with Up and Down (#345)
Up and Down now move a highlight through the family list, starting
from the current family and scrolling to keep it in view. The text
panel previews the highlighted family on the canvas, as it does for a
hovered font style, and Enter applies it. Escape leaves the text as it
was.
2026-10-14 15:24:40 -05:00
midasmatterhorn 65e52aa7b9 engine: long digit strings no longer overflow object.opacityKeys
opacity_from_digits multiplied and added on every character of its input
string before the one-or-two-digit check, so "9999999999" overflowed u32 on
the way (panic in debug builds, wrap in release). The scan now steps n with
checked_mul/checked_add and stops (None) at the first character the number
cannot take, so a long digit string is refused like any other bad input.

Test: opacity_digits (engine keymap) covers the ten-digit string and the
command's BadParams refusal.
2026-10-14 23:22:41 +03:00
IanHollow 1ddc2c338b Fit contributor columns inside the About window
Assisted-by: OpenAI Codex (GPT-6)
Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-14 13:12:53 -07:00
IanHollow 212438a6e3 Set the native window identity to match the desktop entry
Assisted-by: OpenAI Codex (GPT-6)
Signed-off-by: IanHollow <72767437+IanHollow@users.noreply.github.com>
2026-10-14 13:12:38 -07:00
HaSh3003 f387d3f464 M9: translate Remove from session
The menu item and the collab.removePerson label in es, de, fr, ja, ko, pt-BR and zh-Hans (es must be complete).
2026-10-14 23:00:42 +03:00
Barzabel 90a4606c65 M9: a compaction cut short closes the file instead of confirming lost edits (#183) 2026-10-14 22:53:02 +03:00
midasmatterhorn 245837ff27 doc: name counters stop at u64::MAX instead of overflowing
Document::next_name summed max + 1 over numbers parsed from existing layer
names, and bump_name did the same for the duplicate-rename path: a document
(or peer, or node.set) holding a layer named "Frame 18446744073709551615"
overflowed both (panic in debug, wrap to a wrong name in release). next_name
now collects the numbers it sees and, when the counter is spent, picks the
lowest free number (mirrors new_style_id); bump_name only bumps when the
number can step, else falls to its existing " 2" branch.

Tests: next_name_never_overflows (doc) and
duplicating_a_layer_named_past_the_counter_does_not_overflow (engine panel
behaviour).
2026-10-14 22:52:15 +03:00
midasmatterhorn ca2f5dbcee collab: refuse sequence numbers a host cannot advance
The welcome's seq and processed.last_batch are the host's word and were used
unchecked: accepted computed self.seq + 1 and queue bumped next_batch, so a
host sending u64::MAX overflowed the client (panic in debug, wrap in release).
Both counters now step with checked_add/saturating_add, and a sequence that
cannot advance is refused as a protocol error (the established rejoin path).

Test: hostile_sequence_numbers_do_not_overflow_the_client.
2026-10-14 22:47:51 +03:00
Barzabel 5e14632207 M1: cursor and double-click tests scan the system fonts themselves (#333) 2026-10-14 22:39:17 +03:00
HaSh3003 fa0365470e M9: remove someone from a live session
Right-click a person's avatar ▸ "Remove <name> from session", or
`collab.removePerson {client}`, when you host the session or own the file
on a server. The hub closes their connection as the end of the session for
them (close 1001: they keep their copy and don't reconnect) and bars their
address from that file while it runs, so the code or link they hold no
longer gets them in; everyone else stays connected.

Protocol addition within version 2: `Admin::RemovePeer {file, client}` on
an open hosting connection with the file's owner token (or the server
key). Older servers say they can't.

Tests: loopback (removed, can't rejoin, others stay), engine (host can,
guest can't, bad ids refused), codec round trip; the collab junk sweep
covers the new command.
2026-10-14 22:32:56 +03:00
Barzabel b8043cc2ad M3: renaming a style folder no longer closes the app 2026-10-14 22:23:51 +03:00