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