xref: /trunk/main/vcl/source/control/scrbar.cxx (revision f02ea3ea)
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 
ImplMulDiv(long nNumber,long nNumerator,long nDenominator)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 
ImplInit(Window * pParent,WinBits nStyle)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 
ImplInitStyle(WinBits nStyle)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 
ScrollBar(Window * pParent,WinBits nStyle)146 ScrollBar::ScrollBar( Window* pParent, WinBits nStyle ) :
147     Control( WINDOW_SCROLLBAR )
148 {
149     ImplInit( pParent, nStyle );
150 }
151 
152 // -----------------------------------------------------------------------
153 
ScrollBar(Window * pParent,const ResId & rResId)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 
~ScrollBar()168 ScrollBar::~ScrollBar()
169 {
170     if( mpData )
171         delete mpData;
172 }
173 
174 // -----------------------------------------------------------------------
175 
ImplLoadRes(const ResId & rResId)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 
ImplUpdateRects(sal_Bool bUpdate)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 
ImplCalcThumbPos(long nPixPos)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 
ImplCalcThumbPosPix(long nPos)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 
ImplCalc(sal_Bool bUpdate)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                 if (aBtn1Region.IsEmpty() && aBtn2Region.IsEmpty())
358                 {
359                     Size aBtnSize( aSize.Height(), aSize.Height() );
360                     maBtn2Rect.Top() = maBtn1Rect.Top();
361                     maBtn2Rect.Left() = aSize.Width()-aSize.Height();
362                     maBtn1Rect.SetSize( aBtnSize );
363                     maBtn2Rect.SetSize( aBtnSize );
364                 }
365                 else
366                 {
367                     maBtn1Rect.SetEmpty();
368                     maBtn2Rect.SetEmpty();
369                 }
370             }
371 
372             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_HORZ_AREA,
373 	                 aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) )
374             {
375                 maTrackRect = aTrackRegion;
376             }
377             else
378             {
379                 if ( ! maBtn1Rect.IsEmpty())
380                     maTrackRect = Rectangle( maBtn1Rect.TopRight(), maBtn2Rect.BottomLeft() );
381                 else
382                     maTrackRect = aControlRegion;
383             }
384 
385             // Check if available space is big enough for thumb ( min thumb size = ScrBar width/height )
386             mnThumbPixRange = maTrackRect.Right() - maTrackRect.Left();
387             if( mnThumbPixRange > 0 )
388             {
389                 maPage1Rect.Left()      = maTrackRect.Left();
390                 maPage1Rect.Bottom()	=
391                 maPage2Rect.Bottom()	=
392                 maThumbRect.Bottom()    = maTrackRect.Bottom();
393             }
394             else
395             {
396                 mnThumbPixRange = 0;
397                 maPage1Rect.SetEmpty();
398                 maPage2Rect.SetEmpty();
399             }
400         }
401         else
402         {
403             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_UP,
404                         aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn1Region ) &&
405                  GetNativeControlRegion( CTRL_SCROLLBAR, PART_BUTTON_DOWN,
406                         aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aBtn2Region ) )
407             {
408                 maBtn1Rect = aBtn1Region;
409                 maBtn2Rect = aBtn2Region;
410             }
411             else
412             {
413                 if (aBtn1Region.IsEmpty() && aBtn2Region.IsEmpty())
414                 {
415                     const Size aBtnSize( aSize.Width(), aSize.Width() );
416                     maBtn2Rect.Left()   = maBtn1Rect.Left();
417                     maBtn2Rect.Top()    = aSize.Height()-aSize.Width();
418                     maBtn1Rect.SetSize( aBtnSize );
419                     maBtn2Rect.SetSize( aBtnSize );
420                 }
421                 else
422                 {
423                     maBtn1Rect.SetEmpty();
424                     maBtn2Rect.SetEmpty();
425                 }
426             }
427 
428             if ( GetNativeControlRegion( CTRL_SCROLLBAR, PART_TRACK_VERT_AREA,
429 	                 aControlRegion, 0, ImplControlValue(), rtl::OUString(), aBoundingRegion, aTrackRegion ) )
430                 maTrackRect = aTrackRegion;
431 			else
432             {
433                 if ( ! maBtn1Rect.IsEmpty())
434                     maTrackRect = Rectangle( maBtn1Rect.BottomLeft()+Point(0,1), maBtn2Rect.TopRight() );
435                 else
436                     maTrackRect = aControlRegion;
437             }
438 
439             // Check if available space is big enough for thumb
440             mnThumbPixRange = maTrackRect.Bottom() - maTrackRect.Top();
441             if( mnThumbPixRange > 0 )
442             {
443                 maPage1Rect.Top()       = maTrackRect.Top();
444                 maPage1Rect.Right()		=
445                 maPage2Rect.Right()		=
446                 maThumbRect.Right()     = maTrackRect.Right();
447             }
448             else
449 			{
450                 mnThumbPixRange = 0;
451                 maPage1Rect.SetEmpty();
452                 maPage2Rect.SetEmpty();
453             }
454         }
455 
456         if ( !mnThumbPixRange )
457             maThumbRect.SetEmpty();
458 
459         mbCalcSize = sal_False;
460     }
461 
462     if ( mnThumbPixRange )
463     {
464         // Werte berechnen
465         if ( (mnVisibleSize >= (mnMaxRange-mnMinRange)) ||
466              ((mnMaxRange-mnMinRange) <= 0) )
467         {
468             mnThumbPos      = mnMinRange;
469             mnThumbPixPos   = 0;
470             mnThumbPixSize  = mnThumbPixRange;
471         }
472         else
473         {
474             if ( mnVisibleSize )
475                 mnThumbPixSize = ImplMulDiv( mnThumbPixRange, mnVisibleSize, mnMaxRange-mnMinRange );
476             else
477             {
478                 if ( GetStyle() & WB_HORZ )
479                     mnThumbPixSize = maThumbRect.GetWidth();
480                 else
481                     mnThumbPixSize = maThumbRect.GetHeight();
482             }
483             if ( mnThumbPixSize < nMinThumbSize )
484                 mnThumbPixSize = nMinThumbSize;
485             if ( mnThumbPixSize > mnThumbPixRange )
486                 mnThumbPixSize = mnThumbPixRange;
487             mnThumbPixPos = ImplCalcThumbPosPix( mnThumbPos );
488         }
489     }
490 
491     // Wenn neu ausgegeben werden soll und wir schon ueber eine
492     // Aktion einen Paint-Event ausgeloest bekommen haben, dann
493     // geben wir nicht direkt aus, sondern invalidieren nur alles
494     if ( bUpdate && HasPaintEvent() )
495     {
496         Invalidate();
497         bUpdate = sal_False;
498     }
499     ImplUpdateRects( bUpdate );
500 }
501 
502 // -----------------------------------------------------------------------
503 
Draw(OutputDevice * pDev,const Point & rPos,const Size & rSize,sal_uLong nFlags)504 void ScrollBar::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
505 {
506     Point       aPos  = pDev->LogicToPixel( rPos );
507     Size        aSize = pDev->LogicToPixel( rSize );
508     Rectangle   aRect( aPos, aSize );
509 
510     pDev->Push();
511     pDev->SetMapMode();
512     if ( !(nFlags & WINDOW_DRAW_MONO) )
513 	{
514 		// DecoView uses the FaceColor...
515 		AllSettings aSettings = pDev->GetSettings();
516 		StyleSettings aStyleSettings = aSettings.GetStyleSettings();
517 		if ( IsControlBackground() )
518 			aStyleSettings.SetFaceColor( GetControlBackground() );
519 		else
520 			aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
521 
522 		aSettings.SetStyleSettings( aStyleSettings );
523 		pDev->SetSettings( aSettings );
524 	}
525 
526     // for printing:
527     // -calculate the size of the rects
528     // -because this is zero-based add the correct offset
529     // -print
530     // -force recalculate
531 
532     if ( mbCalcSize )
533         ImplCalc( sal_False );
534 
535     maBtn1Rect+=aPos;
536     maBtn2Rect+=aPos;
537     maThumbRect+=aPos;
538     mpData->maTrackRect+=aPos; // TODO: update when maTrackRect is no longer in mpData
539     maPage1Rect+=aPos;
540     maPage2Rect+=aPos;
541 
542     ImplDraw( SCRBAR_DRAW_ALL, pDev );
543     pDev->Pop();
544 
545     mbCalcSize = sal_True;
546 }
547 
548 // -----------------------------------------------------------------------
549 
ImplDrawNative(sal_uInt16 nDrawFlags)550 sal_Bool ScrollBar::ImplDrawNative( sal_uInt16 nDrawFlags )
551 {
552     ScrollbarValue scrValue;
553 
554     sal_Bool bNativeOK = IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL);
555     if( bNativeOK )
556     {
557         sal_Bool bHorz = (GetStyle() & WB_HORZ ? true : false);
558 
559         // Draw the entire background if the control supports it
560         if( IsNativeControlSupported(CTRL_SCROLLBAR, bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT) )
561         {
562             ControlState		nState = ( IsEnabled() ? CTRL_STATE_ENABLED : 0 ) | ( HasFocus() ? CTRL_STATE_FOCUSED : 0 );
563 
564             scrValue.mnMin = mnMinRange;
565             scrValue.mnMax = mnMaxRange;
566             scrValue.mnCur = mnThumbPos;
567             scrValue.mnVisibleSize = mnVisibleSize;
568             scrValue.maThumbRect = maThumbRect;
569             scrValue.maButton1Rect = maBtn1Rect;
570             scrValue.maButton2Rect = maBtn2Rect;
571             scrValue.mnButton1State = ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0) |
572 								((!(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)) ? CTRL_STATE_ENABLED : 0);
573             scrValue.mnButton2State = ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0) |
574 								((!(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)) ? CTRL_STATE_ENABLED : 0);
575             scrValue.mnThumbState = nState | ((mnStateFlags & SCRBAR_STATE_THUMB_DOWN) ? CTRL_STATE_PRESSED : 0);
576             scrValue.mnPage1State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0);
577             scrValue.mnPage2State = nState | ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0);
578 
579             if( IsMouseOver() )
580             {
581                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
582                 if( pRect )
583                 {
584                     if( pRect == &maThumbRect )
585                         scrValue.mnThumbState |= CTRL_STATE_ROLLOVER;
586                     else if( pRect == &maBtn1Rect )
587                         scrValue.mnButton1State |= CTRL_STATE_ROLLOVER;
588                     else if( pRect == &maBtn2Rect )
589                         scrValue.mnButton2State |= CTRL_STATE_ROLLOVER;
590                     else if( pRect == &maPage1Rect )
591                         scrValue.mnPage1State |= CTRL_STATE_ROLLOVER;
592                     else if( pRect == &maPage2Rect )
593                         scrValue.mnPage2State |= CTRL_STATE_ROLLOVER;
594                 }
595             }
596 
597             Rectangle aCtrlRegion;
598             aCtrlRegion.Union( maBtn1Rect );
599             aCtrlRegion.Union( maBtn2Rect );
600             aCtrlRegion.Union( maPage1Rect );
601             aCtrlRegion.Union( maPage2Rect );
602             aCtrlRegion.Union( maThumbRect );
603             bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_DRAW_BACKGROUND_HORZ : PART_DRAW_BACKGROUND_VERT),
604                             aCtrlRegion, nState, scrValue, rtl::OUString() );
605         }
606         else
607       {
608         if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) || (nDrawFlags & SCRBAR_DRAW_PAGE2) )
609         {
610             sal_uInt32	part1 = bHorz ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER;
611             sal_uInt32	part2 = bHorz ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER;
612             Rectangle   aCtrlRegion1( maPage1Rect );
613             Rectangle   aCtrlRegion2( maPage2Rect );
614             ControlState nState1 = (IsEnabled() ? CTRL_STATE_ENABLED : 0) | (HasFocus() ? CTRL_STATE_FOCUSED : 0);
615             ControlState nState2 = nState1;
616 
617             nState1 |= ((mnStateFlags & SCRBAR_STATE_PAGE1_DOWN) ? CTRL_STATE_PRESSED : 0);
618             nState2 |= ((mnStateFlags & SCRBAR_STATE_PAGE2_DOWN) ? CTRL_STATE_PRESSED : 0);
619 
620             if( IsMouseOver() )
621             {
622                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
623                 if( pRect )
624                 {
625                     if( pRect == &maPage1Rect )
626                         nState1 |= CTRL_STATE_ROLLOVER;
627                     else if( pRect == &maPage2Rect )
628                         nState2 |= CTRL_STATE_ROLLOVER;
629                 }
630             }
631 
632             if ( nDrawFlags & SCRBAR_DRAW_PAGE1 )
633                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1,
634                                 scrValue, rtl::OUString() );
635 
636             if ( nDrawFlags & SCRBAR_DRAW_PAGE2 )
637                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
638                                 scrValue, rtl::OUString() );
639         }
640         if ( (nDrawFlags & SCRBAR_DRAW_BTN1) || (nDrawFlags & SCRBAR_DRAW_BTN2) )
641         {
642             sal_uInt32	part1 = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP;
643             sal_uInt32	part2 = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN;
644             Rectangle  	aCtrlRegion1( maBtn1Rect );
645             Rectangle  	aCtrlRegion2( maBtn2Rect );
646             ControlState nState1 = HasFocus() ? CTRL_STATE_FOCUSED : 0;
647             ControlState nState2 = nState1;
648 
649             if ( !Window::IsEnabled() || !IsEnabled() )
650                 nState1 = (nState2 &= ~CTRL_STATE_ENABLED);
651             else
652                 nState1 = (nState2 |= CTRL_STATE_ENABLED);
653 
654             nState1 |= ((mnStateFlags & SCRBAR_STATE_BTN1_DOWN) ? CTRL_STATE_PRESSED : 0);
655             nState2 |= ((mnStateFlags & SCRBAR_STATE_BTN2_DOWN) ? CTRL_STATE_PRESSED : 0);
656 
657             if(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE)
658                 nState1 &= ~CTRL_STATE_ENABLED;
659             if(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE)
660                 nState2 &= ~CTRL_STATE_ENABLED;
661 
662             if( IsMouseOver() )
663             {
664                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
665                 if( pRect )
666                 {
667                     if( pRect == &maBtn1Rect )
668                         nState1 |= CTRL_STATE_ROLLOVER;
669                     else if( pRect == &maBtn2Rect )
670                         nState2 |= CTRL_STATE_ROLLOVER;
671                 }
672             }
673 
674             if ( nDrawFlags & SCRBAR_DRAW_BTN1 )
675                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part1, aCtrlRegion1, nState1,
676                                 scrValue, rtl::OUString() );
677 
678             if ( nDrawFlags & SCRBAR_DRAW_BTN2 )
679                 bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, part2, aCtrlRegion2, nState2,
680                                 scrValue, rtl::OUString() );
681         }
682         if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && !maThumbRect.IsEmpty() )
683         {
684             ControlState	nState = IsEnabled() ? CTRL_STATE_ENABLED : 0;
685             Rectangle		aCtrlRegion( maThumbRect );
686 
687             if ( mnStateFlags & SCRBAR_STATE_THUMB_DOWN )
688                 nState |= CTRL_STATE_PRESSED;
689 
690             if ( HasFocus() )
691                 nState |= CTRL_STATE_FOCUSED;
692 
693             if( IsMouseOver() )
694             {
695                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
696                 if( pRect )
697                 {
698                     if( pRect == &maThumbRect )
699                         nState |= CTRL_STATE_ROLLOVER;
700                 }
701             }
702 
703             bNativeOK = DrawNativeControl( CTRL_SCROLLBAR, (bHorz ? PART_THUMB_HORZ : PART_THUMB_VERT),
704                     aCtrlRegion, nState, scrValue, rtl::OUString() );
705         }
706       }
707     }
708     return bNativeOK;
709 }
710 
ImplDraw(sal_uInt16 nDrawFlags,OutputDevice * pOutDev)711 void ScrollBar::ImplDraw( sal_uInt16 nDrawFlags, OutputDevice* pOutDev )
712 {
713     DecorationView          aDecoView( pOutDev );
714     Rectangle               aTempRect;
715     sal_uInt16                  nStyle;
716     const StyleSettings&    rStyleSettings = pOutDev->GetSettings().GetStyleSettings();
717     SymbolType              eSymbolType;
718     sal_Bool                    bEnabled = IsEnabled();
719 
720     // Evt. noch offene Berechnungen nachholen
721     if ( mbCalcSize )
722         ImplCalc( sal_False );
723 
724     Window *pWin = NULL;
725     if( pOutDev->GetOutDevType() == OUTDEV_WINDOW )
726         pWin = (Window*) pOutDev;
727 
728     // Draw the entire control if the native theme engine needs it
729     if ( nDrawFlags && pWin && pWin->IsNativeControlSupported(CTRL_SCROLLBAR, PART_DRAW_BACKGROUND_HORZ) )
730     {
731         ImplDrawNative( SCRBAR_DRAW_BACKGROUND );
732         return;
733     }
734 
735     if( (nDrawFlags & SCRBAR_DRAW_BTN1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN1 ) ) )
736     {
737         nStyle = BUTTON_DRAW_NOLIGHTBORDER;
738         if ( mnStateFlags & SCRBAR_STATE_BTN1_DOWN )
739             nStyle |= BUTTON_DRAW_PRESSED;
740         aTempRect = aDecoView.DrawButton( maBtn1Rect, nStyle );
741         ImplCalcSymbolRect( aTempRect );
742         nStyle = 0;
743         if ( (mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) || !bEnabled )
744             nStyle |= SYMBOL_DRAW_DISABLE;
745         if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW )
746         {
747             if ( GetStyle() & WB_HORZ )
748                 eSymbolType = SYMBOL_ARROW_LEFT;
749             else
750                 eSymbolType = SYMBOL_ARROW_UP;
751         }
752         else
753         {
754             if ( GetStyle() & WB_HORZ )
755                 eSymbolType = SYMBOL_SPIN_LEFT;
756             else
757                 eSymbolType = SYMBOL_SPIN_UP;
758         }
759         aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle );
760     }
761 
762     if ( (nDrawFlags & SCRBAR_DRAW_BTN2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_BTN2 ) ) )
763     {
764         nStyle = BUTTON_DRAW_NOLIGHTBORDER;
765         if ( mnStateFlags & SCRBAR_STATE_BTN2_DOWN )
766             nStyle |= BUTTON_DRAW_PRESSED;
767         aTempRect = aDecoView.DrawButton(  maBtn2Rect, nStyle );
768         ImplCalcSymbolRect( aTempRect );
769         nStyle = 0;
770         if ( (mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) || !bEnabled )
771             nStyle |= SYMBOL_DRAW_DISABLE;
772         if ( rStyleSettings.GetOptions() & STYLE_OPTION_SCROLLARROW )
773         {
774             if ( GetStyle() & WB_HORZ )
775                 eSymbolType = SYMBOL_ARROW_RIGHT;
776             else
777                 eSymbolType = SYMBOL_ARROW_DOWN;
778         }
779         else
780         {
781             if ( GetStyle() & WB_HORZ )
782                 eSymbolType = SYMBOL_SPIN_RIGHT;
783             else
784                 eSymbolType = SYMBOL_SPIN_DOWN;
785         }
786         aDecoView.DrawSymbol( aTempRect, eSymbolType, rStyleSettings.GetButtonTextColor(), nStyle );
787     }
788 
789     pOutDev->SetLineColor();
790 
791     if ( (nDrawFlags & SCRBAR_DRAW_THUMB) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_THUMB ) ) )
792     {
793         if ( !maThumbRect.IsEmpty() )
794         {
795             if ( bEnabled )
796             {
797                 nStyle = BUTTON_DRAW_NOLIGHTBORDER;
798                 aTempRect = aDecoView.DrawButton( maThumbRect, nStyle );
799             }
800             else
801             {
802                 pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
803                 pOutDev->DrawRect( maThumbRect );
804             }
805         }
806     }
807 
808     if ( (nDrawFlags & SCRBAR_DRAW_PAGE1) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE1 ) ) )
809     {
810         if ( mnStateFlags & SCRBAR_STATE_PAGE1_DOWN )
811             pOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
812         else
813             pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
814         pOutDev->DrawRect( maPage1Rect );
815     }
816     if ( (nDrawFlags & SCRBAR_DRAW_PAGE2) && (!pWin || !ImplDrawNative( SCRBAR_DRAW_PAGE2 ) ) )
817     {
818         if ( mnStateFlags & SCRBAR_STATE_PAGE2_DOWN )
819             pOutDev->SetFillColor( rStyleSettings.GetShadowColor() );
820         else
821             pOutDev->SetFillColor( rStyleSettings.GetCheckedColor() );
822         pOutDev->DrawRect( maPage2Rect );
823     }
824 }
825 
826 // -----------------------------------------------------------------------
827 
ImplScroll(long nNewPos,sal_Bool bCallEndScroll)828 long ScrollBar::ImplScroll( long nNewPos, sal_Bool bCallEndScroll )
829 {
830     long nOldPos = mnThumbPos;
831     SetThumbPos( nNewPos );
832     long nDelta = mnThumbPos-nOldPos;
833     if ( nDelta )
834     {
835         mnDelta = nDelta;
836         Scroll();
837         if ( bCallEndScroll )
838             EndScroll();
839         mnDelta = 0;
840     }
841     return nDelta;
842 }
843 
844 // -----------------------------------------------------------------------
845 
ImplDoAction(sal_Bool bCallEndScroll)846 long ScrollBar::ImplDoAction( sal_Bool bCallEndScroll )
847 {
848     long nDelta = 0;
849 
850     switch ( meScrollType )
851     {
852         case SCROLL_LINEUP:
853             nDelta = ImplScroll( mnThumbPos-mnLineSize, bCallEndScroll );
854             break;
855 
856         case SCROLL_LINEDOWN:
857             nDelta = ImplScroll( mnThumbPos+mnLineSize, bCallEndScroll );
858             break;
859 
860         case SCROLL_PAGEUP:
861             nDelta = ImplScroll( mnThumbPos-mnPageSize, bCallEndScroll );
862             break;
863 
864         case SCROLL_PAGEDOWN:
865             nDelta = ImplScroll( mnThumbPos+mnPageSize, bCallEndScroll );
866             break;
867         default:
868             ;
869     }
870 
871     return nDelta;
872 }
873 
874 // -----------------------------------------------------------------------
875 
ImplDoMouseAction(const Point & rMousePos,sal_Bool bCallAction)876 void ScrollBar::ImplDoMouseAction( const Point& rMousePos, sal_Bool bCallAction )
877 {
878     sal_uInt16  nOldStateFlags = mnStateFlags;
879     sal_Bool    bAction = sal_False;
880     sal_Bool    bHorizontal = ( GetStyle() & WB_HORZ )? sal_True: sal_False;
881     sal_Bool    bIsInside = sal_False;
882 
883     Point aPoint( 0, 0 );
884     Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
885 
886     switch ( meScrollType )
887     {
888         case SCROLL_LINEUP:
889             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
890                         aControlRegion, rMousePos, bIsInside )?
891                     bIsInside:
892                     maBtn1Rect.IsInside( rMousePos ) )
893             {
894                 bAction = bCallAction;
895                 mnStateFlags |= SCRBAR_STATE_BTN1_DOWN;
896             }
897             else
898                 mnStateFlags &= ~SCRBAR_STATE_BTN1_DOWN;
899             break;
900 
901         case SCROLL_LINEDOWN:
902             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
903                         aControlRegion, rMousePos, bIsInside )?
904                     bIsInside:
905                     maBtn2Rect.IsInside( rMousePos ) )
906             {
907                 bAction = bCallAction;
908                 mnStateFlags |= SCRBAR_STATE_BTN2_DOWN;
909             }
910             else
911                 mnStateFlags &= ~SCRBAR_STATE_BTN2_DOWN;
912             break;
913 
914         case SCROLL_PAGEUP:
915             // HitTestNativeControl, see remark at top of file
916             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT: PART_TRACK_VERT_UPPER,
917                                        maPage1Rect, rMousePos, bIsInside )?
918                     bIsInside:
919                     maPage1Rect.IsInside( rMousePos ) )
920             {
921                 bAction = bCallAction;
922                 mnStateFlags |= SCRBAR_STATE_PAGE1_DOWN;
923             }
924             else
925                 mnStateFlags &= ~SCRBAR_STATE_PAGE1_DOWN;
926             break;
927 
928         case SCROLL_PAGEDOWN:
929             // HitTestNativeControl, see remark at top of file
930             if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_RIGHT: PART_TRACK_VERT_LOWER,
931                                        maPage2Rect, rMousePos, bIsInside )?
932                     bIsInside:
933                     maPage2Rect.IsInside( rMousePos ) )
934             {
935                 bAction = bCallAction;
936                 mnStateFlags |= SCRBAR_STATE_PAGE2_DOWN;
937             }
938             else
939                 mnStateFlags &= ~SCRBAR_STATE_PAGE2_DOWN;
940             break;
941         default:
942             ;
943     }
944 
945     if ( nOldStateFlags != mnStateFlags )
946         ImplDraw( mnDragDraw, this );
947     if ( bAction )
948         ImplDoAction( sal_False );
949 }
950 
951 // -----------------------------------------------------------------------
952 
ImplDragThumb(const Point & rMousePos)953 void ScrollBar::ImplDragThumb( const Point& rMousePos )
954 {
955     long nMovePix;
956     if ( GetStyle() & WB_HORZ )
957         nMovePix = rMousePos.X()-(maThumbRect.Left()+mnMouseOff);
958     else
959         nMovePix = rMousePos.Y()-(maThumbRect.Top()+mnMouseOff);
960 
961     // move thumb if necessary
962     if ( nMovePix )
963     {
964         mnThumbPixPos += nMovePix;
965         if ( mnThumbPixPos < 0 )
966             mnThumbPixPos = 0;
967         if ( mnThumbPixPos > (mnThumbPixRange-mnThumbPixSize) )
968             mnThumbPixPos = mnThumbPixRange-mnThumbPixSize;
969         long nOldPos = mnThumbPos;
970         mnThumbPos = ImplCalcThumbPos( mnThumbPixPos );
971         ImplUpdateRects();
972         if ( mbFullDrag && (nOldPos != mnThumbPos) )
973         {
974             mnDelta = mnThumbPos-nOldPos;
975             Scroll();
976             mnDelta = 0;
977         }
978     }
979 }
980 
981 // -----------------------------------------------------------------------
982 
MouseButtonDown(const MouseEvent & rMEvt)983 void ScrollBar::MouseButtonDown( const MouseEvent& rMEvt )
984 {
985     if ( rMEvt.IsLeft() || rMEvt.IsMiddle() )
986     {
987         const Point&    rMousePos = rMEvt.GetPosPixel();
988         sal_uInt16          nTrackFlags = 0;
989         sal_Bool            bHorizontal = ( GetStyle() & WB_HORZ )? sal_True: sal_False;
990         sal_Bool            bIsInside = sal_False;
991         sal_Bool            bDragToMouse = sal_False;
992 
993         Point aPoint( 0, 0 );
994         Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
995 
996         if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
997                     aControlRegion, rMousePos, bIsInside )?
998                 bIsInside:
999                 maBtn1Rect.IsInside( rMousePos ) )
1000         {
1001             if ( !(mnStateFlags & SCRBAR_STATE_BTN1_DISABLE) )
1002             {
1003                 nTrackFlags     = STARTTRACK_BUTTONREPEAT;
1004                 meScrollType    = SCROLL_LINEUP;
1005                 mnDragDraw      = SCRBAR_DRAW_BTN1;
1006             }
1007             else
1008                 Sound::Beep( SOUND_DISABLE, this );
1009         }
1010         else if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
1011                     aControlRegion, rMousePos, bIsInside )?
1012                 bIsInside:
1013                 maBtn2Rect.IsInside( rMousePos ) )
1014         {
1015             if ( !(mnStateFlags & SCRBAR_STATE_BTN2_DISABLE) )
1016             {
1017                 nTrackFlags     = STARTTRACK_BUTTONREPEAT;
1018                 meScrollType    = SCROLL_LINEDOWN;
1019                 mnDragDraw      = SCRBAR_DRAW_BTN2;
1020             }
1021             else
1022                 Sound::Beep( SOUND_DISABLE, this );
1023         }
1024         else
1025         {
1026             bool bThumbHit = HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_THUMB_HORZ : PART_THUMB_VERT,
1027                                                    maThumbRect, rMousePos, bIsInside )
1028                              ? bIsInside : maThumbRect.IsInside( rMousePos );
1029             bool bDragHandling = rMEvt.IsMiddle() || bThumbHit || ImplGetSVData()->maNWFData.mbScrollbarJumpPage;
1030             if( bDragHandling )
1031             {
1032                 if( mpData )
1033                 {
1034                     mpData->mbHide = sal_True;  // disable focus blinking
1035                     if( HasFocus() )
1036                         ImplDraw( SCRBAR_DRAW_THUMB, this ); // paint without focus
1037                 }
1038 
1039                 if ( mnVisibleSize < mnMaxRange-mnMinRange )
1040                 {
1041                     nTrackFlags     = 0;
1042                     meScrollType    = SCROLL_DRAG;
1043                     mnDragDraw      = SCRBAR_DRAW_THUMB;
1044 
1045                     // calculate mouse offset
1046                     if( rMEvt.IsMiddle() || (ImplGetSVData()->maNWFData.mbScrollbarJumpPage && !bThumbHit) )
1047                     {
1048                         bDragToMouse = sal_True;
1049                         if ( GetStyle() & WB_HORZ )
1050                             mnMouseOff = maThumbRect.GetWidth()/2;
1051                         else
1052                             mnMouseOff = maThumbRect.GetHeight()/2;
1053                     }
1054                     else
1055                     {
1056                         if ( GetStyle() & WB_HORZ )
1057                             mnMouseOff = rMousePos.X()-maThumbRect.Left();
1058                         else
1059                             mnMouseOff = rMousePos.Y()-maThumbRect.Top();
1060                     }
1061 
1062                     mnStateFlags |= SCRBAR_STATE_THUMB_DOWN;
1063                     ImplDraw( mnDragDraw, this );
1064                 }
1065                 else
1066                     Sound::Beep( SOUND_DISABLE, this );
1067             }
1068             else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_AREA : PART_TRACK_VERT_AREA,
1069                                            aControlRegion, rMousePos, bIsInside )?
1070                 bIsInside : sal_True )
1071             {
1072                 nTrackFlags = STARTTRACK_BUTTONREPEAT;
1073 
1074                 // HitTestNativeControl, see remark at top of file
1075                 if ( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER,
1076                                            maPage1Rect, rMousePos, bIsInside )?
1077                     bIsInside:
1078                     maPage1Rect.IsInside( rMousePos ) )
1079                 {
1080                     meScrollType    = SCROLL_PAGEUP;
1081                     mnDragDraw      = SCRBAR_DRAW_PAGE1;
1082                 }
1083                 else
1084                 {
1085                     meScrollType    = SCROLL_PAGEDOWN;
1086                     mnDragDraw      = SCRBAR_DRAW_PAGE2;
1087                 }
1088             }
1089         }
1090 
1091         // Soll Tracking gestartet werden
1092         if ( meScrollType != SCROLL_DONTKNOW )
1093         {
1094             // remember original position in case of abort or EndScroll-Delta
1095             mnStartPos = mnThumbPos;
1096             // #92906# Call StartTracking() before ImplDoMouseAction(), otherwise
1097             // MouseButtonUp() / EndTracking() may be called if somebody is spending
1098             // a lot of time in the scroll handler
1099             StartTracking( nTrackFlags );
1100             ImplDoMouseAction( rMousePos );
1101 
1102             if( bDragToMouse )
1103                 ImplDragThumb( rMousePos );
1104         }
1105     }
1106 }
1107 
1108 // -----------------------------------------------------------------------
1109 
Tracking(const TrackingEvent & rTEvt)1110 void ScrollBar::Tracking( const TrackingEvent& rTEvt )
1111 {
1112     if ( rTEvt.IsTrackingEnded() )
1113     {
1114         // Button und PageRect-Status wieder herstellen
1115         sal_uInt16 nOldStateFlags = mnStateFlags;
1116         mnStateFlags &= ~(SCRBAR_STATE_BTN1_DOWN | SCRBAR_STATE_BTN2_DOWN |
1117                           SCRBAR_STATE_PAGE1_DOWN | SCRBAR_STATE_PAGE2_DOWN |
1118                           SCRBAR_STATE_THUMB_DOWN);
1119         if ( nOldStateFlags != mnStateFlags )
1120             ImplDraw( mnDragDraw, this );
1121         mnDragDraw = 0;
1122 
1123         // Bei Abbruch, die alte ThumbPosition wieder herstellen
1124         if ( rTEvt.IsTrackingCanceled() )
1125         {
1126             long nOldPos = mnThumbPos;
1127             SetThumbPos( mnStartPos );
1128             mnDelta = mnThumbPos-nOldPos;
1129             Scroll();
1130         }
1131 
1132         if ( meScrollType == SCROLL_DRAG )
1133         {
1134             // Wenn gedragt wurde, berechnen wir den Thumb neu, damit
1135             // er wieder auf einer gerundeten ThumbPosition steht
1136             ImplCalc();
1137 
1138             if ( !mbFullDrag && (mnStartPos != mnThumbPos) )
1139             {
1140                 mnDelta = mnThumbPos-mnStartPos;
1141                 Scroll();
1142                 mnDelta = 0;
1143             }
1144         }
1145 
1146         mnDelta = mnThumbPos-mnStartPos;
1147         EndScroll();
1148         mnDelta = 0;
1149         meScrollType = SCROLL_DONTKNOW;
1150 
1151         if( mpData )
1152             mpData->mbHide = sal_False; // re-enable focus blinking
1153     }
1154     else
1155     {
1156         const Point rMousePos = rTEvt.GetMouseEvent().GetPosPixel();
1157 
1158         // Dragging wird speziell behandelt
1159         if ( meScrollType == SCROLL_DRAG )
1160             ImplDragThumb( rMousePos );
1161         else
1162             ImplDoMouseAction( rMousePos, rTEvt.IsTrackingRepeat() );
1163 
1164         // Wenn ScrollBar-Werte so umgesetzt wurden, das es nichts
1165         // mehr zum Tracking gibt, dann berechen wir hier ab
1166         if ( !IsVisible() || (mnVisibleSize >= (mnMaxRange-mnMinRange)) )
1167             EndTracking();
1168     }
1169 }
1170 
1171 // -----------------------------------------------------------------------
1172 
KeyInput(const KeyEvent & rKEvt)1173 void ScrollBar::KeyInput( const KeyEvent& rKEvt )
1174 {
1175     if ( !rKEvt.GetKeyCode().GetModifier() )
1176     {
1177         switch ( rKEvt.GetKeyCode().GetCode() )
1178         {
1179             case KEY_HOME:
1180                 DoScroll( 0 );
1181                 break;
1182 
1183             case KEY_END:
1184                 DoScroll( GetRangeMax() );
1185                 break;
1186 
1187             case KEY_LEFT:
1188             case KEY_UP:
1189                 DoScrollAction( SCROLL_LINEUP );
1190                 break;
1191 
1192             case KEY_RIGHT:
1193             case KEY_DOWN:
1194                 DoScrollAction( SCROLL_LINEDOWN );
1195                 break;
1196 
1197             case KEY_PAGEUP:
1198                 DoScrollAction( SCROLL_PAGEUP );
1199                 break;
1200 
1201             case KEY_PAGEDOWN:
1202                 DoScrollAction( SCROLL_PAGEDOWN );
1203                 break;
1204 
1205             default:
1206                 Control::KeyInput( rKEvt );
1207                 break;
1208         }
1209     }
1210     else
1211         Control::KeyInput( rKEvt );
1212 }
1213 
1214 // -----------------------------------------------------------------------
1215 
Paint(const Rectangle &)1216 void ScrollBar::Paint( const Rectangle& )
1217 {
1218     ImplDraw( SCRBAR_DRAW_ALL, this );
1219 }
1220 
1221 // -----------------------------------------------------------------------
1222 
Resize()1223 void ScrollBar::Resize()
1224 {
1225     Control::Resize();
1226     mbCalcSize = sal_True;
1227     if ( IsReallyVisible() )
1228         ImplCalc( sal_False );
1229     Invalidate();
1230 }
1231 
1232 // -----------------------------------------------------------------------
1233 
IMPL_LINK(ScrollBar,ImplAutoTimerHdl,AutoTimer *,EMPTYARG)1234 IMPL_LINK( ScrollBar, ImplAutoTimerHdl, AutoTimer*, EMPTYARG )
1235 {
1236     if( mpData && mpData->mbHide )
1237         return 0;
1238     ImplInvert();
1239     return 0;
1240 }
1241 
ImplInvert()1242 void ScrollBar::ImplInvert()
1243 {
1244     Rectangle aRect( maThumbRect );
1245     if( aRect.getWidth() > 4 )
1246     {
1247         aRect.Left() += 2;
1248         aRect.Right() -= 2;
1249     }
1250     if( aRect.getHeight() > 4 )
1251     {
1252         aRect.Top() += 2;
1253         aRect.Bottom() -= 2;
1254     }
1255 
1256     Invert( aRect, 0 );
1257 }
1258 
1259 // -----------------------------------------------------------------------
1260 
GetFocus()1261 void ScrollBar::GetFocus()
1262 {
1263     if( !mpData )
1264     {
1265 	    mpData = new ImplScrollBarData;
1266 		mpData->maTimer.SetTimeoutHdl( LINK( this, ScrollBar, ImplAutoTimerHdl ) );
1267         mpData->mbHide = sal_False;
1268     }
1269     ImplInvert();   // react immediately
1270 	mpData->maTimer.SetTimeout( GetSettings().GetStyleSettings().GetCursorBlinkTime() );
1271     mpData->maTimer.Start();
1272     Control::GetFocus();
1273 }
1274 
1275 // -----------------------------------------------------------------------
1276 
LoseFocus()1277 void ScrollBar::LoseFocus()
1278 {
1279     if( mpData )
1280         mpData->maTimer.Stop();
1281     ImplDraw( SCRBAR_DRAW_THUMB, this );
1282 
1283     Control::LoseFocus();
1284 }
1285 
1286 // -----------------------------------------------------------------------
1287 
StateChanged(StateChangedType nType)1288 void ScrollBar::StateChanged( StateChangedType nType )
1289 {
1290     Control::StateChanged( nType );
1291 
1292     if ( nType == STATE_CHANGE_INITSHOW )
1293         ImplCalc( sal_False );
1294     else if ( nType == STATE_CHANGE_DATA )
1295     {
1296         if ( IsReallyVisible() && IsUpdateMode() )
1297             ImplCalc( sal_True );
1298     }
1299     else if ( nType == STATE_CHANGE_UPDATEMODE )
1300     {
1301         if ( IsReallyVisible() && IsUpdateMode() )
1302         {
1303             ImplCalc( sal_False );
1304             Invalidate();
1305         }
1306     }
1307     else if ( nType == STATE_CHANGE_ENABLE )
1308     {
1309         if ( IsReallyVisible() && IsUpdateMode() )
1310             Invalidate();
1311     }
1312     else if ( nType == STATE_CHANGE_STYLE )
1313     {
1314         ImplInitStyle( GetStyle() );
1315         if ( IsReallyVisible() && IsUpdateMode() )
1316         {
1317             if ( (GetPrevStyle() & SCRBAR_VIEW_STYLE) !=
1318                  (GetStyle() & SCRBAR_VIEW_STYLE) )
1319             {
1320                 mbCalcSize = sal_True;
1321                 ImplCalc( sal_False );
1322                 Invalidate();
1323             }
1324         }
1325     }
1326 }
1327 
1328 // -----------------------------------------------------------------------
1329 
DataChanged(const DataChangedEvent & rDCEvt)1330 void ScrollBar::DataChanged( const DataChangedEvent& rDCEvt )
1331 {
1332     Control::DataChanged( rDCEvt );
1333 
1334     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1335          (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1336     {
1337         mbCalcSize = sal_True;
1338         ImplCalc( sal_False );
1339         Invalidate();
1340     }
1341 }
1342 
1343 // -----------------------------------------------------------------------
1344 
ImplFindPartRect(const Point & rPt)1345 Rectangle* ScrollBar::ImplFindPartRect( const Point& rPt )
1346 {
1347     sal_Bool    bHorizontal = ( GetStyle() & WB_HORZ )? sal_True: sal_False;
1348     sal_Bool    bIsInside = sal_False;
1349 
1350     Point aPoint( 0, 0 );
1351     Rectangle aControlRegion( aPoint, GetOutputSizePixel() );
1352 
1353     if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_LEFT: PART_BUTTON_UP,
1354                 aControlRegion, rPt, bIsInside )?
1355             bIsInside:
1356             maBtn1Rect.IsInside( rPt ) )
1357         return &maBtn1Rect;
1358     else if( HitTestNativeControl( CTRL_SCROLLBAR, bHorizontal? PART_BUTTON_RIGHT: PART_BUTTON_DOWN,
1359                 aControlRegion, rPt, bIsInside )?
1360             bIsInside:
1361             maBtn2Rect.IsInside( rPt ) )
1362         return &maBtn2Rect;
1363     // HitTestNativeControl, see remark at top of file
1364     else if( HitTestNativeControl( CTRL_SCROLLBAR,  bHorizontal ? PART_TRACK_HORZ_LEFT : PART_TRACK_VERT_UPPER,
1365                 maPage1Rect, rPt, bIsInside)?
1366             bIsInside:
1367             maPage1Rect.IsInside( rPt ) )
1368         return &maPage1Rect;
1369     // HitTestNativeControl, see remark at top of file
1370     else if( HitTestNativeControl( CTRL_SCROLLBAR,  bHorizontal ? PART_TRACK_HORZ_RIGHT : PART_TRACK_VERT_LOWER,
1371                 maPage2Rect, rPt, bIsInside)?
1372             bIsInside:
1373             maPage2Rect.IsInside( rPt ) )
1374         return &maPage2Rect;
1375     // HitTestNativeControl, see remark at top of file
1376     else if( HitTestNativeControl( CTRL_SCROLLBAR,  bHorizontal ? PART_THUMB_HORZ : PART_THUMB_VERT,
1377                 maThumbRect, rPt, bIsInside)?
1378              bIsInside:
1379              maThumbRect.IsInside( rPt ) )
1380         return &maThumbRect;
1381     else
1382         return NULL;
1383 }
1384 
PreNotify(NotifyEvent & rNEvt)1385 long ScrollBar::PreNotify( NotifyEvent& rNEvt )
1386 {
1387     long nDone = 0;
1388     const MouseEvent* pMouseEvt = NULL;
1389 
1390     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
1391     {
1392         if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
1393         {
1394             // trigger redraw if mouse over state has changed
1395             if( IsNativeControlSupported(CTRL_SCROLLBAR, PART_ENTIRE_CONTROL) )
1396             {
1397                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
1398                 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
1399                 if( pRect != pLastRect || pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow() )
1400                 {
1401                     Region aRgn( GetActiveClipRegion() );
1402                     Region aClipRegion;
1403 
1404                     if ( pRect )
1405                         aClipRegion.Union( *pRect );
1406                     if ( pLastRect )
1407                         aClipRegion.Union( *pLastRect );
1408 
1409                     // Support for 3-button scroll bars
1410                     sal_Bool bHas3Buttons = IsNativeControlSupported( CTRL_SCROLLBAR, HAS_THREE_BUTTONS );
1411                     if ( bHas3Buttons && ( pRect == &maBtn1Rect || pLastRect == &maBtn1Rect ) )
1412                     {
1413                         aClipRegion.Union( maBtn2Rect );
1414                     }
1415 
1416                     SetClipRegion( aClipRegion );
1417                     Paint( aClipRegion.GetBoundRect() );
1418 
1419                     SetClipRegion( aRgn );
1420                 }
1421             }
1422         }
1423     }
1424 
1425     return nDone ? nDone : Control::PreNotify(rNEvt);
1426 }
1427 
1428 // -----------------------------------------------------------------------
1429 
Scroll()1430 void ScrollBar::Scroll()
1431 {
1432     ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_SCROLL, maScrollHdl, this );
1433 }
1434 
1435 // -----------------------------------------------------------------------
1436 
EndScroll()1437 void ScrollBar::EndScroll()
1438 {
1439     ImplCallEventListenersAndHandler( VCLEVENT_SCROLLBAR_ENDSCROLL, maEndScrollHdl, this );
1440 }
1441 
1442 // -----------------------------------------------------------------------
1443 
DoScroll(long nNewPos)1444 long ScrollBar::DoScroll( long nNewPos )
1445 {
1446     if ( meScrollType != SCROLL_DONTKNOW )
1447         return 0;
1448 
1449     meScrollType = SCROLL_DRAG;
1450     long nDelta = ImplScroll( nNewPos, sal_True );
1451     meScrollType = SCROLL_DONTKNOW;
1452     return nDelta;
1453 }
1454 
1455 // -----------------------------------------------------------------------
1456 
DoScrollAction(ScrollType eScrollType)1457 long ScrollBar::DoScrollAction( ScrollType eScrollType )
1458 {
1459     if ( (meScrollType != SCROLL_DONTKNOW) ||
1460          (eScrollType == SCROLL_DONTKNOW) ||
1461          (eScrollType == SCROLL_DRAG) )
1462         return 0;
1463 
1464     meScrollType = eScrollType;
1465     long nDelta = ImplDoAction( sal_True );
1466     meScrollType = SCROLL_DONTKNOW;
1467     return nDelta;
1468 }
1469 
1470 // -----------------------------------------------------------------------
1471 
SetRangeMin(long nNewRange)1472 void ScrollBar::SetRangeMin( long nNewRange )
1473 {
1474     SetRange( Range( nNewRange, GetRangeMax() ) );
1475 }
1476 
1477 // -----------------------------------------------------------------------
1478 
SetRangeMax(long nNewRange)1479 void ScrollBar::SetRangeMax( long nNewRange )
1480 {
1481     SetRange( Range( GetRangeMin(), nNewRange ) );
1482 }
1483 
1484 // -----------------------------------------------------------------------
1485 
SetRange(const Range & rRange)1486 void ScrollBar::SetRange( const Range& rRange )
1487 {
1488     // Range einpassen
1489     Range aRange = rRange;
1490     aRange.Justify();
1491     long nNewMinRange = aRange.Min();
1492     long nNewMaxRange = aRange.Max();
1493 
1494     // Wenn Range sich unterscheidet, dann neuen setzen
1495     if ( (mnMinRange != nNewMinRange) ||
1496          (mnMaxRange != nNewMaxRange) )
1497     {
1498         mnMinRange = nNewMinRange;
1499         mnMaxRange = nNewMaxRange;
1500 
1501         // Thumb einpassen
1502         if ( mnThumbPos > mnMaxRange-mnVisibleSize )
1503             mnThumbPos = mnMaxRange-mnVisibleSize;
1504         if ( mnThumbPos < mnMinRange )
1505             mnThumbPos = mnMinRange;
1506 
1507         StateChanged( STATE_CHANGE_DATA );
1508     }
1509 }
1510 
1511 // -----------------------------------------------------------------------
1512 
SetThumbPos(long nNewThumbPos)1513 void ScrollBar::SetThumbPos( long nNewThumbPos )
1514 {
1515     if ( nNewThumbPos > mnMaxRange-mnVisibleSize )
1516         nNewThumbPos = mnMaxRange-mnVisibleSize;
1517     if ( nNewThumbPos < mnMinRange )
1518         nNewThumbPos = mnMinRange;
1519 
1520     if ( mnThumbPos != nNewThumbPos )
1521     {
1522         mnThumbPos = nNewThumbPos;
1523         StateChanged( STATE_CHANGE_DATA );
1524     }
1525 }
1526 
1527 // -----------------------------------------------------------------------
1528 
SetVisibleSize(long nNewSize)1529 void ScrollBar::SetVisibleSize( long nNewSize )
1530 {
1531     if ( mnVisibleSize != nNewSize )
1532     {
1533         mnVisibleSize = nNewSize;
1534 
1535         // Thumb einpassen
1536         if ( mnThumbPos > mnMaxRange-mnVisibleSize )
1537             mnThumbPos = mnMaxRange-mnVisibleSize;
1538         if ( mnThumbPos < mnMinRange )
1539             mnThumbPos = mnMinRange;
1540         StateChanged( STATE_CHANGE_DATA );
1541     }
1542 }
1543 
1544 // =======================================================================
1545 
ImplInit(Window * pParent,WinBits nStyle)1546 void ScrollBarBox::ImplInit( Window* pParent, WinBits nStyle )
1547 {
1548     Window::ImplInit( pParent, nStyle, NULL );
1549 
1550     const StyleSettings& rStyleSettings = GetSettings().GetStyleSettings();
1551     long nScrollSize = rStyleSettings.GetScrollBarSize();
1552     SetSizePixel( Size( nScrollSize, nScrollSize ) );
1553     ImplInitSettings();
1554 }
1555 
1556 // -----------------------------------------------------------------------
1557 
ScrollBarBox(Window * pParent,WinBits nStyle)1558 ScrollBarBox::ScrollBarBox( Window* pParent, WinBits nStyle ) :
1559     Window( WINDOW_SCROLLBARBOX )
1560 {
1561     ImplInit( pParent, nStyle );
1562 }
1563 
1564 // -----------------------------------------------------------------------
1565 
ScrollBarBox(Window * pParent,const ResId & rResId)1566 ScrollBarBox::ScrollBarBox( Window* pParent, const ResId& rResId ) :
1567     Window( WINDOW_SCROLLBARBOX )
1568 {
1569     rResId.SetRT( RSC_SCROLLBAR );
1570     ImplInit( pParent, ImplInitRes( rResId ) );
1571     ImplLoadRes( rResId );
1572 }
1573 
1574 // -----------------------------------------------------------------------
1575 
ImplInitSettings()1576 void ScrollBarBox::ImplInitSettings()
1577 {
1578     // Hack, damit man auch DockingWindows ohne Hintergrund bauen kann
1579     // und noch nicht alles umgestellt ist
1580     if ( IsBackground() )
1581     {
1582         Color aColor;
1583         if ( IsControlBackground() )
1584             aColor = GetControlBackground();
1585         else
1586             aColor = GetSettings().GetStyleSettings().GetFaceColor();
1587         SetBackground( aColor );
1588     }
1589 }
1590 
1591 // -----------------------------------------------------------------------
1592 
StateChanged(StateChangedType nType)1593 void ScrollBarBox::StateChanged( StateChangedType nType )
1594 {
1595     Window::StateChanged( nType );
1596 
1597     if ( nType == STATE_CHANGE_CONTROLBACKGROUND )
1598     {
1599         ImplInitSettings();
1600         Invalidate();
1601     }
1602 }
1603 
1604 // -----------------------------------------------------------------------
1605 
DataChanged(const DataChangedEvent & rDCEvt)1606 void ScrollBarBox::DataChanged( const DataChangedEvent& rDCEvt )
1607 {
1608     Window::DataChanged( rDCEvt );
1609 
1610     if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) &&
1611          (rDCEvt.GetFlags() & SETTINGS_STYLE) )
1612     {
1613         ImplInitSettings();
1614         Invalidate();
1615     }
1616 }
1617