]> git.saurik.com Git - wxWidgets.git/blame - src/common/cshelp.cpp
Make radiobutton tab behaviour the same on MSW
[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{
ba8c1601
MB
355 m_hashIds.erase((long)id);
356 m_hashIds[id] = text;
bd83cb56
VZ
357}
358
53e112a0
JS
359// removes the association
360void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
361{
ba8c1601 362 m_hashWindows.erase((long)window);
53e112a0
JS
363}
364
bd83cb56
VZ
365bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
366{
f38bcae5 367#if wxUSE_TIPWINDOW
173e8bbf
JS
368 static wxTipWindow* s_tipWindow = NULL;
369
370 if (s_tipWindow)
371 {
372 // Prevent s_tipWindow being nulled in OnIdle,
373 // thereby removing the chance for the window to be closed by ShowHelp
374 s_tipWindow->SetTipWindowPtr(NULL);
375 s_tipWindow->Close();
376 }
377 s_tipWindow = NULL;
378
bd83cb56
VZ
379 wxString text = GetHelp(window);
380 if ( !text.empty() )
381 {
173e8bbf 382 s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
bd83cb56 383
c9d59ee7 384 return true;
bd83cb56 385 }
f38bcae5 386#endif // wxUSE_TIPWINDOW
bd83cb56 387
c9d59ee7 388 return false;
bd83cb56
VZ
389}
390
5100cabf
JS
391// ----------------------------------------------------------------------------
392// wxHelpControllerHelpProvider
393// ----------------------------------------------------------------------------
394
395wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
396{
397 m_helpController = hc;
398}
399
400bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
401{
402 wxString text = GetHelp(window);
403 if ( !text.empty() )
404 {
405 if (m_helpController)
406 {
407 if (text.IsNumber())
408 return m_helpController->DisplayContextPopup(wxAtoi(text));
409
410 // If the help controller is capable of popping up the text...
411 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
412 {
c9d59ee7 413 return true;
5100cabf
JS
414 }
415 else
416 // ...else use the default method.
417 return wxSimpleHelpProvider::ShowHelp(window);
418 }
419 else
420 return wxSimpleHelpProvider::ShowHelp(window);
421
422 }
423
c9d59ee7 424 return false;
5100cabf
JS
425}
426
427// Convenience function for turning context id into wxString
428wxString wxContextId(int id)
429{
11968fef 430 return wxString::Format(_T("%d"), id);
5100cabf
JS
431}
432
129caadd
JS
433// ----------------------------------------------------------------------------
434// wxHelpProviderModule: module responsible for cleaning up help provider.
435// ----------------------------------------------------------------------------
436
437class wxHelpProviderModule : public wxModule
438{
439public:
440 bool OnInit();
441 void OnExit();
442
443private:
444 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
445};
446
447IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
448
449bool wxHelpProviderModule::OnInit()
450{
451 // Probably we don't want to do anything by default,
452 // since it could pull in extra code
453 // wxHelpProvider::Set(new wxSimpleHelpProvider);
454
c9d59ee7 455 return true;
129caadd
JS
456}
457
458void wxHelpProviderModule::OnExit()
459{
460 if (wxHelpProvider::Get())
461 {
462 delete wxHelpProvider::Get();
463 wxHelpProvider::Set(NULL);
464 }
465}
466
fb6261e9 467#endif // wxUSE_HELP