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