xref: /aoo41x/main/vcl/source/control/spinbtn.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_vcl.hxx"
30 #include <tools/rcid.h>
31 #include <vcl/spin.h>
32 #include <vcl/event.hxx>
33 #include <vcl/spin.hxx>
34 
35 // =======================================================================
36 
37 void SpinButton::ImplInit( Window* pParent, WinBits nStyle )
38 {
39     mbUpperIn     = sal_False;
40     mbLowerIn     = sal_False;
41     mbInitialUp   = sal_False;
42     mbInitialDown = sal_False;
43 
44     mnMinRange  = 0;
45     mnMaxRange  = 100;
46     mnValue     = 0;
47     mnValueStep = 1;
48 
49     maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
50     maRepeatTimer.SetTimeoutHdl( LINK( this, SpinButton, ImplTimeout ) );
51 
52     mbRepeat = 0 != ( nStyle & WB_REPEAT );
53 
54     if ( nStyle & WB_HSCROLL )
55         mbHorz = sal_True;
56     else
57         mbHorz = sal_False;
58 
59     Control::ImplInit( pParent, nStyle, NULL );
60 }
61 
62 // -----------------------------------------------------------------------
63 
64 SpinButton::SpinButton( Window* pParent, WinBits nStyle )
65     :Control( WINDOW_SPINBUTTON )
66     ,mbUpperIsFocused( sal_False )
67 {
68     ImplInit( pParent, nStyle );
69 }
70 
71 // -----------------------------------------------------------------------
72 
73 SpinButton::SpinButton( Window* pParent, const ResId& rResId )
74     :Control( WINDOW_SPINBUTTON )
75     ,mbUpperIsFocused( sal_False )
76 {
77     rResId.SetRT( RSC_SPINBUTTON );
78     ImplInit( pParent, ImplInitRes( rResId ) );
79     ImplLoadRes( rResId );
80     Resize();
81 }
82 
83 // -----------------------------------------------------------------------
84 
85 SpinButton::~SpinButton()
86 {
87 }
88 
89 // -----------------------------------------------------------------------
90 
91 IMPL_LINK( SpinButton, ImplTimeout, Timer*, pTimer )
92 {
93     if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() )
94     {
95         pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() );
96         pTimer->Start();
97     }
98     else
99     {
100         if ( mbInitialUp )
101             Up();
102         else
103             Down();
104     }
105 
106     return 0;
107 }
108 
109 // -----------------------------------------------------------------------
110 
111 void SpinButton::Up()
112 {
113     if ( ImplIsUpperEnabled() )
114     {
115         mnValue += mnValueStep;
116         StateChanged( STATE_CHANGE_DATA );
117 
118         ImplMoveFocus( sal_True );
119     }
120 
121     ImplCallEventListenersAndHandler( VCLEVENT_SPINBUTTON_UP, maUpHdlLink, this );
122 }
123 
124 // -----------------------------------------------------------------------
125 
126 void SpinButton::Down()
127 {
128     if ( ImplIsLowerEnabled() )
129     {
130         mnValue -= mnValueStep;
131         StateChanged( STATE_CHANGE_DATA );
132 
133         ImplMoveFocus( sal_False );
134     }
135 
136     ImplCallEventListenersAndHandler( VCLEVENT_SPINBUTTON_DOWN, maDownHdlLink, this );
137 }
138 
139 // -----------------------------------------------------------------------
140 
141 void SpinButton::Resize()
142 {
143     Control::Resize();
144 
145     Size aSize( GetOutputSizePixel() );
146 	Point aTmpPoint;
147     Rectangle aRect( aTmpPoint, aSize );
148     if ( mbHorz )
149     {
150         maLowerRect = Rectangle( 0, 0, aSize.Width()/2, aSize.Height()-1 );
151         maUpperRect = Rectangle( maLowerRect.TopRight(), aRect.BottomRight() );
152     }
153     else
154     {
155         maUpperRect = Rectangle( 0, 0, aSize.Width()-1, aSize.Height()/2 );
156         maLowerRect = Rectangle( maUpperRect.BottomLeft(), aRect.BottomRight() );
157     }
158 
159     ImplCalcFocusRect( ImplIsUpperEnabled() || !ImplIsLowerEnabled() );
160 
161     Invalidate();
162 }
163 
164 // -----------------------------------------------------------------------
165 
166 void SpinButton::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags )
167 {
168     Point       aPos  = pDev->LogicToPixel( rPos );
169     Size        aSize = pDev->LogicToPixel( rSize );
170 
171     pDev->Push();
172     pDev->SetMapMode();
173     if ( !(nFlags & WINDOW_DRAW_MONO) )
174 	{
175 		// DecoView uses the FaceColor...
176 		AllSettings aSettings = pDev->GetSettings();
177 		StyleSettings aStyleSettings = aSettings.GetStyleSettings();
178 		if ( IsControlBackground() )
179 			aStyleSettings.SetFaceColor( GetControlBackground() );
180 		else
181 			aStyleSettings.SetFaceColor( GetSettings().GetStyleSettings().GetFaceColor() );
182 
183 		aSettings.SetStyleSettings( aStyleSettings );
184 		pDev->SetSettings( aSettings );
185 	}
186 
187     Rectangle   aRect( Point( 0, 0 ), aSize );
188     Rectangle aLowerRect, aUpperRect;
189     if ( mbHorz )
190     {
191         aLowerRect = Rectangle( 0, 0, aSize.Width()/2, aSize.Height()-1 );
192         aUpperRect = Rectangle( aLowerRect.TopRight(), aRect.BottomRight() );
193     }
194     else
195     {
196         aUpperRect = Rectangle( 0, 0, aSize.Width()-1, aSize.Height()/2 );
197         aLowerRect = Rectangle( aUpperRect.BottomLeft(), aRect.BottomRight() );
198     }
199 
200     aUpperRect += aPos;
201     aLowerRect += aPos;
202 
203     ImplDrawSpinButton( pDev, aUpperRect, aLowerRect, sal_False, sal_False,
204                         IsEnabled() && ImplIsUpperEnabled(),
205                         IsEnabled() && ImplIsLowerEnabled(), mbHorz, sal_True );
206     pDev->Pop();
207 }
208 
209 
210 void SpinButton::Paint( const Rectangle& )
211 {
212     HideFocus();
213 
214     sal_Bool bEnable = IsEnabled();
215     ImplDrawSpinButton( this, maUpperRect, maLowerRect, mbUpperIn, mbLowerIn,
216                         bEnable && ImplIsUpperEnabled(),
217                         bEnable && ImplIsLowerEnabled(), mbHorz, sal_True );
218 
219     if ( HasFocus() )
220         ShowFocus( maFocusRect );
221 }
222 
223 // -----------------------------------------------------------------------
224 
225 void SpinButton::MouseButtonDown( const MouseEvent& rMEvt )
226 {
227     if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsUpperEnabled() ) )
228     {
229         mbUpperIn   = sal_True;
230         mbInitialUp = sal_True;
231         Invalidate( maUpperRect );
232     }
233     else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) && ( ImplIsLowerEnabled() ) )
234     {
235         mbLowerIn     = sal_True;
236         mbInitialDown = sal_True;
237         Invalidate( maLowerRect );
238     }
239 
240     if ( mbUpperIn || mbLowerIn )
241     {
242         Update();
243         CaptureMouse();
244         if ( mbRepeat )
245             maRepeatTimer.Start();
246     }
247 }
248 
249 // -----------------------------------------------------------------------
250 
251 void SpinButton::MouseButtonUp( const MouseEvent& )
252 {
253     ReleaseMouse();
254     if ( mbRepeat )
255     {
256         maRepeatTimer.Stop();
257         maRepeatTimer.SetTimeout(GetSettings().GetMouseSettings().GetButtonStartRepeat() );
258     }
259 
260     if ( mbUpperIn )
261     {
262         mbUpperIn   = sal_False;
263         Invalidate( maUpperRect );
264         Update();
265         Up();
266     }
267     else if ( mbLowerIn )
268     {
269         mbLowerIn = sal_False;
270         Invalidate( maLowerRect );
271         Update();
272         Down();
273     }
274 
275     mbInitialUp = mbInitialDown = sal_False;
276 }
277 
278 // -----------------------------------------------------------------------
279 
280 void SpinButton::MouseMove( const MouseEvent& rMEvt )
281 {
282     if ( !rMEvt.IsLeft() || (!mbInitialUp && !mbInitialDown) )
283         return;
284 
285     if ( !maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
286          mbUpperIn && mbInitialUp )
287     {
288         mbUpperIn = sal_False;
289         maRepeatTimer.Stop();
290         Invalidate( maUpperRect );
291         Update();
292     }
293     else if ( !maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
294               mbLowerIn & mbInitialDown )
295     {
296         mbLowerIn = sal_False;
297         maRepeatTimer.Stop();
298         Invalidate( maLowerRect );
299         Update();
300     }
301     else if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) &&
302               !mbUpperIn && mbInitialUp )
303     {
304         mbUpperIn = sal_True;
305         if ( mbRepeat )
306             maRepeatTimer.Start();
307         Invalidate( maUpperRect );
308         Update();
309     }
310     else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) &&
311               !mbLowerIn && mbInitialDown )
312     {
313         mbLowerIn = sal_True;
314         if ( mbRepeat )
315             maRepeatTimer.Start();
316         Invalidate( maLowerRect );
317         Update();
318     }
319 }
320 
321 // -----------------------------------------------------------------------
322 
323 void SpinButton::KeyInput( const KeyEvent& rKEvt )
324 {
325     KeyCode aCode = rKEvt.GetKeyCode();
326 
327     if ( !rKEvt.GetKeyCode().GetModifier() )
328     {
329         switch ( rKEvt.GetKeyCode().GetCode() )
330         {
331         case KEY_LEFT:
332         case KEY_RIGHT:
333         {
334             sal_Bool bUp = KEY_RIGHT == rKEvt.GetKeyCode().GetCode();
335             if ( mbHorz && !ImplMoveFocus( bUp ) )
336                 bUp ? Up() : Down();
337         }
338         break;
339 
340         case KEY_UP:
341         case KEY_DOWN:
342         {
343             sal_Bool bUp = KEY_UP == rKEvt.GetKeyCode().GetCode();
344             if ( !mbHorz && !ImplMoveFocus( KEY_UP == rKEvt.GetKeyCode().GetCode() ) )
345                 bUp ? Up() : Down();
346         }
347         break;
348 
349         case KEY_SPACE:
350             mbUpperIsFocused ? Up() : Down();
351             break;
352 
353         default:
354             Control::KeyInput( rKEvt );
355             break;
356         }
357     }
358     else
359         Control::KeyInput( rKEvt );
360 }
361 
362 // -----------------------------------------------------------------------
363 
364 void SpinButton::StateChanged( StateChangedType nType )
365 {
366     switch ( nType )
367     {
368     case STATE_CHANGE_DATA:
369     case STATE_CHANGE_ENABLE:
370         Invalidate();
371         break;
372 
373     case STATE_CHANGE_STYLE:
374     {
375         sal_Bool bNewRepeat = 0 != ( GetStyle() & WB_REPEAT );
376         if ( bNewRepeat != mbRepeat )
377         {
378             if ( maRepeatTimer.IsActive() )
379             {
380                 maRepeatTimer.Stop();
381                 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() );
382             }
383             mbRepeat = bNewRepeat;
384         }
385 
386         sal_Bool bNewHorz = 0 != ( GetStyle() & WB_HSCROLL );
387         if ( bNewHorz != mbHorz )
388         {
389             mbHorz = bNewHorz;
390             Resize();
391         }
392     }
393     break;
394     }
395 
396     Control::StateChanged( nType );
397 }
398 
399 // -----------------------------------------------------------------------
400 
401 void SpinButton::SetRangeMin( long nNewRange )
402 {
403     SetRange( Range( nNewRange, GetRangeMax() ) );
404 }
405 
406 // -----------------------------------------------------------------------
407 
408 void SpinButton::SetRangeMax( long nNewRange )
409 {
410     SetRange( Range( GetRangeMin(), nNewRange ) );
411 }
412 
413 // -----------------------------------------------------------------------
414 
415 void SpinButton::SetRange( const Range& rRange )
416 {
417     // adjust rage
418     Range aRange = rRange;
419     aRange.Justify();
420     long nNewMinRange = aRange.Min();
421     long nNewMaxRange = aRange.Max();
422 
423     // do something only if old and new range differ
424     if ( (mnMinRange != nNewMinRange) ||
425          (mnMaxRange != nNewMaxRange) )
426     {
427         mnMinRange = nNewMinRange;
428         mnMaxRange = nNewMaxRange;
429 
430         // adjust value to new range, if necessary
431         if ( mnValue > mnMaxRange )
432             mnValue = mnMaxRange;
433         if ( mnValue < mnMinRange )
434             mnValue = mnMinRange;
435 
436         StateChanged( STATE_CHANGE_DATA );
437     }
438 }
439 
440 // -----------------------------------------------------------------------
441 
442 void SpinButton::SetValue( long nValue )
443 {
444     // adjust, if necessary
445     if ( nValue > mnMaxRange )
446         nValue = mnMaxRange;
447     if ( nValue < mnMinRange )
448         nValue = mnMinRange;
449 
450     if ( mnValue != nValue )
451     {
452         mnValue = nValue;
453         StateChanged( STATE_CHANGE_DATA );
454     }
455 }
456 
457 // -----------------------------------------------------------------------
458 
459 void SpinButton::GetFocus()
460 {
461     ShowFocus( maFocusRect );
462     Control::GetFocus();
463 }
464 
465 // -----------------------------------------------------------------------
466 
467 void SpinButton::LoseFocus()
468 {
469     HideFocus();
470     Control::LoseFocus();
471 }
472 
473 // -----------------------------------------------------------------------
474 
475 sal_Bool SpinButton::ImplMoveFocus( sal_Bool _bUpper )
476 {
477     if ( _bUpper == mbUpperIsFocused )
478         return sal_False;
479 
480     HideFocus();
481     ImplCalcFocusRect( _bUpper );
482     if ( HasFocus() )
483         ShowFocus( maFocusRect );
484     return sal_True;
485 }
486 
487 // -----------------------------------------------------------------------
488 
489 void SpinButton::ImplCalcFocusRect( sal_Bool _bUpper )
490 {
491     maFocusRect = _bUpper ? maUpperRect : maLowerRect;
492     // inflate by some pixels
493     maFocusRect.Left() += 2;
494     maFocusRect.Top() += 2;
495     maFocusRect.Right() -= 2;
496     maFocusRect.Bottom() -= 2;
497     mbUpperIsFocused = _bUpper;
498 }
499 
500 // -----------------------------------------------------------------------
501 
502 Rectangle* SpinButton::ImplFindPartRect( const Point& rPt )
503 {
504     if( maUpperRect.IsInside( rPt ) )
505         return &maUpperRect;
506     else if( maLowerRect.IsInside( rPt ) )
507         return &maLowerRect;
508     else
509         return NULL;
510 }
511 
512 long SpinButton::PreNotify( NotifyEvent& rNEvt )
513 {
514     long nDone = 0;
515     const MouseEvent* pMouseEvt = NULL;
516 
517     if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL )
518     {
519         if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() )
520         {
521             // trigger redraw if mouse over state has changed
522             if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ||
523                 IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) )
524             {
525                 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() );
526                 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() );
527                 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) )
528                 {
529                     Region aRgn( GetActiveClipRegion() );
530                     if( pLastRect )
531                     {
532                         SetClipRegion( *pLastRect );
533                         Paint( *pLastRect );
534                         SetClipRegion( aRgn );
535                     }
536                     if( pRect )
537                     {
538                         SetClipRegion( *pRect );
539                         Paint( *pRect );
540                         SetClipRegion( aRgn );
541                     }
542                 }
543             }
544         }
545     }
546 
547     return nDone ? nDone : Control::PreNotify(rNEvt);
548 }
549 
550 // -----------------------------------------------------------------------
551