Implemented wxSpinButton for wxMotif.
[wxWidgets.git] / src / generic / spinctlg.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/generic/spinctlg.cpp
3 // Purpose: implements wxSpinCtrl as a composite control
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 29.01.01
7 // RCS-ID: $Id$
8 // Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // License: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #ifdef __GNUG__
21 #pragma implementation "spinctlg.h"
22 #endif
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if !(defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXPM__)) || \
32 defined(__WXMAC__) || defined(__WXUNIVERSAL__)
33
34 #ifndef WX_PRECOMP
35 #include "wx/textctrl.h"
36 #endif //WX_PRECOMP
37
38 #if wxUSE_SPINCTRL
39
40 #include "wx/spinbutt.h"
41 #include "wx/spinctrl.h"
42
43 // ----------------------------------------------------------------------------
44 // constants
45 // ----------------------------------------------------------------------------
46
47 // the margin between the text control and the spin
48 static const wxCoord MARGIN = 2;
49
50 // ----------------------------------------------------------------------------
51 // wxSpinCtrlText: text control used by spin control
52 // ----------------------------------------------------------------------------
53
54 class wxSpinCtrlText : public wxTextCtrl
55 {
56 public:
57 wxSpinCtrlText(wxSpinCtrl *spin, const wxString& value)
58 : wxTextCtrl(spin->GetParent(), -1, value)
59 {
60 m_spin = spin;
61 }
62
63 protected:
64 void OnTextChange(wxCommandEvent& event)
65 {
66 int val;
67 if ( m_spin->GetTextValue(&val) )
68 {
69 m_spin->GetSpinButton()->SetValue(val);
70 }
71
72 event.Skip();
73 }
74
75 bool ProcessEvent(wxEvent &event)
76 {
77 // Hand button down events to wxSpinCtrl. Doesn't work.
78 if (event.GetEventType() == wxEVT_LEFT_DOWN && m_spin->ProcessEvent( event ))
79 return TRUE;
80
81 return wxTextCtrl::ProcessEvent( event );
82 }
83
84 private:
85 wxSpinCtrl *m_spin;
86
87 DECLARE_EVENT_TABLE()
88 };
89
90 BEGIN_EVENT_TABLE(wxSpinCtrlText, wxTextCtrl)
91 EVT_TEXT(-1, wxSpinCtrlText::OnTextChange)
92 END_EVENT_TABLE()
93
94 // ----------------------------------------------------------------------------
95 // wxSpinCtrlButton: spin button used by spin control
96 // ----------------------------------------------------------------------------
97
98 class wxSpinCtrlButton : public wxSpinButton
99 {
100 public:
101 wxSpinCtrlButton(wxSpinCtrl *spin, int style)
102 : wxSpinButton(spin->GetParent())
103 {
104 m_spin = spin;
105
106 SetWindowStyle(style | wxSP_VERTICAL);
107 }
108
109 protected:
110 void OnSpinButton(wxSpinEvent& eventSpin)
111 {
112 #ifdef __WXMAC__
113 m_spin->SetTextValue(eventSpin.GetPosition());
114
115 wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, m_spin->GetId());
116 event.SetEventObject(m_spin);
117 event.SetInt(eventSpin.GetPosition());
118
119 m_spin->GetEventHandler()->ProcessEvent(event);
120 #else
121 m_spin->SetTextValue(eventSpin.GetPosition());
122 eventSpin.Skip();
123 #endif
124 }
125
126 private:
127 wxSpinCtrl *m_spin;
128
129 DECLARE_EVENT_TABLE()
130 };
131
132 BEGIN_EVENT_TABLE(wxSpinCtrlButton, wxSpinButton)
133 EVT_SPIN(-1, wxSpinCtrlButton::OnSpinButton)
134 END_EVENT_TABLE()
135
136 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl)
137
138 // ============================================================================
139 // implementation
140 // ============================================================================
141
142 // ----------------------------------------------------------------------------
143 // wxSpinCtrl creation
144 // ----------------------------------------------------------------------------
145
146 void wxSpinCtrl::Init()
147 {
148 m_text = NULL;
149 m_btn = NULL;
150 }
151
152 bool wxSpinCtrl::Create(wxWindow *parent,
153 wxWindowID id,
154 const wxString& value,
155 const wxPoint& pos,
156 const wxSize& size,
157 long style,
158 int min,
159 int max,
160 int initial,
161 const wxString& name)
162 {
163 if ( !wxControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, style,
164 wxDefaultValidator, name) )
165 {
166 return FALSE;
167 }
168
169 // the string value overrides the numeric one (for backwards compatibility
170 // reasons and also because it is simpler to satisfy the string value which
171 // comes much sooner in the list of arguments and leave the initial
172 // parameter unspecified)
173 if ( !value.empty() )
174 {
175 long l;
176 if ( value.ToLong(&l) )
177 initial = l;
178 }
179
180 SetBackgroundColour(*wxRED);
181 m_text = new wxSpinCtrlText(this, value);
182 m_btn = new wxSpinCtrlButton(this, style);
183
184 m_btn->SetRange(min, max);
185 m_btn->SetValue(initial);
186 #ifdef __WXMAC__
187 wxSize csize = size ;
188 if ( size.y == -1 ) {
189 csize.y = m_text->GetSize().y ;
190 }
191 DoSetSize(pos.x, pos.y, csize.x, csize.y);
192 #else
193 wxSize best = GetBestSize();
194 if ( size.x != -1 ) best.x = size.x;
195 if ( size.y != -1 ) best.y = size.y;
196 DoSetSize(pos.x, pos.y, best.x, best.y);
197 #endif
198 // have to disable this window to avoid interfering it with message
199 // processing to the text and the button... but pretend it is enabled to
200 // make IsEnabled() return TRUE
201 wxControl::Enable(FALSE); // don't use non virtual Disable() here!
202 m_isEnabled = TRUE;
203
204 // we don't even need to show this window itself - and not doing it avoids
205 // that it overwrites the text control
206 wxControl::Show(FALSE);
207 #ifndef __WXMAC__
208 m_isShown = TRUE;
209 #endif
210 return TRUE;
211 }
212
213 wxSpinCtrl::~wxSpinCtrl()
214 {
215 // delete the controls now, don't leave them alive even though they woudl
216 // still be eventually deleted by our parent - but it will be too late, the
217 // user code expects them to be gone now
218 delete m_text;
219 delete m_btn;
220 }
221
222 // ----------------------------------------------------------------------------
223 // geometry
224 // ----------------------------------------------------------------------------
225
226 wxSize wxSpinCtrl::DoGetBestSize() const
227 {
228 wxSize sizeBtn = m_btn->GetBestSize(),
229 sizeText = m_text->GetBestSize();
230
231 return wxSize(sizeBtn.x + sizeText.x + MARGIN, sizeText.y);
232 }
233
234 void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
235 {
236 wxControl::DoMoveWindow(x, y, width, height);
237
238 wxPoint p = GetParent() ?
239 GetParent()->GetClientAreaOrigin() : wxPoint(0,0);
240
241 // position the subcontrols inside the client area
242 wxSize sizeBtn = m_btn->GetSize();
243
244 wxCoord wText = width - sizeBtn.x;
245 m_text->SetSize(x-p.x, y-p.y, wText, height);
246 #ifdef __WXMAC__
247 m_btn->SetSize(x-p.x + wText + MARGIN, y-p.y, -1, -1);
248 #else
249 m_btn->SetSize(x-p.x + wText + MARGIN, y-p.y, -1, height);
250 #endif
251 }
252
253 // ----------------------------------------------------------------------------
254 // operations forwarded to the subcontrols
255 // ----------------------------------------------------------------------------
256
257 bool wxSpinCtrl::Enable(bool enable)
258 {
259 if ( !wxControl::Enable(enable) )
260 return FALSE;
261
262 m_btn->Enable(enable);
263 m_text->Enable(enable);
264
265 return TRUE;
266 }
267
268 bool wxSpinCtrl::Show(bool show)
269 {
270 if ( !wxControl::Show(show) )
271 return FALSE;
272
273 // under GTK Show() is called the first time before we are fully
274 // constructed
275 if ( m_btn )
276 {
277 m_btn->Show(show);
278 m_text->Show(show);
279 }
280
281 return TRUE;
282 }
283
284 // ----------------------------------------------------------------------------
285 // value and range access
286 // ----------------------------------------------------------------------------
287
288 bool wxSpinCtrl::GetTextValue(int *val) const
289 {
290 long l;
291 if ( !m_text->GetValue().ToLong(&l) )
292 {
293 // not a number at all
294 return FALSE;
295 }
296
297 if ( l < GetMin() || l > GetMax() )
298 {
299 // out of range
300 return FALSE;
301 }
302
303 *val = l;
304
305 return TRUE;
306 }
307
308 int wxSpinCtrl::GetValue() const
309 {
310 return m_btn ? m_btn->GetValue() : 0;
311 }
312
313 int wxSpinCtrl::GetMin() const
314 {
315 return m_btn ? m_btn->GetMin() : 0;
316 }
317
318 int wxSpinCtrl::GetMax() const
319 {
320 return m_btn ? m_btn->GetMax() : 0;
321 }
322
323 // ----------------------------------------------------------------------------
324 // changing value and range
325 // ----------------------------------------------------------------------------
326
327 void wxSpinCtrl::SetTextValue(int val)
328 {
329 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") );
330
331 m_text->SetValue(wxString::Format(_T("%d"), val));
332
333 // select all text
334 m_text->SetSelection(0, -1);
335
336 // and give focus to the control!
337 // m_text->SetFocus(); Why???? TODO.
338 }
339
340 void wxSpinCtrl::SetValue(int val)
341 {
342 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") );
343
344 SetTextValue(val);
345
346 m_btn->SetValue(val);
347 }
348
349 void wxSpinCtrl::SetValue(const wxString& text)
350 {
351 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") );
352
353 long val;
354 if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) )
355 {
356 SetValue((int)val);
357 }
358 else // not a number at all or out of range
359 {
360 m_text->SetValue(text);
361 m_text->SetSelection(0, -1);
362 }
363 }
364
365 void wxSpinCtrl::SetRange(int min, int max)
366 {
367 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") );
368
369 m_btn->SetRange(min, max);
370 }
371
372 #endif // wxUSE_SPINCTRL
373 #endif // !wxPort-with-native-spinctrl