Lay the ratio chips out by hand, because Slint will not lay them out
The ratio chips shipped inside a `GridLayout` with `row` and `col`
computed from the repeater's index. It compiles. On screen every chip
piles into a single row that runs off the panel, and the terminal fills
with
Internal error in Slint: RepeatedItemTree::grid_layout_input_data()
not implemented
once per frame. A `for` inside a `GridLayout` is not supported, and
nothing says so until it is running.
A `HorizontalLayout` is not the answer either: six chips side by side
need over 400px, and this column's width is the largest width any panel
declares — so one row would widen every other panel in the application to
fit a control that is on screen only while cropping.
So the grid is arithmetic over the index inside a plain `Rectangle`. It
costs the layout engine nothing, it wraps a seventh ratio onto a third
row by itself, and — because a bare `Rectangle` declares no preferred
width — it takes the width the column already has instead of setting it.
The Portrait chip gets a container of its own for the same reason: a
`ChoiceChip` dropped straight into a `VerticalLayout` is stretched the
full width of the panel and reads as a button for the section rather than
as one more chip.
The three conditional pieces are also now individually-conditional
children of the one layout rather than a nested layout under a single
`if`, which is the convention `app.slint` and `masks.slint` already carry
notes about: a conditional nested layout under-reports its height here
and the panels below it draw on top of one another.
All of this was invisible in the source and obvious in a screenshot.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
+62
-22
@@ -625,34 +625,74 @@ export component GeometryPanel inherits Rectangle {
|
||||
// the offered set lives in one place: `CropAspect::CHOICES`. Their
|
||||
// positions are computed from the index for the same reason — a
|
||||
// seventh ratio wraps onto a third row by itself.
|
||||
if root.cropping: VerticalLayout {
|
||||
spacing: 4px;
|
||||
padding-top: Theme.gap-sm;
|
||||
// **Three individually-conditional children, not one `if` around a
|
||||
// nested layout.** A nested `VerticalLayout` under a condition
|
||||
// under-reports its height here, and the panels below it get drawn
|
||||
// on top of one another — invisible in this file and obvious on
|
||||
// screen. `app.slint` and `masks.slint` both carry the same note
|
||||
// for the same reason.
|
||||
if root.cropping: Label { text: "Ratio"; body: true; }
|
||||
|
||||
Label { text: "Ratio"; body: true; }
|
||||
// **The chips are placed, not laid out, and that is not a
|
||||
// shortcut.** Slint has no wrapping layout, and a `for` inside a
|
||||
// `GridLayout` compiles and then fails at run time —
|
||||
// `RepeatedItemTree::grid_layout_input_data() not implemented`,
|
||||
// printed once per frame while every chip piles into a single row
|
||||
// that runs off the panel. A `HorizontalLayout` is worse still: six
|
||||
// chips side by side need over 400px, and this column's width is
|
||||
// the largest any panel declares, so it would widen every other
|
||||
// panel in the application to fit a control that is on screen only
|
||||
// while cropping.
|
||||
//
|
||||
// So the grid is arithmetic over the index. It costs the layout
|
||||
// engine nothing, it wraps a seventh ratio onto a third row by
|
||||
// itself, and — because a bare `Rectangle` declares no preferred
|
||||
// width — it takes whatever width the column already has instead
|
||||
// of setting it.
|
||||
if root.cropping: Rectangle {
|
||||
property <int> columns: 3;
|
||||
property <int> rows: ceil(root.aspects.length / self.columns);
|
||||
property <length> pitch: Theme.control-height + Theme.gap-sm;
|
||||
property <length> chip-width:
|
||||
(self.width - (self.columns - 1) * Theme.gap-sm) / self.columns;
|
||||
|
||||
GridLayout {
|
||||
spacing: Theme.gap-sm;
|
||||
// A floor, so a narrow window shrinks the column rather than
|
||||
// the chips: three chips at the width `ChoiceChip` calls
|
||||
// comfortable is what this row is for.
|
||||
min-width: self.columns * 64px + (self.columns - 1) * Theme.gap-sm;
|
||||
height: self.rows * self.pitch - Theme.gap-sm;
|
||||
|
||||
for name[i] in root.aspects: ChoiceChip {
|
||||
row: floor(i / 3);
|
||||
col: mod(i, 3);
|
||||
label: name;
|
||||
selected: i == root.aspect;
|
||||
enabled: root.enabled;
|
||||
clicked => { root.aspect-picked(i); }
|
||||
}
|
||||
for name[i] in root.aspects: ChoiceChip {
|
||||
x: mod(i, parent.columns) * (parent.chip-width + Theme.gap-sm);
|
||||
y: floor(i / parent.columns) * parent.pitch;
|
||||
width: parent.chip-width;
|
||||
height: Theme.control-height;
|
||||
label: name;
|
||||
selected: i == root.aspect;
|
||||
enabled: root.enabled;
|
||||
clicked => { root.aspect-picked(i); }
|
||||
}
|
||||
}
|
||||
|
||||
// One chip, lit when the ratio is standing on its short edge,
|
||||
// rather than a Landscape/Portrait pair: the second chip in such a
|
||||
// pair says nothing the first does not, and this column is narrow.
|
||||
//
|
||||
// Disabled rather than hidden where the ratio has no second
|
||||
// orientation, so the panel does not change height as the chips
|
||||
// above it are tried.
|
||||
//
|
||||
// In a container of its own so it takes one chip's width and sits
|
||||
// under the first column: a `ChoiceChip` placed straight into the
|
||||
// `VerticalLayout` is stretched across the whole panel, which reads
|
||||
// as a button for the section rather than as one more chip.
|
||||
if root.cropping: Rectangle {
|
||||
height: Theme.control-height;
|
||||
|
||||
// One chip, lit when the ratio is standing on its short edge,
|
||||
// rather than a Landscape/Portrait pair: the second chip in
|
||||
// such a pair says nothing the first does not, and this row is
|
||||
// already the widest thing in the panel.
|
||||
//
|
||||
// Disabled rather than hidden where the ratio has no second
|
||||
// orientation, so the panel does not change height as the
|
||||
// chips above it are tried.
|
||||
ChoiceChip {
|
||||
x: 0;
|
||||
width: (parent.width - 2 * Theme.gap-sm) / 3;
|
||||
height: 100%;
|
||||
label: "Portrait";
|
||||
selected: root.portrait;
|
||||
enabled: root.enabled && root.aspect-turnable;
|
||||
|
||||
Reference in New Issue
Block a user