1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  *   Licensed to the Apache Software Foundation (ASF) under one or more
12  *   contributor license agreements. See the NOTICE file distributed
13  *   with this work for additional information regarding copyright
14  *   ownership. The ASF licenses this file to you under the Apache
15  *   License, Version 2.0 (the "License"); you may not use this file
16  *   except in compliance with the License. You may obtain a copy of
17  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <controller/SlsScrollBarManager.hxx>
21 
22 #include <SlideSorter.hxx>
23 #include <ViewShell.hxx>
24 #include <controller/SlideSorterController.hxx>
25 #include <controller/SlsVisibleAreaManager.hxx>
26 #include <model/SlideSorterModel.hxx>
27 #include <model/SlsPageDescriptor.hxx>
28 #include <view/SlideSorterView.hxx>
29 #include <view/SlsLayouter.hxx>
30 #include <Window.hxx>
31 #include <sdpage.hxx>
32 #include <osl/diagnose.h>
33 
34 #include <vcl/scrbar.hxx>
35 
36 namespace sd::slidesorter::controller {
37 
38 constexpr double gnHorizontalScrollFactor(0.15);
39 constexpr double gnVerticalScrollFactor(0.25);
40 
ScrollBarManager(SlideSorter & rSlideSorter)41 ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter)
42     : mrSlideSorter(rSlideSorter),
43       mpHorizontalScrollBar(mrSlideSorter.GetHorizontalScrollBar()),
44       mpVerticalScrollBar(mrSlideSorter.GetVerticalScrollBar()),
45       mnHorizontalPosition (0),
46       mnVerticalPosition (0),
47       maScrollBorder (20,20),
48       mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()),
49       maAutoScrollTimer(),
50       maAutoScrollOffset(0,0),
51       mbIsAutoScrollActive(false),
52       mpContentWindow(mrSlideSorter.GetContentWindow()),
53       maAutoScrollFunctor()
54 {
55     // Hide the scroll bars by default to prevent display errors while
56     // switching between view shells:  In the short time between initiating
57     // such a switch and the final rearrangement of UI controls the scroll
58     // bars and the filler where displayed in the upper left corner of the
59     // ViewTabBar.
60     mpHorizontalScrollBar->Hide();
61     mpVerticalScrollBar->Hide();
62     mpScrollBarFiller->Hide();
63 
64     maAutoScrollTimer.SetTimeout(25);
65     maAutoScrollTimer.SetInvokeHandler (
66         LINK(this, ScrollBarManager, AutoScrollTimeoutHandler));
67 }
68 
~ScrollBarManager()69 ScrollBarManager::~ScrollBarManager()
70 {
71 }
72 
Connect()73 void ScrollBarManager::Connect()
74 {
75     if (mpVerticalScrollBar != nullptr)
76     {
77         mpVerticalScrollBar->SetScrollHdl (
78             LINK(this, ScrollBarManager, VerticalScrollBarHandler));
79     }
80     if (mpHorizontalScrollBar != nullptr)
81     {
82         mpHorizontalScrollBar->SetScrollHdl(
83             LINK(this, ScrollBarManager, HorizontalScrollBarHandler));
84     }
85 }
86 
Disconnect()87 void ScrollBarManager::Disconnect()
88 {
89     if (mpVerticalScrollBar != nullptr)
90     {
91         mpVerticalScrollBar->SetScrollHdl( Link<ScrollBar*,void>() );
92     }
93     if (mpHorizontalScrollBar != nullptr)
94     {
95         mpHorizontalScrollBar->SetScrollHdl( Link<ScrollBar*,void>() );
96     }
97 }
98 
99 /** Placing the scroll bars is an iterative process.  The visibility of one
100     scroll bar affects the remaining size and thus may lead to the other
101     scroll bar becoming visible.
102 
103     First we determine the visibility of the horizontal scroll bar.  After
104     that we do the same for the vertical scroll bar.  To have an initial
105     value for the required size we call the layouter before that.  When one
106     of the two scroll bars is made visible then the size of the browser
107     window changes and a second call to the layouter becomes necessary.
108     That call is made anyway after this method returns.
109 */
PlaceScrollBars(const::tools::Rectangle & rAvailableArea,const bool bIsHorizontalScrollBarAllowed,const bool bIsVerticalScrollBarAllowed)110 ::tools::Rectangle ScrollBarManager::PlaceScrollBars (
111     const ::tools::Rectangle& rAvailableArea,
112     const bool bIsHorizontalScrollBarAllowed,
113     const bool bIsVerticalScrollBarAllowed)
114 {
115     ::tools::Rectangle aRemainingSpace (DetermineScrollBarVisibilities(
116         rAvailableArea,
117         bIsHorizontalScrollBarAllowed,
118         bIsVerticalScrollBarAllowed));
119 
120     if (mpHorizontalScrollBar!=nullptr && mpHorizontalScrollBar->IsVisible())
121         PlaceHorizontalScrollBar (rAvailableArea);
122 
123     if (mpVerticalScrollBar!=nullptr && mpVerticalScrollBar->IsVisible())
124         PlaceVerticalScrollBar (rAvailableArea);
125 
126     if (mpScrollBarFiller!=nullptr && mpScrollBarFiller->IsVisible())
127         PlaceFiller (rAvailableArea);
128 
129     return aRemainingSpace;
130 }
131 
PlaceHorizontalScrollBar(const::tools::Rectangle & aAvailableArea)132 void ScrollBarManager::PlaceHorizontalScrollBar (const ::tools::Rectangle& aAvailableArea)
133 {
134     // Save the current relative position.
135     mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos())
136         / double(mpHorizontalScrollBar->GetRange().Len());
137 
138     // Place the scroll bar.
139     Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel());
140     mpHorizontalScrollBar->SetPosSizePixel (
141         Point(aAvailableArea.Left(),
142             aAvailableArea.Bottom()-aScrollBarSize.Height()+1),
143         Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(),
144             aScrollBarSize.Height()));
145 
146     // Restore the relative position.
147     mpHorizontalScrollBar->SetThumbPos(
148         static_cast<::tools::Long>(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len()));
149 }
150 
PlaceVerticalScrollBar(const::tools::Rectangle & aArea)151 void ScrollBarManager::PlaceVerticalScrollBar (const ::tools::Rectangle& aArea)
152 {
153     const sal_Int32 nThumbPosition (mpVerticalScrollBar->GetThumbPos());
154 
155     // Place the scroll bar.
156     Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel());
157     Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top());
158     Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight());
159     mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize);
160 
161     // Restore the position.
162     mpVerticalScrollBar->SetThumbPos(static_cast<::tools::Long>(nThumbPosition));
163     mnVerticalPosition = nThumbPosition / double(mpVerticalScrollBar->GetRange().Len());
164 }
165 
PlaceFiller(const::tools::Rectangle & aArea)166 void ScrollBarManager::PlaceFiller (const ::tools::Rectangle& aArea)
167 {
168     mpScrollBarFiller->SetPosSizePixel(
169         Point(
170             aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1,
171             aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1),
172         Size (
173             mpVerticalScrollBar->GetSizePixel().Width(),
174             mpHorizontalScrollBar->GetSizePixel().Height()));
175 }
176 
UpdateScrollBars(bool bUseScrolling)177 void ScrollBarManager::UpdateScrollBars(bool bUseScrolling)
178 {
179     ::tools::Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
180     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
181     Size aWindowModelSize (pWindow->PixelToLogic(pWindow->GetSizePixel()));
182 
183     // The horizontal scroll bar is only shown when the window is
184     // horizontally smaller than the view.
185     if (mpHorizontalScrollBar != nullptr && mpHorizontalScrollBar->IsVisible())
186     {
187         mpHorizontalScrollBar->Show();
188         mpHorizontalScrollBar->SetRange (
189             Range(aModelArea.Left(), aModelArea.Right()));
190         mnHorizontalPosition =
191                 double(mpHorizontalScrollBar->GetThumbPos())
192                 / double(mpHorizontalScrollBar->GetRange().Len());
193 
194         mpHorizontalScrollBar->SetVisibleSize (aWindowModelSize.Width());
195 
196         const ::tools::Long nWidth (mpContentWindow->PixelToLogic(
197             mpContentWindow->GetSizePixel()).Width());
198         // Make the line size about 10% of the visible width.
199         mpHorizontalScrollBar->SetLineSize (nWidth / 10);
200         // Make the page size about 90% of the visible width.
201         mpHorizontalScrollBar->SetPageSize ((nWidth * 9) / 10);
202     }
203     else
204     {
205         mnHorizontalPosition = 0;
206     }
207 
208     // The vertical scroll bar is always shown.
209     if (mpVerticalScrollBar != nullptr && mpVerticalScrollBar->IsVisible())
210     {
211         mpVerticalScrollBar->SetRange (
212             Range(aModelArea.Top(), aModelArea.Bottom()));
213         mnVerticalPosition =
214                 double(mpVerticalScrollBar->GetThumbPos())
215                 / double(mpVerticalScrollBar->GetRange().Len());
216 
217         mpVerticalScrollBar->SetVisibleSize (aWindowModelSize.Height());
218 
219         const ::tools::Long nHeight (mpContentWindow->PixelToLogic(
220             mpContentWindow->GetSizePixel()).Height());
221         // Make the line size about 10% of the visible height.
222         mpVerticalScrollBar->SetLineSize (nHeight / 10);
223         // Make the page size about 90% of the visible height.
224         mpVerticalScrollBar->SetPageSize ((nHeight * 9) / 10);
225     }
226     else
227     {
228         mnVerticalPosition = 0;
229     }
230 
231     double nEps (::std::numeric_limits<double>::epsilon());
232     if (fabs(mnHorizontalPosition-pWindow->GetVisibleX()) > nEps
233         || fabs(mnVerticalPosition-pWindow->GetVisibleY()) > nEps)
234     {
235         mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
236         if (bUseScrolling)
237             pWindow->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition);
238         else
239             SetWindowOrigin(mnHorizontalPosition, mnVerticalPosition);
240     }
241 }
242 
IMPL_LINK(ScrollBarManager,VerticalScrollBarHandler,ScrollBar *,pScrollBar,void)243 IMPL_LINK(ScrollBarManager, VerticalScrollBarHandler, ScrollBar*, pScrollBar, void)
244 {
245     if (pScrollBar!=nullptr
246         && pScrollBar==mpVerticalScrollBar.get()
247         && pScrollBar->IsVisible()
248         && mrSlideSorter.GetContentWindow())
249     {
250         double nRelativePosition = double(pScrollBar->GetThumbPos())
251             / double(pScrollBar->GetRange().Len());
252         mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
253         mrSlideSorter.GetContentWindow()->SetVisibleXY(-1, nRelativePosition);
254         mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking();
255     }
256 }
257 
IMPL_LINK(ScrollBarManager,HorizontalScrollBarHandler,ScrollBar *,pScrollBar,void)258 IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar, void)
259 {
260     if (pScrollBar!=nullptr
261         && pScrollBar==mpHorizontalScrollBar.get()
262         && pScrollBar->IsVisible()
263         && mrSlideSorter.GetContentWindow())
264     {
265         double nRelativePosition = double(pScrollBar->GetThumbPos())
266             / double(pScrollBar->GetRange().Len());
267         mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
268         mrSlideSorter.GetContentWindow()->SetVisibleXY(nRelativePosition, -1);
269         mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking();
270     }
271 }
272 
SetWindowOrigin(double nHorizontalPosition,double nVerticalPosition)273 void ScrollBarManager::SetWindowOrigin (
274     double nHorizontalPosition,
275     double nVerticalPosition)
276 {
277     mnHorizontalPosition = nHorizontalPosition;
278     mnVerticalPosition = nVerticalPosition;
279 
280     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
281     Size aViewSize (pWindow->GetViewSize());
282     Point aOrigin (
283         static_cast<::tools::Long>(mnHorizontalPosition * aViewSize.Width()),
284         static_cast<::tools::Long>(mnVerticalPosition * aViewSize.Height()));
285 
286     pWindow->SetWinViewPos (aOrigin);
287     pWindow->UpdateMapMode ();
288     pWindow->Invalidate ();
289 }
290 
291 /** Determining the visibility of the scroll bars is quite complicated.  The
292     visibility of one influences that of the other because showing a scroll
293     bar makes the available space smaller and may lead to the need of
294     displaying the other.
295     To solve this we test all four combinations of showing or hiding each
296     scroll bar and use the best one.  The best one is that combination that
297     a) shows the least number of scroll bars with preference of showing the
298     vertical over showing the horizontal and
299     b) when not showing a scroll bar the area used by the page objects fits
300     into the available area in the scroll bars orientation.
301 */
DetermineScrollBarVisibilities(const::tools::Rectangle & rAvailableArea,const bool bIsHorizontalScrollBarAllowed,const bool bIsVerticalScrollBarAllowed)302 ::tools::Rectangle ScrollBarManager::DetermineScrollBarVisibilities (
303     const ::tools::Rectangle& rAvailableArea,
304     const bool bIsHorizontalScrollBarAllowed,
305     const bool bIsVerticalScrollBarAllowed)
306 {
307     // Test which combination of scroll bars is the best.
308     bool bShowHorizontal = false;
309     bool bShowVertical = false;
310     if (mrSlideSorter.GetModel().GetPageCount() == 0)
311     {
312         // No pages => no scroll bars.
313     }
314     else if (TestScrollBarVisibilities(false, false, rAvailableArea))
315     {
316         // Nothing to be done.
317     }
318     else if (bIsHorizontalScrollBarAllowed
319         && TestScrollBarVisibilities(true, false, rAvailableArea))
320     {
321         bShowHorizontal = true;
322     }
323     else if (bIsVerticalScrollBarAllowed
324         && TestScrollBarVisibilities(false, true, rAvailableArea))
325     {
326         bShowVertical = true;
327     }
328     else
329     {
330         bShowHorizontal = true;
331         bShowVertical = true;
332     }
333 
334     // Make the visibility of the scroll bars permanent.
335     mpVerticalScrollBar->Show(bShowVertical);
336     mpHorizontalScrollBar->Show(bShowHorizontal);
337     mpScrollBarFiller->Show(bShowVertical && bShowHorizontal);
338 
339     // Adapt the remaining space accordingly.
340     ::tools::Rectangle aRemainingSpace (rAvailableArea);
341     if (bShowVertical)
342         aRemainingSpace.AdjustRight( -(mpVerticalScrollBar->GetSizePixel().Width()) );
343     if (bShowHorizontal)
344         aRemainingSpace.AdjustBottom( -(mpHorizontalScrollBar->GetSizePixel().Height()) );
345 
346     return aRemainingSpace;
347 }
348 
TestScrollBarVisibilities(bool bHorizontalScrollBarVisible,bool bVerticalScrollBarVisible,const::tools::Rectangle & rAvailableArea)349 bool ScrollBarManager::TestScrollBarVisibilities (
350     bool bHorizontalScrollBarVisible,
351     bool bVerticalScrollBarVisible,
352     const ::tools::Rectangle& rAvailableArea)
353 {
354     model::SlideSorterModel& rModel (mrSlideSorter.GetModel());
355 
356     // Adapt the available size by subtracting the sizes of the scroll bars
357     // visible in this combination.
358     Size aBrowserSize (rAvailableArea.GetSize());
359     if (bHorizontalScrollBarVisible)
360         aBrowserSize.AdjustHeight( -(mpHorizontalScrollBar->GetSizePixel().Height()) );
361     if (bVerticalScrollBarVisible)
362         aBrowserSize.AdjustWidth( -(mpVerticalScrollBar->GetSizePixel().Width()) );
363 
364     // Tell the view to rearrange its page objects and check whether the
365     // page objects can be shown without clipping.
366     bool bRearrangeSuccess (mrSlideSorter.GetView().GetLayouter().Rearrange (
367         mrSlideSorter.GetView().GetOrientation(),
368         aBrowserSize,
369         rModel.GetPageDescriptor(0)->GetPage()->GetSize(),
370         rModel.GetPageCount()));
371 
372     if (bRearrangeSuccess)
373     {
374         Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetTotalBoundingBox().GetSize();
375         Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize);
376 
377         // The content may be clipped, i.e. not fully visible, in one
378         // direction only when the scroll bar is visible in that direction.
379         if (aPageSize.Width() > aWindowModelSize.Width())
380             if ( ! bHorizontalScrollBarVisible)
381                 return false;
382         if (aPageSize.Height() > aWindowModelSize.Height())
383             if ( ! bVerticalScrollBarVisible)
384                 return false;
385 
386         return true;
387     }
388     else
389         return false;
390 }
391 
SetTopLeft(const Point & rNewTopLeft)392 void ScrollBarManager::SetTopLeft(const Point& rNewTopLeft)
393 {
394     if (( ! mpVerticalScrollBar
395             || mpVerticalScrollBar->GetThumbPos() == rNewTopLeft.Y())
396         && ( ! mpHorizontalScrollBar
397             || mpHorizontalScrollBar->GetThumbPos() == rNewTopLeft.X()))
398         return;
399 
400     // Flush pending repaints before scrolling to avoid temporary artifacts.
401     mrSlideSorter.GetContentWindow()->PaintImmediately();
402 
403     if (mpVerticalScrollBar)
404     {
405         mpVerticalScrollBar->SetThumbPos(rNewTopLeft.Y());
406         mnVerticalPosition = rNewTopLeft.Y() / double(mpVerticalScrollBar->GetRange().Len());
407     }
408     if (mpHorizontalScrollBar)
409     {
410         mpHorizontalScrollBar->SetThumbPos(rNewTopLeft.X());
411         mnHorizontalPosition = rNewTopLeft.X() / double(mpHorizontalScrollBar->GetRange().Len());
412     }
413 
414     mrSlideSorter.GetContentWindow()->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition);
415     mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
416 }
417 
GetVerticalScrollBarWidth() const418 int ScrollBarManager::GetVerticalScrollBarWidth() const
419 {
420     if (mpVerticalScrollBar != nullptr && mpVerticalScrollBar->IsVisible())
421         return mpVerticalScrollBar->GetSizePixel().Width();
422     else
423         return 0;
424 }
425 
GetHorizontalScrollBarHeight() const426 int ScrollBarManager::GetHorizontalScrollBarHeight() const
427 {
428     if (mpHorizontalScrollBar != nullptr && mpHorizontalScrollBar->IsVisible())
429         return mpHorizontalScrollBar->GetSizePixel().Height();
430     else
431         return 0;
432 }
433 
CalcAutoScrollOffset(const Point & rMouseWindowPosition)434 void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition)
435 {
436     sd::Window *pWindow (mrSlideSorter.GetContentWindow().get());
437 
438     int nDx = 0;
439     int nDy = 0;
440 
441     Size aWindowSize = pWindow->GetOutputSizePixel();
442     ::tools::Rectangle aWindowArea (pWindow->GetPosPixel(), aWindowSize);
443     ::tools::Rectangle aViewPixelArea (
444         pWindow->LogicToPixel(mrSlideSorter.GetView().GetModelArea()));
445 
446     if (aWindowSize.Width() > maScrollBorder.Width() * 3
447         && mpHorizontalScrollBar != nullptr
448         && mpHorizontalScrollBar->IsVisible())
449     {
450         if (rMouseWindowPosition.X() < maScrollBorder.Width()
451             && aWindowArea.Left() > aViewPixelArea.Left())
452         {
453             nDx = -1 + static_cast<int>(gnHorizontalScrollFactor
454                 * (rMouseWindowPosition.X() - maScrollBorder.Width()));
455         }
456 
457         if (rMouseWindowPosition.X() >= (aWindowSize.Width() - maScrollBorder.Width())
458             && aWindowArea.Right() < aViewPixelArea.Right())
459         {
460             nDx = 1 + static_cast<int>(gnHorizontalScrollFactor
461                 * (rMouseWindowPosition.X() - aWindowSize.Width()
462                     + maScrollBorder.Width()));
463         }
464     }
465 
466     if (aWindowSize.Height() > maScrollBorder.Height() * 3
467         && aWindowSize.Height() < aViewPixelArea.GetHeight())
468     {
469         if (rMouseWindowPosition.Y() < maScrollBorder.Height()
470             && aWindowArea.Top() > aViewPixelArea.Top())
471         {
472             nDy = -1 + static_cast<int>(gnVerticalScrollFactor
473                 * (rMouseWindowPosition.Y() - maScrollBorder.Height()));
474         }
475 
476         if (rMouseWindowPosition.Y() >= (aWindowSize.Height() - maScrollBorder.Height())
477             && aWindowArea.Bottom() < aViewPixelArea.Bottom())
478         {
479             nDy = 1 + static_cast<int>(gnVerticalScrollFactor
480                 * (rMouseWindowPosition.Y() - aWindowSize.Height()
481                     + maScrollBorder.Height()));
482         }
483     }
484 
485     maAutoScrollOffset = Size(nDx,nDy);
486 }
487 
AutoScroll(const Point & rMouseWindowPosition,const::std::function<void ()> & rAutoScrollFunctor)488 bool ScrollBarManager::AutoScroll (
489     const Point& rMouseWindowPosition,
490     const ::std::function<void ()>& rAutoScrollFunctor)
491 {
492     maAutoScrollFunctor = rAutoScrollFunctor;
493     CalcAutoScrollOffset(rMouseWindowPosition);
494     bool bResult (true);
495     if ( ! mbIsAutoScrollActive)
496         bResult = RepeatAutoScroll();
497 
498     return bResult;
499 }
500 
StopAutoScroll()501 void ScrollBarManager::StopAutoScroll()
502 {
503     maAutoScrollTimer.Stop();
504     mbIsAutoScrollActive = false;
505 }
506 
RepeatAutoScroll()507 bool ScrollBarManager::RepeatAutoScroll()
508 {
509     if (maAutoScrollOffset != Size(0,0))
510     {
511         if (mrSlideSorter.GetViewShell() != nullptr)
512         {
513             mrSlideSorter.GetViewShell()->Scroll(
514                 maAutoScrollOffset.Width(),
515                 maAutoScrollOffset.Height());
516             mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
517 
518             if (maAutoScrollFunctor)
519                 maAutoScrollFunctor();
520 
521             mbIsAutoScrollActive = true;
522             maAutoScrollTimer.Start();
523 
524             return true;
525         }
526     }
527 
528     clearAutoScrollFunctor();
529     mbIsAutoScrollActive = false;
530     return false;
531 }
532 
clearAutoScrollFunctor()533 void ScrollBarManager::clearAutoScrollFunctor()
534 {
535     maAutoScrollFunctor = ::std::function<void ()>();
536 }
537 
IMPL_LINK_NOARG(ScrollBarManager,AutoScrollTimeoutHandler,Timer *,void)538 IMPL_LINK_NOARG(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, void)
539 {
540     RepeatAutoScroll();
541 }
542 
Scroll(const Orientation eOrientation,const sal_Int32 nDistance)543 void ScrollBarManager::Scroll(
544     const Orientation eOrientation,
545     const sal_Int32 nDistance)
546 {
547     bool bIsVertical (false);
548     switch (eOrientation)
549     {
550         case Orientation_Horizontal: bIsVertical = false; break;
551         case Orientation_Vertical: bIsVertical = true; break;
552         default:
553             OSL_ASSERT(eOrientation==Orientation_Horizontal || eOrientation==Orientation_Vertical);
554             return;
555     }
556 
557     Point aNewTopLeft (
558         mpHorizontalScrollBar ? mpHorizontalScrollBar->GetThumbPos() : 0,
559         mpVerticalScrollBar ? mpVerticalScrollBar->GetThumbPos() : 0);
560 
561     view::Layouter& rLayouter (mrSlideSorter.GetView().GetLayouter());
562 
563     // Calculate estimate of new location.
564     if (bIsVertical)
565         aNewTopLeft.AdjustY(nDistance * rLayouter.GetPageObjectSize().Height() );
566     else
567         aNewTopLeft.AdjustX(nDistance * rLayouter.GetPageObjectSize().Width() );
568 
569     // Adapt location to show whole slides.
570     if (bIsVertical)
571         if (nDistance > 0)
572         {
573             const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
574                 Point(aNewTopLeft.X(), aNewTopLeft.Y()+mpVerticalScrollBar->GetVisibleSize()),
575                 true));
576             aNewTopLeft.setY( rLayouter.GetPageObjectBox(nIndex,true).Bottom()
577                 - mpVerticalScrollBar->GetVisibleSize() );
578         }
579         else
580         {
581             const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
582                 Point(aNewTopLeft.X(), aNewTopLeft.Y()),
583                 true));
584             aNewTopLeft.setY( rLayouter.GetPageObjectBox(nIndex,true).Top() );
585         }
586     else
587         if (nDistance > 0)
588         {
589             const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
590                 Point(aNewTopLeft.X()+mpVerticalScrollBar->GetVisibleSize(), aNewTopLeft.Y()),
591                 true));
592             aNewTopLeft.setX( rLayouter.GetPageObjectBox(nIndex,true).Right()
593                 - mpVerticalScrollBar->GetVisibleSize() );
594         }
595         else
596         {
597             const sal_Int32 nIndex (rLayouter.GetIndexAtPoint(
598                 Point(aNewTopLeft.X(), aNewTopLeft.Y()),
599                     true));
600             aNewTopLeft.setX( rLayouter.GetPageObjectBox(nIndex,true).Left() );
601         }
602 
603     mrSlideSorter.GetController().GetVisibleAreaManager().DeactivateCurrentSlideTracking();
604     SetTopLeft(aNewTopLeft);
605 }
606 
607 } // end of namespace ::sd::slidesorter::controller
608 
609 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
610