1 /*
2  *  Copyright (c) 2017 Dmitry Kazakov <dimula73@gmail.com>
3  *
4  *  This program is free software; you can redistribute it and/or modify
5  *  it under the terms of the GNU General Public License as published by
6  *  the Free Software Foundation; either version 2 of the License, or
7  *  (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *  GNU General Public License for more details.
13  *
14  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18 
19 #ifndef KISASYNCANIMATIONRENDERERBASE_H
20 #define KISASYNCANIMATIONRENDERERBASE_H
21 
22 #include <QObject>
23 #include "kis_types.h"
24 
25 #include "kritaui_export.h"
26 
27 class KisRegion;
28 
29 /**
30  * KisAsyncAnimationRendererBase is a special class representing a
31  * single worker thread inside KisAsyncAnimationRenderDialogBase. It connects
32  * the specified image using correct Qt::DirectConnection connections and
33  * reacts on them. On sigFrameReady() signal it calls frameCompletedCallback(),
34  * so the derived class can fetch a frame from the image and process it. On
35  * sigFrameCancelled() it calls frameCancelledCallback(). The derived class
36  * should override these two methods to do the actual work.
37  */
38 
39 class KRITAUI_EXPORT KisAsyncAnimationRendererBase : public QObject
40 {
41     Q_OBJECT
42 public:
43     explicit KisAsyncAnimationRendererBase(QObject *parent = 0);
44     virtual ~KisAsyncAnimationRendererBase();
45 
46     /**
47      * Initiates the rendering of the frame \p frame on an image \p image.
48      * Only \p regionOfInterest is regenerated. If \p regionOfInterest is
49      * empty, then entire bounds of the image is regenerated.
50      */
51     void startFrameRegeneration(KisImageSP image, int frame, const KisRegion &regionOfInterest);
52 
53     /**
54      * Convenience overload that regenerates the full image
55      */
56     void startFrameRegeneration(KisImageSP image, int frame);
57 
58     /**
59      * @return true if the regeneration process is in progress
60      */
61     bool isActive() const;
62 
63 public Q_SLOTS:
64     /**
65      * @brief cancels current rendering operation
66      *
67      * After calling this slot requestedImage() becomes invalid.
68      * @see requestedImage()
69      */
70     void cancelCurrentFrameRendering();
71 
72 Q_SIGNALS:
73     void sigFrameCompleted(int frame);
74     void sigFrameCancelled(int frame);
75 
76 private Q_SLOTS:
77     void slotFrameRegenerationCancelled();
78     void slotFrameRegenerationFinished(int frame);
79 
80 protected Q_SLOTS:
81     /**
82      * Called by a derived class to continue processing of the frames
83      */
84     void notifyFrameCompleted(int frame);
85 
86     /**
87      * Called by a derived class to cancel processing of the frames. After calling
88      * this method, the dialog will stop processing the frames and close.
89      */
90     void notifyFrameCancelled(int frame);
91 
92 protected:
93     /**
94      * @brief frameCompletedCallback is called by the renderer when
95      *        a new frame becomes ready
96      *
97      * NOTE1: the callback is called from the context of a image
98      *        worker thread! So it is asynchronous from the GUI thread.
99      * NOTE2: in case of successful processing of the frame, the callback
100      *        must issue some signal, connected to notifyFrameCompleted()
101      *        via auto connection, to continue processing. Please do not
102      *        call the method directly, because notifyFame*() slots should
103      *        be called from the context of the GUI thread.
104      * NOTE3: In case of failure, notifyFrameCancelled(). The same threading
105      *        rules apply.
106      */
107     virtual void frameCompletedCallback(int frame, const KisRegion &requestedRegion) = 0;
108 
109     /**
110      * @brief frameCancelledCallback is called when the rendering of
111      *        the frame was cancelled.
112      *
113      * The rendering of the frame can be either cancelled by the image itself or
114      * by receiving a timeout signal (10 seconds).
115      *
116      * NOTE: the slot is called in the GUI thread. Don't forget to call
117      *       notifyFrameCancelled() in he end of your call.
118      */
119     virtual void frameCancelledCallback(int frame) = 0;
120 
121 
122     /**
123      * Called by KisAsyncAnimationRendererBase when the processing has been completed
124      * and the internal state of the populator should be cleared
125      *
126      * @param isCancelled tells if frame regeneration has failed to be regenerated
127      */
128     virtual void clearFrameRegenerationState(bool isCancelled);
129 
130 protected:
131     /**
132      * @return the image that for which the rendering was requested using
133      * startFrameRegeneration(). Should be used by the derived classes only.
134      *
135      * Please note that requestedImage() will become null as soon as the user
136      * cancels the processing. That happens in the GUI thread so
137      * frameCompletedCallback() should be extremely careful when requesting the
138      * value (check the shared pointer after fetching).
139      */
140     KisImageSP requestedImage() const;
141 
142 private:
143     struct Private;
144     const QScopedPointer<Private> m_d;
145 };
146 
147 #endif // KISASYNCANIMATIONRENDERERBASE_H
148