]> git.sesse.net Git - kdenlive/blob - src/scopes/abstractscopewidget.h
Fix includes
[kdenlive] / src / scopes / 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
13 #ifndef ABSTRACTSCOPEWIDGET_H
14 #define ABSTRACTSCOPEWIDGET_H
15
16 #include <QWidget>
17 #include <QSemaphore>
18 #include <QFuture>
19 class QMenu;
20 /**
21   \brief Abstract class for audio/colour scopes (receive data and paint it).
22
23   This abstract widget is a proof that abstract things sometimes \b *are* useful.
24
25   The widget expects three layers which
26   \li Will be painted on top of each other on each update
27   \li Are rendered in a separate thread so that the UI is not blocked
28   \li Are rendered only if necessary (e.g., if a layer does not depend
29     on input images, it will not be re-rendered for incoming frames)
30
31   The layer order is as follows:
32   \verbatim
33      _____________________
34     /                     \
35    /      HUD Layer        \
36   /                         \
37   ---------------------------
38      _____________________
39     /                     \
40    /     Scope Layer       \
41   /                         \
42   ---------------------------
43      _____________________
44     /                     \
45    /   Background Layer    \
46   /                         \
47   ---------------------------
48   \endverbatim
49
50   Colors of Scope Widgets are defined in here (and thus don't need to be
51   re-defined in the implementation of the widget's .ui file).
52
53   The custom context menu already contains entries, like for enabling auto-
54   refresh. It can certainly be extended in the implementation of the widget.
55
56   If you intend to write an own widget inheriting from this one, please read
57   the comments on the unimplemented methods carefully. They are not only here
58   for optical amusement, but also contain important information.
59  */
60 class AbstractScopeWidget : public QWidget
61 {
62     Q_OBJECT
63
64 public:
65     /**
66       \param trackMouse enables mouse tracking; The variables m_mousePos and m_mouseWithinWidget will be set
67             if mouse tracking is enabled.
68       \see signalMousePositionChanged(): Emitted when mouse tracking is enabled
69       */
70     explicit AbstractScopeWidget(bool trackMouse = false, QWidget *parent = 0);
71     virtual ~AbstractScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks
72
73
74     enum RescaleDirection { North, Northeast, East, Southeast };
75
76
77     QPalette m_scopePalette;
78
79     /** Initializes widget settings (reads configuration).
80       Has to be called in the implementing object. */
81     virtual void init();
82
83     /** Tell whether this scope has auto-refresh enabled. Required for determining whether
84         new data (e.g. an image frame) has to be delivered to this widget. */
85     bool autoRefreshEnabled() const;
86
87     bool needsSingleFrame();
88
89     ///// Unimplemented /////
90
91     virtual QString widgetName() const = 0;
92
93     ///// Variables /////
94     static const QColor colHighlightLight;
95     static const QColor colHighlightDark;
96     static const QColor colDarkWhite;
97
98     static const QPen penThick;
99     static const QPen penThin;
100     static const QPen penLight;
101     static const QPen penLightDots;
102     static const QPen penLighter;
103     static const QPen penDark;
104     static const QPen penDarkDots;
105     static const QPen penBackground;
106
107     static const QString directions[]; // Mainly for debug output
108
109 protected:
110     ///// Variables /////
111
112     /** The context menu. Feel free to add new entries in your implementation. */
113     QMenu *m_menu;
114
115     /** Enables auto refreshing of the scope.
116         This is when fresh data is incoming.
117         Resize events always force a recalculation. */
118     QAction *m_aAutoRefresh;
119
120     /** Realtime rendering. Should be disabled if it is not supported.
121         Use the accelerationFactor variable passed to the render functions as a hint of
122         how many times faster the scope should be calculated. */
123     QAction *m_aRealtime;
124
125     /** The mouse position; Updated when the mouse enters the widget
126         AND mouse tracking has been enabled. */
127     QPoint m_mousePos;
128     /** Knows whether the mouse currently lies within the widget or not.
129         Can e.g. be used for drawing a HUD only when the mouse is in the widget. */
130     bool m_mouseWithinWidget;
131
132     /** Offset from the widget's borders */
133     const uchar offset;
134
135     /** The rect on the widget we're painting in.
136         Can be used by the implementing widget, e.g. in the render methods.
137         Is updated when necessary (size changes). */
138     QRect m_scopeRect;
139
140     /** Images storing the calculated layers. Will be used on repaint events. */
141     QImage m_imgHUD;
142     QImage m_imgScope;
143     QImage m_imgBackground;
144
145     /** The acceleration factors can be accessed also by other renderer tasks,
146         e.g. to display the scope's acceleration factor in the HUD renderer. */
147     int m_accelFactorHUD;
148     int m_accelFactorScope;
149     int m_accelFactorBackground;
150
151     /** Reads the widget's configuration.
152         Can be extended in the implementing subclass (make sure to run readConfig as well). */
153     virtual void readConfig();
154     /** Writes the widget configuration.
155         Implementing widgets have to implement an own method and run it in their destructor. */
156     void writeConfig();
157     /** Identifier for the widget's configuration. */
158     QString configName();
159
160
161     ///// Unimplemented Methods /////
162
163     /** Where on the widget we can paint in.
164         May also update other variables, like m_scopeRect or custom ones,
165         that have to change together with the widget's size.  */
166     virtual QRect scopeRect() = 0;
167
168     /** @brief HUD renderer. Must emit signalHUDRenderingFinished().
169         @see renderScope(uint). */
170     virtual QImage renderHUD(uint accelerationFactor) = 0;
171     /** @brief Rendering function for the scope layer.
172         This function \b must emit signalScopeRenderingFinished(), otherwise the scope
173         will not attempt to ever call this function again. This signal is required for multi-threading;
174         not emitting it on unused rendering function may increase performance.
175         @param accelerationFactor hints how much faster than usual the calculation should be accomplished, if possible.
176         @see renderHUD(uint) for the upper layer
177         @see renderBackground(uint) for the layer below
178          */
179     virtual QImage renderScope(uint accelerationFactor) = 0;
180     /** @brief Background renderer. Must emit signalBackgroundRenderingFinished().
181         @see renderScope(uint) */
182     virtual QImage renderBackground(uint accelerationFactor) = 0;
183
184     /** Must return true if the HUD layer depends on the input data.
185         If it does not, then it does not need to be re-calculated when
186         fresh data is incoming. */
187     virtual bool isHUDDependingOnInput() const = 0;
188     /** @see isHUDDependingOnInput() */
189     virtual bool isScopeDependingOnInput() const = 0;
190     /** @see isHUDDependingOnInput() */
191     virtual bool isBackgroundDependingOnInput() const = 0;
192
193     ///// Can be reimplemented /////
194     /** Calculates the acceleration factor to be used by the render thread.
195         This method can be refined in the subclass if required. */
196     virtual uint calculateAccelFactorHUD(uint oldMseconds, uint oldFactor);
197     virtual uint calculateAccelFactorScope(uint oldMseconds, uint oldFactor);
198     virtual uint calculateAccelFactorBackground(uint oldMseconds, uint oldFactor);
199
200     /** The Abstract Scope will try to detect the movement direction when dragging on the widget with the mouse.
201         As soon as the direction is determined it will execute this method. Can be used e.g. for re-scaling content.
202         This is just a dummy function, re-implement to add functionality. */
203     virtual void handleMouseDrag(const QPoint &movement, const RescaleDirection rescaleDirection, const Qt::KeyboardModifiers rescaleModifiers);
204
205     ///// Reimplemented /////
206
207     void mouseMoveEvent(QMouseEvent *event);
208     void mousePressEvent(QMouseEvent *event);
209     void mouseReleaseEvent(QMouseEvent *event);
210     void leaveEvent(QEvent *);
211     void paintEvent(QPaintEvent *);
212     void resizeEvent(QResizeEvent *);
213     void showEvent(QShowEvent *); // Called when the widget is activated via the Menu entry
214     //    void raise(); // Called only when  manually calling the event -> useless
215
216
217 public slots:
218     /** Forces an update of all layers. */
219     void forceUpdate(bool doUpdate = true);
220     void forceUpdateHUD();
221     void forceUpdateScope();
222     void forceUpdateBackground();
223
224 protected slots:
225     void slotAutoRefreshToggled(bool);
226
227 signals:
228     /**
229       \param mseconds represents the time taken for the calculation.
230       \param accelerationFactor is the acceleration factor that has been used for this calculation.
231       */
232     void signalHUDRenderingFinished(uint mseconds, uint accelerationFactor);
233     void signalScopeRenderingFinished(uint mseconds, uint accelerationFactor);
234     void signalBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
235
236     /** For the mouse position itself see m_mousePos.
237         To check whether the mouse has leaved the widget, see m_mouseWithinWidget.
238         This signal is typically connected to forceUpdateHUD(). */
239     void signalMousePositionChanged();
240
241     /** Do we need the renderer to send its frames to us?
242         Emitted when auto-refresh is toggled. */
243     void requestAutoRefresh(bool);
244
245 private:
246
247     /** Counts the number of data frames that have been rendered in the active monitor.
248         The frame number will be reset when the calculation starts for the current data set. */
249     QAtomicInt m_newHUDFrames;
250     QAtomicInt m_newScopeFrames;
251     QAtomicInt m_newBackgroundFrames;
252
253     /** Counts the number of updates that, unlike new frames, force a recalculation
254         of the scope, like for example a resize event. */
255     QAtomicInt m_newHUDUpdates;
256     QAtomicInt m_newScopeUpdates;
257     QAtomicInt m_newBackgroundUpdates;
258
259     /** The semaphores ensure that the QFutures for the HUD/Scope/Background threads cannot
260         be assigned a new thread while it is still running. (Could cause deadlocks and other
261         nasty things known from parallelism.) */
262     QSemaphore m_semaphoreHUD;
263     QSemaphore m_semaphoreScope;
264     QSemaphore m_semaphoreBackground;
265
266     QFuture<QImage> m_threadHUD;
267     QFuture<QImage> m_threadScope;
268     QFuture<QImage> m_threadBackground;
269
270     bool initialDimensionUpdateDone;
271     bool m_requestForcedUpdate;
272
273     QImage m_scopeImage;
274
275     QString m_widgetName;
276
277     void prodHUDThread();
278     void prodScopeThread();
279     void prodBackgroundThread();
280
281     ///// Movement detection /////
282     const int m_rescaleMinDist;
283     const float m_rescaleVerticalThreshold;
284
285     bool m_rescaleActive;
286     bool m_rescalePropertiesLocked;
287     bool m_rescaleFirstRescaleDone;
288     Qt::KeyboardModifiers m_rescaleModifiers;
289     RescaleDirection m_rescaleDirection;
290     QPoint m_rescaleStartPoint;
291
292
293 protected slots:
294     void customContextMenuRequested(const QPoint &pos);
295     /** To be called when a new frame has been received.
296         The scope then decides whether and when it wants to recalculate the scope, depending
297         on whether it is currently visible and whether a calculation thread is already running. */
298     void slotRenderZoneUpdated();
299     /** The following slots are called when rendering of a component has finished. They e.g. update
300         the widget and decide whether to immediately restart the calculation thread. */
301     void slotHUDRenderingFinished(uint mseconds, uint accelerationFactor);
302     void slotScopeRenderingFinished(uint mseconds, uint accelerationFactor);
303     void slotBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
304
305     /** Resets the acceleration factors to 1 when realtime rendering is disabled. */
306     void slotResetRealtimeFactor(bool realtimeChecked);
307
308 };
309
310 #endif // ABSTRACTSCOPEWIDGET_H