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