xref: /aoo42x/main/vcl/source/control/scrbar.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_vcl.hxx"
30 
31 #include "vcl/event.hxx"
32 #include "vcl/sound.hxx"
33 #include "vcl/decoview.hxx"
34 #include "vcl/scrbar.hxx"
35 #include "vcl/timer.hxx"
36 
37 #include "svdata.hxx"
38 
39 #include "rtl/string.hxx"
40 #include "tools/rc.h"
41 
42 
43 
44 using namespace rtl;
45 
46 /*  #i77549#
47     HACK: for scrollbars in case of thumb rect, page up and page down rect we
48     abuse the HitTestNativeControl interface. All theming engines but aqua
49     are actually able to draw the thumb according to our internal representation.
50     However aqua draws a little outside. The canonical way would be to enhance the
51     HitTestNativeControl passing a ScrollbarValue additionally so all necessary
52     information is available in the call.
53     .
54     However since there is only this one small exception we will deviate a little and
55     instead pass the respective rect as control region to allow for a small correction.
56 
57     So all places using HitTestNativeControl on PART_THUMB_HORZ, PART_THUMB_VERT,
58     PART_TRACK_HORZ_LEFT, PART_TRACK_HORZ_RIGHT, PART_TRACK_VERT_UPPER, PART_TRACK_VERT_LOWER
59     do not use the control rectangle as region but the actuall part rectangle, making
60     only small deviations feasible.
61 */
62 
63 
64 // =======================================================================
65 
66 static long ImplMulDiv( long nNumber, long nNumerator, long nDenominator )
67 {
68     double n = ((double)nNumber * (double)nNumerator) / (double)nDenominator;
69     return (long)n;
70 }
71 
72 // =======================================================================
73 
74 #define SCRBAR_DRAW_BTN1            ((sal_uInt16)0x0001)
75 #define SCRBAR_DRAW_BTN2            ((sal_uInt16)0x0002)
76 #define SCRBAR_DRAW_PAGE1           ((sal_uInt16)0x0004)
77 #define SCRBAR_DRAW_PAGE2           ((sal_uInt16)0x0008)
78 #define SCRBAR_DRAW_THUMB           ((sal_uInt16)0x0010)
79 #define SCRBAR_DRAW_BACKGROUND      ((sal_uInt16)0x0020)
80 #define SCRBAR_DRAW_ALL             (SCRBAR_DRAW_BTN1 | SCRBAR_DRAW_BTN2 |  \
81                                      SCRBAR_DRAW_PAGE1 | SCRBAR_DRAW_PAGE2 |\
82                                      SCRBAR_DRAW_THUMB | SCRBAR_DRAW_BACKGROUND )
83 
84 #define SCRBAR_STATE_BTN1_DOWN      ((sal_uInt16)0x0001)
85 #define SCRBAR_STATE_BTN1_DISABLE   ((sal_uInt16)0x0002)
86 #define SCRBAR_STATE_BTN2_DOWN      ((sal_uInt16)0x0004)
87 #define SCRBAR_STATE_BTN2_DISABLE   ((sal_uInt16)0x0008)
88 #define SCRBAR_STATE_PAGE1_DOWN     ((sal_uInt16)0x0010)
89 #define SCRBAR_STATE_PAGE2_DOWN     ((sal_uInt16)0x0020)
90 #define SCRBAR_STATE_THUMB_DOWN     ((sal_uInt16)0x0040)
91 
92 #define SCRBAR_VIEW_STYLE           (WB_3DLOOK | WB_HORZ | WB_VERT)
93 
94 struct ImplScrollBarData
95 {
96 	AutoTimer		maTimer;			// Timer
97     sal_Bool            mbHide;
98 	Rectangle		maTrackRect; // TODO: move to ScrollBar class when binary incompatibility of ScrollBar class is no longer problematic
99 };
100 
101 // =======================================================================
102 
103 void ScrollBar::ImplInit( Window* pParent, WinBits nStyle )
104 {
105     mpData              = NULL;
106     mnThumbPixRange     = 0;
107     mnThumbPixPos       = 0;
108     mnThumbPixSize      = 0;
109     mnMinRange          = 0;
110     mnMaxRange          = 100;
111     mnThumbPos          = 0;
112     mnVisibleSize       = 0;
113     mnLineSize          = 1;
114     mnPageSize          = 1;
115     mnDelta             = 0;
116     mnDragDraw          = 0;
117     mnStateFlags        = 0;
118     meScrollType        = SCROLL_DONTKNOW;
119     meDDScrollType      = SCROLL_DONTKNOW;
120     mbCalcSize          = sal_True;
121     mbFullDrag          = 0;
122 
123     if( !mpData )  // TODO: remove when maTrackRect is no longer in mpData
124     {
125 	    mpData = new ImplScrollBarData;
126 		mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
127         mpData->mbHide = sal_False;
128     }
129 
130     ImplInitStyle( nStyle );
131     Control::ImplInit( pParent, nStyle, NULL );
132 
133     long nScrollSize = GetSettings().GetStyleSettings().GetScrollBarSize();
134     SetSizePixel( Size( nScrollSize, nScrollSize ) );
135     SetBackground();
136 }
137 
138 // -----------------------------------------------------------------------
139 
140 void ScrollBar::ImplInitStyle( WinBits nStyle )
141 {
142     if ( nStyle & WB_DRAG )
143         mbFullDrag = sal_True;
144     else
145         mbFullDrag = (GetSettings().GetStyleSettings().GetDragFullOptions() & DRAGFULL_OPTION_SCROLL) != 0;
146 }
147 
148 // -----------------------------------------------------------------------
149 
150 ScrollBar::ScrollBar( Window* pParent, WinBits nStyle ) :
151     Control( WINDOW_SCROLLBAR )
152 {
153     ImplInit( pParent, nStyle );
154 }
155 
156 // -----------------------------------------------------------------------
157 
158 ScrollBar::ScrollBar( Window* pParent, const ResId& rResId ) :
159     Control( WINDOW_SCROLLBAR )
160 {
161     rResId.SetRT( RSC_SCROLLBAR );
162     WinBits nStyle = ImplInitRes( rResId );
163     ImplInit( pParent, nStyle );
164     ImplLoadRes( rResId );
165 
166     if ( !(nStyle & WB_HIDE) )
167         Show();
168 }
169 
170 // -----------------------------------------------------------------------
171 
172 ScrollBar::~ScrollBar()
173 {
174     if( mpData )
175         delete mpData;
176 }
177 
178 // -----------------------------------------------------------------------
179 
180 void ScrollBar::ImplLoadRes( const ResId& rResId )
181 {
182     Control::ImplLoadRes( rResId );
183 
184     sal_Int16 nMin          = ReadShortRes();
185     sal_Int16 nMax          = ReadShortRes();
186     sal_Int16 nThumbPos     = ReadShortRes();
187     sal_Int16 nPage         = ReadShortRes();
188     sal_Int16 nStep         = ReadShortRes();
189     sal_Int16 nVisibleSize  = ReadShortRes();
190 
191     SetRange( Range( nMin, nMax ) );
192     SetLineSize( nStep );
193     SetPageSize( nPage );
194     SetVisibleSize( nVisibleSize );
195     SetThumbPos( nThumbPos );
196 }
197 
198 // -----------------------------------------------------------------------
199 
200 void ScrollBar::ImplUpdateRects( sal_Bool bUpdate )
201 {
202     sal_uInt16      nOldStateFlags  = mnStateFlags;
203     Rectangle   aOldPage1Rect = maPage1Rect;
204     Rectangle   aOldPage2Rect = maPage2Rect;
205     Rectangle   aOldThumbRect = maThumbRect;
206 
207     mnStateFlags  &= ~SCRBAR_STATE_BTN1_DISABLE;
208     mnStateFlags  &= ~SCRBAR_STATE_BTN2_DISABLE;
209 
210 	Rectangle& maTrackRect = mpData->maTrackRect; // TODO: remove when maTrackRect is no longer in mpData
211     if ( mnThumbPixRange )
212     {
213         if ( GetStyle() & WB_HORZ )
214         {
215             maThumbRect.Left()      = maTrackRect.Left()+mnThumbPixPos;
216             maThumbRect.Right()     = maThumbRect.Left()+mnThumbPixSize-1;
217             if ( !mnThumbPixPos )
218                 maPage1Rect.Right()     = RECT_EMPTY;
219             else
220                 maPage1Rect.Right()     = maThumbRect.Left()-1;
221             if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
222                 maPage2Rect.Right()     = RECT_EMPTY;
223             else
224             {
225                 maPage2Rect.Left()      = maThumbRect.Right()+1;
226                 maPage2Rect.Right()     = maTrackRect.Right();
227             }
228         }
229         else
230         {
231             maThumbRect.Top()       = maTrackRect.Top()+mnThumbPixPos;
232             maThumbRect.Bottom()    = maThumbRect.Top()+mnThumbPixSize-1;
233             if ( !mnThumbPixPos )
234                 maPage1Rect.Bottom()    = RECT_EMPTY;
235             else
236                 maPage1Rect.Bottom()    = maThumbRect.Top()-1;
237             if ( mnThumbPixPos >= (mnThumbPixRange-mnThumbPixSize) )
238                 maPage2Rect.Bottom()    = RECT_EMPTY;
239             else
240             {
241                 maPage2Rect.Top()       = maThumbRect.Bottom()+1;
242                 maPage2Rect.Bottom()    = maTrackRect.Bottom();
243             }
244         }
245     }
246     else
247     {
248         Size aScrBarSize = GetOutputSizePixel();
249         if ( GetStyle() & WB_HORZ )
250         {
251             const long nSpace = maTrackRect.Right() - maTrackRect.Left();
252             if ( nSpace > 0 )
253             {
254                 maPage1Rect.Left()   = maTrackRect.Left();
255                 maPage1Rect.Right()  = maTrackRect.Left() + (nSpace/2);
256                 maPage2Rect.Left()   = maPage1Rect.Right() + 1;
257                 maPage2Rect.Right()  = maTrackRect.Right();
258             }
259         }
260         else
261         {
262             const long nSpace = maTrackRect.Bottom() - maTrackRect.Top();
263             if ( nSpace > 0 )
264             {
265                 maPage1Rect.Top()    = maTrackRect.Top();
266                 maPage1Rect.Bottom() = maTrackRect.Top() + (nSpace/2);
267                 maPage2Rect.Top()    = maPage1Rect.Bottom() + 1;
268                 maPage2Rect.Bottom() = maTrackRect.Bottom();
269             }
270         }
271     }
272 
273     if( !IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) )
274     {
275         // disable scrollbar buttons only in VCL's own 'theme'
276         // as it is uncommon on other platforms
277         if ( mnThumbPos == mnMinRange )
278             mnStateFlags |= SCRBAR_STATE_BTN1_DISABLE;
279         if ( mnThumbPos >= (mnMaxRange-mnVisibleSize) )
280             mnStateFlags |= SCRBAR_STATE_BTN2_DISABLE;
281     }
282 
283     if ( bUpdate )
284     {
285         sal_uInt16 nDraw = 0;
286         if ( (nOldStateFlags & SCRBAR_STATE_BTN1_DISABLE) !=
287              (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
288             nDraw |= SCRBAR_DRAW_BTN1;
289         if ( (nOldStateFlags & SCRBAR_STATE_BTN2_DISABLE) !=
290              (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
291             nDraw |= SCRBAR_DRAW_BTN2;
292         if ( aOldPage1Rect != maPage1Rect )
293             nDraw |= SCRBAR_DRAW_PAGE1;
294         if ( aOldPage2Rect != maPage2Rect )
295             nDraw |= SCRBAR_DRAW_PAGE2;
296         if ( aOldThumbRect != maThumbRect )
297             nDraw |= SCRBAR_DRAW_THUMB;
298         ImplDraw( nDraw, this );
299     }
300 }
301 
302 // -----------------------------------------------------------------------
303 
304 long ScrollBar::ImplCalcThumbPos( long nPixPos )
305 {
306     // Position berechnen
307     long nCalcThumbPos;
308     nCalcThumbPos = ImplMulDiv( nPixPos, mnMaxRange-mnVisibleSize-mnMinRange,
309                                 mnThumbPixRange-mnThumbPixSize );
310     nCalcThumbPos += mnMinRange;
311     return nCalcThumbPos;
312 }
313 
314 // -----------------------------------------------------------------------
315 
316 long ScrollBar::ImplCalcThumbPosPix( long nPos )
317 {
318     long nCalcThumbPos;
319 
320     // Position berechnen
321     nCalcThumbPos = ImplMulDiv( nPos-mnMinRange, mnThumbPixRange-mnThumbPixSize,
322                                 mnMaxRange-mnVisibleSize-mnMinRange );
323 
324     // Am Anfang und Ende des ScrollBars versuchen wir die Anzeige korrekt
325     // anzuzeigen
326     if ( !nCalcThumbPos && (mnThumbPos > mnMinRange) )
327         nCalcThumbPos = 1;
328     if ( nCalcThumbPos &&
329          ((nCalcThumbPos+mnThumbPixSize) >= mnThumbPixRange) &&
330          (mnThumbPos < (mnMaxRange-mnVisibleSize)) )
331         nCalcThumbPos--;
332 
333     return nCalcThumbPos;
334 }
335 
336 // -----------------------------------------------------------------------
337 
338 void ScrollBar::ImplCalc( sal_Bool bUpdate )
339 {
340     const Size aSize = GetOutputSizePixel();
341     const long nMinThumbSize = GetSettings().GetStyleSettings().GetMinThumbSize();;
342 
343 	Rectangle& maTrackRect = mpData->maTrackRect;  // TODO: remove when maTrackRect is no longer in mpData
344     if ( mbCalcSize )
345     {
346         const Rectangle aControlRegion( Point(0,0), aSize );
347         Rectangle aBtn1Region, aBtn2Region, aTrackRegion, aBoundingRegion;
348 
349         if ( GetStyle() & WB_HORZ )
350         {
351             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_LEFT,
352                         aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) &&
353                  GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_RIGHT,
354                         aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) )
355             {
356                 maBtn1Rect = aBtn1Region;
357                 maBtn2Rect = aBtn2Region;
358             }
359             else
360             {
361                 Size aBtnSize( aSize.Height(), aSize.Height() );
362                 maBtn2Rect.Top()    = maBtn1Rect.Top();
363                 maBtn2Rect.Left()   = aSize.Width()-aSize.Height();
364                 maBtn1Rect.SetSize( aBtnSize );
365                 maBtn2Rect.SetSize( aBtnSize );
366             }
367 
368             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_HORZ_AREA,
369 	                 aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) )
370                 maTrackRect = aTrackRegion;
371             else
372                 maTrackRect = Rectangle( maBtn1Rect.TopRight(), maBtn2Rect.BottomLeft() );
373 
374             // Check if available space is big enough for thumb ( min thumb size = ScrBar width/height )
375             mnThumbPixRange = maTrackRect.Right() - maTrackRect.Left();
376             if( mnThumbPixRange > 0 )
377             {
378                 maPage1Rect.Left()      = maTrackRect.Left();
379                 maPage1Rect.Bottom()	=
380                 maPage2Rect.Bottom()	=
381                 maThumbRect.Bottom()    = maTrackRect.Bottom();
382             }
383             else
384             {
385                 mnThumbPixRange = 0;
386                 maPage1Rect.SetEmpty();
387                 maPage2Rect.SetEmpty();
388             }
389         }
390         else
391         {
392             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_UP,
393                         aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) &&
394                  GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_DOWN,
395                         aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) )
396             {
397                 maBtn1Rect = aBtn1Region;
398                 maBtn2Rect = aBtn2Region;
399             }
400             else
401             {
402                 const Size aBtnSize( aSize.Width(), aSize.Width() );
403                 maBtn2Rect.Left()   = maBtn1Rect.Left();
404                 maBtn2Rect.Top()    = aSize.Height()-aSize.Width();
405                 maBtn1Rect.SetSize( aBtnSize );
406                 maBtn2Rect.SetSize( aBtnSize );
407             }
408 
409             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_VERT_AREA,
410 	                 aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) )
411                 maTrackRect = aTrackRegion;
412 			else
413 				maTrackRect = Rectangle( maBtn1Rect.BottomLeft()+Point(0,1), maBtn2Rect.TopRight() );
414 
415             // Check if available space is big enough for thumb
416             mnThumbPixRange = maTrackRect.Bottom() - maTrackRect.Top();
417             if( mnThumbPixRange > 0 )
418             {
419                 maPage1Rect.Top()       = maTrackRect.Top();
420                 maPage1Rect.Right()		=
421                 maPage2Rect.Right()		=
422                 maThumbRect.Right()     = maTrackRect.Right();
423             }
424             else
425 			{
426                 mnThumbPixRange = 0;
427                 maPage1Rect.SetEmpty();
428                 maPage2Rect.SetEmpty();
429             }
430         }
431 
432         if ( !mnThumbPixRange )
433             maThumbRect.SetEmpty();
434 
435         mbCalcSize = sal_False;
436     }
437 
438     if ( mnThumbPixRange )
439     {
440         // Werte berechnen
441         if ( (mnVisibleSize >= (mnMaxRange-mnMinRange)) ||
442              ((mnMaxRange-mnMinRange) <= 0) )
443         {
444             mnThumbPos      = mnMinRange;
445             mnThumbPixPos   = 0;
446             mnThumbPixSize  = mnThumbPixRange;
447         }
448         else
449         {
450             if ( mnVisibleSize )
451                 mnThumbPixSize = ImplMulDiv( mnThumbPixRange, mnVisibleSize, mnMaxRange-mnMinRange );
452             else
453             {
454                 if ( GetStyle() & WB_HORZ )
455                     mnThumbPixSize = maThumbRect.GetWidth();
456                 else
457                     mnThumbPixSize = maThumbRect.GetHeight();
458             }
459             if ( mnThumbPixSize < nMinThumbSize )
460                 mnThumbPixSize = nMinThumbSize;
461             if ( mnThumbPixSize > mnThumbPixRange )
462                 mnThumbPixSize = mnThumbPixRange;
463             mnThumbPixPos = ImplCalcThumbPosPix( mnThumbPos );
464         }
465     }
466 
467     // Wenn neu ausgegeben werden soll und wir schon ueber eine
468     // Aktion einen Paint-Event ausgeloest bekommen haben, dann
469     // geben wir nicht direkt aus, sondern invalidieren nur alles
470     if ( bUpdate && HasPaintEvent() )
471     {
472         Invalidate();
473         bUpdate = sal_False;
474     }
475     ImplUpdateRects( bUpdate );
476 }
477 
478 // -----------------------------------------------------------------------
479 
480 void ScrollBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
481 {
482     Point       aPos  = pDev->LogicToPixel( rPos );
483     Size        aSize = pDev->LogicToPixel( rSize );
484     Rectangle   aRect( aPos, aSize );
485 
486     pDev->Push();
487     pDev->SetMapMode();
488     if ( !(nFlags & WINDOW_DRAW_MONO) )
489 	{
490 		// DecoView uses the FaceColor...
491 		AllSettings aSettings = pDev->GetSettings();
492 		StyleSettings aStyleSettings = aSettings.GetStyleSettings();
493 		if ( IsControlBackground() )
494 			aStyleSettings.SetFaceColor( GetControlBackground() );
495 		else
496 			aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
497 
498 		aSettings.SetStyleSettings( aStyleSettings );
499 		pDev->SetSettings( aSettings );
500 	}
501 
502     // for printing:
503     // -calculate the size of the rects
504     // -because this is zero-based add the correct offset
505     // -print
506     // -force recalculate
507 
508     if ( mbCalcSize )
509         ImplCalc( sal_False );
510 
511     maBtn1Rect+=aPos;
512     maBtn2Rect+=aPos;
513     maThumbRect+=aPos;
514     mpData->maTrackRect+=aPos; // TODO: update when maTrackRect is no longer in mpData
515     maPage1Rect+=aPos;
516     maPage2Rect+=aPos;
517 
518     ImplDraw( SCRBAR_DRAW_ALL, pDev );
519     pDev->Pop();
520 
521     mbCalcSize = sal_True;
522 }
523 
524 // -----------------------------------------------------------------------
525 
526 sal_Bool ScrollBar::ImplDrawNative( sal_uInt16 nDrawFlags )
527 {
528     ScrollbarValue scrValue;
529 
530     sal_Bool bNativeOK = IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL);
531     if( bNativeOK )
532     {
533         sal_Bool bHorz = (GetStyle() & WB_HORZ ? true : false);
534 
535         // Draw the entire background if the control supports it
536         if( IsNativeControlSupported(CTRL_SCROLLBAR, bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT) )
537         {
538             ControlState		nState = ( IsEnabled() ? CTRL_STATE_ENABLED : 0 ) | ( HasFocus() ? CTRL_STATE_FOCUSED : 0 );
539 
540             scrValue.mnMin = mnMinRange;
541             scrValue.mnMax = mnMaxRange;
542             scrValue.mnCur = mnThumbPos;
543             scrValue.mnVisibleSize = mnVisibleSize;
544             scrValue.maThumbRect = maThumbRect;
545             scrValue.maButton1Rect = maBtn1Rect;
546             scrValue.maButton2Rect = maBtn2Rect;
547             scrValue.mnButton1State = ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0) |
548 								((!(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)) ? CTRL_STATE_ENABLED : 0);
549             scrValue.mnButton2State = ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0) |
550 								((!(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)) ? CTRL_STATE_ENABLED : 0);
551             scrValue.mnThumbState = nState | ((mnStateFlags & SCRBAR_STATE_THUMB_DOWN) ? CTRL_STATE_PRESSED : 0);
552             scrValue.mnPage1State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0);
553             scrValue.mnPage2State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0);
554 
555             if( IsMouseOver() )
556             {
557                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
558                 if( pRect )
559                 {
560                     if( pRect == &maThumbRect )
561                         scrValue.mnThumbState |= CTRL_STATE_ROLLOVER;
562                     else if( pRect == &maBtn1Rect )
563                         scrValue.mnButton1State |= CTRL_STATE_ROLLOVER;
564                     else if( pRect == &maBtn2Rect )
565                         scrValue.mnButton2State |= CTRL_STATE_ROLLOVER;
566                     else if( pRect == &maPage1Rect )
567                         scrValue.mnPage1State |= CTRL_STATE_ROLLOVER;
568                     else if( pRect == &maPage2Rect )
569                         scrValue.mnPage2State |= CTRL_STATE_ROLLOVER;
570                 }
571             }
572 
573             Rectangle aCtrlRegion;
574             aCtrlRegion.Union( maBtn1Rect );
575             aCtrlRegion.Union( maBtn2Rect );
576             aCtrlRegion.Union( maPage1Rect );
577             aCtrlRegion.Union( maPage2Rect );
578             aCtrlRegion.Union( maThumbRect );
579             bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT),
580                             aCtrlRegion, nState, scrValue, rtl::OUString() );
581         }
582         else
583       {
584         if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) || (nDrawFlags & SCRBAR_DRAW_PAGE2) )
585         {
586             sal_uInt32	part1 = bHorz ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER;
587             sal_uInt32	part2 = bHorz ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER;
588             Rectangle   aCtrlRegion1( maPage1Rect );
589             Rectangle   aCtrlRegion2( maPage2Rect );
590             ControlState nState1 = (IsEnabled() ? CTRL_STATE_ENABLED : 0) | (HasFocus() ? CTRL_STATE_FOCUSED : 0);
591             ControlState nState2 = nState1;
592 
593             nState1 |= ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0);
594             nState2 |= ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0);
595 
596             if( IsMouseOver() )
597             {
598                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
599                 if( pRect )
600                 {
601                     if( pRect == &maPage1Rect )
602                         nState1 |= CTRL_STATE_ROLLOVER;
603                     else if( pRect == &maPage2Rect )
604                         nState2 |= CTRL_STATE_ROLLOVER;
605                 }
606             }
607 
608             if ( nDrawFlags & SCRBAR_DRAW_PAGE1 )
609                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1,
610                                 scrValue, rtl::OUString() );
611 
612             if ( nDrawFlags & SCRBAR_DRAW_PAGE2 )
613                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
614                                 scrValue, rtl::OUString() );
615         }
616         if ( (nDrawFlags & SCRBAR_DRAW_BTN1) || (nDrawFlags & SCRBAR_DRAW_BTN2) )
617         {
618             sal_uInt32	part1 = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
619             sal_uInt32	part2 = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
620             Rectangle  	aCtrlRegion1( maBtn1Rect );
621             Rectangle  	aCtrlRegion2( maBtn2Rect );
622             ControlState nState1 = HasFocus() ? CTRL_STATE_FOCUSED : 0;
623             ControlState nState2 = nState1;
624 
625             if ( !Window::IsEnabled() || !IsEnabled() )
626                 nState1 = (nState2 &= ~CTRL_STATE_ENABLED);
627             else
628                 nState1 = (nState2 |= CTRL_STATE_ENABLED);
629 
630             nState1 |= ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0);
631             nState2 |= ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0);
632 
633             if(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)
634                 nState1 &= ~CTRL_STATE_ENABLED;
635             if(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)
636                 nState2 &= ~CTRL_STATE_ENABLED;
637 
638             if( IsMouseOver() )
639             {
640                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
641                 if( pRect )
642                 {
643                     if( pRect == &maBtn1Rect )
644                         nState1 |= CTRL_STATE_ROLLOVER;
645                     else if( pRect == &maBtn2Rect )
646                         nState2 |= CTRL_STATE_ROLLOVER;
647                 }
648             }
649 
650             if ( nDrawFlags & SCRBAR_DRAW_BTN1 )
651                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1,
652                                 scrValue, rtl::OUString() );
653 
654             if ( nDrawFlags & SCRBAR_DRAW_BTN2 )
655                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
656                                 scrValue, rtl::OUString() );
657         }
658         if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty() )
659         {
660             ControlState	nState = IsEnabled() ? CTRL_STATE_ENABLED : 0;
661             Rectangle		aCtrlRegion( maThumbRect );
662 
663             if ( mnStateFlags & SCRBAR_STATE_THUMB_DOWN )
664                 nState |= CTRL_STATE_PRESSED;
665 
666             if ( HasFocus() )
667                 nState |= CTRL_STATE_FOCUSED;
668 
669             if( IsMouseOver() )
670             {
671                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
672                 if( pRect )
673                 {
674                     if( pRect == &maThumbRect )
675                         nState |= CTRL_STATE_ROLLOVER;
676                 }
677             }
678 
679             bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_THUMB_HORZ : PART_THUMB_VERT),
680                     aCtrlRegion, nState, scrValue, rtl::OUString() );
681         }
682       }
683     }
684     return bNativeOK;
685 }
686 
687 void ScrollBar::ImplDraw( sal_uInt16 nDrawFlags, OutputDevice* pOutDev )
688 {
689     DecorationView          aDecoView( pOutDev );
690     Rectangle               aTempRect;
691     sal_uInt16                  nStyle;
692     const StyleSettings&    rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
693     SymbolType              eSymbolType;
694     sal_Bool                    bEnabled = IsEnabled();
695 
696     // Evt. noch offene Berechnungen nachholen
697     if ( mbCalcSize )
698         ImplCalc( sal_False );
699 
700     Window *pWin = NULL;
701     if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
702         pWin = (Window*) pOutDev;
703 
704     // Draw the entire control if the native theme engine needs it
705     if ( nDrawFlags && pWin && pWin->IsNativeControlSupported(CTRL_SCROLLBAR, PART_DRAW_BACKGROUND_HORZ) )
706     {
707         ImplDrawNative( SCRBAR_DRAW_BACKGROUND );
708         return;
709     }
710 
711     if( (nDrawFlags & SCRBAR_DRAW_BTN1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN1 ) ) )
712     {
713         nStyle = BUTTON_DRAW_NOLIGHTBORDER;
714         if ( mnStateFlags & SCRBAR_STATE_BTN1_DOWN )
715             nStyle |= BUTTON_DRAW_PRESSED;
716         aTempRect = aDecoView.DrawButton( maBtn1Rect, nStyle );
717         ImplCalcSymbolRect( aTempRect );
718         nStyle = 0;
719         if ( (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) || !bEnabled )
720             nStyle |= SYMBOL_DRAW_DISABLE;
721         if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW )
722         {
723             if ( GetStyle() & WB_HORZ )
724                 eSymbolType = SYMBOL_ARROW_LEFT;
725             else
726                 eSymbolType = SYMBOL_ARROW_UP;
727         }
728         else
729         {
730             if ( GetStyle() & WB_HORZ )
731                 eSymbolType = SYMBOL_SPIN_LEFT;
732             else
733                 eSymbolType = SYMBOL_SPIN_UP;
734         }
735         aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle );
736     }
737 
738     if ( (nDrawFlags & SCRBAR_DRAW_BTN2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN2 ) ) )
739     {
740         nStyle = BUTTON_DRAW_NOLIGHTBORDER;
741         if ( mnStateFlags & SCRBAR_STATE_BTN2_DOWN )
742             nStyle |= BUTTON_DRAW_PRESSED;
743         aTempRect = aDecoView.DrawButton(  maBtn2Rect, nStyle );
744         ImplCalcSymbolRect( aTempRect );
745         nStyle = 0;
746         if ( (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) || !bEnabled )
747             nStyle |= SYMBOL_DRAW_DISABLE;
748         if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW )
749         {
750             if ( GetStyle() & WB_HORZ )
751                 eSymbolType = SYMBOL_ARROW_RIGHT;
752             else
753                 eSymbolType = SYMBOL_ARROW_DOWN;
754         }
755         else
756         {
757             if ( GetStyle() & WB_HORZ )
758                 eSymbolType = SYMBOL_SPIN_RIGHT;
759             else
760                 eSymbolType = SYMBOL_SPIN_DOWN;
761         }
762         aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle );
763     }
764 
765     pOutDev->SetLineColor();
766 
767     if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_THUMB ) ) )
768     {
769         if ( !maThumbRect.IsEmpty() )
770         {
771             if ( bEnabled )
772             {
773                 nStyle = BUTTON_DRAW_NOLIGHTBORDER;
774                 aTempRect = aDecoView.DrawButton( maThumbRect, nStyle );
775             }
776             else
777             {
778                 pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
779                 pOutDev->DrawRect( maThumbRect );
780             }
781         }
782     }
783 
784     if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE1 ) ) )
785     {
786         if ( mnStateFlags & SCRBAR_STATE_PAGE1_DOWN )
787             pOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
788         else
789             pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
790         pOutDev->DrawRect( maPage1Rect );
791     }
792     if ( (nDrawFlags & SCRBAR_DRAW_PAGE2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE2 ) ) )
793     {
794         if ( mnStateFlags & SCRBAR_STATE_PAGE2_DOWN )
795             pOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
796         else
797             pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
798         pOutDev->DrawRect( maPage2Rect );
799     }
800 }
801 
802 // -----------------------------------------------------------------------
803 
804 long ScrollBar::ImplScroll( long nNewPos, sal_Bool bCallEndScroll )
805 {
806     long nOldPos = mnThumbPos;
807     SetThumbPos( nNewPos );
808     long nDelta = mnThumbPos-nOldPos;
809     if ( nDelta )
810     {
811         mnDelta = nDelta;
812         Scroll();
813         if ( bCallEndScroll )
814             EndScroll();
815         mnDelta = 0;
816     }
817     return nDelta;
818 }
819 
820 // -----------------------------------------------------------------------
821 
822 long ScrollBar::ImplDoAction( sal_Bool bCallEndScroll )
823 {
824     long nDelta = 0;
825 
826     switch ( meScrollType )
827     {
828         case SCROLL_LINEUP:
829             nDelta = ImplScroll( mnThumbPos-mnLineSize, bCallEndScroll );
830             break;
831 
832         case SCROLL_LINEDOWN:
833             nDelta = ImplScroll( mnThumbPos+mnLineSize, bCallEndScroll );
834             break;
835 
836         case SCROLL_PAGEUP:
837             nDelta = ImplScroll( mnThumbPos-mnPageSize, bCallEndScroll );
838             break;
839 
840         case SCROLL_PAGEDOWN:
841             nDelta = ImplScroll( mnThumbPos+mnPageSize, bCallEndScroll );
842             break;
843         default:
844             ;
845     }
846 
847     return nDelta;
848 }
849 
850 // -----------------------------------------------------------------------
851 
852 void ScrollBar::ImplDoMouseAction( const Point& rMousePos, sal_Bool bCallAction )
853 {
854     sal_uInt16  nOldStateFlags = mnStateFlags;
855     sal_Bool    bAction = sal_False;
856     sal_Bool    bHorizontal = ( GetStyle() & WB_HORZ )? sal_True: sal_False;
857     sal_Bool    bIsInside = sal_False;
858 
859     Point aPoint( 0, 0 );
860     Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
861 
862     switch ( meScrollType )
863     {
864         case SCROLL_LINEUP:
865             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
866                         aControlRegion, rMousePos, bIsInside )?
867                     bIsInside:
868                     maBtn1Rect.IsInside( rMousePos ) )
869             {
870                 bAction = bCallAction;
871                 mnStateFlags |= SCRBAR_STATE_BTN1_DOWN;
872             }
873             else
874                 mnStateFlags &= ~SCRBAR_STATE_BTN1_DOWN;
875             break;
876 
877         case SCROLL_LINEDOWN:
878             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
879                         aControlRegion, rMousePos, bIsInside )?
880                     bIsInside:
881                     maBtn2Rect.IsInside( rMousePos ) )
882             {
883                 bAction = bCallAction;
884                 mnStateFlags |= SCRBAR_STATE_BTN2_DOWN;
885             }
886             else
887                 mnStateFlags &= ~SCRBAR_STATE_BTN2_DOWN;
888             break;
889 
890         case SCROLL_PAGEUP:
891             // HitTestNativeControl, see remark at top of file
892             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT: PART_TRACK_VERT_UPPER,
893                                        maPage1Rect, rMousePos, bIsInside )?
894                     bIsInside:
895                     maPage1Rect.IsInside( rMousePos ) )
896             {
897                 bAction = bCallAction;
898                 mnStateFlags |= SCRBAR_STATE_PAGE1_DOWN;
899             }
900             else
901                 mnStateFlags &= ~SCRBAR_STATE_PAGE1_DOWN;
902             break;
903 
904         case SCROLL_PAGEDOWN:
905             // HitTestNativeControl, see remark at top of file
906             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_RIGHT: PART_TRACK_VERT_LOWER,
907                                        maPage2Rect, rMousePos, bIsInside )?
908                     bIsInside:
909                     maPage2Rect.IsInside( rMousePos ) )
910             {
911                 bAction = bCallAction;
912                 mnStateFlags |= SCRBAR_STATE_PAGE2_DOWN;
913             }
914             else
915                 mnStateFlags &= ~SCRBAR_STATE_PAGE2_DOWN;
916             break;
917         default:
918             ;
919     }
920 
921     if ( nOldStateFlags != mnStateFlags )
922         ImplDraw( mnDragDraw, this );
923     if ( bAction )
924         ImplDoAction( sal_False );
925 }
926 
927 // -----------------------------------------------------------------------
928 
929 void ScrollBar::ImplDragThumb( const Point& rMousePos )
930 {
931     long nMovePix;
932     if ( GetStyle() & WB_HORZ )
933         nMovePix = rMousePos.X()-(maThumbRect.Left()+mnMouseOff);
934     else
935         nMovePix = rMousePos.Y()-(maThumbRect.Top()+mnMouseOff);
936 
937     // move thumb if necessary
938     if ( nMovePix )
939     {
940         mnThumbPixPos += nMovePix;
941         if ( mnThumbPixPos < 0 )
942             mnThumbPixPos = 0;
943         if ( mnThumbPixPos > (mnThumbPixRange-mnThumbPixSize) )
944             mnThumbPixPos = mnThumbPixRange-mnThumbPixSize;
945         long nOldPos = mnThumbPos;
946         mnThumbPos = ImplCalcThumbPos( mnThumbPixPos );
947         ImplUpdateRects();
948         if ( mbFullDrag && (nOldPos != mnThumbPos) )
949         {
950             mnDelta = mnThumbPos-nOldPos;
951             Scroll();
952             mnDelta = 0;
953         }
954     }
955 }
956 
957 // -----------------------------------------------------------------------
958 
959 void ScrollBar::MouseButtonDown( const MouseEvent& rMEvt )
960 {
961     if ( rMEvt.IsLeft() || rMEvt.IsMiddle() )
962     {
963         const Point&    rMousePos = rMEvt.GetPosPixel();
964         sal_uInt16          nTrackFlags = 0;
965         sal_Bool            bHorizontal = ( GetStyle() & WB_HORZ )? sal_True: sal_False;
966         sal_Bool            bIsInside = sal_False;
967         sal_Bool            bDragToMouse = sal_False;
968 
969         Point aPoint( 0, 0 );
970         Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
971 
972         if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
973                     aControlRegion, rMousePos, bIsInside )?
974                 bIsInside:
975                 maBtn1Rect.IsInside( rMousePos ) )
976         {
977             if ( !(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
978             {
979                 nTrackFlags     = STARTTRACK_BUTTONREPEAT;
980                 meScrollType    = SCROLL_LINEUP;
981                 mnDragDraw      = SCRBAR_DRAW_BTN1;
982             }
983             else
984                 Sound::Beep( SOUND_DISABLE, this );
985         }
986         else if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
987                     aControlRegion, rMousePos, bIsInside )?
988                 bIsInside:
989                 maBtn2Rect.IsInside( rMousePos ) )
990         {
991             if ( !(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
992             {
993                 nTrackFlags     = STARTTRACK_BUTTONREPEAT;
994                 meScrollType    = SCROLL_LINEDOWN;
995                 mnDragDraw      = SCRBAR_DRAW_BTN2;
996             }
997             else
998                 Sound::Beep( SOUND_DISABLE, this );
999         }
1000         else
1001         {
1002             bool bThumbHit = HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_THUMB_HORZ : PART_THUMB_VERT,
1003                                                    maThumbRect, rMousePos, bIsInside )
1004                              ? bIsInside : maThumbRect.IsInside( rMousePos );
1005             bool bDragHandling = rMEvt.IsMiddle() || bThumbHit || ImplGetSVData()->maNWFData.mbScrollbarJumpPage;
1006             if( bDragHandling )
1007             {
1008                 if( mpData )
1009                 {
1010                     mpData->mbHide = sal_True;  // disable focus blinking
1011                     if( HasFocus() )
1012                         ImplDraw( SCRBAR_DRAW_THUMB, this ); // paint without focus
1013                 }
1014 
1015                 if ( mnVisibleSize < mnMaxRange-mnMinRange )
1016                 {
1017                     nTrackFlags     = 0;
1018                     meScrollType    = SCROLL_DRAG;
1019                     mnDragDraw      = SCRBAR_DRAW_THUMB;
1020 
1021                     // calculate mouse offset
1022                     if( rMEvt.IsMiddle() || (ImplGetSVData()->maNWFData.mbScrollbarJumpPage && !bThumbHit) )
1023                     {
1024                         bDragToMouse = sal_True;
1025                         if ( GetStyle() & WB_HORZ )
1026                             mnMouseOff = maThumbRect.GetWidth()/2;
1027                         else
1028                             mnMouseOff = maThumbRect.GetHeight()/2;
1029                     }
1030                     else
1031                     {
1032                         if ( GetStyle() & WB_HORZ )
1033                             mnMouseOff = rMousePos.X()-maThumbRect.Left();
1034                         else
1035                             mnMouseOff = rMousePos.Y()-maThumbRect.Top();
1036                     }
1037 
1038                     mnStateFlags |= SCRBAR_STATE_THUMB_DOWN;
1039                     ImplDraw( mnDragDraw, this );
1040                 }
1041                 else
1042                     Sound::Beep( SOUND_DISABLE, this );
1043             }
1044             else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_AREA : PART_TRACK_VERT_AREA,
1045                                            aControlRegion, rMousePos, bIsInside )?
1046                 bIsInside : sal_True )
1047             {
1048                 nTrackFlags = STARTTRACK_BUTTONREPEAT;
1049 
1050                 // HitTestNativeControl, see remark at top of file
1051                 if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER,
1052                                            maPage1Rect, rMousePos, bIsInside )?
1053                     bIsInside:
1054                     maPage1Rect.IsInside( rMousePos ) )
1055                 {
1056                     meScrollType    = SCROLL_PAGEUP;
1057                     mnDragDraw      = SCRBAR_DRAW_PAGE1;
1058                 }
1059                 else
1060                 {
1061                     meScrollType    = SCROLL_PAGEDOWN;
1062                     mnDragDraw      = SCRBAR_DRAW_PAGE2;
1063                 }
1064             }
1065         }
1066 
1067         // Soll Tracking gestartet werden
1068         if ( meScrollType != SCROLL_DONTKNOW )
1069         {
1070             // remember original position in case of abort or EndScroll-Delta
1071             mnStartPos = mnThumbPos;
1072             // #92906# Call StartTracking() before ImplDoMouseAction(), otherwise
1073             // MouseButtonUp() / EndTracking() may be called if somebody is spending
1074             // a lot of time in the scroll handler
1075             StartTracking( nTrackFlags );
1076             ImplDoMouseAction( rMousePos );
1077 
1078             if( bDragToMouse )
1079                 ImplDragThumb( rMousePos );
1080         }
1081     }
1082 }
1083 
1084 // -----------------------------------------------------------------------
1085 
1086 void ScrollBar::Tracking( const TrackingEvent& rTEvt )
1087 {
1088     if ( rTEvt.IsTrackingEnded() )
1089     {
1090         // Button und PageRect-Status wieder herstellen
1091         sal_uInt16 nOldStateFlags = mnStateFlags;
1092         mnStateFlags &= ~(SCRBAR_STATE_BTN1_DOWN | SCRBAR_STATE_BTN2_DOWN |
1093                           SCRBAR_STATE_PAGE1_DOWN | SCRBAR_STATE_PAGE2_DOWN |
1094                           SCRBAR_STATE_THUMB_DOWN);
1095         if ( nOldStateFlags != mnStateFlags )
1096             ImplDraw( mnDragDraw, this );
1097         mnDragDraw = 0;
1098 
1099         // Bei Abbruch, die alte ThumbPosition wieder herstellen
1100         if ( rTEvt.IsTrackingCanceled() )
1101         {
1102             long nOldPos = mnThumbPos;
1103             SetThumbPos( mnStartPos );
1104             mnDelta = mnThumbPos-nOldPos;
1105             Scroll();
1106         }
1107 
1108         if ( meScrollType == SCROLL_DRAG )
1109         {
1110             // Wenn gedragt wurde, berechnen wir den Thumb neu, damit
1111             // er wieder auf einer gerundeten ThumbPosition steht
1112             ImplCalc();
1113 
1114             if ( !mbFullDrag && (mnStartPos != mnThumbPos) )
1115             {
1116                 mnDelta = mnThumbPos-mnStartPos;
1117                 Scroll();
1118                 mnDelta = 0;
1119             }
1120         }
1121 
1122         mnDelta = mnThumbPos-mnStartPos;
1123         EndScroll();
1124         mnDelta = 0;
1125         meScrollType = SCROLL_DONTKNOW;
1126 
1127         if( mpData )
1128             mpData->mbHide = sal_False; // re-enable focus blinking
1129     }
1130     else
1131     {
1132         const Point rMousePos = rTEvt.GetMouseEvent().GetPosPixel();
1133 
1134         // Dragging wird speziell behandelt
1135         if ( meScrollType == SCROLL_DRAG )
1136             ImplDragThumb( rMousePos );
1137         else
1138             ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() );
1139 
1140         // Wenn ScrollBar-Werte so umgesetzt wurden, das es nichts
1141         // mehr zum Tracking gibt, dann berechen wir hier ab
1142         if ( !IsVisible() || (mnVisibleSize >= (mnMaxRange-mnMinRange)) )
1143             EndTracking();
1144     }
1145 }
1146 
1147 // -----------------------------------------------------------------------
1148 
1149 void ScrollBar::KeyInput( const KeyEvent& rKEvt )
1150 {
1151     if ( !rKEvt.GetKeyCode().GetModifier() )
1152     {
1153         switch ( rKEvt.GetKeyCode().GetCode() )
1154         {
1155             case KEY_HOME:
1156                 DoScroll( 0 );
1157                 break;
1158 
1159             case KEY_END:
1160                 DoScroll( GetRangeMax() );
1161                 break;
1162 
1163             case KEY_LEFT:
1164             case KEY_UP:
1165                 DoScrollAction( SCROLL_LINEUP );
1166                 break;
1167 
1168             case KEY_RIGHT:
1169             case KEY_DOWN:
1170                 DoScrollAction( SCROLL_LINEDOWN );
1171                 break;
1172 
1173             case KEY_PAGEUP:
1174                 DoScrollAction( SCROLL_PAGEUP );
1175                 break;
1176 
1177             case KEY_PAGEDOWN:
1178                 DoScrollAction( SCROLL_PAGEDOWN );
1179                 break;
1180 
1181             default:
1182                 Control::KeyInput( rKEvt );
1183                 break;
1184         }
1185     }
1186     else
1187         Control::KeyInput( rKEvt );
1188 }
1189 
1190 // -----------------------------------------------------------------------
1191 
1192 void ScrollBar::Paint( const Rectangle& )
1193 {
1194     ImplDraw( SCRBAR_DRAW_ALL, this );
1195 }
1196 
1197 // -----------------------------------------------------------------------
1198 
1199 void ScrollBar::Resize()
1200 {
1201     Control::Resize();
1202     mbCalcSize = sal_True;
1203     if ( IsReallyVisible() )
1204         ImplCalc( sal_False );
1205     Invalidate();
1206 }
1207 
1208 // -----------------------------------------------------------------------
1209 
1210 IMPL_LINK( ScrollBar, ImplAutoTimerHdl, AutoTimer*, EMPTYARG )
1211 {
1212     if( mpData && mpData->mbHide )
1213         return 0;
1214     ImplInvert();
1215     return 0;
1216 }
1217 
1218 void ScrollBar::ImplInvert()
1219 {
1220     Rectangle aRect( maThumbRect );
1221     if( aRect.getWidth() > 4 )
1222     {
1223         aRect.Left() += 2;
1224         aRect.Right() -= 2;
1225     }
1226     if( aRect.getHeight() > 4 )
1227     {
1228         aRect.Top() += 2;
1229         aRect.Bottom() -= 2;
1230     }
1231 
1232     Invert( aRect, 0 );
1233 }
1234 
1235 // -----------------------------------------------------------------------
1236 
1237 void ScrollBar::GetFocus()
1238 {
1239     if( !mpData )
1240     {
1241 	    mpData = new ImplScrollBarData;
1242 		mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
1243         mpData->mbHide = sal_False;
1244     }
1245     ImplInvert();   // react immediately
1246 	mpData->maTimer.SetTimeout( GetSettings().GetStyleSettings().GetCursorBlinkTime() );
1247     mpData->maTimer.Start();
1248     Control::GetFocus();
1249 }
1250 
1251 // -----------------------------------------------------------------------
1252 
1253 void ScrollBar::LoseFocus()
1254 {
1255     if( mpData )
1256         mpData->maTimer.Stop();
1257     ImplDraw( SCRBAR_DRAW_THUMB, this );
1258 
1259     Control::LoseFocus();
1260 }
1261 
1262 // -----------------------------------------------------------------------
1263 
1264 void ScrollBar::StateChanged( StateChangedType nType )
1265 {
1266     Control::StateChanged( nType );
1267 
1268     if ( nType == STATE_CHANGE_INITSHOW )
1269         ImplCalc( sal_False );
1270     else if ( nType == STATE_CHANGE_DATA )
1271     {
1272         if ( IsReallyVisible() && IsUpdateMode() )
1273             ImplCalc( sal_True );
1274     }
1275     else if ( nType == STATE_CHANGE_UPDATEMODE )
1276     {
1277         if ( IsReallyVisible() && IsUpdateMode() )
1278         {
1279             ImplCalc( sal_False );
1280             Invalidate();
1281         }
1282     }
1283     else if ( nType == STATE_CHANGE_ENABLE )
1284     {
1285         if ( IsReallyVisible() && IsUpdateMode() )
1286             Invalidate();
1287     }
1288     else if ( nType == STATE_CHANGE_STYLE )
1289     {
1290         ImplInitStyle( GetStyle() );
1291         if ( IsReallyVisible() && IsUpdateMode() )
1292         {
1293             if ( (GetPrevStyle() & SCRBAR_VIEW_STYLE) !=
1294                  (GetStyle() & SCRBAR_VIEW_STYLE) )
1295             {
1296                 mbCalcSize = sal_True;
1297                 ImplCalc( sal_False );
1298                 Invalidate();
1299             }
1300         }
1301     }
1302 }
1303 
1304 // -----------------------------------------------------------------------
1305 
1306 void ScrollBar::DataChanged( const DataChangedEvent& rDCEvt )
1307 {
1308     Control::DataChanged( rDCEvt );
1309 
1310     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1311          (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1312     {
1313         mbCalcSize = sal_True;
1314         ImplCalc( sal_False );
1315         Invalidate();
1316     }
1317 }
1318 
1319 // -----------------------------------------------------------------------
1320 
1321 Rectangle* ScrollBar::ImplFindPartRect( const Point& rPt )
1322 {
1323     sal_Bool    bHorizontal = ( GetStyle() & WB_HORZ )? sal_True: sal_False;
1324     sal_Bool    bIsInside = sal_False;
1325 
1326     Point aPoint( 0, 0 );
1327     Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
1328 
1329     if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
1330                 aControlRegion, rPt, bIsInside )?
1331             bIsInside:
1332             maBtn1Rect.IsInside( rPt ) )
1333         return &maBtn1Rect;
1334     else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
1335                 aControlRegion, rPt, bIsInside )?
1336             bIsInside:
1337             maBtn2Rect.IsInside( rPt ) )
1338         return &maBtn2Rect;
1339     // HitTestNativeControl, see remark at top of file
1340     else if( HitTestNativeControl( CTRL_SCROLLBAR,  bHorizontal ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER,
1341                 maPage1Rect, rPt, bIsInside)?
1342             bIsInside:
1343             maPage1Rect.IsInside( rPt ) )
1344         return &maPage1Rect;
1345     // HitTestNativeControl, see remark at top of file
1346     else if( HitTestNativeControl( CTRL_SCROLLBAR,  bHorizontal ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER,
1347                 maPage2Rect, rPt, bIsInside)?
1348             bIsInside:
1349             maPage2Rect.IsInside( rPt ) )
1350         return &maPage2Rect;
1351     // HitTestNativeControl, see remark at top of file
1352     else if( HitTestNativeControl( CTRL_SCROLLBAR,  bHorizontal ? PART_THUMB_HORZ : PART_THUMB_VERT,
1353                 maThumbRect, rPt, bIsInside)?
1354              bIsInside:
1355              maThumbRect.IsInside( rPt ) )
1356         return &maThumbRect;
1357     else
1358         return NULL;
1359 }
1360 
1361 long ScrollBar::PreNotify( NotifyEvent& rNEvt )
1362 {
1363     long nDone = 0;
1364     const MouseEvent* pMouseEvt = NULL;
1365 
1366     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
1367     {
1368         if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1369         {
1370             // trigger redraw if mouse over state has changed
1371             if( IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) )
1372             {
1373                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1374                 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1375                 if( pRect != pLastRect || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
1376                 {
1377                     Region aRgn( GetActiveClipRegion() );
1378                     Region aClipRegion;
1379 
1380                     if ( pRect )
1381                         aClipRegion.Union( *pRect );
1382                     if ( pLastRect )
1383                         aClipRegion.Union( *pLastRect );
1384 
1385                     // Support for 3-button scroll bars
1386                     sal_Bool bHas3Buttons = IsNativeControlSupported( CTRL_SCROLLBAR, HAS_THREE_BUTTONS );
1387                     if ( bHas3Buttons && ( pRect == &maBtn1Rect || pLastRect == &maBtn1Rect ) )
1388                     {
1389                         aClipRegion.Union( maBtn2Rect );
1390                     }
1391 
1392                     SetClipRegion( aClipRegion );
1393                     Paint( aClipRegion.GetBoundRect() );
1394 
1395                     SetClipRegion( aRgn );
1396                 }
1397             }
1398         }
1399     }
1400 
1401     return nDone ? nDone : Control::PreNotify(rNEvt);
1402 }
1403 
1404 // -----------------------------------------------------------------------
1405 
1406 void ScrollBar::Scroll()
1407 {
1408     ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_SCROLL, maScrollHdl, this );
1409 }
1410 
1411 // -----------------------------------------------------------------------
1412 
1413 void ScrollBar::EndScroll()
1414 {
1415     ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_ENDSCROLL, maEndScrollHdl, this );
1416 }
1417 
1418 // -----------------------------------------------------------------------
1419 
1420 long ScrollBar::DoScroll( long nNewPos )
1421 {
1422     if ( meScrollType != SCROLL_DONTKNOW )
1423         return 0;
1424 
1425     meScrollType = SCROLL_DRAG;
1426     long nDelta = ImplScroll( nNewPos, sal_True );
1427     meScrollType = SCROLL_DONTKNOW;
1428     return nDelta;
1429 }
1430 
1431 // -----------------------------------------------------------------------
1432 
1433 long ScrollBar::DoScrollAction( ScrollType eScrollType )
1434 {
1435     if ( (meScrollType != SCROLL_DONTKNOW) ||
1436          (eScrollType == SCROLL_DONTKNOW) ||
1437          (eScrollType == SCROLL_DRAG) )
1438         return 0;
1439 
1440     meScrollType = eScrollType;
1441     long nDelta = ImplDoAction( sal_True );
1442     meScrollType = SCROLL_DONTKNOW;
1443     return nDelta;
1444 }
1445 
1446 // -----------------------------------------------------------------------
1447 
1448 void ScrollBar::SetRangeMin( long nNewRange )
1449 {
1450     SetRange( Range( nNewRange, GetRangeMax() ) );
1451 }
1452 
1453 // -----------------------------------------------------------------------
1454 
1455 void ScrollBar::SetRangeMax( long nNewRange )
1456 {
1457     SetRange( Range( GetRangeMin(), nNewRange ) );
1458 }
1459 
1460 // -----------------------------------------------------------------------
1461 
1462 void ScrollBar::SetRange( const Range& rRange )
1463 {
1464     // Range einpassen
1465     Range aRange = rRange;
1466     aRange.Justify();
1467     long nNewMinRange = aRange.Min();
1468     long nNewMaxRange = aRange.Max();
1469 
1470     // Wenn Range sich unterscheidet, dann neuen setzen
1471     if ( (mnMinRange != nNewMinRange) ||
1472          (mnMaxRange != nNewMaxRange) )
1473     {
1474         mnMinRange = nNewMinRange;
1475         mnMaxRange = nNewMaxRange;
1476 
1477         // Thumb einpassen
1478         if ( mnThumbPos > mnMaxRange-mnVisibleSize )
1479             mnThumbPos = mnMaxRange-mnVisibleSize;
1480         if ( mnThumbPos < mnMinRange )
1481             mnThumbPos = mnMinRange;
1482 
1483         StateChanged( STATE_CHANGE_DATA );
1484     }
1485 }
1486 
1487 // -----------------------------------------------------------------------
1488 
1489 void ScrollBar::SetThumbPos( long nNewThumbPos )
1490 {
1491     if ( nNewThumbPos > mnMaxRange-mnVisibleSize )
1492         nNewThumbPos = mnMaxRange-mnVisibleSize;
1493     if ( nNewThumbPos < mnMinRange )
1494         nNewThumbPos = mnMinRange;
1495 
1496     if ( mnThumbPos != nNewThumbPos )
1497     {
1498         mnThumbPos = nNewThumbPos;
1499         StateChanged( STATE_CHANGE_DATA );
1500     }
1501 }
1502 
1503 // -----------------------------------------------------------------------
1504 
1505 void ScrollBar::SetVisibleSize( long nNewSize )
1506 {
1507     if ( mnVisibleSize != nNewSize )
1508     {
1509         mnVisibleSize = nNewSize;
1510 
1511         // Thumb einpassen
1512         if ( mnThumbPos > mnMaxRange-mnVisibleSize )
1513             mnThumbPos = mnMaxRange-mnVisibleSize;
1514         if ( mnThumbPos < mnMinRange )
1515             mnThumbPos = mnMinRange;
1516         StateChanged( STATE_CHANGE_DATA );
1517     }
1518 }
1519 
1520 // =======================================================================
1521 
1522 void ScrollBarBox::ImplInit( Window* pParent, WinBits nStyle )
1523 {
1524     Window::ImplInit( pParent, nStyle, NULL );
1525 
1526     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1527     long nScrollSize = rStyleSettings.GetScrollBarSize();
1528     SetSizePixel( Size( nScrollSize, nScrollSize ) );
1529     ImplInitSettings();
1530 }
1531 
1532 // -----------------------------------------------------------------------
1533 
1534 ScrollBarBox::ScrollBarBox( Window* pParent, WinBits nStyle ) :
1535     Window( WINDOW_SCROLLBARBOX )
1536 {
1537     ImplInit( pParent, nStyle );
1538 }
1539 
1540 // -----------------------------------------------------------------------
1541 
1542 ScrollBarBox::ScrollBarBox( Window* pParent, const ResId& rResId ) :
1543     Window( WINDOW_SCROLLBARBOX )
1544 {
1545     rResId.SetRT( RSC_SCROLLBAR );
1546     ImplInit( pParent, ImplInitRes( rResId ) );
1547     ImplLoadRes( rResId );
1548 }
1549 
1550 // -----------------------------------------------------------------------
1551 
1552 void ScrollBarBox::ImplInitSettings()
1553 {
1554     // Hack, damit man auch DockingWindows ohne Hintergrund bauen kann
1555     // und noch nicht alles umgestellt ist
1556     if ( IsBackground() )
1557     {
1558         Color aColor;
1559         if ( IsControlBackground() )
1560             aColor = GetControlBackground();
1561         else
1562             aColor = GetSettings().GetStyleSettings().GetFaceColor();
1563         SetBackground( aColor );
1564     }
1565 }
1566 
1567 // -----------------------------------------------------------------------
1568 
1569 void ScrollBarBox::StateChanged( StateChangedType nType )
1570 {
1571     Window::StateChanged( nType );
1572 
1573     if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
1574     {
1575         ImplInitSettings();
1576         Invalidate();
1577     }
1578 }
1579 
1580 // -----------------------------------------------------------------------
1581 
1582 void ScrollBarBox::DataChanged( const DataChangedEvent& rDCEvt )
1583 {
1584     Window::DataChanged( rDCEvt );
1585 
1586     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1587          (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1588     {
1589         ImplInitSettings();
1590         Invalidate();
1591     }
1592 }
1593