]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/cshelp.cpp
Help text for regions
[wxWidgets.git] / src / common / cshelp.cpp
... / ...
CommitLineData
1/////////////////////////////////////////////////////////////////////////////
2// Name: src/common/cshelp.cpp
3// Purpose: Context sensitive help class implementation
4// Author: Julian Smart, Vadim Zeitlin
5// Modified by:
6// Created: 08/09/2000
7// RCS-ID: $Id$
8// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
9// Licence: wxWindows licence
10/////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_HELP
28
29#ifndef WX_PRECOMP
30 #include "wx/app.h"
31#endif
32
33#include "wx/tipwin.h"
34#include "wx/module.h"
35#include "wx/cshelp.h"
36
37// ----------------------------------------------------------------------------
38// wxContextHelpEvtHandler private class
39// ----------------------------------------------------------------------------
40
41// This class exists in order to eat events until the left mouse button is
42// pressed
43class wxContextHelpEvtHandler: public wxEvtHandler
44{
45public:
46 wxContextHelpEvtHandler(wxContextHelp* contextHelp)
47 {
48 m_contextHelp = contextHelp;
49 }
50
51 virtual bool ProcessEvent(wxEvent& event);
52
53//// Data
54 wxContextHelp* m_contextHelp;
55
56 DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler)
57};
58
59// ============================================================================
60// implementation
61// ============================================================================
62
63// ----------------------------------------------------------------------------
64// wxContextHelp
65// ----------------------------------------------------------------------------
66
67/*
68 * Invokes context-sensitive help
69 */
70
71
72IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
73
74wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
75{
76 m_inHelp = false;
77
78 if (beginHelp)
79 BeginContextHelp(win);
80}
81
82wxContextHelp::~wxContextHelp()
83{
84 if (m_inHelp)
85 EndContextHelp();
86}
87
88// Not currently needed, but on some systems capture may not work as
89// expected so we'll leave it here for now.
90#ifdef __WXMOTIF__
91static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
92{
93 if (push)
94 win->PushEventHandler(new wxContextHelpEvtHandler(help));
95 else
96 win->PopEventHandler(true);
97
98 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
99 while (node)
100 {
101 wxWindow* child = node->GetData();
102 wxPushOrPopEventHandlers(help, child, push);
103
104 node = node->GetNext();
105 }
106}
107#endif
108
109// Begin 'context help mode'
110bool wxContextHelp::BeginContextHelp(wxWindow* win)
111{
112 if (!win)
113 win = wxTheApp->GetTopWindow();
114 if (!win)
115 return false;
116
117 wxCursor cursor(wxCURSOR_QUESTION_ARROW);
118 wxCursor oldCursor = win->GetCursor();
119 win->SetCursor(cursor);
120
121#ifdef __WXMSW__
122 // wxSetCursor(cursor);
123#endif
124
125 m_status = false;
126
127#ifdef __WXMOTIF__
128 wxPushOrPopEventHandlers(this, win, true);
129#else
130 win->PushEventHandler(new wxContextHelpEvtHandler(this));
131#endif
132
133 win->CaptureMouse();
134
135 EventLoop();
136
137 win->ReleaseMouse();
138
139#ifdef __WXMOTIF__
140 wxPushOrPopEventHandlers(this, win, false);
141#else
142 win->PopEventHandler(true);
143#endif
144
145 win->SetCursor(oldCursor);
146
147 if (m_status)
148 {
149 wxPoint pt;
150 wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
151
152#if 0
153 if (winAtPtr)
154 {
155 printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(),
156 winAtPtr->GetId());
157 }
158#endif
159
160 if (winAtPtr)
161 DispatchEvent(winAtPtr, pt);
162 }
163
164 return true;
165}
166
167bool wxContextHelp::EndContextHelp()
168{
169 m_inHelp = false;
170
171 return true;
172}
173
174bool wxContextHelp::EventLoop()
175{
176 m_inHelp = true;
177
178 while ( m_inHelp )
179 {
180 if (wxTheApp->Pending())
181 {
182 wxTheApp->Dispatch();
183 }
184 else
185 {
186 wxTheApp->ProcessIdle();
187 }
188 }
189
190 return true;
191}
192
193bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
194{
195 if (event.GetEventType() == wxEVT_LEFT_DOWN)
196 {
197 m_contextHelp->SetStatus(true);
198 m_contextHelp->EndContextHelp();
199 return true;
200 }
201
202 if ((event.GetEventType() == wxEVT_CHAR) ||
203 (event.GetEventType() == wxEVT_KEY_DOWN) ||
204 (event.GetEventType() == wxEVT_ACTIVATE) ||
205 (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
206 {
207 // May have already been set to true by a left-click
208 //m_contextHelp->SetStatus(false);
209 m_contextHelp->EndContextHelp();
210 return true;
211 }
212
213 if ((event.GetEventType() == wxEVT_PAINT) ||
214 (event.GetEventType() == wxEVT_ERASE_BACKGROUND))
215 {
216 event.Skip();
217 return false;
218 }
219
220 return true;
221}
222
223// Dispatch the help event to the relevant window
224bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
225{
226 wxCHECK_MSG( win, false, _T("win parameter can't be NULL") );
227
228 wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt,
229 wxHelpEvent::Origin_HelpButton);
230 helpEvent.SetEventObject(win);
231
232 return win->GetEventHandler()->ProcessEvent(helpEvent);
233}
234
235// ----------------------------------------------------------------------------
236// wxContextHelpButton
237// ----------------------------------------------------------------------------
238
239/*
240 * wxContextHelpButton
241 * You can add this to your dialogs (especially on non-Windows platforms)
242 * to put the application into context help mode.
243 */
244
245#ifndef __WXPM__
246
247static const char * csquery_xpm[] = {
248"12 11 2 1",
249" c None",
250". c #000000",
251" ",
252" .... ",
253" .. .. ",
254" .. .. ",
255" .. ",
256" .. ",
257" .. ",
258" ",
259" .. ",
260" .. ",
261" "};
262
263#endif
264
265IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
266
267BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
268 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
269END_EVENT_TABLE()
270
271wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
272 wxWindowID id,
273 const wxPoint& pos,
274 const wxSize& size,
275 long style)
276#if defined(__WXPM__)
277 : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
278 ,wxBITMAP_TYPE_RESOURCE
279 ),
280 pos, size, style)
281#else
282 : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
283 pos, size, style)
284#endif
285{
286}
287
288void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
289{
290 wxContextHelp contextHelp(GetParent());
291}
292
293// ----------------------------------------------------------------------------
294// wxHelpProvider
295// ----------------------------------------------------------------------------
296
297wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
298
299// trivial implementation of some methods which we don't want to make pure
300// virtual for convenience
301
302void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
303 const wxString& WXUNUSED(text))
304{
305}
306
307void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
308 const wxString& WXUNUSED(text))
309{
310}
311
312// removes the association
313void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
314{
315}
316
317wxHelpProvider::~wxHelpProvider()
318{
319}
320
321wxString wxHelpProvider::GetHelpTextMaybeAtPoint(wxWindowBase *window)
322{
323 if ( m_helptextAtPoint != wxDefaultPosition ||
324 m_helptextOrigin != wxHelpEvent::Origin_Unknown )
325 {
326 wxCHECK_MSG( window, wxEmptyString, _T("window must not be NULL") );
327
328 wxPoint pt = m_helptextAtPoint;
329 wxHelpEvent::Origin origin = m_helptextOrigin;
330
331 m_helptextAtPoint = wxDefaultPosition;
332 m_helptextOrigin = wxHelpEvent::Origin_Unknown;
333
334 return window->GetHelpTextAtPoint(pt, origin);
335 }
336
337 return GetHelp(window);
338}
339
340// ----------------------------------------------------------------------------
341// wxSimpleHelpProvider
342// ----------------------------------------------------------------------------
343
344#define WINHASH_KEY(w) wxPtrToUInt(w)
345
346wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
347{
348 wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
349
350 if ( it == m_hashWindows.end() )
351 {
352 it = m_hashIds.find(window->GetId());
353 if ( it == m_hashIds.end() )
354 return wxEmptyString;
355 }
356
357 return it->second;
358}
359
360void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
361{
362 m_hashWindows.erase(WINHASH_KEY(window));
363 m_hashWindows[WINHASH_KEY(window)] = text;
364}
365
366void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
367{
368 wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
369 m_hashIds.erase(key);
370 m_hashIds[key] = text;
371}
372
373// removes the association
374void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
375{
376 m_hashWindows.erase(WINHASH_KEY(window));
377}
378
379bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
380{
381#if wxUSE_TIPWINDOW
382 static wxTipWindow* s_tipWindow = NULL;
383
384 if (s_tipWindow)
385 {
386 // Prevent s_tipWindow being nulled in OnIdle,
387 // thereby removing the chance for the window to be closed by ShowHelp
388 s_tipWindow->SetTipWindowPtr(NULL);
389 s_tipWindow->Close();
390 }
391 s_tipWindow = NULL;
392
393 const wxString text = GetHelpTextMaybeAtPoint(window);
394 if ( !text.empty() )
395 {
396 s_tipWindow = new wxTipWindow((wxWindow *)window, text,
397 100, &s_tipWindow);
398
399 return true;
400 }
401#else
402 wxUnusedVar(window);
403#endif // wxUSE_TIPWINDOW
404
405 return false;
406}
407
408// ----------------------------------------------------------------------------
409// wxHelpControllerHelpProvider
410// ----------------------------------------------------------------------------
411
412wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
413{
414 m_helpController = hc;
415}
416
417bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
418{
419 const wxString text = GetHelpTextMaybeAtPoint(window);
420
421 if ( text.empty() )
422 return false;
423
424 if ( m_helpController )
425 {
426 // if it's a numeric topic, show it
427 long topic;
428 if ( text.ToLong(&topic) )
429 return m_helpController->DisplayContextPopup(topic);
430
431 // otherwise show the text directly
432 if ( m_helpController->DisplayTextPopup(text, wxGetMousePosition()) )
433 return true;
434 }
435
436 // if there is no help controller or it's not capable of showing the help,
437 // fallback to the default method
438 return wxSimpleHelpProvider::ShowHelp(window);
439}
440
441// Convenience function for turning context id into wxString
442wxString wxContextId(int id)
443{
444 return wxString::Format(_T("%d"), id);
445}
446
447// ----------------------------------------------------------------------------
448// wxHelpProviderModule: module responsible for cleaning up help provider.
449// ----------------------------------------------------------------------------
450
451class wxHelpProviderModule : public wxModule
452{
453public:
454 bool OnInit();
455 void OnExit();
456
457private:
458 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
459};
460
461IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
462
463bool wxHelpProviderModule::OnInit()
464{
465 // Probably we don't want to do anything by default,
466 // since it could pull in extra code
467 // wxHelpProvider::Set(new wxSimpleHelpProvider);
468
469 return true;
470}
471
472void wxHelpProviderModule::OnExit()
473{
474 if (wxHelpProvider::Get())
475 {
476 delete wxHelpProvider::Get();
477 wxHelpProvider::Set(NULL);
478 }
479}
480
481#endif // wxUSE_HELP