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