From 2704d320891823e4a676de331081799bf4338bf5 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 27 Aug 2019 23:06:04 +0200 Subject: [PATCH 1/7] Update wxDPIChangedEvent documentation --- interface/wx/event.h | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/interface/wx/event.h b/interface/wx/event.h index 4c3abd95d6..9a4c125e9a 100644 --- a/interface/wx/event.h +++ b/interface/wx/event.h @@ -3322,15 +3322,15 @@ public: /** @class wxDPIChangedEvent - Event sent when the resolution (measured in dots-per-inch, or DPI) of the - monitor a window is on changes. + Event sent when the display scale factor or pixel density (measured in + dots-per-inch, or DPI) of the monitor a window is on changes. The event is sent to each wxTopLevelWindow affected by the change, and all - its children recursively. For example, this event is sent to the window - when it is moved, by the user, from a display using some DPI value to - another display using a different DPI value. It also sent to all program - windows on the given display if its DPI changes due to a change in the - system settings. + its children recursively (post-order traversal). For example, this event is + sent to the window when it is moved, by the user, from a display using some + DPI value to another display using a different DPI value. It also sent to + all program windows on the given display if its DPI changes due to a change + in the system settings. Currently this event is generated by wxMSW port if only and only if the MSW application runs under Windows 10 Creators Update (v1703) or later and @@ -3359,15 +3359,11 @@ class wxDPIChangedEvent : public wxEvent public: /** Returns the old DPI. - - @since 3.1.3 */ wxSize GetOldDPI() const; /** Returns the new DPI. - - @since 3.1.3 */ wxSize GetNewDPI() const; }; From 13cb9d41d8f1ffc9cb11b9fe0c0a0ad59501ba45 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 27 Aug 2019 23:14:35 +0200 Subject: [PATCH 2/7] Require wxWindow parameter for wxNativeFontInfo constructor in MSW Use the DPI of the window to determine the correct font pointSize. To not break user code, add a default argument when not building the library. --- include/wx/fontutil.h | 16 +++++++++++----- src/msw/font.cpp | 5 +++++ src/msw/fontdlg.cpp | 2 +- src/msw/fontutil.cpp | 2 +- src/msw/menuitem.cpp | 12 ++---------- src/msw/msgdlg.cpp | 11 ++--------- src/msw/settings.cpp | 16 ++++------------ src/msw/textctrl.cpp | 5 +++-- 8 files changed, 29 insertions(+), 40 deletions(-) diff --git a/include/wx/fontutil.h b/include/wx/fontutil.h index 424c100136..05a0a66666 100644 --- a/include/wx/fontutil.h +++ b/include/wx/fontutil.h @@ -34,6 +34,7 @@ #endif class WXDLLIMPEXP_FWD_BASE wxArrayString; +class WXDLLIMPEXP_FWD_CORE wxWindow; struct WXDLLIMPEXP_FWD_CORE wxNativeEncodingInfo; #if defined(_WX_X_FONTLIKE) @@ -118,11 +119,16 @@ public: // set the XFLD void SetXFontName(const wxString& xFontName); #elif defined(__WXMSW__) - wxNativeFontInfo(const LOGFONT& lf_) - : lf(lf_), - pointSize(GetPointSizeAtPPI(lf.lfHeight)) - { - } + // Preserve compatibility in the semi-public (i.e. private, but still + // unfortunately used by some existing code outside of the library) API + // by allowing to create wxNativeFontInfo from just LOGFONT, but ensure + // that we always specify the window, to use the correct DPI, when creating + // fonts inside the library itself. + wxNativeFontInfo(const LOGFONT& lf_, const wxWindow* win +#ifndef WXBUILDING + = NULL +#endif + ); // MSW-specific: get point size from LOGFONT height using specified DPI, // or screen DPI when 0. diff --git a/src/msw/font.cpp b/src/msw/font.cpp index e83b07488a..c54e2601ad 100644 --- a/src/msw/font.cpp +++ b/src/msw/font.cpp @@ -403,6 +403,11 @@ void wxFontRefData::Free() // wxNativeFontInfo // ---------------------------------------------------------------------------- +wxNativeFontInfo::wxNativeFontInfo(const LOGFONT& lf_, const wxWindow* win) + : lf(lf_), + pointSize(GetPointSizeAtPPI(lf.lfHeight, win ? win->GetDPI().y : 0)) +{ } + /* static */ float wxNativeFontInfo::GetPointSizeAtPPI(int lfHeight, int ppi) { diff --git a/src/msw/fontdlg.cpp b/src/msw/fontdlg.cpp index 8edd4a9f91..610b2c21b1 100644 --- a/src/msw/fontdlg.cpp +++ b/src/msw/fontdlg.cpp @@ -152,7 +152,7 @@ int wxFontDialog::ShowModal() if ( ChooseFont(&chooseFontStruct) != 0 ) { wxRGBToColour(m_fontData.m_fontColour, chooseFontStruct.rgbColors); - m_fontData.m_chosenFont = wxFont(wxNativeFontInfo(logFont)); + m_fontData.m_chosenFont = wxFont(wxNativeFontInfo(logFont, this)); m_fontData.EncodingInfo().facename = logFont.lfFaceName; m_fontData.EncodingInfo().charset = logFont.lfCharSet; diff --git a/src/msw/fontutil.cpp b/src/msw/fontutil.cpp index b55222a874..c22f668975 100644 --- a/src/msw/fontutil.cpp +++ b/src/msw/fontutil.cpp @@ -278,7 +278,7 @@ void wxFillLogFont(LOGFONT *logFont, const wxFont *font) wxFont wxCreateFontFromLogFont(const LOGFONT *logFont) { - return wxFont(wxNativeFontInfo(*logFont)); + return wxFont(wxNativeFontInfo(*logFont, NULL)); } #endif // WXWIN_COMPATIBILITY_3_0 diff --git a/src/msw/menuitem.cpp b/src/msw/menuitem.cpp index cbf114bb9a..3163cd5575 100644 --- a/src/msw/menuitem.cpp +++ b/src/msw/menuitem.cpp @@ -348,7 +348,7 @@ void MenuDrawData::Init() wxUxThemeFont themeFont; ::GetThemeSysFont(hTheme, TMT_MENUFONT, themeFont.GetPtr()); - Font = wxFont(themeFont.GetLOGFONT()); + Font = wxFont(wxNativeFontInfo(themeFont.GetLOGFONT(), window)); Theme = true; @@ -392,15 +392,7 @@ void MenuDrawData::Init() Offset = -12; - wxNativeFontInfo info(metrics.lfMenuFont); - // wxNativeFontInfo constructor calculates the pointSize using the - // main screen DPI. But lfHeight is based on the window DPI. - if ( window ) - { - info.pointSize = wxNativeFontInfo::GetPointSizeAtPPI( - info.lf.lfHeight, window->GetDPI().y); - } - Font = wxFont(info); + Font = wxFont(wxNativeFontInfo(metrics.lfMenuFont, window)); Theme = false; } diff --git a/src/msw/msgdlg.cpp b/src/msw/msgdlg.cpp index 21fbfc4e4b..54534f21f7 100644 --- a/src/msw/msgdlg.cpp +++ b/src/msw/msgdlg.cpp @@ -397,15 +397,8 @@ void wxMessageDialog::AdjustButtonLabels() wxFont wxMessageDialog::GetMessageFont() { const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - wxNativeFontInfo info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont); - - // wxNativeFontInfo constructor calculates the pointSize using the - // main screen DPI. But lfHeight is based on the window DPI. - if ( win ) - { - info.pointSize = wxNativeFontInfo::GetPointSizeAtPPI( - info.lf.lfHeight, win->GetDPI().y); - } + const wxNativeFontInfo + info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont, win); return info; } diff --git a/src/msw/settings.cpp b/src/msw/settings.cpp index c2029cc67f..4be42f593d 100644 --- a/src/msw/settings.cpp +++ b/src/msw/settings.cpp @@ -150,7 +150,7 @@ wxFont wxCreateFontFromStockObject(int index) LOGFONT lf; if ( ::GetObject(hFont, sizeof(LOGFONT), &lf) != 0 ) { - wxNativeFontInfo info(lf); + wxNativeFontInfo info(lf, NULL); font.Create(info); } else @@ -183,16 +183,8 @@ wxFont wxSystemSettingsNative::GetFont(wxSystemFont index) // controls may prefer to use lfStatusFont or lfCaptionFont if it // is more appropriate for them const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - wxNativeFontInfo - info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont); - - // wxNativeFontInfo constructor calculates the pointSize using the - // main screen DPI. But lfHeight is based on the window DPI. - if ( win ) - { - info.pointSize = wxNativeFontInfo::GetPointSizeAtPPI( - info.lf.lfHeight, win->GetDPI().y); - } + const wxNativeFontInfo + info(wxMSWImpl::GetNonClientMetrics(win).lfMessageFont, win); gs_fontDefault = new wxFont(info); } @@ -358,7 +350,7 @@ extern wxFont wxGetCCDefaultFont() win ) ) { - return wxFont(lf); + return wxFont(wxNativeFontInfo(lf, win)); } else { diff --git a/src/msw/textctrl.cpp b/src/msw/textctrl.cpp index a9139507ff..82c346a85b 100644 --- a/src/msw/textctrl.cpp +++ b/src/msw/textctrl.cpp @@ -3207,7 +3207,8 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) // CHARFORMAT stores it to pixel-based units used by LOGFONT. // Note that RichEdit seems to always use standard DPI of 96, even when the // window is a monitor using a higher DPI. - lf.lfHeight = wxNativeFontInfo::GetLogFontHeightAtPPI(cf.yHeight/20.0f, 96); + lf.lfHeight = wxNativeFontInfo::GetLogFontHeightAtPPI(cf.yHeight/20.0f, + GetDPI().y); lf.lfWidth = 0; lf.lfCharSet = ANSI_CHARSET; // FIXME: how to get correct charset? lf.lfClipPrecision = 0; @@ -3240,7 +3241,7 @@ bool wxTextCtrl::GetStyle(long position, wxTextAttr& style) else lf.lfWeight = FW_NORMAL; - wxFont font(lf); + wxFont font(wxNativeFontInfo(lf, this)); if (font.IsOk()) { style.SetFont(font); From 587f894f9663a382049cf535e582f84f7b170e59 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 27 Aug 2019 23:20:20 +0200 Subject: [PATCH 3/7] Fix font of wxRadioBox after DPI change --- include/wx/msw/radiobox.h | 2 ++ src/msw/radiobox.cpp | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/include/wx/msw/radiobox.h b/include/wx/msw/radiobox.h index f3898edc1e..1564093a19 100644 --- a/include/wx/msw/radiobox.h +++ b/include/wx/msw/radiobox.h @@ -162,6 +162,8 @@ protected: virtual WXHRGN MSWGetRegionWithoutChildren() wxOVERRIDE; + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + // resolve ambiguity in base classes virtual wxBorder GetDefaultBorder() const wxOVERRIDE { return wxRadioBoxBase::GetDefaultBorder(); } diff --git a/src/msw/radiobox.cpp b/src/msw/radiobox.cpp index c0b93032a7..423acbbfc1 100644 --- a/src/msw/radiobox.cpp +++ b/src/msw/radiobox.cpp @@ -751,6 +751,14 @@ int wxRadioBox::GetItemFromPoint(const wxPoint& pt) const return wxNOT_FOUND; } +void wxRadioBox::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxStaticBox::MSWUpdateFontOnDPIChange(newDPI); + + if ( m_font.IsOk() ) + m_radioButtons->SetFont(m_font); +} + // ---------------------------------------------------------------------------- // radio box drawing // ---------------------------------------------------------------------------- From 4713301cf50ee5d18e42d0e510541be278c6518c Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 27 Aug 2019 23:26:27 +0200 Subject: [PATCH 4/7] Fix font and thumb size of wxSlider after DPI change --- include/wx/msw/slider.h | 3 +++ src/msw/slider.cpp | 31 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/include/wx/msw/slider.h b/include/wx/msw/slider.h index 0668590eb9..57495d1568 100644 --- a/include/wx/msw/slider.h +++ b/include/wx/msw/slider.h @@ -122,6 +122,9 @@ protected: WXHBRUSH DoMSWControlColor(WXHDC pDC, wxColour colBg, WXHWND hWnd) wxOVERRIDE; + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + + void OnDPIChanged(wxDPIChangedEvent& event); // the labels windows, if any wxSubwindows *m_labels; diff --git a/src/msw/slider.cpp b/src/msw/slider.cpp index 659320b96f..49e4bb07cb 100644 --- a/src/msw/slider.cpp +++ b/src/msw/slider.cpp @@ -163,13 +163,17 @@ bool wxSlider::Create(wxWindow *parent, m_labels->Set(n, wnd, lblid); } - m_labels->SetFont(GetFont()); } // now create the main control too if ( !MSWCreateControl(TRACKBAR_CLASS, wxEmptyString, pos, size) ) return false; + if ( m_labels ) + { + m_labels->SetFont(GetFont()); + } + // and initialize everything SetRange(minValue, maxValue); SetValue(value); @@ -183,6 +187,8 @@ bool wxSlider::Create(wxWindow *parent, SetSize(size); } + Bind(wxEVT_DPI_CHANGED, &wxSlider::OnDPIChanged, this); + return true; } @@ -541,7 +547,7 @@ void wxSlider::DoMoveWindow(int x, int y, int width, int height) wxSize wxSlider::DoGetBestSize() const { // this value is arbitrary: - static const int length = FromDIP(100); + const int length = FromDIP(100); const int thumbSize = GetThumbLength(); const int tickSize = FromDIP(TICK); @@ -619,6 +625,27 @@ WXHBRUSH wxSlider::DoMSWControlColor(WXHDC pDC, wxColour colBg, WXHWND hWnd) return hBrush; } +void wxSlider::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxSliderBase::MSWUpdateFontOnDPIChange(newDPI); + + if ( m_labels && m_font.IsOk() ) + { + m_labels->SetFont(m_font); + } +} + +void wxSlider::OnDPIChanged(wxDPIChangedEvent& event) +{ + int thumbLen = GetThumbLength(); + + const double scaleFactor = (double)event.GetNewDPI().x / event.GetOldDPI().x; + const double thumbLenScaled = thumbLen * scaleFactor; + thumbLen = (int)(scaleFactor > 1.0 ? ceil(thumbLenScaled) : floor(thumbLenScaled)); + + SetThumbLength(thumbLen); +} + // ---------------------------------------------------------------------------- // slider-specific methods // ---------------------------------------------------------------------------- From e312569b946f2d4a97b47ef7448b449c2f82e085 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Tue, 3 Sep 2019 22:07:49 +0200 Subject: [PATCH 5/7] Fix wxStatusBar font and position after DPI changes Update the font of the associated wxDC so ellipsization uses the correct font size. --- include/wx/msw/statusbar.h | 2 ++ src/msw/frame.cpp | 13 +++++++++++-- src/msw/statusbar.cpp | 11 ++++++++++- 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/include/wx/msw/statusbar.h b/include/wx/msw/statusbar.h index 5f2760bd39..a503a8c1e4 100644 --- a/include/wx/msw/statusbar.h +++ b/include/wx/msw/statusbar.h @@ -72,6 +72,8 @@ protected: // implementation of the public SetStatusWidths() void MSWUpdateFieldsWidths(); + virtual void MSWUpdateFontOnDPIChange(const wxSize& newDPI) wxOVERRIDE; + // used by DoUpdateStatusText() wxClientDC *m_pDC; diff --git a/src/msw/frame.cpp b/src/msw/frame.cpp index adf9ec9b1a..607b82f320 100644 --- a/src/msw/frame.cpp +++ b/src/msw/frame.cpp @@ -335,6 +335,14 @@ void wxFrame::PositionStatusBar() //else: no adjustments necessary for the toolbar on top #endif // wxUSE_TOOLBAR + // GetSize returns the height of the clientSize in which the statusbar + // height is subtracted (see wxFrame::DoGetClientSize). When the DPI of the + // window changes, the statusbar height will likely change so we need to + // account for this difference. If not, the statusbar will be positioned + // too high or low. + int shOld; + m_frameStatusBar->GetSize(NULL, &shOld); + // Resize the status bar to its default height, as it could have been set // to a wrong value before by WM_SIZE sent during the frame creation and // our status bars preserve their programmatically set size to avoid being @@ -342,8 +350,9 @@ void wxFrame::PositionStatusBar() // this here, the status bar would retain the possibly wrong current height. m_frameStatusBar->SetSize(x, h, w, wxDefaultCoord, wxSIZE_AUTO_HEIGHT); - int sw, sh; - m_frameStatusBar->GetSize(&sw, &sh); + int sh; + m_frameStatusBar->GetSize(NULL, &sh); + h += shOld - sh; // Since we wish the status bar to be directly under the client area, // we use the adjusted sizes without using wxSIZE_NO_ADJUSTMENTS. diff --git a/src/msw/statusbar.cpp b/src/msw/statusbar.cpp index ad9b4eff96..52696769b3 100644 --- a/src/msw/statusbar.cpp +++ b/src/msw/statusbar.cpp @@ -166,7 +166,8 @@ bool wxStatusBar::SetFont(const wxFont& font) if (!wxWindow::SetFont(font)) return false; - if (m_pDC) m_pDC->SetFont(font); + if ( m_pDC ) + m_pDC->SetFont(m_font); return true; } @@ -256,6 +257,14 @@ void wxStatusBar::MSWUpdateFieldsWidths() delete [] pWidths; } +void wxStatusBar::MSWUpdateFontOnDPIChange(const wxSize& newDPI) +{ + wxStatusBarBase::MSWUpdateFontOnDPIChange(newDPI); + + if ( m_pDC && m_font.IsOk() ) + m_pDC->SetFont(m_font); +} + void wxStatusBar::DoUpdateStatusText(int nField) { if (!m_pDC) From fa2242a0a6b1f53b79c65e02340eb94f0915a5f2 Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Wed, 4 Sep 2019 20:47:52 +0200 Subject: [PATCH 6/7] Reset static sizes when DPI changes --- include/wx/private/window.h | 62 +++++++++++++++++++++++++++++++++++++ include/wx/sizer.h | 10 +----- src/common/sizer.cpp | 15 +++++---- src/common/wincmn.cpp | 10 +++--- src/msw/button.cpp | 28 ++++++++++++----- src/msw/checkbox.cpp | 24 +++++++------- src/msw/cursor.cpp | 22 +++---------- src/msw/radiobut.cpp | 23 +++++++------- 8 files changed, 125 insertions(+), 69 deletions(-) diff --git a/include/wx/private/window.h b/include/wx/private/window.h index 1192fb97b2..18815b3d49 100644 --- a/include/wx/private/window.h +++ b/include/wx/private/window.h @@ -11,6 +11,7 @@ #define _WX_PRIVATE_WINDOW_H_ #include "wx/gdicmn.h" +#include "wx/dynlib.h" namespace wxPrivate { @@ -33,6 +34,67 @@ inline wxSize GetAverageASCIILetterSize(const T& of_what) return s; } +namespace +{ + +inline bool SupportsPerMonitorDPI() +{ + static bool s_checkDPI = +#if defined(__WXMSW__) && wxUSE_DYNLIB_CLASS + // Only check the DPI when GetDpiForWindow is available because the old + // method (GetDeviceCaps) is a lot slower (about 1500 times). + // And when GetDpiForWindow is not available (for example older Windows + // versions), per-monitor DPI (V2) is also not available. + wxLoadedDLL("user32.dll").HasSymbol("GetDpiForWindow"); +#else + false; +#endif + return s_checkDPI; +} + +} + +template +class DpiDependentValue +{ +public: + // Explicit initialization is needed if T is a primitive type. + DpiDependentValue() + : m_value(), m_dpi() + { } + + bool HasChanged(const wxWindowBase* win) + { + if ( win && SupportsPerMonitorDPI() ) + { + const wxSize dpi = win->GetDPI(); + if ( dpi != m_dpi ) + { + m_dpi = dpi; + return true; + } + } + + // Ensure that we return true the first time we're called, + // asuming that the value will always be set to a non-default value. + return m_value == T(); + } + + void SetAtNewDPI(const T& value) + { + m_value = value; + } + + T& Get() + { + return m_value; + } + +private: + T m_value; + wxSize m_dpi; +}; + } // namespace wxPrivate #endif // _WX_PRIVATE_WINDOW_H_ diff --git a/include/wx/sizer.h b/include/wx/sizer.h index 4f34ccd3ed..0d4fdeac09 100644 --- a/include/wx/sizer.h +++ b/include/wx/sizer.h @@ -120,13 +120,7 @@ public: // current DPI, do it once (and cache the result) in another function. #define wxNEEDS_BORDER_IN_PX - // We don't react to dynamic DPI changes, so we can cache the values of - // the border in on-screen pixels after computing it once. This - // could/should change in the future. - if ( !ms_defaultBorderInPx ) - ms_defaultBorderInPx = DoGetDefaultBorderInPx(); - - return ms_defaultBorderInPx; + return DoGetDefaultBorderInPx(); #endif #else return 0; @@ -230,8 +224,6 @@ public: private: #ifdef wxNEEDS_BORDER_IN_PX static int DoGetDefaultBorderInPx(); - - static int ms_defaultBorderInPx; #endif // wxNEEDS_BORDER_IN_PX int m_proportion; diff --git a/src/common/sizer.cpp b/src/common/sizer.cpp index d34ad21eec..d6b270e3e8 100644 --- a/src/common/sizer.cpp +++ b/src/common/sizer.cpp @@ -28,11 +28,13 @@ #include "wx/button.h" #include "wx/statbox.h" #include "wx/toplevel.h" + #include "wx/app.h" #endif // WX_PRECOMP #include "wx/display.h" #include "wx/vector.h" #include "wx/listimpl.cpp" +#include "wx/private/window.h" //--------------------------------------------------------------------------- @@ -90,8 +92,6 @@ WX_DEFINE_EXPORTED_LIST( wxSizerItemList ) #ifdef wxNEEDS_BORDER_IN_PX -int wxSizerFlags::ms_defaultBorderInPx = 0; - /* static */ int wxSizerFlags::DoGetDefaultBorderInPx() { @@ -103,11 +103,14 @@ int wxSizerFlags::DoGetDefaultBorderInPx() // between related and unrelated controls, as explained at the above URL, // but we don't have a way to specify this in our API currently. // - // We also have to use the DPI for the primary monitor here as we don't - // have any associated window, so this is wrong on systems using multiple - // monitors with different resolutions too -- but, again, without changes + // We also have to use the DPI for the monitor showing the top window here + // as we don't have any associated window -- but, again, without changes // in the API, there is nothing we can do about this. - return wxWindow::FromDIP(5, NULL); + const wxWindow* const win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; + static wxPrivate::DpiDependentValue s_defaultBorderInPx; + if ( s_defaultBorderInPx.HasChanged(win) ) + s_defaultBorderInPx.SetAtNewDPI(wxWindow::FromDIP(5, win)); + return s_defaultBorderInPx.Get(); } #endif // wxNEEDS_BORDER_IN_PX diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index bc8a88139a..9d0ef0a1b8 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -2921,7 +2921,7 @@ wxWindowBase::ToDIP(const wxSize& sz, const wxWindowBase* w) // using them. wxSize wxWindowBase::GetDlgUnitBase() const { - const wxWindowBase * const parent = wxGetTopLevelParent((wxWindow*)this); + const wxWindowBase* const parent = wxGetTopLevelParent((wxWindow*)this); wxCHECK_MSG( parent, wxDefaultSize, wxS("Must have TLW parent") ); @@ -2929,10 +2929,10 @@ wxSize wxWindowBase::GetDlgUnitBase() const { // Default GUI font is used. This is the most common case, so // cache the results. - static wxSize s_defFontSize; - if ( s_defFontSize.x == 0 ) - s_defFontSize = wxPrivate::GetAverageASCIILetterSize(*parent); - return s_defFontSize; + static wxPrivate::DpiDependentValue s_defFontSize; + if ( s_defFontSize.HasChanged(parent) ) + s_defFontSize.SetAtNewDPI(wxPrivate::GetAverageASCIILetterSize(*parent)); + return s_defFontSize.Get(); } else { diff --git a/src/msw/button.cpp b/src/msw/button.cpp index c9df03a590..786bdc143d 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -162,12 +162,25 @@ WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const /* static */ wxSize wxButtonBase::GetDefaultSize() { - static wxSize s_sizeBtn; + wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - if ( s_sizeBtn.x == 0 ) + static wxPrivate::DpiDependentValue s_sizeBtn; + + if ( s_sizeBtn.HasChanged(win) ) { - wxScreenDC dc; - dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + wxSize base; + if ( win ) + { + wxClientDC dc(win); + dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + base = wxPrivate::GetAverageASCIILetterSize(dc); + } + else + { + wxScreenDC dc; + dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); + base = wxPrivate::GetAverageASCIILetterSize(dc); + } // The size of a standard button in the dialog units is 50x14, // translate this to pixels. @@ -180,12 +193,11 @@ wxSize wxButtonBase::GetDefaultSize() // // NB: wxMulDivInt32() is used, because it correctly rounds the result - const wxSize base = wxPrivate::GetAverageASCIILetterSize(dc); - s_sizeBtn.x = wxMulDivInt32(50, base.x, 4); - s_sizeBtn.y = wxMulDivInt32(14, base.y, 8); + s_sizeBtn.SetAtNewDPI(wxSize(wxMulDivInt32(50, base.x, 4), + wxMulDivInt32(14, base.y, 8))); } - return s_sizeBtn; + return s_sizeBtn.Get(); } // ---------------------------------------------------------------------------- diff --git a/src/msw/checkbox.cpp b/src/msw/checkbox.cpp index fa8ca811ce..5414ceca21 100644 --- a/src/msw/checkbox.cpp +++ b/src/msw/checkbox.cpp @@ -28,15 +28,14 @@ #include "wx/checkbox.h" #ifndef WX_PRECOMP - #include "wx/brush.h" #include "wx/dcclient.h" - #include "wx/dcscreen.h" #include "wx/settings.h" #endif #include "wx/renderer.h" #include "wx/msw/uxtheme.h" #include "wx/msw/private/button.h" +#include "wx/private/window.h" #include "wx/msw/missing.h" // ============================================================================ @@ -98,16 +97,17 @@ WXDWORD wxCheckBox::MSWGetStyle(long style, WXDWORD *exstyle) const wxSize wxCheckBox::DoGetBestClientSize() const { - static int s_checkSize = 0; + static wxPrivate::DpiDependentValue s_checkSize; - if ( !s_checkSize ) + if ( s_checkSize.HasChanged(this) ) { - wxScreenDC dc; + wxClientDC dc(const_cast(this)); dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - s_checkSize = dc.GetCharHeight(); + s_checkSize.SetAtNewDPI(dc.GetCharHeight()); } + wxCoord& checkSize = s_checkSize.Get(); wxString str = wxGetWindowText(GetHWND()); int wCheckbox, hCheckbox; @@ -116,7 +116,7 @@ wxSize wxCheckBox::DoGetBestClientSize() const wxClientDC dc(const_cast(this)); dc.SetFont(GetFont()); dc.GetMultiLineTextExtent(GetLabelText(str), &wCheckbox, &hCheckbox); - wCheckbox += s_checkSize + GetCharWidth(); + wCheckbox += checkSize + GetCharWidth(); if ( ::GetWindowLong(GetHwnd(), GWL_STYLE) & BS_MULTILINE ) { @@ -128,16 +128,16 @@ wxSize wxCheckBox::DoGetBestClientSize() const // label appears on 3 lines, not 2, under Windows 2003 using // classic look and feel (although it works fine under Windows 7, // with or without themes). - wCheckbox += s_checkSize; + wCheckbox += checkSize; } - if ( hCheckbox < s_checkSize ) - hCheckbox = s_checkSize; + if ( hCheckbox < checkSize ) + hCheckbox = checkSize; } else { - wCheckbox = s_checkSize; - hCheckbox = s_checkSize; + wCheckbox = checkSize; + hCheckbox = checkSize; } return wxSize(wCheckbox, hCheckbox); diff --git a/src/msw/cursor.cpp b/src/msw/cursor.cpp index d051acc52f..d57f980ea5 100644 --- a/src/msw/cursor.cpp +++ b/src/msw/cursor.cpp @@ -63,9 +63,6 @@ public: private: bool m_destroyCursor; - - // standard cursor size, computed on first use - static wxSize ms_sizeStd; }; // ---------------------------------------------------------------------------- @@ -110,28 +107,17 @@ public: // wxCursorRefData // ---------------------------------------------------------------------------- -wxSize wxCursorRefData::ms_sizeStd; wxCoord wxCursorRefData::GetStandardWidth() { - if ( !ms_sizeStd.x ) - { - wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - ms_sizeStd.x = wxSystemSettings::GetMetric(wxSYS_CURSOR_X, win); - } - - return ms_sizeStd.x; + const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; + return wxSystemSettings::GetMetric(wxSYS_CURSOR_X, win); } wxCoord wxCursorRefData::GetStandardHeight() { - if ( !ms_sizeStd.y ) - { - wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - ms_sizeStd.y = wxSystemSettings::GetMetric(wxSYS_CURSOR_Y, win); - } - - return ms_sizeStd.y; + const wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; + return wxSystemSettings::GetMetric(wxSYS_CURSOR_Y, win); } wxCursorRefData::wxCursorRefData(HCURSOR hcursor, bool destroy) diff --git a/src/msw/radiobut.cpp b/src/msw/radiobut.cpp index 84a16ddbfa..ef3d7ec15f 100644 --- a/src/msw/radiobut.cpp +++ b/src/msw/radiobut.cpp @@ -29,11 +29,11 @@ #ifndef WX_PRECOMP #include "wx/settings.h" - #include "wx/dcscreen.h" - #include "wx/toplevel.h" + #include "wx/dcclient.h" #endif #include "wx/msw/private.h" +#include "wx/private/window.h" #include "wx/renderer.h" #include "wx/msw/uxtheme.h" @@ -238,31 +238,32 @@ bool wxRadioButton::MSWCommand(WXUINT param, WXWORD WXUNUSED(id)) wxSize wxRadioButton::DoGetBestSize() const { - static int s_radioSize = 0; + static wxPrivate::DpiDependentValue s_radioSize; - if ( !s_radioSize ) + if ( s_radioSize.HasChanged(this) ) { - wxScreenDC dc; + wxClientDC dc(const_cast(this)); dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT)); - s_radioSize = dc.GetCharHeight(); + s_radioSize.SetAtNewDPI(dc.GetCharHeight()); } + wxCoord& radioSize = s_radioSize.Get(); wxString str = GetLabel(); int wRadio, hRadio; if ( !str.empty() ) { GetTextExtent(GetLabelText(str), &wRadio, &hRadio); - wRadio += s_radioSize + GetCharWidth(); + wRadio += radioSize + GetCharWidth(); - if ( hRadio < s_radioSize ) - hRadio = s_radioSize; + if ( hRadio < radioSize ) + hRadio = radioSize; } else { - wRadio = s_radioSize; - hRadio = s_radioSize; + wRadio = radioSize; + hRadio = radioSize; } return wxSize(wRadio, hRadio); From 462f2a4686855ca2fdaeff1daa537b189d7b6cab Mon Sep 17 00:00:00 2001 From: Maarten Bent Date: Wed, 4 Sep 2019 20:53:07 +0200 Subject: [PATCH 7/7] Add optional wxWindow parameter to wxButtonBase::GetDefaultSize() When per-monitor DPI is used, the default button size depends on the DPI of the display. Use the window to determine this DPI. --- include/wx/button.h | 5 +++-- interface/wx/button.h | 11 +++++++---- src/gtk/button.cpp | 2 +- src/gtk1/button.cpp | 2 +- src/msw/button.cpp | 4 +--- src/osx/button_osx.cpp | 2 +- src/qt/button.cpp | 2 +- src/univ/button.cpp | 2 +- 8 files changed, 16 insertions(+), 14 deletions(-) diff --git a/include/wx/button.h b/include/wx/button.h index f31166413e..0f26c65b0c 100644 --- a/include/wx/button.h +++ b/include/wx/button.h @@ -39,8 +39,9 @@ public: // returns the old default item (possibly NULL) virtual wxWindow *SetDefault(); - // returns the default button size for this platform - static wxSize GetDefaultSize(); + // returns the default button size for this platform, and optionally for a + // specific window when the platform supports per-monitor DPI + static wxSize GetDefaultSize(wxWindow* win = NULL); protected: wxDECLARE_NO_COPY_CLASS(wxButtonBase); diff --git a/interface/wx/button.h b/interface/wx/button.h index 923415ae17..b4cdbb2517 100644 --- a/interface/wx/button.h +++ b/interface/wx/button.h @@ -179,11 +179,14 @@ public: /** - Returns the default size for the buttons. It is advised to make all the dialog - buttons of the same size and this function allows retrieving the (platform and - current font dependent size) which should be the best suited for this. + Returns the default size for the buttons. It is advised to make all the + dialog buttons of the same size and this function allows retrieving the + (platform, and current font dependent) size which should be the best + suited for this. + The optional wxWindow parameter allows to get a per-monitor DPI + specific size. */ - static wxSize GetDefaultSize(); + static wxSize GetDefaultSize(wxWindow* win = NULL); /** Returns the string label for the button. diff --git a/src/gtk/button.cpp b/src/gtk/button.cpp index ce72ff150a..012aa24b44 100644 --- a/src/gtk/button.cpp +++ b/src/gtk/button.cpp @@ -165,7 +165,7 @@ wxWindow *wxButton::SetDefault() } /* static */ -wxSize wxButtonBase::GetDefaultSize() +wxSize wxButtonBase::GetDefaultSize(wxWindow* WXUNUSED(win)) { static wxSize size = wxDefaultSize; if (size == wxDefaultSize) diff --git a/src/gtk1/button.cpp b/src/gtk1/button.cpp index 3f7c09026b..932ef8bdbc 100644 --- a/src/gtk1/button.cpp +++ b/src/gtk1/button.cpp @@ -166,7 +166,7 @@ wxWindow *wxButton::SetDefault() } /* static */ -wxSize wxButtonBase::GetDefaultSize() +wxSize wxButtonBase::GetDefaultSize(wxWindow* WXUNUSED(win)) { return wxSize(80,26); } diff --git a/src/msw/button.cpp b/src/msw/button.cpp index 786bdc143d..31a27b41d9 100644 --- a/src/msw/button.cpp +++ b/src/msw/button.cpp @@ -160,10 +160,8 @@ WXDWORD wxButton::MSWGetStyle(long style, WXDWORD *exstyle) const } /* static */ -wxSize wxButtonBase::GetDefaultSize() +wxSize wxButtonBase::GetDefaultSize(wxWindow* win) { - wxWindow* win = wxTheApp ? wxTheApp->GetTopWindow() : NULL; - static wxPrivate::DpiDependentValue s_sizeBtn; if ( s_sizeBtn.HasChanged(win) ) diff --git a/src/osx/button_osx.cpp b/src/osx/button_osx.cpp index 8895171565..8ee6dc55b2 100644 --- a/src/osx/button_osx.cpp +++ b/src/osx/button_osx.cpp @@ -137,7 +137,7 @@ bool wxButton::OSXHandleClicked( double WXUNUSED(timestampsec) ) } /* static */ -wxSize wxButtonBase::GetDefaultSize() +wxSize wxButtonBase::GetDefaultSize(wxWindow* WXUNUSED(win)) { return wxAnyButton::GetDefaultSize(); } diff --git a/src/qt/button.cpp b/src/qt/button.cpp index aa61ab127a..3911f987b0 100644 --- a/src/qt/button.cpp +++ b/src/qt/button.cpp @@ -61,7 +61,7 @@ wxWindow *wxButton::SetDefault() } /* static */ -wxSize wxButtonBase::GetDefaultSize() +wxSize wxButtonBase::GetDefaultSize(wxWindow* WXUNUSED(win)) { static wxSize size = wxDefaultSize; if (size == wxDefaultSize) diff --git a/src/univ/button.cpp b/src/univ/button.cpp index 7819391786..aa3a02cceb 100644 --- a/src/univ/button.cpp +++ b/src/univ/button.cpp @@ -110,7 +110,7 @@ wxButton::~wxButton() // ---------------------------------------------------------------------------- /* static */ -wxSize wxButtonBase::GetDefaultSize() +wxSize wxButtonBase::GetDefaultSize(wxWindow* WXUNUSED(win)) { static wxSize s_sizeBtn;