sd/source/ui/inc/ViewShell.hxx                                 |    1 
 sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx |    1 
 sd/source/ui/view/drawview.cxx                                 |    1 
 sd/source/ui/view/sdwindow.cxx                                 |   12 -
 sd/source/ui/view/viewshe2.cxx                                 |   97 
++++++++--
 sd/source/ui/view/viewshel.cxx                                 |    7 
 6 files changed, 95 insertions(+), 24 deletions(-)

New commits:
commit dfb412699b96e12b2758be0e422c3e775f183d17
Author:     Sarper Akdemir <[email protected]>
AuthorDate: Tue Apr 23 16:00:32 2024 +0200
Commit:     Sarper Akdemir <[email protected]>
CommitDate: Wed Apr 24 11:28:00 2024 +0200

    tdf#38164: sd: allow panning across pages when zoomed in
    
    Change-Id: I513b2b8cbdc91733e551da71a1e6782fecc981a3
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/166542
    Tested-by: Jenkins
    Reviewed-by: Sarper Akdemir <[email protected]>

diff --git a/sd/source/ui/inc/ViewShell.hxx b/sd/source/ui/inc/ViewShell.hxx
index 6ee126db9027..9e5e8e068160 100644
--- a/sd/source/ui/inc/ViewShell.hxx
+++ b/sd/source/ui/inc/ViewShell.hxx
@@ -382,6 +382,7 @@ public:
     */
     virtual void ShowUIControls (bool bVisible);
     bool IsPageFlipMode() const;
+    bool CanPanAcrossPages() const;
 
     /** Set the given window as new parent window.  This is not possible for
         all views, so the return value tells the caller if the relocation
diff --git a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx 
b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx
index 9203c06e8f9f..e8fc847a4a7b 100644
--- a/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx
+++ b/sd/source/ui/slidesorter/controller/SlsCurrentSlideManager.cxx
@@ -176,6 +176,7 @@ void CurrentSlideManager::SetCurrentSlideAtViewShellBase 
(const SharedPageDescri
             pDrawViewShell->SwitchPage(nPageNumber);
             TabControl& rPageTabControl = pDrawViewShell->GetPageTabControl();
             
rPageTabControl.SetCurPageId(rPageTabControl.GetPageId(nPageNumber));
+            pDrawViewShell->UpdateScrollBars();
         }
     }
 }
diff --git a/sd/source/ui/view/drawview.cxx b/sd/source/ui/view/drawview.cxx
index 6792250fd8e7..99c166002cbd 100644
--- a/sd/source/ui/view/drawview.cxx
+++ b/sd/source/ui/view/drawview.cxx
@@ -407,6 +407,7 @@ void DrawView::Notify(SfxBroadcaster& rBC, const SfxHint& 
rHint)
         if ( mnPOCHSmph == 0 && eHintKind == SdrHintKind::PageOrderChange )
         {
             mpDrawViewShell->ResetActualPage();
+            mpDrawViewShell->UpdateScrollBars();
         }
         else if ( eHintKind == SdrHintKind::LayerChange || eHintKind == 
SdrHintKind::LayerOrderChange )
         {
diff --git a/sd/source/ui/view/sdwindow.cxx b/sd/source/ui/view/sdwindow.cxx
index ab8a7bbd8889..8f71c17db957 100644
--- a/sd/source/ui/view/sdwindow.cxx
+++ b/sd/source/ui/view/sdwindow.cxx
@@ -667,8 +667,6 @@ void Window::SetVisibleXY(double fX, double fY)
 double Window::GetVisibleWidth() const
 {
     Size aWinSize = PixelToLogic(GetOutputSizePixel());
-    if ( aWinSize.Width() > maViewSize.Width() )
-        aWinSize.setWidth( maViewSize.Width() );
     return
         maViewSize.Width() == 0 ? 0 : (static_cast<double>(aWinSize.Width()) / 
maViewSize.Width());
 }
@@ -680,8 +678,6 @@ double Window::GetVisibleWidth() const
 double Window::GetVisibleHeight() const
 {
     Size aWinSize = PixelToLogic(GetOutputSizePixel());
-    if ( aWinSize.Height() > maViewSize.Height() )
-        aWinSize.setHeight( maViewSize.Height() );
     return maViewSize.Height() == 0
         ? 0 : (static_cast<double>(aWinSize.Height()) / maViewSize.Height());
 }
@@ -705,7 +701,7 @@ Point Window::GetVisibleCenter()
  */
 double Window::GetScrlLineWidth() const
 {
-    return (GetVisibleWidth() * SCROLL_LINE_FACT);
+    return std::min(1.0, GetVisibleWidth()) * SCROLL_LINE_FACT;
 }
 
 /**
@@ -714,7 +710,7 @@ double Window::GetScrlLineWidth() const
  */
 double Window::GetScrlLineHeight() const
 {
-    return (GetVisibleHeight() * SCROLL_LINE_FACT);
+    return std::min(1.0, GetVisibleHeight()) * SCROLL_LINE_FACT;
 }
 
 /**
@@ -723,7 +719,7 @@ double Window::GetScrlLineHeight() const
  */
 double Window::GetScrlPageWidth() const
 {
-    return (GetVisibleWidth() * SCROLL_PAGE_FACT);
+    return std::min(1.0, GetVisibleWidth()) * SCROLL_PAGE_FACT;
 }
 
 /**
@@ -732,7 +728,7 @@ double Window::GetScrlPageWidth() const
  */
 double Window::GetScrlPageHeight() const
 {
-    return (GetVisibleHeight() * SCROLL_PAGE_FACT);
+    return std::min(1.0, GetVisibleHeight()) * SCROLL_PAGE_FACT;
 }
 
 /**
diff --git a/sd/source/ui/view/viewshe2.cxx b/sd/source/ui/view/viewshe2.cxx
index b7ae44f2c3e1..18658fc8c929 100644
--- a/sd/source/ui/view/viewshe2.cxx
+++ b/sd/source/ui/view/viewshe2.cxx
@@ -63,6 +63,19 @@
 
 using namespace com::sun::star;
 
+namespace
+{
+inline double getViewToScrollScalarForPanAcrossPages(sal_uInt16 nTotalPages, 
double fVisibleHeight,
+                                                     ::tools::Long 
nScrollRangeMax)
+{
+    // fTotalScrollableRange is (1 - fVisibleHeight) for all of the
+    // pages except the last one. Because switch to the next page
+    // happens when the view reaches bottom.
+    double fTotalScrollableRange = (nTotalPages - 1) * (1 - fVisibleHeight) + 
1.0;
+    return nScrollRangeMax / fTotalScrollableRange;
+}
+}
+
 namespace sd {
 
 /**
@@ -72,7 +85,7 @@ void ViewShell::UpdateScrollBars()
 {
     if (mpHorizontalScrollBar)
     {
-        ::tools::Long nW = 
static_cast<::tools::Long>(mpContentWindow->GetVisibleWidth() * 32000);
+        ::tools::Long nW = static_cast<::tools::Long>(std::min(1.0, 
mpContentWindow->GetVisibleWidth()) * 32000);
         ::tools::Long nX = 
static_cast<::tools::Long>(mpContentWindow->GetVisibleX() * 32000);
         mpHorizontalScrollBar->SetVisibleSize(nW);
         mpHorizontalScrollBar->SetThumbPos(nX);
@@ -85,10 +98,32 @@ void ViewShell::UpdateScrollBars()
 
     if (mpVerticalScrollBar)
     {
-        ::tools::Long nH = 
static_cast<::tools::Long>(mpContentWindow->GetVisibleHeight() * 32000);
-        ::tools::Long nY = 
static_cast<::tools::Long>(mpContentWindow->GetVisibleY() * 32000);
+        if (CanPanAcrossPages())
+        {
+            SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
+            sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) / 2;
+            sal_uInt16 nTotalPages = 
GetDoc()->GetSdPageCount(pPage->GetPageKind());
 
-        if(IsPageFlipMode()) // ie in zoom mode where no panning
+            // nRangeMax is max int, and not ::tools::Long since the underlying
+            // implementation weld::Scrollbar uses int
+            ::tools::Long nRangeMax = std::numeric_limits<int>::max();
+            double fVisibleHeight = 
std::min(mpContentWindow->GetVisibleHeight(), 1.0);
+            double fMappingFactor
+                = getViewToScrollScalarForPanAcrossPages(nTotalPages, 
fVisibleHeight, nRangeMax);
+            double fVisibleY = std::max(0.0, mpContentWindow->GetVisibleY());
+            double fCurrentThumbPos = nCurPage * (1 - fVisibleHeight) + 
fVisibleY;
+            double fScrollLineHeight
+                = mpContentWindow->GetScrlLineHeight() * (1.0 - 
fVisibleHeight);
+            double fScrollPageHeight
+                = mpContentWindow->GetScrlPageHeight() * (1.0 - 
fVisibleHeight);
+
+            mpVerticalScrollBar->SetRange(Range(0, nRangeMax));
+            mpVerticalScrollBar->SetVisibleSize(fVisibleHeight * 
fMappingFactor);
+            mpVerticalScrollBar->SetThumbPos(fCurrentThumbPos * 
fMappingFactor);
+            mpVerticalScrollBar->SetLineSize(fScrollLineHeight * 
fMappingFactor);
+            mpVerticalScrollBar->SetPageSize(fScrollPageHeight * 
fMappingFactor);
+        }
+        else if (IsPageFlipMode()) // ie in zoom mode where no panning
         {
             SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
             sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) / 2;
@@ -99,8 +134,11 @@ void ViewShell::UpdateScrollBars()
             mpVerticalScrollBar->SetLineSize(256);
             mpVerticalScrollBar->SetPageSize(256);
         }
-        else
+        else // single page pan mode
         {
+            ::tools::Long nH = static_cast<::tools::Long>(std::min(1.0, 
mpContentWindow->GetVisibleHeight()) * 32000);
+            ::tools::Long nY = 
static_cast<::tools::Long>(mpContentWindow->GetVisibleY() * 32000);
+
             mpVerticalScrollBar->SetRange(Range(0,32000));
             mpVerticalScrollBar->SetVisibleSize(nH);
             mpVerticalScrollBar->SetThumbPos(nY);
@@ -180,18 +218,8 @@ IMPL_LINK_NOARG(ViewShell, VScrollHdl, weld::Scrollbar&, 
void)
  */
 void ViewShell::VirtVScrollHdl(ScrollAdaptor* pVScroll)
 {
-    if(IsPageFlipMode())
-    {
-        SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
-        sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) >> 1;
-        sal_uInt16 nNewPage = 
static_cast<sal_uInt16>(pVScroll->GetThumbPos())/256;
-        if( nCurPage != nNewPage )
-            static_cast<DrawViewShell*>(this)->SwitchPage(nNewPage);
-    }
-    else //panning mode
+    auto doScrollView = [&](double fY)
     {
-        double fY = static_cast<double>(pVScroll->GetThumbPos()) / 
pVScroll->GetRange().Len();
-
         ::sd::View* pView = GetView();
         OutlinerView* pOLV = nullptr;
 
@@ -222,7 +250,44 @@ void ViewShell::VirtVScrollHdl(ScrollAdaptor* pVScroll)
 
         if (mbHasRulers)
             UpdateVRuler();
+    };
 
+    if (CanPanAcrossPages())
+    {
+        SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
+        sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) >> 1;
+        sal_uInt16 nTotalPages = 
GetDoc()->GetSdPageCount(pPage->GetPageKind());
+
+        double fVisibleHeight = mpContentWindow->GetVisibleHeight();
+        double fMappingFactor = 
getViewToScrollScalarForPanAcrossPages(nTotalPages, fVisibleHeight,
+                                                                       
pVScroll->GetRange().Max());
+
+        double fScrollableDistancePerPage = 1 - std::min(fVisibleHeight, 1.0);
+
+        sal_uInt16 nNewPage
+            = std::min((pVScroll->GetThumbPos() / fMappingFactor) / 
fScrollableDistancePerPage,
+                       static_cast<double>(nTotalPages - 1));
+
+        if (nCurPage != nNewPage)
+            static_cast<DrawViewShell*>(this)->SwitchPage(nNewPage);
+
+        double fNewPageStart = nNewPage * fScrollableDistancePerPage;
+        double fY = (pVScroll->GetThumbPos() / fMappingFactor) - fNewPageStart;
+
+        doScrollView(fY);
+    }
+    else if (IsPageFlipMode())
+    {
+        SdPage* pPage = static_cast<DrawViewShell*>(this)->GetActualPage();
+        sal_uInt16 nCurPage = (pPage->GetPageNum() - 1) >> 1;
+        sal_uInt16 nNewPage = 
static_cast<sal_uInt16>(pVScroll->GetThumbPos())/256;
+        if( nCurPage != nNewPage )
+            static_cast<DrawViewShell*>(this)->SwitchPage(nNewPage);
+    }
+    else // single page panning mode
+    {
+        double fY = static_cast<double>(pVScroll->GetThumbPos()) / 
pVScroll->GetRange().Len();
+        doScrollView(fY);
     }
 }
 
diff --git a/sd/source/ui/view/viewshel.cxx b/sd/source/ui/view/viewshel.cxx
index 9d0c7c98b7db..b341c8a29d85 100644
--- a/sd/source/ui/view/viewshel.cxx
+++ b/sd/source/ui/view/viewshel.cxx
@@ -111,6 +111,13 @@ private:
 
 namespace sd {
 
+/// When true, scrolling to bottom of a page switches to the next page.
+bool ViewShell::CanPanAcrossPages() const
+{
+    return dynamic_cast<const DrawViewShell*>(this) && mpContentWindow &&
+        mpContentWindow->GetVisibleHeight() < 1.0;
+}
+
 bool ViewShell::IsPageFlipMode() const
 {
     return dynamic_cast< const DrawViewShell *>( this ) !=  nullptr && 
mpContentWindow &&

Reply via email to