Lay the develop view out by coordinate, so the column can sit below

Slint cannot turn a layout on its side, and that is what D-N7 asks for. So
the HorizontalLayout holding the rail, the canvas and the develop column
becomes a plain Rectangle and each of the three states its own x, y, width
and height. With `column-below` false those come out where the layout put
them to the pixel — a HorizontalLayout has no spacing or padding of its own,
the rail and the column took their declared widths at the two edges, and the
canvas was the only child that stretched.

The alternative was the column subtree declared twice under two `if`s, which
is four hundred lines of bindings copied, in a file whose own notes record a
conditional child in a layout as the shape that has produced binding loops
here before.

The column is the same column either way: the same contents, the same
Flickable, the same toggle. `panel-visible` collapses the dock's height
exactly as it collapsed the column's width, so `column-width` and
`dock-height` are each zero unless the column is both open and on that axis,
and the canvas can subtract both without asking which case it is in. The
stack inside stretches to the dock's width on its own — a layout that is the
direct child of a Rectangle fills it, and the Flickable's viewport was
already bound to its own width. Nothing is reflowed; N9 does that.

`dock-height` is mandated in style.yaml for the reason `panel-width` beside
it is, on the other axis: a dock that sizes itself to its contents is a
photograph that changes height when a caption wraps. 480 until N6 measures
the device.

The seam follows the column round: a hairline down its left edge beside the
photograph, along its top edge under it, so it stays between the two.
This commit is contained in:
2026-09-06 20:00:37 +02:00
parent 0e065389db
commit 04d8090729
2 changed files with 111 additions and 17 deletions
+19
View File
@@ -235,6 +235,25 @@ lengths:
`column.min-width` and read it off the running app; there is no way to
get the number out of the layout engine short of asking it.
dock-height:
value: 480
doc: |
The same column, docked under the photograph on a tall window (D-N7).
Mandated for the reason `panel-width` above is, on the other axis: a dock
that sizes itself to its contents is a photograph that changes height
when a caption wraps, and the photograph is the thing being judged.
480 is room for the pinned instruments — about 260 of histogram and
capture metadata, per N4 — with a group of sliders under them, chosen
against what has to fit *above* it: a 3:2 frame across a 900px dock is
600 tall, and 480 below it still leaves that frame its height on the
tablet at either of the two scale factors Android might report.
Provisional until N6 measures the device. Every figure behind it was
computed at a guessed density, and the guess moves the available height
by 200px.
_roll:
section: the photo roll
+92 -17
View File
@@ -1875,7 +1875,49 @@ in property <bool> panel-visible: true;
redo() => { root.redo(); }
}
HorizontalLayout {
// The develop view's frame: the rail, the photograph, the column.
//
// **A Rectangle rather than the HorizontalLayout this was**, and
// every child below states its own `x`, `y`, `width` and `height`
// instead of being placed by one. Slint cannot turn a layout on its
// side, and D-N7 asks for exactly that: on a tall window the column
// goes under the photograph rather than beside it, and the rail
// stays down the left in both cases.
//
// The alternative was the whole subtree declared twice under two
// `if`s, which is four hundred lines of bindings copied — and a
// conditional child in a layout is the shape that has produced
// binding loops in this file before (see the develop column below,
// and the group strip inside it).
//
// With `column-below` false the three rectangles come out where the
// layout put them, to the pixel: a `HorizontalLayout` has no
// spacing or padding of its own, so the rail took its declared
// width on the left, the column its declared width on the right,
// and the canvas — the only child with `horizontal-stretch: 1` —
// everything in between.
frame := Rectangle {
horizontal-stretch: 1;
vertical-stretch: 1;
// What the column takes when it is beside the photograph, and
// what it takes when it is under it. Exactly one of the two is
// ever non-zero, which is what lets the canvas subtract both
// without asking which case it is in.
//
// Zero is also how the column is put away, on either axis:
// `panel-visible` collapses the dock's height exactly as it
// collapses the column's width, and for the same reason the
// note on the column gives — an `if` here would be a layout
// that depends on a property derived from the window the layout
// then influences.
property <length> column-width: !root.column-below && root.panel-visible
? min(root.panel-max-width, Theme.panel-width)
: 0px;
property <length> dock-height: root.column-below && root.panel-visible
? Theme.dock-height
: 0px;
// **The tools, on the far side from their consequences.**
//
// A fixed rail rather than a row of chips inside the develop
@@ -1895,7 +1937,16 @@ in property <bool> panel-visible: true;
// collapses itself on `enabled`, and an `if` in this layout is
// the shape that has caused binding loops in this file before
// (see the develop column below).
ToolRail {
rail := ToolRail {
// Full height down the left in both arrangements — D-N7 is
// explicit that the rail does not move, and a vertical list
// of finger-sized entries wants the height a tall window
// has more of. Its width is its own (`rail-width`, or zero
// when it stands down), which is why the two boxes beside
// it can measure from `rail.width`.
x: 0;
y: 0;
height: parent.height;
enabled: root.total > 0 && root.load-error == "";
mode: root.view-mode;
picked(m) => { root.mode-picked(m); }
@@ -1915,7 +1966,14 @@ in property <bool> panel-visible: true;
// The canvas: compute output composited directly. No CPU
// round-trip anywhere in this path (ARCH §6.1).
canvas-area := Rectangle {
horizontal-stretch: 1;
// What is left of the frame: beside the rail, and above or
// beside the column — whichever of the two dimensions above
// is the non-zero one. This is what `horizontal-stretch: 1`
// used to say to the layout.
x: rail.width;
y: 0;
width: parent.width - rail.width - parent.column-width;
height: parent.height - parent.dock-height;
background: Theme.ground;
clip: true;
@@ -2736,9 +2794,24 @@ in property <bool> panel-visible: true;
// `expanded` above describes; Rust already measures the
// window for `layout-class`, so this is one more thing said
// in the same breath.
width: root.panel-visible
? min(root.panel-max-width, Theme.panel-width)
: 0px;
//
// **Which of those two numbers applies is the only thing
// `column-below` changes here.** The column's contents,
// its collapse and its toggle are the same on both axes —
// it is the same column, moved, and not a second one.
//
// Beside the photograph it is `column-width` wide against
// the frame's right edge and full height. Under it, it is
// `dock-height` tall against the frame's bottom edge and
// runs from the rail to that same right edge. `dock-height`
// rather than a measured height for the reason the note
// above gives about the width: a dock that sizes itself to
// its contents is a photograph that changes height when a
// caption wraps.
x: root.column-below ? rail.width : parent.width - parent.column-width;
y: root.column-below ? parent.height - parent.dock-height : 0;
width: root.column-below ? parent.width - rail.width : parent.column-width;
height: root.column-below ? parent.dock-height : parent.height;
visible: root.panel-visible;
background: Theme.surface;
clip: true;
@@ -3138,20 +3211,22 @@ in property <bool> panel-visible: true;
}
}
// The seam between the photograph and the column.
// The seam between the photograph and the column, on
// whichever side of the column the photograph is.
//
// **`x: 0` is load-bearing.** A child of a plain Rectangle
// that declares a size and no position is *centred* in it,
// so this hairline was being drawn straight down the middle
// of the develop column — over the histogram, the geometry
// controls and every slider below them. Invisible in the
// source and, at one pixel of `rule` grey, quiet enough on
// screen to be read as a divider that was meant to be
// there.
// **`x: 0` and `y: 0` are load-bearing.** A child of a
// plain Rectangle that declares a size and no position is
// *centred* in it, so this hairline was being drawn
// straight down the middle of the develop column — over the
// histogram, the geometry controls and every slider below
// them. Invisible in the source and, at one pixel of `rule`
// grey, quiet enough on screen to be read as a divider that
// was meant to be there.
Rectangle {
x: 0;
width: 1px;
height: 100%;
y: 0;
width: root.column-below ? parent.width : 1px;
height: root.column-below ? 1px : parent.height;
background: Theme.rule;
}
}