Merge branch 'spinctrl-gettextvalue'
Add wxSpinCtrl::GetTextValue() and allow clearing the text value in wxGTK version for compatibility with MSW. See https://github.com/wxWidgets/wxWidgets/pull/2334
This commit is contained in:
@@ -60,6 +60,7 @@ public:
|
||||
virtual ~wxSpinCtrlGenericBase();
|
||||
|
||||
// accessors
|
||||
virtual wxString GetTextValue() const wxOVERRIDE;
|
||||
// T GetValue() const
|
||||
// T GetMin() const
|
||||
// T GetMax() const
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
// wxSpinCtrl(Double) methods call DoXXX functions of the same name
|
||||
|
||||
// accessors
|
||||
virtual wxString GetTextValue() const wxOVERRIDE;
|
||||
// T GetValue() const
|
||||
// T GetMin() const
|
||||
// T GetMax() const
|
||||
@@ -57,7 +58,26 @@ public:
|
||||
// implementation
|
||||
void OnChar( wxKeyEvent &event );
|
||||
|
||||
|
||||
// These values map to the possible return values of "input" GTK signal but
|
||||
// are more readable and type-safe.
|
||||
enum GTKInputResult
|
||||
{
|
||||
GTKInput_Error = -1,
|
||||
GTKInput_Default,
|
||||
GTKInput_Converted
|
||||
};
|
||||
|
||||
virtual GTKInputResult GTKInput(double* value) const = 0;
|
||||
virtual bool GTKOutput(wxString* text) const = 0;
|
||||
|
||||
virtual void GTKValueChanged() = 0;
|
||||
void GTKTextChanged();
|
||||
|
||||
protected:
|
||||
wxSpinCtrlGTKBase();
|
||||
~wxSpinCtrlGTKBase();
|
||||
|
||||
double DoGetValue() const;
|
||||
double DoGetMin() const;
|
||||
double DoGetMax() const;
|
||||
@@ -82,6 +102,26 @@ protected:
|
||||
// override this and return true.
|
||||
virtual bool UseGTKStyleBase() const wxOVERRIDE { return true; }
|
||||
|
||||
// Set m_textOverride to use the given text instead of the numeric value.
|
||||
void GTKSetTextOverride(const wxString& text);
|
||||
|
||||
// Reset the override and changing the value to correspond to the
|
||||
// previously overridden numeric value.
|
||||
void GTKResetTextOverride();
|
||||
|
||||
// Just reset the override, without touching the value, returning true if
|
||||
// we did it. In most cases, the function above should be used instead.
|
||||
bool GTKResetTextOverrideOnly();
|
||||
|
||||
private:
|
||||
// This function does _not_ take into account m_textOverride, so it is
|
||||
// private and normally shouldn't be used -- use DoGetValue() instead.
|
||||
double GTKGetValue() const;
|
||||
|
||||
// Non-null when the text value is different from the numeric value.
|
||||
class wxSpinCtrlGTKTextOverride* m_textOverride;
|
||||
|
||||
|
||||
friend class wxSpinCtrlEventDisabler;
|
||||
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
@@ -137,6 +177,10 @@ public:
|
||||
virtual int GetBase() const wxOVERRIDE { return m_base; }
|
||||
virtual bool SetBase(int base) wxOVERRIDE;
|
||||
|
||||
virtual GTKInputResult GTKInput(double* value) const wxOVERRIDE;
|
||||
virtual bool GTKOutput(wxString* text) const wxOVERRIDE;
|
||||
virtual void GTKValueChanged() wxOVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void GtkSetEntryWidth() wxOVERRIDE;
|
||||
|
||||
@@ -205,6 +249,10 @@ public:
|
||||
virtual int GetBase() const wxOVERRIDE { return 10; }
|
||||
virtual bool SetBase(int WXUNUSED(base)) wxOVERRIDE { return false; }
|
||||
|
||||
virtual GTKInputResult GTKInput(double* value) const wxOVERRIDE;
|
||||
virtual bool GTKOutput(wxString* text) const wxOVERRIDE;
|
||||
virtual void GTKValueChanged() wxOVERRIDE;
|
||||
|
||||
protected:
|
||||
virtual void GtkSetEntryWidth() wxOVERRIDE;
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@ public:
|
||||
void SetValue(const wxString& text);
|
||||
void SetSelection(long from, long to);
|
||||
|
||||
virtual wxString GetTextValue() const;
|
||||
virtual int GetValue() const;
|
||||
virtual void SetValue( int value );
|
||||
virtual void SetRange( int minVal, int maxVal );
|
||||
|
||||
@@ -62,6 +62,7 @@ public:
|
||||
void SetSelection(long from, long to);
|
||||
|
||||
// wxSpinCtrlBase methods
|
||||
virtual wxString GetTextValue() const;
|
||||
virtual int GetBase() const;
|
||||
virtual bool SetBase(int base);
|
||||
|
||||
|
||||
@@ -29,6 +29,7 @@ public:
|
||||
T min, T max, T initial, T inc,
|
||||
const wxString& name );
|
||||
|
||||
virtual wxString GetTextValue() const wxOVERRIDE;
|
||||
virtual void SetValue(const wxString&) wxOVERRIDE {}
|
||||
|
||||
virtual void SetSnapToTicks(bool snap_to_ticks) wxOVERRIDE;
|
||||
|
||||
@@ -35,6 +35,7 @@ public:
|
||||
wxSpinCtrlBase() {}
|
||||
|
||||
// accessor functions that derived classes are expected to have
|
||||
virtual wxString GetTextValue() const = 0;
|
||||
// T GetValue() const
|
||||
// T GetMin() const
|
||||
// T GetMax() const
|
||||
|
||||
@@ -133,6 +133,13 @@ public:
|
||||
*/
|
||||
int GetMin() const;
|
||||
|
||||
/**
|
||||
Returns the text in the text entry part of the control.
|
||||
|
||||
@since 3.1.6
|
||||
*/
|
||||
wxString GetTextValue() const;
|
||||
|
||||
/**
|
||||
Gets the value of the spin control.
|
||||
*/
|
||||
@@ -190,6 +197,10 @@ public:
|
||||
Sets the value of the spin control.
|
||||
|
||||
It is recommended to use the overload taking an integer value instead.
|
||||
The behaviour of this function when @a text doesn't represent a valid
|
||||
number currently differs between the platforms, however passing an
|
||||
empty string does clear the text part contents, without affecting the
|
||||
value returned by GetValue(), under all of them.
|
||||
|
||||
Notice that, unlike wxTextCtrl::SetValue(), but like most of the other
|
||||
setter methods in wxWidgets, calling this method does not generate any
|
||||
@@ -243,6 +254,14 @@ public:
|
||||
/**
|
||||
Constructor, creating and showing a spin control.
|
||||
|
||||
If @a value is non-empty, it will be shown in the text entry part of
|
||||
the control and if it has numeric value, the initial numeric value of
|
||||
the control, as returned by GetValue() will also be determined by it
|
||||
instead of by @a initial. Hence, it only makes sense to specify @a
|
||||
initial if @a value is an empty string or is not convertible to a
|
||||
number, otherwise @a initial is simply ignored and the number specified
|
||||
by @a value is used.
|
||||
|
||||
@param parent
|
||||
Parent window. Must not be @NULL.
|
||||
@param value
|
||||
@@ -315,6 +334,13 @@ public:
|
||||
*/
|
||||
double GetMin() const;
|
||||
|
||||
/**
|
||||
Returns the text in the text entry part of the control.
|
||||
|
||||
@since 3.1.6
|
||||
*/
|
||||
wxString GetTextValue() const;
|
||||
|
||||
/**
|
||||
Gets the value of the spin control.
|
||||
*/
|
||||
@@ -342,6 +368,10 @@ public:
|
||||
Sets the value of the spin control.
|
||||
|
||||
It is recommended to use the overload taking a double value instead.
|
||||
The behaviour of this function when @a text doesn't represent a valid
|
||||
number currently differs between the platforms, however
|
||||
passing an empty string does clear the text part contents, without
|
||||
affecting the value returned by GetValue(), under all of them.
|
||||
|
||||
Notice that, unlike wxTextCtrl::SetValue(), but like most of the other
|
||||
setter methods in wxWidgets, calling this method does not generate any
|
||||
|
||||
@@ -483,6 +483,14 @@ void SpinBtnWidgetsPage::OnButtonSetBase(wxCommandEvent& WXUNUSED(event))
|
||||
|
||||
void SpinBtnWidgetsPage::OnButtonSetValue(wxCommandEvent& WXUNUSED(event))
|
||||
{
|
||||
if ( m_textValue->IsEmpty() )
|
||||
{
|
||||
m_spinctrl->SetValue( wxEmptyString );
|
||||
m_spinctrldbl->SetValue( wxEmptyString );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
long val;
|
||||
if ( !m_textValue->GetValue().ToLong(&val) || !IsValidValue(val) )
|
||||
{
|
||||
@@ -499,7 +507,8 @@ void SpinBtnWidgetsPage::OnButtonSetValue(wxCommandEvent& WXUNUSED(event))
|
||||
void SpinBtnWidgetsPage::OnUpdateUIValueButton(wxUpdateUIEvent& event)
|
||||
{
|
||||
long val;
|
||||
event.Enable( m_textValue->GetValue().ToLong(&val) && IsValidValue(val) );
|
||||
event.Enable( m_textValue->IsEmpty() ||
|
||||
( m_textValue->GetValue().ToLong(&val) && IsValidValue(val) ) );
|
||||
}
|
||||
|
||||
void SpinBtnWidgetsPage::OnUpdateUIMinMaxButton(wxUpdateUIEvent& event)
|
||||
|
||||
@@ -506,6 +506,11 @@ bool wxSpinCtrlGenericBase::SyncSpinToText(SendEvent sendEvent)
|
||||
// changing value and range
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxSpinCtrlGenericBase::GetTextValue() const
|
||||
{
|
||||
return m_textCtrl ? m_textCtrl->GetValue() : wxString();
|
||||
}
|
||||
|
||||
void wxSpinCtrlGenericBase::SetValue(const wxString& text)
|
||||
{
|
||||
wxCHECK_RET( m_textCtrl, wxT("invalid call to wxSpinCtrl::SetValue") );
|
||||
|
||||
@@ -37,27 +37,12 @@ extern bool g_blockEventsOnDrag;
|
||||
|
||||
extern "C" {
|
||||
static void
|
||||
gtk_value_changed(GtkSpinButton* spinbutton, wxSpinCtrlGTKBase* win)
|
||||
gtk_value_changed(GtkSpinButton*, wxSpinCtrlGTKBase* win)
|
||||
{
|
||||
if (g_blockEventsOnDrag)
|
||||
return;
|
||||
|
||||
if (wxIsKindOf(win, wxSpinCtrl))
|
||||
{
|
||||
wxSpinEvent event(wxEVT_SPINCTRL, win->GetId());
|
||||
event.SetEventObject( win );
|
||||
event.SetPosition(static_cast<wxSpinCtrl*>(win)->GetValue());
|
||||
event.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton)));
|
||||
win->HandleWindowEvent( event );
|
||||
}
|
||||
else // wxIsKindOf(win, wxSpinCtrlDouble)
|
||||
{
|
||||
wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, win->GetId());
|
||||
event.SetEventObject( win );
|
||||
event.SetValue(static_cast<wxSpinCtrlDouble*>(win)->GetValue());
|
||||
event.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton)));
|
||||
win->HandleWindowEvent( event );
|
||||
}
|
||||
win->GTKValueChanged();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,16 +52,53 @@ gtk_value_changed(GtkSpinButton* spinbutton, wxSpinCtrlGTKBase* win)
|
||||
|
||||
extern "C" {
|
||||
static void
|
||||
gtk_changed(GtkSpinButton* spinbutton, wxSpinCtrl* win)
|
||||
gtk_changed(GtkSpinButton*, wxSpinCtrl* win)
|
||||
{
|
||||
wxCommandEvent event( wxEVT_TEXT, win->GetId() );
|
||||
event.SetEventObject( win );
|
||||
event.SetString(gtk_entry_get_text(GTK_ENTRY(spinbutton)));
|
||||
event.SetInt(win->GetValue());
|
||||
win->HandleWindowEvent( event );
|
||||
win->GTKTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// "input" and "output"
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
extern "C"
|
||||
{
|
||||
|
||||
static gint
|
||||
wx_gtk_spin_input(GtkSpinButton*, gdouble* val, wxSpinCtrlGTKBase* win)
|
||||
{
|
||||
switch ( win->GTKInput(val) )
|
||||
{
|
||||
case wxSpinCtrl::GTKInput_Error:
|
||||
return GTK_INPUT_ERROR;
|
||||
|
||||
case wxSpinCtrl::GTKInput_Default:
|
||||
return FALSE;
|
||||
|
||||
case wxSpinCtrl::GTKInput_Converted:
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
wxFAIL_MSG("unreachable");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrlGTKBase* win)
|
||||
{
|
||||
wxString text;
|
||||
if ( !win->GTKOutput(&text) )
|
||||
return FALSE;
|
||||
|
||||
if ( text != win->GetTextValue() )
|
||||
gtk_entry_set_text(GTK_ENTRY(spin), text.utf8_str());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSpinCtrlEventDisabler: helper to temporarily disable GTK+ events
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -101,6 +123,22 @@ private:
|
||||
wxDECLARE_NO_COPY_CLASS(wxSpinCtrlEventDisabler);
|
||||
};
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// wxSpinCtrlGTKTextOverride: extra data for using a separate string value
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
class wxSpinCtrlGTKTextOverride
|
||||
{
|
||||
public:
|
||||
wxSpinCtrlGTKTextOverride()
|
||||
: m_value(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
wxString m_text;
|
||||
double m_value;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxSpinCtrlGTKBase
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -109,6 +147,62 @@ wxBEGIN_EVENT_TABLE(wxSpinCtrlGTKBase, wxSpinCtrlBase)
|
||||
EVT_CHAR(wxSpinCtrlGTKBase::OnChar)
|
||||
wxEND_EVENT_TABLE()
|
||||
|
||||
wxSpinCtrlGTKBase::wxSpinCtrlGTKBase()
|
||||
: m_textOverride(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
wxSpinCtrlGTKBase::~wxSpinCtrlGTKBase()
|
||||
{
|
||||
delete m_textOverride;
|
||||
}
|
||||
|
||||
void wxSpinCtrlGTKBase::GTKSetTextOverride(const wxString& text)
|
||||
{
|
||||
if ( !m_textOverride )
|
||||
{
|
||||
// Remember the original numeric value, that we're going to keep using
|
||||
// it while this override is valid, and do it before initializing
|
||||
// m_textOverride as our own "input" handler called from GTKGetValue()
|
||||
// would use it if it were non-null.
|
||||
const double value = GTKGetValue();
|
||||
|
||||
m_textOverride = new wxSpinCtrlGTKTextOverride();
|
||||
m_textOverride->m_value = value;
|
||||
}
|
||||
//else: No need to change the value, it stays the same anyhow.
|
||||
|
||||
// Update the text in any case.
|
||||
m_textOverride->m_text = text;
|
||||
}
|
||||
|
||||
bool wxSpinCtrlGTKBase::GTKResetTextOverrideOnly()
|
||||
{
|
||||
if ( !m_textOverride )
|
||||
return false;
|
||||
|
||||
delete m_textOverride;
|
||||
m_textOverride = NULL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxSpinCtrlGTKBase::GTKResetTextOverride()
|
||||
{
|
||||
if ( !GTKResetTextOverrideOnly() )
|
||||
return;
|
||||
|
||||
// Update the text part to reflect the numeric value now that we don't
|
||||
// override it any longer, otherwise we'd keep showing the old one because
|
||||
// the text is updated by GTK before "value" is generated.
|
||||
wxSpinCtrlEventDisabler disable(this);
|
||||
gtk_spin_button_set_value
|
||||
(
|
||||
GTK_SPIN_BUTTON(m_widget),
|
||||
gtk_spin_button_get_value(GTK_SPIN_BUTTON(m_widget))
|
||||
);
|
||||
}
|
||||
|
||||
bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id,
|
||||
const wxString& value,
|
||||
const wxPoint& pos, const wxSize& size,
|
||||
@@ -146,6 +240,9 @@ bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id,
|
||||
g_signal_connect_after(m_widget, "value_changed", G_CALLBACK(gtk_value_changed), this);
|
||||
g_signal_connect_after(m_widget, "changed", G_CALLBACK(gtk_changed), this);
|
||||
|
||||
g_signal_connect(m_widget, "input", G_CALLBACK(wx_gtk_spin_input), this);
|
||||
g_signal_connect(m_widget, "output", G_CALLBACK(wx_gtk_spin_output), this);
|
||||
|
||||
m_parent->DoAddChild( this );
|
||||
|
||||
PostCreation(size);
|
||||
@@ -159,6 +256,15 @@ bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id,
|
||||
}
|
||||
|
||||
double wxSpinCtrlGTKBase::DoGetValue() const
|
||||
{
|
||||
// While using a text override, the text value is fixed by the program and
|
||||
// shouldn't be used, just return the numeric value we had had before, as
|
||||
// the text override is reset whenever it changes, so it must not have
|
||||
// changed yet.
|
||||
return m_textOverride ? m_textOverride->m_value : GTKGetValue();
|
||||
}
|
||||
|
||||
double wxSpinCtrlGTKBase::GTKGetValue() const
|
||||
{
|
||||
wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") );
|
||||
|
||||
@@ -214,6 +320,13 @@ double wxSpinCtrlGTKBase::DoGetIncrement() const
|
||||
return inc;
|
||||
}
|
||||
|
||||
wxString wxSpinCtrlGTKBase::GetTextValue() const
|
||||
{
|
||||
wxCHECK_MSG(m_widget, wxEmptyString, "invalid spin button");
|
||||
|
||||
return wxGTK_CONV_BACK(gtk_entry_get_text( GTK_ENTRY(m_widget) ));
|
||||
}
|
||||
|
||||
bool wxSpinCtrlGTKBase::GetSnapToTicks() const
|
||||
{
|
||||
wxCHECK_MSG(m_widget, false, "invalid spin button");
|
||||
@@ -233,7 +346,12 @@ void wxSpinCtrlGTKBase::SetValue( const wxString& value )
|
||||
return;
|
||||
}
|
||||
|
||||
// invalid number - set text as is (wxMSW compatible)
|
||||
// invalid number - set text as is (wxMSW compatible) and remember that it
|
||||
// is set to avoid overwriting it later, which is notably important when
|
||||
// we're called before the window is realized as the default "realize"
|
||||
// handler will call our "output" handler
|
||||
GTKSetTextOverride(value);
|
||||
|
||||
wxSpinCtrlEventDisabler disable(this);
|
||||
gtk_entry_set_text( GTK_ENTRY(m_widget), wxGTK_CONV( value ) );
|
||||
}
|
||||
@@ -242,6 +360,8 @@ void wxSpinCtrlGTKBase::DoSetValue( double value )
|
||||
{
|
||||
wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") );
|
||||
|
||||
GTKResetTextOverride();
|
||||
|
||||
wxSpinCtrlEventDisabler disable(this);
|
||||
gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget), value);
|
||||
}
|
||||
@@ -336,9 +456,7 @@ void wxSpinCtrlGTKBase::OnChar( wxKeyEvent &event )
|
||||
{
|
||||
wxCommandEvent evt( wxEVT_TEXT_ENTER, m_windowId );
|
||||
evt.SetEventObject(this);
|
||||
GtkSpinButton *gsb = GTK_SPIN_BUTTON(m_widget);
|
||||
wxString val = wxGTK_CONV_BACK( gtk_entry_get_text( &gsb->entry ) );
|
||||
evt.SetString( val );
|
||||
evt.SetString(GetTextValue());
|
||||
if (HandleWindowEvent(evt)) return;
|
||||
}
|
||||
|
||||
@@ -390,46 +508,46 @@ wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
|
||||
return GetDefaultAttributesFromGTKWidget(gtk_spin_button_new_with_range(0, 100, 1), true);
|
||||
}
|
||||
|
||||
wxSpinCtrlGTKBase::GTKInputResult wxSpinCtrlGTKBase::GTKInput(double* value) const
|
||||
{
|
||||
if ( m_textOverride )
|
||||
{
|
||||
*value = m_textOverride->m_value;
|
||||
return GTKInput_Converted;
|
||||
}
|
||||
|
||||
return GTKInput_Default;
|
||||
}
|
||||
|
||||
bool wxSpinCtrlGTKBase::GTKOutput(wxString* text) const
|
||||
{
|
||||
if ( m_textOverride )
|
||||
{
|
||||
*text = m_textOverride->m_text;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxSpinCtrlGTKBase::GTKTextChanged()
|
||||
{
|
||||
// We can't use GTKResetTextOverride() itself here because it would also
|
||||
// reset the value and we do not want this to happen -- the value is being
|
||||
// changed to correspond to the new text.
|
||||
GTKResetTextOverrideOnly();
|
||||
|
||||
wxCommandEvent event( wxEVT_TEXT, GetId() );
|
||||
event.SetEventObject( this );
|
||||
event.SetString(GetTextValue());
|
||||
event.SetInt(static_cast<int>(DoGetValue()));
|
||||
HandleWindowEvent( event );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// 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),
|
||||
wxSpinCtrlImpl::FormatAsHex(val, win->GetMax()).utf8_str()
|
||||
);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
|
||||
void wxSpinCtrl::GtkSetEntryWidth()
|
||||
{
|
||||
const int minVal = static_cast<int>(DoGetMin());
|
||||
@@ -462,23 +580,6 @@ bool wxSpinCtrl::SetBase(int 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( m_widget, "input",
|
||||
G_CALLBACK(wx_gtk_spin_input), this);
|
||||
g_signal_connect( m_widget, "output",
|
||||
G_CALLBACK(wx_gtk_spin_output), this);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_signal_handlers_disconnect_by_func(m_widget,
|
||||
(gpointer)wx_gtk_spin_input,
|
||||
this);
|
||||
g_signal_handlers_disconnect_by_func(m_widget,
|
||||
(gpointer)wx_gtk_spin_output,
|
||||
this);
|
||||
}
|
||||
|
||||
InvalidateBestSize();
|
||||
|
||||
GtkSetEntryWidth();
|
||||
@@ -489,6 +590,61 @@ bool wxSpinCtrl::SetBase(int base)
|
||||
return true;
|
||||
}
|
||||
|
||||
wxSpinCtrl::GTKInputResult wxSpinCtrl::GTKInput(double* value) const
|
||||
{
|
||||
GTKInputResult res = wxSpinCtrlGTKBase::GTKInput(value);
|
||||
if ( res != GTKInput_Default )
|
||||
return res;
|
||||
|
||||
// Don't override the default logic unless really needed.
|
||||
if ( GetBase() == 10 )
|
||||
return GTKInput_Default;
|
||||
|
||||
long lval;
|
||||
if ( !GetTextValue().ToLong(&lval, GetBase()) )
|
||||
return GTKInput_Error;
|
||||
|
||||
*value = lval;
|
||||
|
||||
return GTKInput_Converted;
|
||||
}
|
||||
|
||||
bool wxSpinCtrl::GTKOutput(wxString* text) const
|
||||
{
|
||||
if ( wxSpinCtrlGTKBase::GTKOutput(text) )
|
||||
return true;
|
||||
|
||||
switch ( GetBase() )
|
||||
{
|
||||
default:
|
||||
wxFAIL_MSG("unsupported base");
|
||||
wxFALLTHROUGH;
|
||||
|
||||
case 10:
|
||||
// Don't override the default output format unless really needed.
|
||||
return false;
|
||||
|
||||
case 16:
|
||||
const gint val = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(m_widget));
|
||||
|
||||
*text = wxSpinCtrlImpl::FormatAsHex(val, GetMax());
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxSpinCtrl::GTKValueChanged()
|
||||
{
|
||||
GTKResetTextOverride();
|
||||
|
||||
wxSpinEvent event(wxEVT_SPINCTRL, GetId());
|
||||
event.SetEventObject( this );
|
||||
event.SetPosition(GetValue());
|
||||
event.SetString(GetTextValue());
|
||||
HandleWindowEvent( event );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// wxSpinCtrlDouble
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -523,4 +679,28 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits)
|
||||
GtkSetEntryWidth();
|
||||
}
|
||||
|
||||
wxSpinCtrl::GTKInputResult wxSpinCtrlDouble::GTKInput(double* value) const
|
||||
{
|
||||
return wxSpinCtrlGTKBase::GTKInput(value);
|
||||
}
|
||||
|
||||
bool wxSpinCtrlDouble::GTKOutput(wxString* text) const
|
||||
{
|
||||
if ( wxSpinCtrlGTKBase::GTKOutput(text) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void wxSpinCtrlDouble::GTKValueChanged()
|
||||
{
|
||||
GTKResetTextOverride();
|
||||
|
||||
wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, GetId());
|
||||
event.SetEventObject( this );
|
||||
event.SetValue(GetValue());
|
||||
event.SetString(GetTextValue());
|
||||
HandleWindowEvent( event );
|
||||
}
|
||||
|
||||
#endif // wxUSE_SPINCTRL
|
||||
|
||||
@@ -203,6 +203,13 @@ int wxSpinCtrl::GetMax() const
|
||||
return (int)ceil(m_adjust->upper);
|
||||
}
|
||||
|
||||
wxString wxSpinCtrl::GetTextValue() const
|
||||
{
|
||||
wxCHECK_MSG(m_widget, wxEmptyString, "invalid spin button");
|
||||
|
||||
return gtk_entry_get_text( GTK_ENTRY(m_widget) );
|
||||
}
|
||||
|
||||
int wxSpinCtrl::GetValue() const
|
||||
{
|
||||
wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") );
|
||||
|
||||
@@ -442,6 +442,11 @@ bool wxSpinCtrl::SetBase(int base)
|
||||
// wxTextCtrl-like methods
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
wxString wxSpinCtrl::GetTextValue() const
|
||||
{
|
||||
return wxGetWindowText(m_hwndBuddy);
|
||||
}
|
||||
|
||||
void wxSpinCtrl::SetValue(const wxString& text)
|
||||
{
|
||||
if ( !::SetWindowText(GetBuddyHwnd(), text.c_str()) )
|
||||
|
||||
@@ -58,6 +58,12 @@ bool wxSpinCtrlQt< T, Widget >::Create( wxWindow *parent, wxWindowID id,
|
||||
return QtCreateControl( parent, id, pos, size, style, wxDefaultValidator, name );
|
||||
}
|
||||
|
||||
template< typename T, typename Widget >
|
||||
wxString wxSpinCtrlQt< T, Widget >::GetTextValue() const
|
||||
{
|
||||
return wxQtConvertString(m_qtSpinBox->text());
|
||||
}
|
||||
|
||||
template< typename T, typename Widget >
|
||||
void wxSpinCtrlQt< T, Widget >::SetValue( T val )
|
||||
{
|
||||
|
||||
@@ -19,76 +19,59 @@
|
||||
#include "wx/uiaction.h"
|
||||
#include "wx/spinctrl.h"
|
||||
|
||||
class SpinCtrlDoubleTestCase : public CppUnit::TestCase
|
||||
class SpinCtrlDoubleTestCase
|
||||
{
|
||||
public:
|
||||
SpinCtrlDoubleTestCase() { }
|
||||
SpinCtrlDoubleTestCase(int style = wxSP_ARROW_KEYS)
|
||||
: m_spin(new wxSpinCtrlDouble(wxTheApp->GetTopWindow(), wxID_ANY, "",
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
style))
|
||||
{
|
||||
}
|
||||
|
||||
void setUp() wxOVERRIDE;
|
||||
void tearDown() wxOVERRIDE;
|
||||
~SpinCtrlDoubleTestCase()
|
||||
{
|
||||
delete m_spin;
|
||||
}
|
||||
|
||||
private:
|
||||
CPPUNIT_TEST_SUITE( SpinCtrlDoubleTestCase );
|
||||
CPPUNIT_TEST( NoEventsInCtor );
|
||||
WXUISIM_TEST( Arrows );
|
||||
WXUISIM_TEST( Wrap );
|
||||
CPPUNIT_TEST( Range );
|
||||
CPPUNIT_TEST( Value );
|
||||
WXUISIM_TEST( Increment );
|
||||
CPPUNIT_TEST( Digits );
|
||||
CPPUNIT_TEST_SUITE_END();
|
||||
|
||||
void NoEventsInCtor();
|
||||
void Arrows();
|
||||
void Wrap();
|
||||
void Range();
|
||||
void Value();
|
||||
void Increment();
|
||||
void Digits();
|
||||
|
||||
wxSpinCtrlDouble* m_spin;
|
||||
protected:
|
||||
wxSpinCtrlDouble* const m_spin;
|
||||
|
||||
wxDECLARE_NO_COPY_CLASS(SpinCtrlDoubleTestCase);
|
||||
};
|
||||
|
||||
// register in the unnamed registry so that these tests are run by default
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION( SpinCtrlDoubleTestCase );
|
||||
|
||||
// also include in its own registry so that these tests can be run alone
|
||||
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( SpinCtrlDoubleTestCase, "SpinCtrlDoubleTestCase" );
|
||||
|
||||
void SpinCtrlDoubleTestCase::setUp()
|
||||
class SpinCtrlDoubleTestCaseWrap : public SpinCtrlDoubleTestCase
|
||||
{
|
||||
m_spin = new wxSpinCtrlDouble(wxTheApp->GetTopWindow());
|
||||
}
|
||||
public:
|
||||
SpinCtrlDoubleTestCaseWrap()
|
||||
: SpinCtrlDoubleTestCase(wxSP_ARROW_KEYS | wxSP_WRAP)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void SpinCtrlDoubleTestCase::tearDown()
|
||||
{
|
||||
wxDELETE(m_spin);
|
||||
}
|
||||
|
||||
void SpinCtrlDoubleTestCase::NoEventsInCtor()
|
||||
TEST_CASE("SpinCtrlDouble::NoEventsInCtor", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
// Verify that creating the control does not generate any events. This is
|
||||
// unexpected and shouldn't happen.
|
||||
wxWindow* const parent = m_spin->GetParent();
|
||||
delete m_spin;
|
||||
m_spin = new wxSpinCtrlDouble;
|
||||
wxSpinCtrlDouble *m_spin = new wxSpinCtrlDouble;
|
||||
|
||||
EventCounter updatedSpin(m_spin, wxEVT_SPINCTRLDOUBLE);
|
||||
EventCounter updatedText(m_spin, wxEVT_TEXT);
|
||||
|
||||
m_spin->Create(parent, wxID_ANY, "",
|
||||
m_spin->Create(wxTheApp->GetTopWindow(), wxID_ANY, "",
|
||||
wxDefaultPosition, wxDefaultSize, 0,
|
||||
0., 100., 17.);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0, updatedSpin.GetCount());
|
||||
CPPUNIT_ASSERT_EQUAL(0, updatedText.GetCount());
|
||||
CHECK( updatedSpin.GetCount() == 0 );
|
||||
CHECK( updatedText.GetCount() == 0 );
|
||||
}
|
||||
|
||||
void SpinCtrlDoubleTestCase::Arrows()
|
||||
{
|
||||
#if wxUSE_UIACTIONSIMULATOR
|
||||
|
||||
TEST_CASE_METHOD(SpinCtrlDoubleTestCase,
|
||||
"SpinCtrlDouble::Arrows", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
EventCounter updated(m_spin, wxEVT_SPINCTRLDOUBLE);
|
||||
|
||||
wxUIActionSimulator sim;
|
||||
@@ -99,26 +82,20 @@ void SpinCtrlDoubleTestCase::Arrows()
|
||||
sim.Char(WXK_UP);
|
||||
wxYield();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, updated.GetCount());
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_spin->GetValue());
|
||||
CHECK( updated.GetCount() == 1 );
|
||||
CHECK( m_spin->GetValue() == 1.0 );
|
||||
updated.Clear();
|
||||
|
||||
sim.Char(WXK_DOWN);
|
||||
wxYield();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(1, updated.GetCount());
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetValue());
|
||||
#endif
|
||||
CHECK( updated.GetCount() == 1 );
|
||||
CHECK( m_spin->GetValue() == 0.0 );
|
||||
}
|
||||
|
||||
void SpinCtrlDoubleTestCase::Wrap()
|
||||
TEST_CASE_METHOD(SpinCtrlDoubleTestCaseWrap,
|
||||
"SpinCtrlDouble::Wrap", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
#if wxUSE_UIACTIONSIMULATOR
|
||||
wxDELETE(m_spin);
|
||||
m_spin = new wxSpinCtrlDouble(wxTheApp->GetTopWindow(), wxID_ANY, "",
|
||||
wxDefaultPosition, wxDefaultSize,
|
||||
wxSP_ARROW_KEYS | wxSP_WRAP);
|
||||
|
||||
wxUIActionSimulator sim;
|
||||
|
||||
m_spin->SetFocus();
|
||||
@@ -128,20 +105,21 @@ void SpinCtrlDoubleTestCase::Wrap()
|
||||
|
||||
wxYield();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(100.0, m_spin->GetValue());
|
||||
CHECK( m_spin->GetValue() == 100.0 );
|
||||
|
||||
sim.Char(WXK_UP);
|
||||
|
||||
wxYield();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetValue());
|
||||
#endif
|
||||
CHECK( m_spin->GetValue() == 0.0 );
|
||||
}
|
||||
#endif // wxUSE_UIACTIONSIMULATOR
|
||||
|
||||
void SpinCtrlDoubleTestCase::Range()
|
||||
TEST_CASE_METHOD(SpinCtrlDoubleTestCase,
|
||||
"SpinCtrlDouble::Range", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetMin());
|
||||
CPPUNIT_ASSERT_EQUAL(100.0, m_spin->GetMax());
|
||||
CHECK( m_spin->GetMin() == 0.0 );
|
||||
CHECK( m_spin->GetMax() == 100.0 );
|
||||
|
||||
// Test that the value is adjusted to be inside the new valid range but
|
||||
// that this doesn't result in any events (as this is not something done by
|
||||
@@ -151,26 +129,27 @@ void SpinCtrlDoubleTestCase::Range()
|
||||
EventCounter updatedText(m_spin, wxEVT_TEXT);
|
||||
|
||||
m_spin->SetRange(1., 10.);
|
||||
CPPUNIT_ASSERT_EQUAL(1., m_spin->GetValue());
|
||||
CHECK( m_spin->GetValue() == 1. );
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0, updatedSpin.GetCount());
|
||||
CPPUNIT_ASSERT_EQUAL(0, updatedText.GetCount());
|
||||
CHECK( updatedSpin.GetCount() == 0 );
|
||||
CHECK( updatedText.GetCount() == 0 );
|
||||
}
|
||||
|
||||
//Test negative ranges
|
||||
m_spin->SetRange(-10.0, 10.0);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(-10.0, m_spin->GetMin());
|
||||
CPPUNIT_ASSERT_EQUAL(10.0, m_spin->GetMax());
|
||||
CHECK( m_spin->GetMin() == -10.0 );
|
||||
CHECK( m_spin->GetMax() == 10.0 );
|
||||
|
||||
//Test backwards ranges
|
||||
m_spin->SetRange(75.0, 50.0);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(75.0, m_spin->GetMin());
|
||||
CPPUNIT_ASSERT_EQUAL(50.0, m_spin->GetMax());
|
||||
CHECK( m_spin->GetMin() == 75.0 );
|
||||
CHECK( m_spin->GetMax() == 50.0 );
|
||||
}
|
||||
|
||||
void SpinCtrlDoubleTestCase::Value()
|
||||
TEST_CASE_METHOD(SpinCtrlDoubleTestCase,
|
||||
"SpinCtrlDouble::Value", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
EventCounter updatedSpin(m_spin, wxEVT_SPINCTRLDOUBLE);
|
||||
EventCounter updatedText(m_spin, wxEVT_TEXT);
|
||||
@@ -178,28 +157,41 @@ void SpinCtrlDoubleTestCase::Value()
|
||||
m_spin->SetDigits(2);
|
||||
m_spin->SetIncrement(0.1);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0.0, m_spin->GetValue());
|
||||
CHECK( m_spin->GetValue() == 0.0 );
|
||||
|
||||
m_spin->SetValue(50.0);
|
||||
CPPUNIT_ASSERT_EQUAL(50.0, m_spin->GetValue());
|
||||
CHECK( m_spin->GetValue() == 50.0 );
|
||||
|
||||
m_spin->SetValue(49.1);
|
||||
CPPUNIT_ASSERT_EQUAL(49.1, m_spin->GetValue());
|
||||
CHECK( m_spin->GetValue() == 49.1 );
|
||||
|
||||
// Calling SetValue() shouldn't have generated any events.
|
||||
CPPUNIT_ASSERT_EQUAL(0, updatedSpin.GetCount());
|
||||
CPPUNIT_ASSERT_EQUAL(0, updatedText.GetCount());
|
||||
CHECK( updatedSpin.GetCount() == 0 );
|
||||
CHECK( updatedText.GetCount() == 0 );
|
||||
|
||||
// Also test that setting the text value works.
|
||||
CHECK( m_spin->GetTextValue() == "49.10" );
|
||||
|
||||
m_spin->SetValue("57.30");
|
||||
CHECK( m_spin->GetTextValue() == "57.30" );
|
||||
CHECK( m_spin->GetValue() == 57.3 );
|
||||
|
||||
m_spin->SetValue("");
|
||||
CHECK( m_spin->GetTextValue() == "" );
|
||||
CHECK( m_spin->GetValue() == 57.3 );
|
||||
}
|
||||
|
||||
void SpinCtrlDoubleTestCase::Increment()
|
||||
{
|
||||
#if wxUSE_UIACTIONSIMULATOR
|
||||
CPPUNIT_ASSERT_EQUAL(1.0, m_spin->GetIncrement());
|
||||
|
||||
TEST_CASE_METHOD(SpinCtrlDoubleTestCase,
|
||||
"SpinCtrlDouble::Increment", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
CHECK( m_spin->GetIncrement() == 1.0 );
|
||||
|
||||
m_spin->SetDigits(1);
|
||||
m_spin->SetIncrement(0.1);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0.1, m_spin->GetIncrement());
|
||||
CHECK( m_spin->GetIncrement() == 0.1 );
|
||||
|
||||
wxUIActionSimulator sim;
|
||||
|
||||
@@ -210,15 +202,17 @@ void SpinCtrlDoubleTestCase::Increment()
|
||||
|
||||
wxYield();
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(0.1, m_spin->GetValue());
|
||||
#endif
|
||||
CHECK( m_spin->GetValue() == 0.1 );
|
||||
}
|
||||
|
||||
void SpinCtrlDoubleTestCase::Digits()
|
||||
#endif // wxUSE_UIACTIONSIMULATOR
|
||||
|
||||
TEST_CASE_METHOD(SpinCtrlDoubleTestCase,
|
||||
"SpinCtrlDouble::Digits", "[spinctrl][spinctrldouble]")
|
||||
{
|
||||
m_spin->SetDigits(5);
|
||||
|
||||
CPPUNIT_ASSERT_EQUAL(5, m_spin->GetDigits());
|
||||
CHECK( m_spin->GetDigits() == 5 );
|
||||
}
|
||||
|
||||
static inline unsigned int GetInitialDigits(double inc)
|
||||
@@ -230,7 +224,7 @@ static inline unsigned int GetInitialDigits(double inc)
|
||||
return digits;
|
||||
}
|
||||
|
||||
TEST_CASE("SpinCtrlDoubleTestCase::InitialDigits", "[spinctrldouble][initialdigits]")
|
||||
TEST_CASE("SpinCtrlDouble::InitialDigits", "[spinctrldouble][initialdigits]")
|
||||
{
|
||||
REQUIRE(GetInitialDigits(15) == 0);
|
||||
REQUIRE(GetInitialDigits(10) == 0);
|
||||
|
||||
@@ -268,6 +268,17 @@ TEST_CASE_METHOD(SpinCtrlTestCase2, "SpinCtrl::Value", "[spinctrl]")
|
||||
// Calling SetValue() shouldn't have generated any events.
|
||||
CHECK(updatedSpin.GetCount() == 0);
|
||||
CHECK(updatedText.GetCount() == 0);
|
||||
|
||||
// Also test that setting the text value works.
|
||||
CHECK( m_spin->GetTextValue() == "100" );
|
||||
|
||||
m_spin->SetValue("57");
|
||||
CHECK( m_spin->GetTextValue() == "57" );
|
||||
CHECK( m_spin->GetValue() == 57 );
|
||||
|
||||
m_spin->SetValue("");
|
||||
CHECK( m_spin->GetTextValue() == "" );
|
||||
CHECK( m_spin->GetValue() == 57 );
|
||||
}
|
||||
|
||||
TEST_CASE_METHOD(SpinCtrlTestCase2, "SpinCtrl::Base", "[spinctrl]")
|
||||
|
||||
Reference in New Issue
Block a user