/* LICENSE BEGIN This file is part of the SixtyFPS Project -- https://sixtyfps.io Copyright (c) 2020 Olivier Goffart Copyright (c) 2020 Simon Hausmann SPDX-License-Identifier: GPL-3.0-only This file is also available under commercial licensing terms. Please contact info@sixtyfps.io for more information. LICENSE END */ #pragma once #include #include namespace sixtyfps { namespace cbindgen_private { struct PropertyAnimation; } } #include "sixtyfps_properties_internal.h" namespace sixtyfps { using cbindgen_private::StateInfo; namespace private_api { void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void*, int32_t*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyAnimation *animation_data, 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); } void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void*, float*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyAnimation *animation_data, 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); } void sixtyfps_property_set_animated_binding_helper(const cbindgen_private::PropertyHandleOpaque *handle, void (*binding)(void*, Color*), void *user_data, void (*drop_user_data)(void*), const cbindgen_private::PropertyAnimation *animation_data, 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); } } template struct Property { Property() { cbindgen_private::sixtyfps_property_init(&inner); } ~Property() { cbindgen_private::sixtyfps_property_drop(&inner); } Property(const Property &) = delete; Property(Property &&) = delete; Property &operator=(const Property &) = delete; explicit Property(const T &value) : value(value) { cbindgen_private::sixtyfps_property_init(&inner); } /* Should it be implicit? void operator=(const T &value) { set(value); }*/ void set(const T &value) const { if (this->value != value) { this->value = value; cbindgen_private::sixtyfps_property_set_changed(&inner, &this->value); } } const T &get() const { cbindgen_private::sixtyfps_property_update(&inner, &value); return value; } template void set_binding(F binding) const { cbindgen_private::sixtyfps_property_set_binding( &inner, [](void *user_data, void *value) { *reinterpret_cast(value) = (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }, nullptr, nullptr); } inline void set_animated_value(const T &value, const cbindgen_private::PropertyAnimation &animation_data) const ; template inline void set_animated_binding(F binding, const cbindgen_private::PropertyAnimation &animation_data) const { private_api::sixtyfps_property_set_animated_binding_helper( &inner, [](void *user_data, T *value) { *reinterpret_cast(value) = (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }, &animation_data, nullptr); } template inline void set_animated_binding_for_transition(F binding, Trans animation) const { struct UserData { F binding; Trans animation; }; private_api::sixtyfps_property_set_animated_binding_helper( &inner, [](void *user_data, T *value) { *reinterpret_cast(value) = reinterpret_cast(user_data)->binding(); }, new UserData{binding, animation}, [](void *user_data) { delete reinterpret_cast(user_data); }, nullptr, [](void *user_data, uint64_t *instant) { return reinterpret_cast(user_data)->animation(instant); }); } bool is_dirty() const { return cbindgen_private::sixtyfps_property_is_dirty(&inner); } static void link_two_way(const Property *p1, const Property *p2) { auto value = p2->get(); cbindgen_private::PropertyHandleOpaque handle{}; if ((p2->inner._0 & 0b10) == 0b10) { std::swap(handle, const_cast*>(p2)->inner); } auto common_property = std::make_shared>(handle, std::move(value)); struct TwoWayBinding { std::shared_ptr> common_property; }; auto del_fn = [](void *user_data) { delete reinterpret_cast(user_data); }; auto call_fn = [](void *user_data, void *value) { *reinterpret_cast(value) = reinterpret_cast(user_data)->common_property->get(); }; auto intercept_fn = [] (void *user_data, const void *value) { reinterpret_cast(user_data)->common_property->set( *reinterpret_cast(value)); return true; }; auto intercept_binding_fn = [] (void *user_data, void *value) { cbindgen_private::sixtyfps_property_set_binding_internal( &reinterpret_cast(user_data)->common_property->inner, value); return true; }; cbindgen_private::sixtyfps_property_set_binding(&p1->inner, call_fn, new TwoWayBinding{common_property}, del_fn, intercept_fn, intercept_binding_fn); cbindgen_private::sixtyfps_property_set_binding(&p2->inner, call_fn, new TwoWayBinding{common_property}, del_fn, intercept_fn, intercept_binding_fn); } /// Internal (private) constructor used by link_two_way explicit Property(cbindgen_private::PropertyHandleOpaque inner, T value) : inner(inner), value(std::move(value)) {} private: cbindgen_private::PropertyHandleOpaque inner; mutable T value {}; template friend void set_state_binding(const Property &property, F binding); }; template<> void Property::set_animated_value( const int32_t &new_value, const cbindgen_private::PropertyAnimation &animation_data) const { cbindgen_private::sixtyfps_property_set_animated_value_int(&inner, value, new_value, &animation_data); } template<> void Property::set_animated_value(const float &new_value, const cbindgen_private::PropertyAnimation &animation_data) const { cbindgen_private::sixtyfps_property_set_animated_value_float(&inner, value, new_value, &animation_data); } template void set_state_binding(const Property &property, F binding) { cbindgen_private::sixtyfps_property_set_state_binding( &property.inner, [](void *user_data) -> int32_t { return (*reinterpret_cast(user_data))(); }, new F(binding), [](void *user_data) { delete reinterpret_cast(user_data); }); } struct PropertyTracker { PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_init(&inner); } ~PropertyTracker() { cbindgen_private::sixtyfps_property_tracker_drop(&inner); } PropertyTracker(const PropertyTracker &) = delete; PropertyTracker &operator=(const PropertyTracker &) = delete; bool is_dirty() const { return cbindgen_private::sixtyfps_property_tracker_is_dirty(&inner); } template auto evaluate(const F &f) const -> std::enable_if_t> { cbindgen_private::sixtyfps_property_tracker_evaluate( &inner, [](void *f) { (*reinterpret_cast(f))(); }, const_cast(&f)); } template auto evaluate(const F &f) const -> std::enable_if_t, decltype(f())> { decltype(f()) result; this->evaluate([&] { result = f(); }); return result; } private: cbindgen_private::PropertyTrackerOpaque inner; }; } // namespace sixtyfps