Layouting: Take in account explicit constraints when generating layout info base on content (#6306)

Fixes #6285

ChangeLog: Fixed geometry constraints when they are partially infered
from the content, and partially infered from the explicit constraints
This commit is contained in:
Olivier Goffart 2024-09-30 10:57:23 +02:00 committed by GitHub
parent 25ae55b5dd
commit 53e79000a4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 131 additions and 5 deletions

View file

@ -6,9 +6,6 @@ import { AppText } from "./controls/generic.slint";
import { AboutSlint } from "std-widgets.slint";
component AboutFelgo {
width: 100%;
height: 100%;
VerticalLayout {
spacing: 5px;
@ -81,7 +78,7 @@ export component AboutBox {
padding-bottom: 10px;
}
}
AboutSlint {
max-width: 200px;
}

View file

@ -179,10 +179,10 @@ impl LayoutConstraints {
apply_size_constraint("height", s, enclosing, depth, &mut constraints.max_height);
});
find_binding(element, "width", |s, enclosing, depth| {
constraints.fixed_width = true;
if s.expression.ty() == Type::Percent {
apply_size_constraint("width", s, enclosing, depth, &mut constraints.min_width);
} else {
constraints.fixed_width = true;
apply_size_constraint("width", s, enclosing, depth, &mut constraints.min_width);
apply_size_constraint("width", s, enclosing, depth, &mut constraints.max_width);
}

View file

@ -216,6 +216,14 @@ fn gen_layout_info_prop(elem: &ElementRc, diag: &mut BuildDiagnostics) {
let mut expr_h = implicit_layout_info_call(elem, Orientation::Horizontal);
let mut expr_v = implicit_layout_info_call(elem, Orientation::Vertical);
let explicit_constraints = LayoutConstraints::new(elem, diag);
if !explicit_constraints.fixed_width {
merge_explicit_constraints(&mut expr_h, &explicit_constraints, Orientation::Horizontal);
}
if !explicit_constraints.fixed_height {
merge_explicit_constraints(&mut expr_v, &explicit_constraints, Orientation::Vertical);
}
for child_info in child_infos {
if let Some(h) = child_info.0 {
expr_h = Expression::BinaryExpression {
@ -239,6 +247,55 @@ fn gen_layout_info_prop(elem: &ElementRc, diag: &mut BuildDiagnostics) {
li_h.element().borrow_mut().bindings.insert(li_h.name().into(), expr_h.into());
}
fn merge_explicit_constraints(
expr: &mut Expression,
constraints: &LayoutConstraints,
orientation: Orientation,
) {
if constraints.has_explicit_restrictions(orientation) {
static COUNT: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0);
let unique_name =
format!("layout_info_{}", COUNT.fetch_add(1, std::sync::atomic::Ordering::Relaxed));
let ty = expr.ty();
let store = Expression::StoreLocalVariable {
name: unique_name.clone(),
value: Box::new(std::mem::take(expr)),
};
let Type::Struct { fields, .. } = &ty else { unreachable!() };
let mut values = fields
.keys()
.map(|p| {
(
p.clone(),
Expression::StructFieldAccess {
base: Expression::ReadLocalVariable {
name: unique_name.clone(),
ty: ty.clone(),
}
.into(),
name: p.clone(),
},
)
})
.collect::<HashMap<_, _>>();
for (nr, s) in constraints.for_each_restrictions(orientation) {
let e = nr
.element()
.borrow()
.bindings
.get(nr.name())
.expect("constraint must have binding")
.borrow()
.expression
.clone();
debug_assert!(!matches!(e, Expression::Invalid));
values.insert(s.into(), e);
}
*expr = Expression::CodeBlock([store, Expression::Struct { ty, values }].into());
}
}
fn explicit_layout_info(e: &ElementRc, orientation: Orientation) -> Expression {
let mut values = HashMap::new();
let (size, orient) = match orientation {

View file

@ -0,0 +1,72 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
component C1 {
Rectangle {
min-width: 200px;
min-height: 300px;
inner := Rectangle {}
}
}
component C2 {
Rectangle {
min-width: 200px;
min-height: 300px;
inner := Rectangle { width: 100%; }
}
}
component FillParent {
preferred-height: 100%;
preferred-width: 100%;
min-height: l.min-height;
min-width: l.min-width;
l := VerticalLayout {
Text {}
}
}
export component Bug6315 {
r := Rectangle {
width: self.preferred-width;
r2 := Rectangle {
preferred-width: 100px;
Rectangle {
preferred-width: 40px;
}
}
}
Text {
text: (
"\{r.width / 1px}, " +
"\{r2.width / 1px}, " +
""
);
}
out property <bool> ok: r.width == 100px && r2.width == 100px;
}
export component W inherits Window {
Rectangle {
VerticalLayout {
FillParent {
min-height: self.preferred-height;
}
}
}
c1:= C1 {}
c2:= C2 {}
bug-6315 := Bug6315 {}
out property <bool> test: c1.min-height == 300px && c1.min-width == 200px
&& c2.min-height == 300px && c2.min-width == 200px
&& bug-6315.ok;
}