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