winit maps CursorIcon::ZoomIn/ZoomOut to the plain arrow on Windows, so
the Zoom tool showed no cursor feedback there. Draw the magnifier (plus,
or minus while Alt zooms out) as an OS cursor bitmap, like the Hand
tool's #2196 fix; macOS and Linux keep their stock zoom cursors. Camera
Raw's preview zoom uses it too.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(channels): Channel Options dialog to make alpha channels spot colours (#3761)
Double-clicking an alpha channel's thumbnail in the Channels panel now opens
Photoshop's Channel Options dialog (double-clicking the name still renames it):
Name, Color Indicates Masked Areas / Selected Areas / Spot Color, the overlay
or ink colour (Color Picker) and Opacity, which becomes Solidity for spot
channels. A saved selection can now be turned into a spot channel with its own
ink for screen-print separations. The row context menu gains Channel Options…
and Quick Mask Options…, and `channel.options` without params from a menu
opens the dialog on the targeted channel. OK runs the existing engine command,
so agents can still call it directly with params.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* style: rustfmt module order in ui-egui lib.rs
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* feat(channels): New Spot Channel dialog (#3761)
Channels › New Spot Channel… now opens Photoshop's dialog instead of adding
a channel straight away: Name (prefilled with the next free "Spot Color N"),
and Ink Characteristics: Color (opens the Color Picker) and Solidity. OK
creates the spot channel from the selection, as before, and remembers the ink
and solidity for next time. `channel.newSpot` with params still runs the
engine directly for agents, the CLI and MCP. The engine's `next_alpha_name`
helper is now public so the dialog's name matches the engine's default.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: keep main's Czech rows, add Vietnamese strings (#3761 review)
- cs.tsv: main has removed its duplicate copies of Tool, Stroke Path…,
Clone Stamp, History Brush, Dodge, Burn and Sponge, so this branch keeps
main's single rows; the only Czech change is the Channel Options / New Spot
Channel block.
- vi.tsv: the Vietnamese catalog is complete since #2636, so it gets rows for
Channel Color, Color Indicates:, Solidity: and Ink Characteristics.
- it.tsv: main now translates Masked Areas and Selected Areas, so this
branch's duplicate rows are dropped.
Every catalog now only adds lines relative to main.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Channel Options: Serbian, Hungarian and Turkish rows for the new strings
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The font menu's preview samples, family list and localized names were
cached on fonts::generation(), which any FontDb moves, and the previews
also on the served catalog's generation. Other engines registering fonts
(tests running in parallel) re-rendered every visible sample each pass,
and families covering Arabic asked for a repaint, so Harness::run never
settled: options_font_family_preserves_peer_faces_and_batches_layer_flags
and the font picker tests failed intermittently with "exceeded max_steps".
- photocraft-text: fonts::shared_generation(), moved only by the shared
engine's FontDb (FontDb::mark_shared from new_shared).
- ui-egui: families(), localized_families() and the preview cache key on
it; previews no longer key on the served catalog (a served family's
sample appears when its fonts register, which moves the generation).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
The "web build and wasm size gate" job failed on main and every PR: the
release `_bg.wasm` measured 25,379,677 bytes at 8d49ecf5, over the
25,165,824-byte limit in packaging/web/package.sh.
- egui's default fonts (Ubuntu Light, Hack, Noto Emoji, emoji-icon-font)
were embedded uncompressed (1.4 MB) by egui's `default_fonts` feature.
The app now builds egui without it; ui-egui's build.rs deflates the
same files from the `epaint_default_fonts` crate (a build-dependency,
so no font files are committed) and `egui_fonts.rs` rebuilds egui's
exact default stack from them on first use. Test builds keep the
feature as the oracle: the rebuilt definitions equal egui's byte for
byte.
- Translation catalogs: every catalog repeated the same English sources.
build.rs now stores the `context<TAB>source` keys once and each catalog
as references plus translations, losslessly (`text()` still returns
each .tsv byte for byte; malformed lines are kept as they are).
- wasm-release profile: opt-level "z" for PhotoCraft's own crates.
Dependencies stay at "s" (at "z" the wasm grew 0.4 MB, measured), the
file-decoding crates (codecs, psd, raw, heif, vector) stay at "s" and
the pixel crates at 3, so decoding and filters keep their speed.
Measured with `trunk build --release` (trunk 0.21.14, wasm-opt v123 -Oz):
upstream main 8d49ecf5 25,379,677 bytes
this change 24,167,186 bytes (-1,212,491)
gate 25,165,824 bytes (998,638 headroom)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* View: remember Extras, Show and Snap To across restarts (#3762)
View › Extras, the View › Show items (Pixel Grid, Grid, Guides, …) and
the View › Snap To targets reset to their defaults on every launch. They
are now saved in Preferences (`viewExtras`) as they change and restored at
startup, as Photoshop keeps them between sessions.
Only items that differ from their defaults are stored, so a default
changed in a later release still reaches users who never touched it. A
hand-edited file can't break them: unknown keys and non-boolean values
keep their defaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* View: rustfmt the view-extras restart test (#3762)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Dragging a document tab more than 24 pt above or below the tab strip now
tears it off into a separate OS window placed where it was dropped, so it
can be moved anywhere, other screens included (as in Photoshop). Sideways
drags still reorder. Both tab strips share the new tab_drag helper.
window.arrange.floatInWindow takes optional `document` and `position`
params (validated: bad values are errors, not panics); DocWindow gains a
serde-default `position`.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>