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 // check if we're currently in a paint event
39 inline bool wxInPaintEvent(wxWindow
* win
, wxDC
& dc
)
42 return ( win
->MacGetCGContextRef() != NULL
);
47 class WXDLLEXPORT wxRendererMac
: public wxDelegateRendererNative
50 // draw the header control button (used by wxListCtrl)
51 virtual int DrawHeaderButton( wxWindow
*win
,
55 wxHeaderSortIconType sortArrow
= wxHDR_SORT_ICON_NONE
,
56 wxHeaderButtonParams
* params
= NULL
);
58 virtual int GetHeaderButtonHeight(wxWindow
*win
);
60 // draw the expanded/collapsed icon for a tree control item
61 virtual void DrawTreeItemButton( wxWindow
*win
,
66 // draw a (vertical) sash
67 virtual void DrawSplitterSash( wxWindow
*win
,
74 virtual void DrawCheckBox(wxWindow
*win
,
79 virtual wxSize
GetCheckBoxSize(wxWindow
* win
);
81 virtual void DrawComboBoxDropButton(wxWindow
*win
,
86 virtual void DrawPushButton(wxWindow
*win
,
91 virtual void DrawItemSelectionRect(wxWindow
*win
,
96 virtual void DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
= 0);
98 virtual void DrawChoice(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
100 virtual void DrawComboBox(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
102 virtual void DrawTextCtrl(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
104 virtual void DrawRadioButton(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
=0);
107 void DrawMacThemeButton(wxWindow
*win
,
115 wxBitmap m_bmpTreeExpanded
;
116 wxBitmap m_bmpTreeCollapsed
;
119 // ============================================================================
121 // ============================================================================
124 wxRendererNative
& wxRendererNative::GetDefault()
126 static wxRendererMac s_rendererMac
;
128 return s_rendererMac
;
131 int wxRendererMac::DrawHeaderButton( wxWindow
*win
,
135 wxHeaderSortIconType sortArrow
,
136 wxHeaderButtonParams
* params
)
138 const wxCoord x
= rect
.x
;
139 const wxCoord y
= rect
.y
;
140 const wxCoord w
= rect
.width
;
141 const wxCoord h
= rect
.height
;
143 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
145 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
146 if ( !wxInPaintEvent(win
, dc
) )
148 win
->Refresh( &rect
);
152 CGContextRef cgContext
;
153 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
155 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
158 HIThemeButtonDrawInfo drawInfo
;
161 memset( &drawInfo
, 0, sizeof(drawInfo
) );
162 drawInfo
.version
= 0;
163 drawInfo
.kind
= kThemeListHeaderButton
;
164 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
165 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
166 drawInfo
.adornment
= kThemeAdornmentNone
;
168 // The down arrow is drawn automatically, change it to an up arrow if needed.
169 if ( sortArrow
== wxHDR_SORT_ICON_UP
)
170 drawInfo
.adornment
= kThemeAdornmentHeaderButtonSortUp
;
172 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
174 // If we don't want any arrows we need to draw over the one already there
175 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
== wxHDR_SORT_ICON_NONE
) )
177 // clip to the header rectangle
178 CGContextSaveGState( cgContext
);
179 CGContextClipToRect( cgContext
, headerRect
);
180 // but draw bigger than that so the arrow will get clipped off
181 headerRect
.size
.width
+= 25;
182 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
183 CGContextRestoreGState( cgContext
);
188 // Reserve room for the arrows before writing the label, and turn off the
189 // flags we've already handled
190 wxRect
newRect(rect
);
191 if ( (flags
& wxCONTROL_SELECTED
) && (sortArrow
!= wxHDR_SORT_ICON_NONE
) )
194 sortArrow
= wxHDR_SORT_ICON_NONE
;
196 flags
&= ~wxCONTROL_SELECTED
;
198 return DrawHeaderButtonContents(win
, dc
, newRect
, flags
, sortArrow
, params
);
202 int wxRendererMac::GetHeaderButtonHeight(wxWindow
* WXUNUSED(win
))
204 SInt32 standardHeight
;
207 errStatus
= GetThemeMetric( kThemeMetricListHeaderHeight
, &standardHeight
);
208 if (errStatus
== noErr
)
210 return standardHeight
;
215 void wxRendererMac::DrawTreeItemButton( wxWindow
*win
,
220 // now the wxGCDC is using native transformations
221 const wxCoord x
= rect
.x
;
222 const wxCoord y
= rect
.y
;
223 const wxCoord w
= rect
.width
;
224 const wxCoord h
= rect
.height
;
226 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
228 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
229 if ( !wxInPaintEvent(win
, dc
) )
231 win
->Refresh( &rect
);
235 CGContextRef cgContext
;
237 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
238 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
240 HIThemeButtonDrawInfo drawInfo
;
243 memset( &drawInfo
, 0, sizeof(drawInfo
) );
244 drawInfo
.version
= 0;
245 drawInfo
.kind
= kThemeDisclosureButton
;
246 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
247 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
248 // We need to set the value using the 'old' DrawThemeButton constants instead.
249 drawInfo
.value
= (flags
& wxCONTROL_EXPANDED
) ? kThemeDisclosureDown
: kThemeDisclosureRight
;
250 drawInfo
.adornment
= kThemeAdornmentNone
;
252 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
256 void wxRendererMac::DrawSplitterSash( wxWindow
*win
,
260 wxOrientation orient
,
261 int WXUNUSED(flags
) )
263 bool hasMetal
= win
->MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL
;
265 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight
, &height
);
267 if (orient
== wxVERTICAL
)
268 splitterRect
= CGRectMake( position
, 0, height
, size
.y
);
270 splitterRect
= CGRectMake( 0, position
, size
.x
, height
);
272 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
273 // strange redraw errors occur if we don't do this
275 if ( !wxInPaintEvent(win
, dc
) )
277 wxRect
rect( (int) splitterRect
.origin
.x
, (int) splitterRect
.origin
.y
, (int) splitterRect
.size
.width
,
278 (int) splitterRect
.size
.height
);
279 win
->Refresh( &rect
);
283 CGContextRef cgContext
;
284 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
285 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
287 HIThemeSplitterDrawInfo drawInfo
;
288 drawInfo
.version
= 0;
289 drawInfo
.state
= kThemeStateActive
;
290 drawInfo
.adornment
= hasMetal
? kHIThemeSplitterAdornmentMetal
: kHIThemeSplitterAdornmentNone
;
291 HIThemeDrawPaneSplitter( &splitterRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);
296 wxRendererMac::DrawItemSelectionRect(wxWindow
* WXUNUSED(win
),
301 if ( !(flags
& wxCONTROL_SELECTED
) )
304 wxColour
col( wxMacCreateCGColorFromHITheme( (flags
& wxCONTROL_FOCUSED
) ?
305 kThemeBrushAlternatePrimaryHighlightColor
306 : kThemeBrushSecondaryHighlightColor
) );
307 wxBrush
selBrush( col
);
309 dc
.SetPen( *wxTRANSPARENT_PEN
);
310 dc
.SetBrush( selBrush
);
311 dc
.DrawRectangle( rect
);
316 wxRendererMac::DrawMacThemeButton(wxWindow
*win
,
323 // now the wxGCDC is using native transformations
324 const wxCoord x
= rect
.x
;
325 const wxCoord y
= rect
.y
;
326 const wxCoord w
= rect
.width
;
327 const wxCoord h
= rect
.height
;
329 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
331 HIRect headerRect
= CGRectMake( x
, y
, w
, h
);
332 if ( !wxInPaintEvent(win
, dc
) )
334 win
->Refresh( &rect
);
338 wxGCDCImpl
*impl
= (wxGCDCImpl
*) dc
.GetImpl();
339 CGContextRef cgContext
;
340 cgContext
= (CGContextRef
) impl
->GetGraphicsContext()->GetNativeContext();
342 HIThemeButtonDrawInfo drawInfo
;
345 memset( &drawInfo
, 0, sizeof(drawInfo
) );
346 drawInfo
.version
= 0;
347 drawInfo
.kind
= kind
;
348 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
349 drawInfo
.value
= (flags
& wxCONTROL_SELECTED
) ? kThemeButtonOn
: kThemeButtonOff
;
350 if (flags
& wxCONTROL_UNDETERMINED
)
351 drawInfo
.value
= kThemeButtonMixed
;
352 drawInfo
.adornment
= adornment
;
353 if (flags
& wxCONTROL_FOCUSED
)
354 drawInfo
.adornment
|= kThemeAdornmentFocus
;
356 HIThemeDrawButton( &headerRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
, &labelRect
);
361 wxRendererMac::DrawCheckBox(wxWindow
*win
,
366 if (flags
& wxCONTROL_CHECKED
)
367 flags
|= wxCONTROL_SELECTED
;
371 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
372 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
373 kind
= kThemeCheckBoxSmall
;
374 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
375 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
376 kind
= kThemeCheckBoxMini
;
378 kind
= kThemeCheckBox
;
381 DrawMacThemeButton(win
, dc
, rect
, flags
,
382 kind
, kThemeAdornmentNone
);
385 wxSize
wxRendererMac::GetCheckBoxSize(wxWindow
* WXUNUSED(win
))
388 SInt32 width
, height
;
391 errStatus
= GetThemeMetric(kThemeMetricCheckBoxWidth
, &width
);
392 if (errStatus
== noErr
)
394 size
.SetWidth(width
);
397 errStatus
= GetThemeMetric(kThemeMetricCheckBoxHeight
, &height
);
398 if (errStatus
== noErr
)
400 size
.SetHeight(height
);
407 wxRendererMac::DrawComboBoxDropButton(wxWindow
*win
,
413 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
414 kind
= kThemeArrowButtonSmall
;
415 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
416 kind
= kThemeArrowButtonMini
;
418 kind
= kThemeArrowButton
;
420 DrawMacThemeButton(win
, dc
, rect
, flags
,
421 kind
, kThemeAdornmentArrowDownArrow
);
425 wxRendererMac::DrawPushButton(wxWindow
*win
,
431 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
432 kind
= kThemeBevelButtonSmall
;
433 // There is no kThemeBevelButtonMini, but in this case, use Small
434 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
|| (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
435 kind
= kThemeBevelButtonSmall
;
437 kind
= kThemeBevelButton
;
439 DrawMacThemeButton(win
, dc
, rect
, flags
,
440 kind
, kThemeAdornmentNone
);
444 wxRendererMac::DrawFocusRect(wxWindow
* win
, wxDC
& dc
, const wxRect
& rect
, int flags
)
448 wxDelegateRendererNative::DrawFocusRect(win
, dc
, rect
, flags
);
452 CGRect cgrect
= CGRectMake( rect
.x
, rect
.y
, rect
.width
, rect
.height
) ;
454 HIThemeFrameDrawInfo info
;
456 memset( &info
, 0 , sizeof(info
) ) ;
460 info
.state
= kThemeStateActive
;
461 info
.isFocused
= true ;
463 CGContextRef cgContext
= (CGContextRef
) win
->MacGetCGContextRef() ;
464 wxASSERT( cgContext
) ;
466 HIThemeDrawFocusRect( &cgrect
, true , cgContext
, kHIThemeOrientationNormal
) ;
469 void wxRendererMac::DrawChoice(wxWindow
* win
, wxDC
& dc
,
470 const wxRect
& rect
, int flags
)
474 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
475 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
476 kind
= kThemePopupButtonSmall
;
477 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
478 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
479 kind
= kThemePopupButtonMini
;
481 kind
= kThemePopupButton
;
483 DrawMacThemeButton(win
, dc
, rect
, flags
, kind
, kThemeAdornmentNone
);
487 void wxRendererMac::DrawComboBox(wxWindow
* win
, wxDC
& dc
,
488 const wxRect
& rect
, int flags
)
492 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
493 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
494 kind
= kThemeComboBoxSmall
;
495 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
496 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
497 kind
= kThemeComboBoxMini
;
499 kind
= kThemeComboBox
;
501 DrawMacThemeButton(win
, dc
, rect
, flags
, kind
, kThemeAdornmentNone
);
504 void wxRendererMac::DrawRadioButton(wxWindow
* win
, wxDC
& dc
,
505 const wxRect
& rect
, int flags
)
509 if (win
->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
||
510 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL
))
511 kind
= kThemeRadioButtonSmall
;
512 else if (win
->GetWindowVariant() == wxWINDOW_VARIANT_MINI
||
513 (win
->GetParent() && win
->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI
))
514 kind
= kThemeRadioButtonMini
;
516 kind
= kThemeRadioButton
;
518 if (flags
& wxCONTROL_CHECKED
)
519 flags
|= wxCONTROL_SELECTED
;
521 DrawMacThemeButton(win
, dc
, rect
, flags
,
522 kind
, kThemeAdornmentNone
);
525 void wxRendererMac::DrawTextCtrl(wxWindow
* win
, wxDC
& dc
,
526 const wxRect
& rect
, int flags
)
528 const wxCoord x
= rect
.x
;
529 const wxCoord y
= rect
.y
;
530 const wxCoord w
= rect
.width
;
531 const wxCoord h
= rect
.height
;
533 dc
.SetBrush( *wxWHITE_BRUSH
);
534 dc
.SetPen( *wxTRANSPARENT_PEN
);
535 dc
.DrawRectangle(rect
);
537 dc
.SetBrush( *wxTRANSPARENT_BRUSH
);
539 HIRect hiRect
= CGRectMake( x
, y
, w
, h
);
540 if ( !wxInPaintEvent(win
, dc
) )
542 win
->Refresh( &rect
);
546 CGContextRef cgContext
;
548 cgContext
= (CGContextRef
) static_cast<wxGCDCImpl
*>(dc
.GetImpl())->GetGraphicsContext()->GetNativeContext();
551 HIThemeFrameDrawInfo drawInfo
;
553 memset( &drawInfo
, 0, sizeof(drawInfo
) );
554 drawInfo
.version
= 0;
555 drawInfo
.kind
= kHIThemeFrameTextFieldSquare
;
556 drawInfo
.state
= (flags
& wxCONTROL_DISABLED
) ? kThemeStateInactive
: kThemeStateActive
;
557 if (flags
& wxCONTROL_FOCUSED
)
558 drawInfo
.isFocused
= true;
560 HIThemeDrawFrame( &hiRect
, &drawInfo
, cgContext
, kHIThemeOrientationNormal
);