]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/statusbar.cpp
Output the extracted number from wxString::ToXXX() even if it returns false.
[wxWidgets.git] / src / msw / statusbar.cpp
index c21dac1aa9edbb650d6e4274e7a91b0df30c5d8c..8b588197574f18527fe5ed0010067913014b13f5 100644 (file)
@@ -31,6 +31,7 @@
 #endif
 
 #include "wx/msw/private.h"
+#include "wx/tooltip.h"
 #include <windowsx.h>
 
 #if wxUSE_UXTHEME
@@ -71,7 +72,7 @@ bool wxStatusBar::Create(wxWindow *parent,
                          long style,
                          const wxString& name)
 {
-    wxCHECK_MSG( parent, false, wxT("status bar must have a parent") );
+    wxCHECK_MSG( parent, false, "status bar must have a parent" );
 
     SetName(name);
     SetWindowStyleFlag(style);
@@ -107,7 +108,7 @@ bool wxStatusBar::Create(wxWindow *parent,
     m_hWnd = CreateWindow
              (
                 STATUSCLASSNAME,
-                _T(""),
+                wxT(""),
                 wstyle,
                 0, 0, 0, 0,
                 GetHwndOf(parent),
@@ -125,7 +126,7 @@ bool wxStatusBar::Create(wxWindow *parent,
     SetFieldsCount(1);
     SubclassWin(m_hWnd);
 
-    // cache the DC instance used by UpdateFieldText:
+    // cache the DC instance used by DoUpdateStatusText:
     // NOTE: create the DC before calling InheritAttributes() since
     //       it may result in a call to our SetFont()
     m_pDC = new wxClientDC(this);
@@ -152,6 +153,16 @@ wxStatusBar::~wxStatusBar()
     // occupy
     PostSizeEventToParent();
 
+    // delete existing tooltips
+    for (size_t i=0; i<m_tooltips.size(); i++)
+    {
+        if (m_tooltips[i])
+        {
+            delete m_tooltips[i];
+            m_tooltips[i] = NULL;
+        }
+    }
+
     wxDELETE(m_pDC);
 }
 
@@ -167,21 +178,36 @@ bool wxStatusBar::SetFont(const wxFont& font)
 void wxStatusBar::SetFieldsCount(int nFields, const int *widths)
 {
     // this is a Windows limitation
-    wxASSERT_MSG( (nFields > 0) && (nFields < 255), _T("too many fields") );
+    wxASSERT_MSG( (nFields > 0) && (nFields < 255), "too many fields" );
 
     wxStatusBarBase::SetFieldsCount(nFields, widths);
 
-    SetFieldsWidth();
+    MSWUpdateFieldsWidths();
+
+    // keep in synch also our m_tooltips array
+
+    // reset all current tooltips
+    for (size_t i=0; i<m_tooltips.size(); i++)
+    {
+        if (m_tooltips[i])
+        {
+            delete m_tooltips[i];
+            m_tooltips[i] = NULL;
+        }
+    }
+
+    // shrink/expand the array:
+    m_tooltips.resize(m_panes.GetCount(), NULL);
 }
 
 void wxStatusBar::SetStatusWidths(int n, const int widths[])
 {
     wxStatusBarBase::SetStatusWidths(n, widths);
 
-    SetFieldsWidth();
+    MSWUpdateFieldsWidths();
 }
 
-void wxStatusBar::SetFieldsWidth()
+void wxStatusBar::MSWUpdateFieldsWidths()
 {
     if ( m_panes.IsEmpty() )
         return;
@@ -191,41 +217,36 @@ void wxStatusBar::SetFieldsWidth()
 
     int extraWidth = aBorders[2]; // space between fields
 
+
+    // distribute the available space (client width) among the various fields:
+
     wxArrayInt widthsAbs =
         CalculateAbsWidths(GetClientSize().x - extraWidth*(m_panes.GetCount() - 1));
 
+
+    // update the field widths in the native control:
+
     int *pWidths = new int[m_panes.GetCount()];
 
     int nCurPos = 0;
-    for ( size_t i = 0; i < m_panes.GetCount(); i++ ) {
+    for ( size_t i = 0; i < m_panes.GetCount(); i++ )
+    {
         nCurPos += widthsAbs[i] + extraWidth;
         pWidths[i] = nCurPos;
     }
 
-    if ( !StatusBar_SetParts(GetHwnd(), m_panes.GetCount(), pWidths) ) {
-        wxLogLastError(wxT("StatusBar_SetParts"));
+    if ( !StatusBar_SetParts(GetHwnd(), m_panes.GetCount(), pWidths) )
+    {
+        wxLogLastError("StatusBar_SetParts");
     }
 
     delete [] pWidths;
-}
-
-void wxStatusBar::SetStatusText(const wxString& strText, int nField)
-{
-    wxCHECK_RET( (nField >= 0) && ((size_t)nField < m_panes.GetCount()),
-                 _T("invalid statusbar field index") );
-
-    if ( strText == GetStatusText(nField) )
-    {
-       // don't call StatusBar_SetText() to avoid flicker
-       return;
-    }
 
-    wxStatusBarBase::SetStatusText(strText, nField);
 
-    UpdateFieldText(nField);
+    // FIXME: we may want to call DoUpdateStatusText() here since we may need to (de)ellipsize status texts
 }
 
-void wxStatusBar::UpdateFieldText(int nField)
+void wxStatusBar::DoUpdateStatusText(int nField)
 {
     if (!m_pDC)
         return;
@@ -256,18 +277,71 @@ void wxStatusBar::UpdateFieldText(int nField)
     else
         margin = 4;
 
+    int maxWidth = rc.GetWidth() - margin;    // leave a small margin
+    wxString text = GetStatusText(nField);
+
     // do we need to ellipsize this string?
-    wxString ellipsizedStr =
-        wxControl::Ellipsize(GetStatusText(nField), *m_pDC,
-            GetLayoutDirection() == wxLayout_RightToLeft ? wxELLIPSIZE_START : wxELLIPSIZE_END,
-            rc.GetWidth() - margin,    // leave a small margin
-            wxELLIPSIZE_EXPAND_TAB);
-
-    // Pass both field number and style. MSDN library doesn't mention
-    // that nField and style have to be 'ORed'
-    if ( !StatusBar_SetText(GetHwnd(), nField | style, ellipsizedStr.wx_str()) )
+    wxEllipsizeMode ellmode = (wxEllipsizeMode)-1;
+    if (HasFlag(wxSTB_ELLIPSIZE_START)) ellmode = wxELLIPSIZE_START;
+    else if (HasFlag(wxSTB_ELLIPSIZE_MIDDLE)) ellmode = wxELLIPSIZE_MIDDLE;
+    else if (HasFlag(wxSTB_ELLIPSIZE_END)) ellmode = wxELLIPSIZE_END;
+
+    if (ellmode == (wxEllipsizeMode)-1)
+    {
+        // if we have the wxSTB_SHOW_TIPS we must set the ellipsized flag even if
+        // we don't ellipsize the text but just truncate it
+        if (HasFlag(wxSTB_SHOW_TIPS))
+            SetEllipsizedFlag(nField, m_pDC->GetTextExtent(text).GetWidth() > maxWidth);
+    }
+    else
+    {
+        text = wxControl::Ellipsize(text,
+                                     *m_pDC,
+                                     ellmode,
+                                     maxWidth,
+                                     wxELLIPSIZE_EXPAND_TAB);
+
+        // update the ellipsization status for this pane; this is used later to
+        // decide whether a tooltip should be shown or not for this pane
+        // (if we have wxSTB_SHOW_TIPS)
+        SetEllipsizedFlag(nField, text != GetStatusText(nField));
+    }
+
+    // Set the status text in the native control passing both field number and style.
+    // NOTE: MSDN library doesn't mention that nField and style have to be 'ORed'
+    if ( !StatusBar_SetText(GetHwnd(), nField | style, text.wx_str()) )
     {
-        wxLogLastError(wxT("StatusBar_SetText"));
+        wxLogLastError("StatusBar_SetText");
+    }
+
+    if (HasFlag(wxSTB_SHOW_TIPS))
+    {
+        wxASSERT(m_tooltips.size() == m_panes.GetCount());
+
+        if (m_tooltips[nField])
+        {
+            if (GetField(nField).IsEllipsized())
+            {
+                // update the rect of this tooltip:
+                m_tooltips[nField]->SetRect(rc);
+
+                // update also the text:
+                m_tooltips[nField]->SetTip(GetStatusText(nField));
+            }
+            else
+            {
+                // delete the tooltip associated with this pane; it's not needed anymore
+                delete m_tooltips[nField];
+                m_tooltips[nField] = NULL;
+            }
+        }
+        else
+        {
+            // create a new tooltip for this pane if needed
+            if (GetField(nField).IsEllipsized())
+                m_tooltips[nField] = new wxToolTip(this, nField, GetStatusText(nField), rc);
+            //else: leave m_tooltips[nField]==NULL
+        }
     }
 }
 
@@ -291,23 +365,23 @@ void wxStatusBar::SetMinHeight(int height)
 {
     SendMessage(GetHwnd(), SB_SETMINHEIGHT, height + 2*GetBorderY(), 0);
 
-    // have to send a (dummy) WM_SIZE to redraw it now
+    // we have to send a (dummy) WM_SIZE to redraw it now
     SendMessage(GetHwnd(), WM_SIZE, 0, 0);
 }
 
 bool wxStatusBar::GetFieldRect(int i, wxRect& rect) const
 {
     wxCHECK_MSG( (i >= 0) && ((size_t)i < m_panes.GetCount()), false,
-                 _T("invalid statusbar field index") );
+                 "invalid statusbar field index" );
 
     RECT r;
     if ( !::SendMessage(GetHwnd(), SB_GETRECT, i, (LPARAM)&r) )
     {
-        wxLogLastError(wxT("SendMessage(SB_GETRECT)"));
+        wxLogLastError("SendMessage(SB_GETRECT)");
     }
 
 #if wxUSE_UXTHEME
-    wxUxThemeHandle theme((wxStatusBar *)this, L"Status"); // const_cast
+    wxUxThemeHandle theme(const_cast<wxStatusBar*>(this), L"Status");
     if ( theme )
     {
         // by default Windows has a 2 pixel border to the right of the left
@@ -392,7 +466,7 @@ void wxStatusBar::DoMoveWindow(int x, int y, int width, int height)
     }
 
     // adjust fields widths to the new size
-    SetFieldsWidth();
+    MSWUpdateFieldsWidths();
 
     // we have to trigger wxSizeEvent if there are children window in status
     // bar because GetFieldRect returned incorrect (not updated) values up to
@@ -428,13 +502,14 @@ void wxStatusBar::SetStatusStyles(int n, const int styles[])
             style = 0;
             break;
         }
+
         // The SB_SETTEXT message is both used to set the field's text as well as
-        // the fields' styles. MSDN library doesn't mention
-        // that nField and style have to be 'ORed'
+        // the fields' styles.
+        // NOTE: MSDN library doesn't mention that nField and style have to be 'ORed'
         wxString text = GetStatusText(i);
         if (!StatusBar_SetText(GetHwnd(), style | i, text.wx_str()))
         {
-            wxLogLastError(wxT("StatusBar_SetText"));
+            wxLogLastError("StatusBar_SetText");
         }
     }
 }
@@ -483,10 +558,13 @@ wxStatusBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
     }
 #endif
 
-    if ( nMsg == WM_SIZE )
+    bool needsEllipsization = HasFlag(wxSTB_ELLIPSIZE_START) ||
+                              HasFlag(wxSTB_ELLIPSIZE_MIDDLE) ||
+                              HasFlag(wxSTB_ELLIPSIZE_END);
+    if ( nMsg == WM_SIZE && needsEllipsization )
     {
         for (int i=0; i<GetFieldsCount(); i++)
-            UpdateFieldText(i);
+            DoUpdateStatusText(i);
             // re-set the field text, in case we need to ellipsize
             // (or de-ellipsize) some parts of it
     }
@@ -494,4 +572,47 @@ wxStatusBar::MSWWindowProc(WXUINT nMsg, WXWPARAM wParam, WXLPARAM lParam)
     return wxStatusBarBase::MSWWindowProc(nMsg, wParam, lParam);
 }
 
+#if wxUSE_TOOLTIPS
+bool wxStatusBar::MSWProcessMessage(WXMSG* pMsg)
+{
+    if ( HasFlag(wxSTB_SHOW_TIPS) )
+    {
+        // for a tooltip to be shown, we need to relay mouse events to it;
+        // this is typically done by wxWindowMSW::MSWProcessMessage but only
+        // if wxWindow::m_tooltip pointer is non-NULL.
+        // Since wxStatusBar has multiple tooltips for a single HWND, it keeps
+        // wxWindow::m_tooltip == NULL and then relays mouse events here:
+        MSG *msg = (MSG *)pMsg;
+        if ( msg->message == WM_MOUSEMOVE )
+            wxToolTip::RelayEvent(pMsg);
+    }
+
+    return wxWindow::MSWProcessMessage(pMsg);
+}
+
+bool wxStatusBar::MSWOnNotify(int WXUNUSED(idCtrl), WXLPARAM lParam, WXLPARAM* WXUNUSED(result))
+{
+    if ( HasFlag(wxSTB_SHOW_TIPS) )
+    {
+        // see comment in wxStatusBar::MSWProcessMessage for more info;
+        // basically we need to override wxWindow::MSWOnNotify because
+        // we have wxWindow::m_tooltip always NULL but we still use tooltips...
+
+        NMHDR* hdr = (NMHDR *)lParam;
+
+        wxString str;
+        if (hdr->idFrom < m_tooltips.size() && m_tooltips[hdr->idFrom])
+            str = m_tooltips[hdr->idFrom]->GetTip();
+
+        if ( HandleTooltipNotify(hdr->code, lParam, str))
+        {
+            // processed
+            return true;
+        }
+    }
+
+    return false;
+}
+#endif // wxUSE_TOOLTIPS
+
 #endif // wxUSE_STATUSBAR && wxUSE_NATIVE_STATUSBAR