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 ***************************************************************************/
13 #ifndef ABSTRACTSCOPEWIDGET_H
14 #define ABSTRACTSCOPEWIDGET_H
21 \brief Abstract class for audio/colour scopes (receive data and paint it).
23 This abstract widget is a proof that abstract things sometimes \b *are* useful.
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)
31 The layer order is as follows:
37 ---------------------------
42 ---------------------------
47 ---------------------------
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).
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.
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.
60 class AbstractScopeWidget : public QWidget
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
70 AbstractScopeWidget(bool trackMouse = false, QWidget *parent = 0);
71 virtual ~AbstractScopeWidget(); // Must be virtual because of inheritance, to avoid memory leaks
74 enum RescaleDirection { North, Northeast, East, Southeast };
77 QPalette m_scopePalette;
79 /** Initializes widget settings (reads configuration).
80 Has to be called in the implementing object. */
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;
87 bool needsSingleFrame();
89 ///// Unimplemented /////
91 virtual QString widgetName() const = 0;
94 static const QColor colHighlightLight;
95 static const QColor colHighlightDark;
96 static const QColor colDarkWhite;
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;
107 static const QString directions[]; // Mainly for debug output
110 ///// Variables /////
112 /** The context menu. Feel free to add new entries in your implementation. */
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;
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;
125 /** The mouse position; Updated when the mouse enters the widget
126 AND mouse tracking has been enabled. */
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;
132 /** Offset from the widget's borders */
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). */
140 /** Images storing the calculated layers. Will be used on repaint events. */
143 QImage m_imgBackground;
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;
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. */
157 /** Identifier for the widget's configuration. */
158 QString configName();
161 ///// Unimplemented Methods /////
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;
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
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;
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;
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);
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);
205 ///// Reimplemented /////
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
218 /** Forces an update of all layers. */
219 void forceUpdate(bool doUpdate = true);
220 void forceUpdateHUD();
221 void forceUpdateScope();
222 void forceUpdateBackground();
225 void slotAutoRefreshToggled(bool);
229 \param mseconds represents the time taken for the calculation.
230 \param accelerationFactor is the acceleration factor that has been used for this calculation.
232 void signalHUDRenderingFinished(uint mseconds, uint accelerationFactor);
233 void signalScopeRenderingFinished(uint mseconds, uint accelerationFactor);
234 void signalBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
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();
241 /** Do we need the renderer to send its frames to us?
242 Emitted when auto-refresh is toggled. */
243 void requestAutoRefresh(bool);
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;
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;
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;
266 QFuture<QImage> m_threadHUD;
267 QFuture<QImage> m_threadScope;
268 QFuture<QImage> m_threadBackground;
270 bool initialDimensionUpdateDone;
271 bool m_requestForcedUpdate;
275 QString m_widgetName;
277 void prodHUDThread();
278 void prodScopeThread();
279 void prodBackgroundThread();
281 ///// Movement detection /////
282 const int m_rescaleMinDist;
283 const float m_rescaleVerticalThreshold;
285 bool m_rescaleActive;
286 bool m_rescalePropertiesLocked;
287 bool m_rescaleFirstRescaleDone;
288 short m_rescaleScale;
289 Qt::KeyboardModifiers m_rescaleModifiers;
290 RescaleDirection m_rescaleDirection;
291 QPoint m_rescaleStartPoint;
295 void customContextMenuRequested(const QPoint &pos);
296 /** To be called when a new frame has been received.
297 The scope then decides whether and when it wants to recalculate the scope, depending
298 on whether it is currently visible and whether a calculation thread is already running. */
299 void slotRenderZoneUpdated();
300 /** The following slots are called when rendering of a component has finished. They e.g. update
301 the widget and decide whether to immediately restart the calculation thread. */
302 void slotHUDRenderingFinished(uint mseconds, uint accelerationFactor);
303 void slotScopeRenderingFinished(uint mseconds, uint accelerationFactor);
304 void slotBackgroundRenderingFinished(uint mseconds, uint accelerationFactor);
306 /** Resets the acceleration factors to 1 when realtime rendering is disabled. */
307 void slotResetRealtimeFactor(bool realtimeChecked);
311 #endif // ABSTRACTSCOPEWIDGET_H