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
ImplInit(Window * pParent,WinBits nStyle)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
SpinButton(Window * pParent,WinBits nStyle)58 SpinButton::SpinButton( Window* pParent, WinBits nStyle )
59 :Control( WINDOW_SPINBUTTON )
60 ,mbUpperIsFocused( sal_False )
61 {
62 ImplInit( pParent, nStyle );
63 }
64
65 // -----------------------------------------------------------------------
66
SpinButton(Window * pParent,const ResId & rResId)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
~SpinButton()79 SpinButton::~SpinButton()
80 {
81 }
82
83 // -----------------------------------------------------------------------
84
IMPL_LINK(SpinButton,ImplTimeout,Timer *,pTimer)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
Up()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
Down()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
Resize()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
Draw(OutputDevice * pDev,const Point & rPos,const Size & rSize,sal_uLong nFlags)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
Paint(const Rectangle &)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
MouseButtonDown(const MouseEvent & rMEvt)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
MouseButtonUp(const MouseEvent &)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
MouseMove(const MouseEvent & rMEvt)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
KeyInput(const KeyEvent & rKEvt)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
StateChanged(StateChangedType nType)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
SetRangeMin(long nNewRange)395 void SpinButton::SetRangeMin( long nNewRange )
396 {
397 SetRange( Range( nNewRange, GetRangeMax() ) );
398 }
399
400 // -----------------------------------------------------------------------
401
SetRangeMax(long nNewRange)402 void SpinButton::SetRangeMax( long nNewRange )
403 {
404 SetRange( Range( GetRangeMin(), nNewRange ) );
405 }
406
407 // -----------------------------------------------------------------------
408
SetRange(const Range & rRange)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
SetValue(long nValue)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
GetFocus()453 void SpinButton::GetFocus()
454 {
455 ShowFocus( maFocusRect );
456 Control::GetFocus();
457 }
458
459 // -----------------------------------------------------------------------
460
LoseFocus()461 void SpinButton::LoseFocus()
462 {
463 HideFocus();
464 Control::LoseFocus();
465 }
466
467 // -----------------------------------------------------------------------
468
ImplMoveFocus(sal_Bool _bUpper)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
ImplCalcFocusRect(sal_Bool _bUpper)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
ImplFindPartRect(const Point & rPt)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
PreNotify(NotifyEvent & rNEvt)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