Files
GoldenCheetah/qwt/examples/realtime/ScrollZoomer.cpp
Joachim Kohlhammer 49cf6340a4 Upgraded Qwt to 6.2 (branch: qwt-multiaxes) (#4427)
This commit is based on https://github.com/GoldenCheetah/GoldenCheetah/pull/3956
with the following additions / changes:
* Upgraded to the latest version of the multiaxes-branch, thus eliminating crashes of GoldenCheetah on startup
* Disabled the emitting of Layout Requests on geometry changes of QwtScaleWidget - without this, CPU utilization was up to 100% on one core
* Added the class SplineLookup, reusing small portions of code from Qwt 6.1
* Re-added the splines in WPrime and RideFile (resampling), using the new interface of QwtSpline
* Appveyor: qwt in cache-section now depends on qwt/qwtconfig.prin.in for refresh on version change
2024-01-06 18:59:55 -03:00

504 lines
12 KiB
C++

/*****************************************************************************
* Qwt Examples - Copyright (C) 2002 Uwe Rathmann
* This file may be used under the terms of the 3-clause BSD License
*****************************************************************************/
#include "ScrollZoomer.h"
#include "ScrollBar.h"
#include <QwtPlotLayout>
#include <QwtScaleWidget>
#include <QResizeEvent>
#include <QMargins>
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 )
, m_cornerWidget( NULL )
, m_hScrollData( NULL )
, m_vScrollData( NULL )
, m_inZoom( false )
{
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
m_alignCanvasToScales[ axisPos ] = false;
if ( !canvas )
return;
m_hScrollData = new ScrollData;
m_vScrollData = new ScrollData;
}
ScrollZoomer::~ScrollZoomer()
{
delete m_cornerWidget;
delete m_vScrollData;
delete m_hScrollData;
}
void ScrollZoomer::rescale()
{
QwtScaleWidget* xScale = plot()->axisWidget( xAxis() );
QwtScaleWidget* yScale = plot()->axisWidget( yAxis() );
if ( zoomRectIndex() <= 0 )
{
if ( m_inZoom )
{
xScale->setMinBorderDist( 0, 0 );
yScale->setMinBorderDist( 0, 0 );
QwtPlotLayout* layout = plot()->plotLayout();
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
layout->setAlignCanvasToScale( axisPos, m_alignCanvasToScales[ axisPos ] );
m_inZoom = false;
}
}
else
{
if ( !m_inZoom )
{
/*
We set a minimum border distance.
Otherwise the canvas size changes when scrolling,
between situations where the major ticks are at
the canvas borders (requiring extra space for the label)
and situations where all labels can be painted below/top
or left/right of the canvas.
*/
int start, end;
xScale->getBorderDistHint( start, end );
xScale->setMinBorderDist( start, end );
yScale->getBorderDistHint( start, end );
yScale->setMinBorderDist( start, end );
QwtPlotLayout* layout = plot()->plotLayout();
for ( int axisPos = 0; axisPos < QwtAxis::AxisPositions; axisPos++ )
{
m_alignCanvasToScales[axisPos] =
layout->alignCanvasToScale( axisPos );
}
layout->setAlignCanvasToScales( false );
m_inZoom = true;
}
}
QwtPlotZoomer::rescale();
updateScrollBars();
}
ScrollBar* ScrollZoomer::scrollBar( Qt::Orientation orientation )
{
ScrollBar*& sb = ( orientation == Qt::Vertical )
? m_vScrollData->scrollBar : m_hScrollData->scrollBar;
if ( sb == NULL )
{
sb = new ScrollBar( orientation, canvas() );
sb->hide();
connect( sb,
SIGNAL(valueChanged(Qt::Orientation,double,double)),
SLOT(scrollBarMoved(Qt::Orientation,double,double)) );
}
return sb;
}
ScrollBar* ScrollZoomer::horizontalScrollBar() const
{
return m_hScrollData->scrollBar;
}
ScrollBar* ScrollZoomer::verticalScrollBar() const
{
return m_vScrollData->scrollBar;
}
void ScrollZoomer::setHScrollBarMode( Qt::ScrollBarPolicy mode )
{
if ( hScrollBarMode() != mode )
{
m_hScrollData->mode = mode;
updateScrollBars();
}
}
void ScrollZoomer::setVScrollBarMode( Qt::ScrollBarPolicy mode )
{
if ( vScrollBarMode() != mode )
{
m_vScrollData->mode = mode;
updateScrollBars();
}
}
Qt::ScrollBarPolicy ScrollZoomer::hScrollBarMode() const
{
return m_hScrollData->mode;
}
Qt::ScrollBarPolicy ScrollZoomer::vScrollBarMode() const
{
return m_vScrollData->mode;
}
void ScrollZoomer::setHScrollBarPosition( ScrollBarPosition pos )
{
if ( m_hScrollData->position != pos )
{
m_hScrollData->position = pos;
updateScrollBars();
}
}
void ScrollZoomer::setVScrollBarPosition( ScrollBarPosition pos )
{
if ( m_vScrollData->position != pos )
{
m_vScrollData->position = pos;
updateScrollBars();
}
}
ScrollZoomer::ScrollBarPosition ScrollZoomer::hScrollBarPosition() const
{
return m_hScrollData->position;
}
ScrollZoomer::ScrollBarPosition ScrollZoomer::vScrollBarPosition() const
{
return m_vScrollData->position;
}
void ScrollZoomer::setCornerWidget( QWidget* w )
{
if ( w != m_cornerWidget )
{
if ( canvas() )
{
delete m_cornerWidget;
m_cornerWidget = w;
if ( m_cornerWidget->parent() != canvas() )
m_cornerWidget->setParent( canvas() );
updateScrollBars();
}
}
}
QWidget* ScrollZoomer::cornerWidget() const
{
return m_cornerWidget;
}
bool ScrollZoomer::eventFilter( QObject* object, QEvent* event )
{
if ( object == canvas() )
{
switch( event->type() )
{
case QEvent::Resize:
{
const QMargins m = canvas()->contentsMargins();
QRect rect;
rect.setSize( static_cast< QResizeEvent* >( event )->size() );
rect.adjust( m.left(), m.top(), -m.right(), -m.bottom() );
layoutScrollBars( rect );
break;
}
case QEvent::ChildRemoved:
{
const QObject* child =
static_cast< QChildEvent* >( event )->child();
if ( child == m_cornerWidget )
{
m_cornerWidget = NULL;
}
else if ( child == m_hScrollData->scrollBar )
{
m_hScrollData->scrollBar = NULL;
}
else if ( child == m_vScrollData->scrollBar )
{
m_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 = m_hScrollData->mode;
baseMin = zoomBase().left();
baseMax = zoomBase().right();
zoomMin = zoomRect().left();
zoomMax = zoomRect().right();
}
else
{
mode = m_vScrollData->mode;
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()
{
if ( !canvas() )
return;
const int xAxis = QwtPlotZoomer::xAxis().pos;
const int yAxis = QwtPlotZoomer::yAxis().pos;
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->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( zoomBase().top(), zoomBase().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 ( m_cornerWidget == NULL )
{
m_cornerWidget = new QWidget( canvas() );
m_cornerWidget->setAutoFillBackground( true );
m_cornerWidget->setPalette( plot()->palette() );
}
m_cornerWidget->show();
}
else
{
if ( m_cornerWidget )
m_cornerWidget->hide();
}
layoutScrollBars( canvas()->contentsRect() );
plot()->updateLayout();
}
void ScrollZoomer::layoutScrollBars( const QRect& rect )
{
int hPos = xAxis().pos;
if ( hScrollBarPosition() == OppositeToScale )
hPos = oppositeAxis( hPos );
int vPos = yAxis().pos;
if ( vScrollBarPosition() == OppositeToScale )
vPos = oppositeAxis( vPos );
ScrollBar* hScrollBar = horizontalScrollBar();
ScrollBar* vScrollBar = verticalScrollBar();
const int hdim = hScrollBar ? hScrollBar->extent() : 0;
const int vdim = vScrollBar ? vScrollBar->extent() : 0;
if ( hScrollBar && hScrollBar->isVisible() )
{
int x = rect.x();
int y = ( hPos == QwtAxis::XTop )
? rect.top() : rect.bottom() - hdim + 1;
int w = rect.width();
if ( vScrollBar && vScrollBar->isVisible() )
{
if ( vPos == QwtAxis::YLeft )
x += vdim;
w -= vdim;
}
hScrollBar->setGeometry( x, y, w, hdim );
}
if ( vScrollBar && vScrollBar->isVisible() )
{
int pos = yAxis().pos;
if ( vScrollBarPosition() == OppositeToScale )
pos = oppositeAxis( pos );
int x = ( vPos == QwtAxis::YLeft )
? rect.left() : rect.right() - vdim + 1;
int y = rect.y();
int h = rect.height();
if ( hScrollBar && hScrollBar->isVisible() )
{
if ( hPos == QwtAxis::XTop )
y += hdim;
h -= hdim;
}
vScrollBar->setGeometry( x, y, vdim, h );
}
if ( hScrollBar && hScrollBar->isVisible() &&
vScrollBar && vScrollBar->isVisible() )
{
if ( m_cornerWidget )
{
QRect cornerRect(
vScrollBar->pos().x(), hScrollBar->pos().y(),
vdim, hdim );
m_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
{
using namespace QwtAxis;
switch( axis )
{
case XBottom:
return XTop;
case XTop:
return XBottom;
case YLeft:
return YRight;
case YRight:
return YLeft;
default:
;
}
return axis;
}
#include "moc_ScrollZoomer.cpp"