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