From 00748bbaef864e58b50123feeba1b263873e3d70 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Fri, 20 Mar 2015 00:01:57 +0100 Subject: [PATCH] Add wxWindow::FromDIP() for simpler high DPI support. This method allows to scale a pixel value by a DPI-dependent factor to the value used by the underlying toolkit only if necessary, i.e. when not using GTK+ 3 or OS X which already do this internally. --- docs/changes.txt | 1 + include/wx/window.h | 25 ++++++++++++++++++++++-- interface/wx/window.h | 44 ++++++++++++++++++++++++++++++++++++------- src/common/wincmn.cpp | 14 +++++++++++++- 4 files changed, 74 insertions(+), 10 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index dcba1e43d7..729c60f99a 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -65,6 +65,7 @@ Unix: All (GUI): - Allow requesting modern (3.x+) OpenGL version in wxGLCanvas (Fabio Arnold). +- Add wxWindow::FromDIP() for simpler high DPI support. - Allow customizing window shown by wxBusyInfo. - Add wxAddRemoveCtrl. - Add wxAppProgressIndicator for MSW (Chaobin Zhang) and OS X (Tobias Taschner). diff --git a/include/wx/window.h b/include/wx/window.h index 6dd141ac41..6be9f2e1c4 100644 --- a/include/wx/window.h +++ b/include/wx/window.h @@ -950,8 +950,18 @@ public: #endif // wxUSE_HOTKEY - // dialog units translations - // ------------------------- + // translation between different units + // ----------------------------------- + + // DPI-independent pixels, or DIPs, are pixel values for the standard + // 96 DPI display, they are scaled to take the current resolution into + // account (i.e. by the factor returned by GetContentScaleFactor()) if + // necessary for the current platform. + + wxSize FromDIP(const wxSize& sz) const; + + + // Dialog units are based on the size of the current font. wxPoint ConvertPixelsToDialog( const wxPoint& pt ) const; wxPoint ConvertDialogToPixels( const wxPoint& pt ) const; @@ -1891,6 +1901,9 @@ inline void wxWindowBase::SetInitialBestSize(const wxSize& size) #define wxWindowGTK wxWindow #endif // wxUniv #include "wx/gtk/window.h" + #ifdef __WXGTK3__ + #define wxHAVE_DPI_INDEPENDENT_PIXELS + #endif #elif defined(__WXGTK__) #ifdef __WXUNIVERSAL__ #define wxWindowNative wxWindowGTK @@ -1915,6 +1928,7 @@ inline void wxWindowBase::SetInitialBestSize(const wxSize& size) #define wxWindowMac wxWindow #endif // wxUniv #include "wx/osx/window.h" + #define wxHAVE_DPI_INDEPENDENT_PIXELS #elif defined(__WXQT__) #ifdef __WXUNIVERSAL__ #define wxWindowNative wxWindowQt @@ -1944,6 +1958,13 @@ inline wxWindow *wxWindowBase::GetGrandParent() const return m_parent ? m_parent->GetParent() : NULL; } +#ifdef wxHAVE_DPI_INDEPENDENT_PIXELS + +// FromDIP() becomes trivial in this case, so make it inline to avoid overhead. +inline wxSize wxWindowBase::FromDIP(const wxSize& sz) const { return sz; } + +#endif // wxHAVE_DPI_INDEPENDENT_PIXELS + // ---------------------------------------------------------------------------- // global functions // ---------------------------------------------------------------------------- diff --git a/interface/wx/window.h b/interface/wx/window.h index cc25b31beb..44cb77dfd0 100644 --- a/interface/wx/window.h +++ b/interface/wx/window.h @@ -918,6 +918,35 @@ public: */ virtual void FitInside(); + /** + Convert DPI-independent pixel values to the value in pixels appropriate + for the current toolkit. + + A DPI-independent pixel is just a pixel at the standard 96 DPI + resolution. To keep the same physical size at higher resolution, the + physical pixel value must be scaled by GetContentScaleFactor() but this + scaling may be already done by the underlying toolkit (GTK+, Cocoa, + ...) automatically. This method performs the conversion only if it is + not already done by the lower level toolkit and so by using it with + pixel values you can guarantee that the physical size of the + corresponding elements will remain the same in all resolutions under + all platforms. For example, instead of creating a bitmap of the hard + coded size of 32 pixels you should use + @code + wxBitmap bmp(FromDIP(32, 32)); + @endcode + to avoid using tiny bitmaps on high DPI screens. + + Notice that this function is only needed when using hard coded pixel + values. It is not necessary if the sizes are already based on the + DPI-independent units such as dialog units or if you are relying on the + controls automatic best size determination and using sizers to lay out + them. + + @since 3.1.0 + */ + wxSize FromDIP(const wxSize& sz) const; + /** This functions returns the best acceptable minimal size for the window. @@ -1126,13 +1155,14 @@ public: Returns the magnification of the backing store of this window, eg 2.0 for a window on a retina screen. - This method can be used to adjust hard coded pixel values to the values - appropriate for the current screen resolution. E.g. instead of using - 32px icons, which would look tiny on the high resolution (also known as - HiDPI or retina) displays, you should use - @code - wxRound(32*GetContentScaleFactor()) - @endcode instead. + This factor should be used to determine the size of bitmaps and similar + "content-containing" windows appropriate for the current resolution. + E.g. the program may load a 32px bitmap if the content scale factor is + 1.0 or 64px version of the same bitmap if it is 2.0 or bigger. + + Notice that this method should @e not be used for window sizes, as they + are already scaled by this factor by the underlying toolkit under some + platforms. Use FromDIP() for anything window-related instead. @since 2.9.5 */ diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp index 58025cbc17..7489fdfd9f 100644 --- a/src/common/wincmn.cpp +++ b/src/common/wincmn.cpp @@ -27,6 +27,7 @@ #include "wx/string.h" #include "wx/log.h" #include "wx/intl.h" + #include "wx/math.h" #include "wx/frame.h" #include "wx/window.h" #include "wx/control.h" @@ -2860,9 +2861,20 @@ void wxWindowBase::OnInternalIdle() } // ---------------------------------------------------------------------------- -// dialog units translations +// DPI-independent pixels and dialog units translations // ---------------------------------------------------------------------------- +#ifndef wxHAVE_DPI_INDEPENDENT_PIXELS + +wxSize wxWindowBase::FromDIP(const wxSize& sz) const +{ + const double scale = GetContentScaleFactor(); + + return wxSize(wxRound(scale*sz.x), wxRound(scale*sz.y)); +} + +#endif // !wxHAVE_DPI_INDEPENDENT_PIXELS + // Windows' computes dialog units using average character width over upper- // and lower-case ASCII alphabet and not using the average character width // metadata stored in the font; see