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