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