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