Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions include/AutomationEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -240,8 +240,6 @@ protected slots:
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;

void adjustLeftRightScoll(int value);

TimePos m_currentPosition;

Action m_action;
Expand All @@ -251,8 +249,11 @@ protected slots:
float m_drawLastLevel;
tick_t m_drawLastTick;

//! Pixels per bar
int m_ppb;
//! Pixels per step on the Y axis (when Y zoom is not Auto)
int m_y_delta;
//! True if Y zoom is Auto
bool m_y_auto;

// Time position (key) of automation node whose outValue is being dragged
Expand Down
2 changes: 0 additions & 2 deletions include/PianoRoll.h
Original file line number Diff line number Diff line change
Expand Up @@ -382,8 +382,6 @@ protected slots:
QScrollBar * m_leftRightScroll;
QScrollBar * m_topBottomScroll;

void adjustLeftRightScoll(int value);

TimePos m_currentPosition;
bool m_recording;
bool m_doAutoQuantization{false};
Expand Down
1 change: 1 addition & 0 deletions include/PianoView.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,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* event) override;


private:
Expand Down
138 changes: 138 additions & 0 deletions include/Scroll.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
/*
* Scroll.h - calculate scroll distance
*
* Copyright (c) 2025 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_H
#define SCROLL_H

#include "Flags.h"
#include "lmms_export.h"


class QWheelEvent;


namespace lmms::gui {


class LMMS_EXPORT Scroll
{
public:
//! QWheelEvent->angleDelta() that corresponds to a "wheel tick"
static constexpr float ANGLE_DELTA_PER_TICK = 120;
//! Default scroll speed for various editors
static constexpr int PIXELS_PER_STEP = 36;

enum class Flag {
NoFlag = 0x0,
Horizontal = 0x1,
//! Change any natural (inverted) scroll to regular scroll.
//! This is useful for widgets like faders, where you want up to be up.
//! Some operating systems does not support this.
DisableNaturalScrolling = 0x2,
//! Swap x/y scroll orientation when pressing Shift or Alt.
//! Most software uses Shift for this, but Qt uses Alt by default
//! so it is included here to match QScrollBar and other widgets.
SwapWithShiftOrAlt = 0x4,
};

using Flags = lmms::Flags<Flag>;


/*! \brief Scroll delta
*
* This class measures scroll delta in "wheel ticks",
* unlike QWheelEvent which measures scroll delta in 1/8ths of a degree.
*/
Scroll(QWheelEvent* event);


/*! \brief Return number of completely scrolled steps of some size
*
* The return value is positive when the wheel is rotated away from the hand.
*
* `stepsPerWheelTick` is the number of steps to count for every wheel tick.
* If set to 5 it will count a step whenever the wheel has moved 1/5 of a tick.
* It will always cound at least one step per wheel tick.
*
* --------------------------------------------------------------------------
*
* You should always use this function instead of the following:
* int steps = wheelEvent->angleDelta().y() / some_value
*
* This is because some trackpads and mice report much smaller chunks of angleDelta
* than the standard 120 (which is a "wheel tick"). In the worst case scenario
* the result will always be rounded down to 0. This function solves it by accumulating
* the angleDelta until a complete step is reached.
*
* Note: don't call this function if you intend to ignore() the event, as it
* may result in double-counting scroll delta.
*/
int getSteps(const float stepsPerWheelTick = 1.0, const Flags flags = Flag::NoFlag);

inline int getSteps(const Flags flags)
{
return getSteps(1.0, flags);
}


/*! \brief Return number of scrolled "wheel ticks"
*
* The value is positive when the wheel is rotated away from the hand.
*
* If you intend to use this in a calculation where the end result is an integer,
* you should probably use getSteps() instead to avoid rounding issues with
* smooth scrolling trackpads and mice.
*/
inline float getStepsFloat(const Flags flags)
{
return getAngleDelta(flags) / ANGLE_DELTA_PER_TICK;
}

//! \brief True when scrolling vertically
bool isVertical();

//! \brief True when scrolling horizontally
bool isHorizontal();

private:
int getAngleDelta(const Flags flags = Flag::NoFlag);
int calculateSteps(const int angleDelta, const float stepsPerTick, const bool horizontal);

QWheelEvent* m_event;

// These are used by calculateSteps() to accumulate partially scrolled steps
// They are shared across all widgets but that doesn't notisable affect the user experience
static float s_partialStepX;
static float s_partialStepY;

const float m_initialPartialStepX;
const float m_initialPartialStepY;
};

LMMS_DECLARE_OPERATORS_FOR_FLAGS(Scroll::Flag)


} // namespace lmms::gui

#endif
2 changes: 0 additions & 2 deletions include/SongEditor.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,8 +128,6 @@ private slots:

QScrollBar * m_leftRightScroll;

void adjustLeftRightScoll(int value);

LcdSpinBox * m_tempoSpinBox;

TimeLineWidget * m_timeLine;
Expand Down
10 changes: 9 additions & 1 deletion plugins/AudioFileProcessor/AudioFileProcessorWaveView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include "DeprecationHelper.h"
#include "SampleThumbnail.h"
#include "FontHelper.h"
#include "Scroll.h"


#include <QPainter>
Expand Down Expand Up @@ -198,7 +199,14 @@ void AudioFileProcessorWaveView::mouseMoveEvent(QMouseEvent * me)

void AudioFileProcessorWaveView::wheelEvent(QWheelEvent * we)
{
zoom(we->angleDelta().y() > 0);
auto scroll = Scroll(we);
we->accept();

int scrolledSteps = scroll.getSteps();
if (scrolledSteps == 0) { return; }

bool zoomOut = scrolledSteps < 0;
zoom(zoomOut);
update();
}

Expand Down
8 changes: 6 additions & 2 deletions plugins/Compressor/CompressorControlDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include "Knob.h"
#include "MainWindow.h"
#include "PixmapButton.h"
#include "Scroll.h"

namespace lmms::gui
{
Expand Down Expand Up @@ -645,9 +646,12 @@ void CompressorControlDialog::resizeEvent(QResizeEvent *event)

void CompressorControlDialog::wheelEvent(QWheelEvent * event)
{
auto scroll = Scroll(event);
event->accept();

const float temp = m_dbRange;
const float dbRangeNew = m_dbRange - copysignf(COMP_GRID_SPACING, event->angleDelta().y());
m_dbRange = round(qBound(COMP_GRID_SPACING, dbRangeNew, COMP_GRID_MAX) / COMP_GRID_SPACING) * COMP_GRID_SPACING;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since scroll.getSteps() returns an int I don't think we need to round to the nearest multiple of COMP_GRID_SPACING because the new value will always be a multiple of COMP_GRID_SPACING.

const float dbRangeNew = m_dbRange - scroll.getSteps() * COMP_GRID_SPACING;
m_dbRange = std::clamp(dbRangeNew, COMP_GRID_SPACING, COMP_GRID_MAX);

// Only reset view if the scolling had an effect
if (m_dbRange != temp)
Expand Down
5 changes: 3 additions & 2 deletions plugins/Eq/EqCurve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -561,8 +561,10 @@ void EqHandle::mouseReleaseEvent( QGraphicsSceneMouseEvent *event )

void EqHandle::wheelEvent( QGraphicsSceneWheelEvent *wevent )
{
wevent->accept();

float highestBandwich = m_type != EqHandleType::Para ? 10 : 4;
int numDegrees = wevent->delta() / 120;
float numDegrees = wevent->delta() / 120.f;
float numSteps = 0;
if( wevent->modifiers() == Qt::ControlModifier )
{
Expand All @@ -579,7 +581,6 @@ void EqHandle::wheelEvent( QGraphicsSceneWheelEvent *wevent )

emit positionChanged();
}
wevent->accept();
}


Expand Down
15 changes: 11 additions & 4 deletions plugins/Vectorscope/VectorView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "GuiApplication.h"
#include "FontHelper.h"
#include "MainWindow.h"
#include "Scroll.h"
#include "VecControls.h"

namespace lmms::gui
Expand Down Expand Up @@ -240,12 +241,18 @@ void VectorView::mouseDoubleClickEvent(QMouseEvent *event)
// Change zoom level using the mouse wheel
void VectorView::wheelEvent(QWheelEvent *event)
{
// Go through integers to avoid accumulating errors
auto scroll = Scroll(event);
event->accept();

// Increment 20% per mouse wheel step
const int increment = scroll.getSteps(20);

// Round zoom percentage to 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);
// Min-max bounds are 20 and 1000 %
const unsigned short new_zoom = std::clamp(old_zoom + increment, 20, 1000);

m_zoom = new_zoom / 100.f;
event->accept();
m_zoomTimestamp = std::chrono::duration_cast<std::chrono::milliseconds>
(
std::chrono::high_resolution_clock::now().time_since_epoch()
Expand Down
1 change: 1 addition & 0 deletions src/gui/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ SET(LMMS_SRCS
gui/SampleLoader.cpp
gui/SampleTrackWindow.cpp
gui/SampleThumbnail.cpp
gui/Scroll.cpp
gui/SendButtonIndicator.cpp
gui/SideBar.cpp
gui/SideBarWidget.cpp
Expand Down
Loading
Loading