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 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.
48 #ifndef ABSTRACTSCOPEWIDGET_H
49 #define ABSTRACTSCOPEWIDGET_H
56 class AbstractScopeWidget : public QWidget
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
67 enum RescaleDirection { North, Northeast, East, Southeast };
70 QPalette m_scopePalette;
72 /** Initializes widget settings (reads configuration).
73 Has to be called in the implementing object. */
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();
80 ///// Unimplemented /////
82 virtual QString widgetName() const = 0;
85 static const QColor colHighlightLight;
86 static const QColor colHighlightDark;
87 static const QColor colDarkWhite;
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;
98 static const QString directions[]; // Mainly for debug output
101 ///// Variables /////
103 /** The context menu. Feel free to add new entries in your implementation. */
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;
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;
116 /** The mouse position; Updated when the mouse enters the widget
117 AND mouse tracking has been enabled. */
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;
123 /** Offset from the widget's borders */
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). */
131 /** Images storing the calculated layers. Will be used on repaint events. */
134 QImage m_imgBackground;
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;
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. */
148 /** Identifier for the widget's configuration. */
149 QString configName();
152 ///// Unimplemented Methods /////
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;
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;
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;
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);
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);
189 ///// Reimplemented /////
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
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);
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);
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();
221 /** Do we need the renderer to send its frames to us? */
222 void requestAutoRefresh(bool);
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;
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;
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;
245 QFuture<QImage> m_threadHUD;
246 QFuture<QImage> m_threadScope;
247 QFuture<QImage> m_threadBackground;
249 bool initialDimensionUpdateDone;
250 bool m_requestForcedUpdate;
254 QString m_widgetName;
256 void prodHUDThread();
257 void prodScopeThread();
258 void prodBackgroundThread();
260 ///// Movement detection /////
261 const int m_rescaleMinDist;
262 const float m_rescaleVerticalThreshold;
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;
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);
285 /** Resets the acceleration factors to 1 when realtime rendering is disabled. */
286 void slotResetRealtimeFactor(bool realtimeChecked);
290 #endif // ABSTRACTSCOPEWIDGET_H