]> git.saurik.com Git - wxWidgets.git/blob - src/msw/control.cpp
Make wx{List,Tree}Ctrl resize their standard font if the user changes the system...
[wxWidgets.git] / src / msw / control.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/control.cpp
3 // Purpose: wxControl class
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 01/02/97
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: 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 #if wxUSE_CONTROLS
28
29 #ifndef WX_PRECOMP
30 #include "wx/event.h"
31 #include "wx/app.h"
32 #include "wx/dcclient.h"
33 #include "wx/log.h"
34 #include "wx/settings.h"
35 #endif
36
37 #include "wx/control.h"
38
39 #if wxUSE_LISTCTRL
40 #include "wx/listctrl.h"
41 #endif // wxUSE_LISTCTRL
42
43 #if wxUSE_TREECTRL
44 #include "wx/treectrl.h"
45 #endif // wxUSE_TREECTRL
46
47 #include "wx/msw/private.h"
48 #include "wx/msw/uxtheme.h"
49
50 // include <commctrl.h> "properly"
51 #include "wx/msw/wrapcctl.h"
52
53 // ----------------------------------------------------------------------------
54 // wxWin macros
55 // ----------------------------------------------------------------------------
56
57 IMPLEMENT_ABSTRACT_CLASS(wxControl, wxWindow)
58
59 // ============================================================================
60 // wxControl implementation
61 // ============================================================================
62
63 // ----------------------------------------------------------------------------
64 // wxControl ctor/dtor
65 // ----------------------------------------------------------------------------
66
67 wxControl::~wxControl()
68 {
69 m_isBeingDeleted = true;
70 }
71
72 // ----------------------------------------------------------------------------
73 // control window creation
74 // ----------------------------------------------------------------------------
75
76 bool wxControl::Create(wxWindow *parent,
77 wxWindowID id,
78 const wxPoint& pos,
79 const wxSize& size,
80 long style,
81 const wxValidator& wxVALIDATOR_PARAM(validator),
82 const wxString& name)
83 {
84 if ( !wxWindow::Create(parent, id, pos, size, style, name) )
85 return false;
86
87 #if wxUSE_VALIDATORS
88 SetValidator(validator);
89 #endif
90
91 return true;
92 }
93
94 bool wxControl::MSWCreateControl(const wxChar *classname,
95 const wxString& label,
96 const wxPoint& pos,
97 const wxSize& size)
98 {
99 WXDWORD exstyle;
100 WXDWORD msStyle = MSWGetStyle(GetWindowStyle(), &exstyle);
101
102 return MSWCreateControl(classname, msStyle, pos, size, label, exstyle);
103 }
104
105 bool wxControl::MSWCreateControl(const wxChar *classname,
106 WXDWORD style,
107 const wxPoint& pos,
108 const wxSize& size,
109 const wxString& label,
110 WXDWORD exstyle)
111 {
112 // if no extended style given, determine it ourselves
113 if ( exstyle == (WXDWORD)-1 )
114 {
115 exstyle = 0;
116 (void) MSWGetStyle(GetWindowStyle(), &exstyle);
117 }
118
119 // all controls should have this style
120 style |= WS_CHILD;
121
122 // create the control visible if it's currently shown for wxWidgets
123 if ( m_isShown )
124 {
125 style |= WS_VISIBLE;
126 }
127
128 // choose the position for the control: we have a problem with default size
129 // here as we can't calculate the best size before the control exists
130 // (DoGetBestSize() may need to use m_hWnd), so just choose the minimal
131 // possible but non 0 size because 0 window width/height result in problems
132 // elsewhere
133 int x = pos.x == wxDefaultCoord ? 0 : pos.x,
134 y = pos.y == wxDefaultCoord ? 0 : pos.y,
135 w = size.x == wxDefaultCoord ? 1 : size.x,
136 h = size.y == wxDefaultCoord ? 1 : size.y;
137
138 // ... and adjust it to account for a possible parent frames toolbar
139 AdjustForParentClientOrigin(x, y);
140
141 m_hWnd = (WXHWND)::CreateWindowEx
142 (
143 exstyle, // extended style
144 classname, // the kind of control to create
145 label, // the window name
146 style, // the window style
147 x, y, w, h, // the window position and size
148 GetHwndOf(GetParent()), // parent
149 (HMENU)GetId(), // child id
150 wxGetInstance(), // app instance
151 NULL // creation parameters
152 );
153
154 if ( !m_hWnd )
155 {
156 #ifdef __WXDEBUG__
157 wxFAIL_MSG(wxString::Format
158 (
159 _T("CreateWindowEx(\"%s\", flags=%08x, ex=%08x) failed"),
160 classname, (unsigned int)style, (unsigned int)exstyle
161 ));
162 #endif // __WXDEBUG__
163
164 return false;
165 }
166
167 // install wxWidgets window proc for this window
168 SubclassWin(m_hWnd);
169
170 // set up fonts and colours
171 InheritAttributes();
172 if ( !m_hasFont )
173 {
174 #if wxUSE_LISTCTRL || wxUSE_TREECTRL
175 // if we set a font for {list,tree}ctrls and the font size is changed in
176 // the display properties then the font size for these controls doesn't
177 // automatically adjust when they receive WM_SETTINGCHANGE
178 if ( wxDynamicCastThis(wxListCtrl) || wxDynamicCastThis(wxTreeCtrl) )
179 {
180 // not sure if we need to explicitly set the font here for Win95/NT4
181 // but we definitely can't do it for any newer version
182 // see wxGetCCDefaultFont() in src/msw/settings.cpp for explanation
183 // of why this test works
184
185 // TODO: test Win95/NT4 to see if this is needed or breaks the
186 // font resizing as it does on newer versions
187 wxFont font = GetDefaultAttributes().font;
188 if ( font == wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT) )
189 {
190 SetFont(font);
191 }
192 }
193 else
194 #endif // wxUSE_LISTCTRL || wxUSE_TREECTRL
195 {
196 SetFont(GetDefaultAttributes().font);
197 }
198 }
199
200 // set the size now if no initial size specified
201 SetInitialBestSize(size);
202
203 return true;
204 }
205
206 // ----------------------------------------------------------------------------
207 // various accessors
208 // ----------------------------------------------------------------------------
209
210 wxBorder wxControl::GetDefaultBorder() const
211 {
212 // we want to automatically give controls a sunken style (confusingly,
213 // it may not really mean sunken at all as we map it to WS_EX_CLIENTEDGE
214 // which is not sunken at all under Windows XP -- rather, just the default)
215 #if defined(__POCKETPC__) || defined(__SMARTPHONE__)
216 return wxBORDER_SIMPLE;
217 #else
218 return wxBORDER_SUNKEN;
219 #endif
220 }
221
222 WXDWORD wxControl::MSWGetStyle(long style, WXDWORD *exstyle) const
223 {
224 long msStyle = wxWindow::MSWGetStyle(style, exstyle);
225
226 if ( AcceptsFocus() )
227 {
228 msStyle |= WS_TABSTOP;
229 }
230
231 return msStyle;
232 }
233
234 wxSize wxControl::DoGetBestSize() const
235 {
236 return wxSize(DEFAULT_ITEM_WIDTH, DEFAULT_ITEM_HEIGHT);
237 }
238
239 // This is a helper for all wxControls made with UPDOWN native control.
240 // In wxMSW it was only wxSpinCtrl derived from wxSpinButton but in
241 // WinCE of Smartphones this happens also for native wxTextCtrl,
242 // wxChoice and others.
243 wxSize wxControl::GetBestSpinnerSize(const bool is_vertical) const
244 {
245 // take size according to layout
246 wxSize bestSize(
247 #if defined(__SMARTPHONE__) && defined(__WXWINCE__)
248 0,GetCharHeight()
249 #else
250 ::GetSystemMetrics(is_vertical ? SM_CXVSCROLL : SM_CXHSCROLL),
251 ::GetSystemMetrics(is_vertical ? SM_CYVSCROLL : SM_CYHSCROLL)
252 #endif
253 );
254
255 // correct size as for undocumented MSW variants cases (WinCE and perhaps others)
256 if (bestSize.x==0)
257 bestSize.x = bestSize.y;
258 if (bestSize.y==0)
259 bestSize.y = bestSize.x;
260
261 // double size according to layout
262 if (is_vertical)
263 bestSize.y *= 2;
264 else
265 bestSize.x *= 2;
266
267 return bestSize;
268 }
269
270 /* static */ wxVisualAttributes
271 wxControl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
272 {
273 wxVisualAttributes attrs;
274
275 // old school (i.e. not "common") controls use the standard dialog font
276 // by default
277 attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
278
279 // most, or at least many, of the controls use the same colours as the
280 // buttons -- others will have to override this (and possibly simply call
281 // GetCompositeControlsDefaultAttributes() from their versions)
282 attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT);
283 attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE);
284
285 return attrs;
286 }
287
288 // another version for the "composite", i.e. non simple controls
289 /* static */ wxVisualAttributes
290 wxControl::GetCompositeControlsDefaultAttributes(wxWindowVariant WXUNUSED(variant))
291 {
292 wxVisualAttributes attrs;
293 attrs.font = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
294 attrs.colFg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
295 attrs.colBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
296
297 return attrs;
298 }
299
300 // ----------------------------------------------------------------------------
301 // message handling
302 // ----------------------------------------------------------------------------
303
304 bool wxControl::ProcessCommand(wxCommandEvent& event)
305 {
306 return GetEventHandler()->ProcessEvent(event);
307 }
308
309 bool wxControl::MSWOnNotify(int idCtrl,
310 WXLPARAM lParam,
311 WXLPARAM* result)
312 {
313 wxEventType eventType wxDUMMY_INITIALIZE(wxEVT_NULL);
314
315 NMHDR *hdr = (NMHDR*) lParam;
316 switch ( hdr->code )
317 {
318 case NM_CLICK:
319 eventType = wxEVT_COMMAND_LEFT_CLICK;
320 break;
321
322 case NM_DBLCLK:
323 eventType = wxEVT_COMMAND_LEFT_DCLICK;
324 break;
325
326 case NM_RCLICK:
327 eventType = wxEVT_COMMAND_RIGHT_CLICK;
328 break;
329
330 case NM_RDBLCLK:
331 eventType = wxEVT_COMMAND_RIGHT_DCLICK;
332 break;
333
334 case NM_SETFOCUS:
335 eventType = wxEVT_COMMAND_SET_FOCUS;
336 break;
337
338 case NM_KILLFOCUS:
339 eventType = wxEVT_COMMAND_KILL_FOCUS;
340 break;
341
342 case NM_RETURN:
343 eventType = wxEVT_COMMAND_ENTER;
344 break;
345
346 default:
347 return wxWindow::MSWOnNotify(idCtrl, lParam, result);
348 }
349
350 wxCommandEvent event(wxEVT_NULL, m_windowId);
351 event.SetEventType(eventType);
352 event.SetEventObject(this);
353
354 return GetEventHandler()->ProcessEvent(event);
355 }
356
357 WXHBRUSH wxControl::DoMSWControlColor(WXHDC pDC, wxColour colBg, WXHWND hWnd)
358 {
359 HDC hdc = (HDC)pDC;
360 if ( m_hasFgCol )
361 {
362 ::SetTextColor(hdc, wxColourToRGB(GetForegroundColour()));
363 }
364
365 WXHBRUSH hbr = 0;
366 if ( !colBg.Ok() )
367 {
368 hbr = MSWGetBgBrush(pDC, hWnd);
369
370 // if the control doesn't have any bg colour, foreground colour will be
371 // ignored as the return value would be 0 -- so forcefully give it a
372 // non default background brush in this case
373 if ( !hbr && m_hasFgCol )
374 colBg = GetBackgroundColour();
375 }
376
377 // use the background colour override if a valid colour is given
378 if ( colBg.Ok() )
379 {
380 ::SetBkColor(hdc, wxColourToRGB(colBg));
381
382 // draw children with the same colour as the parent
383 wxBrush *brush = wxTheBrushList->FindOrCreateBrush(colBg, wxSOLID);
384
385 hbr = (WXHBRUSH)brush->GetResourceHandle();
386
387 // if we use custom background, we should set foreground ourselves too
388 if ( !m_hasFgCol )
389 {
390 ::SetTextColor(hdc, ::GetSysColor(COLOR_WINDOWTEXT));
391 }
392 //else: already set above
393 }
394
395 return hbr;
396 }
397
398 WXHBRUSH wxControl::MSWControlColor(WXHDC pDC, WXHWND hWnd)
399 {
400 wxColour colBg;
401
402 if ( HasTransparentBackground() )
403 ::SetBkMode((HDC)pDC, TRANSPARENT);
404 else // if the control is opaque it shouldn't use the parents background
405 colBg = GetBackgroundColour();
406
407 return DoMSWControlColor(pDC, colBg, hWnd);
408 }
409
410 WXHBRUSH wxControl::MSWControlColorDisabled(WXHDC pDC)
411 {
412 return DoMSWControlColor(pDC,
413 wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE),
414 GetHWND());
415 }
416
417 // ---------------------------------------------------------------------------
418 // global functions
419 // ---------------------------------------------------------------------------
420
421 // this is used in radiobox.cpp and slider95.cpp and should be removed as soon
422 // as it is not needed there any more!
423 //
424 // Call this repeatedly for several wnds to find the overall size
425 // of the widget.
426 // Call it initially with wxDefaultCoord for all values in rect.
427 // Keep calling for other widgets, and rect will be modified
428 // to calculate largest bounding rectangle.
429 void wxFindMaxSize(WXHWND wnd, RECT *rect)
430 {
431 int left = rect->left;
432 int right = rect->right;
433 int top = rect->top;
434 int bottom = rect->bottom;
435
436 GetWindowRect((HWND) wnd, rect);
437
438 if (left < 0)
439 return;
440
441 if (left < rect->left)
442 rect->left = left;
443
444 if (right > rect->right)
445 rect->right = right;
446
447 if (top < rect->top)
448 rect->top = top;
449
450 if (bottom > rect->bottom)
451 rect->bottom = bottom;
452 }
453
454 #endif // wxUSE_CONTROLS