File indexing completed on 2024-12-15 04:01:00

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 "base.hpp"
0010 
0011 #include "command/base.hpp"
0012 #include "model/animation/animatable.hpp"
0013 #include "model/document.hpp"
0014 #include "model/object.hpp"
0015 
0016 namespace glaxnimate::command {
0017 
0018 class SetKeyframe : public MergeableCommand<Id::SetKeyframe, SetKeyframe>
0019 {
0020 public:
0021     SetKeyframe(
0022         model::AnimatableBase* prop,
0023         model::FrameTime time,
0024         const QVariant& value,
0025         bool commit,
0026         bool force_insert = false
0027     );
0028 
0029     void undo() override;
0030 
0031     void redo() override;
0032 
0033     bool merge_with(const SetKeyframe& other);
0034 
0035 private:
0036     model::AnimatableBase* prop;
0037     model::FrameTime time;
0038     QVariant before;
0039     QVariant after;
0040     bool had_before;
0041     bool calculated = false;
0042     int insert_index = -1;
0043     model::KeyframeTransition trans_before;
0044     model::KeyframeTransition left;
0045     model::KeyframeTransition right;
0046     bool force_insert = false;
0047 };
0048 
0049 class RemoveKeyframeTime : public QUndoCommand
0050 {
0051 public:
0052     RemoveKeyframeTime(
0053         model::AnimatableBase* prop,
0054         model::FrameTime time
0055     );
0056 
0057     void undo() override;
0058 
0059     void redo() override;
0060 
0061 private:
0062     model::AnimatableBase* prop;
0063     model::FrameTime time;
0064     int index;
0065     QVariant before;
0066     model::KeyframeTransition prev_transition_before;
0067     model::KeyframeTransition prev_transition_after;
0068 };
0069 
0070 
0071 class RemoveKeyframeIndex: public QUndoCommand
0072 {
0073 public:
0074     RemoveKeyframeIndex(
0075         model::AnimatableBase* prop,
0076         int index
0077     );
0078 
0079     void undo() override;
0080 
0081     void redo() override;
0082 
0083 private:
0084     model::AnimatableBase* prop;
0085     int index;
0086     model::FrameTime time;
0087     QVariant before;
0088     model::KeyframeTransition prev_transition_before;
0089     model::KeyframeTransition prev_transition_after;
0090 };
0091 
0092 
0093 
0094 class RemoveAllKeyframes : public QUndoCommand
0095 {
0096 public:
0097     RemoveAllKeyframes(model::AnimatableBase* prop, QVariant value);
0098 
0099     void undo() override;
0100 
0101     void redo() override;
0102 
0103 private:
0104     struct Keframe
0105     {
0106         model::FrameTime time;
0107         QVariant value;
0108         model::KeyframeTransition transition;
0109     };
0110     model::AnimatableBase* prop;
0111     std::vector<Keframe> keyframes;
0112     QVariant before;
0113     QVariant after;
0114 };
0115 
0116 
0117 /**
0118  * \brief Command that sets multiple animated properties at once,
0119  * setting keyframes based on the document record_to_keyframe
0120  */
0121 class SetMultipleAnimated : public MergeableCommand<Id::SetMultipleAnimated, SetMultipleAnimated>
0122 {
0123 public:
0124     SetMultipleAnimated(model::AnimatableBase* prop, QVariant after, bool commit);
0125 
0126     template<class... Args>
0127     SetMultipleAnimated(
0128         const QString& name,
0129         bool commit,
0130         const std::vector<model::AnimatableBase*>& props,
0131         Args... vals
0132     ) : SetMultipleAnimated(name, props, {}, {QVariant::fromValue(vals)...}, commit)
0133     {}
0134 
0135     /**
0136      * \pre props.size() == after.size() && (props.size() == before.size() || before.empty())
0137      *
0138      * If before.empty() it will be populated by the properties
0139      */
0140     SetMultipleAnimated(
0141         const QString& name,
0142         const std::vector<model::AnimatableBase*>& props,
0143         const QVariantList& before,
0144         const QVariantList& after,
0145         bool commit
0146     );
0147 
0148     SetMultipleAnimated(const QString& name, bool commit);
0149 
0150     void push_property(model::AnimatableBase* prop, const QVariant& after);
0151     void push_property_not_animated(model::BaseProperty* prop, const QVariant& after);
0152 
0153     void undo() override;
0154 
0155     void redo() override;
0156 
0157     bool merge_with(const SetMultipleAnimated& other);
0158 
0159     const std::vector<model::AnimatableBase*>& properties() const { return props; }
0160 
0161     bool empty() const;
0162 
0163 private:
0164     static QString auto_name(model::AnimatableBase* prop);
0165 
0166     std::vector<model::AnimatableBase*> props;
0167     QVariantList before;
0168     QVariantList after;
0169     std::vector<int> keyframe_before;
0170     bool keyframe_after;
0171     model::FrameTime time;
0172     std::vector<bool> add_0;
0173     std::vector<model::BaseProperty*> props_not_animated;
0174 };
0175 
0176 
0177 class SetKeyframeTransition : public QUndoCommand
0178 {
0179 public:
0180     SetKeyframeTransition(
0181         model::AnimatableBase* prop,
0182         int keyframe_index,
0183         model::KeyframeTransition::Descriptive desc,
0184         const QPointF& point,
0185         bool before_transition
0186     );
0187 
0188     SetKeyframeTransition(
0189         model::AnimatableBase* prop,
0190         int keyframe_index,
0191         const model::KeyframeTransition& transition
0192     );
0193 
0194     void undo() override;
0195     void redo() override;
0196 
0197 private:
0198     model::KeyframeBase* keyframe() const;
0199 
0200     model::AnimatableBase* prop;
0201     int keyframe_index;
0202     model::KeyframeTransition undo_value;
0203     model::KeyframeTransition redo_value;
0204 };
0205 
0206 
0207 class MoveKeyframe : public QUndoCommand
0208 {
0209 public:
0210     MoveKeyframe(
0211         model::AnimatableBase* prop,
0212         int keyframe_index,
0213         model::FrameTime time_after
0214     );
0215 
0216     void undo() override;
0217 
0218     void redo() override;
0219 
0220     /**
0221      * \brief The index after redo()
0222      * \pre redo() called at least once
0223      */
0224     int redo_index() const;
0225 
0226 private:
0227     model::AnimatableBase* prop;
0228     int keyframe_index_before;
0229     int keyframe_index_after = -1;
0230     model::FrameTime time_before;
0231     model::FrameTime time_after;
0232 };
0233 
0234 template<class T>
0235 class StretchTimeCommand: public QUndoCommand
0236 {
0237 public:
0238     /**
0239      * \pre multiplier > 0
0240      */
0241     StretchTimeCommand(T* target, qreal multiplier)
0242         : QUndoCommand(i18n("Stretch Time")),
0243           target(target),
0244           multiplier(multiplier)
0245     {}
0246 
0247     void undo() override
0248     {
0249         target->stretch_time(1/multiplier);
0250         if constexpr ( !std::is_same_v<T, model::Document> )
0251             target->set_time(target->document()->current_time());
0252     }
0253 
0254     void redo() override
0255     {
0256         target->stretch_time(multiplier);
0257         if constexpr ( !std::is_same_v<T, model::Document> )
0258             target->set_time(target->document()->current_time());
0259     }
0260 
0261 private:
0262     T* target;
0263     qreal multiplier;
0264 };
0265 
0266 
0267 /**
0268  * \brief Command that sets the path of an animated position
0269  */
0270 class SetPositionBezier : public MergeableCommand<Id::SetMultipleAnimated, SetPositionBezier>
0271 {
0272 public:
0273     SetPositionBezier(model::detail::AnimatedPropertyPosition* prop, math::bezier::Bezier after, bool commit, const QString& name = "");
0274     SetPositionBezier(model::detail::AnimatedPropertyPosition* prop, math::bezier::Bezier before, math::bezier::Bezier after, bool commit, const QString& name = "");
0275 
0276     void undo() override;
0277 
0278     void redo() override;
0279 
0280     bool merge_with(const SetPositionBezier& other);
0281 
0282 private:
0283     model::detail::AnimatedPropertyPosition* property;
0284     math::bezier::Bezier before;
0285     math::bezier::Bezier after;
0286 };
0287 
0288 
0289 /**
0290  * \brief Undo command whose children are done and undone in custom order
0291  */
0292 class ReorderedUndoCommand : public QUndoCommand
0293 {
0294 public:
0295     using QUndoCommand::QUndoCommand;
0296 
0297     void add_command(std::unique_ptr<QUndoCommand> cmd, int order_redo, int order_undo)
0298     {
0299         undo_map[order_undo] = cmd.get();
0300         redo_map[order_redo] = std::move(cmd);
0301     }
0302 
0303     void undo() override
0304     {
0305         for ( const auto& p : undo_map )
0306             p.second->undo();
0307     }
0308 
0309     void redo() override
0310     {
0311         for ( const auto& p : redo_map )
0312             p.second->redo();
0313     }
0314 
0315 private:
0316     std::map<int, std::unique_ptr<QUndoCommand>> redo_map;
0317     std::map<int, QUndoCommand*> undo_map;
0318 };
0319 
0320 } // namespace glaxnimate::command