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 <sarper@libreoffice.org>
diff --git a/sd/source/ui/inc/ViewShell.hxx b/sd/source/ui/inc/ViewShell.hxx
index 6ee126d..9e5e8e0 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 9203c06..e8fc847 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 6792250..99c1660 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 ab8a7bb..8f71c17 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 b7ae44f..18658fc 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())
auto doScrollView = [&](double fY)
{
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
{
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 9d0c7c9..b341c8a 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 &&