Update ooo320-m1
[ooovba.git] / sd / source / ui / slidesorter / controller / SlsScrollBarManager.cxx
blobf42cc0f245b9e0a2d4b25db6cd873c1de1563baa
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: SlsScrollBarManager.cxx,v $
10 * $Revision: 1.13 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 #include "precompiled_sd.hxx"
33 #include "controller/SlsScrollBarManager.hxx"
35 #include "SlideSorter.hxx"
36 #include "controller/SlideSorterController.hxx"
37 #include "model/SlideSorterModel.hxx"
38 #include "model/SlsPageDescriptor.hxx"
39 #include "view/SlideSorterView.hxx"
40 #include "view/SlsLayouter.hxx"
41 #include "view/SlsViewOverlay.hxx"
42 #include "Window.hxx"
43 #include "sdpage.hxx"
45 #include <boost/limits.hpp>
47 #include <vcl/scrbar.hxx>
49 namespace sd { namespace slidesorter { namespace controller {
51 ScrollBarManager::ScrollBarManager (SlideSorter& rSlideSorter)
52 : mrSlideSorter(rSlideSorter),
53 mpHorizontalScrollBar(mrSlideSorter.GetHorizontalScrollBar()),
54 mpVerticalScrollBar(mrSlideSorter.GetVerticalScrollBar()),
55 mnHorizontalPosition (0),
56 mnVerticalPosition (0),
57 maScrollBorder (10,10),
58 mnHorizontalScrollFactor (0.1),
59 mnVerticalScrollFactor (0.1),
60 mpScrollBarFiller(mrSlideSorter.GetScrollBarFiller()),
61 mpContentWindow(mrSlideSorter.GetContentWindow())
63 // Hide the scroll bars by default to prevent display errors while
64 // switching between view shells: In the short time between initiating
65 // such a switch and the final rearrangement of UI controls the scroll
66 // bars and the filler where displayed in the upper left corner of the
67 // ViewTabBar.
68 mpHorizontalScrollBar->Hide();
69 mpVerticalScrollBar->Hide();
70 mpScrollBarFiller->Hide();
72 maAutoScrollTimer.SetTimeout(50);
73 maAutoScrollTimer.SetTimeoutHdl (
74 LINK(this, ScrollBarManager, AutoScrollTimeoutHandler));
80 ScrollBarManager::~ScrollBarManager (void)
87 void ScrollBarManager::LateInitialization (void)
94 void ScrollBarManager::Connect (void)
96 if (mpVerticalScrollBar != NULL)
97 mpVerticalScrollBar->SetScrollHdl (
98 LINK(
99 this,
100 ScrollBarManager,
101 VerticalScrollBarHandler));
102 if (mpHorizontalScrollBar != NULL)
103 mpHorizontalScrollBar->SetScrollHdl (
104 LINK(
105 this,
106 ScrollBarManager,
107 HorizontalScrollBarHandler));
113 void ScrollBarManager::Disconnect (void)
115 if (mpVerticalScrollBar != NULL)
116 mpVerticalScrollBar->SetScrollHdl (Link());
117 if (mpHorizontalScrollBar != NULL)
118 mpHorizontalScrollBar->SetScrollHdl (Link());
124 /** Placing the scroll bars is an iterative process. The visibility of one
125 scroll bar affects the remaining size and thus may lead to the other
126 scroll bar becoming visible.
128 First we determine the visibility of the horizontal scroll bar. After
129 that we do the same for the vertical scroll bar. To have an initial
130 value for the required size we call the layouter before that. When one
131 of the two scroll bars is made visible then the size of the browser
132 window changes and a second call to the layouter becomes necessary.
133 That call is made anyway after this method returns.
135 Rectangle ScrollBarManager::PlaceScrollBars (const Rectangle& rAvailableArea)
137 Rectangle aRemainingSpace (DetermineScrollBarVisibilities(rAvailableArea));
138 PlaceHorizontalScrollBar (rAvailableArea);
139 PlaceVerticalScrollBar (rAvailableArea);
140 PlaceFiller (rAvailableArea);
142 return aRemainingSpace;
148 void ScrollBarManager::PlaceHorizontalScrollBar (const Rectangle& aAvailableArea)
150 if (mpHorizontalScrollBar != NULL
151 && mpHorizontalScrollBar->IsVisible())
153 // Save the current relative position.
154 mnHorizontalPosition = double(mpHorizontalScrollBar->GetThumbPos())
155 / double(mpHorizontalScrollBar->GetRange().Len());
157 // Place the scroll bar.
158 Size aScrollBarSize (mpHorizontalScrollBar->GetSizePixel());
159 mpHorizontalScrollBar->SetPosSizePixel (
160 Point(aAvailableArea.Left(),
161 aAvailableArea.Bottom()-aScrollBarSize.Height()+1),
162 Size (aAvailableArea.GetWidth() - GetVerticalScrollBarWidth(),
163 aScrollBarSize.Height()));
165 // Restore the relative position.
166 mpHorizontalScrollBar->SetThumbPos(
167 (long)(0.5 + mnHorizontalPosition * mpHorizontalScrollBar->GetRange().Len()));
174 void ScrollBarManager::PlaceVerticalScrollBar (const Rectangle& aArea)
176 if (mpVerticalScrollBar != NULL
177 && mpVerticalScrollBar->IsVisible())
179 view::Layouter::DoublePoint aLayouterPosition
180 = mrSlideSorter.GetView().GetLayouter().ConvertModelToLayouterCoordinates (
181 Point (0, mpVerticalScrollBar->GetThumbPos()));
183 // Place the scroll bar.
184 Size aScrollBarSize (mpVerticalScrollBar->GetSizePixel());
185 Point aPosition (aArea.Right()-aScrollBarSize.Width()+1, aArea.Top());
186 Size aSize (aScrollBarSize.Width(), aArea.GetHeight() - GetHorizontalScrollBarHeight());
187 mpVerticalScrollBar->SetPosSizePixel(aPosition, aSize);
189 // Restore the position.
190 mpVerticalScrollBar->SetThumbPos(
191 mrSlideSorter.GetView().GetLayouter().ConvertLayouterToModelCoordinates(
192 aLayouterPosition).Y());
193 mnVerticalPosition = double(mpVerticalScrollBar->GetThumbPos())
194 / double(mpVerticalScrollBar->GetRange().Len());
201 void ScrollBarManager::PlaceFiller (const Rectangle& aArea)
203 // Place the filler when both scroll bars are visible.
204 if (mpHorizontalScrollBar != NULL
205 && mpVerticalScrollBar != NULL
206 && mpHorizontalScrollBar->IsVisible()
207 && mpVerticalScrollBar->IsVisible())
209 mpScrollBarFiller->SetPosSizePixel(
210 Point(
211 aArea.Right()-mpVerticalScrollBar->GetSizePixel().Width()+1,
212 aArea.Bottom()-mpHorizontalScrollBar->GetSizePixel().Height()+1),
213 Size (
214 mpVerticalScrollBar->GetSizePixel().Width(),
215 mpHorizontalScrollBar->GetSizePixel().Height()));
216 mpScrollBarFiller->Show();
218 else
219 mpScrollBarFiller->Hide();
225 void ScrollBarManager::AdaptWindowSize (const Rectangle& rArea)
227 Size aPixelContentSize (mpContentWindow->LogicToPixel(
228 mrSlideSorter.GetView().GetLayouter().GetPageBox (
229 mrSlideSorter.GetModel().GetPageCount()).GetSize()));
230 int nHeightDifference = aPixelContentSize.Height() - rArea.GetHeight();
231 ::Window* pParentWindow = mpContentWindow->GetParent();
232 Size aNewWindowSize (pParentWindow->GetSizePixel());
233 if (nHeightDifference != 0)
235 aNewWindowSize.Height() += nHeightDifference;
236 pParentWindow->SetPosSizePixel(
237 pParentWindow->GetPosPixel(),
238 aNewWindowSize);
245 void ScrollBarManager::UpdateScrollBars (bool bResetThumbPosition, bool bUseScrolling)
247 Rectangle aModelArea (mrSlideSorter.GetView().GetModelArea());
248 ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow();
249 Size aWindowModelSize (pWindow->PixelToLogic(pWindow->GetSizePixel()));
251 // The horizontal scroll bar is only shown when the window is
252 // horizontally smaller than the view.
253 if (mpHorizontalScrollBar != NULL && mpHorizontalScrollBar->IsVisible())
255 mpHorizontalScrollBar->Show();
256 mpHorizontalScrollBar->SetRange (
257 Range(aModelArea.Left(), aModelArea.Right()));
258 if (bResetThumbPosition)
260 mpHorizontalScrollBar->SetThumbPos (0);
261 mnHorizontalPosition = 0;
263 else
264 mnHorizontalPosition =
265 double(mpHorizontalScrollBar->GetThumbPos())
266 / double(mpHorizontalScrollBar->GetRange().Len());
268 mpHorizontalScrollBar->SetVisibleSize (aWindowModelSize.Width());
270 const long nWidth (mpContentWindow->PixelToLogic(
271 mpContentWindow->GetSizePixel()).Width());
272 // Make the line size about 10% of the visible width.
273 mpHorizontalScrollBar->SetLineSize (nWidth / 10);
274 // Make the page size about 90% of the visible width.
275 mpHorizontalScrollBar->SetPageSize ((nWidth * 9) / 10);
277 else
279 mnHorizontalPosition = 0;
282 // The vertical scroll bar is always shown.
283 if (mpVerticalScrollBar != NULL && mpVerticalScrollBar->IsVisible())
285 mpVerticalScrollBar->SetRange (
286 Range(aModelArea.Top(), aModelArea.Bottom()));
287 if (bResetThumbPosition)
289 mpVerticalScrollBar->SetThumbPos (0);
290 mnVerticalPosition = 0;
292 else
293 mnVerticalPosition =
294 double(mpVerticalScrollBar->GetThumbPos())
295 / double(mpVerticalScrollBar->GetRange().Len());
297 mpVerticalScrollBar->SetVisibleSize (aWindowModelSize.Height());
299 const long nHeight (mpContentWindow->PixelToLogic(
300 mpContentWindow->GetSizePixel()).Height());
301 // Make the line size about 10% of the visible height.
302 mpVerticalScrollBar->SetLineSize (nHeight / 10);
303 // Make the page size about 90% of the visible height.
304 mpVerticalScrollBar->SetPageSize ((nHeight * 9) / 10);
306 else
308 mnVerticalPosition = 0;
312 double nEps (::std::numeric_limits<double>::epsilon());
313 if (fabs(mnHorizontalPosition-pWindow->GetVisibleX()) > nEps
314 || fabs(mnVerticalPosition-pWindow->GetVisibleY()) > nEps)
316 mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
317 if (bUseScrolling)
318 pWindow->SetVisibleXY(mnHorizontalPosition, mnVerticalPosition);
319 else
320 SetWindowOrigin(mnHorizontalPosition, mnVerticalPosition);
327 IMPL_LINK(ScrollBarManager, VerticalScrollBarHandler, ScrollBar*, pScrollBar)
329 if (pScrollBar!=NULL
330 && pScrollBar==mpVerticalScrollBar.get()
331 && pScrollBar->IsVisible()
332 && mrSlideSorter.GetView().GetWindow()!=NULL)
334 double nRelativePosition = double(pScrollBar->GetThumbPos())
335 / double(pScrollBar->GetRange().Len());
336 mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
337 mrSlideSorter.GetView().GetWindow()->SetVisibleXY (
338 -1,
339 nRelativePosition);
341 return TRUE;
347 IMPL_LINK(ScrollBarManager, HorizontalScrollBarHandler, ScrollBar*, pScrollBar)
349 if (pScrollBar!=NULL
350 && pScrollBar==mpHorizontalScrollBar.get()
351 && pScrollBar->IsVisible()
352 && mrSlideSorter.GetView().GetWindow()!=NULL)
354 double nRelativePosition = double(pScrollBar->GetThumbPos())
355 / double(pScrollBar->GetRange().Len());
356 mrSlideSorter.GetView().InvalidatePageObjectVisibilities();
357 mrSlideSorter.GetView().GetWindow()->SetVisibleXY (nRelativePosition, -1);
359 return TRUE;
365 void ScrollBarManager::SetWindowOrigin (
366 double nHorizontalPosition,
367 double nVerticalPosition)
369 mnHorizontalPosition = nHorizontalPosition;
370 mnVerticalPosition = nVerticalPosition;
372 ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow();
373 Size aViewSize (pWindow->GetViewSize());
374 Point aOrigin (
375 (long int) (mnHorizontalPosition * aViewSize.Width()),
376 (long int) (mnVerticalPosition * aViewSize.Height()));
378 pWindow->SetWinViewPos (aOrigin);
379 pWindow->UpdateMapMode ();
380 pWindow->Invalidate ();
386 /** Determining the visibility of the scroll bars is quite complicated. The
387 visibility of one influences that of the other because showing a scroll
388 bar makes the available space smaller and may lead to the need of
389 displaying the other.
390 To solve this we test all four combinations of showing or hiding each
391 scroll bar and use the best one. The best one is that combination that
392 a) shows the least number of scroll bars with preference of showing the
393 vertical over showing the horizontal and
394 b) when not showing a scroll bar the area used by the page objects fits
395 into the available area in the scroll bars orientation.
397 Rectangle ScrollBarManager::DetermineScrollBarVisibilities (const Rectangle& rAvailableArea)
399 // Test which combination of scroll bars is the best.
400 bool bShowHorizontal = false;
401 bool bShowVertical = false;
404 if (mrSlideSorter.GetModel().GetPageCount() == 0)
405 // No pages => no scroll bars.
406 break;
408 if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=false, rAvailableArea))
409 break;
410 if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=false, rAvailableArea))
411 break;
412 if (TestScrollBarVisibilities(bShowHorizontal=false, bShowVertical=true, rAvailableArea))
413 break;
414 if (TestScrollBarVisibilities(bShowHorizontal=true, bShowVertical=true, rAvailableArea))
415 break;
417 while (false);
419 // Make the visibility of the scroll bars permanent.
420 mpVerticalScrollBar->Show(bShowVertical);
421 mpHorizontalScrollBar->Show(bShowHorizontal);
423 // Adapt the remaining space accordingly.
424 Rectangle aRemainingSpace (rAvailableArea);
425 if (bShowVertical)
426 aRemainingSpace.Right() -= mpVerticalScrollBar->GetSizePixel().Width();
427 if (bShowHorizontal)
428 aRemainingSpace.Bottom() -= mpHorizontalScrollBar->GetSizePixel().Height();
430 return aRemainingSpace;
436 bool ScrollBarManager::TestScrollBarVisibilities (
437 bool bHorizontalScrollBarVisible,
438 bool bVerticalScrollBarVisible,
439 const Rectangle& rAvailableArea)
441 bool bAreVisibilitiesOK = true;
443 // Adapt the available size by subtracting the sizes of the scroll bars
444 // visible in this combination.
445 Size aBrowserSize (rAvailableArea.GetSize());
446 if (bHorizontalScrollBarVisible)
447 aBrowserSize.Height() -= mpHorizontalScrollBar->GetSizePixel().Height();
448 if (bVerticalScrollBarVisible)
449 aBrowserSize.Width() -= mpVerticalScrollBar->GetSizePixel().Width();
451 // Tell the view to rearrange its page objects and check whether the
452 // page objects can be shown without clipping.
453 bool bRearrangeSuccess (false);
454 if (mrSlideSorter.GetView().GetOrientation() == view::SlideSorterView::HORIZONTAL)
456 bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeHorizontal (
457 aBrowserSize,
458 mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(),
459 mpContentWindow.get(),
460 mrSlideSorter.GetModel().GetPageCount());
462 else
464 bRearrangeSuccess = mrSlideSorter.GetView().GetLayouter().RearrangeVertical (
465 aBrowserSize,
466 mrSlideSorter.GetModel().GetPageDescriptor(0)->GetPage()->GetSize(),
467 mpContentWindow.get());
470 if (bRearrangeSuccess)
472 Size aPageSize = mrSlideSorter.GetView().GetLayouter().GetPageBox (
473 mrSlideSorter.GetModel().GetPageCount()).GetSize();
474 Size aWindowModelSize = mpContentWindow->PixelToLogic(aBrowserSize);
476 bool bHorizontallyClipped = (aPageSize.Width() > aWindowModelSize.Width());
477 bool bVerticallyClipped = (aPageSize.Height() > aWindowModelSize.Height());
478 bAreVisibilitiesOK = (bHorizontallyClipped == bHorizontalScrollBarVisible)
479 && (bVerticallyClipped == bVerticalScrollBarVisible);
481 else
482 bAreVisibilitiesOK = false;
484 return bAreVisibilitiesOK;
490 void ScrollBarManager::SetTop (const sal_Int32 nNewTop)
492 if (mpVerticalScrollBar != NULL
493 && mpVerticalScrollBar->GetThumbPos() != nNewTop)
495 // Flush pending repaints before scrolling to avoid temporary artifacts.
496 mrSlideSorter.GetView().GetWindow()->Update();
498 mpVerticalScrollBar->SetThumbPos(nNewTop);
499 mnVerticalPosition = double(nNewTop) / double(mpVerticalScrollBar->GetRange().Len());
500 mrSlideSorter.GetView().GetWindow()->SetVisibleXY (
501 mnHorizontalPosition, mnVerticalPosition);
508 void ScrollBarManager::SetLeft (const sal_Int32 nNewLeft)
510 if (mpHorizontalScrollBar != NULL
511 && mpHorizontalScrollBar->GetThumbPos() != nNewLeft)
513 // Flush pending repaints before scrolling to avoid temporary artifacts.
514 mrSlideSorter.GetView().GetWindow()->Update();
516 mpHorizontalScrollBar->SetThumbPos(nNewLeft);
517 mnHorizontalPosition = double(nNewLeft) / double(mpHorizontalScrollBar->GetRange().Len());
518 mrSlideSorter.GetView().GetWindow()->SetVisibleXY (
519 mnHorizontalPosition, mnVerticalPosition);
526 int ScrollBarManager::GetVerticalScrollBarWidth (void) const
528 if (mpVerticalScrollBar != NULL && mpVerticalScrollBar->IsVisible())
529 return mpVerticalScrollBar->GetSizePixel().Width();
530 else
531 return 0;
537 int ScrollBarManager::GetHorizontalScrollBarHeight (void) const
539 if (mpHorizontalScrollBar != NULL && mpHorizontalScrollBar->IsVisible())
540 return mpHorizontalScrollBar->GetSizePixel().Height();
541 else
542 return 0;
548 void ScrollBarManager::CalcAutoScrollOffset (const Point& rMouseWindowPosition)
550 ::sd::Window* pWindow = mrSlideSorter.GetView().GetWindow();
552 int nDx = 0;
553 int nDy = 0;
555 Size aWindowSize = pWindow->GetOutputSizePixel();
556 Rectangle aWindowArea (pWindow->GetPosPixel(), aWindowSize);
557 Rectangle aViewPixelArea (
558 pWindow->LogicToPixel(mrSlideSorter.GetView().GetModelArea()));
560 if (aWindowSize.Width() > maScrollBorder.Width() * 3
561 && mpHorizontalScrollBar != NULL
562 && mpHorizontalScrollBar->IsVisible())
564 if (rMouseWindowPosition.X() < maScrollBorder.Width()
565 && aWindowArea.Left() > aViewPixelArea.Left())
567 nDx = -1 + (int)(mnHorizontalScrollFactor
568 * (rMouseWindowPosition.X() - maScrollBorder.Width()));
571 if (rMouseWindowPosition.X() >= (aWindowSize.Width() - maScrollBorder.Width())
572 && aWindowArea.Right() < aViewPixelArea.Right())
574 nDx = 1 + (int)(mnHorizontalScrollFactor
575 * (rMouseWindowPosition.X() - aWindowSize.Width()
576 + maScrollBorder.Width()));
580 if (aWindowSize.Height() > maScrollBorder.Height() * 3
581 && aWindowSize.Height() < aViewPixelArea.GetHeight())
583 if (rMouseWindowPosition.Y() < maScrollBorder.Height()
584 && aWindowArea.Top() > aViewPixelArea.Top())
586 nDy = -1 + (int)(mnVerticalScrollFactor
587 * (rMouseWindowPosition.Y() - maScrollBorder.Height()));
590 if (rMouseWindowPosition.Y() >= (aWindowSize.Height() - maScrollBorder.Height())
591 && aWindowArea.Bottom() < aViewPixelArea.Bottom())
593 nDy = 1 + (int)(mnVerticalScrollFactor
594 * (rMouseWindowPosition.Y() - aWindowSize.Height()
595 + maScrollBorder.Height()));
599 maAutoScrollOffset = Size(nDx,nDy);
605 bool ScrollBarManager::AutoScroll (const Point& rMouseWindowPosition)
607 CalcAutoScrollOffset (rMouseWindowPosition);
608 bool bResult = RepeatAutoScroll();
609 if (bResult)
611 maAutoScrollTimer.Start();
613 return bResult;
619 void ScrollBarManager::StopAutoScroll (void)
621 maAutoScrollTimer.Stop();
627 bool ScrollBarManager::RepeatAutoScroll (void)
629 if (maAutoScrollOffset != Size(0,0))
631 if (mrSlideSorter.GetViewShell() != NULL)
633 mrSlideSorter.GetViewShell()->ScrollLines(
634 maAutoScrollOffset.Width(),
635 maAutoScrollOffset.Height());
636 return true;
640 return false;
646 IMPL_LINK(ScrollBarManager, AutoScrollTimeoutHandler, Timer *, EMPTYARG)
648 RepeatAutoScroll();
650 return 0;
654 } } } // end of namespace ::sd::slidesorter::controller