-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Natural, smooth and zoom-relative scrolling #6700
base: master
Are you sure you want to change the base?
Changes from 11 commits
86688f3
ca56506
d220265
6b90f68
1c26aa5
5d1623b
67f9f29
d3b07b0
63fcab6
4f7b2f2
c2e10f7
e75f431
19ba829
e6dd42e
2fe54cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* | ||
* ScrollHelpers.h - helper functions for wheel events | ||
* | ||
* Copyright (c) 2023 Alex <allejok96/gmail> | ||
* | ||
* This file is part of LMMS - https://lmms.io | ||
* | ||
* This program 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 2 of the License, or (at your option) any later version. | ||
* | ||
* This program 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 this program (see COPYING); if not, write to the | ||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
* Boston, MA 02110-1301 USA. | ||
* | ||
*/ | ||
|
||
#ifndef SCROLL_HELPERS_H | ||
#define SCROLL_HELPERS_H | ||
|
||
#include <Qt> | ||
|
||
#include "lmms_export.h" | ||
|
||
class QWheelEvent; | ||
|
||
|
||
namespace lmms { | ||
|
||
|
||
/*! \brief Mark event as ignored and return true if it matches the orientation | ||
* | ||
* Convenience function that may be used for early return in wheelEvent. | ||
* Events that doesn't match the orientation are marked accepted. | ||
*/ | ||
bool LMMS_EXPORT ignoreScroll(const Qt::Orientation orientation, QWheelEvent* event); | ||
|
||
|
||
|
||
/*! \brief Return number of scrolled steps. | ||
* | ||
* By default it counts standard scroll wheel steps of 15°. | ||
* | ||
* If you intend to round or divide WheelEvent::angleDelta() this function should ALWAYS be used to get proper | ||
* support for smooth scrolling mice and trackpads. | ||
* | ||
* Only call this function ONCE per event and orientation. Never call it if the event will be ignored. | ||
* | ||
* \param event - QWheelEvent to get delta value from. | ||
* \param orientation - Vertical or horizontal. | ||
* \param factor - Scroll speed/precision. If factor=2 it returns 2 for a complete step and 1 for a halfstep. | ||
* \param allowNatural - Whether macOS-style natural scroll should be allowed or inverted to regular scroll. | ||
*/ | ||
int LMMS_EXPORT getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const float factor, | ||
const bool allowNatural); | ||
|
||
|
||
/*! \brief Overload of getScroll | ||
* | ||
* Returns a positive value if the top of the wheel is moved to the left | ||
*/ | ||
int LMMS_EXPORT horizontalScroll(const QWheelEvent* event, const float factor = 1, const bool allowNatural = true); | ||
|
||
|
||
/*! \brief Overload of getScroll | ||
* | ||
* Returns a positive value if the top of the wheel is rotating away from the hand operating it | ||
*/ | ||
int LMMS_EXPORT verticalScroll(const QWheelEvent* event, const float factor = 1, const bool allowNatural = true); | ||
|
||
|
||
} // namespace lmms | ||
|
||
#endif |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
/* | ||
* ScrollHelpers.cpp - helper functions for wheel events | ||
* | ||
* Copyright (c) 2023 Alex <allejok96/gmail> | ||
* | ||
* This file is part of LMMS - https://lmms.io | ||
* | ||
* This program 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 2 of the License, or (at your option) any later version. | ||
* | ||
* This program 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 this program (see COPYING); if not, write to the | ||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | ||
* Boston, MA 02110-1301 USA. | ||
* | ||
*/ | ||
|
||
#include "ScrollHelpers.h" | ||
|
||
#include <QWheelEvent> | ||
|
||
|
||
namespace lmms { | ||
|
||
|
||
bool ignoreScroll(const Qt::Orientation orientation, QWheelEvent* event) | ||
{ | ||
bool hasOtherOrientation = orientation == Qt::Horizontal ? event->angleDelta().y() : event->angleDelta().x(); | ||
allejok96 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
event->setAccepted(hasOtherOrientation); | ||
return !hasOtherOrientation; | ||
} | ||
|
||
|
||
|
||
|
||
// TODO: is there a good way to prevent calling this method multiple times with the same event? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where are we calling it multiple times? I don't seem to see any. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For diagonal scroll events, Qt 5 generates two events(one for vertical, the other for horizontal) for Qt 4 compatibility. AFAIK, this isn't the case in Qt 6. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the insight @PhysSong, I was wondering about that. This is not a problem atm, but I was thinking about fool proofing. I tried to make it clear in the doc string, but you know.... people. If called improperly the counter will be double increased and it will be hard to detect. |
||
int getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const float factor, const bool allowNatural) | ||
{ | ||
static int xRemainder; | ||
static int yRemainder; | ||
Comment on lines
+81
to
+82
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a huge fan of these being static. The value will carry over to another event and might cause unintended scroll values. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure, but per-widget counters might be useful for fractional parts. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've considered this a lot... My conclusion is: does it really matter? Per-widget counter - the logical solution:
Global counter - the simple solution:
Another thing: the remainder is reset every time the wheel changes direction. This is how Qt handles it and it's a clever way to prevent offsets building up over time and also pretty logical when you think about it. But it comes with this side effect:
|
||
|
||
int& remainder = orientation == Qt::Horizontal ? xRemainder : yRemainder; | ||
|
||
int delta = orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y(); | ||
if (event->inverted() && !allowNatural) | ||
{ | ||
delta = -delta; | ||
} | ||
|
||
// If the wheel changed direction forget the accumulated value | ||
if (delta * remainder < 0) { remainder = 0; } | ||
|
||
// A normal scroll wheel click is 15° and Qt counts angle delta in 1/8 of a degree | ||
const float deltaPerWheelTick = 120; | ||
// Angle delta needed to scroll one step (never more than 15°) | ||
const float deltaPerStep = deltaPerWheelTick / std::max(1.0f, factor); | ||
|
||
// Summarize, return whole steps and keep what's left | ||
remainder += delta; | ||
int steps = remainder / deltaPerStep; | ||
remainder -= steps * deltaPerStep; | ||
|
||
return steps; | ||
} | ||
|
||
|
||
|
||
|
||
int horizontalScroll(const QWheelEvent* event, const float factor, const bool allowNatural) | ||
{ | ||
return getScroll(event, Qt::Horizontal, factor, allowNatural); | ||
} | ||
|
||
|
||
|
||
|
||
int verticalScroll(const QWheelEvent* event, const float factor, const bool allowNatural) | ||
{ | ||
return getScroll(event, Qt::Vertical, factor, allowNatural); | ||
} | ||
|
||
|
||
} // namespace lmms |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tresf changing to
allowNatural = false
in these two places should fix the issue of natural scrolling on knobs. I'll get around to fixing it later...There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wouldn't this change belong in
Knob.cpp
instead? Anyway, I tried it and it has no effect.Possibly related: #5507 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😢 Could you add a
printf
somewhere to see ifQWheelEvent->inverted()
is true? On Linux it's not detected. If we can't know if the scroll is natural or not I guess the only way is having a setting for it.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, if you don't mind being more specific; there's no (obvious) place to add...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I got it...
model()->incValue(verticalScroll(we, scrollFactor) - horizontalScroll(we, scrollFactor)); + printf("Inverted: %d\n", we->inverted()); s_textFloat->setText( displayValue() );
Shows:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope the last commit fixed this