More support for drawing native column headers, adds more states
[wxWidgets.git] / src / msw / renderer.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/renderer.cpp
3 // Purpose: implementation of wxRendererNative for Windows
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 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // for compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/string.h"
29 #include "wx/window.h"
30 #include "wx/dc.h"
31 #include "wx/settings.h"
32 #endif //WX_PRECOMP
33
34 #include "wx/splitter.h"
35 #include "wx/renderer.h"
36 #include "wx/msw/uxtheme.h"
37 #include "wx/msw/private.h"
38
39 // tmschema.h is in Win32 Platform SDK and might not be available with earlier
40 // compilers
41 #ifndef CP_DROPDOWNBUTTON
42 #define BP_PUSHBUTTON 1
43 #define BP_CHECKBOX 3
44 #define CBS_UNCHECKEDNORMAL 1
45 #define CBS_CHECKEDNORMAL (CBS_UNCHECKEDNORMAL + 4)
46 #define CBS_MIXEDNORMAL (CBS_CHECKEDNORMAL + 4)
47
48 #define PBS_NORMAL 1
49 #define PBS_HOT 2
50 #define PBS_PRESSED 3
51 #define PBS_DISABLED 4
52 #define PBS_DEFAULTED 5
53
54 #define CP_DROPDOWNBUTTON 1
55
56 #define CBXS_NORMAL 1
57 #define CBXS_HOT 2
58 #define CBXS_PRESSED 3
59 #define CBXS_DISABLED 4
60
61 #define TVP_GLYPH 2
62
63 #define GLPS_CLOSED 1
64 #define GLPS_OPENED 2
65
66 #define HP_HEADERITEM 1
67
68 #define HIS_NORMAL 1
69 #define HIS_HOT 2
70 #define HIS_PRESSED 3
71
72 #define TMT_HEIGHT 2417
73
74 #define HP_HEADERSORTARROW 4
75 #define HSAS_SORTEDUP 1
76 #define HSAS_SORTEDDOWN 2
77 #endif
78
79 #if defined(__WXWINCE__) && !defined(DFCS_FLAT)
80 #define DFCS_FLAT 0
81 #endif
82
83 // ----------------------------------------------------------------------------
84 // wxRendererMSW: wxRendererNative implementation for "old" Win32 systems
85 // ----------------------------------------------------------------------------
86
87 class WXDLLEXPORT wxRendererMSW : public wxDelegateRendererNative
88 {
89 public:
90 wxRendererMSW() { }
91
92 static wxRendererNative& Get();
93
94 virtual void DrawComboBoxDropButton(wxWindow *win,
95 wxDC& dc,
96 const wxRect& rect,
97 int flags = 0);
98
99 virtual void DrawPushButton(wxWindow *win,
100 wxDC& dc,
101 const wxRect& rect,
102 int flags = 0);
103
104 private:
105 DECLARE_NO_COPY_CLASS(wxRendererMSW)
106 };
107
108 // ----------------------------------------------------------------------------
109 // wxRendererXP: wxRendererNative implementation for Windows XP and later
110 // ----------------------------------------------------------------------------
111
112 #if wxUSE_UXTHEME
113
114 class WXDLLEXPORT wxRendererXP : public wxDelegateRendererNative
115 {
116 public:
117 wxRendererXP() : wxDelegateRendererNative(wxRendererMSW::Get()) { }
118
119 static wxRendererNative& Get();
120
121 virtual void DrawHeaderButton(wxWindow *win,
122 wxDC& dc,
123 const wxRect& rect,
124 int flags = 0,
125 wxHeaderButtonParams* params = NULL);
126 virtual int GetHeaderButtonHeight(wxWindow *win);
127
128 virtual void DrawTreeItemButton(wxWindow *win,
129 wxDC& dc,
130 const wxRect& rect,
131 int flags = 0);
132 virtual void DrawSplitterBorder(wxWindow *win,
133 wxDC& dc,
134 const wxRect& rect,
135 int flags = 0);
136 virtual void DrawSplitterSash(wxWindow *win,
137 wxDC& dc,
138 const wxSize& size,
139 wxCoord position,
140 wxOrientation orient,
141 int flags = 0);
142 virtual void DrawComboBoxDropButton(wxWindow *win,
143 wxDC& dc,
144 const wxRect& rect,
145 int flags = 0);
146 virtual void DrawCheckBox(wxWindow *win,
147 wxDC& dc,
148 const wxRect& rect,
149 int flags = 0);
150
151 virtual void DrawPushButton(wxWindow *win,
152 wxDC& dc,
153 const wxRect& rect,
154 int flags = 0);
155
156 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
157 private:
158 DECLARE_NO_COPY_CLASS(wxRendererXP)
159 };
160
161 #endif // wxUSE_UXTHEME
162
163 // ============================================================================
164 // wxRendererNative and wxRendererMSW implementation
165 // ============================================================================
166
167 /* static */
168 wxRendererNative& wxRendererNative::GetDefault()
169 {
170 #if wxUSE_UXTHEME
171 wxUxThemeEngine *themeEngine = wxUxThemeEngine::Get();
172 if ( themeEngine && themeEngine->IsAppThemed() )
173 return wxRendererXP::Get();
174 #endif // wxUSE_UXTHEME
175
176 return wxRendererMSW::Get();
177 }
178
179 /* static */
180 wxRendererNative& wxRendererMSW::Get()
181 {
182 static wxRendererMSW s_rendererMSW;
183
184 return s_rendererMSW;
185 }
186
187 void
188 wxRendererMSW::DrawComboBoxDropButton(wxWindow * WXUNUSED(win),
189 wxDC& dc,
190 const wxRect& rect,
191 int flags)
192 {
193 RECT r;
194 r.left = rect.GetLeft();
195 r.top = rect.GetTop();
196 r.bottom = rect.y + rect.height;
197 r.right = rect.x + rect.width;
198
199 int style = DFCS_SCROLLCOMBOBOX;
200 if ( flags & wxCONTROL_DISABLED )
201 style |= DFCS_INACTIVE;
202 if ( flags & wxCONTROL_PRESSED )
203 style |= DFCS_PUSHED | DFCS_FLAT;
204
205 ::DrawFrameControl(GetHdcOf(dc), &r, DFC_SCROLL, style);
206 }
207
208 void
209 wxRendererMSW::DrawPushButton(wxWindow * WXUNUSED(win),
210 wxDC& dc,
211 const wxRect& rect,
212 int flags)
213 {
214 RECT r;
215 r.left = rect.GetLeft();
216 r.top = rect.GetTop();
217 r.bottom = rect.y + rect.height;
218 r.right = rect.x + rect.width;
219
220 int style = DFCS_BUTTONPUSH;
221 if ( flags & wxCONTROL_DISABLED )
222 style |= DFCS_INACTIVE;
223 if ( flags & wxCONTROL_PRESSED )
224 style |= DFCS_PUSHED | DFCS_FLAT;
225
226 ::DrawFrameControl(GetHdcOf(dc), &r, DFC_BUTTON, style);
227 }
228
229 // ============================================================================
230 // wxRendererXP implementation
231 // ============================================================================
232
233 #if wxUSE_UXTHEME
234
235 /* static */
236 wxRendererNative& wxRendererXP::Get()
237 {
238 static wxRendererXP s_rendererXP;
239
240 return s_rendererXP;
241 }
242
243 // NOTE: There is no guarantee that the button drawn fills the entire rect (XP
244 // default theme, for example), so the caller should have cleared button's
245 // background before this call. This is quite likely a wxMSW-specific thing.
246 void
247 wxRendererXP::DrawComboBoxDropButton(wxWindow * win,
248 wxDC& dc,
249 const wxRect& rect,
250 int flags)
251 {
252 wxUxThemeHandle hTheme(win, L"COMBOBOX");
253 if ( !hTheme )
254 {
255 m_rendererNative.DrawComboBoxDropButton(win, dc, rect, flags);
256 return;
257 }
258
259 RECT r;
260 wxCopyRectToRECT(rect, r);
261
262 int state;
263 if ( flags & wxCONTROL_PRESSED )
264 state = CBXS_PRESSED;
265 else if ( flags & wxCONTROL_CURRENT )
266 state = CBXS_HOT;
267 else if ( flags & wxCONTROL_DISABLED )
268 state = CBXS_DISABLED;
269 else
270 state = CBXS_NORMAL;
271
272 wxUxThemeEngine::Get()->DrawThemeBackground
273 (
274 hTheme,
275 GetHdcOf(dc),
276 CP_DROPDOWNBUTTON,
277 state,
278 &r,
279 NULL
280 );
281
282 }
283
284 void
285 wxRendererXP::DrawHeaderButton(wxWindow *win,
286 wxDC& dc,
287 const wxRect& rect,
288 int flags,
289 wxHeaderButtonParams* params)
290 {
291 wxUxThemeHandle hTheme(win, L"HEADER");
292 if ( !hTheme )
293 {
294 m_rendererNative.DrawHeaderButton(win, dc, rect, flags, params);
295 return;
296 }
297
298 RECT r;
299 wxCopyRectToRECT(rect, r);
300
301 int state;
302 if ( flags & wxCONTROL_PRESSED )
303 state = HIS_PRESSED;
304 else if ( flags & wxCONTROL_CURRENT )
305 state = HIS_HOT;
306 else
307 state = HIS_NORMAL;
308 wxUxThemeEngine::Get()->DrawThemeBackground
309 (
310 hTheme,
311 GetHdcOf(dc),
312 HP_HEADERITEM,
313 state,
314 &r,
315 NULL
316 );
317
318 // NOTE: Using the theme to draw HP_HEADERSORTARROW doesn't do anything.
319 // Why? If this can be fixed then draw the sort arrows using the theme
320 // and then clear those flags before calling DrawHeaderButtonContents.
321
322 // Add any extras that are specified in flags and params
323 DrawHeaderButtonContents(win, dc, rect, flags, params);
324 }
325
326
327 int
328 wxRendererXP::GetHeaderButtonHeight(wxWindow *win)
329 {
330 wxUxThemeHandle hTheme(win, L"HEADER");
331 if ( !hTheme )
332 {
333 return m_rendererNative.GetHeaderButtonHeight(win);
334 }
335
336 HRESULT hr;
337 int value = -1;
338
339 hr = wxUxThemeEngine::Get()->GetThemeMetric( hTheme,
340 NULL,
341 HP_HEADERITEM,
342 HIS_NORMAL,
343 TMT_HEIGHT,
344 &value );
345 if ( hr == S_OK )
346 return value;
347 else
348 return 20;
349 }
350
351
352 void
353 wxRendererXP::DrawTreeItemButton(wxWindow *win,
354 wxDC& dc,
355 const wxRect& rect,
356 int flags)
357 {
358 wxUxThemeHandle hTheme(win, L"TREEVIEW");
359 if ( !hTheme )
360 {
361 m_rendererNative.DrawTreeItemButton(win, dc, rect, flags);
362 return;
363 }
364
365 RECT r;
366 wxCopyRectToRECT(rect, r);
367
368 int state = flags & wxCONTROL_EXPANDED ? GLPS_OPENED : GLPS_CLOSED;
369 wxUxThemeEngine::Get()->DrawThemeBackground
370 (
371 hTheme,
372 GetHdcOf(dc),
373 TVP_GLYPH,
374 state,
375 &r,
376 NULL
377 );
378 }
379
380 void
381 wxRendererXP::DrawCheckBox(wxWindow *win,
382 wxDC& dc,
383 const wxRect& rect,
384 int flags)
385 {
386 wxUxThemeHandle hTheme(win, L"BUTTON");
387 if ( !hTheme )
388 {
389 m_rendererNative.DrawCheckBox(win, dc, rect, flags);
390 return;
391 }
392
393 RECT r;
394 wxCopyRectToRECT(rect, r);
395
396 int state;
397 if ( flags & wxCONTROL_CHECKED )
398 state = CBS_CHECKEDNORMAL;
399 else if ( flags & wxCONTROL_UNDETERMINED )
400 state = CBS_MIXEDNORMAL;
401 else
402 state = CBS_UNCHECKEDNORMAL;
403
404 // CBS_XXX is followed by CBX_XXXGOT, then CBS_XXXPRESSED and DISABLED
405 if ( flags & wxCONTROL_CURRENT )
406 state += 1;
407 else if ( flags & wxCONTROL_PRESSED )
408 state += 2;
409 else if ( flags & wxCONTROL_DISABLED )
410 state += 3;
411
412 wxUxThemeEngine::Get()->DrawThemeBackground
413 (
414 hTheme,
415 GetHdcOf(dc),
416 BP_CHECKBOX,
417 state,
418 &r,
419 NULL
420 );
421 }
422
423 void
424 wxRendererXP::DrawPushButton(wxWindow * win,
425 wxDC& dc,
426 const wxRect& rect,
427 int flags)
428 {
429 wxUxThemeHandle hTheme(win, L"BUTTON");
430 if ( !hTheme )
431 {
432 m_rendererNative.DrawPushButton(win, dc, rect, flags);
433 return;
434 }
435
436 RECT r;
437 wxCopyRectToRECT(rect, r);
438
439 int state;
440 if ( flags & wxCONTROL_PRESSED )
441 state = PBS_PRESSED;
442 else if ( flags & wxCONTROL_CURRENT )
443 state = PBS_HOT;
444 else if ( flags & wxCONTROL_DISABLED )
445 state = PBS_DISABLED;
446 else if ( flags & wxCONTROL_ISDEFAULT )
447 state = PBS_DEFAULTED;
448 else
449 state = PBS_NORMAL;
450
451 wxUxThemeEngine::Get()->DrawThemeBackground
452 (
453 hTheme,
454 GetHdcOf(dc),
455 BP_PUSHBUTTON,
456 state,
457 &r,
458 NULL
459 );
460
461 }
462
463 // ----------------------------------------------------------------------------
464 // splitter drawing
465 // ----------------------------------------------------------------------------
466
467 // the width of the sash: this is the same as used by Explorer...
468 static const wxCoord SASH_WIDTH = 4;
469
470 wxSplitterRenderParams
471 wxRendererXP::GetSplitterParams(const wxWindow * win)
472 {
473 if ( win->HasFlag(wxSP_NO_XP_THEME) )
474 return m_rendererNative.GetSplitterParams(win);
475 else
476 return wxSplitterRenderParams(SASH_WIDTH, 0, false);
477 }
478
479 void
480 wxRendererXP::DrawSplitterBorder(wxWindow * win,
481 wxDC& dc,
482 const wxRect& rect,
483 int flags)
484 {
485 if ( win->HasFlag(wxSP_NO_XP_THEME) )
486 {
487 m_rendererNative.DrawSplitterBorder(win, dc, rect, flags);
488 }
489 }
490
491 void
492 wxRendererXP::DrawSplitterSash(wxWindow *win,
493 wxDC& dc,
494 const wxSize& size,
495 wxCoord position,
496 wxOrientation orient,
497 int flags)
498 {
499 if ( !win->HasFlag(wxSP_NO_XP_THEME) )
500 {
501 dc.SetPen(*wxTRANSPARENT_PEN);
502 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)));
503 if ( orient == wxVERTICAL )
504 {
505 dc.DrawRectangle(position, 0, SASH_WIDTH, size.y);
506 }
507 else // wxHORIZONTAL
508 {
509 dc.DrawRectangle(0, position, size.x, SASH_WIDTH);
510 }
511
512 return;
513 }
514
515 m_rendererNative.DrawSplitterSash(win, dc, size, position, orient, flags);
516 }
517
518 #endif // wxUSE_UXTHEME