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