Avoid using DTM_GETIDEALSIZE with DTS_SHOWNONE
This message is completely broken when DTS_SHOWNONE is used, it returns wrong result (less than the size without DTS_SHOWNONE) initially and completely wrong results after a DPI change. Create a temporary date time picker control without DTS_SHOWNONE and call DTM_GETIDEALSIZE for it instead. This is wasteful, but at least returns correct results. This commit is best viewed ignoring whitespace-only changes.
This commit is contained in:
@@ -164,24 +164,66 @@ wxSize wxDateTimePickerCtrl::DoGetBestSize() const
|
|||||||
{
|
{
|
||||||
wxSize size;
|
wxSize size;
|
||||||
|
|
||||||
// We can ask the control itself to compute its ideal size, but we only use
|
// Use DTM_GETIDEALSIZE to ask the control itself to compute its ideal size.
|
||||||
// it for the horizontal component: the vertical size is not computed
|
SIZE idealSize = { 0, 0 };
|
||||||
// correctly after the DPI of the window has changed because for every DPI
|
if ( wxGetWinVersion() >= wxWinVersion_Vista )
|
||||||
// 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;
|
// We can't use DTM_GETIDEALSIZE with DTS_SHOWNONE because handling of
|
||||||
size.y = GetCharHeight();
|
// 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else // Compute the size ourselves.
|
|
||||||
|
if ( !idealSize.cx ) // Compute the size ourselves.
|
||||||
{
|
{
|
||||||
// Use the same native format as the underlying native control.
|
// Use the same native format as the underlying native control.
|
||||||
#if wxUSE_INTL
|
#if wxUSE_INTL
|
||||||
@@ -202,16 +244,13 @@ wxSize wxDateTimePickerCtrl::DoGetBestSize() const
|
|||||||
size.x += wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_X, m_parent);
|
size.x += wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_X, m_parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to account for the checkbox, if we have one -- DTM_GETIDEALSIZE
|
// Account for the checkbox.
|
||||||
// doesn't take it into account (actually, it somehow returns _smaller_
|
|
||||||
// size when using DTS_SHOWNONE than when not using it, which doesn't make
|
|
||||||
// any sense at all).
|
|
||||||
if ( MSWAllowsNone() )
|
if ( MSWAllowsNone() )
|
||||||
{
|
{
|
||||||
// The extra 10px here was determined heuristically as the value which
|
// The extra 8px here was determined heuristically as the value which
|
||||||
// results in the same layout with and without DTS_SHOWNONE under
|
// results in the same layout with and without DTS_SHOWNONE under
|
||||||
// Windows 7 and Windows 10 with 100%, 150% and 200% scaling.
|
// Windows 7 and Windows 10 with 100%, 150% and 200% scaling.
|
||||||
size.x += wxGetSystemMetrics(SM_CXMENUCHECK, m_parent) + 10;
|
size.x += wxGetSystemMetrics(SM_CXMENUCHECK, m_parent) + 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
int scrollY = wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_Y, m_parent);
|
int scrollY = wxSystemSettings::GetMetric(wxSYS_HSCROLL_ARROW_Y, m_parent);
|
||||||
|
Reference in New Issue
Block a user