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