File indexing completed on 2024-05-19 04:26:17

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 class KisLockFrameGenerationLock;
0022 
0023 namespace KisLayerUtils {
0024     struct SwitchFrameCommand;
0025 }
0026 
0027 class KRITAIMAGE_EXPORT KisImageAnimationInterface : public QObject
0028 {
0029     Q_OBJECT
0030 
0031 public:
0032     KisImageAnimationInterface(KisImage *image);
0033     KisImageAnimationInterface(const KisImageAnimationInterface &rhs, KisImage *newImage);
0034     ~KisImageAnimationInterface() override;
0035 
0036     /**
0037      * Returns true of the image has at least one animated layer
0038      */
0039     bool hasAnimation() const;
0040 
0041     /**
0042      * Returns currently active frame of the underlying image. Some strokes
0043      * can override this value and it will report a different value.
0044      */
0045     int currentTime() const;
0046 
0047     /**
0048      * Same as currentTime, except it isn't changed when background strokes
0049      * are running.
0050      */
0051     int currentUITime() const;
0052 
0053     /**
0054      * While any non-current frame is being regenerated by the
0055      * strategy, the image is kept in a special state, named
0056      * 'externalFrameActive'. Is this state the following applies:
0057      *
0058      * 1) All the animated paint devices switch its state into
0059      *    frameId() defined by global time.
0060      *
0061      * 2) All animation-not-capable devices switch to a temporary
0062      *    content device, which *is in undefined state*. The stroke
0063      *    should regenerate the image projection manually.
0064      */
0065     bool externalFrameActive() const;
0066 
0067     void requestTimeSwitchWithUndo(int time);
0068 
0069     void requestTimeSwitchNonGUI(int time, bool useUndo = false);
0070 
0071     /**
0072      * Start a background thread that will recalculate some extra frame.
0073      * The result will be reported using two types of signals:
0074      *
0075      * 1) KisImage::sigImageUpdated() will be emitted for every chunk
0076      *    of updated area.
0077      *
0078      * 2) sigFrameReady() will be emitted in the end of the operation.
0079      *    IMPORTANT: to get the result you must connect to this signal
0080      *    with Qt::DirectConnection and fetch the result from
0081      *    frameProjection().  After the signal handler is exited, the
0082      *    data will no longer be available.
0083      *
0084      * 3) The passed lock will be released when the stroke is finished
0085      *    execution (and the strategy is destroyed)
0086      */
0087     void requestFrameRegeneration(int frameId, const KisRegion &dirtyRegion, bool isCancellable, KisLockFrameGenerationLock &&lock);
0088 
0089     void notifyNodeChanged(const KisNode *node, const QRect &rect, bool recursive);
0090     void notifyNodeChanged(const KisNode *node, const QVector<QRect> &rects, bool recursive);
0091     void invalidateFrames(const KisTimeSpan &range, const QRect &rect);
0092     void invalidateFrame(const int time, KisNodeSP target);
0093 
0094     /**
0095      * Changes the default color of the "external frame" projection of
0096      * the image's root layer. Please note that this command should be
0097      * executed from a context of an exclusive job!
0098      */
0099     void setDefaultProjectionColor(const KoColor &color);
0100 
0101     /**
0102      * @brief documentPlaybackRange
0103      * @return A KisTimeSpan reflecting actual document time range. This is
0104      * the actual play back range associated with a krita document.
0105      */
0106     const KisTimeSpan& documentPlaybackRange() const;
0107     void setDocumentRange(const KisTimeSpan range);
0108 
0109     /**
0110      * @brief activePlaybackRange
0111      * @return Returns the current clip range that the user wishes play through.
0112      * Takes into account selection range when available as a custom loop override.
0113      * Should be used in the PlaybackEngine to determine proper loop points.
0114      */
0115     const KisTimeSpan &activePlaybackRange() const;
0116     void setActivePlaybackRange(const KisTimeSpan range);
0117 
0118     int framerate() const;
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     QSet<int> activeLayerSelectedTimes();
0130     void setActiveLayerSelectedTimes(const QSet<int> &times);
0131 
0132     KisImageWSP image() const;
0133 
0134     int totalLength();
0135 
0136     /**
0137      * Blocks background processes like frame cache populator from starting the
0138      * generation process, hence giving priority to the interactive frame
0139      * generation methods.
0140      *
0141      * This method is **not** blocking, it just forbids further
0142      * actions. If there is any backround action is running, it
0143      * continues to run. Use lockFrameGeneration() to wait
0144      * for completion of such actions.
0145      *
0146      * \see KisBlockBackgroundFrameGenerationLock for RAII wrapper
0147      */
0148     void blockBackgroundFrameGeneration();
0149 
0150     /**
0151      * Unblocks background generation process.
0152      *
0153      * \see blockBackgroundFrameGeneration()
0154      */
0155     void unblockBackgroundFrameGeneration();
0156 
0157     /**
0158      * Reports if background generation process is blocked
0159      *
0160      * \see blockBackgroundFrameGeneration()
0161      */
0162     bool backgroundFrameGenerationBlocked() const;
0163 
0164     /**
0165      * Acquire an exclusive lock for the frame generation process
0166      * initiated by requestFrameRegeneration().
0167      *
0168      * It is impossible to execute multiple background frame
0169      * generation processes on a single image, because the
0170      * image returns the result using global signals. Hence
0171      * the initiator of the generation should acquire the lock
0172      * first and pass it to requestFrameRegeneration(). The lock
0173      * will be automatically released when the frame generation
0174      * process is ended and all the signals are emitted.
0175      *
0176      * Calling to lockFrameGeneration() may block until the
0177      * currently executing frame generation process is running.
0178      *
0179      * \see KisLockFrameGenerationLock for RAII wrapper
0180      */
0181     void lockFrameGeneration();
0182 
0183     /**
0184      * Release frame generation lock
0185      *
0186      * \see lockFrameGeneration()
0187      */
0188     void unlockFrameGeneration();
0189 
0190     /**
0191      * Try to acquire frame generation lock
0192      *
0193      * \see lockFrameGeneration()
0194      */
0195     bool tryLockFrameGeneration();
0196 
0197     enum SwitchTimeAsyncOption {
0198         STAO_NONE = 0,
0199         STAO_USE_UNDO = 1 << 1,
0200         STAO_FORCE_REGENERATION = 1 << 2
0201     };
0202     Q_DECLARE_FLAGS(SwitchTimeAsyncFlags, SwitchTimeAsyncOption);
0203 
0204 public Q_SLOTS:
0205 
0206     /**
0207      * Switches current frame (synchronously) and starts an
0208      * asynchronous regeneration of the entire image.
0209      */
0210     void switchCurrentTimeAsync(int frameId, SwitchTimeAsyncFlags options = STAO_NONE);
0211 
0212     void setDocumentRangeStartFrame(int column);
0213     void setDocumentRangeEndFrame(int column);
0214 
0215     void setFramerate(int fps);
0216 
0217 Q_SIGNALS:
0218     /**
0219      * @brief sigFrameReady notifies when an External frame has been regenerated and is available.
0220      * @param time -- frame index
0221      *
0222      * Used for background processing of frames where we want to ensure that an external frame has
0223      * been fully processed before updating.
0224      *
0225      */
0226     void sigFrameReady(int time);
0227 
0228     /**
0229      * @brief sigFrameRegenerated notifies when internal frame has been fully regenerated.
0230      * @param time
0231      *
0232      * Used to notify switchCurrentTimeAsync clients that the frame is visible to the user.
0233      * Only notifies when internal frame regeneration occurs, not external.
0234      * Currently used in AnimationPlayer to update what it considers to be the "visible" frame
0235      */
0236     void sigFrameRegenerated(int time);
0237 
0238     /**
0239      * @brief sigFrameRegenerationSkipped notified when async frame changes are skipped.
0240      * @param time
0241      *
0242      * Skipping frame regeneration occurs when the contents of the frame are deemed unimportant
0243      * and not work updating the canvas for (generally for image-wide hold frames, for example.)
0244      */
0245     void sigFrameRegenerationSkipped(int time);
0246 
0247     void sigFrameCancelled();
0248     void sigUiTimeChanged(int newTime);
0249     void sigFramesChanged(const KisTimeSpan &range, const QRect &rect);
0250 
0251     void sigInternalRequestTimeSwitch(int frameId, bool useUndo);
0252 
0253     void sigFramerateChanged();
0254     void sigPlaybackRangeChanged();
0255 
0256     void sigKeyframeAdded(const KisKeyframeChannel* channel, int time);
0257     void sigKeyframeRemoved(const KisKeyframeChannel* channel, int time);
0258 
0259 private:
0260     // interface for:
0261     friend class KisRegenerateFrameStrokeStrategy;
0262     friend class KisSuspendProjectionUpdatesStrokeStrategy; //TODO These friend classes are ugly. Let's refactor after Krita 5 release.
0263     friend class KisAnimationFrameCacheTest;
0264     friend struct KisLayerUtils::SwitchFrameCommand;
0265     friend class KisImageTest;
0266     void saveAndResetCurrentTime(int frameId, int *savedValue);
0267     void restoreCurrentTime(int *savedValue);
0268     void notifyFrameReady();
0269     void notifyFrameCancelled();
0270     void notifyFrameRegenerated();
0271     bool requiresOnionSkinRendering();
0272 
0273     KisUpdatesFacade* updatesFacade() const;
0274 
0275     void blockFrameInvalidation(bool value);
0276 
0277     friend class KisSwitchTimeStrokeStrategy;
0278     friend class TransformStrokeStrategy;
0279     void explicitlySetCurrentTime(int frameId);
0280     struct Private;
0281     const QScopedPointer<Private> m_d;
0282 };
0283 
0284 #endif /* __KIS_IMAGE_ANIMATION_INTERFACE_H */