From c2c02f7d1e66361c383b06943f7588d6931de62f Mon Sep 17 00:00:00 2001 From: SKefalidis Date: Thu, 23 Jul 2020 10:07:46 +0300 Subject: [PATCH] fix #306234: added teleportation to smooth scrolling, for dealing with repeats + improved comments --- framework/preferencekeys.h | 2 ++ mscore/preferences.cpp | 2 ++ mscore/scoreview.cpp | 38 +++++++++++++++++++++++++++++++++----- mscore/scoreview.h | 27 ++++++++++++++++----------- 4 files changed, 53 insertions(+), 16 deletions(-) diff --git a/framework/preferencekeys.h b/framework/preferencekeys.h index 29b551a5a3c8c..b0de63c3d400b 100644 --- a/framework/preferencekeys.h +++ b/framework/preferencekeys.h @@ -187,6 +187,8 @@ #define PREF_PAN_MODIFIER_MAX "smoothPan/modifier/maxSpeed" #define PREF_PAN_CURSOR_POS "smoothPan/cursor/position" #define PREF_PAN_CURSOR_VISIBLE "smoothPan/cursor/visible" +#define PREF_PAN_TELEPORT_RIGHT "smoothPan/cursor/teleportRight" +#define PREF_PAN_TELEPORT_LEFT "smoothPan/cursor/teleportLeft" //#define PREF_PAN_DISTANCE_LEFT "smoothPan/distance/left" //#define PREF_PAN_DISTANCE_LEFT1 "smoothPan/distance/left1" //#define PREF_PAN_DISTANCE_LEFT2 "smoothPan/distance/left2" diff --git a/mscore/preferences.cpp b/mscore/preferences.cpp index 14d5f9ed7fa5d..2a068917f3e5c 100644 --- a/mscore/preferences.cpp +++ b/mscore/preferences.cpp @@ -290,6 +290,8 @@ void Preferences::init(bool storeInMemoryOnly) { PREF_PAN_CURSOR_VISIBLE, new BoolPreference(false, true) }, { PREF_PAN_CURSOR_POS, new DoublePreference(0.3, true) }, { PREF_PAN_SMOOTHLY_ENABLED, new BoolPreference(false, true) }, + { PREF_PAN_TELEPORT_LEFT, new BoolPreference(true, true) }, + { PREF_PAN_TELEPORT_RIGHT, new BoolPreference(false, true) }, // {PREF_PAN_DISTANCE_LEFT, new DoublePreference(-250, false)}, // {PREF_PAN_DISTANCE_LEFT1, new DoublePreference(-125, false)}, // {PREF_PAN_DISTANCE_LEFT2, new DoublePreference(-50, false)}, diff --git a/mscore/scoreview.cpp b/mscore/scoreview.cpp index f3fe9ce8b6fae..ec9cf8268660b 100644 --- a/mscore/scoreview.cpp +++ b/mscore/scoreview.cpp @@ -668,8 +668,8 @@ void ScoreView::moveControlCursor(const Fraction& tick) int controlX = _controlCursor->rect().x(); double distance = realX - controlX; - if (seq->isPlaying()) { - //playbackCursor in front of the controlCursor + if (seq->isPlaying() && isCursorDistanceReasonable()) { + // playbackCursor in front of the controlCursor if (distance > _panSettings.rightDistance) { _controlModifier += _panSettings.controlModifierSteps; } else if (distance > _panSettings.rightDistance1 && _controlModifier < _panSettings.rightMod1) { @@ -683,7 +683,7 @@ void ScoreView::moveControlCursor(const Fraction& tick) } else if (_controlModifier > _panSettings.rightMod3 && distance < _panSettings.rightDistance3) { _controlModifier = _panSettings.controlModifierBase; } - //playbackCursor behind the controlCursor + // playbackCursor behind the controlCursor else if (distance < _panSettings.leftDistance) { _controlModifier -= _panSettings.controlModifierSteps; } else if (_controlModifier < _panSettings.leftMod1 && distance > _panSettings.leftDistance1) { @@ -694,7 +694,7 @@ void ScoreView::moveControlCursor(const Fraction& tick) _controlModifier = _panSettings.controlModifierBase; } - //enforce limits + // enforce limits if (_controlModifier < _panSettings.minContinuousModifier) { _controlModifier = _panSettings.minContinuousModifier; } else if (_controlModifier > _panSettings.maxContinuousModifier) { @@ -737,7 +737,7 @@ void ScoreView::moveControlCursor(const Fraction& tick) _playbackCursorTimer.restart(); } - //Calculate the position of the controlCursor based on the timeElapsed (which is not the real time that has passed) + // Calculate the position of the controlCursor based on the timeElapsed (which is not the real time that has passed) qreal x = score()->firstMeasure()->pos().x() + (score()->lastMeasure()->pos().x() - score()->firstMeasure()->pos().x()) * (_timeElapsed / (score()->duration() * 1000)); @@ -746,6 +746,32 @@ void ScoreView::moveControlCursor(const Fraction& tick) update(_matrix.mapRect(_controlCursor->rect()).toRect().adjusted(-1,-1,1,1)); } +//--------------------------------------------------------- +// isCursorDistanceReasonable +// check if the control cursor needs to be teleported +// to catch up with the playback cursor (for smooth panning) +//--------------------------------------------------------- + +bool ScoreView::isCursorDistanceReasonable() +{ + qreal viewWidth = canvasViewport().width(); + qreal controlX = _controlCursor->rect().x(); + qreal playbackX = _cursor->rect().x(); + qreal cursorDistance = abs(controlX - playbackX); + double maxLeftDistance = viewWidth * (_panSettings.controlCursorScreenPos + 0.07); // 0.05 left margin + 0.02 for making this less sensitive + double maxRightDistance = viewWidth * (1 - _panSettings.controlCursorScreenPos + 0.15); // teleporting to the right is harder to trigger (we don't want to overdo it) + + if (controlX < playbackX && _panSettings.teleportRightEnabled) { + return cursorDistance < maxRightDistance; + } + + if (playbackX < controlX && _panSettings.teleportLeftEnabled) { + return cursorDistance < maxLeftDistance; + } + + return true; +} + //--------------------------------------------------------- // moveCursor // move cursor in note input mode @@ -5635,5 +5661,7 @@ void SmoothPanSettings::loadFromPreferences() // advancedWeighting = preferences.getBool(PREF_PAN_WEIGHT_ADVANCED); // cursorTimerDuration = preferences.getInt(PREF_PAN_SMART_TIMER_DURATION); controlCursorScreenPos = preferences.getDouble(PREF_PAN_CURSOR_POS); + teleportLeftEnabled = preferences.getBool(PREF_PAN_TELEPORT_LEFT); + teleportRightEnabled = preferences.getBool(PREF_PAN_TELEPORT_RIGHT); } } // namespace Ms diff --git a/mscore/scoreview.h b/mscore/scoreview.h index 59f827eb566e8..b81534857773f 100644 --- a/mscore/scoreview.h +++ b/mscore/scoreview.h @@ -68,28 +68,32 @@ enum class MagIdx : char; struct SmoothPanSettings { // these are all actually loaded from the loadFromPreferences method so don't change these initializations to change the default values, // change the corresponding default preference value - double controlModifierBase { 1 }; - double controlModifierSteps { 0.01 }; - double minContinuousModifier { 0.2 }; - double maxContinuousModifier { 5 }; + double controlModifierBase { 1 }; // initial speed modifier + double controlModifierSteps { 0.01 }; // modification steps for the modifier + double minContinuousModifier { 0.2 }; // minimum speed, 0.2 was chosen instead of 0 to remove stuttering + double maxContinuousModifier { 5 }; // maximum speed - // Changing the distance will change the sensitivity/accuracy/jitter of the algorithm. Larger absolut values are generally smoother. - double leftDistance { -250 }; + // Changing the distance will change the sensitivity/accuracy/jitter of the algorithm. Larger absolute values are generally smoother. + double leftDistance { -250 }; // decelarate double leftDistance1 { -125 }; double leftDistance2 { -50 }; double leftDistance3 { -25 }; - double rightDistance { 500 }; + double rightDistance { 500 }; // accelerate double rightDistance1 { 250 }; double rightDistance2 { 125 }; double rightDistance3 { 50 }; - double leftMod1 { 0.8 }; - double leftMod2 { 0.9 }; + // used to smooth back to normal speed when the playback cursor is getting closer + double leftMod1 { 0.8 }; // minimum speed at the first level + double leftMod2 { 0.9 }; // etc double leftMod3 { 0.95 }; - double rightMod1 { 1.2 }; - double rightMod2 { 1.1 }; + // used to smooth back to normal speed when the control cursor is getting closer to the playback cursor + double rightMod1 { 1.2 }; // maximum speed at the first level + double rightMod2 { 1.1 }; // etc double rightMod3 { 1.05 }; double controlCursorScreenPos { 0.3 }; + bool teleportLeftEnabled { true }; + bool teleportRightEnabled { false }; bool advancedWeighting { false }; // enables the 'smart weight' double normalWeight { 1 }; @@ -359,6 +363,7 @@ public slots: void moveCursor(const Fraction& tick); void moveControlCursor(const Fraction& tick); + bool isCursorDistanceReasonable(); Fraction cursorTick() const; void setCursorOn(bool); void setBackground(QPixmap*);