]> git.saurik.com Git - wxWidgets.git/blob - src/msw/spinctrl.cpp
wxFrame's m_mainWidget didn't have themes.
[wxWidgets.git] / src / msw / spinctrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: msw/spinctrl.cpp
3 // Purpose: wxSpinCtrl class implementation for Win32
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 22.07.99
7 // RCS-ID: $Id$
8 // Copyright: (c) Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 #ifdef __GNUG__
17 #pragma implementation "spinctrlbase.h"
18 #pragma implementation "spinctrl.h"
19 #endif
20
21 // ----------------------------------------------------------------------------
22 // headers
23 // ----------------------------------------------------------------------------
24
25 // for compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
27
28 #ifdef __BORLANDC__
29 #pragma hdrstop
30 #endif
31
32 #ifndef WX_PRECOMP
33 #include "wx/wx.h"
34 #endif
35
36 #if wxUSE_SPINCTRL
37
38 #if defined(__WIN95__)
39
40 #include "wx/spinctrl.h"
41 #include "wx/msw/private.h"
42
43 #if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) || defined(__TWIN32__))
44 #include <commctrl.h>
45 #endif
46
47 #include <limits.h> // for INT_MIN
48
49 // ----------------------------------------------------------------------------
50 // macros
51 // ----------------------------------------------------------------------------
52
53 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl)
54
55 BEGIN_EVENT_TABLE(wxSpinCtrl, wxSpinButton)
56 EVT_SPIN(-1, wxSpinCtrl::OnSpinChange)
57 END_EVENT_TABLE()
58
59 // ----------------------------------------------------------------------------
60 // constants
61 // ----------------------------------------------------------------------------
62
63 // the margin between the up-down control and its buddy (can be arbitrary,
64 // choose what you like - or may be decide during run-time depending on the
65 // font size?)
66 static const int MARGIN_BETWEEN = 1;
67
68 // ============================================================================
69 // implementation
70 // ============================================================================
71
72 // ----------------------------------------------------------------------------
73 // wnd proc for the buddy text ctrl
74 // ----------------------------------------------------------------------------
75
76 LRESULT APIENTRY _EXPORT wxBuddyTextWndProc(HWND hwnd,
77 UINT message,
78 WPARAM wParam,
79 LPARAM lParam)
80 {
81 wxSpinCtrl *spin = (wxSpinCtrl *)::GetWindowLong(hwnd, GWL_USERDATA);
82
83 // forward some messages (the key ones only so far) to the spin ctrl
84 switch ( message )
85 {
86 case WM_CHAR:
87 case WM_DEADCHAR:
88 case WM_KEYUP:
89 case WM_KEYDOWN:
90 spin->MSWWindowProc(message, wParam, lParam);
91 break;
92 }
93
94 return ::CallWindowProc(CASTWNDPROC spin->GetBuddyWndProc(),
95 hwnd, message, wParam, lParam);
96 }
97
98 // ----------------------------------------------------------------------------
99 // construction
100 // ----------------------------------------------------------------------------
101
102 bool wxSpinCtrl::Create(wxWindow *parent,
103 wxWindowID id,
104 const wxString& value,
105 const wxPoint& pos,
106 const wxSize& size,
107 long style,
108 int min, int max, int initial,
109 const wxString& name)
110 {
111 // before using DoGetBestSize(), have to set style to let the base class
112 // know whether this is a horizontal or vertical control (we're always
113 // vertical)
114 style |= wxSP_VERTICAL;
115 SetWindowStyle(style);
116
117 // calculate the sizes: the size given is the toal size for both controls
118 // and we need to fit them both in the given width (height is the same)
119 wxSize sizeText(size), sizeBtn(size);
120 sizeBtn.x = wxSpinButton::DoGetBestSize().x;
121 if ( sizeText.x <= 0 )
122 {
123 // DEFAULT_ITEM_WIDTH is the default width for the text control
124 sizeText.x = DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN + sizeBtn.x;
125 }
126
127 sizeText.x -= sizeBtn.x + MARGIN_BETWEEN;
128 if ( sizeText.x <= 0 )
129 {
130 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
131 }
132
133 wxPoint posBtn(pos);
134 posBtn.x += sizeText.x + MARGIN_BETWEEN;
135
136 // create the spin button
137 if ( !wxSpinButton::Create(parent, id, posBtn, sizeBtn, style, name) )
138 {
139 return FALSE;
140 }
141
142 SetRange(min, max);
143 SetValue(initial);
144
145 // create the text window
146 m_hwndBuddy = (WXHWND)::CreateWindowEx
147 (
148 WS_EX_CLIENTEDGE, // sunken border
149 _T("EDIT"), // window class
150 NULL, // no window title
151 WS_CHILD | WS_BORDER /* | WS_CLIPSIBLINGS */, // style (will be shown later)
152 pos.x, pos.y, // position
153 0, 0, // size (will be set later)
154 GetHwndOf(parent), // parent
155 (HMENU)-1, // control id
156 wxGetInstance(), // app instance
157 NULL // unused client data
158 );
159
160 if ( !m_hwndBuddy )
161 {
162 wxLogLastError(wxT("CreateWindow(buddy text window)"));
163
164 return FALSE;
165 }
166
167 // subclass the text ctrl to be able to intercept some events
168 m_oldBuddyWndProc = (WXFARPROC)::GetWindowLong((HWND)m_hwndBuddy, GWL_WNDPROC);
169 ::SetWindowLong((HWND)m_hwndBuddy, GWL_USERDATA, (LONG)this);
170 ::SetWindowLong((HWND)m_hwndBuddy, GWL_WNDPROC, (LONG)wxBuddyTextWndProc);
171
172 // should have the same font as the other controls
173 SetFont(GetParent()->GetFont());
174
175 // set the size of the text window - can do it only now, because we
176 // couldn't call DoGetBestSize() before as font wasn't set
177 if ( sizeText.y <= 0 )
178 {
179 int cx, cy;
180 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
181
182 sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
183 }
184
185 DoMoveWindow(pos.x, pos.y,
186 sizeText.x + sizeBtn.x + MARGIN_BETWEEN, sizeText.y);
187
188 (void)::ShowWindow((HWND)m_hwndBuddy, SW_SHOW);
189
190 // associate the text window with the spin button
191 (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0);
192
193 if ( !value.IsEmpty() )
194 {
195 SetValue(value);
196 }
197
198 return TRUE;
199 }
200
201 wxSpinCtrl::~wxSpinCtrl()
202 {
203 // destroy the buddy window because this pointer which wxBuddyTextWndProc
204 // uses will not soon be valid any more
205 ::DestroyWindow((HWND)m_hwndBuddy);
206 }
207
208 // ----------------------------------------------------------------------------
209 // wxTextCtrl-like methods
210 // ----------------------------------------------------------------------------
211
212 void wxSpinCtrl::SetValue(const wxString& text)
213 {
214 if ( !::SetWindowText((HWND)m_hwndBuddy, text.c_str()) )
215 {
216 wxLogLastError(wxT("SetWindowText(buddy)"));
217 }
218 }
219
220 int wxSpinCtrl::GetValue() const
221 {
222 wxString val = wxGetWindowText(m_hwndBuddy);
223
224 long n;
225 if ( (wxSscanf(val, wxT("%lu"), &n) != 1) )
226 n = INT_MIN;
227
228 return n;
229 }
230
231 // ----------------------------------------------------------------------------
232 // forward some methods to subcontrols
233 // ----------------------------------------------------------------------------
234
235 bool wxSpinCtrl::SetFont(const wxFont& font)
236 {
237 if ( !wxWindowBase::SetFont(font) )
238 {
239 // nothing to do
240 return FALSE;
241 }
242
243 WXHANDLE hFont = GetFont().GetResourceHandle();
244 (void)::SendMessage((HWND)m_hwndBuddy, WM_SETFONT, (WPARAM)hFont, TRUE);
245
246 return TRUE;
247 }
248
249 bool wxSpinCtrl::Show(bool show)
250 {
251 if ( !wxControl::Show(show) )
252 {
253 return FALSE;
254 }
255
256 ::ShowWindow((HWND)m_hwndBuddy, show ? SW_SHOW : SW_HIDE);
257
258 return TRUE;
259 }
260
261 bool wxSpinCtrl::Enable(bool enable)
262 {
263 if ( !wxControl::Enable(enable) )
264 {
265 return FALSE;
266 }
267
268 ::EnableWindow((HWND)m_hwndBuddy, enable);
269
270 return TRUE;
271 }
272
273 void wxSpinCtrl::SetFocus()
274 {
275 ::SetFocus((HWND)m_hwndBuddy);
276 }
277
278 // ----------------------------------------------------------------------------
279 // event processing
280 // ----------------------------------------------------------------------------
281
282 void wxSpinCtrl::OnSpinChange(wxSpinEvent& eventSpin)
283 {
284 wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, GetId());
285 event.SetEventObject(this);
286 event.SetInt(eventSpin.GetPosition());
287
288 (void)GetEventHandler()->ProcessEvent(event);
289
290 if ( eventSpin.GetSkipped() )
291 {
292 event.Skip();
293 }
294 }
295
296 // ----------------------------------------------------------------------------
297 // size calculations
298 // ----------------------------------------------------------------------------
299
300 wxSize wxSpinCtrl::DoGetBestSize() const
301 {
302 wxSize sizeBtn = wxSpinButton::DoGetBestSize();
303 sizeBtn.x += DEFAULT_ITEM_WIDTH + MARGIN_BETWEEN;
304
305 int y;
306 wxGetCharSize(GetHWND(), NULL, &y, &GetFont());
307 y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(y);
308
309 if ( sizeBtn.y < y )
310 {
311 // make the text tall enough
312 sizeBtn.y = y;
313 }
314
315 return sizeBtn;
316 }
317
318 void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
319 {
320 int widthBtn = wxSpinButton::DoGetBestSize().x;
321 int widthText = width - widthBtn - MARGIN_BETWEEN;
322 if ( widthText <= 0 )
323 {
324 wxLogDebug(_T("not enough space for wxSpinCtrl!"));
325 }
326
327 if ( !::MoveWindow((HWND)m_hwndBuddy, x, y, widthText, height, TRUE) )
328 {
329 wxLogLastError(wxT("MoveWindow(buddy)"));
330 }
331
332 x += widthText + MARGIN_BETWEEN;
333 if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) )
334 {
335 wxLogLastError(wxT("MoveWindow"));
336 }
337 }
338
339 // get total size of the control
340 void wxSpinCtrl::DoGetSize(int *x, int *y) const
341 {
342 RECT spinrect, textrect, ctrlrect;
343 GetWindowRect(GetHwnd(), &spinrect);
344 GetWindowRect((HWND)m_hwndBuddy, &textrect);
345 UnionRect(&ctrlrect,&textrect, &spinrect);
346
347 if ( x )
348 *x = ctrlrect.right - ctrlrect.left;
349 if ( y )
350 *y = ctrlrect.bottom - ctrlrect.top;
351 }
352
353 void wxSpinCtrl::DoGetPosition(int *x, int *y) const
354 {
355 // hack: pretend that our HWND is the text control just for a moment
356 WXHWND hWnd = GetHWND();
357 wxConstCast(this, wxSpinCtrl)->m_hWnd = m_hwndBuddy;
358
359 wxSpinButton::DoGetPosition(x, y);
360
361 wxConstCast(this, wxSpinCtrl)->m_hWnd = hWnd;
362 }
363
364 #endif // __WIN95__
365
366 #endif
367 // wxUSE_SPINCTRL
368