tons of fixes for wxGTK/Univ - seems to work, more or less, now
[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(__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
151 m_text = new wxSpinCtrlText(this, value);
152 m_btn = new wxSpinCtrlButton(this, style);
153
154 m_btn->SetRange(min, max);
155 m_btn->SetValue(initial);
156
157 DoSetSize(pos.x, pos.y, size.x, size.y);
158
159 // have to disable this window to avoid interfering it with message
160 // processing to the text and the button... but pretend it is enabled to
161 // make IsEnabled() return TRUE
162 wxControl::Enable(FALSE); // don't use non virtual Disable() here!
163 m_isEnabled = TRUE;
164
165 // we don't even need to show this window itself - and not doing it avoids
166 // that it overwrites the text control
167 wxControl::Show(FALSE);
168 m_isShown = TRUE;
169
170 return TRUE;
171 }
172
173 wxSpinCtrl::~wxSpinCtrl()
174 {
175 // delete the controls now, don't leave them alive even though they woudl
176 // still be eventually deleted by our parent - but it will be too late, the
177 // user code expects them to be gone now
178 delete m_text;
179 delete m_btn;
180 }
181
182 // ----------------------------------------------------------------------------
183 // geometry
184 // ----------------------------------------------------------------------------
185
186 wxSize wxSpinCtrl::DoGetBestClientSize() const
187 {
188 wxSize sizeBtn = m_btn->GetBestSize(),
189 sizeText = m_text->GetBestSize();
190
191 return wxSize(sizeBtn.x + sizeText.x + MARGIN, sizeText.y);
192 }
193
194 void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
195 {
196 wxControl::DoMoveWindow(x, y, width, height);
197
198 // position the subcontrols inside the client area
199 wxSize sizeBtn = m_btn->GetSize();
200
201 wxCoord wText = width - sizeBtn.x;
202 m_text->SetSize(x, y, wText, height);
203 m_btn->SetSize(x + wText + MARGIN, y, -1, height);
204 }
205
206 // ----------------------------------------------------------------------------
207 // operations forwarded to the subcontrols
208 // ----------------------------------------------------------------------------
209
210 bool wxSpinCtrl::Enable(bool enable)
211 {
212 if ( !wxControl::Enable(enable) )
213 return FALSE;
214
215 m_btn->Enable(enable);
216 m_text->Enable(enable);
217
218 return TRUE;
219 }
220
221 bool wxSpinCtrl::Show(bool show)
222 {
223 if ( !wxControl::Show(show) )
224 return FALSE;
225
226 // under GTK Show() is called the first time before we are fully
227 // constructed
228 if ( m_btn )
229 {
230 m_btn->Show(show);
231 m_text->Show(show);
232 }
233
234 return TRUE;
235 }
236
237 // ----------------------------------------------------------------------------
238 // value and range access
239 // ----------------------------------------------------------------------------
240
241 bool wxSpinCtrl::GetTextValue(int *val) const
242 {
243 long l;
244 if ( !m_text->GetValue().ToLong(&l) )
245 {
246 // not a number at all
247 return FALSE;
248 }
249
250 if ( l < GetMin() || l > GetMax() )
251 {
252 // out of range
253 return FALSE;
254 }
255
256 *val = l;
257
258 return TRUE;
259 }
260
261 int wxSpinCtrl::GetValue() const
262 {
263 return m_btn ? m_btn->GetValue() : 0;
264 }
265
266 int wxSpinCtrl::GetMin() const
267 {
268 return m_btn ? m_btn->GetMin() : 0;
269 }
270
271 int wxSpinCtrl::GetMax() const
272 {
273 return m_btn ? m_btn->GetMax() : 0;
274 }
275
276 // ----------------------------------------------------------------------------
277 // changing value and range
278 // ----------------------------------------------------------------------------
279
280 void wxSpinCtrl::SetTextValue(int val)
281 {
282 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") );
283
284 m_text->SetValue(wxString::Format(_T("%d"), val));
285
286 // select all text
287 m_text->SetSelection(0, -1);
288
289 // and give focus to the control!
290 m_text->SetFocus();
291 }
292
293 void wxSpinCtrl::SetValue(int val)
294 {
295 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") );
296
297 SetTextValue(val);
298
299 m_btn->SetValue(val);
300 }
301
302 void wxSpinCtrl::SetValue(const wxString& text)
303 {
304 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") );
305
306 long val;
307 if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) )
308 {
309 SetValue((int)val);
310 }
311 else // not a number at all or out of range
312 {
313 m_text->SetValue(text);
314 m_text->SetSelection(0, -1);
315 }
316 }
317
318 void wxSpinCtrl::SetRange(int min, int max)
319 {
320 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") );
321
322 m_btn->SetRange(min, max);
323 }
324
325 #endif // !wxPort-with-native-spinctrl