xref: /trunk/main/svtools/source/control/scrwin.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_svtools.hxx"
30 
31 #define _SVT_SCRWIN_CXX
32 #include <svtools/scrwin.hxx>
33 
34 //===================================================================
35 
36 void ScrollableWindow::ImpInitialize( ScrollableWindowFlags nFlags )
37 {
38     bHandleDragging = (sal_Bool) ( nFlags & SCRWIN_THUMBDRAGGING );
39     bVCenter = (nFlags & SCRWIN_VCENTER) == SCRWIN_VCENTER;
40     bHCenter = (nFlags & SCRWIN_HCENTER) == SCRWIN_HCENTER;
41     bScrolling = sal_False;
42 
43     // set the handlers for the scrollbars
44     aVScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) );
45     aHScroll.SetScrollHdl( LINK(this, ScrollableWindow, ScrollHdl) );
46     aVScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) );
47     aHScroll.SetEndScrollHdl( LINK(this, ScrollableWindow, EndScrollHdl) );
48 
49     nColumnPixW = nLinePixH = GetSettings().GetStyleSettings().GetScrollBarSize();
50 }
51 
52 //-------------------------------------------------------------------
53 
54 ScrollableWindow::ScrollableWindow( Window* pParent, WinBits nBits,
55                                     ScrollableWindowFlags nFlags ) :
56     Window( pParent, WinBits(nBits|WB_CLIPCHILDREN) ),
57     aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ),
58     aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ),
59     aCornerWin( this )
60 {
61     ImpInitialize( nFlags );
62 }
63 
64 //-------------------------------------------------------------------
65 
66 ScrollableWindow::ScrollableWindow( Window* pParent, const ResId& rId,
67                                     ScrollableWindowFlags nFlags ) :
68     Window( pParent, rId ),
69     aVScroll( this, WinBits(WB_VSCROLL | WB_DRAG) ),
70     aHScroll( this, WinBits(WB_HSCROLL | WB_DRAG) ),
71     aCornerWin( this )
72 {
73     ImpInitialize( nFlags );
74 }
75 
76 // -----------------------------------------------------------------------
77 
78 void ScrollableWindow::Command( const CommandEvent& rCEvt )
79 {
80     if ( (rCEvt.GetCommand() == COMMAND_WHEEL) ||
81          (rCEvt.GetCommand() == COMMAND_STARTAUTOSCROLL) ||
82          (rCEvt.GetCommand() == COMMAND_AUTOSCROLL) )
83     {
84         ScrollBar* pHScrBar;
85         ScrollBar* pVScrBar;
86         if ( aHScroll.IsVisible() )
87             pHScrBar = &aHScroll;
88         else
89             pHScrBar = NULL;
90         if ( aVScroll.IsVisible() )
91             pVScrBar = &aVScroll;
92         else
93             pVScrBar = NULL;
94         if ( HandleScrollCommand( rCEvt, pHScrBar, pVScrBar ) )
95             return;
96     }
97 
98     Window::Command( rCEvt );
99 }
100 
101 //-------------------------------------------------------------------
102 
103 void ScrollableWindow::DataChanged( const DataChangedEvent& rDCEvt )
104 {
105     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
106          (rDCEvt.GetFlags() & SETTINGS_STYLE) )
107     {
108         Resize();
109         Invalidate();
110     }
111 
112     Window::DataChanged( rDCEvt );
113 }
114 
115 //-------------------------------------------------------------------
116 
117 Size __EXPORT ScrollableWindow::GetOutputSizePixel() const
118 {
119     Size aSz( Window::GetOutputSizePixel() );
120 
121     long nTmp = GetSettings().GetStyleSettings().GetScrollBarSize();
122     if ( aHScroll.IsVisible() )
123         aSz.Height() -= nTmp;
124     if ( aVScroll.IsVisible() )
125         aSz.Width() -= nTmp;
126     return aSz;
127 }
128 
129 //-------------------------------------------------------------------
130 
131 Size ScrollableWindow::GetOutputSize() const
132 {
133     return PixelToLogic( GetOutputSizePixel() );
134 }
135 
136 //-------------------------------------------------------------------
137 
138 IMPL_LINK( ScrollableWindow, EndScrollHdl, ScrollBar *, pScroll )
139 {
140     // notify the start of scrolling, if not already scrolling
141     if ( !bScrolling )
142         StartScroll(), bScrolling = sal_True;
143 
144     // get the delta in logic coordinates
145     Size aDelta( PixelToLogic( Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) );
146 
147     // scroll the window, if this is not already done
148     if ( !bHandleDragging )
149     {
150         if ( pScroll == &aHScroll )
151             Scroll( aDelta.Width(), 0 );
152         else
153             Scroll( 0, aDelta.Height() );
154     }
155 
156     // notify the end of scrolling
157     bScrolling = sal_False;
158     EndScroll( aDelta.Width(), aDelta.Height() );
159     return 0;
160 }
161 
162 //-------------------------------------------------------------------
163 
164 IMPL_LINK( ScrollableWindow, ScrollHdl, ScrollBar *, pScroll )
165 {
166     // notify the start of scrolling, if not already scrolling
167     if ( !bScrolling )
168         StartScroll(), bScrolling = sal_True;
169 
170     if ( bHandleDragging )
171     {
172         // get the delta in logic coordinates
173         Size aDelta( PixelToLogic(
174             Size( aHScroll.GetDelta(), aVScroll.GetDelta() ) ) );
175         if ( pScroll == &aHScroll )
176             Scroll( aDelta.Width(), 0 );
177         else
178             Scroll( 0, aDelta.Height() );
179     }
180     return 0;
181 }
182 
183 //-------------------------------------------------------------------
184 
185 void __EXPORT ScrollableWindow::Resize()
186 {
187     // get the new output-size in pixel
188     Size aOutPixSz = Window::GetOutputSizePixel();
189 
190     // determine the size of the output-area and if we need scrollbars
191     const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize();
192     sal_Bool bVVisible = sal_False; // by default no vertical-ScrollBar
193     sal_Bool bHVisible = sal_False; // by default no horizontal-ScrollBar
194     sal_Bool bChanged;          // determines if a visiblility was changed
195     do
196     {
197         bChanged = sal_False;
198 
199         // does we need a vertical ScrollBar
200         if ( aOutPixSz.Width() < aTotPixSz.Width() && !bHVisible )
201         {   bHVisible = sal_True;
202             aOutPixSz.Height() -= nScrSize;
203             bChanged = sal_True;
204         }
205 
206         // does we need a horizontal ScrollBar
207         if ( aOutPixSz.Height() < aTotPixSz.Height() && !bVVisible )
208         {   bVVisible = sal_True;
209             aOutPixSz.Width() -= nScrSize;
210             bChanged = sal_True;
211         }
212 
213     }
214     while ( bChanged );   // until no visibility has changed
215 
216     // store the old offset and map-mode
217     MapMode aMap( GetMapMode() );
218     Point aOldPixOffset( aPixOffset );
219 
220     // justify (right/bottom borders should never exceed the virtual window)
221     Size aPixDelta;
222     if ( aPixOffset.X() < 0 &&
223          aPixOffset.X() + aTotPixSz.Width() < aOutPixSz.Width() )
224         aPixDelta.Width() =
225             aOutPixSz.Width() - ( aPixOffset.X() + aTotPixSz.Width() );
226     if ( aPixOffset.Y() < 0 &&
227          aPixOffset.Y() + aTotPixSz.Height() < aOutPixSz.Height() )
228         aPixDelta.Height() =
229             aOutPixSz.Height() - ( aPixOffset.Y() + aTotPixSz.Height() );
230     if ( aPixDelta.Width() || aPixDelta.Height() )
231     {
232         aPixOffset.X() += aPixDelta.Width();
233         aPixOffset.Y() += aPixDelta.Height();
234     }
235 
236     // for axis without scrollbar restore the origin
237     if ( !bVVisible || !bHVisible )
238     {
239         aPixOffset = Point(
240                      bHVisible
241                      ? aPixOffset.X()
242                      : ( bHCenter
243                             ? (aOutPixSz.Width()-aTotPixSz.Width()) / 2
244                             : 0 ),
245                      bVVisible
246                      ? aPixOffset.Y()
247                      : ( bVCenter
248                             ? (aOutPixSz.Height()-aTotPixSz.Height()) / 2
249                             : 0 ) );
250     }
251     if ( bHVisible && !aHScroll.IsVisible() )
252         aPixOffset.X() = 0;
253     if ( bVVisible && !aVScroll.IsVisible() )
254         aPixOffset.Y() = 0;
255 
256     // select the shifted map-mode
257     if ( aPixOffset != aOldPixOffset )
258     {
259         Window::SetMapMode( MapMode( MAP_PIXEL ) );
260         Window::Scroll(
261             aPixOffset.X() - aOldPixOffset.X(),
262             aPixOffset.Y() - aOldPixOffset.Y() );
263         SetMapMode( aMap );
264     }
265 
266     // show or hide scrollbars
267     aVScroll.Show( bVVisible );
268     aHScroll.Show( bHVisible );
269 
270     // disable painting in the corner between the scrollbars
271     if ( bVVisible && bHVisible )
272     {
273         aCornerWin.SetPosSizePixel(Point(aOutPixSz.Width(), aOutPixSz.Height()),
274             Size(nScrSize, nScrSize) );
275         aCornerWin.Show();
276     }
277     else
278         aCornerWin.Hide();
279 
280     // resize scrollbars and set their ranges
281     if ( bHVisible )
282     {
283         aHScroll.SetPosSizePixel(
284             Point( 0, aOutPixSz.Height() ),
285             Size( aOutPixSz.Width(), nScrSize ) );
286         aHScroll.SetRange( Range( 0, aTotPixSz.Width() ) );
287         aHScroll.SetPageSize( aOutPixSz.Width() );
288         aHScroll.SetVisibleSize( aOutPixSz.Width() );
289         aHScroll.SetLineSize( nColumnPixW );
290         aHScroll.SetThumbPos( -aPixOffset.X() );
291     }
292     if ( bVVisible )
293     {
294         aVScroll.SetPosSizePixel(
295             Point( aOutPixSz.Width(), 0 ),
296             Size( nScrSize,aOutPixSz.Height() ) );
297         aVScroll.SetRange( Range( 0, aTotPixSz.Height() ) );
298         aVScroll.SetPageSize( aOutPixSz.Height() );
299         aVScroll.SetVisibleSize( aOutPixSz.Height() );
300         aVScroll.SetLineSize( nLinePixH );
301         aVScroll.SetThumbPos( -aPixOffset.Y() );
302     }
303 }
304 
305 //-------------------------------------------------------------------
306 
307 void __EXPORT ScrollableWindow::StartScroll()
308 {
309 }
310 
311 //-------------------------------------------------------------------
312 
313 void __EXPORT ScrollableWindow::EndScroll( long, long )
314 {
315 }
316 
317 //-------------------------------------------------------------------
318 
319 void ScrollableWindow::SetMapMode( const MapMode& rNewMapMode )
320 {
321     MapMode aMap( rNewMapMode );
322     aMap.SetOrigin( aMap.GetOrigin() + PixelToLogic( aPixOffset, aMap ) );
323     Window::SetMapMode( aMap );
324 }
325 
326 //-------------------------------------------------------------------
327 
328 MapMode ScrollableWindow::GetMapMode() const
329 {
330     MapMode aMap( Window::GetMapMode() );
331     aMap.SetOrigin( aMap.GetOrigin() - PixelToLogic( aPixOffset ) );
332     return aMap;
333 }
334 
335 //-------------------------------------------------------------------
336 
337 void ScrollableWindow::SetTotalSize( const Size& rNewSize )
338 {
339     aTotPixSz = LogicToPixel( rNewSize );
340     ScrollableWindow::Resize();
341 }
342 
343 //-------------------------------------------------------------------
344 
345 void ScrollableWindow::SetVisibleSize( const Size& rNewSize )
346 {
347     // get the rectangle, we wish to view
348     Rectangle aWish( Point(0, 0), LogicToPixel(rNewSize) );
349 
350     // get maximum rectangle for us from our parent-window (subst our border!)
351     Rectangle aMax( Point(0, 0), GetParent()->GetOutputSizePixel() );
352     aMax.Left() -=  ( Window::GetSizePixel().Width() -
353                     Window::GetOutputSizePixel().Width() );
354     aMax.Bottom() -= (Window::GetSizePixel().Height() -
355                      Window::GetOutputSizePixel().Height());
356 
357     Size aWill( aWish.GetIntersection(aMax).GetSize() );
358     sal_Bool bHScroll = sal_False;
359     const long nScrSize = GetSettings().GetStyleSettings().GetScrollBarSize();
360     if ( aWill.Width() < aWish.GetSize().Width() )
361     {   bHScroll = sal_True;
362         aWill.Height() =
363             Min( aWill.Height()+nScrSize, aMax.GetSize().Height() );
364     }
365     if ( aWill.Height() < aWish.GetSize().Height() )
366         aWill.Width() =
367             Min( aWill.Width()+nScrSize, aMax.GetSize().Width() );
368     if ( !bHScroll && (aWill.Width() < aWish.GetSize().Width()) )
369         aWill.Height() =
370             Min( aWill.Height()+nScrSize, aMax.GetSize().Height() );
371     Window::SetOutputSizePixel( aWill );
372 }
373 
374 //-------------------------------------------------------------------
375 
376 sal_Bool ScrollableWindow::MakeVisible( const Rectangle& rTarget, sal_Bool bSloppy )
377 {
378     Rectangle aTarget;
379     Rectangle aTotRect( Point(0, 0), PixelToLogic( aTotPixSz ) );
380 
381     if ( bSloppy )
382     {
383         aTarget = rTarget;
384 
385         // at maximum to right border
386         if ( aTarget.Right() > aTotRect.Right() )
387         {
388             long nDelta = aTarget.Right() - aTotRect.Right();
389             aTarget.Left() -= nDelta;
390             aTarget.Right() -= nDelta;
391 
392             // too wide?
393             if ( aTarget.Left() < aTotRect.Left() )
394                 aTarget.Left() = aTotRect.Left();
395         }
396 
397         // at maximum to bottom border
398         if ( aTarget.Bottom() > aTotRect.Bottom() )
399         {
400             long nDelta = aTarget.Bottom() - aTotRect.Bottom();
401             aTarget.Top() -= nDelta;
402             aTarget.Bottom() -= nDelta;
403 
404             // too high?
405             if ( aTarget.Top() < aTotRect.Top() )
406                 aTarget.Top() = aTotRect.Top();
407         }
408 
409         // at maximum to left border
410         if ( aTarget.Left() < aTotRect.Left() )
411         {
412             long nDelta = aTarget.Left() - aTotRect.Left();
413             aTarget.Right() -= nDelta;
414             aTarget.Left() -= nDelta;
415 
416             // too wide?
417             if ( aTarget.Right() > aTotRect.Right() )
418                 aTarget.Right() = aTotRect.Right();
419         }
420 
421         // at maximum to top border
422         if ( aTarget.Top() < aTotRect.Top() )
423         {
424             long nDelta = aTarget.Top() - aTotRect.Top();
425             aTarget.Bottom() -= nDelta;
426             aTarget.Top() -= nDelta;
427 
428             // too high?
429             if ( aTarget.Bottom() > aTotRect.Bottom() )
430                 aTarget.Bottom() = aTotRect.Bottom();
431         }
432     }
433     else
434         aTarget = rTarget.GetIntersection( aTotRect );
435 
436     // is the area already visible?
437     Rectangle aVisArea( GetVisibleArea() );
438     if ( aVisArea.IsInside(rTarget) )
439         return sal_True;
440 
441     // is there somewhat to scroll?
442     if ( aVisArea.TopLeft() != aTarget.TopLeft() )
443     {
444         Rectangle aBox( aTarget.GetUnion(aVisArea) );
445         long  nDeltaX = ( aBox.Right() - aVisArea.Right() ) +
446                         ( aBox.Left() - aVisArea.Left() );
447         long  nDeltaY = ( aBox.Top() - aVisArea.Top() ) +
448                         ( aBox.Bottom() - aVisArea.Bottom() );
449         Scroll( nDeltaX, nDeltaY );
450     }
451 
452     // determine if the target is completely visible
453     return aVisArea.GetWidth() >= aTarget.GetWidth() &&
454            aVisArea.GetHeight() >= aTarget.GetHeight();
455 }
456 
457 //-------------------------------------------------------------------
458 
459 Rectangle ScrollableWindow::GetVisibleArea() const
460 {
461     Point aTopLeft( PixelToLogic( Point() ) );
462     Size aSz( GetOutputSize() );
463     return Rectangle( aTopLeft, aSz );
464 }
465 
466 //-------------------------------------------------------------------
467 
468 void ScrollableWindow::SetLineSize( sal_uLong nHorz, sal_uLong nVert )
469 {
470     Size aPixSz( LogicToPixel( Size(nHorz, nVert) ) );
471     nColumnPixW = aPixSz.Width();
472     nLinePixH = aPixSz.Height();
473     aVScroll.SetLineSize( nLinePixH );
474     aHScroll.SetLineSize( nColumnPixW );
475 }
476 
477 //-------------------------------------------------------------------
478 
479 void ScrollableWindow::Scroll( long nDeltaX, long nDeltaY, sal_uInt16 )
480 {
481     if ( !bScrolling )
482         StartScroll();
483 
484     // get the delta in pixel
485     Size aDeltaPix( LogicToPixel( Size(nDeltaX, nDeltaY) ) );
486     Size aOutPixSz( GetOutputSizePixel() );
487     MapMode aMap( GetMapMode() );
488     Point aNewPixOffset( aPixOffset );
489 
490     // scrolling horizontally?
491     if ( nDeltaX != 0 )
492     {
493         aNewPixOffset.X() -= aDeltaPix.Width();
494         if ( ( aOutPixSz.Width() - aNewPixOffset.X() ) > aTotPixSz.Width() )
495             aNewPixOffset.X() = - ( aTotPixSz.Width() - aOutPixSz.Width() );
496         else if ( aNewPixOffset.X() > 0 )
497             aNewPixOffset.X() = 0;
498     }
499 
500     // scrolling vertically?
501     if ( nDeltaY != 0 )
502     {
503         aNewPixOffset.Y() -= aDeltaPix.Height();
504         if ( ( aOutPixSz.Height() - aNewPixOffset.Y() ) > aTotPixSz.Height() )
505             aNewPixOffset.Y() = - ( aTotPixSz.Height() - aOutPixSz.Height() );
506         else if ( aNewPixOffset.Y() > 0 )
507             aNewPixOffset.Y() = 0;
508     }
509 
510     // recompute the logical scroll units
511     aDeltaPix.Width() = aPixOffset.X() - aNewPixOffset.X();
512     aDeltaPix.Height() = aPixOffset.Y() - aNewPixOffset.Y();
513     Size aDelta( PixelToLogic(aDeltaPix) );
514     nDeltaX = aDelta.Width();
515     nDeltaY = aDelta.Height();
516     aPixOffset = aNewPixOffset;
517 
518     // scrolling?
519     if ( nDeltaX != 0 || nDeltaY != 0 )
520     {
521         Update();
522 
523         // does the new area overlap the old one?
524         if ( Abs( (int)aDeltaPix.Height() ) < aOutPixSz.Height() ||
525              Abs( (int)aDeltaPix.Width() ) < aOutPixSz.Width() )
526         {
527             // scroll the overlapping area
528             SetMapMode( aMap );
529 
530             // never scroll the scrollbars itself!
531             Window::Scroll(-nDeltaX, -nDeltaY,
532                 PixelToLogic( Rectangle( Point(0, 0), aOutPixSz ) ) );
533         }
534         else
535         {
536             // repaint all
537             SetMapMode( aMap );
538             Invalidate();
539         }
540 
541         Update();
542     }
543 
544     if ( !bScrolling )
545     {
546         EndScroll( nDeltaX, nDeltaY );
547         if ( nDeltaX )
548             aHScroll.SetThumbPos( -aPixOffset.X() );
549         if ( nDeltaY )
550             aVScroll.SetThumbPos( -aPixOffset.Y() );
551     }
552 }
553 
554 //-------------------------------------------------------------------
555 
556 void ScrollableWindow::ScrollLines( long nLinesX, long nLinesY )
557 {
558     Size aDelta( PixelToLogic( Size( nColumnPixW, nLinePixH ) ) );
559     Scroll( aDelta.Width()*nLinesX, aDelta.Height()*nLinesY );
560 }
561 
562 //-------------------------------------------------------------------
563 
564 void ScrollableWindow::ScrollPages( long nPagesX, sal_uLong nOverlapX,
565                                     long nPagesY, sal_uLong nOverlapY )
566 {
567     Size aOutSz( GetVisibleArea().GetSize() );
568     Scroll( nPagesX * aOutSz.Width() + (nPagesX>0 ? 1 : -1) * nOverlapX,
569             nPagesY * aOutSz.Height() + (nPagesY>0 ? 1 : -1) * nOverlapY );
570 }
571 
572 
573