xref: /aoo41x/main/svtools/source/control/scrwin.cxx (revision cdf0e10c)
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