Fix wxMSW wxSpinCtrl appearance: show arrows inside the control
As recommended in the "Spin Controls" MSDN documentation (see https://msdn.microsoft.com/en-us/library/windows/desktop/dn742439.aspx), put the spin control inside the associated "buddy" edit control and not near it. Closes #12297. Closes https://github.com/wxWidgets/wxWidgets/pull/410
This commit is contained in:
parent
8e47b3ca97
commit
05b980aba1
@ -141,6 +141,7 @@ wxMSW:
|
||||
- Add support for building with Microsoft Visual Studio 2017 (Tobias Taschner).
|
||||
- Enable wxStackWalker in MinGW64 builds.
|
||||
- Fix crash when using wxCHMHelpController() in 64 bit builds (Xlord2).
|
||||
- Fix wxSpinCtrl appearance: show arrows inside the control (Catalin Raceanu).
|
||||
- Fix MDI menu display after failure to create a child frame (troelsk).
|
||||
- Fix wxScreenDC::GetSize() with multiple monitors (iwbnwif).
|
||||
- Fix background colour returned by wxTextCtrl::GetStyle() (Andreas Falkenhahn).
|
||||
|
@ -159,6 +159,9 @@ private:
|
||||
// hexadecimal prefix, ...) in it.
|
||||
void UpdateBuddyStyle();
|
||||
|
||||
// Determine the (horizontal) pixel overlap between the spin button
|
||||
// (up-down control) and the text control (buddy window).
|
||||
int GetOverlap() const;
|
||||
|
||||
wxDECLARE_DYNAMIC_CLASS(wxSpinCtrl);
|
||||
wxDECLARE_EVENT_TABLE();
|
||||
|
@ -94,7 +94,8 @@ bool wxSpinButton::Create(wxWindow *parent,
|
||||
// translate the styles
|
||||
DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | /* WS_CLIPSIBLINGS | */
|
||||
UDS_NOTHOUSANDS | // never useful, sometimes harmful
|
||||
UDS_SETBUDDYINT; // it doesn't harm if we don't have buddy
|
||||
UDS_ALIGNRIGHT | // these styles are effectively used only
|
||||
UDS_SETBUDDYINT; // by wxSpinCtrl but do no harm otherwise
|
||||
|
||||
if ( m_windowStyle & wxCLIP_SIBLINGS )
|
||||
wstyle |= WS_CLIPSIBLINGS;
|
||||
|
@ -55,15 +55,6 @@ wxEND_EVENT_TABLE()
|
||||
|
||||
#define GetBuddyHwnd() (HWND)(m_hwndBuddy)
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// constants
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
// the margin between the up-down control and its buddy (can be arbitrary,
|
||||
// choose what you like - or may be decide during run-time depending on the
|
||||
// font size?)
|
||||
static const int MARGIN_BETWEEN = 1;
|
||||
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// global vars
|
||||
@ -278,9 +269,7 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
||||
int min, int max, int initial,
|
||||
const wxString& name)
|
||||
{
|
||||
// before using DoGetBestSize(), have to set style to let the base class
|
||||
// know whether this is a horizontal or vertical control (we're always
|
||||
// vertical)
|
||||
// set style for the base class
|
||||
style |= wxSP_VERTICAL;
|
||||
|
||||
if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
|
||||
@ -301,27 +290,6 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
||||
else if ( style & wxALIGN_CENTER )
|
||||
msStyle |= ES_CENTER;
|
||||
|
||||
// calculate the sizes: the size given is the total size for both controls
|
||||
// and we need to fit them both in the given width (height is the same)
|
||||
wxSize sizeText(size), sizeBtn(size);
|
||||
sizeBtn.x = wxSpinButton::DoGetBestSize().x;
|
||||
if ( sizeText.x <= 0 )
|
||||
{
|
||||
// DEFAULT_ITEM_WIDTH is the default width for the text control
|
||||
sizeText.x = FromDIP(DEFAULT_ITEM_WIDTH) + MARGIN_BETWEEN + sizeBtn.x;
|
||||
}
|
||||
|
||||
sizeText.x -= sizeBtn.x + MARGIN_BETWEEN;
|
||||
if ( sizeText.x <= 0 )
|
||||
{
|
||||
wxLogDebug(wxS("wxSpinCtrl \"%s\": initial width %d is too small, ")
|
||||
wxS("at least %d pixels needed."),
|
||||
name, size.x, sizeBtn.x + MARGIN_BETWEEN + 1);
|
||||
}
|
||||
|
||||
wxPoint posBtn(pos);
|
||||
posBtn.x += sizeText.x + MARGIN_BETWEEN;
|
||||
|
||||
// we must create the text control before the spin button for the purpose
|
||||
// of the dialog navigation: if there is a static text just before the spin
|
||||
// control, activating it by Alt-letter should give focus to the text
|
||||
@ -353,7 +321,7 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
||||
|
||||
|
||||
// create the spin button
|
||||
if ( !wxSpinButton::Create(parent, id, posBtn, sizeBtn, style, name) )
|
||||
if ( !wxSpinButton::Create(parent, id, wxPoint(0, 0), wxSize(0, 0), style, name) )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -366,28 +334,46 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
||||
m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
|
||||
wxBuddyTextWndProc);
|
||||
|
||||
// associate the text window with the spin button
|
||||
(void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0);
|
||||
|
||||
// set up fonts and colours (This is nomally done in MSWCreateControl)
|
||||
InheritAttributes();
|
||||
if (!m_hasFont)
|
||||
SetFont(GetDefaultAttributes().font);
|
||||
|
||||
// set the size of the text window - can do it only now, because we
|
||||
// couldn't call DoGetBestSize() before as font wasn't set
|
||||
if ( sizeText.y <= 0 )
|
||||
// finally deal with the size, now that both windows are created and the
|
||||
// font is set
|
||||
const wxSize sizeBtn = wxSpinButton::DoGetBestSize();
|
||||
const int effectiveBtnWidth = sizeBtn.x - 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) + effectiveBtnWidth;
|
||||
}
|
||||
else if ( sizeCtrl.x <= effectiveBtnWidth )
|
||||
{
|
||||
wxLogDebug(wxS("wxSpinCtrl \"%s\": initial width %d is too small, ")
|
||||
wxS("at least %d pixels needed."),
|
||||
name, size.x, effectiveBtnWidth);
|
||||
}
|
||||
{
|
||||
}
|
||||
|
||||
// adjust an invalid height for text control
|
||||
if ( sizeCtrl.y <= 0 )
|
||||
{
|
||||
int cx, cy;
|
||||
wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
|
||||
|
||||
sizeText.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
|
||||
sizeCtrl.y = EDIT_HEIGHT_FROM_CHAR_HEIGHT(cy);
|
||||
}
|
||||
|
||||
SetInitialSize(size);
|
||||
SetInitialSize(sizeCtrl);
|
||||
|
||||
(void)::ShowWindow(GetBuddyHwnd(), SW_SHOW);
|
||||
|
||||
// associate the text window with the spin button
|
||||
(void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)m_hwndBuddy, 0);
|
||||
|
||||
// If the initial text value is actually a number, it overrides the
|
||||
// "initial" argument specified later.
|
||||
long initialFromText;
|
||||
@ -632,7 +618,7 @@ bool wxSpinCtrl::Reparent(wxWindowBase *newParent)
|
||||
|
||||
// create and initialize the new one
|
||||
if ( !wxSpinButton::Create(GetParent(), GetId(),
|
||||
rect.GetPosition(), rect.GetSize(),
|
||||
wxPoint(0, 0), wxSize(0, 0), // it will have a buddy
|
||||
GetWindowStyle(), GetName()) )
|
||||
return false;
|
||||
|
||||
@ -640,14 +626,14 @@ bool wxSpinCtrl::Reparent(wxWindowBase *newParent)
|
||||
wxSpinButton::SetValue(GetValue());
|
||||
SetRange(m_min, m_max);
|
||||
|
||||
// also set the size again with wxSIZE_ALLOW_MINUS_ONE flag: this is
|
||||
// necessary if our original position used -1 for either x or y
|
||||
SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
|
||||
|
||||
// associate it with the buddy control again
|
||||
::SetParent(GetBuddyHwnd(), GetHwndOf(GetParent()));
|
||||
(void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0);
|
||||
|
||||
// also set the size again with wxSIZE_ALLOW_MINUS_ONE flag: this is
|
||||
// necessary if our original position used -1 for either x or y
|
||||
SetSize(rect, wxSIZE_ALLOW_MINUS_ONE);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -732,6 +718,21 @@ bool wxSpinCtrl::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM *re
|
||||
// size calculations
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
int wxSpinCtrl::GetOverlap() const
|
||||
{
|
||||
if ( !GetHwnd() )
|
||||
{
|
||||
// We can be called from GetSizeFromTextSize() before the window is
|
||||
// created and still need to return something reasonable in this case,
|
||||
// so return the overlap equal to the default border size.
|
||||
return FromDIP(2);
|
||||
}
|
||||
|
||||
// The sign here is correct because the button is positioned inside its
|
||||
// buddy window.
|
||||
return wxGetWindowRect(m_hwndBuddy).right - wxGetWindowRect(GetHwnd()).left;
|
||||
}
|
||||
|
||||
wxSize wxSpinCtrl::DoGetBestSize() const
|
||||
{
|
||||
return DoGetSizeFromTextSize(DEFAULT_ITEM_WIDTH);
|
||||
@ -748,7 +749,7 @@ wxSize wxSpinCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
|
||||
// that's too big. So never use the height calculated
|
||||
// from wxSpinButton::DoGetBestSize().
|
||||
|
||||
wxSize tsize(xlen + sizeBtn.x + MARGIN_BETWEEN + 3*y/10 + 10,
|
||||
wxSize tsize(xlen + sizeBtn.x - GetOverlap(),
|
||||
EDIT_HEIGHT_FROM_CHAR_HEIGHT(y));
|
||||
|
||||
// Check if the user requested a non-standard height.
|
||||
@ -760,8 +761,11 @@ wxSize wxSpinCtrl::DoGetSizeFromTextSize(int xlen, int ylen) const
|
||||
|
||||
void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
|
||||
{
|
||||
// make sure the given width will be the total of both controls
|
||||
const int overlap = GetOverlap();
|
||||
int widthBtn = wxSpinButton::DoGetBestSize().x;
|
||||
int widthText = width - widthBtn - MARGIN_BETWEEN;
|
||||
int widthText = width - widthBtn + overlap;
|
||||
|
||||
if ( widthText < 0 )
|
||||
{
|
||||
// This can happen during the initial window layout when it's total
|
||||
@ -775,6 +779,9 @@ void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
|
||||
widthText = 0;
|
||||
}
|
||||
|
||||
if ( widthBtn > width )
|
||||
widthBtn = width;
|
||||
|
||||
// Because both subcontrols are positioned relatively
|
||||
// to the parent which can have different layout direction
|
||||
// then our control, we need to mirror their positions manually.
|
||||
@ -785,9 +792,7 @@ void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
|
||||
DoMoveSibling(m_hwndBuddy, x, y, widthText, height);
|
||||
|
||||
// 2) The button window
|
||||
if ( widthText > 0 )
|
||||
x += widthText + MARGIN_BETWEEN;
|
||||
wxSpinButton::DoMoveWindow(x, y, widthBtn, height);
|
||||
wxSpinButton::DoMoveWindow(x + widthText - overlap, y, widthBtn, height);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -796,8 +801,7 @@ void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
|
||||
wxSpinButton::DoMoveWindow(x, y, widthBtn, height);
|
||||
|
||||
// 2) The buddy window
|
||||
x += widthBtn + MARGIN_BETWEEN;
|
||||
DoMoveSibling(m_hwndBuddy, x, y, widthText, height);
|
||||
DoMoveSibling(m_hwndBuddy, x + widthBtn - overlap, y, widthText, height);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user