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