]> git.saurik.com Git - wxWidgets.git/commitdiff
Update all windows associated with the tooltip when it changes in wxMSW.
authorVadim Zeitlin <vadim@wxwidgets.org>
Sun, 7 Nov 2010 13:12:16 +0000 (13:12 +0000)
committerVadim Zeitlin <vadim@wxwidgets.org>
Sun, 7 Nov 2010 13:12:16 +0000 (13:12 +0000)
Although the tooltip was initially correctly set for all windows associated
with it, it was only updated for the main one if its text changed later. This
resulted in leaving the old tooltip for the composite controls such as
wxComboBox or controls with sub-windows such as wxRadioBox.

Fix this by storing all windows associated with the tooltip (for space
efficiency, only allocate the array if necessary however as it will be empty
in the majority of cases) and apply SetTip() to all of them, not just the main
one.

Closes #12659.

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

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

index c720ae3dc2aa4916b5fec9355ae57993f00bff53..a5184071af015550c4891c301a289291cbc4d8cc 100644 (file)
@@ -16,6 +16,7 @@
 #include "wx/gdicmn.h"
 
 class WXDLLIMPEXP_FWD_CORE wxWindow;
+class wxToolTipOtherWindows;
 
 class WXDLLIMPEXP_CORE wxToolTip : public wxObject
 {
@@ -64,11 +65,23 @@ public:
     // remove any tooltip from the window
     static void Remove(WXHWND hwnd, unsigned int id, const wxRect& rc);
 
-    // the rect we're associated with
+    // Set the rectangle we're associated with. This rectangle is only used for
+    // the main window, not any sub-windows added with Add() so in general it
+    // makes sense to use it for tooltips associated with a single window only.
     void SetRect(const wxRect& rc);
-    const wxRect& GetRect() const { return m_rect; }
 
 private:
+    // Adds a window other than our main m_window to this tooltip.
+    void DoAddOtherWindow(WXHWND hWnd);
+
+    // Perform the specified operation for the given window only.
+    void DoSetTip(WXHWND hWnd);
+    void DoRemove(WXHWND hWnd);
+
+    // Call the given function for all windows we're associated with.
+    void DoForAllWindows(void (wxToolTip::*func)(WXHWND));
+
+
     // the one and only one tooltip control we use - never access it directly
     // but use GetToolTipCtrl() which will create it when needed
     static WXHWND ms_hwndTT;
@@ -83,7 +96,8 @@ private:
     void Remove();
 
     wxString  m_text;           // tooltip text
-    wxWindow* m_window;         // window we're associated with
+    wxWindow* m_window;         // main window we're associated with
+    wxToolTipOtherWindows *m_others; // other windows associated with it or NULL
     wxRect    m_rect;           // the rect of the window for which this tooltip is shown
                                 // (or a rect with width/height == 0 to show it for the entire window)
     unsigned int m_id;          // the id of this tooltip (ignored when m_rect width/height is 0)
index f43fed3843e996d8ccc8339aa913b10169feb895..e9e84c7621cd3db8c01ab1c11d06bb814c486fd5 100644 (file)
@@ -34,6 +34,7 @@
 #endif
 
 #include "wx/tokenzr.h"
+#include "wx/vector.h"
 #include "wx/msw/private.h"
 
 #ifndef TTTOOLINFO_V1_SIZE
@@ -75,6 +76,12 @@ static WNDPROC gs_wndprocToolTip = (WNDPROC)NULL;
 // private classes
 // ----------------------------------------------------------------------------
 
+// This is simply a wrapper for vector<HWND> but defined as a class to hide the
+// details from the public header.
+class wxToolTipOtherWindows : public wxVector<WXHWND>
+{
+};
+
 // a wrapper around TOOLINFO Win32 structure
 #ifdef __VISUALC__
     #pragma warning( disable : 4097 ) // we inherit from a typedef - so what?
@@ -308,6 +315,7 @@ wxToolTip::wxToolTip(const wxString &tip)
          : m_text(tip)
 {
     m_window = NULL;
+    m_others = NULL;
 
     // make sure m_rect.IsEmpty() == true
     m_rect.SetWidth(0);
@@ -321,6 +329,7 @@ wxToolTip::wxToolTip(wxWindow* win, unsigned int id, const wxString &tip, const
          : m_text(tip), m_rect(rc), m_id(id)
 {
     m_window = NULL;
+    m_others = NULL;
 
     SetWindow(win);
 }
@@ -330,6 +339,8 @@ wxToolTip::~wxToolTip()
     // the tooltip has to be removed before deleting. Otherwise, if it is visible
     // while being deleted, there will be a delay before it goes away.
     Remove();
+
+    delete m_others;
 }
 
 // ----------------------------------------------------------------------------
@@ -344,16 +355,36 @@ void wxToolTip::Remove(WXHWND hWnd, unsigned int id, const wxRect& rc)
     (void)SendTooltipMessage(GetToolTipCtrl(), TTM_DELTOOL, &ti);
 }
 
-void wxToolTip::Remove()
+void wxToolTip::DoRemove(WXHWND hWnd)
 {
-    // remove this tool from the tooltip control
-    if ( m_window )
+    if ( hWnd == m_window->GetHWND() )
+    {
+        // Remove the tooltip from the main window.
+        Remove(hWnd, m_id, m_rect);
+    }
+    else
     {
-        Remove(m_window->GetHWND(), m_id, m_rect);
+        // Not really sure what to pass to remove in this case...
+        Remove(hWnd, 0, wxRect());
     }
 }
 
+void wxToolTip::Remove()
+{
+    DoForAllWindows(&wxToolTip::DoRemove);
+}
+
 void wxToolTip::Add(WXHWND hWnd)
+{
+    if ( !m_others )
+        m_others = new wxToolTipOtherWindows;
+
+    m_others->push_back(hWnd);
+
+    DoAddOtherWindow(hWnd);
+}
+
+void wxToolTip::DoAddOtherWindow(WXHWND hWnd)
 {
     HWND hwnd = (HWND)hWnd;
 
@@ -486,7 +517,7 @@ void wxToolTip::SetWindow(wxWindow *win)
             HWND hwnd = GetDlgItem(GetHwndOf(m_window), id);
             if ( !hwnd )
             {
-                // may be it's a child of parent of the control, in fact?
+                // maybe it's a child of parent of the control, in fact?
                 // (radiobuttons are subcontrols, i.e. children of the radiobox
                 // for wxWidgets but are its siblings at Windows level)
                 hwnd = GetDlgItem(GetHwndOf(m_window->GetParent()), id);
@@ -516,19 +547,43 @@ void wxToolTip::SetTip(const wxString& tip)
 {
     m_text = tip;
 
-    if ( m_window )
+    DoForAllWindows(&wxToolTip::DoSetTip);
+}
+
+void wxToolTip::DoSetTip(WXHWND hWnd)
+{
+    // update the tip text shown by the control
+    wxToolInfo ti((HWND)hWnd, m_id, m_rect);
+
+    // for some reason, changing the tooltip text directly results in
+    // repaint of the controls under it, see #10520 -- but this doesn't
+    // happen if we reset it first
+    ti.lpszText = const_cast<wxChar *>(wxT(""));
+    (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, &ti);
+
+    ti.lpszText = const_cast<wxChar *>(m_text.wx_str());
+    (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, &ti);
+}
+
+void wxToolTip::DoForAllWindows(void (wxToolTip::*func)(WXHWND))
+{
+    if ( !m_window )
     {
-        // update the tip text shown by the control
-        wxToolInfo ti(GetHwndOf(m_window), m_id, m_rect);
+        wxASSERT_MSG( !m_others,
+                      wxS("Can't have other windows without the main one.") );
+        return;
+    }
 
-        // for some reason, changing the tooltip text directly results in
-        // repaint of the controls under it, see #10520 -- but this doesn't
-        // happen if we reset it first
-        ti.lpszText = const_cast<wxChar *>(wxT(""));
-        (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, &ti);
+    (this->*func)(m_window->GetHWND());
 
-        ti.lpszText = const_cast<wxChar *>(m_text.wx_str());
-        (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, &ti);
+    if ( m_others )
+    {
+        for ( wxToolTipOtherWindows::const_iterator it = m_others->begin();
+              it != m_others->end();
+              ++it )
+        {
+            (this->*func)(*it);
+        }
     }
 }