]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/renderer.cpp
Ensure that InsertItem doesn't lead to a crash in virtual mode, and don't use SortPro...
[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 void 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 private:
76 void DrawMacThemeButton(wxWindow *win,
77 wxDC& dc,
78 const wxRect& rect,
79 int flags,
80 int kind,
81 int adornment);
82
83 // the tree buttons
84 wxBitmap m_bmpTreeExpanded;
85 wxBitmap m_bmpTreeCollapsed;
86 };
87
88 // ============================================================================
89 // implementation
90 // ============================================================================
91
92 // static
93 wxRendererNative& wxRendererNative::GetDefault()
94 {
95 static wxRendererMac s_rendererMac;
96
97 return s_rendererMac;
98 }
99
100 void wxRendererMac::DrawHeaderButton( wxWindow *win,
101 wxDC& dc,
102 const wxRect& rect,
103 int flags,
104 wxHeaderSortIconType sortArrow,
105 wxHeaderButtonParams* params )
106 {
107 #if !wxMAC_USE_CORE_GRAPHICS
108 const wxCoord x = dc.LogicalToDeviceX(rect.x);
109 const wxCoord y = dc.LogicalToDeviceY(rect.y);
110 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
111 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
112 #else
113 // now the wxGCDC is using native transformations
114 const wxCoord x = rect.x;
115 const wxCoord y = rect.y;
116 const wxCoord w = rect.width;
117 const wxCoord h = rect.height;
118 #endif
119
120 dc.SetBrush( *wxTRANSPARENT_BRUSH );
121
122 HIRect headerRect = CGRectMake( x, y, w, h );
123 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
124 {
125 Rect r =
126 {
127 (short) headerRect.origin.y, (short) headerRect.origin.x,
128 (short) (headerRect.origin.y + headerRect.size.height),
129 (short) (headerRect.origin.x + headerRect.size.width)
130 };
131
132 RgnHandle updateRgn = NewRgn();
133 RectRgn( updateRgn, &r );
134 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
135 DisposeRgn( updateRgn );
136 }
137 else
138 {
139 CGContextRef cgContext;
140
141 #if wxMAC_USE_CORE_GRAPHICS
142 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
143 #else
144 Rect bounds;
145
146 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
147 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
148
149 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
150 CGContextScaleCTM( cgContext, 1, -1 );
151
152 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
153 CGContextClip( cgContext );
154 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
155 #endif
156
157 {
158 HIThemeButtonDrawInfo drawInfo;
159 HIRect labelRect;
160
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;
167
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;
171
172 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
173
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) )
176 {
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 );
184 }
185 }
186
187 #if wxMAC_USE_CORE_GRAPHICS
188 #else
189 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
190 #endif
191 }
192
193 // Reserve room for the arrows before writing the label, and turn off the
194 // flags we've already handled
195 wxRect newRect(rect);
196 if ( (flags & wxCONTROL_SELECTED) && (sortArrow != wxHDR_SORT_ICON_NONE) )
197 {
198 newRect.width -= 12;
199 sortArrow = wxHDR_SORT_ICON_NONE;
200 }
201 flags &= ~wxCONTROL_SELECTED;
202
203 DrawHeaderButtonContents(win, dc, newRect, flags, sortArrow, params);
204 }
205
206
207 int wxRendererMac::GetHeaderButtonHeight(wxWindow* WXUNUSED(win))
208 {
209 SInt32 standardHeight;
210 OSStatus errStatus;
211
212 errStatus = GetThemeMetric( kThemeMetricListHeaderHeight, &standardHeight );
213 if (errStatus == noErr)
214 {
215 return standardHeight;
216 }
217 return -1;
218 }
219
220 void wxRendererMac::DrawTreeItemButton( wxWindow *win,
221 wxDC& dc,
222 const wxRect& rect,
223 int flags )
224 {
225 #if !wxMAC_USE_CORE_GRAPHICS
226 const wxCoord x = dc.LogicalToDeviceX(rect.x);
227 const wxCoord y = dc.LogicalToDeviceY(rect.y);
228 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
229 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
230 #else
231 // now the wxGCDC is using native transformations
232 const wxCoord x = rect.x;
233 const wxCoord y = rect.y;
234 const wxCoord w = rect.width;
235 const wxCoord h = rect.height;
236 #endif
237
238 dc.SetBrush( *wxTRANSPARENT_BRUSH );
239
240 HIRect headerRect = CGRectMake( x, y, w, h );
241 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
242 {
243 Rect r =
244 {
245 (short) headerRect.origin.y, (short) headerRect.origin.x,
246 (short) (headerRect.origin.y + headerRect.size.height),
247 (short) (headerRect.origin.x + headerRect.size.width)
248 };
249
250 RgnHandle updateRgn = NewRgn();
251 RectRgn( updateRgn, &r );
252 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
253 DisposeRgn( updateRgn );
254 }
255 else
256 {
257 CGContextRef cgContext;
258
259 #if wxMAC_USE_CORE_GRAPHICS
260 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
261 #else
262 Rect bounds;
263
264 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
265 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
266
267 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
268 CGContextScaleCTM( cgContext, 1, -1 );
269
270 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
271 CGContextClip( cgContext );
272 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
273 #endif
274
275 {
276 HIThemeButtonDrawInfo drawInfo;
277 HIRect labelRect;
278
279 memset( &drawInfo, 0, sizeof(drawInfo) );
280 drawInfo.version = 0;
281 drawInfo.kind = kThemeDisclosureButton;
282 drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
283 // Apple mailing list posts say to use the arrow adornment constants, but those don't work.
284 // We need to set the value using the 'old' DrawThemeButton constants instead.
285 drawInfo.value = (flags & wxCONTROL_EXPANDED) ? kThemeDisclosureDown : kThemeDisclosureRight;
286 drawInfo.adornment = kThemeAdornmentNone;
287
288 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
289
290 }
291
292 #if wxMAC_USE_CORE_GRAPHICS
293 #else
294 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
295 #endif
296 }
297 }
298
299 void wxRendererMac::DrawSplitterSash( wxWindow *win,
300 wxDC& dc,
301 const wxSize& size,
302 wxCoord position,
303 wxOrientation orient,
304 int WXUNUSED(flags) )
305 {
306 bool hasMetal = win->MacGetTopLevelWindow()->MacGetMetalAppearance();
307 SInt32 height;
308 GetThemeMetric( kThemeMetricSmallPaneSplitterHeight, &height );
309 HIRect splitterRect;
310 if (orient == wxVERTICAL)
311 splitterRect = CGRectMake( position, 0, height, size.y );
312 else
313 splitterRect = CGRectMake( 0, position, size.x, height );
314
315 #if !wxMAC_USE_CORE_GRAPHICS
316 HIViewConvertRect(
317 &splitterRect,
318 (HIViewRef) win->GetHandle(),
319 (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
320 #endif
321
322 // under compositing we should only draw when called by the OS, otherwise just issue a redraw command
323 // strange redraw errors occur if we don't do this
324
325 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
326 {
327 Rect r =
328 {
329 (short) splitterRect.origin.y,
330 (short) splitterRect.origin.x,
331 (short) (splitterRect.origin.y + splitterRect.size.height),
332 (short) (splitterRect.origin.x + splitterRect.size.width)
333 };
334
335 RgnHandle updateRgn = NewRgn();
336 RectRgn( updateRgn, &r );
337 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
338 DisposeRgn( updateRgn );
339 }
340 else
341 {
342 CGContextRef cgContext;
343
344 #if wxMAC_USE_CORE_GRAPHICS
345 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
346 #else
347 Rect bounds;
348 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
349 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
350 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
351 CGContextScaleCTM( cgContext, 1, -1 );
352 #endif
353
354 HIThemeSplitterDrawInfo drawInfo;
355 drawInfo.version = 0;
356 drawInfo.state = kThemeStateActive;
357 drawInfo.adornment = hasMetal ? kHIThemeSplitterAdornmentMetal : kHIThemeSplitterAdornmentNone;
358 HIThemeDrawPaneSplitter( &splitterRect, &drawInfo, cgContext, kHIThemeOrientationNormal );
359
360 #if wxMAC_USE_CORE_GRAPHICS
361 #else
362 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
363 #endif
364 }
365 }
366
367 void
368 wxRendererMac::DrawItemSelectionRect(wxWindow *win,
369 wxDC& dc,
370 const wxRect& rect,
371 int flags )
372 {
373 RGBColor selColor;
374 if (flags & wxCONTROL_SELECTED)
375 {
376 if (flags & wxCONTROL_FOCUSED)
377 GetThemeBrushAsColor(kThemeBrushAlternatePrimaryHighlightColor, 32, true, &selColor);
378 else
379 GetThemeBrushAsColor(kThemeBrushSecondaryHighlightColor, 32, true, &selColor);
380 }
381
382 wxBrush selBrush = wxBrush( wxColour( selColor.red, selColor.green, selColor.blue ), wxSOLID );
383
384 dc.SetPen( *wxTRANSPARENT_PEN );
385 dc.SetBrush( selBrush );
386 dc.DrawRectangle( rect );
387 }
388
389
390 void
391 wxRendererMac::DrawMacThemeButton(wxWindow *win,
392 wxDC& dc,
393 const wxRect& rect,
394 int flags,
395 int kind,
396 int adornment)
397 {
398 #if !wxMAC_USE_CORE_GRAPHICS
399 const wxCoord x = dc.LogicalToDeviceX(rect.x);
400 const wxCoord y = dc.LogicalToDeviceY(rect.y);
401 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
402 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
403 #else
404 // now the wxGCDC is using native transformations
405 const wxCoord x = rect.x;
406 const wxCoord y = rect.y;
407 const wxCoord w = rect.width;
408 const wxCoord h = rect.height;
409 #endif
410
411 dc.SetBrush( *wxTRANSPARENT_BRUSH );
412
413 HIRect headerRect = CGRectMake( x, y, w, h );
414 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
415 {
416 Rect r =
417 {
418 (short) headerRect.origin.y, (short) headerRect.origin.x,
419 (short) (headerRect.origin.y + headerRect.size.height),
420 (short) (headerRect.origin.x + headerRect.size.width)
421 };
422
423 RgnHandle updateRgn = NewRgn();
424 RectRgn( updateRgn, &r );
425 HIViewSetNeedsDisplayInRegion( (HIViewRef) win->GetHandle(), updateRgn, true );
426 DisposeRgn( updateRgn );
427 }
428 else
429 {
430 CGContextRef cgContext;
431
432 #if wxMAC_USE_CORE_GRAPHICS
433 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
434 #else
435 Rect bounds;
436
437 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
438 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
439
440 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
441 CGContextScaleCTM( cgContext, 1, -1 );
442
443 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
444 CGContextClip( cgContext );
445 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
446 #endif
447
448 {
449 HIThemeButtonDrawInfo drawInfo;
450 HIRect labelRect;
451
452 memset( &drawInfo, 0, sizeof(drawInfo) );
453 drawInfo.version = 0;
454 drawInfo.kind = kind;
455 drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
456 drawInfo.value = (flags & wxCONTROL_SELECTED) ? kThemeButtonOn : kThemeButtonOff;
457 drawInfo.adornment = adornment;
458
459 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
460 }
461
462 #if wxMAC_USE_CORE_GRAPHICS
463 #else
464 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
465 #endif
466 }
467 }
468
469
470 void
471 wxRendererMac::DrawComboBoxDropButton(wxWindow *win,
472 wxDC& dc,
473 const wxRect& rect,
474 int flags)
475 {
476 DrawMacThemeButton(win, dc, rect, flags,
477 kThemeArrowButton, kThemeAdornmentArrowDownArrow);
478 }
479
480 void
481 wxRendererMac::DrawPushButton(wxWindow *win,
482 wxDC& dc,
483 const wxRect& rect,
484 int flags)
485 {
486 DrawMacThemeButton(win, dc, rect, flags,
487 kThemeBevelButton, kThemeAdornmentNone);
488 }
489