From dc6588e771dc7180a69841a1b5ec29b4e5ea73d0 Mon Sep 17 00:00:00 2001
From: Vadim Zeitlin <vadim@wxwidgets.org>
Date: Sun, 11 Jun 2006 21:10:32 +0000
Subject: [PATCH] made it possible to associate context help to a region of a
 window

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@39675 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
---
 docs/changes.txt           |  1 +
 docs/latex/wx/helpprov.tex | 41 +++++++++++++++++++++---
 docs/latex/wx/hprovcnt.tex |  2 +-
 docs/latex/wx/hprovsmp.tex |  2 +-
 docs/latex/wx/window.tex   | 19 ++++++++++-
 include/wx/cshelp.h        | 65 ++++++++++++++++++++++++++++++++++----
 include/wx/window.h        | 16 ++++++++--
 src/common/cshelp.cpp      | 61 ++++++++++++++++++++++-------------
 src/common/wincmn.cpp      | 11 ++++---
 9 files changed, 174 insertions(+), 44 deletions(-)

diff --git a/docs/changes.txt b/docs/changes.txt
index 2be07bccdb..7e446ee585 100644
--- a/docs/changes.txt
+++ b/docs/changes.txt
@@ -151,6 +151,7 @@ All (GUI):
 - Added wxTB_NO_TOOLTIPS style (Igor Korot)
 - Added wxGenericDirCtrl::CollapsePath() (Christian Buhtz)
 - Fixed 64-bit issue in wxNotebook causing segfaults on Tru64 Unix.
+- Made it possible to associate context help to a region of a window
 
 wxMSW:
 
diff --git a/docs/latex/wx/helpprov.tex b/docs/latex/wx/helpprov.tex
index d7ccdf33ef..c05e2ee37b 100644
--- a/docs/latex/wx/helpprov.tex
+++ b/docs/latex/wx/helpprov.tex
@@ -18,16 +18,18 @@ No base class
 
 \helpref{wxContextHelp}{wxcontexthelp}, \helpref{wxContextHelpButton}{wxcontexthelpbutton}, 
 \helpref{wxSimpleHelpProvider}{wxsimplehelpprovider}, \helpref{wxHelpControllerHelpProvider}{wxhelpcontrollerhelpprovider}, 
-\helpref{wxWindow::SetHelpText}{wxwindowsethelptext}, \helpref{wxWindow::GetHelpText}{wxwindowgethelptext}
+\helpref{wxWindow::SetHelpText}{wxwindowsethelptext}, \helpref{wxWindow::GetHelpTextAtPoint}{wxwindowgethelptextatpoint}
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
+
 \membersection{wxHelpProvider::\destruct{wxHelpProvider}}\label{wxhelpproviderdtor}
 
 \func{}{\destruct{wxHelpProvider}}{\void}
 
 Virtual destructor for any base class.
 
+
 \membersection{wxHelpProvider::AddHelp}\label{wxhelpprovideraddhelp}
 
 \func{void}{AddHelp}{\param{wxWindowBase* }{window}, \param{const wxString\& }{text}}
@@ -36,6 +38,7 @@ Associates the text with the given window or id. Although all help
 providers have these functions to allow making \helpref{wxWindow::SetHelpText}{wxwindowsethelptext} 
 work, not all of them implement the functions.
 
+
 \membersection{wxHelpProvider::Get}\label{wxhelpproviderget}
 
 \func{wxHelpProvider*}{Get}{\void}
@@ -43,6 +46,7 @@ work, not all of them implement the functions.
 Unlike some other classes, the help provider is not created on demand.
 This must be explicitly done by the application.
 
+
 \membersection{wxHelpProvider::GetHelp}\label{wxhelpprovidergethelp}
 
 \func{wxString}{GetHelp}{\param{const wxWindowBase* }{window}}
@@ -57,6 +61,7 @@ This version associates the given text with all windows with this id.
 May be used to set the same help string for all Cancel buttons in
 the application, for example.
 
+
 \membersection{wxHelpProvider::RemoveHelp}\label{wxhelpproviderremovehelp}
 
 \func{void}{RemoveHelp}{\param{wxWindowBase* }{window}}
@@ -65,6 +70,7 @@ Removes the association between the window pointer and the help text. This is
 called by the wxWindow destructor. Without this, the table of help strings will fill up
 and when window pointers are reused, the wrong help string will be found.
 
+
 \membersection{wxHelpProvider::Set}\label{wxhelpproviderset}
 
 \func{wxHelpProvider*}{Set}{\param{wxHelpProvider* }{helpProvider}}
@@ -72,13 +78,38 @@ and when window pointers are reused, the wrong help string will be found.
 Get/set the current, application-wide help provider. Returns
 the previous one.
 
+
+\membersection{wxHelpProvider::ShowHelpAtPoint}\label{wxhelpprovidershowhelpatpoint}
+
+\func{bool}{ShowHelpAtPoint}{\param{wxWindowBase* }{window}, \param{const wxPoint & }{point}, \param{wxHelpEvent::Origin }{origin}}
+
+This function may be overridden to show help for the window when it should
+depend on the position inside the window, By default this method forwards to 
+\helpref{ShowHelp}{wxhelpprovidershowhelp}, so it is enough to only implement
+the latter if the help doesn't depend on the position.
+
+Returns \true if help was shown, or \false if no help was available for this
+window.
+
+\wxheading{Parameters}
+
+\docparam{window}{Window to show help text for.}
+
+\docparam{point}{Coordinates of the mouse at the moment of help event emission.}
+
+\docparam{origin}{Help event origin, see also \helpref{wxHelpEvent::Origin}{wxhelpeventorigin}.}
+
+\newsince{2.7.0}
+
+
 \membersection{wxHelpProvider::ShowHelp}\label{wxhelpprovidershowhelp}
 
 \func{bool}{ShowHelp}{\param{wxWindowBase* }{window}}
 
-Shows help for the given window. Uses \helpref{GetHelp}{wxhelpprovidergethelp} internally if
-applicable.
+Shows help for the given window. Override this function if the help doesn't
+depend on the exact position inside the window, otherwise you need to override 
+\helpref{ShowHelpAtPoint}{wxhelpprovidershowhelpatpoint}.
 
-Returns true if it was done, or false if no help was available
-for this window.
+Returns \true if help was shown, or \false if no help was available for this
+window.
 
diff --git a/docs/latex/wx/hprovcnt.tex b/docs/latex/wx/hprovcnt.tex
index f5df37c824..763b28f429 100644
--- a/docs/latex/wx/hprovcnt.tex
+++ b/docs/latex/wx/hprovcnt.tex
@@ -22,7 +22,7 @@ id to a string for passing to \helpref{wxWindow::SetHelpText}{wxwindowsethelptex
 
 \helpref{wxHelpProvider}{wxhelpprovider}, \helpref{wxSimpleHelpProvider}{wxsimplehelpprovider}, 
 \helpref{wxContextHelp}{wxcontexthelp}, \helpref{wxWindow::SetHelpText}{wxwindowsethelptext}, 
-\helpref{wxWindow::GetHelpText}{wxwindowgethelptext}
+\helpref{wxWindow::GetHelpTextAtPoint}{wxwindowgethelptextatpoint}
 
 \latexignore{\rtfignore{\wxheading{Members}}}
 
diff --git a/docs/latex/wx/hprovsmp.tex b/docs/latex/wx/hprovsmp.tex
index 25f77bec0e..d739295166 100644
--- a/docs/latex/wx/hprovsmp.tex
+++ b/docs/latex/wx/hprovsmp.tex
@@ -16,5 +16,5 @@ control (if any) in a tooltip.
 
 \helpref{wxHelpProvider}{wxhelpprovider}, \helpref{wxHelpControllerHelpProvider}{wxhelpcontrollerhelpprovider}, 
 \helpref{wxContextHelp}{wxcontexthelp}, \helpref{wxWindow::SetHelpText}{wxwindowsethelptext}, 
-\helpref{wxWindow::GetHelpText}{wxwindowgethelptext}
+\helpref{wxWindow::GetHelpTextAtPoint}{wxwindowgethelptextatpoint}
 
diff --git a/docs/latex/wx/window.tex b/docs/latex/wx/window.tex
index 25d5cea9c4..09d10e0072 100644
--- a/docs/latex/wx/window.tex
+++ b/docs/latex/wx/window.tex
@@ -1016,6 +1016,23 @@ handle, such as {\bf HWND} for Windows, {\bf Widget} for Motif, {\bf GtkWidget}
 \perlnote{This method will return an integer in wxPerl.}
 
 
+\membersection{wxWindow::GetHelpTextAtPoint}\label{wxwindowgethelptextatpoint}
+
+\constfunc{virtual wxString}{GetHelpTextAtPoint}{\param{const wxPoint &}{point}, \param{wxHelpEvent::Origin }{origin}}
+
+Gets the help text to be used as context-sensitive help for this window. This
+method should be overridden if the help message depends on the position inside
+the window, otherwise \helpref{GetHelpText}{wxwindowgethelptext} can be used.
+
+\wxheading{Parameters}
+
+\docparam{point}{Coordinates of the mouse at the moment of help event emission.}
+
+\docparam{origin}{Help event origin, see also \helpref{wxHelpEvent::Origin}{wxhelpeventorigin}.}
+
+\newsince{2.7.0}
+
+
 \membersection{wxWindow::GetHelpText}\label{wxwindowgethelptext}
 
 \constfunc{virtual wxString}{GetHelpText}{\void}
@@ -1027,7 +1044,7 @@ and not in the window object itself.
 
 \wxheading{See also}
 
-\helpref{SetHelpText}{wxwindowsethelptext}, \helpref{wxHelpProvider}{wxhelpprovider}
+\helpref{SetHelpText}{wxwindowsethelptext}, \helpref{GetHelpTextAtPoint}{wxwindowgethelptextatpoint}, \helpref{wxHelpProvider}{wxhelpprovider}
 
 
 \membersection{wxWindow::GetId}\label{wxwindowgetid}
diff --git a/include/wx/cshelp.h b/include/wx/cshelp.h
index 7f85910dd7..e80c2d0ab4 100644
--- a/include/wx/cshelp.h
+++ b/include/wx/cshelp.h
@@ -9,8 +9,8 @@
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
-#ifndef _WX_CSHELPH__
-#define _WX_CSHELPH__
+#ifndef _WX_CSHELP_H_
+#define _WX_CSHELP_H_
 
 #include "wx/defs.h"
 
@@ -23,6 +23,8 @@
 #include "wx/bmpbuttn.h"
 #endif
 
+#include "wx/event.h"
+
 // ----------------------------------------------------------------------------
 // classes used to implement context help UI
 // ----------------------------------------------------------------------------
@@ -91,6 +93,19 @@ private:
 //
 // The current help provider must be explicitly set by the application using
 // wxHelpProvider::Set().
+//
+// Special note about ShowHelpAtPoint() and ShowHelp(): we want to be able to
+// override ShowHelpAtPoint() when we need to use different help messages for
+// different parts of the window, but it should also be possible to override
+// just ShowHelp() both for backwards compatibility and just because most
+// often the help does not, in fact, depend on the position and so
+// implementing just ShowHelp() is simpler and more natural, so by default
+// ShowHelpAtPoint() forwards to ShowHelp(). But this means that
+// wxSimpleHelpProvider has to override ShowHelp() and not ShowHelpAtPoint()
+// for backwards compatibility as otherwise the existing code deriving from it
+// and overriding ShowHelp() but calling the base class version wouldn't work
+// any more, which forces us to use a rather ugly hack and pass the extra
+// parameters of ShowHelpAtPoint() to ShowHelp() via member variables.
 class WXDLLEXPORT wxHelpProvider
 {
 public:
@@ -112,10 +127,23 @@ public:
     // the window) for this window
     virtual wxString GetHelp(const wxWindowBase *window) = 0;
 
-    // do show help for the given window (uses GetHelp() internally if
-    // applicable), return true if it was done or false if no help available
-    // for this window
-    virtual bool ShowHelp(wxWindowBase *window) = 0;
+    // do show help for the given window (uses window->GetHelpAtPoint()
+    // internally if applicable), return true if it was done or false
+    // if no help available for this window
+    virtual bool ShowHelpAtPoint(wxWindowBase *window,
+                                 const wxPoint& pt,
+                                 wxHelpEvent::Origin origin)
+    {
+        wxCHECK_MSG( window, false, _T("window must not be NULL") );
+
+        m_helptextAtPoint = pt;
+        m_helptextOrigin = origin;
+
+        return ShowHelp(window);
+    }
+
+    // show help for the given window, see ShowHelpAtPoint() above
+    virtual bool ShowHelp(wxWindowBase * WXUNUSED(window)) { return false; }
 
     // associate the text with the given window or id: although all help
     // providers have these functions to allow making wxWindow::SetHelpText()
@@ -133,6 +161,23 @@ public:
     // virtual dtor for any base class
     virtual ~wxHelpProvider();
 
+protected:
+    wxHelpProvider()
+        : m_helptextAtPoint(wxDefaultPosition),
+          m_helptextOrigin(wxHelpEvent::Origin_Unknown)
+    {
+    }
+
+    // helper method used by ShowHelp(): returns the help string to use by
+    // using m_helptextAtPoint/m_helptextOrigin if they're set or just GetHelp
+    // otherwise
+    wxString GetHelpTextMaybeAtPoint(wxWindowBase *window);
+
+
+    // parameters of the last ShowHelpAtPoint() call, used by ShowHelp()
+    wxPoint m_helptextAtPoint;
+    wxHelpEvent::Origin m_helptextOrigin;
+
 private:
     static wxHelpProvider *ms_helpProvider;
 };
@@ -148,7 +193,10 @@ class WXDLLEXPORT wxSimpleHelpProvider : public wxHelpProvider
 public:
     // implement wxHelpProvider methods
     virtual wxString GetHelp(const wxWindowBase *window);
+
+    // override ShowHelp() and not ShowHelpAtPoint() as explained above
     virtual bool ShowHelp(wxWindowBase *window);
+
     virtual void AddHelp(wxWindowBase *window, const wxString& text);
     virtual void AddHelp(wxWindowID id, const wxString& text);
     virtual void RemoveHelp(wxWindowBase* window);
@@ -172,6 +220,9 @@ public:
     wxHelpControllerHelpProvider(wxHelpControllerBase* hc = (wxHelpControllerBase*) NULL);
 
     // implement wxHelpProvider methods
+
+    // again (see above): this should be ShowHelpAtPoint() but we need to
+    // override ShowHelp() to avoid breaking existing code
     virtual bool ShowHelp(wxWindowBase *window);
 
     // Other accessors
@@ -189,5 +240,5 @@ WXDLLEXPORT wxString wxContextId(int id);
 
 #endif // wxUSE_HELP
 
-#endif // _WX_CSHELPH__
+#endif // _WX_CSHELP_H_
 
diff --git a/include/wx/window.h b/include/wx/window.h
index abdd96aa05..2462fb0d27 100644
--- a/include/wx/window.h
+++ b/include/wx/window.h
@@ -927,9 +927,19 @@ public:
         // associate this help text with all windows with the same id as this
         // one
     void SetHelpTextForId(const wxString& text);
-        // get the help string associated with this window (may be empty)
-    wxString GetHelpText() const;
-#else
+        // get the help string associated with the given position in this window
+        //
+        // notice that pt may be invalid if event origin is keyboard or unknown
+        // and this method should return the global window help text then
+    virtual wxString GetHelpTextAtPoint(const wxPoint& pt,
+                                        wxHelpEvent::Origin origin) const;
+        // returns the position-independent help text
+    wxString GetHelpText() const
+    {
+        return GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Unknown);
+    }
+
+#else // !wxUSE_HELP
     // silently ignore SetHelpText() calls
     void SetHelpText(const wxString& WXUNUSED(text)) { }
     void SetHelpTextForId(const wxString& WXUNUSED(text)) { }
diff --git a/src/common/cshelp.cpp b/src/common/cshelp.cpp
index f1433c3bed..efe31c27f4 100644
--- a/src/common/cshelp.cpp
+++ b/src/common/cshelp.cpp
@@ -327,6 +327,25 @@ wxHelpProvider::~wxHelpProvider()
 {
 }
 
+wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
+{
+    if ( m_helptextAtPoint != wxDefaultPosition ||
+            m_helptextOrigin != wxHelpEvent::Origin_Unknown )
+    {
+        wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") );
+
+        wxPoint pt = m_helptextAtPoint;
+        wxHelpEvent::Origin origin = m_helptextOrigin;
+
+        m_helptextAtPoint = wxDefaultPosition;
+        m_helptextOrigin = wxHelpEvent::Origin_Unknown;
+
+        return window->GetHelpTextAtPoint(pt, origin);
+    }
+
+    return GetHelp(window);
+}
+
 // ----------------------------------------------------------------------------
 // wxSimpleHelpProvider
 // ----------------------------------------------------------------------------
@@ -380,10 +399,11 @@ bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
     }
     s_tipWindow = NULL;
 
-    wxString text = GetHelp(window);
+    const wxString text = GetHelpTextMaybeAtPoint(window);
     if ( !text.empty() )
     {
-        s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
+        s_tipWindow = new wxTipWindow((wxWindow *)window, text,
+                                        100, &s_tipWindow);
 
         return true;
     }
@@ -405,29 +425,26 @@ wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase*
 
 bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
 {
-    wxString text = GetHelp(window);
-    if ( !text.empty() )
-    {
-        if (m_helpController)
-        {
-            if (text.IsNumber())
-                return m_helpController->DisplayContextPopup(wxAtoi(text));
-
-            // If the help controller is capable of popping up the text...
-            else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
-            {
-                return true;
-            }
-            else
-            // ...else use the default method.
-                return wxSimpleHelpProvider::ShowHelp(window);
-        }
-        else
-            return wxSimpleHelpProvider::ShowHelp(window);
+    const wxString text = GetHelpTextMaybeAtPoint(window);
 
+    if ( text.empty() )
+        return false;
+
+    if ( m_helpController )
+    {
+        // if it's a numeric topic, show it
+        long topic;
+        if ( text.ToLong(&topic) )
+            return m_helpController->DisplayContextPopup(topic);
+
+        // otherwise show the text directly
+        if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
+            return true;
     }
 
-    return false;
+    // if there is no help controller or it's not capable of showing the help,
+    // fallback to the default method
+    return wxSimpleHelpProvider::ShowHelp(window);
 }
 
 // Convenience function for turning context id into wxString
diff --git a/src/common/wincmn.cpp b/src/common/wincmn.cpp
index b485672dcc..7bf7177a6a 100644
--- a/src/common/wincmn.cpp
+++ b/src/common/wincmn.cpp
@@ -1469,7 +1469,10 @@ void wxWindowBase::SetHelpTextForId(const wxString& text)
 }
 
 // get the help string associated with this window (may be empty)
-wxString wxWindowBase::GetHelpText() const
+// default implementation forwards calls to the help provider
+wxString
+wxWindowBase::GetHelpTextAtPoint(const wxPoint & WXUNUSED(pt),
+                                 wxHelpEvent::Origin WXUNUSED(origin)) const
 {
     wxString text;
     wxHelpProvider *helpProvider = wxHelpProvider::Get();
@@ -1487,7 +1490,7 @@ void wxWindowBase::OnHelp(wxHelpEvent& event)
     wxHelpProvider *helpProvider = wxHelpProvider::Get();
     if ( helpProvider )
     {
-        if ( helpProvider->ShowHelp(this) )
+        if ( helpProvider->ShowHelpAtPoint(this, event.GetPosition(), event.GetOrigin()) )
         {
             // skip the event.Skip() below
             return;
@@ -2801,7 +2804,7 @@ wxAccStatus wxWindowAccessible::GetDescription(int WXUNUSED(childId), wxString*
     if (!GetWindow())
         return wxACC_FAIL;
 
-    wxString ht(GetWindow()->GetHelpText());
+    wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard));
     if (!ht.empty())
     {
         *description = ht;
@@ -2817,7 +2820,7 @@ wxAccStatus wxWindowAccessible::GetHelpText(int WXUNUSED(childId), wxString* hel
     if (!GetWindow())
         return wxACC_FAIL;
 
-    wxString ht(GetWindow()->GetHelpText());
+    wxString ht(GetWindow()->GetHelpTextAtPoint(wxDefaultPosition, wxHelpEvent::Origin_Keyboard));
     if (!ht.empty())
     {
         *helpText = ht;
-- 
2.45.2

