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 #include "vcl/salnativewidgets.hxx" 25 #include "vcl/decoview.hxx" 26 #include "vcl/svapp.hxx" 27 #include "vcl/timer.hxx" 28 29 #include "aqua/salconst.h" 30 #include "aqua/salgdi.h" 31 #include "aqua/salnativewidgets.h" 32 #include "aqua/saldata.hxx" 33 #include "aqua/salframe.h" 34 35 #include "premac.h" 36 #include <Carbon/Carbon.h> 37 #include "postmac.h" 38 39 class AquaBlinker : public Timer 40 { 41 AquaSalFrame* mpFrame; 42 Rectangle maInvalidateRect; 43 44 AquaBlinker( AquaSalFrame* pFrame, const Rectangle& rRect ) 45 : mpFrame( pFrame ), maInvalidateRect( rRect ) 46 { 47 mpFrame->maBlinkers.push_back( this ); 48 } 49 50 public: 51 52 static void Blink( AquaSalFrame*, const Rectangle&, int nTimeout = 80 ); 53 54 virtual void Timeout() 55 { 56 Stop(); 57 if( AquaSalFrame::isAlive( mpFrame ) && mpFrame->mbShown ) 58 { 59 mpFrame->maBlinkers.remove( this ); 60 mpFrame->SendPaintEvent( &maInvalidateRect ); 61 } 62 delete this; 63 } 64 }; 65 66 void AquaBlinker::Blink( AquaSalFrame* pFrame, const Rectangle& rRect, int nTimeout ) 67 { 68 // prevent repeated paints from triggering themselves all the time 69 for( std::list< AquaBlinker* >::const_iterator it = pFrame->maBlinkers.begin(); 70 it != pFrame->maBlinkers.end(); ++it ) 71 { 72 if( (*it)->maInvalidateRect == rRect ) 73 return; 74 } 75 AquaBlinker* pNew = new AquaBlinker( pFrame, rRect ); 76 pNew->SetTimeout( nTimeout ); 77 pNew->Start(); 78 } 79 80 ControlPart ImplgetCounterPart( ControlPart nPart ) 81 { 82 ControlPart nCounterPart = 0; 83 switch (nPart) 84 { 85 case PART_BUTTON_UP: 86 nCounterPart = PART_BUTTON_DOWN; 87 break; 88 case PART_BUTTON_DOWN: 89 nCounterPart = PART_BUTTON_UP; 90 break; 91 case PART_BUTTON_LEFT: 92 nCounterPart = PART_BUTTON_RIGHT; 93 break; 94 case PART_BUTTON_RIGHT: 95 nCounterPart = PART_BUTTON_LEFT; 96 break; 97 } 98 return nCounterPart; 99 } 100 101 102 // Helper returns an HIRect 103 104 static HIRect ImplGetHIRectFromRectangle(Rectangle aRect) 105 { 106 HIRect aHIRect; 107 aHIRect.origin.x = static_cast<float>(aRect.Left()); 108 aHIRect.origin.y = static_cast<float>(aRect.Top()); 109 aHIRect.size.width = static_cast<float>(aRect.GetWidth()); 110 aHIRect.size.height = static_cast<float>(aRect.GetHeight()); 111 return aHIRect; 112 } 113 114 static ThemeButtonValue ImplGetButtonValue( ButtonValue aButtonValue ) 115 { 116 switch( aButtonValue ) 117 { 118 case BUTTONVALUE_ON: 119 return kThemeButtonOn; 120 break; 121 122 case BUTTONVALUE_OFF: 123 return kThemeButtonOff; 124 break; 125 126 case BUTTONVALUE_MIXED: 127 case BUTTONVALUE_DONTKNOW: 128 default: 129 return kThemeButtonMixed; 130 break; 131 } 132 } 133 134 // the scrollbar arrows disappeared in OSX>=10.7 135 #define SCROLL_BUTTON_HEIGHT 0 136 #define SCROLL_BUTTON_WIDTH 0 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*SCROLL_BUTTON_HEIGHT; 149 rResultRect.Bottom() = rResultRect.Top() + SCROLL_BUTTON_HEIGHT; 150 break; 151 152 case PART_BUTTON_DOWN: 153 rResultRect.Top() = rControlRect.Bottom() - SCROLL_BUTTON_HEIGHT; 154 break; 155 156 case PART_BUTTON_LEFT: 157 if( GetSalData()->mbIsScrollbarDoubleMax ) 158 rResultRect.Left() = rControlRect.Right() - 2*SCROLL_BUTTON_WIDTH; 159 rResultRect.Right() = rResultRect.Left() + SCROLL_BUTTON_WIDTH; 160 break; 161 162 case PART_BUTTON_RIGHT: 163 rResultRect.Left() = rControlRect.Right() - SCROLL_BUTTON_WIDTH; 164 break; 165 166 case PART_TRACK_HORZ_AREA: 167 rResultRect.Right() -= SCROLL_BUTTON_WIDTH + 1; 168 if( GetSalData()->mbIsScrollbarDoubleMax ) 169 rResultRect.Right() -= SCROLL_BUTTON_WIDTH; 170 else 171 rResultRect.Left() += SCROLL_BUTTON_WIDTH + 1; 172 break; 173 174 case PART_TRACK_VERT_AREA: 175 rResultRect.Bottom() -= SCROLL_BUTTON_HEIGHT + 1; 176 if( GetSalData()->mbIsScrollbarDoubleMax ) 177 rResultRect.Bottom() -= SCROLL_BUTTON_HEIGHT; 178 else 179 rResultRect.Top() += SCROLL_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 const bool bDrawActive = mpFrame ? ([mpFrame->getNSWindow() 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 const bool bDrawActive = mpFrame ? ([mpFrame->getNSWindow() 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 CGFloat aGrey[] = { 0.45, 0.45, 0.45, 1.0 }; 718 CGContextSetFillColor( mrContext, aGrey ); 719 CGContextBeginPath( mrContext ); 720 CGFloat x = rc.origin.x + rc.size.width; 721 CGFloat 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 const ScrollbarValue* pScrollbarVal = (aValue.getType() == CTRL_SCROLLBAR) ? static_cast<const ScrollbarValue*>(&aValue) : NULL; 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 const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue*>(&aValue) : NULL; 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 HIThemeButtonDrawInfo aSpinInfo; 1100 aSpinInfo.kind = kThemeIncDecButton; 1101 aSpinInfo.state = kThemeStateActive; 1102 if(nUpperState & CTRL_STATE_PRESSED) 1103 aSpinInfo.state = kThemeStatePressedUp; 1104 else if(nLowerState & CTRL_STATE_PRESSED) 1105 aSpinInfo.state = kThemeStatePressedDown; 1106 else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED)) 1107 aSpinInfo.state = kThemeStateInactive; 1108 else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER)) 1109 aSpinInfo.state = kThemeStateRollover; 1110 1111 Rectangle aSpinRect( pSpinButtonVal->maUpperRect ); 1112 aSpinRect.Union( pSpinButtonVal->maLowerRect ); 1113 HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect); 1114 1115 // FIXME: without this fuzz factor there is some unwanted clipping 1116 if( Application::GetSettings().GetLayoutRTL() ) 1117 buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ; 1118 else 1119 buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ; 1120 1121 switch( aValue.getTristateVal() ) 1122 { 1123 case BUTTONVALUE_ON: aSpinInfo.value = kThemeButtonOn; 1124 break; 1125 case BUTTONVALUE_OFF: aSpinInfo.value = kThemeButtonOff; 1126 break; 1127 case BUTTONVALUE_MIXED: 1128 case BUTTONVALUE_DONTKNOW: 1129 default: aSpinInfo.value = kThemeButtonMixed; 1130 break; 1131 } 1132 1133 aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) || 1134 ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ? 1135 kThemeAdornmentDefault : 1136 kThemeAdornmentNone; 1137 if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 )) 1138 aSpinInfo.adornment |= kThemeAdornmentFocus; 1139 1140 HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL ); 1141 } 1142 1143 bOK=true; 1144 } 1145 1146 } 1147 break; 1148 1149 case CTRL_FRAME: 1150 { 1151 sal_uInt16 nStyle = aValue.getNumericVal(); 1152 if( nPart == PART_BORDER ) { 1153 if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) ) 1154 { 1155 // #i84756# strange effects start to happen when HIThemeDrawFrame 1156 // meets the border of the window. These can be avoided by clipping 1157 // to the boundary of the frame 1158 if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 ) 1159 { 1160 CGMutablePathRef rPath = CGPathCreateMutable(); 1161 CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) ); 1162 1163 CGContextBeginPath( mrContext ); 1164 CGContextAddPath( mrContext, rPath ); 1165 CGContextClip( mrContext ); 1166 CGPathRelease( rPath ); 1167 } 1168 1169 HIThemeFrameDrawInfo aTextDrawInfo; 1170 aTextDrawInfo.version=0; 1171 aTextDrawInfo.kind=kHIThemeFrameListBox; 1172 aTextDrawInfo.state=kThemeStateActive; 1173 aTextDrawInfo.isFocused=false; 1174 1175 HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal); 1176 1177 bOK=true; 1178 } 1179 } 1180 } 1181 break; 1182 1183 case CTRL_LISTNET: 1184 { 1185 //do nothing as there isn't net for listviews on macos 1186 bOK=true; 1187 } 1188 break; 1189 1190 } 1191 1192 CGContextRestoreGState( mrContext ); 1193 1194 /* #i90291# in most cases invalidating the whole control region instead 1195 of just the unclipped part of it is sufficient (and probably faster). 1196 However for the window background we should not unnecessarily enlarge 1197 the really changed rectangle since the difference is usually quite high 1198 (the background is always drawn as a whole since we don't know anything 1199 about its possible contents) 1200 */ 1201 if( nType == CTRL_WINDOW_BACKGROUND ) 1202 { 1203 CGRect aRect = { { 0, 0 }, { 0, 0 } }; 1204 if( mxClipPath ) 1205 aRect = CGPathGetBoundingBox( mxClipPath ); 1206 if( aRect.size.width != 0 && aRect.size.height != 0 ) 1207 buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x), 1208 static_cast<long int>(aRect.origin.y) ), 1209 Size( static_cast<long int>(aRect.size.width), 1210 static_cast<long int>(aRect.size.height) ) ) ); 1211 } 1212 1213 RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() ); 1214 1215 return bOK; 1216 } 1217 1218 /* 1219 * DrawNativeControlText() 1220 * 1221 * OPTIONAL. Draws the requested text for the control described by nPart/nState. 1222 * Used if text not drawn by DrawNativeControl(). 1223 * 1224 * rControlRegion: The bounding region of the complete control in VCL frame coordinates. 1225 * aValue: An optional value (tristate/numerical/string) 1226 * aCaption: A caption or title string (like button text etc) 1227 */ 1228 sal_Bool AquaSalGraphics::drawNativeControlText( ControlType /*nType*/, ControlPart /*nPart*/, const Rectangle& /*rControlRegion*/, 1229 ControlState /*nState*/, const ImplControlValue& /*aValue*/, 1230 const rtl::OUString& ) 1231 { 1232 return( sal_False ); 1233 } 1234 1235 1236 /* 1237 * GetNativeControlRegion() 1238 * 1239 * If the return value is sal_True, rNativeBoundingRegion 1240 * contains the true bounding region covered by the control 1241 * including any adornment, while rNativeContentRegion contains the area 1242 * within the control that can be safely drawn into without drawing over 1243 * the borders of the control. 1244 * 1245 * rControlRegion: The bounding region of the control in VCL frame coordinates. 1246 * aValue: An optional value (tristate/numerical/string) 1247 * aCaption: A caption or title string (like button text etc) 1248 */ 1249 sal_Bool AquaSalGraphics::getNativeControlRegion( ControlType nType, ControlPart nPart, const Rectangle& rControlRegion, ControlState /*nState*/, 1250 const ImplControlValue& aValue, const rtl::OUString&, 1251 Rectangle &rNativeBoundingRegion, Rectangle &rNativeContentRegion ) 1252 1253 { 1254 sal_Bool toReturn = sal_False; 1255 1256 Rectangle aCtrlBoundRect( rControlRegion ); 1257 short x = aCtrlBoundRect.Left(); 1258 short y = aCtrlBoundRect.Top(); 1259 short w, h; 1260 1261 sal_uInt8 nBorderCleanup = 0; 1262 1263 switch (nType) 1264 { 1265 case CTRL_SLIDER: 1266 { 1267 if( nPart == PART_THUMB_HORZ ) 1268 { 1269 w = 19; // taken from HIG 1270 h = aCtrlBoundRect.GetHeight(); 1271 rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1272 toReturn = true; 1273 } 1274 else if( nPart == PART_THUMB_VERT ) 1275 { 1276 w = aCtrlBoundRect.GetWidth(); 1277 h = 18; // taken from HIG 1278 rNativeBoundingRegion = rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1279 toReturn = true; 1280 } 1281 } 1282 break; 1283 1284 case CTRL_SCROLLBAR: 1285 { 1286 Rectangle aRect; 1287 if( AquaGetScrollRect( /* m_nScreen */ nPart, aCtrlBoundRect, aRect ) ) 1288 { 1289 toReturn = sal_True; 1290 rNativeBoundingRegion = aRect; 1291 rNativeContentRegion = aRect; 1292 } 1293 } 1294 break; 1295 1296 case CTRL_PUSHBUTTON: 1297 case CTRL_RADIOBUTTON: 1298 case CTRL_CHECKBOX: 1299 { 1300 if ( nType == CTRL_PUSHBUTTON ) 1301 { 1302 w = aCtrlBoundRect.GetWidth(); 1303 h = aCtrlBoundRect.GetHeight(); 1304 } 1305 else 1306 { 1307 // checkbox and radio borders need cleanup after unchecking them 1308 nBorderCleanup = 4; 1309 1310 // TEXT_SEPARATOR to respect Aqua HIG 1311 w = BUTTON_WIDTH + TEXT_SEPARATOR; 1312 h = BUTTON_HEIGHT; 1313 1314 } 1315 1316 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h + nBorderCleanup) ); 1317 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1318 1319 toReturn = sal_True; 1320 } 1321 break; 1322 case CTRL_PROGRESS: 1323 { 1324 Rectangle aRect( aCtrlBoundRect ); 1325 if( aRect.GetHeight() < 16 ) 1326 aRect.Bottom() = aRect.Top() + 9; // values taken from HIG for medium progress 1327 else 1328 aRect.Bottom() = aRect.Top() + 15; // values taken from HIG for large progress 1329 rNativeBoundingRegion = aRect; 1330 rNativeContentRegion = aRect; 1331 toReturn = sal_True; 1332 } 1333 break; 1334 1335 case CTRL_INTROPROGRESS: 1336 { 1337 Rectangle aRect( aCtrlBoundRect ); 1338 aRect.Bottom() = aRect.Top() + INTRO_PROGRESS_HEIGHT; // values taken from HIG for medium progress 1339 rNativeBoundingRegion = aRect; 1340 rNativeContentRegion = aRect; 1341 toReturn = sal_True; 1342 } 1343 break; 1344 1345 case CTRL_TAB_ITEM: 1346 1347 w = aCtrlBoundRect.GetWidth() + 2*TAB_TEXT_OFFSET - 2*VCL_TAB_TEXT_OFFSET; 1348 1349 #ifdef OLD_TAB_STYLE 1350 h = TAB_HEIGHT_NORMAL; 1351 #else 1352 h = TAB_HEIGHT_NORMAL+2; 1353 #endif 1354 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1355 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1356 1357 toReturn = sal_True; 1358 1359 break; 1360 1361 case CTRL_EDITBOX: 1362 { 1363 w = aCtrlBoundRect.GetWidth(); 1364 if( w < 3+2*FOCUS_RING_WIDTH ) 1365 w = 3+2*FOCUS_RING_WIDTH; 1366 h = TEXT_EDIT_HEIGHT_NORMAL+2*FOCUS_RING_WIDTH; 1367 if( h < aCtrlBoundRect.GetHeight() ) 1368 h = aCtrlBoundRect.GetHeight(); 1369 1370 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*(FOCUS_RING_WIDTH+1), h-2*(FOCUS_RING_WIDTH+1) ) ); 1371 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1372 1373 toReturn = sal_True; 1374 } 1375 break; 1376 case CTRL_LISTBOX: 1377 case CTRL_COMBOBOX: 1378 { 1379 if( nPart == PART_ENTIRE_CONTROL ) 1380 { 1381 w = aCtrlBoundRect.GetWidth(); 1382 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height 1383 1384 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y+FOCUS_RING_WIDTH ), Size( w-2*FOCUS_RING_WIDTH, h ) ); 1385 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); 1386 1387 toReturn = sal_True; 1388 } 1389 else if( nPart == PART_BUTTON_DOWN ) 1390 { 1391 w = aCtrlBoundRect.GetWidth(); 1392 if( w < 3+2*FOCUS_RING_WIDTH ) 1393 w = 3+2*FOCUS_RING_WIDTH; 1394 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height 1395 1396 x += w-DROPDOWN_BUTTON_WIDTH - FOCUS_RING_WIDTH; 1397 y += FOCUS_RING_WIDTH; 1398 w = DROPDOWN_BUTTON_WIDTH; 1399 1400 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1401 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) ); 1402 1403 toReturn = true; 1404 } 1405 else if( nPart == PART_SUB_EDIT ) 1406 { 1407 w = aCtrlBoundRect.GetWidth(); 1408 h = COMBOBOX_HEIGHT_NORMAL;//listboxes and comboxes have the same height 1409 1410 x += FOCUS_RING_WIDTH; 1411 x += 3; // add an offset for rounded borders 1412 y += 2; // don't draw into upper border 1413 y += FOCUS_RING_WIDTH; 1414 w -= 3 + DROPDOWN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH; 1415 if( nType == CTRL_LISTBOX ) 1416 w -= 9; // HIG specifies 9 units distance between dropdown button area and content 1417 h -= 4; // don't draw into lower border 1418 1419 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1420 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w+FOCUS_RING_WIDTH, h+2*FOCUS_RING_WIDTH ) ); 1421 1422 toReturn = true; 1423 } 1424 } 1425 break; 1426 case CTRL_SPINBOX: 1427 if( nPart == PART_ENTIRE_CONTROL ) { 1428 w = aCtrlBoundRect.GetWidth(); 1429 if( w < 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH ) 1430 w = 3+2*FOCUS_RING_WIDTH+SPIN_BUTTON_SPACE+SPIN_BUTTON_WIDTH; 1431 h = TEXT_EDIT_HEIGHT_NORMAL; 1432 1433 rNativeContentRegion = Rectangle( Point( x+FOCUS_RING_WIDTH, y ), Size( w-2*FOCUS_RING_WIDTH, h ) ); 1434 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); 1435 1436 toReturn = sal_True; 1437 } 1438 else if( nPart == PART_SUB_EDIT ) { 1439 w = aCtrlBoundRect.GetWidth() - SPIN_BUTTON_SPACE - SPIN_BUTTON_WIDTH; 1440 h = TEXT_EDIT_HEIGHT_NORMAL; 1441 x += 4; // add an offset for rounded borders 1442 y += 2; // don't draw into upper border 1443 w -= 8; // offset for left and right rounded border 1444 h -= 4; // don't draw into upper or ower border 1445 1446 rNativeContentRegion = Rectangle( Point( x + FOCUS_RING_WIDTH, y + FOCUS_RING_WIDTH ), Size( w - 2* FOCUS_RING_WIDTH, h ) ); 1447 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h+2*FOCUS_RING_WIDTH ) ); 1448 1449 toReturn = sal_True; 1450 } 1451 else if( nPart == PART_BUTTON_UP ) { 1452 //aCtrlBoundRect.GetWidth() contains the width of the full control 1453 //ie the width of the textfield + button 1454 //x is the position of the left corner of the full control 1455 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ; 1456 y += FOCUS_RING_WIDTH - CLIP_FUZZ; 1457 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ; 1458 h = SPIN_UPPER_BUTTON_HEIGHT + 2*CLIP_FUZZ; 1459 1460 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1461 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1462 1463 toReturn = sal_True; 1464 } 1465 else if( nPart == PART_BUTTON_DOWN ) { 1466 x += aCtrlBoundRect.GetWidth() - SPIN_BUTTON_WIDTH - SPIN_BUTTON_SPACE - CLIP_FUZZ; 1467 y += SPIN_UPPER_BUTTON_HEIGHT + FOCUS_RING_WIDTH - CLIP_FUZZ; 1468 w = SPIN_BUTTON_WIDTH + 2*CLIP_FUZZ; 1469 h = SPIN_LOWER_BUTTON_HEIGHT + 2*CLIP_FUZZ; 1470 1471 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1472 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1473 1474 toReturn = sal_True; 1475 } 1476 break; 1477 case CTRL_FRAME: 1478 { 1479 sal_uInt16 nStyle = aValue.getNumericVal(); 1480 if( ( nPart == PART_BORDER ) && 1481 !( nStyle & (FRAME_DRAW_MENU | FRAME_DRAW_WINDOWBORDER | FRAME_DRAW_BORDERWINDOWBORDER) ) ) 1482 { 1483 Rectangle aRect(aCtrlBoundRect); 1484 if( nStyle & FRAME_DRAW_DOUBLEIN ) 1485 { 1486 aRect.Left() += 1; 1487 aRect.Top() += 1; 1488 //rRect.Right() -= 1; 1489 //rRect.Bottom() -= 1; 1490 } 1491 else 1492 { 1493 aRect.Left() += 1; 1494 aRect.Top() += 1; 1495 aRect.Right() -= 1; 1496 aRect.Bottom() -= 1; 1497 } 1498 1499 rNativeContentRegion = aRect; 1500 rNativeBoundingRegion = aRect; 1501 1502 toReturn = sal_True; 1503 } 1504 } 1505 break; 1506 1507 case CTRL_MENUBAR: 1508 case CTRL_MENU_POPUP: 1509 { 1510 if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) { 1511 1512 w=10; 1513 h=10;//dimensions of the mark (10px font) 1514 1515 rNativeContentRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1516 rNativeBoundingRegion = Rectangle( Point( x, y ), Size( w, h ) ); 1517 1518 toReturn = sal_True; 1519 } 1520 } 1521 break; 1522 1523 } 1524 1525 return toReturn; 1526 } 1527