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