Qwt User's Guide 6.3.0
Loading...
Searching...
No Matches
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
21static QImage::Format qwtMaskImageFormat()
22{
24 return QImage::Format_ARGB32;
25
26 return QImage::Format_ARGB32_Premultiplied;
27}
28
29static 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
93class 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
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
144{
145 delete m_data;
146}
147
155{
156 if ( mode != m_data->maskMode )
157 {
158 m_data->maskMode = mode;
159 m_data->resetRgbaBuffer();
160 }
161}
162
168{
169 return m_data->maskMode;
170}
171
179{
180 m_data->renderMode = mode;
181}
182
188{
189 return m_data->renderMode;
190}
191
196{
197 updateMask();
198 update();
199}
200
201void 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
261void 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
323void QwtWidgetOverlay::resizeEvent( QResizeEvent* event )
324{
325 Q_UNUSED( event );
326
327 m_data->resetRgbaBuffer();
328}
329
330void 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
374{
375 return QRegion();
376}
377
389bool 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}
399
400#include "moc_qwt_widget_overlay.cpp"
static bool isX11GraphicsSystem()
An overlay for a widget.
@ AlphaMask
Calculate a mask by checking the alpha values.
@ MaskHint
Use maskHint() as mask.
void setMaskMode(MaskMode)
Specify how to find the mask for the overlay.
virtual bool eventFilter(QObject *, QEvent *) override
Event filter.
void setRenderMode(RenderMode)
MaskMode maskMode() const
RenderMode renderMode() const
@ AutoRenderMode
Copy the buffer, when using the raster paint engine.
@ CopyAlphaMask
Always copy the buffer.
@ DrawOverlay
Never copy the buffer.
virtual void drawOverlay(QPainter *painter) const =0
virtual void resizeEvent(QResizeEvent *) override
virtual QRegion maskHint() const
Calculate an approximation for the mask.
virtual void paintEvent(QPaintEvent *) override
virtual ~QwtWidgetOverlay()
Destructor.
QwtWidgetOverlay(QWidget *)
Constructor.