]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/renderer.cpp
e0f9bc23e2f4734b4eb8e1cac2bf0d7226c5f01e
[wxWidgets.git] / src / mac / carbon / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/mac/carbon/renderer.cpp
3 // Purpose: implementation of wxRendererNative for Mac
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 20.07.2003
7 // RCS-ID: $Id$
8 // Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9 // License: wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // for compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18
19 #ifndef WX_PRECOMP
20 #include "wx/string.h"
21 #include "wx/dc.h"
22 #include "wx/bitmap.h"
23 #include "wx/settings.h"
24 #include "wx/dcclient.h"
25 #include "wx/toplevel.h"
26 #endif
27
28 #include "wx/renderer.h"
29 #include "wx/graphics.h"
30 #include "wx/mac/uma.h"
31
32
33 class WXDLLEXPORT wxRendererMac : public wxDelegateRendererNative
34 {
35 public:
36 // draw the header control button (used by wxListCtrl)
37 virtual int DrawHeaderButton( wxWindow *win,
38 wxDC& dc,
39 const wxRect& rect,
40 int flags = 0,
41 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
42 wxHeaderButtonParams* params = NULL );
43
44 virtual int GetHeaderButtonHeight(wxWindow *win);
45
46 // draw the expanded/collapsed icon for a tree control item
47 virtual void DrawTreeItemButton( wxWindow *win,
48 wxDC& dc,
49 const wxRect& rect,
50 int flags = 0 );
51
52 // draw a (vertical) sash
53 virtual void DrawSplitterSash( wxWindow *win,
54 wxDC& dc,
55 const wxSize& size,
56 wxCoord position,
57 wxOrientation orient,
58 int flags = 0 );
59
60 virtual void DrawComboBoxDropButton(wxWindow *win,
61 wxDC& dc,
62 const wxRect& rect,
63 int flags = 0);
64
65 virtual void DrawPushButton(wxWindow *win,
66 wxDC& dc,
67 const wxRect& rect,
68 int flags = 0);
69
70 virtual void DrawItemSelectionRect(wxWindow *win,
71 wxDC& dc,
72 const wxRect& rect,
73 int flags = 0);
74
75 virtual void DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags = 0);
76
77 private:
78 void DrawMacThemeButton(wxWindow *win,
79 wxDC& dc,
80 const wxRect& rect,
81 int flags,
82 int kind,
83 int adornment);
84
85 // the tree buttons
86 wxBitmap m_bmpTreeExpanded;
87 wxBitmap m_bmpTreeCollapsed;
88 };
89
90 // ============================================================================
91 // implementation
92 // ============================================================================
93
94 // static
95 wxRendererNative& wxRendererNative::GetDefault()
96 {
97 static wxRendererMac s_rendererMac;
98
99 return s_rendererMac;
100 }
101
102 int wxRendererMac::DrawHeaderButton( wxWindow *win,
103 wxDC& dc,
104 const wxRect& rect,
105 int flags,
106 wxHeaderSortIconType sortArrow,
107 wxHeaderButtonParams* params )
108 {
109 #if !wxMAC_USE_CORE_GRAPHICS
110 const wxCoord x = dc.LogicalToDeviceX(rect.x);
111 const wxCoord y = dc.LogicalToDeviceY(rect.y);
112 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
113 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
114 #else
115 // now the wxGCDC is using native transformations
116 const wxCoord x = rect.x;
117 const wxCoord y = rect.y;
118 const wxCoord w = rect.width;
119 const wxCoord h = rect.height;
120 #endif
121
122 dc.SetBrush( *wxTRANSPARENT_BRUSH );
123
124 HIRect headerRect = CGRectMake( x, y, w, h );
125 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
126 {
127 Rect r =
128 {
129 (short) headerRect.origin.y, (short) headerRect.origin.x,
130 (short) (headerRect.origin.y + headerRect.size.height),
131 (short) (headerRect.origin.x + headerRect.size.width)
132 };
133
134 RgnHandle updateRgn = NewRgn();
135 RectRgn( updateRgn, &r );
136 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
137 DisposeRgn( updateRgn );
138 }
139 else
140 {
141 CGContextRef cgContext;
142
143 #if wxMAC_USE_CORE_GRAPHICS
144 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
145 #else
146 Rect bounds;
147
148 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
149 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
150
151 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
152 CGContextScaleCTM( cgContext, 1, -1 );
153
154 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
155 CGContextClip( cgContext );
156 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
157 #endif
158
159 {
160 HIThemeButtonDrawInfo drawInfo;
161 HIRect labelRect;
162
163 memset( &drawInfo, 0, sizeof(drawInfo) );
164 drawInfo.version = 0;
165 drawInfo.kind = kThemeListHeaderButton;
166 drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
167 drawInfo.value = (flags & wxCONTROL_SELECTED) ? kThemeButtonOn : kThemeButtonOff;
168 drawInfo.adornment = kThemeAdornmentNone;
169
170 // The down arrow is drawn automatically, change it to an up arrow if needed.
171 if ( sortArrow == wxHDR_SORT_ICON_UP )
172 drawInfo.adornment = kThemeAdornmentHeaderButtonSortUp;
173
174 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
175
176 // If we don't want any arrows we need to draw over the one already there
177 if ( (flags & wxCONTROL_SELECTED) && (sortArrow == wxHDR_SORT_ICON_NONE) )
178 {
179 // clip to the header rectangle
180 CGContextSaveGState( cgContext );
181 CGContextClipToRect( cgContext, headerRect );
182 // but draw bigger than that so the arrow will get clipped off
183 headerRect.size.width += 25;
184 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
185 CGContextRestoreGState( cgContext );
186 }
187 }
188
189 #if wxMAC_USE_CORE_GRAPHICS
190 #else
191 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
192 #endif
193 }
194
195 // Reserve room for the arrows before writing the label, and turn off the
196 // flags we've already handled
197 wxRect newRect(rect);
198 if ( (flags & wxCONTROL_SELECTED) && (sortArrow != wxHDR_SORT_ICON_NONE) )
199 {
200 newRect.width -= 12;
201 sortArrow = wxHDR_SORT_ICON_NONE;
202 }
203 flags &= ~wxCONTROL_SELECTED;
204
205 return DrawHeaderButtonContents(win, dc, newRect, flags, sortArrow, params);
206 }
207
208
209 int wxRendererMac::GetHeaderButtonHeight(wxWindow* WXUNUSED(win))
210 {
211 SInt32 standardHeight;
212 OSStatus errStatus;
213
214 errStatus = GetThemeMetric( kThemeMetricListHeaderHeight, &standardHeight );
215 if (errStatus == noErr)
216 {
217 return standardHeight;
218 }
219 return -1;
220 }
221
222 void wxRendererMac::DrawTreeItemButton( wxWindow *win,
223 wxDC& dc,
224 const wxRect& rect,
225 int flags )
226 {
227 #if !wxMAC_USE_CORE_GRAPHICS
228 const wxCoord x = dc.LogicalToDeviceX(rect.x);
229 const wxCoord y = dc.LogicalToDeviceY(rect.y);
230 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
231 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
232 #else
233 // now the wxGCDC is using native transformations
234 const wxCoord x = rect.x;
235 const wxCoord y = rect.y;
236 const wxCoord w = rect.width;
237 const wxCoord h = rect.height;
238 #endif
239
240 dc.SetBrush( *wxTRANSPARENT_BRUSH );
241
242 HIRect headerRect = CGRectMake( x, y, w, h );
243 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
244 {
245 Rect r =
246 {
247 (short) headerRect.origin.y, (short) headerRect.origin.x,
248 (short) (headerRect.origin.y + headerRect.size.height),
249 (short) (headerRect.origin.x + headerRect.size.width)
250 };
251
252 RgnHandle updateRgn = NewRgn();
253 RectRgn( updateRgn, &r );
254 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
255 DisposeRgn( updateRgn );
256 }
257 else
258 {
259 CGContextRef cgContext;
260
261 #if wxMAC_USE_CORE_GRAPHICS
262 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
263 #else
264 Rect bounds;
265
266 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
267 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
268
269 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
270 CGContextScaleCTM( cgContext, 1, -1 );
271
272 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
273 CGContextClip( cgContext );
274 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
275 #endif
276
277 {
278 HIThemeButtonDrawInfo drawInfo;
279 HIRect labelRect;
280
281 memset( &drawInfo, 0, sizeof(drawInfo) );
282 drawInfo.version = 0;
283 drawInfo.kind = kThemeDisclosureButton;
284 drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
285 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
286 // We need to set the value using the 'old' DrawThemeButton constants instead.
287 drawInfo.value = (flags & wxCONTROL_EXPANDED) ? kThemeDisclosureDown : kThemeDisclosureRight;
288 drawInfo.adornment = kThemeAdornmentNone;
289
290 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
291
292 }
293
294 #if wxMAC_USE_CORE_GRAPHICS
295 #else
296 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
297 #endif
298 }
299 }
300
301 void wxRendererMac::DrawSplitterSash( wxWindow *win,
302 wxDC& dc,
303 const wxSize& size,
304 wxCoord position,
305 wxOrientation orient,
306 int WXUNUSED(flags) )
307 {
308 bool hasMetal = win->MacGetTopLevelWindow()->MacGetMetalAppearance();
309 SInt32 height;
310 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight, &height );
311 HIRect splitterRect;
312 if (orient == wxVERTICAL)
313 splitterRect = CGRectMake( position, 0, height, size.y );
314 else
315 splitterRect = CGRectMake( 0, position, size.x, height );
316
317 #if !wxMAC_USE_CORE_GRAPHICS
318 HIViewConvertRect(
319 &splitterRect,
320 (HIViewRef) win->GetHandle(),
321 (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
322 #endif
323
324 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
325 // strange redraw errors occur if we don't do this
326
327 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
328 {
329 Rect r =
330 {
331 (short) splitterRect.origin.y,
332 (short) splitterRect.origin.x,
333 (short) (splitterRect.origin.y + splitterRect.size.height),
334 (short) (splitterRect.origin.x + splitterRect.size.width)
335 };
336
337 RgnHandle updateRgn = NewRgn();
338 RectRgn( updateRgn, &r );
339 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
340 DisposeRgn( updateRgn );
341 }
342 else
343 {
344 CGContextRef cgContext;
345
346 #if wxMAC_USE_CORE_GRAPHICS
347 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
348 #else
349 Rect bounds;
350 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
351 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
352 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
353 CGContextScaleCTM( cgContext, 1, -1 );
354 #endif
355
356 HIThemeSplitterDrawInfo drawInfo;
357 drawInfo.version = 0;
358 drawInfo.state = kThemeStateActive;
359 drawInfo.adornment = hasMetal ? kHIThemeSplitterAdornmentMetal : kHIThemeSplitterAdornmentNone;
360 HIThemeDrawPaneSplitter( &splitterRect, &drawInfo, cgContext, kHIThemeOrientationNormal );
361
362 #if wxMAC_USE_CORE_GRAPHICS
363 #else
364 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
365 #endif
366 }
367 }
368
369 void
370 wxRendererMac::DrawItemSelectionRect(wxWindow *win,
371 wxDC& dc,
372 const wxRect& rect,
373 int flags )
374 {
375 if ( !(flags & wxCONTROL_SELECTED) )
376 return;
377
378 RGBColor selColor;
379 GetThemeBrushAsColor(flags & wxCONTROL_FOCUSED
380 ? kThemeBrushAlternatePrimaryHighlightColor
381 : kThemeBrushSecondaryHighlightColor,
382 32, true, &selColor);
383
384 wxBrush selBrush(selColor);
385
386 dc.SetPen( *wxTRANSPARENT_PEN );
387 dc.SetBrush( selBrush );
388 dc.DrawRectangle( rect );
389 }
390
391
392 void
393 wxRendererMac::DrawMacThemeButton(wxWindow *win,
394 wxDC& dc,
395 const wxRect& rect,
396 int flags,
397 int kind,
398 int adornment)
399 {
400 #if !wxMAC_USE_CORE_GRAPHICS
401 const wxCoord x = dc.LogicalToDeviceX(rect.x);
402 const wxCoord y = dc.LogicalToDeviceY(rect.y);
403 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
404 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
405 #else
406 // now the wxGCDC is using native transformations
407 const wxCoord x = rect.x;
408 const wxCoord y = rect.y;
409 const wxCoord w = rect.width;
410 const wxCoord h = rect.height;
411 #endif
412
413 dc.SetBrush( *wxTRANSPARENT_BRUSH );
414
415 HIRect headerRect = CGRectMake( x, y, w, h );
416 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
417 {
418 Rect r =
419 {
420 (short) headerRect.origin.y, (short) headerRect.origin.x,
421 (short) (headerRect.origin.y + headerRect.size.height),
422 (short) (headerRect.origin.x + headerRect.size.width)
423 };
424
425 RgnHandle updateRgn = NewRgn();
426 RectRgn( updateRgn, &r );
427 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
428 DisposeRgn( updateRgn );
429 }
430 else
431 {
432 CGContextRef cgContext;
433
434 #if wxMAC_USE_CORE_GRAPHICS
435 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
436 #else
437 Rect bounds;
438
439 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
440 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
441
442 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
443 CGContextScaleCTM( cgContext, 1, -1 );
444
445 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
446 CGContextClip( cgContext );
447 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
448 #endif
449
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_SELECTED) ? kThemeButtonOn : kThemeButtonOff;
459 drawInfo.adornment = adornment;
460
461 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
462 }
463
464 #if wxMAC_USE_CORE_GRAPHICS
465 #else
466 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
467 #endif
468 }
469 }
470
471
472 void
473 wxRendererMac::DrawComboBoxDropButton(wxWindow *win,
474 wxDC& dc,
475 const wxRect& rect,
476 int flags)
477 {
478 int kind;
479 if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
480 kind = kThemeArrowButtonSmall;
481 else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
482 kind = kThemeArrowButtonMini;
483 else
484 kind = kThemeArrowButton;
485
486 DrawMacThemeButton(win, dc, rect, flags,
487 kind, kThemeAdornmentArrowDownArrow);
488 }
489
490 void
491 wxRendererMac::DrawPushButton(wxWindow *win,
492 wxDC& dc,
493 const wxRect& rect,
494 int flags)
495 {
496 int kind;
497 if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
498 kind = kThemeBevelButtonSmall;
499 // There is no kThemeBevelButtonMini, but in this case, use Small
500 else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
501 kind = kThemeBevelButtonSmall;
502 else
503 kind = kThemeBevelButton;
504
505 DrawMacThemeButton(win, dc, rect, flags,
506 kind, kThemeAdornmentNone);
507 }
508
509 void
510 wxRendererMac::DrawFocusRect(wxWindow* win, wxDC& dc, const wxRect& rect, int flags)
511 {
512 if (!win)
513 {
514 wxDelegateRendererNative::DrawFocusRect(win, dc, rect, flags);
515 return;
516 }
517
518 #if wxMAC_USE_CORE_GRAPHICS
519 {
520 CGRect cgrect = CGRectMake( rect.x , rect.y , rect.width, rect.height ) ;
521
522 HIThemeFrameDrawInfo info ;
523 memset( &info, 0 , sizeof(info) ) ;
524
525 info.version = 0 ;
526 info.kind = 0 ;
527 info.state = kThemeStateActive;
528 info.isFocused = true ;
529
530 CGContextRef cgContext = (CGContextRef) win->MacGetCGContextRef() ;
531 wxASSERT( cgContext ) ;
532
533 HIThemeDrawFocusRect( &cgrect , true , cgContext , kHIThemeOrientationNormal ) ;
534 }
535 #else
536 // FIXME: not yet working for !wxMAC_USE_CORE_GRAPHICS
537 {
538 Rect r;
539 r.left = rect.x; r.top = rect.y; r.right = rect.GetRight(); r.bottom = rect.GetBottom();
540 wxTopLevelWindowMac* top = win->MacGetTopLevelWindow();
541 if ( top )
542 {
543 wxPoint pt(0, 0) ;
544 wxMacControl::Convert( &pt , win->GetPeer() , top->GetPeer() ) ;
545 OffsetRect( &r , pt.x , pt.y ) ;
546 }
547
548 DrawThemeFocusRect( &r , true ) ;
549 }
550 #endif
551 }
552