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