qwt_widget_overlay.cpp
/******************************************************************************
* Qwt Widget Library
* Copyright (C) 1997 Josef Wilgen
* Copyright (C) 2002 Uwe Rathmann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the Qwt License, Version 1.0
*****************************************************************************/
#include "qwt_widget_overlay.h"
#include "qwt_painter.h"
#include <qpainter.h>
#include <qpaintengine.h>
#include <qpainterpath.h>
#include <qimage.h>
#include <qevent.h>
#include <cstdlib>
static QImage::Format qwtMaskImageFormat()
{
if ( QwtPainter::isX11GraphicsSystem() )
return QImage::Format_ARGB32;
return QImage::Format_ARGB32_Premultiplied;
}
static QRegion qwtAlphaMask( const QImage& image, const QRegion& region )
{
const int w = image.width();
const int h = image.height();
QRegion mask;
QRect rect;
#if QT_VERSION >= 0x050800
for ( QRegion::const_iterator it = region.cbegin();
it != region.cend(); ++it )
{
const QRect& r = *it;
#else
const QVector< QRect > rects = region.rects();
for ( int i = 0; i < rects.size(); i++ )
{
const QRect& r = rects[i];
#endif
int x1, x2, y1, y2;
r.getCoords( &x1, &y1, &x2, &y2 );
x1 = qMax( x1, 0 );
x2 = qMin( x2, w - 1 );
y1 = qMax( y1, 0 );
y2 = qMin( y2, h - 1 );
for ( int y = y1; y <= y2; ++y )
{
bool inRect = false;
int rx0 = -1;
const uint* line =
reinterpret_cast< const uint* > ( image.scanLine( y ) ) + x1;
for ( int x = x1; x <= x2; x++ )
{
const bool on = ( ( *line++ >> 24 ) != 0 );
if ( on != inRect )
{
if ( inRect )
{
rect.setCoords( rx0, y, x - 1, y );
mask += rect;
}
else
{
rx0 = x;
}
inRect = on;
}
}
if ( inRect )
{
rect.setCoords( rx0, y, x2, y );
mask = mask.united( rect );
}
}
}
return mask;
}
class QwtWidgetOverlay::PrivateData
{
public:
PrivateData()
: maskMode( QwtWidgetOverlay::MaskHint )
, renderMode( QwtWidgetOverlay::AutoRenderMode )
, rgbaBuffer( NULL )
{
}
~PrivateData()
{
resetRgbaBuffer();
}
void resetRgbaBuffer()
{
if ( rgbaBuffer )
{
std::free( rgbaBuffer );
rgbaBuffer = NULL;
}
}
MaskMode maskMode;
RenderMode renderMode;
uchar* rgbaBuffer;
};
QwtWidgetOverlay::QwtWidgetOverlay( QWidget* widget )
: QWidget( widget )
{
m_data = new PrivateData;
setAttribute( Qt::WA_TransparentForMouseEvents );
setAttribute( Qt::WA_NoSystemBackground );
setFocusPolicy( Qt::NoFocus );
if ( widget )
{
resize( widget->size() );
widget->installEventFilter( this );
}
}
QwtWidgetOverlay::~QwtWidgetOverlay()
{
delete m_data;
}
void QwtWidgetOverlay::setMaskMode( MaskMode mode )
{
if ( mode != m_data->maskMode )
{
m_data->maskMode = mode;
m_data->resetRgbaBuffer();
}
}
QwtWidgetOverlay::MaskMode QwtWidgetOverlay::maskMode() const
{
return m_data->maskMode;
}
void QwtWidgetOverlay::setRenderMode( RenderMode mode )
{
m_data->renderMode = mode;
}
QwtWidgetOverlay::RenderMode QwtWidgetOverlay::renderMode() const
{
return m_data->renderMode;
}
void QwtWidgetOverlay::updateOverlay()
{
updateMask();
update();
}
void QwtWidgetOverlay::updateMask()
{
m_data->resetRgbaBuffer();
QRegion mask;
if ( m_data->maskMode == QwtWidgetOverlay::MaskHint )
{
mask = maskHint();
}
else if ( m_data->maskMode == QwtWidgetOverlay::AlphaMask )
{
// TODO: the image doesn't need to be larger than
// the bounding rectangle of the hint !!
QRegion hint = maskHint();
if ( hint.isEmpty() )
hint += QRect( 0, 0, width(), height() );
// A fresh buffer from calloc() is usually faster
// than reinitializing an existing one with
// QImage::fill( 0 ) or memset()
m_data->rgbaBuffer = ( uchar* )::calloc( width() * height(), 4 );
QImage image( m_data->rgbaBuffer,
width(), height(), qwtMaskImageFormat() );
QPainter painter( &image );
draw( &painter );
painter.end();
mask = qwtAlphaMask( image, hint );
if ( m_data->renderMode == QwtWidgetOverlay::DrawOverlay )
{
// we don't need the buffer later
m_data->resetRgbaBuffer();
}
}
// A bug in Qt initiates a full repaint of the widget
// when we change the mask, while we are visible !
setVisible( false );
if ( mask.isEmpty() )
clearMask();
else
setMask( mask );
setVisible( true );
}
void QwtWidgetOverlay::paintEvent( QPaintEvent* event )
{
const QRegion& clipRegion = event->region();
QPainter painter( this );
bool useRgbaBuffer = false;
if ( m_data->renderMode == QwtWidgetOverlay::CopyAlphaMask )
{
useRgbaBuffer = true;
}
else if ( m_data->renderMode == QwtWidgetOverlay::AutoRenderMode )
{
if ( painter.paintEngine()->type() == QPaintEngine::Raster )
useRgbaBuffer = true;
}
if ( m_data->rgbaBuffer && useRgbaBuffer )
{
const QImage image( m_data->rgbaBuffer,
width(), height(), qwtMaskImageFormat() );
const int rectCount = clipRegion.rectCount();
if ( rectCount > 2000 )
{
// the region is to complex
painter.setClipRegion( clipRegion );
const QRect r = clipRegion.boundingRect();
painter.drawImage( r.topLeft(), image, r );
}
else
{
#if QT_VERSION >= 0x050800
for ( QRegion::const_iterator it = clipRegion.cbegin();
it != clipRegion.cend(); ++it )
{
const QRect& r = *it;
painter.drawImage( r.topLeft(), image, r );
}
#else
const QVector< QRect > rects = clipRegion.rects();
for ( int i = 0; i < rects.size(); i++ )
{
const QRect& r = rects[i];
painter.drawImage( r.topLeft(), image, r );
}
#endif
}
}
else
{
painter.setClipRegion( clipRegion );
draw( &painter );
}
}
void QwtWidgetOverlay::resizeEvent( QResizeEvent* event )
{
Q_UNUSED( event );
m_data->resetRgbaBuffer();
}
void QwtWidgetOverlay::draw( QPainter* painter ) const
{
if ( QWidget* widget = parentWidget() )
{
painter->setClipRect( widget->contentsRect() );
// something special for the plot canvas
const int idx = widget->metaObject()->indexOfMethod( "borderPath(QRect)" );
if ( idx >= 0 )
{
QPainterPath clipPath;
( void )QMetaObject::invokeMethod(
widget, "borderPath", Qt::DirectConnection,
Q_RETURN_ARG( QPainterPath, clipPath ), Q_ARG( QRect, rect() ) );
if (!clipPath.isEmpty() )
painter->setClipPath( clipPath, Qt::IntersectClip );
}
}
drawOverlay( painter );
}
QRegion QwtWidgetOverlay::maskHint() const
{
return QRegion();
}
bool QwtWidgetOverlay::eventFilter( QObject* object, QEvent* event )
{
if ( object == parent() && event->type() == QEvent::Resize )
{
QResizeEvent* resizeEvent = static_cast< QResizeEvent* >( event );
resize( resizeEvent->size() );
}
return QObject::eventFilter( object, event );
}
QVector
Definition: qwt_clipper.h:23
QwtPainter::isX11GraphicsSystem
static bool isX11GraphicsSystem()
Definition: qwt_painter.cpp:233
QwtWidgetOverlay
An overlay for a widget.
Definition: qwt_widget_overlay.h:41
QwtWidgetOverlay::updateOverlay
void updateOverlay()
Definition: qwt_widget_overlay.cpp:195
QwtWidgetOverlay::MaskMode
MaskMode
Mask mode.
Definition: qwt_widget_overlay.h:61
QwtWidgetOverlay::AlphaMask
@ AlphaMask
Calculate a mask by checking the alpha values.
Definition: qwt_widget_overlay.h:84
QwtWidgetOverlay::MaskHint
@ MaskHint
Use maskHint() as mask.
Definition: qwt_widget_overlay.h:72
QwtWidgetOverlay::setMaskMode
void setMaskMode(MaskMode)
Specify how to find the mask for the overlay.
Definition: qwt_widget_overlay.cpp:154
QwtWidgetOverlay::eventFilter
virtual bool eventFilter(QObject *, QEvent *) override
Event filter.
Definition: qwt_widget_overlay.cpp:389
QwtWidgetOverlay::setRenderMode
void setRenderMode(RenderMode)
Definition: qwt_widget_overlay.cpp:178
QwtWidgetOverlay::maskMode
MaskMode maskMode() const
Definition: qwt_widget_overlay.cpp:167
QwtWidgetOverlay::renderMode
RenderMode renderMode() const
Definition: qwt_widget_overlay.cpp:187
QwtWidgetOverlay::RenderMode
RenderMode
Render mode.
Definition: qwt_widget_overlay.h:103
QwtWidgetOverlay::AutoRenderMode
@ AutoRenderMode
Copy the buffer, when using the raster paint engine.
Definition: qwt_widget_overlay.h:105
QwtWidgetOverlay::CopyAlphaMask
@ CopyAlphaMask
Always copy the buffer.
Definition: qwt_widget_overlay.h:108
QwtWidgetOverlay::DrawOverlay
@ DrawOverlay
Never copy the buffer.
Definition: qwt_widget_overlay.h:111
QwtWidgetOverlay::drawOverlay
virtual void drawOverlay(QPainter *painter) const =0
QwtWidgetOverlay::resizeEvent
virtual void resizeEvent(QResizeEvent *) override
Definition: qwt_widget_overlay.cpp:323
QwtWidgetOverlay::maskHint
virtual QRegion maskHint() const
Calculate an approximation for the mask.
Definition: qwt_widget_overlay.cpp:373
QwtWidgetOverlay::paintEvent
virtual void paintEvent(QPaintEvent *) override
Definition: qwt_widget_overlay.cpp:261
QwtWidgetOverlay::~QwtWidgetOverlay
virtual ~QwtWidgetOverlay()
Destructor.
Definition: qwt_widget_overlay.cpp:143
QwtWidgetOverlay::QwtWidgetOverlay
QwtWidgetOverlay(QWidget *)
Constructor.
Definition: qwt_widget_overlay.cpp:126