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