Skip to content
Snippets Groups Projects
qwt_painter.cpp 34.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • 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_painter.h"
    #include "qwt_math.h"
    #include "qwt_clipper.h"
    #include "qwt_color_map.h"
    #include "qwt_scale_map.h"
    
    pixhawk's avatar
    pixhawk committed
    #include <qwindowdefs.h>
    #include <qwidget.h>
    
    Bryant's avatar
    Bryant committed
    #include <qframe.h>
    
    pixhawk's avatar
    pixhawk committed
    #include <qrect.h>
    #include <qpainter.h>
    #include <qpalette.h>
    #include <qpaintdevice.h>
    #include <qpixmap.h>
    #include <qstyle.h>
    #include <qtextdocument.h>
    #include <qabstracttextdocumentlayout.h>
    #include <qstyleoption.h>
    #include <qpaintengine.h>
    
    Bryant's avatar
    Bryant committed
    #include <qapplication.h>
    #include <qdesktopwidget.h>
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    #if QT_VERSION >= 0x050000
    #include <qwindow.h>
    #endif
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    #if QT_VERSION < 0x050000 
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    #ifdef Q_WS_X11
    #include <qx11info_x11.h>
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
    #endif
    
    
    Bryant's avatar
    Bryant committed
    bool QwtPainter::d_polylineSplitting = true;
    bool QwtPainter::d_roundingAlignment = true;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    static inline bool qwtIsClippingNeeded( 
        const QPainter *painter, QRectF &clipRect )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        bool doClipping = false;
        const QPaintEngine *pe = painter->paintEngine();
        if ( pe && pe->type() == QPaintEngine::SVG )
        {
            // The SVG paint engine ignores any clipping,
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            if ( painter->hasClipping() )
            {
                doClipping = true;
                clipRect = painter->clipRegion().boundingRect();
            }
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        return doClipping;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    template <class T>
    static inline void qwtDrawPolyline( QPainter *painter,
        const T *points, int pointCount, bool polylineSplitting )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        bool doSplit = false;
        if ( polylineSplitting )
        {
            const QPaintEngine *pe = painter->paintEngine();
            if ( pe && pe->type() == QPaintEngine::Raster )
            {
                /*
                    The raster paint engine seems to use some algo with O(n*n).
                    ( Qt 4.3 is better than Qt 4.2, but remains unacceptable)
                    To work around this problem, we have to split the polygon into
                    smaller pieces.
                 */
                doSplit = true;
            }
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( doSplit )
        {
            const int splitSize = 20;
            for ( int i = 0; i < pointCount; i += splitSize )
            {
                const int n = qMin( splitSize + 1, pointCount - i );
                painter->drawPolyline( points + i, n );
            }
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
        else
            painter->drawPolyline( points, pointCount );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    static inline void qwtUnscaleFont( QPainter *painter )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( painter->font().pixelSize() >= 0 )
            return;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        static QSize screenResolution;
        if ( !screenResolution.isValid() )
        {
            QDesktopWidget *desktop = QApplication::desktop();
            if ( desktop )
            {
                screenResolution.setWidth( desktop->logicalDpiX() );
                screenResolution.setHeight( desktop->logicalDpiY() );
            }
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        const QPaintDevice *pd = painter->device();
        if ( pd->logicalDpiX() != screenResolution.width() ||
            pd->logicalDpiY() != screenResolution.height() )
        {
            QFont pixelFont( painter->font(), QApplication::desktop() );
            pixelFont.setPixelSize( QFontInfo( pixelFont ).pixelSize() );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            painter->setFont( pixelFont );
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Check is the application is running with the X11 graphics system
      that has some special capabilities that can be used for incremental
      painting to a widget.
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \return True, when the graphics system is X11
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    bool QwtPainter::isX11GraphicsSystem()
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        static int onX11 = -1;
        if ( onX11 < 0 )
        {
            QPixmap pm( 1, 1 );
            QPainter painter( &pm );
    
            onX11 = ( painter.paintEngine()->type() == QPaintEngine::X11 ) ? 1 : 0;
        }
    
        return onX11 == 1;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
      Check if the painter is using a paint engine, that aligns
      coordinates to integers. Today these are all paint engines
      beside QPaintEngine::Pdf and QPaintEngine::SVG.
    
      If we have an integer based paint engine it is also
      checked if the painter has a transformation matrix,
      that rotates or scales.
    
      \param  painter Painter
      \return true, when the painter is aligning
    
      \sa setRoundingAlignment()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    bool QwtPainter::isAligning( QPainter *painter )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( painter && painter->isActive() )
        {
            switch ( painter->paintEngine()->type() )
            {
                case QPaintEngine::Pdf:
                case QPaintEngine::SVG:
                    return false;
    
                default:;
            }
    
            const QTransform tr = painter->transform();
            if ( tr.isRotating() || tr.isScaling() )
            {
                // we might have to check translations too
                return false;
            }
        }
    
        return true;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
      Enable whether coordinates should be rounded, before they are painted
      to a paint engine that floors to integer values. For other paint engines
      this ( PDF, SVG ), this flag has no effect.
      QwtPainter stores this flag only, the rounding itself is done in 
      the painting code ( f.e the plot items ).
    
      The default setting is true. 
    
      \sa roundingAlignment(), isAligning()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPainter::setRoundingAlignment( bool enable )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        d_roundingAlignment = enable;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    /*!
    
    Bryant's avatar
    Bryant committed
      \brief En/Disable line splitting for the raster paint engine
    
      In some Qt versions the raster paint engine paints polylines of many points
      much faster when they are split in smaller chunks: f.e all supported Qt versions
      >= Qt 5.0 when drawing an antialiased polyline with a pen width >=2.
    
      The default setting is true.
    
      \sa polylineSplitting()
    
    pixhawk's avatar
    pixhawk committed
    */
    
    Bryant's avatar
    Bryant committed
    void QwtPainter::setPolylineSplitting( bool enable )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        d_polylineSplitting = enable;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPath()
    void QwtPainter::drawPath( QPainter *painter, const QPainterPath &path )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        painter->drawPath( path );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawRect()
    void QwtPainter::drawRect( QPainter *painter, double x, double y, double w, double h )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        drawRect( painter, QRectF( x, y, w, h ) );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawRect()
    void QwtPainter::drawRect( QPainter *painter, const QRectF &rect )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        const QRectF r = rect;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
        if ( deviceClipping )
    
    Bryant's avatar
    Bryant committed
        {
            if ( !clipRect.intersects( r ) )
    
    pixhawk's avatar
    pixhawk committed
                return;
    
    
    Bryant's avatar
    Bryant committed
            if ( !clipRect.contains( r ) )
            {
                fillRect( painter, r & clipRect, painter->brush() );
    
    pixhawk's avatar
    pixhawk committed
    
                painter->save();
    
    Bryant's avatar
    Bryant committed
                painter->setBrush( Qt::NoBrush );
                drawPolyline( painter, QPolygonF( r ) );
    
    pixhawk's avatar
    pixhawk committed
                painter->restore();
    
                return;
            }
        }
    
    
    Bryant's avatar
    Bryant committed
        painter->drawRect( r );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::fillRect()
    void QwtPainter::fillRect( QPainter *painter,
        const QRectF &rect, const QBrush &brush )
    
    pixhawk's avatar
    pixhawk committed
    {
        if ( !rect.isValid() )
            return;
    
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
        /*
    
    Bryant's avatar
    Bryant committed
          Performance of Qt4 is horrible for a non trivial brush. Without
          clipping expect minutes or hours for repainting large rectangles
    
    pixhawk's avatar
    pixhawk committed
          (might result from zooming)
        */
    
    
    Bryant's avatar
    Bryant committed
        if ( deviceClipping )
            clipRect &= painter->window();
        else
            clipRect = painter->window();
    
    
    pixhawk's avatar
    pixhawk committed
        if ( painter->hasClipping() )
            clipRect &= painter->clipRegion().boundingRect();
    
    
    Bryant's avatar
    Bryant committed
        QRectF r = rect;
        if ( deviceClipping )
            r = r.intersected( clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
        if ( r.isValid() )
    
    Bryant's avatar
    Bryant committed
            painter->fillRect( r, brush );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPie()
    void QwtPainter::drawPie( QPainter *painter, const QRectF &rect,
        int a, int alen )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
        if ( deviceClipping && !clipRect.contains( rect ) )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        painter->drawPie( rect, a, alen );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawEllipse()
    void QwtPainter::drawEllipse( QPainter *painter, const QRectF &rect )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( deviceClipping && !clipRect.contains( rect ) )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        painter->drawEllipse( rect );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawText()
    void QwtPainter::drawText( QPainter *painter, double x, double y,
            const QString &text )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        drawText( painter, QPointF( x, y ), text );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawText()
    void QwtPainter::drawText( QPainter *painter, const QPointF &pos,
            const QString &text )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( deviceClipping && !clipRect.contains( pos ) )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
    
        painter->save();
        qwtUnscaleFont( painter );
        painter->drawText( pos, text );
        painter->restore();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawText()
    void QwtPainter::drawText( QPainter *painter,
        double x, double y, double w, double h,
        int flags, const QString &text )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        drawText( painter, QRectF( x, y, w, h ), flags, text );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawText()
    void QwtPainter::drawText( QPainter *painter, const QRectF &rect,
            int flags, const QString &text )
    {
        painter->save();
        qwtUnscaleFont( painter );
        painter->drawText( rect, flags, text );
        painter->restore();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    #ifndef QT_NO_RICHTEXT
    
    /*!
    
    Bryant's avatar
    Bryant committed
      Draw a text document into a rectangle
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
      \param painter Painter
      \param rect Traget rectangle
      \param flags Alignments/Text flags, see QPainter::drawText()
      \param text Text document
    */
    void QwtPainter::drawSimpleRichText( QPainter *painter, const QRectF &rect,
        int flags, const QTextDocument &text )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QTextDocument *txt = text.clone();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->save();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->setFont( txt->defaultFont() );
        qwtUnscaleFont( painter );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        txt->setDefaultFont( painter->font() );
        txt->setPageSize( QSizeF( rect.width(), QWIDGETSIZE_MAX ) );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QAbstractTextDocumentLayout* layout = txt->documentLayout();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        const double height = layout->documentSize().height();
        double y = rect.y();
        if ( flags & Qt::AlignBottom )
            y += ( rect.height() - height );
        else if ( flags & Qt::AlignVCenter )
            y += ( rect.height() - height ) / 2;
    
    pixhawk's avatar
    pixhawk committed
    
        QAbstractTextDocumentLayout::PaintContext context;
    
    Bryant's avatar
    Bryant committed
        context.palette.setColor( QPalette::Text, painter->pen().color() );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->translate( rect.x(), y );
        layout->draw( painter, context );
    
    pixhawk's avatar
    pixhawk committed
    
        painter->restore();
    
    Bryant's avatar
    Bryant committed
        delete txt;
    
    pixhawk's avatar
    pixhawk committed
    }
    
    #endif // !QT_NO_RICHTEXT
    
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawLine()
    void QwtPainter::drawLine( QPainter *painter,
        const QPointF &p1, const QPointF &p2 )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
        if ( deviceClipping &&
    
    Bryant's avatar
    Bryant committed
            !( clipRect.contains( p1 ) && clipRect.contains( p2 ) ) )
        {
            QPolygonF polygon;
            polygon += p1;
            polygon += p2;
            drawPolyline( painter, polygon );
    
    pixhawk's avatar
    pixhawk committed
            return;
        }
    
    
    Bryant's avatar
    Bryant committed
        painter->drawLine( p1, p2 );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPolygon()
    void QwtPainter::drawPolygon( QPainter *painter, const QPolygonF &polygon )
    {
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QPolygonF cpa = polygon;
        if ( deviceClipping )
            cpa = QwtClipper::clipPolygonF( clipRect, polygon );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->drawPolygon( cpa );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPolyline()
    void QwtPainter::drawPolyline( QPainter *painter, const QPolygonF &polygon )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QPolygonF cpa = polygon;
        if ( deviceClipping )
            cpa = QwtClipper::clipPolygonF( clipRect, cpa );
    
        qwtDrawPolyline<QPointF>( painter,
            cpa.constData(), cpa.size(), d_polylineSplitting );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPolyline()
    void QwtPainter::drawPolyline( QPainter *painter,
        const QPointF *points, int pointCount )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
        if ( deviceClipping )
    
    Bryant's avatar
    Bryant committed
        {
            QPolygonF polygon( pointCount );
            ::memcpy( polygon.data(), points, pointCount * sizeof( QPointF ) );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            polygon = QwtClipper::clipPolygonF( clipRect, polygon );
            qwtDrawPolyline<QPointF>( painter,
                polygon.constData(), polygon.size(), d_polylineSplitting );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
        else
        {
            qwtDrawPolyline<QPointF>( painter, points, pointCount, d_polylineSplitting );
        }
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPolygon()
    void QwtPainter::drawPolygon( QPainter *painter, const QPolygon &polygon )
    {
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        QPolygon cpa = polygon;
        if ( deviceClipping )
            cpa = QwtClipper::clipPolygon( clipRect, polygon );
    
        painter->drawPolygon( cpa );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPolyline()
    void QwtPainter::drawPolyline( QPainter *painter, const QPolygon &polygon )
    {
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
        QPolygon cpa = polygon;
        if ( deviceClipping )
            cpa = QwtClipper::clipPolygon( clipRect, cpa );
    
        qwtDrawPolyline<QPoint>( painter,
            cpa.constData(), cpa.size(), d_polylineSplitting );
    }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPolyline()
    void QwtPainter::drawPolyline( QPainter *painter,
        const QPoint *points, int pointCount )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( deviceClipping )
        {
            QPolygon polygon( pointCount );
            ::memcpy( polygon.data(), points, pointCount * sizeof( QPoint ) );
    
            polygon = QwtClipper::clipPolygon( clipRect, polygon );
            qwtDrawPolyline<QPoint>( painter,
                polygon.constData(), polygon.size(), d_polylineSplitting );
        }
        else
            qwtDrawPolyline<QPoint>( painter, points, pointCount, d_polylineSplitting );
    }
    
    //! Wrapper for QPainter::drawPoint()
    void QwtPainter::drawPoint( QPainter *painter, const QPointF &pos )
    {
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( deviceClipping && !clipRect.contains( pos ) )
    
    pixhawk's avatar
    pixhawk committed
            return;
    
    
    Bryant's avatar
    Bryant committed
        painter->drawPoint( pos );
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPoint()
    void QwtPainter::drawPoint( QPainter *painter, const QPoint &pos )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        if ( deviceClipping )
        {
            const int minX = qCeil( clipRect.left() );
            const int maxX = qFloor( clipRect.right() );
            const int minY = qCeil( clipRect.top() );
            const int maxY = qFloor( clipRect.bottom() );
    
            if ( pos.x() < minX || pos.x() > maxX 
                || pos.y() < minY || pos.y() > maxY )
            {
                return;
            }
        }
    
    Bryant's avatar
    Bryant committed
        painter->drawPoint( pos );
    }
    
    //! Wrapper for QPainter::drawPoints()
    void QwtPainter::drawPoints( QPainter *painter, 
        const QPoint *points, int pointCount )
    {
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
        if ( deviceClipping )
        {
            const int minX = qCeil( clipRect.left() );
            const int maxX = qFloor( clipRect.right() );
            const int minY = qCeil( clipRect.top() );
            const int maxY = qFloor( clipRect.bottom() );
    
    Bryant's avatar
    Bryant committed
            const QRect r( minX, minY, maxX - minX, maxY - minY );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            QPolygon clippedPolygon( pointCount );
            QPoint *clippedData = clippedPolygon.data();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
            int numClippedPoints = 0;
            for ( int i = 0; i < pointCount; i++ )
            {
                if ( r.contains( points[i] ) )
                    clippedData[ numClippedPoints++ ] = points[i];
            }
            painter->drawPoints( clippedData, numClippedPoints );
        }
        else
        {
            painter->drawPoints( points, pointCount );
    
    pixhawk's avatar
    pixhawk committed
        }
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawPoints()
    void QwtPainter::drawPoints( QPainter *painter, 
        const QPointF *points, int pointCount )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        QRectF clipRect;
        const bool deviceClipping = qwtIsClippingNeeded( painter, clipRect );
    
        if ( deviceClipping )
        {
            QPolygonF clippedPolygon( pointCount );
            QPointF *clippedData = clippedPolygon.data();
    
            int numClippedPoints = 0;
            for ( int i = 0; i < pointCount; i++ )
            {
                if ( clipRect.contains( points[i] ) )
                    clippedData[ numClippedPoints++ ] = points[i];
            }
            painter->drawPoints( clippedData, numClippedPoints );
        }
        else
        {
            painter->drawPoints( points, pointCount );
        }
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    //! Wrapper for QPainter::drawImage()
    void QwtPainter::drawImage( QPainter *painter,
        const QRectF &rect, const QImage &image )
    {
        const QRect alignedRect = rect.toAlignedRect();
    
        if ( alignedRect != rect )
        {
            const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
    
            painter->save();
            painter->setClipRect( clipRect, Qt::IntersectClip );
            painter->drawImage( alignedRect, image );
            painter->restore();
        }
        else
        {
            painter->drawImage( alignedRect, image );
        }
    }
    
    //! Wrapper for QPainter::drawPixmap()
    void QwtPainter::drawPixmap( QPainter *painter,
        const QRectF &rect, const QPixmap &pixmap )
    {
        const QRect alignedRect = rect.toAlignedRect();
    
        if ( alignedRect != rect )
        {
            const QRectF clipRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
    
            painter->save();
            painter->setClipRect( clipRect, Qt::IntersectClip );
            painter->drawPixmap( alignedRect, pixmap );
            painter->restore();
        }
        else
        {
            painter->drawPixmap( alignedRect, pixmap );
        }
    }
    
    //! Draw a focus rectangle on a widget using its style.
    void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget )
    {
        drawFocusRect( painter, widget, widget->rect() );
    }
    
    //! Draw a focus rectangle on a widget using its style.
    void QwtPainter::drawFocusRect( QPainter *painter, const QWidget *widget,
        const QRect &rect )
    
    pixhawk's avatar
    pixhawk committed
    {
    
        QStyleOptionFocusRect opt;
    
    Bryant's avatar
    Bryant committed
        opt.init( widget );
    
        opt.rect = rect;
        opt.state |= QStyle::State_HasFocus;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        widget->style()->drawPrimitive( QStyle::PE_FrameFocusRect,
            &opt, painter, widget );
    }
    
    /*!
      Draw a round frame 
    
      \param painter Painter
      \param rect Frame rectangle
      \param palette QPalette::WindowText is used for plain borders
                     QPalette::Dark and QPalette::Light for raised
                     or sunken borders
      \param lineWidth Line width
      \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
    */
    void QwtPainter::drawRoundFrame( QPainter *painter,
        const QRectF &rect, const QPalette &palette, 
        int lineWidth, int frameStyle )
    {
        enum Style
        {
            Plain,
            Sunken,
            Raised
        };
    
        Style style = Plain;
        if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
            style = Sunken;
        else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
            style = Raised;
    
        const double lw2 = 0.5 * lineWidth;
        QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
    
        QBrush brush;
    
        if ( style != Plain )
        {
            QColor c1 = palette.color( QPalette::Light );
            QColor c2 = palette.color( QPalette::Dark );
    
            if ( style == Sunken )
                qSwap( c1, c2 );
    
            QLinearGradient gradient( r.topLeft(), r.bottomRight() );
            gradient.setColorAt( 0.0, c1 );
    #if 0
            gradient.setColorAt( 0.3, c1 );
            gradient.setColorAt( 0.7, c2 );
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
    Bryant's avatar
    Bryant committed
            gradient.setColorAt( 1.0, c2 );
    
            brush = QBrush( gradient );
        }
        else // Plain
        {
            brush = palette.brush( QPalette::WindowText );
        }
    
        painter->save();
    
        painter->setPen( QPen( brush, lineWidth ) );
        painter->setBrush( Qt::NoBrush );
    
        painter->drawEllipse( r );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->restore();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Draw a rectangular frame
    
      \param painter Painter
      \param rect Frame rectangle
      \param palette Palette
      \param foregroundRole Foreground role used for QFrame::Plain
      \param frameWidth Frame width
      \param midLineWidth Used for QFrame::Box
      \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
    */
    void QwtPainter::drawFrame( QPainter *painter, const QRectF &rect,
        const QPalette &palette, QPalette::ColorRole foregroundRole,
        int frameWidth, int midLineWidth, int frameStyle )
    
    pixhawk's avatar
    pixhawk committed
    {
    
    Bryant's avatar
    Bryant committed
        if ( frameWidth <= 0 || rect.isEmpty() )
            return;
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        const int shadow = frameStyle & QFrame::Shadow_Mask;
    
        painter->save();
    
        if ( shadow == QFrame::Plain )
        {
            const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
            const QRectF innerRect = outerRect.adjusted( 
                frameWidth, frameWidth, -frameWidth, -frameWidth );
    
            QPainterPath path;
            path.addRect( outerRect );
            path.addRect( innerRect );
    
            painter->setPen( Qt::NoPen );
            painter->setBrush( palette.color( foregroundRole ) );
    
            painter->drawPath( path );
    
    pixhawk's avatar
    pixhawk committed
        }
    
    Bryant's avatar
    Bryant committed
        else
        {
            const int shape = frameStyle & QFrame::Shape_Mask;
    
            if ( shape == QFrame::Box )
            {
                const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
                const QRectF midRect1 = outerRect.adjusted( 
                    frameWidth, frameWidth, -frameWidth, -frameWidth );
                const QRectF midRect2 = midRect1.adjusted( 
                    midLineWidth, midLineWidth, -midLineWidth, -midLineWidth );
    
                const QRectF innerRect = midRect2.adjusted( 
                    frameWidth, frameWidth, -frameWidth, -frameWidth );
    
                QPainterPath path1;
                path1.moveTo( outerRect.bottomLeft() );
                path1.lineTo( outerRect.topLeft() );
                path1.lineTo( outerRect.topRight() );
                path1.lineTo( midRect1.topRight() );
                path1.lineTo( midRect1.topLeft() );
                path1.lineTo( midRect1.bottomLeft() );
    
                QPainterPath path2;
                path2.moveTo( outerRect.bottomLeft() );
                path2.lineTo( outerRect.bottomRight() );
                path2.lineTo( outerRect.topRight() );
                path2.lineTo( midRect1.topRight() );
                path2.lineTo( midRect1.bottomRight() );
                path2.lineTo( midRect1.bottomLeft() );
    
                QPainterPath path3;
                path3.moveTo( midRect2.bottomLeft() );
                path3.lineTo( midRect2.topLeft() );
                path3.lineTo( midRect2.topRight() );
                path3.lineTo( innerRect.topRight() );
                path3.lineTo( innerRect.topLeft() );
                path3.lineTo( innerRect.bottomLeft() );
    
                QPainterPath path4;
                path4.moveTo( midRect2.bottomLeft() );
                path4.lineTo( midRect2.bottomRight() );
                path4.lineTo( midRect2.topRight() );
                path4.lineTo( innerRect.topRight() );
                path4.lineTo( innerRect.bottomRight() );
                path4.lineTo( innerRect.bottomLeft() );
    
                QPainterPath path5;
                path5.addRect( midRect1 );
                path5.addRect( midRect2 );
    
                painter->setPen( Qt::NoPen );
    
                QBrush brush1 = palette.dark().color();
                QBrush brush2 = palette.light().color();
    
                if ( shadow == QFrame::Raised )
                    qSwap( brush1, brush2 );
    
                painter->setBrush( brush1 );
                painter->drawPath( path1 );
                painter->drawPath( path4 );
    
                painter->setBrush( brush2 );
                painter->drawPath( path2 );
                painter->drawPath( path3 );
    
                painter->setBrush( palette.mid() );
                painter->drawPath( path5 );
            }
    #if 0
            // qDrawWinPanel doesn't result in something nice
            // on a scalable document like PDF. Better draw a
            // Panel.
    
            else if ( shape == QFrame::WinPanel )
            {
                painter->setRenderHint( QPainter::NonCosmeticDefaultPen, true );
                qDrawWinPanel ( painter, rect.toRect(), palette,
                    frameStyle & QFrame::Sunken );
            }
            else if ( shape == QFrame::StyledPanel )
            {
            }
    
    pixhawk's avatar
    pixhawk committed
    #endif
    
    Bryant's avatar
    Bryant committed
            else
            {
                const QRectF outerRect = rect.adjusted( 0.0, 0.0, -1.0, -1.0 );
                const QRectF innerRect = outerRect.adjusted( 
                    frameWidth - 1.0, frameWidth - 1.0, 
                    -( frameWidth - 1.0 ), -( frameWidth - 1.0 ) );
    
                QPainterPath path1;
                path1.moveTo( outerRect.bottomLeft() );
                path1.lineTo( outerRect.topLeft() );
                path1.lineTo( outerRect.topRight() );
                path1.lineTo( innerRect.topRight() );
                path1.lineTo( innerRect.topLeft() );
                path1.lineTo( innerRect.bottomLeft() );
    
    
                QPainterPath path2;
                path2.moveTo( outerRect.bottomLeft() );
                path2.lineTo( outerRect.bottomRight() );
                path2.lineTo( outerRect.topRight() );
                path2.lineTo( innerRect.topRight() );
                path2.lineTo( innerRect.bottomRight() );
                path2.lineTo( innerRect.bottomLeft() );
    
                painter->setPen( Qt::NoPen );
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                QBrush brush1 = palette.dark().color();
                QBrush brush2 = palette.light().color();
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
                if ( shadow == QFrame::Raised )
                    qSwap( brush1, brush2 );
    
                painter->setBrush( brush1 );
                painter->drawPath( path1 );
    
                painter->setBrush( brush2 );
                painter->drawPath( path2 );
            }
    
        }
    
    pixhawk's avatar
    pixhawk committed
    
    
    Bryant's avatar
    Bryant committed
        painter->restore();
    
    pixhawk's avatar
    pixhawk committed
    }
    
    
    Bryant's avatar
    Bryant committed
    /*!
      Draw a rectangular frame with rounded borders
    
      \param painter Painter
      \param rect Frame rectangle
      \param xRadius x-radius of the ellipses defining the corners
      \param yRadius y-radius of the ellipses defining the corners
      \param palette QPalette::WindowText is used for plain borders
                     QPalette::Dark and QPalette::Light for raised
                     or sunken borders
      \param lineWidth Line width
      \param frameStyle bitwise OR´ed value of QFrame::Shape and QFrame::Shadow
    */
    
    void QwtPainter::drawRoundedFrame( QPainter *painter, 
        const QRectF &rect, double xRadius, double yRadius, 
        const QPalette &palette, int lineWidth, int frameStyle )
    {
        painter->save();
        painter->setRenderHint( QPainter::Antialiasing, true );
        painter->setBrush( Qt::NoBrush );
    
        double lw2 = lineWidth * 0.5;
        QRectF r = rect.adjusted( lw2, lw2, -lw2, -lw2 );
    
        QPainterPath path;
        path.addRoundedRect( r, xRadius, yRadius );
    
        enum Style
        {
            Plain,
            Sunken,
            Raised
        };
    
        Style style = Plain;
        if ( (frameStyle & QFrame::Sunken) == QFrame::Sunken )
            style = Sunken;
        else if ( (frameStyle & QFrame::Raised) == QFrame::Raised )
            style = Raised;
    
        if ( style != Plain && path.elementCount() == 17 )
        {
            // move + 4 * ( cubicTo + lineTo )
            QPainterPath pathList[8];
            
            for ( int i = 0; i < 4; i++ )
            {
                const int j = i * 4 + 1;
                
                pathList[ 2 * i ].moveTo(
                    path.elementAt(j - 1).x, path.elementAt( j - 1 ).y
                );  
                
                pathList[ 2 * i ].cubicTo(
                    path.elementAt(j + 0).x, path.elementAt(j + 0).y,
                    path.elementAt(j + 1).x, path.elementAt(j + 1).y,
                    path.elementAt(j + 2).x, path.elementAt(j + 2).y );
                    
                pathList[ 2 * i + 1 ].moveTo(
                    path.elementAt(j + 2).x, path.elementAt(j + 2).y
                );  
                pathList[ 2 * i + 1 ].lineTo(
                    path.elementAt(j + 3).x, path.elementAt(j + 3).y
                );  
            }   
    
            QColor c1( palette.color( QPalette::Dark ) );
            QColor c2( palette.color( QPalette::Light ) );
    
            if ( style == Raised )
                qSwap( c1, c2 );
    
            for ( int i = 0; i < 4; i++ )
            {
                QRectF r = pathList[2 * i].controlPointRect();
    
                QPen arcPen;
                arcPen.setCapStyle( Qt::FlatCap );
                arcPen.setWidth( lineWidth );
    
                QPen linePen;
                linePen.setCapStyle( Qt::FlatCap );
                linePen.setWidth( lineWidth );
    
                switch( i )
                {
                    case 0:
                    {
                        arcPen.setColor( c1 );
                        linePen.setColor( c1 );
                        break;
                    }
                    case 1:
                    {
                        QLinearGradient gradient;
                        gradient.setStart( r.topLeft() );
                        gradient.setFinalStop( r.bottomRight() );