]> git.sesse.net Git - kdenlive/blob - src/abstractscopewidget.h
140f127ad2b5601d6ceb9a46e538e0557f8191cd
[kdenlive] / src / abstractscopewidget.h
1 /***************************************************************************
2  *   Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com)      *
3  *   This file is part of kdenlive. See www.kdenlive.org.                  *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 2 of the License, or     *
8  *   (at your option) any later version.                                   *
9  ***************************************************************************/
10
11 /**
12   This abstract widget is a proof that abstract things sometimes *are* useful.
13
14   The widget expects three layers which
15   * Will be painted on top of each other on each update
16   * Are rendered in a separate thread so that the UI is not blocked
17   * Are rendered only if necessary (e.g., if a layer does not depend
18     on input images, it will not be re-rendered for incoming frames)
19
20   The layer order is as follows:
21      _____________________
22     /                     \
23    /      HUD Layer        \
24   /                         \
25   ---------------------------
26      _____________________
27     /                     \
28    /     Scope Layer       \
29   /                         \
30   ---------------------------
31      _____________________
32     /                     \
33    /   Background Layer    \
34   /                         \
35   ---------------------------
36
37   Colors of Scope Widgets are defined in here (and thus don't need to be
38   re-defined in the implementation of the widget's .ui file).
39
40   The custom context menu already contains entries, like for enabling auto-
41   refresh. It can certainly be extended in the implementation of the widget.
42
43   Note: Widgets deriving from this class should connect slotActiveMonitorChanged
44   to the appropriate signal.
45
46   If you intend to write an own widget inheriting from this one, please read
47   the comments on the unimplemented methods carefully. They are not only here
48   for optical amusement, but also contain important information.
49  */
50
51 #ifndef ABSTRACTSCOPEWIDGET_H
52 #define ABSTRACTSCOPEWIDGET_H
53
54 #include <QtCore>
55 #include <QWidget>
56
57 class QMenu;
58
59 class Monitor;
60 class Render;
61
62 class AbstractScopeWidget : public QWidget
63 {
64     Q_OBJECT
65
66 public:
67     AbstractScopeWidget(Monitor *projMonitor, Monitor *clipMonitor, bool trackMouse = false, QWidget *parent = 0);
68     virtual ~AbstractScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks
69     QPalette m_scopePalette;
70
71     /** Initializes widget settings (reads configuration).
72       Has to be called in the implementing object. */
73     void init();
74
75     ///// Unimplemented /////
76
77     virtual QString widgetName() const = 0;
78
79     ///// Variables /////
80     static const QPen penThick;
81     static const QPen penThin;
82     static const QPen penLight;
83     static const QPen penDark;
84
85 protected:
86     ///// Variables /////
87
88     Monitor *m_projMonitor;
89     Monitor *m_clipMonitor;
90     Render *m_activeRender;
91
92
93     /** The context menu. Feel free to add new entries in your implementation. */
94     QMenu *m_menu;
95
96     /** Enables auto refreshing of the scope.
97         This is when a new frame is shown on the active monitor.
98         Resize events always force a recalculation. */
99     QAction *m_aAutoRefresh;
100
101     /** Realtime rendering. Should be disabled if it is not supported.
102         Use the accelerationFactor variable passed to the render functions as a hint of
103         how many times faster the scope should be calculated. */
104     QAction *m_aRealtime;
105
106     /** The mouse position; Updated when the mouse enters the widget
107         AND mouse tracking has been enabled. */
108     QPoint m_mousePos;
109     /** Knows whether the mouse currently lies within the widget or not.
110         Can e.g. be used for drawing a HUD only when the mouse is in the widget. */
111     bool m_mouseWithinWidget;
112
113     /** Offset from the widget's borders */
114     const uchar offset;
115
116     /** The rect on the widget we're painting in.
117         Can be used by the implementing widget, e.g. in the render methods.
118         Is updated when necessary (size changes). */
119     QRect m_scopeRect;
120
121     /** Images storing the calculated layers. Will be used on repaint events. */
122     QImage m_imgHUD;
123     QImage m_imgScope;
124     QImage m_imgBackground;
125
126     /** The acceleration factors can be accessed also by other renderer tasks,
127         e.g. to display the scope's acceleration factor in the HUD renderer. */
128     int m_accelFactorHUD;
129     int m_accelFactorScope;
130     int m_accelFactorBackground;
131
132     /** Reads the widget's configuration.
133         Can be extended in the implementing subclass (make sure to run readConfig as well). */
134     virtual void readConfig();
135     /** Writes the widget configuration.
136         Implementing widgets have to implement an own method and run it in their destructor. */
137     void writeConfig();
138     /** Identifier for the widget's configuration. */
139     QString configName();
140
141
142     ///// Unimplemented Methods /////
143
144     /** Where on the widget we can paint in.
145         May also update other variables that depend on the widget's size.  */
146     virtual QRect scopeRect() = 0;
147
148     /** @brief HUD renderer. Must emit signalHUDRenderingFinished(). @see renderScope */
149     virtual QImage renderHUD(uint accelerationFactor) = 0;
150     /** @brief Scope renderer. Must emit signalScopeRenderingFinished()
151         when calculation has finished, to allow multi-threading.
152         accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible. */
153     virtual QImage renderScope(uint accelerationFactor, QImage) = 0;
154     /** @brief Background renderer. Must emit signalBackgroundRenderingFinished(). @see renderScope */
155     virtual QImage renderBackground(uint accelerationFactor) = 0;
156
157     /** Must return true if the HUD layer depends on the input monitor.
158         If it does not, then it does not need to be re-calculated when
159         a new frame from the monitor is incoming. */
160     virtual bool isHUDDependingOnInput() const = 0;
161     /** @see isHUDDependingOnInput() */
162     virtual bool isScopeDependingOnInput() const = 0;
163     /** @see isHUDDependingOnInput() */
164     virtual bool isBackgroundDependingOnInput() const = 0;
165
166     ///// Can be reimplemented /////
167     /** Calculates the acceleration factor to be used by the render thread.
168         This method can be refined in the subclass if required. */
169     virtual uint calculateAccelFactorHUD(uint oldMseconds, uint oldFactor);
170     virtual uint calculateAccelFactorScope(uint oldMseconds, uint oldFactor);
171     virtual uint calculateAccelFactorBackground(uint oldMseconds, uint oldFactor);
172
173     ///// Reimplemented /////
174
175     void mouseMoveEvent(QMouseEvent *);
176     void leaveEvent(QEvent *);
177     void mouseReleaseEvent(QMouseEvent *);
178     void paintEvent(QPaintEvent *);
179     void resizeEvent(QResizeEvent *);
180     void showEvent(QShowEvent *); // Called when the widget is activated via the Menu entry
181     //    void raise(); // Called only when  manually calling the event -> useless
182
183
184 protected slots:
185     /** Forces an update of all layers. */
186     void forceUpdate(bool doUpdate = true);
187     void forceUpdateHUD();
188     void forceUpdateScope();
189     void forceUpdateBackground();
190     void slotAutoRefreshToggled(bool);
191
192 signals:
193     /** mseconds represent the time taken for the calculation,
194         accelerationFactor is the acceleration factor that has been used. */
195     void signalHUDRenderingFinished(uint mseconds, uint accelerationFactor);
196     void signalScopeRenderingFinished(uint mseconds, uint accelerationFactor);
197     void signalBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
198
199     /** For the mouse position itself see m_mousePos.
200         To check whether the mouse has leaved the widget, see m_mouseWithinWidget. */
201     void signalMousePositionChanged();
202
203 private:
204
205     /** Counts the number of frames that have been rendered in the active monitor.
206       The frame number will be reset when the calculation starts for the current frame. */
207     QAtomicInt m_newHUDFrames;
208     QAtomicInt m_newScopeFrames;
209     QAtomicInt m_newBackgroundFrames;
210
211     /** Counts the number of updates that, unlike new frames, force a recalculation
212       of the scope, like for example a resize event. */
213     QAtomicInt m_newHUDUpdates;
214     QAtomicInt m_newScopeUpdates;
215     QAtomicInt m_newBackgroundUpdates;
216
217     /** The semaphores ensure that the QFutures for the HUD/Scope/Background threads cannot
218       be assigned a new thread while it is still running. (Could cause deadlocks and other
219       nasty things known from parallelism. */
220     QSemaphore m_semaphoreHUD;
221     QSemaphore m_semaphoreScope;
222     QSemaphore m_semaphoreBackground;
223
224     QFuture<QImage> m_threadHUD;
225     QFuture<QImage> m_threadScope;
226     QFuture<QImage> m_threadBackground;
227
228     QImage m_scopeImage;
229
230     QString m_widgetName;
231
232     bool initialDimensionUpdateDone;
233     void prodHUDThread();
234     void prodScopeThread();
235     void prodBackgroundThread();
236
237
238 private slots:
239     /** @brief Must be called when the active monitor has shown a new frame.
240       This slot must be connected in the implementing class, it is *not*
241       done in this abstract class. */
242     void slotActiveMonitorChanged(bool isClipMonitor);
243     void customContextMenuRequested(const QPoint &pos);
244     /** To be called when a new frame has been received.
245       The scope then decides whether and when it wants to recalculate the scope, depending
246       on whether it is currently visible and whether a calculation thread is already running. */
247     void slotRenderZoneUpdated();
248     void slotRenderZoneUpdated(QImage);
249     /** The following slots are called when rendering of a component has finished. They e.g. update
250       the widget and decide whether to immediately restart the calculation thread. */
251     void slotHUDRenderingFinished(uint mseconds, uint accelerationFactor);
252     void slotScopeRenderingFinished(uint mseconds, uint accelerationFactor);
253     void slotBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
254
255     /** Resets the acceleration factors to 1 when realtime rendering is disabled. */
256     void slotResetRealtimeFactor(bool realtimeChecked);
257
258 };
259
260 #endif // ABSTRACTSCOPEWIDGET_H