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

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 <limits>
0010 #include <iterator>
0011 
0012 #include <QVariant>
0013 #include <QList>
0014 
0015 #include "model/animation/keyframe_transition.hpp"
0016 #include "model/property/property.hpp"
0017 #include "math/math.hpp"
0018 #include "math/bezier/point.hpp"
0019 #include "math/bezier/solver.hpp"
0020 #include "math/bezier/bezier_length.hpp"
0021 
0022 /*
0023  * Arguments: type, name, default, emitter, flags
0024  * For float: type, name, default, emitter, min, max, flags
0025  */
0026 #define GLAXNIMATE_ANIMATABLE(type, name, ...)                                  \
0027 public:                                                                         \
0028     glaxnimate::model::AnimatedProperty<type> name{this, kli18n(#name), __VA_ARGS__};   \
0029     glaxnimate::model::AnimatableBase* get_##name() { return &name; }           \
0030 private:                                                                        \
0031     Q_PROPERTY(glaxnimate::model::AnimatableBase* name READ get_##name)         \
0032     Q_CLASSINFO(#name, "property animated " #type)                              \
0033     // macro end
0034 
0035 
0036 namespace glaxnimate::model {
0037 
0038 class KeyframeBase : public QObject
0039 {
0040     Q_OBJECT
0041 
0042     Q_PROPERTY(QVariant value READ value)
0043     Q_PROPERTY(double time READ time)
0044 public:
0045     explicit KeyframeBase(FrameTime time) : time_ { time } {}
0046     virtual ~KeyframeBase() = default;
0047 
0048     virtual QVariant value() const = 0;
0049     virtual bool set_value(const QVariant& value) = 0;
0050 
0051     FrameTime time() const { return time_; }
0052     void set_time(FrameTime t) { time_ = t; }
0053 
0054     /**
0055      * \brief Transition into the next value
0056      */
0057     const KeyframeTransition& transition() const { return transition_; }
0058 
0059     void set_transition(const KeyframeTransition& trans)
0060     {
0061         transition_ = trans;
0062         Q_EMIT transition_changed(transition_.before_descriptive(), transition_.after_descriptive());
0063     }
0064 
0065     void stretch_time(qreal multiplier)
0066     {
0067         time_ *= multiplier;
0068     }
0069 
0070     /**
0071      * \brief Splits a keyframe into multiple segments
0072      * \param other The keyframe following this
0073      * \param splits Array of splits in [0, 1], indicating the fractions at which splits shall occur
0074      * \pre \p other must be the same type of keyframe as \b this
0075      * \returns An array of keyframes matching the splits,
0076      *      this will include a copy of \p other, which might have been modified slightly.
0077      *      This should be used as \p this for the next keyframe
0078      */
0079     std::vector<std::unique_ptr<KeyframeBase>> split(const KeyframeBase* other, std::vector<qreal> splits) const;
0080 
0081     std::unique_ptr<KeyframeBase> clone() const
0082     {
0083         auto clone = do_clone();
0084         clone->set_transition(transition_);
0085         return clone;
0086     }
0087 
0088 Q_SIGNALS:
0089     void transition_changed(KeyframeTransition::Descriptive before, KeyframeTransition::Descriptive after);
0090 
0091 protected:
0092     virtual std::unique_ptr<KeyframeBase> do_clone() const = 0;
0093 
0094     class KeyframeSplitter
0095     {
0096     public:
0097         virtual ~KeyframeSplitter() = default;
0098         virtual void step(const QPointF& p) = 0;
0099         virtual std::unique_ptr<KeyframeBase> left(const QPointF& p) const = 0;
0100         virtual std::unique_ptr<KeyframeBase> right(const QPointF& p) const = 0;
0101         virtual std::unique_ptr<KeyframeBase> last() const = 0;
0102     };
0103 
0104     virtual std::unique_ptr<KeyframeSplitter> splitter(const KeyframeBase* other) const = 0;
0105 
0106 private:
0107     FrameTime time_;
0108     KeyframeTransition transition_;
0109 };
0110 
0111 class AnimatableBase : public QObject, public BaseProperty
0112 {
0113     Q_OBJECT
0114 
0115     Q_PROPERTY(int keyframe_count READ keyframe_count)
0116     Q_PROPERTY(QVariant value READ value WRITE set_undoable)
0117     Q_PROPERTY(bool animated READ animated)
0118 
0119 public:
0120     enum KeyframeStatus
0121     {
0122         NotAnimated,    ///< Value is not animated
0123         Tween,          ///< Value is animated but the given time isn't a keyframe
0124         IsKeyframe,     ///< Value is animated and the given time is a keyframe
0125         Mismatch        ///< Value is animated and the current value doesn't match the animated value
0126     };
0127 
0128     struct SetKeyframeInfo
0129     {
0130         bool insertion;
0131         int index;
0132     };
0133 
0134     struct MidTransition
0135     {
0136         enum Type
0137         {
0138             Invalid,
0139             SingleKeyframe,
0140             Middle,
0141         };
0142         Type type = Invalid;
0143 
0144         QVariant value;
0145         model::KeyframeTransition from_previous;
0146         model::KeyframeTransition to_next;
0147     };
0148 
0149     using BaseProperty::BaseProperty;
0150 
0151     virtual ~AnimatableBase() = default;
0152 
0153     /**
0154      * \brief Number of keyframes
0155      */
0156     virtual int keyframe_count() const = 0;
0157 
0158     /**
0159      * \param i Keyframe index
0160      * \pre \p i in [0, keyframe_count())
0161      * \return the Corresponding keyframe or nullptr if not found
0162      *
0163      * keyframe(i).time() < keyframe(j).time() <=> i < j
0164      */
0165     virtual const KeyframeBase* keyframe(int i) const = 0;
0166     virtual KeyframeBase* keyframe(int i) = 0;
0167 
0168     /**
0169      * \brief Sets a value at a keyframe
0170      * \param time          Time to set the value at
0171      * \param value         Value to set
0172      * \param info          If not nullptr, it will be written to with information about what has been node
0173      * \param force_insert  If \b true, it will always add a new keyframe
0174      * \post value(time) == \p value && animate() == true
0175      * \return The keyframe or nullptr if it couldn't be added.
0176      * If there is already a keyframe at \p time the returned value might be an existing keyframe
0177      */
0178     virtual KeyframeBase* set_keyframe(FrameTime time, const QVariant& value, SetKeyframeInfo* info = nullptr, bool force_insert = false) = 0;
0179 
0180     /**
0181      * \brief Removes the keyframe at index \p i
0182      */
0183     virtual void remove_keyframe(int i) = 0;
0184 
0185     /**
0186      * \brief Removes all keyframes
0187      * \post !animated()
0188      */
0189     virtual void clear_keyframes() = 0;
0190 
0191     /**
0192      * \brief Removes the keyframe with the given time
0193      * \returns whether a keyframe was found and removed
0194      */
0195     virtual bool remove_keyframe_at_time(FrameTime time) = 0;
0196 
0197     /**
0198      * \brief Get the value at the given time
0199      */
0200     virtual QVariant value(FrameTime time) const = 0;
0201 
0202     bool set_undoable(const QVariant& val, bool commit=true) override;
0203 
0204     using BaseProperty::value;
0205 
0206     /**
0207      * \brief Moves a keyframe
0208      * \param keyframe_index Index of the keyframe to move
0209      * \param time New time for the keyframe
0210      * \return The new index for that keyframe
0211      */
0212     virtual int move_keyframe(int keyframe_index, FrameTime time) = 0;
0213 
0214     /**
0215      * If animated(), whether the current value has been changed over the animated value
0216      */
0217     Q_INVOKABLE virtual bool value_mismatch() const = 0;
0218 
0219     bool assign_from(const BaseProperty* prop) override;
0220 
0221     /**
0222      * \brief Set the current time
0223      * \post value() == value(time)
0224      */
0225     void set_time(FrameTime time) override
0226     {
0227         current_time = time;
0228         on_set_time(time);
0229     }
0230 
0231     FrameTime time() const
0232     {
0233         return current_time;
0234     }
0235 
0236     /**
0237      * \brief Set the value for the given keyframe
0238      */
0239     bool set_keyframe_value(int keyframe_index, const QVariant& value)
0240     {
0241         if ( auto kf = keyframe(keyframe_index) )
0242             return kf->set_value(value);
0243         return false;
0244     }
0245 
0246     /**
0247      * \brief Whether it has multiple keyframes
0248      */
0249     bool animated() const
0250     {
0251         return keyframe_count() != 0;
0252     }
0253 
0254     /**
0255      * \brief Index of the keyframe whose time lays in the transition
0256      * \pre animated()
0257      *
0258      * If all keyframes are after \p time, returns 0
0259      * This means keyframe(keyframe_index(t)) is always valid when animated
0260      */
0261     Q_INVOKABLE int keyframe_index(double time) const
0262     {
0263         auto kfcount = keyframe_count();
0264 
0265         for ( int i = 0; i < kfcount; i++ )
0266         {
0267             auto kftime = keyframe(i)->time();
0268             if ( kftime == time )
0269                 return i;
0270             else if ( kftime > time )
0271                 return std::max(0, i-1);
0272         }
0273         return kfcount - 1;
0274     }
0275 
0276     int keyframe_index(KeyframeBase* kf) const
0277     {
0278         auto kfcount = keyframe_count();
0279 
0280         for ( int i = 0; i < kfcount; i++ )
0281         {
0282             if ( keyframe(i) == kf )
0283                 return i;
0284         }
0285         return -1;
0286     }
0287 
0288     KeyframeStatus keyframe_status(FrameTime time) const
0289     {
0290         if ( !animated() )
0291             return NotAnimated;
0292         if ( value_mismatch() )
0293             return Mismatch;
0294         if ( keyframe(keyframe_index(time))->time() == time )
0295             return IsKeyframe;
0296         return Tween;
0297     }
0298 
0299     bool has_keyframe(FrameTime time) const
0300     {
0301         if ( !animated() )
0302             return false;
0303         return keyframe(keyframe_index(time))->time() == time;
0304     }
0305 
0306     MidTransition mid_transition(FrameTime time) const;
0307 
0308     /**
0309      * \brief Clears all keyframes and creates an associated undo action
0310      * \param value Value to be set after clearing
0311      */
0312     virtual void clear_keyframes_undoable(QVariant value = {});
0313 
0314     /**
0315      * \brief Adds a keyframe at the given time
0316      */
0317     virtual void add_smooth_keyframe_undoable(FrameTime time, const QVariant& value);
0318 
0319 Q_SIGNALS:
0320     void keyframe_added(int index, KeyframeBase* keyframe);
0321     void keyframe_removed(int index);
0322     void keyframe_updated(int index, KeyframeBase* keyframe);
0323 
0324 protected:
0325     virtual void on_set_time(FrameTime time) = 0;
0326 
0327     MidTransition do_mid_transition(const KeyframeBase* kf_before, const KeyframeBase* kf_after, qreal ratio, int index) const;
0328     virtual QVariant do_mid_transition_value(const KeyframeBase* kf_before, const KeyframeBase* kf_after, qreal ratio) const = 0;
0329 
0330     FrameTime current_time = 0;
0331 };
0332 
0333 template<class Type>
0334 class Keyframe : public KeyframeBase
0335 {
0336 public:
0337     using value_type = Type;
0338     using reference = const Type&;
0339 
0340     Keyframe(FrameTime time, Type value)
0341         : KeyframeBase(time), value_(std::move(value)) {}
0342 
0343     void set(reference value)
0344     {
0345         value_ = value;
0346     }
0347 
0348     reference get() const
0349     {
0350         return value_;
0351     }
0352 
0353     QVariant value() const override
0354     {
0355         return QVariant::fromValue(value_);
0356     }
0357 
0358     bool set_value(const QVariant& val) override
0359     {
0360         if ( auto v = detail::variant_cast<Type>(val) )
0361         {
0362             set(*v);
0363             return true;
0364         }
0365         return false;
0366     }
0367 
0368     value_type lerp(const Keyframe& other, double t) const
0369     {
0370         return math::lerp(value_, other.get(), this->transition().lerp_factor(t));
0371     }
0372 
0373 
0374 protected:
0375     std::unique_ptr<KeyframeBase> do_clone() const override
0376     {
0377         return std::make_unique<Keyframe>(time(), value_);
0378     }
0379 
0380     class TypedKeyframeSplitter : public KeyframeSplitter
0381     {
0382     public:
0383         TypedKeyframeSplitter(const Keyframe* a, const Keyframe* b) : a(a), b(b) {}
0384 
0385         void step(const QPointF&) override {}
0386 
0387         std::unique_ptr<KeyframeBase> left(const QPointF& p) const override
0388         {
0389             return std::make_unique<Keyframe>(
0390                 math::lerp(a->time(), b->time(), p.x()),
0391                 math::lerp(a->get(), b->get(), p.y())
0392             );
0393         }
0394 
0395         std::unique_ptr<KeyframeBase> right(const QPointF& p) const override
0396         {
0397             return std::make_unique<Keyframe>(
0398                 math::lerp(a->time(), b->time(), p.x()),
0399                 math::lerp(a->get(), b->get(), p.y())
0400             );
0401         }
0402 
0403         std::unique_ptr<KeyframeBase> last() const override { return b->clone(); }
0404 
0405         const Keyframe* a;
0406         const Keyframe* b;
0407     };
0408 
0409     virtual std::unique_ptr<KeyframeSplitter> splitter(const KeyframeBase* other) const override
0410     {
0411         return std::make_unique<TypedKeyframeSplitter>(this, static_cast<const Keyframe*>(other));
0412     }
0413 
0414 private:
0415     Type value_;
0416 };
0417 
0418 
0419 template<>
0420 class Keyframe<QPointF> : public KeyframeBase
0421 {
0422 public:
0423     using value_type = QPointF;
0424     using reference = const QPointF&;
0425 
0426     Keyframe(FrameTime time, const QPointF& value)
0427         : KeyframeBase(time), point_(value) {}
0428 
0429 
0430     Keyframe(FrameTime time, const math::bezier::Point& value)
0431         : KeyframeBase(time), point_(value), linear(point_is_linear(value))
0432         {}
0433 
0434     void set(reference value)
0435     {
0436         point_.translate_to(value);
0437     }
0438 
0439     reference get() const
0440     {
0441         return point_.pos;
0442     }
0443 
0444     QVariant value() const override
0445     {
0446         return QVariant::fromValue(point_);
0447     }
0448 
0449     bool set_value(const QVariant& val) override
0450     {
0451         if ( val.userType() == QMetaType::QPointF )
0452         {
0453             set(val.value<QPointF>());
0454             return true;
0455         }
0456         else if ( auto v = detail::variant_cast<math::bezier::Point>(val) )
0457         {
0458             set_point(*v);
0459             return true;
0460         }
0461         return false;
0462     }
0463 
0464     value_type lerp(const Keyframe& other, double t) const
0465     {
0466         auto factor = transition().lerp_factor(t);
0467         if ( linear && other.linear )
0468             return math::lerp(get(), other.get(), factor);
0469 
0470         auto solver = bezier_solver(other);
0471         math::bezier::LengthData len(solver, 20);
0472         return solver.solve(len.at_ratio(factor).ratio);
0473     }
0474 
0475     void set_point(const math::bezier::Point& point)
0476     {
0477         point_ = point;
0478         linear = point_is_linear(point);
0479     }
0480 
0481     const math::bezier::Point& point() const
0482     {
0483         return point_;
0484     }
0485 
0486     math::bezier::CubicBezierSolver<QPointF> bezier_solver(const Keyframe& other) const
0487     {
0488         return math::bezier::CubicBezierSolver<QPointF>(
0489             point_.pos, point_.tan_out, other.point_.tan_in, other.point_.pos
0490         );
0491     }
0492 
0493     bool is_linear() const
0494     {
0495         return linear;
0496     }
0497 
0498 protected:
0499     std::unique_ptr<KeyframeBase> do_clone() const override
0500     {
0501         return std::make_unique<Keyframe>(time(), point_);
0502     }
0503 
0504     class PointKeyframeSplitter;
0505     std::unique_ptr<KeyframeSplitter> splitter(const KeyframeBase* other) const override;
0506 
0507 private:
0508     static bool point_is_linear(const math::bezier::Point& point)
0509     {
0510         return point.tan_in == point.pos && point.tan_out == point.pos;
0511     }
0512 
0513     math::bezier::Point point_;
0514     bool linear = true;
0515 };
0516 
0517 template<class Type>
0518 class AnimatedProperty;
0519 
0520 namespace detail {
0521 
0522 template<class Type>
0523 class AnimatedProperty : public AnimatableBase
0524 {
0525 public:
0526     using keyframe_type = Keyframe<Type>;
0527     using value_type = typename Keyframe<Type>::value_type;
0528     using reference = typename Keyframe<Type>::reference;
0529 
0530     class iterator
0531     {
0532     public:
0533         using value_type = keyframe_type;
0534         using pointer = const value_type*;
0535         using reference = const value_type&;
0536         using difference_type = int;
0537         using iterator_category = std::random_access_iterator_tag;
0538 
0539         iterator(const AnimatedProperty* prop, int index) noexcept
0540         : prop(prop), index(index) {}
0541 
0542         reference operator*() const { return *prop->keyframes_[index]; }
0543         pointer operator->() const { return prop->keyframes_[index].get(); }
0544 
0545         bool operator==(const iterator& other) const noexcept
0546         {
0547             return prop == other.prop && index == other.index;
0548         }
0549         bool operator!=(const iterator& other) const noexcept
0550         {
0551             return prop != other.prop || index != other.index;
0552         }
0553         bool operator<=(const iterator& other) const noexcept
0554         {
0555             return prop < other.prop || (prop == other.prop && index <= other.index);
0556         }
0557         bool operator<(const iterator& other) const noexcept
0558         {
0559             return prop < other.prop || (prop == other.prop && index < other.index);
0560         }
0561         bool operator>=(const iterator& other) const noexcept
0562         {
0563             return prop > other.prop || (prop == other.prop && index >= other.index);
0564         }
0565         bool operator>(const iterator& other) const noexcept
0566         {
0567             return prop > other.prop || (prop == other.prop && index > other.index);
0568         }
0569 
0570         iterator& operator++() noexcept
0571         {
0572             index++;
0573             return *this;
0574         }
0575         iterator operator++(int) noexcept
0576         {
0577             auto copy = this;
0578             index++;
0579             return copy;
0580         }
0581         iterator& operator--() noexcept
0582         {
0583             index--;
0584             return *this;
0585         }
0586         iterator operator--(int) noexcept
0587         {
0588             auto copy = this;
0589             index--;
0590             return copy;
0591         }
0592         iterator& operator+=(difference_type d) noexcept
0593         {
0594             index += d;
0595             return *this;
0596         }
0597         iterator operator+(difference_type d) const noexcept
0598         {
0599             auto copy = this;
0600             return copy += d;
0601         }
0602         iterator& operator-=(difference_type d) noexcept
0603         {
0604             index -= d;
0605             return *this;
0606         }
0607         iterator operator-(difference_type d) const noexcept
0608         {
0609             auto copy = this;
0610             return copy -= d;
0611         }
0612         difference_type operator-(const iterator& other) const noexcept
0613         {
0614             return index - other.index;
0615         }
0616 
0617     private:
0618         const AnimatedProperty* prop;
0619         int index;
0620     };
0621 
0622     AnimatedProperty(
0623         Object* object,
0624         const KLazyLocalizedString& name,
0625         reference default_value,
0626         PropertyCallback<void, Type> emitter = {},
0627         int flags = 0
0628     )
0629     : AnimatableBase(
0630         object, name, PropertyTraits::from_scalar<Type>(
0631             PropertyTraits::Animated|PropertyTraits::Visual|flags
0632         )),
0633       value_{default_value},
0634       emitter(std::move(emitter))
0635     {}
0636 
0637     int keyframe_count() const override
0638     {
0639         return keyframes_.size();
0640     }
0641 
0642     const keyframe_type* keyframe(int i) const override
0643     {
0644         if ( i < 0 || i >= int(keyframes_.size()) )
0645             return nullptr;
0646         return keyframes_[i].get();
0647     }
0648 
0649     keyframe_type* keyframe(int i) override
0650     {
0651         if ( i < 0 || i >= int(keyframes_.size()) )
0652             return nullptr;
0653         return keyframes_[i].get();
0654     }
0655 
0656     QVariant value() const override
0657     {
0658         return QVariant::fromValue(value_);
0659     }
0660 
0661     QVariant value(FrameTime time) const override
0662     {
0663         return QVariant::fromValue(get_at(time));
0664     }
0665 
0666     keyframe_type* set_keyframe(FrameTime time, const QVariant& val, SetKeyframeInfo* info = nullptr, bool force_insert = false) override
0667     {
0668         if ( auto v = detail::variant_cast<Type>(val) )
0669             return static_cast<model::AnimatedProperty<Type>*>(this)->set_keyframe(time, *v, info, force_insert);
0670         return nullptr;
0671     }
0672 
0673     void remove_keyframe(int i) override
0674     {
0675         if ( i >= 0 && i <= int(keyframes_.size()) )
0676         {
0677             keyframes_.erase(keyframes_.begin() + i);
0678             Q_EMIT this->keyframe_removed(i);
0679             value_changed();
0680         }
0681     }
0682 
0683     void clear_keyframes() override
0684     {
0685         int n = keyframes_.size();
0686         keyframes_.clear();
0687         for ( int i = n - 1; i >= 0; i-- )
0688             Q_EMIT this->keyframe_removed(i);
0689     }
0690 
0691     bool remove_keyframe_at_time(FrameTime time) override
0692     {
0693         for ( auto it = keyframes_.begin(); it != keyframes_.end(); ++it )
0694         {
0695             if ( (*it)->time() == time )
0696             {
0697                 int index = it - keyframes_.begin();
0698                 keyframes_.erase(it);
0699                 Q_EMIT this->keyframe_removed(index);
0700                 on_keyframe_updated(time, index-1, index);
0701                 return true;
0702             }
0703         }
0704         return false;
0705     }
0706 
0707     bool set_value(const QVariant& val) override
0708     {
0709         if ( auto v = detail::variant_cast<Type>(val) )
0710             return static_cast<model::AnimatedProperty<Type>*>(this)->set(*v);
0711         return false;
0712     }
0713 
0714     bool valid_value(const QVariant& val) const override
0715     {
0716         if ( detail::variant_cast<Type>(val) )
0717             return true;
0718         return false;
0719     }
0720 
0721     bool set(reference val)
0722     {
0723         value_ = val;
0724         mismatched_ = !keyframes_.empty();
0725         this->value_changed();
0726         emitter(this->object(), value_);
0727         return true;
0728     }
0729 
0730     keyframe_type* set_keyframe(FrameTime time, reference value, SetKeyframeInfo* info = nullptr, bool force_insert = false)
0731     {
0732         // First keyframe
0733         if ( keyframes_.empty() )
0734         {
0735             value_ = value;
0736             this->value_changed();
0737             emitter(this->object(), value_);
0738             keyframes_.push_back(std::make_unique<keyframe_type>(time, value));
0739             Q_EMIT this->keyframe_added(0, keyframes_.back().get());
0740             if ( info )
0741                 *info = {true, 0};
0742             return keyframes_.back().get();
0743         }
0744 
0745         // Current time, update value_
0746         if ( time == this->time() )
0747         {
0748             value_ = value;
0749             this->value_changed();
0750             emitter(this->object(), value_);
0751         }
0752 
0753         // Find the right keyframe
0754         int index = this->keyframe_index(time);
0755         auto kf = keyframe(index);
0756 
0757         // Time matches, update
0758         if ( kf->time() == time && !force_insert )
0759         {
0760             kf->set(value);
0761             Q_EMIT this->keyframe_updated(index, kf);
0762             on_keyframe_updated(time, index-1, index+1);
0763             if ( info )
0764                 *info = {false, index};
0765             return kf;
0766         }
0767 
0768         // First keyframe not at 0, might have to add the new keyframe at 0
0769         if ( index == 0 && kf->time() > time )
0770         {
0771             keyframes_.insert(keyframes_.begin(), std::make_unique<keyframe_type>(time, value));
0772             Q_EMIT this->keyframe_added(0, keyframes_.front().get());
0773             on_keyframe_updated(time, -1, 1);
0774             if ( info )
0775                 *info = {true, 0};
0776             return keyframes_.front().get();
0777         }
0778 
0779         // Insert somewhere in the middle
0780         auto it = keyframes_.insert(
0781             keyframes_.begin() + index + 1,
0782             std::make_unique<keyframe_type>(time, value)
0783         );
0784         Q_EMIT this->keyframe_added(index + 1, it->get());
0785         on_keyframe_updated(time, index, index+2);
0786         if ( info )
0787             *info = {true, index+1};
0788         return it->get();
0789     }
0790 
0791     value_type get() const
0792     {
0793         return value_;
0794     }
0795 
0796     value_type get_at(FrameTime time) const
0797     {
0798         if ( time == this->time() )
0799             return value_;
0800         return get_at_impl(time).second;
0801     }
0802 
0803     bool value_mismatch() const override
0804     {
0805         return mismatched_;
0806     }
0807 
0808     int move_keyframe(int keyframe_index, FrameTime time) override
0809     {
0810         if ( keyframe_index < 0 || keyframe_index >= int(keyframes_.size()) )
0811             return keyframe_index;
0812 
0813         int new_index = 0;
0814         for ( ; new_index < int(keyframes_.size()); new_index++ )
0815         {
0816             if ( keyframes_[new_index]->time() > time )
0817                 break;
0818         }
0819 
0820         if ( new_index > keyframe_index )
0821             new_index--;
0822 
0823         keyframes_[keyframe_index]->set_time(time);
0824 
0825         if ( keyframe_index != new_index )
0826         {
0827 
0828             QPointF incoming(-1, -1);
0829             if ( keyframe_index > 0 )
0830             {
0831                 auto trans_before_src = keyframes_[keyframe_index - 1]->transition();
0832                 incoming = trans_before_src.after();
0833                 trans_before_src.set_after(keyframes_[keyframe_index]->transition().after());
0834                 keyframes_[keyframe_index - 1]->set_transition(trans_before_src);
0835             }
0836 
0837 
0838             auto move = std::move(keyframes_[keyframe_index]);
0839             keyframes_.erase(keyframes_.begin() + keyframe_index);
0840             keyframes_.insert(keyframes_.begin() + new_index, std::move(move));
0841 
0842             int ia = keyframe_index;
0843             int ib = new_index;
0844             if ( ia > ib )
0845                 std::swap(ia, ib);
0846 
0847             if ( new_index > 0 )
0848             {
0849                 auto trans_before_dst = keyframes_[new_index - 1]->transition();
0850                 QPointF outgoing = trans_before_dst.after();
0851 
0852                 if ( incoming.x() != -1 )
0853                 {
0854                     trans_before_dst.set_after(incoming);
0855                     keyframes_[new_index - 1]->set_transition(trans_before_dst);
0856                 }
0857 
0858                 auto trans_moved = keyframes_[new_index]->transition();
0859                 trans_moved.set_after(outgoing);
0860                 keyframes_[new_index]->set_transition(trans_moved);
0861             }
0862 
0863             for ( ; ia <= ib; ia++ )
0864                 Q_EMIT this->keyframe_updated(ia, keyframes_[ia].get());
0865         }
0866         else
0867         {
0868             Q_EMIT this->keyframe_updated(keyframe_index, keyframes_[keyframe_index].get());
0869         }
0870 
0871         return new_index;
0872     }
0873 
0874     iterator begin() const { return iterator{this, 0}; }
0875     iterator end() const { return iterator{this, int(keyframes_.size())}; }
0876 
0877     void stretch_time(qreal multiplier) override
0878     {
0879         for ( std::size_t i = 0; i < keyframes_.size(); i++ )
0880         {
0881             keyframes_[i]->stretch_time(multiplier);
0882             Q_EMIT keyframe_updated(i, keyframes_[i].get());
0883         }
0884 
0885         current_time *= multiplier;
0886     }
0887 
0888 protected:
0889     void on_set_time(FrameTime time) override
0890     {
0891         if ( !keyframes_.empty() )
0892         {
0893             const keyframe_type* kf;
0894             std::tie(kf, value_) = get_at_impl(time);
0895             this->value_changed();
0896             emitter(this->object(), value_);
0897         }
0898         mismatched_ = false;
0899     }
0900 
0901     void on_keyframe_updated(FrameTime kf_time, int prev_index, int next_index)
0902     {
0903         auto cur_time = time();
0904         // if no keyframes or the current keyframe is being modified => update value_
0905         if ( !keyframes_.empty() && cur_time != kf_time )
0906         {
0907             if ( kf_time > cur_time )
0908             {
0909                 // if the modified keyframe is far ahead => don't update value_
0910                 if ( prev_index >= 0 && keyframes_[prev_index]->time() > cur_time )
0911                     return;
0912             }
0913             else
0914             {
0915                 // if the modified keyframe is far behind => don't update value_
0916                 if ( next_index < int(keyframes_.size()) && keyframes_[next_index]->time() < cur_time )
0917                     return;
0918             }
0919         }
0920 
0921         on_set_time(cur_time);
0922     }
0923 
0924     std::pair<const keyframe_type*, value_type> get_at_impl(FrameTime time) const
0925     {
0926         if ( keyframes_.empty() )
0927             return {nullptr, value_};
0928 
0929         const keyframe_type* first = keyframe(0);
0930         int count = keyframe_count();
0931         if ( count < 2 || first->time() >= time )
0932             return {first, first->get()};
0933 
0934         // We have at least 2 keyframes and time is after the first keyframe
0935         int index = this->keyframe_index(time);
0936         first = keyframe(index);
0937 
0938         // Only one keyframe needed to get the value
0939         if ( index == count - 1 || first->time() == time )
0940             return {first, first->get()};
0941 
0942         // Interpolate between two keyframes
0943         const keyframe_type* second = keyframe(index+1);
0944         double scaled_time = (time - first->time()) / (second->time() - first->time());
0945         return {nullptr, first->lerp(*second, scaled_time)};
0946     }
0947 
0948     QVariant do_mid_transition_value(const KeyframeBase* kf_before, const KeyframeBase* kf_after, qreal ratio) const override
0949     {
0950         return QVariant::fromValue(
0951             static_cast<const keyframe_type*>(kf_before)->lerp(
0952                 *static_cast<const keyframe_type*>(kf_after),
0953                 ratio
0954             )
0955         );
0956     }
0957 
0958     value_type value_;
0959     std::vector<std::unique_ptr<keyframe_type>> keyframes_;
0960     bool mismatched_ = false;
0961     PropertyCallback<void, Type> emitter;
0962 };
0963 
0964 // Intermediare non-templated class so Q_OBJECT works
0965 class AnimatedPropertyPosition: public detail::AnimatedProperty<QPointF>
0966 {
0967     Q_OBJECT
0968 public:
0969     AnimatedPropertyPosition(
0970         Object* object,
0971         const KLazyLocalizedString& name,
0972         reference default_value,
0973         PropertyCallback<void, QPointF> emitter = {},
0974         int flags = 0
0975     ) : detail::AnimatedProperty<QPointF>(object, name, default_value, std::move(emitter), flags)
0976     {
0977     }
0978 
0979 
0980     void set_closed(bool closed);
0981 
0982     Q_INVOKABLE void split_segment(int index, qreal factor);
0983 
0984     Q_INVOKABLE bool set_bezier(glaxnimate::math::bezier::Bezier bezier);
0985 
0986     Q_INVOKABLE glaxnimate::math::bezier::Bezier bezier() const;
0987 
0988     void remove_points(const std::set<int>& indices);
0989 
0990     keyframe_type* set_keyframe(FrameTime time, const QVariant& val, SetKeyframeInfo* info = nullptr, bool force_insert = false) override;
0991 
0992     keyframe_type* set_keyframe(FrameTime time, reference value, SetKeyframeInfo* info = nullptr, bool force_insert = false);
0993 
0994     bool set_value(const QVariant& val) override;
0995 
0996     bool valid_value(const QVariant& val) const override;
0997 
0998     void add_smooth_keyframe_undoable(FrameTime time, const QVariant& value) override;
0999 
1000     /**
1001      * \brief Gets the bezier derivative at the given time
1002      * \returns The derivative point, if defined
1003      */
1004     std::optional<QPointF> derivative_at(FrameTime time) const;
1005 
1006 Q_SIGNALS:
1007     /// Invoked on set_bezier()
1008     void  bezier_set(const math::bezier::Bezier& bezier);
1009 };
1010 
1011 
1012 } // namespace detail
1013 
1014 
1015 template<class Type>
1016 class AnimatedProperty : public detail::AnimatedProperty<Type>
1017 {
1018 public:
1019     using detail::AnimatedProperty<Type>::AnimatedProperty;
1020 };
1021 
1022 
1023 template<>
1024 class AnimatedProperty<float> : public detail::AnimatedProperty<float>
1025 {
1026 public:
1027     AnimatedProperty(
1028         Object* object,
1029         const KLazyLocalizedString& name,
1030         reference default_value,
1031         PropertyCallback<void, float> emitter = {},
1032         float min = std::numeric_limits<float>::lowest(),
1033         float max = std::numeric_limits<float>::max(),
1034         bool cycle = false,
1035         int flags = 0
1036     ) : detail::AnimatedProperty<float>(object, name, default_value, std::move(emitter), flags),
1037         min_(min),
1038         max_(max),
1039         cycle_(cycle)
1040     {
1041     }
1042 
1043     float max() const { return max_; }
1044     float min() const { return min_; }
1045 
1046     bool set(reference val)
1047     {
1048         return detail::AnimatedProperty<float>::set(bound(val));
1049     }
1050 
1051     using AnimatableBase::set_keyframe;
1052 
1053     keyframe_type* set_keyframe(FrameTime time, reference value, SetKeyframeInfo* info = nullptr, bool force_insert = false)
1054     {
1055         return detail::AnimatedProperty<float>::set_keyframe(time, bound(value), info, force_insert);
1056     }
1057 
1058 private:
1059     float bound(float value) const
1060     {
1061         return cycle_ ?
1062             math::fmod(value, max_) :
1063             math::bound(min_, value, max_)
1064         ;
1065     }
1066 
1067     float min_;
1068     float max_;
1069     bool cycle_;
1070 };
1071 
1072 
1073 template<>
1074 class AnimatedProperty<QPointF> : public detail::AnimatedPropertyPosition
1075 {
1076 public:
1077     using detail::AnimatedPropertyPosition::AnimatedPropertyPosition;
1078 };
1079 
1080 } // namespace glaxnimate::model