mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-28 04:45:13 +00:00
Implement support for nested layouts in the C++ generator
This commit is contained in:
parent
884af3c88f
commit
cb7aca54d4
2 changed files with 271 additions and 155 deletions
|
@ -28,8 +28,8 @@ using internal::ComponentVTable;
|
|||
using internal::ItemTreeNode;
|
||||
using ComponentRef = VRef<ComponentVTable>;
|
||||
using ItemVisitorRefMut = VRefMut<internal::ItemVisitorVTable>;
|
||||
using internal::WindowProperties;
|
||||
using internal::EasingCurve;
|
||||
using internal::WindowProperties;
|
||||
|
||||
struct ComponentWindow
|
||||
{
|
||||
|
@ -52,12 +52,12 @@ private:
|
|||
};
|
||||
|
||||
using internal::BorderRectangle;
|
||||
using internal::Flickable;
|
||||
using internal::Image;
|
||||
using internal::Path;
|
||||
using internal::Rectangle;
|
||||
using internal::Text;
|
||||
using internal::TouchArea;
|
||||
using internal::Flickable;
|
||||
|
||||
constexpr inline ItemTreeNode<uint8_t> make_item_node(std::uintptr_t offset,
|
||||
const internal::ItemVTable *vtable,
|
||||
|
@ -76,6 +76,7 @@ constexpr inline ItemTreeNode<uint8_t> make_dyn_node(std::uintptr_t offset)
|
|||
using internal::sixtyfps_visit_item_tree;
|
||||
|
||||
// layouts:
|
||||
using internal::grid_layout_info;
|
||||
using internal::GridLayoutCellData;
|
||||
using internal::GridLayoutData;
|
||||
using internal::PathLayoutData;
|
||||
|
@ -145,7 +146,13 @@ struct Repeater
|
|||
}
|
||||
};
|
||||
|
||||
Flickable::Flickable() { sixtyfps_flickable_data_init(&data); }
|
||||
Flickable::~Flickable() { sixtyfps_flickable_data_free(&data); }
|
||||
Flickable::Flickable()
|
||||
{
|
||||
sixtyfps_flickable_data_init(&data);
|
||||
}
|
||||
Flickable::~Flickable()
|
||||
{
|
||||
sixtyfps_flickable_data_free(&data);
|
||||
}
|
||||
|
||||
} // namespace sixtyfps
|
||||
|
|
|
@ -131,7 +131,7 @@ mod cpp_ast {
|
|||
|
||||
use crate::diagnostics::{BuildDiagnostics, CompilerDiagnostic, Spanned};
|
||||
use crate::expression_tree::{EasingCurve, Expression, ExpressionSpanned};
|
||||
use crate::layout::{Layout, LayoutItem};
|
||||
use crate::layout::{GridLayout, Layout, LayoutItem, PathLayout};
|
||||
use crate::object_tree::{Component, Element, ElementRc, RepeatedElementInfo};
|
||||
use crate::typeregister::Type;
|
||||
use cpp_ast::*;
|
||||
|
@ -891,9 +891,41 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(derive_more::From)]
|
||||
pub enum PendingLayout<'a> {
|
||||
GridLayout(&'a GridLayout),
|
||||
PathLayout(&'a PathLayout),
|
||||
}
|
||||
|
||||
pub struct GridLayoutWithCells<'a> {
|
||||
grid: &'a GridLayout,
|
||||
cell_creation_code: String,
|
||||
cell_ref_variable: String,
|
||||
}
|
||||
|
||||
#[derive(derive_more::From)]
|
||||
enum LayoutTreeItem<'a> {
|
||||
GridLayout(GridLayoutWithCells<'a>),
|
||||
PathLayout(&'a PathLayout),
|
||||
}
|
||||
|
||||
impl<'a> LayoutTreeItem<'a> {
|
||||
fn layout_info(&self) -> String {
|
||||
match self {
|
||||
LayoutTreeItem::GridLayout(grid_layout) => {
|
||||
format!("sixtyfps::grid_layout_info(&{cv})", cv = grid_layout.cell_ref_variable)
|
||||
}
|
||||
LayoutTreeItem::PathLayout(_) => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
trait LayoutItemCodeGen {
|
||||
fn get_property_ref(&self, name: &str) -> String;
|
||||
fn get_layout_info_ref(&self) -> String;
|
||||
fn get_layout_info_ref<'a, 'b>(
|
||||
&'a self,
|
||||
layout_tree: &'b mut Vec<LayoutTreeItem<'a>>,
|
||||
) -> String;
|
||||
}
|
||||
|
||||
impl LayoutItemCodeGen for LayoutItem {
|
||||
|
@ -903,20 +935,31 @@ impl LayoutItemCodeGen for LayoutItem {
|
|||
LayoutItem::Layout(l) => l.get_property_ref(name),
|
||||
}
|
||||
}
|
||||
fn get_layout_info_ref(&self) -> String {
|
||||
fn get_layout_info_ref<'a, 'b>(
|
||||
&'a self,
|
||||
layout_tree: &'b mut Vec<LayoutTreeItem<'a>>,
|
||||
) -> String {
|
||||
match self {
|
||||
LayoutItem::Element(e) => e.get_layout_info_ref(),
|
||||
LayoutItem::Layout(l) => l.get_layout_info_ref(),
|
||||
LayoutItem::Element(e) => e.get_layout_info_ref(layout_tree),
|
||||
LayoutItem::Layout(l) => l.get_layout_info_ref(layout_tree),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LayoutItemCodeGen for Layout {
|
||||
fn get_property_ref(&self, _name: &str) -> String {
|
||||
todo!()
|
||||
fn get_property_ref(&self, name: &str) -> String {
|
||||
let moved_property_name = match self.rect().mapped_property_name(name) {
|
||||
Some(name) => name,
|
||||
None => return "nullptr".to_owned(),
|
||||
};
|
||||
format!("&self->{}", moved_property_name)
|
||||
}
|
||||
fn get_layout_info_ref(&self) -> String {
|
||||
todo!()
|
||||
fn get_layout_info_ref<'a, 'b>(
|
||||
&'a self,
|
||||
layout_tree: &'b mut Vec<LayoutTreeItem<'a>>,
|
||||
) -> String {
|
||||
let self_as_layout_tree_item = collect_layouts_recursively(layout_tree, &self);
|
||||
self_as_layout_tree_item.layout_info()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -928,7 +971,10 @@ impl LayoutItemCodeGen for ElementRc {
|
|||
"nullptr".to_owned()
|
||||
}
|
||||
}
|
||||
fn get_layout_info_ref(&self) -> String {
|
||||
fn get_layout_info_ref<'a, 'b>(
|
||||
&'a self,
|
||||
_layout_tree: &'b mut Vec<LayoutTreeItem<'a>>,
|
||||
) -> String {
|
||||
format!(
|
||||
"sixtyfps::{vt}.layouting_info({{&sixtyfps::{vt}, const_cast<sixtyfps::{ty}*>(&self->{id})}})",
|
||||
vt = self.borrow().base_type.as_native().vtable_symbol,
|
||||
|
@ -938,55 +984,89 @@ impl LayoutItemCodeGen for ElementRc {
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
||||
let mut res = vec![];
|
||||
|
||||
res.push(format!(
|
||||
"[[maybe_unused]] auto self = reinterpret_cast<const {ty}*>(component.instance);",
|
||||
ty = component_id(component)
|
||||
));
|
||||
component.layout_constraints.borrow().iter().for_each(|layout| match &layout {
|
||||
Layout::GridLayout(grid) => {
|
||||
res.push("{".to_owned());
|
||||
res.push(" sixtyfps::GridLayoutCellData grid_data[] = {".to_owned());
|
||||
for cell in &grid.elems {
|
||||
res.push(format!(
|
||||
fn collect_layouts_recursively<'a, 'b>(
|
||||
layout_tree: &'b mut Vec<LayoutTreeItem<'a>>,
|
||||
layout: &'a Layout,
|
||||
) -> &'b LayoutTreeItem<'a> {
|
||||
match layout {
|
||||
Layout::GridLayout(grid_layout) => {
|
||||
let mut cell_creation_code = Vec::new();
|
||||
for cell in &grid_layout.elems {
|
||||
cell_creation_code.push(format!(
|
||||
" {{ {c}, {r}, {cs}, {rs}, {li}, {x}, {y}, {w}, {h} }},",
|
||||
c = cell.col,
|
||||
r = cell.row,
|
||||
cs = cell.colspan,
|
||||
rs = cell.rowspan,
|
||||
li = cell.item.get_layout_info_ref(),
|
||||
li = cell.item.get_layout_info_ref(layout_tree),
|
||||
x = cell.item.get_property_ref("x"),
|
||||
y = cell.item.get_property_ref("y"),
|
||||
w = cell.item.get_property_ref("width"),
|
||||
h = cell.item.get_property_ref("height")
|
||||
));
|
||||
}
|
||||
res.push(" };".to_owned());
|
||||
res.push(format!(
|
||||
" auto width = {};",
|
||||
compile_expression(&grid.rect.width_reference, component)
|
||||
let cell_ref_variable = format!("cells_{}", layout_tree.len()).to_owned();
|
||||
cell_creation_code.insert(
|
||||
0,
|
||||
format!(" sixtyfps::GridLayoutCellData {}_data[] = {{", cell_ref_variable,),
|
||||
);
|
||||
cell_creation_code.push(" };".to_owned());
|
||||
cell_creation_code.push(format!(
|
||||
" const sixtyfps::Slice<sixtyfps::GridLayoutCellData> {cv}{{{cv}_data, std::size({cv}_data)}};",
|
||||
cv = cell_ref_variable
|
||||
));
|
||||
res.push(format!(
|
||||
" auto height = {};",
|
||||
compile_expression(&grid.rect.height_reference, component)
|
||||
));
|
||||
res.push(" sixtyfps::GridLayoutData grid { ".into());
|
||||
res.push(format!(
|
||||
" width, height, {}, {},",
|
||||
compile_expression(&grid.rect.x_reference, component),
|
||||
compile_expression(&grid.rect.y_reference, component)
|
||||
));
|
||||
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());
|
||||
}
|
||||
Layout::PathLayout(path_layout) => {
|
||||
res.push("{".to_owned());
|
||||
|
||||
let path_layout_item_data = |elem: &ElementRc, elem_cpp: &str, component_cpp: &str| {
|
||||
layout_tree.push(
|
||||
GridLayoutWithCells {
|
||||
grid: grid_layout,
|
||||
cell_creation_code: cell_creation_code.join("\n"),
|
||||
cell_ref_variable,
|
||||
}
|
||||
.into(),
|
||||
)
|
||||
}
|
||||
Layout::PathLayout(path_layout) => layout_tree.push(path_layout.into()),
|
||||
}
|
||||
layout_tree.last().unwrap()
|
||||
}
|
||||
|
||||
impl<'a> LayoutTreeItem<'a> {
|
||||
fn layout_info_collecting_code(&self) -> Option<String> {
|
||||
match self {
|
||||
LayoutTreeItem::GridLayout(grid_layout) => Some(grid_layout.cell_creation_code.clone()),
|
||||
LayoutTreeItem::PathLayout(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn emit_solve_calls(&self, component: &Rc<Component>, code_stream: &mut Vec<String>) {
|
||||
match self {
|
||||
LayoutTreeItem::GridLayout(grid_layout) => {
|
||||
code_stream.push(" { ".into());
|
||||
code_stream.push(format!(
|
||||
" auto width = {};",
|
||||
compile_expression(&grid_layout.grid.rect.width_reference, component)
|
||||
));
|
||||
code_stream.push(format!(
|
||||
" auto height = {};",
|
||||
compile_expression(&grid_layout.grid.rect.height_reference, component)
|
||||
));
|
||||
code_stream.push(" sixtyfps::GridLayoutData grid { ".into());
|
||||
code_stream.push(format!(
|
||||
" width, height, {}, {},",
|
||||
compile_expression(&grid_layout.grid.rect.x_reference, component),
|
||||
compile_expression(&grid_layout.grid.rect.y_reference, component)
|
||||
));
|
||||
code_stream
|
||||
.push(format!(" {cv}", cv = grid_layout.cell_ref_variable).to_owned());
|
||||
code_stream.push(" };".to_owned());
|
||||
code_stream.push(" sixtyfps::solve_grid_layout(&grid);".to_owned());
|
||||
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) == Type::Length {
|
||||
format!("&{}.{}", elem_cpp, n)
|
||||
|
@ -1023,23 +1103,25 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
|||
path_layout.elements.iter().all(|elem| elem.borrow().repeated.is_none());
|
||||
|
||||
let slice = if is_static_array {
|
||||
res.push(" sixtyfps::PathLayoutItemData items[] = {".to_owned());
|
||||
code_stream.push(" sixtyfps::PathLayoutItemData items[] = {".to_owned());
|
||||
for elem in &path_layout.elements {
|
||||
res.push(format!(" {},", path_layout_item_data_for_elem(elem)));
|
||||
code_stream
|
||||
.push(format!(" {},", path_layout_item_data_for_elem(elem)));
|
||||
}
|
||||
res.push(" };".to_owned());
|
||||
code_stream.push(" };".to_owned());
|
||||
" {items, std::size(items)},".to_owned()
|
||||
} else {
|
||||
res.push(" std::vector<sixtyfps::PathLayoutItemData> items;".to_owned());
|
||||
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();
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" for (auto &&sub_comp : self->repeater_{}.data)",
|
||||
elem.borrow().id
|
||||
));
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" items.push_back({});",
|
||||
path_layout_item_data(
|
||||
&root_element,
|
||||
|
@ -1048,7 +1130,7 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
|||
)
|
||||
));
|
||||
} else {
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" items.push_back({});",
|
||||
path_layout_item_data_for_elem(elem)
|
||||
));
|
||||
|
@ -1057,38 +1139,65 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
|||
" {items.data(), std::size(items)},".to_owned()
|
||||
};
|
||||
|
||||
res.push(format!(" auto path = {};", compile_path(&path_layout.path, component)));
|
||||
code_stream.push(format!(
|
||||
" auto path = {};",
|
||||
compile_path(&path_layout.path, component)
|
||||
));
|
||||
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" auto x = {};",
|
||||
compile_expression(&path_layout.rect.x_reference, component)
|
||||
));
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" auto y = {};",
|
||||
compile_expression(&path_layout.rect.y_reference, component)
|
||||
));
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" auto width = {};",
|
||||
compile_expression(&path_layout.rect.width_reference, component)
|
||||
));
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" auto height = {};",
|
||||
compile_expression(&path_layout.rect.height_reference, component)
|
||||
));
|
||||
|
||||
res.push(format!(
|
||||
code_stream.push(format!(
|
||||
" auto offset = {};",
|
||||
compile_expression(&path_layout.offset_reference, component)
|
||||
));
|
||||
|
||||
res.push(" sixtyfps::PathLayoutData pl { ".into());
|
||||
res.push(" &path,".to_owned());
|
||||
res.push(slice);
|
||||
res.push(" x, y, width, height, offset".to_owned());
|
||||
res.push(" };".to_owned());
|
||||
res.push(" sixtyfps::solve_path_layout(&pl);".to_owned());
|
||||
res.push("}".to_owned());
|
||||
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::solve_path_layout(&pl);".to_owned());
|
||||
code_stream.push("}".to_owned());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
||||
let mut res = vec![];
|
||||
|
||||
res.push(format!(
|
||||
"[[maybe_unused]] auto self = reinterpret_cast<const {ty}*>(component.instance);",
|
||||
ty = component_id(component)
|
||||
));
|
||||
component.layout_constraints.borrow().iter().for_each(|layout| {
|
||||
let mut inverse_layout_tree = Vec::new();
|
||||
|
||||
collect_layouts_recursively(&mut inverse_layout_tree, layout);
|
||||
|
||||
res.extend(
|
||||
inverse_layout_tree.iter().filter_map(|layout| layout.layout_info_collecting_code()),
|
||||
);
|
||||
|
||||
inverse_layout_tree
|
||||
.iter()
|
||||
.rev()
|
||||
.for_each(|layout| layout.emit_solve_calls(component, &mut res));
|
||||
});
|
||||
|
||||
res
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue