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