]> git.saurik.com Git - wxWidgets.git/commitdiff
Fixed dialog units <-> pixels conversion.
authorVáclav Slavík <vslavik@fastmail.fm>
Sun, 24 Jan 2010 11:51:09 +0000 (11:51 +0000)
committerVáclav Slavík <vslavik@fastmail.fm>
Sun, 24 Jan 2010 11:51:09 +0000 (11:51 +0000)
The computation is now identical to Windows native one. To achieve this,
MSDN-recommended GetTextExtent() call is used instead of GetCharWidth().
wxMulDivInt32() is used instead of integer arithmetics to achieve
correct rounding.

Use toplevel parent's font instead of window's own. This makes more
sense, as dialog units are defined for TLWs, not individual subcontrols.

Also fixed wxMSW's wxButton::GetDefaultSize() to compute dialog units
correctly.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@63251 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/private/window.h [new file with mode: 0644]
include/wx/window.h
src/common/wincmn.cpp
src/msw/button.cpp

diff --git a/include/wx/private/window.h b/include/wx/private/window.h
new file mode 100644 (file)
index 0000000..3084665
--- /dev/null
@@ -0,0 +1,39 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        wx/private/window.h
+// Purpose:     misc wxWindow helpers
+// Author:      Vaclav Slavik
+// Created:     2010-01-21
+// RCS-ID:      $Id$
+// Copyright:   (c) 2010 Vaclav Slavik
+// Licence:     wxWindows licence
+/////////////////////////////////////////////////////////////////////////////
+
+#ifndef _WX_PRIVATE_WINDOW_H_
+#define _WX_PRIVATE_WINDOW_H_
+
+#include "wx/gdicmn.h"
+
+namespace wxPrivate
+{
+
+// 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
+// http://support.microsoft.com/default.aspx/kb/145994 for detailed discussion.
+//
+// This helper function computes font dimensions in the same way. It works with
+// either wxDC or wxWindow argument.
+template<typename T>
+inline wxSize GetAverageASCIILetterSize(const T& of_what)
+{
+    const wxStringCharType *TEXT_TO_MEASURE =
+        wxS("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz");
+
+    wxSize s = of_what.GetTextExtent(TEXT_TO_MEASURE);
+    s.x = (s.x / 26 + 1) / 2;
+    return s;
+}
+
+} // namespace wxPrivate
+
+#endif // _WX_PRIVATE_WINDOW_H_
index e4f15868b4b211dd61322ad10d84d0c347141ffb..9218362735bf52068b2cfa78def8497e516bfbb9 100644 (file)
@@ -1736,6 +1736,8 @@ private:
     // explicitly disabled with SetAutoLayout(false)
     void InternalOnSize(wxSizeEvent& event);
 
+    // base for dialog unit conversion, i.e. average character size
+    wxSize GetDlgUnitBase() const;
 
     // the stack of windows which have captured the mouse
     static struct WXDLLIMPEXP_FWD_CORE wxWindowNext *ms_winCaptureNext;
index a9c2b445052faca8af1bf66ab75890a21edf02f3..e67ee6a67b738af3204f44ec06a53863b7b5a662 100644 (file)
 #endif
 
 #include "wx/platinfo.h"
+#include "wx/private/window.h"
+
+#ifdef __WXMSW__
+    #include "wx/msw/wrapwin.h"
+#endif
 
 // Windows List
 WXDLLIMPEXP_DATA_CORE(wxWindowList) wxTopLevelWindows;
@@ -2461,24 +2466,57 @@ void wxWindowBase::DoUpdateWindowUI(wxUpdateUIEvent& event)
 // dialog units translations
 // ----------------------------------------------------------------------------
 
+// 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
+// http://support.microsoft.com/default.aspx/kb/145994 for detailed discussion.
+// It's important that we perform the conversion in identical way, because
+// dialog units natively exist only on Windows and Windows HIG is expressed
+// using them.
+wxSize wxWindowBase::GetDlgUnitBase() const
+{
+    const wxWindow *parent = wxGetTopLevelParent((wxWindow*)this);
+
+    if ( !parent->m_font.IsOk() )
+    {
+        // 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;
+    }
+    else
+    {
+        // Custom font, we always need to compute the result
+        return wxPrivate::GetAverageASCIILetterSize(*parent);
+    }
+}
+
 wxPoint wxWindowBase::ConvertPixelsToDialog(const wxPoint& pt) const
 {
+    const wxSize base = GetDlgUnitBase();
+
+    // NB: wxMulDivInt32() is used, because it correctly rounds the result
+
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
-        pt2.x = (int) ((pt.x * 4) / GetCharWidth());
+        pt2.x = wxMulDivInt32(pt.x, 4, base.x);
     if (pt.y != wxDefaultCoord)
-        pt2.y = (int) ((pt.y * 8) / GetCharHeight());
+        pt2.y = wxMulDivInt32(pt.y, 8, base.y);
 
     return pt2;
 }
 
 wxPoint wxWindowBase::ConvertDialogToPixels(const wxPoint& pt) const
 {
+    const wxSize base = GetDlgUnitBase();
+
     wxPoint pt2 = wxDefaultPosition;
     if (pt.x != wxDefaultCoord)
-        pt2.x = (int) ((pt.x * GetCharWidth()) / 4);
+        pt2.x = wxMulDivInt32(pt.x, base.x, 4);
     if (pt.y != wxDefaultCoord)
-        pt2.y = (int) ((pt.y * GetCharHeight()) / 8);
+        pt2.y = wxMulDivInt32(pt.y, base.y, 8);
 
     return pt2;
 }
index ad3f9a452fa01f4e93db1e53e9594647ce17ebd8..2f68d8b36253c3d791cdf091c10a95679a64d3f8 100644 (file)
@@ -44,6 +44,7 @@
 #include "wx/msw/private.h"
 #include "wx/msw/private/button.h"
 #include "wx/msw/private/dc.h"
+#include "wx/private/window.h"
 
 using namespace wxMSWImpl;
 
@@ -662,16 +663,20 @@ wxSize wxButtonBase::GetDefaultSize()
         wxScreenDC dc;
         dc.SetFont(wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT));
 
-        // the size of a standard button in the dialog units is 50x14,
-        // translate this to pixels
-        // NB1: the multipliers come from the Windows convention
-        // NB2: the extra +1/+2 were needed to get the size be the same as the
-        //      size of the buttons in the standard dialog - I don't know how
-        //      this happens, but on my system this size is 75x23 in pixels and
-        //      23*8 isn't even divisible by 14... Would be nice to understand
-        //      why these constants are needed though!
-        s_sizeBtn.x = (50 * (dc.GetCharWidth() + 1))/4;
-        s_sizeBtn.y = ((14 * dc.GetCharHeight()) + 2)/8;
+        // The size of a standard button in the dialog units is 50x14,
+        // translate this to 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
+        // http://support.microsoft.com/default.aspx/kb/145994 for detailed
+        // discussion.
+        //
+        // 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);
     }
 
     return s_sizeBtn;