diff --git a/include/wx/gtk/spinctrl.h b/include/wx/gtk/spinctrl.h index be7e1013eb..0b96827dd6 100644 --- a/include/wx/gtk/spinctrl.h +++ b/include/wx/gtk/spinctrl.h @@ -71,7 +71,9 @@ protected: void GtkDisableEvents() const; void GtkEnableEvents() const; - virtual wxSize DoGetBestSize() const wxOVERRIDE; + // Update the number of digits used to match our range (and base). + void GtkSetEntryWidth(); + virtual wxSize DoGetSizeFromTextSize(int xlen, int ylen = -1) const wxOVERRIDE; virtual GdkWindow *GTKGetWindow(wxArrayGdkWindows& windows) const wxOVERRIDE; diff --git a/include/wx/private/spinctrl.h b/include/wx/private/spinctrl.h new file mode 100644 index 0000000000..af2ae47270 --- /dev/null +++ b/include/wx/private/spinctrl.h @@ -0,0 +1,31 @@ +/////////////////////////////////////////////////////////////////////////////// +// Name: wx/private/spinctrl.h +// Purpose: Private functions used in wxSpinCtrl implementation. +// Author: Vadim Zeitlin +// Created: 2019-11-13 +// Copyright: (c) 2019 Vadim Zeitlin +// Licence: wxWindows licence +/////////////////////////////////////////////////////////////////////////////// + +#ifndef _WX_PRIVATE_SPINCTRL_H_ +#define _WX_PRIVATE_SPINCTRL_H_ + +namespace wxSpinCtrlImpl +{ + +// This is an internal helper function currently used by all ports: return the +// string containing hexadecimal representation of the given number. +extern wxString FormatAsHex(long val, long maxVal); + +// Another helper returning the maximum length of a string representing a value +// valid in the given control. +extern int GetMaxValueLength(int minVal, int maxVal, int base); + +// The helper function to determine the best size for the given control. +// We can't implement this function in the wxSpinCtrlBase because MSW implementation +// of wxSpinCtrl is derived from wxSpinButton but uses the same algorithm. +extern wxSize GetBestSize(const wxControl* spin, int minVal, int maxVal, int base); + +} // namespace wxSpinCtrlImpl + +#endif // _WX_PRIVATE_SPINCTRL_H_ diff --git a/include/wx/spinctrl.h b/include/wx/spinctrl.h index 0051737fbc..775672f97b 100644 --- a/include/wx/spinctrl.h +++ b/include/wx/spinctrl.h @@ -136,19 +136,6 @@ typedef void (wxEvtHandler::*wxSpinDoubleEventFunction)(wxSpinDoubleEvent&); #if !defined(wxHAS_NATIVE_SPINCTRL) || !defined(wxHAS_NATIVE_SPINCTRLDOUBLE) #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); - -// The helper function to determine the best size for the given control. -// We can't implement this function in the wxSpinCtrlBase because MSW implementation -// of wxSpinCtrl is derived from wxSpinButton but uses the same algorithm. -extern wxSize wxSpinCtrlGetBestSize(const wxControl* spin, int minVal, int maxVal, int base); - -} // namespace wxPrivate // old wxEVT_COMMAND_* constants #define wxEVT_COMMAND_SPINCTRL_UPDATED wxEVT_SPINCTRL diff --git a/src/common/spinctrlcmn.cpp b/src/common/spinctrlcmn.cpp index 9598ef829d..7098ff1d04 100644 --- a/src/common/spinctrlcmn.cpp +++ b/src/common/spinctrlcmn.cpp @@ -25,6 +25,8 @@ #include "wx/spinbutt.h" #include "wx/spinctrl.h" +#include "wx/private/spinctrl.h" + #if wxUSE_SPINCTRL wxDEFINE_EVENT(wxEVT_SPINCTRL, wxSpinEvent); @@ -102,7 +104,9 @@ wxCONSTRUCTOR_6( wxSpinCtrl, wxWindow*, Parent, wxWindowID, Id, \ wxSize, Size, long, WindowStyle ) -wxString wxPrivate::wxSpinCtrlFormatAsHex(long val, long maxVal) +using namespace wxSpinCtrlImpl; + +wxString wxSpinCtrlImpl::FormatAsHex(long val, long maxVal) { // We format the value like this is for compatibility with (native // behaviour of) wxMSW @@ -115,16 +119,21 @@ wxString wxPrivate::wxSpinCtrlFormatAsHex(long val, long maxVal) return text; } -wxSize wxPrivate::wxSpinCtrlGetBestSize(const wxControl* spin, - int minVal, int maxVal, int base) +int wxSpinCtrlImpl::GetMaxValueLength(int minVal, int maxVal, int base) { const int lenMin = (base == 16 ? - wxSpinCtrlFormatAsHex(minVal, maxVal) : + FormatAsHex(minVal, maxVal) : wxString::Format("%d", minVal)).length(); const int lenMax = (base == 16 ? - wxSpinCtrlFormatAsHex(maxVal, maxVal) : + FormatAsHex(maxVal, maxVal) : wxString::Format("%d", maxVal)).length(); - const wxString largestString('8', wxMax(lenMin, lenMax)); + return wxMax(lenMin, lenMax); +} + +wxSize wxSpinCtrlImpl::GetBestSize(const wxControl* spin, + int minVal, int maxVal, int base) +{ + const wxString largestString('8', GetMaxValueLength(minVal, maxVal, base)); return spin->GetSizeFromText(largestString); } diff --git a/src/generic/spinctlg.cpp b/src/generic/spinctlg.cpp index b49c5db77b..0620948741 100644 --- a/src/generic/spinctlg.cpp +++ b/src/generic/spinctlg.cpp @@ -32,6 +32,8 @@ #if wxUSE_SPINCTRL +#include "wx/private/spinctrl.h" + wxIMPLEMENT_DYNAMIC_CLASS(wxSpinDoubleEvent, wxNotifyEvent); // There are port-specific versions for the wxSpinCtrl, so exclude the @@ -654,8 +656,7 @@ wxString wxSpinCtrl::DoValueToText(double val) switch ( GetBase() ) { case 16: - return wxPrivate::wxSpinCtrlFormatAsHex(static_cast(val), - GetMax()); + return wxSpinCtrlImpl::FormatAsHex(static_cast(val), GetMax()); default: wxFAIL_MSG( wxS("Unsupported spin control base") ); diff --git a/src/gtk/spinctrl.cpp b/src/gtk/spinctrl.cpp index eaeeea8b3c..a341b79752 100644 --- a/src/gtk/spinctrl.cpp +++ b/src/gtk/spinctrl.cpp @@ -16,10 +16,13 @@ #ifndef WX_PRECOMP #include "wx/textctrl.h" // for wxEVT_TEXT + #include "wx/math.h" // wxRound() #include "wx/utils.h" #include "wx/wxcrtvararg.h" #endif +#include "wx/private/spinctrl.h" + #include "wx/gtk/private.h" //----------------------------------------------------------------------------- @@ -135,6 +138,8 @@ bool wxSpinCtrlGTKBase::Create(wxWindow *parent, wxWindowID id, gtk_entry_set_alignment(GTK_ENTRY(m_widget), align); + GtkSetEntryWidth(); + gtk_spin_button_set_wrap( GTK_SPIN_BUTTON(m_widget), (int)(m_windowStyle & wxSP_WRAP) ); @@ -269,6 +274,8 @@ void wxSpinCtrlGTKBase::DoSetRange(double minVal, double maxVal) gtk_spin_button_set_range( GTK_SPIN_BUTTON(m_widget), minVal, maxVal); InvalidateBestSize(); + + GtkSetEntryWidth(); } void wxSpinCtrlGTKBase::DoSetIncrement(double inc) @@ -353,38 +360,35 @@ GdkWindow *wxSpinCtrlGTKBase::GTKGetWindow(wxArrayGdkWindows& windows) const return NULL; } -wxSize wxSpinCtrlGTKBase::DoGetBestSize() const +void wxSpinCtrlGTKBase::GtkSetEntryWidth() { const int minVal = static_cast(DoGetMin()); const int maxVal = static_cast(DoGetMax()); - return wxPrivate::wxSpinCtrlGetBestSize(this, minVal, maxVal, GetBase()); + + gtk_entry_set_width_chars + ( + GTK_ENTRY(m_widget), + wxSpinCtrlImpl::GetMaxValueLength(minVal, maxVal, GetBase()) + ); } wxSize wxSpinCtrlGTKBase::DoGetSizeFromTextSize(int xlen, int ylen) const { wxASSERT_MSG( m_widget, wxS("GetSizeFromTextSize called before creation") ); + // This is a bit stupid as we typically compute xlen by measuring some + // string of digits in the first place, but there doesn't seem to be + // anything better to do (unless we add some GetSizeFromNumberOfDigits()). + const double widthDigit = GetTextExtent("0123456789").GetWidth() / 10.0; + const int numDigits = wxRound(xlen / widthDigit); + const gint widthChars = gtk_entry_get_width_chars(GTK_ENTRY(m_widget)); - gtk_entry_set_width_chars(GTK_ENTRY(m_widget), 0); -#if GTK_CHECK_VERSION(3,12,0) - gint maxWidthChars = 0; - if ( gtk_check_version(3,12,0) == NULL ) - { - maxWidthChars = gtk_entry_get_max_width_chars(GTK_ENTRY(m_widget)); - gtk_entry_set_max_width_chars(GTK_ENTRY(m_widget), 0); - } -#endif // GTK+ 3.12+ + gtk_entry_set_width_chars(GTK_ENTRY(m_widget), numDigits); - wxSize totalS = GTKGetPreferredSize(m_widget); + wxSize tsize = GTKGetPreferredSize(m_widget); -#if GTK_CHECK_VERSION(3,12,0) - if ( gtk_check_version(3,12,0) == NULL ) - gtk_entry_set_max_width_chars(GTK_ENTRY(m_widget), maxWidthChars); -#endif // GTK+ 3.12+ gtk_entry_set_width_chars(GTK_ENTRY(m_widget), widthChars); - wxSize tsize(xlen + totalS.x, totalS.y); - // Check if the user requested a non-standard height. if ( ylen > 0 ) tsize.IncBy(0, ylen - GetCharHeight()); @@ -431,7 +435,7 @@ wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrl* win) gtk_entry_set_text ( GTK_ENTRY(spin), - wxPrivate::wxSpinCtrlFormatAsHex(val, win->GetMax()).utf8_str() + wxSpinCtrlImpl::FormatAsHex(val, win->GetMax()).utf8_str() ); return TRUE; @@ -474,6 +478,8 @@ bool wxSpinCtrl::SetBase(int base) InvalidateBestSize(); + GtkSetEntryWidth(); + // Update the displayed text after changing the base it uses. SetValue(GetValue()); diff --git a/src/gtk1/spinctrl.cpp b/src/gtk1/spinctrl.cpp index d462dbe0ca..98934ec791 100644 --- a/src/gtk1/spinctrl.cpp +++ b/src/gtk1/spinctrl.cpp @@ -21,6 +21,8 @@ #include "wx/crt.h" #endif +#include "wx/private/spinctrl.h" + #include "wx/gtk1/private.h" //----------------------------------------------------------------------------- @@ -69,7 +71,7 @@ wx_gtk_spin_output(GtkSpinButton* spin, wxSpinCtrl* win) gtk_entry_set_text ( GTK_ENTRY(spin), - wxPrivate::wxSpinCtrlFormatAsHex(val, win->GetMax()).utf8_str() + wxSpinCtrlImpl::FormatAsHex(val, win->GetMax()).utf8_str() ); return TRUE; diff --git a/src/msw/spinctrl.cpp b/src/msw/spinctrl.cpp index 321f6b11c5..f5f7c442f1 100644 --- a/src/msw/spinctrl.cpp +++ b/src/msw/spinctrl.cpp @@ -35,6 +35,8 @@ #include "wx/wxcrtvararg.h" #endif +#include "wx/private/spinctrl.h" + #include "wx/msw/private.h" #include "wx/msw/private/winstyle.h" @@ -474,7 +476,7 @@ void wxSpinCtrl::SetValue(int val) (text[1] != 'x' && text[1] != 'X')) ) { ::SetWindowText(GetBuddyHwnd(), - wxPrivate::wxSpinCtrlFormatAsHex(val, m_max).t_str()); + wxSpinCtrlImpl::FormatAsHex(val, m_max).t_str()); } m_oldValue = GetValue(); @@ -741,7 +743,7 @@ int wxSpinCtrl::GetOverlap() const wxSize wxSpinCtrl::DoGetBestSize() const { - return wxPrivate::wxSpinCtrlGetBestSize(this, GetMin(), GetMax(), GetBase()); + return wxSpinCtrlImpl::GetBestSize(this, GetMin(), GetMax(), GetBase()); } wxSize wxSpinCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const