]> git.saurik.com Git - wxWidgets.git/commitdiff
Account for the margins used by Windows around status bar text.
authorVadim Zeitlin <vadim@wxwidgets.org>
Mon, 21 Sep 2009 13:00:36 +0000 (13:00 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Mon, 21 Sep 2009 13:00:36 +0000 (13:00 +0000)
Because Windows uses margins around the text drawn in the status bar, naively
setting a field width to the size of the text didn't work (see previous
commit for an example). As this seems a natural enough thing to do, account
for this margin inside wxStatusBar itself to avoid the user code the trouble
of having to call some special function to do it. Notice that this does mean
that fields not containing text may be slightly larger than needed, but we
consider that this (rarer) case is less important.

Also account correctly for the status bar grip size. And while we still hard
code its size, do it in a clearly named function instead of using completely
mysterious constants here and there.

Closes #10696.

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

include/wx/msw/statusbar.h
src/msw/statusbar.cpp

index 14e65d47af2d13c22287e640f0ccff84775529ad..e942dd56b990582187531825fb1c940cd391cf28 100644 (file)
@@ -79,6 +79,28 @@ protected:
     wxVector<wxToolTip*> m_tooltips;
 
 private:
+    struct MSWBorders
+    {
+        int horz,
+            vert,
+            between;
+    };
+
+    // retrieve all status bar borders using SB_GETBORDERS
+    MSWBorders MSWGetBorders() const;
+
+    // return the size of the border between the fields
+    int MSWGetBorderWidth() const;
+
+    struct MSWMetrics
+    {
+        int gripWidth,
+            textMargin;
+    };
+
+    // return the various status bar metrics
+    static const MSWMetrics& MSWGetMetrics();
+
     DECLARE_DYNAMIC_CLASS_NO_COPY(wxStatusBar)
 };
 
index 8b588197574f18527fe5ed0010067913014b13f5..663c7f6505832cdea40f10d4bc266f3f2ed453a9 100644 (file)
@@ -9,6 +9,14 @@
 // Licence:     wxWindows licence
 ///////////////////////////////////////////////////////////////////////////////
 
+// ============================================================================
+// declarations
+// ============================================================================
+
+// ----------------------------------------------------------------------------
+// headers
+// ----------------------------------------------------------------------------
+
 // for compilers that support precompilation, includes "wx.h".
 #include "wx/wxprec.h"
 
     #include "wx/msw/uxtheme.h"
 #endif
 
+// ----------------------------------------------------------------------------
+// constants
+// ----------------------------------------------------------------------------
+
+namespace
+{
+
 // no idea for a default width, just choose something
-#define DEFAULT_FIELD_WIDTH 25
+static const int DEFAULT_FIELD_WIDTH = 25;
+
+} // anonymous namespace
 
 // ----------------------------------------------------------------------------
 // macros
@@ -212,30 +229,35 @@ void wxStatusBar::MSWUpdateFieldsWidths()
     if ( m_panes.IsEmpty() )
         return;
 
-    int aBorders[3];
-    SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)aBorders);
+    const int count = m_panes.GetCount();
+
+    const int extraWidth = MSWGetBorderWidth() + MSWGetMetrics().textMargin;
 
-    int extraWidth = aBorders[2]; // space between fields
+    // compute the effectively available amount of space:
+    int widthAvailable = GetClientSize().x;     // start with the entire width
+    widthAvailable -= extraWidth*(count - 1);   // extra space between fields
+    widthAvailable -= MSWGetMetrics().textMargin;   // and for the last field
 
+    if ( HasFlag(wxSTB_SIZEGRIP) )
+        widthAvailable -= MSWGetMetrics().gripWidth;
 
     // distribute the available space (client width) among the various fields:
 
-    wxArrayInt widthsAbs =
-        CalculateAbsWidths(GetClientSize().x - extraWidth*(m_panes.GetCount() - 1));
+    wxArrayInt widthsAbs = CalculateAbsWidths(widthAvailable);
 
 
     // update the field widths in the native control:
 
-    int *pWidths = new int[m_panes.GetCount()];
+    int *pWidths = new int[count];
 
     int nCurPos = 0;
-    for ( size_t i = 0; i < m_panes.GetCount(); i++ )
+    for ( int i = 0; i < count; i++ )
     {
         nCurPos += widthsAbs[i] + extraWidth;
         pWidths[i] = nCurPos;
     }
 
-    if ( !StatusBar_SetParts(GetHwnd(), m_panes.GetCount(), pWidths) )
+    if ( !StatusBar_SetParts(GetHwnd(), count, pWidths) )
     {
         wxLogLastError("StatusBar_SetParts");
     }
@@ -271,13 +293,8 @@ void wxStatusBar::DoUpdateStatusText(int nField)
     wxRect rc;
     GetFieldRect(nField, rc);
 
-    int margin;
-    if (nField == GetFieldsCount()-1)
-        margin = -6;        // windows reports a smaller rect for the last field; enlarge it
-    else
-        margin = 4;
+    const int maxWidth = rc.GetWidth() - MSWGetMetrics().textMargin;
 
-    int maxWidth = rc.GetWidth() - margin;    // leave a small margin
     wxString text = GetStatusText(nField);
 
     // do we need to ellipsize this string?
@@ -345,20 +362,59 @@ void wxStatusBar::DoUpdateStatusText(int nField)
     }
 }
 
-int wxStatusBar::GetBorderX() const
+wxStatusBar::MSWBorders wxStatusBar::MSWGetBorders() const
 {
     int aBorders[3];
     SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)aBorders);
 
-    return aBorders[0];
+    MSWBorders borders;
+    borders.horz = aBorders[0];
+    borders.vert = aBorders[1];
+    borders.between = aBorders[2];
+    return borders;
+}
+
+int wxStatusBar::GetBorderX() const
+{
+    return MSWGetBorders().horz;
 }
 
 int wxStatusBar::GetBorderY() const
 {
-    int aBorders[3];
-    SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)aBorders);
+    return MSWGetBorders().vert;
+}
 
-    return aBorders[1];
+int wxStatusBar::MSWGetBorderWidth() const
+{
+    return MSWGetBorders().between;
+}
+
+/* static */
+const wxStatusBar::MSWMetrics& wxStatusBar::MSWGetMetrics()
+{
+    static MSWMetrics s_metrics = { 0 };
+    if ( !s_metrics.textMargin )
+    {
+        // Grip size should be self explanatory (the only problem with it is
+        // that it's hard coded as we don't know how to find its size using
+        // API) but the margin might merit an explanation: Windows offsets the
+        // text drawn in status bar panes so we need to take this extra margin
+        // into account to make sure the text drawn by user fits inside the
+        // pane. Notice that it's not the value returned by SB_GETBORDERS
+        // which, at least on this Windows 2003 system, returns {0, 2, 2}
+        if ( wxUxThemeEngine::GetIfActive() )
+        {
+            s_metrics.gripWidth = 20;
+            s_metrics.textMargin = 8;
+        }
+        else // classic/unthemed look
+        {
+            s_metrics.gripWidth = 18;
+            s_metrics.textMargin = 4;
+        }
+    }
+
+    return s_metrics;
 }
 
 void wxStatusBar::SetMinHeight(int height)
@@ -399,13 +455,20 @@ bool wxStatusBar::GetFieldRect(int i, wxRect& rect) const
 
     wxCopyRECTToRect(r, rect);
 
+    // Windows seems to under-report the size of the last field rectangle,
+    // presumably in order to prevent the buggy applications from overflowing
+    // onto the size grip but we want to return the real size to wx users
+    if ( HasFlag(wxSTB_SIZEGRIP) && i == (int)m_panes.GetCount() - 1 )
+    {
+        rect.width += MSWGetMetrics().gripWidth - MSWGetBorderWidth();
+    }
+
     return true;
 }
 
 wxSize wxStatusBar::DoGetBestSize() const
 {
-    int borders[3];
-    SendMessage(GetHwnd(), SB_GETBORDERS, 0, (LPARAM)borders);
+    const MSWBorders borders = MSWGetBorders();
 
     // calculate width
     int width = 0;
@@ -425,7 +488,7 @@ wxSize wxStatusBar::DoGetBestSize() const
         }
 
         // add the space between fields
-        width += borders[2];
+        width += borders.between;
     }
 
     if ( !width )
@@ -438,7 +501,7 @@ wxSize wxStatusBar::DoGetBestSize() const
     int height;
     wxGetCharSize(GetHWND(), NULL, &height, GetFont());
     height = EDIT_HEIGHT_FROM_CHAR_HEIGHT(height);
-    height += borders[1];
+    height += borders.vert;
 
     wxSize best(width, height);
     CacheBestSize(best);