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