mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 14:21:16 +00:00
Docs for PropertyTracker
This commit is contained in:
parent
bfd2a2add9
commit
26b58bb0a5
1 changed files with 116 additions and 63 deletions
|
@ -25,37 +25,48 @@ using cbindgen_private::StateInfo;
|
||||||
|
|
||||||
namespace private_api {
|
namespace private_api {
|
||||||
|
|
||||||
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle,
|
void sixtyfps_property_set_animated_binding_helper(
|
||||||
void (*binding)(void*, int32_t*), void *user_data, void (*drop_user_data)(void*),
|
const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, int32_t *),
|
||||||
|
void *user_data, void (*drop_user_data)(void *),
|
||||||
const cbindgen_private::PropertyAnimation *animation_data,
|
const cbindgen_private::PropertyAnimation *animation_data,
|
||||||
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) {
|
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
|
||||||
cbindgen_private::sixtyfps_property_set_animated_binding_int(handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
{
|
||||||
|
cbindgen_private::sixtyfps_property_set_animated_binding_int(
|
||||||
|
handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle,
|
void sixtyfps_property_set_animated_binding_helper(
|
||||||
void (*binding)(void*, float*), void *user_data, void (*drop_user_data)(void*),
|
const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, float *),
|
||||||
|
void *user_data, void (*drop_user_data)(void *),
|
||||||
const cbindgen_private::PropertyAnimation *animation_data,
|
const cbindgen_private::PropertyAnimation *animation_data,
|
||||||
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) {
|
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
|
||||||
cbindgen_private::sixtyfps_property_set_animated_binding_float(handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
{
|
||||||
|
cbindgen_private::sixtyfps_property_set_animated_binding_float(
|
||||||
|
handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle,
|
void sixtyfps_property_set_animated_binding_helper(
|
||||||
void (*binding)(void*, Color*), void *user_data, void (*drop_user_data)(void*),
|
const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, Color *),
|
||||||
|
void *user_data, void (*drop_user_data)(void *),
|
||||||
const cbindgen_private::PropertyAnimation *animation_data,
|
const cbindgen_private::PropertyAnimation *animation_data,
|
||||||
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) {
|
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
|
||||||
cbindgen_private::sixtyfps_property_set_animated_binding_color(handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
{
|
||||||
|
cbindgen_private::sixtyfps_property_set_animated_binding_color(
|
||||||
|
handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle,
|
void sixtyfps_property_set_animated_binding_helper(
|
||||||
void (*binding)(void*, Brush*), void *user_data, void (*drop_user_data)(void*),
|
const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void *, Brush *),
|
||||||
|
void *user_data, void (*drop_user_data)(void *),
|
||||||
const cbindgen_private::PropertyAnimation *animation_data,
|
const cbindgen_private::PropertyAnimation *animation_data,
|
||||||
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *)) {
|
cbindgen_private::PropertyAnimation (*transition_data)(void *, uint64_t *))
|
||||||
cbindgen_private::sixtyfps_property_set_animated_binding_brush(handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
{
|
||||||
|
cbindgen_private::sixtyfps_property_set_animated_binding_brush(
|
||||||
|
handle, binding, user_data, drop_user_data, animation_data, transition_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct Property
|
struct Property
|
||||||
{
|
{
|
||||||
|
@ -101,10 +112,11 @@ struct Property
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void set_animated_value(const T &value,
|
inline void set_animated_value(const T &value,
|
||||||
const cbindgen_private::PropertyAnimation &animation_data) const ;
|
const cbindgen_private::PropertyAnimation &animation_data) const;
|
||||||
template<typename F>
|
template<typename F>
|
||||||
inline void set_animated_binding(F binding,
|
inline void
|
||||||
const cbindgen_private::PropertyAnimation &animation_data) const {
|
set_animated_binding(F binding, const cbindgen_private::PropertyAnimation &animation_data) const
|
||||||
|
{
|
||||||
private_api::sixtyfps_property_set_animated_binding_helper(
|
private_api::sixtyfps_property_set_animated_binding_helper(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, T *value) {
|
[](void *user_data, T *value) {
|
||||||
|
@ -115,19 +127,21 @@ struct Property
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename Trans>
|
template<typename F, typename Trans>
|
||||||
inline void set_animated_binding_for_transition(F binding, Trans animation) const {
|
inline void set_animated_binding_for_transition(F binding, Trans animation) const
|
||||||
struct UserData {
|
{
|
||||||
|
struct UserData
|
||||||
|
{
|
||||||
F binding;
|
F binding;
|
||||||
Trans animation;
|
Trans animation;
|
||||||
};
|
};
|
||||||
private_api::sixtyfps_property_set_animated_binding_helper(
|
private_api::sixtyfps_property_set_animated_binding_helper(
|
||||||
&inner,
|
&inner,
|
||||||
[](void *user_data, T *value) {
|
[](void *user_data, T *value) {
|
||||||
*reinterpret_cast<T *>(value) = reinterpret_cast<UserData *>(user_data)->binding();
|
*reinterpret_cast<T *>(value) =
|
||||||
|
reinterpret_cast<UserData *>(user_data)->binding();
|
||||||
},
|
},
|
||||||
new UserData{binding, animation},
|
new UserData { binding, animation },
|
||||||
[](void *user_data) { delete reinterpret_cast<UserData *>(user_data); },
|
[](void *user_data) { delete reinterpret_cast<UserData *>(user_data); }, nullptr,
|
||||||
nullptr,
|
|
||||||
[](void *user_data, uint64_t *instant) {
|
[](void *user_data, uint64_t *instant) {
|
||||||
return reinterpret_cast<UserData *>(user_data)->animation(instant);
|
return reinterpret_cast<UserData *>(user_data)->animation(instant);
|
||||||
});
|
});
|
||||||
|
@ -135,14 +149,16 @@ struct Property
|
||||||
|
|
||||||
bool is_dirty() const { return cbindgen_private::sixtyfps_property_is_dirty(&inner); }
|
bool is_dirty() const { return cbindgen_private::sixtyfps_property_is_dirty(&inner); }
|
||||||
|
|
||||||
static void link_two_way(const Property<T> *p1, const Property<T> *p2) {
|
static void link_two_way(const Property<T> *p1, const Property<T> *p2)
|
||||||
|
{
|
||||||
auto value = p2->get();
|
auto value = p2->get();
|
||||||
cbindgen_private::PropertyHandleOpaque handle{};
|
cbindgen_private::PropertyHandleOpaque handle {};
|
||||||
if ((p2->inner._0 & 0b10) == 0b10) {
|
if ((p2->inner._0 & 0b10) == 0b10) {
|
||||||
std::swap(handle, const_cast<Property<T>*>(p2)->inner);
|
std::swap(handle, const_cast<Property<T> *>(p2)->inner);
|
||||||
}
|
}
|
||||||
auto common_property = std::make_shared<Property<T>>(handle, std::move(value));
|
auto common_property = std::make_shared<Property<T>>(handle, std::move(value));
|
||||||
struct TwoWayBinding {
|
struct TwoWayBinding
|
||||||
|
{
|
||||||
std::shared_ptr<Property<T>> common_property;
|
std::shared_ptr<Property<T>> common_property;
|
||||||
};
|
};
|
||||||
auto del_fn = [](void *user_data) { delete reinterpret_cast<TwoWayBinding *>(user_data); };
|
auto del_fn = [](void *user_data) { delete reinterpret_cast<TwoWayBinding *>(user_data); };
|
||||||
|
@ -150,31 +166,35 @@ struct Property
|
||||||
*reinterpret_cast<T *>(value) =
|
*reinterpret_cast<T *>(value) =
|
||||||
reinterpret_cast<TwoWayBinding *>(user_data)->common_property->get();
|
reinterpret_cast<TwoWayBinding *>(user_data)->common_property->get();
|
||||||
};
|
};
|
||||||
auto intercept_fn = [] (void *user_data, const void *value) {
|
auto intercept_fn = [](void *user_data, const void *value) {
|
||||||
reinterpret_cast<TwoWayBinding *>(user_data)->common_property->set(
|
reinterpret_cast<TwoWayBinding *>(user_data)->common_property->set(
|
||||||
*reinterpret_cast<const T *>(value));
|
*reinterpret_cast<const T *>(value));
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
auto intercept_binding_fn = [] (void *user_data, void *value) {
|
auto intercept_binding_fn = [](void *user_data, void *value) {
|
||||||
cbindgen_private::sixtyfps_property_set_binding_internal(
|
cbindgen_private::sixtyfps_property_set_binding_internal(
|
||||||
&reinterpret_cast<TwoWayBinding *>(user_data)->common_property->inner,
|
&reinterpret_cast<TwoWayBinding *>(user_data)->common_property->inner, value);
|
||||||
value);
|
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
cbindgen_private::sixtyfps_property_set_binding(&p1->inner, call_fn,
|
cbindgen_private::sixtyfps_property_set_binding(&p1->inner, call_fn,
|
||||||
new TwoWayBinding{common_property}, del_fn, intercept_fn, intercept_binding_fn);
|
new TwoWayBinding { common_property },
|
||||||
|
del_fn, intercept_fn, intercept_binding_fn);
|
||||||
cbindgen_private::sixtyfps_property_set_binding(&p2->inner, call_fn,
|
cbindgen_private::sixtyfps_property_set_binding(&p2->inner, call_fn,
|
||||||
new TwoWayBinding{common_property}, del_fn, intercept_fn, intercept_binding_fn);
|
new TwoWayBinding { common_property },
|
||||||
|
del_fn, intercept_fn, intercept_binding_fn);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Internal (private) constructor used by link_two_way
|
/// Internal (private) constructor used by link_two_way
|
||||||
explicit Property(cbindgen_private::PropertyHandleOpaque inner, T value)
|
explicit Property(cbindgen_private::PropertyHandleOpaque inner, T value)
|
||||||
: inner(inner), value(std::move(value)) {}
|
: inner(inner), value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
cbindgen_private::PropertyHandleOpaque inner;
|
cbindgen_private::PropertyHandleOpaque inner;
|
||||||
mutable T value {};
|
mutable T value {};
|
||||||
template<typename F> friend void set_state_binding(const Property<StateInfo> &property, F binding);
|
template<typename F>
|
||||||
|
friend void set_state_binding(const Property<StateInfo> &property, F binding);
|
||||||
};
|
};
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
@ -186,32 +206,51 @@ void Property<int32_t>::set_animated_value(
|
||||||
}
|
}
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
void Property<float>::set_animated_value(const float &new_value,
|
void Property<float>::set_animated_value(
|
||||||
const cbindgen_private::PropertyAnimation &animation_data) const
|
const float &new_value, const cbindgen_private::PropertyAnimation &animation_data) const
|
||||||
{
|
{
|
||||||
cbindgen_private::sixtyfps_property_set_animated_value_float(&inner, value, new_value,
|
cbindgen_private::sixtyfps_property_set_animated_value_float(&inner, value, new_value,
|
||||||
&animation_data);
|
&animation_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void set_state_binding(const Property<StateInfo> &property, F binding) {
|
void set_state_binding(const Property<StateInfo> &property, F binding)
|
||||||
|
{
|
||||||
cbindgen_private::sixtyfps_property_set_state_binding(
|
cbindgen_private::sixtyfps_property_set_state_binding(
|
||||||
&property.inner,
|
&property.inner,
|
||||||
[](void *user_data) -> int32_t { return (*reinterpret_cast<F *>(user_data))(); },
|
[](void *user_data) -> int32_t { return (*reinterpret_cast<F *>(user_data))(); },
|
||||||
new F(binding),
|
new F(binding), [](void *user_data) { delete reinterpret_cast<F *>(user_data); });
|
||||||
[](void *user_data) { delete reinterpret_cast<F *>(user_data); });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// PropertyTracker allows keeping track of when properties change and lazily evaluate code
|
||||||
|
/// if necessary.
|
||||||
|
/// Once constructed, you can call evaluate() with a functor that will be invoked. Any
|
||||||
|
/// Property<T> types that have their value read from within the invoked functor or any code that's
|
||||||
|
/// reached from there are added to internal book-keeping. When after returning from evaluate(),
|
||||||
|
/// any of these accessed properties change their value, the property tracker's is_dirt() function
|
||||||
|
/// will return true.
|
||||||
|
///
|
||||||
|
/// PropertyTracker instances nest, so if during the evaluation of one tracker, another tracker's
|
||||||
|
/// evaluate() function gets called and properties from within that evaluation change their value
|
||||||
|
/// later, both tracker instances will report true for is_dirty(). If you would like to disable the
|
||||||
|
/// nesting, use the evaluate_as_dependency_root() function instead.
|
||||||
struct PropertyTracker
|
struct PropertyTracker
|
||||||
{
|
{
|
||||||
|
/// Constructs a new property tracker instance.
|
||||||
PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_init(&inner); }
|
PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_init(&inner); }
|
||||||
|
/// Destroys the property tracker.
|
||||||
~PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_drop(&inner); }
|
~PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_drop(&inner); }
|
||||||
|
/// The copy constructor is intentionally deleted, property trackers cannot be copied.
|
||||||
PropertyTracker(const PropertyTracker &) = delete;
|
PropertyTracker(const PropertyTracker &) = delete;
|
||||||
|
/// The assignment operator is intentionally deleted, property trackers cannot be copied.
|
||||||
PropertyTracker &operator=(const PropertyTracker &) = delete;
|
PropertyTracker &operator=(const PropertyTracker &) = delete;
|
||||||
|
|
||||||
|
/// Returns true if any properties accessed during the last evaluate() call have changed their
|
||||||
|
/// value since then.
|
||||||
bool is_dirty() const { return cbindgen_private::sixtyfps_property_tracker_is_dirty(&inner); }
|
bool is_dirty() const { return cbindgen_private::sixtyfps_property_tracker_is_dirty(&inner); }
|
||||||
|
|
||||||
|
/// Invokes the provided functor \a f and tracks accessed to any properties during that
|
||||||
|
/// invokation.
|
||||||
template<typename F>
|
template<typename F>
|
||||||
auto evaluate(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>>
|
auto evaluate(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>>
|
||||||
{
|
{
|
||||||
|
@ -219,6 +258,9 @@ struct PropertyTracker
|
||||||
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
|
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the provided functor \a f and tracks accessed to any properties during that
|
||||||
|
/// invokation. Use this overload if your functor returns a value, as evaluate() will pass it on
|
||||||
|
/// and return it.
|
||||||
template<typename F>
|
template<typename F>
|
||||||
auto evaluate(const F &f) const
|
auto evaluate(const F &f) const
|
||||||
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
|
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
|
||||||
|
@ -228,13 +270,25 @@ struct PropertyTracker
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the provided functor \a f and tracks accessed to any properties during that
|
||||||
|
/// invokation.
|
||||||
|
///
|
||||||
|
/// This starts a new dependency chain and if called during the evaluation of another
|
||||||
|
/// property tracker, the outer tracker will not be notified if any accessed properties change.
|
||||||
template<typename F>
|
template<typename F>
|
||||||
auto evaluate_as_dependency_root(const F &f) const -> std::enable_if_t<std::is_same_v<decltype(f()), void>>
|
auto evaluate_as_dependency_root(const F &f) const
|
||||||
|
-> std::enable_if_t<std::is_same_v<decltype(f()), void>>
|
||||||
{
|
{
|
||||||
cbindgen_private::sixtyfps_property_tracker_evaluate_as_dependency_root(
|
cbindgen_private::sixtyfps_property_tracker_evaluate_as_dependency_root(
|
||||||
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
|
&inner, [](void *f) { (*reinterpret_cast<const F *>(f))(); }, const_cast<F *>(&f));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Invokes the provided functor \a f and tracks accessed to any properties during that
|
||||||
|
/// invokation. Use this overload if your functor returns a value, as evaluate() will pass it on
|
||||||
|
/// and return it.
|
||||||
|
///
|
||||||
|
/// This starts a new dependency chain and if called during the evaluation of another
|
||||||
|
/// property tracker, the outer tracker will not be notified if any accessed properties change.
|
||||||
template<typename F>
|
template<typename F>
|
||||||
auto evaluate_as_dependency_root(const F &f) const
|
auto evaluate_as_dependency_root(const F &f) const
|
||||||
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
|
-> std::enable_if_t<!std::is_same_v<decltype(f()), void>, decltype(f())>
|
||||||
|
@ -249,4 +303,3 @@ private:
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace sixtyfps
|
} // namespace sixtyfps
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue