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