From 0fd6390800969d174dba819c54c4183a99e8f83c Mon Sep 17 00:00:00 2001 From: Richard Moe Gustavsen Date: Tue, 27 Oct 2009 09:14:28 +0100 Subject: Implement support for wheel delta with finer resolution than 15 deg. At the moment, Qt, in many places, does not really understand that a mouse wheel, or touch pad, might operate on a much higher granularity than 15 degrees (that is, a delta of 120). This is clear disadvantage on mac, since the mighty mouse, and track pad, got a resolution that is close to 1 degree. This is called pixel scrolling. This patch first and formost changes the implementation of QAbstractSlider::wheelEvent to _really_ understand what to do when delta is less than 120. Rather than accumulate delta until 120 is reached, then scroll with a value equal to: offset * step * QApplication::wheelScrollLines (default = 3), we multiply offset directly, before waiting for 120. This means that event tough offset is below 120, multiplying it with wheelScrollLines and step will very often give a value over 120, menaing we can scroll much earlier and _much more_ fined grained. This also fixes some auto tests that was ifdeffed out because of specialised mac code written inside this function from before. (NB: we still plan to introduce a new event for pixel scrolling, perhaps for Qt-4.7) Rev-By: Andreas Rev-By: denis --- src/gui/kernel/qapplication.cpp | 4 -- src/gui/kernel/qapplication_mac.mm | 37 +++--------------- src/gui/kernel/qcocoaview_mac.mm | 24 ++++++------ src/gui/widgets/qabstractslider.cpp | 44 ++++++++++------------ tests/auto/qabstractslider/tst_qabstractslider.cpp | 16 -------- 5 files changed, 38 insertions(+), 87 deletions(-) diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp index 7c38d4b..85b055e 100644 --- a/src/gui/kernel/qapplication.cpp +++ b/src/gui/kernel/qapplication.cpp @@ -940,12 +940,8 @@ void QApplicationPrivate::initialize() graphics_system = QGraphicsSystemFactory::create(graphics_system_name); #endif #ifndef QT_NO_WHEELEVENT -#ifdef Q_OS_MAC - QApplicationPrivate::wheel_scroll_lines = 1; -#else QApplicationPrivate::wheel_scroll_lines = 3; #endif -#endif initializeMultitouch(); } diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm index 771cddc..84e0d50 100644 --- a/src/gui/kernel/qapplication_mac.mm +++ b/src/gui/kernel/qapplication_mac.mm @@ -1697,15 +1697,14 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event // (actually two events; one for horizontal and one for vertical). // As a results of this, and to make sure we dont't receive duplicate events, // we try to detect when this happend by checking the 'compatibilityEvent'. - const int scrollFactor = 4 * 8; SInt32 mdelt = 0; GetEventParameter(event, kEventParamMouseWheelSmoothHorizontalDelta, typeSInt32, 0, sizeof(mdelt), 0, &mdelt); - wheel_deltaX = mdelt * scrollFactor; + wheel_deltaX = mdelt; mdelt = 0; GetEventParameter(event, kEventParamMouseWheelSmoothVerticalDelta, typeSInt32, 0, sizeof(mdelt), 0, &mdelt); - wheel_deltaY = mdelt * scrollFactor; + wheel_deltaY = mdelt; GetEventParameter(event, kEventParamEventRef, typeEventRef, 0, sizeof(compatibilityEvent), 0, &compatibilityEvent); } else if (ekind == kEventMouseWheelMoved) { @@ -1718,31 +1717,11 @@ QApplicationPrivate::globalEventProcessor(EventHandlerCallRef er, EventRef event GetEventParameter(event, kEventParamMouseWheelAxis, typeMouseWheelAxis, 0, sizeof(axis), 0, &axis); - // The 'new' event has acceleration applied by the OS, while the old (on - // Carbon only), has not. So we introduce acceleration here to be consistent. - // The acceleration is trying to respect both pixel based and line scrolling, - // which turns out to be rather difficult. - int linesToScroll = mdelt > 0 ? 1 : -1; - static QTime t; - int elapsed = t.elapsed(); - t.restart(); - if (elapsed < 20) - linesToScroll *= 120; - else if (elapsed < 30) - linesToScroll *= 60; - else if (elapsed < 50) - linesToScroll *= 30; - else if (elapsed < 100) - linesToScroll *= 6; - else if (elapsed < 200) - linesToScroll *= 3; - else if (elapsed < 300) - linesToScroll *= 2; - + // Remove acceleration, and use either -120 or 120 as delta: if (axis == kEventMouseWheelAxisX) - wheel_deltaX = linesToScroll * 120; + wheel_deltaX = qBound(-120, int(mdelt * 10000), 120); else - wheel_deltaY = linesToScroll * 120; + wheel_deltaY = qBound(-120, int(mdelt * 10000), 120); } } @@ -2695,11 +2674,7 @@ int QApplication::keyboardInputInterval() void QApplication::setWheelScrollLines(int n) { - Q_UNUSED(n); - // On Mac, acceleration is handled by the OS. Multiplying wheel scroll - // deltas with n will not be as cross platform as one might think! So - // we choose to go native in this case (and let wheel_scroll_lines == 1). - // QApplicationPrivate::wheel_scroll_lines = n; + QApplicationPrivate::wheel_scroll_lines = n; } int QApplication::wheelScrollLines() diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm index d49c150..ecc6bc9 100644 --- a/src/gui/kernel/qcocoaview_mac.mm +++ b/src/gui/kernel/qcocoaview_mac.mm @@ -795,23 +795,23 @@ extern "C" { const EventRef carbonEvent = (EventRef)[theEvent eventRef]; const UInt32 carbonEventKind = carbonEvent ? ::GetEventKind(carbonEvent) : 0; - if (carbonEventKind == kEventMouseScroll) { + const bool scrollEvent = carbonEventKind == kEventMouseScroll; + + if (scrollEvent) { // The mouse device containts pixel scroll wheel support (Mighty Mouse, Trackpad). // Since deviceDelta is delivered as pixels rather than degrees, we need to // convert from pixels to degrees in a sensible manner. // It looks like four degrees per pixel behaves most native. // Qt expects the unit for delta to be 1/8 of a degree: - const int scrollFactor = 4 * 8; - deltaX = (int)[theEvent deviceDeltaX] * scrollFactor; - deltaY = (int)[theEvent deviceDeltaY] * scrollFactor; - deltaZ = (int)[theEvent deviceDeltaZ] * scrollFactor; - } else { // carbonEventKind == kEventMouseWheelMoved - // Mouse wheel deltas seem to tick in at increments of 0.1. - // Qt widgets expect the delta to be a multiple of 120. - const int scrollFactor = 10 * 120; - deltaX = [theEvent deltaX] * scrollFactor; - deltaY = [theEvent deltaY] * scrollFactor; - deltaZ = [theEvent deltaZ] * scrollFactor; + deltaX = [theEvent deviceDeltaX]; + deltaY = [theEvent deviceDeltaY]; + deltaZ = [theEvent deviceDeltaZ]; + } else { + // carbonEventKind == kEventMouseWheelMoved + // Remove acceleration, and use either -120 or 120 as delta: + deltaX = qBound(-120, int([theEvent deltaX] * 10000), 120); + deltaY = qBound(-120, int([theEvent deltaY] * 10000), 120); + deltaZ = qBound(-120, int([theEvent deltaZ] * 10000), 120); } if (deltaX != 0) { diff --git a/src/gui/widgets/qabstractslider.cpp b/src/gui/widgets/qabstractslider.cpp index 588a48e..fec9fab 100644 --- a/src/gui/widgets/qabstractslider.cpp +++ b/src/gui/widgets/qabstractslider.cpp @@ -693,29 +693,27 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) if (e->orientation() != d->orientation && !rect().contains(e->pos())) return; - qreal currentOffset = qreal(e->delta()) / 120; - d->offset_accumulated += currentOffset; - if (int(d->offset_accumulated) == 0) { - // QAbstractSlider works on integer values. So if the accumulated - // offset is less than +/- 1, we need to wait until we get more - // wheel events (this means that the wheel resolution is higher than - // 15 degrees, e.g. when using mac mighty mouse/trackpad): - return; - } + int stepsToScroll = 0; + qreal offset = qreal(e->delta()) / 120; - int stepsToScroll; if ((e->modifiers() & Qt::ControlModifier) || (e->modifiers() & Qt::ShiftModifier)) { - stepsToScroll = currentOffset > 0 ? d->pageStep : -d->pageStep; + // Scroll one page regardless of delta: + stepsToScroll = qBound(-d->pageStep, int(offset * d->pageStep), d->pageStep); + d->offset_accumulated = 0; } else { - // Calculate the number of steps to scroll (per 15 degrees of rotate): -#ifdef Q_OS_MAC - // On mac, since mouse wheel scrolling is accelerated and - // fine tuned by the OS, we skip applying acceleration: - stepsToScroll = int(d->offset_accumulated); -#else - stepsToScroll = int(d->offset_accumulated) * QApplication::wheelScrollLines() * d->singleStep; -#endif - stepsToScroll = qBound(-d->pageStep, stepsToScroll, d->pageStep); + // Calculate how many lines to scroll. Depending on what delta is (and + // offset), we might end up with a fraction (e.g. scroll 1.3 lines). We can + // only scroll whole lines, so we keep the reminder until next event. + qreal stepsToScrollF = offset * QApplication::wheelScrollLines() * d->singleStep; + // Check if wheel changed direction since last event: + if (d->offset_accumulated != 0 && (offset / d->offset_accumulated) < 0) + d->offset_accumulated = 0; + + d->offset_accumulated += stepsToScrollF; + stepsToScroll = qBound(-d->pageStep, int(d->offset_accumulated), d->pageStep); + d->offset_accumulated -= int(d->offset_accumulated); + if (stepsToScroll == 0) + return; } if (d->invertedControls) @@ -725,12 +723,10 @@ void QAbstractSlider::wheelEvent(QWheelEvent * e) d->position = d->overflowSafeAdd(stepsToScroll); // value will be updated by triggerAction() triggerAction(SliderMove); - if (prevValue == d->value) { + if (prevValue == d->value) d->offset_accumulated = 0; - } else { - d->offset_accumulated -= int(d->offset_accumulated); + else e->accept(); - } } #endif #ifdef QT_KEYPAD_NAVIGATION diff --git a/tests/auto/qabstractslider/tst_qabstractslider.cpp b/tests/auto/qabstractslider/tst_qabstractslider.cpp index 5c70bde..d9574df 100644 --- a/tests/auto/qabstractslider/tst_qabstractslider.cpp +++ b/tests/auto/qabstractslider/tst_qabstractslider.cpp @@ -714,11 +714,7 @@ void tst_QAbstractSlider::wheelEvent_data() << 1 // delta << int(Qt::Vertical) // orientation of slider << int(Qt::Vertical) // orientation of wheel -#ifdef Q_WS_MAC - << 1 // expected position after -#else << 20 // expected position after -#endif << QPoint(0,0); QTest::newRow("Normal data page") << 0 // initial position @@ -777,11 +773,7 @@ void tst_QAbstractSlider::wheelEvent_data() << 1 // delta << int(Qt::Horizontal) // orientation of slider << int(Qt::Horizontal) // orientation of wheel -#ifdef Q_WS_MAC - << 49 // expected position after -#else << 30 // expected position after -#endif << QPoint(1,1); QTest::newRow("Past end") << 50 // initial position @@ -792,11 +784,7 @@ void tst_QAbstractSlider::wheelEvent_data() << false // inverted controls << 1 // wheel scroll lines << false // with modifiers -#ifdef Q_WS_MAC - << 60 // delta -#else << 2 // delta -#endif << int(Qt::Horizontal) // orientation of slider << int(Qt::Horizontal) // orientation of wheel << 100 // expected position after @@ -810,11 +798,7 @@ void tst_QAbstractSlider::wheelEvent_data() << false // inverted controls << 1 // wheel scroll lines << false // with modifiers -#ifdef Q_WS_MAC - << -60 // delta -#else << -2 // delta -#endif << int(Qt::Horizontal) // orientation of slider << int(Qt::Horizontal) // orientation of wheel << 0 // expected position after -- cgit v0.12