]> git.saurik.com Git - wxWidgets.git/blame - src/common/cshelp.cpp
Include wx/colour.h according to precompiled headers of wx/wx.h (with other minor...
[wxWidgets.git] / src / common / cshelp.cpp
CommitLineData
fb6261e9 1/////////////////////////////////////////////////////////////////////////////
bd83cb56 2// Name: src/common/cshelp.cpp
fb6261e9 3// Purpose: Context sensitive help class implementation
bd83cb56 4// Author: Julian Smart, Vadim Zeitlin
fb6261e9
JS
5// Modified by:
6// Created: 08/09/2000
7// RCS-ID: $Id$
bd83cb56 8// Copyright: (c) 2000 Julian Smart, Vadim Zeitlin
65571936 9// Licence: wxWindows licence
fb6261e9
JS
10/////////////////////////////////////////////////////////////////////////////
11
bd83cb56
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
bd83cb56
VZ
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
fb6261e9
JS
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
bd83cb56 24 #pragma hdrstop
fb6261e9
JS
25#endif
26
bd83cb56
VZ
27#if wxUSE_HELP
28
fb6261e9 29#ifndef WX_PRECOMP
670f9935 30 #include "wx/app.h"
fb6261e9
JS
31#endif
32
afb02ca5 33#include "wx/tipwin.h"
129caadd 34#include "wx/module.h"
fb6261e9
JS
35#include "wx/cshelp.h"
36
bd83cb56
VZ
37// ----------------------------------------------------------------------------
38// wxContextHelpEvtHandler private class
39// ----------------------------------------------------------------------------
fb6261e9 40
bd83cb56
VZ
41// This class exists in order to eat events until the left mouse button is
42// pressed
fb6261e9
JS
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;
22f3361e
VZ
55
56 DECLARE_NO_COPY_CLASS(wxContextHelpEvtHandler)
fb6261e9
JS
57};
58
bd83cb56
VZ
59// ============================================================================
60// implementation
61// ============================================================================
62
63// ----------------------------------------------------------------------------
64// wxContextHelp
65// ----------------------------------------------------------------------------
66
67/*
68 * Invokes context-sensitive help
69 */
70
71
fb6261e9
JS
72IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
73
74wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
75{
c9d59ee7 76 m_inHelp = false;
fb6261e9
JS
77
78 if (beginHelp)
79 BeginContextHelp(win);
80}
81
82wxContextHelp::~wxContextHelp()
83{
84 if (m_inHelp)
85 EndContextHelp();
86}
87
449d48f9
JS
88// Not currently needed, but on some systems capture may not work as
89// expected so we'll leave it here for now.
ecb9c007 90#ifdef __WXMOTIF__
b8b9d8a7
JS
91static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
92{
93 if (push)
94 win->PushEventHandler(new wxContextHelpEvtHandler(help));
95 else
c9d59ee7 96 win->PopEventHandler(true);
b8b9d8a7 97
094112e9 98 wxWindowList::compatibility_iterator node = win->GetChildren().GetFirst();
b8b9d8a7
JS
99 while (node)
100 {
ecb9c007 101 wxWindow* child = node->GetData();
b8b9d8a7
JS
102 wxPushOrPopEventHandlers(help, child, push);
103
ecb9c007 104 node = node->GetNext();
b8b9d8a7
JS
105 }
106}
449d48f9 107#endif
b8b9d8a7 108
fb6261e9
JS
109// Begin 'context help mode'
110bool wxContextHelp::BeginContextHelp(wxWindow* win)
111{
112 if (!win)
113 win = wxTheApp->GetTopWindow();
114 if (!win)
c9d59ee7 115 return false;
fb6261e9
JS
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
c9d59ee7 125 m_status = false;
b8b9d8a7 126
ecb9c007 127#ifdef __WXMOTIF__
c9d59ee7 128 wxPushOrPopEventHandlers(this, win, true);
ecb9c007 129#else
449d48f9 130 win->PushEventHandler(new wxContextHelpEvtHandler(this));
ecb9c007 131#endif
fb6261e9
JS
132
133 win->CaptureMouse();
134
135 EventLoop();
136
137 win->ReleaseMouse();
138
ecb9c007 139#ifdef __WXMOTIF__
c9d59ee7 140 wxPushOrPopEventHandlers(this, win, false);
ecb9c007 141#else
c9d59ee7 142 win->PopEventHandler(true);
ecb9c007 143#endif
fb6261e9
JS
144
145 win->SetCursor(oldCursor);
146
147 if (m_status)
148 {
149 wxPoint pt;
150 wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
ecb9c007
MB
151
152#if 0
d1c8aaa3
JS
153 if (winAtPtr)
154 {
ecb9c007
MB
155 printf("Picked %s (%d)\n", winAtPtr->GetName().c_str(),
156 winAtPtr->GetId());
d1c8aaa3 157 }
ecb9c007 158#endif
d1c8aaa3 159
fb6261e9
JS
160 if (winAtPtr)
161 DispatchEvent(winAtPtr, pt);
162 }
163
c9d59ee7 164 return true;
fb6261e9
JS
165}
166
167bool wxContextHelp::EndContextHelp()
168{
c9d59ee7 169 m_inHelp = false;
fb6261e9 170
c9d59ee7 171 return true;
fb6261e9
JS
172}
173
174bool wxContextHelp::EventLoop()
175{
c9d59ee7 176 m_inHelp = true;
dc4211aa 177
fb6261e9
JS
178 while ( m_inHelp )
179 {
180 if (wxTheApp->Pending())
181 {
182 wxTheApp->Dispatch();
183 }
184 else
185 {
186 wxTheApp->ProcessIdle();
187 }
188 }
dc4211aa 189
c9d59ee7 190 return true;
fb6261e9
JS
191}
192
193bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
194{
77d4384e 195 if (event.GetEventType() == wxEVT_LEFT_DOWN)
fb6261e9 196 {
c9d59ee7 197 m_contextHelp->SetStatus(true);
77d4384e 198 m_contextHelp->EndContextHelp();
c9d59ee7 199 return true;
fb6261e9 200 }
33ac7e6f 201
77d4384e
RR
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 {
c9d59ee7
WS
207 // May have already been set to true by a left-click
208 //m_contextHelp->SetStatus(false);
77d4384e 209 m_contextHelp->EndContextHelp();
c9d59ee7 210 return true;
77d4384e 211 }
33ac7e6f 212
77d4384e
RR
213 if ((event.GetEventType() == wxEVT_PAINT) ||
214 (event.GetEventType() == wxEVT_ERASE_BACKGROUND))
215 {
216 event.Skip();
c9d59ee7 217 return false;
77d4384e 218 }
33ac7e6f 219
c9d59ee7 220 return true;
fb6261e9
JS
221}
222
223// Dispatch the help event to the relevant window
224bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
225{
1ed403dc 226 wxCHECK_MSG( win, false, _T("win parameter can't be NULL") );
dc4211aa 227
1ed403dc
VZ
228 wxHelpEvent helpEvent(wxEVT_HELP, win->GetId(), pt,
229 wxHelpEvent::Origin_HelpButton);
230 helpEvent.SetEventObject(win);
dc4211aa 231
1ed403dc 232 return win->GetEventHandler()->ProcessEvent(helpEvent);
fb6261e9
JS
233}
234
bd83cb56
VZ
235// ----------------------------------------------------------------------------
236// wxContextHelpButton
237// ----------------------------------------------------------------------------
238
fb6261e9
JS
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
7a893a31
WS
245#ifndef __WXPM__
246
90350682 247static const char * csquery_xpm[] = {
fb6261e9 248"12 11 2 1",
57591e0e
JS
249" c None",
250". c #000000",
fb6261e9
JS
251" ",
252" .... ",
253" .. .. ",
254" .. .. ",
255" .. ",
256" .. ",
257" .. ",
258" ",
259" .. ",
260" .. ",
261" "};
fb6261e9 262
7a893a31
WS
263#endif
264
fb6261e9
JS
265IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
266
267BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
268 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
269END_EVENT_TABLE()
270
84bfc0d5
VZ
271wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
272 wxWindowID id,
273 const wxPoint& pos,
274 const wxSize& size,
275 long style)
dc4211aa
DW
276#if defined(__WXPM__)
277 : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
278 ,wxBITMAP_TYPE_RESOURCE
279 ),
280 pos, size, style)
281#else
e0f4c2c8 282 : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
84bfc0d5 283 pos, size, style)
dc4211aa 284#endif
fb6261e9 285{
fb6261e9
JS
286}
287
33ac7e6f 288void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
fb6261e9 289{
57591e0e 290 wxContextHelp contextHelp(GetParent());
fb6261e9
JS
291}
292
bd83cb56
VZ
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
53e112a0
JS
312// removes the association
313void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
314{
315}
316
bd83cb56
VZ
317wxHelpProvider::~wxHelpProvider()
318{
319}
320
dc6588e7
VZ
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
bd83cb56
VZ
340// ----------------------------------------------------------------------------
341// wxSimpleHelpProvider
342// ----------------------------------------------------------------------------
343
17a1ebd1
VZ
344#define WINHASH_KEY(w) wxPtrToUInt(w)
345
bd83cb56
VZ
346wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
347{
871192ce 348 wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
bd83cb56 349
ba8c1601
MB
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;
bd83cb56
VZ
358}
359
360void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
361{
17a1ebd1
VZ
362 m_hashWindows.erase(WINHASH_KEY(window));
363 m_hashWindows[WINHASH_KEY(window)] = text;
bd83cb56
VZ
364}
365
366void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
367{
871192ce 368 wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
65aeb571
WS
369 m_hashIds.erase(key);
370 m_hashIds[key] = text;
bd83cb56
VZ
371}
372
53e112a0
JS
373// removes the association
374void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
375{
17a1ebd1 376 m_hashWindows.erase(WINHASH_KEY(window));
53e112a0
JS
377}
378
bd83cb56
VZ
379bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
380{
f38bcae5 381#if wxUSE_TIPWINDOW
173e8bbf
JS
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
dc6588e7 393 const wxString text = GetHelpTextMaybeAtPoint(window);
bd83cb56
VZ
394 if ( !text.empty() )
395 {
dc6588e7
VZ
396 s_tipWindow = new wxTipWindow((wxWindow *)window, text,
397 100, &s_tipWindow);
bd83cb56 398
c9d59ee7 399 return true;
bd83cb56 400 }
ddc80eb4
WS
401#else
402 wxUnusedVar(window);
f38bcae5 403#endif // wxUSE_TIPWINDOW
bd83cb56 404
c9d59ee7 405 return false;
bd83cb56
VZ
406}
407
5100cabf
JS
408// ----------------------------------------------------------------------------
409// wxHelpControllerHelpProvider
410// ----------------------------------------------------------------------------
411
412wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
413{
414 m_helpController = hc;
415}
416
417bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
418{
dc6588e7 419 const wxString text = GetHelpTextMaybeAtPoint(window);
5100cabf 420
dc6588e7
VZ
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;
5100cabf
JS
434 }
435
dc6588e7
VZ
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);
5100cabf
JS
439}
440
441// Convenience function for turning context id into wxString
442wxString wxContextId(int id)
443{
11968fef 444 return wxString::Format(_T("%d"), id);
5100cabf
JS
445}
446
129caadd
JS
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
c9d59ee7 469 return true;
129caadd
JS
470}
471
472void wxHelpProviderModule::OnExit()
473{
474 if (wxHelpProvider::Get())
475 {
476 delete wxHelpProvider::Get();
477 wxHelpProvider::Set(NULL);
478 }
479}
480
fb6261e9 481#endif // wxUSE_HELP