Allow using a different text value in wxGTK wxSpinCtrl
Make it possible to use a string value different from the numeric value, as wxMSW version allows this and some existing code depends on it. Closes #19140.
This commit is contained in:
@@ -74,6 +74,9 @@ public:
|
|||||||
virtual void GTKValueChanged() = 0;
|
virtual void GTKValueChanged() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
wxSpinCtrlGTKBase();
|
||||||
|
~wxSpinCtrlGTKBase();
|
||||||
|
|
||||||
double DoGetValue() const;
|
double DoGetValue() const;
|
||||||
double DoGetMin() const;
|
double DoGetMin() const;
|
||||||
double DoGetMax() const;
|
double DoGetMax() const;
|
||||||
@@ -98,6 +101,19 @@ protected:
|
|||||||
// override this and return true.
|
// override this and return true.
|
||||||
virtual bool UseGTKStyleBase() const wxOVERRIDE { return true; }
|
virtual bool UseGTKStyleBase() const wxOVERRIDE { return true; }
|
||||||
|
|
||||||
|
// Set or reset m_textOverride.
|
||||||
|
void GTKSetTextOverride(const wxString& text);
|
||||||
|
void GTKResetTextOverride();
|
||||||
|
|
||||||
|
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;
|
friend class wxSpinCtrlEventDisabler;
|
||||||
|
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
|
@@ -127,6 +127,22 @@ private:
|
|||||||
wxDECLARE_NO_COPY_CLASS(wxSpinCtrlEventDisabler);
|
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
|
// wxSpinCtrlGTKBase
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -135,6 +151,54 @@ wxBEGIN_EVENT_TABLE(wxSpinCtrlGTKBase, wxSpinCtrlBase)
|
|||||||
EVT_CHAR(wxSpinCtrlGTKBase::OnChar)
|
EVT_CHAR(wxSpinCtrlGTKBase::OnChar)
|
||||||
wxEND_EVENT_TABLE()
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wxSpinCtrlGTKBase::GTKResetTextOverride()
|
||||||
|
{
|
||||||
|
if ( !m_textOverride )
|
||||||
|
return;
|
||||||
|
|
||||||
|
delete m_textOverride;
|
||||||
|
m_textOverride = NULL;
|
||||||
|
|
||||||
|
// 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,
|
bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id,
|
||||||
const wxString& value,
|
const wxString& value,
|
||||||
const wxPoint& pos, const wxSize& size,
|
const wxPoint& pos, const wxSize& size,
|
||||||
@@ -188,6 +252,15 @@ bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
double wxSpinCtrlGTKBase::DoGetValue() const
|
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") );
|
wxCHECK_MSG( (m_widget != NULL), 0, wxT("invalid spin button") );
|
||||||
|
|
||||||
@@ -269,7 +342,12 @@ void wxSpinCtrlGTKBase::SetValue( const wxString& value )
|
|||||||
return;
|
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);
|
wxSpinCtrlEventDisabler disable(this);
|
||||||
gtk_entry_set_text( GTK_ENTRY(m_widget), wxGTK_CONV( value ) );
|
gtk_entry_set_text( GTK_ENTRY(m_widget), wxGTK_CONV( value ) );
|
||||||
}
|
}
|
||||||
@@ -278,6 +356,8 @@ void wxSpinCtrlGTKBase::DoSetValue( double value )
|
|||||||
{
|
{
|
||||||
wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") );
|
wxCHECK_RET( (m_widget != NULL), wxT("invalid spin button") );
|
||||||
|
|
||||||
|
GTKResetTextOverride();
|
||||||
|
|
||||||
wxSpinCtrlEventDisabler disable(this);
|
wxSpinCtrlEventDisabler disable(this);
|
||||||
gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget), value);
|
gtk_spin_button_set_value( GTK_SPIN_BUTTON(m_widget), value);
|
||||||
}
|
}
|
||||||
@@ -424,6 +504,28 @@ wxSpinCtrlGTKBase::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
|
|||||||
return GetDefaultAttributesFromGTKWidget(gtk_spin_button_new_with_range(0, 100, 1), true);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// wxSpinCtrl
|
// wxSpinCtrl
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
@@ -470,9 +572,12 @@ bool wxSpinCtrl::SetBase(int base)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSpinCtrl::GTKInputResult
|
wxSpinCtrl::GTKInputResult wxSpinCtrl::GTKInput(double* value) const
|
||||||
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.
|
// Don't override the default logic unless really needed.
|
||||||
if ( GetBase() == 10 )
|
if ( GetBase() == 10 )
|
||||||
return GTKInput_Default;
|
return GTKInput_Default;
|
||||||
@@ -488,6 +593,9 @@ wxSpinCtrl::GTKInput(double* value) const
|
|||||||
|
|
||||||
bool wxSpinCtrl::GTKOutput(wxString* text) const
|
bool wxSpinCtrl::GTKOutput(wxString* text) const
|
||||||
{
|
{
|
||||||
|
if ( wxSpinCtrlGTKBase::GTKOutput(text) )
|
||||||
|
return true;
|
||||||
|
|
||||||
switch ( GetBase() )
|
switch ( GetBase() )
|
||||||
{
|
{
|
||||||
default:
|
default:
|
||||||
@@ -510,6 +618,8 @@ bool wxSpinCtrl::GTKOutput(wxString* text) const
|
|||||||
|
|
||||||
void wxSpinCtrl::GTKValueChanged()
|
void wxSpinCtrl::GTKValueChanged()
|
||||||
{
|
{
|
||||||
|
GTKResetTextOverride();
|
||||||
|
|
||||||
wxSpinEvent event(wxEVT_SPINCTRL, GetId());
|
wxSpinEvent event(wxEVT_SPINCTRL, GetId());
|
||||||
event.SetEventObject( this );
|
event.SetEventObject( this );
|
||||||
event.SetPosition(GetValue());
|
event.SetPosition(GetValue());
|
||||||
@@ -551,19 +661,23 @@ void wxSpinCtrlDouble::SetDigits(unsigned digits)
|
|||||||
GtkSetEntryWidth();
|
GtkSetEntryWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
wxSpinCtrl::GTKInputResult
|
wxSpinCtrl::GTKInputResult wxSpinCtrlDouble::GTKInput(double* value) const
|
||||||
wxSpinCtrlDouble::GTKInput(double* WXUNUSED(value)) const
|
|
||||||
{
|
{
|
||||||
return GTKInput_Default;
|
return wxSpinCtrlGTKBase::GTKInput(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxSpinCtrlDouble::GTKOutput(wxString* WXUNUSED(text)) const
|
bool wxSpinCtrlDouble::GTKOutput(wxString* text) const
|
||||||
{
|
{
|
||||||
|
if ( wxSpinCtrlGTKBase::GTKOutput(text) )
|
||||||
|
return true;
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxSpinCtrlDouble::GTKValueChanged()
|
void wxSpinCtrlDouble::GTKValueChanged()
|
||||||
{
|
{
|
||||||
|
GTKResetTextOverride();
|
||||||
|
|
||||||
wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, GetId());
|
wxSpinDoubleEvent event( wxEVT_SPINCTRLDOUBLE, GetId());
|
||||||
event.SetEventObject( this );
|
event.SetEventObject( this );
|
||||||
event.SetValue(GetValue());
|
event.SetValue(GetValue());
|
||||||
|
@@ -168,6 +168,17 @@ TEST_CASE_METHOD(SpinCtrlDoubleTestCase,
|
|||||||
// Calling SetValue() shouldn't have generated any events.
|
// Calling SetValue() shouldn't have generated any events.
|
||||||
CHECK( updatedSpin.GetCount() == 0 );
|
CHECK( updatedSpin.GetCount() == 0 );
|
||||||
CHECK( updatedText.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 );
|
||||||
}
|
}
|
||||||
|
|
||||||
#if wxUSE_UIACTIONSIMULATOR
|
#if wxUSE_UIACTIONSIMULATOR
|
||||||
|
@@ -268,6 +268,17 @@ TEST_CASE_METHOD(SpinCtrlTestCase2, "SpinCtrl::Value", "[spinctrl]")
|
|||||||
// Calling SetValue() shouldn't have generated any events.
|
// Calling SetValue() shouldn't have generated any events.
|
||||||
CHECK(updatedSpin.GetCount() == 0);
|
CHECK(updatedSpin.GetCount() == 0);
|
||||||
CHECK(updatedText.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]")
|
TEST_CASE_METHOD(SpinCtrlTestCase2, "SpinCtrl::Base", "[spinctrl]")
|
||||||
|
Reference in New Issue
Block a user