* Linux: a virtual keyboard claiming BTN_TOOL_PEN no longer sends the window through Xwayland (#5284)
On Wayland the app opens its window through Xwayland when a pen is attached
(#639), and it took any input device whose key bitmap has BTN_TOOL_PEN for a
pen. A virtual keyboard made with uinput (RustDesk's, for one) claims every
key code, that one included, so the window went through Xwayland on machines
with no pen at all. On a fractionally scaled desktop (GNOME 46 at 125%) the
X11 window is drawn at the logical size and upscaled by the compositor, so
the UI came out blurred even though Auto UI Scale already followed the
system's 1.25 (#1237): native Wayland, where winit negotiates
wp_fractional_scale_v1 and renders at the physical 3840 px, was never used.
A pen now also needs ABS_X and ABS_Y in its absolute-axis bitmap, as
libinput asks of a tablet tool; a keyboard has no axes. Regression tests
with the virtual keyboard's own bitmaps, a pen beside it, and a pen display.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* Docs: on a fractionally scaled Wayland desktop, Xwayland is blurred and native Wayland has no file drops (#5284)
Say where the trade-off is: a native Wayland window is sharp at 125%,
150% and 175% but takes no dropped files (#386); an Xwayland window takes
drops and pen input (#639) but is enlarged by the compositor. List the ways
to open through Xwayland and what counts as a pen.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
When appearance mode was toggled between dark and light with default
settings, PhotoCraft switched from Pro Medium (Pro layout) to Studio Light
(Studio layout), altering the UI and displaying a Fit button in the status
bar.
Now that the Photoshop Pro light brightness levels exist (#2661), default
the saved light theme to Pro Light so the Pro interface layout and status
bar are preserved when toggling appearance. Also map the "light" alias to
Pro Light and list the Pro options first under Light Theme preferences.
Fixes#5016.
A translated label beside a fixed-width control could run over its neighbours: the Layers
Lock/Fill row guarded only the redundant "Lock:" caption, so "Fill:" ("Заливка:" in Russian,
longer still as pt-br "Preenchimento:" / fr "Remplissage :") overlapped the lock icons.
Rather than a per-row fit check, add the one shared primitive for fixed chrome:
`widgets::elided_label(ui, text, max_w)` lays the text out no wider than its room, cuts it with
'…' and puts the full string on hover (built on the existing `tab_strip::elided`). The
Opacity/Fill scrub labels now elide to the room beside their field, so any translation shrinks
instead of overlapping, in every locale.
Documented the rule in docs/ui-design.md: wrap by default; beside a fixed control, elide; a
redundant caption may drop on a narrow dock (the lock icons carry the meaning).
Test: widgets::tests::elided_label_never_exceeds_its_room. Full photocraft-ui-egui suite: 2077
pass; fmt and clippy clean.
Load Work Path, saved path and layer path thumbnails as selections on
Ctrl/Cmd-click. Support Shift to add, Alt to subtract and Shift+Alt to
intersect, without changing the selected path or treating the click as
Save Path. Clicking the row name keeps its existing selection behavior.
Render uncached shape transparency instead of selecting the entire canvas.
Add regression tests for thumbnail hit testing, active-layer preservation,
selection combinations, undo/redo and 8/16/32-bit uncached shapes.
Co-authored-by: kotulsky <7805437+kotulsky@users.noreply.github.com>
* fix(ui): respect native desktop scale under Auto UI scaling (#1278)
* UI scale: drop the now-unused monitor size, update docs and scorecard
Merge main; Auto no longer reads the monitor size, so remove the parameter and its
computation, simplify the test, and update ui-design.md and UI-217-9 to match.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Mirror the shell for right-to-left UI languages (DIST-220-4)
Arabic, Hebrew, Persian and Urdu read right to left, but the window's
chrome was hard-wired left to right, so an RTL catalog (#2505) would
put Arabic labels into a left-to-right layout.
The reading direction now follows the language code
(i18n::dir_for_code: ar, ckb, dv, fa, he, ps, sd, ug, ur, yi), so a
catalog needs no extra setting and the LANGUAGES rows are unchanged.
In a right-to-left language the shell mirrors:
- the menu bar starts at the right with File; menus open under their
title's right edge, and the arrow keys step through them in screen
order
- the toolbox docks on the right, the panel dock and its rail on the
left; tool flyouts open towards the canvas and their corner marks
and the header chevrons follow
- the title, options and status bars read from the right, with the
workspace controls and the Fit/progress group at the left end; the
title and window-drag gap use the free span between them
New module direction.rs holds the helpers (start_panel/end_panel,
row/trailing layouts, horizontal_centered, the popup alignment). Left
to right, every change lays out as before.
No RTL catalog ships yet, so PHOTOCRAFT_UI_DIRECTION=rtl forces the
mirrored layout for review (read once, native only). Panel interiors,
dialogs, menu rows, submenus and document tabs stay left to right, and
egui still draws UI labels without Arabic shaping or bidi reordering;
docs/localization.md and the parity docs say so.
Adds Lucide's chevron-left (the status bar's info menu arrow points
left in RTL; Timeline's Previous frame button asked for it too and drew
the fallback square).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Localization docs: egui shapes Arabic words; what's missing is a font and bidi word order
egui 0.36 shapes right-to-left runs with HarfRust, so letters join within
a word. The gaps are an Arabic fallback font in the UI and paragraph bidi
(words are placed left to right; emilk/egui#8576, #8577).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: MathMattTech <334629259+MathMattTech@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Rulers: clip tick marks and labels outside the origin corner
* Rulers test: set ViewXform's new aspect field after merging main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Two Studio-layout themes for KDE Plasma desktops: original colour values
chosen to sit close to Breeze's cool blue-grey surfaces and blue accent
(and its 5 px radius) so the app blends into a Plasma desktop, without
copying Breeze's colour schemes. Text readability comes first.
- theme.rs: ThemeKind::BreezeLight / BreezeDark. Every text colour (text,
secondary, faint, accent, danger, warning) holds 4.5:1 on every surface
and on hovered, pressed and selected states; the primary button is a
deeper blue that takes white text and stays above 4.5:1 while it
darkens on hover and press. Breeze's own inactive text and link blue
are only about 2.8:1 on its light surfaces, so ours are darker. The
close button goes red on hover.
- prefs: Theme/LightTheme::BreezeLight ("breezeLight") and
Theme/DarkTheme::BreezeDark ("breezeDark"): Preferences > Interface,
`prefs.set`.
- Window > Theme > Breeze Light/Dark Theme (`window.theme.breezeLight`,
`window.theme.breezeDark`) and `ui.set {"theme": ...}` (aliases:
breeze, kde, plasma for the light one; ...dark for the dark one).
- i18n: the four new labels in all 16 catalogs.
- docs/ui-design.md and ATTRIBUTION.md (original work, credits Breeze as
the inspiration; Breeze's schemes are LGPL-2.0-or-later and none of
their values, files or code are copied).
- Tests: names/aliases, surface order and blue-grey character, the
contrast matrix for both themes, and the preference/mode selection.
* Expand arithmetic expressions across numeric inputs
* Test arithmetic and scientific notation in indexed color counts
* Drop the numeric_fields example (it wrote PNGs to /tmp; the widget tests cover the behaviour)
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* feat(ui): follow system appearance with a System theme
Follow the OS appearance through the existing egui input while retaining System as the saved theme choice. Apply the resolved palette to both egui styles and custom surfaces, and keep document surround settings independent.
Cover launch and live transitions, persistence, manual themes, menu checks, the Interface picker and Home contrast. Validate engine/UI suites, adversarial commands, wasm, layering, parity and the AutoReview gate. Strict Clippy reports pre-existing findings documented in the PR.
Refs: storytold/photocraft#2074
* Keep the document surround on the displayed theme in Sync with system (drop the dark-surround pinning)
---------
Co-authored-by: coygeek <coygeek@users.noreply.github.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Appearance modes: sync with system, separate dark and light themes
* Appearance button cycles Auto, Light, Dark
* Appearance: default stays Dark, follow the portal signal instead of polling, split out the Preferences resize
* Preferences: size both appearance cards for the five dark themes
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Toolbar: Studio themes draw large round colour chips with Switch Colors right below
* Toolbar: round chips keep Default Colors, follow Tokens::round_chips, lie side by side in two columns
* Theme: Solarized Dark and Adwaita use the Studio round colour chips
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Brush preset chip: draw the tip preview in the icon colour on light themes
The options-bar chip always painted the round tip white, which nearly vanished on Studio
Light's chrome (246 gray) and disappears entirely on a white header bar. Dark themes keep
Photoshop's white tip; light themes use their icon token.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add Adwaita and Adwaita Dark themes
Two opt-in themes that put the Studio layout in GNOME's libadwaita palette, so PhotoCraft
sits with the rest of a GNOME desktop: header bar, sidebar, card and view colours, the
GNOME blue accent (#3584e4), destructive and warning colours, 6 / 9 / 12 px radii, and a
neutral (not red) close button as in GNOME's title bars. The default theme is unchanged.
Wired through ThemeKind, the interface.theme preference (adwaita, adwaitaDark), Window ›
Theme and the control channel, with menu and preference labels in every complete-menus
language ("Adwaita" kept as the proper name). A test holds both themes to WCAG contrast:
7:1 for text and 4.5:1 for dim text on every surface that carries labels.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: translate the Adwaita theme names in Dutch and Ukrainian
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
As in Photoshop CC 2019 and later, dragging an edge handle now scales both axes by the same
factor about the middle of the box (Alt: about the reference point), and Shift stretches the
one axis. Use Legacy Free Transform restores the old behaviour for edges as well as corners.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
On Windows and Linux the System title bar checkbox now carries the existing "Applies at next
launch." note, since saving it does not change the current window. Fixes#1661.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* type: transform editable text with temporary Ctrl/Cmd handles
* type: cover temporary transforms, editable files and preview costs
* docs: describe temporary Type transforms and automation
* type: release temporary previews immediately when gestures end
* test: benchmark the active 24 MP Type document
Auto forced at least 200% on any 4K monitor, overriding a fractional
system scale such as 125% or 150%, so Linux users on 4K got either
100% or 200% and nothing between. Auto now follows whatever scale the
system reports and uses the 200% fallback only when the system reports
no scaling (100%), which is the case #225 was fixing.
Claude-Session: https://claude.ai/code/session_01QcbChgBDVrdhjfsFA5D9nt
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Windows and Linux: one title bar with the app icon, like Photoshop
The window had the OS title bar stacked above PhotoCraft's own top bar. On
Windows and Linux the window now has no OS decorations and the top bar is
the title bar, as in VectorCraft and Photoshop on Windows:
- the app icon (brand.rs) leads the bar, before the menus;
- Minimize, Maximize/Restore and Close sit flush in the top-right corner
(Close turns red on hover; it runs File > Exit, so unsaved work is asked
about first);
- the free gap between the menus and the controls still drags the window
and a double-click there maximizes it;
- invisible 5 pt edges (12 pt corners) resize the window.
The right-hand group gets its own rect between the menus and the caption
buttons (egui's MenuBar takes the whole row, so it used to be laid out from
past the bar's end). Narrow windows drop what is also in a menu before
anything overlaps: Discord, then the theme toggle, then search, then the
workspace switcher narrows. macOS keeps its traffic lights.
New theme tokens caption_close / caption_close_text, Minimize / Maximize /
Restore in all 12 catalogs, and a --custom-titlebar flag for the snapshot
example.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Long right-click menus scroll inside the window instead of running off it
widgets::menu_scroll caps a context menu at the visible window height
(clear of a taskbar a too-tall window runs under, #315). egui moves the
popup up to fit, and it scrolls only when it is taller than the window.
Used by the Layers, canvas tool, Channels, Paths and document-tab menus;
the menu bar's menus already scroll (menu_nav::level).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* ⌘⌥⌃-click on the canvas selects the topmost layer under the pointer
With any tool, ⌘⌥⌃-click runs `layer.pickAt` at the pointer (the topmost
visible layer with pixels there becomes the selected layer) without
switching to the Move tool; the press, drag and release are swallowed so the
active tool never paints or draws. It runs before the ⌃⌥ brush-resize
gesture, which the same keys would otherwise trigger.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* quick_pick: document the macOS-only gesture, report a failed pick as an error
Windows and Linux never report mac_cmd, so the gesture is a documented no-op there and
Ctrl+Alt keeps resizing the brush. Tests cover both, plus a failed pick.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Jason Short <3344856+jason4short@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Apply the Interface UI Font Size preference
* Regenerate the scorecard after rebase (58 unread settings); drop the before/after screenshots
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* add 75-300% fixed ui scale steps
* UI scale: French and Indonesian labels for the new steps
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n(ko): UI scale steps
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* feat(i18n): add Korean and live language switching
* i18n(ko): Edit Type (#598)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: complete Simplified Chinese UI catalog and brush labels
* i18n(zh-hans): translate labels added on main since this PR (opening/cancel, layer navigation)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n(zh-hans): keep main's Mixer Brush entries, translate the rendering-mode strings added since (#434)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Camera Raw: interactive histogram, clipping warnings and scopes (part of #215)
- RGB histogram of the preview proxy (algo::histogram), drawn as RGB ribbons;
Before/After, five draggable tonal zones, shadow/highlight clipping warnings
(U/O) and Alt-drag channel diagnostics.
- Pixel hover readout, up to nine RGB/Lab colour samplers (S), an ICC-managed
vectorscope (algo::vectorscope) with skin-tone line, and a floating scope panel.
- Settings regrouped as Light, Color, Effects, Curve, Color Mixer, Color Grading
and Detail; Camera Raw labels translated through the cameraRaw context.
- One point-curve editor (point_curve.rs) shared by Camera Raw, the Curves dialog
and adjustment-layer Properties; fixes Camera Raw curve points not dragging.
- Double-clicking a Camera Raw smart filter reopens the Camera Raw dialog with its
settings and updates that filter, instead of the generic parameter form.
- New point curves are validated (2-16 points, increasing inputs); stored Smart
Filters keep loading.
- camera_raw_bench for P31/P36 (not enforced until a baseline includes them).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Histogram tests: as_chunks for triangle indices (clippy 1.99)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Regenerate docs/scorecard.md after rebasing onto main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n tests: close the Mixer Brush test before the Camera Raw one (rebase)
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>
A double-click anywhere on a Layers row started a rename. Now only a
double-click on the name renames; the rest of the row follows the
layer's kind: an adjustment or fill thumbnail opens its Properties
(Layer Content Options), a Smart Object thumbnail opens its contents
(Edit Contents), and anywhere else opens Layer Style (Blending Options).
The Background still becomes a normal layer, mask thumbnails keep their
own clicks, and a command that's disabled for the layer does nothing.
docs/ui-design.md lists the row's double-click targets.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Localise the UI: i18n foundation and a Japanese catalog
Adds a small i18n layer and a complete Japanese catalog for the menus, the
command palette, dialogs and panels. English stays the default and the source
language; command ids, the control protocol, the CLI and MCP are unchanged.
- i18n (crates/ui-egui/src/i18n): one TSV catalog per language, registered with
one row in LANGUAGES. Lookups: tr/tl! (plain), tr_ctx (context), tr_id
(command-id keyed, English fallback), trn (plurals), fmt ({name}
placeholders). Locale tags resolve most-specific-first; macOS falls back to
the preferred-languages list.
- New preference interface.language (auto | language code), a dropdown in
Preferences > Interface. The engine stores a validated code and does not
know the language list.
- Widgets (checkbox, slider_row, dropdown, buttons, tabs, icon tooltips)
translate their labels; direct egui calls use tl!("...").
- Japanese catalog (about 2,000 entries) written from the meaning of the
English labels; no string table was extracted from any other product.
- Tests: catalog well-formedness (duplicates, placeholders, ellipses, plural
forms, command ids) and coverage of menus, tl! literals, blend modes and
generated preference labels.
Status-bar messages and errors stay English. Per-language font fallback,
right-to-left layout and locale-aware number formats are not done yet.
Rebased onto main (maintainer): conflicts resolved keeping main's newer UI
(tab strips, platform shortcut labels, menu navigation, Properties layout)
with the tl!/tr wrapping. command_label/tip_label translate their label
before appending the shortcut, shortcut hints use {key} placeholders, and
strings main added since are wrapped and translated where unambiguous.
The macOS locale lookup runs /usr/bin/defaults by absolute path and
ignores failures.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Menus widen to fit translated labels instead of wrapping them
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Workspace switcher keeps English keys so translated labels still select a workspace
The options' keys were translated too, so in Japanese the current workspace
showed as "—" and picking one never matched apply_workspace.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Regenerate docs/scorecard.md for interface.language
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>