1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/mac/carbon/spinbutt.cpp 
   5 // Modified by: Mark Newsam (Based on GTK file) 
   7 // Copyright:   (c) Robert Roebling 
   8 // Licence:     wxWindows licence 
   9 ///////////////////////////////////////////////////////////////////////////// 
  11 #include "wx/wxprec.h" 
  15 #include "wx/spinbutt.h" 
  18     #include "wx/textctrl.h" 
  21 #include "wx/spinctrl.h" 
  22 #include "wx/containr.h" 
  24 // ---------------------------------------------------------------------------- 
  26 // ---------------------------------------------------------------------------- 
  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 
  30 static const wxCoord TEXTBORDER 
= 4 ; 
  31 // the margin between the text control and the spin 
  32 static const wxCoord MARGIN 
= 8 - TEXTBORDER
; 
  34 // ---------------------------------------------------------------------------- 
  35 // wxSpinCtrlText: text control used by spin control 
  36 // ---------------------------------------------------------------------------- 
  38 class wxSpinCtrlText 
: public wxTextCtrl
 
  41     wxSpinCtrlText(wxSpinCtrl 
*spin
, const wxString
& value
) 
  42         : wxTextCtrl(spin 
, -1, value
, wxDefaultPosition
, wxSize(40, -1)) 
  46         // remove the default minsize, the spinctrl will have one instead 
  50     bool ProcessEvent(wxEvent 
&event
) 
  52         // Hand button down events to wxSpinCtrl. Doesn't work. 
  53         if (event
.GetEventType() == wxEVT_LEFT_DOWN 
&& m_spin
->ProcessEvent( event 
)) 
  56         return wxTextCtrl::ProcessEvent( event 
); 
  60     void OnTextChange(wxCommandEvent
& event
) 
  63         if ( m_spin
->GetTextValue(&val
) ) 
  65             m_spin
->GetSpinButton()->SetValue(val
); 
  67             // If we're already processing a text update from m_spin, 
  68             // don't send it again, since we could end up recursing 
  70             if (event
.GetId() == m_spin
->GetId()) 
  76             // Send event that the text was manually changed 
  77             wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, m_spin
->GetId()); 
  78             event
.SetEventObject(m_spin
); 
  79             event
.SetString(m_spin
->GetText()->GetValue()); 
  82             m_spin
->GetEventHandler()->ProcessEvent(event
); 
  94 BEGIN_EVENT_TABLE(wxSpinCtrlText
, wxTextCtrl
) 
  95     EVT_TEXT(-1, wxSpinCtrlText::OnTextChange
) 
  98 // ---------------------------------------------------------------------------- 
  99 // wxSpinCtrlButton: spin button used by spin control 
 100 // ---------------------------------------------------------------------------- 
 102 class wxSpinCtrlButton 
: public wxSpinButton
 
 105     wxSpinCtrlButton(wxSpinCtrl 
*spin
, int style
) 
 106         : wxSpinButton(spin 
) 
 109         SetWindowStyle(style 
| wxSP_VERTICAL
); 
 111         // TODO: The spin button gets truncated a little bit due to size 
 112         // differences so change it's default size a bit.  SMALL still gets a 
 113         // bit truncated, but MINI seems to be too small...  Readdress this 
 114         // when the textctrl issues are all sorted out. 
 115         //SetWindowVariant(wxWINDOW_VARIANT_SMALL); 
 117         // remove the default minsize, the spinctrl will have one instead 
 122     void OnSpinButton(wxSpinEvent
& eventSpin
) 
 124       m_spin
->SetTextValue(eventSpin
.GetPosition()); 
 126       wxCommandEvent 
event(wxEVT_COMMAND_SPINCTRL_UPDATED
, m_spin
->GetId()); 
 127       event
.SetEventObject(m_spin
); 
 128       event
.SetInt(eventSpin
.GetPosition()); 
 130       m_spin
->GetEventHandler()->ProcessEvent(event
); 
 136     DECLARE_EVENT_TABLE() 
 139 BEGIN_EVENT_TABLE(wxSpinCtrlButton
, wxSpinButton
) 
 140     EVT_SPIN(-1, wxSpinCtrlButton::OnSpinButton
) 
 143 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
, wxControl
) 
 145 BEGIN_EVENT_TABLE(wxSpinCtrl
, wxControl
) 
 146     WX_EVENT_TABLE_CONTROL_CONTAINER(wxSpinCtrl
) 
 149 WX_DELEGATE_TO_CONTROL_CONTAINER(wxSpinCtrl
) 
 152 // ============================================================================ 
 154 // ============================================================================ 
 156 // ---------------------------------------------------------------------------- 
 157 // wxSpinCtrl creation 
 158 // ---------------------------------------------------------------------------- 
 160 void wxSpinCtrl::Init() 
 164     m_container
.SetContainerWindow(this); 
 167 bool wxSpinCtrl::Create(wxWindow 
*parent
, 
 169                         const wxString
& value
, 
 176                         const wxString
& name
) 
 178     m_macIsUserPane 
= true; 
 179     if ( !wxControl::Create(parent
, id
, pos
, size
, style
, 
 180                             wxDefaultValidator
, name
) ) 
 185     // the string value overrides the numeric one (for backwards compatibility 
 186     // reasons and also because it is simpler to satisfy the string value which 
 187     // comes much sooner in the list of arguments and leave the initial 
 188     // parameter unspecified) 
 189     if ( !value
.empty() ) 
 192         if ( value
.ToLong(&l
) ) 
 196     wxSize csize 
= size 
; 
 197     m_text 
= new wxSpinCtrlText(this, value
); 
 198     m_btn 
= new wxSpinCtrlButton(this, style
); 
 200     m_btn
->SetRange(min
, max
); 
 201     m_btn
->SetValue(initial
); 
 204         csize
.x 
= m_text
->GetSize().x 
+ MARGIN 
+ m_btn
->GetSize().x 
; 
 207     if ( size
.y 
== -1 ) { 
 208         csize
.y 
= m_text
->GetSize().y 
+ 2 * TEXTBORDER 
; //allow for text border highlights 
 209         if ( m_btn
->GetSize().y 
> csize
.y 
) 
 210             csize
.y 
= m_btn
->GetSize().y 
; 
 215     //MacPostControlCreate(pos, csize); 
 216     SetInitialBestSize(csize
); 
 221 wxSpinCtrl::~wxSpinCtrl() 
 223     // delete the controls now, don't leave them alive even though they would 
 224     // still be eventually deleted by our parent - but it will be too late, the 
 225     // user code expects them to be gone now 
 232 // ---------------------------------------------------------------------------- 
 234 // ---------------------------------------------------------------------------- 
 236 wxSize 
wxSpinCtrl::DoGetBestSize() const 
 238     if (!m_btn 
|| !m_text
) 
 241     wxSize sizeBtn 
= m_btn
->GetBestSize(), 
 242            sizeText 
= m_text
->GetBestSize(); 
 244     sizeText
.y 
+= 2 * TEXTBORDER 
; 
 245     sizeText
.x 
+= 2 * TEXTBORDER 
; 
 248     if (sizeText
.y 
> sizeBtn
.y
) 
 253     return wxSize(sizeBtn
.x 
+ sizeText
.x 
+ MARGIN
, height 
); 
 256 void wxSpinCtrl::DoMoveWindow(int x
, int y
, int width
, int height
) 
 258     // position the subcontrols inside the client area 
 259     wxSize sizeBtn 
= m_btn
->GetSize(); 
 260     wxSize sizeText 
= m_text
->GetSize(); 
 262     wxControl::DoMoveWindow(x
, y
, width
, height
); 
 264     wxCoord wText 
= width 
- sizeBtn
.x 
- MARGIN 
- 2 * TEXTBORDER
; 
 266     m_text
->SetSize(TEXTBORDER
, (height 
- sizeText
.y
) / 2, wText
, -1); 
 267     m_btn
->SetSize(0 + wText 
+ MARGIN 
+ 2 * TEXTBORDER 
, (height 
- sizeBtn
.y
) / 2 , -1, -1 ); 
 270 // ---------------------------------------------------------------------------- 
 271 // operations forwarded to the subcontrols 
 272 // ---------------------------------------------------------------------------- 
 274 bool wxSpinCtrl::Enable(bool enable
) 
 276     if ( !wxControl::Enable(enable
) ) 
 281 bool wxSpinCtrl::Show(bool show
) 
 283     if ( !wxControl::Show(show
) ) 
 288 // ---------------------------------------------------------------------------- 
 289 // value and range access 
 290 // ---------------------------------------------------------------------------- 
 292 bool wxSpinCtrl::GetTextValue(int *val
) const 
 295     if ( !m_text
->GetValue().ToLong(&l
) ) 
 297         // not a number at all 
 301     if ( l 
< GetMin() || l 
> GetMax() ) 
 312 int wxSpinCtrl::GetValue() const 
 314     return m_btn 
? m_btn
->GetValue() : 0; 
 317 int wxSpinCtrl::GetMin() const 
 319     return m_btn 
? m_btn
->GetMin() : 0; 
 322 int wxSpinCtrl::GetMax() const 
 324     return m_btn 
? m_btn
->GetMax() : 0; 
 327 // ---------------------------------------------------------------------------- 
 328 // changing value and range 
 329 // ---------------------------------------------------------------------------- 
 331 void wxSpinCtrl::SetTextValue(int val
) 
 333     wxCHECK_RET( m_text
, _T("invalid call to wxSpinCtrl::SetTextValue") ); 
 335     m_text
->SetValue(wxString::Format(_T("%d"), val
)); 
 338     m_text
->SetSelection(0, -1); 
 340     // and give focus to the control! 
 341     // m_text->SetFocus();    Why???? TODO. 
 344 void wxSpinCtrl::SetValue(int val
) 
 346     wxCHECK_RET( m_btn
, _T("invalid call to wxSpinCtrl::SetValue") ); 
 350     m_btn
->SetValue(val
); 
 353 void wxSpinCtrl::SetValue(const wxString
& text
) 
 355     wxCHECK_RET( m_text
, _T("invalid call to wxSpinCtrl::SetValue") ); 
 358     if ( text
.ToLong(&val
) && ((val 
> INT_MIN
) && (val 
< INT_MAX
)) ) 
 362     else // not a number at all or out of range 
 364         m_text
->SetValue(text
); 
 365         m_text
->SetSelection(0, -1); 
 369 void wxSpinCtrl::SetRange(int min
, int max
) 
 371     wxCHECK_RET( m_btn
, _T("invalid call to wxSpinCtrl::SetRange") ); 
 373     m_btn
->SetRange(min
, max
); 
 376 void wxSpinCtrl::SetSelection(long from
, long to
) 
 378     // if from and to are both -1, it means (in wxWidgets) that all text should 
 380     if ( (from 
== -1) && (to 
== -1) ) 
 384     m_text
->SetSelection(from
, to
); 
 387 #endif // wxUSE_SPINCTRL