]> git.saurik.com Git - wxWidgets.git/blame - src/common/cshelp.cpp
use "event-after" signal to send thumb release event
[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{
226 wxWindow* subjectOfHelp = win;
c9d59ee7 227 bool eventProcessed = false;
fb6261e9
JS
228 while (subjectOfHelp && !eventProcessed)
229 {
b107e8d5
VZ
230 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt,
231 wxHelpEvent::Origin_HelpButton);
6fefc28d 232 helpEvent.SetEventObject(subjectOfHelp);
dc4211aa 233
fb6261e9 234 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
dc4211aa 235
fb6261e9
JS
236 // Go up the window hierarchy until the event is handled (or not).
237 // I.e. keep submitting ancestor windows until one is recognised
238 // by the app code that processes the ids and displays help.
239 subjectOfHelp = subjectOfHelp->GetParent();
240 }
241 return eventProcessed;
242}
243
bd83cb56
VZ
244// ----------------------------------------------------------------------------
245// wxContextHelpButton
246// ----------------------------------------------------------------------------
247
fb6261e9
JS
248/*
249 * wxContextHelpButton
250 * You can add this to your dialogs (especially on non-Windows platforms)
251 * to put the application into context help mode.
252 */
253
7a893a31
WS
254#ifndef __WXPM__
255
90350682 256static const char * csquery_xpm[] = {
fb6261e9 257"12 11 2 1",
57591e0e
JS
258" c None",
259". c #000000",
fb6261e9
JS
260" ",
261" .... ",
262" .. .. ",
263" .. .. ",
264" .. ",
265" .. ",
266" .. ",
267" ",
268" .. ",
269" .. ",
270" "};
fb6261e9 271
7a893a31
WS
272#endif
273
fb6261e9
JS
274IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
275
276BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
277 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
278END_EVENT_TABLE()
279
84bfc0d5
VZ
280wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
281 wxWindowID id,
282 const wxPoint& pos,
283 const wxSize& size,
284 long style)
dc4211aa
DW
285#if defined(__WXPM__)
286 : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
287 ,wxBITMAP_TYPE_RESOURCE
288 ),
289 pos, size, style)
290#else
e0f4c2c8 291 : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
84bfc0d5 292 pos, size, style)
dc4211aa 293#endif
fb6261e9 294{
fb6261e9
JS
295}
296
33ac7e6f 297void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
fb6261e9 298{
57591e0e 299 wxContextHelp contextHelp(GetParent());
fb6261e9
JS
300}
301
bd83cb56
VZ
302// ----------------------------------------------------------------------------
303// wxHelpProvider
304// ----------------------------------------------------------------------------
305
306wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
307
308// trivial implementation of some methods which we don't want to make pure
309// virtual for convenience
310
311void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
312 const wxString& WXUNUSED(text))
313{
314}
315
316void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
317 const wxString& WXUNUSED(text))
318{
319}
320
53e112a0
JS
321// removes the association
322void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
323{
324}
325
bd83cb56
VZ
326wxHelpProvider::~wxHelpProvider()
327{
328}
329
330// ----------------------------------------------------------------------------
331// wxSimpleHelpProvider
332// ----------------------------------------------------------------------------
333
17a1ebd1
VZ
334#define WINHASH_KEY(w) wxPtrToUInt(w)
335
bd83cb56
VZ
336wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
337{
871192ce 338 wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
bd83cb56 339
ba8c1601
MB
340 if ( it == m_hashWindows.end() )
341 {
342 it = m_hashIds.find(window->GetId());
343 if ( it == m_hashIds.end() )
344 return wxEmptyString;
345 }
346
347 return it->second;
bd83cb56
VZ
348}
349
350void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
351{
17a1ebd1
VZ
352 m_hashWindows.erase(WINHASH_KEY(window));
353 m_hashWindows[WINHASH_KEY(window)] = text;
bd83cb56
VZ
354}
355
356void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
357{
871192ce 358 wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
65aeb571
WS
359 m_hashIds.erase(key);
360 m_hashIds[key] = text;
bd83cb56
VZ
361}
362
53e112a0
JS
363// removes the association
364void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
365{
17a1ebd1 366 m_hashWindows.erase(WINHASH_KEY(window));
53e112a0
JS
367}
368
bd83cb56
VZ
369bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
370{
f38bcae5 371#if wxUSE_TIPWINDOW
173e8bbf
JS
372 static wxTipWindow* s_tipWindow = NULL;
373
374 if (s_tipWindow)
375 {
376 // Prevent s_tipWindow being nulled in OnIdle,
377 // thereby removing the chance for the window to be closed by ShowHelp
378 s_tipWindow->SetTipWindowPtr(NULL);
379 s_tipWindow->Close();
380 }
381 s_tipWindow = NULL;
382
bd83cb56
VZ
383 wxString text = GetHelp(window);
384 if ( !text.empty() )
385 {
173e8bbf 386 s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
bd83cb56 387
c9d59ee7 388 return true;
bd83cb56 389 }
ddc80eb4
WS
390#else
391 wxUnusedVar(window);
f38bcae5 392#endif // wxUSE_TIPWINDOW
bd83cb56 393
c9d59ee7 394 return false;
bd83cb56
VZ
395}
396
5100cabf
JS
397// ----------------------------------------------------------------------------
398// wxHelpControllerHelpProvider
399// ----------------------------------------------------------------------------
400
401wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
402{
403 m_helpController = hc;
404}
405
406bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
407{
408 wxString text = GetHelp(window);
409 if ( !text.empty() )
410 {
411 if (m_helpController)
412 {
413 if (text.IsNumber())
414 return m_helpController->DisplayContextPopup(wxAtoi(text));
415
416 // If the help controller is capable of popping up the text...
417 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
418 {
c9d59ee7 419 return true;
5100cabf
JS
420 }
421 else
422 // ...else use the default method.
423 return wxSimpleHelpProvider::ShowHelp(window);
424 }
425 else
426 return wxSimpleHelpProvider::ShowHelp(window);
427
428 }
429
c9d59ee7 430 return false;
5100cabf
JS
431}
432
433// Convenience function for turning context id into wxString
434wxString wxContextId(int id)
435{
11968fef 436 return wxString::Format(_T("%d"), id);
5100cabf
JS
437}
438
129caadd
JS
439// ----------------------------------------------------------------------------
440// wxHelpProviderModule: module responsible for cleaning up help provider.
441// ----------------------------------------------------------------------------
442
443class wxHelpProviderModule : public wxModule
444{
445public:
446 bool OnInit();
447 void OnExit();
448
449private:
450 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
451};
452
453IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
454
455bool wxHelpProviderModule::OnInit()
456{
457 // Probably we don't want to do anything by default,
458 // since it could pull in extra code
459 // wxHelpProvider::Set(new wxSimpleHelpProvider);
460
c9d59ee7 461 return true;
129caadd
JS
462}
463
464void wxHelpProviderModule::OnExit()
465{
466 if (wxHelpProvider::Get())
467 {
468 delete wxHelpProvider::Get();
469 wxHelpProvider::Set(NULL);
470 }
471}
472
fb6261e9 473#endif // wxUSE_HELP