xref: /trunk/main/vcl/source/control/spinbtn.cxx (revision f85112c9)
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