File indexing completed on 2024-05-19 04:26:18
0001 /* 0002 * SPDX-FileCopyrightText: 2015 Jouni Pentikäinen <joupent@gmail.com> 0003 * SPDX-FileCopyrightText: 2020 Emmet O 'Neill <emmetoneill.pdx@gmail.com> 0004 * SPDX-FileCopyrightText: 2020 Eoin O 'Neill <eoinoneill1991@gmail.com> 0005 * 0006 * SPDX-License-Identifier: GPL-2.0-or-later 0007 */ 0008 0009 #ifndef KIS_KEYFRAME_CHANNEL_H 0010 #define KIS_KEYFRAME_CHANNEL_H 0011 0012 #include <QVariant> 0013 #include <QDomElement> 0014 #include <kundo2command.h> 0015 0016 #include "kis_types.h" 0017 #include "KoID.h" 0018 #include "kis_keyframe.h" 0019 #include "kis_default_bounds.h" 0020 #include "kis_default_bounds_node_wrapper.h" 0021 0022 #include "kritaimage_export.h" 0023 0024 class KisTimeSpan; 0025 0026 0027 /** @brief KisKeyframeChannel stores and manages KisKeyframes. 0028 * Maps units of time to virtual keyframe values. 0029 * This class is a key piece of Krita's animation backend. 0030 * Abstract base class of KisRasterKeyframeChannel, KisScalarKeyframeChannel, etc. 0031 */ 0032 class KRITAIMAGE_EXPORT KisKeyframeChannel : public QObject 0033 { 0034 Q_OBJECT 0035 0036 public: 0037 static const KoID Raster; 0038 static const KoID Opacity; 0039 static const KoID TransformArguments; 0040 static const KoID PositionX; 0041 static const KoID PositionY; 0042 static const KoID ScaleX; 0043 static const KoID ScaleY; 0044 static const KoID ShearX; 0045 static const KoID ShearY; 0046 static const KoID RotationX; 0047 static const KoID RotationY; 0048 static const KoID RotationZ; 0049 0050 KisKeyframeChannel(const KoID &id, KisDefaultBoundsBaseSP bounds); 0051 KisKeyframeChannel(const KisKeyframeChannel &rhs); 0052 ~KisKeyframeChannel() override; 0053 0054 /** @brief Add a new keyframe to the channel at the specified time. */ 0055 void addKeyframe(int time, KUndo2Command *parentUndoCmd = nullptr); 0056 0057 /** @brief Insert an existing keyframe into the channel at the specified time. */ 0058 virtual void insertKeyframe(int time, KisKeyframeSP keyframe, KUndo2Command *parentUndoCmd = nullptr); 0059 0060 /** @brief Remove a keyframe from the channel at the specified time. */ 0061 virtual void removeKeyframe(int time, KUndo2Command *parentUndoCmd = nullptr); 0062 0063 // Inter-channel operations.. 0064 /** @brief Move a keyframe across channel(s) at the specified times. */ 0065 static void moveKeyframe(KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command* parentUndoCmd = nullptr); 0066 0067 /** @brief Copy a keyframe across channel(s) at the specified times. */ 0068 static void copyKeyframe(const KisKeyframeChannel *sourceChannel, int sourceTime, KisKeyframeChannel *targetChannel, int targetTime, KUndo2Command* parentUndoCmd = nullptr); 0069 0070 /** @brief Swap two keyframes across channel(s) at the specified times. */ 0071 static void swapKeyframes(KisKeyframeChannel *channelA, int timeA, KisKeyframeChannel *channelB, int timeB, KUndo2Command* parentUndoCmd = nullptr); 0072 0073 // Intra-channel convenience methods.. 0074 void moveKeyframe(int sourceTime, int targetTime, KUndo2Command* parentUndoCmd = nullptr) { moveKeyframe(this, sourceTime, this, targetTime, parentUndoCmd); } 0075 void copyKeyframe(int sourceTime, int targetTime, KUndo2Command* parentUndoCmd = nullptr) { copyKeyframe(this, sourceTime, this, targetTime, parentUndoCmd); } 0076 void swapKeyframes(int timeA, int timeB, KUndo2Command* parentUndoCmd = nullptr) { swapKeyframes(this, timeA, this, timeB, parentUndoCmd); } 0077 0078 // Keyframe methods.. 0079 /** @brief Get a keyframe at specified time. 0080 * Used primarily when the value of a given keyframe is needed. */ 0081 KisKeyframeSP keyframeAt(int time) const; 0082 KisKeyframeSP activeKeyframeAt(int time) const { return keyframeAt(activeKeyframeTime(time)); } 0083 0084 // Quick casting convenience templates.. 0085 template <class KeyframeType> 0086 QSharedPointer<KeyframeType> keyframeAt(int time) const { 0087 return keyframeAt(time).dynamicCast<KeyframeType>(); 0088 } 0089 0090 template <class KeyframeType> 0091 QSharedPointer<KeyframeType> activeKeyframeAt(int time) const { 0092 return activeKeyframeAt(time).dynamicCast<KeyframeType>(); 0093 } 0094 0095 int keyframeCount() const; 0096 0097 // Time methods.. 0098 /** @brief Get the time of the active keyframe. 0099 * Useful for snapping any time to that of the most recent keyframe. 0100 * @param time Input time. When not specified, currentTime() will be used. 0101 */ 0102 int activeKeyframeTime(int time) const; 0103 int activeKeyframeTime() const { return activeKeyframeTime(currentTime()); } 0104 0105 int firstKeyframeTime() const; 0106 int previousKeyframeTime(const int time) const; 0107 int nextKeyframeTime(const int time) const; 0108 int lastKeyframeTime() const; 0109 0110 /** @brief Get a set of all integer times that map to a keyframe. */ 0111 QSet<int> allKeyframeTimes() const; 0112 0113 QString id() const; 0114 QString name() const; 0115 0116 void setNode(KisNodeWSP node); 0117 KisNodeWSP node() const; 0118 void setDefaultBounds(KisDefaultBoundsBaseSP bounds); 0119 0120 /** @brief Calculates a pseudo-unique hash based on 0121 * the relevant internal state of the channel. */ 0122 int channelHash() const; 0123 0124 /** @brief Get the set of frames affected by any changes to the value 0125 * or content of the active keyframe at the given time. */ 0126 virtual KisTimeSpan affectedFrames(int time) const; 0127 0128 /** @brief Get a span of times for which the channel gives identical 0129 * results compared to frame at a given time. 0130 * NOTE: This set may be different than the set of affected frames 0131 * due to interpolation. 0132 */ 0133 virtual KisTimeSpan identicalFrames(int time) const; 0134 0135 /** 0136 * The rect that is affected by a frame at the given time 0137 */ 0138 virtual QRect affectedRect(int time) const = 0; 0139 0140 virtual QDomElement toXML(QDomDocument doc, const QString &layerFilename); 0141 virtual void loadXML(const QDomElement &channelNode); 0142 0143 static KoID channelIdToKoId(const QString &id); 0144 0145 Q_SIGNALS: 0146 /** @brief This signal is emitted just AFTER a keyframe was added to the channel. */ 0147 void sigAddedKeyframe(const KisKeyframeChannel *channel, int time); 0148 0149 /** @brief This signal is emitted just BEFORE a keyframe is removed from the channel. */ 0150 void sigKeyframeAboutToBeRemoved(const KisKeyframeChannel *channel, int time); 0151 0152 /** @brief This signal is emitted just AFTER a keyframe is removed from the channel. */ 0153 void sigKeyframeHasBeenRemoved(const KisKeyframeChannel *channel, int time); 0154 0155 /** @brief This signal is emitted just AFTER a non-raster keyframe was changed its value */ 0156 void sigKeyframeChanged(const KisKeyframeChannel *channel, int time); 0157 0158 /** This signal is an aggregate of the following signals: 0159 * - sigAddedKeyframe 0160 * - sigKeyframeHasBeenRemoved 0161 * - sigKeyframeChanged 0162 */ 0163 void sigAnyKeyframeChange(); 0164 0165 protected: 0166 typedef QMap<int, KisKeyframeSP> TimeKeyframeMap; 0167 TimeKeyframeMap &keys(); 0168 const TimeKeyframeMap &constKeys() const; 0169 int currentTime() const; 0170 0171 /** 0172 * Actual implementation of the frame removal that does everything except of 0173 * the signal emission (that should be emitted **before** the removal) 0174 */ 0175 virtual void removeKeyframeImpl(int time, KUndo2Command *parentUndoCmd); 0176 0177 /** 0178 * @brief Between Krita 4.1 and 4.4 Krita had a bug which resulted in creating frames 0179 * with negative time stamp. The bug has been fixed, but there might be some files 0180 * still in the wild. 0181 * 0182 * TODO: remove this workaround in Krita 5.0, when no such file are left :) 0183 */ 0184 Q_DECL_DEPRECATED void workaroundBrokenFrameTimeBug(int *time); 0185 0186 private: 0187 struct Private; 0188 QScopedPointer<Private> m_d; 0189 0190 /** @brief Virtual keyframe creation function. 0191 * Derived classes implement this function based on the needs 0192 * of their specific KisKeyframe subclasses. 0193 */ 0194 virtual KisKeyframeSP createKeyframe() = 0; 0195 virtual QPair<int, KisKeyframeSP> loadKeyframe(const QDomElement &keyframeNode) = 0; 0196 virtual void saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename) = 0; 0197 }; 0198 0199 #endif // KIS_KEYFRAME_CHANNEL_H