]> git.saurik.com Git - wxWidgets.git/blob - src/mac/carbon/tooltip.cpp
allowing ampersands in choices and comboboxes means we have to strip outside of uma.cpp
[wxWidgets.git] / src / mac / carbon / tooltip.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: tooltip.cpp
3 // Purpose: wxToolTip implementation
4 // Author: Stefan Csomor
5 // Id: $Id$
6 // Copyright: (c) Stefan Csomor
7 // Licence: wxWindows licence
8 /////////////////////////////////////////////////////////////////////////////
9
10 #include "wx/wxprec.h"
11
12 #if wxUSE_TOOLTIPS
13
14 #include "wx/app.h"
15 #include "wx/dc.h"
16 #include "wx/window.h"
17 #include "wx/tooltip.h"
18 #include "wx/timer.h"
19 #include "wx/geometry.h"
20 #include "wx/mac/uma.h"
21
22 //-----------------------------------------------------------------------------
23 // global data
24 //-----------------------------------------------------------------------------
25
26 class wxMacToolTipTimer ;
27
28 class wxMacToolTip
29 {
30 public :
31 wxMacToolTip() ;
32 ~wxMacToolTip() ;
33
34 void Setup( WindowRef window , const wxString& text , const wxPoint& localPosition ) ;
35 void Draw() ;
36 void Clear() ;
37
38 long GetMark()
39 { return m_mark ; }
40
41 bool IsShown()
42 { return m_shown ; }
43
44 private :
45 wxString m_label ;
46 wxPoint m_position ;
47 Rect m_rect ;
48 WindowRef m_window ;
49 PicHandle m_backpict ;
50 bool m_shown ;
51 long m_mark ;
52 wxMacToolTipTimer* m_timer ;
53
54 #if TARGET_CARBON
55 wxMacCFStringHolder m_helpTextRef ;
56 #endif
57 } ;
58
59 class wxMacToolTipTimer : public wxTimer
60 {
61 public:
62 wxMacToolTipTimer(wxMacToolTip* tip, int iMilliseconds) ;
63 wxMacToolTipTimer() {} ;
64 virtual ~wxMacToolTipTimer() {} ;
65
66 void Notify()
67 {
68 if ( m_mark == m_tip->GetMark() )
69 m_tip->Draw() ;
70 }
71
72 protected:
73 wxMacToolTip* m_tip;
74 long m_mark ;
75 };
76
77 //-----------------------------------------------------------------------------
78 // wxToolTip
79 //-----------------------------------------------------------------------------
80 static long s_ToolTipDelay = 500 ;
81 static bool s_ShowToolTips = true ;
82 static wxMacToolTip s_ToolTip ;
83 static wxWindow* s_LastWindowEntered = NULL ;
84 static wxRect2DInt s_ToolTipArea ;
85 static WindowRef s_ToolTipWindowRef = NULL ;
86
87 IMPLEMENT_ABSTRACT_CLASS(wxToolTip, wxObject)
88
89
90 wxToolTip::wxToolTip( const wxString &tip )
91 {
92 m_text = tip;
93 m_window = (wxWindow*) NULL;
94 }
95
96 wxToolTip::~wxToolTip()
97 {
98 }
99
100 void wxToolTip::SetTip( const wxString &tip )
101 {
102 m_text = tip;
103
104 if ( m_window )
105 {
106 #if 0
107 // update it immediately
108 wxToolInfo ti(GetHwndOf(m_window));
109 ti.lpszText = (wxChar *)m_text.c_str();
110
111 (void)SendTooltipMessage(GetToolTipCtrl(), TTM_UPDATETIPTEXT, 0, &ti);
112 #endif
113 }
114 }
115
116 void wxToolTip::SetWindow( wxWindow *win )
117 {
118 m_window = win ;
119 }
120
121 void wxToolTip::Enable( bool flag )
122 {
123 if ( s_ShowToolTips != flag )
124 {
125 s_ShowToolTips = flag ;
126
127 if ( s_ShowToolTips )
128 {
129 }
130 else
131 {
132 s_ToolTip.Clear() ;
133 }
134 }
135 }
136
137 void wxToolTip::SetDelay( long msecs )
138 {
139 s_ToolTipDelay = msecs ;
140 }
141
142 void wxToolTip::RelayEvent( wxWindow *win , wxMouseEvent &event )
143 {
144 if ( s_ShowToolTips )
145 {
146 if ( event.GetEventType() == wxEVT_LEAVE_WINDOW )
147 {
148 s_ToolTip.Clear() ;
149 }
150 else if (event.GetEventType() == wxEVT_ENTER_WINDOW || event.GetEventType() == wxEVT_MOTION )
151 {
152 wxPoint2DInt where( event.m_x , event.m_y ) ;
153 if ( s_LastWindowEntered == win && s_ToolTipArea.Contains( where ) )
154 {
155 }
156 else
157 {
158 s_ToolTip.Clear() ;
159 s_ToolTipArea = wxRect2DInt( event.m_x - 2 , event.m_y - 2 , 4 , 4 ) ;
160 s_LastWindowEntered = win ;
161
162 WindowRef window = MAC_WXHWND( win->MacGetTopLevelWindowRef() ) ;
163 int x = event.m_x ;
164 int y = event.m_y ;
165 wxPoint local( x , y ) ;
166 win->MacClientToRootWindow( &x, &y ) ;
167 wxPoint windowlocal( x , y ) ;
168 s_ToolTip.Setup( window , win->MacGetToolTipString( local ) , windowlocal ) ;
169 }
170 }
171 }
172 }
173
174 void wxToolTip::RemoveToolTips()
175 {
176 s_ToolTip.Clear() ;
177 }
178
179 // --- mac specific
180
181 wxMacToolTipTimer::wxMacToolTipTimer( wxMacToolTip *tip , int msec )
182 {
183 m_tip = tip;
184 m_mark = tip->GetMark() ;
185 Start(msec, true);
186 }
187
188 wxMacToolTip::wxMacToolTip()
189 {
190 m_window = NULL ;
191 m_backpict = NULL ;
192 m_timer = NULL ;
193 m_mark = 0 ;
194 m_shown = false ;
195 }
196
197 void wxMacToolTip::Setup( WindowRef win , const wxString& text , const wxPoint& localPosition )
198 {
199 m_mark++ ;
200
201 Clear() ;
202 m_position = localPosition ;
203 m_label = text ;
204 m_window =win;
205 s_ToolTipWindowRef = m_window ;
206 m_backpict = NULL ;
207
208 if ( m_timer )
209 delete m_timer ;
210
211 m_timer = new wxMacToolTipTimer( this , s_ToolTipDelay ) ;
212 }
213
214 wxMacToolTip::~wxMacToolTip()
215 {
216 if ( m_timer )
217 {
218 delete m_timer ;
219 m_timer = NULL;
220 }
221
222 if ( m_backpict )
223 Clear() ;
224 }
225
226 const short kTipBorder = 2 ;
227 const short kTipOffset = 5 ;
228
229 void wxMacToolTip::Draw()
230 {
231 if ( m_label.Length() == 0 )
232 return ;
233
234 if ( m_window == s_ToolTipWindowRef )
235 {
236 m_shown = true ;
237
238 #if TARGET_CARBON
239 HMHelpContentRec tag ;
240 tag.version = kMacHelpVersion;
241 SetRect( &tag.absHotRect , m_position.x - 2 , m_position.y - 2 , m_position.x + 2 , m_position.y + 2 ) ;
242
243 QDLocalToGlobalRect( GetWindowPort( m_window ) , &tag.absHotRect ) ;
244
245 m_helpTextRef.Assign( m_label , wxFONTENCODING_DEFAULT ) ;
246 tag.content[kHMMinimumContentIndex].contentType = kHMCFStringContent ;
247 tag.content[kHMMinimumContentIndex].u.tagCFString = m_helpTextRef ;
248 tag.content[kHMMaximumContentIndex].contentType = kHMCFStringContent ;
249 tag.content[kHMMaximumContentIndex].u.tagCFString = m_helpTextRef ;
250 tag.tagSide = kHMDefaultSide;
251 HMDisplayTag( &tag );
252 #else
253 wxMacPortStateHelper help( (GrafPtr)GetWindowPort( m_window ) );
254 FontFamilyID fontId ;
255 Str255 fontName ;
256 SInt16 fontSize ;
257 Style fontStyle ;
258 GetThemeFont( kThemeSmallSystemFont , GetApplicationScript() , fontName , &fontSize , &fontStyle ) ;
259 GetFNum( fontName, &fontId );
260
261 TextFont( fontId ) ;
262 TextSize( fontSize ) ;
263 TextFace( fontStyle ) ;
264 FontInfo fontInfo;
265 ::GetFontInfo(&fontInfo);
266 short lineh = fontInfo.ascent + fontInfo.descent + fontInfo.leading;
267 short height = 0 ;
268
269 int i = 0 ;
270 int length = m_label.Length() ;
271 int width = 0 ;
272 int thiswidth = 0 ;
273 int laststop = 0 ;
274 wxCharBuffer text = m_label.mb_str( wxConvLocal ) ;
275
276 while ( i < length )
277 {
278 if ( text[i] == 13 || text[i] == 10)
279 {
280 thiswidth = ::TextWidth( text , laststop , i - laststop ) ;
281 if ( thiswidth > width )
282 width = thiswidth ;
283
284 height += lineh ;
285 laststop = i + 1 ;
286 }
287
288 i++ ;
289 }
290
291 if ( i - laststop > 0 )
292 {
293 thiswidth = ::TextWidth( text , laststop , i - laststop ) ;
294 if ( thiswidth > width )
295 width = thiswidth ;
296 height += lineh ;
297 }
298
299 m_rect.left = m_position.x + kTipOffset;
300 m_rect.top = m_position.y + kTipOffset;
301 m_rect.right = m_rect.left + width + 2 * kTipBorder;
302
303 m_rect.bottom = m_rect.top + height + 2 * kTipBorder;
304 Rect r ;
305
306 GetPortBounds( GetWindowPort( m_window ) , &r ) ;
307 if ( m_rect.top < 0 )
308 {
309 m_rect.bottom += -m_rect.top ;
310 m_rect.top = 0 ;
311 }
312 if ( m_rect.left < 0 )
313 {
314 m_rect.right += -m_rect.left ;
315 m_rect.left = 0 ;
316 }
317 if ( m_rect.right > r.right )
318 {
319 m_rect.left -= (m_rect.right - r.right ) ;
320 m_rect.right = r.right ;
321 }
322 if ( m_rect.bottom > r.bottom )
323 {
324 m_rect.top -= (m_rect.bottom - r.bottom) ;
325 m_rect.bottom = r.bottom ;
326 }
327
328 GWorldPtr port ;
329 CGrafPtr origPort ;
330 GDHandle origDevice ;
331
332 ClipRect( &m_rect ) ;
333 BackColor( whiteColor ) ;
334 ForeColor(blackColor ) ;
335 NewGWorld( &port , wxDisplayDepth() , &m_rect , NULL , NULL , 0 ) ;
336
337 GetGWorld( &origPort , &origDevice ) ;
338 SetGWorld( port , NULL ) ;
339
340 m_backpict = OpenPicture(&m_rect);
341
342 CopyBits(GetPortBitMapForCopyBits(GetWindowPort(m_window)),
343 GetPortBitMapForCopyBits(port),
344 &m_rect,
345 &m_rect,
346 srcCopy,
347 NULL);
348 ClosePicture();
349 SetGWorld( origPort , origDevice ) ;
350 DisposeGWorld( port ) ;
351 PenNormal() ;
352
353 RGBColor tooltipbackground = { 0xFFFF , 0xFFFF , 0xC000 } ;
354 BackColor( whiteColor ) ;
355 RGBForeColor( &tooltipbackground ) ;
356
357 PaintRect( &m_rect ) ;
358 ForeColor(blackColor ) ;
359 FrameRect( &m_rect ) ;
360 SetThemeTextColor(kThemeTextColorNotification,wxDisplayDepth(),true) ;
361 ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder);
362
363 i = 0 ;
364 laststop = 0 ;
365 height = 0 ;
366
367 while ( i < length )
368 {
369 if ( text[i] == 13 || text[i] == 10)
370 {
371 ::DrawText( text , laststop , i - laststop ) ;
372 height += lineh ;
373 ::MoveTo( m_rect.left + kTipBorder , m_rect.top + fontInfo.ascent + kTipBorder + height );
374 laststop = i+1 ;
375 }
376
377 i++ ;
378 }
379
380 ::DrawText( text , laststop , i - laststop ) ;
381 ::TextMode( srcOr ) ;
382 #endif
383 }
384 }
385
386 void wxToolTip::NotifyWindowDelete( WXHWND win )
387 {
388 if ( win == s_ToolTipWindowRef )
389 s_ToolTipWindowRef = NULL ;
390 }
391
392 void wxMacToolTip::Clear()
393 {
394 m_mark++ ;
395
396 if ( m_timer )
397 {
398 delete m_timer ;
399 m_timer = NULL ;
400 }
401
402 if ( !m_shown )
403 return ;
404
405 #if TARGET_CARBON
406 HMHideTag() ;
407 m_helpTextRef.Release() ;
408 #else
409 if ( m_window == s_ToolTipWindowRef && m_backpict )
410 {
411 wxMacPortStateHelper help( (GrafPtr)GetWindowPort( m_window ) ) ;
412
413 m_shown = false ;
414
415 BackColor( whiteColor ) ;
416 ForeColor( blackColor ) ;
417 DrawPicture( m_backpict, &m_rect );
418 KillPicture( m_backpict );
419 m_backpict = NULL ;
420 }
421 #endif
422 }
423
424 #endif
425