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 #include "vcl/salnativewidgets.hxx" 29 #include "vcl/decoview.hxx" 30 #include "vcl/svapp.hxx" 31 #include "vcl/timer.hxx" 32 33 #include "aqua/salconst.h" 34 #include "aqua/salgdi.h" 35 #include "aqua/salnativewidgets.h" 36 #include "aqua/saldata.hxx" 37 #include "aqua/salframe.h" 38 39 #include "premac.h" 40 #include <Carbon/Carbon.h> 41 #include "postmac.h" 42 43 class AquaBlinker : public Timer 44 { 45 AquaSalFrame* mpFrame; 46 Rectangle maInvalidateRect; 47 48 AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect ) 49 : mpFrame( pFrame ), maInvalidateRect( rRect ) 50 { 51 mpFrame->maBlinkers.push_back( this ); 52 } 53 54 public: 55 56 static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 ); 57 58 virtual void Timeout() 59 { 60 Stop(); 61 if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown ) 62 { 63 mpFrame->maBlinkers.remove( this ); 64 mpFrame->SendPaintEvent( &maInvalidateRect ); 65 } 66 delete this; 67 } 68 }; 69 70 void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout ) 71 { 72 // prevent repeated paints from triggering themselves all the time 73 for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin(); 74 it != pFrame->maBlinkers.end(); ++it ) 75 { 76 if( (*it)->maInvalidateRect == rRect ) 77 return; 78 } 79 AquaBlinker* pNew = new AquaBlinker( pFrame, rRect ); 80 pNew->SetTimeout( nTimeout ); 81 pNew->Start(); 82 } 83 84 ControlPart ImplgetCounterPart( ControlPart nPart ) 85 { 86 ControlPart nCounterPart = 0; 87 switch (nPart) 88 { 89 case PART_BUTTON_UP: 90 nCounterPart = PART_BUTTON_DOWN; 91 break; 92 case PART_BUTTON_DOWN: 93 nCounterPart = PART_BUTTON_UP; 94 break; 95 case PART_BUTTON_LEFT: 96 nCounterPart = PART_BUTTON_RIGHT; 97 break; 98 case PART_BUTTON_RIGHT: 99 nCounterPart = PART_BUTTON_LEFT; 100 break; 101 } 102 return nCounterPart; 103 } 104 105 106 // Helper returns an HIRect 107 108 static HIRect ImplGetHIRectFromRectangle(Rectangle aRect) 109 { 110 HIRect aHIRect; 111 aHIRect.origin.x = static_cast<float>(aRect.Left()); 112 aHIRect.origin.y = static_cast<float>(aRect.Top()); 113 aHIRect.size.width = static_cast<float>(aRect.GetWidth()); 114 aHIRect.size.height = static_cast<float>(aRect.GetHeight()); 115 return aHIRect; 116 } 117 118 static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue ) 119 { 120 switch( aButtonValue ) 121 { 122 case BUTTONVALUE_ON: 123 return kThemeButtonOn; 124 break; 125 126 case BUTTONVALUE_OFF: 127 return kThemeButtonOff; 128 break; 129 130 case BUTTONVALUE_MIXED: 131 case BUTTONVALUE_DONTKNOW: 132 default: 133 return kThemeButtonMixed; 134 break; 135 } 136 } 137 138 static bool AquaGetScrollRect( /* TODO: int nScreen, */ ControlPart nPart, 139 const Rectangle& rControlRect, Rectangle& rResultRect ) 140 { 141 bool bRetVal = true; 142 rResultRect = rControlRect; 143 144 switch( nPart ) 145 { 146 case PART_BUTTON_UP: 147 if( GetSalData()->mbIsScrollbarDoubleMax ) 148 rResultRect.Top() = rControlRect.Bottom() - 2*BUTTON_HEIGHT; 149 rResultRect.Bottom() = rResultRect.Top() + BUTTON_HEIGHT; 150 break; 151 152 case PART_BUTTON_DOWN: 153 rResultRect.Top() = rControlRect.Bottom() - BUTTON_HEIGHT; 154 break; 155 156 case PART_BUTTON_LEFT: 157 if( GetSalData()->mbIsScrollbarDoubleMax ) 158 rResultRect.Left() = rControlRect.Right() - 2*BUTTON_WIDTH; 159 rResultRect.Right() = rResultRect.Left() + BUTTON_WIDTH; 160 break; 161 162 case PART_BUTTON_RIGHT: 163 rResultRect.Left() = rControlRect.Right() - BUTTON_WIDTH; 164 break; 165 166 case PART_TRACK_HORZ_AREA: 167 rResultRect.Right() -= BUTTON_WIDTH + 1; 168 if( GetSalData()->mbIsScrollbarDoubleMax ) 169 rResultRect.Right() -= BUTTON_WIDTH; 170 else 171 rResultRect.Left() += BUTTON_WIDTH + 1; 172 break; 173 174 case PART_TRACK_VERT_AREA: 175 rResultRect.Bottom() -= BUTTON_HEIGHT + 1; 176 if( GetSalData()->mbIsScrollbarDoubleMax ) 177 rResultRect.Bottom() -= BUTTON_HEIGHT; 178 else 179 rResultRect.Top() += BUTTON_HEIGHT + 1; 180 break; 181 case PART_THUMB_HORZ: 182 if( GetSalData()->mbIsScrollbarDoubleMax ) 183 { 184 rResultRect.Left() += 8; 185 rResultRect.Right() += 6; 186 } 187 else 188 { 189 rResultRect.Left() += 4; 190 rResultRect.Right() += 4; 191 } 192 break; 193 case PART_THUMB_VERT: 194 if( GetSalData()->mbIsScrollbarDoubleMax ) 195 { 196 rResultRect.Top() += 8; 197 rResultRect.Bottom() += 8; 198 } 199 else 200 { 201 rResultRect.Top() += 4; 202 rResultRect.Bottom() += 4; 203 } 204 break; 205 case PART_TRACK_HORZ_LEFT: 206 if( GetSalData()->mbIsScrollbarDoubleMax ) 207 rResultRect.Right() += 8; 208 else 209 rResultRect.Right() += 4; 210 break; 211 case PART_TRACK_HORZ_RIGHT: 212 if( GetSalData()->mbIsScrollbarDoubleMax ) 213 rResultRect.Left() += 6; 214 else 215 rResultRect.Left() += 4; 216 break; 217 case PART_TRACK_VERT_UPPER: 218 if( GetSalData()->mbIsScrollbarDoubleMax ) 219 rResultRect.Bottom() += 8; 220 else 221 rResultRect.Bottom() += 4; 222 break; 223 case PART_TRACK_VERT_LOWER: 224 if( GetSalData()->mbIsScrollbarDoubleMax ) 225 rResultRect.Top() += 8; 226 else 227 rResultRect.Top() += 4; 228 break; 229 default: 230 bRetVal = false; 231 } 232 233 return bRetVal; 234 } 235 236 /* 237 * IsNativeControlSupported() 238 * -------------------------- 239 * Returns sal_True if the platform supports native 240 * drawing of the control defined by nPart. 241 * 242 */ 243 sal_Bool AquaSalGraphics::IsNativeControlSupported( ControlType nType, ControlPart nPart ) 244 { 245 bool bOk = sal_False; 246 247 // Native controls are now defaults 248 // If you want to disable experimental native controls code, 249 // just set the environment variable SAL_NO_NWF to something 250 // and vcl controls will be used as default again. 251 252 switch( nType ) 253 { 254 case CTRL_PUSHBUTTON: 255 case CTRL_RADIOBUTTON: 256 case CTRL_CHECKBOX: 257 case CTRL_LISTNODE: 258 if( nPart == PART_ENTIRE_CONTROL ) 259 return true; 260 break; 261 262 case CTRL_SCROLLBAR: 263 if( nPart == PART_DRAW_BACKGROUND_HORZ || 264 nPart == PART_DRAW_BACKGROUND_VERT || 265 nPart == PART_ENTIRE_CONTROL || 266 nPart == HAS_THREE_BUTTONS ) 267 return true; 268 break; 269 270 case CTRL_SLIDER: 271 if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA ) 272 return true; 273 break; 274 275 case CTRL_EDITBOX: 276 if( nPart == PART_ENTIRE_CONTROL || 277 nPart == HAS_BACKGROUND_TEXTURE ) 278 return true; 279 break; 280 281 case CTRL_MULTILINE_EDITBOX: 282 if( nPart == PART_ENTIRE_CONTROL || 283 nPart == HAS_BACKGROUND_TEXTURE ) 284 return true; 285 break; 286 287 case CTRL_SPINBOX: 288 if( nPart == PART_ENTIRE_CONTROL || 289 nPart == PART_ALL_BUTTONS || 290 nPart == HAS_BACKGROUND_TEXTURE ) 291 return true; 292 break; 293 294 case CTRL_SPINBUTTONS: 295 return false; 296 break; 297 298 case CTRL_COMBOBOX: 299 if( nPart == PART_ENTIRE_CONTROL || 300 nPart == HAS_BACKGROUND_TEXTURE ) 301 return true; 302 break; 303 304 case CTRL_LISTBOX: 305 if( nPart == PART_ENTIRE_CONTROL || 306 nPart == PART_WINDOW || 307 nPart == HAS_BACKGROUND_TEXTURE || 308 nPart == PART_SUB_EDIT 309 ) 310 return true; 311 break; 312 313 case CTRL_TAB_ITEM: 314 case CTRL_TAB_PANE: 315 case CTRL_TAB_BODY: // see vcl/source/window/tabpage.cxx 316 case CTRL_FIXEDBORDER: 317 if( nPart == PART_ENTIRE_CONTROL || 318 nPart == PART_TABS_DRAW_RTL || 319 nPart == HAS_BACKGROUND_TEXTURE ) 320 return true; 321 break; 322 323 // when PART_BUTTON is used, toolbar icons are not highlighted when mouse rolls over. 324 // More Aqua compliant 325 case CTRL_TOOLBAR: 326 if( nPart == PART_ENTIRE_CONTROL || 327 nPart == PART_DRAW_BACKGROUND_HORZ || 328 nPart == PART_DRAW_BACKGROUND_VERT) 329 return true; 330 break; 331 332 case CTRL_WINDOW_BACKGROUND: 333 if ( nPart == PART_BACKGROUND_WINDOW || 334 nPart == PART_BACKGROUND_DIALOG ) 335 return true; 336 break; 337 338 case CTRL_MENUBAR: 339 if( nPart == PART_ENTIRE_CONTROL ) 340 return true; 341 break; 342 343 case CTRL_TOOLTIP: // ** TO DO 344 #if 0 345 if( nPart == PART_ENTIRE_CONTROL ) // we don't currently support the tooltip 346 return true; 347 #endif 348 break; 349 350 case CTRL_MENU_POPUP: 351 if( nPart == PART_ENTIRE_CONTROL || 352 nPart == PART_MENU_ITEM || 353 nPart == PART_MENU_ITEM_CHECK_MARK || 354 nPart == PART_MENU_ITEM_RADIO_MARK) 355 return true; 356 break; 357 case CTRL_PROGRESS: 358 case CTRL_INTROPROGRESS: 359 if( nPart == PART_ENTIRE_CONTROL ) 360 return true; 361 break; 362 case CTRL_FRAME: 363 if( nPart == PART_BORDER ) 364 return true; 365 break; 366 case CTRL_LISTNET: 367 if( nPart == PART_ENTIRE_CONTROL ) 368 return true; 369 break; 370 } 371 372 return bOk; 373 } 374 375 /* 376 * HitTestNativeControl() 377 * 378 * If the return value is sal_True, bIsInside contains information whether 379 * aPos was or was not inside the native widget specified by the 380 * nType/nPart combination. 381 */ 382 sal_Bool AquaSalGraphics::hitTestNativeControl( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, 383 const Point& rPos, sal_Bool& rIsInside ) 384 { 385 if ( nType == CTRL_SCROLLBAR ) 386 { 387 Rectangle aRect; 388 bool bValid = AquaGetScrollRect( /* TODO: m_nScreen */ nPart, rControlRegion, aRect ); 389 rIsInside = bValid ? aRect.IsInside( rPos ) : sal_False; 390 if( GetSalData()->mbIsScrollbarDoubleMax ) 391 { 392 // in double max mode the actual trough is a little smaller than the track 393 // there is some visual filler that is not sensitive 394 if( bValid && rIsInside ) 395 { 396 if( nPart == PART_TRACK_HORZ_AREA ) 397 { 398 // the left 4 pixels are not hit sensitive 399 if( rPos.X() - aRect.Left() < 4 ) 400 rIsInside = sal_False; 401 } 402 else if( nPart == PART_TRACK_VERT_AREA ) 403 { 404 // the top 4 pixels are not hit sensitive 405 if( rPos.Y() - aRect.Top() < 4 ) 406 rIsInside = sal_False; 407 } 408 } 409 } 410 return bValid; 411 } // CTRL_SCROLLBAR 412 413 return sal_False; 414 } 415 416 /* 417 kThemeStateInactive = 0, 418 kThemeStateActive = 1, 419 kThemeStatePressed = 2, 420 kThemeStateRollover = 6, 421 kThemeStateUnavailable = 7, 422 kThemeStateUnavailableInactive = 8 423 kThemeStatePressedUp = 2, 424 kThemeStatePressedDown = 3 425 426 #define CTRL_STATE_ENABLED 0x0001 427 #define CTRL_STATE_FOCUSED 0x0002 428 #define CTRL_STATE_PRESSED 0x0004 429 #define CTRL_STATE_ROLLOVER 0x0008 430 #define CTRL_STATE_HIDDEN 0x0010 431 #define CTRL_STATE_DEFAULT 0x0020 432 #define CTRL_STATE_SELECTED 0x0040 433 #define CTRL_CACHING_ALLOWED 0x8000 // set when the control is completely visible (i.e. not clipped) 434 */ 435 UInt32 AquaSalGraphics::getState( ControlState nState ) 436 { 437 bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true; 438 if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive ) 439 { 440 if( (nState & CTRL_STATE_HIDDEN) == 0 ) 441 return kThemeStateInactive; 442 else 443 return kThemeStateUnavailableInactive; 444 } 445 446 if( (nState & CTRL_STATE_HIDDEN) != 0 ) 447 return kThemeStateUnavailable; 448 449 if( (nState & CTRL_STATE_PRESSED) != 0 ) 450 return kThemeStatePressed; 451 452 return kThemeStateActive; 453 } 454 455 UInt32 AquaSalGraphics::getTrackState( ControlState nState ) 456 { 457 bool bDrawActive = mpFrame ? ([mpFrame->getWindow() isKeyWindow] ? true : false) : true; 458 if( (nState & CTRL_STATE_ENABLED) == 0 || ! bDrawActive ) 459 return kThemeTrackInactive; 460 461 return kThemeTrackActive; 462 } 463 464 /* 465 * DrawNativeControl() 466 * 467 * Draws the requested control described by nPart/nState. 468 * 469 * rControlRegion: The bounding region of the complete control in VCL frame coordinates. 470 * aValue: An optional value (tristate/numerical/string) 471 * aCaption: A caption or title string (like button text etc) 472 */ 473 sal_Bool AquaSalGraphics::drawNativeControl(ControlType nType, 474 ControlPart nPart, 475 const Rectangle& rControlRegion, 476 ControlState nState, 477 const ImplControlValue& aValue, 478 const rtl::OUString& ) 479 { 480 sal_Bool bOK = sal_False; 481 482 if( ! CheckContext() ) 483 return false; 484 485 CGContextSaveGState( mrContext ); 486 487 Rectangle buttonRect = rControlRegion; 488 HIRect rc = ImplGetHIRectFromRectangle(buttonRect); 489 490 /** Scrollbar parts code equivalent ** 491 PART_BUTTON_UP 101 492 PART_BUTTON_DOWN 102 493 PART_THUMB_VERT 211 494 PART_TRACK_VERT_UPPER 201 495 PART_TRACK_VERT_LOWER 203 496 497 PART_DRAW_BACKGROUND_HORZ 1000 498 PART_DRAW_BACKGROUND_VERT 1001 499 **/ 500 501 switch( nType ) 502 { 503 504 case CTRL_COMBOBOX: 505 if ( nPart == HAS_BACKGROUND_TEXTURE || 506 nPart == PART_ENTIRE_CONTROL ) 507 { 508 HIThemeButtonDrawInfo aComboInfo; 509 aComboInfo.version = 0; 510 aComboInfo.kind = kThemeComboBox; 511 aComboInfo.state = getState( nState ); 512 aComboInfo.value = kThemeButtonOn; 513 aComboInfo.adornment = kThemeAdornmentNone; 514 515 if( (nState & CTRL_STATE_FOCUSED) != 0 ) 516 aComboInfo.adornment |= kThemeAdornmentFocus; 517 518 HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc); 519 bOK = true; 520 } 521 break; 522 523 case CTRL_FIXEDBORDER: 524 case CTRL_TOOLBAR: 525 { 526 HIThemeMenuItemDrawInfo aMenuItemDrawInfo; 527 aMenuItemDrawInfo.version = 0; 528 aMenuItemDrawInfo.state = kThemeMenuActive; 529 aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground; 530 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL); 531 bOK = true; 532 } 533 break; 534 535 case CTRL_WINDOW_BACKGROUND: 536 { 537 HIThemeBackgroundDrawInfo aThemeBackgroundInfo; 538 aThemeBackgroundInfo.version = 0; 539 aThemeBackgroundInfo.state = getState( nState ); 540 aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundInactive; 541 // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom 542 rc.size.width += 2; 543 rc.size.height += 2; 544 545 HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal); 546 CGContextFillRect( mrContext, rc ); 547 bOK = true; 548 } 549 break; 550 551 case CTRL_MENUBAR: 552 case CTRL_MENU_POPUP: 553 { 554 if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE )) 555 { 556 // FIXME: without this magical offset there is a 2 pixel black border on the right 557 rc.size.width += 2; 558 559 HIThemeMenuDrawInfo aMenuInfo; 560 aMenuInfo.version = 0; 561 aMenuInfo.menuType = kThemeMenuTypePullDown; 562 563 HIThemeMenuItemDrawInfo aMenuItemDrawInfo; 564 // the Aqua grey theme when the item is selected is drawn here. 565 aMenuItemDrawInfo.itemType = kThemeMenuItemPlain; 566 567 if ((nPart == PART_MENU_ITEM ) && (nState & CTRL_STATE_SELECTED)) 568 { 569 // the blue theme when the item is selected is drawn here. 570 aMenuItemDrawInfo.state = kThemeMenuSelected; 571 } 572 else 573 { 574 // normal color for non selected item 575 aMenuItemDrawInfo.state = kThemeMenuActive; 576 } 577 578 // repaints the background of the pull down menu 579 HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal); 580 581 // repaints the item either blue (selected) and/or Aqua grey (active only) 582 HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc); 583 584 bOK = true; 585 } 586 else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) { 587 if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx) 588 HIThemeTextInfo aTextInfo; 589 aTextInfo.version = 0; 590 aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive; 591 aTextInfo.fontID = kThemeMenuItemMarkFont; 592 aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter; 593 aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop; 594 aTextInfo.options=kHIThemeTextBoxOptionNone; 595 aTextInfo.truncationPosition=kHIThemeTextTruncationNone; 596 //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone 597 598 if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted 599 600 UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713; 601 CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull); 602 HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal); 603 if (cfString) 604 CFRelease(cfString); 605 606 bOK = true; 607 } 608 } 609 } 610 break; 611 612 case CTRL_PUSHBUTTON: 613 { 614 // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented) 615 const int PB_Mini_Height = 15; 616 const int PB_Norm_Height = 21; 617 618 HIThemeButtonDrawInfo aPushInfo; 619 aPushInfo.version = 0; 620 621 // no animation 622 aPushInfo.animation.time.start = 0; 623 aPushInfo.animation.time.current = 0; 624 PushButtonValue* pPBVal = aValue.getType() == CTRL_PUSHBUTTON ? (PushButtonValue*)&aValue : NULL; 625 int nPaintHeight = static_cast<int>(rc.size.height); 626 627 if( pPBVal && pPBVal->mbBevelButton ) 628 { 629 aPushInfo.kind = kThemeRoundedBevelButton; 630 } 631 else if( rc.size.height <= PB_Norm_Height ) 632 { 633 aPushInfo.kind = kThemePushButtonMini; 634 nPaintHeight = PB_Mini_Height; 635 } 636 else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) ) 637 { 638 aPushInfo.kind = kThemePushButtonNormal; 639 nPaintHeight = PB_Norm_Height; 640 641 // avoid clipping when focused 642 rc.origin.x += FOCUS_RING_WIDTH/2; 643 rc.size.width -= FOCUS_RING_WIDTH; 644 645 if( (nState & CTRL_STATE_DEFAULT) != 0 ) 646 { 647 AquaBlinker::Blink( mpFrame, buttonRect ); 648 // show correct animation phase 649 aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent(); 650 } 651 } 652 else 653 aPushInfo.kind = kThemeBevelButton; 654 655 // translate the origin for controls with fixed paint height 656 // so content ends up somewhere sensible 657 int delta_y = static_cast<int>(rc.size.height) - nPaintHeight; 658 rc.origin.y += delta_y/2; 659 660 aPushInfo.state = getState( nState ); 661 aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() ); 662 663 aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ? 664 kThemeAdornmentDefault : 665 kThemeAdornmentNone; 666 if( (nState & CTRL_STATE_FOCUSED) != 0 ) 667 aPushInfo.adornment |= kThemeAdornmentFocus; 668 669 HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL ); 670 bOK = true; 671 } 672 break; 673 674 case CTRL_RADIOBUTTON: 675 case CTRL_CHECKBOX: 676 { 677 HIThemeButtonDrawInfo aInfo; 678 aInfo.version = 0; 679 switch( nType ) 680 { 681 case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton; 682 else aInfo.kind = kThemeSmallRadioButton; 683 break; 684 case CTRL_CHECKBOX: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox; 685 else aInfo.kind = kThemeSmallCheckBox; 686 break; 687 } 688 689 aInfo.state = getState( nState ); 690 691 ButtonValue aButtonValue = aValue.getTristateVal(); 692 aInfo.value = ImplGetButtonValue( aButtonValue ); 693 694 aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ? 695 kThemeAdornmentDefault : 696 kThemeAdornmentNone; 697 if( (nState & CTRL_STATE_FOCUSED) != 0 ) 698 aInfo.adornment |= kThemeAdornmentFocus; 699 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL ); 700 bOK = true; 701 } 702 break; 703 704 case CTRL_LISTNODE: 705 { 706 ButtonValue aButtonValue = aValue.getTristateVal(); 707 708 if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF ) 709 { 710 // FIXME: a value of kThemeDisclosureLeft 711 // should draw a theme compliant left disclosure triangle 712 // sadly this does not seem to work, so we'll draw a left 713 // grey equilateral triangle here ourselves. 714 // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ? 715 716 CGContextSetShouldAntialias( mrContext, true ); 717 float aGrey[] = { 0.45, 0.45, 0.45, 1.0 }; 718 CGContextSetFillColor( mrContext, aGrey ); 719 CGContextBeginPath( mrContext ); 720 float x = rc.origin.x + rc.size.width; 721 float y = rc.origin.y; 722 CGContextMoveToPoint( mrContext, x, y ); 723 y += rc.size.height; 724 CGContextAddLineToPoint( mrContext, x, y ); 725 x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866 726 y -= rc.size.height/2; 727 CGContextAddLineToPoint( mrContext, x, y ); 728 CGContextDrawPath( mrContext, kCGPathEOFill ); 729 } 730 else 731 { 732 HIThemeButtonDrawInfo aInfo; 733 aInfo.version = 0; 734 aInfo.kind = kThemeDisclosureTriangle; 735 aInfo.value = kThemeDisclosureRight; 736 aInfo.state = getState( nState ); 737 738 aInfo.adornment = kThemeAdornmentNone; 739 740 switch( aButtonValue ) { 741 case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded 742 break; 743 case BUTTONVALUE_OFF: 744 // FIXME: this should have drawn a theme compliant disclosure triangle 745 // (see above) 746 if( Application::GetSettings().GetLayoutRTL() ) 747 { 748 aInfo.value = kThemeDisclosureLeft;//collapsed, RTL 749 } 750 break; 751 case BUTTONVALUE_DONTKNOW: //what to do? 752 default: 753 break; 754 } 755 756 HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL ); 757 } 758 bOK = true; 759 } 760 break; 761 762 case CTRL_PROGRESS: 763 case CTRL_INTROPROGRESS: 764 { 765 long nProgressWidth = aValue.getNumericVal(); 766 HIThemeTrackDrawInfo aTrackInfo; 767 aTrackInfo.version = 0; 768 aTrackInfo.kind = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium; 769 aTrackInfo.bounds = rc; 770 aTrackInfo.min = 0; 771 aTrackInfo.max = static_cast<SInt32>(rc.size.width); 772 aTrackInfo.value = nProgressWidth; 773 aTrackInfo.reserved = 0; 774 aTrackInfo.bounds.origin.y -= 2; // FIXME: magic for shadow 775 aTrackInfo.bounds.size.width -= 2; // FIXME: magic for shadow 776 aTrackInfo.attributes = kThemeTrackHorizontal; 777 if( Application::GetSettings().GetLayoutRTL() ) 778 aTrackInfo.attributes |= kThemeTrackRightToLeft; 779 aTrackInfo.enableState = getTrackState( nState ); 780 // the intro bitmap never gets key anyway; we want to draw that enabled 781 if( nType == CTRL_INTROPROGRESS ) 782 aTrackInfo.enableState = kThemeTrackActive; 783 aTrackInfo.filler1 = 0; 784 aTrackInfo.trackInfo.progress.phase = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0); 785 786 HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal ); 787 bOK = true; 788 } 789 break; 790 791 case CTRL_SLIDER: 792 { 793 SliderValue* pSLVal = (SliderValue*)&aValue; 794 795 HIThemeTrackDrawInfo aTrackDraw; 796 aTrackDraw.kind = kThemeSliderMedium; 797 if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA ) 798 { 799 aTrackDraw.bounds = rc; 800 aTrackDraw.min = pSLVal->mnMin; 801 aTrackDraw.max = pSLVal->mnMax;; 802 aTrackDraw.value = pSLVal->mnCur; 803 aTrackDraw.reserved = 0; 804 aTrackDraw.attributes = kThemeTrackShowThumb; 805 if( nPart == PART_TRACK_HORZ_AREA ) 806 aTrackDraw.attributes |= kThemeTrackHorizontal; 807 aTrackDraw.enableState = (nState & CTRL_STATE_ENABLED) 808 ? kThemeTrackActive : kThemeTrackInactive; 809 810 SliderTrackInfo aSlideInfo; 811 aSlideInfo.thumbDir = kThemeThumbUpward; 812 aSlideInfo.pressState = 0; 813 aTrackDraw.trackInfo.slider = aSlideInfo; 814 815 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal ); 816 bOK = true; 817 } 818 } 819 break; 820 821 case CTRL_SCROLLBAR: 822 { 823 ScrollbarValue* pScrollbarVal = (ScrollbarValue *)&aValue; 824 825 if( nPart == PART_DRAW_BACKGROUND_VERT || 826 nPart == PART_DRAW_BACKGROUND_HORZ ) 827 { 828 HIThemeTrackDrawInfo aTrackDraw; 829 aTrackDraw.kind = kThemeMediumScrollBar; 830 // FIXME: the scrollbar length must be adjusted 831 if (nPart == PART_DRAW_BACKGROUND_VERT) 832 rc.size.height += 2; 833 else 834 rc.size.width += 2; 835 836 aTrackDraw.bounds = rc; 837 aTrackDraw.min = pScrollbarVal->mnMin; 838 aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize; 839 aTrackDraw.value = pScrollbarVal->mnCur; 840 aTrackDraw.reserved = 0; 841 aTrackDraw.attributes = kThemeTrackShowThumb; 842 if( nPart == PART_DRAW_BACKGROUND_HORZ ) 843 aTrackDraw.attributes |= kThemeTrackHorizontal; 844 aTrackDraw.enableState = getTrackState( nState ); 845 846 ScrollBarTrackInfo aScrollInfo; 847 aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize; 848 aScrollInfo.pressState = 0; 849 850 if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED ) 851 { 852 if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED ) 853 aScrollInfo.pressState = kThemeTopOutsideArrowPressed; 854 } 855 856 if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED ) 857 { 858 if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED ) 859 aScrollInfo.pressState = kThemeBottomOutsideArrowPressed; 860 } 861 862 if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED ) 863 { 864 if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED ) 865 aScrollInfo.pressState = kThemeThumbPressed; 866 } 867 868 aTrackDraw.trackInfo.scrollbar = aScrollInfo; 869 870 HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal ); 871 bOK = true; 872 } 873 } 874 break; 875 876 //#define OLD_TAB_STYLE 877 #ifdef OLD_TAB_STYLE 878 case CTRL_TAB_PANE: 879 { 880 HIThemeTabPaneDrawInfo aTabPaneDrawInfo; 881 aTabPaneDrawInfo.version = 0; 882 aTabPaneDrawInfo.state = kThemeStateActive; 883 aTabPaneDrawInfo.direction=kThemeTabNorth; 884 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal; 885 886 //the border is outside the rect rc for Carbon 887 //but for VCL it should be inside 888 rc.origin.x+=1; 889 rc.size.width-=2; 890 891 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal); 892 bOK = true; 893 } 894 break; 895 896 case CTRL_TAB_ITEM: 897 { 898 HIThemeTabDrawInfo aTabItemDrawInfo; 899 aTabItemDrawInfo.version=0; 900 aTabItemDrawInfo.style=kThemeTabNonFront; 901 aTabItemDrawInfo.direction=kThemeTabNorth; 902 aTabItemDrawInfo.size=kHIThemeTabSizeNormal; 903 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone; 904 905 if(nState & CTRL_STATE_SELECTED) { 906 aTabItemDrawInfo.style=kThemeTabFront; 907 } 908 if(nState & CTRL_STATE_FOCUSED) { 909 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus; 910 } 911 912 /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL; 913 else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL; 914 else rc.size.height=TAB_HEIGHT_MINI;*/ 915 //now we only use the default size 916 rc.size.height=TAB_HEIGHT_NORMAL; 917 918 HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc ); 919 920 bOK=true; 921 } 922 break; 923 #else 924 case CTRL_TAB_PANE: 925 { 926 HIThemeTabPaneDrawInfo aTabPaneDrawInfo; 927 aTabPaneDrawInfo.version = 1; 928 aTabPaneDrawInfo.state = kThemeStateActive; 929 aTabPaneDrawInfo.direction=kThemeTabNorth; 930 aTabPaneDrawInfo.size=kHIThemeTabSizeNormal; 931 aTabPaneDrawInfo.kind=kHIThemeTabKindNormal; 932 933 //the border is outside the rect rc for Carbon 934 //but for VCL it should be inside 935 rc.origin.x+=1; 936 rc.origin.y-=TAB_HEIGHT_NORMAL/2; 937 rc.size.height+=TAB_HEIGHT_NORMAL/2; 938 rc.size.width-=2; 939 940 HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal); 941 942 bOK = true; 943 } 944 break; 945 946 case CTRL_TAB_ITEM: 947 { 948 HIThemeTabDrawInfo aTabItemDrawInfo; 949 aTabItemDrawInfo.version=1; 950 aTabItemDrawInfo.style=kThemeTabNonFront; 951 aTabItemDrawInfo.direction=kThemeTabNorth; 952 aTabItemDrawInfo.size=kHIThemeTabSizeNormal; 953 aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator; 954 //State 955 if(nState & CTRL_STATE_SELECTED) { 956 aTabItemDrawInfo.style=kThemeTabFront; 957 } 958 if(nState & CTRL_STATE_FOCUSED) { 959 aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus; 960 } 961 962 //first, last or middle tab 963 aTabItemDrawInfo.position=kHIThemeTabPositionMiddle; 964 965 TabitemValue* pTabValue = (TabitemValue *) &aValue; 966 unsigned int nAlignment = pTabValue->mnAlignment; 967 //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab 968 //when there are several lines of tabs because there is only one first tab and one 969 //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the 970 //line width is different from window width, there may not be TABITEM_RIGHTALIGNED 971 if( ( (nAlignment & TABITEM_LEFTALIGNED)&&(nAlignment & TABITEM_RIGHTALIGNED) ) || 972 ( (nAlignment & TABITEM_FIRST_IN_GROUP)&&(nAlignment & TABITEM_LAST_IN_GROUP) ) 973 ) //tab alone 974 aTabItemDrawInfo.position=kHIThemeTabPositionOnly; 975 else if((nAlignment & TABITEM_LEFTALIGNED)||(nAlignment & TABITEM_FIRST_IN_GROUP)) 976 aTabItemDrawInfo.position=kHIThemeTabPositionFirst; 977 else if((nAlignment & TABITEM_RIGHTALIGNED)||(nAlignment & TABITEM_LAST_IN_GROUP)) 978 aTabItemDrawInfo.position=kHIThemeTabPositionLast; 979 980 //support for RTL 981 //see issue 79748 982 if( Application::GetSettings().GetLayoutRTL() ) { 983 if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst ) 984 aTabItemDrawInfo.position = kHIThemeTabPositionLast; 985 else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast ) 986 aTabItemDrawInfo.position = kHIThemeTabPositionFirst; 987 } 988 989 rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs 990 rc.origin.x-=1; 991 992 HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc ); 993 994 bOK=true; 995 } 996 break; 997 #endif 998 999 case CTRL_LISTBOX: 1000 switch( nPart) 1001 { 1002 case PART_ENTIRE_CONTROL: 1003 case PART_BUTTON_DOWN: 1004 { 1005 HIThemeButtonDrawInfo aListInfo; 1006 aListInfo.version = 0; 1007 aListInfo.kind = kThemePopupButton; 1008 aListInfo.state = getState( nState );//kThemeStateInactive -> greyed 1009 aListInfo.value = kThemeButtonOn; 1010 1011 aListInfo.adornment = kThemeAdornmentDefault; 1012 if( (nState & CTRL_STATE_FOCUSED) != 0 ) 1013 aListInfo.adornment |= kThemeAdornmentFocus; 1014 1015 HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc); 1016 bOK = true; 1017 break; 1018 } 1019 case PART_WINDOW: 1020 { 1021 HIThemeFrameDrawInfo aTextDrawInfo; 1022 aTextDrawInfo.version=0; 1023 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare; 1024 aTextDrawInfo.state=getState( nState ); 1025 aTextDrawInfo.isFocused=false; 1026 1027 rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border 1028 rc.size.height+=1; 1029 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal); 1030 1031 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal); 1032 1033 bOK=true; 1034 break; 1035 } 1036 } 1037 break; 1038 1039 case CTRL_EDITBOX: 1040 case CTRL_MULTILINE_EDITBOX: 1041 { 1042 HIThemeFrameDrawInfo aTextDrawInfo; 1043 aTextDrawInfo.version=0; 1044 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare; 1045 aTextDrawInfo.state=getState( nState ); 1046 aTextDrawInfo.isFocused=false; 1047 1048 rc.size.width += 1; // else there may be a white space because aqua theme hasn't a 3D border 1049 // change rc so that the frame will encompass only the content region 1050 // see counterpart in GetNativeControlRegion 1051 rc.size.width += 2; 1052 rc.size.height += 2; 1053 1054 //CGContextSetFillColorWithColor 1055 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); 1056 //fill a white background, because drawFrame only draws the border 1057 1058 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal); 1059 1060 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal); 1061 1062 bOK=true; 1063 } 1064 break; 1065 1066 case CTRL_SPINBOX: 1067 { 1068 if(nPart == PART_ENTIRE_CONTROL) 1069 { 1070 //text field: 1071 HIThemeFrameDrawInfo aTextDrawInfo; 1072 aTextDrawInfo.version=0; 1073 aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare; 1074 aTextDrawInfo.state=getState( nState ); 1075 aTextDrawInfo.isFocused=false; 1076 1077 //rc.size.width contains the full size of the spinbox ie textfield + button 1078 //so we remove the button width and the space between the button and the textfield 1079 rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH; 1080 rc.origin.x += FOCUS_RING_WIDTH; 1081 rc.origin.y += FOCUS_RING_WIDTH; 1082 1083 //CGContextSetFillColorWithColor 1084 CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height)); 1085 //fill a white background, because drawFrame only draws the border 1086 1087 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal); 1088 1089 if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal); 1090 1091 //buttons: 1092 SpinbuttonValue* pSpinButtonVal = (SpinbuttonValue *)&aValue; 1093 ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button 1094 ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button 1095 if(pSpinButtonVal) {//pSpinButtonVal is sometimes null 1096 nUpperState = (ControlState) pSpinButtonVal->mnUpperState; 1097 nLowerState = (ControlState) pSpinButtonVal->mnLowerState; 1098 } 1099 1100 if( pSpinButtonVal ) 1101 { 1102 HIThemeButtonDrawInfo aSpinInfo; 1103 aSpinInfo.kind = kThemeIncDecButton; 1104 aSpinInfo.state = kThemeStateActive; 1105 if(nUpperState & CTRL_STATE_PRESSED) 1106 aSpinInfo.state = kThemeStatePressedUp; 1107 else if(nLowerState & CTRL_STATE_PRESSED) 1108 aSpinInfo.state = kThemeStatePressedDown; 1109 else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED)) 1110 aSpinInfo.state = kThemeStateInactive; 1111 else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER)) 1112 aSpinInfo.state = kThemeStateRollover; 1113 1114 Rectangle aSpinRect( pSpinButtonVal->maUpperRect ); 1115 aSpinRect.Union( pSpinButtonVal->maLowerRect ); 1116 HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect); 1117 1118 // FIXME: without this fuzz factor there is some unwanted clipping 1119 if( Application::GetSettings().GetLayoutRTL() ) 1120 buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ; 1121 else 1122 buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ; 1123 1124 switch( aValue.getTristateVal() ) 1125 { 1126 case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn; 1127 break; 1128 case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff; 1129 break; 1130 case BUTTONVALUE_MIXED: 1131 case BUTTONVALUE_DONTKNOW: 1132 default: aSpinInfo.value = kThemeButtonMixed; 1133 break; 1134 } 1135 1136 aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) || 1137 ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ? 1138 kThemeAdornmentDefault : 1139 kThemeAdornmentNone; 1140 if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 )) 1141 aSpinInfo.adornment |= kThemeAdornmentFocus; 1142 1143 HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL ); 1144 } 1145 1146 bOK=true; 1147 } 1148 1149 } 1150 break; 1151 1152 case CTRL_FRAME: 1153 { 1154 sal_uInt16 nStyle = aValue.getNumericVal(); 1155 if( nPart == PART_BORDER ) { 1156 if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) ) 1157 { 1158 // #i84756# strange effects start to happen when HIThemeDrawFrame 1159 // meets the border of the window. These can be avoided by clipping 1160 // to the boundary of the frame 1161 if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 ) 1162 { 1163 CGMutablePathRef rPath = CGPathCreateMutable(); 1164 CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) ); 1165 1166 CGContextBeginPath( mrContext ); 1167 CGContextAddPath( mrContext, rPath ); 1168 CGContextClip( mrContext ); 1169 CGPathRelease( rPath ); 1170 } 1171 1172 HIThemeFrameDrawInfo aTextDrawInfo; 1173 aTextDrawInfo.version=0; 1174 aTextDrawInfo.kind=kHIThemeFrameListBox; 1175 aTextDrawInfo.state=kThemeStateActive; 1176 aTextDrawInfo.isFocused=false; 1177 1178 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal); 1179 1180 bOK=true; 1181 } 1182 } 1183 } 1184 break; 1185 1186 case CTRL_LISTNET: 1187 { 1188 //do nothing as there isn't net for listviews on macos 1189 bOK=true; 1190 } 1191 break; 1192 1193 } 1194 1195 CGContextRestoreGState( mrContext ); 1196 1197 /* #i90291# in most cases invalidating the whole control region instead 1198 of just the unclipped part of it is sufficient (and probably faster). 1199 However for the window background we should not unnecessarily enlarge 1200 the really changed rectangle since the difference is usually quite high 1201 (the background is always drawn as a whole since we don't know anything 1202 about its possible contents) 1203 */ 1204 if( nType == CTRL_WINDOW_BACKGROUND ) 1205 { 1206 CGRect aRect = { { 0, 0 }, { 0, 0 } }; 1207 if( mxClipPath ) 1208 aRect = CGPathGetBoundingBox( mxClipPath ); 1209 if( aRect.size.width != 0 && aRect.size.height != 0 ) 1210 buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x), 1211 static_cast<long int>(aRect.origin.y) ), 1212 Size( static_cast<long int>(aRect.size.width), 1213 static_cast<long int>(aRect.size.height) ) ) ); 1214 } 1215 1216 RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() ); 1217 1218 return bOK; 1219 } 1220 1221 /* 1222 * DrawNativeControlText() 1223 * 1224 * OPTIONAL. Draws the requested text for the control described by nPart/nState. 1225 * Used if text not drawn by DrawNativeControl(). 1226 * 1227 * rControlRegion: The bounding region of the complete control in VCL frame coordinates. 1228 * aValue: An optional value (tristate/numerical/string) 1229 * aCaption: A caption or title string (like button text etc) 1230 */ 1231 sal_Bool AquaSalGraphics::drawNativeControlText( ControlType /*nType*/, ControlPart /*nPart*/, const Rectangle& /*rControlRegion*/, 1232 ControlState /*nState*/, const ImplControlValue& /*aValue*/, 1233 const rtl::OUString& ) 1234 { 1235 return( sal_False ); 1236 } 1237 1238 1239 /* 1240 * GetNativeControlRegion() 1241 * 1242 * If the return value is sal_True, rNativeBoundingRegion 1243 * contains the true bounding region covered by the control 1244 * including any adornment, while rNativeContentRegion contains the area 1245 * within the control that can be safely drawn into without drawing over 1246 * the borders of the control. 1247 * 1248 * rControlRegion: The bounding region of the control in VCL frame coordinates. 1249 * aValue: An optional value (tristate/numerical/string) 1250 * aCaption: A caption or title string (like button text etc) 1251 */ 1252 sal_Bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState /*nState*/, 1253 const ImplControlValue& aValue, const rtl::OUString&, 1254 Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion ) 1255 1256 { 1257 sal_Bool toReturn = sal_False; 1258 1259 Rectangle aCtrlBoundRect( rControlRegion ); 1260 short x = aCtrlBoundRect.Left(); 1261 short y = aCtrlBoundRect.Top(); 1262 short w, h; 1263 1264 sal_uInt8 nBorderCleanup = 0; 1265 1266 switch (nType) 1267 { 1268 case CTRL_SLIDER: 1269 { 1270 if( nPart == PART_THUMB_HORZ ) 1271 { 1272 w = 19; // taken from HIG 1273 h = aCtrlBoundRect.GetHeight(); 1274 rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1275 toReturn = true; 1276 } 1277 else if( nPart == PART_THUMB_VERT ) 1278 { 1279 w = aCtrlBoundRect.GetWidth(); 1280 h = 18; // taken from HIG 1281 rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1282 toReturn = true; 1283 } 1284 } 1285 break; 1286 1287 case CTRL_SCROLLBAR: 1288 { 1289 Rectangle aRect; 1290 if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) ) 1291 { 1292 toReturn = sal_True; 1293 rNativeBoundingRegion = aRect; 1294 rNativeContentRegion = aRect; 1295 } 1296 } 1297 break; 1298 1299 case CTRL_PUSHBUTTON: 1300 case CTRL_RADIOBUTTON: 1301 case CTRL_CHECKBOX: 1302 { 1303 if ( nType == CTRL_PUSHBUTTON ) 1304 { 1305 w = aCtrlBoundRect.GetWidth(); 1306 h = aCtrlBoundRect.GetHeight(); 1307 } 1308 else 1309 { 1310 // checkbox and radio borders need cleanup after unchecking them 1311 nBorderCleanup = 4; 1312 1313 // TEXT_SEPARATOR to respect Aqua HIG 1314 w = BUTTON_WIDTH + TEXT_SEPARATOR; 1315 h = BUTTON_HEIGHT; 1316 1317 } 1318 1319 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) ); 1320 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1321 1322 toReturn = sal_True; 1323 } 1324 break; 1325 case CTRL_PROGRESS: 1326 { 1327 Rectangle aRect( aCtrlBoundRect ); 1328 if( aRect.GetHeight() < 16 ) 1329 aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress 1330 else 1331 aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress 1332 rNativeBoundingRegion = aRect; 1333 rNativeContentRegion = aRect; 1334 toReturn = sal_True; 1335 } 1336 break; 1337 1338 case CTRL_INTROPROGRESS: 1339 { 1340 Rectangle aRect( aCtrlBoundRect ); 1341 aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress 1342 rNativeBoundingRegion = aRect; 1343 rNativeContentRegion = aRect; 1344 toReturn = sal_True; 1345 } 1346 break; 1347 1348 case CTRL_TAB_ITEM: 1349 1350 w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET; 1351 1352 #ifdef OLD_TAB_STYLE 1353 h = TAB_HEIGHT_NORMAL; 1354 #else 1355 h = TAB_HEIGHT_NORMAL+2; 1356 #endif 1357 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1358 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1359 1360 toReturn = sal_True; 1361 1362 break; 1363 1364 case CTRL_EDITBOX: 1365 { 1366 w = aCtrlBoundRect.GetWidth(); 1367 if( w < 3+2*FOCUS_RING_WIDTH ) 1368 w = 3+2*FOCUS_RING_WIDTH; 1369 h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH; 1370 if( h < aCtrlBoundRect.GetHeight() ) 1371 h = aCtrlBoundRect.GetHeight(); 1372 1373 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*(FOCUS_RING_WIDTH+1), h-2*(FOCUS_RING_WIDTH+1) ) ); 1374 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1375 1376 toReturn = sal_True; 1377 } 1378 break; 1379 case CTRL_LISTBOX: 1380 case CTRL_COMBOBOX: 1381 { 1382 if( nPart == PART_ENTIRE_CONTROL ) 1383 { 1384 w = aCtrlBoundRect.GetWidth(); 1385 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height 1386 1387 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) ); 1388 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); 1389 1390 toReturn = sal_True; 1391 } 1392 else if( nPart == PART_BUTTON_DOWN ) 1393 { 1394 w = aCtrlBoundRect.GetWidth(); 1395 if( w < 3+2*FOCUS_RING_WIDTH ) 1396 w = 3+2*FOCUS_RING_WIDTH; 1397 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height 1398 1399 x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH; 1400 y += FOCUS_RING_WIDTH; 1401 w = DROPDOWN_BUTTON_WIDTH; 1402 1403 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1404 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) ); 1405 1406 toReturn = true; 1407 } 1408 else if( nPart == PART_SUB_EDIT ) 1409 { 1410 w = aCtrlBoundRect.GetWidth(); 1411 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height 1412 1413 x += FOCUS_RING_WIDTH; 1414 x += 3; // add an offset for rounded borders 1415 y += 2; // don't draw into upper border 1416 y += FOCUS_RING_WIDTH; 1417 w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH; 1418 if( nType == CTRL_LISTBOX ) 1419 w -= 9; // HIG specifies 9 units distance between dropdown button area and content 1420 h -= 4; // don't draw into lower border 1421 1422 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1423 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) ); 1424 1425 toReturn = true; 1426 } 1427 } 1428 break; 1429 case CTRL_SPINBOX: 1430 if( nPart == PART_ENTIRE_CONTROL ) { 1431 w = aCtrlBoundRect.GetWidth(); 1432 if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH ) 1433 w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH; 1434 h = TEXT_EDIT_HEIGHT_NORMAL; 1435 1436 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) ); 1437 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); 1438 1439 toReturn = sal_True; 1440 } 1441 else if( nPart == PART_SUB_EDIT ) { 1442 w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH; 1443 h = TEXT_EDIT_HEIGHT_NORMAL; 1444 x += 4; // add an offset for rounded borders 1445 y += 2; // don't draw into upper border 1446 w -= 8; // offset for left and right rounded border 1447 h -= 4; // don't draw into upper or ower border 1448 1449 rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) ); 1450 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); 1451 1452 toReturn = sal_True; 1453 } 1454 else if( nPart == PART_BUTTON_UP ) { 1455 //aCtrlBoundRect.GetWidth() contains the width of the full control 1456 //ie the width of the textfield + button 1457 //x is the position of the left corner of the full control 1458 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ; 1459 y += FOCUS_RING_WIDTH - CLIP_FUZZ; 1460 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ; 1461 h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ; 1462 1463 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1464 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1465 1466 toReturn = sal_True; 1467 } 1468 else if( nPart == PART_BUTTON_DOWN ) { 1469 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ; 1470 y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ; 1471 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ; 1472 h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ; 1473 1474 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1475 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1476 1477 toReturn = sal_True; 1478 } 1479 break; 1480 case CTRL_FRAME: 1481 { 1482 sal_uInt16 nStyle = aValue.getNumericVal(); 1483 if( ( nPart == PART_BORDER ) && 1484 !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) ) 1485 { 1486 Rectangle aRect(aCtrlBoundRect); 1487 if( nStyle & FRAME_DRAW_DOUBLEIN ) 1488 { 1489 aRect.Left() += 1; 1490 aRect.Top() += 1; 1491 //rRect.Right() -= 1; 1492 //rRect.Bottom() -= 1; 1493 } 1494 else 1495 { 1496 aRect.Left() += 1; 1497 aRect.Top() += 1; 1498 aRect.Right() -= 1; 1499 aRect.Bottom() -= 1; 1500 } 1501 1502 rNativeContentRegion = aRect; 1503 rNativeBoundingRegion = aRect; 1504 1505 toReturn = sal_True; 1506 } 1507 } 1508 break; 1509 1510 case CTRL_MENUBAR: 1511 case CTRL_MENU_POPUP: 1512 { 1513 if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) { 1514 1515 w=10; 1516 h=10;//dimensions of the mark (10px font) 1517 1518 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1519 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1520 1521 toReturn = sal_True; 1522 } 1523 } 1524 break; 1525 1526 } 1527 1528 return toReturn; 1529 } 1530