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