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
,
75 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
78 void DrawMacThemeButton(wxWindow
*win
,
86 wxBitmap m_bmpTreeExpanded
;
87 wxBitmap m_bmpTreeCollapsed
;
90 // ============================================================================
92 // ============================================================================
95 wxRendererNative
& wxRendererNative::GetDefault()
97 static wxRendererMac s_rendererMac
;
102 int wxRendererMac::DrawHeaderButton( wxWindow
*win
,
106 wxHeaderSortIconType sortArrow
,
107 wxHeaderButtonParams
* params
)
109 #if !wxMAC_USE_CORE_GRAPHICS
110 const wxCoord x
= dc
.LogicalToDeviceX(rect
.x
);
111 const wxCoord y
= dc
.LogicalToDeviceY(rect
.y
);
112 const wxCoord w
= dc
.LogicalToDeviceXRel(rect
.width
);
113 const wxCoord h
= dc
.LogicalToDeviceYRel(rect
.height
);
115 // now the wxGCDC is using native transformations
116 const wxCoord x
= rect
.x
;
117 const wxCoord y
= rect
.y
;
118 const wxCoord w
= rect
.width
;
119 const wxCoord h
= rect
.height
;
122 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
124 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
125 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
129 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
130 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
131 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
134 RgnHandle updateRgn
= NewRgn();
135 RectRgn( updateRgn
, &r
);
136 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
137 DisposeRgn( updateRgn
);
141 CGContextRef cgContext
;
143 #if wxMAC_USE_CORE_GRAPHICS
144 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
148 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
149 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
151 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
152 CGContextScaleCTM( cgContext
, 1, -1 );
154 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn
), cgContext
);
155 CGContextClip( cgContext
);
156 HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
160 HIThemeButtonDrawInfo drawInfo
;
163 memset( &drawInfo
, 0, sizeof(drawInfo
) );
164 drawInfo
.version
= 0;
165 drawInfo
.kind
= kThemeListHeaderButton
;
166 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
167 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
168 drawInfo
.adornment
= kThemeAdornmentNone
;
170 // The down arrow is drawn automatically, change it to an up arrow if needed.
171 if ( sortArrow
== wxHDR_SORT_ICON_UP
)
172 drawInfo
.adornment
= kThemeAdornmentHeaderButtonSortUp
;
174 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
176 // If we don't want any arrows we need to draw over the one already there
177 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
== wxHDR_SORT_ICON_NONE
) )
179 // clip to the header rectangle
180 CGContextSaveGState( cgContext
);
181 CGContextClipToRect( cgContext
, headerRect
);
182 // but draw bigger than that so the arrow will get clipped off
183 headerRect
.size
.width
+= 25;
184 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
185 CGContextRestoreGState( cgContext
);
189 #if wxMAC_USE_CORE_GRAPHICS
191 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
195 // Reserve room for the arrows before writing the label, and turn off the
196 // flags we've already handled
197 wxRect
newRect(rect
);
198 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
!= wxHDR_SORT_ICON_NONE
) )
201 sortArrow
= wxHDR_SORT_ICON_NONE
;
203 flags
&= ~wxCONTROL_SELECTED
;
205 return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
);
209 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
))
211 SInt32 standardHeight
;
214 errStatus
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight
);
215 if (errStatus
== noErr
)
217 return standardHeight
;
222 void wxRendererMac::DrawTreeItemButton( wxWindow
*win
,
227 #if !wxMAC_USE_CORE_GRAPHICS
228 const wxCoord x
= dc
.LogicalToDeviceX(rect
.x
);
229 const wxCoord y
= dc
.LogicalToDeviceY(rect
.y
);
230 const wxCoord w
= dc
.LogicalToDeviceXRel(rect
.width
);
231 const wxCoord h
= dc
.LogicalToDeviceYRel(rect
.height
);
233 // now the wxGCDC is using native transformations
234 const wxCoord x
= rect
.x
;
235 const wxCoord y
= rect
.y
;
236 const wxCoord w
= rect
.width
;
237 const wxCoord h
= rect
.height
;
240 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
242 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
243 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
247 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
248 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
249 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
252 RgnHandle updateRgn
= NewRgn();
253 RectRgn( updateRgn
, &r
);
254 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
255 DisposeRgn( updateRgn
);
259 CGContextRef cgContext
;
261 #if wxMAC_USE_CORE_GRAPHICS
262 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
266 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
267 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
269 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
270 CGContextScaleCTM( cgContext
, 1, -1 );
272 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn
), cgContext
);
273 CGContextClip( cgContext
);
274 HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
278 HIThemeButtonDrawInfo drawInfo
;
281 memset( &drawInfo
, 0, sizeof(drawInfo
) );
282 drawInfo
.version
= 0;
283 drawInfo
.kind
= kThemeDisclosureButton
;
284 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
285 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
286 // We need to set the value using the 'old' DrawThemeButton constants instead.
287 drawInfo
.value
= (flags
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown
: kThemeDisclosureRight
;
288 drawInfo
.adornment
= kThemeAdornmentNone
;
290 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
294 #if wxMAC_USE_CORE_GRAPHICS
296 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
301 void wxRendererMac::DrawSplitterSash( wxWindow
*win
,
305 wxOrientation orient
,
306 int WXUNUSED(flags
) )
308 bool hasMetal
= win
->MacGetTopLevelWindow()->MacGetMetalAppearance();
310 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height
);
312 if (orient
== wxVERTICAL
)
313 splitterRect
= CGRectMake( position
, 0, height
, size
.y
);
315 splitterRect
= CGRectMake( 0, position
, size
.x
, height
);
317 #if !wxMAC_USE_CORE_GRAPHICS
320 (HIViewRef
) win
->GetHandle(),
321 (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
324 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
325 // strange redraw errors occur if we don't do this
327 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
331 (short) splitterRect
.origin
.y
,
332 (short) splitterRect
.origin
.x
,
333 (short) (splitterRect
.origin
.y
+ splitterRect
.size
.height
),
334 (short) (splitterRect
.origin
.x
+ splitterRect
.size
.width
)
337 RgnHandle updateRgn
= NewRgn();
338 RectRgn( updateRgn
, &r
);
339 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
340 DisposeRgn( updateRgn
);
344 CGContextRef cgContext
;
346 #if wxMAC_USE_CORE_GRAPHICS
347 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
350 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
351 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
352 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
353 CGContextScaleCTM( cgContext
, 1, -1 );
356 HIThemeSplitterDrawInfo drawInfo
;
357 drawInfo
.version
= 0;
358 drawInfo
.state
= kThemeStateActive
;
359 drawInfo
.adornment
= hasMetal
? kHIThemeSplitterAdornmentMetal
: kHIThemeSplitterAdornmentNone
;
360 HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);
362 #if wxMAC_USE_CORE_GRAPHICS
364 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
370 wxRendererMac::DrawItemSelectionRect(wxWindow
*win
,
375 if ( !(flags
& wxCONTROL_SELECTED
) )
378 if (flags
& wxCONTROL_FOCUSED
)
380 if (!IsControlActive( (ControlRef
)win
->GetHandle() ))
381 flags
= wxCONTROL_SELECTED
;
385 GetThemeBrushAsColor(flags
& wxCONTROL_FOCUSED
386 ? kThemeBrushAlternatePrimaryHighlightColor
387 : kThemeBrushSecondaryHighlightColor
,
388 32, true, &selColor
);
390 wxBrush
selBrush(selColor
);
392 dc
.SetPen( *wxTRANSPARENT_PEN
);
393 dc
.SetBrush( selBrush
);
394 dc
.DrawRectangle( rect
);
399 wxRendererMac::DrawMacThemeButton(wxWindow
*win
,
406 #if !wxMAC_USE_CORE_GRAPHICS
407 const wxCoord x
= dc
.LogicalToDeviceX(rect
.x
);
408 const wxCoord y
= dc
.LogicalToDeviceY(rect
.y
);
409 const wxCoord w
= dc
.LogicalToDeviceXRel(rect
.width
);
410 const wxCoord h
= dc
.LogicalToDeviceYRel(rect
.height
);
412 // now the wxGCDC is using native transformations
413 const wxCoord x
= rect
.x
;
414 const wxCoord y
= rect
.y
;
415 const wxCoord w
= rect
.width
;
416 const wxCoord h
= rect
.height
;
419 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
421 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
422 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
426 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
427 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
428 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
431 RgnHandle updateRgn
= NewRgn();
432 RectRgn( updateRgn
, &r
);
433 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
434 DisposeRgn( updateRgn
);
438 CGContextRef cgContext
;
440 #if wxMAC_USE_CORE_GRAPHICS
441 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
445 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
446 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
448 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
449 CGContextScaleCTM( cgContext
, 1, -1 );
451 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn
), cgContext
);
452 CGContextClip( cgContext
);
453 HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
457 HIThemeButtonDrawInfo drawInfo
;
460 memset( &drawInfo
, 0, sizeof(drawInfo
) );
461 drawInfo
.version
= 0;
462 drawInfo
.kind
= kind
;
463 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
464 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
465 drawInfo
.adornment
= adornment
;
467 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
470 #if wxMAC_USE_CORE_GRAPHICS
472 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
479 wxRendererMac::DrawComboBoxDropButton(wxWindow
*win
,
485 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
486 kind
= kThemeArrowButtonSmall
;
487 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
488 kind
= kThemeArrowButtonMini
;
490 kind
= kThemeArrowButton
;
492 DrawMacThemeButton(win
, dc
, rect
, flags
,
493 kind
, kThemeAdornmentArrowDownArrow
);
497 wxRendererMac::DrawPushButton(wxWindow
*win
,
503 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
504 kind
= kThemeBevelButtonSmall
;
505 // There is no kThemeBevelButtonMini, but in this case, use Small
506 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
507 kind
= kThemeBevelButtonSmall
;
509 kind
= kThemeBevelButton
;
511 DrawMacThemeButton(win
, dc
, rect
, flags
,
512 kind
, kThemeAdornmentNone
);
516 wxRendererMac::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
520 wxDelegateRendererNative::DrawFocusRect(win
, dc
, rect
, flags
);
524 #if wxMAC_USE_CORE_GRAPHICS
526 CGRect cgrect
= CGRectMake( rect
.x
, rect
.y
, rect
.width
, rect
.height
) ;
528 HIThemeFrameDrawInfo info
;
529 memset( &info
, 0 , sizeof(info
) ) ;
533 info
.state
= kThemeStateActive
;
534 info
.isFocused
= true ;
536 CGContextRef cgContext
= (CGContextRef
) win
->MacGetCGContextRef() ;
537 wxASSERT( cgContext
) ;
539 HIThemeDrawFocusRect( &cgrect
, true , cgContext
, kHIThemeOrientationNormal
) ;
542 // FIXME: not yet working for !wxMAC_USE_CORE_GRAPHICS
545 r
.left
= rect
.x
; r
.top
= rect
.y
; r
.right
= rect
.GetRight(); r
.bottom
= rect
.GetBottom();
546 wxTopLevelWindowMac
* top
= win
->MacGetTopLevelWindow();
550 wxMacControl::Convert( &pt
, win
->GetPeer() , top
->GetPeer() ) ;
551 OffsetRect( &r
, pt
.x
, pt
.y
) ;
554 DrawThemeFocusRect( &r
, true ) ;