Skip to content

Commit fd2d9ae

Browse files
committed
consider spacing and padding when using relative values for the layout
1 parent 95fe5ba commit fd2d9ae

File tree

6 files changed

+252
-7
lines changed

6 files changed

+252
-7
lines changed

internal/core/layout.rs

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use num_traits::Float;
1616

1717
pub use crate::items::Orientation;
1818

19-
/// The constraint that applies to an item
19+
/// The constraint that applies to a layout
2020
// Also, the field needs to be in alphabetical order because how the generated code sort fields for struct
2121
#[repr(C)]
2222
#[derive(Clone, Copy, Debug, PartialEq)]
@@ -1139,18 +1139,22 @@ pub struct LayoutItemInfo {
11391139
/// Solve a BoxLayout
11401140
pub fn solve_box_layout(data: &BoxLayoutData, repeater_indices: Slice<u32>) -> SharedVector<Coord> {
11411141
let mut result = SharedVector::<Coord>::default();
1142+
// TODO: why *2?
11421143
result.resize(data.cells.len() * 2 + repeater_indices.len(), 0 as _);
11431144

11441145
if data.cells.is_empty() {
11451146
return result;
11461147
}
11471148

1149+
let size_without_padding = data.size - data.padding.begin - data.padding.end;
1150+
let num_spacings = (data.cells.len() - 1) as Coord;
1151+
let content_size = size_without_padding - num_spacings * data.spacing; // The width the cells can occupy without going outside of the layout
11481152
let mut layout_data: Vec<_> = data
11491153
.cells
11501154
.iter()
11511155
.map(|c| {
1152-
let min = c.constraint.min.max(c.constraint.min_percent * data.size / 100 as Coord);
1153-
let max = c.constraint.max.min(c.constraint.max_percent * data.size / 100 as Coord);
1156+
let min = c.constraint.min.max(c.constraint.min_percent * content_size / 100 as Coord);
1157+
let max = c.constraint.max.min(c.constraint.max_percent * content_size / 100 as Coord);
11541158
grid_internal::LayoutData {
11551159
min,
11561160
max,
@@ -1161,9 +1165,7 @@ pub fn solve_box_layout(data: &BoxLayoutData, repeater_indices: Slice<u32>) -> S
11611165
})
11621166
.collect();
11631167

1164-
let size_without_padding = data.size - data.padding.begin - data.padding.end;
11651168
let pref_size: Coord = layout_data.iter().map(|it| it.pref).sum();
1166-
let num_spacings = (layout_data.len() - 1) as Coord;
11671169
let spacings = data.spacing * num_spacings;
11681170

11691171
let align = match data.alignment {
@@ -1239,12 +1241,12 @@ pub fn box_layout_info(
12391241
return info;
12401242
};
12411243
let extra_w = padding.begin + padding.end + spacing * (count - 1) as Coord;
1242-
let min = cells.iter().map(|c| c.constraint.min).sum::<Coord>() + extra_w;
1244+
let min = cells.iter().map(|c| c.constraint.min).sum::<Coord>() + extra_w; // Minimum width of the complete layout
12431245
let max = if is_stretch {
12441246
(cells.iter().map(|c| c.constraint.max).fold(extra_w, Saturating::add)).max(min)
12451247
} else {
12461248
Coord::MAX
1247-
};
1249+
}; // Maximum width of the complete layout
12481250
let preferred = cells.iter().map(|c| c.constraint.preferred_bounded()).sum::<Coord>() + extra_w;
12491251
let stretch = cells.iter().map(|c| c.constraint.stretch).sum::<f32>();
12501252
LayoutInfo { min, max, min_percent: 0 as _, max_percent: 100 as _, preferred, stretch }

internal/interpreter/eval_layout.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ pub(crate) fn compute_grid_layout_info(
6060
.into()
6161
}
6262

63+
/// Determine layout info of a box layout
6364
pub(crate) fn compute_box_layout_info(
6465
box_layout: &BoxLayout,
6566
orientation: Orientation,
@@ -394,6 +395,7 @@ fn flexbox_layout_data(
394395
(cells_h, cells_v, repeated_indices)
395396
}
396397

398+
/// Determine the evaluated padding and spacing values from the layout geometry
397399
fn padding_and_spacing(
398400
layout_geometry: &LayoutGeometry,
399401
orientation: Orientation,
@@ -614,6 +616,7 @@ fn grid_layout_constraints(
614616
constraints
615617
}
616618

619+
/// Collect all elements in this layout and store the LayoutItemInfo of it for further calculation
617620
fn box_layout_data(
618621
box_layout: &i_slint_compiler::layout::BoxLayout,
619622
orientation: Orientation,
@@ -625,6 +628,7 @@ fn box_layout_data(
625628
let mut cells = Vec::with_capacity(box_layout.elems.len());
626629
for cell in &box_layout.elems {
627630
if cell.element.borrow().repeated.is_some() {
631+
// Collect all repeated elements
628632
let component_vec = repeater_instances(component, &cell.element);
629633
if let Some(ri) = repeater_indices.as_mut() {
630634
ri.push(cells.len() as _);
@@ -636,6 +640,7 @@ fn box_layout_data(
636640
.map(|x| x.as_pin_ref().layout_item_info(to_runtime(orientation), None)),
637641
);
638642
} else {
643+
// Collect non repeated elements
639644
let mut layout_info =
640645
get_layout_info(&cell.element, component, &window_adapter, orientation);
641646
fill_layout_info_constraints(
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright © SixtyFPS GmbH <info@slint.dev>
2+
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3+
4+
// For the rectangle width the spacing must be subtracted when setting the width to 100%
5+
6+
import { HorizontalBox } from "std-widgets.slint";
7+
export component TestCase inherits Window {
8+
preferred-width: 300px;
9+
preferred-height: 300px;
10+
11+
box:= HorizontalLayout {
12+
spacing: 6px;
13+
padding: 10px;
14+
rect:= Rectangle {
15+
width: 100%;
16+
background: red;
17+
}
18+
}
19+
20+
out property <bool> check_padding: box.padding > 0;
21+
out property <bool> check_x: rect.x == box.x + box.padding;
22+
out property <bool> check_y: rect.y == box.y + box.padding;
23+
out property <bool> check_width: rect.width == root.width - 2 * box.padding;
24+
out property <bool> check_height: rect.height == root.height - 2 * box.padding;
25+
}
26+
27+
/*
28+
29+
```cpp
30+
auto handle = TestCase::create();
31+
const TestCase &instance = *handle;
32+
assert(instance.get_check_padding());
33+
assert(instance.get_check_x());
34+
assert(instance.get_check_x());
35+
assert(instance.get_check_width());
36+
assert(instance.get_check_height());
37+
```
38+
39+
```rust
40+
let instance = TestCase::new().unwrap();
41+
assert!(instance.get_check_padding());
42+
assert!(instance.get_check_x());
43+
assert!(instance.get_check_y());
44+
assert!(instance.get_check_width());
45+
assert!(instance.get_check_height());
46+
```
47+
48+
49+
```js
50+
var instance = new slint.TestCase();
51+
assert(instance.check_padding);
52+
assert(instance.check_x);
53+
assert(instance.check_y);
54+
assert(instance.check_width);
55+
assert(instance.check_height);
56+
```
57+
*/
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright © SixtyFPS GmbH <info@slint.dev>
2+
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3+
4+
// The spacing and the padding must be considered for the determination of the width of the rectangles
5+
6+
import { HorizontalBox } from "std-widgets.slint";
7+
export component TestCase inherits Window {
8+
preferred-width: 300px;
9+
preferred-height: 300px;
10+
11+
layout:= HorizontalLayout {
12+
spacing: 10px; // Between elements
13+
padding: 7px;
14+
rect:= Rectangle {
15+
width: 50%;
16+
background: red;
17+
}
18+
19+
rect2:= Rectangle {
20+
width: 50%;
21+
background: blue;
22+
}
23+
}
24+
25+
out property <bool> check_spacing: layout.spacing > 0;
26+
out property <bool> check_padding: layout.padding > 0;
27+
out property <bool> check_x: rect.x == layout.x + layout.padding;
28+
out property <bool> check_width: rect.width + rect2.width + 2* layout.padding + layout.spacing == root.width;
29+
}
30+
31+
/*
32+
33+
```cpp
34+
auto handle = TestCase::create();
35+
const TestCase &instance = *handle;
36+
assert(instance.get_check_spacing());
37+
assert(instance.get_check_padding());
38+
assert(instance.get_check_x());
39+
assert(instance.get_check_width());
40+
```
41+
42+
```rust
43+
let instance = TestCase::new().unwrap();
44+
assert!(instance.get_check_spacing());
45+
assert!(instance.get_check_padding());
46+
assert!(instance.get_check_x());
47+
assert!(instance.get_check_width());
48+
```
49+
50+
51+
```js
52+
var instance = new slint.TestCase();
53+
assert(instance.check_spacing);
54+
assert(instance.check_padding);
55+
assert(instance.check_x);
56+
assert(instance.check_width);
57+
```
58+
*/
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
// Copyright © SixtyFPS GmbH <info@slint.dev>
2+
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3+
4+
// For the rectangle height the spacing must be subtracted when setting the height to 100%
5+
6+
import { HorizontalBox } from "std-widgets.slint";
7+
export component TestCase inherits Window {
8+
preferred-width: 300px;
9+
preferred-height: 300px;
10+
11+
box:= VerticalLayout {
12+
spacing: 6px;
13+
padding: 10px;
14+
rect:= Rectangle {
15+
height: 100%;
16+
background: red;
17+
}
18+
}
19+
20+
out property <bool> check_padding: box.padding > 0;
21+
out property <bool> check_x: rect.x == box.x + box.padding;
22+
out property <bool> check_y: rect.y == box.y + box.padding;
23+
out property <bool> check_width: rect.width == root.width - 2 * box.padding;
24+
out property <bool> check_height: rect.height == root.height - 2 * box.padding;
25+
}
26+
27+
/*
28+
29+
```cpp
30+
auto handle = TestCase::create();
31+
const TestCase &instance = *handle;
32+
assert(instance.get_check_padding());
33+
assert(instance.get_check_x());
34+
assert(instance.get_check_y());
35+
assert(instance.get_check_width());
36+
assert(instance.get_check_height());
37+
```
38+
39+
```rust
40+
let instance = TestCase::new().unwrap();
41+
assert!(instance.get_check_padding());
42+
assert!(instance.get_check_x());
43+
assert!(instance.get_check_y());
44+
assert!(instance.get_check_width());
45+
assert!(instance.get_check_height());
46+
```
47+
48+
49+
```js
50+
var instance = new slint.TestCase();
51+
assert(instance.check_padding);
52+
assert(instance.check_x);
53+
assert(instance.check_y);
54+
assert(instance.check_width);
55+
assert(instance.check_height);
56+
```
57+
*/
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// Copyright © SixtyFPS GmbH <info@slint.dev>
2+
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
3+
4+
// The spacing and the padding must be considered for the determination of the height of the elements
5+
6+
import { HorizontalBox } from "std-widgets.slint";
7+
export component TestCase inherits Window {
8+
preferred-width: 300px;
9+
preferred-height: 300px;
10+
11+
layout:= VerticalLayout {
12+
spacing: 10px; // Between elements
13+
padding: 7px;
14+
rect:= Rectangle {
15+
height: 50%;
16+
background: red;
17+
}
18+
19+
rect2:= Rectangle {
20+
height: 50%;
21+
background: blue;
22+
}
23+
}
24+
25+
out property <bool> check_spacing: layout.spacing > 0;
26+
out property <bool> check_padding: layout.padding > 0;
27+
out property <bool> check_x: rect.x == layout.x + layout.padding;
28+
out property <bool> check_y: rect.y == layout.y + layout.padding;
29+
out property <bool> check_width: rect.width == root.width - 2 * layout.padding;
30+
out property <bool> check_height: rect.height + rect2.height + 2* layout.padding + layout.spacing == root.height;
31+
}
32+
33+
/*
34+
35+
```cpp
36+
auto handle = TestCase::create();
37+
const TestCase &instance = *handle;
38+
assert(instance.get_check_spacing());
39+
assert(instance.get_check_padding());
40+
assert(instance.get_check_x());
41+
assert(instance.get_check_y());
42+
assert(instance.get_check_width());
43+
assert(instance.get_check_height());
44+
```
45+
46+
```rust
47+
let instance = TestCase::new().unwrap();
48+
assert!(instance.get_check_spacing());
49+
assert!(instance.get_check_padding());
50+
assert!(instance.get_check_x());
51+
assert!(instance.get_check_y());
52+
assert!(instance.get_check_width());
53+
assert!(instance.get_check_height());
54+
```
55+
56+
57+
```js
58+
var instance = new slint.TestCase();
59+
assert(instance.check_spacing);
60+
assert(instance.check_padding);
61+
assert(instance.check_x);
62+
assert(instance.check_y);
63+
assert(instance.check_width);
64+
assert(instance.check_height);
65+
```
66+
*/

0 commit comments

Comments
 (0)