1
///////////////////////////////////////////////////////////////////////////////
2
// Name: src/msw/renderer.cpp
3
// Purpose: implementation of wxRendererNative for Windows
4
// Author: Vadim Zeitlin
7
// RCS-ID: $Id: renderer.cpp 71569 2012-05-26 12:29:46Z VZ $
8
// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
9
// Licence: wxWindows licence
10
///////////////////////////////////////////////////////////////////////////////
12
// ============================================================================
14
// ============================================================================
16
// ----------------------------------------------------------------------------
18
// ----------------------------------------------------------------------------
20
// for compilers that support precompilation, includes "wx.h".
21
#include "wx/wxprec.h"
28
#include "wx/string.h"
29
#include "wx/window.h"
31
#include "wx/settings.h"
34
#include "wx/dcgraph.h"
35
#include "wx/scopeguard.h"
36
#include "wx/splitter.h"
37
#include "wx/renderer.h"
38
#include "wx/msw/private.h"
39
#include "wx/msw/uxtheme.h"
41
// tmschema.h is in Win32 Platform SDK and might not be available with earlier
43
#ifndef CP_DROPDOWNBUTTON
44
#define BP_PUSHBUTTON 1
45
#define BP_RADIOBUTTON 2
47
#define RBS_UNCHECKEDNORMAL 1
48
#define RBS_CHECKEDNORMAL (RBS_UNCHECKEDNORMAL + 4)
49
#define RBS_MIXEDNORMAL (RBS_CHECKEDNORMAL + 4)
50
#define CBS_UNCHECKEDNORMAL 1
51
#define CBS_CHECKEDNORMAL (CBS_UNCHECKEDNORMAL + 4)
52
#define CBS_MIXEDNORMAL (CBS_CHECKEDNORMAL + 4)
57
#define PBS_DISABLED 4
58
#define PBS_DEFAULTED 5
60
#define CP_DROPDOWNBUTTON 1
64
#define CBXS_PRESSED 3
65
#define CBXS_DISABLED 4
72
#define HP_HEADERITEM 1
78
#define TMT_HEIGHT 2417
80
#define HP_HEADERSORTARROW 4
81
#define HSAS_SORTEDUP 1
82
#define HSAS_SORTEDDOWN 2
87
#define ETS_SELECTED 3
88
#define ETS_DISABLED 4
90
#define ETS_READONLY 6
92
#define TMT_FILLCOLOR 3802
93
#define TMT_TEXTCOLOR 3803
94
#define TMT_BORDERCOLOR 3801
95
#define TMT_EDGEFILLCOLOR 3808
97
#define WP_MINBUTTON 15
98
#define WP_MAXBUTTON 17
99
#define WP_CLOSEBUTTON 18
100
#define WP_RESTOREBUTTON 21
101
#define WP_HELPBUTTON 23
104
#if defined(__WXWINCE__)
114
#define DFCS_HOT 0x1000
117
// ----------------------------------------------------------------------------
118
// methods common to wxRendererMSW and wxRendererXP
119
// ----------------------------------------------------------------------------
121
class wxRendererMSWBase : public wxDelegateRendererNative
124
wxRendererMSWBase() { }
125
wxRendererMSWBase(wxRendererNative& rendererNative)
126
: wxDelegateRendererNative(rendererNative) { }
128
void DrawFocusRect(wxWindow * win,
133
void DrawItemSelectionRect(wxWindow *win,
138
void DrawChoice(wxWindow* win,
143
void DrawComboBox(wxWindow* win,
148
virtual void DrawComboBoxDropButton(wxWindow *win,
153
virtual void DrawTextCtrl(wxWindow* win,
159
// ----------------------------------------------------------------------------
160
// wxRendererMSW: wxRendererNative implementation for "old" Win32 systems
161
// ----------------------------------------------------------------------------
163
class wxRendererMSW : public wxRendererMSWBase
168
static wxRendererNative& Get();
170
virtual void DrawComboBoxDropButton(wxWindow *win,
175
virtual void DrawCheckBox(wxWindow *win,
180
DoDrawButton(DFCS_BUTTONCHECK, win, dc, rect, flags);
183
virtual void DrawPushButton(wxWindow *win,
188
virtual void DrawTextCtrl(wxWindow* win,
193
virtual void DrawRadioBitmap(wxWindow* win,
198
DoDrawButton(DFCS_BUTTONRADIO, win, dc, rect, flags);
201
virtual void DrawTitleBarBitmap(wxWindow *win,
204
wxTitleBarButton button,
207
virtual wxSize GetCheckBoxSize(wxWindow *win);
209
virtual int GetHeaderButtonHeight(wxWindow *win);
211
virtual int GetHeaderButtonMargin(wxWindow *win);
214
// wrapper of DrawFrameControl()
215
void DoDrawFrameControl(UINT type,
222
// common part of Draw{PushButton,CheckBox,RadioBitmap}(): wraps
223
// DrawFrameControl(DFC_BUTTON)
224
void DoDrawButton(UINT kind,
230
DoDrawFrameControl(DFC_BUTTON, kind, win, dc, rect, flags);
233
wxDECLARE_NO_COPY_CLASS(wxRendererMSW);
236
// ----------------------------------------------------------------------------
237
// wxRendererXP: wxRendererNative implementation for Windows XP and later
238
// ----------------------------------------------------------------------------
242
class wxRendererXP : public wxRendererMSWBase
245
wxRendererXP() : wxRendererMSWBase(wxRendererMSW::Get()) { }
247
static wxRendererNative& Get();
249
virtual int DrawHeaderButton(wxWindow *win,
253
wxHeaderSortIconType sortArrow = wxHDR_SORT_ICON_NONE,
254
wxHeaderButtonParams* params = NULL);
256
virtual void DrawTreeItemButton(wxWindow *win,
260
virtual void DrawSplitterBorder(wxWindow *win,
264
virtual void DrawSplitterSash(wxWindow *win,
268
wxOrientation orient,
270
virtual void DrawComboBoxDropButton(wxWindow *win,
274
virtual void DrawCheckBox(wxWindow *win,
279
if ( !DoDrawXPButton(BP_CHECKBOX, win, dc, rect, flags) )
280
m_rendererNative.DrawCheckBox(win, dc, rect, flags);
283
virtual void DrawPushButton(wxWindow *win,
288
if ( !DoDrawXPButton(BP_PUSHBUTTON, win, dc, rect, flags) )
289
m_rendererNative.DrawPushButton(win, dc, rect, flags);
292
virtual void DrawTextCtrl(wxWindow* win,
297
virtual void DrawRadioBitmap(wxWindow *win,
302
if ( !DoDrawXPButton(BP_RADIOBUTTON, win, dc, rect, flags) )
303
m_rendererNative.DrawRadioBitmap(win, dc, rect, flags);
306
virtual void DrawTitleBarBitmap(wxWindow *win,
309
wxTitleBarButton button,
312
virtual wxSplitterRenderParams GetSplitterParams(const wxWindow *win);
315
// wrapper around DrawThemeBackground() translating flags to NORMAL/HOT/
316
// PUSHED/DISABLED states (and so suitable for drawing anything
318
void DoDrawButtonLike(HTHEME htheme,
324
// common part of DrawCheckBox(), DrawPushButton() and DrawRadioBitmap()
325
bool DoDrawXPButton(int kind,
331
wxDECLARE_NO_COPY_CLASS(wxRendererXP);
334
#endif // wxUSE_UXTHEME
337
// ============================================================================
338
// wxRendererMSWBase implementation
339
// ============================================================================
341
void wxRendererMSWBase::DrawFocusRect(wxWindow * WXUNUSED(win),
347
wxCopyRectToRECT(rect, rc);
349
::DrawFocusRect(GetHdcOf(dc.GetTempHDC()), &rc);
352
void wxRendererMSWBase::DrawItemSelectionRect(wxWindow *win,
358
if ( flags & wxCONTROL_SELECTED )
360
if ( flags & wxCONTROL_FOCUSED )
362
brush = wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
366
brush = wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
371
brush = *wxTRANSPARENT_BRUSH;
375
dc.SetPen(*wxTRANSPARENT_PEN);
376
dc.DrawRectangle( rect );
378
if ((flags & wxCONTROL_FOCUSED) && (flags & wxCONTROL_CURRENT))
379
DrawFocusRect( win, dc, rect, flags );
382
void wxRendererMSWBase::DrawChoice(wxWindow* win,
387
DrawComboBox(win, dc, rect, flags);
390
void wxRendererMSWBase::DrawComboBox(wxWindow* win,
395
// Draw the main part of the control same as TextCtrl
396
DrawTextCtrl(win, dc, rect, flags);
398
// Draw the button inside the border, on the right side
401
br.x += br.width - br.height - 1;
402
br.width = br.height;
405
DrawComboBoxDropButton(win, dc, br, flags);
408
// ============================================================================
409
// wxRendererNative and wxRendererMSW implementation
410
// ============================================================================
413
wxRendererNative& wxRendererNative::GetDefault()
416
wxUxThemeEngine *themeEngine = wxUxThemeEngine::Get();
417
if ( themeEngine && themeEngine->IsAppThemed() )
418
return wxRendererXP::Get();
419
#endif // wxUSE_UXTHEME
421
return wxRendererMSW::Get();
425
wxRendererNative& wxRendererMSW::Get()
427
static wxRendererMSW s_rendererMSW;
429
return s_rendererMSW;
433
wxRendererMSW::DrawComboBoxDropButton(wxWindow * WXUNUSED(win),
438
wxCHECK_RET( dc.GetImpl(), wxT("Invalid wxDC") );
440
wxRect adjustedRect = dc.GetImpl()->MSWApplyGDIPlusTransform(rect);
443
wxCopyRectToRECT(adjustedRect, r);
445
int style = DFCS_SCROLLCOMBOBOX;
446
if ( flags & wxCONTROL_DISABLED )
447
style |= DFCS_INACTIVE;
448
if ( flags & wxCONTROL_PRESSED )
449
style |= DFCS_PUSHED | DFCS_FLAT;
451
::DrawFrameControl(GetHdcOf(dc.GetTempHDC()), &r, DFC_SCROLL, style);
455
wxRendererMSW::DoDrawFrameControl(UINT type,
457
wxWindow * WXUNUSED(win),
462
wxCHECK_RET( dc.GetImpl(), wxT("Invalid wxDC") );
464
wxRect adjustedRect = dc.GetImpl()->MSWApplyGDIPlusTransform(rect);
467
wxCopyRectToRECT(adjustedRect, r);
470
if ( flags & wxCONTROL_CHECKED )
471
style |= DFCS_CHECKED;
472
if ( flags & wxCONTROL_DISABLED )
473
style |= DFCS_INACTIVE;
474
if ( flags & wxCONTROL_FLAT )
476
if ( flags & wxCONTROL_PRESSED )
477
style |= DFCS_PUSHED;
478
if ( flags & wxCONTROL_CURRENT )
480
if ( flags & wxCONTROL_UNDETERMINED )
481
// Using DFCS_BUTTON3STATE here doesn't work (as might be expected),
482
// use the following two styles to get the same look of a check box
483
// in the undetermined state.
484
style |= DFCS_INACTIVE | DFCS_CHECKED;
486
::DrawFrameControl(GetHdcOf(dc.GetTempHDC()), &r, type, style);
490
wxRendererMSW::DrawPushButton(wxWindow *win,
492
const wxRect& rectOrig,
495
wxRect rect(rectOrig);
496
if ( flags & wxCONTROL_ISDEFAULT )
498
// DrawFrameControl() doesn't seem to support default buttons so we
499
// have to draw the border ourselves
500
wxDCPenChanger pen(dc, *wxBLACK_PEN);
501
wxDCBrushChanger brush(dc, *wxTRANSPARENT_BRUSH);
502
dc.DrawRectangle(rect);
506
DoDrawButton(DFCS_BUTTONPUSH, win, dc, rect, flags);
510
wxRendererMSW::DrawTitleBarBitmap(wxWindow *win,
513
wxTitleBarButton button,
519
case wxTITLEBAR_BUTTON_CLOSE:
520
kind = DFCS_CAPTIONCLOSE;
523
case wxTITLEBAR_BUTTON_MAXIMIZE:
524
kind = DFCS_CAPTIONMAX;
527
case wxTITLEBAR_BUTTON_ICONIZE:
528
kind = DFCS_CAPTIONMIN;
531
case wxTITLEBAR_BUTTON_RESTORE:
532
kind = DFCS_CAPTIONRESTORE;
535
case wxTITLEBAR_BUTTON_HELP:
536
kind = DFCS_CAPTIONHELP;
540
wxFAIL_MSG( "unsupported title bar button" );
544
DoDrawFrameControl(DFC_CAPTION, kind, win, dc, rect, flags);
547
wxSize wxRendererMSW::GetCheckBoxSize(wxWindow * WXUNUSED(win))
549
return wxSize(::GetSystemMetrics(SM_CXMENUCHECK),
550
::GetSystemMetrics(SM_CYMENUCHECK));
553
int wxRendererMSW::GetHeaderButtonHeight(wxWindow * WXUNUSED(win))
555
// some "reasonable" value returned in case of error, it doesn't really
556
// correspond to anything but it's better than returning 0
557
static const int DEFAULT_HEIGHT = 20;
560
// create a temporary header window just to get its geometry
561
HWND hwndHeader = ::CreateWindow(WC_HEADER, NULL, 0,
562
0, 0, 0, 0, NULL, NULL, NULL, NULL);
564
return DEFAULT_HEIGHT;
566
wxON_BLOCK_EXIT1( ::DestroyWindow, hwndHeader );
568
// initialize the struct filled with the values by Header_Layout()
569
RECT parentRect = { 0, 0, 100, 100 };
570
WINDOWPOS wp = { 0, 0, 0, 0, 0, 0, 0 };
571
HDLAYOUT hdl = { &parentRect, &wp };
573
return Header_Layout(hwndHeader, &hdl) ? wp.cy : DEFAULT_HEIGHT;
576
int wxRendererMSW::GetHeaderButtonMargin(wxWindow *WXUNUSED(win))
581
// Uses the theme to draw the border and fill for something like a wxTextCtrl
582
void wxRendererMSW::DrawTextCtrl(wxWindow* WXUNUSED(win),
590
fill = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
596
dc.DrawRectangle(rect);
600
// ============================================================================
601
// wxRendererXP implementation
602
// ============================================================================
607
wxRendererNative& wxRendererXP::Get()
609
static wxRendererXP s_rendererXP;
614
// NOTE: There is no guarantee that the button drawn fills the entire rect (XP
615
// default theme, for example), so the caller should have cleared button's
616
// background before this call. This is quite likely a wxMSW-specific thing.
618
wxRendererXP::DrawComboBoxDropButton(wxWindow * win,
623
wxUxThemeHandle hTheme(win, L"COMBOBOX");
626
m_rendererNative.DrawComboBoxDropButton(win, dc, rect, flags);
630
wxCHECK_RET( dc.GetImpl(), wxT("Invalid wxDC") );
632
wxRect adjustedRect = dc.GetImpl()->MSWApplyGDIPlusTransform(rect);
635
wxCopyRectToRECT(adjustedRect, r);
638
if ( flags & wxCONTROL_PRESSED )
639
state = CBXS_PRESSED;
640
else if ( flags & wxCONTROL_CURRENT )
642
else if ( flags & wxCONTROL_DISABLED )
643
state = CBXS_DISABLED;
647
wxUxThemeEngine::Get()->DrawThemeBackground
650
GetHdcOf(dc.GetTempHDC()),
660
wxRendererXP::DrawHeaderButton(wxWindow *win,
664
wxHeaderSortIconType sortArrow,
665
wxHeaderButtonParams* params)
667
wxUxThemeHandle hTheme(win, L"HEADER");
670
return m_rendererNative.DrawHeaderButton(win, dc, rect, flags, sortArrow, params);
673
wxCHECK_MSG( dc.GetImpl(), -1, wxT("Invalid wxDC") );
675
wxRect adjustedRect = dc.GetImpl()->MSWApplyGDIPlusTransform(rect);
678
wxCopyRectToRECT(adjustedRect, r);
681
if ( flags & wxCONTROL_PRESSED )
683
else if ( flags & wxCONTROL_CURRENT )
687
wxUxThemeEngine::Get()->DrawThemeBackground
690
GetHdcOf(dc.GetTempHDC()),
697
// NOTE: Using the theme to draw HP_HEADERSORTARROW doesn't do anything.
698
// Why? If this can be fixed then draw the sort arrows using the theme
699
// and then clear those flags before calling DrawHeaderButtonContents.
701
// Add any extras that are specified in flags and params
702
return DrawHeaderButtonContents(win, dc, rect, flags, sortArrow, params);
707
wxRendererXP::DrawTreeItemButton(wxWindow *win,
712
wxUxThemeHandle hTheme(win, L"TREEVIEW");
715
m_rendererNative.DrawTreeItemButton(win, dc, rect, flags);
719
wxCHECK_RET( dc.GetImpl(), wxT("Invalid wxDC") );
721
wxRect adjustedRect = dc.GetImpl()->MSWApplyGDIPlusTransform(rect);
724
wxCopyRectToRECT(adjustedRect, r);
726
int state = flags & wxCONTROL_EXPANDED ? GLPS_OPENED : GLPS_CLOSED;
727
wxUxThemeEngine::Get()->DrawThemeBackground
730
GetHdcOf(dc.GetTempHDC()),
739
wxRendererXP::DoDrawXPButton(int kind,
745
wxUxThemeHandle hTheme(win, L"BUTTON");
749
DoDrawButtonLike(hTheme, kind, dc, rect, flags);
755
wxRendererXP::DoDrawButtonLike(HTHEME htheme,
761
wxCHECK_RET( dc.GetImpl(), wxT("Invalid wxDC") );
763
wxRect adjustedRect = dc.GetImpl()->MSWApplyGDIPlusTransform(rect);
766
wxCopyRectToRECT(adjustedRect, r);
768
// the base state is always 1, whether it is PBS_NORMAL,
769
// {CBS,RBS}_UNCHECKEDNORMAL or CBS_NORMAL
772
// XBS_XXX is followed by XBX_XXXHOT, then XBS_XXXPRESSED and DISABLED
782
// in both RBS_ and CBS_ enums CHECKED elements are offset by 4 from base
783
// (UNCHECKED) ones and MIXED are offset by 4 again as there are all states
784
// from the above enum in between them
785
if ( flags & wxCONTROL_CHECKED )
786
state += STATES_COUNT;
787
else if ( flags & wxCONTROL_UNDETERMINED )
788
state += 2*STATES_COUNT;
790
if ( flags & wxCONTROL_DISABLED )
791
state += DISABLED_OFFSET;
792
else if ( flags & wxCONTROL_PRESSED )
793
state += PRESSED_OFFSET;
794
else if ( flags & wxCONTROL_CURRENT )
796
// wxCONTROL_ISDEFAULT flag is only valid for push buttons
797
else if ( part == BP_PUSHBUTTON && (flags & wxCONTROL_ISDEFAULT) )
798
state = PBS_DEFAULTED;
800
wxUxThemeEngine::Get()->DrawThemeBackground
803
GetHdcOf(dc.GetTempHDC()),
812
wxRendererXP::DrawTitleBarBitmap(wxWindow *win,
815
wxTitleBarButton button,
818
wxUxThemeHandle hTheme(win, L"WINDOW");
821
m_rendererNative.DrawTitleBarBitmap(win, dc, rect, button, flags);
828
case wxTITLEBAR_BUTTON_CLOSE:
829
part = WP_CLOSEBUTTON;
832
case wxTITLEBAR_BUTTON_MAXIMIZE:
836
case wxTITLEBAR_BUTTON_ICONIZE:
840
case wxTITLEBAR_BUTTON_RESTORE:
841
part = WP_RESTOREBUTTON;
844
case wxTITLEBAR_BUTTON_HELP:
845
part = WP_HELPBUTTON;
849
wxFAIL_MSG( "unsupported title bar button" );
853
DoDrawButtonLike(hTheme, part, dc, rect, flags);
856
// Uses the theme to draw the border and fill for something like a wxTextCtrl
857
void wxRendererXP::DrawTextCtrl(wxWindow* win,
862
wxUxThemeHandle hTheme(win, L"EDIT");
865
m_rendererNative.DrawTextCtrl(win,dc,rect,flags);
873
wxUxThemeEngine::Get()->GetThemeColor(hTheme, EP_EDITTEXT,
874
ETS_NORMAL, TMT_FILLCOLOR, &cref);
875
fill = wxRGBToColour(cref);
878
if ( flags & wxCONTROL_DISABLED )
879
etsState = ETS_DISABLED;
881
etsState = ETS_NORMAL;
883
wxUxThemeEngine::Get()->GetThemeColor(hTheme, EP_EDITTEXT,
884
etsState, TMT_BORDERCOLOR, &cref);
885
bdr = wxRGBToColour(cref);
889
dc.DrawRectangle(rect);
892
// ----------------------------------------------------------------------------
894
// ----------------------------------------------------------------------------
896
// the width of the sash: this is the same as used by Explorer...
897
static const wxCoord SASH_WIDTH = 4;
899
wxSplitterRenderParams
900
wxRendererXP::GetSplitterParams(const wxWindow * win)
902
if ( win->HasFlag(wxSP_NO_XP_THEME) )
903
return m_rendererNative.GetSplitterParams(win);
905
return wxSplitterRenderParams(SASH_WIDTH, 0, false);
909
wxRendererXP::DrawSplitterBorder(wxWindow * win,
914
if ( win->HasFlag(wxSP_NO_XP_THEME) )
916
m_rendererNative.DrawSplitterBorder(win, dc, rect, flags);
921
wxRendererXP::DrawSplitterSash(wxWindow *win,
925
wxOrientation orient,
928
if ( !win->HasFlag(wxSP_NO_XP_THEME) )
930
dc.SetPen(*wxTRANSPARENT_PEN);
931
dc.SetBrush(wxBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)));
932
if ( orient == wxVERTICAL )
934
dc.DrawRectangle(position, 0, SASH_WIDTH, size.y);
938
dc.DrawRectangle(0, position, size.x, SASH_WIDTH);
944
m_rendererNative.DrawSplitterSash(win, dc, size, position, orient, flags);
947
#endif // wxUSE_UXTHEME