+ // If the initial text value is actually a number, it overrides the
+ // "initial" argument specified later.
+ long initialFromText;
+ if ( value.ToLong(&initialFromText) )
+ initial = initialFromText;
+
+ // Set the range in the native control: notice that we must do it before
+ // calling SetValue() to use the correct validity checks for the initial
+ // value.
+ SetRange(min, max);
+ SetValue(initial);
+
+ // Also set the text part of the control if it was specified independently
+ // but don't generate an event for this, it would be unexpected.
+ m_blockEvent = true;
+ if ( !value.empty() )
+ SetValue(value);
+ m_blockEvent = false;
+
+ return true;
+}
+
+wxSpinCtrl::~wxSpinCtrl()
+{
+ // destroy the buddy window because this pointer which wxBuddyTextWndProc
+ // uses will not soon be valid any more
+ ::DestroyWindow( GetBuddyHwnd() );
+
+ gs_spinForTextCtrl.erase(GetBuddyHwnd());
+}
+
+// ----------------------------------------------------------------------------
+// wxSpinCtrl-specific methods
+// ----------------------------------------------------------------------------
+
+int wxSpinCtrl::GetBase() const
+{
+ return ::SendMessage(GetHwnd(), UDM_GETBASE, 0, 0);
+}
+
+bool wxSpinCtrl::SetBase(int base)
+{
+ if ( !::SendMessage(GetHwnd(), UDM_SETBASE, base, 0) )
+ return false;
+
+ // Whether we need to be able enter "x" or not influences whether we should
+ // use ES_NUMBER for the buddy control.
+ UpdateBuddyStyle();
+
+ return true;
+}
+
+// ----------------------------------------------------------------------------
+// wxTextCtrl-like methods
+// ----------------------------------------------------------------------------
+
+void wxSpinCtrl::SetValue(const wxString& text)
+{
+ if ( !::SetWindowText(GetBuddyHwnd(), text.c_str()) )
+ {
+ wxLogLastError(wxT("SetWindowText(buddy)"));
+ }
+}
+
+void wxSpinCtrl::SetValue(int val)
+{
+ m_blockEvent = true;
+
+ wxSpinButton::SetValue(val);
+
+ // Normally setting the value of the spin button is enough as it updates
+ // its buddy control automatically but in a couple of situations it doesn't
+ // do it, for whatever reason, do it explicitly then:
+ const wxString text = wxGetWindowText(m_hwndBuddy);
+
+ // First case is when the text control is empty and the value is 0: the
+ // spin button just leaves it empty in this case, while we want to show 0
+ // in it.
+ if ( text.empty() && !val )
+ {
+ ::SetWindowText(GetBuddyHwnd(), wxT("0"));
+ }
+
+ // Another one is when we're using hexadecimal base but the user input
+ // doesn't start with "0x" -- we prefer to show it to avoid ambiguity
+ // between decimal and hexadecimal.
+ if ( GetBase() == 16 &&
+ (text.length() < 3 || text[0] != '0' ||
+ (text[1] != 'x' && text[1] != 'X')) )
+ {
+ ::SetWindowText(GetBuddyHwnd(),
+ wxPrivate::wxSpinCtrlFormatAsHex(val, m_max).t_str());
+ }
+
+ m_oldValue = GetValue();
+
+ m_blockEvent = false;
+}
+
+int wxSpinCtrl::GetValue() const
+{
+ const wxString val = wxGetWindowText(m_hwndBuddy);
+
+ long n;
+ if ( !val.ToLong(&n, GetBase()) )
+ n = INT_MIN;
+
+ if ( n < m_min )
+ n = m_min;
+ if ( n > m_max )
+ n = m_max;
+
+ return n;
+}
+
+void wxSpinCtrl::SetSelection(long from, long to)
+{
+ // if from and to are both -1, it means (in wxWidgets) that all text should
+ // be selected - translate into Windows convention
+ if ( (from == -1) && (to == -1) )
+ {
+ from = 0;
+ }
+
+ ::SendMessage(GetBuddyHwnd(), EM_SETSEL, (WPARAM)from, (LPARAM)to);
+}
+
+// ----------------------------------------------------------------------------
+// wxSpinButton methods
+// ----------------------------------------------------------------------------
+
+void wxSpinCtrl::SetRange(int minVal, int maxVal)
+{
+ // Manually adjust the old value to avoid an event being sent from
+ // NormalizeValue() called from inside the base class SetRange() as we're
+ // not supposed to generate any events from here.
+ if ( m_oldValue < minVal )
+ m_oldValue = minVal;
+ else if ( m_oldValue > maxVal )
+ m_oldValue = maxVal;
+
+ wxSpinButton::SetRange(minVal, maxVal);
+
+ UpdateBuddyStyle();
+}
+
+void wxSpinCtrl::UpdateBuddyStyle()
+{
+ // this control is used for numeric entry so restrict the input to numeric
+ // keys only -- but only if we don't need to be able to enter "-" in it as
+ // otherwise this would become impossible and also if we don't use
+ // hexadecimal as entering "x" of the "0x" prefix wouldn't be allowed
+ // neither then
+ const DWORD styleOld = ::GetWindowLong(GetBuddyHwnd(), GWL_STYLE);
+ DWORD styleNew;
+ if ( m_min < 0 || GetBase() != 10 )
+ styleNew = styleOld & ~ES_NUMBER;
+ else
+ styleNew = styleOld | ES_NUMBER;
+
+ if ( styleNew != styleOld )
+ ::SetWindowLong(GetBuddyHwnd(), GWL_STYLE, styleNew);