Skip to content
qwt_plot_panner.cpp 6.49 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_panner.h"
pixhawk's avatar
pixhawk committed
#include "qwt_scale_div.h"
#include "qwt_plot.h"
Bryant's avatar
Bryant committed
#include "qwt_painter.h"
#include <qbitmap.h>
#include <qstyle.h>
#include <qstyleoption.h>

static QBitmap qwtBorderMask( const QWidget *canvas, const QSize &size )
{
    const QRect r( 0, 0, size.width(), size.height() );

    QPainterPath borderPath;

    ( void )QMetaObject::invokeMethod( 
        const_cast< QWidget *>( canvas ), "borderPath", Qt::DirectConnection,
        Q_RETURN_ARG( QPainterPath, borderPath ), Q_ARG( QRect, r ) );

    if ( borderPath.isEmpty() )
    {
        if ( canvas->contentsRect() == canvas->rect() )
            return QBitmap();

        QBitmap mask( size );
        mask.fill( Qt::color0 );

        QPainter painter( &mask );
        painter.fillRect( canvas->contentsRect(), Qt::color1 );

        return mask;
    }

    QImage image( size, QImage::Format_ARGB32_Premultiplied );
    image.fill( Qt::color0 );

    QPainter painter( &image );
    painter.setClipPath( borderPath );
    painter.fillRect( r, Qt::color1 );

    // now erase the frame

    painter.setCompositionMode( QPainter::CompositionMode_DestinationOut );

    if ( canvas->testAttribute(Qt::WA_StyledBackground ) )
    {
        QStyleOptionFrame opt;
        opt.initFrom(canvas);
        opt.rect = r;
        canvas->style()->drawPrimitive( QStyle::PE_Frame, &opt, &painter, canvas );
    }
    else
    {
        const QVariant borderRadius = canvas->property( "borderRadius" );
        const QVariant frameWidth = canvas->property( "frameWidth" );

        if ( borderRadius.type() == QVariant::Double 
            && frameWidth.type() == QVariant::Int )
        {
            const double br = borderRadius.toDouble();
            const int fw = frameWidth.toInt();
        
            if ( br > 0.0 && fw > 0 )
            {
                painter.setPen( QPen( Qt::color1, fw ) );
                painter.setBrush( Qt::NoBrush );
                painter.setRenderHint( QPainter::Antialiasing, true );

                painter.drawPath( borderPath );
            }
        }
    }

    painter.end();

    const QImage mask = image.createMaskFromColor(
        QColor( Qt::color1 ).rgb(), Qt::MaskOutColor );

    return QBitmap::fromImage( mask );
}
pixhawk's avatar
pixhawk committed

class QwtPlotPanner::PrivateData
{
public:
Bryant's avatar
Bryant committed
    PrivateData()
    {
pixhawk's avatar
pixhawk committed
        for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
            isAxisEnabled[axis] = true;
    }

    bool isAxisEnabled[QwtPlot::axisCnt];
};

/*!
Bryant's avatar
Bryant committed
  \brief A panner for the canvas of a QwtPlot
pixhawk's avatar
pixhawk committed

  The panner is enabled for all axes

  \param canvas Plot canvas to pan, also the parent object

Bryant's avatar
Bryant committed
  \sa setAxisEnabled()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
QwtPlotPanner::QwtPlotPanner( QWidget *canvas ):
    QwtPanner( canvas )
pixhawk's avatar
pixhawk committed
{
    d_data = new PrivateData();

Bryant's avatar
Bryant committed
    connect( this, SIGNAL( panned( int, int ) ),
        SLOT( moveCanvas( int, int ) ) );
pixhawk's avatar
pixhawk committed
}

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

/*!
   \brief En/Disable an axis

   Axes that are enabled will be synchronized to the
   result of panning. All other axes will remain unchanged.

   \param axis Axis, see QwtPlot::Axis
   \param on On/Off

Bryant's avatar
Bryant committed
   \sa isAxisEnabled(), moveCanvas()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
void QwtPlotPanner::setAxisEnabled( int axis, bool on )
pixhawk's avatar
pixhawk committed
{
    if ( axis >= 0 && axis < QwtPlot::axisCnt )
        d_data->isAxisEnabled[axis] = on;
}

/*!
   Test if an axis is enabled

   \param axis Axis, see QwtPlot::Axis
   \return True, if the axis is enabled
Bryant's avatar
Bryant committed
   \sa setAxisEnabled(), moveCanvas()
pixhawk's avatar
pixhawk committed
*/
Bryant's avatar
Bryant committed
bool QwtPlotPanner::isAxisEnabled( int axis ) const
pixhawk's avatar
pixhawk committed
{
    if ( axis >= 0 && axis < QwtPlot::axisCnt )
        return d_data->isAxisEnabled[axis];

    return true;
}

//! Return observed plot canvas
Bryant's avatar
Bryant committed
QWidget *QwtPlotPanner::canvas()
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return parentWidget();
pixhawk's avatar
pixhawk committed
}

//! Return Observed plot canvas
Bryant's avatar
Bryant committed
const QWidget *QwtPlotPanner::canvas() const
pixhawk's avatar
pixhawk committed
{
Bryant's avatar
Bryant committed
    return parentWidget();
pixhawk's avatar
pixhawk committed
}

//! Return plot widget, containing the observed plot canvas
QwtPlot *QwtPlotPanner::plot()
{
Bryant's avatar
Bryant committed
    QWidget *w = canvas();
    if ( w )
        w = w->parentWidget();
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    return qobject_cast<QwtPlot *>( w );
pixhawk's avatar
pixhawk committed
}

//! Return plot widget, containing the observed plot canvas
const QwtPlot *QwtPlotPanner::plot() const
{
Bryant's avatar
Bryant committed
    const QWidget *w = canvas();
    if ( w )
        w = w->parentWidget();

    return qobject_cast<const QwtPlot *>( w );
pixhawk's avatar
pixhawk committed
}

/*!
   Adjust the enabled axes according to dx/dy

   \param dx Pixel offset in x direction
   \param dy Pixel offset in y direction

   \sa QwtPanner::panned()
*/
Bryant's avatar
Bryant committed
void QwtPlotPanner::moveCanvas( int dx, int dy )
pixhawk's avatar
pixhawk committed
{
    if ( dx == 0 && dy == 0 )
        return;

Bryant's avatar
Bryant committed
    QwtPlot *plot = this->plot();
pixhawk's avatar
pixhawk committed
    if ( plot == NULL )
        return;
pixhawk's avatar
pixhawk committed
    const bool doAutoReplot = plot->autoReplot();
Bryant's avatar
Bryant committed
    plot->setAutoReplot( false );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
    for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
    {
pixhawk's avatar
pixhawk committed
        if ( !d_data->isAxisEnabled[axis] )
            continue;

Bryant's avatar
Bryant committed
        const QwtScaleMap map = plot->canvasMap( axis );
pixhawk's avatar
pixhawk committed

Bryant's avatar
Bryant committed
        const double p1 = map.transform( plot->axisScaleDiv( axis ).lowerBound() );
        const double p2 = map.transform( plot->axisScaleDiv( axis ).upperBound() );
pixhawk's avatar
pixhawk committed

        double d1, d2;
Bryant's avatar
Bryant committed
        if ( axis == QwtPlot::xBottom || axis == QwtPlot::xTop )
        {
            d1 = map.invTransform( p1 - dx );
            d2 = map.invTransform( p2 - dx );
        }
        else
        {
            d1 = map.invTransform( p1 - dy );
            d2 = map.invTransform( p2 - dy );
pixhawk's avatar
pixhawk committed
        }

Bryant's avatar
Bryant committed
        plot->setAxisScale( axis, d1, d2 );
pixhawk's avatar
pixhawk committed
    }

Bryant's avatar
Bryant committed
    plot->setAutoReplot( doAutoReplot );
pixhawk's avatar
pixhawk committed
    plot->replot();
}
Bryant's avatar
Bryant committed

/*!
   Calculate a mask from the border path of the canvas

   \return Mask as bitmap
   \sa QwtPlotCanvas::borderPath()
*/
QBitmap QwtPlotPanner::contentsMask() const
{
    if ( canvas() )
        return qwtBorderMask( canvas(), size() );

    return QwtPanner::contentsMask();
}

/*!
   \return Pixmap with the content of the canvas
 */
QPixmap QwtPlotPanner::grab() const
{   
    const QWidget *cv = canvas();
    if ( cv && cv->inherits( "QGLWidget" ) )
    {
        // we can't grab from a QGLWidget

        QPixmap pm( cv->size() );
        QwtPainter::fillPixmap( cv, pm );

        QPainter painter( &pm );
        const_cast<QwtPlot *>( plot() )->drawCanvas( &painter );

        return pm;
    }

    return QwtPanner::grab();
}