New event types for use in external libs (and from
[wxWidgets.git] / src / common / cshelp.cpp
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 #ifdef __GNUG__
17 #pragma implementation "cshelp.h"
18 #endif
19
20 // ----------------------------------------------------------------------------
21 // headers
22 // ----------------------------------------------------------------------------
23
24 // For compilers that support precompilation, includes "wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28 #pragma hdrstop
29 #endif
30
31 #if wxUSE_HELP
32
33 #ifndef WX_PRECOMP
34 #endif
35
36 #include "wx/tipwin.h"
37 #include "wx/app.h"
38 #include "wx/module.h"
39 #include "wx/cshelp.h"
40
41 // ----------------------------------------------------------------------------
42 // wxContextHelpEvtHandler private class
43 // ----------------------------------------------------------------------------
44
45 // This class exists in order to eat events until the left mouse button is
46 // pressed
47 class wxContextHelpEvtHandler: public wxEvtHandler
48 {
49 public:
50 wxContextHelpEvtHandler(wxContextHelp* contextHelp)
51 {
52 m_contextHelp = contextHelp;
53 }
54
55 virtual bool ProcessEvent(wxEvent& event);
56
57 //// Data
58 wxContextHelp* m_contextHelp;
59 };
60
61 // ============================================================================
62 // implementation
63 // ============================================================================
64
65 // ----------------------------------------------------------------------------
66 // wxContextHelp
67 // ----------------------------------------------------------------------------
68
69 /*
70 * Invokes context-sensitive help
71 */
72
73
74 IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
75
76 wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
77 {
78 m_inHelp = FALSE;
79
80 if (beginHelp)
81 BeginContextHelp(win);
82 }
83
84 wxContextHelp::~wxContextHelp()
85 {
86 if (m_inHelp)
87 EndContextHelp();
88 }
89
90 // Begin 'context help mode'
91 bool wxContextHelp::BeginContextHelp(wxWindow* win)
92 {
93 if (!win)
94 win = wxTheApp->GetTopWindow();
95 if (!win)
96 return FALSE;
97
98 wxCursor cursor(wxCURSOR_QUESTION_ARROW);
99 wxCursor oldCursor = win->GetCursor();
100 win->SetCursor(cursor);
101
102 #ifdef __WXMSW__
103 // wxSetCursor(cursor);
104 #endif
105
106 win->PushEventHandler(new wxContextHelpEvtHandler(this));
107
108 win->CaptureMouse();
109
110 EventLoop();
111
112 win->ReleaseMouse();
113
114 win->PopEventHandler(TRUE);
115
116 win->SetCursor(oldCursor);
117
118 if (m_status)
119 {
120 wxPoint pt;
121 wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
122 /*
123 if (winAtPtr)
124 {
125 wxString msg;
126 msg.Printf("Picked %s (%d)", (const char*) winAtPtr->GetName(), winAtPtr->GetId());
127 cout << msg << '\n';
128 }
129 */
130
131 if (winAtPtr)
132 DispatchEvent(winAtPtr, pt);
133 }
134
135 return TRUE;
136 }
137
138 bool wxContextHelp::EndContextHelp()
139 {
140 m_inHelp = FALSE;
141
142 return TRUE;
143 }
144
145 bool wxContextHelp::EventLoop()
146 {
147 m_inHelp = TRUE;
148 while ( m_inHelp )
149 {
150 if (wxTheApp->Pending())
151 {
152 wxTheApp->Dispatch();
153 }
154 else
155 {
156 wxTheApp->ProcessIdle();
157 }
158 }
159 return TRUE;
160 }
161
162 bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
163 {
164 if (event.GetEventType() == wxEVT_LEFT_DOWN)
165 {
166 m_contextHelp->SetStatus(TRUE);
167 m_contextHelp->EndContextHelp();
168 return TRUE;
169 }
170
171 if ((event.GetEventType() == wxEVT_CHAR) ||
172 (event.GetEventType() == wxEVT_KEY_DOWN) ||
173 (event.GetEventType() == wxEVT_ACTIVATE) ||
174 (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
175 {
176 m_contextHelp->SetStatus(FALSE);
177 m_contextHelp->EndContextHelp();
178 return TRUE;
179 }
180
181 if ((event.GetEventType() == wxEVT_PAINT) ||
182 (event.GetEventType() == wxEVT_ERASE_BACKGROUND))
183 {
184 event.Skip();
185 return FALSE;
186 }
187
188 return TRUE;
189 }
190
191 // Dispatch the help event to the relevant window
192 bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
193 {
194 wxWindow* subjectOfHelp = win;
195 bool eventProcessed = FALSE;
196 while (subjectOfHelp && !eventProcessed)
197 {
198 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
199 helpEvent.SetEventObject(this);
200 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
201
202 // Go up the window hierarchy until the event is handled (or not).
203 // I.e. keep submitting ancestor windows until one is recognised
204 // by the app code that processes the ids and displays help.
205 subjectOfHelp = subjectOfHelp->GetParent();
206 }
207 return eventProcessed;
208 }
209
210 // ----------------------------------------------------------------------------
211 // wxContextHelpButton
212 // ----------------------------------------------------------------------------
213
214 /*
215 * wxContextHelpButton
216 * You can add this to your dialogs (especially on non-Windows platforms)
217 * to put the application into context help mode.
218 */
219
220 #if !defined(__WXMSW__)
221 static char * csquery_xpm[] = {
222 "12 11 2 1",
223 " c None",
224 ". c #000000",
225 " ",
226 " .... ",
227 " .. .. ",
228 " .. .. ",
229 " .. ",
230 " .. ",
231 " .. ",
232 " ",
233 " .. ",
234 " .. ",
235 " "};
236 #endif
237
238 IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
239
240 BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
241 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
242 END_EVENT_TABLE()
243
244 wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
245 wxWindowID id,
246 const wxPoint& pos,
247 const wxSize& size,
248 long style)
249 : wxBitmapButton(parent, id, wxBITMAP(csquery),
250 pos, size, style)
251 {
252 }
253
254 void wxContextHelpButton::OnContextHelp(wxCommandEvent& event)
255 {
256 wxContextHelp contextHelp(GetParent());
257 }
258
259 // ----------------------------------------------------------------------------
260 // wxHelpProvider
261 // ----------------------------------------------------------------------------
262
263 wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
264
265 // trivial implementation of some methods which we don't want to make pure
266 // virtual for convenience
267
268 void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
269 const wxString& WXUNUSED(text))
270 {
271 }
272
273 void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
274 const wxString& WXUNUSED(text))
275 {
276 }
277
278 wxHelpProvider::~wxHelpProvider()
279 {
280 }
281
282 // ----------------------------------------------------------------------------
283 // wxSimpleHelpProvider
284 // ----------------------------------------------------------------------------
285
286 wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
287 {
288 bool wasFound;
289 wxString text = m_hashWindows.Get((long)window, &wasFound);
290 if ( !wasFound )
291 text = m_hashIds.Get(window->GetId());
292
293 return text;
294 }
295
296 void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
297 {
298 m_hashWindows.Put((long)window, text);
299 }
300
301 void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
302 {
303 m_hashIds.Put(id, text);
304 }
305
306 bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
307 {
308 wxString text = GetHelp(window);
309 if ( !text.empty() )
310 {
311 new wxTipWindow((wxWindow *)window, text);
312
313 return TRUE;
314 }
315
316 return FALSE;
317 }
318
319 // ----------------------------------------------------------------------------
320 // wxHelpControllerHelpProvider
321 // ----------------------------------------------------------------------------
322
323 wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
324 {
325 m_helpController = hc;
326 }
327
328 bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
329 {
330 wxString text = GetHelp(window);
331 if ( !text.empty() )
332 {
333 if (m_helpController)
334 {
335 if (text.IsNumber())
336 return m_helpController->DisplayContextPopup(wxAtoi(text));
337
338 // If the help controller is capable of popping up the text...
339 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
340 {
341 return TRUE;
342 }
343 else
344 // ...else use the default method.
345 return wxSimpleHelpProvider::ShowHelp(window);
346 }
347 else
348 return wxSimpleHelpProvider::ShowHelp(window);
349
350 }
351
352 return FALSE;
353 }
354
355 // Convenience function for turning context id into wxString
356 wxString wxContextId(int id)
357 {
358 return wxString(IntToString(id));
359 }
360
361 // ----------------------------------------------------------------------------
362 // wxHelpProviderModule: module responsible for cleaning up help provider.
363 // ----------------------------------------------------------------------------
364
365 class wxHelpProviderModule : public wxModule
366 {
367 public:
368 bool OnInit();
369 void OnExit();
370
371 private:
372 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
373 };
374
375 IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
376
377 bool wxHelpProviderModule::OnInit()
378 {
379 // Probably we don't want to do anything by default,
380 // since it could pull in extra code
381 // wxHelpProvider::Set(new wxSimpleHelpProvider);
382
383 return TRUE;
384 }
385
386 void wxHelpProviderModule::OnExit()
387 {
388 if (wxHelpProvider::Get())
389 {
390 delete wxHelpProvider::Get();
391 wxHelpProvider::Set(NULL);
392 }
393 }
394
395 #endif // wxUSE_HELP