mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00

Instead of using a solve_layout function in the component, use property to hold a layout cache. This commit only implement the GridLayout and only the interpreter part
175 lines
6.5 KiB
Rust
175 lines
6.5 KiB
Rust
/* LICENSE BEGIN
|
|
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
|
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
|
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
|
|
|
SPDX-License-Identifier: GPL-3.0-only
|
|
This file is also available under commercial licensing terms.
|
|
Please contact info@sixtyfps.io for more information.
|
|
LICENSE END */
|
|
|
|
use crate::dynamic_component::InstanceRef;
|
|
use crate::eval::{self, ComponentInstance, EvalLocalContext};
|
|
use crate::Value;
|
|
use sixtyfps_compilerlib::expression_tree::Expression;
|
|
use sixtyfps_compilerlib::langtype::Type;
|
|
use sixtyfps_compilerlib::layout::{Layout, LayoutConstraints, LayoutItem};
|
|
use sixtyfps_compilerlib::namedreference::NamedReference;
|
|
use sixtyfps_corelib::layout as core_layout;
|
|
use sixtyfps_corelib::slice::Slice;
|
|
use sixtyfps_corelib::window::ComponentWindow;
|
|
use std::convert::TryInto;
|
|
|
|
pub(crate) fn compute_layout_info(lay: &Layout, local_context: &mut EvalLocalContext) -> Value {
|
|
let component = match local_context.component_instance {
|
|
ComponentInstance::InstanceRef(c) => c,
|
|
ComponentInstance::GlobalComponent(_) => panic!("Cannot compute layout from a Global"),
|
|
};
|
|
let expr_eval = |nr: &NamedReference| -> f32 {
|
|
eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
|
|
};
|
|
match lay {
|
|
Layout::GridLayout(grid_layout) => {
|
|
let (cells, padding, spacing) = grid_layout_data(grid_layout, component, &expr_eval);
|
|
core_layout::grid_layout_info(&Slice::from(cells.as_slice()), spacing, &padding).into()
|
|
}
|
|
_ => todo!(),
|
|
}
|
|
}
|
|
|
|
pub(crate) fn solve_layout(lay: &Layout, local_context: &mut EvalLocalContext) -> Value {
|
|
let component = match local_context.component_instance {
|
|
ComponentInstance::InstanceRef(c) => c,
|
|
ComponentInstance::GlobalComponent(_) => panic!("Cannot compute layout from a Global"),
|
|
};
|
|
let expr_eval = |nr: &NamedReference| -> f32 {
|
|
eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap()
|
|
};
|
|
|
|
match lay {
|
|
Layout::GridLayout(grid_layout) => {
|
|
let (cells, padding, spacing) = grid_layout_data(grid_layout, component, &expr_eval);
|
|
|
|
Value::LayoutCache(core_layout::solve_grid_layout(&core_layout::GridLayoutData {
|
|
width: grid_layout
|
|
.geometry
|
|
.rect
|
|
.width_reference
|
|
.as_ref()
|
|
.map(expr_eval)
|
|
.unwrap_or(0.),
|
|
height: grid_layout
|
|
.geometry
|
|
.rect
|
|
.height_reference
|
|
.as_ref()
|
|
.map(expr_eval)
|
|
.unwrap_or(0.),
|
|
x: 0.,
|
|
y: 0.,
|
|
spacing,
|
|
padding: &padding,
|
|
cells: Slice::from(cells.as_slice()),
|
|
}))
|
|
}
|
|
_ => todo!(),
|
|
}
|
|
}
|
|
|
|
/// return the celldata, the padding, and the spacing of a grid layout
|
|
fn grid_layout_data(
|
|
grid_layout: &sixtyfps_compilerlib::layout::GridLayout,
|
|
component: InstanceRef,
|
|
expr_eval: &impl Fn(&NamedReference) -> f32,
|
|
) -> (Vec<core_layout::GridLayoutCellData>, core_layout::Padding, f32) {
|
|
let cells = grid_layout
|
|
.elems
|
|
.iter()
|
|
.map(|cell| {
|
|
let mut layout_info =
|
|
get_layout_info(&cell.item, component, &eval::window_ref(component).unwrap());
|
|
fill_layout_info_constraints(&mut layout_info, &cell.item.constraints, &expr_eval);
|
|
core_layout::GridLayoutCellData {
|
|
col: cell.col,
|
|
row: cell.row,
|
|
colspan: cell.colspan,
|
|
rowspan: cell.rowspan,
|
|
constraint: layout_info,
|
|
}
|
|
})
|
|
.collect::<Vec<_>>();
|
|
let spacing = grid_layout.geometry.spacing.as_ref().map_or(0., expr_eval);
|
|
let padding = core_layout::Padding {
|
|
left: grid_layout.geometry.padding.left.as_ref().map_or(0., expr_eval),
|
|
right: grid_layout.geometry.padding.right.as_ref().map_or(0., expr_eval),
|
|
top: grid_layout.geometry.padding.top.as_ref().map_or(0., expr_eval),
|
|
bottom: grid_layout.geometry.padding.bottom.as_ref().map_or(0., expr_eval),
|
|
};
|
|
(cells, padding, spacing)
|
|
}
|
|
|
|
pub(crate) fn fill_layout_info_constraints(
|
|
layout_info: &mut core_layout::LayoutInfo,
|
|
constraints: &LayoutConstraints,
|
|
expr_eval: &impl Fn(&NamedReference) -> f32,
|
|
) {
|
|
let is_percent =
|
|
|nr: &NamedReference| Expression::PropertyReference(nr.clone()).ty() == Type::Percent;
|
|
constraints.minimum_width.as_ref().map(|e| {
|
|
if !is_percent(e) {
|
|
layout_info.min_width = expr_eval(e)
|
|
} else {
|
|
layout_info.min_width_percent = expr_eval(e)
|
|
}
|
|
});
|
|
constraints.maximum_width.as_ref().map(|e| {
|
|
if !is_percent(e) {
|
|
layout_info.max_width = expr_eval(e)
|
|
} else {
|
|
layout_info.max_width_percent = expr_eval(e)
|
|
}
|
|
});
|
|
constraints.minimum_height.as_ref().map(|e| {
|
|
if !is_percent(e) {
|
|
layout_info.min_height = expr_eval(e)
|
|
} else {
|
|
layout_info.min_height_percent = expr_eval(e)
|
|
}
|
|
});
|
|
constraints.maximum_height.as_ref().map(|e| {
|
|
if !is_percent(e) {
|
|
layout_info.max_height = expr_eval(e)
|
|
} else {
|
|
layout_info.max_height_percent = expr_eval(e)
|
|
}
|
|
});
|
|
constraints.preferred_width.as_ref().map(|e| {
|
|
layout_info.preferred_width = expr_eval(e);
|
|
});
|
|
constraints.preferred_height.as_ref().map(|e| {
|
|
layout_info.preferred_height = expr_eval(e);
|
|
});
|
|
constraints.horizontal_stretch.as_ref().map(|e| layout_info.horizontal_stretch = expr_eval(e));
|
|
constraints.vertical_stretch.as_ref().map(|e| layout_info.vertical_stretch = expr_eval(e));
|
|
}
|
|
|
|
fn get_layout_info<'a, 'b>(
|
|
item: &'a LayoutItem,
|
|
component: InstanceRef<'a, '_>,
|
|
window: &ComponentWindow,
|
|
) -> core_layout::LayoutInfo {
|
|
let elem = item.element.borrow();
|
|
let item = &component
|
|
.component_type
|
|
.items
|
|
.get(elem.id.as_str())
|
|
.unwrap_or_else(|| panic!("Internal error: Item {} not found", elem.id));
|
|
let r = unsafe { item.item_from_component(component.as_ptr()).as_ref().layouting_info(window) };
|
|
if let Some(nr) = &elem.layout_info_prop {
|
|
r.merge(
|
|
&eval::load_property(component, &nr.element(), nr.name()).unwrap().try_into().unwrap(),
|
|
)
|
|
} else {
|
|
r
|
|
}
|
|
}
|