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