Mostly Mingw32/Cygwin corrections
[wxWidgets.git] / src / msw / tooltip.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: msw/tooltip.cpp
3 // Purpose: wxToolTip class implementation for MSW
4 // Author: Vadim Zeitlin
5 // Modified by:
6 // Created: 31.01.99
7 // RCS-ID: $Id$
8 // Copyright: (c) 1999 Vadim Zeitlin
9 // Licence: wxWindows license
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #include "wx/wxprec.h"
21
22 #ifdef __BORLANDC__
23 #pragma hdrstop
24 #endif
25
26 #ifndef WX_PRECOMP
27 #include "wx/wx.h"
28 #endif
29
30 #if wxUSE_TOOLTIPS
31
32 #include "wx/tooltip.h"
33 #include "wx/msw/private.h"
34
35 #if defined(__WIN95__) && (!defined(__GNUWIN32__) || defined(__MINGW32__))
36 #include <commctrl.h>
37 #endif
38
39 // VZ: normally, the trick with subclassing the tooltip control and processing
40 // TTM_WINDOWFROMPOINT should work but, somehow, it doesn't. I leave the
41 // code here for now (but it's not compiled) in case we need it later.
42 //
43 // For now, instead of this, we just add all radiobox buttons to the
44 // tooltip control as well (see SetWindow) - this is probably less
45 // efficient, but it works.
46 #define wxUSE_TTM_WINDOWFROMPOINT 0
47
48 // ----------------------------------------------------------------------------
49 // global variables
50 // ----------------------------------------------------------------------------
51
52 // the tooltip parent window
53 WXHWND wxToolTip::ms_hwndTT = (WXHWND)NULL;
54
55 #if wxUSE_TTM_WINDOWFROMPOINT
56
57 // the tooltip window proc
58 static WNDPROC gs_wndprocToolTip = (WNDPROC)NULL;
59
60 #endif // wxUSE_TTM_WINDOWFROMPOINT
61
62 // ----------------------------------------------------------------------------
63 // private classes
64 // ----------------------------------------------------------------------------
65
66 // a simple wrapper around TOOLINFO Win32 structure
67 #ifdef __VISUALC__
68 #pragma warning( disable : 4097 ) // we inherit from a typedef - so what?
69 #endif
70 class wxToolInfo : public TOOLINFO
71 {
72 public:
73 wxToolInfo(HWND hwnd)
74 {
75 // initialize all members
76 ::ZeroMemory(this, sizeof(TOOLINFO));
77
78 cbSize = sizeof(TOOLINFO);
79 uFlags = TTF_IDISHWND;
80 uId = (UINT)hwnd;
81 }
82 };
83 #ifdef __VISUALC__
84 #pragma warning( default : 4097 )
85 #endif
86
87 // ----------------------------------------------------------------------------
88 // private functions
89 // ----------------------------------------------------------------------------
90
91 // send a message to the tooltip control
92 inline LRESULT SendTooltipMessage(WXHWND hwnd,
93 UINT msg,
94 WPARAM wParam,
95 void *lParam)
96 {
97 return hwnd ? ::SendMessage((HWND)hwnd, msg, wParam, (LPARAM)lParam)
98 : 0;
99 }
100
101 // send a message to all existing tooltip controls
102 static void SendTooltipMessageToAll(WXHWND hwnd,
103 UINT msg,
104 WPARAM wParam,
105 LPARAM lParam)
106 {
107 (void)SendTooltipMessage((WXHWND)hwnd, msg, wParam, (void *)lParam);
108 }
109
110 // ============================================================================
111 // implementation
112 // ============================================================================
113
114 #if wxUSE_TTM_WINDOWFROMPOINT
115
116 // ----------------------------------------------------------------------------
117 // window proc for our tooltip control
118 // ----------------------------------------------------------------------------
119
120 LRESULT APIENTRY wxToolTipWndProc(HWND hwndTT,
121 UINT msg,
122 WPARAM wParam,
123 LPARAM lParam)
124 {
125 if ( msg == TTM_WINDOWFROMPOINT )
126 {
127 LPPOINT ppt = (LPPOINT)lParam;
128 // is the window under control a wxWindow?
129 HWND hwnd = ::WindowFromPoint(*ppt);
130
131 // return a HWND correspondign to wxWindow because only wxWindows are
132 // associated with tooltips using TTM_ADDTOOL
133 while ( hwnd && !wxFindWinFromHandle((WXHWND)hwnd) )
134 {
135 hwnd = ::GetParent(hwnd);
136 }
137
138 if ( hwnd )
139 {
140 // modify the point too!
141 RECT rect;
142 GetWindowRect(hwnd, &rect);
143
144 ppt->x = rect.left;
145 ppt->y = rect.top;
146
147 return (LRESULT)hwnd;
148 }
149 }
150
151 return ::CallWindowProc(gs_wndprocToolTip, hwndTT, msg, wParam, lParam);
152 }
153
154 #endif // wxUSE_TTM_WINDOWFROMPOINT
155
156 // ----------------------------------------------------------------------------
157 // static functions
158 // ----------------------------------------------------------------------------
159
160 void wxToolTip::Enable(bool flag)
161 {
162 SendTooltipMessageToAll(ms_hwndTT, TTM_ACTIVATE, flag, 0);
163 }
164
165 void wxToolTip::SetDelay(long milliseconds)
166 {
167 SendTooltipMessageToAll(ms_hwndTT, TTM_SETDELAYTIME,
168 TTDT_INITIAL, milliseconds);
169 }
170
171 // ---------------------------------------------------------------------------
172 // implementation helpers
173 // ---------------------------------------------------------------------------
174
175 // create the tooltip ctrl for our parent frame if it doesn't exist yet
176 WXHWND wxToolTip::GetToolTipCtrl()
177 {
178 if ( !ms_hwndTT )
179 {
180 ms_hwndTT = (WXHWND)::CreateWindow(TOOLTIPS_CLASS,
181 (LPSTR)NULL,
182 TTS_ALWAYSTIP,
183 CW_USEDEFAULT, CW_USEDEFAULT,
184 CW_USEDEFAULT, CW_USEDEFAULT,
185 NULL, (HMENU)NULL,
186 wxGetInstance(),
187 NULL);
188 if ( ms_hwndTT )
189 {
190 HWND hwnd = (HWND)ms_hwndTT;
191 SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
192 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
193
194 #if wxUSE_TTM_WINDOWFROMPOINT
195 // subclass the newly created control
196 gs_wndprocToolTip = (WNDPROC)::GetWindowLong(hwnd, GWL_WNDPROC);
197 ::SetWindowLong(hwnd, GWL_WNDPROC, (long)wxToolTipWndProc);
198 #endif // wxUSE_TTM_WINDOWFROMPOINT
199 }
200 }
201
202 return ms_hwndTT;
203 }
204
205 void wxToolTip::RelayEvent(WXMSG *msg)
206 {
207 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_RELAYEVENT, 0, msg);
208 }
209
210 // ----------------------------------------------------------------------------
211 // ctor & dtor
212 // ----------------------------------------------------------------------------
213
214 wxToolTip::wxToolTip(const wxString &tip)
215 : m_text(tip)
216 {
217 m_window = NULL;
218 }
219
220 wxToolTip::~wxToolTip()
221 {
222 // there is no need to Remove() this tool - it will be done automatically
223 // anyhow
224 }
225
226 // ----------------------------------------------------------------------------
227 // others
228 // ----------------------------------------------------------------------------
229
230 void wxToolTip::Remove()
231 {
232 // remove this tool from the tooltip control
233 if ( m_window )
234 {
235 wxToolInfo ti(GetHwndOf(m_window));
236 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_DELTOOL, 0, &ti);
237 }
238 }
239
240 void wxToolTip::Add(WXHWND hWnd)
241 {
242 HWND hwnd = (HWND)hWnd;
243
244 wxToolInfo ti(hwnd);
245
246 // as we store our text anyhow, it seems useless to waste system memory
247 // by asking the tooltip ctrl to remember it too - instead it will send
248 // us TTN_NEEDTEXT (via WM_NOTIFY) when it is about to be shown
249 ti.hwnd = hwnd;
250 ti.lpszText = LPSTR_TEXTCALLBACK;
251 // instead of: ti.lpszText = (char *)m_text.c_str();
252
253 if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, 0, &ti) )
254 {
255 wxLogSysError(_("Failed to create the tooltip '%s'"),
256 m_text.c_str());
257 }
258 }
259
260 void wxToolTip::SetWindow(wxWindow *win)
261 {
262 Remove();
263
264 m_window = win;
265
266 // add the window itself
267 if ( m_window )
268 {
269 Add(m_window->GetHWND());
270 }
271
272 // and all of its subcontrols (e.g. radiobuttons in a radiobox) as well
273 wxControl *control = wxDynamicCast(m_window, wxControl);
274 if ( control )
275 {
276 size_t count = control->GetSubcontrols().GetCount();
277 for ( size_t n = 0; n < count; n++ )
278 {
279 wxWindowID id = control->GetSubcontrols()[n];
280 HWND hwnd = GetDlgItem(GetHwndOf(m_window), id);
281
282 if ( hwnd )
283 {
284 Add((WXHWND)hwnd);
285 }
286 }
287 }
288 }
289
290 void wxToolTip::SetTip(const wxString& tip)
291 {
292 m_text = tip;
293
294 if ( m_window )
295 {
296 // update it immediately
297 wxToolInfo ti(GetHwndOf(m_window));
298 ti.lpszText = (wxChar *)m_text.c_str();
299
300 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, 0, &ti);
301 }
302 }
303
304 #endif // wxUSE_TOOLTIPS