1 /***************************************************************************
2 * Copyright (C) 2010 by Simon Andreas Eugster (simon.eu@gmail.com) *
3 * This file is part of kdenlive. See www.kdenlive.org. *
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 ***************************************************************************/
12 This abstract widget is a proof that abstract things sometimes *are* useful.
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)
20 The layer order is as follows:
25 ---------------------------
30 ---------------------------
35 ---------------------------
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).
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.
43 Note: Widgets deriving from this class should connect slotActiveMonitorChanged
44 to the appropriate signal.
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.
51 #ifndef ABSTRACTSCOPEWIDGET_H
52 #define ABSTRACTSCOPEWIDGET_H
62 class AbstractScopeWidget : public QWidget
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;
71 /** Initializes widget settings (reads configuration).
72 Has to be called in the implementing object. */
75 /** Does this scope have auto-refresh enabled */
76 bool autoRefreshEnabled();
78 ///// Unimplemented /////
80 virtual QString widgetName() const = 0;
83 static const QPen penThick;
84 static const QPen penThin;
85 static const QPen penLight;
86 static const QPen penDark;
91 Monitor *m_projMonitor;
92 Monitor *m_clipMonitor;
93 Render *m_activeRender;
96 /** The context menu. Feel free to add new entries in your implementation. */
99 /** Enables auto refreshing of the scope.
100 This is when a new frame is shown on the active monitor.
101 Resize events always force a recalculation. */
102 QAction *m_aAutoRefresh;
104 /** Realtime rendering. Should be disabled if it is not supported.
105 Use the accelerationFactor variable passed to the render functions as a hint of
106 how many times faster the scope should be calculated. */
107 QAction *m_aRealtime;
109 /** The mouse position; Updated when the mouse enters the widget
110 AND mouse tracking has been enabled. */
112 /** Knows whether the mouse currently lies within the widget or not.
113 Can e.g. be used for drawing a HUD only when the mouse is in the widget. */
114 bool m_mouseWithinWidget;
116 /** Offset from the widget's borders */
119 /** The rect on the widget we're painting in.
120 Can be used by the implementing widget, e.g. in the render methods.
121 Is updated when necessary (size changes). */
124 /** Images storing the calculated layers. Will be used on repaint events. */
127 QImage m_imgBackground;
129 /** The acceleration factors can be accessed also by other renderer tasks,
130 e.g. to display the scope's acceleration factor in the HUD renderer. */
131 int m_accelFactorHUD;
132 int m_accelFactorScope;
133 int m_accelFactorBackground;
135 /** Reads the widget's configuration.
136 Can be extended in the implementing subclass (make sure to run readConfig as well). */
137 virtual void readConfig();
138 /** Writes the widget configuration.
139 Implementing widgets have to implement an own method and run it in their destructor. */
141 /** Identifier for the widget's configuration. */
142 QString configName();
145 ///// Unimplemented Methods /////
147 /** Where on the widget we can paint in.
148 May also update other variables that depend on the widget's size. */
149 virtual QRect scopeRect() = 0;
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, const QImage) = 0;
157 /** @brief Background renderer. Must emit signalBackgroundRenderingFinished(). @see renderScope */
158 virtual QImage renderBackground(uint accelerationFactor) = 0;
160 /** Must return true if the HUD layer depends on the input monitor.
161 If it does not, then it does not need to be re-calculated when
162 a new frame from the monitor 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;
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);
176 ///// Reimplemented /////
178 void mouseMoveEvent(QMouseEvent *);
179 void leaveEvent(QEvent *);
180 void mouseReleaseEvent(QMouseEvent *);
181 void paintEvent(QPaintEvent *);
182 void resizeEvent(QResizeEvent *);
183 void showEvent(QShowEvent *); // Called when the widget is activated via the Menu entry
184 // void raise(); // Called only when manually calling the event -> useless
188 /** Forces an update of all layers. */
189 void forceUpdate(bool doUpdate = true);
190 void forceUpdateHUD();
191 void forceUpdateScope();
192 void forceUpdateBackground();
193 void slotAutoRefreshToggled(bool);
196 /** mseconds represent the time taken for the calculation,
197 accelerationFactor is the acceleration factor that has been used. */
198 void signalHUDRenderingFinished(uint mseconds, uint accelerationFactor);
199 void signalScopeRenderingFinished(uint mseconds, uint accelerationFactor);
200 void signalBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
202 /** For the mouse position itself see m_mousePos.
203 To check whether the mouse has leaved the widget, see m_mouseWithinWidget. */
204 void signalMousePositionChanged();
206 /** Do we need the renderer to send its frames to us? */
207 void requestAutoRefresh(bool);
211 /** Counts the number of frames that have been rendered in the active monitor.
212 The frame number will be reset when the calculation starts for the current frame. */
213 QAtomicInt m_newHUDFrames;
214 QAtomicInt m_newScopeFrames;
215 QAtomicInt m_newBackgroundFrames;
217 /** Counts the number of updates that, unlike new frames, force a recalculation
218 of the scope, like for example a resize event. */
219 QAtomicInt m_newHUDUpdates;
220 QAtomicInt m_newScopeUpdates;
221 QAtomicInt m_newBackgroundUpdates;
223 /** The semaphores ensure that the QFutures for the HUD/Scope/Background threads cannot
224 be assigned a new thread while it is still running. (Could cause deadlocks and other
225 nasty things known from parallelism. */
226 QSemaphore m_semaphoreHUD;
227 QSemaphore m_semaphoreScope;
228 QSemaphore m_semaphoreBackground;
230 QFuture<QImage> m_threadHUD;
231 QFuture<QImage> m_threadScope;
232 QFuture<QImage> m_threadBackground;
234 bool initialDimensionUpdateDone;
235 bool m_requestForcedUpdate;
239 QString m_widgetName;
241 void prodHUDThread();
242 void prodScopeThread();
243 void prodBackgroundThread();
246 /** @brief Must be called when the active monitor has shown a new frame.
247 This slot must be connected in the implementing class, it is *not*
248 done in this abstract class. */
249 void slotActiveMonitorChanged(bool isClipMonitor);
252 void customContextMenuRequested(const QPoint &pos);
253 /** To be called when a new frame has been received.
254 The scope then decides whether and when it wants to recalculate the scope, depending
255 on whether it is currently visible and whether a calculation thread is already running. */
256 void slotRenderZoneUpdated();
257 void slotRenderZoneUpdated(QImage);
258 /** The following slots are called when rendering of a component has finished. They e.g. update
259 the widget and decide whether to immediately restart the calculation thread. */
260 void slotHUDRenderingFinished(uint mseconds, uint accelerationFactor);
261 void slotScopeRenderingFinished(uint mseconds, uint accelerationFactor);
262 void slotBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
264 /** Resets the acceleration factors to 1 when realtime rendering is disabled. */
265 void slotResetRealtimeFactor(bool realtimeChecked);
269 #endif // ABSTRACTSCOPEWIDGET_H