Skip to content
qwt_plot_canvas.cpp 27.8 KiB
Newer Older
pixhawk's avatar
pixhawk committed
/* -*- mode: C++ ; c-file-style: "stroustrup" -*- *****************************
 * 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
 *****************************************************************************/

Bryant's avatar
Bryant committed
#include "qwt_plot_canvas.h"
#include "qwt_painter.h"
#include "qwt_null_paintdevice.h"
#include "qwt_math.h"
#include "qwt_plot.h"
pixhawk's avatar
pixhawk committed
#include <qpainter.h>
#include <qstyle.h>
#include <qstyleoption.h>
#include <qpaintengine.h>
Bryant's avatar
Bryant committed
#include <qevent.h>

class QwtStyleSheetRecorder: public QwtNullPaintDevice
{
public:
    QwtStyleSheetRecorder( const QSize &size ):
        d_size( size )
    {
    }

    virtual void updateState( const QPaintEngineState &state )
    {
        if ( state.state() & QPaintEngine::DirtyPen )
        {
            d_pen = state.pen();
        }
        if ( state.state() & QPaintEngine::DirtyBrush )
        {
            d_brush = state.brush();
        }
        if ( state.state() & QPaintEngine::DirtyBrushOrigin )
        {
            d_origin = state.brushOrigin();
        }
    }

    virtual void drawRects(const QRectF *rects, int count )
    {
        for ( int i = 0; i < count; i++ )
            border.rectList += rects[i];
    }

    virtual void drawPath( const QPainterPath &path )
    {
        const QRectF rect( QPointF( 0.0, 0.0 ), d_size );
        if ( path.controlPointRect().contains( rect.center() ) )
        {
            setCornerRects( path );
            alignCornerRects( rect );

            background.path = path;
            background.brush = d_brush;
            background.origin = d_origin;
        }
        else
        {
            border.pathList += path;
        }
    }

    void setCornerRects( const QPainterPath &path )
    {
        QPointF pos( 0.0, 0.0 );

        for ( int i = 0; i < path.elementCount(); i++ )
        {
            QPainterPath::Element el = path.elementAt(i); 
            switch( el.type )
            {
                case QPainterPath::MoveToElement:
                case QPainterPath::LineToElement:
                {
                    pos.setX( el.x );
                    pos.setY( el.y );
                    break;
                }
                case QPainterPath::CurveToElement:
                {
                    QRectF r( pos, QPointF( el.x, el.y ) );
                    clipRects += r.normalized();

                    pos.setX( el.x );
                    pos.setY( el.y );

                    break;
                }
                case QPainterPath::CurveToDataElement:
                {
                    if ( clipRects.size() > 0 )
                    {
                        QRectF r = clipRects.last();
                        r.setCoords( 
                            qMin( r.left(), el.x ),
                            qMin( r.top(), el.y ),
                            qMax( r.right(), el.x ),
                            qMax( r.bottom(), el.y )
                        );
                        clipRects.last() = r.normalized();
                    }
                    break;
                }
            }
        }
    }

protected:
    virtual QSize sizeMetrics() const
    {
        return d_size;
    }

private:
    void alignCornerRects( const QRectF &rect )
    {
        for ( int i = 0; i < clipRects.size(); i++ )
        {
            QRectF &r = clipRects[i];
            if ( r.center().x() < rect.center().x() )
                r.setLeft( rect.left() );
            else
                r.setRight( rect.right() );

            if ( r.center().y() < rect.center().y() )
                r.setTop( rect.top() );
            else
                r.setBottom( rect.bottom() );
        }
    }


public:
    QVector<QRectF> clipRects;

    struct Border
    {
        QList<QPainterPath> pathList;
        QList<QRectF> rectList;
        QRegion clipRegion;
    } border;

    struct Background
    {
        QPainterPath path;
        QBrush brush;
        QPointF origin;
    } background;

private:
    const QSize d_size;

    QPen d_pen;
    QBrush d_brush;
    QPointF d_origin;
};

static void qwtDrawBackground( QPainter *painter, QwtPlotCanvas *canvas )
{
    painter->save();

    const QPainterPath borderClip = canvas->borderPath( canvas->rect() );
    if ( !borderClip.isEmpty() )
        painter->setClipPath( borderClip, Qt::IntersectClip );

    const QBrush &brush = 
        canvas->palette().brush( canvas->backgroundRole() );

    if ( brush.style() == Qt::TexturePattern )
    {
        QPixmap pm( canvas->size() );
        QwtPainter::fillPixmap( canvas, pm );
        painter->drawPixmap( 0, 0, pm );
    }
    else if ( brush.gradient() )
    {
        QVector<QRect> rects;

        if ( brush.gradient()->coordinateMode() == QGradient::ObjectBoundingMode )
        {
            rects += canvas->rect();
        } 
        else 
        {
            rects = painter->clipRegion().rects();
        }

#if 1
        bool useRaster = false;

        if ( painter->paintEngine()->type() == QPaintEngine::X11 )
        {
            // Qt 4.7.1: gradients on X11 are broken ( subrects + 
            // QGradient::StretchToDeviceMode ) and horrible slow.
            // As workaround we have to use the raster paintengine.
            // Even if the QImage -> QPixmap translation is slow
            // it is three times faster, than using X11 directly

            useRaster = true;
        }
pixhawk's avatar
pixhawk committed
#endif
Bryant's avatar
Bryant committed
        if ( useRaster )
        {
            QImage::Format format = QImage::Format_RGB32;

            const QGradientStops stops = brush.gradient()->stops();
            for ( int i = 0; i < stops.size(); i++ )
            {
                if ( stops[i].second.alpha() != 255 )
                {
                    // don't use Format_ARGB32_Premultiplied. It's
                    // recommended by the Qt docs, but QPainter::drawImage()
                    // is horrible slow on X11.

                    format = QImage::Format_ARGB32;
                    break;
                }
            }
            
            QImage image( canvas->size(), format );

            QPainter p( &image );
            p.setPen( Qt::NoPen );
            p.setBrush( brush );

            p.drawRects( rects );

            p.end();

            painter->drawImage( 0, 0, image );
        }
        else
        {
            painter->setPen( Qt::NoPen );
            painter->setBrush( brush );

            painter->drawRects( rects );
        }
    }
    else
    {
        painter->setPen( Qt::NoPen );
        painter->setBrush( brush );

        painter->drawRects( painter->clipRegion().rects() );

    }

    painter->restore();
}

static inline void qwtRevertPath( QPainterPath &path )
{
    if ( path.elementCount() == 4 )
    {
        QPainterPath::Element el0 = path.elementAt(0);
        QPainterPath::Element el3 = path.elementAt(3);

        path.setElementPositionAt( 0, el3.x, el3.y );
        path.setElementPositionAt( 3, el0.x, el0.y );
    }
}

static QPainterPath qwtCombinePathList( const QRectF &rect, 
    const QList<QPainterPath> &pathList )
{
    if ( pathList.isEmpty() )
        return QPainterPath();

    QPainterPath ordered[8]; // starting top left

    for ( int i = 0; i < pathList.size(); i++ )
    {
        int index = -1;
        QPainterPath subPath = pathList[i];

        const QRectF br = pathList[i].controlPointRect();
        if ( br.center().x() < rect.center().x() )
        {
            if ( br.center().y() < rect.center().y() )
            {
                if ( qAbs( br.top() - rect.top() ) < 
                    qAbs( br.left() - rect.left() ) )
                {
                    index = 1;
                }
                else
                {
                    index = 0;
                }
            }
            else
            {
                if ( qAbs( br.bottom() - rect.bottom() ) < 
                    qAbs( br.left() - rect.left() ) )
                {
                    index = 6;
                }
                else
                {
                    index = 7;
                }
            }

            if ( subPath.currentPosition().y() > br.center().y() )
                qwtRevertPath( subPath );
        }
        else
        {
            if ( br.center().y() < rect.center().y() )
            {
                if ( qAbs( br.top() - rect.top() ) < 
                    qAbs( br.right() - rect.right() ) )
                {
                    index = 2;
                }
                else
                {
                    index = 3;
                }
            }
            else
            {
                if ( qAbs( br.bottom() - rect.bottom() ) < 
                    qAbs( br.right() - rect.right() ) )
                {
                    index = 5;
                }
                else
                {
                    index = 4;
                }
            }
            if ( subPath.currentPosition().y() < br.center().y() )
                qwtRevertPath( subPath );
        }   
        ordered[index] = subPath;
    }

    for ( int i = 0; i < 4; i++ )
    {
        if ( ordered[ 2 * i].isEmpty() != ordered[2 * i + 1].isEmpty() )
        {
            // we don't accept incomplete rounded borders
            return QPainterPath();
        }
    }


    const QPolygonF corners( rect );

    QPainterPath path;
    //path.moveTo( rect.topLeft() );

    for ( int i = 0; i < 4; i++ )
    {
        if ( ordered[2 * i].isEmpty() )
        {
            path.lineTo( corners[i] );
        }
        else
        {
            path.connectPath( ordered[2 * i] );
            path.connectPath( ordered[2 * i + 1] );
        }
    }

    path.closeSubpath();

#if 0
    return path.simplified();
#else
    return path;
pixhawk's avatar
pixhawk committed
#endif
Bryant's avatar
Bryant committed
}

static inline void qwtDrawStyledBackground( 
    QWidget *w, QPainter *painter )
{
    QStyleOption opt;
    opt.initFrom(w);
    w->style()->drawPrimitive( QStyle::PE_Widget, &opt, painter, w);
}

static QWidget *qwtBackgroundWidget( QWidget *w )
{
    if ( w->parentWidget() == NULL )
        return w;

    if ( w->autoFillBackground() )
    {
        const QBrush brush = w->palette().brush( w->backgroundRole() );
        if ( brush.color().alpha() > 0 )
            return w;
    }

    if ( w->testAttribute( Qt::WA_StyledBackground ) )
    {
        QImage image( 1, 1, QImage::Format_ARGB32 );
        image.fill( Qt::transparent );

        QPainter painter( &image );
        painter.translate( -w->rect().center() );
        qwtDrawStyledBackground( w, &painter );
        painter.end();

        if ( qAlpha( image.pixel( 0, 0 ) ) != 0 )
            return w;
    }

    return qwtBackgroundWidget( w->parentWidget() );
}

static void qwtFillBackground( QPainter *painter, 
    QWidget *widget, const QVector<QRectF> &fillRects )
{
    if ( fillRects.isEmpty() )
        return;

    QRegion clipRegion;
    if ( painter->hasClipping() )
        clipRegion = painter->transform().map( painter->clipRegion() );
    else
        clipRegion = widget->contentsRect();

    // Try to find out which widget fills
    // the unfilled areas of the styled background

    QWidget *bgWidget = qwtBackgroundWidget( widget->parentWidget() );

    for ( int i = 0; i < fillRects.size(); i++ )
    {
        const QRect rect = fillRects[i].toAlignedRect();
        if ( clipRegion.intersects( rect ) )
        {
            QPixmap pm( rect.size() );
            QwtPainter::fillPixmap( bgWidget, pm, widget->mapTo( bgWidget, rect.topLeft() ) );
            painter->drawPixmap( rect, pm );
        }
    }
}

static void qwtFillBackground( QPainter *painter, QwtPlotCanvas *canvas )
{
    QVector<QRectF> rects;

    if ( canvas->testAttribute( Qt::WA_StyledBackground ) )
    {
        QwtStyleSheetRecorder recorder( canvas->size() );

        QPainter p( &recorder );
        qwtDrawStyledBackground( canvas, &p );
        p.end();

        if ( recorder.background.brush.isOpaque() )
            rects = recorder.clipRects;
        else
            rects += canvas->rect();
    }
    else
    {
        const QRectF r = canvas->rect();
        const double radius = canvas->borderRadius();
        if ( radius > 0.0 )
        {
            QSizeF sz( radius, radius );

            rects += QRectF( r.topLeft(), sz );
            rects += QRectF( r.topRight() - QPointF( radius, 0 ), sz );
            rects += QRectF( r.bottomRight() - QPointF( radius, radius ), sz );
            rects += QRectF( r.bottomLeft() - QPointF( 0, radius ), sz );
        }
    }

    qwtFillBackground( painter, canvas, rects);
}

pixhawk's avatar
pixhawk committed

class QwtPlotCanvas::PrivateData
{
public:
    PrivateData():
Bryant's avatar
Bryant committed
        focusIndicator( NoFocusIndicator ),
        borderRadius( 0 ),
        paintAttributes( 0 ),
        backingStore( NULL )
    {
        styleSheet.hasBorder = false;
pixhawk's avatar
pixhawk committed
    }

Bryant's avatar
Bryant committed
    ~PrivateData()
    {
        delete backingStore;
pixhawk's avatar
pixhawk committed
    }

    FocusIndicator focusIndicator;
Bryant's avatar
Bryant committed
    double borderRadius;
    QwtPlotCanvas::PaintAttributes paintAttributes;
    QPixmap *backingStore;

    struct StyleSheet
    {
        bool hasBorder;
        QPainterPath borderPath;
        QVector<QRectF> cornerRects;

        struct StyleSheetBackground
        {
            QBrush brush;
            QPointF origin;
        } background;

    } styleSheet;

pixhawk's avatar
pixhawk committed
};

Bryant's avatar
Bryant committed
/*! 
  \brief Constructor
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param plot Parent plot widget
  \sa QwtPlot::setCanvas()
*/
QwtPlotCanvas::QwtPlotCanvas( QwtPlot *plot ):
    QFrame( plot )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    setFrameStyle( QFrame::Panel | QFrame::Sunken );
    setLineWidth( 2 );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    d_data = new PrivateData;
pixhawk's avatar
pixhawk committed

#ifndef QT_NO_CURSOR
Bryant's avatar
Bryant committed
    setCursor( Qt::CrossCursor );
pixhawk's avatar
pixhawk committed
#endif

Bryant's avatar
Bryant committed
    setAutoFillBackground( true );
    setPaintAttribute( QwtPlotCanvas::BackingStore, true );
    setPaintAttribute( QwtPlotCanvas::Opaque, true );
    setPaintAttribute( QwtPlotCanvas::HackStyledBackground, true );
pixhawk's avatar
pixhawk committed
}

//! Destructor
QwtPlotCanvas::~QwtPlotCanvas()
{
    delete d_data;
}

//! Return parent plot widget
QwtPlot *QwtPlotCanvas::plot()
{
Bryant's avatar
Bryant committed
    return qobject_cast<QwtPlot *>( parent() );
pixhawk's avatar
pixhawk committed
}

//! Return parent plot widget
const QwtPlot *QwtPlotCanvas::plot() const
{
Bryant's avatar
Bryant committed
    return qobject_cast<const QwtPlot *>( parent() );
pixhawk's avatar
pixhawk committed
}

/*!
  \brief Changing the paint attributes

  \param attribute Paint attribute
  \param on On/Off

Bryant's avatar
Bryant committed
  \sa testPaintAttribute(), backingStore()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotCanvas::setPaintAttribute( PaintAttribute attribute, bool on )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( bool( d_data->paintAttributes & attribute ) == on )
pixhawk's avatar
pixhawk committed
        return;

    if ( on )
        d_data->paintAttributes |= attribute;
    else
        d_data->paintAttributes &= ~attribute;

Bryant's avatar
Bryant committed
    switch ( attribute )
    {
        case BackingStore:
        {
            if ( on )
            {
                if ( d_data->backingStore == NULL )
                    d_data->backingStore = new QPixmap();

                if ( isVisible() )
                {
#if QT_VERSION >= 0x050000
                    *d_data->backingStore = grab( rect() );
#else
                    *d_data->backingStore = 
                        QPixmap::grabWidget( this, rect() );
#endif
                }
Bryant's avatar
Bryant committed
            else
            {
                delete d_data->backingStore;
                d_data->backingStore = NULL;
            }
            break;
pixhawk's avatar
pixhawk committed
        }
Bryant's avatar
Bryant committed
        case Opaque:
        {
            if ( on )
                setAttribute( Qt::WA_OpaquePaintEvent, true );
Bryant's avatar
Bryant committed
            break;
        }
        case HackStyledBackground:
        case ImmediatePaint:
        {
            break;
        }
pixhawk's avatar
pixhawk committed
    }
}

/*!
Bryant's avatar
Bryant committed
  Test whether a paint attribute is enabled
pixhawk's avatar
pixhawk committed

  \param attribute Paint attribute
Bryant's avatar
Bryant committed
  \return true, when attribute is enabled
pixhawk's avatar
pixhawk committed
  \sa setPaintAttribute()
*/
Bryant's avatar
Bryant committed
bool QwtPlotCanvas::testPaintAttribute( PaintAttribute attribute ) const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->paintAttributes & attribute;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
//! \return Backing store, might be null
const QPixmap *QwtPlotCanvas::backingStore() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return d_data->backingStore;
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
//! Invalidate the internal backing store
void QwtPlotCanvas::invalidateBackingStore()
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->backingStore )
        *d_data->backingStore = QPixmap();
pixhawk's avatar
pixhawk committed
}

/*!
  Set the focus indicator

Bryant's avatar
Bryant committed
  \sa FocusIndicator, focusIndicator()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotCanvas::setFocusIndicator( FocusIndicator focusIndicator )
pixhawk's avatar
pixhawk committed
{
    d_data->focusIndicator = focusIndicator;
}

/*!
  \return Focus indicator
Bryant's avatar
Bryant committed
  \sa FocusIndicator, setFocusIndicator()
pixhawk's avatar
pixhawk committed
*/
QwtPlotCanvas::FocusIndicator QwtPlotCanvas::focusIndicator() const
{
    return d_data->focusIndicator;
}

Bryant's avatar
Bryant committed
/*!
  Set the radius for the corners of the border frame

  \param radius Radius of a rounded corner
  \sa borderRadius()
*/
void QwtPlotCanvas::setBorderRadius( double radius )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    d_data->borderRadius = qMax( 0.0, radius );
}

/*!
  \return Radius for the corners of the border frame
  \sa setBorderRadius()
*/
double QwtPlotCanvas::borderRadius() const
{
    return d_data->borderRadius;
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
  Qt event handler for QEvent::PolishRequest and QEvent::StyleChange
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param event Qt Event
  \return See QFrame::event()
*/
bool QwtPlotCanvas::event( QEvent *event )
{
    if ( event->type() == QEvent::PolishRequest ) 
    {
        if ( testPaintAttribute( QwtPlotCanvas::Opaque ) )
        {
            // Setting a style sheet changes the 
            // Qt::WA_OpaquePaintEvent attribute, but we insist
            // on painting the background.
            
            setAttribute( Qt::WA_OpaquePaintEvent, true );
        }
pixhawk's avatar
pixhawk committed
    }
Bryant's avatar
Bryant committed

    if ( event->type() == QEvent::PolishRequest || 
        event->type() == QEvent::StyleChange )
    {
        updateStyleSheetInfo();
    }

    return QFrame::event( event );
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
/*!
  Paint event
  \param event Paint event
*/
void QwtPlotCanvas::paintEvent( QPaintEvent *event )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    QPainter painter( this );
    painter.setClipRegion( event->region() );

    if ( testPaintAttribute( QwtPlotCanvas::BackingStore ) &&
        d_data->backingStore != NULL )
    {
        QPixmap &bs = *d_data->backingStore;
        if ( bs.size() != size() )
        {
            bs = QwtPainter::backingStore( this, size() );
Bryant's avatar
Bryant committed
            if ( testAttribute(Qt::WA_StyledBackground) )
            {
                QPainter p( &bs );
                qwtFillBackground( &p, this );
                drawCanvas( &p, true );
            }
            else
            {
                QPainter p;
                if ( d_data->borderRadius <= 0.0 )
                {
                    QwtPainter::fillPixmap( this, bs );
                    p.begin( &bs );
                    drawCanvas( &p, false );
                }
                else
                {
                    p.begin( &bs );
                    qwtFillBackground( &p, this );
                    drawCanvas( &p, true );
                }

                if ( frameWidth() > 0 )
                    drawBorder( &p );
            }
        }

        painter.drawPixmap( 0, 0, *d_data->backingStore );
pixhawk's avatar
pixhawk committed
    }
Bryant's avatar
Bryant committed
    else
    {
        if ( testAttribute(Qt::WA_StyledBackground ) )
        {
            if ( testAttribute( Qt::WA_OpaquePaintEvent ) )
            {
                qwtFillBackground( &painter, this );
                drawCanvas( &painter, true );
            }
            else
            {
                drawCanvas( &painter, false );
            }
        }
        else
        {
            if ( testAttribute( Qt::WA_OpaquePaintEvent ) )
            {
                if ( autoFillBackground() )
                {
                    qwtFillBackground( &painter, this );
                    qwtDrawBackground( &painter, this );
                }
            }
            else
            {
                if ( borderRadius() > 0.0 )
                {
                    QPainterPath clipPath;
                    clipPath.addRect( rect() );
                    clipPath = clipPath.subtracted( borderPath( rect() ) );

                    painter.save();

                    painter.setClipPath( clipPath, Qt::IntersectClip );
                    qwtFillBackground( &painter, this );
                    qwtDrawBackground( &painter, this );

                    painter.restore();
                }
            }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            drawCanvas( &painter, false );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
            if ( frameWidth() > 0 ) 
                drawBorder( &painter );
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( hasFocus() && focusIndicator() == CanvasFocusIndicator )
        drawFocusIndicator( &painter );
pixhawk's avatar
pixhawk committed
}

Bryant's avatar
Bryant committed
void QwtPlotCanvas::drawCanvas( QPainter *painter, bool withBackground ) 
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    bool hackStyledBackground = false;

    if ( withBackground && testAttribute( Qt::WA_StyledBackground ) 
        && testPaintAttribute( HackStyledBackground ) )
    {
        // Antialiasing rounded borders is done by
        // inserting pixels with colors between the 
        // border color and the color on the canvas,
        // When the border is painted before the plot items
        // these colors are interpolated for the canvas
        // and the plot items need to be clipped excluding
        // the anialiased pixels. In situations, where
        // the plot items fill the area at the rounded
        // borders this is noticeable.
        // The only way to avoid these annoying "artefacts"
        // is to paint the border on top of the plot items.

        if ( d_data->styleSheet.hasBorder &&
            !d_data->styleSheet.borderPath.isEmpty() )
        {
            // We have a border with at least one rounded corner
            hackStyledBackground = true;
        }
    }
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    if ( withBackground )
    {
        painter->save();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        if ( testAttribute( Qt::WA_StyledBackground ) )
        {
            if ( hackStyledBackground )
            {
                // paint background without border

                painter->setPen( Qt::NoPen );
                painter->setBrush( d_data->styleSheet.background.brush ); 
                painter->setBrushOrigin( d_data->styleSheet.background.origin );
                painter->setClipPath( d_data->styleSheet.borderPath );
                painter->drawRect( contentsRect() );
            }
            else
            {
                qwtDrawStyledBackground( this, painter );
            }
        }
        else if ( autoFillBackground() )
        {
            painter->setPen( Qt::NoPen );
            painter->setBrush( palette().brush( backgroundRole() ) );

            if ( d_data->borderRadius > 0.0 && ( rect() == frameRect() ) )
            {
                if ( frameWidth() > 0 )
                {
                    painter->setClipPath( borderPath( rect() ) );
                    painter->drawRect( rect() );
                }
                else
                {
                    painter->setRenderHint( QPainter::Antialiasing, true );
                    painter->drawPath( borderPath( rect() ) );
                }
            }
            else
            {
                painter->drawRect( rect() );
            }
        }

        painter->restore();
pixhawk's avatar
pixhawk committed
    }

Bryant's avatar
Bryant committed
    painter->save();

    if ( !d_data->styleSheet.borderPath.isEmpty() )
    {
        painter->setClipPath( 
            d_data->styleSheet.borderPath, Qt::IntersectClip );
    }
    else
    {
        if ( d_data->borderRadius > 0.0 )
            painter->setClipPath( borderPath( frameRect() ), Qt::IntersectClip );
        else
            painter->setClipRect( contentsRect(), Qt::IntersectClip );
    }

    plot()->drawCanvas( painter );

    painter->restore();

    if ( withBackground && hackStyledBackground )
    {
        // Now paint the border on top
        QStyleOptionFrame opt;
        opt.initFrom(this);
        style()->drawPrimitive( QStyle::PE_Frame, &opt, painter, this);
    }
pixhawk's avatar
pixhawk committed
}

/*!
Bryant's avatar
Bryant committed
  Draw the border of the plot canvas
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
  \param painter Painter
  \sa setBorderRadius()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotCanvas::drawBorder( QPainter *painter )
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    if ( d_data->borderRadius > 0 )
    {
        if ( frameWidth() > 0 )
        {
            QwtPainter::drawRoundedFrame( painter, QRectF( frameRect() ), 
                d_data->borderRadius, d_data->borderRadius,
                palette(), frameWidth(), frameStyle() );
        }
    }
    else
    {
#if QT_VERSION >= 0x040500
        QStyleOptionFrameV3 opt;
        opt.init(this);
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        int frameShape  = frameStyle() & QFrame::Shape_Mask;
        int frameShadow = frameStyle() & QFrame::Shadow_Mask;

        opt.frameShape = QFrame::Shape( int( opt.frameShape ) | frameShape );
#if 0
        opt.rect = frameRect();
pixhawk's avatar
pixhawk committed
#endif

Bryant's avatar
Bryant committed
        switch (frameShape) 
        {
            case QFrame::Box:
            case QFrame::HLine:
            case QFrame::VLine:
            case QFrame::StyledPanel:
            case QFrame::Panel:
            {
                opt.lineWidth = lineWidth();
                opt.midLineWidth = midLineWidth();
                break; 
            }
            default: 
            {
                opt.lineWidth = frameWidth();
                break;
            }
        }
    
        if ( frameShadow == Sunken )
            opt.state |= QStyle::State_Sunken;
        else if ( frameShadow == Raised )
            opt.state |= QStyle::State_Raised;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        style()->drawControl(QStyle::CE_ShapedFrame, &opt, painter, this);
pixhawk's avatar
pixhawk committed
#else
Bryant's avatar
Bryant committed
        drawFrame( painter );
pixhawk's avatar
pixhawk committed
#endif
Bryant's avatar
Bryant committed
    }
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
  Resize event
  \param event Resize event
*/
void QwtPlotCanvas::resizeEvent( QResizeEvent *event )
{
    QFrame::resizeEvent( event );
    updateStyleSheetInfo();
}
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
/*!
  Draw the focus indication
  \param painter Painter
*/
void QwtPlotCanvas::drawFocusIndicator( QPainter *painter )
{
    const int margin = 1;
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    QRect focusRect = contentsRect();