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