]> git.saurik.com Git - wxWidgets.git/blame - src/mac/carbon/spinctrl.cpp
fixed crash introduced in v1.41
[wxWidgets.git] / src / mac / carbon / spinctrl.cpp
CommitLineData
a5bc50ee
GD
1/////////////////////////////////////////////////////////////////////////////
2// Name: spinbutt.cpp
3// Purpose: wxSpinCtrl
4// Author: Robert
5// Modified by: Mark Newsam (Based on GTK file)
6// RCS-ID: $Id$
7// Copyright: (c) Robert Roebling
65571936 8// Licence: wxWindows licence
a5bc50ee
GD
9/////////////////////////////////////////////////////////////////////////////
10
3d1a4878 11#include "wx/wxprec.h"
a5bc50ee
GD
12
13#if wxUSE_SPINCTRL
14
327788ac 15#include "wx/spinbutt.h"
a842a96e 16#include "wx/spinctrl.h"
571d14b2 17#include "wx/textctrl.h"
a842a96e 18
a5bc50ee 19
327788ac
SC
20// ----------------------------------------------------------------------------
21// constants
22// ----------------------------------------------------------------------------
a842a96e 23
0fa8508d
SC
24// the focus rect around a text may have 4 pixels in each direction
25// we handle these problems right now in an extended vis region of a window
24567921 26static const wxCoord TEXTBORDER = 4 ;
327788ac 27// the margin between the text control and the spin
0fa8508d 28static const wxCoord MARGIN = 8 - TEXTBORDER;
a842a96e 29
327788ac
SC
30// ----------------------------------------------------------------------------
31// wxSpinCtrlText: text control used by spin control
32// ----------------------------------------------------------------------------
a842a96e 33
327788ac
SC
34class wxSpinCtrlText : public wxTextCtrl
35{
36public:
37 wxSpinCtrlText(wxSpinCtrl *spin, const wxString& value)
0fa8508d 38 : wxTextCtrl(spin , -1, value, wxDefaultPosition, wxSize(40, -1))
327788ac
SC
39 {
40 m_spin = spin;
571d14b2
RD
41
42 // remove the default minsize, the spinctrl will have one instead
43 SetSizeHints(-1,-1);
327788ac
SC
44 }
45
46protected:
47 void OnTextChange(wxCommandEvent& event)
48 {
49 int val;
50 if ( m_spin->GetTextValue(&val) )
51 {
52 m_spin->GetSpinButton()->SetValue(val);
5b884f4c 53
f3e87475
JS
54 // If we're already processing a text update from m_spin,
55 // don't send it again, since we could end up recursing
56 // infinitely.
57 if (event.GetId() == m_spin->GetId())
58 {
59 event.Skip();
60 return;
61 }
62
5b884f4c
KH
63 // Send event that the text was manually changed
64 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, m_spin->GetId());
65 event.SetEventObject(m_spin);
66 event.SetInt(val);
67
68 m_spin->GetEventHandler()->ProcessEvent(event);
327788ac
SC
69 }
70
71 event.Skip();
72 }
73
74 bool ProcessEvent(wxEvent &event)
75 {
76 // Hand button down events to wxSpinCtrl. Doesn't work.
77 if (event.GetEventType() == wxEVT_LEFT_DOWN && m_spin->ProcessEvent( event ))
78 return TRUE;
79
80 return wxTextCtrl::ProcessEvent( event );
81 }
82
83private:
84 wxSpinCtrl *m_spin;
85
86 DECLARE_EVENT_TABLE()
87};
88
89BEGIN_EVENT_TABLE(wxSpinCtrlText, wxTextCtrl)
90 EVT_TEXT(-1, wxSpinCtrlText::OnTextChange)
91END_EVENT_TABLE()
92
93// ----------------------------------------------------------------------------
94// wxSpinCtrlButton: spin button used by spin control
95// ----------------------------------------------------------------------------
96
97class wxSpinCtrlButton : public wxSpinButton
98{
99public:
100 wxSpinCtrlButton(wxSpinCtrl *spin, int style)
101 : wxSpinButton(spin )
102 {
103 m_spin = spin;
327788ac 104 SetWindowStyle(style | wxSP_VERTICAL);
571d14b2
RD
105
106 // TODO: The spin button gets truncated a little bit due to size
107 // differences so change it's default size a bit. SMALL still gets a
108 // bit truncated, but MINI seems to be too small... Readdress this
109 // when the textctrl issues are all sorted out.
3109d198 110 //SetWindowVariant(wxWINDOW_VARIANT_SMALL);
571d14b2
RD
111
112 // remove the default minsize, the spinctrl will have one instead
113 SetSizeHints(-1,-1);
327788ac 114 }
a5bc50ee 115
327788ac
SC
116protected:
117 void OnSpinButton(wxSpinEvent& eventSpin)
118 {
327788ac 119 m_spin->SetTextValue(eventSpin.GetPosition());
a5bc50ee 120
327788ac
SC
121 wxCommandEvent event(wxEVT_COMMAND_SPINCTRL_UPDATED, m_spin->GetId());
122 event.SetEventObject(m_spin);
123 event.SetInt(eventSpin.GetPosition());
124
125 m_spin->GetEventHandler()->ProcessEvent(event);
327788ac
SC
126 }
127
128private:
129 wxSpinCtrl *m_spin;
130
131 DECLARE_EVENT_TABLE()
132};
133
134BEGIN_EVENT_TABLE(wxSpinCtrlButton, wxSpinButton)
135 EVT_SPIN(-1, wxSpinCtrlButton::OnSpinButton)
136END_EVENT_TABLE()
137
138IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl, wxControl)
139
140// ============================================================================
141// implementation
142// ============================================================================
143
144// ----------------------------------------------------------------------------
145// wxSpinCtrl creation
146// ----------------------------------------------------------------------------
147
148void wxSpinCtrl::Init()
149{
150 m_text = NULL;
151 m_btn = NULL;
152}
153
154bool wxSpinCtrl::Create(wxWindow *parent,
155 wxWindowID id,
156 const wxString& value,
157 const wxPoint& pos,
158 const wxSize& size,
159 long style,
160 int min,
161 int max,
162 int initial,
163 const wxString& name)
164{
3109d198
KO
165 m_macIsUserPane = true;
166 if ( !wxControl::Create(parent, id, pos, size, style,
327788ac
SC
167 wxDefaultValidator, name) )
168 {
169 return FALSE;
170 }
171
172 // the string value overrides the numeric one (for backwards compatibility
173 // reasons and also because it is simpler to satisfy the string value which
174 // comes much sooner in the list of arguments and leave the initial
175 // parameter unspecified)
176 if ( !value.empty() )
177 {
178 long l;
179 if ( value.ToLong(&l) )
180 initial = l;
181 }
182
183 wxSize csize = size ;
184 m_text = new wxSpinCtrlText(this, value);
185 m_btn = new wxSpinCtrlButton(this, style);
3109d198 186
327788ac
SC
187 m_btn->SetRange(min, max);
188 m_btn->SetValue(initial);
189
3109d198
KO
190 if ( size.x == -1 ){
191 csize.x = m_text->GetSize().x + MARGIN + m_btn->GetSize().x ;
192 }
193
327788ac 194 if ( size.y == -1 ) {
0fa8508d
SC
195 csize.y = m_text->GetSize().y + 2 * TEXTBORDER ; //allow for text border highlights
196 if ( m_btn->GetSize().y > csize.y )
197 csize.y = m_btn->GetSize().y ;
327788ac 198 }
3109d198
KO
199
200 //SetSize(csize);
201
e07a2142 202 //MacPostControlCreate(pos, csize);
3109d198 203 SetInitialBestSize(csize);
327788ac
SC
204
205 return TRUE;
206}
207
208wxSpinCtrl::~wxSpinCtrl()
209{
210 // delete the controls now, don't leave them alive even though they would
211 // still be eventually deleted by our parent - but it will be too late, the
212 // user code expects them to be gone now
213 delete m_text;
214 m_text = NULL ;
215 delete m_btn;
216 m_btn = NULL ;
217}
218
219// ----------------------------------------------------------------------------
220// geometry
221// ----------------------------------------------------------------------------
222
223wxSize wxSpinCtrl::DoGetBestSize() const
224{
51e14ebe
JS
225 if (!m_btn || !m_text)
226 return GetSize();
227
327788ac
SC
228 wxSize sizeBtn = m_btn->GetBestSize(),
229 sizeText = m_text->GetBestSize();
230
0fa8508d
SC
231 sizeText.y += 2 * TEXTBORDER ;
232 sizeText.x += 2 * TEXTBORDER ;
233
3109d198
KO
234 int height;
235 if (sizeText.y > sizeBtn.y)
236 height = sizeText.y;
237 else
238 height = sizeBtn.y;
239
0fa8508d 240 return wxSize(sizeBtn.x + sizeText.x + MARGIN, height );
327788ac
SC
241}
242
243void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
244{
327788ac
SC
245 // position the subcontrols inside the client area
246 wxSize sizeBtn = m_btn->GetSize();
0fa8508d 247 wxSize sizeText = m_text->GetSize();
3109d198
KO
248
249 wxControl::DoMoveWindow(x, y, width, height);
327788ac 250
0fa8508d 251 wxCoord wText = width - sizeBtn.x - MARGIN - 2 * TEXTBORDER;
3109d198 252
0fa8508d
SC
253 m_text->SetSize(TEXTBORDER, (height - sizeText.y) / 2, wText, -1);
254 m_btn->SetSize(0 + wText + MARGIN + 2 * TEXTBORDER , (height - sizeBtn.y) / 2 , -1, -1 );
327788ac
SC
255}
256
257// ----------------------------------------------------------------------------
258// operations forwarded to the subcontrols
259// ----------------------------------------------------------------------------
260
261bool wxSpinCtrl::Enable(bool enable)
262{
263 if ( !wxControl::Enable(enable) )
264 return FALSE;
265 return TRUE;
266}
267
268bool wxSpinCtrl::Show(bool show)
269{
270 if ( !wxControl::Show(show) )
271 return FALSE;
272 return TRUE;
273}
274
c3aee5c1
SC
275void wxSpinCtrl::SetFocus()
276{
277 if ( m_text != NULL) {
278 m_text->SetFocus();
279 }
280}
281
327788ac
SC
282// ----------------------------------------------------------------------------
283// value and range access
284// ----------------------------------------------------------------------------
285
286bool wxSpinCtrl::GetTextValue(int *val) const
287{
288 long l;
289 if ( !m_text->GetValue().ToLong(&l) )
290 {
291 // not a number at all
292 return FALSE;
293 }
294
295 if ( l < GetMin() || l > GetMax() )
296 {
297 // out of range
298 return FALSE;
299 }
300
301 *val = l;
302
303 return TRUE;
304}
305
306int wxSpinCtrl::GetValue() const
307{
308 return m_btn ? m_btn->GetValue() : 0;
309}
310
311int wxSpinCtrl::GetMin() const
312{
313 return m_btn ? m_btn->GetMin() : 0;
314}
315
316int wxSpinCtrl::GetMax() const
317{
318 return m_btn ? m_btn->GetMax() : 0;
319}
320
321// ----------------------------------------------------------------------------
322// changing value and range
323// ----------------------------------------------------------------------------
324
325void wxSpinCtrl::SetTextValue(int val)
326{
327 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetTextValue") );
328
329 m_text->SetValue(wxString::Format(_T("%d"), val));
330
331 // select all text
332 m_text->SetSelection(0, -1);
333
334 // and give focus to the control!
335 // m_text->SetFocus(); Why???? TODO.
336}
337
338void wxSpinCtrl::SetValue(int val)
339{
340 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetValue") );
341
342 SetTextValue(val);
343
344 m_btn->SetValue(val);
345}
346
347void wxSpinCtrl::SetValue(const wxString& text)
348{
349 wxCHECK_RET( m_text, _T("invalid call to wxSpinCtrl::SetValue") );
350
351 long val;
352 if ( text.ToLong(&val) && ((val > INT_MIN) && (val < INT_MAX)) )
353 {
354 SetValue((int)val);
355 }
356 else // not a number at all or out of range
357 {
358 m_text->SetValue(text);
359 m_text->SetSelection(0, -1);
360 }
361}
362
363void wxSpinCtrl::SetRange(int min, int max)
364{
365 wxCHECK_RET( m_btn, _T("invalid call to wxSpinCtrl::SetRange") );
9453cf2b 366
327788ac
SC
367 m_btn->SetRange(min, max);
368}
a5bc50ee 369
a811affe
GD
370void wxSpinCtrl::SetSelection(long from, long to)
371{
77ffb593 372 // if from and to are both -1, it means (in wxWidgets) that all text should
a811affe
GD
373 // be selected
374 if ( (from == -1) && (to == -1) )
375 {
376 from = 0;
377 }
378 m_text->SetSelection(from, to);
379}
380
327788ac 381#endif // wxUSE_SPINCTRL