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