From 04d809072994c0babfd2b0a4ee63ea1658002565 Mon Sep 17 00:00:00 2001 From: Duncan Tourolle Date: Sun, 6 Sep 2026 19:59:11 +0200 Subject: [PATCH] Lay the develop view out by coordinate, so the column can sit below MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- ui/dr-ui/style.yaml | 19 ++++++++ ui/dr-ui/ui/app.slint | 109 +++++++++++++++++++++++++++++++++++------- 2 files changed, 111 insertions(+), 17 deletions(-) diff --git a/ui/dr-ui/style.yaml b/ui/dr-ui/style.yaml index b80d44e..1295526 100644 --- a/ui/dr-ui/style.yaml +++ b/ui/dr-ui/style.yaml @@ -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 diff --git a/ui/dr-ui/ui/app.slint b/ui/dr-ui/ui/app.slint index dd0b123..14785ce 100644 --- a/ui/dr-ui/ui/app.slint +++ b/ui/dr-ui/ui/app.slint @@ -1875,7 +1875,49 @@ in property 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 column-width: !root.column-below && root.panel-visible + ? min(root.panel-max-width, Theme.panel-width) + : 0px; + property 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 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 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 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 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; } }