File indexing completed on 2025-02-02 04:11:05

0001 /*
0002  * SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0003  *
0004  * SPDX-License-Identifier: GPL-3.0-or-later
0005  */
0006 
0007 #pragma once
0008 #include "model/document_node.hpp"
0009 #include "model/property/property.hpp"
0010 
0011 
0012 #define GLAXNIMATE_PROPERTY_REFERENCE(type, name, ...)      \
0013 public:                                                     \
0014     ReferenceProperty<type> name{this, kli18n(#name), __VA_ARGS__}; \
0015     type* get_##name() const { return name.get(); }         \
0016     bool set_##name(type* v)                                \
0017     {                                                       \
0018         return name.set_undoable(QVariant::fromValue(v));   \
0019     }                                                       \
0020 private:                                                    \
0021     Q_PROPERTY(type* name READ get_##name WRITE set_##name) \
0022     Q_CLASSINFO(#name, "property ref " #type)               \
0023     // macro end
0024 
0025 
0026 namespace glaxnimate::model {
0027 
0028 class ReferencePropertyBase : public BaseProperty
0029 {
0030     Q_GADGET
0031 public:
0032     ReferencePropertyBase(
0033         Object* obj,
0034         const KLazyLocalizedString& name,
0035         PropertyCallback<std::vector<DocumentNode*>> valid_options,
0036         PropertyCallback<bool, DocumentNode*> is_valid_option,
0037         PropertyTraits::Flags flags = PropertyTraits::Visual)
0038         : BaseProperty(obj, name, PropertyTraits{PropertyTraits::ObjectReference, flags}),
0039         valid_options_(std::move(valid_options)),
0040         is_valid_option_(std::move(is_valid_option))
0041     {
0042     }
0043 
0044     bool valid_value(const QVariant & v) const override
0045     {
0046         return is_valid_option_(object(), v.value<DocumentNode*>());
0047     }
0048 
0049     std::vector<DocumentNode*> valid_options() const
0050     {
0051         return valid_options_(object());
0052     }
0053 
0054     bool is_valid_option(DocumentNode* ptr) const
0055     {
0056         return is_valid_option_(object(), ptr);
0057     }
0058 
0059     void set_time(FrameTime) override {}
0060 
0061     void transfer(Document*) override;
0062 
0063     virtual bool set_ref(model::DocumentNode* t) = 0;
0064     virtual model::DocumentNode* get_ref() const = 0;
0065 
0066 private:
0067     PropertyCallback<std::vector<DocumentNode*>> valid_options_;
0068     PropertyCallback<bool, DocumentNode*> is_valid_option_;
0069 
0070 protected:
0071 //     static void remove_user(ReferencePropertyBase*, void*) {}
0072 //     static void add_user(ReferencePropertyBase*, void*) {}
0073     static void remove_user(ReferencePropertyBase* prop, model::DocumentNode* obj)
0074     {
0075         obj->remove_user(prop);
0076     }
0077     static void add_user(ReferencePropertyBase* prop, model::DocumentNode* obj)
0078     {
0079         obj->add_user(prop);
0080     }
0081 };
0082 
0083 template<class Type>
0084 class ReferenceProperty : public ReferencePropertyBase
0085 {
0086 public:
0087     using value_type = Type*;
0088 
0089     ReferenceProperty(
0090         Object* obj,
0091         const KLazyLocalizedString& name,
0092         PropertyCallback<std::vector<DocumentNode*>> valid_options,
0093         PropertyCallback<bool, DocumentNode*> is_valid_option,
0094         PropertyCallback<void, Type*, Type*> on_changed = {},
0095         PropertyTraits::Flags flags = PropertyTraits::Visual)
0096         : ReferencePropertyBase(obj, name, std::move(valid_options), std::move(is_valid_option), flags),
0097         on_changed(std::move(on_changed))
0098     {
0099     }
0100 
0101     bool set(Type* value)
0102     {
0103         if ( !is_valid_option(value) )
0104             return false;
0105         set_force(value);
0106         return true;
0107     }
0108 
0109     void set_force(Type* value)
0110     {
0111         auto old = value_;
0112         value_ = value;
0113         value_changed();
0114         if ( old )
0115             remove_user(this, old);
0116         if ( value )
0117             add_user(this, value);
0118         on_changed(object(), value_, old);
0119     }
0120 
0121     Type* get() const
0122     {
0123         return value_;
0124     }
0125 
0126     QVariant value() const override
0127     {
0128         if ( !value_ )
0129             return {};
0130         return QVariant::fromValue(value_);
0131     }
0132 
0133     bool set_value(const QVariant& val) override
0134     {
0135         if ( val.isNull() )
0136             return set(nullptr);
0137         if ( auto v = detail::variant_cast<Type*>(val) )
0138             return set(*v);
0139         return true;
0140     }
0141 
0142     Type* operator->() const
0143     {
0144         return value_;
0145     }
0146 
0147     bool set_ref(model::DocumentNode* t) override
0148     {
0149         if ( !t )
0150         {
0151             set_force(nullptr);
0152             return true;
0153         }
0154         if ( auto p = qobject_cast<Type*>(t) )
0155             return set(p);
0156         return false;
0157     }
0158 
0159     model::DocumentNode* get_ref() const override
0160     {
0161         return value_;
0162     }
0163 
0164 private:
0165     Type* value_ = nullptr;
0166     PropertyCallback<void, Type*, Type*> on_changed;
0167 };
0168 
0169 } // namespace glaxnimate::model