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