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