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 DrawCheckBox(wxWindow
*win
,
65 virtual void DrawComboBoxDropButton(wxWindow
*win
,
70 virtual void DrawPushButton(wxWindow
*win
,
75 virtual void DrawItemSelectionRect(wxWindow
*win
,
80 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
83 void DrawMacThemeButton(wxWindow
*win
,
91 wxBitmap m_bmpTreeExpanded
;
92 wxBitmap m_bmpTreeCollapsed
;
95 // ============================================================================
97 // ============================================================================
100 wxRendererNative
& wxRendererNative::GetDefault()
102 static wxRendererMac s_rendererMac
;
104 return s_rendererMac
;
107 int wxRendererMac::DrawHeaderButton( wxWindow
*win
,
111 wxHeaderSortIconType sortArrow
,
112 wxHeaderButtonParams
* params
)
114 #if !wxMAC_USE_CORE_GRAPHICS
115 const wxCoord x
= dc
.LogicalToDeviceX(rect
.x
);
116 const wxCoord y
= dc
.LogicalToDeviceY(rect
.y
);
117 const wxCoord w
= dc
.LogicalToDeviceXRel(rect
.width
);
118 const wxCoord h
= dc
.LogicalToDeviceYRel(rect
.height
);
120 // now the wxGCDC is using native transformations
121 const wxCoord x
= rect
.x
;
122 const wxCoord y
= rect
.y
;
123 const wxCoord w
= rect
.width
;
124 const wxCoord h
= rect
.height
;
127 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
129 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
130 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
134 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
135 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
136 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
139 RgnHandle updateRgn
= NewRgn();
140 RectRgn( updateRgn
, &r
);
141 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
142 DisposeRgn( updateRgn
);
146 CGContextRef cgContext
;
148 #if wxMAC_USE_CORE_GRAPHICS
149 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
153 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
154 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
156 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
157 CGContextScaleCTM( cgContext
, 1, -1 );
159 HIShapeRef shape
= HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn
);
162 HIShapeReplacePathInCGContext( shape
, cgContext
);
164 CGContextClip( cgContext
);
166 HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
170 HIThemeButtonDrawInfo drawInfo
;
173 memset( &drawInfo
, 0, sizeof(drawInfo
) );
174 drawInfo
.version
= 0;
175 drawInfo
.kind
= kThemeListHeaderButton
;
176 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
177 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
178 drawInfo
.adornment
= kThemeAdornmentNone
;
180 // The down arrow is drawn automatically, change it to an up arrow if needed.
181 if ( sortArrow
== wxHDR_SORT_ICON_UP
)
182 drawInfo
.adornment
= kThemeAdornmentHeaderButtonSortUp
;
184 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
186 // If we don't want any arrows we need to draw over the one already there
187 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
== wxHDR_SORT_ICON_NONE
) )
189 // clip to the header rectangle
190 CGContextSaveGState( cgContext
);
191 CGContextClipToRect( cgContext
, headerRect
);
192 // but draw bigger than that so the arrow will get clipped off
193 headerRect
.size
.width
+= 25;
194 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
195 CGContextRestoreGState( cgContext
);
199 #if wxMAC_USE_CORE_GRAPHICS
201 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
205 // Reserve room for the arrows before writing the label, and turn off the
206 // flags we've already handled
207 wxRect
newRect(rect
);
208 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
!= wxHDR_SORT_ICON_NONE
) )
211 sortArrow
= wxHDR_SORT_ICON_NONE
;
213 flags
&= ~wxCONTROL_SELECTED
;
215 return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
);
219 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
))
221 SInt32 standardHeight
;
224 errStatus
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight
);
225 if (errStatus
== noErr
)
227 return standardHeight
;
232 void wxRendererMac::DrawTreeItemButton( wxWindow
*win
,
237 #if !wxMAC_USE_CORE_GRAPHICS
238 const wxCoord x
= dc
.LogicalToDeviceX(rect
.x
);
239 const wxCoord y
= dc
.LogicalToDeviceY(rect
.y
);
240 const wxCoord w
= dc
.LogicalToDeviceXRel(rect
.width
);
241 const wxCoord h
= dc
.LogicalToDeviceYRel(rect
.height
);
243 // now the wxGCDC is using native transformations
244 const wxCoord x
= rect
.x
;
245 const wxCoord y
= rect
.y
;
246 const wxCoord w
= rect
.width
;
247 const wxCoord h
= rect
.height
;
250 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
252 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
253 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
257 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
258 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
259 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
262 RgnHandle updateRgn
= NewRgn();
263 RectRgn( updateRgn
, &r
);
264 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
265 DisposeRgn( updateRgn
);
269 CGContextRef cgContext
;
271 #if wxMAC_USE_CORE_GRAPHICS
272 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
276 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
277 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
279 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
280 CGContextScaleCTM( cgContext
, 1, -1 );
282 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn
), cgContext
);
283 CGContextClip( cgContext
);
284 HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
288 HIThemeButtonDrawInfo drawInfo
;
291 memset( &drawInfo
, 0, sizeof(drawInfo
) );
292 drawInfo
.version
= 0;
293 drawInfo
.kind
= kThemeDisclosureButton
;
294 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
295 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
296 // We need to set the value using the 'old' DrawThemeButton constants instead.
297 drawInfo
.value
= (flags
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown
: kThemeDisclosureRight
;
298 drawInfo
.adornment
= kThemeAdornmentNone
;
300 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
304 #if wxMAC_USE_CORE_GRAPHICS
306 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
311 void wxRendererMac::DrawSplitterSash( wxWindow
*win
,
315 wxOrientation orient
,
316 int WXUNUSED(flags
) )
318 bool hasMetal
= win
->MacGetTopLevelWindow()->MacGetMetalAppearance();
320 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height
);
322 if (orient
== wxVERTICAL
)
323 splitterRect
= CGRectMake( position
, 0, height
, size
.y
);
325 splitterRect
= CGRectMake( 0, position
, size
.x
, height
);
327 #if !wxMAC_USE_CORE_GRAPHICS
330 (HIViewRef
) win
->GetHandle(),
331 (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
334 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
335 // strange redraw errors occur if we don't do this
337 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
341 (short) splitterRect
.origin
.y
,
342 (short) splitterRect
.origin
.x
,
343 (short) (splitterRect
.origin
.y
+ splitterRect
.size
.height
),
344 (short) (splitterRect
.origin
.x
+ splitterRect
.size
.width
)
347 RgnHandle updateRgn
= NewRgn();
348 RectRgn( updateRgn
, &r
);
349 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
350 DisposeRgn( updateRgn
);
354 CGContextRef cgContext
;
356 #if wxMAC_USE_CORE_GRAPHICS
357 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
360 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
361 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
362 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
363 CGContextScaleCTM( cgContext
, 1, -1 );
366 HIThemeSplitterDrawInfo drawInfo
;
367 drawInfo
.version
= 0;
368 drawInfo
.state
= kThemeStateActive
;
369 drawInfo
.adornment
= hasMetal
? kHIThemeSplitterAdornmentMetal
: kHIThemeSplitterAdornmentNone
;
370 HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);
372 #if wxMAC_USE_CORE_GRAPHICS
374 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
380 wxRendererMac::DrawItemSelectionRect(wxWindow
*win
,
385 if ( !(flags
& wxCONTROL_SELECTED
) )
388 if (flags
& wxCONTROL_FOCUSED
)
390 if (!IsControlActive( (ControlRef
)win
->GetHandle() ))
391 flags
= wxCONTROL_SELECTED
;
395 GetThemeBrushAsColor(flags
& wxCONTROL_FOCUSED
396 ? kThemeBrushAlternatePrimaryHighlightColor
397 : kThemeBrushSecondaryHighlightColor
,
398 32, true, &selColor
);
400 wxBrush
selBrush(selColor
);
402 dc
.SetPen( *wxTRANSPARENT_PEN
);
403 dc
.SetBrush( selBrush
);
404 dc
.DrawRectangle( rect
);
409 wxRendererMac::DrawMacThemeButton(wxWindow
*win
,
416 #if !wxMAC_USE_CORE_GRAPHICS
417 const wxCoord x
= dc
.LogicalToDeviceX(rect
.x
);
418 const wxCoord y
= dc
.LogicalToDeviceY(rect
.y
);
419 const wxCoord w
= dc
.LogicalToDeviceXRel(rect
.width
);
420 const wxCoord h
= dc
.LogicalToDeviceYRel(rect
.height
);
422 // now the wxGCDC is using native transformations
423 const wxCoord x
= rect
.x
;
424 const wxCoord y
= rect
.y
;
425 const wxCoord w
= rect
.width
;
426 const wxCoord h
= rect
.height
;
429 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
431 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
432 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
436 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
437 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
438 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
441 RgnHandle updateRgn
= NewRgn();
442 RectRgn( updateRgn
, &r
);
443 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
444 DisposeRgn( updateRgn
);
448 CGContextRef cgContext
;
450 #if wxMAC_USE_CORE_GRAPHICS
451 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
455 GetPortBounds( (CGrafPtr
) dc
.m_macPort
, &bounds
);
456 QDBeginCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
458 CGContextTranslateCTM( cgContext
, 0, bounds
.bottom
- bounds
.top
);
459 CGContextScaleCTM( cgContext
, 1, -1 );
461 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle
) dc
.m_macCurrentClipRgn
), cgContext
);
462 CGContextClip( cgContext
);
463 HIViewConvertRect( &headerRect
, (HIViewRef
) win
->GetHandle(), (HIViewRef
) win
->MacGetTopLevelWindow()->GetHandle() );
467 HIThemeButtonDrawInfo drawInfo
;
470 memset( &drawInfo
, 0, sizeof(drawInfo
) );
471 drawInfo
.version
= 0;
472 drawInfo
.kind
= kind
;
473 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
474 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
475 if (flags
& wxCONTROL_UNDETERMINED
)
476 drawInfo
.value
= kThemeButtonMixed
;
477 drawInfo
.adornment
= adornment
;
479 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
482 #if wxMAC_USE_CORE_GRAPHICS
484 QDEndCGContext( (CGrafPtr
) dc
.m_macPort
, &cgContext
);
490 wxRendererMac::DrawCheckBox(wxWindow
*win
,
495 if (flags
& wxCONTROL_CHECKED
)
496 flags
|= wxCONTROL_SELECTED
;
498 DrawMacThemeButton(win
, dc
, rect
, flags
,
499 kThemeCheckBox
, kThemeAdornmentNone
);
503 wxRendererMac::DrawComboBoxDropButton(wxWindow
*win
,
509 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
510 kind
= kThemeArrowButtonSmall
;
511 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
512 kind
= kThemeArrowButtonMini
;
514 kind
= kThemeArrowButton
;
516 DrawMacThemeButton(win
, dc
, rect
, flags
,
517 kind
, kThemeAdornmentArrowDownArrow
);
521 wxRendererMac::DrawPushButton(wxWindow
*win
,
527 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
528 kind
= kThemeBevelButtonSmall
;
529 // There is no kThemeBevelButtonMini, but in this case, use Small
530 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
531 kind
= kThemeBevelButtonSmall
;
533 kind
= kThemeBevelButton
;
535 DrawMacThemeButton(win
, dc
, rect
, flags
,
536 kind
, kThemeAdornmentNone
);
540 wxRendererMac::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
544 wxDelegateRendererNative::DrawFocusRect(win
, dc
, rect
, flags
);
548 #if wxMAC_USE_CORE_GRAPHICS
550 CGRect cgrect
= CGRectMake( rect
.x
, rect
.y
, rect
.width
, rect
.height
) ;
552 HIThemeFrameDrawInfo info
;
553 memset( &info
, 0 , sizeof(info
) ) ;
557 info
.state
= kThemeStateActive
;
558 info
.isFocused
= true ;
560 CGContextRef cgContext
= (CGContextRef
) win
->MacGetCGContextRef() ;
561 wxASSERT( cgContext
) ;
563 HIThemeDrawFocusRect( &cgrect
, true , cgContext
, kHIThemeOrientationNormal
) ;
566 // FIXME: not yet working for !wxMAC_USE_CORE_GRAPHICS
569 r
.left
= rect
.x
; r
.top
= rect
.y
; r
.right
= rect
.GetRight(); r
.bottom
= rect
.GetBottom();
570 wxTopLevelWindowMac
* top
= win
->MacGetTopLevelWindow();
574 wxMacControl::Convert( &pt
, win
->GetPeer() , top
->GetPeer() ) ;
575 OffsetRect( &r
, pt
.x
, pt
.y
) ;
578 DrawThemeFocusRect( &r
, true ) ;