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