mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 22:31:14 +00:00
New runtime implementation for the box layout
Currently only horizontal layout is supported
This commit is contained in:
parent
211fa69ef5
commit
aeade826fe
6 changed files with 332 additions and 60 deletions
|
@ -187,10 +187,7 @@ pub mod re_exports {
|
||||||
};
|
};
|
||||||
pub use sixtyfps_corelib::items::*;
|
pub use sixtyfps_corelib::items::*;
|
||||||
pub use sixtyfps_corelib::layout::LayoutInfo;
|
pub use sixtyfps_corelib::layout::LayoutInfo;
|
||||||
pub use sixtyfps_corelib::layout::{
|
pub use sixtyfps_corelib::layout::*;
|
||||||
grid_layout_info, solve_grid_layout, solve_path_layout, GridLayoutCellData, GridLayoutData,
|
|
||||||
Padding, PathLayoutData, PathLayoutItemData,
|
|
||||||
};
|
|
||||||
pub use sixtyfps_corelib::model::*;
|
pub use sixtyfps_corelib::model::*;
|
||||||
pub use sixtyfps_corelib::properties::{Property, PropertyTracker};
|
pub use sixtyfps_corelib::properties::{Property, PropertyTracker};
|
||||||
pub use sixtyfps_corelib::signals::Signal;
|
pub use sixtyfps_corelib::signals::Signal;
|
||||||
|
|
|
@ -1497,6 +1497,61 @@ impl crate::layout::gen::Language for CppLanguageLayoutGen {
|
||||||
cell_ref_variable,
|
cell_ref_variable,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn box_layout_tree_item<'a, 'b>(
|
||||||
|
layout_tree: &'b mut Vec<crate::layout::gen::LayoutTreeItem<'a, Self>>,
|
||||||
|
box_layout: &'a crate::layout::BoxLayout,
|
||||||
|
component: &Rc<Component>,
|
||||||
|
) -> crate::layout::gen::LayoutTreeItem<'a, Self> {
|
||||||
|
let cells: Vec<_> = box_layout
|
||||||
|
.elems
|
||||||
|
.iter()
|
||||||
|
.map(|cell| {
|
||||||
|
let layout_info =
|
||||||
|
get_layout_info_ref(&cell.item, &cell.constraints, layout_tree, component);
|
||||||
|
let lay_rect = cell.item.rect();
|
||||||
|
let get_property_ref = |p: &Option<NamedReference>| match p {
|
||||||
|
Some(nr) => format!("&{}", access_named_reference(nr, component, "self")),
|
||||||
|
None => "nullptr".to_owned(),
|
||||||
|
};
|
||||||
|
format!(
|
||||||
|
" {{ {li}, {x}, {y}, {w}, {h} }},",
|
||||||
|
li = layout_info,
|
||||||
|
x = get_property_ref(&lay_rect.x_reference),
|
||||||
|
y = get_property_ref(&lay_rect.y_reference),
|
||||||
|
w = get_property_ref(&lay_rect.width_reference),
|
||||||
|
h = get_property_ref(&lay_rect.height_reference)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let cell_ref_variable = format!("cells_{}", layout_tree.len()).to_owned();
|
||||||
|
let mut creation_code = cells;
|
||||||
|
creation_code.insert(
|
||||||
|
0,
|
||||||
|
format!(" sixtyfps::GridLayoutCellData {}_data[] = {{", cell_ref_variable,),
|
||||||
|
);
|
||||||
|
creation_code.push(" };".to_owned());
|
||||||
|
creation_code.push(format!(
|
||||||
|
" const sixtyfps::Slice<sixtyfps::GridLayoutCellData> {cv}{{{cv}_data, std::size({cv}_data)}};",
|
||||||
|
cv = cell_ref_variable
|
||||||
|
));
|
||||||
|
|
||||||
|
let (padding, spacing) = generate_layout_padding_and_spacing(
|
||||||
|
&mut creation_code,
|
||||||
|
&box_layout.geometry,
|
||||||
|
&layout_tree,
|
||||||
|
component,
|
||||||
|
);
|
||||||
|
|
||||||
|
LayoutTreeItem::BoxLayout {
|
||||||
|
geometry: &box_layout.geometry,
|
||||||
|
spacing,
|
||||||
|
padding,
|
||||||
|
var_creation_code: creation_code.join("\n"),
|
||||||
|
cell_ref_variable,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LayoutTreeItem<'a> = crate::layout::gen::LayoutTreeItem<'a, CppLanguageLayoutGen>;
|
type LayoutTreeItem<'a> = crate::layout::gen::LayoutTreeItem<'a, CppLanguageLayoutGen>;
|
||||||
|
@ -1515,6 +1570,10 @@ fn get_layout_info_ref<'a, 'b>(
|
||||||
"sixtyfps::grid_layout_info(&{}, {}, &{})",
|
"sixtyfps::grid_layout_info(&{}, {}, &{})",
|
||||||
cell_ref_variable, spacing, padding
|
cell_ref_variable, spacing, padding
|
||||||
),
|
),
|
||||||
|
LayoutTreeItem::BoxLayout { spacing, cell_ref_variable, padding, .. } => format!(
|
||||||
|
"sixtyfps::box_layout_info(&{}, {}, &{})",
|
||||||
|
cell_ref_variable, spacing, padding
|
||||||
|
),
|
||||||
LayoutTreeItem::PathLayout(_) => todo!(),
|
LayoutTreeItem::PathLayout(_) => todo!(),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1623,11 +1682,28 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
s = spacing,
|
s = spacing,
|
||||||
p = padding,
|
p = padding,
|
||||||
));
|
));
|
||||||
code_stream.push(format!(" {cv}", cv = cell_ref_variable).to_owned());
|
code_stream.push(format!(" {cv}", cv = cell_ref_variable));
|
||||||
code_stream.push(" };".to_owned());
|
code_stream.push(" };".to_owned());
|
||||||
code_stream.push(" sixtyfps::solve_grid_layout(&grid);".to_owned());
|
code_stream.push(" sixtyfps::solve_grid_layout(&grid);".to_owned());
|
||||||
code_stream.push(" } ".into());
|
code_stream.push(" } ".into());
|
||||||
}
|
}
|
||||||
|
LayoutTreeItem::BoxLayout { geometry, spacing, cell_ref_variable, padding, .. } => {
|
||||||
|
code_stream.push(" { ".into());
|
||||||
|
code_stream.push(" sixtyfps::BoxLayoutData box { ".into());
|
||||||
|
code_stream.push(format!(
|
||||||
|
" {w}, {h}, {x}, {y}, {s}, &{p},",
|
||||||
|
w = layout_prop(&geometry.rect.width_reference),
|
||||||
|
h = layout_prop(&geometry.rect.height_reference),
|
||||||
|
x = layout_prop(&geometry.rect.x_reference),
|
||||||
|
y = layout_prop(&geometry.rect.y_reference),
|
||||||
|
s = spacing,
|
||||||
|
p = padding,
|
||||||
|
));
|
||||||
|
code_stream.push(format!(" {cv}", cv = cell_ref_variable));
|
||||||
|
code_stream.push(" };".to_owned());
|
||||||
|
code_stream.push(" sixtyfps::solve_box_layout(&box);".to_owned());
|
||||||
|
code_stream.push(" } ".into());
|
||||||
|
}
|
||||||
LayoutTreeItem::PathLayout(path_layout) => {
|
LayoutTreeItem::PathLayout(path_layout) => {
|
||||||
code_stream.push("{".to_owned());
|
code_stream.push("{".to_owned());
|
||||||
|
|
||||||
|
@ -1762,6 +1838,7 @@ fn compute_layout(
|
||||||
|
|
||||||
res.extend(inverse_layout_tree.iter().filter_map(|layout| match layout {
|
res.extend(inverse_layout_tree.iter().filter_map(|layout| match layout {
|
||||||
LayoutTreeItem::GridLayout { var_creation_code, .. } => Some(var_creation_code.clone()),
|
LayoutTreeItem::GridLayout { var_creation_code, .. } => Some(var_creation_code.clone()),
|
||||||
|
LayoutTreeItem::BoxLayout { var_creation_code, .. } => Some(var_creation_code.clone()),
|
||||||
LayoutTreeItem::PathLayout(_) => None,
|
LayoutTreeItem::PathLayout(_) => None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -1371,6 +1371,54 @@ impl crate::layout::gen::Language for RustLanguageLayoutGen {
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn box_layout_tree_item<'a, 'b>(
|
||||||
|
layout_tree: &'b mut Vec<crate::layout::gen::LayoutTreeItem<'a, Self>>,
|
||||||
|
box_layout: &'a crate::layout::BoxLayout,
|
||||||
|
component: &Rc<Component>,
|
||||||
|
) -> crate::layout::gen::LayoutTreeItem<'a, Self> {
|
||||||
|
let cells: Vec<_> = box_layout
|
||||||
|
.elems
|
||||||
|
.iter()
|
||||||
|
.map(|cell| {
|
||||||
|
let get_property_ref = |p: &Option<NamedReference>| match p {
|
||||||
|
Some(nr) => {
|
||||||
|
let p = access_named_reference(nr, component, quote!(_self));
|
||||||
|
quote!(Some(#p.get_ref()))
|
||||||
|
}
|
||||||
|
None => quote!(None),
|
||||||
|
};
|
||||||
|
let lay_rect = cell.item.rect();
|
||||||
|
let width = get_property_ref(&lay_rect.width_reference);
|
||||||
|
let height = get_property_ref(&lay_rect.height_reference);
|
||||||
|
let x = get_property_ref(&lay_rect.x_reference);
|
||||||
|
let y = get_property_ref(&lay_rect.y_reference);
|
||||||
|
let layout_info =
|
||||||
|
get_layout_info_ref(&cell.item, &cell.constraints, layout_tree, component);
|
||||||
|
quote!(BoxLayoutCellData {
|
||||||
|
x: #x,
|
||||||
|
y: #y,
|
||||||
|
width: #width,
|
||||||
|
height: #height,
|
||||||
|
constraint: #layout_info,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
let cell_ref_variable = format_ident!("cells_{}", layout_tree.len());
|
||||||
|
let cell_creation_code = quote!(let #cell_ref_variable
|
||||||
|
= [#( #cells ),*];);
|
||||||
|
let (padding, spacing, spacing_creation_code) =
|
||||||
|
generate_layout_padding_and_spacing(&layout_tree, &box_layout.geometry, component);
|
||||||
|
|
||||||
|
LayoutTreeItem::BoxLayout {
|
||||||
|
geometry: &box_layout.geometry,
|
||||||
|
var_creation_code: quote!(#cell_creation_code #spacing_creation_code),
|
||||||
|
cell_ref_variable: quote!(#cell_ref_variable),
|
||||||
|
spacing,
|
||||||
|
padding,
|
||||||
|
}
|
||||||
|
.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type LayoutTreeItem<'a> = crate::layout::gen::LayoutTreeItem<'a, RustLanguageLayoutGen>;
|
type LayoutTreeItem<'a> = crate::layout::gen::LayoutTreeItem<'a, RustLanguageLayoutGen>;
|
||||||
|
@ -1382,15 +1430,18 @@ fn get_layout_info_ref<'a, 'b>(
|
||||||
component: &Rc<Component>,
|
component: &Rc<Component>,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let layout_info = item.layout.as_ref().map(|l|{
|
let layout_info = item.layout.as_ref().map(|l|{
|
||||||
let layout_tree_item =
|
let layout_tree_item =
|
||||||
crate::layout::gen::collect_layouts_recursively(layout_tree, l, component);
|
crate::layout::gen::collect_layouts_recursively(layout_tree, l, component);
|
||||||
match layout_tree_item {
|
match layout_tree_item {
|
||||||
LayoutTreeItem::GridLayout { cell_ref_variable, spacing, padding, .. } => {
|
LayoutTreeItem::GridLayout { cell_ref_variable, spacing, padding, .. } => {
|
||||||
quote!(grid_layout_info(&Slice::from_slice(&#cell_ref_variable), #spacing, #padding))
|
quote!(grid_layout_info(&Slice::from_slice(&#cell_ref_variable), #spacing, #padding))
|
||||||
}
|
|
||||||
LayoutTreeItem::PathLayout(_) => todo!(),
|
|
||||||
}
|
}
|
||||||
});
|
LayoutTreeItem::BoxLayout { cell_ref_variable, spacing, padding, .. } => {
|
||||||
|
quote!(box_layout_info(&Slice::from_slice(&#cell_ref_variable), #spacing, #padding))
|
||||||
|
}
|
||||||
|
LayoutTreeItem::PathLayout(_) => todo!(),
|
||||||
|
}
|
||||||
|
});
|
||||||
let elem_info = item.element.as_ref().map(|elem| {
|
let elem_info = item.element.as_ref().map(|elem| {
|
||||||
let e = format_ident!("{}", elem.borrow().id);
|
let e = format_ident!("{}", elem.borrow().id);
|
||||||
quote!(Self::FIELD_OFFSETS.#e.apply_pin(self).layouting_info(&window))
|
quote!(Self::FIELD_OFFSETS.#e.apply_pin(self).layouting_info(&window))
|
||||||
|
@ -1488,6 +1539,24 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
LayoutTreeItem::BoxLayout { geometry, cell_ref_variable, spacing, padding, .. } => {
|
||||||
|
let x_pos = layout_prop(&geometry.rect.x_reference);
|
||||||
|
let y_pos = layout_prop(&geometry.rect.y_reference);
|
||||||
|
let width = layout_prop(&geometry.rect.width_reference);
|
||||||
|
let height = layout_prop(&geometry.rect.height_reference);
|
||||||
|
|
||||||
|
code_stream.push(quote! {
|
||||||
|
solve_box_layout(&BoxLayoutData {
|
||||||
|
width: #width,
|
||||||
|
height: #height,
|
||||||
|
x: #x_pos as _,
|
||||||
|
y: #y_pos as _,
|
||||||
|
cells: Slice::from_slice(&#cell_ref_variable),
|
||||||
|
spacing: #spacing,
|
||||||
|
padding: #padding,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
LayoutTreeItem::PathLayout(path_layout) => {
|
LayoutTreeItem::PathLayout(path_layout) => {
|
||||||
let path_layout_item_data =
|
let path_layout_item_data =
|
||||||
|elem: &ElementRc, elem_rs: TokenStream, component_rust: TokenStream| {
|
|elem: &ElementRc, elem_rs: TokenStream, component_rust: TokenStream| {
|
||||||
|
@ -1615,6 +1684,7 @@ fn compute_layout(
|
||||||
|
|
||||||
layouts.extend(inverse_layout_tree.iter().filter_map(|layout| match layout {
|
layouts.extend(inverse_layout_tree.iter().filter_map(|layout| match layout {
|
||||||
LayoutTreeItem::GridLayout { var_creation_code, .. } => Some(var_creation_code.clone()),
|
LayoutTreeItem::GridLayout { var_creation_code, .. } => Some(var_creation_code.clone()),
|
||||||
|
LayoutTreeItem::BoxLayout { var_creation_code, .. } => Some(var_creation_code.clone()),
|
||||||
LayoutTreeItem::PathLayout(_) => None,
|
LayoutTreeItem::PathLayout(_) => None,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
@ -339,6 +339,12 @@ pub mod gen {
|
||||||
cells: Vec<Self::CompiledCode>,
|
cells: Vec<Self::CompiledCode>,
|
||||||
component: &Rc<Component>,
|
component: &Rc<Component>,
|
||||||
) -> LayoutTreeItem<'a, Self>;
|
) -> LayoutTreeItem<'a, Self>;
|
||||||
|
/// Returns a LayoutTree:BoxLayout
|
||||||
|
fn box_layout_tree_item<'a, 'b>(
|
||||||
|
layout_tree: &'b mut Vec<LayoutTreeItem<'a, Self>>,
|
||||||
|
box_layout: &'a BoxLayout,
|
||||||
|
component: &Rc<Component>,
|
||||||
|
) -> LayoutTreeItem<'a, Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(derive_more::From)]
|
#[derive(derive_more::From)]
|
||||||
|
@ -350,6 +356,14 @@ pub mod gen {
|
||||||
var_creation_code: L::CompiledCode,
|
var_creation_code: L::CompiledCode,
|
||||||
cell_ref_variable: L::CompiledCode,
|
cell_ref_variable: L::CompiledCode,
|
||||||
},
|
},
|
||||||
|
BoxLayout {
|
||||||
|
geometry: &'a LayoutGeometry,
|
||||||
|
spacing: L::CompiledCode,
|
||||||
|
padding: L::CompiledCode,
|
||||||
|
var_creation_code: L::CompiledCode,
|
||||||
|
cell_ref_variable: L::CompiledCode,
|
||||||
|
},
|
||||||
|
#[from]
|
||||||
PathLayout(&'a PathLayout),
|
PathLayout(&'a PathLayout),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -382,27 +396,7 @@ pub mod gen {
|
||||||
layout_tree.push(i);
|
layout_tree.push(i);
|
||||||
}
|
}
|
||||||
Layout::BoxLayout(box_layout) => {
|
Layout::BoxLayout(box_layout) => {
|
||||||
let cells: Vec<_> = box_layout
|
let i = L::box_layout_tree_item(layout_tree, box_layout, component);
|
||||||
.elems
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.map(|(idx, cell)| {
|
|
||||||
let (c, r) = if box_layout.is_horizontal { (idx, 0) } else { (0, idx) };
|
|
||||||
L::make_grid_layout_cell_data(
|
|
||||||
&cell.item,
|
|
||||||
&cell.constraints,
|
|
||||||
c as u16,
|
|
||||||
r as u16,
|
|
||||||
1,
|
|
||||||
1,
|
|
||||||
layout_tree,
|
|
||||||
component,
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
let i =
|
|
||||||
L::grid_layout_tree_item(layout_tree, &box_layout.geometry, cells, component);
|
|
||||||
layout_tree.push(i);
|
layout_tree.push(i);
|
||||||
}
|
}
|
||||||
Layout::PathLayout(layout) => layout_tree.push(layout.into()),
|
Layout::PathLayout(layout) => layout_tree.push(layout.into()),
|
||||||
|
|
|
@ -47,7 +47,7 @@ impl LayoutInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod internal {
|
mod grid_internal {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -226,8 +226,8 @@ pub extern "C" fn solve_grid_layout(data: &GridLayoutData) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut row_layout_data = vec![internal::LayoutData::default(); num_row as usize];
|
let mut row_layout_data = vec![grid_internal::LayoutData::default(); num_row as usize];
|
||||||
let mut col_layout_data = vec![internal::LayoutData::default(); num_col as usize];
|
let mut col_layout_data = vec![grid_internal::LayoutData::default(); num_col as usize];
|
||||||
for cell in data.cells.iter() {
|
for cell in data.cells.iter() {
|
||||||
let row_max = cell.constraint.max_height / (cell.rowspan as f32);
|
let row_max = cell.constraint.max_height / (cell.rowspan as f32);
|
||||||
let row_min = cell.constraint.min_height / (cell.rowspan as f32);
|
let row_min = cell.constraint.min_height / (cell.rowspan as f32);
|
||||||
|
@ -252,13 +252,13 @@ pub extern "C" fn solve_grid_layout(data: &GridLayoutData) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal::layout_items(
|
grid_internal::layout_items(
|
||||||
&mut row_layout_data,
|
&mut row_layout_data,
|
||||||
data.y + data.padding.top,
|
data.y + data.padding.top,
|
||||||
data.height - (data.padding.top + data.padding.bottom),
|
data.height - (data.padding.top + data.padding.bottom),
|
||||||
data.spacing,
|
data.spacing,
|
||||||
);
|
);
|
||||||
internal::layout_items(
|
grid_internal::layout_items(
|
||||||
&mut col_layout_data,
|
&mut col_layout_data,
|
||||||
data.x + data.padding.left,
|
data.x + data.padding.left,
|
||||||
data.width - (data.padding.left + data.padding.right),
|
data.width - (data.padding.left + data.padding.right),
|
||||||
|
@ -302,8 +302,8 @@ pub extern "C" fn grid_layout_info<'a>(
|
||||||
return LayoutInfo { min_width: 0., max_width: 0., min_height: 0., max_height: 0. };
|
return LayoutInfo { min_width: 0., max_width: 0., min_height: 0., max_height: 0. };
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut row_layout_data = vec![internal::LayoutData::default(); num_row as usize];
|
let mut row_layout_data = vec![grid_internal::LayoutData::default(); num_row as usize];
|
||||||
let mut col_layout_data = vec![internal::LayoutData::default(); num_col as usize];
|
let mut col_layout_data = vec![grid_internal::LayoutData::default(); num_col as usize];
|
||||||
for cell in cells.iter() {
|
for cell in cells.iter() {
|
||||||
let rdata = &mut row_layout_data[cell.row as usize];
|
let rdata = &mut row_layout_data[cell.row as usize];
|
||||||
let cdata = &mut col_layout_data[cell.col as usize];
|
let cdata = &mut col_layout_data[cell.col as usize];
|
||||||
|
@ -320,8 +320,8 @@ pub extern "C" fn grid_layout_info<'a>(
|
||||||
|
|
||||||
let min_height = row_layout_data.iter().map(|data| data.min).sum::<Coord>()
|
let min_height = row_layout_data.iter().map(|data| data.min).sum::<Coord>()
|
||||||
+ spacing_h
|
+ spacing_h
|
||||||
+ padding.left
|
+ padding.top
|
||||||
+ padding.right;
|
+ padding.bottom;
|
||||||
let max_height = row_layout_data.iter().map(|data| data.max).sum::<Coord>()
|
let max_height = row_layout_data.iter().map(|data| data.max).sum::<Coord>()
|
||||||
+ spacing_h
|
+ spacing_h
|
||||||
+ padding.top
|
+ padding.top
|
||||||
|
@ -332,9 +332,135 @@ pub extern "C" fn grid_layout_info<'a>(
|
||||||
+ padding.right;
|
+ padding.right;
|
||||||
let max_width = col_layout_data.iter().map(|data| data.max).sum::<Coord>()
|
let max_width = col_layout_data.iter().map(|data| data.max).sum::<Coord>()
|
||||||
+ spacing_w
|
+ spacing_w
|
||||||
|
+ padding.left
|
||||||
|
+ padding.right;
|
||||||
|
|
||||||
|
LayoutInfo { min_width, max_width, min_height, max_height }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
/// The BoxLayoutData is used to represent both a Horizontal and Vertical layout.
|
||||||
|
/// The width/height x/y corrspond to that of a horizontal layout.
|
||||||
|
/// For vertical layout, they are inverted
|
||||||
|
pub struct BoxLayoutData<'a> {
|
||||||
|
pub width: Coord,
|
||||||
|
pub height: Coord,
|
||||||
|
pub x: Coord,
|
||||||
|
pub y: Coord,
|
||||||
|
pub spacing: Coord,
|
||||||
|
pub padding: &'a Padding,
|
||||||
|
pub cells: Slice<'a, BoxLayoutCellData<'a>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
pub struct BoxLayoutCellData<'a> {
|
||||||
|
pub constraint: LayoutInfo,
|
||||||
|
pub x: Option<&'a Property<Coord>>,
|
||||||
|
pub y: Option<&'a Property<Coord>>,
|
||||||
|
pub width: Option<&'a Property<Coord>>,
|
||||||
|
pub height: Option<&'a Property<Coord>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Solve the horizontal BoxLayout
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn solve_box_layout(data: &BoxLayoutData) {
|
||||||
|
use stretch::geometry::*;
|
||||||
|
use stretch::number::*;
|
||||||
|
use stretch::style::*;
|
||||||
|
|
||||||
|
let mut stretch = stretch::Stretch::new();
|
||||||
|
|
||||||
|
let box_style = stretch::style::Style {
|
||||||
|
size: Size { width: Dimension::Percent(1.), height: Dimension::Percent(1.) },
|
||||||
|
flex_grow: 1.,
|
||||||
|
display: Display::Flex,
|
||||||
|
flex_direction: FlexDirection::Row,
|
||||||
|
flex_basis: Dimension::Percent(1.),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let flex_box = stretch.new_node(box_style, vec![]).unwrap();
|
||||||
|
|
||||||
|
for (index, cell) in data.cells.iter().enumerate() {
|
||||||
|
let min = if cell.constraint.min_width == 0.0 {
|
||||||
|
Dimension::Undefined
|
||||||
|
} else {
|
||||||
|
Dimension::Points(cell.constraint.min_height)
|
||||||
|
};
|
||||||
|
let max = if cell.constraint.max_width == f32::MAX {
|
||||||
|
Dimension::Undefined
|
||||||
|
} else {
|
||||||
|
Dimension::Points(cell.constraint.max_width)
|
||||||
|
};
|
||||||
|
let mut margin = Rect::default();
|
||||||
|
if index != 0 {
|
||||||
|
margin.start = Dimension::Points(data.spacing / 2.);
|
||||||
|
}
|
||||||
|
if index != data.cells.len() - 1 {
|
||||||
|
margin.end = Dimension::Points(data.spacing / 2.);
|
||||||
|
}
|
||||||
|
|
||||||
|
let cell_style = Style {
|
||||||
|
min_size: Size { width: min, height: Dimension::Auto },
|
||||||
|
max_size: Size { width: max, height: Dimension::Auto },
|
||||||
|
size: Size { width: min, height: Dimension::Auto },
|
||||||
|
flex_grow: 1.,
|
||||||
|
margin,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let cell_item = stretch.new_node(cell_style, vec![]).unwrap();
|
||||||
|
stretch.add_child(flex_box, cell_item).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
stretch
|
||||||
|
.compute_layout(
|
||||||
|
flex_box,
|
||||||
|
Size {
|
||||||
|
width: Number::Defined(data.width - (data.padding.left + data.padding.right)),
|
||||||
|
height: Number::Undefined,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let start_pos = data.x + data.padding.left;
|
||||||
|
|
||||||
|
for (cell, layout) in data.cells.iter().zip(
|
||||||
|
stretch.children(flex_box).unwrap().iter().map(|child| stretch.layout(*child).unwrap()),
|
||||||
|
) {
|
||||||
|
cell.x.map(|p| p.set(start_pos + layout.location.x));
|
||||||
|
cell.y.map(|p| p.set(data.y + data.padding.top));
|
||||||
|
cell.width.map(|p| p.set(layout.size.width));
|
||||||
|
cell.height.map(|p| p.set(data.height - (data.padding.top + data.padding.bottom)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
/// Return the LayoutInfo for a Horizontal BoxLayout with the given cells.
|
||||||
|
/// Transpose everything for vertical
|
||||||
|
pub extern "C" fn box_layout_info<'a>(
|
||||||
|
cells: &Slice<'a, BoxLayoutCellData<'a>>,
|
||||||
|
spacing: Coord,
|
||||||
|
padding: &Padding,
|
||||||
|
) -> LayoutInfo {
|
||||||
|
let count = cells.len();
|
||||||
|
if count < 1 {
|
||||||
|
return LayoutInfo { min_width: 0., max_width: 0., min_height: 0., max_height: 0. };
|
||||||
|
};
|
||||||
|
|
||||||
|
let extra_w = padding.left + padding.right + spacing * (count - 1) as Coord;
|
||||||
|
let order_float = |a: &Coord, b: &Coord| a.partial_cmp(b).unwrap_or(core::cmp::Ordering::Equal);
|
||||||
|
|
||||||
|
let min_height = cells.iter().map(|c| c.constraint.min_height).max_by(order_float).unwrap()
|
||||||
+ padding.top
|
+ padding.top
|
||||||
+ padding.bottom;
|
+ padding.bottom;
|
||||||
|
let max_height = cells.iter().map(|c| c.constraint.max_height).min_by(order_float).unwrap()
|
||||||
|
+ padding.top
|
||||||
|
+ padding.bottom;
|
||||||
|
let min_width = cells.iter().map(|c| c.constraint.min_width).sum::<Coord>() + extra_w;
|
||||||
|
let max_width = cells.iter().map(|c| c.constraint.max_width).sum::<Coord>() + extra_w;
|
||||||
LayoutInfo { min_width, max_width, min_height, max_height }
|
LayoutInfo { min_width, max_width, min_height, max_height }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -919,16 +919,17 @@ fn get_property_ptr(nr: &NamedReference, instance: InstanceRef) -> *const () {
|
||||||
|
|
||||||
use sixtyfps_corelib::layout::*;
|
use sixtyfps_corelib::layout::*;
|
||||||
|
|
||||||
pub struct GridLayoutWithCells<'a> {
|
pub struct LayoutWithCells<'a, C> {
|
||||||
geometry: &'a sixtyfps_compilerlib::layout::LayoutGeometry,
|
geometry: &'a sixtyfps_compilerlib::layout::LayoutGeometry,
|
||||||
cells: Vec<GridLayoutCellData<'a>>,
|
cells: Vec<C>,
|
||||||
spacing: f32,
|
spacing: f32,
|
||||||
padding: Padding,
|
padding: Padding,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(derive_more::From)]
|
#[derive(derive_more::From)]
|
||||||
enum LayoutTreeItem<'a> {
|
enum LayoutTreeItem<'a> {
|
||||||
GridLayout(GridLayoutWithCells<'a>),
|
GridLayout(LayoutWithCells<'a, GridLayoutCellData<'a>>),
|
||||||
|
BoxLayout(LayoutWithCells<'a, BoxLayoutCellData<'a>>),
|
||||||
PathLayout(&'a PathLayout),
|
PathLayout(&'a PathLayout),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -940,6 +941,11 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
grid_layout.spacing,
|
grid_layout.spacing,
|
||||||
&grid_layout.padding,
|
&grid_layout.padding,
|
||||||
),
|
),
|
||||||
|
LayoutTreeItem::BoxLayout(box_layout) => box_layout_info(
|
||||||
|
&Slice::from(box_layout.cells.as_slice()),
|
||||||
|
box_layout.spacing,
|
||||||
|
&box_layout.padding,
|
||||||
|
),
|
||||||
LayoutTreeItem::PathLayout(_) => todo!(),
|
LayoutTreeItem::PathLayout(_) => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1034,32 +1040,24 @@ fn collect_layouts_recursively<'a, 'b>(
|
||||||
bottom: grid_layout.geometry.padding.bottom.as_ref().map_or(0., expr_eval),
|
bottom: grid_layout.geometry.padding.bottom.as_ref().map_or(0., expr_eval),
|
||||||
};
|
};
|
||||||
layout_tree.push(
|
layout_tree.push(
|
||||||
GridLayoutWithCells { geometry: &grid_layout.geometry, cells, spacing, padding }
|
LayoutWithCells { geometry: &grid_layout.geometry, cells, spacing, padding }.into(),
|
||||||
.into(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Layout::BoxLayout(box_layout) => {
|
Layout::BoxLayout(box_layout) => {
|
||||||
let cells = box_layout
|
let cells = box_layout
|
||||||
.elems
|
.elems
|
||||||
.iter()
|
.iter()
|
||||||
.enumerate()
|
.map(|cell| {
|
||||||
.map(|(idx, cell)| {
|
|
||||||
let mut layout_info =
|
let mut layout_info =
|
||||||
get_layout_info(&cell.item, component, layout_tree, window);
|
get_layout_info(&cell.item, component, layout_tree, window);
|
||||||
fill_layout_info_constraints(&mut layout_info, &cell.constraints, &expr_eval);
|
fill_layout_info_constraints(&mut layout_info, &cell.constraints, &expr_eval);
|
||||||
let (col, row) =
|
|
||||||
if box_layout.is_horizontal { (idx as u16, 0) } else { (0, idx as u16) };
|
|
||||||
let rect = cell.item.rect();
|
let rect = cell.item.rect();
|
||||||
|
|
||||||
GridLayoutCellData {
|
BoxLayoutCellData {
|
||||||
x: assume_property_f32(&rect.x_reference),
|
x: assume_property_f32(&rect.x_reference),
|
||||||
y: assume_property_f32(&rect.y_reference),
|
y: assume_property_f32(&rect.y_reference),
|
||||||
width: assume_property_f32(&rect.width_reference),
|
width: assume_property_f32(&rect.width_reference),
|
||||||
height: assume_property_f32(&rect.height_reference),
|
height: assume_property_f32(&rect.height_reference),
|
||||||
col,
|
|
||||||
row,
|
|
||||||
colspan: 1,
|
|
||||||
rowspan: 1,
|
|
||||||
constraint: layout_info,
|
constraint: layout_info,
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -1072,8 +1070,7 @@ fn collect_layouts_recursively<'a, 'b>(
|
||||||
bottom: box_layout.geometry.padding.bottom.as_ref().map_or(0., expr_eval),
|
bottom: box_layout.geometry.padding.bottom.as_ref().map_or(0., expr_eval),
|
||||||
};
|
};
|
||||||
layout_tree.push(
|
layout_tree.push(
|
||||||
GridLayoutWithCells { geometry: &box_layout.geometry, cells, spacing, padding }
|
LayoutWithCells { geometry: &box_layout.geometry, cells, spacing, padding }.into(),
|
||||||
.into(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Layout::PathLayout(layout) => layout_tree.push(layout.into()),
|
Layout::PathLayout(layout) => layout_tree.push(layout.into()),
|
||||||
|
@ -1104,6 +1101,17 @@ impl<'a> LayoutTreeItem<'a> {
|
||||||
cells: Slice::from(grid_layout.cells.as_slice()),
|
cells: Slice::from(grid_layout.cells.as_slice()),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Self::BoxLayout(box_layout) => {
|
||||||
|
solve_box_layout(&BoxLayoutData {
|
||||||
|
width: resolve_prop_ref(&box_layout.geometry.rect.width_reference),
|
||||||
|
height: resolve_prop_ref(&box_layout.geometry.rect.height_reference),
|
||||||
|
x: resolve_prop_ref(&box_layout.geometry.rect.x_reference),
|
||||||
|
y: resolve_prop_ref(&box_layout.geometry.rect.y_reference),
|
||||||
|
spacing: box_layout.spacing,
|
||||||
|
padding: &box_layout.padding,
|
||||||
|
cells: Slice::from(box_layout.cells.as_slice()),
|
||||||
|
});
|
||||||
|
}
|
||||||
Self::PathLayout(path_layout) => {
|
Self::PathLayout(path_layout) => {
|
||||||
use sixtyfps_corelib::layout::*;
|
use sixtyfps_corelib::layout::*;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue