corrected last commit: Inflate() should be Deflate()
[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 wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
126 wxHeaderButtonParams* params = NULL);
127 virtual int GetHeaderButtonHeight(wxWindow *win);
128
129 virtual void DrawTreeItemButton(wxWindow *win,
130 wxDC& dc,
131 const wxRect& rect,
132 int flags = 0);
133 virtual void DrawSplitterBorder(wxWindow *win,
134 wxDC& dc,
135 const wxRect& rect,
136 int flags = 0);
137 virtual void DrawSplitterSash(wxWindow *win,
138 wxDC& dc,
139 const wxSize& size,
140 wxCoord position,
141 wxOrientation orient,
142 int flags = 0);
143 virtual void DrawComboBoxDropButton(wxWindow *win,
144 wxDC& dc,
145 const wxRect& rect,
146 int flags = 0);
147 virtual void DrawCheckBox(wxWindow *win,
148 wxDC& dc,
149 const wxRect& rect,
150 int flags = 0);
151
152 virtual void DrawPushButton(wxWindow *win,
153 wxDC& dc,
154 const wxRect& rect,
155 int flags = 0);
156
157 virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
158 private:
159 DECLARE_NO_COPY_CLASS(wxRendererXP)
160 };
161
162 #endif // wxUSE_UXTHEME
163
164 // ============================================================================
165 // wxRendererNative and wxRendererMSW implementation
166 // ============================================================================
167
168 /* static */
169 wxRendererNative& wxRendererNative::GetDefault()
170 {
171 #if wxUSE_UXTHEME
172 wxUxThemeEngine *themeEngine = wxUxThemeEngine::Get();
173 if ( themeEngine && themeEngine->IsAppThemed() )
174 return wxRendererXP::Get();
175 #endif // wxUSE_UXTHEME
176
177 return wxRendererMSW::Get();
178 }
179
180 /* static */
181 wxRendererNative& wxRendererMSW::Get()
182 {
183 static wxRendererMSW s_rendererMSW;
184
185 return s_rendererMSW;
186 }
187
188 void
189 wxRendererMSW::DrawComboBoxDropButton(wxWindow * WXUNUSED(win),
190 wxDC& dc,
191 const wxRect& rect,
192 int flags)
193 {
194 RECT r;
195 r.left = rect.GetLeft();
196 r.top = rect.GetTop();
197 r.bottom = rect.y + rect.height;
198 r.right = rect.x + rect.width;
199
200 int style = DFCS_SCROLLCOMBOBOX;
201 if ( flags & wxCONTROL_DISABLED )
202 style |= DFCS_INACTIVE;
203 if ( flags & wxCONTROL_PRESSED )
204 style |= DFCS_PUSHED | DFCS_FLAT;
205
206 ::DrawFrameControl(GetHdcOf(dc), &r, DFC_SCROLL, style);
207 }
208
209 void
210 wxRendererMSW::DrawPushButton(wxWindow * WXUNUSED(win),
211 wxDC& dc,
212 const wxRect& rectOrig,
213 int flags)
214 {
215 wxRect rect(rectOrig);
216
217 int style = DFCS_BUTTONPUSH;
218 if ( flags & wxCONTROL_DISABLED )
219 style |= DFCS_INACTIVE;
220 if ( flags & wxCONTROL_PRESSED )
221 style |= DFCS_PUSHED | DFCS_FLAT;
222 if ( flags & wxCONTROL_ISDEFAULT )
223 {
224 // DrawFrameControl() doesn't seem to support default buttons so we
225 // have to draw the border ourselves
226 wxDCPenChanger pen(dc, *wxBLACK_PEN);
227 wxDCBrushChanger brush(dc, *wxTRANSPARENT_BRUSH);
228 dc.DrawRectangle(rect);
229 rect.Deflate(1);
230 }
231
232 RECT rc;
233 wxCopyRectToRECT(rect, rc);
234
235 ::DrawFrameControl(GetHdcOf(dc), &rc, DFC_BUTTON, style);
236 }
237
238 // ============================================================================
239 // wxRendererXP implementation
240 // ============================================================================
241
242 #if wxUSE_UXTHEME
243
244 /* static */
245 wxRendererNative& wxRendererXP::Get()
246 {
247 static wxRendererXP s_rendererXP;
248
249 return s_rendererXP;
250 }
251
252 // NOTE: There is no guarantee that the button drawn fills the entire rect (XP
253 // default theme, for example), so the caller should have cleared button's
254 // background before this call. This is quite likely a wxMSW-specific thing.
255 void
256 wxRendererXP::DrawComboBoxDropButton(wxWindow * win,
257 wxDC& dc,
258 const wxRect& rect,
259 int flags)
260 {
261 wxUxThemeHandle hTheme(win, L"COMBOBOX");
262 if ( !hTheme )
263 {
264 m_rendererNative.DrawComboBoxDropButton(win, dc, rect, flags);
265 return;
266 }
267
268 RECT r;
269 wxCopyRectToRECT(rect, r);
270
271 int state;
272 if ( flags & wxCONTROL_PRESSED )
273 state = CBXS_PRESSED;
274 else if ( flags & wxCONTROL_CURRENT )
275 state = CBXS_HOT;
276 else if ( flags & wxCONTROL_DISABLED )
277 state = CBXS_DISABLED;
278 else
279 state = CBXS_NORMAL;
280
281 wxUxThemeEngine::Get()->DrawThemeBackground
282 (
283 hTheme,
284 GetHdcOf(dc),
285 CP_DROPDOWNBUTTON,
286 state,
287 &r,
288 NULL
289 );
290
291 }
292
293 void
294 wxRendererXP::DrawHeaderButton(wxWindow *win,
295 wxDC& dc,
296 const wxRect& rect,
297 int flags,
298 wxHeaderSortIconType sortArrow,
299 wxHeaderButtonParams* params)
300 {
301 wxUxThemeHandle hTheme(win, L"HEADER");
302 if ( !hTheme )
303 {
304 m_rendererNative.DrawHeaderButton(win, dc, rect, flags, sortArrow, params);
305 return;
306 }
307
308 RECT r;
309 wxCopyRectToRECT(rect, r);
310
311 int state;
312 if ( flags & wxCONTROL_PRESSED )
313 state = HIS_PRESSED;
314 else if ( flags & wxCONTROL_CURRENT )
315 state = HIS_HOT;
316 else
317 state = HIS_NORMAL;
318 wxUxThemeEngine::Get()->DrawThemeBackground
319 (
320 hTheme,
321 GetHdcOf(dc),
322 HP_HEADERITEM,
323 state,
324 &r,
325 NULL
326 );
327
328 // NOTE: Using the theme to draw HP_HEADERSORTARROW doesn't do anything.
329 // Why? If this can be fixed then draw the sort arrows using the theme
330 // and then clear those flags before calling DrawHeaderButtonContents.
331
332 // Add any extras that are specified in flags and params
333 DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
334 }
335
336
337 int
338 wxRendererXP::GetHeaderButtonHeight(wxWindow *win)
339 {
340 wxUxThemeHandle hTheme(win, L"HEADER");
341 if ( !hTheme )
342 {
343 return m_rendererNative.GetHeaderButtonHeight(win);
344 }
345
346 HRESULT hr;
347 int value = -1;
348
349 hr = wxUxThemeEngine::Get()->GetThemeMetric( hTheme,
350 NULL,
351 HP_HEADERITEM,
352 HIS_NORMAL,
353 TMT_HEIGHT,
354 &value );
355 if ( hr == S_OK )
356 return value;
357 else
358 return 20;
359 }
360
361
362 void
363 wxRendererXP::DrawTreeItemButton(wxWindow *win,
364 wxDC& dc,
365 const wxRect& rect,
366 int flags)
367 {
368 wxUxThemeHandle hTheme(win, L"TREEVIEW");
369 if ( !hTheme )
370 {
371 m_rendererNative.DrawTreeItemButton(win, dc, rect, flags);
372 return;
373 }
374
375 RECT r;
376 wxCopyRectToRECT(rect, r);
377
378 int state = flags & wxCONTROL_EXPANDED ? GLPS_OPENED : GLPS_CLOSED;
379 wxUxThemeEngine::Get()->DrawThemeBackground
380 (
381 hTheme,
382 GetHdcOf(dc),
383 TVP_GLYPH,
384 state,
385 &r,
386 NULL
387 );
388 }
389
390 void
391 wxRendererXP::DrawCheckBox(wxWindow *win,
392 wxDC& dc,
393 const wxRect& rect,
394 int flags)
395 {
396 wxUxThemeHandle hTheme(win, L"BUTTON");
397 if ( !hTheme )
398 {
399 m_rendererNative.DrawCheckBox(win, dc, rect, flags);
400 return;
401 }
402
403 RECT r;
404 wxCopyRectToRECT(rect, r);
405
406 int state;
407 if ( flags & wxCONTROL_CHECKED )
408 state = CBS_CHECKEDNORMAL;
409 else if ( flags & wxCONTROL_UNDETERMINED )
410 state = CBS_MIXEDNORMAL;
411 else
412 state = CBS_UNCHECKEDNORMAL;
413
414 // CBS_XXX is followed by CBX_XXXGOT, then CBS_XXXPRESSED and DISABLED
415 if ( flags & wxCONTROL_CURRENT )
416 state += 1;
417 else if ( flags & wxCONTROL_PRESSED )
418 state += 2;
419 else if ( flags & wxCONTROL_DISABLED )
420 state += 3;
421
422 wxUxThemeEngine::Get()->DrawThemeBackground
423 (
424 hTheme,
425 GetHdcOf(dc),
426 BP_CHECKBOX,
427 state,
428 &r,
429 NULL
430 );
431 }
432
433 void
434 wxRendererXP::DrawPushButton(wxWindow * win,
435 wxDC& dc,
436 const wxRect& rect,
437 int flags)
438 {
439 wxUxThemeHandle hTheme(win, L"BUTTON");
440 if ( !hTheme )
441 {
442 m_rendererNative.DrawPushButton(win, dc, rect, flags);
443 return;
444 }
445
446 RECT r;
447 wxCopyRectToRECT(rect, r);
448
449 int state;
450 if ( flags & wxCONTROL_PRESSED )
451 state = PBS_PRESSED;
452 else if ( flags & wxCONTROL_CURRENT )
453 state = PBS_HOT;
454 else if ( flags & wxCONTROL_DISABLED )
455 state = PBS_DISABLED;
456 else if ( flags & wxCONTROL_ISDEFAULT )
457 state = PBS_DEFAULTED;
458 else
459 state = PBS_NORMAL;
460
461 wxUxThemeEngine::Get()->DrawThemeBackground
462 (
463 hTheme,
464 GetHdcOf(dc),
465 BP_PUSHBUTTON,
466 state,
467 &r,
468 NULL
469 );
470
471 }
472
473 // ----------------------------------------------------------------------------
474 // splitter drawing
475 // ----------------------------------------------------------------------------
476
477 // the width of the sash: this is the same as used by Explorer...
478 static const wxCoord SASH_WIDTH = 4;
479
480 wxSplitterRenderParams
481 wxRendererXP::GetSplitterParams(const wxWindow * win)
482 {
483 if ( win->HasFlag(wxSP_NO_XP_THEME) )
484 return m_rendererNative.GetSplitterParams(win);
485 else
486 return wxSplitterRenderParams(SASH_WIDTH, 0, false);
487 }
488
489 void
490 wxRendererXP::DrawSplitterBorder(wxWindow * win,
491 wxDC& dc,
492 const wxRect& rect,
493 int flags)
494 {
495 if ( win->HasFlag(wxSP_NO_XP_THEME) )
496 {
497 m_rendererNative.DrawSplitterBorder(win, dc, rect, flags);
498 }
499 }
500
501 void
502 wxRendererXP::DrawSplitterSash(wxWindow *win,
503 wxDC& dc,
504 const wxSize& size,
505 wxCoord position,
506 wxOrientation orient,
507 int flags)
508 {
509 if ( !win->HasFlag(wxSP_NO_XP_THEME) )
510 {
511 dc.SetPen(*wxTRANSPARENT_PEN);
512 dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)));
513 if ( orient == wxVERTICAL )
514 {
515 dc.DrawRectangle(position, 0, SASH_WIDTH, size.y);
516 }
517 else // wxHORIZONTAL
518 {
519 dc.DrawRectangle(0, position, size.x, SASH_WIDTH);
520 }
521
522 return;
523 }
524
525 m_rendererNative.DrawSplitterSash(win, dc, size, position, orient, flags);
526 }
527
528 #endif // wxUSE_UXTHEME