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

@ -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 {