]> git.saurik.com Git - wxWidgets.git/blame - src/common/cshelp.cpp
Added Set/GetQuickBestSize
[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 {
230 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
6fefc28d 231 helpEvent.SetEventObject(subjectOfHelp);
dc4211aa 232
fb6261e9 233 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
dc4211aa 234
fb6261e9
JS
235 // Go up the window hierarchy until the event is handled (or not).
236 // I.e. keep submitting ancestor windows until one is recognised
237 // by the app code that processes the ids and displays help.
238 subjectOfHelp = subjectOfHelp->GetParent();
239 }
240 return eventProcessed;
241}
242
bd83cb56
VZ
243// ----------------------------------------------------------------------------
244// wxContextHelpButton
245// ----------------------------------------------------------------------------
246
fb6261e9
JS
247/*
248 * wxContextHelpButton
249 * You can add this to your dialogs (especially on non-Windows platforms)
250 * to put the application into context help mode.
251 */
252
7a893a31
WS
253#ifndef __WXPM__
254
90350682 255static const char * csquery_xpm[] = {
fb6261e9 256"12 11 2 1",
57591e0e
JS
257" c None",
258". c #000000",
fb6261e9
JS
259" ",
260" .... ",
261" .. .. ",
262" .. .. ",
263" .. ",
264" .. ",
265" .. ",
266" ",
267" .. ",
268" .. ",
269" "};
fb6261e9 270
7a893a31
WS
271#endif
272
fb6261e9
JS
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
17a1ebd1
VZ
333#define WINHASH_KEY(w) wxPtrToUInt(w)
334
bd83cb56
VZ
335wxString wxSimpleHelpProvider::GetHelp(const wxWindowBase *window)
336{
871192ce 337 wxSimpleHelpProviderHashMap::iterator it = m_hashWindows.find(WINHASH_KEY(window));
bd83cb56 338
ba8c1601
MB
339 if ( it == m_hashWindows.end() )
340 {
341 it = m_hashIds.find(window->GetId());
342 if ( it == m_hashIds.end() )
343 return wxEmptyString;
344 }
345
346 return it->second;
bd83cb56
VZ
347}
348
349void wxSimpleHelpProvider::AddHelp(wxWindowBase *window, const wxString& text)
350{
17a1ebd1
VZ
351 m_hashWindows.erase(WINHASH_KEY(window));
352 m_hashWindows[WINHASH_KEY(window)] = text;
bd83cb56
VZ
353}
354
355void wxSimpleHelpProvider::AddHelp(wxWindowID id, const wxString& text)
356{
871192ce 357 wxSimpleHelpProviderHashMap::key_type key = (wxSimpleHelpProviderHashMap::key_type)id;
65aeb571
WS
358 m_hashIds.erase(key);
359 m_hashIds[key] = text;
bd83cb56
VZ
360}
361
53e112a0
JS
362// removes the association
363void wxSimpleHelpProvider::RemoveHelp(wxWindowBase* window)
364{
17a1ebd1 365 m_hashWindows.erase(WINHASH_KEY(window));
53e112a0
JS
366}
367
bd83cb56
VZ
368bool wxSimpleHelpProvider::ShowHelp(wxWindowBase *window)
369{
f38bcae5 370#if wxUSE_TIPWINDOW
173e8bbf
JS
371 static wxTipWindow* s_tipWindow = NULL;
372
373 if (s_tipWindow)
374 {
375 // Prevent s_tipWindow being nulled in OnIdle,
376 // thereby removing the chance for the window to be closed by ShowHelp
377 s_tipWindow->SetTipWindowPtr(NULL);
378 s_tipWindow->Close();
379 }
380 s_tipWindow = NULL;
381
bd83cb56
VZ
382 wxString text = GetHelp(window);
383 if ( !text.empty() )
384 {
173e8bbf 385 s_tipWindow = new wxTipWindow((wxWindow *)window, text, 100, & s_tipWindow);
bd83cb56 386
c9d59ee7 387 return true;
bd83cb56 388 }
ddc80eb4
WS
389#else
390 wxUnusedVar(window);
f38bcae5 391#endif // wxUSE_TIPWINDOW
bd83cb56 392
c9d59ee7 393 return false;
bd83cb56
VZ
394}
395
5100cabf
JS
396// ----------------------------------------------------------------------------
397// wxHelpControllerHelpProvider
398// ----------------------------------------------------------------------------
399
400wxHelpControllerHelpProvider::wxHelpControllerHelpProvider(wxHelpControllerBase* hc)
401{
402 m_helpController = hc;
403}
404
405bool wxHelpControllerHelpProvider::ShowHelp(wxWindowBase *window)
406{
407 wxString text = GetHelp(window);
408 if ( !text.empty() )
409 {
410 if (m_helpController)
411 {
412 if (text.IsNumber())
413 return m_helpController->DisplayContextPopup(wxAtoi(text));
414
415 // If the help controller is capable of popping up the text...
416 else if (m_helpController->DisplayTextPopup(text, wxGetMousePosition()))
417 {
c9d59ee7 418 return true;
5100cabf
JS
419 }
420 else
421 // ...else use the default method.
422 return wxSimpleHelpProvider::ShowHelp(window);
423 }
424 else
425 return wxSimpleHelpProvider::ShowHelp(window);
426
427 }
428
c9d59ee7 429 return false;
5100cabf
JS
430}
431
432// Convenience function for turning context id into wxString
433wxString wxContextId(int id)
434{
11968fef 435 return wxString::Format(_T("%d"), id);
5100cabf
JS
436}
437
129caadd
JS
438// ----------------------------------------------------------------------------
439// wxHelpProviderModule: module responsible for cleaning up help provider.
440// ----------------------------------------------------------------------------
441
442class wxHelpProviderModule : public wxModule
443{
444public:
445 bool OnInit();
446 void OnExit();
447
448private:
449 DECLARE_DYNAMIC_CLASS(wxHelpProviderModule)
450};
451
452IMPLEMENT_DYNAMIC_CLASS(wxHelpProviderModule, wxModule)
453
454bool wxHelpProviderModule::OnInit()
455{
456 // Probably we don't want to do anything by default,
457 // since it could pull in extra code
458 // wxHelpProvider::Set(new wxSimpleHelpProvider);
459
c9d59ee7 460 return true;
129caadd
JS
461}
462
463void wxHelpProviderModule::OnExit()
464{
465 if (wxHelpProvider::Get())
466 {
467 delete wxHelpProvider::Get();
468 wxHelpProvider::Set(NULL);
469 }
470}
471
fb6261e9 472#endif // wxUSE_HELP