slint/sixtyfps_compiler/passes/lower_layout.rs
Simon Hausmann e914715d88 Rename Diagnostics to FileDiagnostics
As this structure holds the diagnostics just for one file.
2020-07-16 18:25:42 +02:00

137 lines
5.4 KiB
Rust

//! Passe that compute the layout constraint
use crate::diagnostics::FileDiagnostics;
use crate::expression_tree::*;
use crate::layout::*;
use crate::object_tree::*;
use std::rc::Rc;
/// Currently this just removes the layout from the tree
pub fn lower_layouts(component: &Rc<Component>, diag: &mut FileDiagnostics) {
recurse_elem(&component.root_element, &(), &mut |elem_, _| {
let mut elem = elem_.borrow_mut();
let new_children = Vec::with_capacity(elem.children.len());
let old_children = std::mem::replace(&mut elem.children, new_children);
for child in old_children {
let is_grid_layout =
if let crate::typeregister::Type::Builtin(be) = &child.borrow().base_type {
assert!(be.class_name != "Row"); // Caught at element lookup time
be.class_name == "GridLayout"
} else {
false
};
let is_path_layout =
if let crate::typeregister::Type::Builtin(be) = &child.borrow().base_type {
be.class_name == "PathLayout"
} else {
false
};
let ref_child = child.clone();
let prop_ref = move |name: &'static str| {
Box::new(Expression::PropertyReference(NamedReference {
element: Rc::downgrade(&ref_child),
name: name.into(),
}))
};
let (x_reference, y_reference) = if is_grid_layout || is_path_layout {
(prop_ref("x"), prop_ref("y"))
} else {
(Box::new(Expression::Invalid), Box::new(Expression::Invalid))
};
if is_grid_layout {
let mut grid = GridLayout {
within: elem_.clone(),
elems: Default::default(),
x_reference,
y_reference,
};
let mut row = 0;
let mut col = 0;
let child_children = std::mem::take(&mut child.borrow_mut().children);
for cc in child_children {
let is_row =
if let crate::typeregister::Type::Builtin(be) = &cc.borrow().base_type {
be.class_name == "Row"
} else {
false
};
if is_row {
if col > 0 {
row += 1;
col = 0;
}
for x in &cc.borrow().children {
grid.add_element(x.clone(), row, col, diag);
col += 1;
}
elem.children.append(&mut cc.borrow_mut().children);
component.optimized_elements.borrow_mut().push(cc.clone());
} else {
grid.add_element(cc.clone(), row, col, diag);
elem.children.push(cc);
col += 1;
}
}
component.optimized_elements.borrow_mut().push(child.clone());
if !grid.elems.is_empty() {
component.layout_constraints.borrow_mut().grids.push(grid);
}
continue;
} else if is_path_layout {
let layout_elem = child;
let layout_children = std::mem::take(&mut layout_elem.borrow_mut().children);
elem.children.extend(layout_children.iter().cloned());
component.optimized_elements.borrow_mut().push(layout_elem.clone());
let path_elements_expr = match layout_elem.borrow_mut().bindings.remove("elements")
{
Some(Expression::PathElements { elements }) => elements,
_ => {
diag.push_error("Internal error: elements binding in PathLayout does not contain path elements expression".into(), layout_elem.borrow().span());
return;
}
};
if layout_children.is_empty() {
continue;
}
component.layout_constraints.borrow_mut().paths.push(PathLayout {
elements: layout_children,
path: path_elements_expr,
x_reference,
y_reference,
width_reference: prop_ref("width"),
height_reference: prop_ref("height"),
offset_reference: prop_ref("offset"),
});
continue;
} else {
elem.children.push(child);
}
}
});
}
impl GridLayout {
fn add_element(&mut self, elem: ElementRc, row: usize, col: usize, diag: &mut FileDiagnostics) {
fn index_checked<T: Default>(vec: &mut Vec<T>, idx: usize) -> &mut T {
if vec.len() <= idx {
vec.resize_with(idx + 1, T::default)
}
&mut vec[idx]
};
let row_vec = index_checked(&mut self.elems, row);
let cell = index_checked(row_vec, col);
if cell.is_some() {
diag.push_error(format!("Multiple elements in the same cell"), elem.borrow().span())
}
*cell = Some(elem)
}
}