qwt_widget_overlay.cpp
Go to the documentation of this file.
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 
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 {
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 
94 {
95 public:
99  rgbaBuffer( NULL )
100  {
101  }
102 
104  {
105  resetRgbaBuffer();
106  }
107 
109  {
110  if ( rgbaBuffer )
111  {
113  rgbaBuffer = NULL;
114  }
115  }
116 
120 };
121 
127  QWidget( widget )
128 {
129  d_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 d_data;
146 }
147 
155 {
156  if ( mode != d_data->maskMode )
157  {
158  d_data->maskMode = mode;
160  }
161 }
162 
168 {
169  return d_data->maskMode;
170 }
171 
179 {
180  d_data->renderMode = mode;
181 }
182 
188 {
189  return d_data->renderMode;
190 }
191 
196 {
197  updateMask();
198  update();
199 }
200 
202 {
204 
205  QRegion mask;
206 
208  {
209  mask = maskHint();
210  }
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  d_data->rgbaBuffer = ( uchar* )::calloc( width() * height(), 4 );
225 
226  QImage image( d_data->rgbaBuffer,
227  width(), height(), qwtMaskImageFormat() );
228 
229  QPainter painter( &image );
230  draw( &painter );
231  painter.end();
232 
233  mask = qwtAlphaMask( image, hint );
234 
236  {
237  // we don't need the buffer later
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;
269  {
270  useRgbaBuffer = true;
271  }
273  {
274  if ( painter.paintEngine()->type() == QPaintEngine::Raster )
275  useRgbaBuffer = true;
276  }
277 
278  if ( d_data->rgbaBuffer && useRgbaBuffer )
279  {
280  const QImage image( d_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 
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 
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 }
void setRenderMode(RenderMode)
virtual ~QwtWidgetOverlay()
Destructor.
static QRegion qwtAlphaMask(const QImage &image, const QRegion &region)
MaskMode maskMode() const
virtual void resizeEvent(QResizeEvent *) QWT_OVERRIDE
static bool isX11GraphicsSystem()
QwtWidgetOverlay(QWidget *)
Constructor.
RenderMode
Render mode.
void setMaskMode(MaskMode)
Specify how to find the mask for the overlay.
static QImage::Format qwtMaskImageFormat()
virtual void drawOverlay(QPainter *painter) const =0
#define free(x)
Definition: Heap.h:55
Copy the buffer, when using the raster paint engine.
RenderMode renderMode() const
virtual QRegion maskHint() const
Calculate an approximation for the mask.
j template void())
Definition: json.hpp:3707
Use maskHint() as mask.
PrivateData * d_data
Calculate a mask by checking the alpha values.
An overlay for a widget.
#define uchar(c)
Definition: lstrlib.c:40
void draw(QPainter *) const
virtual void paintEvent(QPaintEvent *) QWT_OVERRIDE
virtual bool eventFilter(QObject *, QEvent *) QWT_OVERRIDE
Event filter.


plotjuggler
Author(s): Davide Faconti
autogenerated on Sun Dec 6 2020 03:48:10