]> git.saurik.com Git - wxWidgets.git/blame - src/msw/spinctrl.cpp
fixes from the 2.2 branch
[wxWidgets.git] / src / msw / spinctrl.cpp
CommitLineData
b782f2e0
VZ
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
0e528b99
JS
36#if wxUSE_SPINCTRL
37
b782f2e0
VZ
38#if defined(__WIN95__)
39
40#include "wx/spinctrl.h"
41#include "wx/msw/private.h"
42
c42404a5 43#if defined(__WIN95__) && !(defined(__GNUWIN32_OLD__) || defined(__TWIN32__))
4c0a2c5c
JS
44 #include <commctrl.h>
45#endif
b782f2e0 46
678cd6de
VZ
47#include <limits.h> // for INT_MIN
48
b782f2e0
VZ
49// ----------------------------------------------------------------------------
50// macros
51// ----------------------------------------------------------------------------
52
9750fc42
VZ
53IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl)
54
55BEGIN_EVENT_TABLE(wxSpinCtrl, wxSpinButton)
56 EVT_SPIN(-1, wxSpinCtrl::OnSpinChange)
57END_EVENT_TABLE()
b782f2e0
VZ
58
59// ----------------------------------------------------------------------------
60// constants
61// ----------------------------------------------------------------------------
62
baccb514
VZ
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?)
66static const int MARGIN_BETWEEN = 1;
b782f2e0
VZ
67
68// ============================================================================
69// implementation
70// ============================================================================
71
f6bcfd97
BP
72// ----------------------------------------------------------------------------
73// wnd proc for the buddy text ctrl
74// ----------------------------------------------------------------------------
75
76LRESULT 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
b782f2e0
VZ
98// ----------------------------------------------------------------------------
99// construction
100// ----------------------------------------------------------------------------
101
102bool wxSpinCtrl::Create(wxWindow *parent,
103 wxWindowID id,
678cd6de 104 const wxString& value,
b782f2e0
VZ
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)
882a8f40
VZ
114 style |= wxSP_VERTICAL;
115 SetWindowStyle(style);
b782f2e0
VZ
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;
baccb514
VZ
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
b782f2e0
VZ
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
b782f2e0
VZ
146 m_hwndBuddy = (WXHWND)::CreateWindowEx
147 (
baccb514
VZ
148 WS_EX_CLIENTEDGE, // sunken border
149 _T("EDIT"), // window class
150 NULL, // no window title
f6bcfd97 151 WS_CHILD | WS_BORDER /* | WS_CLIPSIBLINGS */, // style (will be shown later)
baccb514
VZ
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
b782f2e0
VZ
158 );
159
160 if ( !m_hwndBuddy )
161 {
f6bcfd97 162 wxLogLastError(wxT("CreateWindow(buddy text window)"));
b782f2e0
VZ
163
164 return FALSE;
165 }
166
f6bcfd97
BP
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
b782f2e0 172 // should have the same font as the other controls
baccb514
VZ
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 {
882a8f40
VZ
179 int cx, cy;
180 wxGetCharSize(GetHWND(), &cx, &cy, &GetFont());
181
182 sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
baccb514
VZ
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);
b782f2e0
VZ
189
190 // associate the text window with the spin button
baccb514
VZ
191 (void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0);
192
678cd6de
VZ
193 if ( !value.IsEmpty() )
194 {
195 SetValue(value);
196 }
197
baccb514
VZ
198 return TRUE;
199}
200
f6bcfd97
BP
201wxSpinCtrl::~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
678cd6de
VZ
208// ----------------------------------------------------------------------------
209// wxTextCtrl-like methods
210// ----------------------------------------------------------------------------
211
212void wxSpinCtrl::SetValue(const wxString& text)
213{
882a8f40 214 if ( !::SetWindowText((HWND)m_hwndBuddy, text.c_str()) )
678cd6de 215 {
f6bcfd97 216 wxLogLastError(wxT("SetWindowText(buddy)"));
678cd6de
VZ
217 }
218}
219
220int 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
baccb514 231// ----------------------------------------------------------------------------
882a8f40 232// forward some methods to subcontrols
baccb514
VZ
233// ----------------------------------------------------------------------------
234
235bool 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);
b782f2e0
VZ
245
246 return TRUE;
247}
248
882a8f40
VZ
249bool 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
261bool 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
8bf3196d
GRG
273void wxSpinCtrl::SetFocus()
274{
275 ::SetFocus((HWND)m_hwndBuddy);
276}
277
9750fc42
VZ
278// ----------------------------------------------------------------------------
279// event processing
280// ----------------------------------------------------------------------------
281
282void 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
b782f2e0
VZ
296// ----------------------------------------------------------------------------
297// size calculations
298// ----------------------------------------------------------------------------
299
f68586e5 300wxSize wxSpinCtrl::DoGetBestSize() const
baccb514
VZ
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
b782f2e0
VZ
318void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
319{
baccb514 320 int widthBtn = wxSpinButton::DoGetBestSize().x;
b782f2e0
VZ
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 {
f6bcfd97 329 wxLogLastError(wxT("MoveWindow(buddy)"));
b782f2e0
VZ
330 }
331
332 x += widthText + MARGIN_BETWEEN;
333 if ( !::MoveWindow(GetHwnd(), x, y, widthBtn, height, TRUE) )
334 {
f6bcfd97 335 wxLogLastError(wxT("MoveWindow"));
b782f2e0
VZ
336 }
337}
338
f6bcfd97
BP
339// get total size of the control
340void 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
353void 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
b782f2e0 364#endif // __WIN95__
0e528b99
JS
365
366#endif
367 // wxUSE_SPINCTRL
368