4bd8d86c001199364adf6410b38fd0ffcea7c2fe
10
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
f52c4cb8b6 |
Open presets from a menu at the foot of the tool rail
Presets were a "Presets…" button in develop's top bar that opened a sheet over the photograph, so applying one was two clicks with the picture covered. They are now an entry pinned to the bottom of the tool rail, apart from the tools because a preset arms nothing, and it opens a menu beside the rail: the same sectioned rows the sheet lists, one click to apply to the open photograph. The menu's last row, "Save or manage…", opens the sheet, which keeps saving, renaming, reverting and importing, since those take a name or a path. The menu is a PopupWindow for the film list's reasons, with the list in a clipped box of its own; the Flickable alone let its last row draw over the manage row. Choosing from it zeroes preset-apply-count before applying, since the grid may have left its selection count there. The manual says where presets are now and gains a picture of the open menu. The scenes reach the sheet through the menu and aim the manage row from the rail's entry, as the film list's rows are aimed, because the automation reports a popup's elements in the popup's coordinates. |
||
|
|
380cfda695 |
Make develop's Help a "?" beside Settings, so Settings fits at 1600
Adding a labelled Help button to develop's top bar made the strip about 100 pixels wider than a 1600-pixel window. The strip scrolls, so nothing became unreachable, but Settings was off the right-hand end until the bar was dragged. Help is now a square IconButton with a drawn question mark (a new "help" icon, drawn rather than typed for the reason icons.slint gives about Android's fonts), and screen readers still hear it as "Help". That saves 60 pixels, which was not enough alone: the strip had fit with 3 to spare before. The rest comes from the spacing. Controls that belong together now sit in groups at gap-sm with gap between groups: Pick and Reject, Undo and Redo, Copy, Paste and Presets, and "?" and Settings. The empty export-status caption no longer takes a slot and two spacings while it has nothing to say. At 1600 wide with the panel open the whole bar now shows, Settings included. The grid's header keeps its worded Help button; it has room for it. The develop "Open this list" gesture now names the "?" button, and the gesture book is regenerated from it. |
||
|
|
d9f259656a |
Open Help from develop as well as from the grid
The "Controls and shortcuts" sheet was drawn by LibraryGrid, so only the grid's Help button and its F1 could open it. Develop, where most of the keys it lists are bound (Ctrl+E, Ctrl+Shift+C, A/D, Z, R, H, [ ]), had no way to it: a photographer who wanted to look a shortcut up had to leave the photograph they wanted it for. The sheet now hangs off the shell beside the export and copy sheets, on a `help-open` property both views set. The grid's Help button and F1 raise it through a callback, and its keys stand down through the `sheet-open` they already honour for the export sheet, so Escape falls through to the shell, which closes it. Develop gains a Help button beside Settings in its top bar, as in the library header, and F1 in its key scope; its keys decline while the sheet is up, as they do for the other two sheets, so nothing behind it is rated or stepped. The book already begins with the Develop section, so from develop it opens where the reader wants it. Tests hold the shape: the sheet is drawn by the shell and not the grid, and develop's opening guard names all three sheets and its F1 opens this one. The new GESTURE: block puts the develop route in the book. |
||
|
|
d489a34190 |
Drive develop, the grid, the sidebar and People from the keyboard
An audit of every action by view against the keys the handlers bind left develop without zoom, pan, fit or a way back to the grid, the grid without select-none, thumbnail size or keywording, People with no key at all, and the export and copy sheets without Enter. It also found the reverse gap FR-UI-5 forbids: pick and reject had no route but P, X and U, and the 2026-09-19 amendment's judging in develop had not been built. Develop: Ctrl+= and Ctrl+Plus zoom in and Ctrl+- out about the middle of the view, Ctrl+0 fits and Ctrl+1 goes to 1:1, Shift and an arrow pan a magnified view, G goes back to the grid, Ctrl+Y redoes, and Enter keeps a crop that hid a mask. 0-5, P, X and U rate and flag the open photograph without moving on, with stars and Pick/Reject in the top bar as the pointer and touch route. = and - nudge the control last moved by a hundredth of its travel; the framing sliders, perspective included, now count as "last moved", so R puts them back as well. J turns the selected mask part's join chip. Grid: Ctrl+D and Ctrl+Shift+A clear the selection, = and - resize the thumbnails, Ctrl+K opens keywording, and Flag in the selection bar gives pick and reject a pointer and touch route. Sidebar: Enter commits a collection's name, and Enter or Escape hands the keyboard back to the grid, where it used to go nowhere until something was clicked. People: Up and Down walk the rail, F2 puts the name field under the keys, and Escape or Back now leave the screen the way its back button does instead of doing nothing. Sheets: Enter does what the export or copy sheet's button does. The choices follow Lightroom where it has one. No new key steals typing: the grid's and People's keys live on focus holders that are not ancestors of any text field, and the sheets' Enter comes after a focused field has had it. Every binding is tagged beside its handler, and the gate added in the previous commit holds the two to each other. |
||
|
|
46f5b95828 |
Show and set colour labels in the grid and develop, and filter by them
Colour labels could be read from a Lightroom sidecar and queried by the selector, but nothing drew one or set one, so the only labels a library held were ones another program had written. Every mark carries its label's initial on its colour — R, Y, G, B, P — so a label is read without telling red from green, which is what NFR-A11Y-3 asks of colour labels by name. A grid cell shows the mark before its filename. In the grid, 6, 7, 8 and 9 set red, yellow, green and blue as Lightroom's keys do, on the photograph under the pointer or on the selection by the rule the star keys follow; the same key again takes the label off, and over a mixed selection it sets it on all. The selection bar gains Label, which opens the six choices — each a mark and a name — and purple, which has no key, is there. In develop the top bar says "Label: Green" beside the mark, opens the same choices, and 6-9 label the open photograph. Each gesture is one catalog transaction, then the grid, the counts and both sidecars are written as a rating's are. The filter bar gains a chip per label, its mark and its name with a count, one at a time; the filter is one SQL term, travels in the place record, and "All" clears it. |
||
|
|
9ebaa15099 |
Move copy, paste and presets into the develop top bar
They sat in the develop column under a "SETTINGS" heading, which read as application settings, and went away with the panel toggle and in the mask and spot modes. The strip is where undo already is for the same reason: these act on the whole edit, not on any one panel. The paste button still names what it would apply. The TransferPanel component is gone; the Transfer global and its Rust wiring are unchanged. |
||
|
|
0a5eab0487 |
Wire the develop panels through globals, so a second copy is one line
Every panel in the develop column declared its inputs and its callbacks and had `app.slint` bind each one to a property or a callback on the window root. That is fine while a panel is drawn once. N9 draws them a second time, in the portrait dock, and the wiring is what would have to be copied: `MaskPanel` alone ran to forty lines of forwarding, and a callback added to one copy and not the other compiles, renders, and simply does nothing on the layout nobody was looking at. So the wiring moved to Slint globals. A panel reads the global and calls the global; Rust hooks the global instead of the window; and the instantiation in the column is now the panel's name and a pair of braces — every one of the ten children of the column, with no property that differs by placement left to supply. There is a global per panel family rather than one for all of them, and the reason is an import cycle. Each panel's model struct — `ParamRow`, `MaskRow`, `HistogramView` — is declared in the panel's own file, so a single global holding `[MaskRow]` and `[ParamRow]` would have to live in a file importing `masks.slint` and `adjust.slint` while both imported the global back, which Slint rejects. Breaking that needs six model declarations relocated, which is a change to the data model and not to the plumbing this is about. A global beside the panel it serves also lets each name drop the prefix it was carrying only because the window root is one flat namespace: `root.spot-radius` is `Repair.radius`, and `root.peaking-on` is `Peaking.showing`. `session.slint` is new and holds the two facts every family needs and none of them owns: whether there is an open photograph to edit, and which mode the view is in, with the three readings of the mode derived once instead of at each of the dozen places that tested one. `ViewMode` moves there from `adjust.slint`, where it was only ever a lodger. Nothing on screen changes. What is not here: the tool rail and the status strip still take their properties at the instantiation, because they are drawn once and N9 does not copy them; the preset sheet's own state stays on the window, because the library grid opens the same sheet and a global cannot bind the window's state — which is why `Transfer.open-presets` is handled in `presets.rs`, beside the summary it already had to compute. |
||
|
|
c4ddcbe0f7 |
Look the lens up and say plainly whether one was found
`dr-lens` has held a complete Lensfun lookup — distortion, TCA and vignetting coefficients from a lens name, a focal length and an aperture — with no dependents anywhere in the workspace. The three corrections it feeds now exist in the graph, so this connects the two and finishes the chain. The coefficient structs stay duplicated. `dr-pipeline` is organised around having no dependencies so its codegen is testable without a device or a database (ARCH §6.5a), and `dr-lens` carries an XML parser and 5.5 MB of profile data. Neither crate can convert to the other, so the conversion goes above both, in `develop.rs`, which is the only place that sees them together. Both traits grow the same defaulted door. The optical corrections do not sit on the same side of the fetch — distortion and CA rewrite coordinates and are `Warp`s, vignetting applies a gain to the pixel already there and is an ordinary node — and fanning a profile out by which trait each happens to implement would make the caller reason about that distinction. Each correction takes its own share of the whole profile instead, and `set_lens_profile` walks both lists identically. The lookup happens in `set_source_metadata` rather than in its caller, because that is the one place a session is told which file it came from. Doing it there makes it unforgettable, in the shape `FilmRebake` already uses for the other derived thing — and, more to the point, makes *clearing* unforgettable: a session that opened a second photograph while still holding the first one's profile would correct it for the wrong optics, invisibly, in a way that looks exactly like the lens. It needs the whole shot and not just a name. Distortion is interpolated across a zoom's focal range and vignetting depends strongly on aperture — a fast prime can be two stops down in the corners wide open and clean by f/8 — so a lookup missing either returns coefficients measured for a shot nobody took. Missing any of the three refuses rather than guesses. A profile is derived, not persisted: it comes from the file's EXIF and a database, so it is not a parameter, not in the sidecar and not undoable. What is an edit is the manual trim beside it, which each correction composes with the measurement — so a photographer can lean on it, override it, or work without one. `InfoPanel` gains a lens line, and it distinguishes three cases rather than two. `dr-lens` states the rule it exists for: an automatic correction that silently did nothing is worse than one the user can see is unavailable. A session with no header draws nothing, a header naming no lens reads "Lens not recorded", and a lens the database has never heard of reads "· no profile". Collapsing the last two would send somebody hunting for a profile that was never missing — which, for third-party and adapted glass, is the ordinary case. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ef07e6ca3e |
Give the canvas tools a rail of their own, and the column one width
Build and test / Desktop (Linux) (push) Failing after 1h14m38s
Build and test / Layer separation (push) Successful in 48s
🐳 Android image / Build and push (push) Successful in 16m30s
Build and test / android-image (push) Successful in 16m31s
Traceability / Requirement traces (push) Successful in 1m47s
Build and test / Android (aarch64) (push) Successful in 1h0m21s
Crop, Local and Repair were chips at the head of the develop column, sharing a row with the adjustment groups and told apart from them by the shape of their highlight. Three things followed from that, and only the last is cosmetic: the column closes, so the way out of a mode went away with the way in — hence the duplicate "Done Cropping" over the canvas; the chips are generated from the operation set, so the widest thing in the sidebar was a row nobody had chosen the contents of; and a mode and a filter are different kinds of state wearing one control. They are a fixed 60px rail down the left now, generated from a single table in toolrail.slint. A tool is one row of it plus a drawing plus a ViewMode variant; nothing in app.slint is touched to add one. What is left of the strip is the group filters, so it is GroupStrip. The column stops measuring itself. Every panel published a content-width and declared it as min-width, and the column took the largest — which spent the photograph's pixels on whatever happened to be widest, and moved the image sideways when switching tools swapped one set of panels for another. It is panel-width now, one number in style.yaml. That number is 360 and it is measured, not picked: the contents report a minimum of 344 in every mode, and they do not compress below it because a Text that does not elide reports the same minimum as preferred. 320 was tried and sliced Paste down the middle. The Flickable's viewport is floored at the layout's minimum rather than its preferred width for the same reason — content that is never told how much room it has cannot adapt to having less. Removing the eight content-width declarations repairs three comments an earlier edit had spliced sentences into. The raw histogram's note on keeping its hint short is rewritten rather than dropped: an over-long hint no longer widens the column, it pushes the column's minimum past the width it has and clips the panel, which makes that constraint sharper rather than obsolete. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
ffc9e1aea7 |
Give the develop view's chrome a file of its own
StatusBar and InfoPanel sat above AppWindow in app.slint, which read as though they were part of the application shell. They are not: neither is instantiated anywhere but the develop view, and the shell's actual job -- choosing which of the five screens is up -- is easier to follow without two unrelated components standing in front of it. Moved verbatim to develop.slint, matching src/develop.rs. No behaviour change; app.slint loses 232 lines and gains one import. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |