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
,
374 if (flags
& wxCONTROL_SELECTED
)
376 if (flags
& wxCONTROL_FOCUSED
)
377 GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor
, 32, true, &selColor
);
379 GetThemeBrushAsColor(kThemeBrushSecondaryHighlightColor
, 32, true, &selColor
);
382 wxBrush selBrush
= wxBrush( wxColour( selColor
.red
, selColor
.green
, selColor
.blue
), wxSOLID
);
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
);