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