Improve best size determination for wxSpinCtrl

Use the range and the base to determine the widest value string and use
it to calculate the best size.
This commit is contained in:
Ilya Sinitsyn
2019-10-03 00:39:12 +07:00
committed by Vadim Zeitlin
parent 9ef1b1529d
commit 1be43ed67b
4 changed files with 46 additions and 34 deletions

View File

@@ -168,6 +168,9 @@ private:
// (up-down control) and the text control (buddy window).
int GetOverlap() const;
// Calculate the best size for the number with the given number of digits.
wxSize GetBestSizeFromDigitsCount(int digitsCount) const;
wxDECLARE_DYNAMIC_CLASS(wxSpinCtrl);
wxDECLARE_EVENT_TABLE();
wxDECLARE_NO_COPY_CLASS(wxSpinCtrl);

View File

@@ -143,6 +143,11 @@ namespace wxPrivate
// 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

View File

@@ -115,4 +115,17 @@ wxString wxPrivate::wxSpinCtrlFormatAsHex(long val, long maxVal)
return text;
}
wxSize wxPrivate::wxSpinCtrlGetBestSize(const wxControl* spin,
int minVal, int maxVal, int base)
{
const int lenMin = (base == 16 ?
wxSpinCtrlFormatAsHex(minVal, maxVal) :
wxString::Format("%d", minVal)).length();
const int lenMax = (base == 16 ?
wxSpinCtrlFormatAsHex(maxVal, maxVal) :
wxString::Format("%d", maxVal)).length();
const wxString largestString('8', wxMax(lenMin, lenMax));
return spin->GetSizeFromText(largestString);
}
#endif // wxUSE_SPINCTRL

View File

@@ -348,39 +348,6 @@ bool wxSpinCtrl::Create(wxWindow *parent,
if (!m_hasFont)
SetFont(GetDefaultAttributes().font);
// Finally deal with the size: notice that this can only be done now both
// windows are created and the text one is set up as buddy because
// UDM_SETBUDDY changes its size using some unknown algorithm, so setting
// the sizes earlier is useless.
const int bestSpinWidth = wxSpinButton::DoGetBestSize().x;
const int effectiveSpinWidth = bestSpinWidth - GetOverlap();
wxSize sizeCtrl(size);
if ( sizeCtrl.x <= 0 )
{
// DEFAULT_ITEM_WIDTH is the default width for the text control
sizeCtrl.x = FromDIP(DEFAULT_ITEM_WIDTH) + effectiveSpinWidth;
}
else if ( sizeCtrl.x <= effectiveSpinWidth )
{
wxLogDebug(wxS("wxSpinCtrl \"%s\": initial width %d is too small, ")
wxS("at least %d pixels needed."),
name, size.x, effectiveSpinWidth);
}
// adjust an invalid height for text control
if ( sizeCtrl.y <= 0 )
{
int cx, cy;
wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
sizeCtrl.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
}
// This will call our DoMoveWindow() and lay out the windows correctly.
SetInitialSize(sizeCtrl);
(void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);
// If the initial text value is actually a number, it overrides the
// "initial" argument specified later.
long initialFromText;
@@ -400,6 +367,22 @@ bool wxSpinCtrl::Create(wxWindow *parent,
SetValue(value);
m_blockEvent = false;
// Finally deal with the size: notice that this can only be done now both
// windows are created and the text one is set up as buddy because
// UDM_SETBUDDY changes its size using some unknown algorithm, so setting
// the sizes earlier is useless. Do it after setting the range and the base
// because GetBestSize() uses them.
if ( size.x > 0 && size.x < GetBestSize().x )
{
wxLogDebug(wxS("wxSpinCtrl \"%s\": initial width %d is too small, ")
wxS("at least %d pixels needed."),
name, size.x, GetBestSize().x);
}
SetInitialSize(size);
(void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);
return true;
}
@@ -439,10 +422,16 @@ bool wxSpinCtrl::SetBase(int base)
if ( !::SendMessage(GetHwnd(), UDM_SETBASE, base, 0) )
return false;
// DoGetBestSize uses the base.
InvalidateBestSize();
// Whether we need to be able enter "x" or not influences whether we should
// use ES_NUMBER for the buddy control.
UpdateBuddyStyle();
// Update the displayed text after changing the base it uses.
SetValue(GetValue());
return true;
}
@@ -559,6 +548,8 @@ void wxSpinCtrl::SetRange(int minVal, int maxVal)
wxSpinButton::SetRange(minVal, maxVal);
InvalidateBestSize();
UpdateBuddyStyle();
}
@@ -748,7 +739,7 @@ int wxSpinCtrl::GetOverlap() const
wxSize wxSpinCtrl::DoGetBestSize() const
{
return DoGetSizeFromTextSize(FromDIP(DEFAULT_ITEM_WIDTH));
return wxPrivate::wxSpinCtrlGetBestSize(this, GetMin(), GetMax(), GetBase());
}
wxSize wxSpinCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const