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"
33 // check if we're currently in a paint event
34 inline bool wxInPaintEvent(wxWindow
* win
, wxDC
& dc
)
37 return ( win
->MacGetCGContextRef() != NULL
);
42 class WXDLLEXPORT wxRendererMac
: public wxDelegateRendererNative
45 // draw the header control button (used by wxListCtrl)
46 virtual int DrawHeaderButton( wxWindow
*win
,
50 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
,
51 wxHeaderButtonParams
* params
= NULL
);
53 virtual int GetHeaderButtonHeight(wxWindow
*win
);
55 // draw the expanded/collapsed icon for a tree control item
56 virtual void DrawTreeItemButton( wxWindow
*win
,
61 // draw a (vertical) sash
62 virtual void DrawSplitterSash( wxWindow
*win
,
69 virtual void DrawCheckBox(wxWindow
*win
,
74 virtual wxSize
GetCheckBoxSize(wxWindow
* win
);
76 virtual void DrawComboBoxDropButton(wxWindow
*win
,
81 virtual void DrawPushButton(wxWindow
*win
,
86 virtual void DrawItemSelectionRect(wxWindow
*win
,
91 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
93 virtual void DrawChoice(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
95 virtual void DrawComboBox(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
97 virtual void DrawTextCtrl(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
99 virtual void DrawRadioBitmap(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
102 void DrawMacThemeButton(wxWindow
*win
,
110 wxBitmap m_bmpTreeExpanded
;
111 wxBitmap m_bmpTreeCollapsed
;
114 // ============================================================================
116 // ============================================================================
119 wxRendererNative
& wxRendererNative::GetDefault()
121 static wxRendererMac s_rendererMac
;
123 return s_rendererMac
;
126 int wxRendererMac::DrawHeaderButton( wxWindow
*win
,
130 wxHeaderSortIconType sortArrow
,
131 wxHeaderButtonParams
* params
)
133 const wxCoord x
= rect
.x
;
134 const wxCoord y
= rect
.y
;
135 const wxCoord w
= rect
.width
;
136 const wxCoord h
= rect
.height
;
138 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
140 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
141 if ( !wxInPaintEvent(win
, dc
) )
143 win
->Refresh( &rect
);
147 CGContextRef cgContext
;
148 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
150 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
153 HIThemeButtonDrawInfo drawInfo
;
156 memset( &drawInfo
, 0, sizeof(drawInfo
) );
157 drawInfo
.version
= 0;
158 drawInfo
.kind
= kThemeListHeaderButton
;
159 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
160 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
161 drawInfo
.adornment
= kThemeAdornmentNone
;
163 // The down arrow is drawn automatically, change it to an up arrow if needed.
164 if ( sortArrow
== wxHDR_SORT_ICON_UP
)
165 drawInfo
.adornment
= kThemeAdornmentHeaderButtonSortUp
;
167 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
169 // If we don't want any arrows we need to draw over the one already there
170 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
== wxHDR_SORT_ICON_NONE
) )
172 // clip to the header rectangle
173 CGContextSaveGState( cgContext
);
174 CGContextClipToRect( cgContext
, headerRect
);
175 // but draw bigger than that so the arrow will get clipped off
176 headerRect
.size
.width
+= 25;
177 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
178 CGContextRestoreGState( cgContext
);
183 // Reserve room for the arrows before writing the label, and turn off the
184 // flags we've already handled
185 wxRect
newRect(rect
);
186 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
!= wxHDR_SORT_ICON_NONE
) )
189 sortArrow
= wxHDR_SORT_ICON_NONE
;
191 flags
&= ~wxCONTROL_SELECTED
;
193 return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
);
197 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
))
199 SInt32 standardHeight
;
202 errStatus
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight
);
203 if (errStatus
== noErr
)
205 return standardHeight
;
210 void wxRendererMac::DrawTreeItemButton( wxWindow
*win
,
215 // now the wxGCDC is using native transformations
216 const wxCoord x
= rect
.x
;
217 const wxCoord y
= rect
.y
;
218 const wxCoord w
= rect
.width
;
219 const wxCoord h
= rect
.height
;
221 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
223 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
224 if ( !wxInPaintEvent(win
, dc
) )
226 win
->Refresh( &rect
);
230 CGContextRef cgContext
;
232 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
233 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
235 HIThemeButtonDrawInfo drawInfo
;
238 memset( &drawInfo
, 0, sizeof(drawInfo
) );
239 drawInfo
.version
= 0;
240 drawInfo
.kind
= kThemeDisclosureButton
;
241 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
242 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
243 // We need to set the value using the 'old' DrawThemeButton constants instead.
244 drawInfo
.value
= (flags
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown
: kThemeDisclosureRight
;
245 drawInfo
.adornment
= kThemeAdornmentNone
;
247 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
251 void wxRendererMac::DrawSplitterSash( wxWindow
*win
,
255 wxOrientation orient
,
256 int WXUNUSED(flags
) )
258 bool hasMetal
= win
->MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL
;
260 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height
);
262 if (orient
== wxVERTICAL
)
263 splitterRect
= CGRectMake( position
, 0, height
, size
.y
);
265 splitterRect
= CGRectMake( 0, position
, size
.x
, height
);
267 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
268 // strange redraw errors occur if we don't do this
270 if ( !wxInPaintEvent(win
, dc
) )
272 wxRect
rect( (int) splitterRect
.origin
.x
, (int) splitterRect
.origin
.y
, (int) splitterRect
.size
.width
,
273 (int) splitterRect
.size
.height
);
274 win
->Refresh( &rect
);
278 CGContextRef cgContext
;
279 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
280 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
282 HIThemeSplitterDrawInfo drawInfo
;
283 drawInfo
.version
= 0;
284 drawInfo
.state
= kThemeStateActive
;
285 drawInfo
.adornment
= hasMetal
? kHIThemeSplitterAdornmentMetal
: kHIThemeSplitterAdornmentNone
;
286 HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);
291 wxRendererMac::DrawItemSelectionRect(wxWindow
* WXUNUSED(win
),
296 if ( !(flags
& wxCONTROL_SELECTED
) )
299 wxColour
col( wxMacCreateCGColorFromHITheme( (flags
& wxCONTROL_FOCUSED
) ?
300 kThemeBrushAlternatePrimaryHighlightColor
301 : kThemeBrushSecondaryHighlightColor
) );
302 wxBrush
selBrush( col
);
304 dc
.SetPen( *wxTRANSPARENT_PEN
);
305 dc
.SetBrush( selBrush
);
306 dc
.DrawRectangle( rect
);
311 wxRendererMac::DrawMacThemeButton(wxWindow
*win
,
318 // now the wxGCDC is using native transformations
319 const wxCoord x
= rect
.x
;
320 const wxCoord y
= rect
.y
;
321 const wxCoord w
= rect
.width
;
322 const wxCoord h
= rect
.height
;
324 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
326 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
327 if ( !wxInPaintEvent(win
, dc
) )
329 win
->Refresh( &rect
);
333 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
334 CGContextRef cgContext
;
335 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
337 HIThemeButtonDrawInfo drawInfo
;
340 memset( &drawInfo
, 0, sizeof(drawInfo
) );
341 drawInfo
.version
= 0;
342 drawInfo
.kind
= kind
;
343 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
344 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
345 if (flags
& wxCONTROL_UNDETERMINED
)
346 drawInfo
.value
= kThemeButtonMixed
;
347 drawInfo
.adornment
= adornment
;
348 if (flags
& wxCONTROL_FOCUSED
)
349 drawInfo
.adornment
|= kThemeAdornmentFocus
;
351 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
356 wxRendererMac::DrawCheckBox(wxWindow
*win
,
361 if (flags
& wxCONTROL_CHECKED
)
362 flags
|= wxCONTROL_SELECTED
;
366 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
367 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
368 kind
= kThemeCheckBoxSmall
;
369 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
370 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
371 kind
= kThemeCheckBoxMini
;
373 kind
= kThemeCheckBox
;
376 DrawMacThemeButton(win
, dc
, rect
, flags
,
377 kind
, kThemeAdornmentNone
);
380 wxSize
wxRendererMac::GetCheckBoxSize(wxWindow
* WXUNUSED(win
))
383 SInt32 width
, height
;
386 errStatus
= GetThemeMetric(kThemeMetricCheckBoxWidth
, &width
);
387 if (errStatus
== noErr
)
389 size
.SetWidth(width
);
392 errStatus
= GetThemeMetric(kThemeMetricCheckBoxHeight
, &height
);
393 if (errStatus
== noErr
)
395 size
.SetHeight(height
);
402 wxRendererMac::DrawComboBoxDropButton(wxWindow
*win
,
408 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
409 kind
= kThemeArrowButtonSmall
;
410 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
411 kind
= kThemeArrowButtonMini
;
413 kind
= kThemeArrowButton
;
415 DrawMacThemeButton(win
, dc
, rect
, flags
,
416 kind
, kThemeAdornmentArrowDownArrow
);
420 wxRendererMac::DrawPushButton(wxWindow
*win
,
426 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
427 kind
= kThemeBevelButtonSmall
;
428 // There is no kThemeBevelButtonMini, but in this case, use Small
429 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
430 kind
= kThemeBevelButtonSmall
;
432 kind
= kThemeBevelButton
;
434 DrawMacThemeButton(win
, dc
, rect
, flags
,
435 kind
, kThemeAdornmentNone
);
439 wxRendererMac::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
443 wxDelegateRendererNative::DrawFocusRect(win
, dc
, rect
, flags
);
447 CGRect cgrect
= CGRectMake( rect
.x
, rect
.y
, rect
.width
, rect
.height
) ;
449 HIThemeFrameDrawInfo info
;
451 memset( &info
, 0 , sizeof(info
) ) ;
455 info
.state
= kThemeStateActive
;
456 info
.isFocused
= true ;
458 CGContextRef cgContext
= (CGContextRef
) win
->MacGetCGContextRef() ;
459 wxASSERT( cgContext
) ;
461 HIThemeDrawFocusRect( &cgrect
, true , cgContext
, kHIThemeOrientationNormal
) ;
464 void wxRendererMac::DrawChoice(wxWindow
* win
, wxDC
& dc
,
465 const wxRect
& rect
, int flags
)
469 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
470 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
471 kind
= kThemePopupButtonSmall
;
472 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
473 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
474 kind
= kThemePopupButtonMini
;
476 kind
= kThemePopupButton
;
478 DrawMacThemeButton(win
, dc
, rect
, flags
, kind
, kThemeAdornmentNone
);
482 void wxRendererMac::DrawComboBox(wxWindow
* win
, wxDC
& dc
,
483 const wxRect
& rect
, int flags
)
487 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
488 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
489 kind
= kThemeComboBoxSmall
;
490 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
491 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
492 kind
= kThemeComboBoxMini
;
494 kind
= kThemeComboBox
;
496 DrawMacThemeButton(win
, dc
, rect
, flags
, kind
, kThemeAdornmentNone
);
499 void wxRendererMac::DrawRadioBitmap(wxWindow
* win
, wxDC
& dc
,
500 const wxRect
& rect
, int flags
)
504 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
505 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
506 kind
= kThemeRadioButtonSmall
;
507 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
508 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
509 kind
= kThemeRadioButtonMini
;
511 kind
= kThemeRadioButton
;
513 if (flags
& wxCONTROL_CHECKED
)
514 flags
|= wxCONTROL_SELECTED
;
516 DrawMacThemeButton(win
, dc
, rect
, flags
,
517 kind
, kThemeAdornmentNone
);
520 void wxRendererMac::DrawTextCtrl(wxWindow
* win
, wxDC
& dc
,
521 const wxRect
& rect
, int flags
)
523 const wxCoord x
= rect
.x
;
524 const wxCoord y
= rect
.y
;
525 const wxCoord w
= rect
.width
;
526 const wxCoord h
= rect
.height
;
528 dc
.SetBrush( *wxWHITE_BRUSH
);
529 dc
.SetPen( *wxTRANSPARENT_PEN
);
530 dc
.DrawRectangle(rect
);
532 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
534 HIRect hiRect
= CGRectMake( x
, y
, w
, h
);
535 if ( !wxInPaintEvent(win
, dc
) )
537 win
->Refresh( &rect
);
541 CGContextRef cgContext
;
543 cgContext
= (CGContextRef
) static_cast<wxGCDCImpl
*>(dc
.GetImpl())->GetGraphicsContext()->GetNativeContext();
546 HIThemeFrameDrawInfo drawInfo
;
548 memset( &drawInfo
, 0, sizeof(drawInfo
) );
549 drawInfo
.version
= 0;
550 drawInfo
.kind
= kHIThemeFrameTextFieldSquare
;
551 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
552 if (flags
& wxCONTROL_FOCUSED
)
553 drawInfo
.isFocused
= true;
555 HIThemeDrawFrame( &hiRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);