1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/cshelp.cpp
3 // Purpose: Context sensitive help class implementation
4 // Author: Julian Smart, Vadim Zeitlin
8 // Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
31 #include "wx/module.h"
34 #include "wx/tipwin.h"
35 #include "wx/cshelp.h"
37 // wxUSE_MS_HTML_HELP is not defined under platforms other than MSW
38 #ifndef wxUSE_MS_HTML_HELP
39 #define wxUSE_MS_HTML_HELP 0
42 #if wxUSE_MS_HTML_HELP
43 #include "wx/msw/helpchm.h" // for ShowContextHelpPopup
44 #include "wx/utils.h" // for wxGetMousePosition()
47 // ----------------------------------------------------------------------------
48 // wxContextHelpEvtHandler private class
49 // ----------------------------------------------------------------------------
51 // This class exists in order to eat events until the left mouse button is
53 class wxContextHelpEvtHandler
: public wxEvtHandler
56 wxContextHelpEvtHandler(wxContextHelp
* contextHelp
)
58 m_contextHelp
= contextHelp
;
61 virtual bool ProcessEvent(wxEvent
& event
);
64 wxContextHelp
* m_contextHelp
;
66 DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler
)
69 // ============================================================================
71 // ============================================================================
73 // ----------------------------------------------------------------------------
75 // ----------------------------------------------------------------------------
78 * Invokes context-sensitive help
82 IMPLEMENT_DYNAMIC_CLASS(wxContextHelp
, wxObject
)
84 wxContextHelp::wxContextHelp(wxWindow
* win
, bool beginHelp
)
89 BeginContextHelp(win
);
92 wxContextHelp::~wxContextHelp()
98 // Not currently needed, but on some systems capture may not work as
99 // expected so we'll leave it here for now.
101 static void wxPushOrPopEventHandlers(wxContextHelp
* help
, wxWindow
* win
, bool push
)
104 win
->PushEventHandler(new wxContextHelpEvtHandler(help
));
106 win
->PopEventHandler(true);
108 wxWindowList::compatibility_iterator node
= win
->GetChildren().GetFirst();
111 wxWindow
* child
= node
->GetData();
112 wxPushOrPopEventHandlers(help
, child
, push
);
114 node
= node
->GetNext();
119 // Begin 'context help mode'
120 bool wxContextHelp::BeginContextHelp(wxWindow
* win
)
123 win
= wxTheApp
->GetTopWindow();
127 wxCursor
cursor(wxCURSOR_QUESTION_ARROW
);
128 wxCursor oldCursor
= win
->GetCursor();
129 win
->SetCursor(cursor
);
132 // wxSetCursor(cursor);
138 wxPushOrPopEventHandlers(this, win
, true);
140 win
->PushEventHandler(new wxContextHelpEvtHandler(this));
150 wxPushOrPopEventHandlers(this, win
, false);
152 win
->PopEventHandler(true);
155 win
->SetCursor(oldCursor
);
160 wxWindow
* winAtPtr
= wxFindWindowAtPointer(pt
);
165 printf("Picked %s (%d)\n", winAtPtr
->GetName().c_str(),
171 DispatchEvent(winAtPtr
, pt
);
177 bool wxContextHelp::EndContextHelp()
184 bool wxContextHelp::EventLoop()
190 if (wxTheApp
->Pending())
192 wxTheApp
->Dispatch();
196 wxTheApp
->ProcessIdle();
203 bool wxContextHelpEvtHandler::ProcessEvent(wxEvent
& event
)
205 if (event
.GetEventType() == wxEVT_LEFT_DOWN
)
207 m_contextHelp
->SetStatus(true);
208 m_contextHelp
->EndContextHelp();
212 if ((event
.GetEventType() == wxEVT_CHAR
) ||
213 (event
.GetEventType() == wxEVT_KEY_DOWN
) ||
214 (event
.GetEventType() == wxEVT_ACTIVATE
) ||
215 (event
.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED
))
217 // May have already been set to true by a left-click
218 //m_contextHelp->SetStatus(false);
219 m_contextHelp
->EndContextHelp();
223 if ((event
.GetEventType() == wxEVT_PAINT
) ||
224 (event
.GetEventType() == wxEVT_ERASE_BACKGROUND
))
233 // Dispatch the help event to the relevant window
234 bool wxContextHelp::DispatchEvent(wxWindow
* win
, const wxPoint
& pt
)
236 wxCHECK_MSG( win
, false, _T("win parameter can't be NULL") );
238 wxHelpEvent
helpEvent(wxEVT_HELP
, win
->GetId(), pt
,
239 wxHelpEvent::Origin_HelpButton
);
240 helpEvent
.SetEventObject(win
);
242 return win
->GetEventHandler()->ProcessEvent(helpEvent
);
245 // ----------------------------------------------------------------------------
246 // wxContextHelpButton
247 // ----------------------------------------------------------------------------
250 * wxContextHelpButton
251 * You can add this to your dialogs (especially on non-Windows platforms)
252 * to put the application into context help mode.
257 static const char * csquery_xpm
[] = {
275 IMPLEMENT_CLASS(wxContextHelpButton
, wxBitmapButton
)
277 BEGIN_EVENT_TABLE(wxContextHelpButton
, wxBitmapButton
)
278 EVT_BUTTON(wxID_CONTEXT_HELP
, wxContextHelpButton::OnContextHelp
)
281 wxContextHelpButton::wxContextHelpButton(wxWindow
* parent
,
286 #if defined(__WXPM__)
287 : wxBitmapButton(parent
, id
, wxBitmap(wxCSQUERY_BITMAP
288 ,wxBITMAP_TYPE_RESOURCE
292 : wxBitmapButton(parent
, id
, wxBitmap(csquery_xpm
),
298 void wxContextHelpButton::OnContextHelp(wxCommandEvent
& WXUNUSED(event
))
300 wxContextHelp
contextHelp(GetParent());
303 // ----------------------------------------------------------------------------
305 // ----------------------------------------------------------------------------
307 wxHelpProvider
*wxHelpProvider::ms_helpProvider
= (wxHelpProvider
*)NULL
;
309 // trivial implementation of some methods which we don't want to make pure
310 // virtual for convenience
312 void wxHelpProvider::AddHelp(wxWindowBase
* WXUNUSED(window
),
313 const wxString
& WXUNUSED(text
))
317 void wxHelpProvider::AddHelp(wxWindowID
WXUNUSED(id
),
318 const wxString
& WXUNUSED(text
))
322 // removes the association
323 void wxHelpProvider::RemoveHelp(wxWindowBase
* WXUNUSED(window
))
327 wxHelpProvider::~wxHelpProvider()
331 wxString
wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase
*window
)
333 if ( m_helptextAtPoint
!= wxDefaultPosition
||
334 m_helptextOrigin
!= wxHelpEvent::Origin_Unknown
)
336 wxCHECK_MSG( window
, wxEmptyString
, _T("window must not be NULL") );
338 wxPoint pt
= m_helptextAtPoint
;
339 wxHelpEvent::Origin origin
= m_helptextOrigin
;
341 m_helptextAtPoint
= wxDefaultPosition
;
342 m_helptextOrigin
= wxHelpEvent::Origin_Unknown
;
344 return window
->GetHelpTextAtPoint(pt
, origin
);
347 return GetHelp(window
);
350 // ----------------------------------------------------------------------------
351 // wxSimpleHelpProvider
352 // ----------------------------------------------------------------------------
354 #define WINHASH_KEY(w) wxPtrToUInt(w)
356 wxString
wxSimpleHelpProvider::GetHelp(const wxWindowBase
*window
)
358 wxSimpleHelpProviderHashMap::iterator it
= m_hashWindows
.find(WINHASH_KEY(window
));
360 if ( it
== m_hashWindows
.end() )
362 it
= m_hashIds
.find(window
->GetId());
363 if ( it
== m_hashIds
.end() )
364 return wxEmptyString
;
370 void wxSimpleHelpProvider::AddHelp(wxWindowBase
*window
, const wxString
& text
)
372 m_hashWindows
.erase(WINHASH_KEY(window
));
373 m_hashWindows
[WINHASH_KEY(window
)] = text
;
376 void wxSimpleHelpProvider::AddHelp(wxWindowID id
, const wxString
& text
)
378 wxSimpleHelpProviderHashMap::key_type key
= (wxSimpleHelpProviderHashMap::key_type
)id
;
379 m_hashIds
.erase(key
);
380 m_hashIds
[key
] = text
;
383 // removes the association
384 void wxSimpleHelpProvider::RemoveHelp(wxWindowBase
* window
)
386 m_hashWindows
.erase(WINHASH_KEY(window
));
389 bool wxSimpleHelpProvider::ShowHelp(wxWindowBase
*window
)
391 #if wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
392 const wxString text
= GetHelpTextMaybeAtPoint(window
);
396 // use the native help popup style if it's available
397 #if wxUSE_MS_HTML_HELP
398 if ( !wxCHMHelpController::ShowContextHelpPopup
401 wxGetMousePosition(),
404 #endif // wxUSE_MS_HTML_HELP
407 static wxTipWindow
* s_tipWindow
= NULL
;
411 // Prevent s_tipWindow being nulled in OnIdle, thereby removing
412 // the chance for the window to be closed by ShowHelp
413 s_tipWindow
->SetTipWindowPtr(NULL
);
414 s_tipWindow
->Close();
417 s_tipWindow
= new wxTipWindow((wxWindow
*)window
, text
,
419 #else // !wxUSE_TIPWINDOW
420 // we tried wxCHMHelpController but it failed and we don't have
421 // wxTipWindow to fall back on, so
423 #endif // wxUSE_TIPWINDOW
428 #else // !wxUSE_MS_HTML_HELP && !wxUSE_TIPWINDOW
430 #endif // wxUSE_MS_HTML_HELP || wxUSE_TIPWINDOW
435 // ----------------------------------------------------------------------------
436 // wxHelpControllerHelpProvider
437 // ----------------------------------------------------------------------------
439 wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase
* hc
)
441 m_helpController
= hc
;
444 bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase
*window
)
446 const wxString text
= GetHelpTextMaybeAtPoint(window
);
451 if ( m_helpController
)
453 // if it's a numeric topic, show it
455 if ( text
.ToLong(&topic
) )
456 return m_helpController
->DisplayContextPopup(topic
);
458 // otherwise show the text directly
459 if ( m_helpController
->DisplayTextPopup(text
, wxGetMousePosition()) )
463 // if there is no help controller or it's not capable of showing the help,
464 // fallback to the default method
465 return wxSimpleHelpProvider::ShowHelp(window
);
468 // Convenience function for turning context id into wxString
469 wxString
wxContextId(int id
)
471 return wxString::Format(_T("%d"), id
);
474 // ----------------------------------------------------------------------------
475 // wxHelpProviderModule: module responsible for cleaning up help provider.
476 // ----------------------------------------------------------------------------
478 class wxHelpProviderModule
: public wxModule
485 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule
)
488 IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule
, wxModule
)
490 bool wxHelpProviderModule::OnInit()
492 // Probably we don't want to do anything by default,
493 // since it could pull in extra code
494 // wxHelpProvider::Set(new wxSimpleHelpProvider);
499 void wxHelpProviderModule::OnExit()
501 if (wxHelpProvider::Get())
503 delete wxHelpProvider::Get();
504 wxHelpProvider::Set(NULL
);