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