source: ntrip/trunk/BNC/qwt/qwt_widget_overlay.cpp@ 8127

Last change on this file since 8127 was 8127, checked in by stoecker, 7 years ago

update qwt and qwtpolar, many QT5 fixes (unfinished)

File size: 8.4 KB
Line 
1/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
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#include <qpainter.h>
13#include <qpaintengine.h>
14#include <qimage.h>
15#include <qevent.h>
16
17static QImage::Format qwtMaskImageFormat()
18{
19 if ( QwtPainter::isX11GraphicsSystem() )
20 return QImage::Format_ARGB32;
21
22 return QImage::Format_ARGB32_Premultiplied;
23}
24
25static QRegion qwtAlphaMask(
26 const QImage& image, const QVector<QRect> rects )
27{
28 const int w = image.width();
29 const int h = image.height();
30
31 QRegion region;
32 QRect rect;
33
34 for ( int i = 0; i < rects.size(); i++ )
35 {
36 int x1, x2, y1, y2;
37 rects[i].getCoords( &x1, &y1, &x2, &y2 );
38
39 x1 = qMax( x1, 0 );
40 x2 = qMin( x2, w - 1 );
41 y1 = qMax( y1, 0 );
42 y2 = qMin( y2, h - 1 );
43
44 for ( int y = y1; y <= y2; ++y )
45 {
46 bool inRect = false;
47 int rx0 = -1;
48
49 const uint *line =
50 reinterpret_cast<const uint *> ( image.scanLine( y ) ) + x1;
51 for ( int x = x1; x <= x2; x++ )
52 {
53 const bool on = ( ( *line++ >> 24 ) != 0 );
54 if ( on != inRect )
55 {
56 if ( inRect )
57 {
58 rect.setCoords( rx0, y, x - 1, y );
59 region += rect;
60 }
61 else
62 {
63 rx0 = x;
64 }
65
66 inRect = on;
67 }
68 }
69
70 if ( inRect )
71 {
72 rect.setCoords( rx0, y, x2, y );
73 region = region.united( rect );
74 }
75 }
76 }
77
78 return region;
79}
80
81class QwtWidgetOverlay::PrivateData
82{
83public:
84 PrivateData():
85 maskMode( QwtWidgetOverlay::MaskHint ),
86 renderMode( QwtWidgetOverlay::AutoRenderMode ),
87 rgbaBuffer( NULL )
88 {
89 }
90
91 ~PrivateData()
92 {
93 resetRgbaBuffer();
94 }
95
96 void resetRgbaBuffer()
97 {
98 if ( rgbaBuffer )
99 {
100 ::free( rgbaBuffer );
101 rgbaBuffer = NULL;
102 }
103 }
104
105 MaskMode maskMode;
106 RenderMode renderMode;
107 uchar *rgbaBuffer;
108};
109
110/*!
111 \brief Constructor
112 \param widget Parent widget, where the overlay is aligned to
113*/
114QwtWidgetOverlay::QwtWidgetOverlay( QWidget* widget ):
115 QWidget( widget )
116{
117 d_data = new PrivateData;
118
119 setAttribute( Qt::WA_TransparentForMouseEvents );
120 setAttribute( Qt::WA_NoSystemBackground );
121 setFocusPolicy( Qt::NoFocus );
122
123 if ( widget )
124 {
125 resize( widget->size() );
126 widget->installEventFilter( this );
127 }
128}
129
130//! Destructor
131QwtWidgetOverlay::~QwtWidgetOverlay()
132{
133 delete d_data;
134}
135
136/*!
137 \brief Specify how to find the mask for the overlay
138
139 \param mode New mode
140 \sa maskMode()
141 */
142void QwtWidgetOverlay::setMaskMode( MaskMode mode )
143{
144 if ( mode != d_data->maskMode )
145 {
146 d_data->maskMode = mode;
147 d_data->resetRgbaBuffer();
148 }
149}
150
151/*!
152 \return Mode how to find the mask for the overlay
153 \sa setMaskMode()
154 */
155QwtWidgetOverlay::MaskMode QwtWidgetOverlay::maskMode() const
156{
157 return d_data->maskMode;
158}
159
160/*!
161 Set the render mode
162 \param mode Render mode
163
164 \sa RenderMode, renderMode()
165*/
166void QwtWidgetOverlay::setRenderMode( RenderMode mode )
167{
168 d_data->renderMode = mode;
169}
170
171/*!
172 \return Render mode
173 \sa RenderMode, setRenderMode()
174 */
175QwtWidgetOverlay::RenderMode QwtWidgetOverlay::renderMode() const
176{
177 return d_data->renderMode;
178}
179
180/*!
181 Recalculate the mask and repaint the overlay
182 */
183void QwtWidgetOverlay::updateOverlay()
184{
185 updateMask();
186 update();
187}
188
189void QwtWidgetOverlay::updateMask()
190{
191 d_data->resetRgbaBuffer();
192
193 QRegion mask;
194
195 if ( d_data->maskMode == QwtWidgetOverlay::MaskHint )
196 {
197 mask = maskHint();
198 }
199 else if ( d_data->maskMode == QwtWidgetOverlay::AlphaMask )
200 {
201 // TODO: the image doesn't need to be larger than
202 // the bounding rectangle of the hint !!
203
204 QRegion hint = maskHint();
205 if ( hint.isEmpty() )
206 hint += QRect( 0, 0, width(), height() );
207
208 // A fresh buffer from calloc() is usually faster
209 // than reinitializing an existing one with
210 // QImage::fill( 0 ) or memset()
211
212 d_data->rgbaBuffer = ( uchar* )::calloc( width() * height(), 4 );
213
214 QImage image( d_data->rgbaBuffer,
215 width(), height(), qwtMaskImageFormat() );
216
217 QPainter painter( &image );
218 draw( &painter );
219 painter.end();
220
221 mask = qwtAlphaMask( image, hint.rects() );
222
223 if ( d_data->renderMode == QwtWidgetOverlay::DrawOverlay )
224 {
225 // we don't need the buffer later
226 d_data->resetRgbaBuffer();
227 }
228 }
229
230 // A bug in Qt initiates a full repaint of the widget
231 // when we change the mask, while we are visible !
232
233 setVisible( false );
234
235 if ( mask.isEmpty() )
236 clearMask();
237 else
238 setMask( mask );
239
240 setVisible( true );
241}
242
243/*!
244 Paint event
245 \param event Paint event
246
247 \sa drawOverlay()
248*/
249void QwtWidgetOverlay::paintEvent( QPaintEvent* event )
250{
251 const QRegion clipRegion = event->region();
252
253 QPainter painter( this );
254
255 bool useRgbaBuffer = false;
256 if ( d_data->renderMode == QwtWidgetOverlay::CopyAlphaMask )
257 {
258 useRgbaBuffer = true;
259 }
260 else if ( d_data->renderMode == QwtWidgetOverlay::AutoRenderMode )
261 {
262 if ( painter.paintEngine()->type() == QPaintEngine::Raster )
263 useRgbaBuffer = true;
264 }
265
266 if ( d_data->rgbaBuffer && useRgbaBuffer )
267 {
268 const QImage image( d_data->rgbaBuffer,
269 width(), height(), qwtMaskImageFormat() );
270
271 QVector<QRect> rects;
272 if ( clipRegion.rects().size() > 2000 )
273 {
274 // the region is to complex
275 painter.setClipRegion( clipRegion );
276 rects += clipRegion.boundingRect();
277 }
278 else
279 {
280 rects = clipRegion.rects();
281 }
282
283 for ( int i = 0; i < rects.size(); i++ )
284 {
285 const QRect r = rects[i];
286 painter.drawImage( r.topLeft(), image, r );
287 }
288 }
289 else
290 {
291 painter.setClipRegion( clipRegion );
292 draw( &painter );
293 }
294}
295
296/*!
297 Resize event
298 \param event Resize event
299*/
300void QwtWidgetOverlay::resizeEvent( QResizeEvent* event )
301{
302 Q_UNUSED( event );
303
304 d_data->resetRgbaBuffer();
305}
306
307void QwtWidgetOverlay::draw( QPainter *painter ) const
308{
309 QWidget *widget = const_cast< QWidget *>( parentWidget() );
310 if ( widget )
311 {
312 painter->setClipRect( parentWidget()->contentsRect() );
313
314 // something special for the plot canvas
315
316 const int idx = widget->metaObject()->indexOfMethod( "borderPath(QRect)" );
317 if ( idx >= 0 )
318 {
319 QPainterPath clipPath;
320
321 ( void )QMetaObject::invokeMethod(
322 widget, "borderPath", Qt::DirectConnection,
323 Q_RETURN_ARG( QPainterPath, clipPath ), Q_ARG( QRect, rect() ) );
324
325 if (!clipPath.isEmpty())
326 painter->setClipPath( clipPath, Qt::IntersectClip );
327 }
328 }
329
330 drawOverlay( painter );
331}
332
333/*!
334 \brief Calculate an approximation for the mask
335
336 - MaskHint
337 The hint is used as mask.
338
339 - AlphaMask
340 The hint is used to speed up the algorithm
341 for calculating a mask from non transparent pixels
342
343 - NoMask
344 The hint is unused.
345
346 The default implementation returns an invalid region
347 indicating no hint.
348
349 \return Hint for the mask
350 */
351QRegion QwtWidgetOverlay::maskHint() const
352{
353 return QRegion();
354}
355
356/*!
357 \brief Event filter
358
359 Resize the overlay according to the size of the parent widget.
360
361 \param object Object to be filtered
362 \param event Event
363
364 \return See QObject::eventFilter()
365*/
366
367bool QwtWidgetOverlay::eventFilter( QObject* object, QEvent* event )
368{
369 if ( object == parent() && event->type() == QEvent::Resize )
370 {
371 QResizeEvent *resizeEvent = static_cast<QResizeEvent *>( event );
372 resize( resizeEvent->size() );
373 }
374
375 return QObject::eventFilter( object, event );
376}
Note: See TracBrowser for help on using the repository browser.