GnuWin32 corrections (::ZeroMemory doesn't exist)
[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(__TWIN32__)
36 #include <commctrl.h>
37 #endif
38
39 // ----------------------------------------------------------------------------
40 // private classes
41 // ----------------------------------------------------------------------------
42
43 // a simple wrapper around TOOLINFO Win32 structure
44 class wxToolInfo : public TOOLINFO
45 {
46 public:
47 wxToolInfo(wxWindow *win)
48 {
49 // initialize all members
50 #ifdef __GNUWIN32__
51 memset(this, 0, sizeof(TOOLINFO));
52 #else
53 ::ZeroMemory(this, sizeof(TOOLINFO));
54 #endif
55
56 cbSize = sizeof(TOOLINFO);
57 uFlags = TTF_IDISHWND;
58 uId = (UINT)win->GetHWND();
59 }
60 };
61
62 // ----------------------------------------------------------------------------
63 // private functions
64 // ----------------------------------------------------------------------------
65
66 // send a message to the tooltip control
67 inline LRESULT SendTooltipMessage(WXHWND hwnd,
68 UINT msg,
69 WPARAM wParam,
70 void *lParam)
71 {
72 return hwnd ? ::SendMessage((HWND)hwnd, msg, wParam, (LPARAM)lParam)
73 : 0;
74 }
75
76 // send a message to all existing tooltip controls
77 static void SendTooltipMessageToAll(UINT msg, WPARAM wParam, LPARAM lParam)
78 {
79 // NB: it might be somewhat easier to maintain a list of all existing
80 // wxToolTip controls (put them there in ctor, delete from the list
81 // in dtor) - may be it's worth doing it this way? OTOH, typical
82 // application won't have many top level windows, so iterating over all
83 // of them shouldnt' take much time neither...
84
85 // iterate over all top level windows and send message to the tooltip
86 // control of each and every of them (or more precisely to all dialogs and
87 // frames)
88 wxDialog *dialog = NULL;
89 wxFrame *frame = NULL;
90
91 wxNode *node = wxTopLevelWindows.First();
92 while ( node )
93 {
94 wxWindow *win = (wxWindow *)node->Data();
95
96 node = node->Next();
97
98 if ( win->IsKindOf(CLASSINFO(wxFrame)) )
99 {
100 frame = (wxFrame *)win;
101 dialog = NULL;
102 }
103 else if ( win->IsKindOf(CLASSINFO(wxDialog)) )
104 {
105 dialog = (wxDialog *)win;
106 frame = NULL;
107 }
108 else
109 {
110 // skip this strange top level window
111 continue;
112 }
113
114 wxASSERT_MSG( dialog || frame, "logic error" );
115
116 WXHWND hwndTT = frame ? frame->GetToolTipCtrl()
117 : dialog->GetToolTipCtrl();
118 if ( hwndTT )
119 {
120 (void)SendTooltipMessage(hwndTT, msg, wParam, (void *)lParam);
121 }
122 }
123 }
124
125 // ============================================================================
126 // implementation
127 // ============================================================================
128
129 // ----------------------------------------------------------------------------
130 // static functions
131 // ----------------------------------------------------------------------------
132
133 void wxToolTip::Enable(bool flag)
134 {
135 SendTooltipMessageToAll(TTM_ACTIVATE, flag, 0);
136 }
137
138 void wxToolTip::SetDelay(long milliseconds)
139 {
140 SendTooltipMessageToAll(TTM_SETDELAYTIME, TTDT_INITIAL, milliseconds);
141 }
142
143 // ---------------------------------------------------------------------------
144 // implementation helpers
145 // ---------------------------------------------------------------------------
146
147 // create the tooltip ctrl for our parent frame if it doesn't exist yet
148 WXHWND wxToolTip::GetToolTipCtrl()
149 {
150 // find either parent dialog or parent frame - tooltip controls are managed
151 // by these 2 classes only (it doesn't make sense to create one tooltip per
152 // each and every wxWindow)
153 wxFrame *frame = NULL;
154 wxDialog *dialog = NULL;
155
156 wxWindow *parent = m_window;
157 while ( parent )
158 {
159 if ( parent->IsKindOf(CLASSINFO(wxFrame)) )
160 {
161 frame = (wxFrame *)parent;
162
163 break;
164 }
165 else if ( parent->IsKindOf(CLASSINFO(wxDialog)) )
166 {
167 dialog = (wxDialog *)parent;
168
169 break;
170 }
171
172 parent = parent->GetParent();
173 }
174
175 wxCHECK_MSG( frame || dialog, 0,
176 "can't create tooltip control outside a frame or a dialog" );
177
178 HWND hwndTT = (HWND)(frame ? frame->GetToolTipCtrl()
179 : dialog->GetToolTipCtrl());
180 if ( !hwndTT )
181 {
182 hwndTT = ::CreateWindow(TOOLTIPS_CLASS,
183 (LPSTR)NULL,
184 TTS_ALWAYSTIP,
185 CW_USEDEFAULT, CW_USEDEFAULT,
186 CW_USEDEFAULT, CW_USEDEFAULT,
187 (HWND)frame->GetHWND(), (HMENU)NULL,
188 wxGetInstance(), NULL);
189
190 if ( hwndTT )
191 {
192 if ( frame )
193 frame->SetToolTipCtrl((WXHWND)hwndTT);
194 else
195 dialog->SetToolTipCtrl((WXHWND)hwndTT);
196 }
197 else
198 {
199 wxLogSysError(_("Can not create tooltip control"));
200 }
201 }
202
203 return (WXHWND)hwndTT;
204 }
205
206 void wxToolTip::RelayEvent(WXMSG *msg)
207 {
208 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_RELAYEVENT, 0, msg);
209 }
210
211 // ----------------------------------------------------------------------------
212 // ctor & dtor
213 // ----------------------------------------------------------------------------
214
215 wxToolTip::wxToolTip(const wxString &tip)
216 : m_text(tip)
217 {
218 m_window = NULL;
219 }
220
221 wxToolTip::~wxToolTip()
222 {
223 // there is no need to Remove() this tool - it will be done automatically
224 // anyhow
225 }
226
227 // ----------------------------------------------------------------------------
228 // others
229 // ----------------------------------------------------------------------------
230
231 void wxToolTip::Remove()
232 {
233 // remove this tool from the tooltip control
234 if ( m_window )
235 {
236 wxToolInfo ti(m_window);
237 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_DELTOOL, 0, &ti);
238 }
239 }
240
241 void wxToolTip::SetWindow(wxWindow *win)
242 {
243 Remove();
244
245 m_window = win;
246
247 if ( m_window )
248 {
249 wxToolInfo ti(m_window);
250
251 // as we store our text anyhow, it seems useless to waste system memory
252 // by asking the tooltip ctrl to remember it too - instead it will send
253 // us TTN_NEEDTEXT (via WM_NOTIFY) when it is about to be shown
254 ti.hwnd = (HWND)m_window->GetHWND();
255 ti.lpszText = LPSTR_TEXTCALLBACK;
256 // instead of: ti.lpszText = (char *)m_text.c_str();
257
258 if ( !SendTooltipMessage(GetToolTipCtrl(), TTM_ADDTOOL, 0, &ti) )
259 {
260 wxLogSysError(_("Failed to create the tooltip '%s'"),
261 m_text.c_str());
262 }
263 }
264 }
265
266 void wxToolTip::SetTip(const wxString& tip)
267 {
268 m_text = tip;
269
270 if ( m_window )
271 {
272 // update it immediately
273 wxToolInfo ti(m_window);
274 ti.lpszText = (char *)m_text.c_str();
275
276 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, 0, &ti);
277 }
278 }
279
280 #endif // wxUSE_TOOLTIPS