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:
committed by
Vadim Zeitlin
parent
8e47b3ca97
commit
05b980aba1
@@ -141,6 +141,7 @@ wxMSW:
|
|||||||
- Add support for building with Microsoft Visual Studio 2017 (Tobias Taschner).
|
- Add support for building with Microsoft Visual Studio 2017 (Tobias Taschner).
|
||||||
- Enable wxStackWalker in MinGW64 builds.
|
- Enable wxStackWalker in MinGW64 builds.
|
||||||
- Fix crash when using wxCHMHelpController() in 64 bit builds (Xlord2).
|
- 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 MDI menu display after failure to create a child frame (troelsk).
|
||||||
- Fix wxScreenDC::GetSize() with multiple monitors (iwbnwif).
|
- Fix wxScreenDC::GetSize() with multiple monitors (iwbnwif).
|
||||||
- Fix background colour returned by wxTextCtrl::GetStyle() (Andreas Falkenhahn).
|
- Fix background colour returned by wxTextCtrl::GetStyle() (Andreas Falkenhahn).
|
||||||
|
@@ -159,6 +159,9 @@ private:
|
|||||||
// hexadecimal prefix, ...) in it.
|
// hexadecimal prefix, ...) in it.
|
||||||
void UpdateBuddyStyle();
|
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_DYNAMIC_CLASS(wxSpinCtrl);
|
||||||
wxDECLARE_EVENT_TABLE();
|
wxDECLARE_EVENT_TABLE();
|
||||||
|
@@ -94,7 +94,8 @@ bool wxSpinButton::Create(wxWindow *parent,
|
|||||||
// translate the styles
|
// translate the styles
|
||||||
DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | /* WS_CLIPSIBLINGS | */
|
DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | /* WS_CLIPSIBLINGS | */
|
||||||
UDS_NOTHOUSANDS | // never useful, sometimes harmful
|
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 )
|
if ( m_windowStyle & wxCLIP_SIBLINGS )
|
||||||
wstyle |= WS_CLIPSIBLINGS;
|
wstyle |= WS_CLIPSIBLINGS;
|
||||||
|
@@ -55,15 +55,6 @@ wxEND_EVENT_TABLE()
|
|||||||
|
|
||||||
#define GetBuddyHwnd() (HWND)(m_hwndBuddy)
|
#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
|
// global vars
|
||||||
@@ -278,9 +269,7 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
|||||||
int min, int max, int initial,
|
int min, int max, int initial,
|
||||||
const wxString& name)
|
const wxString& name)
|
||||||
{
|
{
|
||||||
// before using DoGetBestSize(), have to set style to let the base class
|
// set style for the base class
|
||||||
// know whether this is a horizontal or vertical control (we're always
|
|
||||||
// vertical)
|
|
||||||
style |= wxSP_VERTICAL;
|
style |= wxSP_VERTICAL;
|
||||||
|
|
||||||
if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
|
if ( (style & wxBORDER_MASK) == wxBORDER_DEFAULT )
|
||||||
@@ -301,27 +290,6 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
|||||||
else if ( style & wxALIGN_CENTER )
|
else if ( style & wxALIGN_CENTER )
|
||||||
msStyle |= ES_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
|
// 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
|
// 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
|
// 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
|
// 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;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -366,28 +334,46 @@ bool wxSpinCtrl::Create(wxWindow *parent,
|
|||||||
m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
|
m_wndProcBuddy = (WXFARPROC)wxSetWindowProc(GetBuddyHwnd(),
|
||||||
wxBuddyTextWndProc);
|
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)
|
// set up fonts and colours (This is nomally done in MSWCreateControl)
|
||||||
InheritAttributes();
|
InheritAttributes();
|
||||||
if (!m_hasFont)
|
if (!m_hasFont)
|
||||||
SetFont(GetDefaultAttributes().font);
|
SetFont(GetDefaultAttributes().font);
|
||||||
|
|
||||||
// set the size of the text window - can do it only now, because we
|
// finally deal with the size, now that both windows are created and the
|
||||||
// couldn't call DoGetBestSize() before as font wasn't set
|
// font is set
|
||||||
if ( sizeText.y <= 0 )
|
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;
|
int cx, cy;
|
||||||
wxGetCharSize(GetHWND(), &cx, &cy, GetFont());
|
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);
|
(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
|
// If the initial text value is actually a number, it overrides the
|
||||||
// "initial" argument specified later.
|
// "initial" argument specified later.
|
||||||
long initialFromText;
|
long initialFromText;
|
||||||
@@ -632,7 +618,7 @@ bool wxSpinCtrl::Reparent(wxWindowBase *newParent)
|
|||||||
|
|
||||||
// create and initialize the new one
|
// create and initialize the new one
|
||||||
if ( !wxSpinButton::Create(GetParent(), GetId(),
|
if ( !wxSpinButton::Create(GetParent(), GetId(),
|
||||||
rect.GetPosition(), rect.GetSize(),
|
wxPoint(0, 0), wxSize(0, 0), // it will have a buddy
|
||||||
GetWindowStyle(), GetName()) )
|
GetWindowStyle(), GetName()) )
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -640,14 +626,14 @@ bool wxSpinCtrl::Reparent(wxWindowBase *newParent)
|
|||||||
wxSpinButton::SetValue(GetValue());
|
wxSpinButton::SetValue(GetValue());
|
||||||
SetRange(m_min, m_max);
|
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
|
// associate it with the buddy control again
|
||||||
::SetParent(GetBuddyHwnd(), GetHwndOf(GetParent()));
|
::SetParent(GetBuddyHwnd(), GetHwndOf(GetParent()));
|
||||||
(void)::SendMessage(GetHwnd(), UDM_SETBUDDY, (WPARAM)GetBuddyHwnd(), 0);
|
(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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -732,6 +718,21 @@ bool wxSpinCtrl::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM *re
|
|||||||
// size calculations
|
// 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
|
wxSize wxSpinCtrl::DoGetBestSize() const
|
||||||
{
|
{
|
||||||
return DoGetSizeFromTextSize(DEFAULT_ITEM_WIDTH);
|
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
|
// that's too big. So never use the height calculated
|
||||||
// from wxSpinButton::DoGetBestSize().
|
// 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));
|
EDIT_HEIGHT_FROM_CHAR_HEIGHT(y));
|
||||||
|
|
||||||
// Check if the user requested a non-standard height.
|
// 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)
|
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 widthBtn = wxSpinButton::DoGetBestSize().x;
|
||||||
int widthText = width - widthBtn - MARGIN_BETWEEN;
|
int widthText = width - widthBtn + overlap;
|
||||||
|
|
||||||
if ( widthText < 0 )
|
if ( widthText < 0 )
|
||||||
{
|
{
|
||||||
// This can happen during the initial window layout when it's total
|
// 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;
|
widthText = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( widthBtn > width )
|
||||||
|
widthBtn = width;
|
||||||
|
|
||||||
// Because both subcontrols are positioned relatively
|
// Because both subcontrols are positioned relatively
|
||||||
// to the parent which can have different layout direction
|
// to the parent which can have different layout direction
|
||||||
// then our control, we need to mirror their positions manually.
|
// 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);
|
DoMoveSibling(m_hwndBuddy, x, y, widthText, height);
|
||||||
|
|
||||||
// 2) The button window
|
// 2) The button window
|
||||||
if ( widthText > 0 )
|
wxSpinButton::DoMoveWindow(x + widthText - overlap, y, widthBtn, height);
|
||||||
x += widthText + MARGIN_BETWEEN;
|
|
||||||
wxSpinButton::DoMoveWindow(x, y, widthBtn, height);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -796,8 +801,7 @@ void wxSpinCtrl::DoMoveWindow(int x, int y, int width, int height)
|
|||||||
wxSpinButton::DoMoveWindow(x, y, widthBtn, height);
|
wxSpinButton::DoMoveWindow(x, y, widthBtn, height);
|
||||||
|
|
||||||
// 2) The buddy window
|
// 2) The buddy window
|
||||||
x += widthBtn + MARGIN_BETWEEN;
|
DoMoveSibling(m_hwndBuddy, x + widthBtn - overlap, y, widthText, height);
|
||||||
DoMoveSibling(m_hwndBuddy, x, y, widthText, height);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user