Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include "qwt_widget_overlay.h"
00011 #include "qwt_painter.h"
00012 #include <qpainter.h>
00013 #include <qpaintengine.h>
00014 #include <qimage.h>
00015 #include <qevent.h>
00016
00017 static QImage::Format qwtMaskImageFormat()
00018 {
00019 if ( QwtPainter::isX11GraphicsSystem() )
00020 return QImage::Format_ARGB32;
00021
00022 return QImage::Format_ARGB32_Premultiplied;
00023 }
00024
00025 static QRegion qwtAlphaMask(
00026 const QImage& image, const QVector<QRect> rects )
00027 {
00028 const int w = image.width();
00029 const int h = image.height();
00030
00031 QRegion region;
00032 QRect rect;
00033
00034 for ( int i = 0; i < rects.size(); i++ )
00035 {
00036 int x1, x2, y1, y2;
00037 rects[i].getCoords( &x1, &y1, &x2, &y2 );
00038
00039 x1 = qMax( x1, 0 );
00040 x2 = qMin( x2, w - 1 );
00041 y1 = qMax( y1, 0 );
00042 y2 = qMin( y2, h - 1 );
00043
00044 for ( int y = y1; y <= y2; ++y )
00045 {
00046 bool inRect = false;
00047 int rx0 = -1;
00048
00049 const uint *line =
00050 reinterpret_cast<const uint *> ( image.scanLine( y ) ) + x1;
00051 for ( int x = x1; x <= x2; x++ )
00052 {
00053 const bool on = ( ( *line++ >> 24 ) != 0 );
00054 if ( on != inRect )
00055 {
00056 if ( inRect )
00057 {
00058 rect.setCoords( rx0, y, x - 1, y );
00059 region += rect;
00060 }
00061 else
00062 {
00063 rx0 = x;
00064 }
00065
00066 inRect = on;
00067 }
00068 }
00069
00070 if ( inRect )
00071 {
00072 rect.setCoords( rx0, y, x2, y );
00073 region = region.united( rect );
00074 }
00075 }
00076 }
00077
00078 return region;
00079 }
00080
00081 class QwtWidgetOverlay::PrivateData
00082 {
00083 public:
00084 PrivateData():
00085 maskMode( QwtWidgetOverlay::MaskHint ),
00086 renderMode( QwtWidgetOverlay::AutoRenderMode ),
00087 rgbaBuffer( NULL )
00088 {
00089 }
00090
00091 ~PrivateData()
00092 {
00093 resetRgbaBuffer();
00094 }
00095
00096 void resetRgbaBuffer()
00097 {
00098 if ( rgbaBuffer )
00099 {
00100 ::free( rgbaBuffer );
00101 rgbaBuffer = NULL;
00102 }
00103 }
00104
00105 MaskMode maskMode;
00106 RenderMode renderMode;
00107 uchar *rgbaBuffer;
00108 };
00109
00114 QwtWidgetOverlay::QwtWidgetOverlay( QWidget* widget ):
00115 QWidget( widget )
00116 {
00117 d_data = new PrivateData;
00118
00119 setAttribute( Qt::WA_TransparentForMouseEvents );
00120 setAttribute( Qt::WA_NoSystemBackground );
00121 setFocusPolicy( Qt::NoFocus );
00122
00123 if ( widget )
00124 {
00125 resize( widget->size() );
00126 widget->installEventFilter( this );
00127 }
00128 }
00129
00131 QwtWidgetOverlay::~QwtWidgetOverlay()
00132 {
00133 delete d_data;
00134 }
00135
00142 void QwtWidgetOverlay::setMaskMode( MaskMode mode )
00143 {
00144 if ( mode != d_data->maskMode )
00145 {
00146 d_data->maskMode = mode;
00147 d_data->resetRgbaBuffer();
00148 }
00149 }
00150
00155 QwtWidgetOverlay::MaskMode QwtWidgetOverlay::maskMode() const
00156 {
00157 return d_data->maskMode;
00158 }
00159
00166 void QwtWidgetOverlay::setRenderMode( RenderMode mode )
00167 {
00168 d_data->renderMode = mode;
00169 }
00170
00175 QwtWidgetOverlay::RenderMode QwtWidgetOverlay::renderMode() const
00176 {
00177 return d_data->renderMode;
00178 }
00179
00183 void QwtWidgetOverlay::updateOverlay()
00184 {
00185 updateMask();
00186 update();
00187 }
00188
00189 void QwtWidgetOverlay::updateMask()
00190 {
00191 d_data->resetRgbaBuffer();
00192
00193 QRegion mask;
00194
00195 if ( d_data->maskMode == QwtWidgetOverlay::MaskHint )
00196 {
00197 mask = maskHint();
00198 }
00199 else if ( d_data->maskMode == QwtWidgetOverlay::AlphaMask )
00200 {
00201
00202
00203
00204 QRegion hint = maskHint();
00205 if ( hint.isEmpty() )
00206 hint += QRect( 0, 0, width(), height() );
00207
00208
00209
00210
00211
00212 d_data->rgbaBuffer = ( uchar* )::calloc( width() * height(), 4 );
00213
00214 QImage image( d_data->rgbaBuffer,
00215 width(), height(), qwtMaskImageFormat() );
00216
00217 QPainter painter( &image );
00218 draw( &painter );
00219 painter.end();
00220
00221 mask = qwtAlphaMask( image, hint.rects() );
00222
00223 if ( d_data->renderMode == QwtWidgetOverlay::DrawOverlay )
00224 {
00225
00226 d_data->resetRgbaBuffer();
00227 }
00228 }
00229
00230
00231
00232
00233 setVisible( false );
00234
00235 if ( mask.isEmpty() )
00236 clearMask();
00237 else
00238 setMask( mask );
00239
00240 setVisible( true );
00241 }
00242
00249 void QwtWidgetOverlay::paintEvent( QPaintEvent* event )
00250 {
00251 const QRegion clipRegion = event->region();
00252
00253 QPainter painter( this );
00254
00255 bool useRgbaBuffer = false;
00256 if ( d_data->renderMode == QwtWidgetOverlay::CopyAlphaMask )
00257 {
00258 useRgbaBuffer = true;
00259 }
00260 else if ( d_data->renderMode == QwtWidgetOverlay::AutoRenderMode )
00261 {
00262 if ( painter.paintEngine()->type() == QPaintEngine::Raster )
00263 useRgbaBuffer = true;
00264 }
00265
00266 if ( d_data->rgbaBuffer && useRgbaBuffer )
00267 {
00268 const QImage image( d_data->rgbaBuffer,
00269 width(), height(), qwtMaskImageFormat() );
00270
00271 QVector<QRect> rects;
00272 if ( clipRegion.rects().size() > 2000 )
00273 {
00274
00275 painter.setClipRegion( clipRegion );
00276 rects += clipRegion.boundingRect();
00277 }
00278 else
00279 {
00280 rects = clipRegion.rects();
00281 }
00282
00283 for ( int i = 0; i < rects.size(); i++ )
00284 {
00285 const QRect r = rects[i];
00286 painter.drawImage( r.topLeft(), image, r );
00287 }
00288 }
00289 else
00290 {
00291 painter.setClipRegion( clipRegion );
00292 draw( &painter );
00293 }
00294 }
00295
00300 void QwtWidgetOverlay::resizeEvent( QResizeEvent* event )
00301 {
00302 Q_UNUSED( event );
00303
00304 d_data->resetRgbaBuffer();
00305 }
00306
00307 void QwtWidgetOverlay::draw( QPainter *painter ) const
00308 {
00309 QWidget *widget = const_cast< QWidget *>( parentWidget() );
00310 if ( widget )
00311 {
00312 painter->setClipRect( parentWidget()->contentsRect() );
00313
00314
00315
00316 const int idx = widget->metaObject()->indexOfMethod( "borderPath(QRect)" );
00317 if ( idx >= 0 )
00318 {
00319 QPainterPath clipPath;
00320
00321 ( void )QMetaObject::invokeMethod(
00322 widget, "borderPath", Qt::DirectConnection,
00323 Q_RETURN_ARG( QPainterPath, clipPath ), Q_ARG( QRect, rect() ) );
00324
00325 if (!clipPath.isEmpty())
00326 painter->setClipPath( clipPath, Qt::IntersectClip );
00327 }
00328 }
00329
00330 drawOverlay( painter );
00331 }
00332
00351 QRegion QwtWidgetOverlay::maskHint() const
00352 {
00353 return QRegion();
00354 }
00355
00367 bool QwtWidgetOverlay::eventFilter( QObject* object, QEvent* event )
00368 {
00369 if ( object == parent() && event->type() == QEvent::Resize )
00370 {
00371 QResizeEvent *resizeEvent = static_cast<QResizeEvent *>( event );
00372 resize( resizeEvent->size() );
00373 }
00374
00375 return QObject::eventFilter( object, event );
00376 }