14#include "AUI/Traits/concepts.h"
15#include "ALayoutInflater.h"
18#include <AUI/Common/SharedPtr.h>
19#include <AUI/Common/ASignal.h>
20#include <AUI/Traits/members.h>
21#include <AUI/View/AViewContainer.h>
22#include <AUI/Reflect/members.h>
37template<
typename View,
typename FieldType>
55 [[deprecated(
"ADataBinding is deprecated. Please use Property System to bind values")]]
63 [[deprecated(
"ADataBinding is deprecated. Please use Property System to bind values")]]
64 static void(View::*
getSetter())(
const FieldType& v) {
69template<aui::derived_from<AViewContainer> Container>
75 [&container = *container](
const _<AView>& viewToInflate) {
82template <
typename Model>
85template<
typename Model,
typename View,
typename ModelField,
typename Getter, aui::invocable<View*, const ModelField&> Setter>
86class ADataBindingLinker {
90 std::decay_t<ModelField>(Model::*mField);
95 std::decay_t<ModelField>(Model::*field)):
96 mBinder(binder), mGetter(getter), setter(std::move(setter)), mField(field) {}
102 auto getSetterFunc()
const {
106 auto getField()
const {
110 auto getGetter()
const {
114template<
typename Model,
typename Data,
typename Projection>
115class ADataBindingLinker2 {
118 Data(Model::*mField);
119 Projection mProjection;
122 ADataBindingLinker2(
ADataBinding<Model>* binder, Data(Model::*field), Projection projection =
nullptr) : mBinder(binder), mField(field), mProjection(std::move(projection)) {}
128 auto getField()
const {
132 Projection getProjection()
const {
200template <
typename Model>
201class [[deprecated(
"consider using AProperty and signal/slot connections instead")]] ADataBinding:
public AObject {
203 using Observer = std::function<void(
const Model& model,
unsigned)>;
206 Model* mModel =
nullptr;
207 bool mOwning =
false;
209 void* mExcept =
nullptr;
213 ADataBinding() =
default;
214 explicit ADataBinding(
const Model& m)
218 explicit ADataBinding(Model* m)
223 virtual ~ADataBinding() {
234 template<
typename View,
typename ModelField,
typename SetterArg>
235 auto operator()(ModelField(Model::*field),
void(View::*setterFunc)(SetterArg)) {
237 return operator()<View, ModelField>(field, (ASignal<ModelField>(View::*))
nullptr, setterFunc);
256 template<
typename ModelField,
typename SetterLambda>
257 auto operator()(ModelField(Model::*field), SetterLambda setterLambda) {
258 using lambda_args =
typename aui::lambda_info<SetterLambda>::args;
260 static_assert(std::is_reference_v<ViewReference>,
"View is expected to be a reference");
262 using View = std::decay_t<ViewReference>;
263 return operator()<View, ModelField>(field, (ASignal<ModelField>(View::*))
nullptr, [setterLambda = std::move(setterLambda)](View* view, DataArgument dataArgument) {
264 std::invoke(setterLambda, *view, std::forward<DataArgument>(dataArgument));
275 template<
typename View,
typename ModelField,
typename GetterRV, aui::invocable<View*, const ModelField&> Setter>
277 ASignal<GetterRV>(View::*getter),
278 Setter setter = (
void(View::*)(
const ModelField&))
nullptr) {
288 template<
typename Data>
298 template<
typename Data, aui::invocable<Data> Projection>
302 const Model& getModel() const noexcept {
306 Model
const * operator->() const noexcept {
310 Model& getEditableModel() {
313 void setModel(
const Model& model) {
318 mModel =
new Model(model);
322 void setModel(Model* model) {
331 const void* getExclusion()
const {
335 void notifyUpdate(
void* except =
nullptr,
unsigned field = -1) {
337 for (
auto& applier : mLinkObservers) {
338 applier(*mModel, field);
343 template<
typename ModelField>
344 void notifyUpdate(ModelField(Model::*field)) {
350 notifyUpdate(
nullptr,
c.i);
353 template<
typename ModelField, aui::convertible_to<ModelField> U>
354 void setValue(ModelField(Model::*field), U&& value) {
355 mModel->*field = std::move(value);
359 void addObserver(Observer applier) {
360 mLinkObservers << std::move(applier);
362 mLinkObservers.
last()(*mModel, -1);
366 template<aui::invocable T>
367 void addObserver(T&& applier) {
368 addObserver([applier = std::forward<T>(applier)](
const Model&,
unsigned) {
373 template<
typename ModelField,
typename FieldObserver>
374 void addObserverNoInitialCall(ModelField(Model::*field), FieldObserver&& observer) {
375 mLinkObservers << [observer = std::forward<FieldObserver>(observer), field](
const Model& model,
unsigned index) {
381 if (
c.i == index || index == -1) {
382 observer(model.*field);
386 template<
typename ModelField,
typename FieldObserver>
387 void addObserver(ModelField(Model::*field), FieldObserver&& observer) {
388 addObserverNoInitialCall(field, std::forward<FieldObserver>(observer));
390 mLinkObservers.
last()(*mModel, -1);
402template<
typename Klass1,
typename View,
typename Model,
typename ModelField,
typename GetterRV,
typename SetterArg>
406 decltype(linker.getField()) p;
408 if (linker.getGetter()) {
409 AObject::connect(modelBinding.get()->*(linker.getGetter()), linker.getBinder(), [modelBinding, linker](
const GetterRV& data) {
410 AUI_ASSERTX(&linker.getBinder()->getEditableModel(),
"please setModel for ADataBinding");
411 modelBinding->setSignalsEnabled(false);
412 linker.getBinder()->getEditableModel().*(linker.getField()) = data;
414 c.p = linker.getField();
415 linker.getBinder()->notifyUpdate(modelBinding.get(), c.i);
416 modelBinding->setSignalsEnabled(true);
421 if (!
bool(linker.getSetterFunc())) {
425 linker.getBinder()->addObserver([modelBinding, linker](
const Model& model,
unsigned field) {
427 c.p = linker.getField();
428 if (
c.i == field || field == -1) {
429 if (modelBinding.get() != linker.getBinder()->getExclusion()) {
430 std::invoke(linker.getSetterFunc(), modelBinding.get(), model.*(linker.getField()));
439namespace aui::detail {
440 template<
typename ForcedClazz,
typename Type>
441 struct pointer_to_member {
442 template<
typename... Args>
443 static Type(ForcedClazz::*with_args(std::tuple<Args...>))(Args...) {
449template<
typename View,
typename Model,
typename Data,
typename Projection>
453 constexpr bool is_default_projection = std::is_same_v<Projection, std::nullptr_t>;
454 using projection_deduced = std::conditional_t<is_default_projection, aui::identity, Projection>;
455 static_assert(std::is_invocable_v<projection_deduced, Data>,
"projection is expected to accept Data value from model");
456 using data_deduced = std::decay_t<std::invoke_result_t<projection_deduced, Data>>;
461 using setter_ret =
typename setter::return_t;
462 using setter_args =
typename setter::args;
464 using my_pointer_to_member =
typename aui::detail::pointer_to_member<View, setter_ret>;
466 using pointer_to_setter =
decltype(my_pointer_to_member::with_args(std::declval<setter_args>()));
468 if constexpr (is_default_projection) {
481 AUI_ASSERTX(g !=
nullptr || s !=
nullptr,
"ADataBindingDefault is not defined for View, Data");
483 object && (*linker.getBinder())(linker.getField(), g, s);
485 object && (*linker.getBinder())(linker.getField(), [projection = linker.getProjection()](View& v,
const Data& d) {
486 auto s = static_cast<pointer_to_setter>(ADataBindingDefault<View, data_deduced>::getSetter());
487 std::invoke(s, &v, projection(d));
493template<
typename View>
503 return &AView::setVisibility;
507template <
typename Object, APropertyReadable Connectable>
513 requires { { Binding::property(
object) } ->
AAnyProperty; } ||
515 "ADataBindingDefault is required to have property() function to return any property or slot def; either "
516 "define proper ADataBindingDefault specialization or explicitly specify the destination property.");
518 requires { { Binding::setup(
object) }; },
519 "ADataBindingDefault is required to have setup(const _<Object>&) function; either define proper "
520 "ADataBindingDefault specialization or explicitly specify the destination property.");
521 Binding::setup(
object);
527template<
typename Object, APropertyWritable Connectable>
531 static_assert(
requires {
533 },
"ADataBindingDefault is required to have property() function to return any property; either define proper "
534 "ADataBindingDefault specialization or explicitly specify the destination property.");
536 requires { { Binding::setup(
object) }; },
537 "ADataBindingDefault is required to have setup(const _<Object>&) function; either define proper "
538 "ADataBindingDefault specialization or explicitly specify the destination property.");
539 Binding::setup(
object);
545template <AAnyProperty Lhs,
typename Destination>
548 Destination destinationPointerToMember;
549 explicit Binding(Lhs sourceProperty, Destination destinationPointerToMember)
550 : sourceProperty(sourceProperty), destinationPointerToMember(destinationPointerToMember) {}
553template <AAnyProperty Property,
typename Destination>
555inline decltype(
auto)
operator>(Property&& sourceProperty, Destination&& rhs) {
559template <
typename Object, APropertyReadable Property,
typename Destination>
563 { std::invoke(binding.destinationPointerToMember, *
object) } ->
AAnyProperty;
566 AObject::connect(binding.sourceProperty, std::invoke(binding.destinationPointerToMember, *
object));
570template <
typename Object, APropertyWritable Property,
typename Destination>
574 { std::invoke(binding.destinationPointerToMember, *
object) } ->
AAnyProperty;
577 AObject::biConnect(binding.sourceProperty, std::invoke(binding.destinationPointerToMember, *
object));
582template <
typename Object, APropertyReadable Property,
typename Destination>
585 { binding.destinationPointerToMember } ->
aui::invocable<Object&,
decltype(*binding.sourceProperty)>;
589 binding.sourceProperty,
object.get(),
590 [
object =
object.get(), wrapped = std::move(binding.destinationPointerToMember)](
591 const std::decay_t<
decltype(*binding.sourceProperty)>& i) { std::invoke(wrapped, *object, i); });
595template <
typename Object, APropertyWritable Property,
typename Destination>
598 { binding.destinationPointerToMember } ->
aui::invocable<Object&,
decltype(*binding.sourceProperty)>;
602 binding.sourceProperty,
object.get(),
603 [
object =
object.get(), wrapped = std::move(binding.destinationPointerToMember)](
604 const std::decay_t<
decltype(*binding.sourceProperty)>& i) { std::invoke(wrapped, *object, i); });
Definition ADataBinding.h:115
Definition ADataBinding.h:86
Data binding implementation.
Definition ADataBinding.h:201
auto operator()(ModelField(Model::*field), ASignal< GetterRV >(View::*getter), Setter setter=(void(View::*)(const ModelField &)) nullptr)
Create a connection to specified pointer-to-member-field signal and pointer-to-member-function setter...
Definition ADataBinding.h:276
auto operator()(ModelField(Model::*field), void(View::*setterFunc)(SetterArg))
Create a connection to setter only.
Definition ADataBinding.h:235
auto operator()(ModelField(Model::*field), SetterLambda setterLambda)
Create a connection to specified lambda setter only.
Definition ADataBinding.h:257
emits modelChanged
Data in the model has changed.
Definition ADataBinding.h:399
auto operator()(Data(Model::*field))
Create a connection via ADataBindingDefault.
Definition ADataBinding.h:289
ADataBindingLinker2< Model, Data, Projection > operator()(Data(Model::*field), Projection projection)
Create a connection via ADataBindingDefault and projection (setter only).
Definition ADataBinding.h:299
A std::deque with AUI extensions.
Definition ADeque.h:27
StoredType & last() noexcept
Definition ADeque.h:164
static void inflate(aui::no_escape< AViewContainer > root, const _< AView > &view)
Wraps view with root using Stacked layout and expanding.
Base class of all UI objects.
Definition AView.h:78
An std::weak_ptr with AUI extensions.
Definition SharedPtrTypes.h:179
Definition concepts.h:226
Invokable concept.
Definition concepts.h:37
Concept of a pointer-to-member.
Definition members.h:124
class_of c
Selects views that are of the specified classes.
Definition class_of.h:84
static void biConnect(PropertySource &&propertySource, PropertyDestination &&propertyDestination)
Connects source property to the destination property and opposite (bidirectionally).
Definition AObject.h:156
static decltype(auto) connect(const Signal &signal, Object *object, Function &&function)
Connects signal to the slot of the specified object.
Definition AObject.h:86
ASignal< Args... > emits
A signal declaration.
Definition ASignal.h:577
#define emit
emits the specified signal in context of this object.
Definition AObject.h:344
#define AUI_ASSERT(condition)
Asserts that the passed condition evaluates to true.
Definition Assert.h:55
#define AUI_ASSERTX(condition, what)
Asserts that the passed condition evaluates to true. Adds extra message string.
Definition Assert.h:74
Definition concepts.h:233
Defines how View handles properties of FieldType type.
Definition ADataBinding.h:38
static void(View::*)(const FieldType &v) getSetter()
Returns setter for ADataBinding (deprecated)
Definition ADataBinding.h:64
static void setup(const _< View > &view)
Called then view linked with field.
Definition ADataBinding.h:44
static void setup(const _< View > &view)
Definition ADataBinding.h:500
static auto property(const _< View > &view)
Returns property definition for FieldType.
Definition ADataBinding.h:50
static ASignal< FieldType >View::* getGetter()
Returns getter for ADataBinding (deprecated)
Definition ADataBinding.h:56
Definition concepts.h:188
Definition ADataBinding.h:546
Pointer to member type (not value) introspection.
Definition members.h:48
Definition parameter_pack.h:76