-
-
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
Open
allejok96
wants to merge
15
commits into
LMMS:master
Choose a base branch
from
allejok96:scrollOverhaul
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
86688f3
Helper functions for scroll handling
allejok96 ca56506
Editors: relative scroll speed and smooth scroll wheel support
allejok96 d220265
PianoView scrollable
allejok96 6b90f68
Never scroll MDI area when hovering a SubWindow
allejok96 1c26aa5
Handle smooth and or natural scroll on various widgets
allejok96 5d1623b
EqHandle::wheelEvent simplified and supports smooth scroll
allejok96 67f9f29
Fix bug when scrolling on empty MidiClip when zoomed in
allejok96 d3b07b0
Fix Alt+Scroll on selected note velocity
allejok96 63fcab6
Increase scroll speed of Knob and Fader + handle natural scroll
allejok96 4f7b2f2
Fix build error
allejok96 c2e10f7
TabWidget natural scroll support
allejok96 e75f431
AutomatableSlider improved smooth scroll
allejok96 19ba829
AutomationEditor constexpr
allejok96 e6dd42e
Explicit bool
allejok96 2fe54cf
Use flags for arguments. Handle Alt modifier. Fix natural scroll bug.
allejok96 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
/* | ||
* 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 <QFlags> | ||
|
||
#include "lmms_export.h" | ||
|
||
class QWheelEvent; | ||
|
||
|
||
namespace lmms { | ||
|
||
enum ScrollFlag | ||
{ | ||
//! Default orientation - placeholder value. | ||
VerticalScroll = 0, | ||
|
||
//! Use horizontal orientation INSTEAD of vertical. | ||
//! Values will be positive if the finger is moving to the left. | ||
HorizontalScroll = 1 << 1, | ||
|
||
//! Pass-through natural (reversed) scroll on macOS. | ||
//! By default natural scroll will be inverted to normal scroll. | ||
AllowNaturalScroll = 1 << 2, | ||
|
||
//! Deactivate Qt's built-in Alt modifier behavior. | ||
//! By default Alt on Windows/Linux will swap scroll orientation. | ||
CustomAltModifierScroll = 1 << 3, | ||
}; | ||
|
||
Q_DECLARE_FLAGS(ScrollFlags, ScrollFlag); | ||
Q_DECLARE_OPERATORS_FOR_FLAGS(ScrollFlags); | ||
|
||
|
||
/*! \brief If event matches orientation, ignore() it and return true. | ||
* | ||
* Convenience function for early return in wheelEvent(). | ||
*/ | ||
bool LMMS_EXPORT ignoreScroll(ScrollFlags options, QWheelEvent* event); | ||
|
||
|
||
/*! \brief Return true if event matches given orientation | ||
* | ||
* Convenience function. Especially useful for CustomAltModifierScroll. | ||
*/ | ||
bool LMMS_EXPORT hasScroll(ScrollFlags options, QWheelEvent* event); | ||
|
||
|
||
/*! \brief Return number of scrolled steps. | ||
* | ||
* 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 on events that will be ignored. | ||
* | ||
* For vertical orientation (default), the return value is positive if the finger moving forward. | ||
* | ||
* If factor=1 it counts number of completed 15° scroll wheel steps. If factor=2 it counts halfsteps, and so on. | ||
* | ||
* \param options - see ScrollFlag | ||
* \param event - QWheelEvent | ||
* \param factor - speed/precision | ||
*/ | ||
int LMMS_EXPORT getScroll(ScrollFlags options, QWheelEvent* event, const float factor = 1); | ||
int LMMS_EXPORT getScroll(QWheelEvent* event, const float factor = 1); | ||
|
||
|
||
} // namespace lmms | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* | ||
* 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 { | ||
|
||
|
||
int getAngleDelta(ScrollFlags options, QWheelEvent* event) | ||
{ | ||
bool getX = options & HorizontalScroll; | ||
#ifndef LMMS_BUILD_APPLE | ||
if (options & CustomAltModifierScroll && event->modifiers() & Qt::AltModifier) | ||
{ | ||
// Qt inverts X and Y when holding Alt on Windows/Linux - here we invert it back | ||
getX = !getX; | ||
} | ||
#endif | ||
return getX ? event->angleDelta().x() : event->angleDelta().y(); | ||
} | ||
|
||
|
||
|
||
|
||
bool ignoreScroll(ScrollFlags options, QWheelEvent* event) | ||
{ | ||
bool hasOtherOrientation = getAngleDelta(options ^ HorizontalScroll, event) != 0; | ||
event->setAccepted(hasOtherOrientation); | ||
return !hasOtherOrientation; | ||
} | ||
|
||
|
||
|
||
|
||
bool hasScroll(ScrollFlags options, QWheelEvent* event) | ||
{ | ||
return getAngleDelta(options, event) != 0; | ||
} | ||
|
||
|
||
|
||
|
||
|
||
int getScroll(ScrollFlags options, QWheelEvent* event, const float factor) | ||
{ | ||
/* TODO: is there a good way to prevent calling this method multiple times with the same event and orientation? | ||
* | ||
* for (auto child: children) | ||
* { | ||
* child->move(getScroll(ev)); | ||
* } | ||
* | ||
* Here the internal yRemainder will be increased by angleDelta().y() for every child until it reaches a full step, | ||
* whereby getScroll() will return non-zero for that child only. For regular mice angleDelta() is always a full step | ||
* so the bug will go unnoticed, but for many trackpads this won't work. | ||
*/ | ||
static int xRemainder; | ||
static int yRemainder; | ||
|
||
int& remainder = options & HorizontalScroll ? xRemainder : yRemainder; | ||
int delta = getAngleDelta(options, event); | ||
|
||
if (event->inverted() && !(options & AllowNaturalScroll)) | ||
{ | ||
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 getScroll(QWheelEvent* event, const float factor) | ||
{ | ||
return getScroll(VerticalScroll, event, factor); | ||
} | ||
|
||
|
||
} // namespace lmms |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back 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.
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 comment
The 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 comment
The 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: