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