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 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 60 SpinButton::SpinButton( Window* pParent, WinBits nStyle ) 61 :Control( WINDOW_SPINBUTTON ) 62 ,mbUpperIsFocused( sal_False ) 63 { 64 ImplInit( pParent, nStyle ); 65 } 66 67 // ----------------------------------------------------------------------- 68 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 81 SpinButton::~SpinButton() 82 { 83 } 84 85 // ----------------------------------------------------------------------- 86 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 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 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 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 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 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 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 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 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 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 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 397 void SpinButton::SetRangeMin( long nNewRange ) 398 { 399 SetRange( Range( nNewRange, GetRangeMax() ) ); 400 } 401 402 // ----------------------------------------------------------------------- 403 404 void SpinButton::SetRangeMax( long nNewRange ) 405 { 406 SetRange( Range( GetRangeMin(), nNewRange ) ); 407 } 408 409 // ----------------------------------------------------------------------- 410 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 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 455 void SpinButton::GetFocus() 456 { 457 ShowFocus( maFocusRect ); 458 Control::GetFocus(); 459 } 460 461 // ----------------------------------------------------------------------- 462 463 void SpinButton::LoseFocus() 464 { 465 HideFocus(); 466 Control::LoseFocus(); 467 } 468 469 // ----------------------------------------------------------------------- 470 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 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 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 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