sal_Bool AquaSalGraphics::drawNativeControl()

in main/vcl/aqua/source/gdi/salnativewidgets.cxx [473:1216]


sal_Bool AquaSalGraphics::drawNativeControl(ControlType nType,
					ControlPart nPart,
					const Rectangle& rControlRegion,
					ControlState nState,
					const ImplControlValue& aValue,
					const rtl::OUString& )
{
    sal_Bool bOK = sal_False;

    if( ! CheckContext() )
        return false;

    CGContextSaveGState( mrContext );

    Rectangle buttonRect = rControlRegion;
	HIRect rc = ImplGetHIRectFromRectangle(buttonRect);

    /** Scrollbar parts code equivalent **
    PART_BUTTON_UP 101
    PART_BUTTON_DOWN 102
	PART_THUMB_VERT 211
	PART_TRACK_VERT_UPPER 201
	PART_TRACK_VERT_LOWER 203

	PART_DRAW_BACKGROUND_HORZ 1000
	PART_DRAW_BACKGROUND_VERT 1001
    **/

    switch( nType )
    {

    case  CTRL_COMBOBOX:
        if ( nPart == HAS_BACKGROUND_TEXTURE ||
             nPart == PART_ENTIRE_CONTROL )
        {
            HIThemeButtonDrawInfo aComboInfo;
            aComboInfo.version = 0;
            aComboInfo.kind = kThemeComboBox;
            aComboInfo.state = getState( nState );
            aComboInfo.value = kThemeButtonOn;
            aComboInfo.adornment = kThemeAdornmentNone;

            if( (nState & CTRL_STATE_FOCUSED) != 0 )
                aComboInfo.adornment |= kThemeAdornmentFocus;

            HIThemeDrawButton(&rc, &aComboInfo, mrContext, kHIThemeOrientationNormal,&rc);
            bOK = true;
        }
        break;

    case CTRL_FIXEDBORDER:
    case CTRL_TOOLBAR:
        {
            HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
            aMenuItemDrawInfo.version = 0;
            aMenuItemDrawInfo.state = kThemeMenuActive;
            aMenuItemDrawInfo.itemType = kThemeMenuItemHierBackground;
            HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,NULL);
            bOK = true;
        }
        break;

        case CTRL_WINDOW_BACKGROUND:
        {
            HIThemeBackgroundDrawInfo aThemeBackgroundInfo;
            aThemeBackgroundInfo.version = 0;
            aThemeBackgroundInfo.state = getState( nState );
            aThemeBackgroundInfo.kind = kThemeBrushDialogBackgroundActive;
            // FIXME: without this magical offset there is a 2 pixel black border on the right and bottom
            rc.size.width += 2;
            rc.size.height += 2;

            HIThemeApplyBackground( &rc, &aThemeBackgroundInfo, mrContext, kHIThemeOrientationNormal);
            CGContextFillRect( mrContext, rc );
            bOK = true;
        }
        break;

    case CTRL_MENUBAR:
    case CTRL_MENU_POPUP:
        {
            if ((nPart == PART_ENTIRE_CONTROL) || (nPart == PART_MENU_ITEM )|| (nPart == HAS_BACKGROUND_TEXTURE ))
            {
                // FIXME: without this magical offset there is a 2 pixel black border on the right
                rc.size.width += 2;

                HIThemeMenuDrawInfo aMenuInfo;
                aMenuInfo.version = 0;
                aMenuInfo.menuType = kThemeMenuTypePullDown;

                HIThemeMenuItemDrawInfo aMenuItemDrawInfo;
                // the Aqua grey theme when the item is selected is drawn here.
                aMenuItemDrawInfo.itemType = kThemeMenuItemPlain;

                if ((nPart == PART_MENU_ITEM ) && (nState & CTRL_STATE_SELECTED))
                {
                    // the blue theme when the item is selected is drawn here.
                    aMenuItemDrawInfo.state = kThemeMenuSelected;
                }
                else
                {
                    // normal color for non selected item
                    aMenuItemDrawInfo.state = kThemeMenuActive;
                }

                // repaints the background of the pull down menu
                HIThemeDrawMenuBackground(&rc,&aMenuInfo,mrContext,kHIThemeOrientationNormal);

                // repaints the item either blue (selected) and/or Aqua grey (active only)
                HIThemeDrawMenuItem(&rc,&rc,&aMenuItemDrawInfo,mrContext,kHIThemeOrientationNormal,&rc);

                bOK = true;
            }
            else if(( nPart == PART_MENU_ITEM_CHECK_MARK )||( nPart == PART_MENU_ITEM_RADIO_MARK )) {
                if( nState & CTRL_STATE_PRESSED ) {//checked, else it is not displayed (see vcl/source/window/menu.cxx)
                    HIThemeTextInfo aTextInfo;
                    aTextInfo.version = 0;
                    aTextInfo.state = ((nState & CTRL_STATE_ENABLED)==0) ? kThemeStateInactive: kThemeStateActive; 
                    aTextInfo.fontID = kThemeMenuItemMarkFont;
                    aTextInfo.horizontalFlushness=kHIThemeTextHorizontalFlushCenter;
                    aTextInfo.verticalFlushness=kHIThemeTextVerticalFlushTop;
                    aTextInfo.options=kHIThemeTextBoxOptionNone;
                    aTextInfo.truncationPosition=kHIThemeTextTruncationNone;
                    //aTextInfo.truncationMaxLines unused because of kHIThemeTextTruncationNone
                    
                    if( nState & CTRL_STATE_SELECTED) aTextInfo.state = kThemeStatePressed; //item highlighted
                    
                    UniChar mark=( nPart == PART_MENU_ITEM_CHECK_MARK ) ? kCheckUnicode: kBulletUnicode;//0x2713;
                    CFStringRef cfString = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, &mark, 1, kCFAllocatorNull);
                    HIThemeDrawTextBox(cfString, &rc, &aTextInfo, mrContext, kHIThemeOrientationNormal); 
					if (cfString)
						CFRelease(cfString);
                    
                    bOK = true;
                }
            }
        }
        break;

    case CTRL_PUSHBUTTON:
        {
            // [ FIXME] : instead of use a value, vcl can retrieve corect values on the fly (to be implemented)
            const int PB_Mini_Height = 15;
            const int PB_Norm_Height = 21;

            HIThemeButtonDrawInfo aPushInfo;
            aPushInfo.version = 0;

            // no animation
            aPushInfo.animation.time.start = 0;
            aPushInfo.animation.time.current = 0;
            PushButtonValue* pPBVal = aValue.getType() == CTRL_PUSHBUTTON ? (PushButtonValue*)&aValue : NULL;
            int nPaintHeight = static_cast<int>(rc.size.height);
            
            if( pPBVal && pPBVal->mbBevelButton )
            {
                aPushInfo.kind = kThemeRoundedBevelButton;
            }
            else if( rc.size.height <= PB_Norm_Height )
            {
                aPushInfo.kind = kThemePushButtonMini;
                nPaintHeight = PB_Mini_Height;
            }
            else if( pPBVal->mbSingleLine || rc.size.height < (PB_Norm_Height + PB_Norm_Height/2) )
            {
                aPushInfo.kind = kThemePushButtonNormal;
                nPaintHeight = PB_Norm_Height;
                
                // avoid clipping when focused
                rc.origin.x += FOCUS_RING_WIDTH/2;
                rc.size.width -= FOCUS_RING_WIDTH;

                if( (nState & CTRL_STATE_DEFAULT) != 0 )
                {
                    AquaBlinker::Blink( mpFrame, buttonRect );
                    // show correct animation phase
                    aPushInfo.animation.time.current = CFAbsoluteTimeGetCurrent();
                }
            }
            else
                aPushInfo.kind = kThemeBevelButton;

            // translate the origin for controls with fixed paint height
            // so content ends up somewhere sensible
            int delta_y = static_cast<int>(rc.size.height) - nPaintHeight;
            rc.origin.y += delta_y/2;

            aPushInfo.state = getState( nState );
            aPushInfo.value = ImplGetButtonValue( aValue.getTristateVal() );

            aPushInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
            kThemeAdornmentDefault :
            kThemeAdornmentNone;
            if( (nState & CTRL_STATE_FOCUSED) != 0 )
                aPushInfo.adornment |= kThemeAdornmentFocus;

            HIThemeDrawButton( &rc, &aPushInfo, mrContext, kHIThemeOrientationNormal, NULL );
            bOK = true;
        }
        break;

    case CTRL_RADIOBUTTON:
    case CTRL_CHECKBOX:
        {
            HIThemeButtonDrawInfo aInfo;
            aInfo.version = 0;
            switch( nType )
            {
            case CTRL_RADIOBUTTON: if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeRadioButton;
                                    else aInfo.kind = kThemeSmallRadioButton;
                break;
            case CTRL_CHECKBOX:   if(rc.size.width >= BUTTON_HEIGHT) aInfo.kind = kThemeCheckBox;
                                    else aInfo.kind = kThemeSmallCheckBox;
                break;
            }

            aInfo.state = getState( nState );

            ButtonValue aButtonValue = aValue.getTristateVal();
            aInfo.value = ImplGetButtonValue( aButtonValue );

            aInfo.adornment = (( nState & CTRL_STATE_DEFAULT ) != 0) ?
            kThemeAdornmentDefault :
            kThemeAdornmentNone;
            if( (nState & CTRL_STATE_FOCUSED) != 0 )
                aInfo.adornment |= kThemeAdornmentFocus;
            HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
            bOK = true;
        }
        break;
        
    case CTRL_LISTNODE:
        {
            ButtonValue aButtonValue = aValue.getTristateVal();
    
            if( Application::GetSettings().GetLayoutRTL() && aButtonValue == BUTTONVALUE_OFF )
            {
                // FIXME: a value of kThemeDisclosureLeft
                // should draw a theme compliant left disclosure triangle
                // sadly this does not seem to work, so we'll draw a left
                // grey equilateral triangle here ourselves.
                // Perhaps some other HIThemeButtonDrawInfo setting would do the trick ?
                
                CGContextSetShouldAntialias( mrContext, true );
                CGFloat aGrey[] = { 0.45, 0.45, 0.45, 1.0 };
                CGContextSetFillColor( mrContext, aGrey );
                CGContextBeginPath( mrContext );
                CGFloat x = rc.origin.x + rc.size.width;
                CGFloat y = rc.origin.y;
                CGContextMoveToPoint( mrContext, x, y );
                y += rc.size.height;
                CGContextAddLineToPoint( mrContext, x, y );
                x -= rc.size.height * 0.866; // cos( 30 degree ) is approx. 0.866
                y -= rc.size.height/2;
                CGContextAddLineToPoint( mrContext, x, y );
                CGContextDrawPath( mrContext, kCGPathEOFill );
            }
            else
            {
                HIThemeButtonDrawInfo aInfo;
                aInfo.version = 0;
                aInfo.kind = kThemeDisclosureTriangle;
                aInfo.value = kThemeDisclosureRight;
                aInfo.state = getState( nState );
    
                aInfo.adornment = kThemeAdornmentNone;
                
                switch( aButtonValue ) {
                    case BUTTONVALUE_ON: aInfo.value = kThemeDisclosureDown;//expanded
                        break;
                    case BUTTONVALUE_OFF:
                        // FIXME: this should have drawn a theme compliant disclosure triangle
                        // (see above)
                        if( Application::GetSettings().GetLayoutRTL() )
                        {
                            aInfo.value = kThemeDisclosureLeft;//collapsed, RTL
                        }
                        break;
                    case BUTTONVALUE_DONTKNOW: //what to do?
                    default:
                        break;
                }
                
                HIThemeDrawButton( &rc, &aInfo, mrContext, kHIThemeOrientationNormal, NULL );
            }
            bOK = true;
        }
        break;
        
    case CTRL_PROGRESS:
    case CTRL_INTROPROGRESS:
        {
            long nProgressWidth = aValue.getNumericVal();
            HIThemeTrackDrawInfo aTrackInfo;
            aTrackInfo.version              = 0;
            aTrackInfo.kind                 = (rc.size.height > 10) ? kThemeProgressBarLarge : kThemeProgressBarMedium;
            aTrackInfo.bounds               = rc;
            aTrackInfo.min                  = 0;
            aTrackInfo.max                  = static_cast<SInt32>(rc.size.width);
            aTrackInfo.value                = nProgressWidth;
            aTrackInfo.reserved             = 0;
            aTrackInfo.bounds.origin.y     -= 2; // FIXME: magic for shadow
            aTrackInfo.bounds.size.width   -= 2; // FIXME: magic for shadow
            aTrackInfo.attributes           = kThemeTrackHorizontal;
            if( Application::GetSettings().GetLayoutRTL() )
                aTrackInfo.attributes      |= kThemeTrackRightToLeft;
            aTrackInfo.enableState          = getTrackState( nState );
            // the intro bitmap never gets key anyway; we want to draw that enabled
            if( nType == CTRL_INTROPROGRESS )
                aTrackInfo.enableState          = kThemeTrackActive;
            aTrackInfo.filler1              = 0;
            aTrackInfo.trackInfo.progress.phase   = static_cast<UInt8>(CFAbsoluteTimeGetCurrent()*10.0);
            
            HIThemeDrawTrack( &aTrackInfo, NULL, mrContext, kHIThemeOrientationNormal );
            bOK = true;
        }
        break;
        
    case CTRL_SLIDER:
        {
            SliderValue* pSLVal = (SliderValue*)&aValue;

            HIThemeTrackDrawInfo aTrackDraw;
            aTrackDraw.kind = kThemeSliderMedium;
            if( nPart == PART_TRACK_HORZ_AREA || nPart == PART_TRACK_VERT_AREA )
            {
                aTrackDraw.bounds = rc;
                aTrackDraw.min   = pSLVal->mnMin;
                aTrackDraw.max   = pSLVal->mnMax;
                aTrackDraw.value = pSLVal->mnCur;
                aTrackDraw.reserved = 0;
                aTrackDraw.attributes = kThemeTrackShowThumb;
                if( nPart == PART_TRACK_HORZ_AREA )
                    aTrackDraw.attributes |= kThemeTrackHorizontal;
                aTrackDraw.enableState = (nState & CTRL_STATE_ENABLED)
                                         ? kThemeTrackActive : kThemeTrackInactive;

                SliderTrackInfo aSlideInfo;
                aSlideInfo.thumbDir = kThemeThumbUpward;
                aSlideInfo.pressState = 0;
                aTrackDraw.trackInfo.slider = aSlideInfo;

                HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
                bOK = true;
            }
        }
        break;

    case CTRL_SCROLLBAR:
        {
            const ScrollbarValue* pScrollbarVal = (aValue.getType() == CTRL_SCROLLBAR) ? static_cast<const ScrollbarValue*>(&aValue) : NULL;

            if( nPart == PART_DRAW_BACKGROUND_VERT ||
                nPart == PART_DRAW_BACKGROUND_HORZ )
            {
                HIThemeTrackDrawInfo aTrackDraw;
                aTrackDraw.kind = kThemeMediumScrollBar;
                // FIXME: the scrollbar length must be adjusted
                if (nPart == PART_DRAW_BACKGROUND_VERT)
                    rc.size.height += 2;
                else
                    rc.size.width += 2;

                aTrackDraw.bounds = rc;
                aTrackDraw.min = pScrollbarVal->mnMin;
                aTrackDraw.max = pScrollbarVal->mnMax - pScrollbarVal->mnVisibleSize;
                aTrackDraw.value = pScrollbarVal->mnCur;
                aTrackDraw.reserved = 0;
                aTrackDraw.attributes = kThemeTrackShowThumb;
                if( nPart == PART_DRAW_BACKGROUND_HORZ )
                    aTrackDraw.attributes |= kThemeTrackHorizontal;
                aTrackDraw.enableState = getTrackState( nState );

                ScrollBarTrackInfo aScrollInfo;
                aScrollInfo.viewsize = pScrollbarVal->mnVisibleSize;
                aScrollInfo.pressState = 0;

                if ( pScrollbarVal->mnButton1State & CTRL_STATE_ENABLED )
                {
                    if ( pScrollbarVal->mnButton1State & CTRL_STATE_PRESSED )
                        aScrollInfo.pressState = kThemeTopOutsideArrowPressed;
                }

                if ( pScrollbarVal->mnButton2State & CTRL_STATE_ENABLED )
                {
                    if ( pScrollbarVal->mnButton2State & CTRL_STATE_PRESSED )
                        aScrollInfo.pressState = kThemeBottomOutsideArrowPressed;
                }

                if ( pScrollbarVal->mnThumbState & CTRL_STATE_ENABLED )
                {
                    if ( pScrollbarVal->mnThumbState & CTRL_STATE_PRESSED )
                        aScrollInfo.pressState = kThemeThumbPressed;
                }

                aTrackDraw.trackInfo.scrollbar = aScrollInfo;

                HIThemeDrawTrack( &aTrackDraw, NULL, mrContext, kHIThemeOrientationNormal );
                bOK = true;
            }
        }
        break;
        
//#define OLD_TAB_STYLE    
#ifdef OLD_TAB_STYLE
    case CTRL_TAB_PANE:
        {
            HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
            aTabPaneDrawInfo.version = 0;
            aTabPaneDrawInfo.state = kThemeStateActive;
            aTabPaneDrawInfo.direction=kThemeTabNorth;
            aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
            
            //the border is outside the rect rc for Carbon
            //but for VCL it should be inside
            rc.origin.x+=1;
            rc.size.width-=2;
            
            HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
            bOK = true;
        }
        break;
        
    case CTRL_TAB_ITEM:
        {
            HIThemeTabDrawInfo aTabItemDrawInfo;
            aTabItemDrawInfo.version=0;
            aTabItemDrawInfo.style=kThemeTabNonFront;
            aTabItemDrawInfo.direction=kThemeTabNorth;
            aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
            aTabItemDrawInfo.adornment=kHIThemeTabAdornmentNone;
            
            if(nState & CTRL_STATE_SELECTED) {
                aTabItemDrawInfo.style=kThemeTabFront;
            }
            if(nState & CTRL_STATE_FOCUSED) {
                aTabItemDrawInfo.adornment=kHIThemeTabAdornmentFocus;
            }
            
            /*if(rc.size.height>=TAB_HEIGHT_NORMAL) rc.size.height=TAB_HEIGHT_NORMAL;
            else if(rc.size.height>=TAB_HEIGHT_SMALL) rc.size.height=TAB_HEIGHT_SMALL;
            else rc.size.height=TAB_HEIGHT_MINI;*/
            //now we only use the default size
            rc.size.height=TAB_HEIGHT_NORMAL;
            
            HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
            
            bOK=true;
        }
        break;    
#else
    case CTRL_TAB_PANE:
        {
            HIThemeTabPaneDrawInfo aTabPaneDrawInfo;
            aTabPaneDrawInfo.version = 1;
            aTabPaneDrawInfo.state = kThemeStateActive;
            aTabPaneDrawInfo.direction=kThemeTabNorth;
            aTabPaneDrawInfo.size=kHIThemeTabSizeNormal;
            aTabPaneDrawInfo.kind=kHIThemeTabKindNormal;
            
            //the border is outside the rect rc for Carbon
            //but for VCL it should be inside
            rc.origin.x+=1;
            rc.origin.y-=TAB_HEIGHT_NORMAL/2;
            rc.size.height+=TAB_HEIGHT_NORMAL/2;
            rc.size.width-=2;
            
            HIThemeDrawTabPane(&rc, &aTabPaneDrawInfo, mrContext, kHIThemeOrientationNormal);
            
            bOK = true;
        }
        break;
        
    case CTRL_TAB_ITEM:
        {
            HIThemeTabDrawInfo aTabItemDrawInfo;
            aTabItemDrawInfo.version=1;
            aTabItemDrawInfo.style=kThemeTabNonFront;
            aTabItemDrawInfo.direction=kThemeTabNorth;
            aTabItemDrawInfo.size=kHIThemeTabSizeNormal;
            aTabItemDrawInfo.adornment=kHIThemeTabAdornmentTrailingSeparator;
            //State 
            if(nState & CTRL_STATE_SELECTED) {
                aTabItemDrawInfo.style=kThemeTabFront;
            }
            if(nState & CTRL_STATE_FOCUSED) {
                aTabItemDrawInfo.adornment|=kHIThemeTabAdornmentFocus;
            }
            
            //first, last or middle tab
            aTabItemDrawInfo.position=kHIThemeTabPositionMiddle;
            
            TabitemValue* pTabValue = (TabitemValue *) &aValue;
            unsigned int nAlignment = pTabValue->mnAlignment;
            //TABITEM_LEFTALIGNED (and TABITEM_RIGHTALIGNED) for the leftmost (or rightmost) tab
            //when there are several lines of tabs because there is only one first tab and one 
            //last tab and TABITEM_FIRST_IN_GROUP (and TABITEM_LAST_IN_GROUP) because when the 
            //line width is different from window width, there may not be TABITEM_RIGHTALIGNED
            if( ( (nAlignment & TABITEM_LEFTALIGNED)&&(nAlignment & TABITEM_RIGHTALIGNED) ) ||
                ( (nAlignment & TABITEM_FIRST_IN_GROUP)&&(nAlignment & TABITEM_LAST_IN_GROUP) )
               ) //tab alone
                aTabItemDrawInfo.position=kHIThemeTabPositionOnly;
            else if((nAlignment & TABITEM_LEFTALIGNED)||(nAlignment & TABITEM_FIRST_IN_GROUP))
                aTabItemDrawInfo.position=kHIThemeTabPositionFirst;
            else if((nAlignment & TABITEM_RIGHTALIGNED)||(nAlignment & TABITEM_LAST_IN_GROUP)) 
                aTabItemDrawInfo.position=kHIThemeTabPositionLast;
            
            //support for RTL
            //see issue 79748
            if( Application::GetSettings().GetLayoutRTL() ) {
                if( aTabItemDrawInfo.position == kHIThemeTabPositionFirst ) 
                        aTabItemDrawInfo.position = kHIThemeTabPositionLast;
                else if( aTabItemDrawInfo.position == kHIThemeTabPositionLast ) 
                        aTabItemDrawInfo.position = kHIThemeTabPositionFirst;
            }
            
            rc.size.width+=2;//because VCL has 2 empty pixels between 2 tabs
            rc.origin.x-=1;
            
            HIThemeDrawTab(&rc, &aTabItemDrawInfo, mrContext, kHIThemeOrientationNormal, &rc );
            
            bOK=true;
        }
        break; 
#endif

    case  CTRL_LISTBOX:
        switch( nPart)
        {
            case PART_ENTIRE_CONTROL:
            case PART_BUTTON_DOWN:
            {
                HIThemeButtonDrawInfo aListInfo;
                aListInfo.version = 0;
                aListInfo.kind = kThemePopupButton;
                aListInfo.state = getState( nState );//kThemeStateInactive -> greyed
                aListInfo.value = kThemeButtonOn;

                aListInfo.adornment = kThemeAdornmentDefault;
                if( (nState & CTRL_STATE_FOCUSED) != 0 )
                    aListInfo.adornment |= kThemeAdornmentFocus;
                
                HIThemeDrawButton(&rc, &aListInfo, mrContext, kHIThemeOrientationNormal,&rc);
                bOK = true;
                break;
            }
            case PART_WINDOW:
            {
                HIThemeFrameDrawInfo aTextDrawInfo;
                aTextDrawInfo.version=0;
                aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
                aTextDrawInfo.state=getState( nState );
                aTextDrawInfo.isFocused=false;
                
                rc.size.width+=1;//else there's a white space because aqua theme hasn't a 3D border
                rc.size.height+=1;
                HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
                
                if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
                
                bOK=true;
                break;
            }
        }
        break;
        
    case CTRL_EDITBOX:
    case CTRL_MULTILINE_EDITBOX:
        {
            HIThemeFrameDrawInfo aTextDrawInfo;
            aTextDrawInfo.version=0;
            aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
            aTextDrawInfo.state=getState( nState );
            aTextDrawInfo.isFocused=false;
            
            rc.size.width  += 1; // else there may be a white space because aqua theme hasn't a 3D border
            // change rc so that the frame will encompass only the content region
            // see counterpart in GetNativeControlRegion
            rc.size.width  += 2; 
            rc.size.height += 2;

            //CGContextSetFillColorWithColor
            CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
            //fill a white background, because drawFrame only draws the border

            HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
            
            if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
            
            bOK=true;
        }
        break;
        
    case CTRL_SPINBOX:
        {
            if(nPart == PART_ENTIRE_CONTROL)
            {
                //text field:
                HIThemeFrameDrawInfo aTextDrawInfo;
                aTextDrawInfo.version=0;
                aTextDrawInfo.kind=kHIThemeFrameTextFieldSquare;
                aTextDrawInfo.state=getState( nState );
                aTextDrawInfo.isFocused=false;
                
                //rc.size.width contains the full size of the spinbox ie textfield + button
                //so we remove the button width and the space between the button and the textfield
                rc.size.width -= SPIN_BUTTON_SPACE + SPIN_BUTTON_WIDTH + 2*FOCUS_RING_WIDTH;
                rc.origin.x += FOCUS_RING_WIDTH;
                rc.origin.y += FOCUS_RING_WIDTH;

                //CGContextSetFillColorWithColor
                CGContextFillRect (mrContext, CGRectMake(rc.origin.x, rc.origin.y, rc.size.width, rc.size.height));
                //fill a white background, because drawFrame only draws the border

                HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
                
                if(nState & CTRL_STATE_FOCUSED) HIThemeDrawFocusRect(&rc, true, mrContext, kHIThemeOrientationNormal);
                
                //buttons:
                const SpinbuttonValue* pSpinButtonVal = (aValue.getType() == CTRL_SPINBUTTONS) ? static_cast<const SpinbuttonValue*>(&aValue) : NULL;
                ControlState nUpperState = CTRL_STATE_ENABLED;//state of the upper button
                ControlState nLowerState = CTRL_STATE_ENABLED;//and of the lower button
                if(pSpinButtonVal) {//pSpinButtonVal is sometimes null
                    nUpperState = (ControlState) pSpinButtonVal->mnUpperState;
                    nLowerState = (ControlState) pSpinButtonVal->mnLowerState;

                    HIThemeButtonDrawInfo aSpinInfo;
                    aSpinInfo.kind = kThemeIncDecButton;
                    aSpinInfo.state = kThemeStateActive;
                    if(nUpperState & CTRL_STATE_PRESSED)
                        aSpinInfo.state = kThemeStatePressedUp;
                    else if(nLowerState & CTRL_STATE_PRESSED)
                        aSpinInfo.state = kThemeStatePressedDown;
                    else if((nUpperState & ~CTRL_STATE_ENABLED)||(nLowerState & ~CTRL_STATE_ENABLED))
                        aSpinInfo.state = kThemeStateInactive;
                    else if((nUpperState & CTRL_STATE_ROLLOVER)||(nLowerState & CTRL_STATE_ROLLOVER))
                        aSpinInfo.state = kThemeStateRollover;
                
                    Rectangle aSpinRect( pSpinButtonVal->maUpperRect );
                    aSpinRect.Union( pSpinButtonVal->maLowerRect );
                    HIRect buttonRc = ImplGetHIRectFromRectangle(aSpinRect);
                    
                    // FIXME: without this fuzz factor there is some unwanted clipping
                    if( Application::GetSettings().GetLayoutRTL() )
                        buttonRc.origin.x -= FOCUS_RING_WIDTH - CLIP_FUZZ;
                    else
                        buttonRc.origin.x += FOCUS_RING_WIDTH + CLIP_FUZZ;
                    
                    switch( aValue.getTristateVal() )
                    {
                        case BUTTONVALUE_ON:        aSpinInfo.value = kThemeButtonOn;
                                                    break;
                        case BUTTONVALUE_OFF:       aSpinInfo.value = kThemeButtonOff;
                                                    break;
                        case BUTTONVALUE_MIXED:
                        case BUTTONVALUE_DONTKNOW: 
                        default:                    aSpinInfo.value = kThemeButtonMixed;
                                                    break;
                    }
                    
                    aSpinInfo.adornment = ( ((nUpperState & CTRL_STATE_DEFAULT) != 0 ) ||
                                            ((nLowerState & CTRL_STATE_DEFAULT) != 0 )) ?
                                       kThemeAdornmentDefault : 
                                       kThemeAdornmentNone;
                    if( ((nUpperState & CTRL_STATE_FOCUSED) != 0 ) || ((nLowerState & CTRL_STATE_FOCUSED) != 0 ))
                        aSpinInfo.adornment |= kThemeAdornmentFocus;
                    
                    HIThemeDrawButton( &buttonRc, &aSpinInfo, mrContext, kHIThemeOrientationNormal, NULL );
                }
                
                bOK=true;
            }
            
        }
        break;
        
    case CTRL_FRAME:
        {
            sal_uInt16 nStyle = aValue.getNumericVal();
            if( nPart == PART_BORDER ) {
                if(!( nStyle & FRAME_DRAW_MENU ) && !(nStyle & FRAME_DRAW_WINDOWBORDER) )
                {
                    // #i84756# strange effects start to happen when HIThemeDrawFrame
                    // meets the border of the window. These can be avoided by clipping
                    // to the boundary of the frame
                    if( rc.origin.y + rc.size.height >= mpFrame->maGeometry.nHeight-3 )
                    {
                        CGMutablePathRef rPath = CGPathCreateMutable();
                        CGPathAddRect( rPath, NULL, CGRectMake( 0, 0, mpFrame->maGeometry.nWidth-1, mpFrame->maGeometry.nHeight-1 ) );
    
                        CGContextBeginPath( mrContext );
                        CGContextAddPath( mrContext, rPath );
                        CGContextClip( mrContext );                    
                        CGPathRelease( rPath );
                    }
                    
                    HIThemeFrameDrawInfo aTextDrawInfo;
                    aTextDrawInfo.version=0;
                    aTextDrawInfo.kind=kHIThemeFrameListBox;
                    aTextDrawInfo.state=kThemeStateActive;
                    aTextDrawInfo.isFocused=false;
                    
                    HIThemeDrawFrame(&rc, &aTextDrawInfo, mrContext, kHIThemeOrientationNormal);
                    
                    bOK=true;
                }
            }
        }
        break;
    
    case CTRL_LISTNET:
        {
           //do nothing as there isn't net for listviews on macos
            bOK=true;
        }
        break;
        
    }

    CGContextRestoreGState( mrContext );
    
    /* #i90291# in most cases invalidating the whole control region instead
       of just the unclipped part of it is sufficient (and probably faster).
       However for the window background we should not unnecessarily enlarge
       the really changed rectangle since the difference is usually quite high
       (the background is always drawn as a whole since we don't know anything
       about its possible contents)
    */
    if( nType == CTRL_WINDOW_BACKGROUND )
    {
        CGRect aRect = { { 0, 0 }, { 0, 0 } };
        if( mxClipPath )
            aRect = CGPathGetBoundingBox( mxClipPath );
        if( aRect.size.width != 0 && aRect.size.height != 0 )
            buttonRect.Intersection( Rectangle( Point( static_cast<long int>(aRect.origin.x),
							static_cast<long int>(aRect.origin.y) ),
                                                Size( 	static_cast<long int>(aRect.size.width),
							static_cast<long int>(aRect.size.height) ) ) );
    }
    
    RefreshRect( buttonRect.Left(), buttonRect.Top(), buttonRect.GetWidth(), buttonRect.GetHeight() );

    return bOK;
}