mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-03 07:04:34 +00:00
C++: Support of dynamic model and if expression
This commit is contained in:
parent
20369c7fc7
commit
90532e80d2
3 changed files with 100 additions and 51 deletions
|
@ -70,9 +70,9 @@ constexpr inline ItemTreeNode<uint8_t> make_dyn_node(std::uintptr_t offset)
|
||||||
using internal::sixtyfps_visit_item_tree;
|
using internal::sixtyfps_visit_item_tree;
|
||||||
|
|
||||||
template<typename Component>
|
template<typename Component>
|
||||||
EvaluationContext evaluation_context_for_root_component(Component *component) {
|
EvaluationContext evaluation_context_for_root_component(const Component *component) {
|
||||||
return EvaluationContext{
|
return EvaluationContext{
|
||||||
VRef<ComponentVTable> { &Component::component_type, component},
|
VRef<ComponentVTable> { &Component::component_type, const_cast<Component *>(component)},
|
||||||
nullptr,
|
nullptr,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -122,8 +122,9 @@ struct Repeater {
|
||||||
std::vector<std::unique_ptr<C>> data;
|
std::vector<std::unique_ptr<C>> data;
|
||||||
|
|
||||||
template<typename Parent>
|
template<typename Parent>
|
||||||
void update_model(Model *model, Parent *parent)
|
void update_model(Model *model, const Parent *parent) const
|
||||||
{
|
{
|
||||||
|
auto &data = const_cast<Repeater*>(this)->data;
|
||||||
data.clear();
|
data.clear();
|
||||||
auto count = model->count();
|
auto count = model->count();
|
||||||
for (auto i = 0; i < count; ++i) {
|
for (auto i = 0; i < count; ++i) {
|
||||||
|
|
|
@ -112,12 +112,12 @@ struct PropertyListenerScope
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
bool evaluate(F &f) const {
|
void evaluate(const F &f) const {
|
||||||
return internal::sixtyfps_property_listener_scope_evaluate(
|
internal::sixtyfps_property_listener_scope_evaluate(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *f){ (*reinterpret_cast<F*>(f))(); },
|
[](void *f){ (*reinterpret_cast<const F*>(f))(); },
|
||||||
&f
|
const_cast<F*>(&f)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -286,19 +286,54 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec<String>)
|
||||||
fn handle_repeater(
|
fn handle_repeater(
|
||||||
repeated: &RepeatedElementInfo,
|
repeated: &RepeatedElementInfo,
|
||||||
base_component: &Rc<Component>,
|
base_component: &Rc<Component>,
|
||||||
|
parent_component: &Rc<Component>,
|
||||||
repeater_count: i32,
|
repeater_count: i32,
|
||||||
component_struct: &mut Struct,
|
component_struct: &mut Struct,
|
||||||
init: &mut Vec<String>,
|
init: &mut Vec<String>,
|
||||||
|
children_repeater_cases: &mut Vec<String>,
|
||||||
) {
|
) {
|
||||||
let repeater_id = format!("repeater_{}", repeater_count);
|
let repeater_id = format!("repeater_{}", repeater_count);
|
||||||
assert!(repeated.model.is_constant(), "TODO: currently model can only be constant");
|
|
||||||
// FIXME: that's not the right component for this expression but that's ok because it is a constant for now
|
let model = compile_expression(&repeated.model, parent_component);
|
||||||
let model = compile_expression(&repeated.model, &base_component);
|
let model = if !repeated.is_conditional_element {
|
||||||
init.push(format!(
|
format!("{}.get()", model)
|
||||||
"self->{repeater_id}.update_model({model}.get(), self);",
|
} else {
|
||||||
repeater_id = repeater_id,
|
// bool converts to int
|
||||||
model = model
|
// FIXME: don't do a heap allocation here
|
||||||
));
|
format!("std::make_shared<sixtyfps::IntModel>({}).get()", model)
|
||||||
|
};
|
||||||
|
|
||||||
|
if repeated.model.is_constant() {
|
||||||
|
children_repeater_cases.push(format!(
|
||||||
|
"\n case {i}: self->repeater_{i}.visit(visitor); break;",
|
||||||
|
i = repeater_count
|
||||||
|
));
|
||||||
|
init.push(format!(
|
||||||
|
"self->{repeater_id}.update_model({model}, self);",
|
||||||
|
repeater_id = repeater_id,
|
||||||
|
model = model,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
let model_id = format!("model_{}", repeater_count);
|
||||||
|
component_struct.members.push(Declaration::Var(Var {
|
||||||
|
ty: "sixtyfps::PropertyListenerScope".to_owned(),
|
||||||
|
name: model_id,
|
||||||
|
init: None,
|
||||||
|
}));
|
||||||
|
children_repeater_cases.push(format!(
|
||||||
|
"\n case {i}: {{
|
||||||
|
if (self->model_{i}.is_dirty()) {{
|
||||||
|
self->model_{i}.evaluate([&] {{
|
||||||
|
self->repeater_{i}.update_model({model}, self);
|
||||||
|
}});
|
||||||
|
}}
|
||||||
|
self->repeater_{i}.visit(visitor);
|
||||||
|
break;
|
||||||
|
}}",
|
||||||
|
i = repeater_count,
|
||||||
|
model = model,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
component_struct.members.push(Declaration::Var(Var {
|
component_struct.members.push(Declaration::Var(Var {
|
||||||
ty: format!("sixtyfps::Repeater<struct {}>", component_id(base_component)),
|
ty: format!("sixtyfps::Repeater<struct {}>", component_id(base_component)),
|
||||||
|
@ -394,36 +429,48 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
}
|
}
|
||||||
|
|
||||||
if !is_root {
|
if !is_root {
|
||||||
component_struct.members.push(Declaration::Var(Var {
|
let parent_element = component.parent_element.upgrade().unwrap();
|
||||||
ty: "sixtyfps::Property<int>".into(),
|
|
||||||
name: "index".into(),
|
let mut update_statements = vec![];
|
||||||
init: None,
|
|
||||||
}));
|
if !parent_element.borrow().repeated.as_ref().map_or(false, |r| r.is_conditional_element) {
|
||||||
let cpp_model_data_type = crate::expression_tree::Expression::RepeaterModelReference {
|
component_struct.members.push(Declaration::Var(Var {
|
||||||
element: component.parent_element.clone(),
|
ty: "sixtyfps::Property<int>".into(),
|
||||||
|
name: "index".into(),
|
||||||
|
init: None,
|
||||||
|
}));
|
||||||
|
let cpp_model_data_type = crate::expression_tree::Expression::RepeaterModelReference {
|
||||||
|
element: component.parent_element.clone(),
|
||||||
|
}
|
||||||
|
.ty()
|
||||||
|
.cpp_type()
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
diag.push_compiler_error(CompilerDiagnostic {
|
||||||
|
message: "Cannot map property type to C++".into(),
|
||||||
|
span: parent_element
|
||||||
|
.borrow()
|
||||||
|
.node
|
||||||
|
.as_ref()
|
||||||
|
.map(|n| n.span())
|
||||||
|
.unwrap_or_default(),
|
||||||
|
});
|
||||||
|
String::default()
|
||||||
|
})
|
||||||
|
.to_owned();
|
||||||
|
component_struct.members.push(Declaration::Var(Var {
|
||||||
|
ty: format!("sixtyfps::Property<{}>", cpp_model_data_type),
|
||||||
|
name: "model_data".into(),
|
||||||
|
init: None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
update_statements = vec![
|
||||||
|
"index.set(i);".into(),
|
||||||
|
format!("model_data.set(*reinterpret_cast<{} const*>(data));", cpp_model_data_type),
|
||||||
|
];
|
||||||
}
|
}
|
||||||
.ty()
|
|
||||||
.cpp_type()
|
|
||||||
.unwrap_or_else(|| {
|
|
||||||
diag.push_compiler_error(CompilerDiagnostic {
|
|
||||||
message: "Cannot map property type to C++".into(),
|
|
||||||
span: component
|
|
||||||
.parent_element
|
|
||||||
.upgrade()
|
|
||||||
.and_then(|e| e.borrow().node.as_ref().map(|n| n.span()))
|
|
||||||
.unwrap_or_default(),
|
|
||||||
});
|
|
||||||
String::default()
|
|
||||||
})
|
|
||||||
.to_owned();
|
|
||||||
component_struct.members.push(Declaration::Var(Var {
|
|
||||||
ty: format!("sixtyfps::Property<{}>", cpp_model_data_type),
|
|
||||||
name: "model_data".into(),
|
|
||||||
init: None,
|
|
||||||
}));
|
|
||||||
component_struct.members.push(Declaration::Var(Var {
|
component_struct.members.push(Declaration::Var(Var {
|
||||||
ty: format!(
|
ty: format!(
|
||||||
"{}*",
|
"{} const *",
|
||||||
self::component_id(
|
self::component_id(
|
||||||
&component
|
&component
|
||||||
.parent_element
|
.parent_element
|
||||||
|
@ -440,16 +487,14 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
}));
|
}));
|
||||||
component_struct.members.push(Declaration::Function(Function {
|
component_struct.members.push(Declaration::Function(Function {
|
||||||
name: "update_data".into(),
|
name: "update_data".into(),
|
||||||
signature: "(int i, const void *data) -> void".into(),
|
signature: "([[maybe_unused]] int i, [[maybe_unused]] const void *data) -> void".into(),
|
||||||
statements: Some(vec![
|
statements: Some(update_statements),
|
||||||
"index.set(i);".into(),
|
|
||||||
format!("model_data.set(*reinterpret_cast<{} const*>(data));", cpp_model_data_type),
|
|
||||||
]),
|
|
||||||
..Function::default()
|
..Function::default()
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut init = vec!["[[maybe_unused]] auto self = this;".into()];
|
let mut init = vec!["[[maybe_unused]] auto self = this;".into()];
|
||||||
|
let mut children_visitor_case = vec![];
|
||||||
let mut tree_array = String::new();
|
let mut tree_array = String::new();
|
||||||
let mut repeater_count = 0;
|
let mut repeater_count = 0;
|
||||||
super::build_array_helper(component, |item, children_offset| {
|
super::build_array_helper(component, |item, children_offset| {
|
||||||
|
@ -469,9 +514,11 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
handle_repeater(
|
handle_repeater(
|
||||||
repeated,
|
repeated,
|
||||||
base_component,
|
base_component,
|
||||||
|
component,
|
||||||
repeater_count,
|
repeater_count,
|
||||||
&mut component_struct,
|
&mut component_struct,
|
||||||
&mut init,
|
&mut init,
|
||||||
|
&mut children_visitor_case,
|
||||||
);
|
);
|
||||||
repeater_count += 1;
|
repeater_count += 1;
|
||||||
} else {
|
} else {
|
||||||
|
@ -539,9 +586,10 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
format!(" {} }};", tree_array),
|
format!(" {} }};", tree_array),
|
||||||
"static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) {".to_owned(),
|
"static const auto dyn_visit = [] (const uint8_t *base, [[maybe_unused]] sixtyfps::ItemVisitorRefMut visitor, uintptr_t dyn_index) {".to_owned(),
|
||||||
format!(" [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);", component_id),
|
format!(" [[maybe_unused]] auto self = reinterpret_cast<const {}*>(base);", component_id),
|
||||||
format!(" switch(dyn_index) {{ {} }}\n }};", (0..repeater_count).map(|i| {
|
// Fixme: this is not the root component
|
||||||
format!("\n case {i}: self->repeater_{i}.visit(visitor); break;", i=i)
|
"auto context_ = sixtyfps::evaluation_context_for_root_component(self);".into(),
|
||||||
}).collect::<Vec<_>>().join("")),
|
"[[maybe_unused]] auto context = &context_;".into(),
|
||||||
|
format!(" switch(dyn_index) {{ {} }}\n }};", children_visitor_case.join("")),
|
||||||
"return sixtyfps::sixtyfps_visit_item_tree(component, { const_cast<sixtyfps::ItemTreeNode<uint8_t>*>(children), std::size(children)}, index, visitor, dyn_visit);".to_owned(),
|
"return sixtyfps::sixtyfps_visit_item_tree(component, { const_cast<sixtyfps::ItemTreeNode<uint8_t>*>(children), std::size(children)}, index, visitor, dyn_visit);".to_owned(),
|
||||||
]),
|
]),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue