From 86688f3924966d6c8845909aba921da36058b0ad Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:01:50 +0200 Subject: [PATCH 01/15] Helper functions for scroll handling --- include/ScrollHelpers.h | 81 +++++++++++++++++++++++++++++++++++ src/gui/CMakeLists.txt | 1 + src/gui/ScrollHelpers.cpp | 90 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 include/ScrollHelpers.h create mode 100644 src/gui/ScrollHelpers.cpp diff --git a/include/ScrollHelpers.h b/include/ScrollHelpers.h new file mode 100644 index 00000000000..f070b100407 --- /dev/null +++ b/include/ScrollHelpers.h @@ -0,0 +1,81 @@ +/* + * ScrollHelpers.h - helper functions for wheel events + * + * Copyright (c) 2023 Alex + * + * 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 + +#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 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 mice and trackpads that report scroll in very small values. + * + * 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 diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 9f940c0354b..8e1d386b9d3 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -34,6 +34,7 @@ SET(LMMS_SRCS gui/ProjectNotes.cpp gui/RowTableView.cpp gui/SampleTrackWindow.cpp + gui/ScrollHelpers.cpp gui/SendButtonIndicator.cpp gui/SideBar.cpp gui/SideBarWidget.cpp diff --git a/src/gui/ScrollHelpers.cpp b/src/gui/ScrollHelpers.cpp new file mode 100644 index 00000000000..5d59e1fff64 --- /dev/null +++ b/src/gui/ScrollHelpers.cpp @@ -0,0 +1,90 @@ +/* + * ScrollHelpers.cpp - helper functions for wheel events + * + * Copyright (c) 2023 Alex + * + * 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 + + +namespace lmms { + + +bool ignoreScroll(const Qt::Orientation orientation, QWheelEvent* event) +{ + bool hasOtherOrientation = orientation == Qt::Horizontal ? event->angleDelta().y() : event->angleDelta().x(); + event->setAccepted(hasOtherOrientation); + return !hasOtherOrientation; +} + + + + +// TODO: is there a good way to prevent calling this method multiple times with the same event? +int getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const float factor, const bool allowNatural) +{ + static int xRemainder; + static int yRemainder; + + int& remainder = orientation == Qt::Horizontal ? xRemainder : yRemainder; + + int delta = orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y(); + if (event->inverted() and !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 From ca565068b8dc40120aa743b5ed2d609c980d3df7 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:03:27 +0200 Subject: [PATCH 02/15] Editors: relative scroll speed and smooth scroll wheel support --- include/AutomationEditor.h | 2 - src/gui/editors/AutomationEditor.cpp | 99 +++++++++------------------- src/gui/editors/PianoRoll.cpp | 67 +++++-------------- src/gui/editors/SongEditor.cpp | 39 +++-------- 4 files changed, 58 insertions(+), 149 deletions(-) diff --git a/include/AutomationEditor.h b/include/AutomationEditor.h index c2ab9809266..9cf076ce3e2 100644 --- a/include/AutomationEditor.h +++ b/include/AutomationEditor.h @@ -180,8 +180,6 @@ protected slots: ComboBoxModel m_zoomingYModel; ComboBoxModel m_quantizeModel; - static const QVector m_zoomXLevels; - FloatModel * m_tensionModel; AutomationClip * m_clip; diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index db56557a4d8..66ca627131d 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -57,6 +57,7 @@ #include "PatternStore.h" #include "PianoRoll.h" #include "ProjectJournal.h" +#include "ScrollHelpers.h" #include "StringPairDrag.h" #include "TextFloat.h" #include "TimeLineWidget.h" @@ -65,6 +66,10 @@ namespace lmms::gui { +const std::vector zoomXLevels = {0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f}; +const std::vector zoomYLevels = {0.25f, 0.50f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f}; + + QPixmap * AutomationEditor::s_toolDraw = nullptr; QPixmap * AutomationEditor::s_toolErase = nullptr; QPixmap * AutomationEditor::s_toolDrawOut = nullptr; @@ -72,10 +77,6 @@ QPixmap * AutomationEditor::s_toolMove = nullptr; QPixmap * AutomationEditor::s_toolYFlip = nullptr; QPixmap * AutomationEditor::s_toolXFlip = nullptr; -const QVector AutomationEditor::m_zoomXLevels = - { 0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f }; - - AutomationEditor::AutomationEditor() : QWidget(), @@ -1089,7 +1090,7 @@ void AutomationEditor::paintEvent(QPaintEvent * pe ) // alternating shades for better contrast float timeSignature = static_cast( Engine::getSong()->getTimeSigModel().getNumerator() ) / static_cast( Engine::getSong()->getTimeSigModel().getDenominator() ); - float zoomFactor = m_zoomXLevels[m_zoomingXModel.value()]; + float zoomFactor = zoomXLevels[m_zoomingXModel.value()]; //the bars which disappears at the left side by scrolling int leftBars = m_currentPosition * zoomFactor / TimePos::ticksPerBar(); @@ -1417,74 +1418,38 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) we->accept(); if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::ShiftModifier ) { - int y = m_zoomingYModel.value(); - if(we->angleDelta().y() > 0) - { - y++; - } - else if(we->angleDelta().y() < 0) - { - y--; - } - y = qBound( 0, y, m_zoomingYModel.size() - 1 ); - m_zoomingYModel.setValue( y ); + m_zoomingYModel.setValue(m_zoomingYModel.value() + verticalScroll(we)); } else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier ) { - int q = m_quantizeModel.value(); - if((we->angleDelta().x() + we->angleDelta().y()) > 0) // alt + scroll becomes horizontal scroll on KDE - { - q--; - } - else if((we->angleDelta().x() + we->angleDelta().y()) < 0) // alt + scroll becomes horizontal scroll on KDE - { - q++; - } - q = qBound( 0, q, m_quantizeModel.size() - 1 ); - m_quantizeModel.setValue( q ); + // Qt swaps x/y scroll when holding alt + m_quantizeModel.setValue(m_quantizeModel.value() - horizontalScroll(we)); update(); } else if( we->modifiers() & Qt::ControlModifier ) { - int x = m_zoomingXModel.value(); - if(we->angleDelta().y() > 0) - { - x++; - } - else if(we->angleDelta().y() < 0) - { - x--; - } - x = qBound( 0, x, m_zoomingXModel.size() - 1 ); - int mouseX = (position( we ).x() - VALUES_WIDTH)* TimePos::ticksPerBar(); // ticks based on the mouse x-position where the scroll wheel was used int ticks = mouseX / m_ppb; - // what would be the ticks in the new zoom level on the very same mouse x - int newTicks = mouseX / (DEFAULT_PPB * m_zoomXLevels[x]); + m_zoomingXModel.setValue(m_zoomingXModel.value() + verticalScroll(we)); + + // ticks in the new zoom level on the very same mouse x + int newTicks = mouseX / m_ppb; // scroll so the tick "selected" by the mouse x doesn't move on the screen m_leftRightScroll->setValue(m_leftRightScroll->value() + ticks - newTicks); - - - m_zoomingXModel.setValue( x ); - } - - // FIXME: Reconsider if determining orientation is necessary in Qt6. - else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal - { - m_leftRightScroll->setValue(m_leftRightScroll->value() - - we->angleDelta().x() * 2 / 15); - } - else if(we->modifiers() & Qt::ShiftModifier) - { - m_leftRightScroll->setValue(m_leftRightScroll->value() - - we->angleDelta().y() * 2 / 15); } else { - m_topBottomScroll->setValue(m_topBottomScroll->value() - - (we->angleDelta().x() + we->angleDelta().y()) / 30); + // TODO does Qt swap x/y when holding Option on Mac? + + // Move 48 ticks per wheel step at 100% horizontal zoom + const float ticksPerStep = 48 / zoomXLevels[m_zoomingXModel.value()]; + m_leftRightScroll->setValue(m_leftRightScroll->value() - horizontalScroll(we, ticksPerStep, true)); + + // Move 10 levels per wheel step at 100% vertical zoom + const float levelsPerStep = 10 / zoomYLevels[m_zoomingYModel.value() - 1]; + m_topBottomScroll->setValue(m_topBottomScroll->value() - verticalScroll(we, levelsPerStep, true)); } } @@ -1680,7 +1645,7 @@ void AutomationEditor::updatePosition(const TimePos & t ) void AutomationEditor::zoomingXChanged() { - m_ppb = m_zoomXLevels[m_zoomingXModel.value()] * DEFAULT_PPB; + m_ppb = zoomXLevels[m_zoomingXModel.value()] * DEFAULT_PPB; assert( m_ppb > 0 ); @@ -1693,12 +1658,12 @@ void AutomationEditor::zoomingXChanged() void AutomationEditor::zoomingYChanged() { - const QString & zfac = m_zoomingYModel.currentText(); - m_y_auto = zfac == "Auto"; + // First value of model is "Auto" + m_y_auto = m_zoomingYModel.value() == 0; + if( !m_y_auto ) { - m_y_delta = zfac.left( zfac.length() - 1 ).toInt() - * DEFAULT_Y_DELTA / 100; + m_y_delta = zoomYLevels[m_zoomingYModel.value() - 1] * DEFAULT_Y_DELTA; } #ifdef LMMS_DEBUG assert( m_y_delta > 0 ); @@ -1905,7 +1870,7 @@ AutomationEditorWindow::AutomationEditorWindow() : m_zoomingXComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); m_zoomingXComboBox->setToolTip( tr( "Horizontal zooming" ) ); - for( float const & zoomLevel : m_editor->m_zoomXLevels ) + for (const auto& zoomLevel : zoomXLevels) { m_editor->m_zoomingXModel.addItem( QString( "%1\%" ).arg( zoomLevel * 100 ) ); } @@ -1923,12 +1888,12 @@ AutomationEditorWindow::AutomationEditorWindow() : m_zoomingYComboBox->setFixedSize( 80, ComboBox::DEFAULT_HEIGHT ); m_zoomingYComboBox->setToolTip( tr( "Vertical zooming" ) ); - m_editor->m_zoomingYModel.addItem( "Auto" ); - for( int i = 0; i < 7; ++i ) + m_editor->m_zoomingYModel.addItem(tr("Auto")); + for (const auto& zoomLevel : zoomYLevels) { - m_editor->m_zoomingYModel.addItem( QString::number( 25 << i ) + "%" ); + m_editor->m_zoomingYModel.addItem(QString("%1\%").arg(zoomLevel * 100)); } - m_editor->m_zoomingYModel.setValue( m_editor->m_zoomingYModel.findText( "Auto" ) ); + m_editor->m_zoomingYModel.setValue(0); m_zoomingYComboBox->setModel( &m_editor->m_zoomingYModel ); diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 8fdf958c033..2786a5f4adb 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -66,6 +66,7 @@ #include "PatternStore.h" #include "PianoView.h" #include "PositionLine.h" +#include "ScrollHelpers.h" #include "SimpleTextFloat.h" #include "SongEditor.h" #include "StepRecorderWidget.h" @@ -3840,71 +3841,35 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier ) { - int q = m_quantizeModel.value(); - if((we->angleDelta().x() + we->angleDelta().y()) > 0) // alt + scroll becomes horizontal scroll on KDE - { - q--; - } - else if((we->angleDelta().x() + we->angleDelta().y()) < 0) // alt + scroll becomes horizontal scroll on KDE - { - q++; - } - q = qBound( 0, q, m_quantizeModel.size() - 1 ); - m_quantizeModel.setValue( q ); + // Qt swaps x/y scroll when holding alt + m_quantizeModel.setValue(m_quantizeModel.value() - horizontalScroll(we)); } else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::ShiftModifier ) { - int l = m_noteLenModel.value(); - if(we->angleDelta().y() > 0) - { - l--; - } - else if(we->angleDelta().y() < 0) - { - l++; - } - l = qBound( 0, l, m_noteLenModel.size() - 1 ); - m_noteLenModel.setValue( l ); + m_noteLenModel.setValue(m_noteLenModel.value() - verticalScroll(we)); } else if( we->modifiers() & Qt::ControlModifier ) { - int z = m_zoomingModel.value(); - if(we->angleDelta().y() > 0) - { - z++; - } - else if(we->angleDelta().y() < 0) - { - z--; - } - z = qBound( 0, z, m_zoomingModel.size() - 1 ); - int x = (position(we).x() - m_whiteKeyWidth) * TimePos::ticksPerBar(); // ticks based on the mouse x-position where the scroll wheel was used int ticks = x / m_ppb; - // what would be the ticks in the new zoom level on the very same mouse x - int newTicks = x / (DEFAULT_PR_PPB * m_zoomLevels[z]); + // update combobox with zooming-factor + m_zoomingModel.setValue(m_zoomingModel.value() + verticalScroll(we)); + // ticks in the new zoom level + int newTicks = x / m_ppb; // scroll so the tick "selected" by the mouse x doesn't move on the screen m_leftRightScroll->setValue(m_leftRightScroll->value() + ticks - newTicks); - // update combobox with zooming-factor - m_zoomingModel.setValue( z ); - } - - // FIXME: Reconsider if determining orientation is necessary in Qt6. - else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal - { - m_leftRightScroll->setValue(m_leftRightScroll->value() - - we->angleDelta().x() * 2 / 15); - } - else if(we->modifiers() & Qt::ShiftModifier) - { - m_leftRightScroll->setValue(m_leftRightScroll->value() - - we->angleDelta().y() * 2 / 15); } else { - m_topBottomScroll->setValue(m_topBottomScroll->value() - - we->angleDelta().y() / 30); + // TODO does Qt swap x/y when holding Option on Mac? + + // Move 48 ticks per wheel step at 100% horizontal zoom + const float ticksPerStep = 48 / m_zoomLevels[m_zoomingModel.value()]; + m_leftRightScroll->setValue(m_leftRightScroll->value() - horizontalScroll(we, ticksPerStep, true)); + + const float keysPerStep = 4; + m_topBottomScroll->setValue(m_topBottomScroll->value() - verticalScroll(we, keysPerStep, true)); } } diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 3e62cc23863..3d91e51d26c 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -48,6 +48,7 @@ #include "Oscilloscope.h" #include "PianoRoll.h" #include "PositionLine.h" +#include "ScrollHelpers.h" #include "SubWindow.h" #include "TextFloat.h" #include "TimeDisplayWidget.h" @@ -535,49 +536,29 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) void SongEditor::wheelEvent( QWheelEvent * we ) { - if( we->modifiers() & Qt::ControlModifier ) + if (we->modifiers() & Qt::ControlModifier && we->angleDelta().y()) { - int z = m_zoomingModel->value(); - - if(we->angleDelta().y() > 0) - { - z++; - } - else if(we->angleDelta().y() < 0) - { - z--; - } - z = qBound( 0, z, m_zoomingModel->size() - 1 ); - - int x = position(we).x() - m_trackHeadWidth; // bar based on the mouse x-position where the scroll wheel was used int bar = x / pixelsPerBar(); - // what would be the bar in the new zoom level on the very same mouse x - int newBar = x / DEFAULT_PIXELS_PER_BAR / m_zoomLevels[z]; + // update combobox with zooming-factor + m_zoomingModel->setValue(m_zoomingModel->value() + verticalScroll(we)); + // the bar in the new zoom level on the very same mouse x + int newBar = x / pixelsPerBar(); // scroll so the bar "selected" by the mouse x doesn't move on the screen m_leftRightScroll->setValue(m_leftRightScroll->value() + bar - newBar); - // update combobox with zooming-factor - m_zoomingModel->setValue( z ); - // update timeline m_song->m_playPos[Song::Mode_PlaySong].m_timeLine-> setPixelsPerBar( pixelsPerBar() ); // and make sure, all Clip's are resized and relocated realignTracks(); } - - // FIXME: Reconsider if determining orientation is necessary in Qt6. - else if(abs(we->angleDelta().x()) > abs(we->angleDelta().y())) // scrolling is horizontal - { - m_leftRightScroll->setValue(m_leftRightScroll->value() - - we->angleDelta().x() /30); - } - else if(we->modifiers() & Qt::ShiftModifier) + else if (we->angleDelta().x()) { - m_leftRightScroll->setValue(m_leftRightScroll->value() - - we->angleDelta().y() / 30); + // Move 2 bars per wheel step at 100% zoom, and more when we zoom out + float barsPerStep = 2.0f * DEFAULT_PIXELS_PER_BAR / pixelsPerBar(); + m_leftRightScroll->setValue(m_leftRightScroll->value() - horizontalScroll(we, barsPerStep, true)); } else { From d220265531dea6879f87d413ee832096cf13a419 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:03:55 +0200 Subject: [PATCH 03/15] PianoView scrollable --- include/PianoView.h | 1 + src/gui/instrument/PianoView.cpp | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/include/PianoView.h b/include/PianoView.h index 6421ff4381c..759c823def1 100644 --- a/include/PianoView.h +++ b/include/PianoView.h @@ -64,6 +64,7 @@ class PianoView : public QWidget, public ModelView void focusOutEvent( QFocusEvent * _fe ) override; void focusInEvent( QFocusEvent * fe ) override; void resizeEvent( QResizeEvent * _event ) override; + void wheelEvent(QWheelEvent* we) override; private: diff --git a/src/gui/instrument/PianoView.cpp b/src/gui/instrument/PianoView.cpp index a2df50e4702..8969b5de1b2 100644 --- a/src/gui/instrument/PianoView.cpp +++ b/src/gui/instrument/PianoView.cpp @@ -738,6 +738,12 @@ void PianoView::resizeEvent(QResizeEvent* event) +void PianoView::wheelEvent(QWheelEvent* we) +{ + QApplication::sendEvent(m_pianoScroll, we); +} + + /*! \brief Convert a key number to an X coordinate in the piano display view * From 6b90f684300150f51719752234526e69d44e3ac7 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:04:38 +0200 Subject: [PATCH 04/15] Never scroll MDI area when hovering a SubWindow --- include/SubWindow.h | 2 ++ src/gui/SubWindow.cpp | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/include/SubWindow.h b/include/SubWindow.h index fdda6de4280..0cf13ec3d43 100644 --- a/include/SubWindow.h +++ b/include/SubWindow.h @@ -37,6 +37,7 @@ class QLabel; class QMoveEvent; class QPushButton; class QResizeEvent; +class QWheelEvent; class QWidget; namespace lmms::gui @@ -75,6 +76,7 @@ class LMMS_EXPORT SubWindow : public QMdiSubWindow void resizeEvent( QResizeEvent * event ) override; void paintEvent( QPaintEvent * pe ) override; void changeEvent( QEvent * event ) override; + void wheelEvent(QWheelEvent* event) override; signals: void focusLost(); diff --git a/src/gui/SubWindow.cpp b/src/gui/SubWindow.cpp index 78e4f586c67..5cd0a13d14b 100644 --- a/src/gui/SubWindow.cpp +++ b/src/gui/SubWindow.cpp @@ -382,4 +382,18 @@ void SubWindow::resizeEvent( QResizeEvent * event ) } -} // namespace lmms::gui \ No newline at end of file + + +/** + * @brief SubWindow::wheelEvent + * + * Capture all WheelEvents that we receive directly or from our subwidgets. + * Don't let them propagate up further to the MDI area. + */ +void SubWindow::wheelEvent(QWheelEvent* event) +{ + event->accept(); +} + + +} // namespace lmms::gui From 1c26aa5a6343aa7aa196ffcdf5c3813fedf95f09 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:07:04 +0200 Subject: [PATCH 05/15] Handle smooth and or natural scroll on various widgets --- plugins/AudioFileProcessor/AudioFileProcessor.cpp | 10 ++++++++-- plugins/Compressor/CompressorControlDialog.cpp | 7 +++++-- plugins/Vectorscope/VectorView.cpp | 7 +++++-- src/gui/widgets/ComboBox.cpp | 13 +++++++------ src/gui/widgets/LcdFloatSpinBox.cpp | 6 ++++-- src/gui/widgets/LcdSpinBox.cpp | 7 ++++--- src/gui/widgets/TabWidget.cpp | 6 +++++- 7 files changed, 38 insertions(+), 18 deletions(-) diff --git a/plugins/AudioFileProcessor/AudioFileProcessor.cpp b/plugins/AudioFileProcessor/AudioFileProcessor.cpp index 2e2d7163b15..ce32f5e502d 100644 --- a/plugins/AudioFileProcessor/AudioFileProcessor.cpp +++ b/plugins/AudioFileProcessor/AudioFileProcessor.cpp @@ -40,6 +40,7 @@ #include "NotePlayHandle.h" #include "PathUtil.h" #include "PixmapButton.h" +#include "ScrollHelpers.h" #include "Song.h" #include "StringPairDrag.h" #include "Clipboard.h" @@ -864,9 +865,14 @@ void AudioFileProcessorWaveView::mouseMoveEvent( QMouseEvent * _me ) -void AudioFileProcessorWaveView::wheelEvent( QWheelEvent * _we ) +void AudioFileProcessorWaveView::wheelEvent(QWheelEvent* we) { - zoom( _we->angleDelta().y() > 0 ); + if (ignoreScroll(Qt::Horizontal, we)) { return; } + + int steps = verticalScroll(we); + if (steps == 0) { return; } + + zoom(steps < 0); update(); } diff --git a/plugins/Compressor/CompressorControlDialog.cpp b/plugins/Compressor/CompressorControlDialog.cpp index 8c6f61bec88..8a0686d204f 100755 --- a/plugins/Compressor/CompressorControlDialog.cpp +++ b/plugins/Compressor/CompressorControlDialog.cpp @@ -38,6 +38,7 @@ #include "Knob.h" #include "MainWindow.h" #include "PixmapButton.h" +#include "ScrollHelpers.h" namespace lmms::gui { @@ -646,8 +647,10 @@ void CompressorControlDialog::resizeEvent(QResizeEvent *event) void CompressorControlDialog::wheelEvent(QWheelEvent * event) { + if (ignoreScroll(Qt::Horizontal, event)) { return; } + const float temp = m_dbRange; - const float dbRangeNew = m_dbRange - copysignf(COMP_GRID_SPACING, event->angleDelta().y()); + const float dbRangeNew = m_dbRange - COMP_GRID_SPACING * verticalScroll(event); m_dbRange = round(qBound(COMP_GRID_SPACING, dbRangeNew, COMP_GRID_MAX) / COMP_GRID_SPACING) * COMP_GRID_SPACING; // Only reset view if the scolling had an effect @@ -768,4 +771,4 @@ void CompressorControlDialog::resetCompressorView() } -} // namespace lmms::gui \ No newline at end of file +} // namespace lmms::gui diff --git a/plugins/Vectorscope/VectorView.cpp b/plugins/Vectorscope/VectorView.cpp index f856f6429e0..c33fca2db2f 100644 --- a/plugins/Vectorscope/VectorView.cpp +++ b/plugins/Vectorscope/VectorView.cpp @@ -31,6 +31,7 @@ #include "ColorChooser.h" #include "GuiApplication.h" #include "MainWindow.h" +#include "ScrollHelpers.h" #include "VecControls.h" namespace lmms::gui @@ -318,10 +319,12 @@ void VectorView::mouseDoubleClickEvent(QMouseEvent *event) // Change zoom level using the mouse wheel void VectorView::wheelEvent(QWheelEvent *event) { + if (ignoreScroll(Qt::Horizontal, event)) { return; } + // Go through integers to avoid accumulating errors const unsigned short old_zoom = round(100 * m_zoom); // Min-max bounds are 20 and 1000 %, step for 15°-increment mouse wheel is 20 % - const unsigned short new_zoom = qBound(20, old_zoom + event->angleDelta().y() / 6, 1000); + const unsigned short new_zoom = qBound(20, old_zoom + verticalScroll(event, 20), 1000); m_zoom = new_zoom / 100.f; event->accept(); m_zoomTimestamp = std::chrono::duration_cast @@ -332,4 +335,4 @@ void VectorView::wheelEvent(QWheelEvent *event) } -} // namespace lmms::gui \ No newline at end of file +} // namespace lmms::gui diff --git a/src/gui/widgets/ComboBox.cpp b/src/gui/widgets/ComboBox.cpp index bdf78ccce36..940c78c761e 100644 --- a/src/gui/widgets/ComboBox.cpp +++ b/src/gui/widgets/ComboBox.cpp @@ -35,6 +35,7 @@ #include "CaptionMenu.h" #include "embed.h" #include "gui_templates.h" +#include "ScrollHelpers.h" namespace lmms::gui { @@ -227,12 +228,12 @@ void ComboBox::paintEvent( QPaintEvent * _pe ) void ComboBox::wheelEvent( QWheelEvent* event ) { - if( model() ) - { - model()->setInitValue(model()->value() + ((event->angleDelta().y() < 0) ? 1 : -1)); - update(); - event->accept(); - } + if (ignoreScroll(Qt::Horizontal, event)) { return; } + + if (!model()) { return; } + + model()->setValue(model()->value() + verticalScroll(event)); + update(); } diff --git a/src/gui/widgets/LcdFloatSpinBox.cpp b/src/gui/widgets/LcdFloatSpinBox.cpp index 6391f314ad9..2a760fbe798 100644 --- a/src/gui/widgets/LcdFloatSpinBox.cpp +++ b/src/gui/widgets/LcdFloatSpinBox.cpp @@ -43,6 +43,7 @@ #include "GuiApplication.h" #include "gui_templates.h" #include "MainWindow.h" +#include "ScrollHelpers.h" namespace lmms::gui { @@ -179,12 +180,13 @@ void LcdFloatSpinBox::mouseReleaseEvent(QMouseEvent*) void LcdFloatSpinBox::wheelEvent(QWheelEvent *event) { + if (ignoreScroll(Qt::Horizontal, event)) { return; } + // switch between integer and fractional step based on cursor position if (position(event).x() < m_wholeDisplay.width()) { m_intStep = true; } else { m_intStep = false; } - event->accept(); - model()->setValue(model()->value() + ((event->angleDelta().y() > 0) ? 1 : -1) * getStep()); + model()->setValue(model()->value() + verticalScroll(event) * getStep()); emit manualChange(); } diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index b53d7ddb5b0..5cdfd921628 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -29,7 +29,7 @@ #include "LcdSpinBox.h" #include "CaptionMenu.h" - +#include "ScrollHelpers.h" namespace lmms::gui { @@ -140,8 +140,9 @@ void LcdSpinBox::mouseReleaseEvent(QMouseEvent*) void LcdSpinBox::wheelEvent(QWheelEvent * we) { - we->accept(); - model()->setValue(model()->value() + ((we->angleDelta().y() > 0) ? 1 : -1) * model()->step()); + if (ignoreScroll(Qt::Horizontal, we)) { return; } + + model()->setValue(model()->value() + verticalScroll(we) * model()->step()); emit manualChange(); } diff --git a/src/gui/widgets/TabWidget.cpp b/src/gui/widgets/TabWidget.cpp index 5ab56fee71c..3668eb0cfbc 100644 --- a/src/gui/widgets/TabWidget.cpp +++ b/src/gui/widgets/TabWidget.cpp @@ -34,6 +34,7 @@ #include "DeprecationHelper.h" #include "embed.h" #include "gui_templates.h" +#include "ScrollHelpers.h" namespace lmms::gui { @@ -293,11 +294,14 @@ void TabWidget::wheelEvent( QWheelEvent * we ) { if(position(we).y() > m_tabheight) { + we->ignore(); return; } we->accept(); - int dir = (we->angleDelta().y() < 0) ? 1 : -1; + + int steps = 0 - horizontalScroll(we) - verticalScroll(we); + int dir = std::clamp(steps, -1, 1); int tab = m_activeTab; while( tab > -1 && static_cast( tab ) < m_widgets.count() ) { From 5d1623b93e505585f734eb6a29ee28633d080064 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:08:02 +0200 Subject: [PATCH 06/15] EqHandle::wheelEvent simplified and supports smooth scroll --- plugins/Eq/EqCurve.cpp | 42 +++++++++--------------------------------- 1 file changed, 9 insertions(+), 33 deletions(-) diff --git a/plugins/Eq/EqCurve.cpp b/plugins/Eq/EqCurve.cpp index 7042312840e..876a5ed968d 100644 --- a/plugins/Eq/EqCurve.cpp +++ b/plugins/Eq/EqCurve.cpp @@ -570,43 +570,19 @@ void EqHandle::mouseReleaseEvent( QGraphicsSceneMouseEvent *event ) void EqHandle::wheelEvent( QGraphicsSceneWheelEvent *wevent ) { - float highestBandwich; - if( m_type != para ) - { - highestBandwich = 10; - } - else - { - highestBandwich = 4; - } + wevent->setAccepted(wevent->orientation() == Qt::Vertical); + if (!wevent->isAccepted()) { return; } - int numDegrees = wevent->delta() / 120; - float numSteps = 0; - if( wevent->modifiers() == Qt::ControlModifier ) - { - numSteps = numDegrees * 0.01; - } - else - { - numSteps = numDegrees * 0.15; - } + float highestBandwidth = m_type != para ? 10 : 4; - if( wevent->orientation() == Qt::Vertical ) - { - m_resonance = m_resonance + ( numSteps ); + // TODO check inverted() for natural scrolling when made available - if( m_resonance < 0.1 ) - { - m_resonance = 0.1; - } + float wheelStepDelta = 120; // Qt unit + float changePerStep = wevent->modifiers() & Qt::ControlModifier ? 0.01f : 0.15f; + float change = wevent->delta() / wheelStepDelta * changePerStep; - if( m_resonance > highestBandwich ) - { - m_resonance = highestBandwich; - } - emit positionChanged(); - } - wevent->accept(); + m_resonance = std::clamp(m_resonance + change, 0.1f, highestBandwidth); + emit positionChanged(); } From 67f9f29b14ad22ed00c8e15e4b01bff4ecdb390a Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:08:50 +0200 Subject: [PATCH 07/15] Fix bug when scrolling on empty MidiClip when zoomed in --- src/gui/clips/MidiClipView.cpp | 37 ++++++++++++++-------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/src/gui/clips/MidiClipView.cpp b/src/gui/clips/MidiClipView.cpp index e3ef9fd20b9..c1a83690bfc 100644 --- a/src/gui/clips/MidiClipView.cpp +++ b/src/gui/clips/MidiClipView.cpp @@ -38,6 +38,7 @@ #include "PianoRoll.h" #include "RenameDialog.h" #include "TrackView.h" +#include "ScrollHelpers.h" namespace lmms::gui { @@ -322,9 +323,12 @@ void MidiClipView::mouseDoubleClickEvent(QMouseEvent *_me) void MidiClipView::wheelEvent(QWheelEvent * we) { - if(m_clip->m_clipType == MidiClip::BeatClip && - (fixedClips() || pixelsPerBar() >= 96) && - position(we).y() > height() - s_stepBtnOff->height()) + bool isBeat = m_clip->m_clipType == MidiClip::BeatClip; + bool showBeat = fixedClips() || (pixelsPerBar() >= 96 && m_legacySEPattern); + bool hoveringEdit = position(we).y() > height() - s_stepBtnOff->height(); + bool scrolledVertical = we->angleDelta().y(); + + if (isBeat && showBeat && hoveringEdit && scrolledVertical) { // get the step number that was wheeled on and // do calculations in floats to prevent rounding errors... @@ -335,34 +339,23 @@ void MidiClipView::wheelEvent(QWheelEvent * we) if( step >= m_clip->m_steps ) { + ClipView::wheelEvent(we); return; } Note * n = m_clip->noteAtStep( step ); - if(!n && we->angleDelta().y() > 0) + int volumeSteps = verticalScroll(we, 5); + + if (!n && volumeSteps > 0) { n = m_clip->addStepNote( step ); n->setVolume( 0 ); } - if( n != nullptr ) + if (n && volumeSteps) { - int vol = n->getVolume(); - - if(we->angleDelta().y() > 0) - { - n->setVolume( qMin( 100, vol + 5 ) ); - } - else - { - n->setVolume( qMax( 0, vol - 5 ) ); - } - - Engine::getSong()->setModified(); - update(); - if( getGUI()->pianoRoll()->currentMidiClip() == m_clip ) - { - getGUI()->pianoRoll()->update(); - } + // Volume is unsigned so it must not go negative + n->setVolume(std::max(0, n->getVolume() + volumeSteps)); + m_clip->dataChanged(); } we->accept(); } From d3b07b0b18d7fcab2e12116d03fcbc3b2ee5deee Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:09:17 +0200 Subject: [PATCH 08/15] Fix Alt+Scroll on selected note velocity --- src/gui/editors/PianoRoll.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index 2786a5f4adb..bb149799fc7 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -3768,8 +3768,13 @@ void PianoRoll::resizeEvent(QResizeEvent* re) void PianoRoll::wheelEvent(QWheelEvent * we ) { we->accept(); + + // Qt swaps x/y scroll when holding alt + bool altPressed = we->modifiers() & Qt::AltModifier; + bool physicallyVertical = altPressed ? we->angleDelta().x() : we->angleDelta().y(); + // handle wheel events for note edit area - for editing note vol/pan with mousewheel - if(position(we).x() > noteEditLeft() && position(we).x() < noteEditRight() + if (physicallyVertical && position(we).x() < noteEditRight() && position(we).y() > noteEditTop() && position(we).y() < noteEditBottom()) { if (!hasValidMidiClip()) {return;} @@ -3781,12 +3786,11 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) int ticks_end = ( x + pixel_range / 2 ) * TimePos::ticksPerBar() / m_ppb + m_currentPosition; - // When alt is pressed we only edit the note under the cursor - bool altPressed = we->modifiers() & Qt::AltModifier; // go through notes to figure out which one we want to change NoteVector nv; for ( Note * i : m_midiClip->notes() ) { + // When alt is pressed we only edit the note under the cursor if( i->withinRange( ticks_start, ticks_end ) || ( i->selected() && !altPressed ) ) { nv += i; @@ -3794,7 +3798,8 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) } if( nv.size() > 0 ) { - const int step = we->angleDelta().y() > 0 ? 1 : -1; + // Qt swaps x/y scroll when holding alt + const int step = altPressed ? horizontalScroll(we) : verticalScroll(we); if( m_noteEditMode == NoteEditVolume ) { for ( Note * n : nv ) From 63fcab6f5a65ca060c672bc888281d4a6173c3cb Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 30 Apr 2023 23:10:35 +0200 Subject: [PATCH 09/15] Increase scroll speed of Knob and Fader + handle natural scroll --- src/gui/widgets/Fader.cpp | 20 +++++++++++--------- src/gui/widgets/Knob.cpp | 12 +++++++++--- 2 files changed, 20 insertions(+), 12 deletions(-) diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index dcf648c37e3..a8a1b12b7f2 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -54,6 +54,7 @@ #include "embed.h" #include "CaptionMenu.h" #include "ConfigManager.h" +#include "ScrollHelpers.h" #include "SimpleTextFloat.h" namespace lmms::gui @@ -252,16 +253,17 @@ void Fader::mouseReleaseEvent( QMouseEvent * mouseEvent ) void Fader::wheelEvent ( QWheelEvent *ev ) { - ev->accept(); + if (ignoreScroll(Qt::Horizontal, ev)) { return; } + + if (!model()) { return; } + + // Number of steps in the model + const float modelSteps = model()->range() / model()->step(); + // Scrolling 200 physical steps should take us from start to end + const float scrollFactor = modelSteps / 200; + + model()->incValue(verticalScroll(ev, scrollFactor)); - if (ev->angleDelta().y() > 0) - { - model()->incValue( 1 ); - } - else - { - model()->incValue( -1 ); - } updateTextFloat(); s_textFloat->setVisibilityTimeOut( 1000 ); } diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index 8640bb81dce..a7617b7d401 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -45,6 +45,7 @@ #include "LocaleHelper.h" #include "MainWindow.h" #include "ProjectJournal.h" +#include "ScrollHelpers.h" #include "SimpleTextFloat.h" #include "StringPairDrag.h" @@ -689,10 +690,15 @@ void Knob::paintEvent( QPaintEvent * _me ) void Knob::wheelEvent(QWheelEvent * we) { we->accept(); - const float stepMult = model()->range() / 2000 / model()->step(); - const int inc = ((we->angleDelta().y() > 0 ) ? 1 : -1) * ((stepMult < 1 ) ? 1 : stepMult); - model()->incValue( inc ); + if (!model()) { return; } + + // Number of steps in the model + const float modelSteps = model()->range() / model()->step(); + // Scrolling 200 physical steps should take us from start to end + const float scrollFactor = modelSteps / 200; + + model()->incValue(verticalScroll(we, scrollFactor) - horizontalScroll(we, scrollFactor)); s_textFloat->setText( displayValue() ); s_textFloat->moveGlobal( this, QPoint( width() + 2, 0 ) ); From 4f7b2f26d9dc330aa4f6e2dced1ec84188c08d2a Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 1 May 2023 00:39:29 +0200 Subject: [PATCH 10/15] Fix build error --- include/ScrollHelpers.h | 4 ++-- src/gui/ScrollHelpers.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/ScrollHelpers.h b/include/ScrollHelpers.h index f070b100407..b0b9337bf52 100644 --- a/include/ScrollHelpers.h +++ b/include/ScrollHelpers.h @@ -44,12 +44,12 @@ bool LMMS_EXPORT ignoreScroll(const Qt::Orientation orientation, QWheelEvent* ev -/*! \brief Return number scrolled steps +/*! \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 mice and trackpads that report scroll in very small values. + * 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. * diff --git a/src/gui/ScrollHelpers.cpp b/src/gui/ScrollHelpers.cpp index 5d59e1fff64..30ab5a1e801 100644 --- a/src/gui/ScrollHelpers.cpp +++ b/src/gui/ScrollHelpers.cpp @@ -49,7 +49,7 @@ int getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const int& remainder = orientation == Qt::Horizontal ? xRemainder : yRemainder; int delta = orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y(); - if (event->inverted() and !allowNatural) + if (event->inverted() && !allowNatural) { delta = -delta; } From c2e10f7be263d24145bf852469f5977a21ddd733 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 1 May 2023 00:40:05 +0200 Subject: [PATCH 11/15] TabWidget natural scroll support --- src/gui/widgets/TabWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/widgets/TabWidget.cpp b/src/gui/widgets/TabWidget.cpp index 3668eb0cfbc..9a454fab1e3 100644 --- a/src/gui/widgets/TabWidget.cpp +++ b/src/gui/widgets/TabWidget.cpp @@ -300,7 +300,7 @@ void TabWidget::wheelEvent( QWheelEvent * we ) we->accept(); - int steps = 0 - horizontalScroll(we) - verticalScroll(we); + int steps = 0 - horizontalScroll(we, 1, true) - verticalScroll(we, 1, true); int dir = std::clamp(steps, -1, 1); int tab = m_activeTab; while( tab > -1 && static_cast( tab ) < m_widgets.count() ) From e75f4317a9c7dbf074a0dc19dcaef63ed1be71bc Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 1 May 2023 12:45:41 +0200 Subject: [PATCH 12/15] AutomatableSlider improved smooth scroll --- src/gui/widgets/AutomatableSlider.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/gui/widgets/AutomatableSlider.cpp b/src/gui/widgets/AutomatableSlider.cpp index 7e1be0e069e..0107c2517f1 100644 --- a/src/gui/widgets/AutomatableSlider.cpp +++ b/src/gui/widgets/AutomatableSlider.cpp @@ -28,6 +28,7 @@ #include #include "CaptionMenu.h" +#include "ScrollHelpers.h" namespace lmms::gui @@ -90,11 +91,11 @@ void AutomatableSlider::mouseReleaseEvent( QMouseEvent * _me ) -void AutomatableSlider::wheelEvent( QWheelEvent * _me ) +void AutomatableSlider::wheelEvent(QWheelEvent* we) { bool old_status = m_showStatus; m_showStatus = true; - QSlider::wheelEvent( _me ); + model()->incValue(verticalScroll(we) - horizontalScroll(we)); m_showStatus = old_status; } From 19ba829b08217ffb431b138fabfb4f29c83527f7 Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 1 May 2023 12:46:10 +0200 Subject: [PATCH 13/15] AutomationEditor constexpr --- src/gui/editors/AutomationEditor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index 66ca627131d..fe764ce2f96 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -66,8 +66,8 @@ namespace lmms::gui { -const std::vector zoomXLevels = {0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f}; -const std::vector zoomYLevels = {0.25f, 0.50f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f}; +constexpr std::array zoomXLevels = {0.125f, 0.25f, 0.5f, 1.0f, 2.0f, 4.0f, 8.0f}; +constexpr std::array zoomYLevels = {0.25f, 0.50f, 1.0f, 2.0f, 4.0f, 8.0f, 16.0f}; QPixmap * AutomationEditor::s_toolDraw = nullptr; From e6dd42ed33c5f7575b9a0a1b38bafb474c378efd Mon Sep 17 00:00:00 2001 From: Alex Date: Mon, 1 May 2023 17:55:56 +0200 Subject: [PATCH 14/15] Explicit bool --- src/gui/ScrollHelpers.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/ScrollHelpers.cpp b/src/gui/ScrollHelpers.cpp index 30ab5a1e801..a847a52896d 100644 --- a/src/gui/ScrollHelpers.cpp +++ b/src/gui/ScrollHelpers.cpp @@ -32,7 +32,9 @@ namespace lmms { bool ignoreScroll(const Qt::Orientation orientation, QWheelEvent* event) { - bool hasOtherOrientation = orientation == Qt::Horizontal ? event->angleDelta().y() : event->angleDelta().x(); + bool hasOtherOrientation = orientation == Qt::Horizontal + ? event->angleDelta().y() != 0 + : event->angleDelta().x() != 0; event->setAccepted(hasOtherOrientation); return !hasOtherOrientation; } From 2fe54cfd6866ca6e56286dbb470d9a4c42429382 Mon Sep 17 00:00:00 2001 From: Alex Date: Sun, 14 May 2023 21:41:37 +0200 Subject: [PATCH 15/15] Use flags for arguments. Handle Alt modifier. Fix natural scroll bug. --- include/ScrollHelpers.h | 65 +++++++++++-------- .../AudioFileProcessor/AudioFileProcessor.cpp | 4 +- .../Compressor/CompressorControlDialog.cpp | 4 +- plugins/Vectorscope/VectorView.cpp | 4 +- src/gui/ScrollHelpers.cpp | 63 ++++++++++++------ src/gui/clips/MidiClipView.cpp | 5 +- src/gui/editors/AutomationEditor.cpp | 15 ++--- src/gui/editors/PianoRoll.cpp | 27 ++++---- src/gui/editors/SongEditor.cpp | 8 +-- src/gui/widgets/AutomatableSlider.cpp | 2 +- src/gui/widgets/ComboBox.cpp | 4 +- src/gui/widgets/Fader.cpp | 4 +- src/gui/widgets/Knob.cpp | 2 +- src/gui/widgets/LcdFloatSpinBox.cpp | 4 +- src/gui/widgets/LcdSpinBox.cpp | 4 +- src/gui/widgets/TabWidget.cpp | 2 +- 16 files changed, 123 insertions(+), 94 deletions(-) diff --git a/include/ScrollHelpers.h b/include/ScrollHelpers.h index b0b9337bf52..2dd1c2f96e2 100644 --- a/include/ScrollHelpers.h +++ b/include/ScrollHelpers.h @@ -25,7 +25,7 @@ #ifndef SCROLL_HELPERS_H #define SCROLL_HELPERS_H -#include +#include #include "lmms_export.h" @@ -34,46 +34,57 @@ class QWheelEvent; namespace lmms { +enum ScrollFlag +{ + //! Default orientation - placeholder value. + VerticalScroll = 0, -/*! \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); + //! 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, +}; -/*! \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. +Q_DECLARE_FLAGS(ScrollFlags, ScrollFlag); +Q_DECLARE_OPERATORS_FOR_FLAGS(ScrollFlags); + + +/*! \brief If event matches orientation, ignore() it and return true. * - * \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. + * Convenience function for early return in wheelEvent(). */ -int LMMS_EXPORT getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const float factor, - const bool allowNatural); +bool LMMS_EXPORT ignoreScroll(ScrollFlags options, QWheelEvent* event); -/*! \brief Overload of getScroll +/*! \brief Return true if event matches given orientation * - * Returns a positive value if the top of the wheel is moved to the left + * Convenience function. Especially useful for CustomAltModifierScroll. */ -int LMMS_EXPORT horizontalScroll(const QWheelEvent* event, const float factor = 1, const bool allowNatural = true); +bool LMMS_EXPORT hasScroll(ScrollFlags options, QWheelEvent* event); -/*! \brief Overload of getScroll +/*! \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. * - * Returns a positive value if the top of the wheel is rotating away from the hand operating it + * \param options - see ScrollFlag + * \param event - QWheelEvent + * \param factor - speed/precision */ -int LMMS_EXPORT verticalScroll(const QWheelEvent* event, const float factor = 1, const bool allowNatural = true); +int LMMS_EXPORT getScroll(ScrollFlags options, QWheelEvent* event, const float factor = 1); +int LMMS_EXPORT getScroll(QWheelEvent* event, const float factor = 1); } // namespace lmms diff --git a/plugins/AudioFileProcessor/AudioFileProcessor.cpp b/plugins/AudioFileProcessor/AudioFileProcessor.cpp index ce32f5e502d..b7b6a009ddd 100644 --- a/plugins/AudioFileProcessor/AudioFileProcessor.cpp +++ b/plugins/AudioFileProcessor/AudioFileProcessor.cpp @@ -867,9 +867,9 @@ void AudioFileProcessorWaveView::mouseMoveEvent( QMouseEvent * _me ) void AudioFileProcessorWaveView::wheelEvent(QWheelEvent* we) { - if (ignoreScroll(Qt::Horizontal, we)) { return; } + if (ignoreScroll(HorizontalScroll, we)) { return; } - int steps = verticalScroll(we); + int steps = getScroll(we); if (steps == 0) { return; } zoom(steps < 0); diff --git a/plugins/Compressor/CompressorControlDialog.cpp b/plugins/Compressor/CompressorControlDialog.cpp index 8a0686d204f..57edb94c805 100755 --- a/plugins/Compressor/CompressorControlDialog.cpp +++ b/plugins/Compressor/CompressorControlDialog.cpp @@ -647,10 +647,10 @@ void CompressorControlDialog::resizeEvent(QResizeEvent *event) void CompressorControlDialog::wheelEvent(QWheelEvent * event) { - if (ignoreScroll(Qt::Horizontal, event)) { return; } + if (ignoreScroll(HorizontalScroll, event)) { return; } const float temp = m_dbRange; - const float dbRangeNew = m_dbRange - COMP_GRID_SPACING * verticalScroll(event); + const float dbRangeNew = m_dbRange - COMP_GRID_SPACING * getScroll(event); m_dbRange = round(qBound(COMP_GRID_SPACING, dbRangeNew, COMP_GRID_MAX) / COMP_GRID_SPACING) * COMP_GRID_SPACING; // Only reset view if the scolling had an effect diff --git a/plugins/Vectorscope/VectorView.cpp b/plugins/Vectorscope/VectorView.cpp index c33fca2db2f..33d86a19d32 100644 --- a/plugins/Vectorscope/VectorView.cpp +++ b/plugins/Vectorscope/VectorView.cpp @@ -319,12 +319,12 @@ void VectorView::mouseDoubleClickEvent(QMouseEvent *event) // Change zoom level using the mouse wheel void VectorView::wheelEvent(QWheelEvent *event) { - if (ignoreScroll(Qt::Horizontal, event)) { return; } + if (ignoreScroll(HorizontalScroll, event)) { return; } // Go through integers to avoid accumulating errors const unsigned short old_zoom = round(100 * m_zoom); // Min-max bounds are 20 and 1000 %, step for 15°-increment mouse wheel is 20 % - const unsigned short new_zoom = qBound(20, old_zoom + verticalScroll(event, 20), 1000); + const unsigned short new_zoom = qBound(20, old_zoom + getScroll(event, 20), 1000); m_zoom = new_zoom / 100.f; event->accept(); m_zoomTimestamp = std::chrono::duration_cast diff --git a/src/gui/ScrollHelpers.cpp b/src/gui/ScrollHelpers.cpp index a847a52896d..cb1c1d48d74 100644 --- a/src/gui/ScrollHelpers.cpp +++ b/src/gui/ScrollHelpers.cpp @@ -30,11 +30,25 @@ namespace lmms { -bool ignoreScroll(const Qt::Orientation orientation, QWheelEvent* event) +int getAngleDelta(ScrollFlags options, QWheelEvent* event) { - bool hasOtherOrientation = orientation == Qt::Horizontal - ? event->angleDelta().y() != 0 - : event->angleDelta().x() != 0; + 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; } @@ -42,16 +56,35 @@ bool ignoreScroll(const Qt::Orientation orientation, QWheelEvent* event) -// TODO: is there a good way to prevent calling this method multiple times with the same event? -int getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const float factor, const bool allowNatural) +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 = orientation == Qt::Horizontal ? xRemainder : yRemainder; + int& remainder = options & HorizontalScroll ? xRemainder : yRemainder; + int delta = getAngleDelta(options, event); - int delta = orientation == Qt::Horizontal ? event->angleDelta().x() : event->angleDelta().y(); - if (event->inverted() && !allowNatural) + if (event->inverted() && !(options & AllowNaturalScroll)) { delta = -delta; } @@ -75,17 +108,9 @@ int getScroll(const QWheelEvent* event, const Qt::Orientation orientation, const -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) +int getScroll(QWheelEvent* event, const float factor) { - return getScroll(event, Qt::Vertical, factor, allowNatural); + return getScroll(VerticalScroll, event, factor); } diff --git a/src/gui/clips/MidiClipView.cpp b/src/gui/clips/MidiClipView.cpp index c1a83690bfc..f2fc903440c 100644 --- a/src/gui/clips/MidiClipView.cpp +++ b/src/gui/clips/MidiClipView.cpp @@ -326,9 +326,8 @@ void MidiClipView::wheelEvent(QWheelEvent * we) bool isBeat = m_clip->m_clipType == MidiClip::BeatClip; bool showBeat = fixedClips() || (pixelsPerBar() >= 96 && m_legacySEPattern); bool hoveringEdit = position(we).y() > height() - s_stepBtnOff->height(); - bool scrolledVertical = we->angleDelta().y(); - if (isBeat && showBeat && hoveringEdit && scrolledVertical) + if (isBeat && showBeat && hoveringEdit && hasScroll(VerticalScroll, we)) { // get the step number that was wheeled on and // do calculations in floats to prevent rounding errors... @@ -344,7 +343,7 @@ void MidiClipView::wheelEvent(QWheelEvent * we) } Note * n = m_clip->noteAtStep( step ); - int volumeSteps = verticalScroll(we, 5); + int volumeSteps = getScroll(we, 5); if (!n && volumeSteps > 0) { diff --git a/src/gui/editors/AutomationEditor.cpp b/src/gui/editors/AutomationEditor.cpp index fe764ce2f96..04c275e08fe 100644 --- a/src/gui/editors/AutomationEditor.cpp +++ b/src/gui/editors/AutomationEditor.cpp @@ -1418,12 +1418,11 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) we->accept(); if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::ShiftModifier ) { - m_zoomingYModel.setValue(m_zoomingYModel.value() + verticalScroll(we)); + m_zoomingYModel.setValue(m_zoomingYModel.value() + getScroll(we)); } else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier ) { - // Qt swaps x/y scroll when holding alt - m_quantizeModel.setValue(m_quantizeModel.value() - horizontalScroll(we)); + m_quantizeModel.setValue(m_quantizeModel.value() - getScroll(CustomAltModifierScroll, we)); update(); } else if( we->modifiers() & Qt::ControlModifier ) @@ -1432,7 +1431,7 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) // ticks based on the mouse x-position where the scroll wheel was used int ticks = mouseX / m_ppb; - m_zoomingXModel.setValue(m_zoomingXModel.value() + verticalScroll(we)); + m_zoomingXModel.setValue(m_zoomingXModel.value() + getScroll(we)); // ticks in the new zoom level on the very same mouse x int newTicks = mouseX / m_ppb; @@ -1441,15 +1440,15 @@ void AutomationEditor::wheelEvent(QWheelEvent * we ) } else { - // TODO does Qt swap x/y when holding Option on Mac? - // Move 48 ticks per wheel step at 100% horizontal zoom const float ticksPerStep = 48 / zoomXLevels[m_zoomingXModel.value()]; - m_leftRightScroll->setValue(m_leftRightScroll->value() - horizontalScroll(we, ticksPerStep, true)); + const int ticks = getScroll(HorizontalScroll | AllowNaturalScroll, we, ticksPerStep); + m_leftRightScroll->setValue(m_leftRightScroll->value() - ticks); // Move 10 levels per wheel step at 100% vertical zoom const float levelsPerStep = 10 / zoomYLevels[m_zoomingYModel.value() - 1]; - m_topBottomScroll->setValue(m_topBottomScroll->value() - verticalScroll(we, levelsPerStep, true)); + const int levels = getScroll(VerticalScroll | AllowNaturalScroll, we, levelsPerStep); + m_topBottomScroll->setValue(m_topBottomScroll->value() - levels); } } diff --git a/src/gui/editors/PianoRoll.cpp b/src/gui/editors/PianoRoll.cpp index bb149799fc7..adf5f5d1693 100644 --- a/src/gui/editors/PianoRoll.cpp +++ b/src/gui/editors/PianoRoll.cpp @@ -3769,12 +3769,8 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) { we->accept(); - // Qt swaps x/y scroll when holding alt - bool altPressed = we->modifiers() & Qt::AltModifier; - bool physicallyVertical = altPressed ? we->angleDelta().x() : we->angleDelta().y(); - // handle wheel events for note edit area - for editing note vol/pan with mousewheel - if (physicallyVertical && position(we).x() < noteEditRight() + if (hasScroll(VerticalScroll | CustomAltModifierScroll, we) && position(we).x() < noteEditRight() && position(we).y() > noteEditTop() && position(we).y() < noteEditBottom()) { if (!hasValidMidiClip()) {return;} @@ -3786,11 +3782,12 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) int ticks_end = ( x + pixel_range / 2 ) * TimePos::ticksPerBar() / m_ppb + m_currentPosition; + // When alt is pressed we only edit the note under the cursor + bool altPressed = we->modifiers() & Qt::AltModifier; // go through notes to figure out which one we want to change NoteVector nv; for ( Note * i : m_midiClip->notes() ) { - // When alt is pressed we only edit the note under the cursor if( i->withinRange( ticks_start, ticks_end ) || ( i->selected() && !altPressed ) ) { nv += i; @@ -3798,8 +3795,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) } if( nv.size() > 0 ) { - // Qt swaps x/y scroll when holding alt - const int step = altPressed ? horizontalScroll(we) : verticalScroll(we); + const int step = getScroll(VerticalScroll | CustomAltModifierScroll, we); if( m_noteEditMode == NoteEditVolume ) { for ( Note * n : nv ) @@ -3846,12 +3842,11 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::AltModifier ) { - // Qt swaps x/y scroll when holding alt - m_quantizeModel.setValue(m_quantizeModel.value() - horizontalScroll(we)); + m_quantizeModel.setValue(m_quantizeModel.value() - getScroll(CustomAltModifierScroll, we)); } else if( we->modifiers() & Qt::ControlModifier && we->modifiers() & Qt::ShiftModifier ) { - m_noteLenModel.setValue(m_noteLenModel.value() - verticalScroll(we)); + m_noteLenModel.setValue(m_noteLenModel.value() - getScroll(we)); } else if( we->modifiers() & Qt::ControlModifier ) { @@ -3859,7 +3854,7 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) // ticks based on the mouse x-position where the scroll wheel was used int ticks = x / m_ppb; // update combobox with zooming-factor - m_zoomingModel.setValue(m_zoomingModel.value() + verticalScroll(we)); + m_zoomingModel.setValue(m_zoomingModel.value() + getScroll(we)); // ticks in the new zoom level int newTicks = x / m_ppb; // scroll so the tick "selected" by the mouse x doesn't move on the screen @@ -3867,14 +3862,14 @@ void PianoRoll::wheelEvent(QWheelEvent * we ) } else { - // TODO does Qt swap x/y when holding Option on Mac? - // Move 48 ticks per wheel step at 100% horizontal zoom const float ticksPerStep = 48 / m_zoomLevels[m_zoomingModel.value()]; - m_leftRightScroll->setValue(m_leftRightScroll->value() - horizontalScroll(we, ticksPerStep, true)); + const int ticks = getScroll(HorizontalScroll | AllowNaturalScroll, we, ticksPerStep); + m_leftRightScroll->setValue(m_leftRightScroll->value() - ticks); const float keysPerStep = 4; - m_topBottomScroll->setValue(m_topBottomScroll->value() - verticalScroll(we, keysPerStep, true)); + const int keys = getScroll(VerticalScroll | AllowNaturalScroll, we, keysPerStep); + m_topBottomScroll->setValue(m_topBottomScroll->value() - keys); } } diff --git a/src/gui/editors/SongEditor.cpp b/src/gui/editors/SongEditor.cpp index 3d91e51d26c..1d2f371e183 100644 --- a/src/gui/editors/SongEditor.cpp +++ b/src/gui/editors/SongEditor.cpp @@ -536,13 +536,13 @@ void SongEditor::keyPressEvent( QKeyEvent * ke ) void SongEditor::wheelEvent( QWheelEvent * we ) { - if (we->modifiers() & Qt::ControlModifier && we->angleDelta().y()) + if (we->modifiers() & Qt::ControlModifier && hasScroll(VerticalScroll, we)) { int x = position(we).x() - m_trackHeadWidth; // bar based on the mouse x-position where the scroll wheel was used int bar = x / pixelsPerBar(); // update combobox with zooming-factor - m_zoomingModel->setValue(m_zoomingModel->value() + verticalScroll(we)); + m_zoomingModel->setValue(m_zoomingModel->value() + getScroll(we)); // the bar in the new zoom level on the very same mouse x int newBar = x / pixelsPerBar(); // scroll so the bar "selected" by the mouse x doesn't move on the screen @@ -554,11 +554,11 @@ void SongEditor::wheelEvent( QWheelEvent * we ) // and make sure, all Clip's are resized and relocated realignTracks(); } - else if (we->angleDelta().x()) + else if (hasScroll(HorizontalScroll, we)) { // Move 2 bars per wheel step at 100% zoom, and more when we zoom out float barsPerStep = 2.0f * DEFAULT_PIXELS_PER_BAR / pixelsPerBar(); - m_leftRightScroll->setValue(m_leftRightScroll->value() - horizontalScroll(we, barsPerStep, true)); + m_leftRightScroll->setValue(m_leftRightScroll->value() - getScroll(HorizontalScroll | AllowNaturalScroll, we, barsPerStep)); } else { diff --git a/src/gui/widgets/AutomatableSlider.cpp b/src/gui/widgets/AutomatableSlider.cpp index 0107c2517f1..1284be57820 100644 --- a/src/gui/widgets/AutomatableSlider.cpp +++ b/src/gui/widgets/AutomatableSlider.cpp @@ -95,7 +95,7 @@ void AutomatableSlider::wheelEvent(QWheelEvent* we) { bool old_status = m_showStatus; m_showStatus = true; - model()->incValue(verticalScroll(we) - horizontalScroll(we)); + model()->incValue(getScroll(we) - getScroll(HorizontalScroll, we)); m_showStatus = old_status; } diff --git a/src/gui/widgets/ComboBox.cpp b/src/gui/widgets/ComboBox.cpp index 940c78c761e..9d863b4564e 100644 --- a/src/gui/widgets/ComboBox.cpp +++ b/src/gui/widgets/ComboBox.cpp @@ -228,11 +228,11 @@ void ComboBox::paintEvent( QPaintEvent * _pe ) void ComboBox::wheelEvent( QWheelEvent* event ) { - if (ignoreScroll(Qt::Horizontal, event)) { return; } + if (ignoreScroll(HorizontalScroll, event)) { return; } if (!model()) { return; } - model()->setValue(model()->value() + verticalScroll(event)); + model()->setValue(model()->value() + getScroll(event)); update(); } diff --git a/src/gui/widgets/Fader.cpp b/src/gui/widgets/Fader.cpp index a8a1b12b7f2..51de735dbff 100644 --- a/src/gui/widgets/Fader.cpp +++ b/src/gui/widgets/Fader.cpp @@ -253,7 +253,7 @@ void Fader::mouseReleaseEvent( QMouseEvent * mouseEvent ) void Fader::wheelEvent ( QWheelEvent *ev ) { - if (ignoreScroll(Qt::Horizontal, ev)) { return; } + if (ignoreScroll(HorizontalScroll, ev)) { return; } if (!model()) { return; } @@ -262,7 +262,7 @@ void Fader::wheelEvent ( QWheelEvent *ev ) // Scrolling 200 physical steps should take us from start to end const float scrollFactor = modelSteps / 200; - model()->incValue(verticalScroll(ev, scrollFactor)); + model()->incValue(getScroll(ev, scrollFactor)); updateTextFloat(); s_textFloat->setVisibilityTimeOut( 1000 ); diff --git a/src/gui/widgets/Knob.cpp b/src/gui/widgets/Knob.cpp index a7617b7d401..c1058d8a66b 100644 --- a/src/gui/widgets/Knob.cpp +++ b/src/gui/widgets/Knob.cpp @@ -698,7 +698,7 @@ void Knob::wheelEvent(QWheelEvent * we) // Scrolling 200 physical steps should take us from start to end const float scrollFactor = modelSteps / 200; - model()->incValue(verticalScroll(we, scrollFactor) - horizontalScroll(we, scrollFactor)); + model()->incValue(getScroll(VerticalScroll, we, scrollFactor) - getScroll(HorizontalScroll, we, scrollFactor)); s_textFloat->setText( displayValue() ); s_textFloat->moveGlobal( this, QPoint( width() + 2, 0 ) ); diff --git a/src/gui/widgets/LcdFloatSpinBox.cpp b/src/gui/widgets/LcdFloatSpinBox.cpp index 2a760fbe798..d343d742810 100644 --- a/src/gui/widgets/LcdFloatSpinBox.cpp +++ b/src/gui/widgets/LcdFloatSpinBox.cpp @@ -180,13 +180,13 @@ void LcdFloatSpinBox::mouseReleaseEvent(QMouseEvent*) void LcdFloatSpinBox::wheelEvent(QWheelEvent *event) { - if (ignoreScroll(Qt::Horizontal, event)) { return; } + if (ignoreScroll(HorizontalScroll, event)) { return; } // switch between integer and fractional step based on cursor position if (position(event).x() < m_wholeDisplay.width()) { m_intStep = true; } else { m_intStep = false; } - model()->setValue(model()->value() + verticalScroll(event) * getStep()); + model()->setValue(model()->value() + getScroll(event) * getStep()); emit manualChange(); } diff --git a/src/gui/widgets/LcdSpinBox.cpp b/src/gui/widgets/LcdSpinBox.cpp index 5cdfd921628..2877c8abd66 100644 --- a/src/gui/widgets/LcdSpinBox.cpp +++ b/src/gui/widgets/LcdSpinBox.cpp @@ -140,9 +140,9 @@ void LcdSpinBox::mouseReleaseEvent(QMouseEvent*) void LcdSpinBox::wheelEvent(QWheelEvent * we) { - if (ignoreScroll(Qt::Horizontal, we)) { return; } + if (ignoreScroll(HorizontalScroll, we)) { return; } - model()->setValue(model()->value() + verticalScroll(we) * model()->step()); + model()->setValue(model()->value() + getScroll(we) * model()->step()); emit manualChange(); } diff --git a/src/gui/widgets/TabWidget.cpp b/src/gui/widgets/TabWidget.cpp index 9a454fab1e3..03f2bff1968 100644 --- a/src/gui/widgets/TabWidget.cpp +++ b/src/gui/widgets/TabWidget.cpp @@ -300,7 +300,7 @@ void TabWidget::wheelEvent( QWheelEvent * we ) we->accept(); - int steps = 0 - horizontalScroll(we, 1, true) - verticalScroll(we, 1, true); + int steps = 0 - getScroll(HorizontalScroll | AllowNaturalScroll, we) - getScroll(we); int dir = std::clamp(steps, -1, 1); int tab = m_activeTab; while( tab > -1 && static_cast( tab ) < m_widgets.count() )