mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-30 13:51:13 +00:00
Some refactoring of the rust generated code
Always use a Pin<Rc> for the component. (This is required to support repeater within repeater as well anyway) Do not use the context within the binding. We can get along by simply capturing a weak pointer to the component
This commit is contained in:
parent
1a0d053889
commit
ab7ae9f3e2
15 changed files with 74 additions and 73 deletions
|
@ -20,7 +20,7 @@ sixtyfps::sixtyfps!{
|
||||||
}
|
}
|
||||||
fn main() {
|
fn main() {
|
||||||
# return; // Don't run a window in an example
|
# return; // Don't run a window in an example
|
||||||
HelloWorld::default().run()
|
HelloWorld::new().run()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ Then in your main file
|
||||||
```ignore
|
```ignore
|
||||||
sixtyfps::include_modules!();
|
sixtyfps::include_modules!();
|
||||||
fn main() {
|
fn main() {
|
||||||
HelloWorld::default().run()
|
HelloWorld::new().run()
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
use core::cell::RefCell;
|
use core::cell::RefCell;
|
||||||
|
use core::pin::Pin;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
/// Component that can be instantiated by a repeater.
|
/// Component that can be instantiated by a repeater.
|
||||||
pub trait RepeatedComponent: sixtyfps_corelib::abi::datastructures::Component {
|
pub trait RepeatedComponent: sixtyfps_corelib::abi::datastructures::Component {
|
||||||
|
@ -11,9 +13,14 @@ pub trait RepeatedComponent: sixtyfps_corelib::abi::datastructures::Component {
|
||||||
|
|
||||||
/// This field is put in a component when using the `for` syntax
|
/// This field is put in a component when using the `for` syntax
|
||||||
/// It helps instantiating the components `C`
|
/// It helps instantiating the components `C`
|
||||||
#[derive(Default)]
|
|
||||||
pub struct Repeater<C> {
|
pub struct Repeater<C> {
|
||||||
components: RefCell<Vec<core::pin::Pin<Box<C>>>>,
|
components: RefCell<Vec<Pin<Rc<C>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> Default for Repeater<C> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Repeater { components: Default::default() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Data, C> Repeater<C>
|
impl<Data, C> Repeater<C>
|
||||||
|
@ -21,7 +28,7 @@ where
|
||||||
C: RepeatedComponent<Data = Data>,
|
C: RepeatedComponent<Data = Data>,
|
||||||
{
|
{
|
||||||
/// Called when the model is changed
|
/// Called when the model is changed
|
||||||
pub fn update_model<'a>(&self, data: impl Iterator<Item = Data>, init: impl Fn() -> C)
|
pub fn update_model<'a>(&self, data: impl Iterator<Item = Data>, init: impl Fn() -> Pin<Rc<C>>)
|
||||||
where
|
where
|
||||||
Data: 'a,
|
Data: 'a,
|
||||||
{
|
{
|
||||||
|
@ -29,7 +36,7 @@ where
|
||||||
for (i, d) in data.enumerate() {
|
for (i, d) in data.enumerate() {
|
||||||
let c = init();
|
let c = init();
|
||||||
c.update(i, d);
|
c.update(i, d);
|
||||||
self.components.borrow_mut().push(Box::pin(c));
|
self.components.borrow_mut().push(c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ Hello := Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = Hello::default();
|
let app = Hello::new();
|
||||||
app.plus_clicked.set_handler(|context, ()| {
|
app.plus_clicked.set_handler(|context, ()| {
|
||||||
let app = context.get_component::<Hello>().unwrap();
|
let app = context.get_component::<Hello>().unwrap();
|
||||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
let counter = Hello::field_offsets().counter.apply_pin(app);
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
sixtyfps::include_modules!();
|
sixtyfps::include_modules!();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let mut app = Hello::default();
|
let app = Hello::new();
|
||||||
|
|
||||||
app.plus_clicked.set_handler(|context, ()| {
|
app.plus_clicked.set_handler(|context, ()| {
|
||||||
let app = context.get_component::<Hello>().unwrap();
|
let app = context.get_component::<Hello>().unwrap();
|
||||||
|
|
|
@ -10,5 +10,5 @@ pub fn wasm_main() {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
console_error_panic_hook::set_once();
|
console_error_panic_hook::set_once();
|
||||||
|
|
||||||
Hello::default().run();
|
Hello::new().run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,7 +115,6 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
let mut repeated_dynmodel_names = Vec::new();
|
let mut repeated_dynmodel_names = Vec::new();
|
||||||
let mut repeated_visit_branch = Vec::new();
|
let mut repeated_visit_branch = Vec::new();
|
||||||
let mut init = Vec::new();
|
let mut init = Vec::new();
|
||||||
let mut init_repeaters = Vec::new();
|
|
||||||
super::build_array_helper(component, |item_rc, children_index| {
|
super::build_array_helper(component, |item_rc, children_index| {
|
||||||
let item = item_rc.borrow();
|
let item = item_rc.borrow();
|
||||||
if let Some(repeated) = &item.repeated {
|
if let Some(repeated) = &item.repeated {
|
||||||
|
@ -166,11 +165,9 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
}
|
}
|
||||||
|
|
||||||
if repeated.model.is_constant() {
|
if repeated.model.is_constant() {
|
||||||
init_repeaters.push(quote! {
|
init.push(quote! {
|
||||||
self_pinned.#repeater_id.update_model(#model, || {
|
self_pinned.#repeater_id.update_model(#model, || {
|
||||||
let mut new_comp = #rep_component_id::default();
|
#rep_component_id::new(self_pinned.self_weak.get().unwrap().clone())
|
||||||
new_comp.parent = self_pinned.self_weak.get().unwrap().clone();
|
|
||||||
new_comp
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
repeated_visit_branch.push(quote!(
|
repeated_visit_branch.push(quote!(
|
||||||
|
@ -189,9 +186,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
);
|
);
|
||||||
let context = &context;
|
let context = &context;
|
||||||
self_pinned.#repeater_id.update_model(#model, || {
|
self_pinned.#repeater_id.update_model(#model, || {
|
||||||
let mut new_comp = #rep_component_id::default();
|
#rep_component_id::new(self_pinned.self_weak.get().unwrap().clone())
|
||||||
new_comp.parent = self_pinned.self_weak.get().unwrap().clone();
|
|
||||||
new_comp
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -231,38 +226,37 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
|
|
||||||
if matches!(item.lookup_property(k.as_str()), Type::Signal) {
|
if matches!(item.lookup_property(k.as_str()), Type::Signal) {
|
||||||
init.push(quote!(
|
init.push(quote!(
|
||||||
self_.#rust_property.set_handler(|context, ()| {
|
self_pinned.#rust_property.set_handler(|context, ()| {
|
||||||
let _self = context.get_component::<#component_id>().unwrap();
|
let _self = context.get_component::<#component_id>().unwrap();
|
||||||
#tokens_for_expression;
|
#tokens_for_expression;
|
||||||
});
|
});
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
if binding_expression.is_constant() {
|
let setter = if binding_expression.is_constant() {
|
||||||
let setter = property_set_value_tokens(
|
property_set_value_tokens(
|
||||||
component,
|
component,
|
||||||
&item_rc,
|
&item_rc,
|
||||||
k,
|
k,
|
||||||
quote!((#tokens_for_expression) as _),
|
quote!((#tokens_for_expression) as _),
|
||||||
);
|
)
|
||||||
init.push(quote!(
|
|
||||||
self_.#rust_property.#setter;
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
let setter = property_set_binding_tokens(
|
property_set_binding_tokens(
|
||||||
component,
|
component,
|
||||||
&item_rc,
|
&item_rc,
|
||||||
k,
|
k,
|
||||||
quote!(
|
quote!({
|
||||||
|context| {
|
let self_weak = sixtyfps::re_exports::WeakPin::downgrade(self_pinned.clone());
|
||||||
let _self = context.get_component::<#component_id>().unwrap();
|
move |context| {
|
||||||
|
let self_pinned = self_weak.upgrade().unwrap();
|
||||||
|
let _self = self_pinned.as_ref();
|
||||||
(#tokens_for_expression) as _
|
(#tokens_for_expression) as _
|
||||||
}
|
}
|
||||||
),
|
}),
|
||||||
);
|
)
|
||||||
init.push(quote!(
|
};
|
||||||
self_.#rust_property.#setter;
|
init.push(quote!(
|
||||||
));
|
self_pinned.#rust_property.#setter;
|
||||||
}
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
item_names.push(field_name);
|
item_names.push(field_name);
|
||||||
|
@ -312,15 +306,10 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
property_and_signal_accessors.push(quote! {
|
property_and_signal_accessors.push(quote! {
|
||||||
fn run(self) {
|
fn run(self : core::pin::Pin<std::rc::Rc<Self>>) {
|
||||||
use sixtyfps::re_exports::*;
|
use sixtyfps::re_exports::*;
|
||||||
let window = sixtyfps::create_window();
|
let window = sixtyfps::create_window();
|
||||||
let self_pinned = Rc::pin(self);
|
window.run(VRef::new_pin(self.as_ref()));
|
||||||
self_pinned.self_weak.set(WeakPin::downgrade(self_pinned.clone()))
|
|
||||||
.map_err(|_|())
|
|
||||||
.expect("Can only be pinned once");
|
|
||||||
#(#init_repeaters)*
|
|
||||||
window.run(VRef::new_pin(self_pinned.as_ref()));
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
@ -349,25 +338,6 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
#(parent : sixtyfps::re_exports::WeakPin<#parent_component_type>,)*
|
#(parent : sixtyfps::re_exports::WeakPin<#parent_component_type>,)*
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ::core::default::Default for #component_id {
|
|
||||||
fn default() -> Self {
|
|
||||||
#![allow(unused)]
|
|
||||||
use sixtyfps::re_exports::*;
|
|
||||||
ComponentVTable_static!(static VT for #component_id);
|
|
||||||
let mut self_ = Self {
|
|
||||||
#(#item_names : ::core::default::Default::default(),)*
|
|
||||||
#(#declared_property_vars : ::core::default::Default::default(),)*
|
|
||||||
#(#declared_signals : ::core::default::Default::default(),)*
|
|
||||||
#(#repeated_element_names : ::core::default::Default::default(),)*
|
|
||||||
#(#repeated_dynmodel_names : ::core::default::Default::default(),)*
|
|
||||||
self_weak : ::core::default::Default::default(),
|
|
||||||
#(parent : sixtyfps::re_exports::WeakPin::<#parent_component_type>::default(),)*
|
|
||||||
};
|
|
||||||
#(#init)*
|
|
||||||
self_
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
impl sixtyfps::re_exports::Component for #component_id {
|
impl sixtyfps::re_exports::Component for #component_id {
|
||||||
fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, visitor: sixtyfps::re_exports::ItemVisitorRefMut) {
|
fn visit_children_item(self: ::core::pin::Pin<&Self>, index: isize, visitor: sixtyfps::re_exports::ItemVisitorRefMut) {
|
||||||
use sixtyfps::re_exports::*;
|
use sixtyfps::re_exports::*;
|
||||||
|
@ -386,6 +356,27 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
}
|
}
|
||||||
|
|
||||||
impl #component_id{
|
impl #component_id{
|
||||||
|
fn new(#(parent: sixtyfps::re_exports::WeakPin::<#parent_component_type>)*)
|
||||||
|
-> core::pin::Pin<std::rc::Rc<Self>>
|
||||||
|
{
|
||||||
|
#![allow(unused)]
|
||||||
|
use sixtyfps::re_exports::*;
|
||||||
|
ComponentVTable_static!(static VT for #component_id);
|
||||||
|
let mut self_ = Self {
|
||||||
|
#(#item_names : ::core::default::Default::default(),)*
|
||||||
|
#(#declared_property_vars : ::core::default::Default::default(),)*
|
||||||
|
#(#declared_signals : ::core::default::Default::default(),)*
|
||||||
|
#(#repeated_element_names : ::core::default::Default::default(),)*
|
||||||
|
#(#repeated_dynmodel_names : ::core::default::Default::default(),)*
|
||||||
|
self_weak : ::core::default::Default::default(),
|
||||||
|
#(parent : parent as sixtyfps::re_exports::WeakPin::<#parent_component_type>,)*
|
||||||
|
};
|
||||||
|
let self_pinned = std::rc::Rc::pin(self_);
|
||||||
|
self_pinned.self_weak.set(WeakPin::downgrade(self_pinned.clone())).map_err(|_|())
|
||||||
|
.expect("Can only be pinned once");
|
||||||
|
#(#init)*
|
||||||
|
self_pinned
|
||||||
|
}
|
||||||
#(#property_and_signal_accessors)*
|
#(#property_and_signal_accessors)*
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ but then it should also be renamed everywhere, including in the language grammar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::properties::EvaluationContext;
|
use super::properties::EvaluationContext;
|
||||||
|
use core::cell::Cell;
|
||||||
|
|
||||||
/// A Signal that can be connected to a handler.
|
/// A Signal that can be connected to a handler.
|
||||||
///
|
///
|
||||||
|
@ -15,7 +16,7 @@ use super::properties::EvaluationContext;
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct Signal<Arg> {
|
pub struct Signal<Arg> {
|
||||||
/// FIXME: Box<dyn> is a fat object and we probaly want to put an erased type in there
|
/// FIXME: Box<dyn> is a fat object and we probaly want to put an erased type in there
|
||||||
handler: Option<Box<dyn Fn(&EvaluationContext, Arg)>>,
|
handler: Cell<Option<Box<dyn Fn(&EvaluationContext, Arg)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Arg> Signal<Arg> {
|
impl<Arg> Signal<Arg> {
|
||||||
|
@ -23,16 +24,18 @@ impl<Arg> Signal<Arg> {
|
||||||
///
|
///
|
||||||
/// The constext must be a context corresponding to the component in which the signal is contained.
|
/// The constext must be a context corresponding to the component in which the signal is contained.
|
||||||
pub fn emit(&self, context: &EvaluationContext, a: Arg) {
|
pub fn emit(&self, context: &EvaluationContext, a: Arg) {
|
||||||
if let Some(h) = &self.handler {
|
if let Some(h) = self.handler.take() {
|
||||||
h(context, a);
|
h(context, a);
|
||||||
|
assert!(self.handler.take().is_none(), "Signal Handler set while emitted");
|
||||||
|
self.handler.set(Some(h))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set an handler to be called when the signal is emited
|
/// Set an handler to be called when the signal is emited
|
||||||
///
|
///
|
||||||
/// There can only be one single handler per signal.
|
/// There can only be one single handler per signal.
|
||||||
pub fn set_handler(&mut self, f: impl Fn(&EvaluationContext, Arg) + 'static) {
|
pub fn set_handler(&self, f: impl Fn(&EvaluationContext, Arg) + 'static) {
|
||||||
self.handler = Some(Box::new(f));
|
self.handler.set(Some(Box::new(f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +60,7 @@ fn signal_simple_test() {
|
||||||
fn compute_layout(self: Pin<&Self>, _: &crate::EvaluationContext) {}
|
fn compute_layout(self: Pin<&Self>, _: &crate::EvaluationContext) {}
|
||||||
}
|
}
|
||||||
use crate::abi::datastructures::ComponentVTable;
|
use crate::abi::datastructures::ComponentVTable;
|
||||||
let mut c = Component::default();
|
let c = Component::default();
|
||||||
c.clicked.set_handler(|c, ()| unsafe {
|
c.clicked.set_handler(|c, ()| unsafe {
|
||||||
(*(c.component.as_ptr() as *const Component)).pressed.set(true)
|
(*(c.component.as_ptr() as *const Component)).pressed.set(true)
|
||||||
});
|
});
|
||||||
|
|
|
@ -18,7 +18,7 @@ assert(instance.get_t4() == 3 + - 5 - 8 - -9 * - - - 120);
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let instance = Box::pin(TestCase::default());
|
let instance = TestCase::new();
|
||||||
let instance = instance.as_ref();
|
let instance = instance.as_ref();
|
||||||
assert_eq!(instance.get_t1(), 4 + 3 * 2 + 2 - 50 - 2);
|
assert_eq!(instance.get_t1(), 4 + 3 * 2 + 2 - 50 - 2);
|
||||||
assert_eq!(instance.get_t2(), 500 / 2 * 30 - 1);
|
assert_eq!(instance.get_t2(), 500 / 2 * 30 - 1);
|
||||||
|
|
|
@ -11,7 +11,7 @@ assert(!instance.get_falsevar());
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let instance = Box::pin(TestCase::default());
|
let instance = TestCase::new();
|
||||||
let instance = instance.as_ref();
|
let instance = instance.as_ref();
|
||||||
assert!(instance.get_truevar(), 1);
|
assert!(instance.get_truevar(), 1);
|
||||||
assert!(!instance.get_falsevar(), 1);
|
assert!(!instance.get_falsevar(), 1);
|
||||||
|
|
|
@ -21,7 +21,7 @@ assert(instance.get_s1() == "123");
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let instance = Box::pin(TestCase::default());
|
let instance = TestCase::new();
|
||||||
let instance = instance.as_ref();
|
let instance = instance.as_ref();
|
||||||
instance.set_condition(true);
|
instance.set_condition(true);
|
||||||
assert_eq!(instance.get_s1(), "abc");
|
assert_eq!(instance.get_s1(), "abc");
|
||||||
|
|
|
@ -27,7 +27,7 @@ assert(t.get_b1() != t.get_r5());
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let t = Box::pin(Test::default());
|
let t = Test::new();
|
||||||
let t = t.as_ref();
|
let t = t.as_ref();
|
||||||
assert_eq!(t.get_r1(), t.get_r2());
|
assert_eq!(t.get_r1(), t.get_r2());
|
||||||
assert_eq!(t.get_r1(), t.get_r3());
|
assert_eq!(t.get_r1(), t.get_r3());
|
||||||
|
|
|
@ -58,7 +58,7 @@ assert(instance.get_t6() == true);
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let instance = Box::pin(TestCase::default());
|
let instance = TestCase::new();
|
||||||
let instance = instance.as_ref();
|
let instance = instance.as_ref();
|
||||||
|
|
||||||
assert_eq!(instance.get_t1(), true);
|
assert_eq!(instance.get_t1(), true);
|
||||||
|
|
|
@ -20,7 +20,7 @@ assert(instance.get_test_value2() == 3);
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let instance = Box::pin(TestCase::default());
|
let instance = TestCase::new();
|
||||||
let instance = instance.as_ref();
|
let instance = instance.as_ref();
|
||||||
instance.set_condition(true);
|
instance.set_condition(true);
|
||||||
assert_eq!(instance.get_test_value(), 1);
|
assert_eq!(instance.get_test_value(), 1);
|
||||||
|
|
|
@ -14,7 +14,7 @@ assert(instance.get_signal_emission_count() == 1);
|
||||||
|
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
let instance = Box::pin(TestCase::default());
|
let instance = TestCase::new();
|
||||||
let instance = instance.as_ref();
|
let instance = instance.as_ref();
|
||||||
instance.set_signal_emission_count(0);
|
instance.set_signal_emission_count(0);
|
||||||
assert_eq!(instance.get_signal_emission_count(), 0);
|
assert_eq!(instance.get_signal_emission_count(), 0);
|
||||||
|
|
|
@ -8,7 +8,7 @@ TestCase instance;
|
||||||
```
|
```
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
TestCase::default();
|
TestCase::new();
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
```js
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue