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