All (GUI):
- Add new wxSimplebook class.
+- Support hexadecimal numbers in wxSpinCtrl.
- Respect window max size in wxBoxSizer (Nathan Ridge).
- Add support for searching in wxWebView for MSW and GTK (Allonii).
- Add possibility to hide and show again wxRibbonBar pages (wxBen).
@subsubsection xrc_wxspinctrl wxSpinCtrl
-wxSpinCtrl supports the properties as @ref xrc_wxspinbutton.
+wxSpinCtrl supports the same properties as @ref xrc_wxspinbutton and, since
+wxWidgets 2.9.5, another one:
+@beginTable
+@row3col{base, integer,
+ Numeric base, currently can be only 10 or 16 (default: 10).}
+@endTable
@subsubsection xrc_wxsplitterwindow wxSplitterWindow
class WXDLLIMPEXP_CORE wxSpinCtrl : public wxSpinCtrlGenericBase
{
public:
- wxSpinCtrl() {}
+ wxSpinCtrl() { Init(); }
wxSpinCtrl(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString& value = wxEmptyString,
int min = 0, int max = 100, int initial = 0,
const wxString& name = wxT("wxSpinCtrl"))
{
+ Init();
+
Create(parent, id, value, pos, size, style, min, max, initial, name);
}
void SetRange( int minVal, int maxVal ) { DoSetRange(minVal, maxVal); }
void SetIncrement(int inc) { DoSetIncrement(inc); }
+ virtual int GetBase() const { return m_base; }
+ virtual bool SetBase(int base);
+
protected:
virtual void DoSendEvent();
virtual bool DoTextToValue(const wxString& text, double *val);
virtual wxString DoValueToText(double val);
+
+private:
+ // Common part of all ctors.
+ void Init()
+ {
+ m_base = 10;
+ }
+
+ int m_base;
+
DECLARE_DYNAMIC_CLASS(wxSpinCtrl)
};
void SetIncrement(double inc) { DoSetIncrement(inc); }
void SetDigits(unsigned digits);
+ // We don't implement bases support for floating point numbers, this is not
+ // very useful in practice.
+ virtual int GetBase() const { return 10; }
+ virtual bool SetBase(int WXUNUSED(base)) { return 0; }
+
protected:
virtual void DoSendEvent();
class WXDLLIMPEXP_CORE wxSpinCtrl : public wxSpinCtrlGTKBase
{
public:
- wxSpinCtrl() {}
+ wxSpinCtrl() { Init(); }
wxSpinCtrl(wxWindow *parent,
wxWindowID id = wxID_ANY,
const wxString& value = wxEmptyString,
int min = 0, int max = 100, int initial = 0,
const wxString& name = wxS("wxSpinCtrl"))
{
+ Init();
+
Create(parent, id, value, pos, size, style, min, max, initial, name);
}
void SetRange( int minVal, int maxVal ) { DoSetRange(minVal, maxVal); }
void SetIncrement(int inc) { DoSetIncrement(inc); }
+ virtual int GetBase() const { return m_base; }
+ virtual bool SetBase(int base);
+
+private:
+ // Common part of all ctors.
+ void Init()
+ {
+ m_base = 10;
+ }
+
+ int m_base;
+
DECLARE_DYNAMIC_CLASS(wxSpinCtrl)
};
void SetIncrement(double inc) { DoSetIncrement(inc); }
void SetDigits(unsigned digits);
+ virtual int GetBase() const { return 10; }
+ virtual bool SetBase(int WXUNUSED(base)) { return false; }
+
DECLARE_DYNAMIC_CLASS(wxSpinCtrlDouble)
};
// another wxTextCtrl-like method
void SetSelection(long from, long to);
+ // wxSpinCtrlBase methods
+ virtual int GetBase() const;
+ virtual bool SetBase(int base);
+
+
// implementation only from now on
// -------------------------------
// Common part of all ctors.
void Init();
+ // Adjust the text control style depending on whether we need to enter only
+ // digits or may need to enter something else (e.g. "-" sign, "x"
+ // hexadecimal prefix, ...) in it.
+ void UpdateBuddyStyle();
+
+
DECLARE_DYNAMIC_CLASS(wxSpinCtrl)
DECLARE_EVENT_TABLE()
wxDECLARE_NO_COPY_CLASS(wxSpinCtrl);
virtual void SetSnapToTicks(bool snap_to_ticks) = 0;
// void SetDigits(unsigned digits) - wxSpinCtrlDouble only
+ // The base for numbers display, e.g. 10 or 16.
+ virtual int GetBase() const = 0;
+ virtual bool SetBase(int base) = 0;
+
// Select text in the textctrl
virtual void SetSelection(long from, long to) = 0;
#include "wx/generic/spinctlg.h"
#endif
+namespace wxPrivate
+{
+
+// This is an internal helper function currently used by all ports: return the
+// string containing hexadecimal representation of the given number.
+extern wxString wxSpinCtrlFormatAsHex(long val, long maxVal);
+
+} // namespace wxPrivate
+
#endif // wxUSE_SPINCTRL
#endif // _WX_SPINCTRL_H_
long style = wxSP_ARROW_KEYS, int min = 0, int max = 100,
int initial = 0, const wxString& name = "wxSpinCtrl");
+ /**
+ Returns the numerical base being currently used, 10 by default.
+
+ @see SetBase()
+
+ @since 2.9.5
+ */
+ int GetBase() const;
+
/**
Gets maximal allowable value.
*/
*/
int GetValue() const;
+ /**
+ Sets the base to use for the numbers in this control.
+
+ Currently the only supported values are 10 (which is the default) and
+ 16.
+
+ Changing the base allows the user to enter the numbers in the specified
+ base, e.g. with "0x" prefix for hexadecimal numbers, and also displays
+ the numbers in the specified base when they are changed using the spin
+ control arrows.
+
+ @param base
+ Numeric base, currently only 10 and 16 are supported.
+ @return
+ @true if the base was successfully changed or @false if it failed,
+ usually meaning that either the base is not 10 or 16.
+
+ @since 2.9.5
+ */
+ bool SetBase(int base);
+
/**
Sets range of allowable values.
SpinBtnPage_Clear,
SpinBtnPage_SetValue,
SpinBtnPage_SetMinAndMax,
+ SpinBtnPage_SetBase,
SpinBtnPage_CurValueText,
SpinBtnPage_ValueText,
SpinBtnPage_MinText,
SpinBtnPage_MaxText,
+ SpinBtnPage_BaseText,
SpinBtnPage_SpinBtn,
SpinBtnPage_SpinCtrl,
SpinBtnPage_SpinCtrlDouble
void OnButtonClear(wxCommandEvent& event);
void OnButtonSetValue(wxCommandEvent& event);
void OnButtonSetMinAndMax(wxCommandEvent& event);
+ void OnButtonSetBase(wxCommandEvent& event);
void OnCheckOrRadioBox(wxCommandEvent& event);
void OnUpdateUIValueButton(wxUpdateUIEvent& event);
void OnUpdateUIMinMaxButton(wxUpdateUIEvent& event);
+ void OnUpdateUIBaseButton(wxUpdateUIEvent& event);
void OnUpdateUIResetButton(wxUpdateUIEvent& event);
// the spinbtn range
int m_min, m_max;
+ // and numeric base
+ int m_base;
+
// the controls
// ------------
*m_chkArrowKeys,
*m_chkWrap,
*m_chkProcessEnter;
- wxRadioBox *m_radioAlign;
+ wxRadioBox *m_radioAlign;
// the spinbtn and the spinctrl and the sizer containing them
wxSpinButton *m_spinbtn;
// the text entries for set value/range
wxTextCtrl *m_textValue,
*m_textMin,
- *m_textMax;
+ *m_textMax,
+ *m_textBase;
private:
DECLARE_EVENT_TABLE()
EVT_BUTTON(SpinBtnPage_Reset, SpinBtnWidgetsPage::OnButtonReset)
EVT_BUTTON(SpinBtnPage_SetValue, SpinBtnWidgetsPage::OnButtonSetValue)
EVT_BUTTON(SpinBtnPage_SetMinAndMax, SpinBtnWidgetsPage::OnButtonSetMinAndMax)
+ EVT_BUTTON(SpinBtnPage_SetBase, SpinBtnWidgetsPage::OnButtonSetBase)
EVT_UPDATE_UI(SpinBtnPage_SetValue, SpinBtnWidgetsPage::OnUpdateUIValueButton)
EVT_UPDATE_UI(SpinBtnPage_SetMinAndMax, SpinBtnWidgetsPage::OnUpdateUIMinMaxButton)
+ EVT_UPDATE_UI(SpinBtnPage_SetBase, SpinBtnWidgetsPage::OnUpdateUIBaseButton)
EVT_UPDATE_UI(SpinBtnPage_Reset, SpinBtnWidgetsPage::OnUpdateUIResetButton)
m_spinbtn = NULL;
m_spinctrl = NULL;
m_spinctrldbl = NULL;
- m_textValue = NULL;
- m_textMin = NULL;
- m_textMax = NULL;
+ m_textValue =
+ m_textMin =
+ m_textMax =
+ m_textBase = NULL;
m_min = 0;
m_max = 10;
+ m_base = 10;
+
m_sizerSpin = NULL;
}
sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
+ sizerRow = CreateSizerWithTextAndButton(SpinBtnPage_SetBase,
+ "Set &base",
+ SpinBtnPage_BaseText,
+ &m_textBase);
+ m_textBase->SetValue("10");
+ sizerMiddle->Add(sizerRow, 0, wxALL | wxGROW, 5);
+
// right pane
wxSizer *sizerRight = new wxBoxSizer(wxVERTICAL);
sizerRight->SetMinSize(150, 0);
m_spinctrldbl->SetRange(minNew, maxNew);
}
+void SpinBtnWidgetsPage::OnButtonSetBase(wxCommandEvent& WXUNUSED(event))
+{
+ unsigned long base;
+ if ( !m_textBase->GetValue().ToULong(&base) || !base )
+ {
+ wxLogWarning("Invalid base value.");
+ return;
+ }
+
+ m_base = base;
+ if ( !m_spinctrl->SetBase(m_base) )
+ {
+ wxLogWarning("Setting base %d failed.", m_base);
+ }
+}
+
void SpinBtnWidgetsPage::OnButtonSetValue(wxCommandEvent& WXUNUSED(event))
{
long val;
mn <= mx);
}
+void SpinBtnWidgetsPage::OnUpdateUIBaseButton(wxUpdateUIEvent& event)
+{
+ unsigned long base;
+ event.Enable( m_textBase->GetValue().ToULong(&base) && base );
+}
+
void SpinBtnWidgetsPage::OnUpdateUIResetButton(wxUpdateUIEvent& event)
{
event.Enable( !m_chkVert->GetValue() ||
<object class="wxSpinCtrl" name="controls_spinctrl">
<size>100,-1</size>
<max>100</max>
- <value>0</value>
+ <value>17</value>
+ <base>16</base>
</object>
</object>
</object>
wxSize, Size, long, WindowStyle )
+wxString wxPrivate::wxSpinCtrlFormatAsHex(long val, long maxVal)
+{
+ // We format the value like this is for compatibility with (native
+ // behaviour of) wxMSW
+ wxString text;
+ if ( maxVal < 0x10000 )
+ text.Printf(wxS("0x%04lx"), val);
+ else
+ text.Printf(wxS("0x%08lx"), val);
+
+ return text;
+}
+
#endif // wxUSE_SPINCTRL
// wxSpinCtrl
//-----------------------------------------------------------------------------
+bool wxSpinCtrl::SetBase(int base)
+{
+ // Currently we only support base 10 and 16. We could add support for base
+ // 8 quite easily but wxMSW doesn't support it natively so don't bother.
+ if ( base != 10 && base != 16 )
+ return false;
+
+ if ( base == m_base )
+ return true;
+
+ // Update the current control contents to show in the new base: be careful
+ // to call DoTextToValue() before changing the base...
+ double val;
+ const bool hasValidVal = DoTextToValue(m_textCtrl->GetValue(), &val);
+
+ m_base = base;
+
+ // ... but DoValueToText() after doing it.
+ if ( hasValidVal )
+ m_textCtrl->SetValue(DoValueToText(val));
+
+ return true;
+}
+
void wxSpinCtrl::DoSendEvent()
{
wxSpinEvent event( wxEVT_COMMAND_SPINCTRL_UPDATED, GetId());
bool wxSpinCtrl::DoTextToValue(const wxString& text, double *val)
{
long lval;
- if ( !text.ToLong(&lval) )
+ if ( !text.ToLong(&lval, GetBase()) )
return false;
*val = static_cast<double>(lval);
wxString wxSpinCtrl::DoValueToText(double val)
{
- return wxString::Format("%ld", static_cast<long>(val));
+ switch ( GetBase() )
+ {
+ case 16:
+ return wxPrivate::wxSpinCtrlFormatAsHex(static_cast<long>(val),
+ GetMax());
+
+ default:
+ wxFAIL_MSG( wxS("Unsupported spin control base") );
+ // Fall through
+
+ case 10:
+ return wxString::Format("%ld", static_cast<long>(val));
+ }
}
#endif // !wxHAS_NATIVE_SPINCTRL
// wxSpinCtrl
//-----------------------------------------------------------------------------
+extern "C"
+{
+
+static gboolean
+wx_gtk_spin_input(GtkSpinButton* spin, gdouble* val, wxSpinCtrl* win)
+{
+ // We might use g_ascii_strtoll() here but it's 2.12+ only, so use our own
+ // wxString function even if this requires an extra conversion.
+ const wxString
+ text(wxString::FromUTF8(gtk_entry_get_text(GTK_ENTRY(spin))));
+
+ long lval;
+ if ( !text.ToLong(&lval, win->GetBase()) )
+ return FALSE;
+
+ *val = lval;
+
+ return TRUE;
+}
+
+static gint
+wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrl* win)
+{
+ const gint val = gtk_spin_button_get_value_as_int(spin);
+
+ gtk_entry_set_text
+ (
+ GTK_ENTRY(spin),
+ wxPrivate::wxSpinCtrlFormatAsHex(val, win->GetMax()).utf8_str()
+ );
+
+ return TRUE;
+}
+
+} // extern "C"
+
+bool wxSpinCtrl::SetBase(int base)
+{
+ // Currently we only support base 10 and 16. We could add support for base
+ // 8 quite easily but wxMSW doesn't support it natively so don't bother
+ // with doing something wxGTK-specific here.
+ if ( base != 10 && base != 16 )
+ return false;
+
+ if ( base == m_base )
+ return true;
+
+ m_base = base;
+
+ // We need to be able to enter letters for any base greater than 10.
+ gtk_spin_button_set_numeric( GTK_SPIN_BUTTON(m_widget), m_base <= 10 );
+
+ if ( m_base != 10 )
+ {
+ g_signal_connect( GTK_SPIN_BUTTON(m_widget), "input",
+ G_CALLBACK(wx_gtk_spin_input), this);
+ g_signal_connect( GTK_SPIN_BUTTON(m_widget), "output",
+ G_CALLBACK(wx_gtk_spin_output), this);
+ }
+ else
+ {
+ g_signal_handlers_disconnect_by_func(GTK_SPIN_BUTTON(m_widget),
+ (gpointer)wx_gtk_spin_input,
+ this);
+ g_signal_handlers_disconnect_by_func(GTK_SPIN_BUTTON(m_widget),
+ (gpointer)wx_gtk_spin_output,
+ this);
+ }
+
+ return true;
+}
+
//-----------------------------------------------------------------------------
// wxSpinCtrlDouble
//-----------------------------------------------------------------------------
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
// ----------------------------------------------------------------------------
wxSpinButton::SetValue(val);
- // normally setting the value of the spin button is enough as it updates
- // its buddy control automatically ...
- if ( wxGetWindowText(m_hwndBuddy).empty() )
+ // 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')) )
{
- // ... but sometimes it doesn't, notably when the value is 0 and the
- // text control is currently empty, the spin button seems to be happy
- // to leave it like this, while we really want to always show the
- // current value in the control, so do it manually
::SetWindowText(GetBuddyHwnd(),
- wxString::Format(wxT("%d"), val).t_str());
+ wxPrivate::wxSpinCtrlFormatAsHex(val, m_max).t_str());
}
m_oldValue = GetValue();
int wxSpinCtrl::GetValue() const
{
- wxString val = wxGetWindowText(m_hwndBuddy);
+ const wxString val = wxGetWindowText(m_hwndBuddy);
long n;
- if ( (wxSscanf(val, wxT("%ld"), &n) != 1) )
+ if ( !val.ToLong(&n, GetBase()) )
n = INT_MIN;
if ( n < m_min )
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
+ // 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 ( minVal < 0 )
+ if ( m_min < 0 || GetBase() != 10 )
styleNew = styleOld & ~ES_NUMBER;
else
styleNew = styleOld | ES_NUMBER;
GetLong(wxT("value"), DEFAULT_VALUE),
GetName());
+ const long base = GetLong(wxS("base"), 10);
+ if ( base != 10 )
+ control->SetBase(base);
+
SetupWindow(control);
return control;