tdf#143209 vcl: track partial scroll deltas
this makes scrolling in calc smoother and makes left/up scrolling
the same speed as right/down scrolling, which was previously not the
case.
prior to this change, Window::HandleScrollCommand only checked each
event for being a large enough scroll to advance one unit. this
happened in lcl_HandleScrollHelper by way of o3tl::saturating_cast,
which meant that nonzero upward/leftward scrolls were always worth at
least one unit, while downward/rightward scrolls needed to be larger
than 1 to count.
now, we accumulate partial scroll offsets in WindowImpl and perform a
saturating cast on the absolute value, so behavior is symmetric and
sensitive to accumulated small scroll values. this feels smoother
and is more correct.
Change-Id: Id3692d14edd45ed26f2952e3418e4d82806e1fc4
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/142948
Tested-by: Jenkins
Tested-by: Caolán McNamara <caolanm@redhat.com>
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/vcl/inc/window.h b/vcl/inc/window.h
index 639bee8..6f10445 100644
--- a/vcl/inc/window.h
+++ b/vcl/inc/window.h
@@ -256,6 +256,8 @@ public:
vcl::Cursor* mpCursor;
PointerStyle maPointer;
Fraction maZoom;
double mfPartialScrollX;
double mfPartialScrollY;
OUString maText;
std::optional<vcl::Font>
mpControlFont;
diff --git a/vcl/source/window/window.cxx b/vcl/source/window/window.cxx
index 4705fe5..5cfc50d 100644
--- a/vcl/source/window/window.cxx
+++ b/vcl/source/window/window.cxx
@@ -590,6 +590,8 @@ WindowImpl::WindowImpl( vcl::Window& rWindow, WindowType nType )
{
mxOutDev = VclPtr<vcl::WindowOutputDevice>::Create(rWindow);
maZoom = Fraction( 1, 1 );
mfPartialScrollX = 0.0;
mfPartialScrollY = 0.0;
maWinRegion = vcl::Region(true);
maWinClipRegion = vcl::Region(true);
mpWinData = nullptr; // Extra Window Data, that we don't need for all windows
diff --git a/vcl/source/window/window2.cxx b/vcl/source/window/window2.cxx
index b6c4ee2..978dc0b 100644
--- a/vcl/source/window/window2.cxx
+++ b/vcl/source/window/window2.cxx
@@ -598,12 +598,14 @@ tools::Long Window::GetDrawPixel( OutputDevice const * pDev, tools::Long nPixels
return nP;
}
static void lcl_HandleScrollHelper( Scrollable* pScrl, double nN, bool isMultiplyByLineSize )
// returns how much was actually scrolled (so that abs(retval) <= abs(nN))
static double lcl_HandleScrollHelper( Scrollable* pScrl, double nN, bool isMultiplyByLineSize )
{
if (!pScrl || !nN || pScrl->Inactive())
return;
return 0.0;
tools::Long nNewPos = pScrl->GetThumbPos();
double scrolled = nN;
if ( nN == double(-LONG_MAX) )
nNewPos += pScrl->GetPageSize();
@@ -616,13 +618,22 @@ static void lcl_HandleScrollHelper( Scrollable* pScrl, double nN, bool isMultipl
nN*=pScrl->GetLineSize();
}
const double fVal = nNewPos - nN;
// compute how many quantized units to scroll
tools::Long magnitude = o3tl::saturating_cast<tools::Long>(abs(nN));
tools::Long change = copysign(magnitude, nN);
nNewPos = o3tl::saturating_cast<tools::Long>(fVal);
nNewPos = nNewPos - change;
scrolled = double(change);
// convert back to chunked/continuous
if(isMultiplyByLineSize){
scrolled /= pScrl->GetLineSize();
}
}
pScrl->DoScroll( nNewPos );
return scrolled;
}
bool Window::HandleScrollCommand( const CommandEvent& rCmd,
@@ -668,6 +679,9 @@ bool Window::HandleScrollCommand( const CommandEvent& rCmd,
{
double nScrollLines = pData->GetScrollLines();
double nLines;
double* partialScroll = pData->IsHorz()
? &mpWindowImpl->mfPartialScrollX
: &mpWindowImpl->mfPartialScrollY;
if ( nScrollLines == COMMAND_WHEEL_PAGESCROLL )
{
if ( pData->GetDelta() < 0 )
@@ -676,13 +690,12 @@ bool Window::HandleScrollCommand( const CommandEvent& rCmd,
nLines = double(LONG_MAX);
}
else
nLines = pData->GetNotchDelta() * nScrollLines;
nLines = *partialScroll + pData->GetNotchDelta() * nScrollLines;
if ( nLines )
{
ImplHandleScroll( nullptr,
0L,
pData->IsHorz() ? pHScrl : pVScrl,
nLines );
Scrollable* pScrl = pData->IsHorz() ? pHScrl : pVScrl;
double scrolled = lcl_HandleScrollHelper( pScrl, nLines, true );
*partialScroll = nLines - scrolled;
bRet = true;
}
}
@@ -806,12 +819,6 @@ bool Window::HandleScrollCommand( const CommandEvent& rCmd,
return bRet;
}
// Note that when called for CommandEventId::Wheel above, despite its name,
// pVScrl isn't necessarily the vertical scroll bar. Depending on
// whether the scroll is horizontal or vertical, it is either the
// horizontal or vertical scroll bar. nY is correspondingly either
// the horizontal or vertical scroll amount.
void Window::ImplHandleScroll( Scrollable* pHScrl, double nX,
Scrollable* pVScrl, double nY )
{