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