1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/renderer.cpp 
   3 // Purpose:     implementation of wxRendererNative for Mac 
   4 // Author:      Vadim Zeitlin 
   8 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwindows.org> 
   9 // License:     wxWindows licence 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // for compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  20     #include "wx/string.h" 
  22     #include "wx/bitmap.h" 
  23     #include "wx/settings.h" 
  24     #include "wx/dcclient.h" 
  25     #include "wx/toplevel.h" 
  28 #include "wx/renderer.h" 
  29 #include "wx/graphics.h" 
  30 #include "wx/mac/uma.h" 
  33 class WXDLLEXPORT wxRendererMac 
: public wxDelegateRendererNative
 
  36     // draw the header control button (used by wxListCtrl) 
  37     virtual int DrawHeaderButton( wxWindow 
*win
, 
  41         wxHeaderSortIconType sortArrow 
= wxHDR_SORT_ICON_NONE
, 
  42         wxHeaderButtonParams
* params 
= NULL 
); 
  44     virtual int GetHeaderButtonHeight(wxWindow 
*win
); 
  46     // draw the expanded/collapsed icon for a tree control item 
  47     virtual void DrawTreeItemButton( wxWindow 
*win
, 
  52     // draw a (vertical) sash 
  53     virtual void DrawSplitterSash( wxWindow 
*win
, 
  60     virtual void DrawComboBoxDropButton(wxWindow 
*win
, 
  65     virtual void DrawPushButton(wxWindow 
*win
, 
  70     virtual void DrawItemSelectionRect(wxWindow 
*win
, 
  76     void DrawMacThemeButton(wxWindow 
*win
, 
  84     wxBitmap m_bmpTreeExpanded
; 
  85     wxBitmap m_bmpTreeCollapsed
; 
  88 // ============================================================================ 
  90 // ============================================================================ 
  93 wxRendererNative
& wxRendererNative::GetDefault() 
  95     static wxRendererMac s_rendererMac
; 
 100 int wxRendererMac::DrawHeaderButton( wxWindow 
*win
, 
 104     wxHeaderSortIconType sortArrow
, 
 105     wxHeaderButtonParams
* params 
) 
 107 #if !wxMAC_USE_CORE_GRAPHICS 
 108     const wxCoord x 
= dc
.LogicalToDeviceX(rect
.x
); 
 109     const wxCoord y 
= dc
.LogicalToDeviceY(rect
.y
); 
 110     const wxCoord w 
= dc
.LogicalToDeviceXRel(rect
.width
); 
 111     const wxCoord h 
= dc
.LogicalToDeviceYRel(rect
.height
); 
 113     // now the wxGCDC is using native transformations 
 114     const wxCoord x 
= rect
.x
; 
 115     const wxCoord y 
= rect
.y
; 
 116     const wxCoord w 
= rect
.width
; 
 117     const wxCoord h 
= rect
.height
; 
 120     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
 122     HIRect headerRect 
= CGRectMake( x
, y
, w
, h 
); 
 123     if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC 
) ) ) 
 127             (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
, 
 128             (short) (headerRect
.origin
.y 
+ headerRect
.size
.height
), 
 129             (short) (headerRect
.origin
.x 
+ headerRect
.size
.width
) 
 132         RgnHandle updateRgn 
= NewRgn(); 
 133         RectRgn( updateRgn
, &r 
); 
 134         HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true ); 
 135         DisposeRgn( updateRgn 
); 
 139         CGContextRef cgContext
; 
 141 #if wxMAC_USE_CORE_GRAPHICS 
 142         cgContext 
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext(); 
 146         GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds 
); 
 147         QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 149         CGContextTranslateCTM( cgContext
, 0, bounds
.bottom 
- bounds
.top 
); 
 150         CGContextScaleCTM( cgContext
, 1, -1 ); 
 152         HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn 
), cgContext 
); 
 153         CGContextClip( cgContext 
); 
 154         HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() ); 
 158             HIThemeButtonDrawInfo drawInfo
; 
 161             memset( &drawInfo
, 0, sizeof(drawInfo
) ); 
 162             drawInfo
.version 
= 0; 
 163             drawInfo
.kind 
= kThemeListHeaderButton
; 
 164             drawInfo
.state 
= (flags 
& wxCONTROL_DISABLED
) ? kThemeStateInactive 
: kThemeStateActive
; 
 165             drawInfo
.value 
= (flags 
& wxCONTROL_SELECTED
) ? kThemeButtonOn 
: kThemeButtonOff
; 
 166             drawInfo
.adornment 
= kThemeAdornmentNone
; 
 168             // The down arrow is drawn automatically, change it to an up arrow if needed. 
 169             if ( sortArrow 
== wxHDR_SORT_ICON_UP 
) 
 170                 drawInfo
.adornment 
= kThemeAdornmentHeaderButtonSortUp
; 
 172             HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect 
); 
 174             // If we don't want any arrows we need to draw over the one already there 
 175             if ( (flags 
& wxCONTROL_SELECTED
) && (sortArrow 
== wxHDR_SORT_ICON_NONE
) ) 
 177                 // clip to the header rectangle 
 178                 CGContextSaveGState( cgContext 
); 
 179                 CGContextClipToRect( cgContext
, headerRect 
); 
 180                 // but draw bigger than that so the arrow will get clipped off 
 181                 headerRect
.size
.width 
+= 25; 
 182                 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect 
); 
 183                 CGContextRestoreGState( cgContext 
); 
 187 #if wxMAC_USE_CORE_GRAPHICS 
 189         QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 193     // Reserve room for the arrows before writing the label, and turn off the 
 194     // flags we've already handled 
 195     wxRect 
newRect(rect
); 
 196     if ( (flags 
& wxCONTROL_SELECTED
) && (sortArrow 
!= wxHDR_SORT_ICON_NONE
) ) 
 199         sortArrow 
= wxHDR_SORT_ICON_NONE
; 
 201     flags 
&= ~wxCONTROL_SELECTED
; 
 203     return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
); 
 207 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
)) 
 209     SInt32              standardHeight
; 
 212     errStatus 
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight 
); 
 213     if (errStatus 
== noErr
) 
 215         return standardHeight
; 
 220 void wxRendererMac::DrawTreeItemButton( wxWindow 
*win
, 
 225 #if !wxMAC_USE_CORE_GRAPHICS 
 226     const wxCoord x 
= dc
.LogicalToDeviceX(rect
.x
); 
 227     const wxCoord y 
= dc
.LogicalToDeviceY(rect
.y
); 
 228     const wxCoord w 
= dc
.LogicalToDeviceXRel(rect
.width
); 
 229     const wxCoord h 
= dc
.LogicalToDeviceYRel(rect
.height
); 
 231     // now the wxGCDC is using native transformations 
 232     const wxCoord x 
= rect
.x
; 
 233     const wxCoord y 
= rect
.y
; 
 234     const wxCoord w 
= rect
.width
; 
 235     const wxCoord h 
= rect
.height
; 
 238     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
 240     HIRect headerRect 
= CGRectMake( x
, y
, w
, h 
); 
 241     if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC 
) ) ) 
 245             (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
, 
 246             (short) (headerRect
.origin
.y 
+ headerRect
.size
.height
), 
 247             (short) (headerRect
.origin
.x 
+ headerRect
.size
.width
) 
 250         RgnHandle updateRgn 
= NewRgn(); 
 251         RectRgn( updateRgn
, &r 
); 
 252         HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true ); 
 253         DisposeRgn( updateRgn 
); 
 257         CGContextRef cgContext
; 
 259 #if wxMAC_USE_CORE_GRAPHICS 
 260         cgContext 
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext(); 
 264         GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds 
); 
 265         QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 267         CGContextTranslateCTM( cgContext
, 0, bounds
.bottom 
- bounds
.top 
); 
 268         CGContextScaleCTM( cgContext
, 1, -1 ); 
 270         HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn 
), cgContext 
); 
 271         CGContextClip( cgContext 
); 
 272         HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() ); 
 276             HIThemeButtonDrawInfo drawInfo
; 
 279             memset( &drawInfo
, 0, sizeof(drawInfo
) ); 
 280             drawInfo
.version 
= 0; 
 281             drawInfo
.kind 
= kThemeDisclosureButton
; 
 282             drawInfo
.state 
= (flags 
& wxCONTROL_DISABLED
) ? kThemeStateInactive 
: kThemeStateActive
; 
 283             // Apple mailing list posts say to use the arrow adornment constants, but those don't work. 
 284             // We need to set the value using the 'old' DrawThemeButton constants instead. 
 285             drawInfo
.value 
= (flags 
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown 
: kThemeDisclosureRight
; 
 286             drawInfo
.adornment 
= kThemeAdornmentNone
; 
 288             HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect 
); 
 292 #if wxMAC_USE_CORE_GRAPHICS 
 294         QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 299 void wxRendererMac::DrawSplitterSash( wxWindow 
*win
, 
 303     wxOrientation orient
, 
 304     int WXUNUSED(flags
) ) 
 306     bool hasMetal 
= win
->MacGetTopLevelWindow()->MacGetMetalAppearance(); 
 308     GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height 
); 
 310     if (orient 
== wxVERTICAL
) 
 311         splitterRect 
= CGRectMake( position
, 0, height
, size
.y 
); 
 313         splitterRect 
= CGRectMake( 0, position
, size
.x
, height 
); 
 315 #if !wxMAC_USE_CORE_GRAPHICS 
 318         (HIViewRef
) win
->GetHandle(), 
 319         (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() ); 
 322     // under compositing we should only draw when called by the OS, otherwise just issue a redraw command 
 323     // strange redraw errors occur if we don't do this 
 325     if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC 
) ) ) 
 329             (short) splitterRect
.origin
.y
, 
 330             (short) splitterRect
.origin
.x
, 
 331             (short) (splitterRect
.origin
.y 
+ splitterRect
.size
.height
), 
 332             (short) (splitterRect
.origin
.x 
+ splitterRect
.size
.width
) 
 335         RgnHandle updateRgn 
= NewRgn(); 
 336         RectRgn( updateRgn
, &r 
); 
 337         HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true ); 
 338         DisposeRgn( updateRgn 
); 
 342         CGContextRef cgContext
; 
 344 #if wxMAC_USE_CORE_GRAPHICS 
 345         cgContext 
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext(); 
 348         GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds 
); 
 349         QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 350         CGContextTranslateCTM( cgContext
, 0, bounds
.bottom 
- bounds
.top 
); 
 351         CGContextScaleCTM( cgContext
, 1, -1 ); 
 354         HIThemeSplitterDrawInfo drawInfo
; 
 355         drawInfo
.version 
= 0; 
 356         drawInfo
.state 
= kThemeStateActive
; 
 357         drawInfo
.adornment 
= hasMetal 
? kHIThemeSplitterAdornmentMetal 
: kHIThemeSplitterAdornmentNone
; 
 358         HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal 
); 
 360 #if wxMAC_USE_CORE_GRAPHICS 
 362         QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 368 wxRendererMac::DrawItemSelectionRect(wxWindow 
*win
, 
 373     if ( !(flags 
& wxCONTROL_SELECTED
) ) 
 377     GetThemeBrushAsColor(flags 
& wxCONTROL_FOCUSED
 
 378                             ? kThemeBrushAlternatePrimaryHighlightColor
 
 379                             : kThemeBrushSecondaryHighlightColor
, 
 380                          32, true, &selColor
); 
 382     wxBrush 
selBrush(selColor
); 
 384     dc
.SetPen( *wxTRANSPARENT_PEN 
); 
 385     dc
.SetBrush( selBrush 
); 
 386     dc
.DrawRectangle( rect 
); 
 391 wxRendererMac::DrawMacThemeButton(wxWindow 
*win
, 
 398 #if !wxMAC_USE_CORE_GRAPHICS 
 399     const wxCoord x 
= dc
.LogicalToDeviceX(rect
.x
); 
 400     const wxCoord y 
= dc
.LogicalToDeviceY(rect
.y
); 
 401     const wxCoord w 
= dc
.LogicalToDeviceXRel(rect
.width
); 
 402     const wxCoord h 
= dc
.LogicalToDeviceYRel(rect
.height
); 
 404     // now the wxGCDC is using native transformations 
 405     const wxCoord x 
= rect
.x
; 
 406     const wxCoord y 
= rect
.y
; 
 407     const wxCoord w 
= rect
.width
; 
 408     const wxCoord h 
= rect
.height
; 
 411     dc
.SetBrush( *wxTRANSPARENT_BRUSH 
); 
 413     HIRect headerRect 
= CGRectMake( x
, y
, w
, h 
); 
 414     if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC 
) ) ) 
 418             (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
, 
 419             (short) (headerRect
.origin
.y 
+ headerRect
.size
.height
), 
 420             (short) (headerRect
.origin
.x 
+ headerRect
.size
.width
) 
 423         RgnHandle updateRgn 
= NewRgn(); 
 424         RectRgn( updateRgn
, &r 
); 
 425         HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true ); 
 426         DisposeRgn( updateRgn 
); 
 430         CGContextRef cgContext
; 
 432 #if wxMAC_USE_CORE_GRAPHICS 
 433         cgContext 
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext(); 
 437         GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds 
); 
 438         QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 440         CGContextTranslateCTM( cgContext
, 0, bounds
.bottom 
- bounds
.top 
); 
 441         CGContextScaleCTM( cgContext
, 1, -1 ); 
 443         HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn 
), cgContext 
); 
 444         CGContextClip( cgContext 
); 
 445         HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() ); 
 449             HIThemeButtonDrawInfo drawInfo
; 
 452             memset( &drawInfo
, 0, sizeof(drawInfo
) ); 
 453             drawInfo
.version 
= 0; 
 454             drawInfo
.kind 
= kind
; 
 455             drawInfo
.state 
= (flags 
& wxCONTROL_DISABLED
) ? kThemeStateInactive 
: kThemeStateActive
; 
 456             drawInfo
.value 
= (flags 
& wxCONTROL_SELECTED
) ? kThemeButtonOn 
: kThemeButtonOff
; 
 457             drawInfo
.adornment 
= adornment
; 
 459             HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect 
); 
 462 #if wxMAC_USE_CORE_GRAPHICS 
 464         QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext 
); 
 471 wxRendererMac::DrawComboBoxDropButton(wxWindow 
*win
, 
 477     if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL 
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
)) 
 478         kind 
= kThemeArrowButtonSmall
; 
 479     else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI 
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
)) 
 480         kind 
= kThemeArrowButtonMini
; 
 482         kind 
= kThemeArrowButton
; 
 484     DrawMacThemeButton(win
, dc
, rect
, flags
, 
 485                        kind
, kThemeAdornmentArrowDownArrow
); 
 489 wxRendererMac::DrawPushButton(wxWindow 
*win
, 
 495     if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL 
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
)) 
 496         kind 
= kThemeBevelButtonSmall
; 
 497     // There is no kThemeBevelButtonMini, but in this case, use Small 
 498     else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI 
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
)) 
 499         kind 
= kThemeBevelButtonSmall
; 
 501         kind 
= kThemeBevelButton
; 
 503     DrawMacThemeButton(win
, dc
, rect
, flags
, 
 504                        kind
, kThemeAdornmentNone
);