]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/renderer.cpp
Fix bug with m_current causing EVT_LIST_KEY_DOWN events not to fire in virtual mode...
[wxWidgets.git] / src / mac / carbon / renderer.cpp
CommitLineData
9c7f49f5 1///////////////////////////////////////////////////////////////////////////////
7af14d71 2// Name: src/mac/carbon/renderer.cpp
38c4cb6a 3// Purpose: implementation of wxRendererNative for Mac
9c7f49f5
VZ
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>
65571936 9// License: wxWindows licence
9c7f49f5
VZ
10///////////////////////////////////////////////////////////////////////////////
11
9c7f49f5
VZ
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"
4c948343
VZ
21 #include "wx/dc.h"
22 #include "wx/bitmap.h"
23 #include "wx/settings.h"
ed4b0fdc 24 #include "wx/dcclient.h"
1832043f 25 #include "wx/toplevel.h"
7af14d71 26#endif
9c7f49f5
VZ
27
28#include "wx/renderer.h"
8acd14d1 29#include "wx/graphics.h"
547aafd2 30#include "wx/mac/uma.h"
9c7f49f5 31
9c7f49f5 32
5cb80ad2 33class WXDLLEXPORT wxRendererMac : public wxDelegateRendererNative
9c7f49f5
VZ
34{
35public:
36 // draw the header control button (used by wxListCtrl)
c97c9952 37 virtual int DrawHeaderButton( wxWindow *win,
7af14d71
DS
38 wxDC& dc,
39 const wxRect& rect,
4b94ddc4 40 int flags = 0,
80752b57 41 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
4b94ddc4 42 wxHeaderButtonParams* params = NULL );
9c7f49f5 43
4b94ddc4 44 virtual int GetHeaderButtonHeight(wxWindow *win);
a61c9122 45
9c7f49f5 46 // draw the expanded/collapsed icon for a tree control item
7af14d71
DS
47 virtual void DrawTreeItemButton( wxWindow *win,
48 wxDC& dc,
49 const wxRect& rect,
50 int flags = 0 );
9c7f49f5 51
b3208e11 52 // draw a (vertical) sash
7af14d71
DS
53 virtual void DrawSplitterSash( wxWindow *win,
54 wxDC& dc,
55 const wxSize& size,
56 wxCoord position,
57 wxOrientation orient,
58 int flags = 0 );
cf511e87
RD
59
60 virtual void DrawComboBoxDropButton(wxWindow *win,
61 wxDC& dc,
62 const wxRect& rect,
63 int flags = 0);
a61c9122 64
cf511e87
RD
65 virtual void DrawPushButton(wxWindow *win,
66 wxDC& dc,
67 const wxRect& rect,
68 int flags = 0);
a61c9122 69
a4609ab8
KO
70 virtual void DrawItemSelectionRect(wxWindow *win,
71 wxDC& dc,
72 const wxRect& rect,
73 int flags = 0);
b3208e11 74
9c7f49f5 75private:
cf511e87
RD
76 void DrawMacThemeButton(wxWindow *win,
77 wxDC& dc,
78 const wxRect& rect,
79 int flags,
80 int kind,
81 int adornment);
a61c9122 82
9c7f49f5 83 // the tree buttons
7af14d71
DS
84 wxBitmap m_bmpTreeExpanded;
85 wxBitmap m_bmpTreeCollapsed;
9c7f49f5
VZ
86};
87
9c7f49f5
VZ
88// ============================================================================
89// implementation
90// ============================================================================
91
7af14d71 92// static
f0244295 93wxRendererNative& wxRendererNative::GetDefault()
9c7f49f5
VZ
94{
95 static wxRendererMac s_rendererMac;
96
97 return s_rendererMac;
98}
99
c97c9952 100int wxRendererMac::DrawHeaderButton( wxWindow *win,
7af14d71
DS
101 wxDC& dc,
102 const wxRect& rect,
4b94ddc4 103 int flags,
80752b57 104 wxHeaderSortIconType sortArrow,
4b94ddc4 105 wxHeaderButtonParams* params )
9c7f49f5 106{
2185a8a3 107#if !wxMAC_USE_CORE_GRAPHICS
1c5decd0
SC
108 const wxCoord x = dc.LogicalToDeviceX(rect.x);
109 const wxCoord y = dc.LogicalToDeviceY(rect.y);
977d15a6
SC
110 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
111 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
1c5decd0
SC
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
7af14d71 119
11d1adbf 120 dc.SetBrush( *wxTRANSPARENT_BRUSH );
9c7f49f5 121
a62f32af
SC
122 HIRect headerRect = CGRectMake( x, y, w, h );
123 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
2480cf88 124 {
a62f32af 125 Rect r =
2480cf88 126 {
a62f32af
SC
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;
7af14d71 140
2480cf88 141#if wxMAC_USE_CORE_GRAPHICS
be01a403 142 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
2480cf88 143#else
a62f32af 144 Rect bounds;
7af14d71 145
a62f32af
SC
146 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
147 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
7af14d71 148
a62f32af
SC
149 CGContextTranslateCTM( cgContext, 0, bounds.bottom - bounds.top );
150 CGContextScaleCTM( cgContext, 1, -1 );
7af14d71 151
a62f32af
SC
152 HIShapeReplacePathInCGContext( HIShapeCreateWithQDRgn( (RgnHandle) dc.m_macCurrentClipRgn ), cgContext );
153 CGContextClip( cgContext );
154 HIViewConvertRect( &headerRect, (HIViewRef) win->GetHandle(), (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
2480cf88 155#endif
7af14d71 156
a62f32af
SC
157 {
158 HIThemeButtonDrawInfo drawInfo;
159 HIRect labelRect;
7af14d71 160
a62f32af
SC
161 memset( &drawInfo, 0, sizeof(drawInfo) );
162 drawInfo.version = 0;
a62f32af 163 drawInfo.kind = kThemeListHeaderButton;
4b94ddc4
RD
164 drawInfo.state = (flags & wxCONTROL_DISABLED) ? kThemeStateInactive : kThemeStateActive;
165 drawInfo.value = (flags & wxCONTROL_SELECTED) ? kThemeButtonOn : kThemeButtonOff;
a62f32af 166 drawInfo.adornment = kThemeAdornmentNone;
4b94ddc4
RD
167
168 // The down arrow is drawn automatically, change it to an up arrow if needed.
80752b57 169 if ( sortArrow == wxHDR_SORT_ICON_UP )
4b94ddc4 170 drawInfo.adornment = kThemeAdornmentHeaderButtonSortUp;
a61c9122 171
a62f32af 172 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
4b94ddc4
RD
173
174 // If we don't want any arrows we need to draw over the one already there
80752b57 175 if ( (flags & wxCONTROL_SELECTED) && (sortArrow == wxHDR_SORT_ICON_NONE) )
4b94ddc4
RD
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 );
a61c9122 184 }
a62f32af 185 }
7af14d71 186
2480cf88
SC
187#if wxMAC_USE_CORE_GRAPHICS
188#else
a62f32af 189 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
2480cf88 190#endif
11d1adbf 191 }
4b94ddc4
RD
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);
80752b57 196 if ( (flags & wxCONTROL_SELECTED) && (sortArrow != wxHDR_SORT_ICON_NONE) )
4b94ddc4
RD
197 {
198 newRect.width -= 12;
80752b57 199 sortArrow = wxHDR_SORT_ICON_NONE;
4b94ddc4 200 }
80752b57 201 flags &= ~wxCONTROL_SELECTED;
4b94ddc4 202
c97c9952 203 return DrawHeaderButtonContents(win, dc, newRect, flags, sortArrow, params);
4b94ddc4
RD
204}
205
206
207int 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;
9c7f49f5
VZ
218}
219
7af14d71
DS
220void wxRendererMac::DrawTreeItemButton( wxWindow *win,
221 wxDC& dc,
222 const wxRect& rect,
223 int flags )
9c7f49f5 224{
1c5decd0
SC
225#if !wxMAC_USE_CORE_GRAPHICS
226 const wxCoord x = dc.LogicalToDeviceX(rect.x);
227 const wxCoord y = dc.LogicalToDeviceY(rect.y);
46b59ead
KO
228 const wxCoord w = dc.LogicalToDeviceXRel(rect.width);
229 const wxCoord h = dc.LogicalToDeviceYRel(rect.height);
f3d0a750 230#else
1c5decd0 231 // now the wxGCDC is using native transformations
f3d0a750
RD
232 const wxCoord x = rect.x;
233 const wxCoord y = rect.y;
234 const wxCoord w = rect.width;
235 const wxCoord h = rect.height;
a61c9122 236#endif
1c5decd0 237
46b59ead
KO
238 dc.SetBrush( *wxTRANSPARENT_BRUSH );
239
240 HIRect headerRect = CGRectMake( x, y, w, h );
241 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
242 {
243 Rect r =
9c7f49f5 244 {
46b59ead
KO
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 );
9c7f49f5 254 }
46b59ead
KO
255 else
256 {
257 CGContextRef cgContext;
9c7f49f5 258
46b59ead
KO
259#if wxMAC_USE_CORE_GRAPHICS
260 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
261#else
262 Rect bounds;
9c7f49f5 263
46b59ead
KO
264 GetPortBounds( (CGrafPtr) dc.m_macPort, &bounds );
265 QDBeginCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
7af14d71 266
46b59ead
KO
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
7af14d71 274
7af14d71 275 {
46b59ead
KO
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;
a61c9122 286 drawInfo.adornment = kThemeAdornmentNone;
46b59ead
KO
287
288 HIThemeDrawButton( &headerRect, &drawInfo, cgContext, kHIThemeOrientationNormal, &labelRect );
a61c9122 289
46b59ead
KO
290 }
291
292#if wxMAC_USE_CORE_GRAPHICS
293#else
294 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
7af14d71 295#endif
46b59ead 296 }
9c7f49f5
VZ
297}
298
7af14d71
DS
299void wxRendererMac::DrawSplitterSash( wxWindow *win,
300 wxDC& dc,
301 const wxSize& size,
302 wxCoord position,
303 wxOrientation orient,
304 int WXUNUSED(flags) )
b3208e11 305{
a62f32af
SC
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 );
7af14d71 314
2480cf88 315#if !wxMAC_USE_CORE_GRAPHICS
a62f32af
SC
316 HIViewConvertRect(
317 &splitterRect,
318 (HIViewRef) win->GetHandle(),
319 (HIViewRef) win->MacGetTopLevelWindow()->GetHandle() );
2480cf88 320#endif
547aafd2 321
a62f32af
SC
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
547aafd2 324
a62f32af
SC
325 if ( !dc.IsKindOf( CLASSINFO( wxPaintDC ) ) )
326 {
327 Rect r =
547aafd2 328 {
a62f32af
SC
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;
7af14d71 343
20b69855 344#if wxMAC_USE_CORE_GRAPHICS
be01a403 345 cgContext = (CGContextRef) dc.GetGraphicsContext()->GetNativeContext();
20b69855 346#else
a62f32af
SC
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 );
2480cf88 352#endif
547aafd2 353
a62f32af
SC
354 HIThemeSplitterDrawInfo drawInfo;
355 drawInfo.version = 0;
356 drawInfo.state = kThemeStateActive;
357 drawInfo.adornment = hasMetal ? kHIThemeSplitterAdornmentMetal : kHIThemeSplitterAdornmentNone;
358 HIThemeDrawPaneSplitter( &splitterRect, &drawInfo, cgContext, kHIThemeOrientationNormal );
2480cf88
SC
359
360#if wxMAC_USE_CORE_GRAPHICS
361#else
a62f32af 362 QDEndCGContext( (CGrafPtr) dc.m_macPort, &cgContext );
20b69855 363#endif
547aafd2 364 }
b3208e11 365}
a4609ab8
KO
366
367void
368wxRendererMac::DrawItemSelectionRect(wxWindow *win,
369 wxDC& dc,
370 const wxRect& rect,
371 int flags )
372{
055de350
VZ
373 if ( !(flags & wxCONTROL_SELECTED) )
374 return;
375
a61c9122 376 RGBColor selColor;
055de350
VZ
377 GetThemeBrushAsColor(flags & wxCONTROL_FOCUSED
378 ? kThemeBrushAlternatePrimaryHighlightColor
379 : kThemeBrushSecondaryHighlightColor,
380 32, true, &selColor);
a61c9122 381
055de350 382 wxBrush selBrush(selColor);
a4609ab8
KO
383
384 dc.SetPen( *wxTRANSPARENT_PEN );
385 dc.SetBrush( selBrush );
386 dc.DrawRectangle( rect );
387}
cf511e87
RD
388
389
390void
391wxRendererMac::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
470void
471wxRendererMac::DrawComboBoxDropButton(wxWindow *win,
472 wxDC& dc,
473 const wxRect& rect,
474 int flags)
475{
f8e1a81f 476 int kind;
a61c9122 477 if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
f8e1a81f 478 kind = kThemeArrowButtonSmall;
a61c9122 479 else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
f8e1a81f
JS
480 kind = kThemeArrowButtonMini;
481 else
482 kind = kThemeArrowButton;
a61c9122 483
cf511e87 484 DrawMacThemeButton(win, dc, rect, flags,
f8e1a81f 485 kind, kThemeAdornmentArrowDownArrow);
cf511e87 486}
a61c9122 487
cf511e87
RD
488void
489wxRendererMac::DrawPushButton(wxWindow *win,
490 wxDC& dc,
491 const wxRect& rect,
492 int flags)
493{
f8e1a81f 494 int kind;
a61c9122
JS
495 if (win->GetWindowVariant() == wxWINDOW_VARIANT_SMALL || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_SMALL))
496 kind = kThemeBevelButtonSmall;
497 // There is no kThemeBevelButtonMini, but in this case, use Small
498 else if (win->GetWindowVariant() == wxWINDOW_VARIANT_MINI || (win->GetParent() && win->GetParent()->GetWindowVariant() == wxWINDOW_VARIANT_MINI))
f8e1a81f
JS
499 kind = kThemeBevelButtonSmall;
500 else
501 kind = kThemeBevelButton;
502
cf511e87 503 DrawMacThemeButton(win, dc, rect, flags,
f8e1a81f 504 kind, kThemeAdornmentNone);
cf511e87 505}
a61c9122 506