1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/cshelp.cpp
3 // Purpose: Context sensitive help class implementation
4 // Author: Julian Smart, Vadim Zeitlin
7 // Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
30 #include "wx/module.h"
33 #include "wx/tipwin.h"
34 #include "wx/cshelp.h"
36 #if wxUSE_MS_HTML_HELP
37 #include "wx/msw/helpchm.h" // for ShowContextHelpPopup
38 #include "wx/utils.h" // for wxGetMousePosition()
41 // ----------------------------------------------------------------------------
42 // wxContextHelpEvtHandler private class
43 // ----------------------------------------------------------------------------
45 // This class exists in order to eat events until the left mouse button is
47 class wxContextHelpEvtHandler
: public wxEvtHandler
50 wxContextHelpEvtHandler(wxContextHelp
* contextHelp
)
52 m_contextHelp
= contextHelp
;
55 virtual bool ProcessEvent(wxEvent
& event
);
58 wxContextHelp
* m_contextHelp
;
60 wxDECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler
);
63 // ============================================================================
65 // ============================================================================
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
72 * Invokes context-sensitive help
76 IMPLEMENT_DYNAMIC_CLASS(wxContextHelp
, wxObject
)
78 wxContextHelp::wxContextHelp(wxWindow
* win
, bool beginHelp
)
83 BeginContextHelp(win
);
86 wxContextHelp::~wxContextHelp()
92 // Not currently needed, but on some systems capture may not work as
93 // expected so we'll leave it here for now.
95 static void wxPushOrPopEventHandlers(wxContextHelp
* help
, wxWindow
* win
, bool push
)
98 win
->PushEventHandler(new wxContextHelpEvtHandler(help
));
100 win
->PopEventHandler(true);
102 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
105 wxWindow
* child
= node
->GetData();
106 wxPushOrPopEventHandlers(help
, child
, push
);
108 node
= node
->GetNext();
113 // Begin 'context help mode'
114 bool wxContextHelp::BeginContextHelp(wxWindow
* win
)
117 win
= wxTheApp
->GetTopWindow();
121 wxCursor
cursor(wxCURSOR_QUESTION_ARROW
);
122 wxCursor oldCursor
= win
->GetCursor();
123 win
->SetCursor(cursor
);
132 wxPushOrPopEventHandlers(this, win
, true);
134 win
->PushEventHandler(new wxContextHelpEvtHandler(this));
144 wxPushOrPopEventHandlers(this, win
, false);
146 win
->PopEventHandler(true);
149 win
->SetCursor(oldCursor
);
152 wxSetCursor(wxNullCursor
);
158 wxWindow
* winAtPtr
= wxFindWindowAtPointer(pt
);
163 printf("Picked %s (%d)\n", winAtPtr
->GetName().c_str(),
169 DispatchEvent(winAtPtr
, pt
);
175 bool wxContextHelp::EndContextHelp()
182 bool wxContextHelp::EventLoop()
188 if (wxTheApp
->Pending())
190 wxTheApp
->Dispatch();
194 wxTheApp
->ProcessIdle();
201 bool wxContextHelpEvtHandler::ProcessEvent(wxEvent
& event
)
203 if (event
.GetEventType() == wxEVT_LEFT_DOWN
)
205 m_contextHelp
->SetStatus(true);
206 m_contextHelp
->EndContextHelp();
210 if ((event
.GetEventType() == wxEVT_CHAR
) ||
211 (event
.GetEventType() == wxEVT_KEY_DOWN
) ||
212 (event
.GetEventType() == wxEVT_ACTIVATE
) ||
213 (event
.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED
))
215 // May have already been set to true by a left-click
216 //m_contextHelp->SetStatus(false);
217 m_contextHelp
->EndContextHelp();
221 if ((event
.GetEventType() == wxEVT_PAINT
) ||
222 (event
.GetEventType() == wxEVT_ERASE_BACKGROUND
))
231 // Dispatch the help event to the relevant window
232 bool wxContextHelp::DispatchEvent(wxWindow
* win
, const wxPoint
& pt
)
234 wxCHECK_MSG( win
, false, wxT("win parameter can't be NULL") );
236 wxHelpEvent
helpEvent(wxEVT_HELP
, win
->GetId(), pt
,
237 wxHelpEvent::Origin_HelpButton
);
238 helpEvent
.SetEventObject(win
);
240 return win
->GetEventHandler()->ProcessEvent(helpEvent
);
243 // ----------------------------------------------------------------------------
244 // wxContextHelpButton
245 // ----------------------------------------------------------------------------
248 * wxContextHelpButton
249 * You can add this to your dialogs (especially on non-Windows platforms)
250 * to put the application into context help mode.
255 static const char * csquery_xpm
[] = {
273 IMPLEMENT_CLASS(wxContextHelpButton
, wxBitmapButton
)
275 BEGIN_EVENT_TABLE(wxContextHelpButton
, wxBitmapButton
)
276 EVT_BUTTON(wxID_CONTEXT_HELP
, wxContextHelpButton::OnContextHelp
)
279 wxContextHelpButton::wxContextHelpButton(wxWindow
* parent
,
284 #if defined(__WXPM__)
285 : wxBitmapButton(parent
, id
, wxBitmap(wxCSQUERY_BITMAP
286 ,wxBITMAP_TYPE_BMP_RESOURCE
290 : wxBitmapButton(parent
, id
, wxBitmap(csquery_xpm
),
296 void wxContextHelpButton::OnContextHelp(wxCommandEvent
& WXUNUSED(event
))
298 wxContextHelp
contextHelp(GetParent());
301 // ----------------------------------------------------------------------------
303 // ----------------------------------------------------------------------------
305 wxHelpProvider
*wxHelpProvider::ms_helpProvider
= NULL
;
307 // trivial implementation of some methods which we don't want to make pure
308 // virtual for convenience
310 void wxHelpProvider::AddHelp(wxWindowBase
* WXUNUSED(window
),
311 const wxString
& WXUNUSED(text
))
315 void wxHelpProvider::AddHelp(wxWindowID
WXUNUSED(id
),
316 const wxString
& WXUNUSED(text
))
320 // removes the association
321 void wxHelpProvider::RemoveHelp(wxWindowBase
* WXUNUSED(window
))
325 wxHelpProvider::~wxHelpProvider()
329 wxString
wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase
*window
)
331 if ( m_helptextAtPoint
!= wxDefaultPosition
||
332 m_helptextOrigin
!= wxHelpEvent::Origin_Unknown
)
334 wxCHECK_MSG( window
, wxEmptyString
, wxT("window must not be NULL") );
336 wxPoint pt
= m_helptextAtPoint
;
337 wxHelpEvent::Origin origin
= m_helptextOrigin
;
339 m_helptextAtPoint
= wxDefaultPosition
;
340 m_helptextOrigin
= wxHelpEvent::Origin_Unknown
;
342 return window
->GetHelpTextAtPoint(pt
, origin
);
345 return GetHelp(window
);
348 // ----------------------------------------------------------------------------
349 // wxSimpleHelpProvider
350 // ----------------------------------------------------------------------------
352 #define WINHASH_KEY(w) wxPtrToUInt(w)
354 wxString
wxSimpleHelpProvider::GetHelp(const wxWindowBase
*window
)
356 wxSimpleHelpProviderHashMap::iterator it
= m_hashWindows
.find(WINHASH_KEY(window
));
358 if ( it
== m_hashWindows
.end() )
360 it
= m_hashIds
.find(window
->GetId());
361 if ( it
== m_hashIds
.end() )
362 return wxEmptyString
;
368 void wxSimpleHelpProvider::AddHelp(wxWindowBase
*window
, const wxString
& text
)
370 m_hashWindows
.erase(WINHASH_KEY(window
));
371 m_hashWindows
[WINHASH_KEY(window
)] = text
;
374 void wxSimpleHelpProvider::AddHelp(wxWindowID id
, const wxString
& text
)
376 wxSimpleHelpProviderHashMap::key_type key
= (wxSimpleHelpProviderHashMap::key_type
)id
;
377 m_hashIds
.erase(key
);
378 m_hashIds
[key
] = text
;
381 // removes the association
382 void wxSimpleHelpProvider::RemoveHelp(wxWindowBase
* window
)
384 m_hashWindows
.erase(WINHASH_KEY(window
));
387 bool wxSimpleHelpProvider::ShowHelp(wxWindowBase
*window
)
389 #if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
390 #if wxUSE_MS_HTML_HELP
391 // m_helptextAtPoint will be reset by GetHelpTextMaybeAtPoint(), stash it
392 const wxPoint posTooltip
= m_helptextAtPoint
;
393 #endif // wxUSE_MS_HTML_HELP
395 const wxString text
= GetHelpTextMaybeAtPoint(window
);
399 // use the native help popup style if it's available
400 #if wxUSE_MS_HTML_HELP
401 if ( !wxCHMHelpController::ShowContextHelpPopup
407 #endif // wxUSE_MS_HTML_HELP
410 static wxTipWindow
* s_tipWindow
= NULL
;
414 // Prevent s_tipWindow being nulled in OnIdle, thereby removing
415 // the chance for the window to be closed by ShowHelp
416 s_tipWindow
->SetTipWindowPtr(NULL
);
417 s_tipWindow
->Close();
420 s_tipWindow
= new wxTipWindow((wxWindow
*)window
, text
,
422 #else // !wxUSE_TIPWINDOW
423 // we tried wxCHMHelpController but it failed and we don't have
424 // wxTipWindow to fall back on, so
426 #endif // wxUSE_TIPWINDOW
431 #else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
433 #endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
438 // ----------------------------------------------------------------------------
439 // wxHelpControllerHelpProvider
440 // ----------------------------------------------------------------------------
442 wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase
* hc
)
444 m_helpController
= hc
;
447 bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase
*window
)
449 const wxString text
= GetHelpTextMaybeAtPoint(window
);
454 if ( m_helpController
)
456 // if it's a numeric topic, show it
458 if ( text
.ToLong(&topic
) )
459 return m_helpController
->DisplayContextPopup(topic
);
461 // otherwise show the text directly
462 if ( m_helpController
->DisplayTextPopup(text
, wxGetMousePosition()) )
466 // if there is no help controller or it's not capable of showing the help,
467 // fallback to the default method
468 return wxSimpleHelpProvider::ShowHelp(window
);
471 // Convenience function for turning context id into wxString
472 wxString
wxContextId(int id
)
474 return wxString::Format(wxT("%d"), id
);
477 // ----------------------------------------------------------------------------
478 // wxHelpProviderModule: module responsible for cleaning up help provider.
479 // ----------------------------------------------------------------------------
481 class wxHelpProviderModule
: public wxModule
488 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule
)
491 IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule
, wxModule
)
493 bool wxHelpProviderModule::OnInit()
495 // Probably we don't want to do anything by default,
496 // since it could pull in extra code
497 // wxHelpProvider::Set(new wxSimpleHelpProvider);
502 void wxHelpProviderModule::OnExit()
504 if (wxHelpProvider::Get())
506 delete wxHelpProvider::Get();
507 wxHelpProvider::Set(NULL
);