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