diff --git a/doc/index.docbook b/doc/index.docbook --- a/doc/index.docbook +++ b/doc/index.docbook @@ -43,8 +43,8 @@ &FDLNotice; -2018-11-09 -1.2.2 (Applications 18.12) +2018-11-23 +1.3.0 (Applications 19.04) @@ -469,7 +469,7 @@ - Here you can set global settings which automatic will be saved when you exit &kmplot;. you can set angle-mode (radians and degrees), zoom in and zoom out factors, and whether to show advanced plot tracing. + Here you can set global settings which automatic will be saved when you exit &kmplot;. You can set angle-mode (radians and degrees), zoom in and zoom out factors for zooming using &Ctrl; with mouse wheel or the corresponding menu items, and whether to show advanced plot tracing. @@ -1214,6 +1214,11 @@ The View Menu The first three items in the menu are related to zooming. + + + The mouse wheel can also be used as a zoom control. To zoom in or out using the mouse, hold down the &Ctrl; key while you turn the mouse wheel. Each tick increases or decreases the zoom factor by the value defined in the &kmplot; General settings. + + diff --git a/kmplot/view.h b/kmplot/view.h --- a/kmplot/view.h +++ b/kmplot/view.h @@ -30,11 +30,13 @@ // Qt includes #include +#include #include #include #include #include #include +#include #include // KDE includes @@ -81,6 +83,7 @@ class View : public QWidget { Q_OBJECT + Q_PROPERTY( QRectF viewport READ getViewport WRITE setViewport ) public: /// Constructor View( bool readOnly, QMenu * functionPopup, QWidget* parent ); @@ -250,6 +253,8 @@ void keyPressEvent(QKeyEvent * ) Q_DECL_OVERRIDE; /// called when a mouse key is released void mouseReleaseEvent ( QMouseEvent * e ) Q_DECL_OVERRIDE; + /// called for zooming with Ctrl+mouse wheel + void wheelEvent(QWheelEvent *event); /// Is needed to be reimplement so that the user can stop a preview-drawing bool event( QEvent * e ) Q_DECL_OVERRIDE; /** @@ -498,7 +503,12 @@ * Positions of the first grid line. */ double ticStartX, ticStartY; - + + /** + * Mouse pointer previous for zooming. + */ + QPoint m_previousMouseMovePos; + QPointF m_crosshairPixelCoords; QPointF m_crosshairPosition; ///< in real coordinates @@ -601,6 +611,8 @@ QPoint m_prevDragMousePos; /// timer that is started when the mouse is pressed QTime * m_mousePressTimer; + /** Current plot viewport. */ + const QRectF getViewport(); /** * The rectangle (in painter, and hence pixel, coordinates) that the @@ -628,6 +640,18 @@ KTextEdit * m_textEdit; ///< Contains m_textDocument QTextDocument * m_textDocument; ///< Used for layout of axis labels + + /// Accumulates mouse or trackpad scrolling to enable Ctrl+mouse wheel scaling on faulty devices + int m_AccumulatedDelta; + + /// Animation for the viewport + QPropertyAnimation * m_viewportAnimation; + + /// Finishes animation of the viewport and get the View back to the Normal mode + void finishAnimation( const QRectF & rect ); + + private slots: + void setViewport( const QRectF & rect ); }; #endif // View_included diff --git a/kmplot/view.cpp b/kmplot/view.cpp --- a/kmplot/view.cpp +++ b/kmplot/view.cpp @@ -87,7 +87,9 @@ : QWidget( parent ), buffer( width(), height() ), m_popupMenu( functionPopup ), - m_readonly( readOnly ) + m_readonly( readOnly ), + m_AccumulatedDelta(0), + m_viewportAnimation( new QPropertyAnimation( this, "viewport" ) ) { assert( !m_self ); // this class should only be constructed once m_self = this; @@ -2972,6 +2974,7 @@ void View::mousePressEvent(QMouseEvent *e) { + m_AccumulatedDelta = 0; m_mousePressTimer->start(); // In general, we want to update the view @@ -3326,6 +3329,12 @@ void View::mouseMoveEvent(QMouseEvent *e) { + if ( m_previousMouseMovePos != e->globalPos() ) + { + m_AccumulatedDelta = 0; + } + m_previousMouseMovePos = e->globalPos(); + m_AccumulatedDelta = 0; if ( m_isDrawing || !e) return; @@ -3392,6 +3401,33 @@ } +void View::wheelEvent(QWheelEvent *e) +{ + m_AccumulatedDelta += e->delta(); + + if (e->modifiers() & Qt::ControlModifier) + { + if (m_AccumulatedDelta >= QWheelEvent::DefaultDeltasPerStep) + { + zoomIn( e->pos(), double(Settings::zoomInStep())/100.0 ); + m_AccumulatedDelta = 0; + } + else if (m_AccumulatedDelta <= -QWheelEvent::DefaultDeltasPerStep) + { + zoomIn( e->pos(), (double(Settings::zoomOutStep())/100.0) + 1.0 ); + m_AccumulatedDelta = 0; + } + e->accept(); + return; + } + else + { + m_AccumulatedDelta = 0; + } + QWidget::wheelEvent(e); +} + + bool View::updateCrosshairPosition() { QPointF mousePos = mapFromGlobal( QCursor::pos() ); @@ -3621,74 +3657,55 @@ m_zoomMode = AnimatingZoom; - double oldCoordsArea = (m_xmax-m_xmin) * (m_ymax-m_ymin); - double newCoordsArea = newCoords.width() * newCoords.height(); - - QPointF beginTL, beginBR, endTL, endBR; - - if ( oldCoordsArea > newCoordsArea ) + if ( style()->styleHint(QStyle::SH_Widget_Animate) && m_viewportAnimation->state() == QAbstractAnimation::Stopped ) { - // zooming in - beginTL = newCoords.topLeft(); - beginBR = newCoords.bottomRight(); - endTL = QPointF( m_xmin, m_ymin ); - endBR = QPointF( m_xmax, m_ymax ); + m_viewportAnimation->setDuration( 150 ); + m_viewportAnimation->setEasingCurve( QEasingCurve::OutCubic ); + m_viewportAnimation->setStartValue( oldCoords ); + m_viewportAnimation->setEndValue( newCoords ); + m_viewportAnimation->start(); + connect(m_viewportAnimation, &QPropertyAnimation::finished, [this, newCoords] + { + finishAnimation( newCoords ); + }); } else - { - // zooming out - beginTL = QPointF( m_xmin, m_ymin ); - beginBR = QPointF( m_xmax, m_ymax ); - - double kx = ( m_xmin - m_xmax ) / ( newCoords.left() - newCoords.right() ); - double ky = ( m_ymin - m_ymax ) / ( newCoords.top() - newCoords.bottom() ); - - double lx = m_xmin - (kx * newCoords.left()); - double ly = m_ymin - (ky * newCoords.top()); - - endTL = QPointF( (kx * m_xmin) + lx, (ky * m_ymin) + ly ); - endBR = QPointF( (kx * m_xmax) + lx, (ky * m_ymax) + ly ); + { + finishAnimation( newCoords ); } + Settings::self()->save(); +} - double MAX = 10; - double ms = MAX*16; // milliseconds to animate for - - for ( int i = 0; i <= MAX; ++i ) - { - QTime t; - t.start(); - - QPointF tl = (( i*endTL) + ((MAX-i)*beginTL)) / MAX; - QPointF br = (( i*endBR) + ((MAX-i)*beginBR)) / MAX; - - m_animateZoomRect = QRectF( tl, QSizeF( br.x()-tl.x(), br.y()-tl.y() ) ); - - repaint(); - - if ( i == MAX ) - break; - else while ( t.elapsed() < (ms/MAX) ) - ; // do nothing - } - - m_xmin = newCoords.left(); - m_xmax = newCoords.right(); - m_ymin = newCoords.top(); - m_ymax = newCoords.bottom(); +void View::finishAnimation( const QRectF & rect ) +{ + m_xmin = rect.left(); + m_xmax = rect.right(); + m_ymin = rect.top(); + m_ymax = rect.bottom(); Settings::setXMin( Parser::number( m_xmin ) ); Settings::setXMax( Parser::number( m_xmax ) ); Settings::setYMin( Parser::number( m_ymin ) ); Settings::setYMax( Parser::number( m_ymax ) ); - Settings::self()->save(); MainDlg::self()->coordsDialog()->updateXYRange(); MainDlg::self()->requestSaveCurrentState(); drawPlot(); //update all graphs m_zoomMode = Normal; } +const QRectF View::getViewport() +{ + return m_animateZoomRect; +} + +void View::setViewport( const QRectF & rect ) +{ + m_animateZoomRect = rect; + repaint(); +} + void View::translateView( int dx, int dy ) {