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 31 #include "tools/rc.h" 32 33 #include "vcl/event.hxx" 34 #include "vcl/decoview.hxx" 35 #include "vcl/spin.h" 36 #include "vcl/spinfld.hxx" 37 38 #include "controldata.hxx" 39 #include "svdata.hxx" 40 41 // ======================================================================= 42 43 void ImplGetSpinbuttonValue( Window *pWin, const Rectangle& rUpperRect, 44 const Rectangle& rLowerRect, 45 sal_Bool bUpperIn, sal_Bool bLowerIn, 46 sal_Bool bUpperEnabled, sal_Bool bLowerEnabled, sal_Bool bHorz, 47 SpinbuttonValue& rValue ) 48 { 49 // convert spinbutton data to a SpinbuttonValue structure for native painting 50 51 rValue.maUpperRect = rUpperRect; 52 rValue.maLowerRect = rLowerRect; 53 54 Point aPointerPos = pWin->GetPointerPosPixel(); 55 56 ControlState nState = CTRL_STATE_ENABLED; 57 if ( bUpperIn ) 58 nState |= CTRL_STATE_PRESSED; 59 if ( !pWin->IsEnabled() || !bUpperEnabled ) 60 nState &= ~CTRL_STATE_ENABLED; 61 if ( pWin->HasFocus() ) 62 nState |= CTRL_STATE_FOCUSED; 63 if( pWin->IsMouseOver() && rUpperRect.IsInside( aPointerPos ) ) 64 nState |= CTRL_STATE_ROLLOVER; 65 rValue.mnUpperState = nState; 66 67 nState = CTRL_STATE_ENABLED; 68 if ( bLowerIn ) 69 nState |= CTRL_STATE_PRESSED; 70 if ( !pWin->IsEnabled() || !bLowerEnabled ) 71 nState &= ~CTRL_STATE_ENABLED; 72 if ( pWin->HasFocus() ) 73 nState |= CTRL_STATE_FOCUSED; 74 // for overlapping spins: highlight only one 75 if( pWin->IsMouseOver() && rLowerRect.IsInside( aPointerPos ) && 76 !rUpperRect.IsInside( aPointerPos ) ) 77 nState |= CTRL_STATE_ROLLOVER; 78 rValue.mnLowerState = nState; 79 80 rValue.mnUpperPart = bHorz ? PART_BUTTON_LEFT : PART_BUTTON_UP; 81 rValue.mnLowerPart = bHorz ? PART_BUTTON_RIGHT : PART_BUTTON_DOWN; 82 } 83 84 85 sal_Bool ImplDrawNativeSpinfield( Window *pWin, const SpinbuttonValue& rSpinbuttonValue ) 86 { 87 sal_Bool bNativeOK = sal_False; 88 89 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) && 90 // there is just no useful native support for spinfields with dropdown 91 !(pWin->GetStyle() & WB_DROPDOWN) ) 92 { 93 if( pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnUpperPart) && 94 pWin->IsNativeControlSupported(CTRL_SPINBOX, rSpinbuttonValue.mnLowerPart) ) 95 { 96 // only paint the embedded spin buttons, all buttons are painted at once 97 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBOX, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED, 98 rSpinbuttonValue, rtl::OUString() ); 99 } 100 else 101 { 102 // paint the spinbox as a whole, use borderwindow to have proper clipping 103 Window *pBorder = pWin->GetWindow( WINDOW_BORDER ); 104 105 // to not overwrite everything, set the button region as clipregion to the border window 106 Rectangle aClipRect( rSpinbuttonValue.maLowerRect ); 107 aClipRect.Union( rSpinbuttonValue.maUpperRect ); 108 109 // convert from screen space to borderwin space 110 aClipRect.SetPos( pBorder->ScreenToOutputPixel(pWin->OutputToScreenPixel(aClipRect.TopLeft())) ); 111 112 Region oldRgn( pBorder->GetClipRegion() ); 113 pBorder->SetClipRegion( Region( aClipRect ) ); 114 115 Point aPt; 116 Size aSize( pBorder->GetOutputSizePixel() ); // the size of the border window, i.e., the whole control 117 Rectangle aBound, aContent; 118 Rectangle aNatRgn( aPt, aSize ); 119 if( ! ImplGetSVData()->maNWFData.mbCanDrawWidgetAnySize && 120 pBorder->GetNativeControlRegion( CTRL_SPINBOX, PART_ENTIRE_CONTROL, 121 aNatRgn, 0, rSpinbuttonValue, rtl::OUString(), aBound, aContent) ) 122 { 123 aSize = aContent.GetSize(); 124 } 125 126 Rectangle aRgn( aPt, aSize ); 127 bNativeOK = pBorder->DrawNativeControl( CTRL_SPINBOX, PART_ENTIRE_CONTROL, aRgn, CTRL_STATE_ENABLED, 128 rSpinbuttonValue, rtl::OUString() ); 129 130 pBorder->SetClipRegion( oldRgn ); 131 } 132 } 133 return bNativeOK; 134 } 135 136 sal_Bool ImplDrawNativeSpinbuttons( Window *pWin, const SpinbuttonValue& rSpinbuttonValue ) 137 { 138 sal_Bool bNativeOK = sal_False; 139 140 if( pWin->IsNativeControlSupported(CTRL_SPINBUTTONS, PART_ENTIRE_CONTROL) ) 141 { 142 // only paint the standalone spin buttons, all buttons are painted at once 143 bNativeOK = pWin->DrawNativeControl( CTRL_SPINBUTTONS, PART_ALL_BUTTONS, Rectangle(), CTRL_STATE_ENABLED, 144 rSpinbuttonValue, rtl::OUString() ); 145 } 146 return bNativeOK; 147 } 148 149 void ImplDrawSpinButton( OutputDevice* pOutDev, 150 const Rectangle& rUpperRect, 151 const Rectangle& rLowerRect, 152 sal_Bool bUpperIn, sal_Bool bLowerIn, 153 sal_Bool bUpperEnabled, sal_Bool bLowerEnabled, sal_Bool bHorz, sal_Bool bMirrorHorz ) 154 { 155 DecorationView aDecoView( pOutDev ); 156 157 sal_uInt16 nStyle = BUTTON_DRAW_NOLEFTLIGHTBORDER; 158 sal_uInt16 nSymStyle = 0; 159 160 SymbolType eType1, eType2; 161 162 const StyleSettings& rStyleSettings = pOutDev->GetSettings().GetStyleSettings(); 163 if ( rStyleSettings.GetOptions() & STYLE_OPTION_SPINARROW ) 164 { 165 // arrows are only use in OS/2 look 166 if ( bHorz ) 167 { 168 eType1 = bMirrorHorz ? SYMBOL_ARROW_RIGHT : SYMBOL_ARROW_LEFT; 169 eType2 = bMirrorHorz ? SYMBOL_ARROW_LEFT : SYMBOL_ARROW_RIGHT; 170 } 171 else 172 { 173 eType1 = SYMBOL_ARROW_UP; 174 eType2 = SYMBOL_ARROW_DOWN; 175 } 176 } 177 else 178 { 179 if ( bHorz ) 180 { 181 eType1 = bMirrorHorz ? SYMBOL_SPIN_RIGHT : SYMBOL_SPIN_LEFT; 182 eType2 = bMirrorHorz ? SYMBOL_SPIN_LEFT : SYMBOL_SPIN_RIGHT; 183 } 184 else 185 { 186 eType1 = SYMBOL_SPIN_UP; 187 eType2 = SYMBOL_SPIN_DOWN; 188 } 189 } 190 191 // Oberen/linken Button malen 192 sal_uInt16 nTempStyle = nStyle; 193 if ( bUpperIn ) 194 nTempStyle |= BUTTON_DRAW_PRESSED; 195 196 sal_Bool bNativeOK = sal_False; 197 Rectangle aUpRect; 198 199 if( pOutDev->GetOutDevType() == OUTDEV_WINDOW ) 200 { 201 Window *pWin = (Window*) pOutDev; 202 203 // are we drawing standalone spin buttons or members of a spinfield ? 204 ControlType aControl = CTRL_SPINBUTTONS; 205 switch( pWin->GetType() ) 206 { 207 case WINDOW_EDIT: 208 case WINDOW_MULTILINEEDIT: 209 case WINDOW_PATTERNFIELD: 210 case WINDOW_METRICFIELD: 211 case WINDOW_CURRENCYFIELD: 212 case WINDOW_DATEFIELD: 213 case WINDOW_TIMEFIELD: 214 case WINDOW_LONGCURRENCYFIELD: 215 case WINDOW_NUMERICFIELD: 216 case WINDOW_SPINFIELD: 217 aControl = CTRL_SPINBOX; 218 break; 219 default: 220 aControl = CTRL_SPINBUTTONS; 221 break; 222 } 223 224 SpinbuttonValue aValue; 225 ImplGetSpinbuttonValue( pWin, rUpperRect, rLowerRect, 226 bUpperIn, bLowerIn, bUpperEnabled, bLowerEnabled, 227 bHorz, aValue ); 228 229 if( aControl == CTRL_SPINBOX ) 230 bNativeOK = ImplDrawNativeSpinfield( pWin, aValue ); 231 else if( aControl == CTRL_SPINBUTTONS ) 232 bNativeOK = ImplDrawNativeSpinbuttons( pWin, aValue ); 233 } 234 235 if( !bNativeOK ) 236 aUpRect = aDecoView.DrawButton( rUpperRect, nTempStyle ); 237 238 // Unteren/rechten Button malen 239 if ( bLowerIn ) 240 nStyle |= BUTTON_DRAW_PRESSED; 241 Rectangle aLowRect; 242 if( !bNativeOK ) 243 aLowRect = aDecoView.DrawButton( rLowerRect, nStyle ); 244 245 // Zusaetzliche Default-Kante wollen wir auch ausnutzen 246 aUpRect.Left()--; 247 aUpRect.Top()--; 248 aUpRect.Right()++; 249 aUpRect.Bottom()++; 250 aLowRect.Left()--; 251 aLowRect.Top()--; 252 aLowRect.Right()++; 253 aLowRect.Bottom()++; 254 255 // Wir malen auch in die Kante rein, damit man etwas erkennen kann, 256 // wenn das Rechteck zu klein ist 257 if ( aUpRect.GetHeight() < 4 ) 258 { 259 aUpRect.Right()++; 260 aUpRect.Bottom()++; 261 aLowRect.Right()++; 262 aLowRect.Bottom()++; 263 } 264 265 // Symbolgroesse berechnen 266 long nTempSize1 = aUpRect.GetWidth(); 267 long nTempSize2 = aLowRect.GetWidth(); 268 if ( Abs( nTempSize1-nTempSize2 ) == 1 ) 269 { 270 if ( nTempSize1 > nTempSize2 ) 271 aUpRect.Left()++; 272 else 273 aLowRect.Left()++; 274 } 275 nTempSize1 = aUpRect.GetHeight(); 276 nTempSize2 = aLowRect.GetHeight(); 277 if ( Abs( nTempSize1-nTempSize2 ) == 1 ) 278 { 279 if ( nTempSize1 > nTempSize2 ) 280 aUpRect.Top()++; 281 else 282 aLowRect.Top()++; 283 } 284 285 nTempStyle = nSymStyle; 286 if ( !bUpperEnabled ) 287 nTempStyle |= SYMBOL_DRAW_DISABLE; 288 if( !bNativeOK ) 289 aDecoView.DrawSymbol( aUpRect, eType1, rStyleSettings.GetButtonTextColor(), nTempStyle ); 290 291 if ( !bLowerEnabled ) 292 nSymStyle |= SYMBOL_DRAW_DISABLE; 293 if( !bNativeOK ) 294 aDecoView.DrawSymbol( aLowRect, eType2, rStyleSettings.GetButtonTextColor(), nSymStyle ); 295 } 296 297 // ======================================================================= 298 299 void SpinField::ImplInitSpinFieldData() 300 { 301 mpEdit = NULL; 302 mbSpin = sal_False; 303 mbRepeat = sal_False; 304 mbUpperIn = sal_False; 305 mbLowerIn = sal_False; 306 mbInitialUp = sal_False; 307 mbInitialDown = sal_False; 308 mbNoSelect = sal_False; 309 mbInDropDown = sal_False; 310 } 311 312 // -------------------------------------------------------------------- 313 314 void SpinField::ImplInit( Window* pParent, WinBits nWinStyle ) 315 { 316 Edit::ImplInit( pParent, nWinStyle ); 317 318 if ( nWinStyle & (WB_SPIN|WB_DROPDOWN) ) 319 { 320 mbSpin = sal_True; 321 322 // Some themes want external spin buttons, therefore the main 323 // spinfield should not overdraw the border between its encapsulated 324 // edit field and the spin buttons 325 if ( (nWinStyle & WB_SPIN) && ImplUseNativeBorder( nWinStyle ) ) 326 { 327 SetBackground(); 328 mpEdit = new Edit( this, WB_NOBORDER ); 329 mpEdit->SetBackground(); 330 } 331 else 332 mpEdit = new Edit( this, WB_NOBORDER ); 333 334 mpEdit->EnableRTL( sal_False ); 335 mpEdit->SetPosPixel( Point() ); 336 mpEdit->Show(); 337 SetSubEdit( mpEdit ); 338 339 maRepeatTimer.SetTimeoutHdl( LINK( this, SpinField, ImplTimeout ) ); 340 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() ); 341 if ( nWinStyle & WB_REPEAT ) 342 mbRepeat = sal_True; 343 344 SetCompoundControl( sal_True ); 345 } 346 } 347 348 // -------------------------------------------------------------------- 349 350 SpinField::SpinField( WindowType nTyp ) : 351 Edit( nTyp ) 352 { 353 ImplInitSpinFieldData(); 354 } 355 356 // -------------------------------------------------------------------- 357 358 SpinField::SpinField( Window* pParent, WinBits nWinStyle ) : 359 Edit( WINDOW_SPINFIELD ) 360 { 361 ImplInitSpinFieldData(); 362 ImplInit( pParent, nWinStyle ); 363 } 364 365 // -------------------------------------------------------------------- 366 367 SpinField::SpinField( Window* pParent, const ResId& rResId ) : 368 Edit( WINDOW_SPINFIELD ) 369 { 370 ImplInitSpinFieldData(); 371 rResId.SetRT( RSC_SPINFIELD ); 372 WinBits nStyle = ImplInitRes( rResId ); 373 ImplInit( pParent, nStyle ); 374 ImplLoadRes( rResId ); 375 376 if ( !(nStyle & WB_HIDE) ) 377 Show(); 378 } 379 380 // -------------------------------------------------------------------- 381 382 SpinField::~SpinField() 383 { 384 delete mpEdit; 385 } 386 387 // -------------------------------------------------------------------- 388 389 void SpinField::Up() 390 { 391 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_UP, maUpHdlLink, this ); 392 } 393 394 // -------------------------------------------------------------------- 395 396 void SpinField::Down() 397 { 398 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_DOWN, maDownHdlLink, this ); 399 } 400 401 // -------------------------------------------------------------------- 402 403 void SpinField::First() 404 { 405 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_FIRST, maFirstHdlLink, this ); 406 } 407 408 // -------------------------------------------------------------------- 409 410 void SpinField::Last() 411 { 412 ImplCallEventListenersAndHandler( VCLEVENT_SPINFIELD_LAST, maLastHdlLink, this ); 413 } 414 415 // -------------------------------------------------------------------- 416 417 void SpinField::MouseButtonDown( const MouseEvent& rMEvt ) 418 { 419 if ( !HasFocus() && ( !mpEdit || !mpEdit->HasFocus() ) ) 420 { 421 mbNoSelect = sal_True; 422 GrabFocus(); 423 } 424 425 if ( !IsReadOnly() ) 426 { 427 if ( maUpperRect.IsInside( rMEvt.GetPosPixel() ) ) 428 { 429 mbUpperIn = sal_True; 430 mbInitialUp = sal_True; 431 Invalidate( maUpperRect ); 432 } 433 else if ( maLowerRect.IsInside( rMEvt.GetPosPixel() ) ) 434 { 435 mbLowerIn = sal_True; 436 mbInitialDown = sal_True; 437 Invalidate( maLowerRect ); 438 } 439 else if ( maDropDownRect.IsInside( rMEvt.GetPosPixel() ) ) 440 { 441 // Rechts daneben liegt der DropDownButton: 442 mbInDropDown = ShowDropDown( mbInDropDown ? sal_False : sal_True ); 443 Paint( Rectangle( Point(), GetOutputSizePixel() ) ); 444 } 445 446 if ( mbUpperIn || mbLowerIn ) 447 { 448 Update(); 449 CaptureMouse(); 450 if ( mbRepeat ) 451 maRepeatTimer.Start(); 452 return; 453 } 454 } 455 456 Edit::MouseButtonDown( rMEvt ); 457 } 458 459 // -------------------------------------------------------------------- 460 461 void SpinField::MouseButtonUp( const MouseEvent& rMEvt ) 462 { 463 ReleaseMouse(); 464 mbInitialUp = mbInitialDown = sal_False; 465 maRepeatTimer.Stop(); 466 maRepeatTimer.SetTimeout( GetSettings().GetMouseSettings().GetButtonStartRepeat() ); 467 468 if ( mbUpperIn ) 469 { 470 mbUpperIn = sal_False; 471 Invalidate( maUpperRect ); 472 Update(); 473 Up(); 474 } 475 else if ( mbLowerIn ) 476 { 477 mbLowerIn = sal_False; 478 Invalidate( maLowerRect ); 479 Update(); 480 Down(); 481 } 482 483 Edit::MouseButtonUp( rMEvt ); 484 } 485 486 // -------------------------------------------------------------------- 487 488 void SpinField::MouseMove( const MouseEvent& rMEvt ) 489 { 490 if ( rMEvt.IsLeft() ) 491 { 492 if ( mbInitialUp ) 493 { 494 sal_Bool bNewUpperIn = maUpperRect.IsInside( rMEvt.GetPosPixel() ); 495 if ( bNewUpperIn != mbUpperIn ) 496 { 497 if ( bNewUpperIn ) 498 { 499 if ( mbRepeat ) 500 maRepeatTimer.Start(); 501 } 502 else 503 maRepeatTimer.Stop(); 504 505 mbUpperIn = bNewUpperIn; 506 Invalidate( maUpperRect ); 507 Update(); 508 } 509 } 510 else if ( mbInitialDown ) 511 { 512 sal_Bool bNewLowerIn = maLowerRect.IsInside( rMEvt.GetPosPixel() ); 513 if ( bNewLowerIn != mbLowerIn ) 514 { 515 if ( bNewLowerIn ) 516 { 517 if ( mbRepeat ) 518 maRepeatTimer.Start(); 519 } 520 else 521 maRepeatTimer.Stop(); 522 523 mbLowerIn = bNewLowerIn; 524 Invalidate( maLowerRect ); 525 Update(); 526 } 527 } 528 } 529 530 Edit::MouseMove( rMEvt ); 531 } 532 533 // -------------------------------------------------------------------- 534 535 long SpinField::Notify( NotifyEvent& rNEvt ) 536 { 537 long nDone = 0; 538 if( rNEvt.GetType() == EVENT_KEYINPUT ) 539 { 540 const KeyEvent& rKEvt = *rNEvt.GetKeyEvent(); 541 if ( !IsReadOnly() ) 542 { 543 sal_uInt16 nMod = rKEvt.GetKeyCode().GetModifier(); 544 switch ( rKEvt.GetKeyCode().GetCode() ) 545 { 546 case KEY_UP: 547 { 548 if ( !nMod ) 549 { 550 Up(); 551 nDone = 1; 552 } 553 } 554 break; 555 case KEY_DOWN: 556 { 557 if ( !nMod ) 558 { 559 Down(); 560 nDone = 1; 561 } 562 else if ( ( nMod == KEY_MOD2 ) && !mbInDropDown && ( GetStyle() & WB_DROPDOWN ) ) 563 { 564 mbInDropDown = ShowDropDown( sal_True ); 565 Paint( Rectangle( Point(), GetOutputSizePixel() ) ); 566 nDone = 1; 567 } 568 } 569 break; 570 case KEY_PAGEUP: 571 { 572 if ( !nMod ) 573 { 574 Last(); 575 nDone = 1; 576 } 577 } 578 break; 579 case KEY_PAGEDOWN: 580 { 581 if ( !nMod ) 582 { 583 First(); 584 nDone = 1; 585 } 586 } 587 break; 588 } 589 } 590 } 591 592 if ( rNEvt.GetType() == EVENT_COMMAND ) 593 { 594 if ( ( rNEvt.GetCommandEvent()->GetCommand() == COMMAND_WHEEL ) && !IsReadOnly() ) 595 { 596 sal_uInt16 nWheelBehavior( GetSettings().GetMouseSettings().GetWheelBehavior() ); 597 if ( ( nWheelBehavior == MOUSE_WHEEL_ALWAYS ) 598 || ( ( nWheelBehavior == MOUSE_WHEEL_FOCUS_ONLY ) 599 && HasChildPathFocus() 600 ) 601 ) 602 { 603 const CommandWheelData* pData = rNEvt.GetCommandEvent()->GetWheelData(); 604 if ( pData->GetMode() == COMMAND_WHEEL_SCROLL ) 605 { 606 if ( pData->GetDelta() < 0L ) 607 Down(); 608 else 609 Up(); 610 nDone = 1; 611 } 612 } 613 else 614 nDone = 0; // don't eat this event, let the default handling happen (i.e. scroll the context) 615 } 616 } 617 618 return nDone ? nDone : Edit::Notify( rNEvt ); 619 } 620 621 // -------------------------------------------------------------------- 622 623 void SpinField::Command( const CommandEvent& rCEvt ) 624 { 625 Edit::Command( rCEvt ); 626 } 627 628 // -------------------------------------------------------------------- 629 630 void SpinField::FillLayoutData() const 631 { 632 if( mbSpin ) 633 { 634 mpControlData->mpLayoutData = new vcl::ControlLayoutData(); 635 AppendLayoutData( *GetSubEdit() ); 636 GetSubEdit()->SetLayoutDataParent( this ); 637 } 638 else 639 Edit::FillLayoutData(); 640 } 641 642 // -------------------------------------------------------------------- 643 644 void SpinField::Paint( const Rectangle& rRect ) 645 { 646 if ( mbSpin ) 647 { 648 sal_Bool bEnable = IsEnabled(); 649 ImplDrawSpinButton( this, maUpperRect, maLowerRect, 650 mbUpperIn, mbLowerIn, bEnable, bEnable ); 651 } 652 653 if ( GetStyle() & WB_DROPDOWN ) 654 { 655 DecorationView aView( this ); 656 657 sal_uInt16 nStyle = BUTTON_DRAW_NOLIGHTBORDER; 658 if ( mbInDropDown ) 659 nStyle |= BUTTON_DRAW_PRESSED; 660 Rectangle aInnerRect = aView.DrawButton( maDropDownRect, nStyle ); 661 662 SymbolType eSymbol = SYMBOL_SPIN_DOWN; 663 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN ) 664 eSymbol = SYMBOL_SPIN_UPDOWN; 665 666 nStyle = IsEnabled() ? 0 : SYMBOL_DRAW_DISABLE; 667 aView.DrawSymbol( aInnerRect, eSymbol, GetSettings().GetStyleSettings().GetButtonTextColor(), nStyle ); 668 } 669 670 Edit::Paint( rRect ); 671 } 672 673 // -------------------------------------------------------------------- 674 675 void SpinField::ImplCalcButtonAreas( OutputDevice* pDev, const Size& rOutSz, Rectangle& rDDArea, Rectangle& rSpinUpArea, Rectangle& rSpinDownArea ) 676 { 677 const StyleSettings& rStyleSettings = pDev->GetSettings().GetStyleSettings(); 678 679 Size aSize = rOutSz; 680 Size aDropDownSize; 681 682 if ( GetStyle() & WB_DROPDOWN ) 683 { 684 long nW = rStyleSettings.GetScrollBarSize(); 685 nW = GetDrawPixel( pDev, nW ); 686 aDropDownSize = Size( CalcZoom( nW ), aSize.Height() ); 687 aSize.Width() -= aDropDownSize.Width(); 688 rDDArea = Rectangle( Point( aSize.Width(), 0 ), aDropDownSize ); 689 rDDArea.Top()--; 690 } 691 else 692 rDDArea.SetEmpty(); 693 694 // Je nach Hoehe, die groessen Berechnen 695 if ( GetStyle() & WB_SPIN ) 696 { 697 long nBottom1 = aSize.Height()/2; 698 long nBottom2 = aSize.Height()-1; 699 long nTop2 = nBottom1; 700 long nTop1 = 0; 701 if ( !(aSize.Height() & 0x01) ) 702 nBottom1--; 703 704 sal_Bool bNativeRegionOK = sal_False; 705 Rectangle aContentUp, aContentDown; 706 707 if ( (pDev->GetOutDevType() == OUTDEV_WINDOW) && 708 // there is just no useful native support for spinfields with dropdown 709 ! (GetStyle() & WB_DROPDOWN) && 710 IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) ) 711 { 712 Window *pWin = (Window*) pDev; 713 Window *pBorder = pWin->GetWindow( WINDOW_BORDER ); 714 715 // get the system's spin button size 716 ImplControlValue aControlValue; 717 Rectangle aBound; 718 Point aPoint; 719 720 // use the full extent of the control 721 Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() ); 722 723 bNativeRegionOK = 724 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_UP, 725 aArea, 0, aControlValue, rtl::OUString(), aBound, aContentUp) && 726 pWin->GetNativeControlRegion(CTRL_SPINBOX, PART_BUTTON_DOWN, 727 aArea, 0, aControlValue, rtl::OUString(), aBound, aContentDown); 728 729 if( bNativeRegionOK ) 730 { 731 // convert back from border space to local coordinates 732 aPoint = pBorder->ScreenToOutputPixel( pWin->OutputToScreenPixel( aPoint ) ); 733 aContentUp.Move(-aPoint.X(), -aPoint.Y()); 734 aContentDown.Move(-aPoint.X(), -aPoint.Y()); 735 } 736 } 737 738 if( bNativeRegionOK ) 739 { 740 rSpinUpArea = aContentUp; 741 rSpinDownArea = aContentDown; 742 } 743 else 744 { 745 aSize.Width() -= CalcZoom( GetDrawPixel( pDev, rStyleSettings.GetSpinSize() ) ); 746 747 rSpinUpArea = Rectangle( aSize.Width(), nTop1, rOutSz.Width()-aDropDownSize.Width()-1, nBottom1 ); 748 rSpinDownArea = Rectangle( rSpinUpArea.Left(), nTop2, rSpinUpArea.Right(), nBottom2 ); 749 } 750 } 751 else 752 { 753 rSpinUpArea.SetEmpty(); 754 rSpinDownArea.SetEmpty(); 755 } 756 } 757 758 // -------------------------------------------------------------------- 759 760 void SpinField::Resize() 761 { 762 if ( mbSpin ) 763 { 764 Control::Resize(); 765 Size aSize = GetOutputSizePixel(); 766 bool bSubEditPositioned = false; 767 768 if ( GetStyle() & (WB_SPIN|WB_DROPDOWN) ) 769 { 770 ImplCalcButtonAreas( this, aSize, maDropDownRect, maUpperRect, maLowerRect ); 771 772 ImplControlValue aControlValue; 773 Point aPoint; 774 Rectangle aContent, aBound; 775 776 // use the full extent of the control 777 Window *pBorder = GetWindow( WINDOW_BORDER ); 778 Rectangle aArea( aPoint, pBorder->GetOutputSizePixel() ); 779 780 // adjust position and size of the edit field 781 if ( GetNativeControlRegion(CTRL_SPINBOX, PART_SUB_EDIT, 782 aArea, 0, aControlValue, rtl::OUString(), aBound, aContent) ) 783 { 784 // convert back from border space to local coordinates 785 aPoint = pBorder->ScreenToOutputPixel( OutputToScreenPixel( aPoint ) ); 786 aContent.Move(-aPoint.X(), -aPoint.Y()); 787 788 // use the themes drop down size 789 mpEdit->SetPosPixel( aContent.TopLeft() ); 790 bSubEditPositioned = true; 791 aSize = aContent.GetSize(); 792 } 793 else 794 { 795 if ( maUpperRect.IsEmpty() ) 796 { 797 DBG_ASSERT( !maDropDownRect.IsEmpty(), "SpinField::Resize: SPIN && DROPDOWN, but all empty rects?" ); 798 aSize.Width() = maDropDownRect.Left(); 799 } 800 else 801 aSize.Width() = maUpperRect.Left(); 802 } 803 } 804 805 if( ! bSubEditPositioned ) 806 { 807 // this moves our sub edit if RTL gets switched 808 mpEdit->SetPosPixel( Point() ); 809 } 810 mpEdit->SetSizePixel( aSize ); 811 812 if ( GetStyle() & WB_SPIN ) 813 Invalidate( Rectangle( maUpperRect.TopLeft(), maLowerRect.BottomRight() ) ); 814 if ( GetStyle() & WB_DROPDOWN ) 815 Invalidate( maDropDownRect ); 816 } 817 } 818 819 // ----------------------------------------------------------------------- 820 821 void SpinField::StateChanged( StateChangedType nType ) 822 { 823 Edit::StateChanged( nType ); 824 825 if ( nType == STATE_CHANGE_ENABLE ) 826 { 827 if ( mbSpin || ( GetStyle() & WB_DROPDOWN ) ) 828 { 829 mpEdit->Enable( IsEnabled() ); 830 831 if ( mbSpin ) 832 { 833 Invalidate( maLowerRect ); 834 Invalidate( maUpperRect ); 835 } 836 if ( GetStyle() & WB_DROPDOWN ) 837 Invalidate( maDropDownRect ); 838 } 839 } 840 else if ( nType == STATE_CHANGE_STYLE ) 841 { 842 if ( GetStyle() & WB_REPEAT ) 843 mbRepeat = sal_True; 844 else 845 mbRepeat = sal_False; 846 } 847 else if ( nType == STATE_CHANGE_ZOOM ) 848 { 849 Resize(); 850 if ( mpEdit ) 851 mpEdit->SetZoom( GetZoom() ); 852 Invalidate(); 853 } 854 else if ( nType == STATE_CHANGE_CONTROLFONT ) 855 { 856 if ( mpEdit ) 857 mpEdit->SetControlFont( GetControlFont() ); 858 ImplInitSettings( sal_True, sal_False, sal_False ); 859 Invalidate(); 860 } 861 else if ( nType == STATE_CHANGE_CONTROLFOREGROUND ) 862 { 863 if ( mpEdit ) 864 mpEdit->SetControlForeground( GetControlForeground() ); 865 ImplInitSettings( sal_False, sal_True, sal_False ); 866 Invalidate(); 867 } 868 else if ( nType == STATE_CHANGE_CONTROLBACKGROUND ) 869 { 870 if ( mpEdit ) 871 mpEdit->SetControlBackground( GetControlBackground() ); 872 ImplInitSettings( sal_False, sal_False, sal_True ); 873 Invalidate(); 874 } 875 else if( nType == STATE_CHANGE_MIRRORING ) 876 { 877 if( mpEdit ) 878 mpEdit->StateChanged( STATE_CHANGE_MIRRORING ); 879 Resize(); 880 } 881 } 882 883 // ----------------------------------------------------------------------- 884 885 void SpinField::DataChanged( const DataChangedEvent& rDCEvt ) 886 { 887 Edit::DataChanged( rDCEvt ); 888 889 if ( (rDCEvt.GetType() == DATACHANGED_SETTINGS) && 890 (rDCEvt.GetFlags() & SETTINGS_STYLE) ) 891 { 892 Resize(); 893 Invalidate(); 894 } 895 } 896 897 // ----------------------------------------------------------------------- 898 899 Rectangle* SpinField::ImplFindPartRect( const Point& rPt ) 900 { 901 if( maUpperRect.IsInside( rPt ) ) 902 return &maUpperRect; 903 else if( maLowerRect.IsInside( rPt ) ) 904 return &maLowerRect; 905 else 906 return NULL; 907 } 908 909 long SpinField::PreNotify( NotifyEvent& rNEvt ) 910 { 911 long nDone = 0; 912 const MouseEvent* pMouseEvt = NULL; 913 914 if( (rNEvt.GetType() == EVENT_MOUSEMOVE) && (pMouseEvt = rNEvt.GetMouseEvent()) != NULL ) 915 { 916 if( !pMouseEvt->GetButtons() && !pMouseEvt->IsSynthetic() && !pMouseEvt->IsModifierChanged() ) 917 { 918 // trigger redraw if mouse over state has changed 919 if( IsNativeControlSupported(CTRL_SPINBOX, PART_ENTIRE_CONTROL) || 920 IsNativeControlSupported(CTRL_SPINBOX, PART_ALL_BUTTONS) ) 921 { 922 Rectangle* pRect = ImplFindPartRect( GetPointerPosPixel() ); 923 Rectangle* pLastRect = ImplFindPartRect( GetLastPointerPosPixel() ); 924 if( pRect != pLastRect || (pMouseEvt->IsLeaveWindow() || pMouseEvt->IsEnterWindow()) ) 925 { 926 // FIXME: this is currently only on aqua 927 // check for other platforms that need similar handling 928 if( ImplGetSVData()->maNWFData.mbNoFocusRects && 929 IsNativeWidgetEnabled() && 930 IsNativeControlSupported( CTRL_EDITBOX, PART_ENTIRE_CONTROL ) ) 931 { 932 ImplInvalidateOutermostBorder( this ); 933 } 934 else 935 { 936 // paint directly 937 Region aRgn( GetActiveClipRegion() ); 938 if( pLastRect ) 939 { 940 SetClipRegion( *pLastRect ); 941 Paint( *pLastRect ); 942 SetClipRegion( aRgn ); 943 } 944 if( pRect ) 945 { 946 SetClipRegion( *pRect ); 947 Paint( *pRect ); 948 SetClipRegion( aRgn ); 949 } 950 } 951 } 952 } 953 } 954 } 955 956 return nDone ? nDone : Edit::PreNotify(rNEvt); 957 } 958 959 // ----------------------------------------------------------------------- 960 961 void SpinField::EndDropDown() 962 { 963 mbInDropDown = sal_False; 964 Paint( Rectangle( Point(), GetOutputSizePixel() ) ); 965 } 966 967 // ----------------------------------------------------------------------- 968 969 sal_Bool SpinField::ShowDropDown( sal_Bool ) 970 { 971 return sal_False; 972 } 973 974 // ----------------------------------------------------------------------- 975 976 Size SpinField::CalcMinimumSize() const 977 { 978 Size aSz = Edit::CalcMinimumSize(); 979 980 if ( GetStyle() & WB_DROPDOWN ) 981 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize(); 982 if ( GetStyle() & WB_SPIN ) 983 aSz.Width() += maUpperRect.GetWidth(); 984 985 return aSz; 986 } 987 988 // ----------------------------------------------------------------------- 989 990 Size SpinField::GetOptimalSize(WindowSizeType eType) const 991 { 992 switch (eType) { 993 case WINDOWSIZE_MINIMUM: 994 return CalcMinimumSize(); 995 default: 996 return Edit::GetOptimalSize( eType ); 997 } 998 } 999 1000 // ----------------------------------------------------------------------- 1001 1002 Size SpinField::CalcSize( sal_uInt16 nChars ) const 1003 { 1004 Size aSz = Edit::CalcSize( nChars ); 1005 1006 if ( GetStyle() & WB_DROPDOWN ) 1007 aSz.Width() += GetSettings().GetStyleSettings().GetScrollBarSize(); 1008 if ( GetStyle() & WB_SPIN ) 1009 aSz.Width() += GetSettings().GetStyleSettings().GetSpinSize(); 1010 1011 return aSz; 1012 } 1013 1014 // -------------------------------------------------------------------- 1015 1016 IMPL_LINK( SpinField, ImplTimeout, Timer*, pTimer ) 1017 { 1018 if ( pTimer->GetTimeout() == GetSettings().GetMouseSettings().GetButtonStartRepeat() ) 1019 { 1020 pTimer->SetTimeout( GetSettings().GetMouseSettings().GetButtonRepeat() ); 1021 pTimer->Start(); 1022 } 1023 else 1024 { 1025 if ( mbInitialUp ) 1026 Up(); 1027 else 1028 Down(); 1029 } 1030 return 0; 1031 } 1032 1033 // ----------------------------------------------------------------------- 1034 1035 void SpinField::Draw( OutputDevice* pDev, const Point& rPos, const Size& rSize, sal_uLong nFlags ) 1036 { 1037 Edit::Draw( pDev, rPos, rSize, nFlags ); 1038 1039 WinBits nFieldStyle = GetStyle(); 1040 if ( !(nFlags & WINDOW_DRAW_NOCONTROLS ) && ( nFieldStyle & (WB_SPIN|WB_DROPDOWN) ) ) 1041 { 1042 Point aPos = pDev->LogicToPixel( rPos ); 1043 Size aSize = pDev->LogicToPixel( rSize ); 1044 OutDevType eOutDevType = pDev->GetOutDevType(); 1045 AllSettings aOldSettings = pDev->GetSettings(); 1046 1047 pDev->Push(); 1048 pDev->SetMapMode(); 1049 1050 if ( eOutDevType == OUTDEV_PRINTER ) 1051 { 1052 StyleSettings aStyleSettings = aOldSettings.GetStyleSettings(); 1053 aStyleSettings.SetFaceColor( COL_LIGHTGRAY ); 1054 aStyleSettings.SetButtonTextColor( COL_BLACK ); 1055 AllSettings aSettings( aOldSettings ); 1056 aSettings.SetStyleSettings( aStyleSettings ); 1057 pDev->SetSettings( aSettings ); 1058 } 1059 1060 Rectangle aDD, aUp, aDown; 1061 ImplCalcButtonAreas( pDev, aSize, aDD, aUp, aDown ); 1062 aDD.Move( aPos.X(), aPos.Y() ); 1063 aUp.Move( aPos.X(), aPos.Y() ); 1064 aUp.Top()++; 1065 aDown.Move( aPos.X(), aPos.Y() ); 1066 1067 Color aButtonTextColor; 1068 if ( ( nFlags & WINDOW_DRAW_MONO ) || ( eOutDevType == OUTDEV_PRINTER ) ) 1069 aButtonTextColor = Color( COL_BLACK ); 1070 else 1071 aButtonTextColor = GetSettings().GetStyleSettings().GetButtonTextColor(); 1072 1073 if ( GetStyle() & WB_DROPDOWN ) 1074 { 1075 DecorationView aView( pDev ); 1076 sal_uInt16 nStyle = BUTTON_DRAW_NOLIGHTBORDER; 1077 Rectangle aInnerRect = aView.DrawButton( aDD, nStyle ); 1078 SymbolType eSymbol = SYMBOL_SPIN_DOWN; 1079 if ( GetSettings().GetStyleSettings().GetOptions() & STYLE_OPTION_SPINUPDOWN ) 1080 eSymbol = SYMBOL_SPIN_UPDOWN; 1081 1082 nStyle = ( IsEnabled() || ( nFlags & WINDOW_DRAW_NODISABLE ) ) ? 0 : SYMBOL_DRAW_DISABLE; 1083 aView.DrawSymbol( aInnerRect, eSymbol, aButtonTextColor, nStyle ); 1084 } 1085 1086 if ( GetStyle() & WB_SPIN ) 1087 { 1088 ImplDrawSpinButton( pDev, aUp, aDown, sal_False, sal_False, sal_True, sal_True ); 1089 } 1090 1091 pDev->Pop(); 1092 pDev->SetSettings( aOldSettings ); 1093 } 1094 } 1095