From 918e102533f2a5e437beabec41da851b2d0f3cce Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Fri, 1 Nov 2019 21:07:15 +0100 Subject: [PATCH] Support DPI change in sizers Return the size of DoGetDefaultBorderInPx as float, so no precision is lost when multiplying it for DoubleBorder and TripleBorder. Closes #18551. --- include/wx/sizer.h | 17 +++++++++++------ interface/wx/sizer.h | 12 ++++++++++++ src/common/sizer.cpp | 9 ++++++--- src/msw/window.cpp | 31 +++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/include/wx/sizer.h b/include/wx/sizer.h index 0d4fdeac09..4a51b11c3f 100644 --- a/include/wx/sizer.h +++ b/include/wx/sizer.h @@ -106,6 +106,11 @@ public: // default border size used by Border() below static int GetDefaultBorder() + { + return wxRound(GetDefaultBorderFractional()); + } + + static float GetDefaultBorderFractional() { #if wxUSE_BORDER_BY_DEFAULT #ifdef __WXGTK20__ @@ -145,7 +150,7 @@ public: wxSizerFlags& Border(int direction = wxALL) { #if wxUSE_BORDER_BY_DEFAULT - return Border(direction, GetDefaultBorder()); + return Border(direction, wxRound(GetDefaultBorderFractional())); #else // no borders by default on limited size screen wxUnusedVar(direction); @@ -157,7 +162,7 @@ public: wxSizerFlags& DoubleBorder(int direction = wxALL) { #if wxUSE_BORDER_BY_DEFAULT - return Border(direction, 2*GetDefaultBorder()); + return Border(direction, wxRound(2 * GetDefaultBorderFractional())); #else wxUnusedVar(direction); @@ -168,7 +173,7 @@ public: wxSizerFlags& TripleBorder(int direction = wxALL) { #if wxUSE_BORDER_BY_DEFAULT - return Border(direction, 3*GetDefaultBorder()); + return Border(direction, wxRound(3 * GetDefaultBorderFractional())); #else wxUnusedVar(direction); @@ -179,7 +184,7 @@ public: wxSizerFlags& HorzBorder() { #if wxUSE_BORDER_BY_DEFAULT - return Border(wxLEFT | wxRIGHT, GetDefaultBorder()); + return Border(wxLEFT | wxRIGHT, wxRound(GetDefaultBorderFractional())); #else return *this; #endif @@ -188,7 +193,7 @@ public: wxSizerFlags& DoubleHorzBorder() { #if wxUSE_BORDER_BY_DEFAULT - return Border(wxLEFT | wxRIGHT, 2*GetDefaultBorder()); + return Border(wxLEFT | wxRIGHT, wxRound(2 * GetDefaultBorderFractional())); #else return *this; #endif @@ -223,7 +228,7 @@ public: private: #ifdef wxNEEDS_BORDER_IN_PX - static int DoGetDefaultBorderInPx(); + static float DoGetDefaultBorderInPx(); #endif // wxNEEDS_BORDER_IN_PX int m_proportion; diff --git a/interface/wx/sizer.h b/interface/wx/sizer.h index 90b2b5751d..a3ceab8e70 100644 --- a/interface/wx/sizer.h +++ b/interface/wx/sizer.h @@ -1493,9 +1493,21 @@ public: This value is scaled appropriately for the current DPI on the systems where physical pixel values are used for the control positions and sizes, i.e. not with wxGTK or wxOSX. + + @see GetDefaultBorderFractional() */ static int GetDefaultBorder(); + /** + Returns the border used by default, with fractional precision. For + example when the border is scaled to a non-integer DPI. + + @see GetDefaultBorder() + + @since 3.1.4 + */ + static float GetDefaultBorderFractional(); + /** Aligns the object to the left, similar for @c Align(wxALIGN_LEFT). diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index d6b270e3e8..da1a350598 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -93,7 +93,7 @@ WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) #ifdef wxNEEDS_BORDER_IN_PX /* static */ -int wxSizerFlags::DoGetDefaultBorderInPx() +float wxSizerFlags::DoGetDefaultBorderInPx() { // Hard code 5px as it's the minimal border size between two controls, see // the table at the bottom of @@ -107,9 +107,12 @@ int wxSizerFlags::DoGetDefaultBorderInPx() // as we don't have any associated window -- but, again, without changes // in the API, there is nothing we can do about this. const wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - static wxPrivate::DpiDependentValue s_defaultBorderInPx; + static wxPrivate::DpiDependentValue s_defaultBorderInPx; if ( s_defaultBorderInPx.HasChanged(win) ) - s_defaultBorderInPx.SetAtNewDPI(wxWindow::FromDIP(5, win)); + { + s_defaultBorderInPx.SetAtNewDPI( + (float)(5 * (win ? win->GetContentScaleFactor() : 1))); + } return s_defaultBorderInPx.Get(); } diff --git a/src/msw/window.cpp b/src/msw/window.cpp index 08028038b0..3e3619b7eb 100644 --- a/src/msw/window.cpp +++ b/src/msw/window.cpp @@ -4884,6 +4884,37 @@ wxWindowMSW::MSWUpdateOnDPIChange(const wxSize& oldDPI, const wxSize& newDPI) // update font if necessary MSWUpdateFontOnDPIChange(newDPI); + // update sizers + if ( GetSizer() ) + { + wxSizerItemList::compatibility_iterator current = + GetSizer()->GetChildren().GetFirst(); + while ( current ) + { + wxSizerItem* sizerItem = current->GetData(); + + int border = sizerItem->GetBorder(); + ScaleCoordIfSet(border, scaleFactor); + sizerItem->SetBorder(border); + + // only scale sizers and spacers, not windows + if ( sizerItem->IsSizer() || sizerItem->IsSpacer() ) + { + wxSize min = sizerItem->GetMinSize(); + ScaleCoordIfSet(min.x, scaleFactor); + ScaleCoordIfSet(min.y, scaleFactor); + sizerItem->SetMinSize(min); + + wxSize size = sizerItem->GetSize(); + ScaleCoordIfSet(size.x, scaleFactor); + ScaleCoordIfSet(size.y, scaleFactor); + sizerItem->SetDimension(wxDefaultPosition, size); + } + + current = current->GetNext(); + } + } + // update children wxWindowList::compatibility_iterator current = GetChildren().GetFirst(); while ( current )