wheel event handling improved

This commit is contained in:
Uwe Rathmann 2022-01-05 11:59:32 +01:00
parent 911847da11
commit e67cccc088
12 changed files with 162 additions and 142 deletions

View File

@ -6,6 +6,7 @@
#include "QskBoundedInput.h"
#include "QskFunctions.h"
#include "QskIntervalF.h"
#include "QskEvent.h"
#include <cmath>
@ -200,19 +201,13 @@ void QskBoundedInput::keyPressEvent( QKeyEvent* event )
void QskBoundedInput::wheelEvent( QWheelEvent* event )
{
if ( isReadOnly() )
if ( !isReadOnly() )
{
increment( qskWheelSteps( event ) * m_stepSize );
return;
}
#if QT_VERSION < 0x050e00
const int wheelDelta = event->delta();
#else
const auto delta = event->angleDelta();
const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
? delta.x() : delta.y();
#endif
const int steps = wheelDelta / QWheelEvent::DefaultDeltasPerStep;
increment( steps * m_stepSize );
Inherited::wheelEvent( event );
}
#endif

View File

@ -63,6 +63,17 @@ QPointF qskMouseScenePosition( const QMouseEvent* event )
#endif
}
QPointF qskHoverPosition( const QHoverEvent* event )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
return event->position();
#else
return event->posF();
#endif
}
#ifndef QT_NO_WHEELEVENT
QPointF qskWheelPosition( const QWheelEvent* event )
{
#if QT_VERSION >= QT_VERSION_CHECK( 5, 14, 0 )
@ -72,15 +83,60 @@ QPointF qskWheelPosition( const QWheelEvent* event )
#endif
}
QPointF qskHoverPosition( const QHoverEvent* event )
{
#if QT_VERSION >= QT_VERSION_CHECK( 6, 0, 0 )
return event->position();
#else
return event->posF();
#endif
#ifndef QT_NO_WHEELEVENT
qreal qskWheelSteps( const QWheelEvent* event, int orientation )
{
qreal delta = 0.0;
// what about event->pixelDelta()
auto aDelta = event->angleDelta();
#if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 )
if ( event->inverted() )
aDelta.setY( -aDelta.y() );
#endif
switch( orientation )
{
case Qt::Horizontal:
delta = aDelta.x();
break;
case Qt::Vertical:
delta = aDelta.y();
break;
default:
delta = aDelta.y() ? aDelta.y() : aDelta.x();
}
return delta / QWheelEvent::DefaultDeltasPerStep;
}
#endif
#ifndef QT_NO_WHEELEVENT
QPointF qskScrollIncrement( const QWheelEvent* event )
{
QPointF increment = event->pixelDelta();
if ( increment.isNull() )
{
increment = event->angleDelta() / QWheelEvent::DefaultDeltasPerStep;
constexpr qreal stepSize = 20.0; // how to find this value ???
increment *= stepSize;
}
return increment;
}
#endif
QskEvent::QskEvent( QskEvent::Type type )
: QEvent( static_cast< QEvent::Type >( type ) )
{

View File

@ -138,7 +138,16 @@ QSK_EXPORT int qskFocusChainIncrement( const QEvent* );
// some helper to work around Qt version incompatibilities
QSK_EXPORT QPointF qskMouseScenePosition( const QMouseEvent* );
QSK_EXPORT QPointF qskMousePosition( const QMouseEvent* );
QSK_EXPORT QPointF qskWheelPosition( const QWheelEvent* );
QSK_EXPORT QPointF qskHoverPosition( const QHoverEvent* );
#ifndef QT_NO_WHEELEVENT
QSK_EXPORT QPointF qskWheelPosition( const QWheelEvent* );
QSK_EXPORT qreal qskWheelSteps(
const QWheelEvent*, int orientation = 0 );
QSK_EXPORT QPointF qskScrollIncrement( const QWheelEvent* );
#endif
#endif

View File

@ -156,12 +156,14 @@ bool QskInputGrabber::event( QEvent* event )
doBlock = isBlocking( qskMousePosition( mouseEvent ) );
break;
}
#ifndef QT_NO_WHEELEVENT
case QEvent::Wheel:
{
const auto wheelEvent = static_cast< QWheelEvent* >( event );
doBlock = isBlocking( qskWheelPosition( wheelEvent ) );
break;
}
#endif
case QEvent::HoverEnter:
case QEvent::HoverLeave:
{

View File

@ -233,18 +233,16 @@ void QskMenu::keyReleaseEvent( QKeyEvent* )
}
}
#ifndef QT_NO_WHEELEVENT
void QskMenu::wheelEvent( QWheelEvent* event )
{
#if QT_VERSION < 0x050e00
const int delta = event->delta();
#else
const int delta = event->angleDelta().y();
#endif
// we ignore the step count and use its direction only
traverse( delta < 0 ? 1 : -1 );
const auto steps = qskWheelSteps( event );
traverse( -steps );
}
#endif
void QskMenu::traverse( int steps )
{
if ( count() == 0 || ( steps % count() == 0 ) )

View File

@ -83,7 +83,10 @@ class QSK_EXPORT QskMenu : public QskPopup
protected:
void keyPressEvent( QKeyEvent* ) override;
void keyReleaseEvent( QKeyEvent* ) override;
#ifndef QT_NO_WHEELEVENT
void wheelEvent( QWheelEvent* ) override;
#endif
void mousePressEvent( QMouseEvent* ) override;
void mouseReleaseEvent( QMouseEvent* ) override;

View File

@ -12,18 +12,6 @@ QSK_SUBCONTROL( QskPageIndicator, Bullet )
QSK_SYSTEM_STATE( QskPageIndicator, Selected, QskAspect::FirstSystemState << 1 )
static void qskSetMouseAccepted( QskPageIndicator* indicator, bool on )
{
auto buttons = indicator->acceptedMouseButtons();
if ( on )
buttons |= Qt::LeftButton;
else
buttons &= ~Qt::LeftButton;
indicator->setAcceptedMouseButtons( buttons );
}
static int qskKeyIncrement(
const QskPageIndicator* indicator, const QKeyEvent* event )
{
@ -63,7 +51,6 @@ class QskPageIndicator::PrivateData
public:
PrivateData( int count )
: count( count )
, interactive( false )
, orientation( Qt::Horizontal )
{
}
@ -72,8 +59,6 @@ class QskPageIndicator::PrivateData
int pressedIndex = -1;
int count;
bool interactive : 1;
Qt::Orientation orientation : 2;
};
@ -122,29 +107,6 @@ void QskPageIndicator::setOrientation( Qt::Orientation orientation )
}
}
bool QskPageIndicator::isInteractive() const
{
return m_data->interactive;
}
void QskPageIndicator::setInteractive( bool on )
{
if ( on == m_data->interactive )
return;
m_data->interactive = on;
qskSetMouseAccepted( this, on );
setWheelEnabled( on );
setFocusPolicy( on ? Qt::StrongFocus : Qt::NoFocus );
// being interactive might have an impact on its representation
resetImplicitSize();
update();
Q_EMIT interactiveChanged( on );
}
void QskPageIndicator::setCount( int count )
{
if ( count != m_data->count )
@ -209,6 +171,13 @@ void QskPageIndicator::mousePressEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
{
/*
The bullets are usually small and therefore hard to click - with
touch input almost impossible. It might be better to
increment in direction of the mouse position ?
A swipe gesture might make more sense, TODO ...
*/
const auto pos = qskMousePosition( event );
m_data->pressedIndex = indexAtPosition( pos );
@ -218,6 +187,11 @@ void QskPageIndicator::mousePressEvent( QMouseEvent* event )
return Inherited::mousePressEvent( event );
}
void QskPageIndicator::mouseUngrabEvent()
{
m_data->pressedIndex = -1;
}
void QskPageIndicator::mouseReleaseEvent( QMouseEvent* event )
{
if ( event->button() == Qt::LeftButton )
@ -242,40 +216,41 @@ void QskPageIndicator::keyPressEvent( QKeyEvent* event )
{
if ( const int increment = qskKeyIncrement( this, event ) )
{
if ( const auto n = m_data->count )
{
int index = m_data->currentIndex;
if ( index < 0 && increment < 0 )
index = n;
// do we need an cycling on/off attribute, TODO ...
index = ( index + increment ) % n;
if ( index < 0 )
index += n;
Q_EMIT pageRequested( index );
}
incrementRequested( increment );
return;
}
Inherited::keyPressEvent( event );
}
#ifndef QT_NO_WHEELEVENT
void QskPageIndicator::wheelEvent( QWheelEvent* event )
{
#if QT_VERSION < 0x050e00
const int delta = event->delta();
#else
const auto angleDelta = event->angleDelta();
incrementRequested( qskWheelSteps( event ) );
}
const int delta = ( orientation() == Qt::Horizontal )
? angleDelta.x() : angleDelta.y();
#endif
Q_UNUSED( delta )
// TODO ...
void QskPageIndicator::incrementRequested( int offset )
{
const auto n = m_data->count;
if ( offset == 0 || n == 0 )
return;
int index = m_data->currentIndex;
if ( index < 0 && offset < 0 )
index = n;
// do we need a cycling on/off attribute, TODO ...
index = ( index + offset ) % n;
if ( index < 0 )
index += n;
if ( index != m_data->currentIndex )
Q_EMIT pageRequested( index );
}
#include "moc_QskPageIndicator.cpp"

View File

@ -18,9 +18,6 @@ class QSK_EXPORT QskPageIndicator : public QskControl
Q_PROPERTY( qreal currentIndex READ currentIndex
WRITE setCurrentIndex NOTIFY currentIndexChanged FINAL )
Q_PROPERTY( bool interactive READ isInteractive
WRITE setInteractive NOTIFY interactiveChanged FINAL )
Q_PROPERTY( Qt::Orientation orientation READ orientation
WRITE setOrientation NOTIFY orientationChanged FINAL )
@ -63,12 +60,18 @@ class QSK_EXPORT QskPageIndicator : public QskControl
protected:
void mousePressEvent( QMouseEvent* e ) override;
void mouseUngrabEvent() override;
void mouseReleaseEvent( QMouseEvent* e ) override;
void keyPressEvent( QKeyEvent* ) override;
#ifndef QT_NO_WHEELEVENT
void wheelEvent( QWheelEvent* ) override;
#endif
private:
void incrementRequested( int );
class PrivateData;
std::unique_ptr< PrivateData > m_data;
};

View File

@ -400,40 +400,14 @@ void QskScrollBox::gestureEvent( QskGestureEvent* event )
#ifndef QT_NO_WHEELEVENT
QPointF QskScrollBox::scrollOffset( const QWheelEvent* event ) const
{
#if QT_VERSION < 0x050e00
const auto pos = event->posF();
#else
const auto pos = event->position();
#endif
if ( viewContentsRect().contains( pos ) )
{
/*
Not sure if that code makes sense, but I don't have an input device
that generates wheel events in both directions. TODO ...
*/
return event->angleDelta();
}
return QPointF();
}
void QskScrollBox::wheelEvent( QWheelEvent* event )
{
QPointF offset = scrollOffset( event );
if ( !offset.isNull() )
const auto pos = qskWheelPosition( event );
if ( viewContentsRect().contains( pos ) )
{
constexpr qreal stepSize = 20.0; // how to find this value
offset *= stepSize / QWheelEvent::DefaultDeltasPerStep;
#if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 )
if ( event->inverted() )
offset = -offset;
#endif
setScrollPos( m_data->scrollPos - offset );
const auto offset = qskScrollIncrement( event );
if ( !offset.isNull() )
setScrollPos( m_data->scrollPos - offset );
}
}

View File

@ -68,7 +68,6 @@ class QSK_EXPORT QskScrollBox : public QskControl
#ifndef QT_NO_WHEELEVENT
void wheelEvent( QWheelEvent* ) override;
virtual QPointF scrollOffset( const QWheelEvent* ) const;
#endif
bool gestureFilter( QQuickItem*, QEvent* ) override;

View File

@ -209,34 +209,40 @@ void QskScrollView::mouseReleaseEvent( QMouseEvent* event )
#ifndef QT_NO_WHEELEVENT
QPointF QskScrollView::scrollOffset( const QWheelEvent* event ) const
void QskScrollView::wheelEvent( QWheelEvent* event )
{
QPointF offset;
const auto wheelPos = qskWheelPosition( event );
const auto pos = qskWheelPosition( event );
#if QT_VERSION < QT_VERSION_CHECK( 5, 14, 0 )
const auto wheelDelta = event->delta();
#else
const QPoint delta = event->angleDelta();
const int wheelDelta = ( qAbs( delta.x() ) > qAbs( delta.y() ) )
? delta.x() : delta.y();
if ( subControlRect( VerticalScrollBar ).contains( pos ) )
{
const auto increment = qskScrollIncrement( event );
offset.setY( increment.y() );
}
else if ( subControlRect( HorizontalScrollBar ).contains( pos ) )
{
const auto increment = qskScrollIncrement( event );
qreal dx = increment.x();
if ( dx == 0 )
{
dx = increment.y();
#if QT_VERSION >= QT_VERSION_CHECK( 5, 7, 0 )
if ( event->inverted() )
dx = -dx;
#endif
if ( subControlRect( VerticalScrollBar ).contains( wheelPos ) )
{
offset.setY( wheelDelta );
}
offset.setX( dx );
}
else if ( subControlRect( HorizontalScrollBar ).contains( wheelPos ) )
else if ( viewContentsRect().contains( pos ) )
{
offset.setX( wheelDelta );
}
else
{
offset = Inherited::scrollOffset( event );
offset = qskScrollIncrement( event );
}
return offset;
if ( !offset.isNull() )
setScrollPos( scrollPos() - offset );
}
#endif

View File

@ -53,7 +53,7 @@ class QSK_EXPORT QskScrollView : public QskScrollBox
void mouseReleaseEvent( QMouseEvent* ) override;
#ifndef QT_NO_WHEELEVENT
QPointF scrollOffset( const QWheelEvent* ) const override;
void wheelEvent( QWheelEvent* ) override;
#endif
private: