File indexing completed on 2024-05-12 16:01:45

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KISASYNCANIMATIONRENDERERBASE_H
0008 #define KISASYNCANIMATIONRENDERERBASE_H
0009 
0010 #include <QObject>
0011 #include "kis_types.h"
0012 
0013 #include "kritaui_export.h"
0014 
0015 class KisRegion;
0016 
0017 /**
0018  * KisAsyncAnimationRendererBase is a special class representing a
0019  * single worker thread inside KisAsyncAnimationRenderDialogBase. It connects
0020  * the specified image using correct Qt::DirectConnection connections and
0021  * reacts on them. On sigFrameReady() signal it calls frameCompletedCallback(),
0022  * so the derived class can fetch a frame from the image and process it. On
0023  * sigFrameCancelled() it calls frameCancelledCallback(). The derived class
0024  * should override these two methods to do the actual work.
0025  */
0026 
0027 class KRITAUI_EXPORT KisAsyncAnimationRendererBase : public QObject
0028 {
0029     Q_OBJECT
0030 
0031 public:
0032     enum Flag
0033     {
0034         None = 0x0,
0035         Cancellable = 0x1
0036     };
0037     Q_DECLARE_FLAGS(Flags, Flag)
0038 
0039     enum CancelReason {
0040         UserCancelled = 0,
0041         RenderingFailed,
0042         RenderingTimedOut
0043     };
0044     Q_ENUM(CancelReason)
0045 
0046 public:
0047     explicit KisAsyncAnimationRendererBase(QObject *parent = 0);
0048     virtual ~KisAsyncAnimationRendererBase();
0049 
0050     /**
0051      * Initiates the rendering of the frame \p frame on an image \p image.
0052      * Only \p regionOfInterest is regenerated. If \p regionOfInterest is
0053      * empty, then entire bounds of the image is regenerated.
0054      */
0055     void startFrameRegeneration(KisImageSP image, int frame, const KisRegion &regionOfInterest, Flags flags = None);
0056 
0057     /**
0058      * Convenience overload that regenerates the full image
0059      */
0060     void startFrameRegeneration(KisImageSP image, int frame, Flags flags = None);
0061 
0062     /**
0063      * @return true if the regeneration process is in progress
0064      */
0065     bool isActive() const;
0066 
0067 public Q_SLOTS:
0068     /**
0069      * @brief cancels current rendering operation
0070      *
0071      * After calling this slot requestedImage() becomes invalid.
0072      * @see requestedImage()
0073      */
0074     void cancelCurrentFrameRendering(CancelReason cancelReason);
0075 
0076 Q_SIGNALS:
0077     void sigFrameCompleted(int frame);
0078     void sigFrameCancelled(int frame, KisAsyncAnimationRendererBase::CancelReason cancelReason);
0079 
0080 private Q_SLOTS:
0081     void slotFrameRegenerationCancelled();
0082     void slotFrameRegenerationTimedOut();
0083     void slotFrameRegenerationFinished(int frame);
0084 
0085 protected Q_SLOTS:
0086     /**
0087      * Called by a derived class to continue processing of the frames
0088      */
0089     void notifyFrameCompleted(int frame);
0090 
0091     /**
0092      * Called by a derived class to cancel processing of the frames. After calling
0093      * this method, the dialog will stop processing the frames and close.
0094      */
0095     void notifyFrameCancelled(int frame, KisAsyncAnimationRendererBase::CancelReason cancelReason);
0096 
0097 protected:
0098     /**
0099      * @brief frameCompletedCallback is called by the renderer when
0100      *        a new frame becomes ready
0101      *
0102      * NOTE1: the callback is called from the context of a image
0103      *        worker thread! So it is asynchronous from the GUI thread.
0104      * NOTE2: in case of successful processing of the frame, the callback
0105      *        must issue some signal, connected to notifyFrameCompleted()
0106      *        via auto connection, to continue processing. Please do not
0107      *        call the method directly, because notifyFame*() slots should
0108      *        be called from the context of the GUI thread.
0109      * NOTE3: In case of failure, notifyFrameCancelled(). The same threading
0110      *        rules apply.
0111      */
0112     virtual void frameCompletedCallback(int frame, const KisRegion &requestedRegion) = 0;
0113 
0114     /**
0115      * @brief frameCancelledCallback is called when the rendering of
0116      *        the frame was cancelled.
0117      *
0118      * The rendering of the frame can be either cancelled by the image itself or
0119      * by receiving a timeout signal (10 seconds).
0120      *
0121      * NOTE: the slot is called in the GUI thread. Don't forget to call
0122      *       notifyFrameCancelled() in he end of your call.
0123      */
0124     virtual void frameCancelledCallback(int frame, CancelReason cancelReason) = 0;
0125 
0126 
0127     /**
0128      * Called by KisAsyncAnimationRendererBase when the processing has been completed
0129      * and the internal state of the populator should be cleared
0130      *
0131      * @param isCancelled tells if frame regeneration has failed to be regenerated
0132      */
0133     virtual void clearFrameRegenerationState(bool isCancelled);
0134 
0135 protected:
0136     /**
0137      * @return the image that for which the rendering was requested using
0138      * startFrameRegeneration(). Should be used by the derived classes only.
0139      *
0140      * Please note that requestedImage() will become null as soon as the user
0141      * cancels the processing. That happens in the GUI thread so
0142      * frameCompletedCallback() should be extremely careful when requesting the
0143      * value (check the shared pointer after fetching).
0144      */
0145     KisImageSP requestedImage() const;
0146 
0147 private:
0148     struct Private;
0149     const QScopedPointer<Private> m_d;
0150 };
0151 
0152 Q_DECLARE_OPERATORS_FOR_FLAGS(KisAsyncAnimationRendererBase::Flags)
0153 
0154 #endif // KISASYNCANIMATIONRENDERERBASE_H