several mac fixes (Mark Newsams patches)
[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 private:
74 wxSpinCtrl *m_spin;
75
76 DECLARE_EVENT_TABLE()
77 };
78
79 BEGIN_EVENT_TABLE(wxSpinCtrlText, wxTextCtrl)
80 EVT_TEXT(-1, wxSpinCtrlText::OnTextChange)
81 END_EVENT_TABLE()
82
83 // ----------------------------------------------------------------------------
84 // wxSpinCtrlButton: spin button used by spin control
85 // ----------------------------------------------------------------------------
86
87 class wxSpinCtrlButton : public wxSpinButton
88 {
89 public:
90 wxSpinCtrlButton(wxSpinCtrl *spin, int style)
91 : wxSpinButton(spin->GetParent())
92 {
93 m_spin = spin;
94
95 SetWindowStyle(style);
96 }
97
98 protected:
99 void OnSpinButton(wxSpinEvent& event)
100 {
101 m_spin->SetTextValue(event.GetPosition());
102
103 event.Skip();
104 }
105
106 private:
107 wxSpinCtrl *m_spin;
108
109 DECLARE_EVENT_TABLE()
110 };
111
112 BEGIN_EVENT_TABLE(wxSpinCtrlButton, wxSpinButton)
113 EVT_SPIN(-1, wxSpinCtrlButton::OnSpinButton)
114 END_EVENT_TABLE()
115
116 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl)
117
118 // ============================================================================
119 // implementation
120 // ============================================================================
121
122 // ----------------------------------------------------------------------------
123 // wxSpinCtrl creation
124 // ----------------------------------------------------------------------------
125
126 void wxSpinCtrl::Init()
127 {
128 m_text = NULL;
129 m_btn = NULL;
130 }
131
132 bool wxSpinCtrl::Create(wxWindow *parent,
133 wxWindowID id,
134 const wxString& value,
135 const wxPoint& pos,
136 const wxSize& size,
137 long style,
138 int min,
139 int max,
140 int initial,
141 const wxString& name)
142 {
143 if ( !wxControl::Create(parent, id, pos, size, style,
144 wxDefaultValidator, name) )
145 {
146 return FALSE;
147 }
148
149 SetBackgroundColour(*wxRED);
150 m_text = new wxSpinCtrlText(this, value);
151 m_btn = new wxSpinCtrlButton(this, style);
152
153 m_btn->SetRange(min, max);
154 m_btn->SetValue(initial);
155
156 DoSetSize(pos.x, pos.y, size.x, size.y);
157 #ifdef __WXMAC__
158 DoMoveWindow( pos.x, pos.y, size.x, size.y ) ;
159 #endif
160 // have to disable this window to avoid interfering it with message
161 // processing to the text and the button... but pretend it is enabled to
162 // make IsEnabled() return TRUE
163 wxControl::Enable(FALSE); // don't use non virtual Disable() here!
164 m_isEnabled = TRUE;
165
166 // we don't even need to show this window itself - and not doing it avoids
167 // that it overwrites the text control
168 wxControl::Show(FALSE);
169 m_isShown = TRUE;
170
171 return TRUE;
172 }
173
174 wxSpinCtrl::~wxSpinCtrl()
175 {
176 // delete the controls now, don't leave them alive even though they woudl
177 // still be eventually deleted by our parent - but it will be too late, the
178 // user code expects them to be gone now
179 delete m_text;
180 delete m_btn;
181 }
182
183 // ----------------------------------------------------------------------------
184 // geometry
185 // ----------------------------------------------------------------------------
186
187 wxSize wxSpinCtrl::DoGetBestClientSize() const
188 {
189 wxSize sizeBtn = m_btn->GetBestSize(),
190 sizeText = m_text->GetBestSize();
191
192 return wxSize(sizeBtn.x + sizeText.x + MARGIN, sizeText.y);
193 }
194
195 void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
196 {
197 wxControl::DoMoveWindow(x, y, width, height);
198
199 // position the subcontrols inside the client area
200 wxSize sizeBtn = m_btn->GetSize();
201
202 wxCoord wText = width - sizeBtn.x;
203 m_text->SetSize(x, y, wText, height);
204 m_btn->SetSize(x + wText + MARGIN, y, -1, height);
205 }
206
207 // ----------------------------------------------------------------------------
208 // operations forwarded to the subcontrols
209 // ----------------------------------------------------------------------------
210
211 bool wxSpinCtrl::Enable(bool enable)
212 {
213 if ( !wxControl::Enable(enable) )
214 return FALSE;
215
216 m_btn->Enable(enable);
217 m_text->Enable(enable);
218
219 return TRUE;
220 }
221
222 bool wxSpinCtrl::Show(bool show)
223 {
224 if ( !wxControl::Show(show) )
225 return FALSE;
226
227 // under GTK Show() is called the first time before we are fully
228 // constructed
229 if ( m_btn )
230 {
231 m_btn->Show(show);
232 m_text->Show(show);
233 }
234
235 return TRUE;
236 }
237
238 // ----------------------------------------------------------------------------
239 // value and range access
240 // ----------------------------------------------------------------------------
241
242 bool wxSpinCtrl::GetTextValue(int *val) const
243 {
244 long l;
245 if ( !m_text->GetValue().ToLong(&l) )
246 {
247 // not a number at all
248 return FALSE;
249 }
250
251 if ( l < GetMin() || l > GetMax() )
252 {
253 // out of range
254 return FALSE;
255 }
256
257 *val = l;
258
259 return TRUE;
260 }
261
262 int wxSpinCtrl::GetValue() const
263 {
264 return m_btn ? m_btn->GetValue() : 0;
265 }
266
267 int wxSpinCtrl::GetMin() const
268 {
269 return m_btn ? m_btn->GetMin() : 0;
270 }
271
272 int wxSpinCtrl::GetMax() const
273 {
274 return m_btn ? m_btn->GetMax() : 0;
275 }
276
277 // ----------------------------------------------------------------------------
278 // changing value and range
279 // ----------------------------------------------------------------------------
280
281 void wxSpinCtrl::SetTextValue(int val)
282 {
283 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") );
284
285 m_text->SetValue(wxString::Format(_T("%d"), val));
286
287 // select all text
288 m_text->SetSelection(0, -1);
289
290 // and give focus to the control!
291 m_text->SetFocus();
292 }
293
294 void wxSpinCtrl::SetValue(int val)
295 {
296 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") );
297
298 SetTextValue(val);
299
300 m_btn->SetValue(val);
301 }
302
303 void wxSpinCtrl::SetValue(const wxString& text)
304 {
305 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") );
306
307 long val;
308 if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) )
309 {
310 SetValue((int)val);
311 }
312 else // not a number at all or out of range
313 {
314 m_text->SetValue(text);
315 m_text->SetSelection(0, -1);
316 }
317 }
318
319 void wxSpinCtrl::SetRange(int min, int max)
320 {
321 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") );
322
323 m_btn->SetRange(min, max);
324 }
325
326 #endif // !wxPort-with-native-spinctrl