Qwt User's Guide 6.2.0

qwt_widget_overlay.cpp
1 /******************************************************************************
2 * Qwt Widget Library
3 * Copyright (C) 1997 Josef Wilgen
4 * Copyright (C) 2002 Uwe Rathmann
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the Qwt License, Version 1.0
8 *****************************************************************************/
9
10 #include "qwt_widget_overlay.h"
11 #include "qwt_painter.h"
12
13 #include <qpainter.h>
14 #include <qpaintengine.h>
15 #include <qpainterpath.h>
16 #include <qimage.h>
17 #include <qevent.h>
18
19 #include <cstdlib>
20
21 static QImage::Format qwtMaskImageFormat()
22 {
23 if ( QwtPainter::isX11GraphicsSystem() )
24 return QImage::Format_ARGB32;
25
26 return QImage::Format_ARGB32_Premultiplied;
27 }
28
29 static QRegion qwtAlphaMask( const QImage& image, const QRegion& region )
30 {
31 const int w = image.width();
32 const int h = image.height();
33
34 QRegion mask;
35 QRect rect;
36
37 #if QT_VERSION >= 0x050800
38 for ( QRegion::const_iterator it = region.cbegin();
39 it != region.cend(); ++it )
40 {
41 const QRect& r = *it;
42 #else
43 const QVector< QRect > rects = region.rects();
44 for ( int i = 0; i < rects.size(); i++ )
45 {
46 const QRect& r = rects[i];
47 #endif
48 int x1, x2, y1, y2;
49 r.getCoords( &x1, &y1, &x2, &y2 );
50
51 x1 = qMax( x1, 0 );
52 x2 = qMin( x2, w - 1 );
53 y1 = qMax( y1, 0 );
54 y2 = qMin( y2, h - 1 );
55
56 for ( int y = y1; y <= y2; ++y )
57 {
58 bool inRect = false;
59 int rx0 = -1;
60
61 const uint* line =
62 reinterpret_cast< const uint* > ( image.scanLine( y ) ) + x1;
63 for ( int x = x1; x <= x2; x++ )
64 {
65 const bool on = ( ( *line++ >> 24 ) != 0 );
66 if ( on != inRect )
67 {
68 if ( inRect )
69 {
70 rect.setCoords( rx0, y, x - 1, y );
71 mask += rect;
72 }
73 else
74 {
75 rx0 = x;
76 }
77
78 inRect = on;
79 }
80 }
81
82 if ( inRect )
83 {
84 rect.setCoords( rx0, y, x2, y );
85 mask = mask.united( rect );
86 }
87 }
88 }
89
90 return mask;
91 }
92
93 class QwtWidgetOverlay::PrivateData
94 {
95 public:
96 PrivateData()
97 : maskMode( QwtWidgetOverlay::MaskHint )
98 , renderMode( QwtWidgetOverlay::AutoRenderMode )
99 , rgbaBuffer( NULL )
100 {
101 }
102
103 ~PrivateData()
104 {
105 resetRgbaBuffer();
106 }
107
108 void resetRgbaBuffer()
109 {
110 if ( rgbaBuffer )
111 {
112 std::free( rgbaBuffer );
113 rgbaBuffer = NULL;
114 }
115 }
116
117 MaskMode maskMode;
118 RenderMode renderMode;
119 uchar* rgbaBuffer;
120 };
121
126 QwtWidgetOverlay::QwtWidgetOverlay( QWidget* widget )
127 : QWidget( widget )
128 {
129 m_data = new PrivateData;
130
131 setAttribute( Qt::WA_TransparentForMouseEvents );
132 setAttribute( Qt::WA_NoSystemBackground );
133 setFocusPolicy( Qt::NoFocus );
134
135 if ( widget )
136 {
137 resize( widget->size() );
138 widget->installEventFilter( this );
139 }
140 }
141
143 QwtWidgetOverlay::~QwtWidgetOverlay()
144 {
145 delete m_data;
146 }
147
154 void QwtWidgetOverlay::setMaskMode( MaskMode mode )
155 {
156 if ( mode != m_data->maskMode )
157 {
158 m_data->maskMode = mode;
159 m_data->resetRgbaBuffer();
160 }
161 }
162
167 QwtWidgetOverlay::MaskMode QwtWidgetOverlay::maskMode() const
168 {
169 return m_data->maskMode;
170 }
171
178 void QwtWidgetOverlay::setRenderMode( RenderMode mode )
179 {
180 m_data->renderMode = mode;
181 }
182
187 QwtWidgetOverlay::RenderMode QwtWidgetOverlay::renderMode() const
188 {
189 return m_data->renderMode;
190 }
191
195 void QwtWidgetOverlay::updateOverlay()
196 {
197 updateMask();
198 update();
199 }
200
201 void QwtWidgetOverlay::updateMask()
202 {
203 m_data->resetRgbaBuffer();
204
205 QRegion mask;
206
207 if ( m_data->maskMode == QwtWidgetOverlay::MaskHint )
208 {
209 mask = maskHint();
210 }
211 else if ( m_data->maskMode == QwtWidgetOverlay::AlphaMask )
212 {
213 // TODO: the image doesn't need to be larger than
214 // the bounding rectangle of the hint !!
215
216 QRegion hint = maskHint();
217 if ( hint.isEmpty() )
218 hint += QRect( 0, 0, width(), height() );
219
220 // A fresh buffer from calloc() is usually faster
221 // than reinitializing an existing one with
222 // QImage::fill( 0 ) or memset()
223
224 m_data->rgbaBuffer = ( uchar* )::calloc( width() * height(), 4 );
225
226 QImage image( m_data->rgbaBuffer,
227 width(), height(), qwtMaskImageFormat() );
228
229 QPainter painter( &image );
230 draw( &painter );
231 painter.end();
232
233 mask = qwtAlphaMask( image, hint );
234
235 if ( m_data->renderMode == QwtWidgetOverlay::DrawOverlay )
236 {
237 // we don't need the buffer later
238 m_data->resetRgbaBuffer();
239 }
240 }
241
242 // A bug in Qt initiates a full repaint of the widget
243 // when we change the mask, while we are visible !
244
245 setVisible( false );
246
247 if ( mask.isEmpty() )
248 clearMask();
249 else
250 setMask( mask );
251
252 setVisible( true );
253 }
254
261 void QwtWidgetOverlay::paintEvent( QPaintEvent* event )
262 {
263 const QRegion& clipRegion = event->region();
264
265 QPainter painter( this );
266
267 bool useRgbaBuffer = false;
268 if ( m_data->renderMode == QwtWidgetOverlay::CopyAlphaMask )
269 {
270 useRgbaBuffer = true;
271 }
272 else if ( m_data->renderMode == QwtWidgetOverlay::AutoRenderMode )
273 {
274 if ( painter.paintEngine()->type() == QPaintEngine::Raster )
275 useRgbaBuffer = true;
276 }
277
278 if ( m_data->rgbaBuffer && useRgbaBuffer )
279 {
280 const QImage image( m_data->rgbaBuffer,
281 width(), height(), qwtMaskImageFormat() );
282
283 const int rectCount = clipRegion.rectCount();
284
285 if ( rectCount > 2000 )
286 {
287 // the region is to complex
288 painter.setClipRegion( clipRegion );
289
290 const QRect r = clipRegion.boundingRect();
291 painter.drawImage( r.topLeft(), image, r );
292 }
293 else
294 {
295 #if QT_VERSION >= 0x050800
296 for ( QRegion::const_iterator it = clipRegion.cbegin();
297 it != clipRegion.cend(); ++it )
298 {
299 const QRect& r = *it;
300 painter.drawImage( r.topLeft(), image, r );
301 }
302 #else
303 const QVector< QRect > rects = clipRegion.rects();
304 for ( int i = 0; i < rects.size(); i++ )
305 {
306 const QRect& r = rects[i];
307 painter.drawImage( r.topLeft(), image, r );
308 }
309 #endif
310 }
311 }
312 else
313 {
314 painter.setClipRegion( clipRegion );
315 draw( &painter );
316 }
317 }
318
323 void QwtWidgetOverlay::resizeEvent( QResizeEvent* event )
324 {
325 Q_UNUSED( event );
326
327 m_data->resetRgbaBuffer();
328 }
329
330 void QwtWidgetOverlay::draw( QPainter* painter ) const
331 {
332 if ( QWidget* widget = parentWidget() )
333 {
334 painter->setClipRect( widget->contentsRect() );
335
336 // something special for the plot canvas
337
338 const int idx = widget->metaObject()->indexOfMethod( "borderPath(QRect)" );
339 if ( idx >= 0 )
340 {
341 QPainterPath clipPath;
342
343 ( void )QMetaObject::invokeMethod(
344 widget, "borderPath", Qt::DirectConnection,
345 Q_RETURN_ARG( QPainterPath, clipPath ), Q_ARG( QRect, rect() ) );
346
347 if (!clipPath.isEmpty() )
348 painter->setClipPath( clipPath, Qt::IntersectClip );
349 }
350 }
351
352 drawOverlay( painter );
353 }
354
373 QRegion QwtWidgetOverlay::maskHint() const
374 {
375 return QRegion();
376 }
377
389 bool QwtWidgetOverlay::eventFilter( QObject* object, QEvent* event )
390 {
391 if ( object == parent() && event->type() == QEvent::Resize )
392 {
393 QResizeEvent* resizeEvent = static_cast< QResizeEvent* >( event );
394 resize( resizeEvent->size() );
395 }
396
397 return QObject::eventFilter( object, event );
398 }
QVector
Definition: qwt_clipper.h:23
QwtPainter::isX11GraphicsSystem
static bool isX11GraphicsSystem()
Definition: qwt_painter.cpp:233
QwtWidgetOverlay
An overlay for a widget.
Definition: qwt_widget_overlay.h:41
QwtWidgetOverlay::updateOverlay
void updateOverlay()
Definition: qwt_widget_overlay.cpp:195
QwtWidgetOverlay::MaskMode
MaskMode
Mask mode.
Definition: qwt_widget_overlay.h:61
QwtWidgetOverlay::AlphaMask
@ AlphaMask
Calculate a mask by checking the alpha values.
Definition: qwt_widget_overlay.h:84
QwtWidgetOverlay::MaskHint
@ MaskHint
Use maskHint() as mask.
Definition: qwt_widget_overlay.h:72
QwtWidgetOverlay::setMaskMode
void setMaskMode(MaskMode)
Specify how to find the mask for the overlay.
Definition: qwt_widget_overlay.cpp:154
QwtWidgetOverlay::eventFilter
virtual bool eventFilter(QObject *, QEvent *) override
Event filter.
Definition: qwt_widget_overlay.cpp:389
QwtWidgetOverlay::setRenderMode
void setRenderMode(RenderMode)
Definition: qwt_widget_overlay.cpp:178
QwtWidgetOverlay::maskMode
MaskMode maskMode() const
Definition: qwt_widget_overlay.cpp:167
QwtWidgetOverlay::renderMode
RenderMode renderMode() const
Definition: qwt_widget_overlay.cpp:187
QwtWidgetOverlay::RenderMode
RenderMode
Render mode.
Definition: qwt_widget_overlay.h:103
QwtWidgetOverlay::AutoRenderMode
@ AutoRenderMode
Copy the buffer, when using the raster paint engine.
Definition: qwt_widget_overlay.h:105
QwtWidgetOverlay::CopyAlphaMask
@ CopyAlphaMask
Always copy the buffer.
Definition: qwt_widget_overlay.h:108
QwtWidgetOverlay::DrawOverlay
@ DrawOverlay
Never copy the buffer.
Definition: qwt_widget_overlay.h:111
QwtWidgetOverlay::drawOverlay
virtual void drawOverlay(QPainter *painter) const =0
QwtWidgetOverlay::resizeEvent
virtual void resizeEvent(QResizeEvent *) override
Definition: qwt_widget_overlay.cpp:323
QwtWidgetOverlay::maskHint
virtual QRegion maskHint() const
Calculate an approximation for the mask.
Definition: qwt_widget_overlay.cpp:373
QwtWidgetOverlay::paintEvent
virtual void paintEvent(QPaintEvent *) override
Definition: qwt_widget_overlay.cpp:261
QwtWidgetOverlay::~QwtWidgetOverlay
virtual ~QwtWidgetOverlay()
Destructor.
Definition: qwt_widget_overlay.cpp:143
QwtWidgetOverlay::QwtWidgetOverlay
QwtWidgetOverlay(QWidget *)
Constructor.
Definition: qwt_widget_overlay.cpp:126