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> ×); 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 */