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