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 const wxCoord x
= rect
.x
;
115 const wxCoord y
= rect
.y
;
116 const wxCoord w
= rect
.width
;
117 const wxCoord h
= rect
.height
;
119 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
121 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
122 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
126 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
127 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
128 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
131 RgnHandle updateRgn
= NewRgn();
132 RectRgn( updateRgn
, &r
);
133 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
134 DisposeRgn( updateRgn
);
138 CGContextRef cgContext
;
140 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
143 HIThemeButtonDrawInfo drawInfo
;
146 memset( &drawInfo
, 0, sizeof(drawInfo
) );
147 drawInfo
.version
= 0;
148 drawInfo
.kind
= kThemeListHeaderButton
;
149 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
150 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
151 drawInfo
.adornment
= kThemeAdornmentNone
;
153 // The down arrow is drawn automatically, change it to an up arrow if needed.
154 if ( sortArrow
== wxHDR_SORT_ICON_UP
)
155 drawInfo
.adornment
= kThemeAdornmentHeaderButtonSortUp
;
157 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
159 // If we don't want any arrows we need to draw over the one already there
160 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
== wxHDR_SORT_ICON_NONE
) )
162 // clip to the header rectangle
163 CGContextSaveGState( cgContext
);
164 CGContextClipToRect( cgContext
, headerRect
);
165 // but draw bigger than that so the arrow will get clipped off
166 headerRect
.size
.width
+= 25;
167 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
168 CGContextRestoreGState( cgContext
);
173 // Reserve room for the arrows before writing the label, and turn off the
174 // flags we've already handled
175 wxRect
newRect(rect
);
176 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
!= wxHDR_SORT_ICON_NONE
) )
179 sortArrow
= wxHDR_SORT_ICON_NONE
;
181 flags
&= ~wxCONTROL_SELECTED
;
183 return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
);
187 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
))
189 SInt32 standardHeight
;
192 errStatus
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight
);
193 if (errStatus
== noErr
)
195 return standardHeight
;
200 void wxRendererMac::DrawTreeItemButton( wxWindow
*win
,
205 // now the wxGCDC is using native transformations
206 const wxCoord x
= rect
.x
;
207 const wxCoord y
= rect
.y
;
208 const wxCoord w
= rect
.width
;
209 const wxCoord h
= rect
.height
;
211 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
213 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
214 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
218 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
219 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
220 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
223 RgnHandle updateRgn
= NewRgn();
224 RectRgn( updateRgn
, &r
);
225 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
226 DisposeRgn( updateRgn
);
230 CGContextRef cgContext
;
232 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
234 HIThemeButtonDrawInfo drawInfo
;
237 memset( &drawInfo
, 0, sizeof(drawInfo
) );
238 drawInfo
.version
= 0;
239 drawInfo
.kind
= kThemeDisclosureButton
;
240 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
241 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
242 // We need to set the value using the 'old' DrawThemeButton constants instead.
243 drawInfo
.value
= (flags
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown
: kThemeDisclosureRight
;
244 drawInfo
.adornment
= kThemeAdornmentNone
;
246 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
250 void wxRendererMac::DrawSplitterSash( wxWindow
*win
,
254 wxOrientation orient
,
255 int WXUNUSED(flags
) )
257 bool hasMetal
= win
->MacGetTopLevelWindow()->MacGetMetalAppearance();
259 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height
);
261 if (orient
== wxVERTICAL
)
262 splitterRect
= CGRectMake( position
, 0, height
, size
.y
);
264 splitterRect
= CGRectMake( 0, position
, size
.x
, height
);
266 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
267 // strange redraw errors occur if we don't do this
269 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
273 (short) splitterRect
.origin
.y
,
274 (short) splitterRect
.origin
.x
,
275 (short) (splitterRect
.origin
.y
+ splitterRect
.size
.height
),
276 (short) (splitterRect
.origin
.x
+ splitterRect
.size
.width
)
279 RgnHandle updateRgn
= NewRgn();
280 RectRgn( updateRgn
, &r
);
281 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
282 DisposeRgn( updateRgn
);
286 CGContextRef cgContext
;
288 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
290 HIThemeSplitterDrawInfo drawInfo
;
291 drawInfo
.version
= 0;
292 drawInfo
.state
= kThemeStateActive
;
293 drawInfo
.adornment
= hasMetal
? kHIThemeSplitterAdornmentMetal
: kHIThemeSplitterAdornmentNone
;
294 HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);
299 wxRendererMac::DrawItemSelectionRect(wxWindow
*win
,
304 if ( !(flags
& wxCONTROL_SELECTED
) )
307 if (flags
& wxCONTROL_FOCUSED
)
309 if (!IsControlActive( (ControlRef
)win
->GetHandle() ))
310 flags
= wxCONTROL_SELECTED
;
314 GetThemeBrushAsColor(flags
& wxCONTROL_FOCUSED
315 ? kThemeBrushAlternatePrimaryHighlightColor
316 : kThemeBrushSecondaryHighlightColor
,
317 32, true, &selColor
);
319 wxBrush
selBrush(selColor
);
321 dc
.SetPen( *wxTRANSPARENT_PEN
);
322 dc
.SetBrush( selBrush
);
323 dc
.DrawRectangle( rect
);
328 wxRendererMac::DrawMacThemeButton(wxWindow
*win
,
335 // now the wxGCDC is using native transformations
336 const wxCoord x
= rect
.x
;
337 const wxCoord y
= rect
.y
;
338 const wxCoord w
= rect
.width
;
339 const wxCoord h
= rect
.height
;
341 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
343 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
344 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
348 (short) headerRect
.origin
.y
, (short) headerRect
.origin
.x
,
349 (short) (headerRect
.origin
.y
+ headerRect
.size
.height
),
350 (short) (headerRect
.origin
.x
+ headerRect
.size
.width
)
353 RgnHandle updateRgn
= NewRgn();
354 RectRgn( updateRgn
, &r
);
355 HIViewSetNeedsDisplayInRegion( (HIViewRef
) win
->GetHandle(), updateRgn
, true );
356 DisposeRgn( updateRgn
);
360 CGContextRef cgContext
;
361 cgContext
= (CGContextRef
) dc
.GetGraphicsContext()->GetNativeContext();
363 HIThemeButtonDrawInfo drawInfo
;
366 memset( &drawInfo
, 0, sizeof(drawInfo
) );
367 drawInfo
.version
= 0;
368 drawInfo
.kind
= kind
;
369 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
370 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
371 if (flags
& wxCONTROL_UNDETERMINED
)
372 drawInfo
.value
= kThemeButtonMixed
;
373 drawInfo
.adornment
= adornment
;
375 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
380 wxRendererMac::DrawCheckBox(wxWindow
*win
,
385 if (flags
& wxCONTROL_CHECKED
)
386 flags
|= wxCONTROL_SELECTED
;
388 DrawMacThemeButton(win
, dc
, rect
, flags
,
389 kThemeCheckBox
, kThemeAdornmentNone
);
393 wxRendererMac::DrawComboBoxDropButton(wxWindow
*win
,
399 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
400 kind
= kThemeArrowButtonSmall
;
401 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
402 kind
= kThemeArrowButtonMini
;
404 kind
= kThemeArrowButton
;
406 DrawMacThemeButton(win
, dc
, rect
, flags
,
407 kind
, kThemeAdornmentArrowDownArrow
);
411 wxRendererMac::DrawPushButton(wxWindow
*win
,
417 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
418 kind
= kThemeBevelButtonSmall
;
419 // There is no kThemeBevelButtonMini, but in this case, use Small
420 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
421 kind
= kThemeBevelButtonSmall
;
423 kind
= kThemeBevelButton
;
425 DrawMacThemeButton(win
, dc
, rect
, flags
,
426 kind
, kThemeAdornmentNone
);
430 wxRendererMac::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
434 wxDelegateRendererNative::DrawFocusRect(win
, dc
, rect
, flags
);
438 CGRect cgrect
= CGRectMake( rect
.x
, rect
.y
, rect
.width
, rect
.height
) ;
440 HIThemeFrameDrawInfo info
;
441 memset( &info
, 0 , sizeof(info
) ) ;
445 info
.state
= kThemeStateActive
;
446 info
.isFocused
= true ;
448 CGContextRef cgContext
= (CGContextRef
) win
->MacGetCGContextRef() ;
449 wxASSERT( cgContext
) ;
451 HIThemeDrawFocusRect( &cgrect
, true , cgContext
, kHIThemeOrientationNormal
) ;