mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Layout refactoring: C++ part
This commit is contained in:
parent
539a78e807
commit
ba1aff84d0
8 changed files with 334 additions and 608 deletions
|
@ -309,7 +309,6 @@ using cbindgen_private::LayoutAlignment;
|
|||
using cbindgen_private::LayoutInfo;
|
||||
using cbindgen_private::Padding;
|
||||
using cbindgen_private::PathLayoutData;
|
||||
using cbindgen_private::PathLayoutItemData;
|
||||
using cbindgen_private::Rect;
|
||||
using cbindgen_private::sixtyfps_box_layout_info;
|
||||
using cbindgen_private::sixtyfps_grid_layout_info;
|
||||
|
@ -346,6 +345,29 @@ inline LayoutInfo LayoutInfo::merge(const LayoutInfo &other) const
|
|||
std::min(vertical_stretch, other.vertical_stretch) };
|
||||
}
|
||||
|
||||
/// FIXME! this should be done by cbindgen
|
||||
namespace cbindgen_private {
|
||||
inline bool operator==(const LayoutInfo &a, const LayoutInfo &b)
|
||||
{
|
||||
return a.min_width == b.min_width &&
|
||||
a.max_width == b.max_width &&
|
||||
a.min_height == b.min_height &&
|
||||
a.max_height == b.max_height &&
|
||||
a.min_width_percent == b.min_width_percent &&
|
||||
a.max_width_percent == b.max_width_percent &&
|
||||
a.min_height_percent == b.min_height_percent &&
|
||||
a.max_height_percent == b.max_height_percent &&
|
||||
a.preferred_width == b.preferred_width &&
|
||||
a.preferred_height == b.preferred_height &&
|
||||
a.horizontal_stretch == b.horizontal_stretch &&
|
||||
a.vertical_stretch == b.vertical_stretch;
|
||||
}
|
||||
inline bool operator!=(const LayoutInfo &a, const LayoutInfo &b)
|
||||
{
|
||||
return !(a == b);
|
||||
}
|
||||
}
|
||||
|
||||
// models
|
||||
struct AbstractRepeaterView
|
||||
{
|
||||
|
|
|
@ -133,7 +133,7 @@ public:
|
|||
return a.inner == b.inner;
|
||||
}
|
||||
friend bool operator!=(const VRc &a, const VRc &b) {
|
||||
return a.inner == b.inner;
|
||||
return a.inner != b.inner;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -169,6 +169,13 @@ public:
|
|||
}
|
||||
|
||||
VWeak<VTable, Dyn> into_dyn() const { return *reinterpret_cast<const VWeak<VTable, Dyn> *>(this); }
|
||||
|
||||
friend bool operator==(const VWeak &a, const VWeak &b) {
|
||||
return a.inner == b.inner;
|
||||
}
|
||||
friend bool operator!=(const VWeak &a, const VWeak &b) {
|
||||
return a.inner != b.inner;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -221,7 +221,7 @@ use crate::expression_tree::{
|
|||
BindingExpression, BuiltinFunction, EasingCurve, Expression, NamedReference,
|
||||
};
|
||||
use crate::langtype::Type;
|
||||
use crate::layout::LayoutGeometry;
|
||||
use crate::layout::{Layout, LayoutGeometry, LayoutRect};
|
||||
use crate::object_tree::{
|
||||
Component, Document, Element, ElementRc, PropertyDeclaration, RepeatedElementInfo,
|
||||
};
|
||||
|
@ -244,20 +244,22 @@ impl CppType for Type {
|
|||
Type::LogicalLength => Some("float".to_owned()),
|
||||
Type::Percent => Some("float".to_owned()),
|
||||
Type::Bool => Some("bool".to_owned()),
|
||||
Type::Struct { fields, name, .. } => {
|
||||
if let Some(name) = name {
|
||||
Some(name.clone())
|
||||
} else {
|
||||
Type::Struct { name: Some(name), node: Some(_), .. } => Some(name.clone()),
|
||||
Type::Struct { name: Some(name), node: None, .. } => {
|
||||
Some(format!("sixtyfps::{}", name))
|
||||
}
|
||||
Type::Struct { fields, .. } => {
|
||||
let elem = fields.values().map(|v| v.cpp_type()).collect::<Option<Vec<_>>>()?;
|
||||
// This will produce a tuple
|
||||
|
||||
Some(format!("std::tuple<{}>", elem.join(", ")))
|
||||
}
|
||||
}
|
||||
|
||||
Type::Array(i) => Some(format!("std::shared_ptr<sixtyfps::Model<{}>>", i.cpp_type()?)),
|
||||
Type::Image => Some("sixtyfps::ImageReference".to_owned()),
|
||||
Type::Builtin(elem) => elem.native_class.cpp_type.clone(),
|
||||
Type::Enumeration(enumeration) => Some(format!("sixtyfps::{}", enumeration.name)),
|
||||
Type::Brush => Some("sixtyfps::Brush".to_owned()),
|
||||
Type::LayoutCache => Some("sixtyfps::SharedVector<float>".into()),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
@ -514,9 +516,6 @@ fn handle_repeater(
|
|||
));
|
||||
|
||||
layout_repeater_code.push(format!("self->{}.ensure_updated(self);", repeater_id));
|
||||
// FIXME: we should probably pass the parent element rect?
|
||||
layout_repeater_code
|
||||
.push(format!("self->{}.compute_layout(sixtyfps::Rect{{ }});", repeater_id,));
|
||||
}
|
||||
|
||||
repeated_input_branch.push(format!(
|
||||
|
@ -550,7 +549,7 @@ pub fn generate(doc: &Document, diag: &mut BuildDiagnostics) -> Option<impl std:
|
|||
file.includes.push("<sixtyfps.h>".into());
|
||||
|
||||
for ty in doc.root_component.used_structs.borrow().iter() {
|
||||
if let Type::Struct { fields, name: Some(name), .. } = ty {
|
||||
if let Type::Struct { fields, name: Some(name), node: Some(_) } = ty {
|
||||
generate_struct(&mut file, name, fields, diag);
|
||||
}
|
||||
}
|
||||
|
@ -834,10 +833,11 @@ fn generate_component(
|
|||
));
|
||||
component_struct.friends.push(parent_component_id);
|
||||
|
||||
if parent_element.borrow().repeated.as_ref().map_or(false, |r| r.is_listview.is_some()) {
|
||||
let p_y = access_member(&component.root_element, "y", component, "this");
|
||||
let p_height = access_member(&component.root_element, "height", component, "this");
|
||||
let p_width = access_member(&component.root_element, "width", component, "this");
|
||||
if parent_element.borrow().repeated.as_ref().map_or(false, |r| r.is_listview.is_some()) {
|
||||
|
||||
component_struct.members.push((
|
||||
Access::Public, // Because Repeater accesses it
|
||||
Declaration::Function(Function {
|
||||
|
@ -847,7 +847,7 @@ fn generate_component(
|
|||
.to_owned(),
|
||||
statements: Some(vec![
|
||||
"float vp_w = viewport_width->get();".to_owned(),
|
||||
format!("apply_layout({{&static_vtable, const_cast<void *>(static_cast<const void *>(this))}}, sixtyfps::Rect{{ 0, *offset_y, vp_w, {h} }});", h = "0/*FIXME: should compute the heigth somehow*/"),
|
||||
|
||||
format!("{}.set(*offset_y);", p_y), // FIXME: shouldn't that be handled by apply layout?
|
||||
format!("*offset_y += {}.get();", p_height),
|
||||
format!("float w = {}.get();", p_width),
|
||||
|
@ -858,22 +858,13 @@ fn generate_component(
|
|||
}),
|
||||
));
|
||||
} else if parent_element.borrow().repeated.is_some() {
|
||||
let p_x = access_member(&component.root_element, "x", component, "this");
|
||||
let root_c = &component.layouts.borrow().root_constraints;
|
||||
|
||||
component_struct.members.push((
|
||||
Access::Public, // Because Repeater accesses it
|
||||
Declaration::Function(Function {
|
||||
name: "box_layout_data".into(),
|
||||
signature: "() const -> sixtyfps::BoxLayoutCellData".to_owned(),
|
||||
statements: Some(vec![format!(
|
||||
"return {{ layouting_info({{&static_vtable, const_cast<void *>(static_cast<const void *>(this))}}), &{x}, &{y}, {w}, {h} }};",
|
||||
x = p_x,
|
||||
y = p_y,
|
||||
w = if root_c.fixed_width { "nullptr".into() } else { format!("&{}", p_width) },
|
||||
h = if root_c.fixed_height { "nullptr".into() } else { format!("&{}", p_height) },
|
||||
statements: Some(vec!["return { layout_info({&static_vtable, const_cast<void *>(static_cast<const void *>(this))}) };".into()]),
|
||||
|
||||
)]),
|
||||
..Function::default()
|
||||
}),
|
||||
));
|
||||
|
@ -1194,30 +1185,18 @@ fn generate_component(
|
|||
}),
|
||||
));
|
||||
|
||||
let (apply_layout, layout_info) = compute_layout(component, &mut repeater_layout_code);
|
||||
|
||||
component_struct.members.push((
|
||||
Access::Public, // FIXME: we call this function from tests
|
||||
Declaration::Function(Function {
|
||||
name: "apply_layout".into(),
|
||||
signature:
|
||||
"(sixtyfps::private_api::ComponentRef component, [[maybe_unused]] sixtyfps::Rect rect) -> void"
|
||||
.into(),
|
||||
is_static: true,
|
||||
statements: Some(apply_layout),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
|
||||
component_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Function(Function {
|
||||
name: "layouting_info".into(),
|
||||
name: "layout_info".into(),
|
||||
signature:
|
||||
"([[maybe_unused]] sixtyfps::private_api::ComponentRef component) -> sixtyfps::LayoutInfo"
|
||||
.into(),
|
||||
is_static: true,
|
||||
statements: Some(layout_info),
|
||||
statements: Some(vec![
|
||||
format!("[[maybe_unused]] auto self = reinterpret_cast<const {}*>(component.instance);", component_id),
|
||||
format!("return {};", get_layout_info(&component.root_element, component, &component.root_constraints.borrow()))
|
||||
]),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
|
@ -1271,7 +1250,7 @@ fn generate_component(
|
|||
ty: "const sixtyfps::private_api::ComponentVTable".to_owned(),
|
||||
name: format!("{}::static_vtable", component_id),
|
||||
init: Some(format!(
|
||||
"{{ visit_children, get_item_ref, parent_item, layouting_info, apply_layout, sixtyfps::private_api::drop_in_place<{}>, sixtyfps::private_api::dealloc }}",
|
||||
"{{ visit_children, get_item_ref, parent_item, layout_info, sixtyfps::private_api::drop_in_place<{}>, sixtyfps::private_api::dealloc }}",
|
||||
component_id)
|
||||
),
|
||||
}));
|
||||
|
@ -1578,7 +1557,7 @@ fn compile_expression(
|
|||
let item = item.upgrade().unwrap();
|
||||
let item = item.borrow();
|
||||
let native_item = item.base_type.as_native();
|
||||
format!("{vt}->layouting_info({{&sixtyfps::private_api::{vt}, const_cast<sixtyfps::{ty}*>(&self->{id})}}, &window)",
|
||||
format!("{vt}->layouting_info({{{vt}, const_cast<sixtyfps::{ty}*>(&self->{id})}}, &window)",
|
||||
vt = native_item.cpp_vtable_getter,
|
||||
ty = native_item.class_name,
|
||||
id = item.id
|
||||
|
@ -1710,6 +1689,98 @@ fn compile_expression(
|
|||
compile_expression(expr, component)
|
||||
),
|
||||
Expression::ReturnStatement(None) => "throw sixtyfps::private_api::ReturnWrapper<void>()".to_owned(),
|
||||
Expression::LayoutCacheAccess { layout_cache_prop, index, repeater_index } => {
|
||||
let cache = access_named_reference(layout_cache_prop, component, "self");
|
||||
if let Some(ri) = repeater_index {
|
||||
format!("[&](auto cache) {{ return cache[int(cache[{}]) + {} * 4]; }} ({}.get())", index, compile_expression(&ri, component), cache)
|
||||
} else {
|
||||
format!("{}.get()[{}]", cache, index)
|
||||
}
|
||||
}
|
||||
Expression::ComputeLayoutInfo(Layout::GridLayout(layout)) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, component);
|
||||
let cells = grid_layout_cell_data(layout, component);
|
||||
format!("[&] {{ \
|
||||
const auto padding = {};\
|
||||
sixtyfps::GridLayoutCellData cells[] = {{ {} }}; \
|
||||
const sixtyfps::Slice<sixtyfps::GridLayoutCellData> slice{{ cells, std::size(cells)}}; \
|
||||
return sixtyfps::sixtyfps_grid_layout_info(slice, {}, &padding);\
|
||||
}}()",
|
||||
padding, cells, spacing
|
||||
)
|
||||
}
|
||||
Expression::ComputeLayoutInfo(Layout::BoxLayout(layout)) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, component);
|
||||
let (cells, alignment) = box_layout_data(layout, component, None);
|
||||
format!("[&] {{ \
|
||||
const auto padding = {};\
|
||||
{}\
|
||||
const sixtyfps::Slice<sixtyfps::BoxLayoutCellData> slice{{ &*std::begin(cells), std::size(cells)}}; \
|
||||
return sixtyfps::sixtyfps_box_layout_info(slice, {}, &padding, {}, {});\
|
||||
}}()",
|
||||
padding, cells, spacing, alignment, layout.is_horizontal
|
||||
)
|
||||
}
|
||||
Expression::ComputeLayoutInfo(Layout::PathLayout(_)) => unimplemented!(),
|
||||
Expression::SolveLayout(Layout::GridLayout(layout)) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, component);
|
||||
let cells = grid_layout_cell_data(layout, component);
|
||||
let (width, height) = layout_geometry_width_height(&layout.geometry.rect, component);
|
||||
format!("[&] {{ \
|
||||
const auto padding = {p};\
|
||||
sixtyfps::GridLayoutCellData cells[] = {{ {c} }}; \
|
||||
const sixtyfps::Slice<sixtyfps::GridLayoutCellData> slice{{ cells, std::size(cells)}}; \
|
||||
const sixtyfps::GridLayoutData grid {{ {w}, {h}, 0, 0, {s}, &padding, slice }};
|
||||
sixtyfps::SharedVector<float> result;
|
||||
sixtyfps::sixtyfps_solve_grid_layout(&grid, &result);\
|
||||
return result;
|
||||
}}()",
|
||||
p = padding, c = cells, s = spacing, w = width, h = height
|
||||
)
|
||||
}
|
||||
Expression::SolveLayout(Layout::BoxLayout(layout)) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, component);
|
||||
let mut repeated_indices = Default::default();
|
||||
let mut repeated_indices_init = Default::default();
|
||||
let (cells, alignment) = box_layout_data(layout, component, Some((&mut repeated_indices, &mut repeated_indices_init)));
|
||||
let (width, height) = layout_geometry_width_height(&layout.geometry.rect, component);
|
||||
format!("[&] {{ \
|
||||
{ri_init}\
|
||||
const auto padding = {p};\
|
||||
{c}\
|
||||
const sixtyfps::Slice<sixtyfps::BoxLayoutCellData> slice{{ &*std::begin(cells), std::size(cells)}}; \
|
||||
sixtyfps::BoxLayoutData box {{ {w}, {h}, 0, 0, {s}, &padding, {a}, slice }};
|
||||
sixtyfps::SharedVector<float> result;
|
||||
sixtyfps::sixtyfps_solve_box_layout(&box, {hz}, {ri}, &result);\
|
||||
return result;
|
||||
}}()",
|
||||
ri_init = repeated_indices_init, ri = repeated_indices,
|
||||
p = padding, c = cells, s = spacing, w = width, h = height, a = alignment,
|
||||
hz = layout.is_horizontal
|
||||
)
|
||||
}
|
||||
Expression::SolveLayout(Layout::PathLayout(layout)) => {
|
||||
let (width, height) = layout_geometry_width_height(&layout.rect, component);
|
||||
let elements = compile_path(&layout.path, component);
|
||||
let prop = |expr: &Option<NamedReference>| {
|
||||
if let Some(nr) = expr.as_ref() {
|
||||
format!("{}.get()", access_named_reference(nr, component, "self"))
|
||||
} else {
|
||||
"0.".into()
|
||||
}
|
||||
};
|
||||
// FIXME! repeater
|
||||
format!("[&] {{ \
|
||||
const auto elements = {e};\
|
||||
sixtyfps::PathLayoutData path {{ &elements, {c}, 0, 0, {w}, {h}, {o} }};
|
||||
sixtyfps::SharedVector<float> result;
|
||||
sixtyfps::sixtyfps_solve_path_layout(&path, {{}}, &result);\
|
||||
return result;
|
||||
}}()",
|
||||
e = elements, c = layout.elements.len(), w = width, h = height, o = prop(&layout.offset_reference)
|
||||
)
|
||||
|
||||
}
|
||||
Expression::Uncompiled(_) | Expression::TwoWayBinding(..) => panic!(),
|
||||
Expression::Invalid => "\n#error invalid expression\n".to_string(),
|
||||
}
|
||||
|
@ -1796,215 +1867,144 @@ fn compile_assignment(
|
|||
}
|
||||
}
|
||||
|
||||
struct CppLanguageLayoutGen;
|
||||
impl crate::layout::gen::Language for CppLanguageLayoutGen {
|
||||
type CompiledCode = String;
|
||||
|
||||
fn make_grid_layout_cell_data<'a, 'b>(
|
||||
item: &'a crate::layout::LayoutItem,
|
||||
col: u16,
|
||||
row: u16,
|
||||
colspan: u16,
|
||||
rowspan: u16,
|
||||
layout_tree: &'b mut Vec<crate::layout::gen::LayoutTreeItem<'a, Self>>,
|
||||
component: &Rc<Component>,
|
||||
) -> Self::CompiledCode {
|
||||
let layout_info = get_layout_info_ref(item, layout_tree, component);
|
||||
let lay_rect = 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!(
|
||||
" {{ {c}, {r}, {cs}, {rs}, {li}, {x}, {y}, {w}, {h} }},",
|
||||
c = col,
|
||||
r = row,
|
||||
cs = colspan,
|
||||
rs = rowspan,
|
||||
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)
|
||||
)
|
||||
}
|
||||
|
||||
fn grid_layout_tree_item<'a, 'b>(
|
||||
layout_tree: &'b mut Vec<crate::layout::gen::LayoutTreeItem<'a, Self>>,
|
||||
geometry: &'a LayoutGeometry,
|
||||
cells: Vec<Self::CompiledCode>,
|
||||
component: &Rc<Component>,
|
||||
) -> crate::layout::gen::LayoutTreeItem<'a, Self> {
|
||||
let cell_ref_variable = format!("cells_{}", layout_tree.len());
|
||||
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,
|
||||
geometry,
|
||||
&layout_tree,
|
||||
component,
|
||||
);
|
||||
|
||||
LayoutTreeItem::GridLayout {
|
||||
geometry: &geometry,
|
||||
spacing,
|
||||
padding,
|
||||
var_creation_code: creation_code.join("\n"),
|
||||
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 is_static_array = box_layout
|
||||
fn grid_layout_cell_data(layout: &crate::layout::GridLayout, component: &Rc<Component>) -> String {
|
||||
layout
|
||||
.elems
|
||||
.iter()
|
||||
.all(|i| i.element.as_ref().map_or(true, |x| x.borrow().repeated.is_none()));
|
||||
|
||||
let mut make_box_layout_cell_data = |cell: &'a crate::layout::LayoutItem| {
|
||||
let layout_info = get_layout_info_ref(&cell, layout_tree, component);
|
||||
let lay_rect = cell.rect();
|
||||
let get_property_ref = |p: &Option<NamedReference>| match p {
|
||||
Some(nr) => format!("&{}", access_named_reference(nr, component, "self")),
|
||||
None => "nullptr".to_owned(),
|
||||
};
|
||||
.map(|c| {
|
||||
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)
|
||||
"sixtyfps::GridLayoutCellData {{ {col}, {row}, {cs}, {rs}, {cstr} }}",
|
||||
col = c.col,
|
||||
row = c.row,
|
||||
cs = c.colspan,
|
||||
rs = c.rowspan,
|
||||
cstr = get_layout_info(&c.item.element, component, &c.item.constraints),
|
||||
)
|
||||
};
|
||||
})
|
||||
.join(", ")
|
||||
}
|
||||
|
||||
let mut creation_code = if is_static_array {
|
||||
let mut creation_code: Vec<_> =
|
||||
box_layout.elems.iter().map(make_box_layout_cell_data).map(|s| s + ",").collect();
|
||||
creation_code.insert(0, "sixtyfps::BoxLayoutCellData @_data[] = {".into());
|
||||
creation_code.push("};".to_owned());
|
||||
creation_code
|
||||
} else {
|
||||
let mut push_code = vec!["std::vector<sixtyfps::BoxLayoutCellData> @_data;".into()];
|
||||
for item in &box_layout.elems {
|
||||
match &item.element {
|
||||
Some(elem) if elem.borrow().repeated.is_some() => {
|
||||
push_code.push(format!(
|
||||
"self->repeater_{}.ensure_updated(self);",
|
||||
elem.borrow().id
|
||||
));
|
||||
push_code.push(format!(
|
||||
"if (self->repeater_{id}.inner) for (auto &&sub_comp : self->repeater_{id}.inner->data)",
|
||||
id = elem.borrow().id
|
||||
));
|
||||
push_code.push(
|
||||
" @_data.push_back((*sub_comp.ptr)->box_layout_data());".to_owned(),
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
push_code.push(format!(
|
||||
"@_data.push_back({});",
|
||||
make_box_layout_cell_data(item)
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
push_code
|
||||
};
|
||||
let cell_ref_variable = format!("cells_{}", layout_tree.len());
|
||||
creation_code.iter_mut().for_each(|s| *s = s.replace('@', cell_ref_variable.as_ref()));
|
||||
creation_code.push(format!(
|
||||
"const sixtyfps::Slice<sixtyfps::BoxLayoutCellData> {cv}{{&*std::begin({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,
|
||||
);
|
||||
|
||||
let alignment = if let Some(nr) = &box_layout.geometry.alignment {
|
||||
/// Returns `(cells, alignment)`.
|
||||
/// The repeated_indices initialize the repeated_indices (var, init_code)
|
||||
fn box_layout_data(
|
||||
layout: &crate::layout::BoxLayout,
|
||||
component: &Rc<Component>,
|
||||
mut repeated_indices: Option<(&mut String, &mut String)>,
|
||||
) -> (String, String) {
|
||||
let alignment = if let Some(nr) = &layout.geometry.alignment {
|
||||
format!("{}.get()", access_named_reference(nr, component, "self"))
|
||||
} else {
|
||||
"{}".into()
|
||||
};
|
||||
|
||||
LayoutTreeItem::BoxLayout {
|
||||
is_horizontal: box_layout.is_horizontal,
|
||||
geometry: &box_layout.geometry,
|
||||
spacing,
|
||||
padding,
|
||||
alignment,
|
||||
var_creation_code: creation_code.join("\n"),
|
||||
cell_ref_variable,
|
||||
}
|
||||
}
|
||||
}
|
||||
let repeater_count =
|
||||
layout.elems.iter().filter(|i| i.element.borrow().repeated.is_some()).count();
|
||||
|
||||
type LayoutTreeItem<'a> = crate::layout::gen::LayoutTreeItem<'a, CppLanguageLayoutGen>;
|
||||
|
||||
impl<'a> LayoutTreeItem<'a> {
|
||||
fn layout_info(&self) -> String {
|
||||
match self {
|
||||
LayoutTreeItem::GridLayout { cell_ref_variable, spacing, padding, .. } => format!(
|
||||
"sixtyfps::sixtyfps_grid_layout_info(&{}, {}, &{})",
|
||||
cell_ref_variable, spacing, padding
|
||||
),
|
||||
LayoutTreeItem::BoxLayout {
|
||||
spacing,
|
||||
cell_ref_variable,
|
||||
padding,
|
||||
alignment,
|
||||
is_horizontal,
|
||||
..
|
||||
} => format!(
|
||||
"sixtyfps::sixtyfps_box_layout_info(&{}, {}, &{}, {}, {})",
|
||||
cell_ref_variable, spacing, padding, alignment, is_horizontal
|
||||
),
|
||||
LayoutTreeItem::PathLayout(_) => "{/*layout_info for path not implemented*/}".into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_layout_info_ref<'a, 'b>(
|
||||
item: &'a crate::layout::LayoutItem,
|
||||
layout_tree: &'b mut Vec<LayoutTreeItem<'a>>,
|
||||
component: &Rc<Component>,
|
||||
) -> String {
|
||||
let layout_info = item.layout.as_ref().map(|l| {
|
||||
crate::layout::gen::collect_layouts_recursively(layout_tree, l, component).layout_info()
|
||||
if repeater_count == 0 {
|
||||
let mut cells = layout.elems.iter().map(|li| {
|
||||
format!(
|
||||
"sixtyfps::BoxLayoutCellData{{ {} }}",
|
||||
get_layout_info(&li.element, component, &li.constraints)
|
||||
)
|
||||
});
|
||||
let elem_info = item.element.as_ref().map(|elem| {
|
||||
if let Some((ri, _)) = &mut repeated_indices {
|
||||
**ri = "{}".into();
|
||||
}
|
||||
(format!("sixtyfps::BoxLayoutCellData cells[] = {{ {} }};", cells.join(", ")), alignment)
|
||||
} else {
|
||||
let mut push_code = "std::vector<sixtyfps::BoxLayoutCellData> cells;".to_owned();
|
||||
if let Some((ri, init)) = &mut repeated_indices {
|
||||
**ri =
|
||||
"sixtyfps::Slice<unsigned int>{&*std::begin(repeater_indices), std::size(repeater_indices)}"
|
||||
.to_owned();
|
||||
**init = format!("std::array<unsigned int, {}> repeater_indices;", repeater_count * 2);
|
||||
}
|
||||
let mut repeater_idx = 0usize;
|
||||
for item in &layout.elems {
|
||||
if item.element.borrow().repeated.is_some() {
|
||||
push_code +=
|
||||
&format!("self->repeater_{}.ensure_updated(self);", item.element.borrow().id);
|
||||
if repeated_indices.is_some() {
|
||||
push_code += &format!("repeater_indices[{}] = cells.size();", repeater_idx * 2);
|
||||
push_code += &format!(
|
||||
"repeater_indices[{c}] = self->repeater_{id}.inner ? self->repeater_{id}.inner->data.size() : 0;",
|
||||
c = repeater_idx * 2 + 1,
|
||||
id = item.element.borrow().id
|
||||
);
|
||||
}
|
||||
repeater_idx += 1;
|
||||
push_code += &format!(
|
||||
"if (self->repeater_{id}.inner) \
|
||||
for (auto &&sub_comp : self->repeater_{id}.inner->data) \
|
||||
cells.push_back((*sub_comp.ptr)->box_layout_data());",
|
||||
id = item.element.borrow().id
|
||||
);
|
||||
} else {
|
||||
push_code += &format!(
|
||||
"cells.push_back({{ {} }});",
|
||||
get_layout_info(&item.element, component, &item.constraints)
|
||||
);
|
||||
}
|
||||
}
|
||||
(push_code, alignment)
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_layout_padding_and_spacing(
|
||||
layout_geometry: &LayoutGeometry,
|
||||
|
||||
component: &Rc<Component>,
|
||||
) -> (String, String) {
|
||||
let prop = |expr: &Option<NamedReference>| {
|
||||
if let Some(nr) = expr.as_ref() {
|
||||
format!("{}.get()", access_named_reference(nr, component, "self"))
|
||||
} else {
|
||||
"0.".into()
|
||||
}
|
||||
};
|
||||
let spacing = prop(&layout_geometry.spacing);
|
||||
let padding = format!(
|
||||
"sixtyfps::Padding {{ {}, {}, {}, {} }};",
|
||||
prop(&layout_geometry.padding.left),
|
||||
prop(&layout_geometry.padding.right),
|
||||
prop(&layout_geometry.padding.top),
|
||||
prop(&layout_geometry.padding.bottom),
|
||||
);
|
||||
|
||||
(padding, spacing)
|
||||
}
|
||||
|
||||
fn layout_geometry_width_height(rect: &LayoutRect, component: &Rc<Component>) -> (String, String) {
|
||||
let prop = |expr: &Option<NamedReference>| {
|
||||
if let Some(nr) = expr.as_ref() {
|
||||
format!("{}.get()", access_named_reference(nr, component, "self"))
|
||||
} else {
|
||||
"0.".into()
|
||||
}
|
||||
};
|
||||
(prop(&rect.width_reference), prop(&rect.height_reference))
|
||||
}
|
||||
|
||||
fn get_layout_info(
|
||||
elem: &ElementRc,
|
||||
component: &Rc<Component>,
|
||||
constraints: &crate::layout::LayoutConstraints,
|
||||
) -> String {
|
||||
let mut layout_info = if let Some(layout_info_prop) = &elem.borrow().layout_info_prop {
|
||||
format!("{}.get()", access_named_reference(layout_info_prop, component, "self"))
|
||||
} else {
|
||||
format!(
|
||||
"{vt}->layouting_info({{{vt}, const_cast<sixtyfps::{ty}*>(&self->{id})}}, &self->window)",
|
||||
vt = elem.borrow().base_type.as_native().cpp_vtable_getter,
|
||||
ty = elem.borrow().base_type.as_native().class_name,
|
||||
id = elem.borrow().id,
|
||||
|
||||
)
|
||||
});
|
||||
let mut layout_info = match (layout_info, elem_info) {
|
||||
(None, None) => String::default(),
|
||||
(None, Some(x)) => x,
|
||||
(Some(x), None) => x,
|
||||
(Some(layout_info), Some(elem_info)) => format!("{}.merge({})", layout_info, elem_info),
|
||||
};
|
||||
if item.constraints.has_explicit_restrictions() {
|
||||
|
||||
if constraints.has_explicit_restrictions() {
|
||||
layout_info = format!("[&]{{ auto layout_info = {};", layout_info);
|
||||
for (expr, name) in item.constraints.for_each_restrictions() {
|
||||
for (expr, name) in constraints.for_each_restrictions() {
|
||||
layout_info += &format!(
|
||||
" layout_info.{} = {}.get();",
|
||||
name,
|
||||
|
@ -2016,305 +2016,6 @@ fn get_layout_info_ref<'a, 'b>(
|
|||
layout_info
|
||||
}
|
||||
|
||||
fn generate_layout_padding_and_spacing<'a, 'b>(
|
||||
creation_code: &mut Vec<String>,
|
||||
layout_geometry: &LayoutGeometry,
|
||||
layout_tree: &'b [LayoutTreeItem<'a>],
|
||||
component: &Rc<Component>,
|
||||
) -> (String, String) {
|
||||
let spacing = if let Some(spacing) = &layout_geometry.spacing {
|
||||
let variable = format!("spacing_{}", layout_tree.len());
|
||||
creation_code.push(format!(
|
||||
"auto {} = {}.get();",
|
||||
variable,
|
||||
access_named_reference(spacing, component, "self")
|
||||
));
|
||||
variable
|
||||
} else {
|
||||
"0.".into()
|
||||
};
|
||||
|
||||
let padding = format!("padding_{}", layout_tree.len());
|
||||
let padding_prop = |expr| {
|
||||
if let Some(nr) = expr {
|
||||
format!("{}.get()", access_named_reference(nr, component, "self"))
|
||||
} else {
|
||||
"0.".into()
|
||||
}
|
||||
};
|
||||
creation_code.push(format!(
|
||||
"sixtyfps::Padding {} = {{ {}, {}, {}, {} }};",
|
||||
padding,
|
||||
padding_prop(layout_geometry.padding.left.as_ref()),
|
||||
padding_prop(layout_geometry.padding.right.as_ref()),
|
||||
padding_prop(layout_geometry.padding.top.as_ref()),
|
||||
padding_prop(layout_geometry.padding.bottom.as_ref()),
|
||||
));
|
||||
|
||||
(padding, spacing)
|
||||
}
|
||||
|
||||
impl<'a> LayoutTreeItem<'a> {
|
||||
fn emit_solve_calls(&self, component: &Rc<Component>, code_stream: &mut Vec<String>) {
|
||||
if let Some(geometry) = self.geometry() {
|
||||
if geometry.materialized_constraints.has_explicit_restrictions() {
|
||||
code_stream.push(" {".into());
|
||||
code_stream.push(format!(" auto layout_info = {};", self.layout_info()));
|
||||
for (expr, name) in geometry.materialized_constraints.for_each_restrictions() {
|
||||
code_stream.push(format!(
|
||||
" {}.set(layout_info.{});",
|
||||
access_named_reference(expr, component, "self"),
|
||||
name
|
||||
));
|
||||
}
|
||||
code_stream.push(" }".into());
|
||||
}
|
||||
}
|
||||
|
||||
let layout_prop = |p: &Option<NamedReference>| match p {
|
||||
Some(nr) => format!("{}.get()", access_named_reference(nr, component, "self")),
|
||||
None => "0".into(),
|
||||
};
|
||||
match self {
|
||||
LayoutTreeItem::GridLayout {
|
||||
geometry, spacing, cell_ref_variable, padding, ..
|
||||
} => {
|
||||
code_stream.push(" { ".into());
|
||||
code_stream.push(" sixtyfps::GridLayoutData grid { ".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::sixtyfps_solve_grid_layout(&grid);".to_owned());
|
||||
code_stream.push(" } ".into());
|
||||
}
|
||||
LayoutTreeItem::BoxLayout {
|
||||
geometry,
|
||||
spacing,
|
||||
cell_ref_variable,
|
||||
padding,
|
||||
alignment,
|
||||
is_horizontal,
|
||||
..
|
||||
} => {
|
||||
code_stream.push(" { ".into());
|
||||
code_stream.push(" sixtyfps::BoxLayoutData box { ".into());
|
||||
code_stream.push(format!(
|
||||
" {w}, {h}, {x}, {y}, {s}, &{p}, {a},",
|
||||
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,
|
||||
a = alignment
|
||||
));
|
||||
code_stream.push(format!(" {cv}", cv = cell_ref_variable));
|
||||
code_stream.push(" };".to_owned());
|
||||
code_stream.push(format!(
|
||||
" sixtyfps::sixtyfps_solve_box_layout(&box, {});",
|
||||
is_horizontal
|
||||
));
|
||||
code_stream.push(" } ".into());
|
||||
}
|
||||
LayoutTreeItem::PathLayout(path_layout) => {
|
||||
code_stream.push("{".to_owned());
|
||||
|
||||
let path_layout_item_data =
|
||||
|elem: &ElementRc, elem_cpp: &str, component_cpp: &str| {
|
||||
let prop_ref = |n: &str| {
|
||||
if elem.borrow().lookup_property(n).property_type == Type::LogicalLength
|
||||
{
|
||||
format!("&{}.{}", elem_cpp, n)
|
||||
} else {
|
||||
"nullptr".to_owned()
|
||||
}
|
||||
};
|
||||
let prop_value = |n: &str| {
|
||||
if elem.borrow().lookup_property(n).property_type == Type::LogicalLength
|
||||
{
|
||||
let value_accessor = access_member(
|
||||
&elem,
|
||||
n,
|
||||
&elem.borrow().enclosing_component.upgrade().unwrap(),
|
||||
component_cpp,
|
||||
);
|
||||
format!("{}.get()", value_accessor)
|
||||
} else {
|
||||
"0.".into()
|
||||
}
|
||||
};
|
||||
format!(
|
||||
"{{ {}, {}, {}, {} }}",
|
||||
prop_ref("x"),
|
||||
prop_ref("y"),
|
||||
prop_value("width"),
|
||||
prop_value("height")
|
||||
)
|
||||
};
|
||||
let path_layout_item_data_for_elem = |elem: &ElementRc| {
|
||||
path_layout_item_data(elem, &format!("self->{}", elem.borrow().id), "self")
|
||||
};
|
||||
|
||||
let is_static_array =
|
||||
path_layout.elements.iter().all(|elem| elem.borrow().repeated.is_none());
|
||||
|
||||
let slice = if is_static_array {
|
||||
code_stream.push(" sixtyfps::PathLayoutItemData items[] = {".to_owned());
|
||||
for elem in &path_layout.elements {
|
||||
code_stream
|
||||
.push(format!(" {},", path_layout_item_data_for_elem(elem)));
|
||||
}
|
||||
code_stream.push(" };".to_owned());
|
||||
" {items, std::size(items)},".to_owned()
|
||||
} else {
|
||||
code_stream
|
||||
.push(" std::vector<sixtyfps::PathLayoutItemData> items;".to_owned());
|
||||
for elem in &path_layout.elements {
|
||||
if elem.borrow().repeated.is_some() {
|
||||
let root_element =
|
||||
elem.borrow().base_type.as_component().root_element.clone();
|
||||
code_stream.push(format!(
|
||||
" for (auto &&sub_comp : self->repeater_{}.inner->data)",
|
||||
elem.borrow().id
|
||||
));
|
||||
code_stream.push(format!(
|
||||
" items.push_back({});",
|
||||
path_layout_item_data(
|
||||
&root_element,
|
||||
&format!("(*sub_comp.ptr)->{}", root_element.borrow().id),
|
||||
"(*sub_comp.ptr)",
|
||||
)
|
||||
));
|
||||
} else {
|
||||
code_stream.push(format!(
|
||||
" items.push_back({});",
|
||||
path_layout_item_data_for_elem(elem)
|
||||
));
|
||||
}
|
||||
}
|
||||
" {items.data(), std::size(items)},".to_owned()
|
||||
};
|
||||
|
||||
code_stream.push(format!(
|
||||
" auto path = {};",
|
||||
compile_path(&path_layout.path, component)
|
||||
));
|
||||
|
||||
code_stream
|
||||
.push(format!(" auto x = {};", layout_prop(&path_layout.rect.x_reference)));
|
||||
code_stream
|
||||
.push(format!(" auto y = {};", layout_prop(&path_layout.rect.y_reference)));
|
||||
code_stream.push(format!(
|
||||
" auto width = {};",
|
||||
layout_prop(&path_layout.rect.width_reference)
|
||||
));
|
||||
code_stream.push(format!(
|
||||
" auto height = {};",
|
||||
layout_prop(&path_layout.rect.height_reference)
|
||||
));
|
||||
|
||||
code_stream.push(format!(
|
||||
" auto offset = {};",
|
||||
layout_prop(&Some(path_layout.offset_reference.clone()))
|
||||
));
|
||||
|
||||
code_stream.push(" sixtyfps::PathLayoutData pl { ".into());
|
||||
code_stream.push(" &path,".to_owned());
|
||||
code_stream.push(slice);
|
||||
code_stream.push(" x, y, width, height, offset".to_owned());
|
||||
code_stream.push(" };".to_owned());
|
||||
code_stream.push(" sixtyfps::sixtyfps_solve_path_layout(&pl);".to_owned());
|
||||
code_stream.push("}".to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_layout(
|
||||
component: &Rc<Component>,
|
||||
repeater_layout_code: &mut Vec<String>,
|
||||
) -> (Vec<String>, Vec<String>) {
|
||||
let intro = format!(
|
||||
"[[maybe_unused]] auto self = reinterpret_cast<const {ty}*>(component.instance);",
|
||||
ty = component_id(component)
|
||||
);
|
||||
let mut res = vec![intro.clone()];
|
||||
let mut layout_info = vec![
|
||||
intro.clone(),
|
||||
"auto layout_info = self->root_item().vtable->layouting_info(self->root_item(), &self->window);".into(),
|
||||
];
|
||||
let component_layouts = component.layouts.borrow();
|
||||
component_layouts.iter().enumerate().for_each(|(idx, layout)| {
|
||||
let mut inverse_layout_tree = Vec::new();
|
||||
|
||||
res.push(" {".into());
|
||||
let layout_item = crate::layout::gen::collect_layouts_recursively(
|
||||
&mut inverse_layout_tree,
|
||||
layout,
|
||||
component,
|
||||
);
|
||||
|
||||
if component_layouts.main_layout == Some(idx) {
|
||||
layout_info = vec![
|
||||
intro.clone(),
|
||||
format!("sixtyfps::LayoutInfo layout_info = {};", layout_item.layout_info()),
|
||||
];
|
||||
}
|
||||
|
||||
let mut creation_code = inverse_layout_tree
|
||||
.iter()
|
||||
.filter_map(|layout| match layout {
|
||||
LayoutTreeItem::GridLayout { var_creation_code, .. } => {
|
||||
Some(var_creation_code.clone())
|
||||
}
|
||||
LayoutTreeItem::BoxLayout { var_creation_code, .. } => {
|
||||
Some(var_creation_code.clone())
|
||||
}
|
||||
LayoutTreeItem::PathLayout(_) => None,
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if component_layouts.main_layout == Some(idx) {
|
||||
layout_info.splice(1..1, creation_code.iter().cloned());
|
||||
}
|
||||
|
||||
res.append(&mut creation_code);
|
||||
|
||||
inverse_layout_tree
|
||||
.iter()
|
||||
.rev()
|
||||
.for_each(|layout| layout.emit_solve_calls(component, &mut res));
|
||||
res.push(" }".into());
|
||||
});
|
||||
|
||||
let root_constraints = &component.layouts.borrow().root_constraints;
|
||||
if root_constraints.has_explicit_restrictions() {
|
||||
layout_info.push("auto layout_info_other = layout_info;".into());
|
||||
for (expr, name) in root_constraints.for_each_restrictions() {
|
||||
layout_info.push(format!(
|
||||
"layout_info_other.{} = {}.get();",
|
||||
name,
|
||||
access_named_reference(expr, component, "self")
|
||||
));
|
||||
}
|
||||
layout_info.push("return layout_info.merge(layout_info_other);".into());
|
||||
} else {
|
||||
layout_info.push("return layout_info;".into());
|
||||
}
|
||||
|
||||
res.append(repeater_layout_code);
|
||||
|
||||
(res, layout_info)
|
||||
}
|
||||
|
||||
fn compile_path(path: &crate::expression_tree::Path, component: &Rc<Component>) -> String {
|
||||
match path {
|
||||
crate::expression_tree::Path::Elements(elements) => {
|
||||
|
|
|
@ -1431,13 +1431,13 @@ fn compile_expression(expr: &Expression, component: &Rc<Component>) -> TokenStre
|
|||
Expression::ComputeLayoutInfo(Layout::GridLayout(layout)) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, component);
|
||||
let cells = grid_layout_cell_data(layout, component);
|
||||
quote!(grid_layout_info(&Slice::from_slice(&#cells), #spacing, #padding))
|
||||
quote!(grid_layout_info(Slice::from_slice(&#cells), #spacing, #padding))
|
||||
}
|
||||
Expression::ComputeLayoutInfo(Layout::BoxLayout(layout)) => {
|
||||
let (padding, spacing) = generate_layout_padding_and_spacing(&layout.geometry, component);
|
||||
let (cells, alignment) = box_layout_data(layout, component, None);
|
||||
let is_horizontal = layout.is_horizontal;
|
||||
quote!(box_layout_info(&Slice::from_slice(&#cells), #spacing, #padding, #alignment, #is_horizontal))
|
||||
quote!(box_layout_info(Slice::from_slice(&#cells), #spacing, #padding, #alignment, #is_horizontal))
|
||||
}
|
||||
Expression::ComputeLayoutInfo(Layout::PathLayout(_)) => unimplemented!(),
|
||||
Expression::SolveLayout(Layout::GridLayout(layout)) => {
|
||||
|
@ -1618,28 +1618,6 @@ fn compile_assignment(
|
|||
}
|
||||
}
|
||||
|
||||
fn apply_layout_constraint(
|
||||
layout_info: TokenStream,
|
||||
constraints: &crate::layout::LayoutConstraints,
|
||||
component: &Rc<Component>,
|
||||
) -> TokenStream {
|
||||
if constraints.has_explicit_restrictions() {
|
||||
let (name, expr): (Vec<_>, Vec<_>) = constraints
|
||||
.for_each_restrictions()
|
||||
.map(|(e, s)| {
|
||||
(format_ident!("{}", s), access_named_reference(e, component, quote!(_self)))
|
||||
})
|
||||
.unzip();
|
||||
quote!({
|
||||
let mut layout_info = #layout_info;
|
||||
#(layout_info.#name = #expr.get();)*
|
||||
layout_info
|
||||
})
|
||||
} else {
|
||||
layout_info
|
||||
}
|
||||
}
|
||||
|
||||
fn grid_layout_cell_data(
|
||||
layout: &crate::layout::GridLayout,
|
||||
component: &Rc<Component>,
|
||||
|
@ -1649,11 +1627,7 @@ fn grid_layout_cell_data(
|
|||
let row = c.row;
|
||||
let colspan = c.colspan;
|
||||
let rowspan = c.rowspan;
|
||||
let layout_info = apply_layout_constraint(
|
||||
get_layout_info(&c.item.element, component),
|
||||
&c.item.constraints,
|
||||
component,
|
||||
);
|
||||
let layout_info = get_layout_info(&c.item.element, component, &c.item.constraints);
|
||||
quote!(GridLayoutCellData {
|
||||
col: #col,
|
||||
row: #row,
|
||||
|
@ -1684,11 +1658,7 @@ fn box_layout_data(
|
|||
|
||||
if repeater_count == 0 {
|
||||
let cells = layout.elems.iter().map(|li| {
|
||||
let layout_info = apply_layout_constraint(
|
||||
get_layout_info(&li.element, component),
|
||||
&li.constraints,
|
||||
component,
|
||||
);
|
||||
let layout_info = get_layout_info(&li.element, component, &li.constraints);
|
||||
quote!(BoxLayoutCellData { constraint: #layout_info })
|
||||
});
|
||||
if let Some((ri, _)) = &mut repeated_indices {
|
||||
|
@ -1730,11 +1700,7 @@ fn box_layout_data(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
let layout_info = apply_layout_constraint(
|
||||
get_layout_info(&item.element, component),
|
||||
&item.constraints,
|
||||
component,
|
||||
);
|
||||
let layout_info = get_layout_info(&item.element, component, &item.constraints);
|
||||
fixed_count += 1;
|
||||
push_code = quote! {
|
||||
#push_code
|
||||
|
@ -1804,11 +1770,7 @@ fn layout_geometry_width_height(
|
|||
|
||||
fn compute_layout(component: &Rc<Component>) -> TokenStream {
|
||||
let elem = &component.root_element;
|
||||
let mut layout_info = get_layout_info(elem, component);
|
||||
|
||||
layout_info =
|
||||
apply_layout_constraint(layout_info, &component.root_constraints.borrow(), component);
|
||||
|
||||
let layout_info = get_layout_info(elem, component, &component.root_constraints.borrow());
|
||||
quote! {
|
||||
fn layout_info(self: ::core::pin::Pin<&Self>) -> sixtyfps::re_exports::LayoutInfo {
|
||||
#![allow(unused)]
|
||||
|
@ -1819,14 +1781,34 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
|
|||
}
|
||||
}
|
||||
|
||||
fn get_layout_info(elem: &ElementRc, component: &Rc<Component>) -> TokenStream {
|
||||
if let Some(layout_info_prop) = &elem.borrow().layout_info_prop {
|
||||
fn get_layout_info(
|
||||
elem: &ElementRc,
|
||||
component: &Rc<Component>,
|
||||
constraints: &crate::layout::LayoutConstraints,
|
||||
) -> TokenStream {
|
||||
let layout_info = if let Some(layout_info_prop) = &elem.borrow().layout_info_prop {
|
||||
let li = access_named_reference(layout_info_prop, component, quote!(_self));
|
||||
quote! {#li.get()}
|
||||
} else {
|
||||
let elem_id = format_ident!("{}", elem.borrow().id);
|
||||
let inner_component_id = inner_component_id(component);
|
||||
quote!(#inner_component_id::FIELD_OFFSETS.#elem_id.apply_pin(_self).layouting_info(&_self.window))
|
||||
};
|
||||
|
||||
if constraints.has_explicit_restrictions() {
|
||||
let (name, expr): (Vec<_>, Vec<_>) = constraints
|
||||
.for_each_restrictions()
|
||||
.map(|(e, s)| {
|
||||
(format_ident!("{}", s), access_named_reference(e, component, quote!(_self)))
|
||||
})
|
||||
.unzip();
|
||||
quote!({
|
||||
let mut layout_info = #layout_info;
|
||||
#(layout_info.#name = #expr.get();)*
|
||||
layout_info
|
||||
})
|
||||
} else {
|
||||
layout_info
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -103,7 +103,7 @@ fn lower_grid_layout(
|
|||
};
|
||||
|
||||
let layout_cache_prop = create_new_prop(grid_layout_element, "layout_cache", Type::LayoutCache);
|
||||
let layout_info_prop = create_new_prop(grid_layout_element, "layout_info", layout_info_type());
|
||||
let layout_info_prop = create_new_prop(grid_layout_element, "layoutinfo", layout_info_type());
|
||||
|
||||
let mut row = 0;
|
||||
let mut col = 0;
|
||||
|
@ -203,7 +203,7 @@ fn lower_box_layout(
|
|||
};
|
||||
|
||||
let layout_cache_prop = create_new_prop(layout_element, "layout_cache", Type::LayoutCache);
|
||||
let layout_info_prop = create_new_prop(layout_element, "layout_info", layout_info_type());
|
||||
let layout_info_prop = create_new_prop(layout_element, "layoutinfo", layout_info_type());
|
||||
|
||||
let layout_children = std::mem::take(&mut layout_element.borrow_mut().children);
|
||||
for layout_child in &layout_children {
|
||||
|
|
|
@ -16,6 +16,7 @@ use crate::{slice::Slice, SharedVector};
|
|||
type Coord = f32;
|
||||
|
||||
/// The constraint that applies to an item
|
||||
// NOTE: when adding new fields, the C++ operator== also need updates
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub struct LayoutInfo {
|
||||
|
@ -371,7 +372,7 @@ pub fn solve_grid_layout(data: &GridLayoutData) -> SharedVector<Coord> {
|
|||
}
|
||||
|
||||
pub fn grid_layout_info<'a>(
|
||||
cells: &Slice<'a, GridLayoutCellData>,
|
||||
cells: Slice<'a, GridLayoutCellData>,
|
||||
spacing: Coord,
|
||||
padding: &Padding,
|
||||
) -> LayoutInfo {
|
||||
|
@ -707,7 +708,7 @@ pub fn solve_box_layout(
|
|||
|
||||
/// Return the LayoutInfo for a BoxLayout with the given cells.
|
||||
pub fn box_layout_info<'a>(
|
||||
cells: &Slice<'a, BoxLayoutCellData>,
|
||||
cells: Slice<'a, BoxLayoutCellData>,
|
||||
spacing: Coord,
|
||||
padding: &Padding,
|
||||
alignment: LayoutAlignment,
|
||||
|
@ -914,13 +915,16 @@ pub(crate) mod ffi {
|
|||
use super::*;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sixtyfps_solve_grid_layout(data: &GridLayoutData) {
|
||||
super::solve_grid_layout(data)
|
||||
pub extern "C" fn sixtyfps_solve_grid_layout(
|
||||
data: &GridLayoutData,
|
||||
result: &mut SharedVector<Coord>,
|
||||
) {
|
||||
*result = super::solve_grid_layout(data)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sixtyfps_grid_layout_info<'a>(
|
||||
cells: &Slice<'a, GridLayoutCellData<'a>>,
|
||||
cells: Slice<'a, GridLayoutCellData>,
|
||||
spacing: Coord,
|
||||
padding: &Padding,
|
||||
) -> LayoutInfo {
|
||||
|
@ -928,14 +932,19 @@ pub(crate) mod ffi {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sixtyfps_solve_box_layout(data: &BoxLayoutData, is_horizontal: bool) {
|
||||
super::solve_box_layout(data, is_horizontal)
|
||||
pub extern "C" fn sixtyfps_solve_box_layout(
|
||||
data: &BoxLayoutData,
|
||||
is_horizontal: bool,
|
||||
repeater_indexes: Slice<u32>,
|
||||
result: &mut SharedVector<Coord>,
|
||||
) {
|
||||
*result = super::solve_box_layout(data, is_horizontal, repeater_indexes)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
/// Return the LayoutInfo for a BoxLayout with the given cells.
|
||||
pub extern "C" fn sixtyfps_box_layout_info<'a>(
|
||||
cells: &Slice<'a, BoxLayoutCellData<'a>>,
|
||||
cells: Slice<'a, BoxLayoutCellData>,
|
||||
spacing: Coord,
|
||||
padding: &Padding,
|
||||
alignment: LayoutAlignment,
|
||||
|
@ -945,7 +954,11 @@ pub(crate) mod ffi {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn sixtyfps_solve_path_layout(data: &PathLayoutData) {
|
||||
super::solve_path_layout(data)
|
||||
pub extern "C" fn sixtyfps_solve_path_layout(
|
||||
data: &PathLayoutData,
|
||||
repeater_indexes: Slice<u32>,
|
||||
result: &mut SharedVector<Coord>,
|
||||
) {
|
||||
*result = super::solve_path_layout(data, repeater_indexes)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,13 +34,13 @@ pub(crate) fn compute_layout_info(lay: &Layout, local_context: &mut EvalLocalCon
|
|||
Layout::GridLayout(grid_layout) => {
|
||||
let cells = grid_layout_data(grid_layout, component, &expr_eval);
|
||||
let (padding, spacing) = padding_and_spacing(&grid_layout.geometry, &expr_eval);
|
||||
core_layout::grid_layout_info(&Slice::from(cells.as_slice()), spacing, &padding).into()
|
||||
core_layout::grid_layout_info(Slice::from(cells.as_slice()), spacing, &padding).into()
|
||||
}
|
||||
Layout::BoxLayout(box_layout) => {
|
||||
let (cells, alignment) = box_layout_data(box_layout, component, &expr_eval, None);
|
||||
let (padding, spacing) = padding_and_spacing(&box_layout.geometry, &expr_eval);
|
||||
core_layout::box_layout_info(
|
||||
&Slice::from(cells.as_slice()),
|
||||
Slice::from(cells.as_slice()),
|
||||
spacing,
|
||||
&padding,
|
||||
alignment,
|
||||
|
|
|
@ -274,7 +274,8 @@ fn gen_corelib(root_dir: &Path, include_dir: &Path) -> anyhow::Result<()> {
|
|||
);
|
||||
config.export.body.insert(
|
||||
"LayoutInfo".to_owned(),
|
||||
" inline LayoutInfo merge(const LayoutInfo &other) const;".into(),
|
||||
" inline LayoutInfo merge(const LayoutInfo &other) const;
|
||||
friend inline LayoutInfo operator+(const LayoutInfo &a, const LayoutInfo &b) { return a.merge(b); }".into(),
|
||||
);
|
||||
config
|
||||
.export
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue