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