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/spinctrl.h" 
  18     #include "wx/textctrl.h" 
  19     #include "wx/containr.h" 
  22 #include "wx/spinbutt.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 
, wxID_ANY
, value
, wxDefaultPosition
, wxSize(40, wxDefaultCoord
)) 
  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 OnKillFocus(wxFocusEvent 
&event
) 
  63          if ( !GetValue().ToLong(&l
) ) 
  65              // not a number at all 
  70          if (l 
< m_spin
->GetMin()) 
  72          if (l 
> m_spin
->GetMax()) 
  75          // Update text control 
  77          str
.Printf( wxT("%d"), (int)l 
); 
  78          if (str 
!= GetValue()) 
  81          if (l 
!= m_spin
->m_oldValue
) 
  83              // set value in spin button 
  84              // does that trigger an event? 
  85              m_spin
->m_btn
->SetValue( l 
); 
  88              wxCommandEvent 
event(wxEVT_COMMAND_SPINCTRL_UPDATED
, m_spin
->GetId()); 
  89              event
.SetEventObject(m_spin
); 
  91              m_spin
->GetEventHandler()->ProcessEvent(event
); 
  93              m_spin
->m_oldValue 
= l
; 
  97     void OnTextChange(wxCommandEvent
& event
) 
 100         if ( m_spin
->GetTextValue(&val
) ) 
 102             m_spin
->GetSpinButton()->SetValue(val
); 
 104             // If we're already processing a text update from m_spin, 
 105             // don't send it again, since we could end up recursing 
 107             if (event
.GetId() == m_spin
->GetId()) 
 113             // Send event that the text was manually changed 
 114             wxCommandEvent 
event(wxEVT_COMMAND_TEXT_UPDATED
, m_spin
->GetId()); 
 115             event
.SetEventObject(m_spin
); 
 116             event
.SetString(m_spin
->GetText()->GetValue()); 
 119             m_spin
->GetEventHandler()->ProcessEvent(event
); 
 128     DECLARE_EVENT_TABLE() 
 131 BEGIN_EVENT_TABLE(wxSpinCtrlText
, wxTextCtrl
) 
 132     EVT_TEXT(wxID_ANY
, wxSpinCtrlText::OnTextChange
) 
 133     EVT_KILL_FOCUS( wxSpinCtrlText::OnKillFocus
) 
 136 // ---------------------------------------------------------------------------- 
 137 // wxSpinCtrlButton: spin button used by spin control 
 138 // ---------------------------------------------------------------------------- 
 140 class wxSpinCtrlButton 
: public wxSpinButton
 
 143     wxSpinCtrlButton(wxSpinCtrl 
*spin
, int style
) 
 144         : wxSpinButton(spin 
) 
 147         SetWindowStyle(style 
| wxSP_VERTICAL
); 
 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. 
 153         //SetWindowVariant(wxWINDOW_VARIANT_SMALL); 
 155         // remove the default minsize, the spinctrl will have one instead 
 160     void OnSpinButton(wxSpinEvent
& eventSpin
) 
 162         int pos 
= eventSpin
.GetPosition(); 
 163         m_spin
->SetTextValue(pos
); 
 165         wxCommandEvent 
event(wxEVT_COMMAND_SPINCTRL_UPDATED
, m_spin
->GetId()); 
 166         event
.SetEventObject(m_spin
); 
 169         m_spin
->GetEventHandler()->ProcessEvent(event
); 
 171         m_spin
->m_oldValue 
= pos
; 
 177     DECLARE_EVENT_TABLE() 
 180 BEGIN_EVENT_TABLE(wxSpinCtrlButton
, wxSpinButton
) 
 181     EVT_SPIN(wxID_ANY
, wxSpinCtrlButton::OnSpinButton
) 
 184 IMPLEMENT_DYNAMIC_CLASS(wxSpinCtrl
, wxControl
) 
 186 BEGIN_EVENT_TABLE(wxSpinCtrl
, wxControl
) 
 187     WX_EVENT_TABLE_CONTROL_CONTAINER(wxSpinCtrl
) 
 190 WX_DELEGATE_TO_CONTROL_CONTAINER(wxSpinCtrl
, wxControl
) 
 193 // ============================================================================ 
 195 // ============================================================================ 
 197 // ---------------------------------------------------------------------------- 
 198 // wxSpinCtrl creation 
 199 // ---------------------------------------------------------------------------- 
 201 void wxSpinCtrl::Init() 
 205     m_container
.SetContainerWindow(this); 
 208 bool wxSpinCtrl::Create(wxWindow 
*parent
, 
 210                         const wxString
& value
, 
 217                         const wxString
& name
) 
 219     m_macIsUserPane 
= true; 
 220     if ( !wxControl::Create(parent
, id
, pos
, size
, style
, 
 221                             wxDefaultValidator
, name
) ) 
 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() ) 
 233         if ( value
.ToLong(&l
) ) 
 237     wxSize csize 
= size 
; 
 238     m_text 
= new wxSpinCtrlText(this, value
); 
 239     m_btn 
= new wxSpinCtrlButton(this, style
); 
 241     m_btn
->SetRange(min
, max
); 
 242     m_btn
->SetValue(initial
); 
 244     m_oldValue 
= GetMin()-1; 
 246     if ( size
.x 
== wxDefaultCoord 
){ 
 247         csize
.x 
= m_text
->GetSize().x 
+ MARGIN 
+ m_btn
->GetSize().x 
; 
 250     if ( size
.y 
== wxDefaultCoord 
) { 
 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 
; 
 258     //MacPostControlCreate(pos, csize); 
 259     SetInitialBestSize(csize
); 
 264 wxSpinCtrl::~wxSpinCtrl() 
 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 
 275 // ---------------------------------------------------------------------------- 
 277 // ---------------------------------------------------------------------------- 
 279 wxSize 
wxSpinCtrl::DoGetBestSize() const 
 281     if (!m_btn 
|| !m_text
) 
 284     wxSize sizeBtn 
= m_btn
->GetBestSize(), 
 285            sizeText 
= m_text
->GetBestSize(); 
 287     sizeText
.y 
+= 2 * TEXTBORDER 
; 
 288     sizeText
.x 
+= 2 * TEXTBORDER 
; 
 291     if (sizeText
.y 
> sizeBtn
.y
) 
 296     return wxSize(sizeBtn
.x 
+ sizeText
.x 
+ MARGIN
, height 
); 
 299 void wxSpinCtrl::DoMoveWindow(int x
, int y
, int width
, int height
) 
 301     // position the subcontrols inside the client area 
 302     wxSize sizeBtn 
= m_btn
->GetSize(); 
 303     wxSize sizeText 
= m_text
->GetSize(); 
 305     wxControl::DoMoveWindow(x
, y
, width
, height
); 
 307     wxCoord wText 
= width 
- sizeBtn
.x 
- MARGIN 
- 2 * TEXTBORDER
; 
 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 ); 
 313 // ---------------------------------------------------------------------------- 
 314 // operations forwarded to the subcontrols 
 315 // ---------------------------------------------------------------------------- 
 317 bool wxSpinCtrl::Enable(bool enable
) 
 319     if ( !wxControl::Enable(enable
) ) 
 324 bool wxSpinCtrl::Show(bool show
) 
 326     if ( !wxControl::Show(show
) ) 
 331 // ---------------------------------------------------------------------------- 
 332 // value and range access 
 333 // ---------------------------------------------------------------------------- 
 335 bool wxSpinCtrl::GetTextValue(int *val
) const 
 338     if ( !m_text
->GetValue().ToLong(&l
) ) 
 340         // not a number at all 
 344     if ( l 
< GetMin() || l 
> GetMax() ) 
 355 int wxSpinCtrl::GetValue() const 
 357     return m_btn 
? m_btn
->GetValue() : 0; 
 360 int wxSpinCtrl::GetMin() const 
 362     return m_btn 
? m_btn
->GetMin() : 0; 
 365 int wxSpinCtrl::GetMax() const 
 367     return m_btn 
? m_btn
->GetMax() : 0; 
 370 // ---------------------------------------------------------------------------- 
 371 // changing value and range 
 372 // ---------------------------------------------------------------------------- 
 374 void wxSpinCtrl::SetTextValue(int val
) 
 376     wxCHECK_RET( m_text
, _T("invalid call to wxSpinCtrl::SetTextValue") ); 
 378     m_text
->SetValue(wxString::Format(_T("%d"), val
)); 
 381     m_text
->SetSelection(0, -1); 
 383     // and give focus to the control! 
 384     // m_text->SetFocus();    Why???? TODO. 
 387 void wxSpinCtrl::SetValue(int val
) 
 389     wxCHECK_RET( m_btn
, _T("invalid call to wxSpinCtrl::SetValue") ); 
 393     m_btn
->SetValue(val
); 
 397 void wxSpinCtrl::SetValue(const wxString
& text
) 
 399     wxCHECK_RET( m_text
, _T("invalid call to wxSpinCtrl::SetValue") ); 
 402     if ( text
.ToLong(&val
) && ((val 
> INT_MIN
) && (val 
< INT_MAX
)) ) 
 406     else // not a number at all or out of range 
 408         m_text
->SetValue(text
); 
 409         m_text
->SetSelection(0, -1); 
 413 void wxSpinCtrl::SetRange(int min
, int max
) 
 415     wxCHECK_RET( m_btn
, _T("invalid call to wxSpinCtrl::SetRange") ); 
 417     m_btn
->SetRange(min
, max
); 
 420 void wxSpinCtrl::SetSelection(long from
, long to
) 
 422     // if from and to are both -1, it means (in wxWidgets) that all text should 
 424     if ( (from 
== -1) && (to 
== -1) ) 
 428     m_text
->SetSelection(from
, to
); 
 431 #endif // wxUSE_SPINCTRL