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

Last change on this file since 9383 was 9383, checked in by stoecker, 3 years ago

update to qwt verion 6.1.1 to fix build with newer Qt5

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