vcl/inc/scrwnd.hxx           |    6 ++--
 vcl/source/window/scrwnd.cxx |   59 +++++++++++++++++++++++++++----------------
 2 files changed, 42 insertions(+), 23 deletions(-)

New commits:
commit f9e2bc8d84fe729d7a501dc3acc6325e246f0b7d
Author:     Marc Mondesir <timepilot3...@gmail.com>
AuthorDate: Fri Oct 25 11:40:46 2024 -0700
Commit:     Patrick Luby <guibomac...@gmail.com>
CommitDate: Wed Oct 30 15:04:17 2024 +0100

    tdf#163582: Fix scrolling distance increasing geometrically.
    
    New scroll distance was previous distance multiplied by speed factor, but 
distance was not reset to base values when mouse not moved (or outside app 
window on some platforms), resulting in continuous multiply amplification. 
Break out base scroll values to separate variables to prevent multiply 
feedback. Add comments to help future code maintenance.
    
    Change-Id: If11baff3b25521abce7436b44aaf8e6a19e54f45
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/175657
    Tested-by: Jenkins
    Reviewed-by: Patrick Luby <guibomac...@gmail.com>

diff --git a/vcl/inc/scrwnd.hxx b/vcl/inc/scrwnd.hxx
index f92ebe556cfb..2f57b31d384e 100644
--- a/vcl/inc/scrwnd.hxx
+++ b/vcl/inc/scrwnd.hxx
@@ -52,8 +52,10 @@ private:
     WheelMode           mnWheelMode;
     sal_uLong           mnMaxWidth;
     sal_uLong           mnActDist;
-    tools::Long                mnActDeltaX;
-    tools::Long                mnActDeltaY;
+    tools::Long         mnStepDeltaX;       // x component of scroll direction
+    tools::Long         mnStepDeltaY;       // y component of scroll direction
+    tools::Long         mnActDeltaX;        // x component of scroll distance
+    tools::Long         mnActDeltaY;        // y component of scroll distance
     void                ImplCreateImageList();
     void                ImplSetRegion(const Bitmap& rRegionBmp);
     using Window::ImplGetMousePointer;
diff --git a/vcl/source/window/scrwnd.cxx b/vcl/source/window/scrwnd.cxx
index 511d60fc2ca5..8634dc2332db 100644
--- a/vcl/source/window/scrwnd.cxx
+++ b/vcl/source/window/scrwnd.cxx
@@ -46,6 +46,8 @@ ImplWheelWindow::ImplWheelWindow( vcl::Window* pParent ) :
             mnTimeout       ( DEF_TIMEOUT ),
             mnWheelMode     ( WheelMode::NONE ),
             mnActDist       ( 0 ),
+            mnStepDeltaX    ( 0 ),
+            mnStepDeltaY    ( 0 ),
             mnActDeltaX     ( 0 ),
             mnActDeltaY     ( 0 )
 {
@@ -189,11 +191,12 @@ void ImplWheelWindow::ImplRecalcScrollValues()
     }
     else
     {
-        sal_uInt64 nCurTime;
+        sal_uInt64 nCurTime;        // Scrolling time interval
 
         // calc current time
         if( mnMaxWidth )
         {
+            // Time interval for each unit of scrolling. Mouse further from 
start point -> shorter time interval -> faster scrolling.
             const double fExp = ( static_cast<double>(mnActDist) / mnMaxWidth 
) * log10( double(MAX_TIME) / MIN_TIME );
             nCurTime = static_cast<sal_uInt64>( MAX_TIME / pow( 10., fExp ) );
         }
@@ -203,19 +206,23 @@ void ImplWheelWindow::ImplRecalcScrollValues()
         if( !nCurTime )
             nCurTime = 1;
 
-        if( mnRepaintTime <= nCurTime )
-            mnTimeout = nCurTime - mnRepaintTime;
-        else
+        if( mnRepaintTime <= nCurTime )     // Draw time less than scroll time 
interval
+        {
+            mnActDeltaX = mnStepDeltaX;     // Scroll 1 unit
+            mnActDeltaY = mnStepDeltaY;
+            mnTimeout = nCurTime - mnRepaintTime;       // Call handler again 
after remaining interval elapsed
+        }
+        else    // Draw time greater than scroll time
         {
-            sal_uInt64 nMult = mnRepaintTime / nCurTime;
+            sal_uInt64 nMult = mnRepaintTime / nCurTime;        // Scroll # 
units based on how many scroll intervals elapsed
 
             if( !( mnRepaintTime % nCurTime ) )
                 mnTimeout = 0;
             else
                 mnTimeout = ++nMult * nCurTime - mnRepaintTime;
 
-            double fValX = static_cast<double>(mnActDeltaX) * nMult;
-            double fValY = static_cast<double>(mnActDeltaY) * nMult;
+            double fValX = static_cast<double>(mnStepDeltaX) * nMult;       // 
Get scroll distance from # units * step
+            double fValY = static_cast<double>(mnStepDeltaY) * nMult;
 
             mnActDeltaX = o3tl::saturating_cast<tools::Long>(fValX);
             mnActDeltaY = o3tl::saturating_cast<tools::Long>(fValY);
@@ -308,23 +315,32 @@ void ImplWheelWindow::MouseMove( const MouseEvent& rMEvt )
     const StartAutoScrollFlags nFlags = 
ImplGetSVData()->mpWinData->mnAutoScrollFlags;
     const bool          bHorz( nFlags & StartAutoScrollFlags::Horz );
     const bool          bVert( nFlags & StartAutoScrollFlags::Vert );
-    const bool          bOuter = mnActDist > WHEEL_RADIUS;
+    const bool          bOuter = mnActDist > WHEEL_RADIUS;      // More than 
minimum distance from start point?
 
-    if( bOuter && ( maLastMousePos != aMousePos ) )
+    if( maLastMousePos != aMousePos )
     {
-        switch( eActStyle )
+        if( bOuter )    // More than minimum distance
+        {
+            switch( eActStyle )
+            {
+                case PointerStyle::AutoScrollN:   mnStepDeltaX = +0; 
mnStepDeltaY = +1; break;
+                case PointerStyle::AutoScrollS:   mnStepDeltaX = +0; 
mnStepDeltaY = -1; break;
+                case PointerStyle::AutoScrollW:   mnStepDeltaX = +1; 
mnStepDeltaY = +0; break;
+                case PointerStyle::AutoScrollE:   mnStepDeltaX = -1; 
mnStepDeltaY = +0; break;
+                case PointerStyle::AutoScrollNW:  mnStepDeltaX = +1; 
mnStepDeltaY = +1; break;
+                case PointerStyle::AutoScrollNE:  mnStepDeltaX = -1; 
mnStepDeltaY = +1; break;
+                case PointerStyle::AutoScrollSW:  mnStepDeltaX = +1; 
mnStepDeltaY = -1; break;
+                case PointerStyle::AutoScrollSE:  mnStepDeltaX = -1; 
mnStepDeltaY = -1; break;
+
+                default:
+                    mnStepDeltaX = 0; mnStepDeltaY = 0;
+                break;
+            }
+        }
+        else    // Less than minimum distance
         {
-            case PointerStyle::AutoScrollN:   mnActDeltaX = +0; mnActDeltaY = 
+1; break;
-            case PointerStyle::AutoScrollS:   mnActDeltaX = +0; mnActDeltaY = 
-1; break;
-            case PointerStyle::AutoScrollW:   mnActDeltaX = +1; mnActDeltaY = 
+0; break;
-            case PointerStyle::AutoScrollE:   mnActDeltaX = -1; mnActDeltaY = 
+0; break;
-            case PointerStyle::AutoScrollNW:  mnActDeltaX = +1; mnActDeltaY = 
+1; break;
-            case PointerStyle::AutoScrollNE:  mnActDeltaX = -1; mnActDeltaY = 
+1; break;
-            case PointerStyle::AutoScrollSW:  mnActDeltaX = +1; mnActDeltaY = 
-1; break;
-            case PointerStyle::AutoScrollSE:  mnActDeltaX = -1; mnActDeltaY = 
-1; break;
-
-            default:
-            break;
+            mnStepDeltaX = 0;
+            mnStepDeltaY = 0;
         }
     }
 
@@ -371,6 +387,7 @@ IMPL_LINK_NOARG(ImplWheelWindow, ImplScrollHdl, Timer *, 
void)
         }
     }
 
+    // Call this handler again based on scrolling time interval
     if ( mnTimeout != mpTimer->GetTimeout() )
         mpTimer->SetTimeout( mnTimeout );
     mpTimer->Start();

Reply via email to