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