File presets in folders that open and close, as collections do

The presets menu and sheet listed every preset under flat section
headings, seventy rows to scroll past. They now list folders, closed
until opened, with how many presets each holds; opening one shows what
is inside it, folders and presets indented beneath.

A category is spelled in the name: "Portraits/Warm skin" is Warm skin
in a Portraits folder under Yours. The file format does not change, so
an older build lists the whole path as the name; renaming a preset is
how it moves, and saving or renaming into a folder opens the way to it.
A Lightroom import names what it reads after the folders below the one
chosen, and a "/" in a displayed name becomes "∕" so it files nothing.
The shipped film sections become Film › Colour, Cinema and Black and
white.

The tree is built and flattened in Rust (PresetTree), each row carrying
its depth, and which folders are open is remembered for the session.

A PopupWindow keeps the size it was shown at, so a folder opened in the
menu pushed its contents under "Save or manage…"; the menu is shown
again after each toggle to take its new height. That is a function on
the rail because Slint 1.17 generates Rust that does not compile for a
popup's close() reached from inside the popup. The sheet's list takes a
preferred height of up to 400px, since a Flickable reports next to
nothing and an opened folder showed three rows.

The manual describes the folders and naming. Its pictures show the menu
with Film › Colour open, and a black-and-white stock applied from Film
› Black and white; the scenes aim popup rows from the rail's entry, and
pick the menu's "Film" over the develop column's film chooser.
This commit is contained in:
2026-09-27 18:37:56 -04:00
parent 89b464db0c
commit 31bcc3a462
14 changed files with 680 additions and 174 deletions
+49 -24
View File
@@ -1157,25 +1157,56 @@ def presets_menu_open():
dr.wait_for('Save or manage…@Button', 5)
def presets_manage():
""""Save or manage…", the menu's last row, pressed to open the sheet.
def in_presets_menu(name):
"""The centre of `name` in the open presets menu, on the screen.
Aimed from the rail's entry rather than by name, as the film list's rows
are: the automation reports a popup's elements in the popup's own
coordinates. The menu opens beside the entry with its foot level with
the entry's, and the row is the last `PRESET_ROW` of it."""
_, _, x1, y1 = dr.rect('Presets@Button')
dr.click(x1 + 100, y1 - PRESET_ROW // 2)
The automation reports a popup's elements in the popup's own
coordinates, so the menu's origin is worked out from what is known: it
opens beside the rail's entry, its foot level with the entry's, and its
last row is "Save or manage…". If the row already reads as on screen —
right of the rail — the report is taken as it stands."""
_, _, rx1, ry1 = dr.rect('Presets@Button')
mx0, _, _, my1 = dr.rect('Save or manage…@Button')
dx, dy = (0, 0) if mx0 >= rx1 else (rx1, ry1 - my1)
# "Film" is also the develop column's film chooser, so of the matches
# the one in the menu's own coordinates — left of the rail's edge — is
# the one meant.
hits = dr.matches(name)
inside = [h for h in hits if h['x'] < rx1] or hits
if not inside:
raise dr.NotFound(f'{name!r}: not in the presets menu')
h = inside[0]
x0, y0, x1, y1 = h['x'], h['y'], h['x'] + h['w'], h['y'] + h['h']
return (x0 + x1) // 2 + dx, (y0 + y1) // 2 + dy
def presets_menu_click(name):
dr.click(*in_presets_menu(name))
def presets_manage():
""""Save or manage…", the menu's last row, pressed to open the sheet."""
presets_menu_click('Save or manage…@Button')
dr.wait_for('CARRIES@Text', 5)
@scene(media=['presets-menu.png', 'presets.png'],
sources=DEVELOP_SRC + ['ui/dr-ui/ui/presets.slint', 'ui/dr-ui/src/presets.rs'])
def presets():
"""The menu with Film and its colour stocks open, then the sheet — its
folders closed again, since opening is remembered only for the menu's
session and the sheet is the same list."""
at_develop()
presets_menu_open()
pause(0.6)
presets_menu_click('Film@Button')
pause(0.6)
presets_menu_click('Colour@Button')
pause(1.0)
shot('presets-menu')
# Put back, so the sheet below opens on the folders alone.
presets_menu_click('Film@Button')
pause(0.6)
presets_manage()
pause(1.5)
shot('presets')
@@ -1187,26 +1218,20 @@ def presets():
sources=DEVELOP_SRC + ['ui/dr-ui/ui/presets.slint', 'ui/dr-ui/src/presets.rs',
'core/dr-pipeline/presets/*.drpl', 'core/dr-pipeline/src/bundled.rs'])
def presets_film():
"""The sheet scrolled from Essentials down through the shipped film
sections, and a black-and-white stock applied from the last of them —
a look, so the sheet closes on the photograph with its film changed and
nothing else — then Before held."""
"""Film opened in the rail's menu, then Black and white inside it, and a
stock applied from there — a look, so the menu closes on the photograph
with its film changed and nothing else — then Before held."""
at_develop()
rec('presets-film')
pause(0.4)
presets_menu_open()
pause(0.8)
presets_manage()
pause(1.5)
x, y = dr.centre('Crisp detail@Button')
for _ in range(80): # a notch at a time, so the film shows the sections pass
if dr.present(f'{PRESET_BW}@Button'):
break
wheel(1, x, y)
pause(0.3)
pause(1.0)
dr.click_on(f'{PRESET_BW}@Button')
dr.wait_gone('CARRIES@Text', 5)
presets_menu_click('Film@Button')
pause(1.0)
presets_menu_click('Black and white@Button')
pause(1.2)
presets_menu_click(f'{PRESET_BW}@Button')
dr.wait_gone('Save or manage…@Button', 5)
pause(4)
hold_before(1.4)
pause(0.8)
@@ -1214,7 +1239,7 @@ def presets_film():
undo_all()
PRESET_BW = 'Ilford HP5 Plus' # a shipped look in the black-and-white film section
PRESET_BW = 'Ilford HP5 Plus' # a shipped look in Film › Black and white
# --- panorama ---------------------------------------------------------------