mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-28 04:45:13 +00:00
Two ways binding with optimized public property in the interpreter
This commit is contained in:
parent
b5d7adef7d
commit
0cb827a901
5 changed files with 104 additions and 34 deletions
|
@ -746,7 +746,7 @@ pub unsafe extern "C" fn sixtyfps_flickable_data_free(data: *mut FlickableDataBo
|
||||||
|
|
||||||
/// The implementation of the `PropertyAnimation` element
|
/// The implementation of the `PropertyAnimation` element
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(FieldOffsets, Default, BuiltinItem, Clone)]
|
#[derive(FieldOffsets, Default, BuiltinItem, Clone, Debug)]
|
||||||
#[pin]
|
#[pin]
|
||||||
pub struct PropertyAnimation {
|
pub struct PropertyAnimation {
|
||||||
#[rtti_field]
|
#[rtti_field]
|
||||||
|
|
|
@ -512,6 +512,9 @@ fn generate_component<'id>(
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, decl) in &root_component.root_element.borrow().property_declarations {
|
for (name, decl) in &root_component.root_element.borrow().property_declarations {
|
||||||
|
if decl.is_alias.is_some() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
let (prop, type_info) = match decl.property_type {
|
let (prop, type_info) = match decl.property_type {
|
||||||
Type::Float32 => animated_property_info::<f32>(),
|
Type::Float32 => animated_property_info::<f32>(),
|
||||||
Type::Int32 => animated_property_info::<i32>(),
|
Type::Int32 => animated_property_info::<i32>(),
|
||||||
|
|
|
@ -194,18 +194,20 @@ pub fn eval_expression(
|
||||||
"naked builtin function reference not allowed, should be handled by function call"
|
"naked builtin function reference not allowed, should be handled by function call"
|
||||||
),
|
),
|
||||||
Expression::PropertyReference(NamedReference { element, name }) => {
|
Expression::PropertyReference(NamedReference { element, name }) => {
|
||||||
load_property(component, &element.upgrade().unwrap(), name.as_ref())
|
load_property(component, &element.upgrade().unwrap(), name.as_ref()).unwrap()
|
||||||
}
|
}
|
||||||
Expression::RepeaterIndexReference { element } => load_property(
|
Expression::RepeaterIndexReference { element } => load_property(
|
||||||
component,
|
component,
|
||||||
&element.upgrade().unwrap().borrow().base_type.as_component().root_element,
|
&element.upgrade().unwrap().borrow().base_type.as_component().root_element,
|
||||||
"index",
|
"index",
|
||||||
),
|
)
|
||||||
|
.unwrap(),
|
||||||
Expression::RepeaterModelReference { element } => load_property(
|
Expression::RepeaterModelReference { element } => load_property(
|
||||||
component,
|
component,
|
||||||
&element.upgrade().unwrap().borrow().base_type.as_component().root_element,
|
&element.upgrade().unwrap().borrow().base_type.as_component().root_element,
|
||||||
"model_data",
|
"model_data",
|
||||||
),
|
)
|
||||||
|
.unwrap(),
|
||||||
Expression::FunctionParameterReference { index, .. } => {
|
Expression::FunctionParameterReference { index, .. } => {
|
||||||
local_context.function_arguments[*index].clone()
|
local_context.function_arguments[*index].clone()
|
||||||
}
|
}
|
||||||
|
@ -275,18 +277,19 @@ pub fn eval_expression(
|
||||||
}
|
}
|
||||||
Expression::SelfAssignment { lhs, rhs, op } => match &**lhs {
|
Expression::SelfAssignment { lhs, rhs, op } => match &**lhs {
|
||||||
Expression::PropertyReference(NamedReference { element, name }) => {
|
Expression::PropertyReference(NamedReference { element, name }) => {
|
||||||
let mut eval = |lhs| {
|
let rhs = eval_expression(&**rhs, component, local_context);
|
||||||
let rhs = eval_expression(&**rhs, component, local_context);
|
if *op == '=' {
|
||||||
match (lhs, rhs, op) {
|
store_property(component, &element.upgrade().unwrap(), name.as_ref(), rhs)
|
||||||
(_, rhs, '=') => rhs,
|
.unwrap();
|
||||||
(Value::Number(a), Value::Number(b), '+') => Value::Number(a + b),
|
return Value::Void;
|
||||||
(Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),
|
}
|
||||||
(Value::Number(a), Value::Number(b), '/') => Value::Number(a / b),
|
let eval = |lhs| match (lhs, rhs, op) {
|
||||||
(Value::Number(a), Value::Number(b), '*') => Value::Number(a * b),
|
(Value::Number(a), Value::Number(b), '+') => Value::Number(a + b),
|
||||||
(lhs, rhs, op) => panic!("unsupported {:?} {} {:?}", lhs, op, rhs),
|
(Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),
|
||||||
}
|
(Value::Number(a), Value::Number(b), '/') => Value::Number(a / b),
|
||||||
|
(Value::Number(a), Value::Number(b), '*') => Value::Number(a * b),
|
||||||
|
(lhs, rhs, op) => panic!("unsupported {:?} {} {:?}", lhs, op, rhs),
|
||||||
};
|
};
|
||||||
|
|
||||||
let element = element.upgrade().unwrap();
|
let element = element.upgrade().unwrap();
|
||||||
generativity::make_guard!(guard);
|
generativity::make_guard!(guard);
|
||||||
let enclosing_component =
|
let enclosing_component =
|
||||||
|
@ -386,16 +389,14 @@ pub fn eval_expression(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Value {
|
pub fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Result<Value, ()> {
|
||||||
generativity::make_guard!(guard);
|
generativity::make_guard!(guard);
|
||||||
let enclosing_component = enclosing_component_for_element(&element, component, guard);
|
let enclosing_component = enclosing_component_for_element(&element, component, guard);
|
||||||
let element = element.borrow();
|
let element = element.borrow();
|
||||||
if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id {
|
if element.id == element.enclosing_component.upgrade().unwrap().root_element.borrow().id {
|
||||||
if let Some(x) = enclosing_component.component_type.custom_properties.get(name) {
|
if let Some(x) = enclosing_component.component_type.custom_properties.get(name) {
|
||||||
return unsafe {
|
return unsafe {
|
||||||
x.prop
|
x.prop.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))
|
||||||
.get(Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset)))
|
|
||||||
.unwrap()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -406,7 +407,37 @@ fn load_property(component: InstanceRef, element: &ElementRc, name: &str) -> Val
|
||||||
.unwrap_or_else(|| panic!("Unkown element for {}.{}", element.id, name));
|
.unwrap_or_else(|| panic!("Unkown element for {}.{}", element.id, name));
|
||||||
core::mem::drop(element);
|
core::mem::drop(element);
|
||||||
let item = unsafe { item_info.item_from_component(enclosing_component.as_ptr()) };
|
let item = unsafe { item_info.item_from_component(enclosing_component.as_ptr()) };
|
||||||
item_info.rtti.properties[name].get(item)
|
Ok(item_info.rtti.properties.get(name).ok_or(())?.get(item))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn store_property(
|
||||||
|
component_instance: InstanceRef,
|
||||||
|
element: &ElementRc,
|
||||||
|
name: &str,
|
||||||
|
value: Value,
|
||||||
|
) -> Result<(), ()> {
|
||||||
|
generativity::make_guard!(guard);
|
||||||
|
let enclosing_component = enclosing_component_for_element(&element, component_instance, guard);
|
||||||
|
let maybe_animation = crate::dynamic_component::animation_for_property(
|
||||||
|
enclosing_component,
|
||||||
|
&element.borrow().property_animations,
|
||||||
|
name,
|
||||||
|
);
|
||||||
|
|
||||||
|
let component = element.borrow().enclosing_component.upgrade().unwrap();
|
||||||
|
if element.borrow().id == component.root_element.borrow().id {
|
||||||
|
if let Some(x) = enclosing_component.component_type.custom_properties.get(name) {
|
||||||
|
unsafe {
|
||||||
|
let p = Pin::new_unchecked(&*enclosing_component.as_ptr().add(x.offset));
|
||||||
|
return x.prop.set(p, value, maybe_animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let item_info = &enclosing_component.component_type.items[element.borrow().id.as_str()];
|
||||||
|
let item = unsafe { item_info.item_from_component(enclosing_component.as_ptr()) };
|
||||||
|
let p = &item_info.rtti.properties.get(name).ok_or(())?;
|
||||||
|
p.set(item, value, maybe_animation);
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn window_ref(component: InstanceRef) -> Option<sixtyfps_corelib::eventloop::ComponentWindow> {
|
pub fn window_ref(component: InstanceRef) -> Option<sixtyfps_corelib::eventloop::ComponentWindow> {
|
||||||
|
|
|
@ -68,19 +68,19 @@ impl<'id> dynamic_component::ComponentDescription<'id> {
|
||||||
if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {
|
if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
let x = self.custom_properties.get(name).ok_or(())?;
|
|
||||||
generativity::make_guard!(guard);
|
generativity::make_guard!(guard);
|
||||||
let maybe_animation = dynamic_component::animation_for_property(
|
let c = unsafe { InstanceRef::from_pin_ref(component, guard) };
|
||||||
unsafe { InstanceRef::from_pin_ref(component, guard) },
|
if let Some(alias) = self
|
||||||
&self.original.root_element.borrow().property_animations,
|
.original
|
||||||
name,
|
.root_element
|
||||||
);
|
.borrow()
|
||||||
unsafe {
|
.property_declarations
|
||||||
x.prop.set(
|
.get(name)
|
||||||
Pin::new_unchecked(&*component.as_ptr().add(x.offset)),
|
.and_then(|d| d.is_alias.as_ref())
|
||||||
value,
|
{
|
||||||
maybe_animation,
|
eval::store_property(c, &alias.element.upgrade().unwrap(), &alias.name, value)
|
||||||
)
|
} else {
|
||||||
|
eval::store_property(c, &self.original.root_element, name, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -114,8 +114,21 @@ impl<'id> dynamic_component::ComponentDescription<'id> {
|
||||||
if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {
|
if !core::ptr::eq((&self.ct) as *const _, component.get_vtable() as *const _) {
|
||||||
return Err(());
|
return Err(());
|
||||||
}
|
}
|
||||||
let x = self.custom_properties.get(name).ok_or(())?;
|
if let Some(alias) = self
|
||||||
unsafe { x.prop.get(Pin::new_unchecked(&*component.as_ptr().add(x.offset))) }
|
.original
|
||||||
|
.root_element
|
||||||
|
.borrow()
|
||||||
|
.property_declarations
|
||||||
|
.get(name)
|
||||||
|
.and_then(|d| d.is_alias.as_ref())
|
||||||
|
{
|
||||||
|
generativity::make_guard!(guard);
|
||||||
|
let c = unsafe { InstanceRef::from_pin_ref(component, guard) };
|
||||||
|
eval::load_property(c, &alias.element.upgrade().unwrap(), &alias.name)
|
||||||
|
} else {
|
||||||
|
let x = self.custom_properties.get(name).ok_or(())?;
|
||||||
|
unsafe { x.prop.get(Pin::new_unchecked(&*component.as_ptr().add(x.offset))) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets an handler for a signal
|
/// Sets an handler for a signal
|
||||||
|
|
|
@ -76,5 +76,28 @@ assert_eq(instance.get_sub_foo1(), 15);
|
||||||
assert_eq(instance.get_sub_foo2(), 15);
|
assert_eq(instance.get_sub_foo2(), 15);
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```js
|
||||||
|
var instance = new sixtyfps.TestCase({});
|
||||||
|
assert.equal(instance.sub_width1, 80.);
|
||||||
|
assert.equal(instance.sub_width2, 80.);
|
||||||
|
instance.sub_width1 = (99.);
|
||||||
|
assert.equal(instance.sub_width1, 99.);
|
||||||
|
assert.equal(instance.sub_width2, 99.);
|
||||||
|
|
||||||
|
// breaks the binding
|
||||||
|
instance.sub_width2 = (23.);
|
||||||
|
assert.equal(instance.sub_width1, 99.);
|
||||||
|
assert.equal(instance.sub_width2, 23.);
|
||||||
|
instance.sub_width1 = (88.);
|
||||||
|
assert.equal(instance.sub_width1, 88.);
|
||||||
|
assert.equal(instance.sub_width2, 23.);
|
||||||
|
|
||||||
|
|
||||||
|
assert.equal(instance.sub_foo1, 44);
|
||||||
|
assert.equal(instance.sub_foo2, 44);
|
||||||
|
instance.sub_foo1 = (15);
|
||||||
|
assert.equal(instance.sub_foo1, 15);
|
||||||
|
assert.equal(instance.sub_foo2, 15);
|
||||||
|
```
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue