When the right panel is open but minimized or behind another tab, F8 keeps
its mode instead of switching to the one it last hid, and view.rightPanel
reveals Tools. Test: F8 on a minimized floating Tools window in Crop opens
the window and stays in Crop.
Showing a panel that has no hidden entry skips craft-ui's right-edge
fallback and opens it beside the photo view on the panel's default side.
Test: Library opens to the left of the photo, Presets to the right.
The side panels are frames whose widths LightCraft tracks, so new_dock_zones
is off. Test: an edge drop of Tools leaves the layout without a Node::Dock.
craft-ui and craft-docpath are pinned to craft-libs
17744430be327d0257496a6a31c8d38fe20a6756, where a divider drag keeps the
split's sizing mode. LightCraft no longer turns dragged ratios back into
side-panel widths.
craft-ui stores a moved divider as a ratio. After each frame the split
beside a side panel takes the width the panel was drawn at, so the panel
keeps its width when the window resizes and left_width / right_width follow
the drag.
craft-ui and craft-docpath are pinned to craft-libs 16fb3d46e1eaa0d455465e4e66a3ac7b17b55bd3.
The saved workspace is craft_ui::docking::Workspace<Panel>; settings written
before it had a version load as version 1. ui.dock params parse as the shared
DockCommand and apply through Workspace::apply_all. LightCraft keeps its
panels, permissions, default layout, photo-view checks, the fallback beside
the photo view for a panel with no recorded place, and its settings file.
The photo view takes side splits (accepts_splits on PROTECTED), so panels
still open and move beside it.
Tests: a version 1 workspace file loads and reopens its hidden panel; a drag
of a group by its bar moves both of its panels.
Resolves the parity summary (regenerated), drops a duplicated #[cfg(test)], files the What's New entry
under today's date and bumps the checklist's Last updated line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main replaced "Show Clipping" with "Clipping": the PR's Beschneidung term moves to the new key.
Also takes CodeRabbit's two wording suggestions.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A pass over all 2,565 interface strings and 299 formats messages of the
German catalogs (What's New lines not included). 108 messages change:
- Lightroom terms: Tönung (Tint), Beschneidung (Clipping)
- one word per thing: Bedienfeld (panel; Bereich stays for sidebar
sections), Begleitdatei (sidecar), Dia (slide), Zuschnitt (crop),
Farbmarkierung (label) where "Markierung" read as the pick/reject flag,
Verschlusszeit, Smart-Album, Perspektivkorrektur (Upright),
Aktivitätsstapel
- "Ihre Dateien/Fotos" at the start of a sentence read as the formal
"your" in a du catalog; rephrased
- double colons and "1 Fotos" in count messages, awkward phrasings
- spaced en dash instead of em dash, no space before a final ellipsis,
German quotes around {profile}
The terms are listed in docs/localization-de.md; localization-parity
records the review.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/catalog/src/local.rs:62 (folder_of), used by forget_local_plan at :192 and :204
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The script runs under #!/bin/sh; on dash the array assignment was a
syntax error. Pass the auth option and its value as two plain words.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* security: bound codec allocation to what a hostile file declares
A GIF's first image descriptor could name a frame up to four times the
canvas budget and be charged that allocation before any size check saw
it; PNG's compressed text chunks were expanded through an unbounded
inflate; JPEG handed hostile frame headers to the allocating decoders
(zune for the common cases, jpeg-decoder for CMYK/scaled/lossless) and
let an APP1 flood drive quadratic metadata reassembly. Each now refuses
on the same max_pixels budget the other decoders honour, with a
regression test per gate.
🤖 Generated with Codebuff
Co-Authored-By: Codebuff <noreply@codebuff.com>
* Fix clippy collapsible_if in DCT-scale size check
* Check jpeg-decoder header on scaled path; cap APP1 markers in decode_codes8
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Codebuff <noreply@codebuff.com>
Co-authored-by: Dylan Taylor <dylan@craftmaker.dev>
Co-authored-by: Claude Sonnet 5.5 <noreply@anthropic.com>
- Reverse slider loop order in UI to match Lightroom layout (Highlights, Lights, Darks, Shadows).
- Sanitize splits and amounts against NaN, inf, and inverted split bounds in ParametricCurve::new, at, and region_at.
- Guard param_drag against zero/negative widget dimensions.
- Update live region readout to display the current frame's dragged value immediately.
- Add regression test for non-finite and inverted split values.
Co-Authored-By: deepseek-flash <noreply@deepseek.com>
FredApps on #2689: a re-check started while the launch list is up (a
library not found looked for again, the window back to the front) never
marked its row as checking, so `apply_answers` skipped the new answer: a
library plugged back in stayed "not found" in the list. A row is re-armed
when its path is asked again about an answer it has (not after a failed
open, whose reason stays on the row). Test
a_library_found_again_comes_back_to_the_launch_list fails without it.
Fixes#2774
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JbBu4MRiaKxEbSrMTZiLj8
- Expose ParametricCurve from lightcraft-pipeline and use it in both
curve_luts and the UI curve editor, eliminating duplicate implementations
and ensuring render and graph never drift.
- Invert the parametric model while holding the other three regions fixed,
converting vertical pointer motion relative to the grabbed region's initial
amount so a horizontal drag with zero vertical travel leaves all sliders
untouched even with heavy overlapping neighbouring bumps (fixes AlexChambers
report: Darks=60, Lights=0 grabbed at x=0.51).
- Replace all raw table indexing with .get() per never-crash rules.
- Add unit and headless integration tests verifying that horizontal drag
with other regions non-zero changes nothing.
Co-Authored-By: deepseek-flash <noreply@deepseek.com>
CodeRabbit nitpick on #2701: a failing assertion skipped giving `Locked` its
permissions back, and a folder left at mode 000 can't be removed. A Drop
guard restores the mode and removes the test's folder on every exit
(found one left behind by an earlier failing run).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JbBu4MRiaKxEbSrMTZiLj8
The gate on cf9334907 failed on
tests_slideshow::playback_settings_drive_the_slideshow_and_bad_ones_are_refused
and ::settings_shows_the_slide_layout_and_a_live_preview (#1287); they passed
on the two gates before and in 15 of 15 local runs of the module with 4
threads, and nothing since touches the slideshow. Each checked its result
one frame after the click / after the preview changed, which a loaded
runner doesn't always give: they wait for it now (the checkbox state, the
green backdrop pixel). Test code only.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JbBu4MRiaKxEbSrMTZiLj8
The revision field and Catalog::apply said an error changes nothing and that the revision counts applied ops; a batch whose rollback fails changes the catalog and advances it.