Merge branch 'msw-datepick-size'

Fix wxDatePickerCtrl best size in wxMSW when using wxDP_ALLOWNONE.

See https://github.com/wxWidgets/wxWidgets/pull/2297
This commit is contained in:
Vadim Zeitlin
2021-04-03 22:17:52 +01:00

View File

@@ -162,47 +162,95 @@ void wxDateTimePickerCtrl::SetNullText(const wxString& text)
wxSize wxDateTimePickerCtrl::DoGetBestSize() const
{
wxClientDC dc(const_cast<wxDateTimePickerCtrl *>(this));
wxSize size;
// Use the same native format as the underlying native control.
// Use DTM_GETIDEALSIZE to ask the control itself to compute its ideal size.
SIZE idealSize = { 0, 0 };
if ( wxGetWinVersion() >= wxWinVersion_Vista )
{
// We can't use DTM_GETIDEALSIZE with DTS_SHOWNONE because handling of
// this flag is completely broken (up to at least Window 10 20H2): it's
// not just ignored, but we get completely wrong results when this flag
// is on, e.g. the returned width is less than the width without it or
// much greater than the real value after a DPI change (and growing
// with every new change, even when repeatedly switching between the
// same DPI values, e.g. dragging a window between 2 monitors with
// different scaling). Moreover, note that even without DTS_SHOWNONE,
// DTM_GETIDEALSIZE still returns wrong results for the height after a
// DPI change, so we never use the vertical component of the value
// returned by it.
//
// Unfortunately, resetting this style doesn't work neither, so we have
// to create a whole new window just for this, which is pretty wasteful
// but seems unavoidable.
HWND hwnd;
if ( MSWAllowsNone() )
{
hwnd = ::CreateWindow
(
DATETIMEPICK_CLASS,
wxT(""),
::GetWindowLong(GetHwnd(), GWL_STYLE) & ~DTS_SHOWNONE,
0, 0, 1, 1,
GetHwndOf(m_parent),
0,
wxGetInstance(),
NULL
);
wxCHECK_MSG( hwnd, wxSize(),
wxS("SysDateTimePick32 creation unexpected failed") );
wxSetWindowFont(hwnd, GetFont());
}
else
{
hwnd = GetHwnd();
}
// Also work around https://bugs.winehq.org/show_bug.cgi?id=44680 by
// checking for the return value: even if all "real" MSW systems do support
// this message, Wine does not, even when it's configured to return Vista
// or later version to the application, and returns FALSE for it.
if ( ::SendMessage(hwnd, DTM_GETIDEALSIZE, 0, (LPARAM)&idealSize) )
{
size.x = idealSize.cx;
size.y = GetCharHeight();
}
if ( hwnd != GetHwnd() )
{
::DestroyWindow(hwnd);
}
}
if ( !idealSize.cx ) // Compute the size ourselves.
{
// Use the same native format as the underlying native control.
#if wxUSE_INTL
wxString s = wxDateTime::Now().Format(wxLocale::GetOSInfo(MSWGetFormat()));
wxString s = wxDateTime::Now().Format(wxLocale::GetOSInfo(MSWGetFormat()));
#else // !wxUSE_INTL
wxString s("XXX-YYY-ZZZZ");
wxString s("XXX-YYY-ZZZZ");
#endif // wxUSE_INTL/!wxUSE_INTL
// the best size for the control is bigger than just the string
// representation of the current value because the control must accommodate
// any date and while the widths of all digits are usually about the same,
// the width of the month string varies a lot, so try to account for it
s += wxS("W");
// the best size for the control is bigger than just the string
// representation of the current value because the control must accommodate
// any date and while the widths of all digits are usually about the same,
// the width of the month string varies a lot, so try to account for it
s += wxS("W");
wxSize size = dc.GetTextExtent(s);
size = GetTextExtent(s);
// We can ask the control itself to compute its ideal size, but we only use
// it for the horizontal component: the vertical size is not computed
// correctly after the DPI of the window has changed because for every DPI
// change, the returned size is 4 pixels higher, even if the DPI is
// lowered, so we always need to compute it ourselves below.
//
// Also work around https://bugs.winehq.org/show_bug.cgi?id=44680 by
// checking for the return value: even if all "real" MSW systems do support
// this message, Wine does not, even when it's configured to return Vista
// or later version to the application, and returns FALSE for it.
SIZE idealSize;
if ( wxGetWinVersion() >= wxWinVersion_Vista
&& ::SendMessage(m_hWnd, DTM_GETIDEALSIZE, 0, (LPARAM)&idealSize) )
{
size.x = idealSize.cx;
}
else // Adjust the size ourselves.
{
// Account for the drop-down arrow or spin arrows.
size.x += wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_X, m_parent);
}
// We need to account for the checkbox, if we have one.
if ( MSWAllowsNone() )
size.x += 3 * GetCharWidth();
// Account for the checkbox.
if ( MSWAllowsNone() )
{
// The extra 8px here was determined heuristically as the value which
// results in the same layout with and without DTS_SHOWNONE under
// Windows 7 and Windows 10 with 100%, 150% and 200% scaling.
size.x += wxGetSystemMetrics(SM_CXMENUCHECK, m_parent) + 8;
}
int scrollY = wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_Y, m_parent);