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 0009 #include <type_traits> 0010 #include <functional> 0011 #include <iterator> 0012 #include <optional> 0013 #include <memory> 0014 0015 #include <QString> 0016 #include <QPointF> 0017 #include <QVector2D> 0018 #include <QColor> 0019 #include <QVariant> 0020 #include <QGradient> 0021 0022 #include <KLazyLocalizedString> 0023 0024 #include "model/animation/frame_time.hpp" 0025 0026 namespace glaxnimate::math::bezier { class Bezier; } 0027 0028 namespace glaxnimate::model { 0029 0030 class Object; 0031 class Document; 0032 0033 struct PropertyTraits 0034 { 0035 enum Type 0036 { 0037 Unknown, 0038 Object, 0039 ObjectReference, 0040 Bool, 0041 Int, 0042 Float, 0043 Point, 0044 Color, 0045 Size, 0046 Scale, 0047 String, 0048 Enum, 0049 Uuid, 0050 Bezier, 0051 Data, 0052 Gradient, 0053 }; 0054 0055 enum Flags 0056 { 0057 NoFlags = 0x00, 0058 List = 0x01, ///< list/array of values 0059 ReadOnly = 0x02, ///< not modifiable by GUI 0060 Animated = 0x04, ///< animated 0061 Visual = 0x08, ///< has visible effects 0062 OptionList = 0x10, ///< has a set of valid values 0063 Percent = 0x20, ///< for Float, show as percentage on the GUI 0064 Hidden = 0x40, ///< for Visual, not shown prominently 0065 }; 0066 0067 0068 Type type = Unknown; 0069 int flags = NoFlags; 0070 0071 bool is_object() const 0072 { 0073 return type == Object || type == ObjectReference; 0074 } 0075 0076 template<class T> 0077 static constexpr Type get_type() noexcept; 0078 0079 template<class T> 0080 static PropertyTraits from_scalar(int flags=NoFlags) 0081 { 0082 return { 0083 get_type<T>(), 0084 flags 0085 }; 0086 } 0087 }; 0088 0089 0090 namespace detail { 0091 0092 0093 template<class T, class = void> 0094 struct GetType; 0095 0096 template<class ObjT> 0097 static constexpr bool is_object_v = std::is_base_of_v<Object, ObjT> || std::is_same_v<Object, ObjT>; 0098 0099 // template<class ObjT> 0100 // struct GetType<ObjT*, std::enable_if_t<is_object_v<ObjT>>> 0101 // { 0102 // static constexpr const PropertyTraits::Type value = PropertyTraits::ObjectReference; 0103 // }; 0104 0105 template<class ObjT> 0106 struct GetType<std::unique_ptr<ObjT>, std::enable_if_t<is_object_v<ObjT>>> 0107 { 0108 static constexpr const PropertyTraits::Type value = PropertyTraits::Object; 0109 }; 0110 0111 template<> struct GetType<bool, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Bool; }; 0112 template<> struct GetType<float, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Float; }; 0113 template<> struct GetType<QVector2D, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Scale; }; 0114 template<> struct GetType<QColor, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Color; }; 0115 template<> struct GetType<QSizeF, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Size; }; 0116 template<> struct GetType<QString, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::String; }; 0117 template<> struct GetType<QUuid, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Uuid; }; 0118 template<> struct GetType<QPointF, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Point; }; 0119 template<> struct GetType<math::bezier::Bezier, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Bezier; }; 0120 template<> struct GetType<QByteArray, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Data; }; 0121 template<> struct GetType<QGradientStops, void> { static constexpr const PropertyTraits::Type value = PropertyTraits::Gradient; }; 0122 0123 template<class ObjT> 0124 struct GetType<ObjT, std::enable_if_t<std::is_integral_v<ObjT>>> 0125 { 0126 static constexpr const PropertyTraits::Type value = PropertyTraits::Int; 0127 }; 0128 template<class ObjT> 0129 struct GetType<ObjT, std::enable_if_t<std::is_enum_v<ObjT>>> 0130 { 0131 static constexpr const PropertyTraits::Type value = PropertyTraits::Enum; 0132 }; 0133 } // namespace detail 0134 0135 0136 template<class T> 0137 inline constexpr PropertyTraits::Type PropertyTraits::get_type() noexcept 0138 { 0139 return detail::GetType<T>::value; 0140 } 0141 0142 0143 #define GLAXNIMATE_PROPERTY_IMPL(type, name) \ 0144 public: \ 0145 type get_##name() const { return name.get(); } \ 0146 bool set_##name(const type& v) { \ 0147 return name.set_undoable(QVariant::fromValue(v)); \ 0148 } \ 0149 private: \ 0150 Q_PROPERTY(type name READ get_##name WRITE set_##name) \ 0151 Q_CLASSINFO(#name, "property " #type) \ 0152 // macro end 0153 0154 #define GLAXNIMATE_PROPERTY(type, name, ...) \ 0155 public: \ 0156 Property<type> name{this, kli18n(#name), __VA_ARGS__}; \ 0157 GLAXNIMATE_PROPERTY_IMPL(type, name) \ 0158 // macro end 0159 0160 #define GLAXNIMATE_PROPERTY_RO(type, name, default_value) \ 0161 public: \ 0162 Property<type> name{this, kli18n(#name), default_value, {}, {}, PropertyTraits::ReadOnly}; \ 0163 type get_##name() const { return name.get(); } \ 0164 private: \ 0165 Q_PROPERTY(type name READ get_##name) \ 0166 Q_CLASSINFO(#name, "property " #type) \ 0167 // macro end 0168 0169 class BaseProperty 0170 { 0171 Q_GADGET 0172 0173 public: 0174 BaseProperty(Object* object, const KLazyLocalizedString& name, PropertyTraits traits); 0175 0176 virtual ~BaseProperty() = default; 0177 0178 virtual QVariant value() const = 0; 0179 virtual bool set_value(const QVariant& val) = 0; 0180 virtual bool set_undoable(const QVariant& val, bool commit = true); 0181 virtual void set_time(FrameTime t) = 0; 0182 virtual void transfer(Document*) {}; 0183 virtual bool valid_value(const QVariant& v) const = 0; 0184 0185 virtual bool assign_from(const BaseProperty* prop) 0186 { 0187 return set_value(prop->value()); 0188 } 0189 0190 /** 0191 * \brief Stretches animations by the given amount 0192 */ 0193 virtual void stretch_time(qreal multiplier) { Q_UNUSED(multiplier); } 0194 0195 QString localized_name() const 0196 { 0197 return name_.toString(); 0198 } 0199 0200 QString name() const 0201 { 0202 return QString::fromLatin1(name_.untranslatedText()); 0203 } 0204 0205 PropertyTraits traits() const 0206 { 0207 return traits_; 0208 } 0209 0210 Object* object() const 0211 { 0212 return object_; 0213 } 0214 0215 protected: 0216 void value_changed(); 0217 0218 private: 0219 Object* object_; 0220 KLazyLocalizedString name_; 0221 PropertyTraits traits_; 0222 }; 0223 0224 namespace detail { 0225 0226 template<class T> inline T defval() { return T(); } 0227 template<> inline void defval<void>() {} 0228 0229 0230 template<class FuncT, class... Args, std::size_t... I> 0231 auto invoke_impl(const FuncT& fun, std::index_sequence<I...>, const std::tuple<Args...>& args) 0232 { 0233 return fun(std::get<I>(args)...); 0234 } 0235 0236 template<int ArgCount, class FuncT, class... Args> 0237 auto invoke(const FuncT& fun, const Args&... t) 0238 { 0239 return invoke_impl(fun, std::make_index_sequence<ArgCount>(), std::make_tuple(t...)); 0240 } 0241 0242 } // namespace detail 0243 0244 template<class Return, class... ArgType> 0245 class PropertyCallback 0246 { 0247 private: 0248 class HolderBase 0249 { 0250 public: 0251 virtual ~HolderBase() = default; 0252 virtual Return invoke(Object* obj, const ArgType&... v) const = 0; 0253 }; 0254 0255 template<class ObjT, class... Arg> 0256 class Holder : public HolderBase 0257 { 0258 public: 0259 using FuncP = std::function<Return (ObjT*, Arg...)>; 0260 0261 Holder(FuncP func) : func(std::move(func)) {} 0262 0263 Return invoke(Object* obj, const ArgType&... v) const override 0264 { 0265 return detail::invoke<sizeof...(Arg)+1>(func, static_cast<ObjT*>(obj), v...); 0266 } 0267 0268 FuncP func; 0269 }; 0270 std::unique_ptr<HolderBase> holder; 0271 public: 0272 PropertyCallback() = default; 0273 0274 PropertyCallback(std::nullptr_t) {} 0275 0276 template<class ObjT, class... Arg> 0277 PropertyCallback(Return (ObjT::*func)(Arg...)) : holder(std::make_unique<Holder<ObjT, Arg...>>(func)) {} 0278 template<class ObjT, class... Arg> 0279 PropertyCallback(Return (ObjT::*func)(Arg...) const) : holder(std::make_unique<Holder<ObjT, Arg...>>(func)) {} 0280 0281 0282 explicit operator bool() const 0283 { 0284 return bool(holder); 0285 } 0286 0287 Return operator() (Object* obj, const ArgType&... v) const 0288 { 0289 if ( holder ) 0290 return holder->invoke(obj, v...); 0291 return detail::defval<Return>(); 0292 } 0293 }; 0294 0295 0296 namespace detail { 0297 0298 template<class Type> 0299 std::optional<Type> variant_cast(const QVariant& val) 0300 { 0301 if ( !val.canConvert<Type>() ) 0302 return {}; 0303 QVariant converted = val; 0304 #if QT_VERSION_MAJOR < 6 0305 if ( !converted.convert(qMetaTypeId<Type>()) ) 0306 #else 0307 if ( !converted.convert(QMetaType::fromType<Type>()) ) 0308 #endif 0309 return {}; 0310 return converted.value<Type>(); 0311 } 0312 0313 0314 template<class Base, class Type> 0315 class PropertyTemplate : public Base 0316 { 0317 public: 0318 using value_type = Type; 0319 using reference = const Type&; 0320 0321 PropertyTemplate(Object* obj, 0322 const KLazyLocalizedString& name, 0323 Type default_value = Type(), 0324 PropertyCallback<void, Type, Type> emitter = {}, 0325 PropertyCallback<bool, Type> validator = {}, 0326 int flags = PropertyTraits::NoFlags 0327 ) 0328 : Base(obj, name, PropertyTraits::from_scalar<Type>(flags)), 0329 value_(std::move(default_value)), 0330 emitter(std::move(emitter)), 0331 validator(std::move(validator)) 0332 {} 0333 0334 bool valid_value(const QVariant& val) const override 0335 { 0336 if ( auto v = detail::variant_cast<Type>(val) ) 0337 return !validator || validator(this->object(), *v); 0338 return false; 0339 } 0340 0341 bool set(Type value) 0342 { 0343 if ( validator && !validator(this->object(), value) ) 0344 return false; 0345 std::swap(value_, value); 0346 this->value_changed(); 0347 if ( emitter ) 0348 emitter(this->object(), value_, value); 0349 return true; 0350 } 0351 0352 reference get() const 0353 { 0354 return value_; 0355 } 0356 0357 QVariant value() const override 0358 { 0359 return QVariant::fromValue(value_); 0360 } 0361 0362 bool set_value(const QVariant& val) override 0363 { 0364 if ( auto v = detail::variant_cast<Type>(val) ) 0365 return set(*v); 0366 return false; 0367 } 0368 0369 void set_time(FrameTime) override {} 0370 0371 private: 0372 Type value_; 0373 PropertyCallback<void, Type, Type> emitter; 0374 PropertyCallback<bool, Type> validator; 0375 }; 0376 0377 } // namespace detail 0378 0379 template<class Type> 0380 class Property : public detail::PropertyTemplate<BaseProperty, Type> 0381 { 0382 public: 0383 using detail::PropertyTemplate<BaseProperty, Type>::PropertyTemplate; 0384 }; 0385 0386 } // namespace glaxnimate::model