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