File indexing completed on 2024-05-12 15:58:23
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 virtual QDomElement toXML(QDomDocument doc, const QString &layerFilename); 0136 virtual void loadXML(const QDomElement &channelNode); 0137 0138 Q_SIGNALS: 0139 /** @brief This signal is emitted whenever the relevant internal state 0140 * of the channel is changed. 0141 * @param affectedTimeSpan The span of times that were affected by the change. 0142 * @param affectedArea The area of the paint device that were affected by the change. 0143 */ 0144 void sigChannelUpdated(const KisTimeSpan &affectedTimeSpan, const QRect &affectedArea) const; 0145 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 sigRemovingKeyframe(const KisKeyframeChannel *channel, int time); 0151 0152 protected: 0153 typedef QMap<int, KisKeyframeSP> TimeKeyframeMap; 0154 TimeKeyframeMap &keys(); 0155 const TimeKeyframeMap &constKeys() const; 0156 int currentTime() const; 0157 0158 /** 0159 * @brief Between Krita 4.1 and 4.4 Krita had a bug which resulted in creating frames 0160 * with negative time stamp. The bug has been fixed, but there might be some files 0161 * still in the wild. 0162 * 0163 * TODO: remove this workaround in Krita 5.0, when no such file are left :) 0164 */ 0165 Q_DECL_DEPRECATED void workaroundBrokenFrameTimeBug(int *time); 0166 0167 private: 0168 struct Private; 0169 QScopedPointer<Private> m_d; 0170 0171 /** @brief Virtual keyframe creation function. 0172 * Derived classes implement this function based on the needs 0173 * of their specific KisKeyframe subclasses. 0174 */ 0175 virtual KisKeyframeSP createKeyframe() = 0; 0176 virtual QRect affectedRect(int time) const = 0; 0177 virtual QPair<int, KisKeyframeSP> loadKeyframe(const QDomElement &keyframeNode) = 0; 0178 virtual void saveKeyframe(KisKeyframeSP keyframe, QDomElement keyframeElement, const QString &layerFilename) = 0; 0179 }; 0180 0181 #endif // KIS_KEYFRAME_CHANNEL_H