mirror of
https://github.com/slint-ui/slint.git
synced 2025-09-29 13:24:48 +00:00
Get rid of the context in properties/signal
This commit is contained in:
parent
ab7ae9f3e2
commit
e00491811b
25 changed files with 389 additions and 653 deletions
|
@ -46,7 +46,6 @@ private:
|
||||||
internal::ComponentWindowOpaque inner;
|
internal::ComponentWindowOpaque inner;
|
||||||
};
|
};
|
||||||
|
|
||||||
using internal::EvaluationContext;
|
|
||||||
using internal::Image;
|
using internal::Image;
|
||||||
using internal::Path;
|
using internal::Path;
|
||||||
using internal::Rectangle;
|
using internal::Rectangle;
|
||||||
|
@ -69,14 +68,6 @@ 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>
|
|
||||||
EvaluationContext evaluation_context_for_root_component(const Component *component) {
|
|
||||||
return EvaluationContext{
|
|
||||||
VRef<ComponentVTable> { &Component::component_type, const_cast<Component *>(component)},
|
|
||||||
nullptr,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// layouts:
|
// layouts:
|
||||||
using internal::Constraint;
|
using internal::Constraint;
|
||||||
using internal::GridLayoutCellData;
|
using internal::GridLayoutCellData;
|
||||||
|
|
|
@ -45,8 +45,8 @@ void Property<Color>::set_animated_binding(F binding,
|
||||||
{
|
{
|
||||||
internal::sixtyfps_property_set_animated_binding_color(
|
internal::sixtyfps_property_set_animated_binding_color(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, const internal::EvaluationContext *context, Color *value) {
|
[](void *user_data, Color *value) {
|
||||||
*reinterpret_cast<Color *>(value) = (*reinterpret_cast<F *>(user_data))(context);
|
*reinterpret_cast<Color *>(value) = (*reinterpret_cast<F *>(user_data))();
|
||||||
},
|
},
|
||||||
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
|
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
|
||||||
&animation_data);
|
&animation_data);
|
||||||
|
|
|
@ -31,9 +31,9 @@ struct Property
|
||||||
internal::sixtyfps_property_set_changed(&inner);
|
internal::sixtyfps_property_set_changed(&inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
const T &get(const internal::EvaluationContext *context) const
|
const T &get() const
|
||||||
{
|
{
|
||||||
internal::sixtyfps_property_update(&inner, context, &value);
|
internal::sixtyfps_property_update(&inner, &value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,8 +42,8 @@ struct Property
|
||||||
{
|
{
|
||||||
internal::sixtyfps_property_set_binding(
|
internal::sixtyfps_property_set_binding(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, const internal::EvaluationContext *context, void *value) {
|
[](void *user_data, void *value) {
|
||||||
*reinterpret_cast<T *>(value) = (*reinterpret_cast<F *>(user_data))(context);
|
*reinterpret_cast<T *>(value) = (*reinterpret_cast<F *>(user_data))();
|
||||||
},
|
},
|
||||||
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });
|
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });
|
||||||
}
|
}
|
||||||
|
@ -79,8 +79,8 @@ void Property<int32_t>::set_animated_binding(F binding,
|
||||||
{
|
{
|
||||||
internal::sixtyfps_property_set_animated_binding_int(
|
internal::sixtyfps_property_set_animated_binding_int(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, const internal::EvaluationContext *context, int32_t *value) {
|
[](void *user_data, int32_t *value) {
|
||||||
*reinterpret_cast<int32_t *>(value) = (*reinterpret_cast<F *>(user_data))(context);
|
*reinterpret_cast<int32_t *>(value) = (*reinterpret_cast<F *>(user_data))();
|
||||||
},
|
},
|
||||||
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
|
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
|
||||||
&animation_data);
|
&animation_data);
|
||||||
|
@ -93,8 +93,8 @@ void Property<float>::set_animated_binding(F binding,
|
||||||
{
|
{
|
||||||
internal::sixtyfps_property_set_animated_binding_float(
|
internal::sixtyfps_property_set_animated_binding_float(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, const internal::EvaluationContext *context, float *value) {
|
[](void *user_data, float *value) {
|
||||||
*reinterpret_cast<float *>(value) = (*reinterpret_cast<F *>(user_data))(context);
|
*reinterpret_cast<float *>(value) = (*reinterpret_cast<F *>(user_data))();
|
||||||
},
|
},
|
||||||
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
|
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); },
|
||||||
&animation_data);
|
&animation_data);
|
||||||
|
|
|
@ -18,15 +18,15 @@ struct Signal
|
||||||
{
|
{
|
||||||
internal::sixtyfps_signal_set_handler(
|
internal::sixtyfps_signal_set_handler(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, const internal::EvaluationContext *value) {
|
[](void *user_data) {
|
||||||
(*reinterpret_cast<F *>(user_data))(value);
|
(*reinterpret_cast<F *>(user_data))();
|
||||||
},
|
},
|
||||||
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });
|
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });
|
||||||
}
|
}
|
||||||
|
|
||||||
void emit(const internal::EvaluationContext *context) const
|
void emit() const
|
||||||
{
|
{
|
||||||
internal::sixtyfps_signal_emit(&inner, context);
|
internal::sixtyfps_signal_emit(&inner);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
|
@ -2,7 +2,7 @@ use core::cell::RefCell;
|
||||||
use neon::prelude::*;
|
use neon::prelude::*;
|
||||||
use sixtyfps_compilerlib::typeregister::Type;
|
use sixtyfps_compilerlib::typeregister::Type;
|
||||||
use sixtyfps_corelib::abi::datastructures::Resource;
|
use sixtyfps_corelib::abi::datastructures::Resource;
|
||||||
use sixtyfps_corelib::{ComponentRefPin, EvaluationContext};
|
use sixtyfps_corelib::ComponentRefPin;
|
||||||
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ fn create<'cx>(
|
||||||
.set_signal_handler(
|
.set_signal_handler(
|
||||||
component.borrow_mut(),
|
component.borrow_mut(),
|
||||||
prop_name.as_str(),
|
prop_name.as_str(),
|
||||||
Box::new(move |_eval_ctx, ()| {
|
Box::new(move |()| {
|
||||||
GLOBAL_CONTEXT.with(|cx_fn| {
|
GLOBAL_CONTEXT.with(|cx_fn| {
|
||||||
cx_fn(&move |cx, presistent_context| {
|
cx_fn(&move |cx, presistent_context| {
|
||||||
presistent_context
|
presistent_context
|
||||||
|
@ -243,7 +243,7 @@ declare_types! {
|
||||||
let x = this.borrow(&lock).0.clone();
|
let x = this.borrow(&lock).0.clone();
|
||||||
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
let value = component.description()
|
let value = component.description()
|
||||||
.get_property(&EvaluationContext::for_root_component(component.borrow()), prop_name.as_str())
|
.get_property(component.borrow(), prop_name.as_str())
|
||||||
.or_else(|_| cx.throw_error(format!("Cannot read property")))?;
|
.or_else(|_| cx.throw_error(format!("Cannot read property")))?;
|
||||||
to_js_value(value, &mut cx)
|
to_js_value(value, &mut cx)
|
||||||
}
|
}
|
||||||
|
@ -275,7 +275,7 @@ declare_types! {
|
||||||
let x = this.borrow(&lock).0.clone();
|
let x = this.borrow(&lock).0.clone();
|
||||||
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
let component = x.ok_or(()).or_else(|()| cx.throw_error("Invalid type"))?;
|
||||||
component.description()
|
component.description()
|
||||||
.emit_signal(&EvaluationContext::for_root_component(component.borrow()), signal_name.as_str())
|
.emit_signal(component.borrow(), signal_name.as_str())
|
||||||
.or_else(|_| cx.throw_error(format!("Cannot emit signal")))?;
|
.or_else(|_| cx.throw_error(format!("Cannot emit signal")))?;
|
||||||
|
|
||||||
Ok(JsUndefined::new().as_value(&mut cx))
|
Ok(JsUndefined::new().as_value(&mut cx))
|
||||||
|
|
|
@ -86,7 +86,6 @@ pub mod re_exports {
|
||||||
};
|
};
|
||||||
pub use sixtyfps_corelib::Color;
|
pub use sixtyfps_corelib::Color;
|
||||||
pub use sixtyfps_corelib::ComponentVTable_static;
|
pub use sixtyfps_corelib::ComponentVTable_static;
|
||||||
pub use sixtyfps_corelib::EvaluationContext;
|
|
||||||
pub use sixtyfps_corelib::Resource;
|
pub use sixtyfps_corelib::Resource;
|
||||||
pub use sixtyfps_corelib::SharedArray;
|
pub use sixtyfps_corelib::SharedArray;
|
||||||
pub use sixtyfps_corelib::SharedString;
|
pub use sixtyfps_corelib::SharedString;
|
||||||
|
|
|
@ -7,14 +7,14 @@ int main()
|
||||||
|
|
||||||
component.foobar.set_handler([](auto...) { std::cout << "Hello from C++" << std::endl; });
|
component.foobar.set_handler([](auto...) { std::cout << "Hello from C++" << std::endl; });
|
||||||
|
|
||||||
component.plus_clicked.set_handler([](auto ctx) {
|
component.plus_clicked.set_handler([]() {
|
||||||
auto &counter = component.counter;
|
auto &counter = component.counter;
|
||||||
counter.set(counter.get(ctx) + 1);
|
counter.set(counter.get() + 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
component.minus_clicked.set_handler([](auto ctx) {
|
component.minus_clicked.set_handler([]() {
|
||||||
auto &counter = component.counter;
|
auto &counter = component.counter;
|
||||||
counter.set(counter.get(ctx) - 1);
|
counter.set(counter.get() - 1);
|
||||||
});
|
});
|
||||||
|
|
||||||
sixtyfps::ComponentWindow window;
|
sixtyfps::ComponentWindow window;
|
||||||
|
|
|
@ -128,15 +128,17 @@ Hello := Rectangle {
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = Hello::new();
|
let app = Hello::new();
|
||||||
app.plus_clicked.set_handler(|context, ()| {
|
let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone());
|
||||||
let app = context.get_component::<Hello>().unwrap();
|
app.plus_clicked.set_handler(move |()| {
|
||||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
let app = app_weak.upgrade().unwrap();
|
||||||
counter.set(counter.get(context) + 1);
|
let counter = Hello::field_offsets().counter.apply_pin(app.as_ref());
|
||||||
|
counter.set(counter.get() + 1);
|
||||||
});
|
});
|
||||||
app.minus_clicked.set_handler(|context, ()| {
|
let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone());
|
||||||
let app = context.get_component::<Hello>().unwrap();
|
app.minus_clicked.set_handler(move |()| {
|
||||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
let app = app_weak.upgrade().unwrap();
|
||||||
counter.set(counter.get(context) - 1);
|
let counter = Hello::field_offsets().counter.apply_pin(app.as_ref());
|
||||||
|
counter.set(counter.get() - 1);
|
||||||
});
|
});
|
||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,16 +4,17 @@ sixtyfps::include_modules!();
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let app = Hello::new();
|
let app = Hello::new();
|
||||||
|
let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone());
|
||||||
app.plus_clicked.set_handler(|context, ()| {
|
app.plus_clicked.set_handler(move |()| {
|
||||||
let app = context.get_component::<Hello>().unwrap();
|
let app = app_weak.upgrade().unwrap();
|
||||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
let counter = Hello::field_offsets().counter.apply_pin(app.as_ref());
|
||||||
counter.set(counter.get(context) + 1);
|
counter.set(counter.get() + 1);
|
||||||
});
|
});
|
||||||
app.minus_clicked.set_handler(|context, ()| {
|
let app_weak = sixtyfps::re_exports::WeakPin::downgrade(app.clone());
|
||||||
let app = context.get_component::<Hello>().unwrap();
|
app.minus_clicked.set_handler(move |()| {
|
||||||
let counter = Hello::field_offsets().counter.apply_pin(app);
|
let app = app_weak.upgrade().unwrap();
|
||||||
counter.set(counter.get(context) - 1);
|
let counter = Hello::field_offsets().counter.apply_pin(app.as_ref());
|
||||||
|
counter.set(counter.get() - 1);
|
||||||
});
|
});
|
||||||
app.run();
|
app.run();
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,13 +247,12 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec<String>)
|
||||||
|
|
||||||
format!(
|
format!(
|
||||||
"{signal_accessor_prefix}{prop}.set_handler(
|
"{signal_accessor_prefix}{prop}.set_handler(
|
||||||
[]([[maybe_unused]] const sixtyfps::EvaluationContext *context) {{
|
[this]() {{
|
||||||
[[maybe_unused]] auto self = reinterpret_cast<const {ty}*>(context->component.instance);
|
[[maybe_unused]] auto self = this;
|
||||||
{code};
|
{code};
|
||||||
}});",
|
}});",
|
||||||
signal_accessor_prefix = signal_accessor_prefix,
|
signal_accessor_prefix = signal_accessor_prefix,
|
||||||
prop = s,
|
prop = s,
|
||||||
ty = main_struct.name,
|
|
||||||
code = compile_expression(i, &item.enclosing_component.upgrade().unwrap())
|
code = compile_expression(i, &item.enclosing_component.upgrade().unwrap())
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
@ -267,7 +266,7 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec<String>)
|
||||||
|
|
||||||
let init = compile_expression(i, component);
|
let init = compile_expression(i, component);
|
||||||
if i.is_constant() {
|
if i.is_constant() {
|
||||||
let setter = property_set_value_code(&component, item, s, init);
|
let setter = property_set_value_code(&component, item, s, init);
|
||||||
format!(
|
format!(
|
||||||
"{accessor_prefix}{cpp_prop}.{setter};",
|
"{accessor_prefix}{cpp_prop}.{setter};",
|
||||||
accessor_prefix = accessor_prefix,
|
accessor_prefix = accessor_prefix,
|
||||||
|
@ -276,11 +275,10 @@ fn handle_item(item: &Element, main_struct: &mut Struct, init: &mut Vec<String>)
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
let binding_code = format!(
|
let binding_code = format!(
|
||||||
"[]([[maybe_unused]] const sixtyfps::EvaluationContext *context) {{
|
"[this]() {{
|
||||||
[[maybe_unused]] auto self = reinterpret_cast<const {ty}*>(context->component.instance);
|
[[maybe_unused]] auto self = this;
|
||||||
return {init};
|
return {init};
|
||||||
}}",
|
}}",
|
||||||
ty = main_struct.name,
|
|
||||||
init = init
|
init = init
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -385,10 +383,7 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
for (cpp_name, property_decl) in component.root_element.borrow().property_declarations.iter() {
|
for (cpp_name, property_decl) in component.root_element.borrow().property_declarations.iter() {
|
||||||
let ty = if property_decl.property_type == Type::Signal {
|
let ty = if property_decl.property_type == Type::Signal {
|
||||||
if property_decl.expose_in_public_api && is_root {
|
if property_decl.expose_in_public_api && is_root {
|
||||||
let signal_emitter: Vec<String> = vec![
|
let signal_emitter: Vec<String> = vec![format!("{}.emit();", cpp_name)];
|
||||||
"[[maybe_unused]] auto context = sixtyfps::evaluation_context_for_root_component(this);".into(),
|
|
||||||
format!("{}.emit(&context);", cpp_name)
|
|
||||||
];
|
|
||||||
|
|
||||||
component_struct.members.push(Declaration::Function(Function {
|
component_struct.members.push(Declaration::Function(Function {
|
||||||
name: format!("emit_{}", cpp_name),
|
name: format!("emit_{}", cpp_name),
|
||||||
|
@ -411,10 +406,7 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
});
|
});
|
||||||
|
|
||||||
if property_decl.expose_in_public_api && is_root {
|
if property_decl.expose_in_public_api && is_root {
|
||||||
let prop_getter: Vec<String> = vec![
|
let prop_getter: Vec<String> = vec![format!("return {}.get();", cpp_name)];
|
||||||
"[[maybe_unused]] auto context = sixtyfps::evaluation_context_for_root_component(this);".into(),
|
|
||||||
format!("return {}.get(&context);", cpp_name)
|
|
||||||
];
|
|
||||||
|
|
||||||
component_struct.members.push(Declaration::Function(Function {
|
component_struct.members.push(Declaration::Function(Function {
|
||||||
name: format!("get_{}", cpp_name),
|
name: format!("get_{}", cpp_name),
|
||||||
|
@ -567,9 +559,7 @@ 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: "compute_layout".into(),
|
name: "compute_layout".into(),
|
||||||
signature:
|
signature: "(sixtyfps::ComponentRef component) -> void".into(),
|
||||||
"(sixtyfps::ComponentRef component, [[maybe_unused]] const sixtyfps::EvaluationContext *context) -> void"
|
|
||||||
.into(),
|
|
||||||
is_static: true,
|
is_static: true,
|
||||||
statements: Some(compute_layout(component)),
|
statements: Some(compute_layout(component)),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
|
@ -601,8 +591,6 @@ fn generate_component(file: &mut File, component: &Rc<Component>, diag: &mut Dia
|
||||||
"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),
|
||||||
// Fixme: this is not the root component
|
// Fixme: this is not the root component
|
||||||
"auto context_ = sixtyfps::evaluation_context_for_root_component(self);".into(),
|
|
||||||
"[[maybe_unused]] auto context = &context_;".into(),
|
|
||||||
format!(" switch(dyn_index) {{ {} }}\n }};", children_visitor_case.join("")),
|
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(),
|
||||||
]),
|
]),
|
||||||
|
@ -627,28 +615,27 @@ fn component_id(component: &Rc<Component>) -> String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the code that can access the given property or signal from the context (but without the set or get)
|
/// Returns the code that can access the given property (but without the set or get)
|
||||||
///
|
///
|
||||||
/// to be used like:
|
/// to be used like:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// let (access, context) = access_member(...)
|
/// let access = access_member(...);
|
||||||
/// format!("context.{access}.get({context})", ...)
|
/// format!("{}.get()", access)
|
||||||
/// ```
|
/// ```
|
||||||
fn access_member(
|
fn access_member(
|
||||||
element: &ElementRc,
|
element: &ElementRc,
|
||||||
name: &str,
|
name: &str,
|
||||||
component: &Rc<Component>,
|
component: &Rc<Component>,
|
||||||
context: &str,
|
|
||||||
component_cpp: &str,
|
component_cpp: &str,
|
||||||
) -> (String, String) {
|
) -> String {
|
||||||
let e = element.borrow();
|
let e = element.borrow();
|
||||||
let enclosing_component = e.enclosing_component.upgrade().unwrap();
|
let enclosing_component = e.enclosing_component.upgrade().unwrap();
|
||||||
if Rc::ptr_eq(component, &enclosing_component) {
|
if Rc::ptr_eq(component, &enclosing_component) {
|
||||||
let e = element.borrow();
|
let e = element.borrow();
|
||||||
if e.property_declarations.contains_key(name) {
|
if e.property_declarations.contains_key(name) {
|
||||||
(format!("{}->{}", component_cpp, name), context.into())
|
format!("{}->{}", component_cpp, name)
|
||||||
} else {
|
} else {
|
||||||
(format!("{}->{}.{}", component_cpp, e.id.as_str(), name), context.into())
|
format!("{}->{}.{}", component_cpp, e.id.as_str(), name)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
access_member(
|
access_member(
|
||||||
|
@ -662,7 +649,6 @@ fn access_member(
|
||||||
.enclosing_component
|
.enclosing_component
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
&format!("{}->parent_context", context),
|
|
||||||
&format!("{}->parent", component_cpp),
|
&format!("{}->parent", component_cpp),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -676,35 +662,25 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
|
||||||
NumberLiteral(n) => n.to_string(),
|
NumberLiteral(n) => n.to_string(),
|
||||||
BoolLiteral(b) => b.to_string(),
|
BoolLiteral(b) => b.to_string(),
|
||||||
PropertyReference(NamedReference { element, name }) => {
|
PropertyReference(NamedReference { element, name }) => {
|
||||||
let (access, context) = access_member(
|
let access =
|
||||||
&element.upgrade().unwrap(),
|
access_member(&element.upgrade().unwrap(), name.as_str(), component, "self");
|
||||||
name.as_str(),
|
format!(r#"{}.get()"#, access)
|
||||||
component,
|
|
||||||
"context",
|
|
||||||
"self",
|
|
||||||
);
|
|
||||||
format!(r#"{}.get({})"#, access, context)
|
|
||||||
}
|
}
|
||||||
SignalReference(NamedReference { element, name }) => {
|
SignalReference(NamedReference { element, name }) => {
|
||||||
let (access, context) = access_member(
|
let access =
|
||||||
&element.upgrade().unwrap(),
|
access_member(&element.upgrade().unwrap(), name.as_str(), component, "self");
|
||||||
name.as_str(),
|
format!(r#"{}.emit()"#, access)
|
||||||
component,
|
|
||||||
"context",
|
|
||||||
"self",
|
|
||||||
);
|
|
||||||
format!(r#"{}.emit({})"#, access, context)
|
|
||||||
}
|
}
|
||||||
RepeaterIndexReference { element } => {
|
RepeaterIndexReference { element } => {
|
||||||
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
||||||
"self->index.get(context)".to_owned()
|
"self->index.get()".to_owned()
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RepeaterModelReference { element } => {
|
RepeaterModelReference { element } => {
|
||||||
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
||||||
"self->model_data.get(context)".to_owned()
|
"self->model_data.get()".to_owned()
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
@ -748,19 +724,13 @@ fn compile_expression(e: &crate::expression_tree::Expression, component: &Rc<Com
|
||||||
}
|
}
|
||||||
SelfAssignment { lhs, rhs, op } => match &**lhs {
|
SelfAssignment { lhs, rhs, op } => match &**lhs {
|
||||||
PropertyReference(NamedReference { element, name }) => {
|
PropertyReference(NamedReference { element, name }) => {
|
||||||
let (access, context) = access_member(
|
let access =
|
||||||
&element.upgrade().unwrap(),
|
access_member(&element.upgrade().unwrap(), name.as_str(), component, "self");
|
||||||
name.as_str(),
|
|
||||||
component,
|
|
||||||
"context",
|
|
||||||
"self",
|
|
||||||
);
|
|
||||||
format!(
|
format!(
|
||||||
r#"{lhs}.set({lhs}.get({context}) {op} {rhs})"#,
|
r#"{lhs}.set({lhs}.get() {op} {rhs})"#,
|
||||||
lhs = access,
|
lhs = access,
|
||||||
rhs = compile_expression(&*rhs, component),
|
rhs = compile_expression(&*rhs, component),
|
||||||
op = op,
|
op = op,
|
||||||
context = context
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
||||||
|
@ -894,8 +864,8 @@ fn compute_layout(component: &Rc<Component>) -> Vec<String> {
|
||||||
// FIXME: add auto conversion from std::array* to Slice
|
// FIXME: add auto conversion from std::array* to Slice
|
||||||
res.push(" { row_constr.data(), row_constr.size() },".to_owned());
|
res.push(" { row_constr.data(), row_constr.size() },".to_owned());
|
||||||
res.push(" { col_constr.data(), col_constr.size() },".to_owned());
|
res.push(" { col_constr.data(), col_constr.size() },".to_owned());
|
||||||
res.push(format!(" self->{}.width.get(context),", grid.within.borrow().id));
|
res.push(format!(" self->{}.width.get(),", grid.within.borrow().id));
|
||||||
res.push(format!(" self->{}.height.get(context),", grid.within.borrow().id));
|
res.push(format!(" self->{}.height.get(),", grid.within.borrow().id));
|
||||||
res.push(" x, y,".to_owned());
|
res.push(" x, y,".to_owned());
|
||||||
res.push(" {cells, std::size(cells)}".to_owned());
|
res.push(" {cells, std::size(cells)}".to_owned());
|
||||||
res.push(" };".to_owned());
|
res.push(" };".to_owned());
|
||||||
|
|
|
@ -52,10 +52,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
quote!(
|
quote!(
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn #emitter_ident(self: ::core::pin::Pin<&Self>) {
|
fn #emitter_ident(self: ::core::pin::Pin<&Self>) {
|
||||||
let eval_context = sixtyfps::re_exports::EvaluationContext::for_root_component(
|
Self::field_offsets().#prop_ident.apply_pin(self).emit(())
|
||||||
sixtyfps::re_exports::ComponentRef::new_pin(self)
|
|
||||||
);
|
|
||||||
Self::field_offsets().#prop_ident.apply_pin(self).emit(&eval_context, ())
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
|
@ -79,10 +76,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
quote!(
|
quote!(
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn #getter_ident(self: ::core::pin::Pin<&Self>) -> #rust_property_type {
|
fn #getter_ident(self: ::core::pin::Pin<&Self>) -> #rust_property_type {
|
||||||
let eval_context = sixtyfps::re_exports::EvaluationContext::for_root_component(
|
Self::field_offsets().#prop_ident.apply_pin(self).get()
|
||||||
sixtyfps::re_exports::ComponentRef::new_pin(self)
|
|
||||||
);
|
|
||||||
Self::field_offsets().#prop_ident.apply_pin(self).get(&eval_context)
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
|
@ -180,11 +174,6 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
if self_pinned.#model_name.is_dirty() {
|
if self_pinned.#model_name.is_dirty() {
|
||||||
#component_id::field_offsets().#model_name.apply_pin(self_pinned).evaluate(|| {
|
#component_id::field_offsets().#model_name.apply_pin(self_pinned).evaluate(|| {
|
||||||
let _self = self_pinned.clone();
|
let _self = self_pinned.clone();
|
||||||
// FIXME: this should not be the root_component (but that's fine as we no longer access the parent)
|
|
||||||
let context = sixtyfps::re_exports::EvaluationContext::for_root_component(
|
|
||||||
sixtyfps::re_exports::ComponentRef::new_pin(_self)
|
|
||||||
);
|
|
||||||
let context = &context;
|
|
||||||
self_pinned.#repeater_id.update_model(#model, || {
|
self_pinned.#repeater_id.update_model(#model, || {
|
||||||
#rep_component_id::new(self_pinned.self_weak.get().unwrap().clone())
|
#rep_component_id::new(self_pinned.self_weak.get().unwrap().clone())
|
||||||
});
|
});
|
||||||
|
@ -226,9 +215,13 @@ 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_pinned.#rust_property.set_handler(|context, ()| {
|
self_pinned.#rust_property.set_handler({
|
||||||
let _self = context.get_component::<#component_id>().unwrap();
|
let self_weak = sixtyfps::re_exports::WeakPin::downgrade(self_pinned.clone());
|
||||||
#tokens_for_expression;
|
move |()| {
|
||||||
|
let self_pinned = self_weak.upgrade().unwrap();
|
||||||
|
let _self = self_pinned.as_ref();
|
||||||
|
#tokens_for_expression;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
@ -246,7 +239,7 @@ pub fn generate(component: &Rc<Component>, diag: &mut Diagnostics) -> Option<Tok
|
||||||
k,
|
k,
|
||||||
quote!({
|
quote!({
|
||||||
let self_weak = sixtyfps::re_exports::WeakPin::downgrade(self_pinned.clone());
|
let self_weak = sixtyfps::re_exports::WeakPin::downgrade(self_pinned.clone());
|
||||||
move |context| {
|
move || {
|
||||||
let self_pinned = self_weak.upgrade().unwrap();
|
let self_pinned = self_weak.upgrade().unwrap();
|
||||||
let _self = self_pinned.as_ref();
|
let _self = self_pinned.as_ref();
|
||||||
(#tokens_for_expression) as _
|
(#tokens_for_expression) as _
|
||||||
|
@ -450,20 +443,19 @@ fn property_set_binding_tokens(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the code that can access the given property or signal from the context (but without the set or get)
|
/// Returns the code that can access the given property or signal (but without the set or get)
|
||||||
///
|
///
|
||||||
/// to be used like:
|
/// to be used like:
|
||||||
/// ```ignore
|
/// ```ignore
|
||||||
/// let (access, context) = access_member(...)
|
/// let access = access_member(...)
|
||||||
/// quote!(#access.get(#context))
|
/// quote!(#access.get())
|
||||||
/// ```
|
/// ```
|
||||||
fn access_member(
|
fn access_member(
|
||||||
element: &ElementRc,
|
element: &ElementRc,
|
||||||
name: &str,
|
name: &str,
|
||||||
component: &Rc<Component>,
|
component: &Rc<Component>,
|
||||||
context: TokenStream,
|
|
||||||
component_rust: TokenStream,
|
component_rust: TokenStream,
|
||||||
) -> (TokenStream, TokenStream) {
|
) -> TokenStream {
|
||||||
let e = element.borrow();
|
let e = element.borrow();
|
||||||
|
|
||||||
let enclosing_component = e.enclosing_component.upgrade().unwrap();
|
let enclosing_component = e.enclosing_component.upgrade().unwrap();
|
||||||
|
@ -471,15 +463,13 @@ fn access_member(
|
||||||
let component_id = component_id(&enclosing_component);
|
let component_id = component_id(&enclosing_component);
|
||||||
let name_ident = quote::format_ident!("{}", name);
|
let name_ident = quote::format_ident!("{}", name);
|
||||||
if e.property_declarations.contains_key(name) {
|
if e.property_declarations.contains_key(name) {
|
||||||
(quote!(#component_id::field_offsets().#name_ident.apply_pin(#component_rust)), context)
|
quote!(#component_id::field_offsets().#name_ident.apply_pin(#component_rust))
|
||||||
} else {
|
} else {
|
||||||
let elem_ident = quote::format_ident!("{}", e.id);
|
let elem_ident = quote::format_ident!("{}", e.id);
|
||||||
let elem_ty = quote::format_ident!("{}", e.base_type.as_builtin().class_name);
|
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)
|
quote!((#component_id::field_offsets().#elem_ident + #elem_ty::field_offsets().#name_ident)
|
||||||
.apply_pin(#component_rust)
|
.apply_pin(#component_rust)
|
||||||
),
|
|
||||||
context,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -494,7 +484,6 @@ fn access_member(
|
||||||
.enclosing_component
|
.enclosing_component
|
||||||
.upgrade()
|
.upgrade()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
quote!((&sixtyfps::re_exports::EvaluationContext::for_root_component(#context.component))),
|
|
||||||
quote!(#component_rust.parent.upgrade().unwrap().as_ref()),
|
quote!(#component_rust.parent.upgrade().unwrap().as_ref()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -520,19 +509,14 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::PropertyReference(NamedReference { element, name }) => {
|
Expression::PropertyReference(NamedReference { element, name }) => {
|
||||||
let (access, context) = access_member(
|
let access =
|
||||||
&element.upgrade().unwrap(),
|
access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self));
|
||||||
name.as_str(),
|
quote!(#access.get())
|
||||||
component,
|
|
||||||
quote!(context),
|
|
||||||
quote!(_self),
|
|
||||||
);
|
|
||||||
quote!(#access.get(#context))
|
|
||||||
}
|
}
|
||||||
Expression::RepeaterIndexReference { element } => {
|
Expression::RepeaterIndexReference { element } => {
|
||||||
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
||||||
let component_id = component_id(&component);
|
let component_id = component_id(&component);
|
||||||
quote!({ #component_id::field_offsets().index.apply_pin(_self).get(context) })
|
quote!({ #component_id::field_offsets().index.apply_pin(_self).get() })
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
@ -540,7 +524,7 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
|
||||||
Expression::RepeaterModelReference { element } => {
|
Expression::RepeaterModelReference { element } => {
|
||||||
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
if element.upgrade().unwrap().borrow().base_type == Type::Component(component.clone()) {
|
||||||
let component_id = component_id(&component);
|
let component_id = component_id(&component);
|
||||||
quote!({ #component_id::field_offsets().model_data.apply_pin(_self).get(context) })
|
quote!({ #component_id::field_offsets().model_data.apply_pin(_self).get() })
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
|
@ -562,14 +546,9 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
|
||||||
quote!({ #(#map);* })
|
quote!({ #(#map);* })
|
||||||
}
|
}
|
||||||
Expression::SignalReference(NamedReference { element, name, .. }) => {
|
Expression::SignalReference(NamedReference { element, name, .. }) => {
|
||||||
let (access, context) = access_member(
|
let access =
|
||||||
&element.upgrade().unwrap(),
|
access_member(&element.upgrade().unwrap(), name.as_str(), component, quote!(_self));
|
||||||
name.as_str(),
|
quote!(#access.emit(()))
|
||||||
component,
|
|
||||||
quote!(context),
|
|
||||||
quote!(_self),
|
|
||||||
);
|
|
||||||
quote!(#access.emit(#context, ()))
|
|
||||||
}
|
}
|
||||||
Expression::FunctionCall { function } => {
|
Expression::FunctionCall { function } => {
|
||||||
if matches!(function.ty(), Type::Signal) {
|
if matches!(function.ty(), Type::Signal) {
|
||||||
|
@ -581,16 +560,15 @@ fn compile_expression(e: &Expression, component: &Rc<Component>) -> TokenStream
|
||||||
}
|
}
|
||||||
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 (lhs, context) = access_member(
|
let lhs = access_member(
|
||||||
&element.upgrade().unwrap(),
|
&element.upgrade().unwrap(),
|
||||||
name.as_str(),
|
name.as_str(),
|
||||||
component,
|
component,
|
||||||
quote!(context),
|
|
||||||
quote!(_self),
|
quote!(_self),
|
||||||
);
|
);
|
||||||
let rhs = compile_expression(&*rhs, &component);
|
let rhs = compile_expression(&*rhs, &component);
|
||||||
let op = proc_macro2::Punct::new(*op, proc_macro2::Spacing::Alone);
|
let op = proc_macro2::Punct::new(*op, proc_macro2::Spacing::Alone);
|
||||||
quote!( #lhs.set(#lhs.get(#context) #op &((#rhs) as _) ))
|
quote!( #lhs.set(#lhs.get() #op &((#rhs) as _) ))
|
||||||
}
|
}
|
||||||
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
||||||
},
|
},
|
||||||
|
@ -725,9 +703,9 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
|
||||||
row_constraint: Slice::from_slice(&[#(#row_constraint),*]),
|
row_constraint: Slice::from_slice(&[#(#row_constraint),*]),
|
||||||
col_constraint: Slice::from_slice(&[#(#col_constraint),*]),
|
col_constraint: Slice::from_slice(&[#(#col_constraint),*]),
|
||||||
width: (Self::field_offsets().#within + #within_ty::field_offsets().width)
|
width: (Self::field_offsets().#within + #within_ty::field_offsets().width)
|
||||||
.apply_pin(self).get(context),
|
.apply_pin(self).get(),
|
||||||
height: (Self::field_offsets().#within + #within_ty::field_offsets().height)
|
height: (Self::field_offsets().#within + #within_ty::field_offsets().height)
|
||||||
.apply_pin(self).get(context),
|
.apply_pin(self).get(),
|
||||||
x: #x_pos,
|
x: #x_pos,
|
||||||
y: #y_pos,
|
y: #y_pos,
|
||||||
cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]),
|
cells: Slice::from_slice(&[#( Slice::from_slice(&[#( #cells ),*])),*]),
|
||||||
|
@ -781,7 +759,7 @@ fn compute_layout(component: &Rc<Component>) -> TokenStream {
|
||||||
fn layout_info(self: ::core::pin::Pin<&Self>) -> sixtyfps::re_exports::LayoutInfo {
|
fn layout_info(self: ::core::pin::Pin<&Self>) -> sixtyfps::re_exports::LayoutInfo {
|
||||||
todo!("Implement in rust.rs")
|
todo!("Implement in rust.rs")
|
||||||
}
|
}
|
||||||
fn compute_layout(self: ::core::pin::Pin<&Self>, context: &sixtyfps::re_exports::EvaluationContext) {
|
fn compute_layout(self: ::core::pin::Pin<&Self>) {
|
||||||
#![allow(unused)]
|
#![allow(unused)]
|
||||||
use sixtyfps::re_exports::*;
|
use sixtyfps::re_exports::*;
|
||||||
let dummy = Property::<f32>::default();
|
let dummy = Property::<f32>::default();
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
//! This module contains the basic datastructures that are exposed to the C API
|
//! This module contains the basic datastructures that are exposed to the C API
|
||||||
|
|
||||||
use super::slice::Slice;
|
use super::slice::Slice;
|
||||||
use crate::EvaluationContext;
|
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use std::cell::Cell;
|
use std::cell::Cell;
|
||||||
use vtable::*;
|
use vtable::*;
|
||||||
|
@ -53,8 +52,7 @@ pub struct ComponentVTable {
|
||||||
pub layout_info: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> LayoutInfo,
|
pub layout_info: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>) -> LayoutInfo,
|
||||||
|
|
||||||
/// Will compute the layout of
|
/// Will compute the layout of
|
||||||
pub compute_layout:
|
pub compute_layout: extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>),
|
||||||
extern "C" fn(core::pin::Pin<VRef<ComponentVTable>>, eval_context: &EvaluationContext),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This structure must be present in items that are Rendered and contains information.
|
/// This structure must be present in items that are Rendered and contains information.
|
||||||
|
@ -111,8 +109,7 @@ pub enum ItemTreeNode<T> {
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct ItemVTable {
|
pub struct ItemVTable {
|
||||||
/// Returns the geometry of this item (relative to its parent item)
|
/// Returns the geometry of this item (relative to its parent item)
|
||||||
pub geometry:
|
pub geometry: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> Rect,
|
||||||
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, context: &crate::EvaluationContext) -> Rect,
|
|
||||||
|
|
||||||
/// offset in bytes fromthe *const ItemImpl.
|
/// offset in bytes fromthe *const ItemImpl.
|
||||||
/// isize::MAX means None
|
/// isize::MAX means None
|
||||||
|
@ -121,17 +118,13 @@ pub struct ItemVTable {
|
||||||
pub cached_rendering_data_offset: usize,
|
pub cached_rendering_data_offset: usize,
|
||||||
|
|
||||||
/// Return the rendering primitive used to display this item.
|
/// Return the rendering primitive used to display this item.
|
||||||
pub rendering_primitive: extern "C" fn(
|
pub rendering_primitive: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> RenderingPrimitive,
|
||||||
core::pin::Pin<VRef<ItemVTable>>,
|
|
||||||
context: &crate::EvaluationContext,
|
|
||||||
) -> RenderingPrimitive,
|
|
||||||
|
|
||||||
/// We would need max/min/preferred size, and all layout info
|
/// We would need max/min/preferred size, and all layout info
|
||||||
pub layouting_info: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> LayoutInfo,
|
pub layouting_info: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>) -> LayoutInfo,
|
||||||
|
|
||||||
/// input event
|
/// input event
|
||||||
pub input_event:
|
pub input_event: extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, MouseEvent),
|
||||||
extern "C" fn(core::pin::Pin<VRef<ItemVTable>>, MouseEvent, &crate::EvaluationContext),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The constraint that applies to an item
|
/// The constraint that applies to an item
|
||||||
|
|
|
@ -21,7 +21,7 @@ use super::datastructures::{
|
||||||
};
|
};
|
||||||
#[cfg(feature = "rtti")]
|
#[cfg(feature = "rtti")]
|
||||||
use crate::rtti::*;
|
use crate::rtti::*;
|
||||||
use crate::{EvaluationContext, Property, SharedString, Signal};
|
use crate::{Property, SharedString, Signal};
|
||||||
use const_field_offset::FieldOffsets;
|
use const_field_offset::FieldOffsets;
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
use corelib_macro::*;
|
use corelib_macro::*;
|
||||||
|
@ -40,27 +40,24 @@ pub struct Rectangle {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for Rectangle {
|
impl Item for Rectangle {
|
||||||
fn geometry(self: Pin<&Self>, context: &EvaluationContext) -> Rect {
|
fn geometry(self: Pin<&Self>) -> Rect {
|
||||||
euclid::rect(
|
euclid::rect(
|
||||||
Self::field_offsets().x.apply_pin(self).get(context),
|
Self::field_offsets().x.apply_pin(self).get(),
|
||||||
Self::field_offsets().y.apply_pin(self).get(context),
|
Self::field_offsets().y.apply_pin(self).get(),
|
||||||
Self::field_offsets().width.apply_pin(self).get(context),
|
Self::field_offsets().width.apply_pin(self).get(),
|
||||||
Self::field_offsets().height.apply_pin(self).get(context),
|
Self::field_offsets().height.apply_pin(self).get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn rendering_primitive(
|
fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive {
|
||||||
self: Pin<&Self>,
|
let width = Self::field_offsets().width.apply_pin(self).get();
|
||||||
context: &crate::EvaluationContext,
|
let height = Self::field_offsets().height.apply_pin(self).get();
|
||||||
) -> RenderingPrimitive {
|
|
||||||
let width = Self::field_offsets().width.apply_pin(self).get(context);
|
|
||||||
let height = Self::field_offsets().height.apply_pin(self).get(context);
|
|
||||||
if width > 0. && height > 0. {
|
if width > 0. && height > 0. {
|
||||||
RenderingPrimitive::Rectangle {
|
RenderingPrimitive::Rectangle {
|
||||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
x: Self::field_offsets().x.apply_pin(self).get(),
|
||||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
y: Self::field_offsets().y.apply_pin(self).get(),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
color: Self::field_offsets().color.apply_pin(self).get(context),
|
color: Self::field_offsets().color.apply_pin(self).get(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RenderingPrimitive::NoContents
|
RenderingPrimitive::NoContents
|
||||||
|
@ -71,12 +68,7 @@ impl Item for Rectangle {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_event(
|
fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {}
|
||||||
self: Pin<&Self>,
|
|
||||||
_: super::datastructures::MouseEvent,
|
|
||||||
_: &crate::EvaluationContext,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemConsts for Rectangle {
|
impl ItemConsts for Rectangle {
|
||||||
|
@ -102,22 +94,19 @@ pub struct Image {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for Image {
|
impl Item for Image {
|
||||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
fn geometry(self: Pin<&Self>) -> Rect {
|
||||||
euclid::rect(
|
euclid::rect(
|
||||||
Self::field_offsets().x.apply_pin(self).get(context),
|
Self::field_offsets().x.apply_pin(self).get(),
|
||||||
Self::field_offsets().y.apply_pin(self).get(context),
|
Self::field_offsets().y.apply_pin(self).get(),
|
||||||
Self::field_offsets().width.apply_pin(self).get(context),
|
Self::field_offsets().width.apply_pin(self).get(),
|
||||||
Self::field_offsets().height.apply_pin(self).get(context),
|
Self::field_offsets().height.apply_pin(self).get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn rendering_primitive(
|
fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive {
|
||||||
self: Pin<&Self>,
|
|
||||||
context: &crate::EvaluationContext,
|
|
||||||
) -> RenderingPrimitive {
|
|
||||||
RenderingPrimitive::Image {
|
RenderingPrimitive::Image {
|
||||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
x: Self::field_offsets().x.apply_pin(self).get(),
|
||||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
y: Self::field_offsets().y.apply_pin(self).get(),
|
||||||
source: Self::field_offsets().source.apply_pin(self).get(context),
|
source: Self::field_offsets().source.apply_pin(self).get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -126,12 +115,7 @@ impl Item for Image {
|
||||||
Default::default()
|
Default::default()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_event(
|
fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {}
|
||||||
self: Pin<&Self>,
|
|
||||||
_: super::datastructures::MouseEvent,
|
|
||||||
_: &crate::EvaluationContext,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemConsts for Image {
|
impl ItemConsts for Image {
|
||||||
|
@ -159,25 +143,22 @@ pub struct Text {
|
||||||
|
|
||||||
impl Item for Text {
|
impl Item for Text {
|
||||||
// FIXME: width / height. or maybe it doesn't matter? (
|
// FIXME: width / height. or maybe it doesn't matter? (
|
||||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
fn geometry(self: Pin<&Self>) -> Rect {
|
||||||
euclid::rect(
|
euclid::rect(
|
||||||
Self::field_offsets().x.apply_pin(self).get(context),
|
Self::field_offsets().x.apply_pin(self).get(),
|
||||||
Self::field_offsets().y.apply_pin(self).get(context),
|
Self::field_offsets().y.apply_pin(self).get(),
|
||||||
0.,
|
0.,
|
||||||
0.,
|
0.,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn rendering_primitive(
|
fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive {
|
||||||
self: Pin<&Self>,
|
|
||||||
context: &crate::EvaluationContext,
|
|
||||||
) -> RenderingPrimitive {
|
|
||||||
RenderingPrimitive::Text {
|
RenderingPrimitive::Text {
|
||||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
x: Self::field_offsets().x.apply_pin(self).get(),
|
||||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
y: Self::field_offsets().y.apply_pin(self).get(),
|
||||||
text: Self::field_offsets().text.apply_pin(self).get(context),
|
text: Self::field_offsets().text.apply_pin(self).get(),
|
||||||
font_family: Self::field_offsets().font_family.apply_pin(self).get(context),
|
font_family: Self::field_offsets().font_family.apply_pin(self).get(),
|
||||||
font_pixel_size: Self::field_offsets().font_pixel_size.apply_pin(self).get(context),
|
font_pixel_size: Self::field_offsets().font_pixel_size.apply_pin(self).get(),
|
||||||
color: Self::field_offsets().color.apply_pin(self).get(context),
|
color: Self::field_offsets().color.apply_pin(self).get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,12 +166,7 @@ impl Item for Text {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_event(
|
fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {}
|
||||||
self: Pin<&Self>,
|
|
||||||
_: super::datastructures::MouseEvent,
|
|
||||||
_: &crate::EvaluationContext,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemConsts for Text {
|
impl ItemConsts for Text {
|
||||||
|
@ -217,18 +193,15 @@ pub struct TouchArea {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for TouchArea {
|
impl Item for TouchArea {
|
||||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
fn geometry(self: Pin<&Self>) -> Rect {
|
||||||
euclid::rect(
|
euclid::rect(
|
||||||
Self::field_offsets().x.apply_pin(self).get(context),
|
Self::field_offsets().x.apply_pin(self).get(),
|
||||||
Self::field_offsets().y.apply_pin(self).get(context),
|
Self::field_offsets().y.apply_pin(self).get(),
|
||||||
Self::field_offsets().width.apply_pin(self).get(context),
|
Self::field_offsets().width.apply_pin(self).get(),
|
||||||
Self::field_offsets().height.apply_pin(self).get(context),
|
Self::field_offsets().height.apply_pin(self).get(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn rendering_primitive(
|
fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive {
|
||||||
self: Pin<&Self>,
|
|
||||||
_context: &crate::EvaluationContext,
|
|
||||||
) -> RenderingPrimitive {
|
|
||||||
RenderingPrimitive::NoContents
|
RenderingPrimitive::NoContents
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -236,11 +209,7 @@ impl Item for TouchArea {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_event(
|
fn input_event(self: Pin<&Self>, event: super::datastructures::MouseEvent) {
|
||||||
self: Pin<&Self>,
|
|
||||||
event: super::datastructures::MouseEvent,
|
|
||||||
context: &crate::EvaluationContext,
|
|
||||||
) {
|
|
||||||
println!("Touch Area Event {:?}", event);
|
println!("Touch Area Event {:?}", event);
|
||||||
Self::field_offsets().pressed.apply_pin(self).set(match event.what {
|
Self::field_offsets().pressed.apply_pin(self).set(match event.what {
|
||||||
super::datastructures::MouseEventType::MousePressed => true,
|
super::datastructures::MouseEventType::MousePressed => true,
|
||||||
|
@ -248,7 +217,7 @@ impl Item for TouchArea {
|
||||||
super::datastructures::MouseEventType::MouseMoved => return,
|
super::datastructures::MouseEventType::MouseMoved => return,
|
||||||
});
|
});
|
||||||
if matches!(event.what, super::datastructures::MouseEventType::MouseReleased) {
|
if matches!(event.what, super::datastructures::MouseEventType::MouseReleased) {
|
||||||
Self::field_offsets().clicked.apply_pin(self).emit(context, ())
|
Self::field_offsets().clicked.apply_pin(self).emit(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,27 +247,24 @@ pub struct Path {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Item for Path {
|
impl Item for Path {
|
||||||
fn geometry(self: Pin<&Self>, context: &crate::EvaluationContext) -> Rect {
|
fn geometry(self: Pin<&Self>) -> Rect {
|
||||||
euclid::rect(
|
euclid::rect(
|
||||||
Self::field_offsets().x.apply_pin(self).get(context),
|
Self::field_offsets().x.apply_pin(self).get(),
|
||||||
Self::field_offsets().y.apply_pin(self).get(context),
|
Self::field_offsets().y.apply_pin(self).get(),
|
||||||
0.,
|
0.,
|
||||||
0.,
|
0.,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
fn rendering_primitive(
|
fn rendering_primitive(self: Pin<&Self>) -> RenderingPrimitive {
|
||||||
self: Pin<&Self>,
|
|
||||||
context: &crate::EvaluationContext,
|
|
||||||
) -> RenderingPrimitive {
|
|
||||||
RenderingPrimitive::Path {
|
RenderingPrimitive::Path {
|
||||||
x: Self::field_offsets().x.apply_pin(self).get(context),
|
x: Self::field_offsets().x.apply_pin(self).get(),
|
||||||
y: Self::field_offsets().y.apply_pin(self).get(context),
|
y: Self::field_offsets().y.apply_pin(self).get(),
|
||||||
width: Self::field_offsets().width.apply_pin(self).get(context),
|
width: Self::field_offsets().width.apply_pin(self).get(),
|
||||||
height: Self::field_offsets().height.apply_pin(self).get(context),
|
height: Self::field_offsets().height.apply_pin(self).get(),
|
||||||
elements: Self::field_offsets().elements.apply_pin(self).get(context),
|
elements: Self::field_offsets().elements.apply_pin(self).get(),
|
||||||
fill_color: Self::field_offsets().fill_color.apply_pin(self).get(context),
|
fill_color: Self::field_offsets().fill_color.apply_pin(self).get(),
|
||||||
stroke_color: Self::field_offsets().stroke_color.apply_pin(self).get(context),
|
stroke_color: Self::field_offsets().stroke_color.apply_pin(self).get(),
|
||||||
stroke_width: Self::field_offsets().stroke_width.apply_pin(self).get(context),
|
stroke_width: Self::field_offsets().stroke_width.apply_pin(self).get(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,12 +272,7 @@ impl Item for Path {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn input_event(
|
fn input_event(self: Pin<&Self>, _: super::datastructures::MouseEvent) {}
|
||||||
self: Pin<&Self>,
|
|
||||||
_: super::datastructures::MouseEvent,
|
|
||||||
_: &crate::EvaluationContext,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ItemConsts for Path {
|
impl ItemConsts for Path {
|
||||||
|
|
|
@ -66,45 +66,6 @@ use core::{marker::PhantomPinned, pin::Pin};
|
||||||
|
|
||||||
use crate::abi::datastructures::Color;
|
use crate::abi::datastructures::Color;
|
||||||
use crate::abi::primitives::PropertyAnimation;
|
use crate::abi::primitives::PropertyAnimation;
|
||||||
use crate::ComponentRefPin;
|
|
||||||
|
|
||||||
/// This structure contains what is required for the property engine to evaluate properties
|
|
||||||
///
|
|
||||||
/// One must pass it to the getter of the property, or emit of signals, and it can
|
|
||||||
/// be accessed from the bindings
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct EvaluationContext<'a> {
|
|
||||||
/// The component which contains the Property or the Signal
|
|
||||||
pub component: core::pin::Pin<vtable::VRef<'a, crate::abi::datastructures::ComponentVTable>>,
|
|
||||||
|
|
||||||
/// The context of the parent component
|
|
||||||
pub parent_context: Option<&'a EvaluationContext<'a>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a> EvaluationContext<'a> {
|
|
||||||
/// Create a new context related to the root component
|
|
||||||
///
|
|
||||||
/// The component need to be a root component, otherwise fetching properties
|
|
||||||
/// might panic.
|
|
||||||
pub fn for_root_component(component: ComponentRefPin<'a>) -> Self {
|
|
||||||
Self { component, parent_context: None }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Create a context for a child component of a component within the current
|
|
||||||
/// context.
|
|
||||||
pub fn child_context(&'a self, child: ComponentRefPin<'a>) -> Self {
|
|
||||||
Self { component: child, parent_context: Some(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Attempt to cast the component to the given type
|
|
||||||
pub fn get_component<
|
|
||||||
T: vtable::HasStaticVTable<crate::abi::datastructures::ComponentVTable>,
|
|
||||||
>(
|
|
||||||
&'a self,
|
|
||||||
) -> Option<core::pin::Pin<&'a T>> {
|
|
||||||
vtable::VRef::downcast_pin(self.component)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The return value of a binding
|
/// The return value of a binding
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
@ -118,11 +79,7 @@ enum BindingResult {
|
||||||
|
|
||||||
struct BindingVTable {
|
struct BindingVTable {
|
||||||
drop: unsafe fn(_self: *mut BindingHolder),
|
drop: unsafe fn(_self: *mut BindingHolder),
|
||||||
evaluate: unsafe fn(
|
evaluate: unsafe fn(_self: *mut BindingHolder, value: *mut ()) -> BindingResult,
|
||||||
_self: *mut BindingHolder,
|
|
||||||
value: *mut (),
|
|
||||||
context: &EvaluationContext,
|
|
||||||
) -> BindingResult,
|
|
||||||
mark_dirty: unsafe fn(_self: *const BindingHolder),
|
mark_dirty: unsafe fn(_self: *const BindingHolder),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,24 +87,16 @@ struct BindingVTable {
|
||||||
trait BindingCallable {
|
trait BindingCallable {
|
||||||
/// This function is called by the property to evaluate the binding and produce a new value. The
|
/// This function is called by the property to evaluate the binding and produce a new value. The
|
||||||
/// previous property value is provided in the value parameter.
|
/// previous property value is provided in the value parameter.
|
||||||
unsafe fn evaluate(
|
unsafe fn evaluate(self: Pin<&Self>, value: *mut ()) -> BindingResult;
|
||||||
self: Pin<&Self>,
|
|
||||||
value: *mut (),
|
|
||||||
context: &EvaluationContext,
|
|
||||||
) -> BindingResult;
|
|
||||||
|
|
||||||
/// This function is used to notify the binding that one of the dependencies was changed
|
/// This function is used to notify the binding that one of the dependencies was changed
|
||||||
/// and therefore this binding may evaluate to a different value, too.
|
/// and therefore this binding may evaluate to a different value, too.
|
||||||
fn mark_dirty(self: Pin<&Self>) {}
|
fn mark_dirty(self: Pin<&Self>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<F: Fn(*mut (), &EvaluationContext) -> BindingResult> BindingCallable for F {
|
impl<F: Fn(*mut ()) -> BindingResult> BindingCallable for F {
|
||||||
unsafe fn evaluate(
|
unsafe fn evaluate(self: Pin<&Self>, value: *mut ()) -> BindingResult {
|
||||||
self: Pin<&Self>,
|
self(value)
|
||||||
value: *mut (),
|
|
||||||
context: &EvaluationContext,
|
|
||||||
) -> BindingResult {
|
|
||||||
self(value, context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,12 +127,10 @@ fn alloc_binding_holder<B: BindingCallable + 'static>(binding: B) -> *mut Bindin
|
||||||
unsafe fn evaluate<B: BindingCallable>(
|
unsafe fn evaluate<B: BindingCallable>(
|
||||||
_self: *mut BindingHolder,
|
_self: *mut BindingHolder,
|
||||||
value: *mut (),
|
value: *mut (),
|
||||||
context: &EvaluationContext,
|
|
||||||
) -> BindingResult {
|
) -> BindingResult {
|
||||||
let pinned_holder = Pin::new_unchecked(&*_self);
|
let pinned_holder = Pin::new_unchecked(&*_self);
|
||||||
CURRENT_BINDING.set(pinned_holder, || {
|
CURRENT_BINDING.set(pinned_holder, || {
|
||||||
Pin::new_unchecked(&((*(_self as *mut BindingHolder<B>)).binding))
|
Pin::new_unchecked(&((*(_self as *mut BindingHolder<B>)).binding)).evaluate(value)
|
||||||
.evaluate(value, context)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -384,7 +331,7 @@ impl PropertyHandle {
|
||||||
|
|
||||||
// `value` is the content of the unsafe cell and will be only dereferenced if the
|
// `value` is the content of the unsafe cell and will be only dereferenced if the
|
||||||
// handle is not locked. (Upholding the requirements of UnsafeCell)
|
// handle is not locked. (Upholding the requirements of UnsafeCell)
|
||||||
unsafe fn update<T>(&self, value: *mut T, context: &EvaluationContext) {
|
unsafe fn update<T>(&self, value: *mut T) {
|
||||||
let remove = self.access(|binding| {
|
let remove = self.access(|binding| {
|
||||||
if let Some(mut binding) = binding {
|
if let Some(mut binding) = binding {
|
||||||
if binding.dirty.get() {
|
if binding.dirty.get() {
|
||||||
|
@ -393,7 +340,6 @@ impl PropertyHandle {
|
||||||
let r = (binding.vtable.evaluate)(
|
let r = (binding.vtable.evaluate)(
|
||||||
binding.as_mut().get_unchecked_mut() as *mut BindingHolder,
|
binding.as_mut().get_unchecked_mut() as *mut BindingHolder,
|
||||||
value as *mut (),
|
value as *mut (),
|
||||||
context,
|
|
||||||
);
|
);
|
||||||
binding.dirty.set(false);
|
binding.dirty.set(false);
|
||||||
if r == BindingResult::RemoveBinding {
|
if r == BindingResult::RemoveBinding {
|
||||||
|
@ -489,8 +435,8 @@ impl<T: Clone> Property<T> {
|
||||||
///
|
///
|
||||||
/// Panics if this property is get while evaluating its own binding or
|
/// Panics if this property is get while evaluating its own binding or
|
||||||
/// cloning the value.
|
/// cloning the value.
|
||||||
pub fn get(self: Pin<&Self>, context: &EvaluationContext) -> T {
|
pub fn get(self: Pin<&Self>) -> T {
|
||||||
unsafe { self.handle.update(self.value.get(), context) };
|
unsafe { self.handle.update(self.value.get()) };
|
||||||
self.handle.register_as_dependency_to_current_binding();
|
self.handle.register_as_dependency_to_current_binding();
|
||||||
self.get_internal()
|
self.get_internal()
|
||||||
}
|
}
|
||||||
|
@ -522,10 +468,10 @@ impl<T: Clone> Property<T> {
|
||||||
///
|
///
|
||||||
/// If other properties have bindings depending of this property, these properties will
|
/// If other properties have bindings depending of this property, these properties will
|
||||||
/// be marked as dirty.
|
/// be marked as dirty.
|
||||||
//FIXME pub fn set_binding(self: Pin<&Self>, f: impl (Fn(&EvaluationContext) -> T) + 'static) {
|
//FIXME pub fn set_binding(self: Pin<&Self>, f: impl (Fn() -> T) + 'static) {
|
||||||
pub fn set_binding(&self, f: impl (Fn(&EvaluationContext) -> T) + 'static) {
|
pub fn set_binding(&self, f: impl (Fn() -> T) + 'static) {
|
||||||
self.handle.set_binding(move |val: *mut (), context: &EvaluationContext| unsafe {
|
self.handle.set_binding(move |val: *mut ()| unsafe {
|
||||||
*(val as *mut T) = f(context);
|
*(val as *mut T) = f();
|
||||||
BindingResult::KeepBinding
|
BindingResult::KeepBinding
|
||||||
});
|
});
|
||||||
self.handle.mark_dirty();
|
self.handle.mark_dirty();
|
||||||
|
@ -542,7 +488,7 @@ impl<T: Clone + InterpolatedPropertyValue + 'static> Property<T> {
|
||||||
pub fn set_animated_value(&self, value: T, animation_data: &PropertyAnimation) {
|
pub fn set_animated_value(&self, value: T, animation_data: &PropertyAnimation) {
|
||||||
// FIXME if the current value is a dirty binding, we must run it, but we do not have the context
|
// FIXME if the current value is a dirty binding, we must run it, but we do not have the context
|
||||||
let d = PropertyValueAnimationData::new(self.get_internal(), value, animation_data.clone());
|
let d = PropertyValueAnimationData::new(self.get_internal(), value, animation_data.clone());
|
||||||
self.handle.set_binding(move |val: *mut (), _context: &EvaluationContext| unsafe {
|
self.handle.set_binding(move |val: *mut ()| unsafe {
|
||||||
let (value, finished) = d.compute_interpolated_value();
|
let (value, finished) = d.compute_interpolated_value();
|
||||||
*(val as *mut T) = value;
|
*(val as *mut T) = value;
|
||||||
if finished {
|
if finished {
|
||||||
|
@ -559,14 +505,14 @@ impl<T: Clone + InterpolatedPropertyValue + 'static> Property<T> {
|
||||||
///
|
///
|
||||||
pub fn set_animated_binding(
|
pub fn set_animated_binding(
|
||||||
&self,
|
&self,
|
||||||
f: impl (Fn(&EvaluationContext) -> T) + 'static,
|
f: impl (Fn() -> T) + 'static,
|
||||||
animation_data: &PropertyAnimation,
|
animation_data: &PropertyAnimation,
|
||||||
) {
|
) {
|
||||||
self.handle.set_binding(AnimatedBindingCallable::<T> {
|
self.handle.set_binding(AnimatedBindingCallable::<T> {
|
||||||
original_binding: PropertyHandle {
|
original_binding: PropertyHandle {
|
||||||
handle: Cell::new(
|
handle: Cell::new(
|
||||||
(alloc_binding_holder(move |val: *mut (), context: &EvaluationContext| unsafe {
|
(alloc_binding_holder(move |val: *mut ()| unsafe {
|
||||||
*(val as *mut T) = f(context);
|
*(val as *mut T) = f();
|
||||||
BindingResult::KeepBinding
|
BindingResult::KeepBinding
|
||||||
}) as usize)
|
}) as usize)
|
||||||
| 0b10,
|
| 0b10,
|
||||||
|
@ -626,11 +572,7 @@ struct AnimatedBindingCallable<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: InterpolatedPropertyValue> BindingCallable for AnimatedBindingCallable<T> {
|
impl<T: InterpolatedPropertyValue> BindingCallable for AnimatedBindingCallable<T> {
|
||||||
unsafe fn evaluate(
|
unsafe fn evaluate(self: Pin<&Self>, value: *mut ()) -> BindingResult {
|
||||||
self: Pin<&Self>,
|
|
||||||
value: *mut (),
|
|
||||||
context: &EvaluationContext,
|
|
||||||
) -> BindingResult {
|
|
||||||
self.original_binding.register_as_dependency_to_current_binding();
|
self.original_binding.register_as_dependency_to_current_binding();
|
||||||
match self.state.get() {
|
match self.state.get() {
|
||||||
AnimatedBindingState::Animating => {
|
AnimatedBindingState::Animating => {
|
||||||
|
@ -644,15 +586,14 @@ impl<T: InterpolatedPropertyValue> BindingCallable for AnimatedBindingCallable<T
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
AnimatedBindingState::NotAnimating => {
|
AnimatedBindingState::NotAnimating => {
|
||||||
self.original_binding.update(value, context);
|
self.original_binding.update(value);
|
||||||
}
|
}
|
||||||
AnimatedBindingState::ShouldStart => {
|
AnimatedBindingState::ShouldStart => {
|
||||||
let value = &mut *(value as *mut T);
|
let value = &mut *(value as *mut T);
|
||||||
self.state.set(AnimatedBindingState::Animating);
|
self.state.set(AnimatedBindingState::Animating);
|
||||||
let mut animation_data = self.animation_data.borrow_mut();
|
let mut animation_data = self.animation_data.borrow_mut();
|
||||||
animation_data.from_value = value.clone();
|
animation_data.from_value = value.clone();
|
||||||
self.original_binding
|
self.original_binding.update((&mut animation_data.to_value) as *mut T as *mut ());
|
||||||
.update((&mut animation_data.to_value) as *mut T as *mut (), context);
|
|
||||||
let (val, finished) = animation_data.compute_interpolated_value();
|
let (val, finished) = animation_data.compute_interpolated_value();
|
||||||
*value = val;
|
*value = val;
|
||||||
if finished {
|
if finished {
|
||||||
|
@ -682,8 +623,8 @@ impl<T: InterpolatedPropertyValue> BindingCallable for AnimatedBindingCallable<T
|
||||||
fn properties_simple_test() {
|
fn properties_simple_test() {
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use weak_pin::rc::WeakPin;
|
use weak_pin::rc::WeakPin;
|
||||||
fn g(prop: &Property<i32>, ctx: &EvaluationContext) -> i32 {
|
fn g(prop: &Property<i32>) -> i32 {
|
||||||
unsafe { Pin::new_unchecked(prop).get(ctx) }
|
unsafe { Pin::new_unchecked(prop).get() }
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -692,32 +633,27 @@ fn properties_simple_test() {
|
||||||
height: Property<i32>,
|
height: Property<i32>,
|
||||||
area: Property<i32>,
|
area: Property<i32>,
|
||||||
}
|
}
|
||||||
let dummy_eval_context = EvaluationContext::for_root_component(unsafe {
|
|
||||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
))
|
|
||||||
});
|
|
||||||
let compo = Rc::pin(Component::default());
|
let compo = Rc::pin(Component::default());
|
||||||
let w = WeakPin::downgrade(compo.clone());
|
let w = WeakPin::downgrade(compo.clone());
|
||||||
compo.area.set_binding(move |ctx| {
|
compo.area.set_binding(move || {
|
||||||
let compo = w.upgrade().unwrap();
|
let compo = w.upgrade().unwrap();
|
||||||
g(&compo.width, ctx) * g(&compo.height, ctx)
|
g(&compo.width) * g(&compo.height)
|
||||||
});
|
});
|
||||||
compo.width.set(4);
|
compo.width.set(4);
|
||||||
compo.height.set(8);
|
compo.height.set(8);
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 4);
|
assert_eq!(g(&compo.width), 4);
|
||||||
assert_eq!(g(&compo.height, &dummy_eval_context), 8);
|
assert_eq!(g(&compo.height), 8);
|
||||||
assert_eq!(g(&compo.area, &dummy_eval_context), 4 * 8);
|
assert_eq!(g(&compo.area), 4 * 8);
|
||||||
|
|
||||||
let w = WeakPin::downgrade(compo.clone());
|
let w = WeakPin::downgrade(compo.clone());
|
||||||
compo.width.set_binding(move |ctx| {
|
compo.width.set_binding(move || {
|
||||||
let compo = w.upgrade().unwrap();
|
let compo = w.upgrade().unwrap();
|
||||||
g(&compo.height, ctx) * 2
|
g(&compo.height) * 2
|
||||||
});
|
});
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 8 * 2);
|
assert_eq!(g(&compo.width), 8 * 2);
|
||||||
assert_eq!(g(&compo.height, &dummy_eval_context), 8);
|
assert_eq!(g(&compo.height), 8);
|
||||||
assert_eq!(g(&compo.area, &dummy_eval_context), 8 * 8 * 2);
|
assert_eq!(g(&compo.area), 8 * 8 * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_camel_case_types)]
|
#[allow(non_camel_case_types)]
|
||||||
|
@ -735,12 +671,8 @@ pub unsafe extern "C" fn sixtyfps_property_init(out: *mut PropertyHandleOpaque)
|
||||||
|
|
||||||
/// To be called before accessing the value
|
/// To be called before accessing the value
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_property_update(
|
pub unsafe extern "C" fn sixtyfps_property_update(handle: &PropertyHandleOpaque, val: *mut c_void) {
|
||||||
handle: &PropertyHandleOpaque,
|
handle.0.update(val);
|
||||||
context: &EvaluationContext,
|
|
||||||
val: *mut c_void,
|
|
||||||
) {
|
|
||||||
handle.0.update(val, context);
|
|
||||||
handle.0.register_as_dependency_to_current_binding();
|
handle.0.register_as_dependency_to_current_binding();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -753,12 +685,12 @@ pub unsafe extern "C" fn sixtyfps_property_set_changed(handle: &PropertyHandleOp
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_c_function_binding(
|
fn make_c_function_binding(
|
||||||
binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut c_void),
|
binding: extern "C" fn(*mut c_void, *mut c_void),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
) -> impl Fn(*mut (), &EvaluationContext) -> BindingResult {
|
) -> impl Fn(*mut ()) -> BindingResult {
|
||||||
struct CFunctionBinding<T> {
|
struct CFunctionBinding<T> {
|
||||||
binding_function: extern "C" fn(*mut c_void, &EvaluationContext, *mut T),
|
binding_function: extern "C" fn(*mut c_void, *mut T),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
}
|
}
|
||||||
|
@ -773,14 +705,13 @@ fn make_c_function_binding(
|
||||||
|
|
||||||
let b = CFunctionBinding { binding_function: binding, user_data, drop_user_data };
|
let b = CFunctionBinding { binding_function: binding, user_data, drop_user_data };
|
||||||
|
|
||||||
move |value_ptr, context| {
|
move |value_ptr| {
|
||||||
(b.binding_function)(b.user_data, context, value_ptr);
|
(b.binding_function)(b.user_data, value_ptr);
|
||||||
BindingResult::KeepBinding
|
BindingResult::KeepBinding
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set a binding
|
/// Set a binding
|
||||||
/// The binding has signature fn(user_data, context, pointer_to_value)
|
|
||||||
///
|
///
|
||||||
/// The current implementation will do usually two memory alocation:
|
/// The current implementation will do usually two memory alocation:
|
||||||
/// 1. the allocation from the calling code to allocate user_data
|
/// 1. the allocation from the calling code to allocate user_data
|
||||||
|
@ -790,11 +721,7 @@ fn make_c_function_binding(
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_property_set_binding(
|
pub unsafe extern "C" fn sixtyfps_property_set_binding(
|
||||||
handle: &PropertyHandleOpaque,
|
handle: &PropertyHandleOpaque,
|
||||||
binding: extern "C" fn(
|
binding: extern "C" fn(user_data: *mut c_void, pointer_to_value: *mut c_void),
|
||||||
user_data: *mut c_void,
|
|
||||||
context: &EvaluationContext,
|
|
||||||
pointer_to_value: *mut c_void,
|
|
||||||
),
|
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
) {
|
) {
|
||||||
|
@ -845,7 +772,7 @@ fn c_set_animated_value<T: InterpolatedPropertyValue>(
|
||||||
animation_data: &crate::abi::primitives::PropertyAnimation,
|
animation_data: &crate::abi::primitives::PropertyAnimation,
|
||||||
) {
|
) {
|
||||||
let d = PropertyValueAnimationData::new(from, to, animation_data.clone());
|
let d = PropertyValueAnimationData::new(from, to, animation_data.clone());
|
||||||
handle.0.set_binding(move |val: *mut (), _: &EvaluationContext| {
|
handle.0.set_binding(move |val: *mut ()| {
|
||||||
let (value, finished) = d.compute_interpolated_value();
|
let (value, finished) = d.compute_interpolated_value();
|
||||||
unsafe {
|
unsafe {
|
||||||
*(val as *mut T) = value;
|
*(val as *mut T) = value;
|
||||||
|
@ -895,14 +822,14 @@ pub unsafe extern "C" fn sixtyfps_property_set_animated_value_color(
|
||||||
|
|
||||||
unsafe fn c_set_animated_binding<T: InterpolatedPropertyValue>(
|
unsafe fn c_set_animated_binding<T: InterpolatedPropertyValue>(
|
||||||
handle: &PropertyHandleOpaque,
|
handle: &PropertyHandleOpaque,
|
||||||
binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut T),
|
binding: extern "C" fn(*mut c_void, *mut T),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
animation_data: &crate::abi::primitives::PropertyAnimation,
|
animation_data: &crate::abi::primitives::PropertyAnimation,
|
||||||
) {
|
) {
|
||||||
let binding = core::mem::transmute::<
|
let binding = core::mem::transmute::<
|
||||||
extern "C" fn(*mut c_void, &EvaluationContext, *mut T),
|
extern "C" fn(*mut c_void, *mut T),
|
||||||
extern "C" fn(*mut c_void, &EvaluationContext, *mut ()),
|
extern "C" fn(*mut c_void, *mut ()),
|
||||||
>(binding);
|
>(binding);
|
||||||
handle.0.set_binding(AnimatedBindingCallable::<T> {
|
handle.0.set_binding(AnimatedBindingCallable::<T> {
|
||||||
original_binding: PropertyHandle {
|
original_binding: PropertyHandle {
|
||||||
|
@ -926,7 +853,7 @@ unsafe fn c_set_animated_binding<T: InterpolatedPropertyValue>(
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_int(
|
pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_int(
|
||||||
handle: &PropertyHandleOpaque,
|
handle: &PropertyHandleOpaque,
|
||||||
binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut i32),
|
binding: extern "C" fn(*mut c_void, *mut i32),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
animation_data: &crate::abi::primitives::PropertyAnimation,
|
animation_data: &crate::abi::primitives::PropertyAnimation,
|
||||||
|
@ -938,7 +865,7 @@ pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_int(
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_float(
|
pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_float(
|
||||||
handle: &PropertyHandleOpaque,
|
handle: &PropertyHandleOpaque,
|
||||||
binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut f32),
|
binding: extern "C" fn(*mut c_void, *mut f32),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
animation_data: &crate::abi::primitives::PropertyAnimation,
|
animation_data: &crate::abi::primitives::PropertyAnimation,
|
||||||
|
@ -950,7 +877,7 @@ pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_float(
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_color(
|
pub unsafe extern "C" fn sixtyfps_property_set_animated_binding_color(
|
||||||
handle: &PropertyHandleOpaque,
|
handle: &PropertyHandleOpaque,
|
||||||
binding: extern "C" fn(*mut c_void, &EvaluationContext, *mut Color),
|
binding: extern "C" fn(*mut c_void, *mut Color),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
animation_data: &crate::abi::primitives::PropertyAnimation,
|
animation_data: &crate::abi::primitives::PropertyAnimation,
|
||||||
|
@ -975,52 +902,44 @@ mod animation_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn properties_test_animation_triggered_by_set() {
|
fn properties_test_animation_triggered_by_set() {
|
||||||
fn g(prop: &Property<i32>, ctx: &EvaluationContext) -> i32 {
|
fn g(prop: &Property<i32>) -> i32 {
|
||||||
unsafe { Pin::new_unchecked(prop).get(ctx) }
|
unsafe { Pin::new_unchecked(prop).get() }
|
||||||
}
|
}
|
||||||
let dummy_eval_context = EvaluationContext {
|
|
||||||
component: unsafe {
|
|
||||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
parent_context: None,
|
|
||||||
};
|
|
||||||
let compo = Rc::new(Component::default());
|
let compo = Rc::new(Component::default());
|
||||||
|
|
||||||
let w = Rc::downgrade(&compo);
|
let w = Rc::downgrade(&compo);
|
||||||
compo.width_times_two.set_binding(move |context| {
|
compo.width_times_two.set_binding(move || {
|
||||||
let compo = w.upgrade().unwrap();
|
let compo = w.upgrade().unwrap();
|
||||||
g(&compo.width, context) * 2
|
g(&compo.width) * 2
|
||||||
});
|
});
|
||||||
|
|
||||||
let animation_details = PropertyAnimation { duration: DURATION.as_millis() as _ };
|
let animation_details = PropertyAnimation { duration: DURATION.as_millis() as _ };
|
||||||
|
|
||||||
compo.width.set(100);
|
compo.width.set(100);
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
assert_eq!(g(&compo.width), 100);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width_times_two), 200);
|
||||||
|
|
||||||
let start_time =
|
let start_time =
|
||||||
crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| driver.current_tick());
|
crate::animations::CURRENT_ANIMATION_DRIVER.with(|driver| driver.current_tick());
|
||||||
|
|
||||||
compo.width.set_animated_value(200, &animation_details);
|
compo.width.set_animated_value(200, &animation_details);
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
assert_eq!(g(&compo.width), 100);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width_times_two), 200);
|
||||||
|
|
||||||
crate::animations::CURRENT_ANIMATION_DRIVER
|
crate::animations::CURRENT_ANIMATION_DRIVER
|
||||||
.with(|driver| driver.update_animations(start_time + DURATION / 2));
|
.with(|driver| driver.update_animations(start_time + DURATION / 2));
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 150);
|
assert_eq!(g(&compo.width), 150);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300);
|
assert_eq!(g(&compo.width_times_two), 300);
|
||||||
|
|
||||||
crate::animations::CURRENT_ANIMATION_DRIVER
|
crate::animations::CURRENT_ANIMATION_DRIVER
|
||||||
.with(|driver| driver.update_animations(start_time + DURATION));
|
.with(|driver| driver.update_animations(start_time + DURATION));
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width), 200);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400);
|
assert_eq!(g(&compo.width_times_two), 400);
|
||||||
crate::animations::CURRENT_ANIMATION_DRIVER
|
crate::animations::CURRENT_ANIMATION_DRIVER
|
||||||
.with(|driver| driver.update_animations(start_time + DURATION * 2));
|
.with(|driver| driver.update_animations(start_time + DURATION * 2));
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width), 200);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400);
|
assert_eq!(g(&compo.width_times_two), 400);
|
||||||
|
|
||||||
// the binding should be removed
|
// the binding should be removed
|
||||||
compo.width.handle.access(|binding| assert!(binding.is_none()));
|
compo.width.handle.access(|binding| assert!(binding.is_none()));
|
||||||
|
@ -1028,24 +947,15 @@ mod animation_tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn properties_test_animation_triggered_by_binding() {
|
fn properties_test_animation_triggered_by_binding() {
|
||||||
fn g(prop: &Property<i32>, ctx: &EvaluationContext) -> i32 {
|
fn g(prop: &Property<i32>) -> i32 {
|
||||||
unsafe { Pin::new_unchecked(prop).get(ctx) }
|
unsafe { Pin::new_unchecked(prop).get() }
|
||||||
}
|
}
|
||||||
let dummy_eval_context = EvaluationContext {
|
|
||||||
component: unsafe {
|
|
||||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
parent_context: None,
|
|
||||||
};
|
|
||||||
let compo = Rc::new(Component::default());
|
let compo = Rc::new(Component::default());
|
||||||
|
|
||||||
let w = Rc::downgrade(&compo);
|
let w = Rc::downgrade(&compo);
|
||||||
compo.width_times_two.set_binding(move |context| {
|
compo.width_times_two.set_binding(move || {
|
||||||
let compo = w.upgrade().unwrap();
|
let compo = w.upgrade().unwrap();
|
||||||
g(&compo.width, context) * 2
|
g(&compo.width) * 2
|
||||||
});
|
});
|
||||||
|
|
||||||
let start_time =
|
let start_time =
|
||||||
|
@ -1055,32 +965,32 @@ mod animation_tests {
|
||||||
|
|
||||||
let w = Rc::downgrade(&compo);
|
let w = Rc::downgrade(&compo);
|
||||||
compo.width.set_animated_binding(
|
compo.width.set_animated_binding(
|
||||||
move |context| {
|
move || {
|
||||||
let compo = w.upgrade().unwrap();
|
let compo = w.upgrade().unwrap();
|
||||||
g(&compo.feed_property, context)
|
g(&compo.feed_property)
|
||||||
},
|
},
|
||||||
&animation_details,
|
&animation_details,
|
||||||
);
|
);
|
||||||
|
|
||||||
compo.feed_property.set(100);
|
compo.feed_property.set(100);
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
assert_eq!(g(&compo.width), 100);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width_times_two), 200);
|
||||||
|
|
||||||
compo.feed_property.set(200);
|
compo.feed_property.set(200);
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 100);
|
assert_eq!(g(&compo.width), 100);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width_times_two), 200);
|
||||||
|
|
||||||
crate::animations::CURRENT_ANIMATION_DRIVER
|
crate::animations::CURRENT_ANIMATION_DRIVER
|
||||||
.with(|driver| driver.update_animations(start_time + DURATION / 2));
|
.with(|driver| driver.update_animations(start_time + DURATION / 2));
|
||||||
|
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 150);
|
assert_eq!(g(&compo.width), 150);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 300);
|
assert_eq!(g(&compo.width_times_two), 300);
|
||||||
|
|
||||||
crate::animations::CURRENT_ANIMATION_DRIVER
|
crate::animations::CURRENT_ANIMATION_DRIVER
|
||||||
.with(|driver| driver.update_animations(start_time + DURATION));
|
.with(|driver| driver.update_animations(start_time + DURATION));
|
||||||
|
|
||||||
assert_eq!(g(&compo.width, &dummy_eval_context), 200);
|
assert_eq!(g(&compo.width), 200);
|
||||||
assert_eq!(g(&compo.width_times_two, &dummy_eval_context), 400);
|
assert_eq!(g(&compo.width_times_two), 400);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1094,7 +1004,7 @@ impl Default for PropertyListenerScope {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
static VT: &'static BindingVTable = &BindingVTable {
|
static VT: &'static BindingVTable = &BindingVTable {
|
||||||
drop: |_| (),
|
drop: |_| (),
|
||||||
evaluate: |_, _, _| BindingResult::KeepBinding,
|
evaluate: |_, _| BindingResult::KeepBinding,
|
||||||
mark_dirty: |_| (),
|
mark_dirty: |_| (),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1134,21 +1044,13 @@ fn test_property_listener_scope() {
|
||||||
let scope = Box::pin(PropertyListenerScope::default());
|
let scope = Box::pin(PropertyListenerScope::default());
|
||||||
let prop1 = Box::pin(Property::new(42));
|
let prop1 = Box::pin(Property::new(42));
|
||||||
assert!(scope.is_dirty()); // It is dirty at the beginning
|
assert!(scope.is_dirty()); // It is dirty at the beginning
|
||||||
let dummy_eval_context = EvaluationContext {
|
|
||||||
component: unsafe {
|
let r = scope.as_ref().evaluate(|| prop1.as_ref().get());
|
||||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
))
|
|
||||||
},
|
|
||||||
parent_context: None,
|
|
||||||
};
|
|
||||||
let r = scope.as_ref().evaluate(|| prop1.as_ref().get(&dummy_eval_context));
|
|
||||||
assert_eq!(r, 42);
|
assert_eq!(r, 42);
|
||||||
assert!(!scope.is_dirty()); // It is no longer dirty
|
assert!(!scope.is_dirty()); // It is no longer dirty
|
||||||
prop1.as_ref().set(88);
|
prop1.as_ref().set(88);
|
||||||
assert!(scope.is_dirty()); // now dirty for prop1 changed.
|
assert!(scope.is_dirty()); // now dirty for prop1 changed.
|
||||||
let r = scope.as_ref().evaluate(|| prop1.as_ref().get(&dummy_eval_context) + 1);
|
let r = scope.as_ref().evaluate(|| prop1.as_ref().get() + 1);
|
||||||
assert_eq!(r, 89);
|
assert_eq!(r, 89);
|
||||||
assert!(!scope.is_dirty());
|
assert!(!scope.is_dirty());
|
||||||
let r = scope.as_ref().evaluate(|| 12);
|
let r = scope.as_ref().evaluate(|| 12);
|
||||||
|
|
|
@ -5,7 +5,6 @@ TODO: reconsider if we should rename that to `Event`
|
||||||
but then it should also be renamed everywhere, including in the language grammar
|
but then it should also be renamed everywhere, including in the language grammar
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use super::properties::EvaluationContext;
|
|
||||||
use core::cell::Cell;
|
use core::cell::Cell;
|
||||||
|
|
||||||
/// A Signal that can be connected to a handler.
|
/// A Signal that can be connected to a handler.
|
||||||
|
@ -16,16 +15,14 @@ use core::cell::Cell;
|
||||||
#[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: Cell<Option<Box<dyn Fn(&EvaluationContext, Arg)>>>,
|
handler: Cell<Option<Box<dyn Fn(Arg)>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<Arg> Signal<Arg> {
|
impl<Arg> Signal<Arg> {
|
||||||
/// Emit the signal with the given argument.
|
/// Emit the signal with the given argument.
|
||||||
///
|
pub fn emit(&self, a: Arg) {
|
||||||
/// The constext must be a context corresponding to the component in which the signal is contained.
|
|
||||||
pub fn emit(&self, context: &EvaluationContext, a: Arg) {
|
|
||||||
if let Some(h) = self.handler.take() {
|
if let Some(h) = self.handler.take() {
|
||||||
h(context, a);
|
h(a);
|
||||||
assert!(self.handler.take().is_none(), "Signal Handler set while emitted");
|
assert!(self.handler.take().is_none(), "Signal Handler set while emitted");
|
||||||
self.handler.set(Some(h))
|
self.handler.set(Some(h))
|
||||||
}
|
}
|
||||||
|
@ -34,44 +31,23 @@ impl<Arg> Signal<Arg> {
|
||||||
/// 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(&self, f: impl Fn(&EvaluationContext, Arg) + 'static) {
|
pub fn set_handler(&self, f: impl Fn(Arg) + 'static) {
|
||||||
self.handler.set(Some(Box::new(f)));
|
self.handler.set(Some(Box::new(f)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn signal_simple_test() {
|
fn signal_simple_test() {
|
||||||
use std::pin::Pin;
|
use std::rc::Rc;
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Component {
|
struct Component {
|
||||||
pressed: core::cell::Cell<bool>,
|
pressed: core::cell::Cell<bool>,
|
||||||
clicked: Signal<()>,
|
clicked: Signal<()>,
|
||||||
}
|
}
|
||||||
impl crate::abi::datastructures::Component for Component {
|
let c = Rc::new(Component::default());
|
||||||
fn visit_children_item(
|
let weak = Rc::downgrade(&c);
|
||||||
self: Pin<&Self>,
|
c.clicked.set_handler(move |()| weak.upgrade().unwrap().pressed.set(true));
|
||||||
_: isize,
|
c.clicked.emit(());
|
||||||
_: crate::abi::datastructures::ItemVisitorRefMut,
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
fn layout_info(self: Pin<&Self>) -> crate::abi::datastructures::LayoutInfo {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
fn compute_layout(self: Pin<&Self>, _: &crate::EvaluationContext) {}
|
|
||||||
}
|
|
||||||
use crate::abi::datastructures::ComponentVTable;
|
|
||||||
let c = Component::default();
|
|
||||||
c.clicked.set_handler(|c, ()| unsafe {
|
|
||||||
(*(c.component.as_ptr() as *const Component)).pressed.set(true)
|
|
||||||
});
|
|
||||||
let vtable = ComponentVTable::new::<Component>();
|
|
||||||
let ctx = super::properties::EvaluationContext::for_root_component(unsafe {
|
|
||||||
Pin::new_unchecked(vtable::VRef::from_raw(
|
|
||||||
core::ptr::NonNull::from(&vtable),
|
|
||||||
core::ptr::NonNull::from(&c).cast(),
|
|
||||||
))
|
|
||||||
});
|
|
||||||
c.clicked.emit(&ctx, ());
|
|
||||||
assert_eq!(c.pressed.get(), true);
|
assert_eq!(c.pressed.get(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,21 +70,18 @@ pub unsafe extern "C" fn sixtyfps_signal_init(out: *mut SignalOpaque) {
|
||||||
|
|
||||||
/// Emit the signal
|
/// Emit the signal
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_signal_emit(
|
pub unsafe extern "C" fn sixtyfps_signal_emit(sig: *const SignalOpaque) {
|
||||||
sig: *const SignalOpaque,
|
|
||||||
component: &EvaluationContext,
|
|
||||||
) {
|
|
||||||
let sig = &*(sig as *const Signal<()>);
|
let sig = &*(sig as *const Signal<()>);
|
||||||
sig.emit(component, ());
|
sig.emit(());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set signal handler.
|
/// Set signal handler.
|
||||||
///
|
///
|
||||||
/// The binding has signature fn(user_data, context)
|
/// The binding has signature fn(user_data)
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn sixtyfps_signal_set_handler(
|
pub unsafe extern "C" fn sixtyfps_signal_set_handler(
|
||||||
sig: *mut SignalOpaque,
|
sig: *mut SignalOpaque,
|
||||||
binding: extern "C" fn(*mut c_void, &EvaluationContext),
|
binding: extern "C" fn(user_data: *mut c_void),
|
||||||
user_data: *mut c_void,
|
user_data: *mut c_void,
|
||||||
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
drop_user_data: Option<extern "C" fn(*mut c_void)>,
|
||||||
) {
|
) {
|
||||||
|
@ -128,8 +101,8 @@ pub unsafe extern "C" fn sixtyfps_signal_set_handler(
|
||||||
}
|
}
|
||||||
let ud = UserData { user_data, drop_user_data };
|
let ud = UserData { user_data, drop_user_data };
|
||||||
|
|
||||||
let real_binding = move |compo: &EvaluationContext, ()| {
|
let real_binding = move |()| {
|
||||||
binding(ud.user_data, compo);
|
binding(ud.user_data);
|
||||||
};
|
};
|
||||||
sig.set_handler(real_binding);
|
sig.set_handler(real_binding);
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,15 +39,7 @@ impl AnimationDriver {
|
||||||
/// The current instant that is to be used for animation
|
/// The current instant that is to be used for animation
|
||||||
/// using this function register the current binding as a dependency
|
/// using this function register the current binding as a dependency
|
||||||
pub fn current_tick(&self) -> instant::Instant {
|
pub fn current_tick(&self) -> instant::Instant {
|
||||||
// FIXME! we need to get rid of the contect there
|
self.global_instant.as_ref().get()
|
||||||
#[allow(unsafe_code)]
|
|
||||||
let dummy_eval_context = crate::EvaluationContext::for_root_component(unsafe {
|
|
||||||
core::pin::Pin::new_unchecked(vtable::VRef::from_raw(
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
core::ptr::NonNull::dangling(),
|
|
||||||
))
|
|
||||||
});
|
|
||||||
self.global_instant.as_ref().get(&dummy_eval_context)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -145,7 +145,7 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow
|
||||||
{
|
{
|
||||||
fn draw(&self, component: crate::ComponentRefPin) {
|
fn draw(&self, component: crate::ComponentRefPin) {
|
||||||
// FIXME: we should do that only if some property change
|
// FIXME: we should do that only if some property change
|
||||||
component.as_ref().compute_layout(&crate::EvaluationContext::for_root_component(component));
|
component.as_ref().compute_layout();
|
||||||
|
|
||||||
let mut this = self.borrow_mut();
|
let mut this = self.borrow_mut();
|
||||||
|
|
||||||
|
@ -156,9 +156,8 @@ impl<Backend: GraphicsBackend> crate::eventloop::GenericWindow
|
||||||
// Generate cached rendering data once
|
// Generate cached rendering data once
|
||||||
crate::item_tree::visit_items(
|
crate::item_tree::visit_items(
|
||||||
component,
|
component,
|
||||||
|ctx, item, _| {
|
|_, item, _| {
|
||||||
crate::item_rendering::update_item_rendering_data(
|
crate::item_rendering::update_item_rendering_data(
|
||||||
ctx,
|
|
||||||
item,
|
item,
|
||||||
&mut this.rendering_cache,
|
&mut this.rendering_cache,
|
||||||
&mut rendering_primitives_builder,
|
&mut rendering_primitives_builder,
|
||||||
|
|
|
@ -12,14 +12,14 @@ pub fn process_mouse_event(component: ComponentRefPin, event: MouseEvent) {
|
||||||
|
|
||||||
crate::item_tree::visit_items(
|
crate::item_tree::visit_items(
|
||||||
component,
|
component,
|
||||||
|context, item, offset| {
|
|_, item, offset| {
|
||||||
let geom = item.as_ref().geometry(context);
|
let geom = item.as_ref().geometry();
|
||||||
let geom = geom.translate(*offset);
|
let geom = geom.translate(*offset);
|
||||||
|
|
||||||
if geom.contains(event.pos) {
|
if geom.contains(event.pos) {
|
||||||
let mut event2 = event.clone();
|
let mut event2 = event.clone();
|
||||||
event2.pos -= geom.origin.to_vector();
|
event2.pos -= geom.origin.to_vector();
|
||||||
item.as_ref().input_event(event2, context);
|
item.as_ref().input_event(event2);
|
||||||
}
|
}
|
||||||
|
|
||||||
geom.origin.to_vector()
|
geom.origin.to_vector()
|
||||||
|
|
|
@ -2,16 +2,14 @@ use super::abi::datastructures::ItemRef;
|
||||||
use super::graphics::{
|
use super::graphics::{
|
||||||
Frame, GraphicsBackend, HasRenderingPrimitive, RenderingCache, RenderingPrimitivesBuilder,
|
Frame, GraphicsBackend, HasRenderingPrimitive, RenderingCache, RenderingPrimitivesBuilder,
|
||||||
};
|
};
|
||||||
use super::EvaluationContext;
|
|
||||||
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
use cgmath::{Matrix4, SquareMatrix, Vector3};
|
||||||
|
|
||||||
pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
|
pub(crate) fn update_item_rendering_data<Backend: GraphicsBackend>(
|
||||||
context: &EvaluationContext,
|
|
||||||
item: core::pin::Pin<ItemRef>,
|
item: core::pin::Pin<ItemRef>,
|
||||||
rendering_cache: &mut RenderingCache<Backend>,
|
rendering_cache: &mut RenderingCache<Backend>,
|
||||||
rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder,
|
rendering_primitives_builder: &mut Backend::RenderingPrimitivesBuilder,
|
||||||
) {
|
) {
|
||||||
let item_rendering_primitive = item.as_ref().rendering_primitive(context);
|
let item_rendering_primitive = item.as_ref().rendering_primitive();
|
||||||
|
|
||||||
let rendering_data = item.cached_rendering_data_offset();
|
let rendering_data = item.cached_rendering_data_offset();
|
||||||
|
|
||||||
|
@ -41,8 +39,8 @@ pub(crate) fn render_component_items<Backend: GraphicsBackend>(
|
||||||
|
|
||||||
crate::item_tree::visit_items(
|
crate::item_tree::visit_items(
|
||||||
component,
|
component,
|
||||||
|context, item, transform| {
|
|_, item, transform| {
|
||||||
let origin = item.as_ref().geometry(context).origin;
|
let origin = item.as_ref().geometry().origin;
|
||||||
let transform =
|
let transform =
|
||||||
transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.));
|
transform * Matrix4::from_translation(Vector3::new(origin.x, origin.y, 0.));
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
use crate::abi::datastructures::{ItemRef, ItemTreeNode, ItemVisitor, ItemVisitorVTable};
|
use crate::abi::datastructures::{ItemRef, ItemTreeNode, ItemVisitor, ItemVisitorVTable};
|
||||||
use crate::ComponentRefPin;
|
use crate::ComponentRefPin;
|
||||||
use crate::EvaluationContext;
|
|
||||||
use core::pin::Pin;
|
use core::pin::Pin;
|
||||||
|
|
||||||
/// Visit each items recursively
|
/// Visit each items recursively
|
||||||
|
@ -8,31 +7,24 @@ use core::pin::Pin;
|
||||||
/// The state parametter returned by the visitor is passed to each children.
|
/// The state parametter returned by the visitor is passed to each children.
|
||||||
pub fn visit_items<State>(
|
pub fn visit_items<State>(
|
||||||
component: ComponentRefPin,
|
component: ComponentRefPin,
|
||||||
mut visitor: impl FnMut(&EvaluationContext, Pin<ItemRef>, &State) -> State,
|
mut visitor: impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> State,
|
||||||
state: State,
|
state: State,
|
||||||
) {
|
) {
|
||||||
let context = EvaluationContext::for_root_component(component);
|
visit_internal(component, &mut visitor, -1, &state)
|
||||||
visit_internal(&context, &mut visitor, -1, &state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_internal<State>(
|
fn visit_internal<State>(
|
||||||
context: &EvaluationContext,
|
component: ComponentRefPin,
|
||||||
visitor: &mut impl FnMut(&EvaluationContext, Pin<ItemRef>, &State) -> State,
|
visitor: &mut impl FnMut(ComponentRefPin, Pin<ItemRef>, &State) -> State,
|
||||||
index: isize,
|
index: isize,
|
||||||
state: &State,
|
state: &State,
|
||||||
) {
|
) {
|
||||||
let mut actual_visitor = |component: ComponentRefPin, index: isize, item: Pin<ItemRef>| {
|
let mut actual_visitor = |component: ComponentRefPin, index: isize, item: Pin<ItemRef>| {
|
||||||
if component.as_ptr() == context.component.as_ptr() {
|
let s = visitor(component, item, state);
|
||||||
let s = visitor(context, item, state);
|
visit_internal(component, visitor, index, &s);
|
||||||
visit_internal(context, visitor, index, &s);
|
|
||||||
} else {
|
|
||||||
let context = context.child_context(component);
|
|
||||||
let s = visitor(&context, item, state);
|
|
||||||
visit_internal(&context, visitor, index, &s);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
|
vtable::new_vref!(let mut actual_visitor : VRefMut<ItemVisitorVTable> for ItemVisitor = &mut actual_visitor);
|
||||||
context.component.as_ref().visit_children_item(index, actual_visitor);
|
component.as_ref().visit_children_item(index, actual_visitor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Visit the children within an array of ItemTreeNode
|
/// Visit the children within an array of ItemTreeNode
|
||||||
|
|
|
@ -44,7 +44,7 @@ pub use abi::sharedarray::SharedArray;
|
||||||
pub use abi::datastructures::Resource;
|
pub use abi::datastructures::Resource;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use abi::properties::{EvaluationContext, Property};
|
pub use abi::properties::Property;
|
||||||
|
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use abi::signals::Signal;
|
pub use abi::signals::Signal;
|
||||||
|
|
|
@ -27,7 +27,7 @@ declare_ValueType![
|
||||||
];
|
];
|
||||||
|
|
||||||
pub trait PropertyInfo<Item, Value> {
|
pub trait PropertyInfo<Item, Value> {
|
||||||
fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result<Value, ()>;
|
fn get(&self, item: Pin<&Item>) -> Result<Value, ()>;
|
||||||
fn set(
|
fn set(
|
||||||
&self,
|
&self,
|
||||||
item: Pin<&Item>,
|
item: Pin<&Item>,
|
||||||
|
@ -37,7 +37,7 @@ pub trait PropertyInfo<Item, Value> {
|
||||||
fn set_binding(
|
fn set_binding(
|
||||||
&self,
|
&self,
|
||||||
item: Pin<&Item>,
|
item: Pin<&Item>,
|
||||||
binding: Box<dyn Fn(&crate::EvaluationContext) -> Value>,
|
binding: Box<dyn Fn() -> Value>,
|
||||||
animation: Option<crate::abi::primitives::PropertyAnimation>,
|
animation: Option<crate::abi::primitives::PropertyAnimation>,
|
||||||
) -> Result<(), ()>;
|
) -> Result<(), ()>;
|
||||||
|
|
||||||
|
@ -61,8 +61,8 @@ where
|
||||||
Value: TryInto<T>,
|
Value: TryInto<T>,
|
||||||
T: TryInto<Value>,
|
T: TryInto<Value>,
|
||||||
{
|
{
|
||||||
fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result<Value, ()> {
|
fn get(&self, item: Pin<&Item>) -> Result<Value, ()> {
|
||||||
self.apply_pin(item).get(context).try_into().map_err(|_| ())
|
self.apply_pin(item).get().try_into().map_err(|_| ())
|
||||||
}
|
}
|
||||||
fn set(
|
fn set(
|
||||||
&self,
|
&self,
|
||||||
|
@ -80,14 +80,14 @@ where
|
||||||
fn set_binding(
|
fn set_binding(
|
||||||
&self,
|
&self,
|
||||||
item: Pin<&Item>,
|
item: Pin<&Item>,
|
||||||
binding: Box<dyn Fn(&crate::EvaluationContext) -> Value>,
|
binding: Box<dyn Fn() -> Value>,
|
||||||
animation: Option<crate::abi::primitives::PropertyAnimation>,
|
animation: Option<crate::abi::primitives::PropertyAnimation>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
if animation.is_some() {
|
if animation.is_some() {
|
||||||
Err(())
|
Err(())
|
||||||
} else {
|
} else {
|
||||||
self.apply_pin(item).set_binding(move |context| {
|
self.apply_pin(item).set_binding(move || {
|
||||||
binding(context).try_into().map_err(|_| ()).expect("binding was of the wrong type")
|
binding().try_into().map_err(|_| ()).expect("binding was of the wrong type")
|
||||||
});
|
});
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -109,8 +109,8 @@ where
|
||||||
T: TryInto<Value>,
|
T: TryInto<Value>,
|
||||||
T: crate::abi::properties::InterpolatedPropertyValue,
|
T: crate::abi::properties::InterpolatedPropertyValue,
|
||||||
{
|
{
|
||||||
fn get(&self, item: Pin<&Item>, context: &crate::EvaluationContext) -> Result<Value, ()> {
|
fn get(&self, item: Pin<&Item>) -> Result<Value, ()> {
|
||||||
self.0.get(item, context)
|
self.0.get(item)
|
||||||
}
|
}
|
||||||
fn set(
|
fn set(
|
||||||
&self,
|
&self,
|
||||||
|
@ -128,16 +128,13 @@ where
|
||||||
fn set_binding(
|
fn set_binding(
|
||||||
&self,
|
&self,
|
||||||
item: Pin<&Item>,
|
item: Pin<&Item>,
|
||||||
binding: Box<dyn Fn(&crate::EvaluationContext) -> Value>,
|
binding: Box<dyn Fn() -> Value>,
|
||||||
animation: Option<crate::abi::primitives::PropertyAnimation>,
|
animation: Option<crate::abi::primitives::PropertyAnimation>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
if let Some(animation) = &animation {
|
if let Some(animation) = &animation {
|
||||||
self.apply_pin(item).set_animated_binding(
|
self.apply_pin(item).set_animated_binding(
|
||||||
move |context| {
|
move || {
|
||||||
binding(context)
|
binding().try_into().map_err(|_| ()).expect("binding was of the wrong type")
|
||||||
.try_into()
|
|
||||||
.map_err(|_| ())
|
|
||||||
.expect("binding was of the wrong type")
|
|
||||||
},
|
},
|
||||||
animation,
|
animation,
|
||||||
);
|
);
|
||||||
|
|
|
@ -13,7 +13,7 @@ use sixtyfps_corelib::abi::primitives::PropertyAnimation;
|
||||||
use sixtyfps_corelib::abi::{properties::PropertyListenerScope, slice::Slice};
|
use sixtyfps_corelib::abi::{properties::PropertyListenerScope, slice::Slice};
|
||||||
use sixtyfps_corelib::rtti::PropertyInfo;
|
use sixtyfps_corelib::rtti::PropertyInfo;
|
||||||
use sixtyfps_corelib::ComponentRefPin;
|
use sixtyfps_corelib::ComponentRefPin;
|
||||||
use sixtyfps_corelib::{rtti, Color, EvaluationContext, Property, SharedString, Signal};
|
use sixtyfps_corelib::{rtti, Color, Property, SharedString, Signal};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::{pin::Pin, rc::Rc};
|
use std::{pin::Pin, rc::Rc};
|
||||||
|
|
||||||
|
@ -129,28 +129,24 @@ unsafe extern "C" fn visit_children_item(
|
||||||
&*(component.as_ptr().add(listener_offset) as *const PropertyListenerScope),
|
&*(component.as_ptr().add(listener_offset) as *const PropertyListenerScope),
|
||||||
);
|
);
|
||||||
if listener.is_dirty() {
|
if listener.is_dirty() {
|
||||||
let eval_context = EvaluationContext::for_root_component(component);
|
|
||||||
listener.evaluate(|| {
|
listener.evaluate(|| {
|
||||||
match eval::eval_expression(
|
match eval::eval_expression(&rep_in_comp.model, &*component_type, component)
|
||||||
&rep_in_comp.model,
|
{
|
||||||
&*component_type,
|
|
||||||
&eval_context,
|
|
||||||
) {
|
|
||||||
crate::Value::Number(count) => populate_model(
|
crate::Value::Number(count) => populate_model(
|
||||||
vec,
|
vec,
|
||||||
rep_in_comp,
|
rep_in_comp,
|
||||||
&eval_context,
|
component,
|
||||||
(0..count as i32)
|
(0..count as i32)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|v| crate::Value::Number(v as f64)),
|
.map(|v| crate::Value::Number(v as f64)),
|
||||||
),
|
),
|
||||||
crate::Value::Array(a) => {
|
crate::Value::Array(a) => {
|
||||||
populate_model(vec, rep_in_comp, &eval_context, a.into_iter())
|
populate_model(vec, rep_in_comp, component, a.into_iter())
|
||||||
}
|
}
|
||||||
crate::Value::Bool(b) => populate_model(
|
crate::Value::Bool(b) => populate_model(
|
||||||
vec,
|
vec,
|
||||||
rep_in_comp,
|
rep_in_comp,
|
||||||
&eval_context,
|
component,
|
||||||
(if b { Some(crate::Value::Void) } else { None }).into_iter(),
|
(if b { Some(crate::Value::Void) } else { None }).into_iter(),
|
||||||
),
|
),
|
||||||
_ => panic!("Unsupported model"),
|
_ => panic!("Unsupported model"),
|
||||||
|
@ -370,7 +366,7 @@ fn generate_component(
|
||||||
|
|
||||||
fn animation_for_property(
|
fn animation_for_property(
|
||||||
component_type: Rc<ComponentDescription>,
|
component_type: Rc<ComponentDescription>,
|
||||||
eval_context: &EvaluationContext,
|
eval_context: ComponentRefPin,
|
||||||
all_animations: &HashMap<String, ElementRc>,
|
all_animations: &HashMap<String, ElementRc>,
|
||||||
property_name: &String,
|
property_name: &String,
|
||||||
) -> Option<PropertyAnimation> {
|
) -> Option<PropertyAnimation> {
|
||||||
|
@ -386,7 +382,7 @@ fn animation_for_property(
|
||||||
|
|
||||||
fn animation_for_element_property(
|
fn animation_for_element_property(
|
||||||
component_type: Rc<ComponentDescription>,
|
component_type: Rc<ComponentDescription>,
|
||||||
eval_context: &EvaluationContext,
|
eval_context: ComponentRefPin,
|
||||||
element: &Element,
|
element: &Element,
|
||||||
property_name: &String,
|
property_name: &String,
|
||||||
) -> Option<PropertyAnimation> {
|
) -> Option<PropertyAnimation> {
|
||||||
|
@ -401,11 +397,11 @@ fn animation_for_element_property(
|
||||||
fn populate_model(
|
fn populate_model(
|
||||||
vec: &mut Vec<ComponentBox>,
|
vec: &mut Vec<ComponentBox>,
|
||||||
rep_in_comp: &RepeaterWithinComponent,
|
rep_in_comp: &RepeaterWithinComponent,
|
||||||
eval_context: &EvaluationContext,
|
component: ComponentRefPin,
|
||||||
model: impl Iterator<Item = eval::Value> + ExactSizeIterator,
|
model: impl Iterator<Item = eval::Value> + ExactSizeIterator,
|
||||||
) {
|
) {
|
||||||
vec.resize_with(model.size_hint().1.unwrap(), || {
|
vec.resize_with(model.size_hint().1.unwrap(), || {
|
||||||
instantiate(rep_in_comp.component_to_repeat.clone(), Some(eval_context))
|
instantiate(rep_in_comp.component_to_repeat.clone(), Some(component))
|
||||||
});
|
});
|
||||||
for (i, (x, val)) in vec.iter().zip(model).enumerate() {
|
for (i, (x, val)) in vec.iter().zip(model).enumerate() {
|
||||||
rep_in_comp
|
rep_in_comp
|
||||||
|
@ -418,20 +414,17 @@ fn populate_model(
|
||||||
|
|
||||||
pub fn instantiate(
|
pub fn instantiate(
|
||||||
component_type: Rc<ComponentDescription>,
|
component_type: Rc<ComponentDescription>,
|
||||||
parent_ctx: Option<&EvaluationContext>,
|
parent_ctx: Option<ComponentRefPin>,
|
||||||
) -> ComponentBox {
|
) -> ComponentBox {
|
||||||
let instance = component_type.dynamic_type.clone().create_instance();
|
let instance = component_type.dynamic_type.clone().create_instance();
|
||||||
let mem = instance.as_ptr().as_ptr() as *mut u8;
|
let mem = instance.as_ptr().as_ptr() as *mut u8;
|
||||||
let component_box = ComponentBox { instance, component_type: component_type.clone() };
|
let component_box = ComponentBox { instance, component_type: component_type.clone() };
|
||||||
|
|
||||||
let eval_context = if let Some(parent) = parent_ctx {
|
if let Some(parent) = parent_ctx {
|
||||||
unsafe {
|
unsafe {
|
||||||
*(mem.add(component_type.parent_component_offset.unwrap())
|
*(mem.add(component_type.parent_component_offset.unwrap())
|
||||||
as *mut Option<ComponentRefPin>) = Some(parent.component);
|
as *mut Option<ComponentRefPin>) = Some(parent);
|
||||||
}
|
}
|
||||||
parent.child_context(component_box.borrow())
|
|
||||||
} else {
|
|
||||||
EvaluationContext::for_root_component(component_box.borrow())
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for item_within_component in component_type.items.values() {
|
for item_within_component in component_type.items.values() {
|
||||||
|
@ -453,8 +446,13 @@ pub fn instantiate(
|
||||||
as *mut Signal<()>);
|
as *mut Signal<()>);
|
||||||
let expr = expr.clone();
|
let expr = expr.clone();
|
||||||
let component_type = component_type.clone();
|
let component_type = component_type.clone();
|
||||||
signal.set_handler(move |eval_context, _| {
|
let instance = component_box.instance.as_ptr();
|
||||||
eval::eval_expression(&expr, &*component_type, &eval_context);
|
signal.set_handler(move |_| {
|
||||||
|
let c = Pin::new_unchecked(vtable::VRef::from_raw(
|
||||||
|
NonNull::from(&component_type.ct).cast(),
|
||||||
|
instance.cast(),
|
||||||
|
));
|
||||||
|
eval::eval_expression(&expr, &*component_type, c);
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
if let Some(prop_rtti) =
|
if let Some(prop_rtti) =
|
||||||
|
@ -462,7 +460,7 @@ pub fn instantiate(
|
||||||
{
|
{
|
||||||
let maybe_animation = animation_for_element_property(
|
let maybe_animation = animation_for_element_property(
|
||||||
component_type.clone(),
|
component_type.clone(),
|
||||||
&eval_context,
|
component_box.borrow(),
|
||||||
&elem,
|
&elem,
|
||||||
prop,
|
prop,
|
||||||
);
|
);
|
||||||
|
@ -470,17 +468,26 @@ pub fn instantiate(
|
||||||
if expr.is_constant() {
|
if expr.is_constant() {
|
||||||
prop_rtti.set(
|
prop_rtti.set(
|
||||||
item,
|
item,
|
||||||
eval::eval_expression(expr, &*component_type, &eval_context),
|
eval::eval_expression(
|
||||||
|
expr,
|
||||||
|
&*component_type,
|
||||||
|
component_box.borrow(),
|
||||||
|
),
|
||||||
maybe_animation,
|
maybe_animation,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
let expr = expr.clone();
|
let expr = expr.clone();
|
||||||
let component_type = component_type.clone();
|
let component_type = component_type.clone();
|
||||||
|
let instance = component_box.instance.as_ptr();
|
||||||
|
|
||||||
prop_rtti.set_binding(
|
prop_rtti.set_binding(
|
||||||
item,
|
item,
|
||||||
Box::new(move |eval_context| {
|
Box::new(move || {
|
||||||
eval::eval_expression(&expr, &*component_type, eval_context)
|
let c = Pin::new_unchecked(vtable::VRef::from_raw(
|
||||||
|
NonNull::from(&component_type.ct).cast(),
|
||||||
|
instance.cast(),
|
||||||
|
));
|
||||||
|
eval::eval_expression(&expr, &*component_type, c)
|
||||||
}),
|
}),
|
||||||
maybe_animation,
|
maybe_animation,
|
||||||
);
|
);
|
||||||
|
@ -491,24 +498,33 @@ pub fn instantiate(
|
||||||
{
|
{
|
||||||
let maybe_animation = animation_for_property(
|
let maybe_animation = animation_for_property(
|
||||||
component_type.clone(),
|
component_type.clone(),
|
||||||
&eval_context,
|
component_box.borrow(),
|
||||||
&component_type.original.root_element.borrow().property_animations,
|
&component_type.original.root_element.borrow().property_animations,
|
||||||
prop,
|
prop,
|
||||||
);
|
);
|
||||||
|
|
||||||
if expr.is_constant() {
|
if expr.is_constant() {
|
||||||
let v = eval::eval_expression(expr, &*component_type, &eval_context);
|
let v = eval::eval_expression(
|
||||||
|
expr,
|
||||||
|
&*component_type,
|
||||||
|
component_box.borrow(),
|
||||||
|
);
|
||||||
prop_info
|
prop_info
|
||||||
.set(Pin::new_unchecked(&*mem.add(*offset)), v, maybe_animation)
|
.set(Pin::new_unchecked(&*mem.add(*offset)), v, maybe_animation)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
} else {
|
} else {
|
||||||
let expr = expr.clone();
|
let expr = expr.clone();
|
||||||
let component_type = component_type.clone();
|
let component_type = component_type.clone();
|
||||||
|
let instance = component_box.instance.as_ptr();
|
||||||
prop_info
|
prop_info
|
||||||
.set_binding(
|
.set_binding(
|
||||||
Pin::new_unchecked(&*mem.add(*offset)),
|
Pin::new_unchecked(&*mem.add(*offset)),
|
||||||
Box::new(move |eval_context| {
|
Box::new(move || {
|
||||||
eval::eval_expression(&expr, &*component_type, eval_context)
|
let c = Pin::new_unchecked(vtable::VRef::from_raw(
|
||||||
|
NonNull::from(&component_type.ct).cast(),
|
||||||
|
instance.cast(),
|
||||||
|
));
|
||||||
|
eval::eval_expression(&expr, &*component_type, c)
|
||||||
}),
|
}),
|
||||||
maybe_animation,
|
maybe_animation,
|
||||||
)
|
)
|
||||||
|
@ -527,20 +543,20 @@ pub fn instantiate(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let vec = unsafe { &mut *(mem.add(rep_in_comp.offset) as *mut RepeaterVec) };
|
let vec = unsafe { &mut *(mem.add(rep_in_comp.offset) as *mut RepeaterVec) };
|
||||||
match eval::eval_expression(&rep_in_comp.model, &*component_type, &eval_context) {
|
match eval::eval_expression(&rep_in_comp.model, &*component_type, component_box.borrow()) {
|
||||||
crate::Value::Number(count) => populate_model(
|
crate::Value::Number(count) => populate_model(
|
||||||
vec,
|
vec,
|
||||||
rep_in_comp,
|
rep_in_comp,
|
||||||
&eval_context,
|
component_box.borrow(),
|
||||||
(0..count as i32).into_iter().map(|v| crate::Value::Number(v as f64)),
|
(0..count as i32).into_iter().map(|v| crate::Value::Number(v as f64)),
|
||||||
),
|
),
|
||||||
crate::Value::Array(a) => {
|
crate::Value::Array(a) => {
|
||||||
populate_model(vec, rep_in_comp, &eval_context, a.into_iter())
|
populate_model(vec, rep_in_comp, component_box.borrow(), a.into_iter())
|
||||||
}
|
}
|
||||||
crate::Value::Bool(b) => populate_model(
|
crate::Value::Bool(b) => populate_model(
|
||||||
vec,
|
vec,
|
||||||
rep_in_comp,
|
rep_in_comp,
|
||||||
&eval_context,
|
component_box.borrow(),
|
||||||
(if b { Some(crate::Value::Void) } else { None }).into_iter(),
|
(if b { Some(crate::Value::Void) } else { None }).into_iter(),
|
||||||
),
|
),
|
||||||
_ => panic!("Unsupported model"),
|
_ => panic!("Unsupported model"),
|
||||||
|
@ -550,17 +566,13 @@ pub fn instantiate(
|
||||||
component_box
|
component_box
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe extern "C" fn compute_layout(component: ComponentRefPin, eval_context: &EvaluationContext) {
|
unsafe extern "C" fn compute_layout(component: ComponentRefPin) {
|
||||||
debug_assert!(component.as_ptr() == eval_context.component.as_ptr());
|
|
||||||
|
|
||||||
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
|
// This is fine since we can only be called with a component that with our vtable which is a ComponentDescription
|
||||||
let component_type =
|
let component_type =
|
||||||
&*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription);
|
&*(component.get_vtable() as *const ComponentVTable as *const ComponentDescription);
|
||||||
|
|
||||||
let resolve_prop_ref = |prop_ref: &expression_tree::Expression| {
|
let resolve_prop_ref = |prop_ref: &expression_tree::Expression| {
|
||||||
eval::eval_expression(&prop_ref, &component_type, eval_context)
|
eval::eval_expression(&prop_ref, &component_type, component).try_into().unwrap_or_default()
|
||||||
.try_into()
|
|
||||||
.unwrap_or_default()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
for it in &component_type.original.layout_constraints.borrow().grids {
|
for it in &component_type.original.layout_constraints.borrow().grids {
|
||||||
|
@ -605,7 +617,7 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin, eval_context: &E
|
||||||
let within_info = &component_type.items[it.within.borrow().id.as_str()];
|
let within_info = &component_type.items[it.within.borrow().id.as_str()];
|
||||||
let within_prop = |name| {
|
let within_prop = |name| {
|
||||||
within_info.rtti.properties[name]
|
within_info.rtti.properties[name]
|
||||||
.get(within_info.item_from_component(component.as_ptr()), &eval_context)
|
.get(within_info.item_from_component(component.as_ptr()))
|
||||||
.try_into()
|
.try_into()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
};
|
};
|
||||||
|
@ -639,7 +651,7 @@ unsafe extern "C" fn compute_layout(component: ComponentRefPin, eval_context: &E
|
||||||
})
|
})
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
let path_elements = eval::convert_path(&it.path, component_type, eval_context);
|
let path_elements = eval::convert_path(&it.path, component_type, component);
|
||||||
|
|
||||||
solve_path_layout(&PathLayoutData {
|
solve_path_layout(&PathLayoutData {
|
||||||
items: Slice::from(items.as_slice()),
|
items: Slice::from(items.as_slice()),
|
||||||
|
|
|
@ -7,18 +7,18 @@ use sixtyfps_compilerlib::{object_tree::ElementRc, typeregister::Type};
|
||||||
use sixtyfps_corelib as corelib;
|
use sixtyfps_corelib as corelib;
|
||||||
use sixtyfps_corelib::{
|
use sixtyfps_corelib::{
|
||||||
abi::datastructures::ItemRef, abi::datastructures::PathElement,
|
abi::datastructures::ItemRef, abi::datastructures::PathElement,
|
||||||
abi::primitives::PropertyAnimation, Color, EvaluationContext, PathData, Resource, SharedArray,
|
abi::primitives::PropertyAnimation, Color, ComponentRefPin, PathData, Resource, SharedArray,
|
||||||
SharedString,
|
SharedString,
|
||||||
};
|
};
|
||||||
use std::{collections::HashMap, rc::Rc};
|
use std::{collections::HashMap, rc::Rc};
|
||||||
|
|
||||||
pub trait ErasedPropertyInfo {
|
pub trait ErasedPropertyInfo {
|
||||||
fn get(&self, item: Pin<ItemRef>, context: &EvaluationContext) -> Value;
|
fn get(&self, item: Pin<ItemRef>) -> Value;
|
||||||
fn set(&self, item: Pin<ItemRef>, value: Value, animation: Option<PropertyAnimation>);
|
fn set(&self, item: Pin<ItemRef>, value: Value, animation: Option<PropertyAnimation>);
|
||||||
fn set_binding(
|
fn set_binding(
|
||||||
&self,
|
&self,
|
||||||
item: Pin<ItemRef>,
|
item: Pin<ItemRef>,
|
||||||
binding: Box<dyn Fn(&EvaluationContext) -> Value>,
|
binding: Box<dyn Fn() -> Value>,
|
||||||
animation: Option<PropertyAnimation>,
|
animation: Option<PropertyAnimation>,
|
||||||
);
|
);
|
||||||
fn offset(&self) -> usize;
|
fn offset(&self) -> usize;
|
||||||
|
@ -27,8 +27,8 @@ pub trait ErasedPropertyInfo {
|
||||||
impl<Item: vtable::HasStaticVTable<corelib::abi::datastructures::ItemVTable>> ErasedPropertyInfo
|
impl<Item: vtable::HasStaticVTable<corelib::abi::datastructures::ItemVTable>> ErasedPropertyInfo
|
||||||
for &'static dyn corelib::rtti::PropertyInfo<Item, Value>
|
for &'static dyn corelib::rtti::PropertyInfo<Item, Value>
|
||||||
{
|
{
|
||||||
fn get(&self, item: Pin<ItemRef>, context: &EvaluationContext) -> Value {
|
fn get(&self, item: Pin<ItemRef>) -> Value {
|
||||||
(*self).get(ItemRef::downcast_pin(item).unwrap(), context).unwrap()
|
(*self).get(ItemRef::downcast_pin(item).unwrap()).unwrap()
|
||||||
}
|
}
|
||||||
fn set(&self, item: Pin<ItemRef>, value: Value, animation: Option<PropertyAnimation>) {
|
fn set(&self, item: Pin<ItemRef>, value: Value, animation: Option<PropertyAnimation>) {
|
||||||
(*self).set(ItemRef::downcast_pin(item).unwrap(), value, animation).unwrap()
|
(*self).set(ItemRef::downcast_pin(item).unwrap(), value, animation).unwrap()
|
||||||
|
@ -36,7 +36,7 @@ impl<Item: vtable::HasStaticVTable<corelib::abi::datastructures::ItemVTable>> Er
|
||||||
fn set_binding(
|
fn set_binding(
|
||||||
&self,
|
&self,
|
||||||
item: Pin<ItemRef>,
|
item: Pin<ItemRef>,
|
||||||
binding: Box<dyn Fn(&EvaluationContext) -> Value>,
|
binding: Box<dyn Fn() -> Value>,
|
||||||
animation: Option<PropertyAnimation>,
|
animation: Option<PropertyAnimation>,
|
||||||
) {
|
) {
|
||||||
(*self).set_binding(ItemRef::downcast_pin(item).unwrap(), binding, animation).unwrap();
|
(*self).set_binding(ItemRef::downcast_pin(item).unwrap(), binding, animation).unwrap();
|
||||||
|
@ -119,7 +119,7 @@ declare_value_conversion!(PathElements => [PathData]);
|
||||||
pub fn eval_expression(
|
pub fn eval_expression(
|
||||||
e: &Expression,
|
e: &Expression,
|
||||||
component_type: &crate::ComponentDescription,
|
component_type: &crate::ComponentDescription,
|
||||||
eval_context: &corelib::EvaluationContext,
|
component_ref: ComponentRefPin,
|
||||||
) -> Value {
|
) -> Value {
|
||||||
match e {
|
match e {
|
||||||
Expression::Invalid => panic!("invalid expression while evaluating"),
|
Expression::Invalid => panic!("invalid expression while evaluating"),
|
||||||
|
@ -130,23 +130,21 @@ pub fn eval_expression(
|
||||||
Expression::SignalReference { .. } => panic!("signal in expression"),
|
Expression::SignalReference { .. } => panic!("signal in expression"),
|
||||||
Expression::PropertyReference(NamedReference { element, name }) => {
|
Expression::PropertyReference(NamedReference { element, name }) => {
|
||||||
let element = element.upgrade().unwrap();
|
let element = element.upgrade().unwrap();
|
||||||
let (component_mem, component_type, eval_context) =
|
let (component_mem, component_type, _) =
|
||||||
enclosing_component_for_element(&element, component_type, eval_context);
|
enclosing_component_for_element(&element, component_type, component_ref);
|
||||||
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) = component_type.custom_properties.get(name) {
|
if let Some(x) = component_type.custom_properties.get(name) {
|
||||||
return unsafe {
|
return unsafe {
|
||||||
x.prop
|
x.prop.get(Pin::new_unchecked(&*component_mem.add(x.offset))).unwrap()
|
||||||
.get(Pin::new_unchecked(&*component_mem.add(x.offset)), &eval_context)
|
|
||||||
.unwrap()
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let item_info = &component_type.items[element.id.as_str()];
|
let item_info = &component_type.items[element.id.as_str()];
|
||||||
core::mem::drop(element);
|
core::mem::drop(element);
|
||||||
let item = unsafe { item_info.item_from_component(component_mem) };
|
let item = unsafe { item_info.item_from_component(component_mem) };
|
||||||
item_info.rtti.properties[name.as_str()].get(item, &eval_context)
|
item_info.rtti.properties[name.as_str()].get(item)
|
||||||
}
|
}
|
||||||
Expression::RepeaterIndexReference { element } => {
|
Expression::RepeaterIndexReference { element } => {
|
||||||
if element.upgrade().unwrap().borrow().base_type
|
if element.upgrade().unwrap().borrow().base_type
|
||||||
|
@ -154,12 +152,7 @@ pub fn eval_expression(
|
||||||
{
|
{
|
||||||
let x = &component_type.custom_properties["index"];
|
let x = &component_type.custom_properties["index"];
|
||||||
unsafe {
|
unsafe {
|
||||||
x.prop
|
x.prop.get(Pin::new_unchecked(&*component_ref.as_ptr().add(x.offset))).unwrap()
|
||||||
.get(
|
|
||||||
Pin::new_unchecked(&*eval_context.component.as_ptr().add(x.offset)),
|
|
||||||
&eval_context,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
|
@ -171,26 +164,21 @@ pub fn eval_expression(
|
||||||
{
|
{
|
||||||
let x = &component_type.custom_properties["model_data"];
|
let x = &component_type.custom_properties["model_data"];
|
||||||
unsafe {
|
unsafe {
|
||||||
x.prop
|
x.prop.get(Pin::new_unchecked(&*component_ref.as_ptr().add(x.offset))).unwrap()
|
||||||
.get(
|
|
||||||
Pin::new_unchecked(&*eval_context.component.as_ptr().add(x.offset)),
|
|
||||||
&eval_context,
|
|
||||||
)
|
|
||||||
.unwrap()
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
todo!();
|
todo!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::ObjectAccess { base, name } => {
|
Expression::ObjectAccess { base, name } => {
|
||||||
if let Value::Object(mut o) = eval_expression(base, component_type, eval_context) {
|
if let Value::Object(mut o) = eval_expression(base, component_type, component_ref) {
|
||||||
o.remove(name).unwrap_or(Value::Void)
|
o.remove(name).unwrap_or(Value::Void)
|
||||||
} else {
|
} else {
|
||||||
Value::Void
|
Value::Void
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Cast { from, to } => {
|
Expression::Cast { from, to } => {
|
||||||
let v = eval_expression(&*from, component_type, eval_context);
|
let v = eval_expression(&*from, component_type, component_ref);
|
||||||
match (v, to) {
|
match (v, to) {
|
||||||
(Value::Number(n), Type::Int32) => Value::Number(n.round()),
|
(Value::Number(n), Type::Int32) => Value::Number(n.round()),
|
||||||
(Value::Number(n), Type::String) => {
|
(Value::Number(n), Type::String) => {
|
||||||
|
@ -203,15 +191,15 @@ pub fn eval_expression(
|
||||||
Expression::CodeBlock(sub) => {
|
Expression::CodeBlock(sub) => {
|
||||||
let mut v = Value::Void;
|
let mut v = Value::Void;
|
||||||
for e in sub {
|
for e in sub {
|
||||||
v = eval_expression(e, component_type, eval_context);
|
v = eval_expression(e, component_type, component_ref);
|
||||||
}
|
}
|
||||||
v
|
v
|
||||||
}
|
}
|
||||||
Expression::FunctionCall { function, .. } => {
|
Expression::FunctionCall { function, .. } => {
|
||||||
if let Expression::SignalReference(NamedReference { element, name }) = &**function {
|
if let Expression::SignalReference(NamedReference { element, name }) = &**function {
|
||||||
let element = element.upgrade().unwrap();
|
let element = element.upgrade().unwrap();
|
||||||
let (component_mem, component_type, eval_context) =
|
let (component_mem, component_type, _) =
|
||||||
enclosing_component_for_element(&element, component_type, eval_context);
|
enclosing_component_for_element(&element, component_type, component_ref);
|
||||||
|
|
||||||
let item_info = &component_type.items[element.borrow().id.as_str()];
|
let item_info = &component_type.items[element.borrow().id.as_str()];
|
||||||
let item = unsafe { item_info.item_from_component(component_mem) };
|
let item = unsafe { item_info.item_from_component(component_mem) };
|
||||||
|
@ -230,7 +218,7 @@ pub fn eval_expression(
|
||||||
.unwrap_or_else(|| panic!("unkown signal {}", name))
|
.unwrap_or_else(|| panic!("unkown signal {}", name))
|
||||||
as *mut corelib::Signal<()>)
|
as *mut corelib::Signal<()>)
|
||||||
};
|
};
|
||||||
signal.emit(&eval_context, ());
|
signal.emit(());
|
||||||
Value::Void
|
Value::Void
|
||||||
} else {
|
} else {
|
||||||
panic!("call of something not a signal")
|
panic!("call of something not a signal")
|
||||||
|
@ -239,7 +227,7 @@ 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 eval = |lhs| {
|
let eval = |lhs| {
|
||||||
let rhs = eval_expression(&**rhs, component_type, eval_context);
|
let rhs = eval_expression(&**rhs, component_type, component_ref);
|
||||||
match (lhs, rhs, op) {
|
match (lhs, rhs, op) {
|
||||||
(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),
|
(Value::Number(a), Value::Number(b), '-') => Value::Number(a - b),
|
||||||
|
@ -250,17 +238,15 @@ pub fn eval_expression(
|
||||||
};
|
};
|
||||||
|
|
||||||
let element = element.upgrade().unwrap();
|
let element = element.upgrade().unwrap();
|
||||||
let (component_mem, component_type, eval_context) =
|
let (component_mem, component_type, _) =
|
||||||
enclosing_component_for_element(&element, component_type, eval_context);
|
enclosing_component_for_element(&element, component_type, component_ref);
|
||||||
|
|
||||||
let component = element.borrow().enclosing_component.upgrade().unwrap();
|
let component = element.borrow().enclosing_component.upgrade().unwrap();
|
||||||
if element.borrow().id == component.root_element.borrow().id {
|
if element.borrow().id == component.root_element.borrow().id {
|
||||||
if let Some(x) = component_type.custom_properties.get(name) {
|
if let Some(x) = component_type.custom_properties.get(name) {
|
||||||
unsafe {
|
unsafe {
|
||||||
let p = Pin::new_unchecked(&*component_mem.add(x.offset));
|
let p = Pin::new_unchecked(&*component_mem.add(x.offset));
|
||||||
x.prop
|
x.prop.set(p, eval(x.prop.get(p).unwrap()), None).unwrap();
|
||||||
.set(p, eval(x.prop.get(p, &eval_context).unwrap()), None)
|
|
||||||
.unwrap();
|
|
||||||
}
|
}
|
||||||
return Value::Void;
|
return Value::Void;
|
||||||
}
|
}
|
||||||
|
@ -268,14 +254,14 @@ pub fn eval_expression(
|
||||||
let item_info = &component_type.items[element.borrow().id.as_str()];
|
let item_info = &component_type.items[element.borrow().id.as_str()];
|
||||||
let item = unsafe { item_info.item_from_component(component_mem) };
|
let item = unsafe { item_info.item_from_component(component_mem) };
|
||||||
let p = &item_info.rtti.properties[name.as_str()];
|
let p = &item_info.rtti.properties[name.as_str()];
|
||||||
p.set(item, eval(p.get(item, &eval_context)), None);
|
p.set(item, eval(p.get(item)), None);
|
||||||
Value::Void
|
Value::Void
|
||||||
}
|
}
|
||||||
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
_ => panic!("typechecking should make sure this was a PropertyReference"),
|
||||||
},
|
},
|
||||||
Expression::BinaryExpression { lhs, rhs, op } => {
|
Expression::BinaryExpression { lhs, rhs, op } => {
|
||||||
let lhs = eval_expression(&**lhs, component_type, eval_context);
|
let lhs = eval_expression(&**lhs, component_type, component_ref);
|
||||||
let rhs = eval_expression(&**rhs, component_type, eval_context);
|
let rhs = eval_expression(&**rhs, component_type, component_ref);
|
||||||
|
|
||||||
match (op, lhs, rhs) {
|
match (op, lhs, rhs) {
|
||||||
('+', Value::Number(a), Value::Number(b)) => Value::Number(a + b),
|
('+', Value::Number(a), Value::Number(b)) => Value::Number(a + b),
|
||||||
|
@ -294,7 +280,7 @@ pub fn eval_expression(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::UnaryOp { sub, op } => {
|
Expression::UnaryOp { sub, op } => {
|
||||||
let sub = eval_expression(&**sub, component_type, eval_context);
|
let sub = eval_expression(&**sub, component_type, component_ref);
|
||||||
match (sub, op) {
|
match (sub, op) {
|
||||||
(Value::Number(a), '+') => Value::Number(a),
|
(Value::Number(a), '+') => Value::Number(a),
|
||||||
(Value::Number(a), '-') => Value::Number(-a),
|
(Value::Number(a), '-') => Value::Number(-a),
|
||||||
|
@ -306,25 +292,25 @@ pub fn eval_expression(
|
||||||
Value::Resource(Resource::AbsoluteFilePath(absolute_source_path.as_str().into()))
|
Value::Resource(Resource::AbsoluteFilePath(absolute_source_path.as_str().into()))
|
||||||
}
|
}
|
||||||
Expression::Condition { condition, true_expr, false_expr } => {
|
Expression::Condition { condition, true_expr, false_expr } => {
|
||||||
match eval_expression(&**condition, component_type, eval_context).try_into()
|
match eval_expression(&**condition, component_type, component_ref).try_into()
|
||||||
as Result<bool, _>
|
as Result<bool, _>
|
||||||
{
|
{
|
||||||
Ok(true) => eval_expression(&**true_expr, component_type, eval_context),
|
Ok(true) => eval_expression(&**true_expr, component_type, component_ref),
|
||||||
Ok(false) => eval_expression(&**false_expr, component_type, eval_context),
|
Ok(false) => eval_expression(&**false_expr, component_type, component_ref),
|
||||||
_ => panic!("conditional expression did not evaluate to boolean"),
|
_ => panic!("conditional expression did not evaluate to boolean"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Array { values, .. } => Value::Array(
|
Expression::Array { values, .. } => Value::Array(
|
||||||
values.iter().map(|e| eval_expression(e, component_type, eval_context)).collect(),
|
values.iter().map(|e| eval_expression(e, component_type, component_ref)).collect(),
|
||||||
),
|
),
|
||||||
Expression::Object { values, .. } => Value::Object(
|
Expression::Object { values, .. } => Value::Object(
|
||||||
values
|
values
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| (k.clone(), eval_expression(v, component_type, eval_context)))
|
.map(|(k, v)| (k.clone(), eval_expression(v, component_type, component_ref)))
|
||||||
.collect(),
|
.collect(),
|
||||||
),
|
),
|
||||||
Expression::PathElements { elements } => {
|
Expression::PathElements { elements } => {
|
||||||
Value::PathElements(convert_path(elements, component_type, eval_context))
|
Value::PathElements(convert_path(elements, component_type, component_ref))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -332,16 +318,16 @@ pub fn eval_expression(
|
||||||
fn enclosing_component_for_element<'a>(
|
fn enclosing_component_for_element<'a>(
|
||||||
element: &ElementRc,
|
element: &ElementRc,
|
||||||
component_type: &'a crate::ComponentDescription,
|
component_type: &'a crate::ComponentDescription,
|
||||||
eval_context: &corelib::EvaluationContext<'a>,
|
component_ref: ComponentRefPin<'a>,
|
||||||
) -> (*const u8, &'a crate::ComponentDescription, corelib::EvaluationContext<'a>) {
|
) -> (*const u8, &'a crate::ComponentDescription, ComponentRefPin<'a>) {
|
||||||
if Rc::ptr_eq(
|
if Rc::ptr_eq(
|
||||||
&element.borrow().enclosing_component.upgrade().unwrap(),
|
&element.borrow().enclosing_component.upgrade().unwrap(),
|
||||||
&component_type.original,
|
&component_type.original,
|
||||||
) {
|
) {
|
||||||
let mem = eval_context.component.as_ptr();
|
let mem = component_ref.as_ptr();
|
||||||
(mem, component_type, EvaluationContext::for_root_component(eval_context.component))
|
(mem, component_type, component_ref)
|
||||||
} else {
|
} else {
|
||||||
let mem = eval_context.component.as_ptr();
|
let mem = component_ref.as_ptr();
|
||||||
let parent_component = unsafe {
|
let parent_component = unsafe {
|
||||||
*(mem.add(component_type.parent_component_offset.unwrap())
|
*(mem.add(component_type.parent_component_offset.unwrap())
|
||||||
as *const Option<corelib::ComponentRefPin>)
|
as *const Option<corelib::ComponentRefPin>)
|
||||||
|
@ -349,11 +335,7 @@ fn enclosing_component_for_element<'a>(
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let parent_component_type =
|
let parent_component_type =
|
||||||
unsafe { crate::dynamic_component::get_component_type(parent_component) };
|
unsafe { crate::dynamic_component::get_component_type(parent_component) };
|
||||||
enclosing_component_for_element(
|
enclosing_component_for_element(element, parent_component_type, parent_component)
|
||||||
element,
|
|
||||||
parent_component_type,
|
|
||||||
&EvaluationContext::for_root_component(parent_component),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -362,12 +344,12 @@ pub fn new_struct_with_bindings<
|
||||||
>(
|
>(
|
||||||
bindings: &HashMap<String, Expression>,
|
bindings: &HashMap<String, Expression>,
|
||||||
component_type: &crate::ComponentDescription,
|
component_type: &crate::ComponentDescription,
|
||||||
eval_context: &corelib::EvaluationContext,
|
component_ref: ComponentRefPin,
|
||||||
) -> ElementType {
|
) -> ElementType {
|
||||||
let mut element = ElementType::default();
|
let mut element = ElementType::default();
|
||||||
for (prop, info) in ElementType::fields::<Value>().into_iter() {
|
for (prop, info) in ElementType::fields::<Value>().into_iter() {
|
||||||
if let Some(binding) = &bindings.get(prop) {
|
if let Some(binding) = &bindings.get(prop) {
|
||||||
let value = eval_expression(&binding, &*component_type, &eval_context);
|
let value = eval_expression(&binding, &*component_type, component_ref);
|
||||||
info.set_field(&mut element, value).unwrap();
|
info.set_field(&mut element, value).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,7 +410,7 @@ fn convert_from_lyon_path<'a>(
|
||||||
pub fn convert_path(
|
pub fn convert_path(
|
||||||
path: &ExprPath,
|
path: &ExprPath,
|
||||||
component_type: &crate::ComponentDescription,
|
component_type: &crate::ComponentDescription,
|
||||||
eval_context: &corelib::EvaluationContext,
|
eval_context: ComponentRefPin,
|
||||||
) -> PathData {
|
) -> PathData {
|
||||||
match path {
|
match path {
|
||||||
ExprPath::Elements(elements) => PathData::Elements(SharedArray::<PathElement>::from_iter(
|
ExprPath::Elements(elements) => PathData::Elements(SharedArray::<PathElement>::from_iter(
|
||||||
|
@ -443,7 +425,7 @@ pub fn convert_path(
|
||||||
fn convert_path_element(
|
fn convert_path_element(
|
||||||
expr_element: &ExprPathElement,
|
expr_element: &ExprPathElement,
|
||||||
component_type: &crate::ComponentDescription,
|
component_type: &crate::ComponentDescription,
|
||||||
eval_context: &corelib::EvaluationContext,
|
eval_context: ComponentRefPin,
|
||||||
) -> PathElement {
|
) -> PathElement {
|
||||||
match expr_element.element_type.class_name.as_str() {
|
match expr_element.element_type.class_name.as_str() {
|
||||||
"LineTo" => PathElement::LineTo(new_struct_with_bindings(
|
"LineTo" => PathElement::LineTo(new_struct_with_bindings(
|
||||||
|
|
|
@ -16,7 +16,7 @@ pub use eval::Value;
|
||||||
|
|
||||||
pub use dynamic_component::ComponentBox;
|
pub use dynamic_component::ComponentBox;
|
||||||
use sixtyfps_corelib::abi::datastructures::{ComponentRef, ComponentRefMut};
|
use sixtyfps_corelib::abi::datastructures::{ComponentRef, ComponentRefMut};
|
||||||
use sixtyfps_corelib::{ComponentRefPin, EvaluationContext, Signal};
|
use sixtyfps_corelib::{ComponentRefPin, Signal};
|
||||||
use std::{collections::HashMap, pin::Pin, rc::Rc};
|
use std::{collections::HashMap, pin::Pin, rc::Rc};
|
||||||
|
|
||||||
impl ComponentDescription {
|
impl ComponentDescription {
|
||||||
|
@ -66,7 +66,7 @@ impl ComponentDescription {
|
||||||
&self,
|
&self,
|
||||||
component: ComponentRef,
|
component: ComponentRef,
|
||||||
name: &str,
|
name: &str,
|
||||||
binding: Box<dyn Fn(&EvaluationContext) -> Value>,
|
binding: Box<dyn Fn() -> Value>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
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(());
|
||||||
|
@ -84,17 +84,12 @@ impl ComponentDescription {
|
||||||
///
|
///
|
||||||
/// Returns an error if the component is not an instance corresponding to this ComponentDescription,
|
/// Returns an error if the component is not an instance corresponding to this ComponentDescription,
|
||||||
/// or if a signal with this name does not exist in this component
|
/// or if a signal with this name does not exist in this component
|
||||||
pub fn get_property(&self, eval_context: &EvaluationContext, name: &str) -> Result<Value, ()> {
|
pub fn get_property(&self, component: ComponentRefPin, name: &str) -> Result<Value, ()> {
|
||||||
if !core::ptr::eq((&self.ct) as *const _, eval_context.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(())?;
|
let x = self.custom_properties.get(name).ok_or(())?;
|
||||||
unsafe {
|
unsafe { x.prop.get(Pin::new_unchecked(&*component.as_ptr().add(x.offset))) }
|
||||||
x.prop.get(
|
|
||||||
Pin::new_unchecked(&*eval_context.component.as_ptr().add(x.offset)),
|
|
||||||
eval_context,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sets an handler for a signal
|
/// Sets an handler for a signal
|
||||||
|
@ -105,7 +100,7 @@ impl ComponentDescription {
|
||||||
&self,
|
&self,
|
||||||
component: Pin<ComponentRefMut>,
|
component: Pin<ComponentRefMut>,
|
||||||
name: &str,
|
name: &str,
|
||||||
handler: Box<dyn Fn(&EvaluationContext, ())>,
|
handler: Box<dyn Fn(())>,
|
||||||
) -> Result<(), ()> {
|
) -> Result<(), ()> {
|
||||||
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(());
|
||||||
|
@ -120,14 +115,13 @@ impl ComponentDescription {
|
||||||
///
|
///
|
||||||
/// Returns an error if the component is not an instance corresponding to this ComponentDescription,
|
/// Returns an error if the component is not an instance corresponding to this ComponentDescription,
|
||||||
/// or if the signal with this name does not exist in this component
|
/// or if the signal with this name does not exist in this component
|
||||||
pub fn emit_signal(&self, eval_context: &EvaluationContext, name: &str) -> Result<(), ()> {
|
pub fn emit_signal(&self, component: ComponentRefPin, name: &str) -> Result<(), ()> {
|
||||||
let component = eval_context.component;
|
|
||||||
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_signals.get(name).ok_or(())?;
|
let x = self.custom_signals.get(name).ok_or(())?;
|
||||||
let sig = unsafe { &mut *(component.as_ptr().add(*x) as *mut Signal<()>) };
|
let sig = unsafe { &mut *(component.as_ptr().add(*x) as *mut Signal<()>) };
|
||||||
sig.emit(eval_context, ());
|
sig.emit(());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue