File indexing completed on 2024-05-12 15:58:21

0001 /*
0002  *  SPDX-FileCopyrightText: 2015 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef __KIS_IMAGE_ANIMATION_INTERFACE_H
0008 #define __KIS_IMAGE_ANIMATION_INTERFACE_H
0009 
0010 #include <QObject>
0011 #include <QScopedPointer>
0012 
0013 #include "kis_types.h"
0014 #include "kritaimage_export.h"
0015 
0016 class KisUpdatesFacade;
0017 class KisTimeSpan;
0018 class KisKeyframeChannel;
0019 class KoColor;
0020 class KisRegion;
0021 
0022 namespace KisLayerUtils {
0023     struct SwitchFrameCommand;
0024 }
0025 
0026 class KRITAIMAGE_EXPORT KisImageAnimationInterface : public QObject
0027 {
0028     Q_OBJECT
0029 
0030 public:
0031     KisImageAnimationInterface(KisImage *image);
0032     KisImageAnimationInterface(const KisImageAnimationInterface &rhs, KisImage *newImage);
0033     ~KisImageAnimationInterface() override;
0034 
0035     /**
0036      * Returns true of the image has at least one animated layer
0037      */
0038     bool hasAnimation() const;
0039 
0040     /**
0041      * Returns currently active frame of the underlying image. Some strokes
0042      * can override this value and it will report a different value.
0043      */
0044     int currentTime() const;
0045 
0046     /**
0047      * Same as currentTime, except it isn't changed when background strokes
0048      * are running.
0049      */
0050     int currentUITime() const;
0051 
0052     /**
0053      * While any non-current frame is being regenerated by the
0054      * strategy, the image is kept in a special state, named
0055      * 'externalFrameActive'. Is this state the following applies:
0056      *
0057      * 1) All the animated paint devices switch its state into
0058      *    frameId() defined by global time.
0059      *
0060      * 2) All animation-not-capable devices switch to a temporary
0061      *    content device, which *is in undefined state*. The stroke
0062      *    should regenerate the image projection manually.
0063      */
0064     bool externalFrameActive() const;
0065 
0066     void requestTimeSwitchWithUndo(int time);
0067 
0068     void requestTimeSwitchNonGUI(int time, bool useUndo = false);
0069 
0070     /**
0071      * Start a background thread that will recalculate some extra frame.
0072      * The result will be reported using two types of signals:
0073      *
0074      * 1) KisImage::sigImageUpdated() will be emitted for every chunk
0075      *    of updated area.
0076      *
0077      * 2) sigFrameReady() will be emitted in the end of the operation.
0078      *    IMPORTANT: to get the result you must connect to this signal
0079      *    with Qt::DirectConnection and fetch the result from
0080      *    frameProjection().  After the signal handler is exited, the
0081      *    data will no longer be available.
0082      */
0083     void requestFrameRegeneration(int frameId, const KisRegion &dirtyRegion, bool isCancellable);
0084 
0085     void notifyNodeChanged(const KisNode *node, const QRect &rect, bool recursive);
0086     void notifyNodeChanged(const KisNode *node, const QVector<QRect> &rects, bool recursive);
0087     void invalidateFrames(const KisTimeSpan &range, const QRect &rect);
0088     void invalidateFrame(const int time, KisNodeSP target);
0089 
0090     /**
0091      * Changes the default color of the "external frame" projection of
0092      * the image's root layer. Please note that this command should be
0093      * executed from a context of an exclusive job!
0094      */
0095     void setDefaultProjectionColor(const KoColor &color);
0096 
0097     /**
0098      * The current time range selected by user.
0099      * @return current time range
0100      */
0101     const KisTimeSpan& fullClipRange() const;
0102     void setFullClipRange(const KisTimeSpan range);
0103 
0104 
0105     const KisTimeSpan &playbackRange() const;
0106     void setPlaybackRange(const KisTimeSpan range);
0107     int framerate() const;
0108 
0109     /**
0110      * @return **absolute** file name of the audio channel file
0111      */
0112     QString audioChannelFileName() const;
0113 
0114     /**
0115      * Sets **absolute** file name of the audio channel file. Don't try to pass
0116      * a relative path, it'll assert!
0117      */
0118     void setAudioChannelFileName(const QString &fileName);
0119 
0120     QString exportSequenceFilePath();
0121     void setExportSequenceFilePath(const QString &filePath);
0122 
0123     QString exportSequenceBaseName();
0124     void setExportSequenceBaseName(const QString &baseName);
0125 
0126     int exportInitialFrameNumber();
0127     void setExportInitialFrameNumber(const int frameNum);
0128 
0129     /**
0130      * @return is the audio channel is currently muted
0131      */
0132     bool isAudioMuted() const;
0133 
0134     /**
0135      * Mutes the audio channel
0136      */
0137     void setAudioMuted(bool value);
0138 
0139     /**
0140      * Returns the preferred audio value in rangle [0, 1]
0141      */
0142     qreal audioVolume() const;
0143 
0144     /**
0145      * Set the preferred volume for the audio channel in range [0, 1]
0146      */
0147     void setAudioVolume(qreal value);
0148 
0149     QSet<int> activeLayerSelectedTimes();
0150     void setActiveLayerSelectedTimes(const QSet<int> &times);
0151 
0152     KisImageWSP image() const;
0153 
0154     int totalLength();
0155 
0156 public Q_SLOTS:
0157     /**
0158      * Switches current frame (synchronously) and starts an
0159      * asynchronous regeneration of the entire image.
0160      */
0161     void switchCurrentTimeAsync(int frameId, bool useUndo = false);
0162 
0163     void setFullClipRangeStartTime(int column);
0164     void setFullClipRangeEndTime(int column);
0165 
0166     void setFramerate(int fps);
0167 
0168 Q_SIGNALS:
0169     void sigFrameReady(int time);
0170     void sigFrameCancelled();
0171     void sigUiTimeChanged(int newTime);
0172     void sigFramesChanged(const KisTimeSpan &range, const QRect &rect);
0173 
0174     void sigInternalRequestTimeSwitch(int frameId, bool useUndo);
0175 
0176     void sigFramerateChanged();
0177     void sigFullClipRangeChanged();
0178     void sigPlaybackRangeChanged();
0179 
0180     /**
0181      * Emitted when the audio channel of the document is changed
0182      */
0183     void sigAudioChannelChanged();
0184 
0185     /**
0186      * Emitted when audion volume changes. Please note that it doesn't change
0187      * when you mute the channel! When muting, sigAudioChannelChanged() is used instead!
0188      */
0189     void sigAudioVolumeChanged();
0190 
0191     void sigKeyframeAdded(const KisKeyframeChannel* channel, int time);
0192     void sigKeyframeRemoved(const KisKeyframeChannel* channel, int time);
0193 
0194 private:
0195     // interface for:
0196     friend class KisRegenerateFrameStrokeStrategy;
0197     friend class KisSuspendProjectionUpdatesStrokeStrategy; //TODO These friend classes are ugly. Let's refactor after Krita 5 release.
0198     friend class KisAnimationFrameCacheTest;
0199     friend struct KisLayerUtils::SwitchFrameCommand;
0200     friend class KisImageTest;
0201     void saveAndResetCurrentTime(int frameId, int *savedValue);
0202     void restoreCurrentTime(int *savedValue);
0203     void notifyFrameReady();
0204     void notifyFrameCancelled();
0205     bool requiresOnionSkinRendering();
0206 
0207     KisUpdatesFacade* updatesFacade() const;
0208 
0209     void blockFrameInvalidation(bool value);
0210 
0211     friend class KisSwitchTimeStrokeStrategy;
0212     friend class TransformStrokeStrategy;
0213     void explicitlySetCurrentTime(int frameId);
0214     struct Private;
0215     const QScopedPointer<Private> m_d;
0216 };
0217 
0218 #endif /* __KIS_IMAGE_ANIMATION_INTERFACE_H */