mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-04 18:58:36 +00:00
Support for changed callback in global
Fixes #6599 ChangeLog: Support property changed callbacks in globals
This commit is contained in:
parent
25607a9706
commit
ff53791ce7
8 changed files with 114 additions and 4 deletions
|
@ -2534,6 +2534,22 @@ fn generate_global(
|
|||
}
|
||||
}
|
||||
|
||||
for (i, _) in global.change_callbacks.iter() {
|
||||
global_struct.members.push((
|
||||
Access::Private,
|
||||
Declaration::Var(Var {
|
||||
ty: "slint::private_api::ChangeTracker".into(),
|
||||
name: format_smolstr!("change_tracker{}", i),
|
||||
..Default::default()
|
||||
}),
|
||||
));
|
||||
}
|
||||
init.extend(global.change_callbacks.iter().map(|(p, e)| {
|
||||
let code = compile_expression(&e.borrow(), &ctx);
|
||||
let prop = access_member(&llr::PropertyReference::Local { sub_component_path: vec![], property_index: *p }, &ctx);
|
||||
format!("this->change_tracker{p}.init(this, [this]([[maybe_unused]] auto self) {{ return {prop}.get(); }}, [this]([[maybe_unused]] auto self, auto) {{ {code}; }});")
|
||||
}));
|
||||
|
||||
global_struct.members.push((
|
||||
Access::Public,
|
||||
Declaration::Function(Function {
|
||||
|
|
|
@ -1357,6 +1357,37 @@ fn generate_global(global: &llr::GlobalComponent, root: &llr::CompilationUnit) -
|
|||
}
|
||||
}
|
||||
|
||||
let public_component_id = ident(&global.name);
|
||||
let global_id = format_ident!("global_{}", public_component_id);
|
||||
|
||||
let change_tracker_names =
|
||||
global.change_callbacks.iter().map(|(idx, _)| format_ident!("change_tracker{idx}"));
|
||||
init.extend(global.change_callbacks.iter().map(|(p, e)| {
|
||||
let code = compile_expression(&e.borrow(), &ctx);
|
||||
let prop = access_member(
|
||||
&llr::PropertyReference::Local { sub_component_path: vec![], property_index: *p },
|
||||
&ctx,
|
||||
)
|
||||
.unwrap();
|
||||
let change_tracker = format_ident!("change_tracker{p}");
|
||||
quote! {
|
||||
#[allow(dead_code, unused)]
|
||||
_self.#change_tracker.init(
|
||||
self_rc.globals.get().unwrap().clone(),
|
||||
move |global_weak| {
|
||||
let self_rc = global_weak.upgrade().unwrap().#global_id.clone();
|
||||
let _self = self_rc.as_ref();
|
||||
#prop.get()
|
||||
},
|
||||
move |global_weak, _| {
|
||||
let self_rc = global_weak.upgrade().unwrap().#global_id.clone();
|
||||
let _self = self_rc.as_ref();
|
||||
#code;
|
||||
}
|
||||
);
|
||||
}
|
||||
}));
|
||||
|
||||
let public_interface = global.exported.then(|| {
|
||||
let property_and_callback_accessors = public_api(
|
||||
&global.public_properties,
|
||||
|
@ -1364,8 +1395,6 @@ fn generate_global(global: &llr::GlobalComponent, root: &llr::CompilationUnit) -
|
|||
quote!(self.0.as_ref()),
|
||||
&ctx,
|
||||
);
|
||||
let public_component_id = ident(&global.name);
|
||||
let global_id = format_ident!("global_{}", public_component_id);
|
||||
let aliases = global.aliases.iter().map(|name| ident(name));
|
||||
let getters = root.public_components.iter().map(|c| {
|
||||
let root_component_id = ident(&c.name);
|
||||
|
@ -1398,6 +1427,7 @@ fn generate_global(global: &llr::GlobalComponent, root: &llr::CompilationUnit) -
|
|||
struct #inner_component_id {
|
||||
#(#declared_property_vars: sp::Property<#declared_property_types>,)*
|
||||
#(#declared_callbacks: sp::Callback<(#(#declared_callbacks_types,)*), #declared_callbacks_ret>,)*
|
||||
#(#change_tracker_names : sp::ChangeTracker,)*
|
||||
globals : sp::OnceCell<sp::Weak<SharedGlobals>>,
|
||||
}
|
||||
|
||||
|
|
|
@ -56,6 +56,8 @@ pub struct GlobalComponent {
|
|||
pub functions: Vec<Function>,
|
||||
/// One entry per property
|
||||
pub init_values: Vec<Option<BindingExpression>>,
|
||||
// maps property to its changed callback
|
||||
pub change_callbacks: BTreeMap<usize, MutExpression>,
|
||||
pub const_properties: Vec<bool>,
|
||||
pub public_properties: PublicProperties,
|
||||
pub private_properties: PrivateProperties,
|
||||
|
@ -434,6 +436,9 @@ impl CompilationUnit {
|
|||
for e in g.init_values.iter().filter_map(|x| x.as_ref()) {
|
||||
visitor(&e.expression, &ctx)
|
||||
}
|
||||
for e in g.change_callbacks.values() {
|
||||
visitor(e, &ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -795,6 +795,20 @@ fn lower_global(
|
|||
});
|
||||
}
|
||||
|
||||
let mut change_callbacks = BTreeMap::new();
|
||||
for (prop, expr) in &global.root_element.borrow().change_callbacks {
|
||||
let nr = NamedReference::new(&global.root_element, prop);
|
||||
let property_index = match mapping.property_mapping[&nr] {
|
||||
PropertyReference::Local { property_index, .. } => property_index,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
let expression = super::lower_expression::lower_expression(
|
||||
&tree_Expression::CodeBlock(expr.borrow().clone()),
|
||||
&ctx,
|
||||
);
|
||||
change_callbacks.insert(property_index, expression.into());
|
||||
}
|
||||
|
||||
let is_builtin = if let Some(builtin) = global.root_element.borrow().native_class() {
|
||||
// We just generate the property so we know how to address them
|
||||
for (p, x) in &builtin.properties {
|
||||
|
@ -828,6 +842,7 @@ fn lower_global(
|
|||
properties,
|
||||
functions,
|
||||
init_values,
|
||||
change_callbacks,
|
||||
const_properties,
|
||||
public_properties,
|
||||
private_properties: global.private_properties.borrow().clone(),
|
||||
|
|
|
@ -154,6 +154,15 @@ impl<'a> PrettyPrinter<'a> {
|
|||
if *is_const { " const" } else { "" }
|
||||
)?;
|
||||
}
|
||||
for (p, e) in &global.change_callbacks {
|
||||
self.indent()?;
|
||||
writeln!(
|
||||
self.writer,
|
||||
"changed {} => {};",
|
||||
global.properties[*p].name,
|
||||
DisplayExpression(&e.borrow(), &ctx),
|
||||
)?
|
||||
}
|
||||
for f in &global.functions {
|
||||
self.indent()?;
|
||||
writeln!(
|
||||
|
|
|
@ -1113,6 +1113,13 @@ pub(crate) fn generate_item_tree<'id>(
|
|||
|
||||
if !component.is_global() {
|
||||
generator::build_item_tree(component, &(), &mut builder);
|
||||
} else {
|
||||
for (prop, expr) in component.root_element.borrow().change_callbacks.iter() {
|
||||
builder.change_callbacks.push((
|
||||
NamedReference::new(&component.root_element, prop),
|
||||
Expression::CodeBlock(expr.borrow().clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
let mut custom_properties = HashMap::new();
|
||||
|
|
|
@ -168,13 +168,15 @@ pub fn instantiate(
|
|||
CompiledGlobal::Component { component, .. } => {
|
||||
generativity::make_guard!(guard);
|
||||
let description = component.unerase(guard);
|
||||
Rc::pin(GlobalComponentInstance(crate::dynamic_item_tree::instantiate(
|
||||
let inst = crate::dynamic_item_tree::instantiate(
|
||||
description.clone(),
|
||||
None,
|
||||
Some(root),
|
||||
None,
|
||||
globals.clone(),
|
||||
)))
|
||||
);
|
||||
inst.run_setup_code();
|
||||
Rc::pin(GlobalComponentInstance(inst))
|
||||
}
|
||||
};
|
||||
globals.extend(
|
||||
|
|
|
@ -1,6 +1,14 @@
|
|||
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
||||
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
|
||||
|
||||
export global Glob {
|
||||
in-out property <int> v: 55;
|
||||
in-out property <string> r;
|
||||
changed v => {
|
||||
r += "|" + v;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
component Chaining {
|
||||
|
||||
|
@ -152,6 +160,12 @@ instance.invoke_sub_do_change();
|
|||
slint_testing::mock_elapsed_time(100);
|
||||
assert_eq!(instance.get_sub_result(), "sub2(124)root2(124)sub(790)root(790)");
|
||||
assert_eq!(instance.get_result(), "||sub2(124)root2(124)sub(790)root(790)");
|
||||
|
||||
// Global
|
||||
instance.global::<Glob<'_>>().set_v(88);
|
||||
assert_eq!(instance.global::<Glob<'_>>().get_r(), "");
|
||||
slint_testing::mock_elapsed_time(100);
|
||||
assert_eq!(instance.global::<Glob<'_>>().get_r(), "|88");
|
||||
```
|
||||
|
||||
```cpp
|
||||
|
@ -192,6 +206,12 @@ instance.invoke_sub_do_change();
|
|||
slint_testing::mock_elapsed_time(100);
|
||||
assert_eq(instance.get_sub_result(), "sub2(124)root2(124)sub(790)root(790)");
|
||||
assert_eq(instance.get_result(), "||sub2(124)root2(124)sub(790)root(790)");
|
||||
|
||||
// Global
|
||||
instance.global<Glob>().set_v(88);
|
||||
assert_eq(instance.global<Glob>().get_r(), "");
|
||||
slint_testing::mock_elapsed_time(100);
|
||||
assert_eq(instance.global<Glob>().get_r(), "|88");
|
||||
```
|
||||
|
||||
```js
|
||||
|
@ -226,6 +246,12 @@ instance.sub_do_change();
|
|||
slintlib.private_api.mock_elapsed_time(100);
|
||||
assert.equal(instance.sub_result, "sub2(124)root2(124)sub(790)root(790)");
|
||||
assert.equal(instance.result, "||sub2(124)root2(124)sub(790)root(790)");
|
||||
|
||||
// Global
|
||||
instance.Glob.v = 88;
|
||||
assert.equal(instance.Glob.r, "");
|
||||
slintlib.private_api.mock_elapsed_time(100);
|
||||
assert.equal(instance.Glob.r, "|88");
|
||||
```
|
||||
|
||||
*/
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue