mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-02 22:54:36 +00:00
Use Pin<&Self> for Property::get
This commit is contained in:
parent
0029921f1a
commit
2d22bac451
5 changed files with 108 additions and 74 deletions
|
@ -112,15 +112,15 @@ Hello := Rectangle {
|
|||
|
||||
fn main() {
|
||||
let mut app = Hello::default();
|
||||
|
||||
app.plus_clicked.set_handler(|context, ()| {
|
||||
let app = context.get_component::<Hello>().unwrap();
|
||||
app.counter.set(app.counter.get(context) + 1);
|
||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
||||
counter.set(counter.get(context) + 1);
|
||||
});
|
||||
app.minus_clicked.set_handler(|context, ()| {
|
||||
let app = context.get_component::<Hello>().unwrap();
|
||||
app.counter.set(app.counter.get(context) - 1);
|
||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
||||
counter.set(counter.get(context) - 1);
|
||||
});
|
||||
|
||||
app.run();
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@ fn main() {
|
|||
|
||||
app.plus_clicked.set_handler(|context, ()| {
|
||||
let app = context.get_component::<Hello>().unwrap();
|
||||
app.counter.set(app.counter.get(context) + 1);
|
||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
||||
counter.set(counter.get(context) + 1);
|
||||
});
|
||||
app.minus_clicked.set_handler(|context, ()| {
|
||||
let app = context.get_component::<Hello>().unwrap();
|
||||
app.counter.set(app.counter.get(context) - 1);
|
||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
||||
counter.set(counter.get(context) - 1);
|
||||
});
|
||||
app.run();
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
|||
let eval_context = sixtyfps::re_exports::EvaluationContext::for_root_component(
|
||||
sixtyfps::re_exports::ComponentRef::new_pin(self)
|
||||
);
|
||||
self.#prop_ident.emit(&eval_context, ())
|
||||
Self::field_offsets().#prop_ident.apply_pin(self).emit(&eval_context, ())
|
||||
}
|
||||
)
|
||||
.into(),
|
||||
|
@ -82,7 +82,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
|||
let eval_context = sixtyfps::re_exports::EvaluationContext::for_root_component(
|
||||
sixtyfps::re_exports::ComponentRef::new_pin(self)
|
||||
);
|
||||
self.#prop_ident.get(&eval_context)
|
||||
Self::field_offsets().#prop_ident.apply_pin(self).get(&eval_context)
|
||||
}
|
||||
)
|
||||
.into(),
|
||||
|
@ -92,7 +92,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
|||
quote!(
|
||||
#[allow(dead_code)]
|
||||
fn #setter_ident(&self, value: #rust_property_type) {
|
||||
self.#prop_ident.set(value)
|
||||
Self::field_offsets().#prop_ident.apply(self).set(value)
|
||||
}
|
||||
)
|
||||
.into(),
|
||||
|
@ -402,10 +402,16 @@ fn access_member(
|
|||
let name_ident = quote::format_ident!("{}", name);
|
||||
let comp = quote!(#context.get_component::<#component_id>().unwrap());
|
||||
if e.property_declarations.contains_key(name) {
|
||||
(quote!(#comp.#name_ident), context)
|
||||
(quote!(#component_id::field_offsets().#name_ident.apply_pin(#comp)), context)
|
||||
} else {
|
||||
let elem_ident = quote::format_ident!("{}", e.id);
|
||||
(quote!(#comp.#elem_ident.#name_ident), context)
|
||||
let elem_ty = quote::format_ident!("{}", e.base_type.as_builtin().class_name);
|
||||
(
|
||||
quote!((#component_id::field_offsets().#elem_ident + #elem_ty::field_offsets().#name_ident)
|
||||
.apply_pin(#comp)
|
||||
),
|
||||
context,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
access_member(element, name, &enclosing_component, quote!(#context.parent_context.unwrap()))
|
||||
|
@ -438,14 +444,16 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
|
|||
}
|
||||
Expression::RepeaterIndexReference { element } => {
|
||||
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
||||
quote!({ _self.index.get(context) })
|
||||
let component_id = component_id(&component);
|
||||
quote!({ #component_id::field_offsets().index.apply_pin(_self).get(context) })
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
}
|
||||
Expression::RepeaterModelReference { element } => {
|
||||
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
||||
quote!({ _self.model_data.get(context) })
|
||||
let component_id = component_id(&component);
|
||||
quote!({ #component_id::field_offsets().model_data.apply_pin(_self).get(context) })
|
||||
} else {
|
||||
todo!();
|
||||
}
|
||||
|
@ -554,6 +562,8 @@ fn compute_layout(component: &Component) -> TokenStream {
|
|||
let mut layouts = vec![];
|
||||
for x in component.layout_constraints.borrow().0.iter() {
|
||||
let within = quote::format_ident!("{}", x.within.borrow().id);
|
||||
let within_ty =
|
||||
quote::format_ident!("{}", x.within.borrow().base_type.as_builtin().class_name);
|
||||
let row_constraint = vec![quote!(Constraint::default()); x.row_count()];
|
||||
let col_constraint = vec![quote!(Constraint::default()); x.col_count()];
|
||||
let cells = x
|
||||
|
@ -594,8 +604,10 @@ fn compute_layout(component: &Component) -> TokenStream {
|
|||
solve_grid_layout(&GridLayoutData {
|
||||
row_constraint: Slice::from_slice(&[#(#row_constraint),*]),
|
||||
col_constraint: Slice::from_slice(&[#(#col_constraint),*]),
|
||||
width: self.#within.width.get(eval_context),
|
||||
height: self.#within.height.get(eval_context),
|
||||
width: (Self::field_offsets().#within + #within_ty::field_offsets().width)
|
||||
.apply_pin(self).get(eval_context),
|
||||
height: (Self::field_offsets().#within + #within_ty::field_offsets().height)
|
||||
.apply_pin(self).get(eval_context),
|
||||
x: 0.,
|
||||
y: 0.,
|
||||
cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]),
|
||||
|
|
|
@ -42,25 +42,27 @@ pub struct Rectangle {
|
|||
impl Item for Rectangle {
|
||||
fn geometry(self: Pin<&Self>, context: &EvaluationContext) -> Rect {
|
||||
euclid::rect(
|
||||
self.x.get(context),
|
||||
self.y.get(context),
|
||||
self.width.get(context),
|
||||
self.height.get(context),
|
||||
Self::field_offsets().x.apply_pin(self).get(context),
|
||||
Self::field_offsets().y.apply_pin(self).get(context),
|
||||
Self::field_offsets().width.apply_pin(self).get(context),
|
||||
Self::field_offsets().height.apply_pin(self).get(context),
|
||||
)
|
||||
}
|
||||
fn rendering_primitive(
|
||||
self: Pin<&Self>,
|
||||
context: &crate::EvaluationContext,
|
||||
) -> RenderingPrimitive {
|
||||
let width = self.width.get(context);
|
||||
let height = self.height.get(context);
|
||||
let width = Self::field_offsets().x.apply_pin(self).get(context);
|
||||
let height = Self::field_offsets().height.apply_pin(self).get(context);
|
||||
if width > 0. && height > 0. {
|
||||
RenderingPrimitive::Rectangle {
|
||||
x: self.x.get(context),
|
||||
y: self.y.get(context),
|
||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
||||
width,
|
||||
height,
|
||||
color: Color::from_argb_encoded(self.color.get(context)),
|
||||
color: Color::from_argb_encoded(
|
||||
Self::field_offsets().color.apply_pin(self).get(context),
|
||||
),
|
||||
}
|
||||
} else {
|
||||
RenderingPrimitive::NoContents
|
||||
|
@ -104,10 +106,10 @@ pub struct Image {
|
|||
impl Item for Image {
|
||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
||||
euclid::rect(
|
||||
self.x.get(context),
|
||||
self.y.get(context),
|
||||
self.width.get(context),
|
||||
self.height.get(context),
|
||||
Self::field_offsets().x.apply_pin(self).get(context),
|
||||
Self::field_offsets().y.apply_pin(self).get(context),
|
||||
Self::field_offsets().width.apply_pin(self).get(context),
|
||||
Self::field_offsets().height.apply_pin(self).get(context),
|
||||
)
|
||||
}
|
||||
fn rendering_primitive(
|
||||
|
@ -115,9 +117,9 @@ impl Item for Image {
|
|||
context: &crate::EvaluationContext,
|
||||
) -> RenderingPrimitive {
|
||||
RenderingPrimitive::Image {
|
||||
x: self.x.get(context),
|
||||
y: self.y.get(context),
|
||||
source: self.source.get(context),
|
||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
||||
source: Self::field_offsets().source.apply_pin(self).get(context),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,19 +162,26 @@ pub struct Text {
|
|||
impl Item for Text {
|
||||
// FIXME: width / height. or maybe it doesn't matter? (
|
||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
||||
euclid::rect(self.x.get(context), self.y.get(context), 0., 0.)
|
||||
euclid::rect(
|
||||
Self::field_offsets().x.apply_pin(self).get(context),
|
||||
Self::field_offsets().y.apply_pin(self).get(context),
|
||||
0.,
|
||||
0.,
|
||||
)
|
||||
}
|
||||
fn rendering_primitive(
|
||||
self: Pin<&Self>,
|
||||
context: &crate::EvaluationContext,
|
||||
) -> RenderingPrimitive {
|
||||
RenderingPrimitive::Text {
|
||||
x: self.x.get(context),
|
||||
y: self.y.get(context),
|
||||
text: self.text.get(context),
|
||||
font_family: self.font_family.get(context),
|
||||
font_pixel_size: self.font_pixel_size.get(context),
|
||||
color: Color::from_argb_encoded(self.color.get(context)),
|
||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
||||
text: Self::field_offsets().text.apply_pin(self).get(context),
|
||||
font_family: Self::field_offsets().font_family.apply_pin(self).get(context),
|
||||
font_pixel_size: Self::field_offsets().font_pixel_size.apply_pin(self).get(context),
|
||||
color: Color::from_argb_encoded(
|
||||
Self::field_offsets().color.apply_pin(self).get(context),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -214,10 +223,10 @@ pub struct TouchArea {
|
|||
impl Item for TouchArea {
|
||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
||||
euclid::rect(
|
||||
self.x.get(context),
|
||||
self.y.get(context),
|
||||
self.width.get(context),
|
||||
self.height.get(context),
|
||||
Self::field_offsets().x.apply_pin(self).get(context),
|
||||
Self::field_offsets().y.apply_pin(self).get(context),
|
||||
Self::field_offsets().width.apply_pin(self).get(context),
|
||||
Self::field_offsets().height.apply_pin(self).get(context),
|
||||
)
|
||||
}
|
||||
fn rendering_primitive(
|
||||
|
@ -237,13 +246,13 @@ impl Item for TouchArea {
|
|||
context: &crate::EvaluationContext,
|
||||
) {
|
||||
println!("Touch Area Event {:?}", event);
|
||||
self.pressed.set(match event.what {
|
||||
Self::field_offsets().pressed.apply_pin(self).set(match event.what {
|
||||
super::datastructures::MouseEventType::MousePressed => true,
|
||||
super::datastructures::MouseEventType::MouseReleased => false,
|
||||
super::datastructures::MouseEventType::MouseMoved => return,
|
||||
});
|
||||
if matches!(event.what, super::datastructures::MouseEventType::MouseReleased) {
|
||||
self.clicked.emit(context, ())
|
||||
Self::field_offsets().clicked.apply_pin(self).emit(context, ())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ use crate::abi::primitives::PropertyAnimation;
|
|||
use crate::ComponentRefPin;
|
||||
use core::cell::*;
|
||||
use core::ops::DerefMut;
|
||||
use core::pin::Pin;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
thread_local!(static CURRENT_BINDING : RefCell<Option<Rc<dyn PropertyNotify>>> = Default::default());
|
||||
|
@ -178,7 +179,7 @@ impl<T: Clone + 'static> Property<T> {
|
|||
///
|
||||
/// The context must be the constext matching the Component which contains this
|
||||
/// property
|
||||
pub fn get(&self, context: &EvaluationContext) -> T {
|
||||
pub fn get(self: Pin<&Self>, context: &EvaluationContext) -> T {
|
||||
self.update(context);
|
||||
self.inner.clone().register_current_binding_as_dependency();
|
||||
self.try_borrow().expect("Binding loop detected").1.clone()
|
||||
|
@ -303,6 +304,10 @@ impl<T: Clone + InterpolatedPropertyValue + 'static> Property<T> {
|
|||
|
||||
#[test]
|
||||
fn properties_simple_test() {
|
||||
fn g(prop: &Property<i32>, ctx: &EvaluationContext) -> i32 {
|
||||
unsafe { Pin::new_unchecked(prop).get(ctx) }
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct Component {
|
||||
width: Property<i32>,
|
||||
|
@ -319,22 +324,22 @@ fn properties_simple_test() {
|
|||
let w = Rc::downgrade(&compo);
|
||||
compo.area.set_binding(move |ctx| {
|
||||
let compo = w.upgrade().unwrap();
|
||||
compo.width.get(ctx) * compo.height.get(ctx)
|
||||
g(&compo.width, ctx) * g(&compo.height, ctx)
|
||||
});
|
||||
compo.width.set(4);
|
||||
compo.height.set(8);
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 4);
|
||||
assert_eq!(compo.height.get(&dummy_eval_context), 8);
|
||||
assert_eq!(compo.area.get(&dummy_eval_context), 4 * 8);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 4);
|
||||
assert_eq!(g(&compo.height, &dummy_eval_context), 8);
|
||||
assert_eq!(g(&compo.area, &dummy_eval_context), 4 * 8);
|
||||
|
||||
let w = Rc::downgrade(&compo);
|
||||
compo.width.set_binding(move |ctx| {
|
||||
let compo = w.upgrade().unwrap();
|
||||
compo.height.get(ctx) * 2
|
||||
g(&compo.height, ctx) * 2
|
||||
});
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 8 * 2);
|
||||
assert_eq!(compo.height.get(&dummy_eval_context), 8);
|
||||
assert_eq!(compo.area.get(&dummy_eval_context), 8 * 8 * 2);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 8 * 2);
|
||||
assert_eq!(g(&compo.height, &dummy_eval_context), 8);
|
||||
assert_eq!(g(&compo.area, &dummy_eval_context), 8 * 8 * 2);
|
||||
}
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
|
@ -724,6 +729,9 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn properties_test_animation_triggered_by_set() {
|
||||
fn g(prop: &Property<i32>, ctx: &EvaluationContext) -> i32 {
|
||||
unsafe { Pin::new_unchecked(prop).get(ctx) }
|
||||
}
|
||||
let dummy_eval_context = EvaluationContext {
|
||||
component: unsafe {
|
||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
||||
|
@ -738,38 +746,41 @@ mod test {
|
|||
let w = Rc::downgrade(&compo);
|
||||
compo.width_times_two.set_binding(move |context| {
|
||||
let compo = w.upgrade().unwrap();
|
||||
compo.width.get(context) * 2
|
||||
g(&compo.width, context) * 2
|
||||
});
|
||||
|
||||
let animation_details = PropertyAnimation { duration: 10000 };
|
||||
|
||||
compo.width.set(100);
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 100);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
||||
|
||||
let animation = compo.width.set_animated_value(200, &animation_details);
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 100);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
||||
assert_eq!(animation.borrow().from_value, 100);
|
||||
assert_eq!(animation.borrow().to_value, 200);
|
||||
|
||||
animation.clone().update_animation_state(AnimationState::Running { progress: 0.5 });
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 150);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 300);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 150);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300);
|
||||
|
||||
animation.clone().update_animation_state(AnimationState::Running { progress: 1.0 });
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 200);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 400);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400);
|
||||
|
||||
animation.clone().update_animation_state(AnimationState::Stopped);
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 200);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 400);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400);
|
||||
|
||||
assert_eq!(Rc::strong_count(&animation), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn properties_test_animation_triggered_by_binding() {
|
||||
fn g(prop: &Property<i32>, ctx: &EvaluationContext) -> i32 {
|
||||
unsafe { Pin::new_unchecked(prop).get(ctx) }
|
||||
}
|
||||
let dummy_eval_context = EvaluationContext {
|
||||
component: unsafe {
|
||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
||||
|
@ -784,7 +795,7 @@ mod test {
|
|||
let w = Rc::downgrade(&compo);
|
||||
compo.width_times_two.set_binding(move |context| {
|
||||
let compo = w.upgrade().unwrap();
|
||||
compo.width.get(context) * 2
|
||||
g(&compo.width, context) * 2
|
||||
});
|
||||
|
||||
let w = Rc::downgrade(&compo);
|
||||
|
@ -794,29 +805,29 @@ mod test {
|
|||
let animation = compo.width.set_animated_binding(
|
||||
move |context| {
|
||||
let compo = w.upgrade().unwrap();
|
||||
compo.feed_property.get(context)
|
||||
g(&compo.feed_property, context)
|
||||
},
|
||||
&animation_details,
|
||||
);
|
||||
|
||||
compo.feed_property.set(100);
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 100);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
||||
|
||||
compo.feed_property.set(200);
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 100);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
||||
|
||||
animation.clone().update_animation_state(AnimationState::Running { progress: 0.5 });
|
||||
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 150);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 300);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 150);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300);
|
||||
assert_eq!(animation.borrow().from_value, 100);
|
||||
assert_eq!(animation.borrow().to_value, 200);
|
||||
|
||||
animation.clone().update_animation_state(AnimationState::Running { progress: 1.0 });
|
||||
|
||||
assert_eq!(compo.width.get(&dummy_eval_context), 200);
|
||||
assert_eq!(compo.width_times_two.get(&dummy_eval_context), 400);
|
||||
assert_eq!(g(&compo.width, &dummy_eval_context), 200);
|
||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue