Changeset - 39b23673b4d1
[Not reviewed]
Hasan Yavuz ÖZDERYA - 9 years ago 2017-04-26 14:43:52
hy@ozderya.net
simplify scrollzoomer, only the x axis needs extra limits

Note: at this point auto-scale is broken, when X scroll is used it disables the
auto-scale on Y axis as well
3 files changed with 25 insertions and 28 deletions:
0 comments (0 inline, 0 general)
src/plot.cpp
Show inline comments
 
/*
 
  Copyright © 2017 Hasan Yavuz Özderya
 

	
 
  This file is part of serialplot.
 

	
 
  serialplot is free software: you can redistribute it and/or modify
 
  it under the terms of the GNU General Public License as published by
 
  the Free Software Foundation, either version 3 of the License, or
 
  (at your option) any later version.
 

	
 
  serialplot is distributed in the hope that it will be useful,
 
  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  GNU General Public License for more details.
 

	
 
  You should have received a copy of the GNU General Public License
 
  along with serialplot.  If not, see <http://www.gnu.org/licenses/>.
 
*/
 

	
 
#include <QRectF>
 
#include <QKeySequence>
 
#include <QColor>
 
#include <qwt_symbol.h>
 
#include <qwt_plot_curve.h>
 
#include <math.h>
 
#include <algorithm>
 

	
 
#include "plot.h"
 
#include "utils.h"
 

	
 
static const int SYMBOL_SHOW_AT_WIDTH = 5;
 
static const int SYMBOL_SIZE_MAX = 7;
 

	
 
Plot::Plot(QWidget* parent) :
 
    QwtPlot(parent),
 
    zoomer(this->canvas(), false),
 
    sZoomer(this, &zoomer)
 
{
 
    isAutoScaled = true;
 
    symbolSize = 0;
 
    numOfSamples = 1;
 

	
 
    QObject::connect(&zoomer, &Zoomer::unzoomed, this, &Plot::unzoomed);
 

	
 
    zoomer.setZoomBase(QRectF(0,-1,2,500));
 
    zoomer.setZoomBase();
 
    grid.attach(this);
 
    legend.attach(this);
 

	
 
    showGrid(false);
 
    darkBackground(false);
 

	
 
    snapshotOverlay = NULL;
 

	
 
    connect(&zoomer, &QwtPlotZoomer::zoomed,
 
            [this](const QRectF &rect)
 
            {
 
                onXScaleChanged();
 
            });
 

	
 
    connect(this, &QwtPlot::itemAttached,
 
            [this](QwtPlotItem *plotItem, bool on)
 
            {
 
                if (symbolSize) updateSymbols();
 
            });
 

	
 
    // init demo indicator
 
    QwtText demoText(" DEMO RUNNING ");  // looks better with spaces
 
    demoText.setColor(QColor("white"));
 
    demoText.setBackgroundBrush(Qt::darkRed);
 
    demoText.setBorderRadius(4);
 
    demoText.setRenderFlags(Qt::AlignLeft | Qt::AlignBottom);
 
    demoIndicator.setText(demoText);
 
    demoIndicator.hide();
 
    demoIndicator.attach(this);
 
}
 

	
 
Plot::~Plot()
 
{
 
    if (snapshotOverlay != NULL) delete snapshotOverlay;
 
}
 

	
 
void Plot::setYAxis(bool autoScaled, double yAxisMin, double yAxisMax)
 
{
 
    this->isAutoScaled = autoScaled;
 

	
 
    if (!autoScaled)
 
    {
 
        yMin = yAxisMin;
 
        yMax = yAxisMax;
 
    }
 

	
 
    zoomer.zoom(0);
 
    resetAxes();
 
}
 

	
 
void Plot::setXAxis(double xMin, double xMax)
 
{
 
    _xMin = xMin;
 
    _xMax = xMax;
 

	
 
    zoomer.zoom(0); // unzoom
 

	
 
    // set axis
 
    setAxisScale(QwtPlot::xBottom, xMin, xMax);
 
    // setAxisScale(QwtPlot::xBottom, xMin, xMax);
 
    replot(); // Note: if we don't replot here scale at startup isn't set correctly
 

	
 
    // reset zoom base
 
    auto base = zoomer.zoomBase();
 
    base.setLeft(xMin);
 
    base.setRight(xMax);
 
    zoomer.setZoomBase(base);
 
    // auto base = zoomer.zoomBase();
 
    // base.setLeft(xMin);
 
    // base.setRight(xMax);
 
    // zoomer.setZoomBase(base);
 

	
 
    onXScaleChanged();
 
}
 

	
 
void Plot::resetAxes()
 
{
 
    // reset y axis
 
    if (isAutoScaled)
 
    {
 
        setAxisAutoScale(QwtPlot::yLeft);
 
    }
 
    else
 
    {
 
        setAxisScale(QwtPlot::yLeft, yMin, yMax);
 
    }
 

	
 
    zoomer.setZoomBase();
 

	
 
    replot();
 
}
 

	
 
void Plot::unzoomed()
 
{
 
    resetAxes();
 
    onXScaleChanged();
 
}
 

	
 
void Plot::showGrid(bool show)
 
{
 
    grid.enableX(show);
 
    grid.enableY(show);
 
    replot();
 
}
 

	
 
void Plot::showMinorGrid(bool show)
 
{
 
    grid.enableXMin(show);
 
    grid.enableYMin(show);
 
    replot();
 
}
 

	
 
void Plot::showLegend(bool show)
 
{
 
    legend.setVisible(show);
 
    replot();
 
}
 

	
 
void Plot::showDemoIndicator(bool show)
src/scrollzoomer.cpp
Show inline comments
 
/*
 
  Copyright © 2014 Uwe Rathmann
 

	
 
  This file is copied from Qwt project; you can redistribute it and/or modify it
 
  under the terms of the Qwt License, Version 1.0. You can obtain the original
 
  source code and the details of the Qwt License from the Qwt website:
 
  http://qwt.sourceforge.net/
 
*/
 

	
 
#include <qevent.h>
 
#include <qwt_plot_canvas.h>
 
#include <qwt_plot_layout.h>
 
#include <qwt_scale_engine.h>
 
#include <qwt_scale_widget.h>
 
#include "scrollbar.h"
 
#include "scrollzoomer.h"
 

	
 
class ScrollData
 
{
 
public:
 
    ScrollData():
 
        scrollBar( NULL ),
 
        position( ScrollZoomer::OppositeToScale ),
 
        mode( Qt::ScrollBarAsNeeded )
 
    {
 
    }
 

	
 
    ~ScrollData()
 
    {
 
        delete scrollBar;
 
    }
 

	
 
    ScrollBar *scrollBar;
 
    ScrollZoomer::ScrollBarPosition position;
 
    Qt::ScrollBarPolicy mode;
 
};
 

	
 
ScrollZoomer::ScrollZoomer( QWidget *canvas ):
 
    QwtPlotZoomer( canvas ),
 
    d_cornerWidget( NULL ),
 
    d_hScrollData( NULL ),
 
    d_vScrollData( NULL ),
 
    d_inZoom( false )
 
{
 
    d_limits = QRectF(0, -10, 10000, 20);
 
    xMin = 0.;
 
    xMax = 10000.;
 

	
 
    for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
 
        d_alignCanvasToScales[ axis ] = false;
 

	
 
    if ( !canvas )
 
        return;
 

	
 
    d_hScrollData = new ScrollData;
 
    d_vScrollData = new ScrollData;
 
}
 

	
 
ScrollZoomer::~ScrollZoomer()
 
{
 
    delete d_cornerWidget;
 
    delete d_vScrollData;
 
    delete d_hScrollData;
 
}
 

	
 
void ScrollZoomer::rescale()
 
{
 
    qDebug() << "rescale";
 

	
 
    QwtScaleWidget *xScale = plot()->axisWidget( xAxis() );
 
    QwtScaleWidget *yScale = plot()->axisWidget( yAxis() );
 

	
 
    if ( zoomRectIndex() <= 0 )
 
    {
 
        if ( d_inZoom )
 
        {
 
            xScale->setMinBorderDist( 0, 0 );
 
            yScale->setMinBorderDist( 0, 0 );
 

	
 
            QwtPlotLayout *layout = plot()->plotLayout();
 

	
 
            for ( int axis = 0; axis < QwtPlot::axisCnt; axis++ )
 
                layout->setAlignCanvasToScale( axis, d_alignCanvasToScales[ axis ] );
 

	
 
            d_inZoom = false;
 
        }
 
    }
 
    else
 
    {
 
        if ( !d_inZoom )
 
        {
 
            /*
 
             We set a minimum border distance.
 
             Otherwise the canvas size changes when scrolling,
 
             between situations where the major ticks are at
 
@@ -229,189 +231,184 @@ bool ScrollZoomer::eventFilter( QObject 
 
    {
 
        switch( event->type() )
 
        {
 
            case QEvent::Resize:
 
            {
 
                int left, top, right, bottom;
 
                canvas()->getContentsMargins( &left, &top, &right, &bottom );
 

	
 
                QRect rect;
 
                rect.setSize( static_cast<QResizeEvent *>( event )->size() );
 
                rect.adjust( left, top, -right, -bottom );
 

	
 
                layoutScrollBars( rect );
 
                break;
 
            }
 
            case QEvent::Show:
 
            {
 
                layoutScrollBars( canvas()->contentsRect() );
 
                break;
 
            }
 
            case QEvent::ChildRemoved:
 
            {
 
                const QObject *child =
 
                    static_cast<QChildEvent *>( event )->child();
 

	
 
                if ( child == d_cornerWidget )
 
                    d_cornerWidget = NULL;
 
                else if ( child == d_hScrollData->scrollBar )
 
                    d_hScrollData->scrollBar = NULL;
 
                else if ( child == d_vScrollData->scrollBar )
 
                    d_vScrollData->scrollBar = NULL;
 
                break;
 
            }
 
            default:
 
                break;
 
        }
 
    }
 
    return QwtPlotZoomer::eventFilter( object, event );
 
}
 

	
 
bool ScrollZoomer::needScrollBar( Qt::Orientation orientation ) const
 
{
 
    Qt::ScrollBarPolicy mode;
 
    double zoomMin, zoomMax, baseMin, baseMax;
 

	
 
    if ( orientation == Qt::Horizontal )
 
    {
 
        mode = d_hScrollData->mode;
 
        // baseMin = zoomBase().left();
 
        // baseMax = zoomBase().right();
 
        baseMin = d_limits.left();
 
        baseMax = d_limits.right();
 
        baseMin = xMin;
 
        baseMax = xMax;
 
        zoomMin = zoomRect().left();
 
        zoomMax = zoomRect().right();
 
    }
 
    else
 
    {
 
        mode = d_vScrollData->mode;
 
        // baseMin = zoomBase().top();
 
        // baseMax = zoomBase().bottom();
 
        baseMin = d_limits.top();
 
        baseMax = d_limits.bottom();
 
        baseMin = zoomBase().top();
 
        baseMax = zoomBase().bottom();
 
        zoomMin = zoomRect().top();
 
        zoomMax = zoomRect().bottom();
 
    }
 

	
 
    bool needed = false;
 
    switch( mode )
 
    {
 
        case Qt::ScrollBarAlwaysOn:
 
            needed = true;
 
            break;
 
        case Qt::ScrollBarAlwaysOff:
 
            needed = false;
 
            break;
 
        default:
 
        {
 
            if ( baseMin < zoomMin || baseMax > zoomMax )
 
                needed = true;
 
            break;
 
        }
 
    }
 
    return needed;
 
}
 

	
 
void ScrollZoomer::updateScrollBars()
 
{
 
    qDebug() << "updateScrollBars()";
 

	
 
    if ( !canvas() )
 
        return;
 

	
 
    const int xAxis = QwtPlotZoomer::xAxis();
 
    const int yAxis = QwtPlotZoomer::yAxis();
 

	
 
    int xScrollBarAxis = xAxis;
 
    if ( hScrollBarPosition() == OppositeToScale )
 
        xScrollBarAxis = oppositeAxis( xScrollBarAxis );
 

	
 
    int yScrollBarAxis = yAxis;
 
    if ( vScrollBarPosition() == OppositeToScale )
 
        yScrollBarAxis = oppositeAxis( yScrollBarAxis );
 

	
 

	
 
    QwtPlotLayout *layout = plot()->plotLayout();
 

	
 
    bool showHScrollBar = needScrollBar( Qt::Horizontal );
 
    if ( showHScrollBar )
 
    {
 
        ScrollBar *sb = scrollBar( Qt::Horizontal );
 
        sb->setPalette( plot()->palette() );
 
        sb->setInverted( !plot()->axisScaleDiv( xAxis ).isIncreasing() );
 
        // sb->setBase( zoomBase().left(), zoomBase().right() );
 
        sb->setBase( d_limits.left(), d_limits.right() );
 
        sb->setBase( xMin, xMax );
 
        sb->moveSlider( zoomRect().left(), zoomRect().right() );
 
        qDebug() << "moveSlider" << zoomRect().left() << zoomRect().right();
 

	
 
        if ( !sb->isVisibleTo( canvas() ) )
 
        {
 
            sb->show();
 
            layout->setCanvasMargin( layout->canvasMargin( xScrollBarAxis )
 
                + sb->extent(), xScrollBarAxis );
 
        }
 
    }
 
    else
 
    {
 
        if ( horizontalScrollBar() )
 
        {
 
            horizontalScrollBar()->hide();
 
            layout->setCanvasMargin( layout->canvasMargin( xScrollBarAxis )
 
                - horizontalScrollBar()->extent(), xScrollBarAxis );
 
        }
 
    }
 

	
 
    bool showVScrollBar = needScrollBar( Qt::Vertical );
 
    if ( showVScrollBar )
 
    {
 
        ScrollBar *sb = scrollBar( Qt::Vertical );
 
        sb->setPalette( plot()->palette() );
 
        sb->setInverted( plot()->axisScaleDiv( yAxis ).isIncreasing() );
 
        sb->setBase( d_limits.top(), d_limits.bottom() );
 
        sb->setBase( zoomRect().top(), zoomRect().bottom() );
 
        sb->moveSlider( zoomRect().top(), zoomRect().bottom() );
 

	
 
        if ( !sb->isVisibleTo( canvas() ) )
 
        {
 
            sb->show();
 
            layout->setCanvasMargin( layout->canvasMargin( yScrollBarAxis )
 
                + sb->extent(), yScrollBarAxis );
 
        }
 
    }
 
    else
 
    {
 
        if ( verticalScrollBar() )
 
        {
 
            verticalScrollBar()->hide();
 
            layout->setCanvasMargin( layout->canvasMargin( yScrollBarAxis )
 
                - verticalScrollBar()->extent(), yScrollBarAxis );
 
        }
 
    }
 

	
 
    if ( showHScrollBar && showVScrollBar )
 
    {
 
        if ( d_cornerWidget == NULL )
 
        {
 
            d_cornerWidget = new QWidget( canvas() );
 
            d_cornerWidget->setAutoFillBackground( true );
 
            d_cornerWidget->setPalette( plot()->palette() );
 
        }
 
        d_cornerWidget->show();
 
    }
 
    else
 
    {
 
        if ( d_cornerWidget )
 
            d_cornerWidget->hide();
 
    }
 

	
 
    layoutScrollBars( canvas()->contentsRect() );
 
    plot()->updateLayout();
 
}
 

	
 
void ScrollZoomer::layoutScrollBars( const QRect &rect )
 
{
 
    qDebug() << "layoutScrollBars" << rect;
 

	
 
    int hPos = xAxis();
 
    if ( hScrollBarPosition() == OppositeToScale )
 
        hPos = oppositeAxis( hPos );
 

	
 
    int vPos = yAxis();
 
@@ -470,69 +467,66 @@ void ScrollZoomer::layoutScrollBars( con
 
            QRect cornerRect(
 
                vScrollBar->pos().x(), hScrollBar->pos().y(),
 
                vdim, hdim );
 
            d_cornerWidget->setGeometry( cornerRect );
 
        }
 
    }
 
}
 

	
 
void ScrollZoomer::scrollBarMoved(
 
    Qt::Orientation o, double min, double max )
 
{
 
    Q_UNUSED( max );
 

	
 
    if ( o == Qt::Horizontal )
 
        moveTo( QPointF( min, zoomRect().top() ) );
 
    else
 
        moveTo( QPointF( zoomRect().left(), min ) );
 

	
 
    Q_EMIT zoomed( zoomRect() );
 
}
 

	
 
int ScrollZoomer::oppositeAxis( int axis ) const
 
{
 
    switch( axis )
 
    {
 
        case QwtPlot::xBottom:
 
            return QwtPlot::xTop;
 
        case QwtPlot::xTop:
 
            return QwtPlot::xBottom;
 
        case QwtPlot::yLeft:
 
            return QwtPlot::yRight;
 
        case QwtPlot::yRight:
 
            return QwtPlot::yLeft;
 
        default:
 
            break;
 
    }
 

	
 
    return axis;
 
}
 

	
 
void ScrollZoomer::moveTo( const QPointF &pos )
 
{
 
    // QwtPlotZoomer::moveTo(pos);
 
    // return;
 

	
 
    double x = pos.x();
 
    double y = pos.y();
 

	
 
    if ( x < d_limits.left() )
 
        x = d_limits.left();
 
    if ( x > d_limits.right() - zoomRect().width() )
 
        x = d_limits.right() - zoomRect().width();
 
    if ( x < xMin )
 
        x = xMin;
 
    if ( x > xMax - zoomRect().width() )
 
        x = xMax - zoomRect().width();
 

	
 
    if ( y < d_limits.top() )
 
        y = d_limits.top();
 
    if ( y > d_limits.bottom() - zoomRect().height() )
 
        y = d_limits.bottom() - zoomRect().height();
 

	
 
    qDebug() << "x,y: "<<x<<y;
 
    if ( y < zoomBase().top() )
 
        y = zoomBase().top();
 
    if ( y > zoomBase().bottom() - zoomRect().height() )
 
        y = zoomBase().bottom() - zoomRect().height();
 

	
 
    if ( x != zoomRect().left() || y != zoomRect().top() )
 
    {
 
        auto zs = zoomStack();
 
        zs[zoomRectIndex()].moveTo( x, y );
 
        // d_data->zoomStack[d_data->zoomRectIndex].moveTo( x, y );
 
        setZoomStack(zs, zoomRectIndex());
 
        rescale();
 
    }
 
}
src/scrollzoomer.h
Show inline comments
 
/*
 
  Copyright © 2014 Uwe Rathmann
 

	
 
  This file is copied from Qwt project; you can redistribute it and/or modify it
 
  under the terms of the Qwt License, Version 1.0. You can obtain the original
 
  source code and the details of the Qwt License from the Qwt website:
 
  http://qwt.sourceforge.net/
 
*/
 

	
 
#ifndef _SCROLLZOOMER_H
 
#define _SCROLLZOOMER_H
 

	
 
#include <qglobal.h>
 
#include <qwt_plot_zoomer.h>
 
#include <qwt_plot.h>
 

	
 
class ScrollData;
 
class ScrollBar;
 

	
 
class ScrollZoomer: public QwtPlotZoomer
 
{
 
    Q_OBJECT
 
public:
 
    enum ScrollBarPosition
 
    {
 
        AttachedToScale,
 
        OppositeToScale
 
    };
 

	
 
    ScrollZoomer( QWidget * );
 
    virtual ~ScrollZoomer();
 

	
 
    ScrollBar *horizontalScrollBar() const;
 
    ScrollBar *verticalScrollBar() const;
 

	
 
    void setHScrollBarMode( Qt::ScrollBarPolicy );
 
    void setVScrollBarMode( Qt::ScrollBarPolicy );
 

	
 
    Qt::ScrollBarPolicy vScrollBarMode () const;
 
    Qt::ScrollBarPolicy hScrollBarMode () const;
 

	
 
    void setHScrollBarPosition( ScrollBarPosition );
 
    void setVScrollBarPosition( ScrollBarPosition );
 

	
 
    ScrollBarPosition hScrollBarPosition() const;
 
    ScrollBarPosition vScrollBarPosition() const;
 

	
 
    void setXLimits(double min, double max);
 

	
 
    QWidget* cornerWidget() const;
 
    virtual void setCornerWidget( QWidget * );
 

	
 
    virtual bool eventFilter( QObject *, QEvent * );
 

	
 
    virtual void rescale();
 

	
 
public Q_SLOTS:
 
    virtual void moveTo( const QPointF & );
 

	
 
protected:
 
    virtual ScrollBar *scrollBar( Qt::Orientation );
 
    virtual void updateScrollBars();
 
    virtual void layoutScrollBars( const QRect & );
 

	
 
private Q_SLOTS:
 
    void scrollBarMoved( Qt::Orientation o, double min, double max );
 

	
 
private:
 
    QRectF d_limits;
 
    double xMin, xMax;
 

	
 
    bool needScrollBar( Qt::Orientation ) const;
 
    int oppositeAxis( int ) const;
 

	
 
    QWidget *d_cornerWidget;
 

	
 
    ScrollData *d_hScrollData;
 
    ScrollData *d_vScrollData;
 

	
 
    bool d_inZoom;
 
    bool d_alignCanvasToScales[ QwtPlot::axisCnt ];
 
};
 

	
 
#endif
0 comments (0 inline, 0 general)