qwt_widget_overlay.cpp
Go to the documentation of this file.
00001 /* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
00002  * Qwt Widget Library
00003  * Copyright (C) 1997   Josef Wilgen
00004  * Copyright (C) 2002   Uwe Rathmann
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the Qwt License, Version 1.0
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         // TODO: the image doesn't need to be larger than
00202         //       the bounding rectangle of the hint !!
00203 
00204         QRegion hint = maskHint();
00205         if ( hint.isEmpty() )
00206             hint += QRect( 0, 0, width(), height() );
00207 
00208         // A fresh buffer from calloc() is usually faster
00209         // than reinitializing an existing one with
00210         // QImage::fill( 0 ) or memset()
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             // we don't need the buffer later
00226             d_data->resetRgbaBuffer();
00227         }
00228     }
00229 
00230     // A bug in Qt initiates a full repaint of the widget
00231     // when we change the mask, while we are visible !
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             // the region is to complex
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         // something special for the plot canvas
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 }


plotjuggler
Author(s): Davide Faconti
autogenerated on Fri Sep 1 2017 02:41:57