1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/osx/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/dcgraph.h"
31 #include "wx/osx/private.h"
34 // bring in the theme headers
35 #include <Carbon/Carbon.h>
38 class WXDLLEXPORT wxRendererMac
: public wxDelegateRendererNative
41 // draw the header control button (used by wxListCtrl)
42 virtual int DrawHeaderButton( wxWindow
*win
,
46 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
,
47 wxHeaderButtonParams
* params
= NULL
);
49 virtual int GetHeaderButtonHeight(wxWindow
*win
);
51 // draw the expanded/collapsed icon for a tree control item
52 virtual void DrawTreeItemButton( wxWindow
*win
,
57 // draw a (vertical) sash
58 virtual void DrawSplitterSash( wxWindow
*win
,
65 virtual void DrawCheckBox(wxWindow
*win
,
70 virtual wxSize
GetCheckBoxSize(wxWindow
* win
);
72 virtual void DrawComboBoxDropButton(wxWindow
*win
,
77 virtual void DrawPushButton(wxWindow
*win
,
82 virtual void DrawItemSelectionRect(wxWindow
*win
,
87 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
90 void DrawMacThemeButton(wxWindow
*win
,
98 wxBitmap m_bmpTreeExpanded
;
99 wxBitmap m_bmpTreeCollapsed
;
102 // ============================================================================
104 // ============================================================================
107 wxRendererNative
& wxRendererNative::GetDefault()
109 static wxRendererMac s_rendererMac
;
111 return s_rendererMac
;
114 int wxRendererMac::DrawHeaderButton( wxWindow
*win
,
118 wxHeaderSortIconType sortArrow
,
119 wxHeaderButtonParams
* params
)
121 const wxCoord x
= rect
.x
;
122 const wxCoord y
= rect
.y
;
123 const wxCoord w
= rect
.width
;
124 const wxCoord h
= rect
.height
;
126 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
128 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
129 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
131 win
->Refresh( &rect
);
135 CGContextRef cgContext
;
136 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
138 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
141 HIThemeButtonDrawInfo drawInfo
;
144 memset( &drawInfo
, 0, sizeof(drawInfo
) );
145 drawInfo
.version
= 0;
146 drawInfo
.kind
= kThemeListHeaderButton
;
147 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
148 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
149 drawInfo
.adornment
= kThemeAdornmentNone
;
151 // The down arrow is drawn automatically, change it to an up arrow if needed.
152 if ( sortArrow
== wxHDR_SORT_ICON_UP
)
153 drawInfo
.adornment
= kThemeAdornmentHeaderButtonSortUp
;
155 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
157 // If we don't want any arrows we need to draw over the one already there
158 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
== wxHDR_SORT_ICON_NONE
) )
160 // clip to the header rectangle
161 CGContextSaveGState( cgContext
);
162 CGContextClipToRect( cgContext
, headerRect
);
163 // but draw bigger than that so the arrow will get clipped off
164 headerRect
.size
.width
+= 25;
165 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
166 CGContextRestoreGState( cgContext
);
171 // Reserve room for the arrows before writing the label, and turn off the
172 // flags we've already handled
173 wxRect
newRect(rect
);
174 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
!= wxHDR_SORT_ICON_NONE
) )
177 sortArrow
= wxHDR_SORT_ICON_NONE
;
179 flags
&= ~wxCONTROL_SELECTED
;
181 return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
);
185 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
))
187 SInt32 standardHeight
;
190 errStatus
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight
);
191 if (errStatus
== noErr
)
193 return standardHeight
;
198 void wxRendererMac::DrawTreeItemButton( wxWindow
*win
,
203 // now the wxGCDC is using native transformations
204 const wxCoord x
= rect
.x
;
205 const wxCoord y
= rect
.y
;
206 const wxCoord w
= rect
.width
;
207 const wxCoord h
= rect
.height
;
209 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
211 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
212 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
214 win
->Refresh( &rect
);
218 CGContextRef cgContext
;
220 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
221 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
223 HIThemeButtonDrawInfo drawInfo
;
226 memset( &drawInfo
, 0, sizeof(drawInfo
) );
227 drawInfo
.version
= 0;
228 drawInfo
.kind
= kThemeDisclosureButton
;
229 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
230 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
231 // We need to set the value using the 'old' DrawThemeButton constants instead.
232 drawInfo
.value
= (flags
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown
: kThemeDisclosureRight
;
233 drawInfo
.adornment
= kThemeAdornmentNone
;
235 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
239 void wxRendererMac::DrawSplitterSash( wxWindow
*win
,
243 wxOrientation orient
,
244 int WXUNUSED(flags
) )
246 bool hasMetal
= win
->MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL
;
248 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height
);
250 if (orient
== wxVERTICAL
)
251 splitterRect
= CGRectMake( position
, 0, height
, size
.y
);
253 splitterRect
= CGRectMake( 0, position
, size
.x
, height
);
255 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
256 // strange redraw errors occur if we don't do this
258 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
260 wxRect
rect( (int) splitterRect
.origin
.x
, (int) splitterRect
.origin
.y
, (int) splitterRect
.size
.width
,
261 (int) splitterRect
.size
.height
);
262 win
->Refresh( &rect
);
266 CGContextRef cgContext
;
267 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
268 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
270 HIThemeSplitterDrawInfo drawInfo
;
271 drawInfo
.version
= 0;
272 drawInfo
.state
= kThemeStateActive
;
273 drawInfo
.adornment
= hasMetal
? kHIThemeSplitterAdornmentMetal
: kHIThemeSplitterAdornmentNone
;
274 HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);
279 wxRendererMac::DrawItemSelectionRect(wxWindow
* WXUNUSED(win
),
284 if ( !(flags
& wxCONTROL_SELECTED
) )
287 wxColour
col( wxMacCreateCGColorFromHITheme( (flags
& wxCONTROL_FOCUSED
) ?
288 kThemeBrushAlternatePrimaryHighlightColor
289 : kThemeBrushSecondaryHighlightColor
) );
290 wxBrush
selBrush( col
);
292 dc
.SetPen( *wxTRANSPARENT_PEN
);
293 dc
.SetBrush( selBrush
);
294 dc
.DrawRectangle( rect
);
299 wxRendererMac::DrawMacThemeButton(wxWindow
*win
,
306 // now the wxGCDC is using native transformations
307 const wxCoord x
= rect
.x
;
308 const wxCoord y
= rect
.y
;
309 const wxCoord w
= rect
.width
;
310 const wxCoord h
= rect
.height
;
312 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
314 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
315 if ( !dc
.IsKindOf( CLASSINFO( wxPaintDC
) ) )
317 win
->Refresh( &rect
);
321 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
322 CGContextRef cgContext
;
323 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
325 HIThemeButtonDrawInfo drawInfo
;
328 memset( &drawInfo
, 0, sizeof(drawInfo
) );
329 drawInfo
.version
= 0;
330 drawInfo
.kind
= kind
;
331 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
332 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
333 if (flags
& wxCONTROL_UNDETERMINED
)
334 drawInfo
.value
= kThemeButtonMixed
;
335 drawInfo
.adornment
= adornment
;
337 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
342 wxRendererMac::DrawCheckBox(wxWindow
*win
,
347 if (flags
& wxCONTROL_CHECKED
)
348 flags
|= wxCONTROL_SELECTED
;
350 DrawMacThemeButton(win
, dc
, rect
, flags
,
351 kThemeCheckBox
, kThemeAdornmentNone
);
354 wxSize
wxRendererMac::GetCheckBoxSize(wxWindow
* WXUNUSED(win
))
357 SInt32 width
, height
;
360 errStatus
= GetThemeMetric(kThemeMetricCheckBoxWidth
, &width
);
361 if (errStatus
== noErr
)
363 size
.SetWidth(width
);
366 errStatus
= GetThemeMetric(kThemeMetricCheckBoxHeight
, &height
);
367 if (errStatus
== noErr
)
369 size
.SetHeight(height
);
376 wxRendererMac::DrawComboBoxDropButton(wxWindow
*win
,
382 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
383 kind
= kThemeArrowButtonSmall
;
384 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
385 kind
= kThemeArrowButtonMini
;
387 kind
= kThemeArrowButton
;
389 DrawMacThemeButton(win
, dc
, rect
, flags
,
390 kind
, kThemeAdornmentArrowDownArrow
);
394 wxRendererMac::DrawPushButton(wxWindow
*win
,
400 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
401 kind
= kThemeBevelButtonSmall
;
402 // There is no kThemeBevelButtonMini, but in this case, use Small
403 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
404 kind
= kThemeBevelButtonSmall
;
406 kind
= kThemeBevelButton
;
408 DrawMacThemeButton(win
, dc
, rect
, flags
,
409 kind
, kThemeAdornmentNone
);
413 wxRendererMac::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
417 wxDelegateRendererNative::DrawFocusRect(win
, dc
, rect
, flags
);
421 CGRect cgrect
= CGRectMake( rect
.x
, rect
.y
, rect
.width
, rect
.height
) ;
423 HIThemeFrameDrawInfo info
;
424 memset( &info
, 0 , sizeof(info
) ) ;
428 info
.state
= kThemeStateActive
;
429 info
.isFocused
= true ;
431 CGContextRef cgContext
= (CGContextRef
) win
->MacGetCGContextRef() ;
432 wxASSERT( cgContext
) ;
434 HIThemeDrawFocusRect( &cgrect
, true , cgContext
, kHIThemeOrientationNormal
) ;