]> git.saurik.com Git - wxWidgets.git/blame - src/common/cshelp.cpp
wxFileName::Normalize(wxPATH_NORM_ENV_VARS) now works
[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
ad9fb033 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{
80 m_inHelp = FALSE;
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.
94#if 0
b8b9d8a7
JS
95static void wxPushOrPopEventHandlers(wxContextHelp* help, wxWindow* win, bool push)
96{
97 if (push)
98 win->PushEventHandler(new wxContextHelpEvtHandler(help));
99 else
100 win->PopEventHandler();
101
102 wxNode* node = win->GetChildren().First();
103 while (node)
104 {
105 wxWindow* child = (wxWindow*) node->Data();
106 wxPushOrPopEventHandlers(help, child, push);
107
108 node = node->Next();
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)
119 return FALSE;
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
b8b9d8a7
JS
129 m_status = FALSE;
130
449d48f9
JS
131 win->PushEventHandler(new wxContextHelpEvtHandler(this));
132 //wxPushOrPopEventHandlers(this, win, TRUE);
fb6261e9
JS
133
134 win->CaptureMouse();
135
136 EventLoop();
137
138 win->ReleaseMouse();
139
449d48f9
JS
140 win->PopEventHandler(TRUE);
141 //wxPushOrPopEventHandlers(this, win, FALSE);
fb6261e9
JS
142
143 win->SetCursor(oldCursor);
144
145 if (m_status)
146 {
147 wxPoint pt;
148 wxWindow* winAtPtr = wxFindWindowAtPointer(pt);
ad9fb033 149 /*
d1c8aaa3
JS
150 if (winAtPtr)
151 {
ad9fb033 152 wxString msg;
d1c8aaa3
JS
153 msg.Printf("Picked %s (%d)", (const char*) winAtPtr->GetName(), winAtPtr->GetId());
154 cout << msg << '\n';
155 }
ad9fb033 156 */
d1c8aaa3 157
fb6261e9
JS
158 if (winAtPtr)
159 DispatchEvent(winAtPtr, pt);
160 }
161
162 return TRUE;
163}
164
165bool wxContextHelp::EndContextHelp()
166{
167 m_inHelp = FALSE;
168
169 return TRUE;
170}
171
172bool wxContextHelp::EventLoop()
173{
174 m_inHelp = TRUE;
dc4211aa 175
fb6261e9
JS
176 while ( m_inHelp )
177 {
178 if (wxTheApp->Pending())
179 {
180 wxTheApp->Dispatch();
181 }
182 else
183 {
184 wxTheApp->ProcessIdle();
185 }
186 }
dc4211aa 187
fb6261e9
JS
188 return TRUE;
189}
190
191bool wxContextHelpEvtHandler::ProcessEvent(wxEvent& event)
192{
77d4384e 193 if (event.GetEventType() == wxEVT_LEFT_DOWN)
fb6261e9 194 {
77d4384e
RR
195 m_contextHelp->SetStatus(TRUE);
196 m_contextHelp->EndContextHelp();
197 return TRUE;
fb6261e9 198 }
33ac7e6f 199
77d4384e
RR
200 if ((event.GetEventType() == wxEVT_CHAR) ||
201 (event.GetEventType() == wxEVT_KEY_DOWN) ||
202 (event.GetEventType() == wxEVT_ACTIVATE) ||
203 (event.GetEventType() == wxEVT_MOUSE_CAPTURE_CHANGED))
204 {
b8b9d8a7
JS
205 // May have already been set to TRUE by a left-click
206 //m_contextHelp->SetStatus(FALSE);
77d4384e
RR
207 m_contextHelp->EndContextHelp();
208 return TRUE;
209 }
33ac7e6f 210
77d4384e
RR
211 if ((event.GetEventType() == wxEVT_PAINT) ||
212 (event.GetEventType() == wxEVT_ERASE_BACKGROUND))
213 {
214 event.Skip();
215 return FALSE;
216 }
33ac7e6f 217
fb6261e9
JS
218 return TRUE;
219}
220
221// Dispatch the help event to the relevant window
222bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
223{
224 wxWindow* subjectOfHelp = win;
225 bool eventProcessed = FALSE;
226 while (subjectOfHelp && !eventProcessed)
227 {
228 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
229 helpEvent.SetEventObject(this);
dc4211aa 230
fb6261e9 231 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
dc4211aa 232
fb6261e9
JS
233 // Go up the window hierarchy until the event is handled (or not).
234 // I.e. keep submitting ancestor windows until one is recognised
235 // by the app code that processes the ids and displays help.
236 subjectOfHelp = subjectOfHelp->GetParent();
237 }
238 return eventProcessed;
239}
240
bd83cb56
VZ
241// ----------------------------------------------------------------------------
242// wxContextHelpButton
243// ----------------------------------------------------------------------------
244
fb6261e9
JS
245/*
246 * wxContextHelpButton
247 * You can add this to your dialogs (especially on non-Windows platforms)
248 * to put the application into context help mode.
249 */
250
90350682 251static const char * csquery_xpm[] = {
fb6261e9 252"12 11 2 1",
57591e0e
JS
253" c None",
254". c #000000",
fb6261e9
JS
255" ",
256" .... ",
257" .. .. ",
258" .. .. ",
259" .. ",
260" .. ",
261" .. ",
262" ",
263" .. ",
264" .. ",
265" "};
fb6261e9
JS
266
267IMPLEMENT_CLASS(wxContextHelpButton, wxBitmapButton)
268
269BEGIN_EVENT_TABLE(wxContextHelpButton, wxBitmapButton)
270 EVT_BUTTON(wxID_CONTEXT_HELP, wxContextHelpButton::OnContextHelp)
271END_EVENT_TABLE()
272
84bfc0d5
VZ
273wxContextHelpButton::wxContextHelpButton(wxWindow* parent,
274 wxWindowID id,
275 const wxPoint& pos,
276 const wxSize& size,
277 long style)
dc4211aa
DW
278#if defined(__WXPM__)
279 : wxBitmapButton(parent, id, wxBitmap(wxCSQUERY_BITMAP
280 ,wxBITMAP_TYPE_RESOURCE
281 ),
282 pos, size, style)
283#else
e0f4c2c8 284 : wxBitmapButton(parent, id, wxBitmap(csquery_xpm),
84bfc0d5 285 pos, size, style)
dc4211aa 286#endif
fb6261e9 287{
fb6261e9
JS
288}
289
33ac7e6f 290void wxContextHelpButton::OnContextHelp(wxCommandEvent& WXUNUSED(event))
fb6261e9 291{
57591e0e 292 wxContextHelp contextHelp(GetParent());
fb6261e9
JS
293}
294
bd83cb56
VZ
295// ----------------------------------------------------------------------------
296// wxHelpProvider
297// ----------------------------------------------------------------------------
298
299wxHelpProvider *wxHelpProvider::ms_helpProvider = (wxHelpProvider *)NULL;
300
301// trivial implementation of some methods which we don't want to make pure
302// virtual for convenience
303
304void wxHelpProvider::AddHelp(wxWindowBase * WXUNUSED(window),
305 const wxString& WXUNUSED(text))
306{
307}
308
309void wxHelpProvider::AddHelp(wxWindowID WXUNUSED(id),
310 const wxString& WXUNUSED(text))
311{
312}
313
53e112a0
JS
314// removes the association
315void wxHelpProvider::RemoveHelp(wxWindowBase* WXUNUSED(window))
316{
317}
318
bd83cb56
VZ
319wxHelpProvider::~wxHelpProvider()
320{
321}
322
323// ----------------------------------------------------------------------------
324// wxSimpleHelpProvider
325// ----------------------------------------------------------------------------
326
327wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
328{
ba8c1601 329 wxLongToStringHashMap::iterator it = m_hashWindows.find((long)window);
bd83cb56 330
ba8c1601
MB
331 if ( it == m_hashWindows.end() )
332 {
333 it = m_hashIds.find(window->GetId());
334 if ( it == m_hashIds.end() )
335 return wxEmptyString;
336 }
337
338 return it->second;
bd83cb56
VZ
339}
340
341void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
342{
ba8c1601
MB
343 m_hashWindows.erase((long)window);
344 m_hashWindows[(long)window] = text;
bd83cb56
VZ
345}
346
347void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
348{
ba8c1601
MB
349 m_hashIds.erase((long)id);
350 m_hashIds[id] = text;
bd83cb56
VZ
351}
352
53e112a0
JS
353// removes the association
354void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
355{
ba8c1601 356 m_hashWindows.erase((long)window);
53e112a0
JS
357}
358
bd83cb56
VZ
359bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
360{
f38bcae5 361#if wxUSE_TIPWINDOW
173e8bbf
JS
362 static wxTipWindow* s_tipWindow = NULL;
363
364 if (s_tipWindow)
365 {
366 // Prevent s_tipWindow being nulled in OnIdle,
367 // thereby removing the chance for the window to be closed by ShowHelp
368 s_tipWindow->SetTipWindowPtr(NULL);
369 s_tipWindow->Close();
370 }
371 s_tipWindow = NULL;
372
bd83cb56
VZ
373 wxString text = GetHelp(window);
374 if ( !text.empty() )
375 {
173e8bbf 376 s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
bd83cb56
VZ
377
378 return TRUE;
379 }
f38bcae5 380#endif // wxUSE_TIPWINDOW
bd83cb56
VZ
381
382 return FALSE;
383}
384
5100cabf
JS
385// ----------------------------------------------------------------------------
386// wxHelpControllerHelpProvider
387// ----------------------------------------------------------------------------
388
389wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
390{
391 m_helpController = hc;
392}
393
394bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
395{
396 wxString text = GetHelp(window);
397 if ( !text.empty() )
398 {
399 if (m_helpController)
400 {
401 if (text.IsNumber())
402 return m_helpController->DisplayContextPopup(wxAtoi(text));
403
404 // If the help controller is capable of popping up the text...
405 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
406 {
407 return TRUE;
408 }
409 else
410 // ...else use the default method.
411 return wxSimpleHelpProvider::ShowHelp(window);
412 }
413 else
414 return wxSimpleHelpProvider::ShowHelp(window);
415
416 }
417
418 return FALSE;
419}
420
421// Convenience function for turning context id into wxString
422wxString wxContextId(int id)
423{
11968fef 424 return wxString::Format(_T("%d"), id);
5100cabf
JS
425}
426
129caadd
JS
427// ----------------------------------------------------------------------------
428// wxHelpProviderModule: module responsible for cleaning up help provider.
429// ----------------------------------------------------------------------------
430
431class wxHelpProviderModule : public wxModule
432{
433public:
434 bool OnInit();
435 void OnExit();
436
437private:
438 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
439};
440
441IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
442
443bool wxHelpProviderModule::OnInit()
444{
445 // Probably we don't want to do anything by default,
446 // since it could pull in extra code
447 // wxHelpProvider::Set(new wxSimpleHelpProvider);
448
449 return TRUE;
450}
451
452void wxHelpProviderModule::OnExit()
453{
454 if (wxHelpProvider::Get())
455 {
456 delete wxHelpProvider::Get();
457 wxHelpProvider::Set(NULL);
458 }
459}
460
fb6261e9 461#endif // wxUSE_HELP