mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-28 04:45:13 +00:00
Refactor GridLayout
This commit is contained in:
parent
0a722c86b3
commit
b57f3775c9
10 changed files with 130 additions and 169 deletions
|
@ -73,7 +73,6 @@ constexpr inline ItemTreeNode<uint8_t> make_dyn_node(std::uintptr_t offset)
|
|||
using internal::sixtyfps_visit_item_tree;
|
||||
|
||||
// layouts:
|
||||
using internal::Constraint;
|
||||
using internal::GridLayoutCellData;
|
||||
using internal::GridLayoutData;
|
||||
using internal::PathLayoutData;
|
||||
|
|
|
@ -81,8 +81,8 @@ pub mod re_exports {
|
|||
pub use sixtyfps_corelib::abi::slice::Slice;
|
||||
pub use sixtyfps_corelib::item_tree::visit_item_tree;
|
||||
pub use sixtyfps_corelib::layout::{
|
||||
solve_grid_layout, solve_path_layout, Constraint, GridLayoutCellData, GridLayoutData,
|
||||
PathLayoutData, PathLayoutItemData,
|
||||
solve_grid_layout, solve_path_layout, GridLayoutCellData, GridLayoutData, PathLayoutData,
|
||||
PathLayoutItemData,
|
||||
};
|
||||
pub use sixtyfps_corelib::Color;
|
||||
pub use sixtyfps_corelib::ComponentVTable_static;
|
||||
|
|
|
@ -892,56 +892,32 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
|||
));
|
||||
for grid in component.layout_constraints.borrow().grids.iter() {
|
||||
res.push("{".to_owned());
|
||||
res.push(format!(" std::array<sixtyfps::Constraint, {}> row_constr;", grid.row_count()));
|
||||
res.push(format!(" std::array<sixtyfps::Constraint, {}> col_constr;", grid.col_count()));
|
||||
res.push(
|
||||
" row_constr.fill(sixtyfps::Constraint{0., std::numeric_limits<float>::max()});"
|
||||
.to_owned(),
|
||||
);
|
||||
res.push(
|
||||
" col_constr.fill(sixtyfps::Constraint{0., std::numeric_limits<float>::max()});"
|
||||
.to_owned(),
|
||||
);
|
||||
res.push(" sixtyfps::GridLayoutCellData grid_data[] = {".to_owned());
|
||||
let mut row_info = vec![];
|
||||
let mut count = 0;
|
||||
for row in &grid.elems {
|
||||
row_info.push(format!("{{ &grid_data[{}], {} }}", count, row.len()));
|
||||
for cell in row {
|
||||
if let Some(cell) = cell {
|
||||
for cell in &grid.elems {
|
||||
let p = |n: &str| {
|
||||
if cell.borrow().lookup_property(n) == Type::Length {
|
||||
format!("&self->{}.{}", cell.borrow().id, n)
|
||||
if cell.item.borrow().lookup_property(n) == Type::Length {
|
||||
format!("&self->{}.{}", cell.item.borrow().id, n)
|
||||
} else {
|
||||
"nullptr".to_owned()
|
||||
}
|
||||
};
|
||||
res.push(format!(
|
||||
" {{ {}, {}, {}, {} }},",
|
||||
p("x"),
|
||||
p("y"),
|
||||
p("width"),
|
||||
p("height")
|
||||
" {{ {c}, {r}, {cs}, {rs}, sixtyfps::{vt}.layouting_info({{&sixtyfps::{vt}, const_cast<sixtyfps::{ty}*>(&self->{id})}}), {x}, {y}, {w}, {h} }},",
|
||||
c = cell.col, r = cell.row, cs = cell.colspan, rs =cell.rowspan,
|
||||
vt = cell.item.borrow().base_type.as_native().vtable_symbol,
|
||||
ty = cell.item.borrow().base_type.as_native().class_name,
|
||||
id = cell.item.borrow().id,
|
||||
x = p("x"), y = p("y"), w = p("width"), h = p("height")
|
||||
));
|
||||
} else {
|
||||
res.push(" {},".into());
|
||||
}
|
||||
count += 1;
|
||||
}
|
||||
}
|
||||
res.push(" };".to_owned());
|
||||
res.push(" sixtyfps::Slice<sixtyfps::GridLayoutCellData> cells[] = {".to_owned());
|
||||
res.push(format!(" {} }};", row_info.join(", ")));
|
||||
res.push(format!(" auto x = {};", compile_expression(&grid.x_reference, component)));
|
||||
res.push(format!(" auto y = {};", compile_expression(&grid.y_reference, component)));
|
||||
res.push(" sixtyfps::GridLayoutData grid { ".into());
|
||||
// FIXME: add auto conversion from std::array* to Slice
|
||||
res.push(" { row_constr.data(), row_constr.size() },".to_owned());
|
||||
res.push(" { col_constr.data(), col_constr.size() },".to_owned());
|
||||
res.push(format!(" self->{}.width.get(),", grid.within.borrow().id));
|
||||
res.push(format!(" self->{}.height.get(),", grid.within.borrow().id));
|
||||
res.push(" x, y,".to_owned());
|
||||
res.push(" {cells, std::size(cells)}".to_owned());
|
||||
res.push(" {grid_data, std::size(grid_data)}".to_owned());
|
||||
res.push(" };".to_owned());
|
||||
res.push(" sixtyfps::solve_grid_layout(&grid);".to_owned());
|
||||
res.push("}".to_owned());
|
||||
|
|
|
@ -720,19 +720,10 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
|
|||
"{}",
|
||||
grid_layout.within.borrow().base_type.as_native().class_name
|
||||
);
|
||||
let row_constraint = vec![quote!(Constraint::default()); grid_layout.row_count()];
|
||||
let col_constraint = vec![quote!(Constraint::default()); grid_layout.col_count()];
|
||||
let cells = grid_layout
|
||||
.elems
|
||||
.iter()
|
||||
.map(|x| {
|
||||
x.iter()
|
||||
.map(|y| {
|
||||
y.as_ref()
|
||||
.map(|elem| {
|
||||
let e = quote::format_ident!("{}", elem.borrow().id);
|
||||
let cells = grid_layout.elems.iter().map(|cell| {
|
||||
let e = quote::format_ident!("{}", cell.item.borrow().id);
|
||||
let p = |n: &str| {
|
||||
if elem.borrow().lookup_property(n) == Type::Length {
|
||||
if cell.item.borrow().lookup_property(n) == Type::Length {
|
||||
let n = quote::format_ident!("{}", n);
|
||||
quote! {Some(&self.#e.#n)}
|
||||
} else {
|
||||
|
@ -743,33 +734,32 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
|
|||
let height = p("height");
|
||||
let x = p("x");
|
||||
let y = p("y");
|
||||
let (col, row, colspan, rowspan) = (cell.col, cell.row, cell.colspan, cell.rowspan);
|
||||
quote!(GridLayoutCellData {
|
||||
x: #x,
|
||||
y: #y,
|
||||
width: #width,
|
||||
height: #height,
|
||||
col: #col,
|
||||
row: #row,
|
||||
colspan: #colspan,
|
||||
rowspan: #rowspan,
|
||||
constraint: Self::field_offsets().#e.apply_pin(self).layouting_info(),
|
||||
})
|
||||
})
|
||||
.unwrap_or_else(|| quote!(GridLayoutCellData::default()))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
});
|
||||
|
||||
let x_pos = compile_expression(&*grid_layout.x_reference, &component);
|
||||
let y_pos = compile_expression(&*grid_layout.y_reference, &component);
|
||||
|
||||
layouts.push(quote! {
|
||||
solve_grid_layout(&GridLayoutData {
|
||||
row_constraint: Slice::from_slice(&[#(#row_constraint),*]),
|
||||
col_constraint: Slice::from_slice(&[#(#col_constraint),*]),
|
||||
width: (Self::field_offsets().#within + #within_ty::field_offsets().width)
|
||||
.apply_pin(self).get(),
|
||||
height: (Self::field_offsets().#within + #within_ty::field_offsets().height)
|
||||
.apply_pin(self).get(),
|
||||
x: #x_pos,
|
||||
y: #y_pos,
|
||||
cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]),
|
||||
cells: Slice::from_slice(&[#( #cells ),*]),
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -17,6 +17,16 @@ impl ExpressionFieldsVisitor for LayoutConstraints {
|
|||
}
|
||||
}
|
||||
|
||||
/// An element in a GridLayout
|
||||
#[derive(Debug)]
|
||||
pub struct GridLayoutElement {
|
||||
pub col: u16,
|
||||
pub row: u16,
|
||||
pub colspan: u16,
|
||||
pub rowspan: u16,
|
||||
pub item: ElementRc,
|
||||
}
|
||||
|
||||
/// Internal representation of a grid layout
|
||||
#[derive(Debug)]
|
||||
pub struct GridLayout {
|
||||
|
@ -24,21 +34,11 @@ pub struct GridLayout {
|
|||
///
|
||||
/// FIXME: This should not be implemented like that instead there should be
|
||||
pub within: ElementRc,
|
||||
/// This is like a matrix of elements.
|
||||
pub elems: Vec<Vec<Option<ElementRc>>>,
|
||||
pub elems: Vec<GridLayoutElement>,
|
||||
pub x_reference: Box<Expression>,
|
||||
pub y_reference: Box<Expression>,
|
||||
}
|
||||
|
||||
impl GridLayout {
|
||||
pub fn col_count(&self) -> usize {
|
||||
self.elems.iter().map(|x| x.len()).max().unwrap_or(0)
|
||||
}
|
||||
pub fn row_count(&self) -> usize {
|
||||
self.elems.len()
|
||||
}
|
||||
}
|
||||
|
||||
impl ExpressionFieldsVisitor for GridLayout {
|
||||
fn visit_expressions(&mut self, mut visitor: impl FnMut(&mut Expression)) {
|
||||
visitor(&mut self.x_reference);
|
||||
|
|
|
@ -100,8 +100,8 @@ pub fn run_passes(
|
|||
passes::inlining::inline(doc);
|
||||
passes::compile_paths::compile_paths(&doc.root_component, &doc.local_registry, diag);
|
||||
passes::unique_id::assign_unique_id(&doc.root_component);
|
||||
passes::materialize_fake_properties::materialize_fake_properties(&doc.root_component);
|
||||
passes::lower_layout::lower_layouts(&doc.root_component, diag);
|
||||
passes::materialize_fake_properties::materialize_fake_properties(&doc.root_component);
|
||||
if compiler_config.embed_resources {
|
||||
passes::collect_resources::collect_resources(&doc.root_component);
|
||||
}
|
||||
|
|
|
@ -119,25 +119,7 @@ pub fn lower_layouts(component: &Rc<Component>, diag: &mut BuildDiagnostics) {
|
|||
}
|
||||
|
||||
impl GridLayout {
|
||||
fn add_element(
|
||||
&mut self,
|
||||
elem: ElementRc,
|
||||
row: usize,
|
||||
col: usize,
|
||||
diag: &mut BuildDiagnostics,
|
||||
) {
|
||||
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())
|
||||
}
|
||||
*cell = Some(elem)
|
||||
fn add_element(&mut self, item: ElementRc, row: u16, col: u16, _diag: &mut BuildDiagnostics) {
|
||||
self.elems.push(GridLayoutElement { col, row, colspan: 1, rowspan: 1, item });
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//! FFI-friendly slice
|
||||
|
||||
use core::{cmp::PartialEq, marker::PhantomData, ptr::NonNull};
|
||||
use core::{cmp::PartialEq, fmt::Debug, marker::PhantomData, ptr::NonNull};
|
||||
|
||||
/// That's basicaly the same as `&'a [T]` but `repr(C)`
|
||||
///
|
||||
|
@ -28,7 +28,7 @@ use core::{cmp::PartialEq, marker::PhantomData, ptr::NonNull};
|
|||
/// assert_eq!(a.as_slice(), b.as_slice());
|
||||
/// ```
|
||||
#[repr(C)]
|
||||
#[derive(PartialEq, Debug)]
|
||||
#[derive(PartialEq)]
|
||||
pub struct Slice<'a, T> {
|
||||
/// Invariant, this is a valid slice of len `len`
|
||||
ptr: NonNull<T>,
|
||||
|
@ -36,6 +36,12 @@ pub struct Slice<'a, T> {
|
|||
phantom: PhantomData<&'a [T]>,
|
||||
}
|
||||
|
||||
impl<'a, T: Debug> Debug for Slice<'a, T> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.as_slice().fmt(f)
|
||||
}
|
||||
}
|
||||
|
||||
// Need to implement manually otheriwse it is not implemented if T do not implement Copy / Clone
|
||||
impl<'a, T> Copy for Slice<'a, T> {}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ type Coord = f32;
|
|||
mod internal {
|
||||
use super::*;
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct LayoutData {
|
||||
// inputs
|
||||
pub min: Coord,
|
||||
|
@ -22,6 +22,12 @@ mod internal {
|
|||
pub size: Coord,
|
||||
}
|
||||
|
||||
impl Default for LayoutData {
|
||||
fn default() -> Self {
|
||||
LayoutData { min: 0., max: Coord::MAX, pref: 0., stretch: 1., pos: 0., size: 0. }
|
||||
}
|
||||
}
|
||||
|
||||
/// Layout the items within a specified size
|
||||
///
|
||||
/// This is quite a simple implementation for now
|
||||
|
@ -112,19 +118,23 @@ impl Default for Constraint {
|
|||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug)]
|
||||
pub struct GridLayoutData<'a> {
|
||||
pub row_constraint: Slice<'a, Constraint>,
|
||||
pub col_constraint: Slice<'a, Constraint>,
|
||||
pub width: Coord,
|
||||
pub height: Coord,
|
||||
pub x: Coord,
|
||||
pub y: Coord,
|
||||
pub cells: Slice<'a, Slice<'a, GridLayoutCellData<'a>>>,
|
||||
pub cells: Slice<'a, GridLayoutCellData<'a>>,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Default)]
|
||||
#[derive(Default, Debug)]
|
||||
pub struct GridLayoutCellData<'a> {
|
||||
pub col: u16,
|
||||
pub row: u16,
|
||||
pub colspan: u16,
|
||||
pub rowspan: u16,
|
||||
pub constraint: crate::abi::datastructures::LayoutInfo,
|
||||
pub x: Option<&'a Property<Coord>>,
|
||||
pub y: Option<&'a Property<Coord>>,
|
||||
pub width: Option<&'a Property<Coord>>,
|
||||
|
@ -134,26 +144,34 @@ pub struct GridLayoutCellData<'a> {
|
|||
/// FIXME: rename with sixstyfps prefix
|
||||
#[no_mangle]
|
||||
pub extern "C" fn solve_grid_layout(data: &GridLayoutData) {
|
||||
let map = |c: &Constraint| internal::LayoutData {
|
||||
min: c.min,
|
||||
max: c.max,
|
||||
pref: c.min,
|
||||
stretch: 1.,
|
||||
pos: 0.,
|
||||
size: 0.,
|
||||
};
|
||||
let (mut num_col, mut num_row) = (0, 0);
|
||||
for cell in data.cells.iter() {
|
||||
num_row = num_row.max(cell.row + cell.rowspan);
|
||||
num_col = num_col.max(cell.col + cell.colspan);
|
||||
}
|
||||
|
||||
let mut row_layout_data = vec![internal::LayoutData::default(); num_row as usize];
|
||||
let mut col_layout_data = vec![internal::LayoutData::default(); num_col as usize];
|
||||
for cell in data.cells.iter() {
|
||||
let rdata = &mut row_layout_data[cell.row as usize];
|
||||
let cdata = &mut col_layout_data[cell.col as usize];
|
||||
rdata.max = rdata.max.min(cell.constraint.max_height);
|
||||
cdata.max = cdata.max.min(cell.constraint.max_width);
|
||||
rdata.min = rdata.min.max(cell.constraint.min_height);
|
||||
cdata.min = cdata.min.max(cell.constraint.min_width);
|
||||
rdata.pref = rdata.pref.max(cell.constraint.min_height);
|
||||
cdata.pref = cdata.pref.max(cell.constraint.min_width);
|
||||
}
|
||||
|
||||
let mut row_layout_data = data.row_constraint.iter().map(map).collect::<Vec<_>>();
|
||||
let mut col_layout_data = data.col_constraint.iter().map(map).collect::<Vec<_>>();
|
||||
internal::layout_items(&mut row_layout_data, data.y, data.height);
|
||||
internal::layout_items(&mut col_layout_data, data.x, data.width);
|
||||
for (row_data, row) in row_layout_data.iter().zip(data.cells.iter()) {
|
||||
for (col_data, cell) in col_layout_data.iter().zip(row.iter()) {
|
||||
cell.x.map(|p| p.set(col_data.pos));
|
||||
cell.width.map(|p| p.set(col_data.size));
|
||||
cell.y.map(|p| p.set(row_data.pos));
|
||||
cell.height.map(|p| p.set(row_data.size));
|
||||
}
|
||||
for cell in data.cells.iter() {
|
||||
let rdata = &row_layout_data[cell.row as usize];
|
||||
let cdata = &col_layout_data[cell.col as usize];
|
||||
cell.x.map(|p| p.set(cdata.pos));
|
||||
cell.width.map(|p| p.set(cdata.size));
|
||||
cell.y.map(|p| p.set(rdata.pos));
|
||||
cell.height.map(|p| p.set(rdata.size));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -629,6 +629,8 @@ pub fn instantiate(
|
|||
component_box
|
||||
}
|
||||
|
||||
use sixtyfps_corelib::layout::*;
|
||||
|
||||
unsafe extern "C" fn compute_layout(component: ComponentRefPin) {
|
||||
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
|
||||
let component_type =
|
||||
|
@ -641,24 +643,11 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin) {
|
|||
};
|
||||
|
||||
for it in &component_type.original.layout_constraints.borrow().grids {
|
||||
use sixtyfps_corelib::layout::*;
|
||||
|
||||
let mut row_constraint = vec![];
|
||||
let mut col_constraint = vec![];
|
||||
//let mut cells = vec![];
|
||||
|
||||
row_constraint.resize_with(it.row_count(), Default::default);
|
||||
col_constraint.resize_with(it.col_count(), Default::default);
|
||||
|
||||
let cells_v = it
|
||||
let cells = it
|
||||
.elems
|
||||
.iter()
|
||||
.map(|x| {
|
||||
x.iter()
|
||||
.map(|y| {
|
||||
y.as_ref()
|
||||
.map(|elem| {
|
||||
let info = &component_type.items[elem.borrow().id.as_str()];
|
||||
.map(|cell| {
|
||||
let info = &component_type.items[cell.item.borrow().id.as_str()];
|
||||
let get_prop = |name| {
|
||||
info.rtti.properties.get(name).map(|p| {
|
||||
&*(component.as_ptr().add(info.offset).add(p.offset())
|
||||
|
@ -670,14 +659,17 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin) {
|
|||
y: get_prop("y"),
|
||||
width: get_prop("width"),
|
||||
height: get_prop("height"),
|
||||
col: cell.col,
|
||||
row: cell.row,
|
||||
colspan: cell.colspan,
|
||||
rowspan: cell.rowspan,
|
||||
constraint: info
|
||||
.item_from_component(component.as_ptr())
|
||||
.as_ref()
|
||||
.layouting_info(),
|
||||
}
|
||||
})
|
||||
.unwrap_or_default()
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
let cells = cells_v.iter().map(|x| x.as_slice().into()).collect::<Vec<Slice<_>>>();
|
||||
|
||||
let within_info = &component_type.items[it.within.borrow().id.as_str()];
|
||||
let within_prop = |name| {
|
||||
|
@ -688,8 +680,6 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin) {
|
|||
};
|
||||
|
||||
solve_grid_layout(&GridLayoutData {
|
||||
row_constraint: Slice::from(row_constraint.as_slice()),
|
||||
col_constraint: Slice::from(col_constraint.as_slice()),
|
||||
width: within_prop("width"),
|
||||
height: within_prop("height"),
|
||||
x: resolve_prop_ref(&it.x_reference),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue