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