]> git.saurik.com Git - wxWidgets.git/blobdiff - src/msw/statusbar.cpp
fix compilation without wxUSE_STREAMS (closes #10900)
[wxWidgets.git] / src / msw / statusbar.cpp
index c21dac1aa9edbb650d6e4274e7a91b0df30c5d8c..c8921219cb9e0130886814c52ad0f8bfac9d3b02 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);
@@ -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,11 +178,26 @@ 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();
+    
+    // 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[])
@@ -191,33 +217,42 @@ 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;
+
+
+    // FIXME: we may want to call UpdateFieldText() here since we may need to (de)ellipsize status texts
 }
 
 void wxStatusBar::SetStatusText(const wxString& strText, int nField)
 {
     wxCHECK_RET( (nField >= 0) && ((size_t)nField < m_panes.GetCount()),
-                 _T("invalid statusbar field index") );
+                 "invalid statusbar field index" );
 
     if ( strText == GetStatusText(nField) )
     {
-       // don't call StatusBar_SetText() to avoid flicker
-       return;
+        // don't call StatusBar_SetText() to avoid flicker
+        return;
     }
 
     wxStatusBarBase::SetStatusText(strText, nField);
@@ -256,18 +291,69 @@ 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)
     {
-        wxLogLastError(wxT("StatusBar_SetText"));
+        // 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("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 +377,21 @@ 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
@@ -428,14 +512,13 @@ 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,7 +566,10 @@ 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);
@@ -494,4 +580,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