1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/osx/carbon/renderer.cpp
3 // Purpose:     implementation of wxRendererNative for Mac
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     20.07.2003
7 // Copyright:   (c) 2003 Vadim Zeitlin <vadim@wxwidgets.org>
8 // Licence:     wxWindows licence
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // for compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
13 
14 #if wxOSX_USE_COCOA_OR_CARBON
15 
16 
17 #ifndef WX_PRECOMP
18     #include "wx/string.h"
19     #include "wx/dc.h"
20     #include "wx/bitmap.h"
21     #include "wx/settings.h"
22     #include "wx/dcclient.h"
23     #include "wx/dcmemory.h"
24     #include "wx/toplevel.h"
25 #endif
26 
27 #include "wx/renderer.h"
28 #include "wx/graphics.h"
29 #include "wx/dcgraph.h"
30 #include "wx/splitter.h"
31 #include "wx/time.h"
32 #include "wx/osx/private.h"
33 #include "wx/osx/private/available.h"
34 
35 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
36     #include "wx/image.h"
37     #include "wx/mstream.h"
38 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
39 
40 
41 // check if we're having a CGContext we can draw into
wxHasCGContext(wxWindow * WXUNUSED (win),wxDC & dc)42 inline bool wxHasCGContext(wxWindow* WXUNUSED(win), wxDC& dc)
43 {
44     wxGCDCImpl* gcdc = wxDynamicCast( dc.GetImpl() , wxGCDCImpl);
45 
46     if ( gcdc )
47     {
48         if ( gcdc->GetGraphicsContext()->GetNativeContext() )
49             return true;
50     }
51     return false;
52 }
53 
54 
55 
56 class WXDLLEXPORT wxRendererMac : public wxDelegateRendererNative
57 {
58 public:
59     // draw the header control button (used by wxListCtrl)
60     virtual int DrawHeaderButton( wxWindow *win,
61         wxDC& dc,
62         const wxRect& rect,
63         int flags = 0,
64         wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
65         wxHeaderButtonParams* params = NULL ) wxOVERRIDE;
66 
67     virtual int GetHeaderButtonHeight(wxWindow *win) wxOVERRIDE;
68 
69     virtual int GetHeaderButtonMargin(wxWindow *win) wxOVERRIDE;
70 
71     // draw the expanded/collapsed icon for a tree control item
72     virtual void DrawTreeItemButton( wxWindow *win,
73         wxDC& dc,
74         const wxRect& rect,
75         int flags = 0 ) wxOVERRIDE;
76 
77     // draw a (vertical) sash
78     virtual void DrawSplitterSash( wxWindow *win,
79         wxDC& dc,
80         const wxSize& size,
81         wxCoord position,
82         wxOrientation orient,
83         int flags = 0 ) wxOVERRIDE;
84 
85     virtual void DrawCheckBox(wxWindow *win,
86                               wxDC& dc,
87                               const wxRect& rect,
88                               int flags = 0) wxOVERRIDE;
89 
90     virtual wxSize GetCheckBoxSize(wxWindow* win, int flags = 0) wxOVERRIDE;
91 
92     virtual void DrawComboBoxDropButton(wxWindow *win,
93                                         wxDC& dc,
94                                         const wxRect& rect,
95                                         int flags = 0) wxOVERRIDE;
96 
97     virtual void DrawPushButton(wxWindow *win,
98                                 wxDC& dc,
99                                 const wxRect& rect,
100                                 int flags = 0) wxOVERRIDE;
101 
102     virtual void DrawCollapseButton(wxWindow *win,
103                                     wxDC& dc,
104                                     const wxRect& rect,
105                                     int flags = 0) wxOVERRIDE;
106 
107     virtual wxSize GetCollapseButtonSize(wxWindow *win, wxDC& dc) wxOVERRIDE;
108 
109     virtual void DrawItemSelectionRect(wxWindow *win,
110                                        wxDC& dc,
111                                        const wxRect& rect,
112                                        int flags = 0) wxOVERRIDE;
113 
114     virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0) wxOVERRIDE;
115 
116     virtual void DrawChoice(wxWindow* win, wxDC& dc, const wxRect& rect, int flags=0) wxOVERRIDE;
117 
118     virtual void DrawComboBox(wxWindow* win, wxDC& dc, const wxRect& rect, int flags=0) wxOVERRIDE;
119 
120     virtual void DrawTextCtrl(wxWindow* win, wxDC& dc, const wxRect& rect, int flags=0) wxOVERRIDE;
121 
122     virtual void DrawRadioBitmap(wxWindow* win, wxDC& dc, const wxRect& rect, int flags=0) wxOVERRIDE;
123 
124 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
125     virtual void DrawTitleBarBitmap(wxWindow *win,
126                                     wxDC& dc,
127                                     const wxRect& rect,
128                                     wxTitleBarButton button,
129                                     int flags = 0) wxOVERRIDE;
130 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
131 
132     virtual void DrawGauge(wxWindow* win,
133                            wxDC& dc,
134                            const wxRect& rect,
135                            int value,
136                            int max,
137                            int flags = 0) wxOVERRIDE;
138 
139     virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win) wxOVERRIDE;
140 
141 private:
142     void DrawMacThemeButton(wxWindow *win,
143                             wxDC& dc,
144                             const wxRect& rect,
145                             int flags,
146                             int kind,
147                             int adornment);
148 
149     // the tree buttons
150     wxBitmap m_bmpTreeExpanded;
151     wxBitmap m_bmpTreeCollapsed;
152 };
153 
154 // ============================================================================
155 // implementation
156 // ============================================================================
157 
158 // static
GetDefault()159 wxRendererNative& wxRendererNative::GetDefault()
160 {
161     static wxRendererMac s_rendererMac;
162 
163     return s_rendererMac;
164 }
165 
DrawHeaderButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags,wxHeaderSortIconType sortArrow,wxHeaderButtonParams * params)166 int wxRendererMac::DrawHeaderButton( wxWindow *win,
167     wxDC& dc,
168     const wxRect& rect,
169     int flags,
170     wxHeaderSortIconType sortArrow,
171     wxHeaderButtonParams* params )
172 {
173     if ( wxSystemSettings::GetAppearance().IsDark() )
174         return wxRendererNative::GetGeneric().DrawHeaderButton(win, dc,  rect, flags, sortArrow, params);
175 
176     const wxCoord x = rect.x;
177     const wxCoord y = rect.y;
178     const wxCoord w = rect.width;
179     const wxCoord h = rect.height;
180 
181     dc.SetBrush( *wxTRANSPARENT_BRUSH );
182 
183     HIRect headerRect = CGRectMake( x, y, w, h );
184     if ( !wxHasCGContext(win, dc) )
185     {
186         win->RefreshRect(rect);
187     }
188     else
189     {
190         CGContextRef cgContext;
191         wxGCDCImpl *impl = (wxGCDCImpl*) dc.GetImpl();
192 
193         cgContext = (CGContextRef) impl->GetGraphicsContext()->GetNativeContext();
194 
195         {
196             HIThemeButtonDrawInfo drawInfo;
197             HIRect labelRect;
198 
199             memset( &drawInfo, 0, sizeof(drawInfo) );
200             drawInfo.version = 0;
201             drawInfo.kind = kThemeListHeaderButton;
202             drawInfo.adornment = kThemeAdornmentNone;
203             drawInfo.value = kThemeButtonOff;
204             if ( flags & wxCONTROL_DISABLED )
205                 drawInfo.state = kThemeStateInactive;
206             else if ( flags & wxCONTROL_PRESSED )
207                 drawInfo.state = kThemeStatePressed;
208             else
209                 drawInfo.state = kThemeStateActive;
210 
211             // The down arrow is drawn automatically (if value is kThemeButtonOn)
212             // change it to an up arrow if needed.
213             if ( sortArrow == wxHDR_SORT_ICON_UP )
214             {
215                 drawInfo.adornment = kThemeAdornmentHeaderButtonSortUp;
216                 drawInfo.value = kThemeButtonOn;
217             }
218             else if (sortArrow == wxHDR_SORT_ICON_DOWN )
219             {
220                 drawInfo.value = kThemeButtonOn;
221             }
222 
223             HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
224         }
225     }
226 
227     // Reserve room for the arrows before writing the label, and turn off the
228     // flags we've already handled
229     wxRect newRect(rect);
230     if ( sortArrow != wxHDR_SORT_ICON_NONE )
231     {
232         newRect.width -= 12;
233         sortArrow = wxHDR_SORT_ICON_NONE;
234     }
235     flags &= ~wxCONTROL_PRESSED;
236 
237     return DrawHeaderButtonContents(win, dc, newRect, flags, sortArrow, params);
238 }
239 
240 
GetHeaderButtonHeight(wxWindow * WXUNUSED (win))241 int wxRendererMac::GetHeaderButtonHeight(wxWindow* WXUNUSED(win))
242 {
243     SInt32      standardHeight;
244     OSStatus        errStatus;
245 
246     errStatus = GetThemeMetric( kThemeMetricListHeaderHeight, &standardHeight );
247     if (errStatus == noErr)
248     {
249         return standardHeight;
250     }
251     return -1;
252 }
253 
GetHeaderButtonMargin(wxWindow * WXUNUSED (win))254 int wxRendererMac::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
255 {
256     return 0; // TODO: How to determine the real margin?
257 }
258 
DrawTreeItemButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)259 void wxRendererMac::DrawTreeItemButton( wxWindow *win,
260     wxDC& dc,
261     const wxRect& rect,
262     int flags )
263 {
264     // now the wxGCDC is using native transformations
265     const wxCoord x = rect.x;
266     const wxCoord y = rect.y;
267     const wxCoord w = rect.width;
268     const wxCoord h = rect.height;
269 
270     dc.SetBrush( *wxTRANSPARENT_BRUSH );
271 
272     HIRect headerRect = CGRectMake( x, y, w, h );
273     if ( !wxHasCGContext(win, dc) )
274     {
275         win->RefreshRect(rect);
276     }
277     else
278     {
279         CGContextRef cgContext;
280 
281         wxGCDCImpl *impl = (wxGCDCImpl*) dc.GetImpl();
282         cgContext = (CGContextRef) impl->GetGraphicsContext()->GetNativeContext();
283 
284         HIThemeButtonDrawInfo drawInfo;
285         HIRect labelRect;
286 
287         memset( &drawInfo, 0, sizeof(drawInfo) );
288         drawInfo.version = 0;
289         drawInfo.kind = kThemeDisclosureButton;
290         drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
291         // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
292         // We need to set the value using the 'old' DrawThemeButton constants instead.
293         drawInfo.value = (flags & wxCONTROL_EXPANDED) ? kThemeDisclosureDown : kThemeDisclosureRight;
294         drawInfo.adornment = kThemeAdornmentNone;
295 
296         HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
297     }
298 }
299 
300 wxSplitterRenderParams
GetSplitterParams(const wxWindow * win)301 wxRendererMac::GetSplitterParams(const wxWindow *win)
302 {
303     // see below
304     SInt32 sashWidth,
305             border;
306 #if wxOSX_USE_COCOA
307     if ( win->HasFlag(wxSP_3DSASH) )
308         GetThemeMetric( kThemeMetricPaneSplitterHeight, &sashWidth ); // Cocoa == Carbon == 7
309     else if ( win->HasFlag(wxSP_NOSASH) ) // actually Cocoa doesn't allow 0
310         sashWidth = 0;
311     else // no 3D effect - Cocoa [NSSplitView dividerThickNess] for NSSplitViewDividerStyleThin
312         sashWidth = 1;
313 #else // Carbon
314     if ( win->HasFlag(wxSP_3DSASH) )
315         GetThemeMetric( kThemeMetricPaneSplitterHeight, &sashWidth );
316     else if ( win->HasFlag(wxSP_NOSASH) )
317         sashWidth = 0;
318     else // no 3D effect
319         GetThemeMetric( kThemeMetricSmallPaneSplitterHeight, &sashWidth );
320 #endif // Cocoa/Carbon
321 
322     if ( win->HasFlag(wxSP_3DBORDER) )
323         border = 2;
324     else // no 3D effect
325         border = 0;
326 
327     return wxSplitterRenderParams(sashWidth, border, false);
328 }
329 
330 
DrawSplitterSash(wxWindow * win,wxDC & dc,const wxSize & size,wxCoord position,wxOrientation orient,int WXUNUSED (flags))331 void wxRendererMac::DrawSplitterSash( wxWindow *win,
332     wxDC& dc,
333     const wxSize& size,
334     wxCoord position,
335     wxOrientation orient,
336     int WXUNUSED(flags) )
337 {
338     // Note that we can't use ternary ?: operator or any other construct with
339     // logical operators here, WX_IS_MACOS_AVAILABLE() must appear inside an
340     // "if" statement to avoid -Wunsupported-availability-guard with Xcode 10.
341     bool hasMetal;
342     if (WX_IS_MACOS_AVAILABLE(10, 14))
343         hasMetal = false;
344     else
345         hasMetal = win->MacGetTopLevelWindow()->GetExtraStyle() & wxFRAME_EX_METAL;
346 
347     SInt32 height;
348 
349     height = wxRendererNative::Get().GetSplitterParams(win).widthSash;
350 
351     // Do not draw over border drawn by wxRendererGeneric::DrawSplitterBorder()
352     const wxCoord borderAdjust = win->HasFlag(wxSP_3DBORDER) ? 2 : 0;
353 
354     HIRect splitterRect;
355     if (orient == wxVERTICAL)
356         splitterRect = CGRectMake( position, borderAdjust, height, size.y - 2*borderAdjust );
357     else
358         splitterRect = CGRectMake( borderAdjust, position, size.x - 2*borderAdjust, height );
359 
360     // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
361     // strange redraw errors occur if we don't do this
362 
363     if ( !wxHasCGContext(win, dc) )
364     {
365         wxRect rect( (int) splitterRect.origin.x, (int) splitterRect.origin.y, (int) splitterRect.size.width,
366                      (int) splitterRect.size.height );
367         win->RefreshRect( rect );
368     }
369     else
370     {
371         CGContextRef cgContext;
372         wxGCDCImpl *impl = (wxGCDCImpl*) dc.GetImpl();
373         cgContext = (CGContextRef) impl->GetGraphicsContext()->GetNativeContext();
374 
375         if ( hasMetal )
376         {
377             HIThemeBackgroundDrawInfo bgdrawInfo;
378             bgdrawInfo.version = 0;
379             bgdrawInfo.state = kThemeStateActive;
380             bgdrawInfo.kind = hasMetal ? kThemeBackgroundMetal : kThemeBackgroundPlacard;
381 
382             HIThemeDrawBackground(&splitterRect, &bgdrawInfo, cgContext, kHIThemeOrientationNormal);
383         }
384         else
385         {
386             CGContextSetFillColorWithColor(cgContext,win->GetBackgroundColour().GetCGColor());
387             CGContextFillRect(cgContext,splitterRect);
388         }
389 
390         if ( win->HasFlag(wxSP_3DSASH) )
391         {
392             if ( !wxSystemSettings::GetAppearance().IsDark() )
393             {
394                 HIThemeSplitterDrawInfo drawInfo;
395                 drawInfo.version = 0;
396                 drawInfo.state = kThemeStateActive;
397                 drawInfo.adornment = hasMetal ? kHIThemeSplitterAdornmentMetal : kHIThemeSplitterAdornmentNone;
398                 HIThemeDrawPaneSplitter( &splitterRect, &drawInfo, cgContext, kHIThemeOrientationNormal );
399             }
400         }
401     }
402 }
403 
404 void
DrawItemSelectionRect(wxWindow * WXUNUSED (win),wxDC & dc,const wxRect & rect,int flags)405 wxRendererMac::DrawItemSelectionRect(wxWindow * WXUNUSED(win),
406                                      wxDC& dc,
407                                      const wxRect& rect,
408                                      int flags)
409 {
410     if ( !(flags & wxCONTROL_SELECTED) )
411         return;
412 
413     wxColour col( wxMacCreateCGColorFromHITheme( (flags & wxCONTROL_FOCUSED) ?
414                                                  kThemeBrushAlternatePrimaryHighlightColor
415                                                                              : kThemeBrushSecondaryHighlightColor ) );
416     wxBrush selBrush( col );
417 
418     dc.SetPen( *wxTRANSPARENT_PEN );
419     dc.SetBrush( selBrush );
420     dc.DrawRectangle( rect );
421 }
422 
423 
424 void
DrawMacThemeButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags,int kind,int adornment)425 wxRendererMac::DrawMacThemeButton(wxWindow *win,
426                                   wxDC& dc,
427                                   const wxRect& rect,
428                                   int flags,
429                                   int kind,
430                                   int adornment)
431 {
432     // now the wxGCDC is using native transformations
433     const wxCoord x = rect.x;
434     const wxCoord y = rect.y;
435     const wxCoord w = rect.width;
436     const wxCoord h = rect.height;
437 
438     dc.SetBrush( *wxTRANSPARENT_BRUSH );
439 
440     HIRect headerRect = CGRectMake( x, y, w, h );
441     if ( !wxHasCGContext(win, dc) )
442     {
443         win->RefreshRect(rect);
444     }
445     else
446     {
447         wxGCDCImpl *impl = (wxGCDCImpl*) dc.GetImpl();
448         CGContextRef cgContext;
449         cgContext = (CGContextRef) impl->GetGraphicsContext()->GetNativeContext();
450 
451         HIThemeButtonDrawInfo drawInfo;
452         HIRect labelRect;
453 
454         memset( &drawInfo, 0, sizeof(drawInfo) );
455         drawInfo.version = 0;
456         drawInfo.kind = kind;
457         drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
458         drawInfo.value = (flags & wxCONTROL_PRESSED) ? kThemeButtonOn : kThemeButtonOff;
459         if (flags & wxCONTROL_UNDETERMINED)
460             drawInfo.value = kThemeButtonMixed;
461         drawInfo.adornment = adornment;
462         if (flags & wxCONTROL_FOCUSED)
463             drawInfo.adornment |= kThemeAdornmentFocus;
464 
465         HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
466     }
467 }
468 
469 void
DrawCheckBox(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)470 wxRendererMac::DrawCheckBox(wxWindow *win,
471                             wxDC& dc,
472                             const wxRect& rect,
473                             int flags)
474 {
475     if (flags & wxCONTROL_CHECKED)
476         flags |= wxCONTROL_PRESSED;
477 
478     int kind;
479 
480     if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL ||
481         (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
482         kind = kThemeCheckBoxSmall;
483     else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI ||
484              (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
485         kind = kThemeCheckBoxMini;
486     else
487         kind = kThemeCheckBox;
488 
489 
490     DrawMacThemeButton(win, dc, rect, flags,
491                        kind, kThemeAdornmentNone);
492 }
493 
GetCheckBoxSize(wxWindow * win,int WXUNUSED (flags))494 wxSize wxRendererMac::GetCheckBoxSize(wxWindow* win, int WXUNUSED(flags))
495 {
496     // Even though we don't use the window in this implementation, still check
497     // that it's valid to avoid surprises when running the same code under the
498     // other platforms.
499     wxCHECK_MSG( win, wxSize(0, 0), "Must have a valid window" );
500 
501     wxSize size;
502     SInt32 width, height;
503     OSStatus errStatus;
504 
505     errStatus = GetThemeMetric(kThemeMetricCheckBoxWidth, &width);
506     if (errStatus == noErr)
507     {
508         size.SetWidth(width);
509     }
510 
511     errStatus = GetThemeMetric(kThemeMetricCheckBoxHeight, &height);
512     if (errStatus == noErr)
513     {
514         size.SetHeight(height);
515     }
516 
517     return size;
518 }
519 
520 void
DrawComboBoxDropButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)521 wxRendererMac::DrawComboBoxDropButton(wxWindow *win,
522                               wxDC& dc,
523                               const wxRect& rect,
524                               int flags)
525 {
526     int kind;
527     if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
528         kind = kThemeArrowButtonSmall;
529     else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
530         kind = kThemeArrowButtonMini;
531     else
532         kind = kThemeArrowButton;
533 
534     DrawMacThemeButton(win, dc, rect, flags,
535                        kind, kThemeAdornmentArrowDownArrow);
536 }
537 
538 void
DrawPushButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)539 wxRendererMac::DrawPushButton(wxWindow *win,
540                               wxDC& dc,
541                               const wxRect& rect,
542                               int flags)
543 {
544     int kind;
545     if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
546         kind = kThemeBevelButtonSmall;
547     // There is no kThemeBevelButtonMini, but in this case, use Small
548     else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
549         kind = kThemeBevelButtonSmall;
550     else
551         kind = kThemeBevelButton;
552 
553     DrawMacThemeButton(win, dc, rect, flags,
554                        kind, kThemeAdornmentNone);
555 }
556 
DrawCollapseButton(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)557 void wxRendererMac::DrawCollapseButton(wxWindow *win,
558                                 wxDC& dc,
559                                 const wxRect& rect,
560                                 int flags)
561 {
562     int adornment = (flags & wxCONTROL_EXPANDED)
563         ? kThemeAdornmentArrowUpArrow
564         : kThemeAdornmentArrowDownArrow;
565 
566     DrawMacThemeButton(win, dc, rect, flags,
567                        kThemeArrowButton, adornment);
568 }
569 
GetCollapseButtonSize(wxWindow * WXUNUSED (win),wxDC & WXUNUSED (dc))570 wxSize wxRendererMac::GetCollapseButtonSize(wxWindow *WXUNUSED(win), wxDC& WXUNUSED(dc))
571 {
572     wxSize size;
573     SInt32 width, height;
574     OSStatus errStatus;
575 
576     errStatus = GetThemeMetric(kThemeMetricDisclosureButtonWidth, &width);
577     if (errStatus == noErr)
578     {
579         size.SetWidth(width);
580     }
581 
582     errStatus = GetThemeMetric(kThemeMetricDisclosureButtonHeight, &height);
583     if (errStatus == noErr)
584     {
585         size.SetHeight(height);
586     }
587 
588     // strict metrics size cutoff the button, increase the size
589     size.IncBy(1);
590 
591     return size;
592 }
593 
594 void
DrawFocusRect(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)595 wxRendererMac::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
596 {
597     if (!win)
598     {
599         wxDelegateRendererNative::DrawFocusRect(win, dc, rect, flags);
600         return;
601     }
602 
603     CGRect cgrect = CGRectMake( rect.x , rect.y , rect.width, rect.height ) ;
604 
605     HIThemeFrameDrawInfo info ;
606 
607     memset( &info, 0 , sizeof(info) ) ;
608 
609     info.version = 0 ;
610     info.kind = 0 ;
611     info.state = kThemeStateActive;
612     info.isFocused = true ;
613 
614     CGContextRef cgContext = (CGContextRef) win->MacGetCGContextRef() ;
615     wxASSERT( cgContext ) ;
616 
617     HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ;
618 }
619 
DrawChoice(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)620 void wxRendererMac::DrawChoice(wxWindow* win, wxDC& dc,
621                            const wxRect& rect, int flags)
622 {
623     int kind;
624 
625     if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL ||
626         (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
627         kind = kThemePopupButtonSmall;
628     else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI ||
629              (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
630         kind = kThemePopupButtonMini;
631     else
632         kind = kThemePopupButton;
633 
634     DrawMacThemeButton(win, dc, rect, flags, kind, kThemeAdornmentNone);
635 }
636 
637 
DrawComboBox(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)638 void wxRendererMac::DrawComboBox(wxWindow* win, wxDC& dc,
639                              const wxRect& rect, int flags)
640 {
641     int kind;
642 
643     if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL ||
644         (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
645         kind = kThemeComboBoxSmall;
646     else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI ||
647              (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
648         kind = kThemeComboBoxMini;
649     else
650         kind = kThemeComboBox;
651 
652     DrawMacThemeButton(win, dc, rect, flags, kind, kThemeAdornmentNone);
653 }
654 
DrawRadioBitmap(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)655 void wxRendererMac::DrawRadioBitmap(wxWindow* win, wxDC& dc,
656                                 const wxRect& rect, int flags)
657 {
658     int kind;
659 
660     if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL ||
661         (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
662         kind = kThemeRadioButtonSmall;
663     else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI ||
664              (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
665         kind = kThemeRadioButtonMini;
666     else
667         kind = kThemeRadioButton;
668 
669     if (flags & wxCONTROL_CHECKED)
670         flags |= wxCONTROL_PRESSED;
671 
672     DrawMacThemeButton(win, dc, rect, flags,
673                           kind, kThemeAdornmentNone);
674 }
675 
DrawTextCtrl(wxWindow * win,wxDC & dc,const wxRect & rect,int flags)676 void wxRendererMac::DrawTextCtrl(wxWindow* win, wxDC& dc,
677                              const wxRect& rect, int flags)
678 {
679     const wxCoord x = rect.x;
680     const wxCoord y = rect.y;
681     const wxCoord w = rect.width;
682     const wxCoord h = rect.height;
683 
684     dc.SetBrush( *wxWHITE_BRUSH );
685     dc.SetPen( *wxTRANSPARENT_PEN );
686     dc.DrawRectangle(rect);
687 
688     dc.SetBrush( *wxTRANSPARENT_BRUSH );
689 
690     HIRect hiRect = CGRectMake( x, y, w, h );
691     if ( !wxHasCGContext(win, dc) )
692     {
693         win->RefreshRect(rect);
694     }
695     else
696     {
697         CGContextRef cgContext;
698 
699         cgContext = (CGContextRef) static_cast<wxGCDCImpl*>(dc.GetImpl())->GetGraphicsContext()->GetNativeContext();
700 
701         {
702             HIThemeFrameDrawInfo drawInfo;
703 
704             memset( &drawInfo, 0, sizeof(drawInfo) );
705             drawInfo.version = 0;
706             drawInfo.kind = kHIThemeFrameTextFieldSquare;
707             drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
708             if (flags & wxCONTROL_FOCUSED)
709                 drawInfo.isFocused = true;
710 
711             HIThemeDrawFrame( &hiRect, &drawInfo, cgContext, kHIThemeOrientationNormal);
712         }
713     }
714 }
715 
716 #ifdef wxHAS_DRAW_TITLE_BAR_BITMAP
717 
DrawTitleBarBitmap(wxWindow * win,wxDC & dc,const wxRect & rect,wxTitleBarButton button,int flags)718 void wxRendererMac::DrawTitleBarBitmap(wxWindow *win,
719                                        wxDC& dc,
720                                        const wxRect& rect,
721                                        wxTitleBarButton button,
722                                        int flags)
723 {
724     // currently we only support the close bitmap here
725     if ( button != wxTITLEBAR_BUTTON_CLOSE )
726     {
727         m_rendererNative.DrawTitleBarBitmap(win, dc, rect, button, flags);
728         return;
729     }
730 
731     wxColour glyphColor;
732 
733     // The following hard coded RGB values are based the close button in
734     // XCode 6+ welcome screen
735     bool drawCircle;
736     if ( flags & wxCONTROL_PRESSED )
737     {
738         drawCircle = true;
739         glyphColor = wxColour(104, 104, 104);
740         dc.SetPen(wxPen(wxColour(70, 70, 71), 1));
741         dc.SetBrush(wxColour(78, 78, 78));
742     }
743     else if ( flags & wxCONTROL_CURRENT )
744     {
745         drawCircle = true;
746         glyphColor = *wxWHITE;
747         dc.SetPen(wxPen(wxColour(163, 165, 166), 1));
748         dc.SetBrush(wxColour(182, 184, 187));
749     }
750     else
751     {
752         drawCircle = false;
753         glyphColor = wxColour(145, 147, 149);
754     }
755 
756     if ( drawCircle )
757     {
758         wxRect circleRect(rect);
759         circleRect.Deflate(2);
760 
761         dc.DrawEllipse(circleRect);
762     }
763 
764     dc.SetPen(wxPen(glyphColor, 1));
765 
766     wxRect centerRect(rect);
767     centerRect.Deflate(5);
768     centerRect.height++;
769     centerRect.width++;
770 
771     dc.DrawLine(centerRect.GetTopLeft(), centerRect.GetBottomRight());
772     dc.DrawLine(centerRect.GetTopRight(), centerRect.GetBottomLeft());
773 }
774 
775 #endif // wxHAS_DRAW_TITLE_BAR_BITMAP
776 
DrawGauge(wxWindow * WXUNUSED (win),wxDC & dc,const wxRect & rect,int value,int max,int WXUNUSED (flags))777 void wxRendererMac::DrawGauge(wxWindow* WXUNUSED(win),
778                               wxDC& dc,
779                               const wxRect& rect,
780                               int value,
781                               int max,
782                               int WXUNUSED(flags))
783 {
784     const wxCoord x = rect.x;
785     const wxCoord y = rect.y;
786     const wxCoord w = rect.width;
787     const wxCoord h = rect.height;
788 
789     HIThemeTrackDrawInfo tdi;
790     tdi.version = 0;
791     tdi.min = 0;
792     tdi.value = value;
793     tdi.max = max;
794     tdi.bounds = CGRectMake(x, y, w, h);
795     tdi.attributes = kThemeTrackHorizontal;
796     tdi.enableState = kThemeTrackActive;
797     tdi.kind = kThemeLargeProgressBar;
798 
799     int milliSecondsPerStep = 1000 / 60;
800     wxLongLongNative localTime = wxGetLocalTimeMillis();
801     tdi.trackInfo.progress.phase = localTime.GetValue() / milliSecondsPerStep % 32;
802 
803     CGContextRef cgContext;
804     wxGCDCImpl *impl = (wxGCDCImpl*) dc.GetImpl();
805 
806     cgContext = (CGContextRef) impl->GetGraphicsContext()->GetNativeContext();
807 
808     HIThemeDrawTrack(&tdi, NULL, cgContext, kHIThemeOrientationNormal);
809 }
810 
811 #endif
812