Added wxHelpEvent, wxContextHelp (MSW only so far), modified help sample
[wxWidgets.git] / src / common / helpbase.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: helpbase.cpp
3 // Purpose: Help system base classes
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "helpbase.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include "wx/defs.h"
25 #endif
26
27 #include "wx/helpbase.h"
28
29 #ifdef __WXMSW__
30 #include "wx/msw/private.h"
31 #endif
32
33 #if wxUSE_HELP
34
35 IMPLEMENT_CLASS(wxHelpControllerBase, wxObject)
36
37 /*
38 * Invokes context-sensitive help
39 */
40
41 IMPLEMENT_DYNAMIC_CLASS(wxContextHelp, wxObject)
42
43 wxContextHelp::wxContextHelp(wxWindow* win, bool beginHelp)
44 {
45 m_inHelp = FALSE;
46
47 if (beginHelp)
48 BeginContextHelp(win);
49 }
50
51 wxContextHelp::~wxContextHelp()
52 {
53 if (m_inHelp)
54 EndContextHelp();
55 }
56
57 bool wxContextHelp::BeginContextHelp(wxWindow* win)
58 {
59 if (!win)
60 win = wxTheApp->GetTopWindow();
61 if (!win)
62 return FALSE;
63
64 wxCursor cursor(wxCURSOR_QUESTION_ARROW);
65 wxSetCursor(cursor);
66
67 win->CaptureMouse();
68
69 EventLoop(cursor, win);
70
71 win->ReleaseMouse();
72
73 return TRUE;
74 }
75
76 bool wxContextHelp::EndContextHelp()
77 {
78 m_inHelp = FALSE;
79
80 return TRUE;
81 }
82
83 bool wxContextHelp::EventLoop(const wxCursor& cursor, wxWindow* win)
84 {
85 #ifdef __WXMSW__
86 m_inHelp = TRUE;
87 while ( m_inHelp )
88 {
89 MSG msg;
90 if (::PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
91 {
92 if (!ProcessHelpMessage((WXMSG*) & msg, cursor, win))
93 {
94 m_inHelp = FALSE;
95 }
96 }
97 else
98 {
99 wxTheApp->ProcessIdle();
100 }
101 }
102 return TRUE;
103 #else
104 return FALSE;
105 #endif
106 }
107
108 #ifdef __WXMSW__
109 bool wxContextHelp::ProcessHelpMessage(WXMSG* wxmsg, const wxCursor& cursor, wxWindow* winInQuestion)
110 {
111 MSG& msg = * (MSG*) wxmsg;
112
113 if (msg.message == WM_KEYDOWN || msg.wParam == VK_ESCAPE)
114 {
115 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
116 return FALSE;
117 }
118
119 if (msg.message == WM_CAPTURECHANGED)
120 {
121 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
122 return FALSE;
123 }
124
125 if (msg.message == WM_ACTIVATE)
126 {
127 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
128 return FALSE;
129 }
130
131 if ((msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST))
132 // || (msg.message >= WM_NCMOUSEFIRST && msg.message <= WM_NCMOUSELAST))
133 {
134 wxSetCursor(cursor);
135
136 HWND hWndHit = ::WindowFromPoint(msg.pt);
137
138 wxWindow* win = wxFindWinFromHandle((WXHWND) hWndHit) ;
139 HWND hWnd = hWndHit;
140
141 // Try to find a window with a wxWindow associated with it
142 while (!win && (hWnd != 0))
143 {
144 hWnd = ::GetParent(hWnd);
145 win = wxFindWinFromHandle((WXHWND) hWnd) ;
146 }
147
148 if (win)
149 {
150 // It's a wxWindows window
151 if (msg.message != WM_LBUTTONDOWN)
152 {
153 // Hit one of our owned windows -- eat the message.
154 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
155 return TRUE;
156 }
157 int iHit = (int)::SendMessage(hWndHit, WM_NCHITTEST, 0,
158 MAKELONG(msg.pt.x, msg.pt.y));
159 if (iHit == HTMENU || iHit == HTSYSMENU)
160 {
161 // Eat this message, send the event and return
162 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
163 DispatchEvent(win, wxPoint(msg.pt.x, msg.pt.y));
164 return FALSE;
165 }
166 else if (iHit == HTCLIENT)
167 {
168 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
169 DispatchEvent(win, wxPoint(msg.pt.x, msg.pt.y));
170 return FALSE;
171 }
172 else
173 {
174 PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE);
175 return FALSE;
176 }
177 }
178 else
179 {
180 // Someone else's message
181 if (PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE))
182 {
183 ::TranslateMessage(&msg);
184 ::DispatchMessage(&msg);
185 }
186 return TRUE;
187 }
188 }
189 else
190 {
191 // allow all other messages to go through (capture still set)
192 if (PeekMessage(&msg, NULL, msg.message, msg.message, PM_REMOVE))
193 DispatchMessage(&msg);
194 return TRUE;
195
196 }
197 return TRUE;
198 }
199 #endif
200
201 // Dispatch the help event to the relevant window
202 bool wxContextHelp::DispatchEvent(wxWindow* win, const wxPoint& pt)
203 {
204 wxWindow* subjectOfHelp = win;
205 bool eventProcessed = FALSE;
206 while (subjectOfHelp && !eventProcessed)
207 {
208 wxHelpEvent helpEvent(wxEVT_HELP, subjectOfHelp->GetId(), pt) ;
209 helpEvent.SetEventObject(this);
210 eventProcessed = win->GetEventHandler()->ProcessEvent(helpEvent);
211
212 // Go up the window hierarchy until the event is handled (or not).
213 // I.e. keep submitting ancestor windows until one is recognised
214 // by the app code that processes the ids and displays help.
215 subjectOfHelp = subjectOfHelp->GetParent();
216 }
217 return eventProcessed;
218 }
219
220
221 #endif // wxUSE_HELP