1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/msw/richtooltip.cpp
3 // Purpose:     Native MSW implementation of wxRichToolTip.
4 // Author:      Vadim Zeitlin
5 // Created:     2011-10-18
6 // Copyright:   (c) 2011 Vadim Zeitlin <vadim@wxwidgets.org>
7 // Licence:     wxWindows licence
8 ///////////////////////////////////////////////////////////////////////////////
9 
10 // ============================================================================
11 // declarations
12 // ============================================================================
13 
14 // ----------------------------------------------------------------------------
15 // headers
16 // ----------------------------------------------------------------------------
17 
18 // for compilers that support precompilation, includes "wx.h".
19 #include "wx/wxprec.h"
20 
21 #ifdef __BORLANDC__
22     #pragma hdrstop
23 #endif
24 
25 #if wxUSE_RICHTOOLTIP
26 
27 #ifndef WX_PRECOMP
28     #include "wx/treectrl.h"
29 #endif // WX_PRECOMP
30 
31 #include "wx/private/richtooltip.h"
32 #include "wx/generic/private/richtooltip.h"
33 #include "wx/msw/private.h"
34 #include "wx/msw/uxtheme.h"
35 
36 // Provide definitions missing from some compilers SDK headers.
37 
38 #ifndef TTI_NONE
39 enum
40 {
41     TTI_NONE,
42     TTI_INFO,
43     TTI_WARNING,
44     TTI_ERROR
45 };
46 #endif // !defined(TTI_XXX)
47 
48 #ifndef Edit_ShowBalloonTip
49 struct EDITBALLOONTIP
50 {
51     DWORD cbStruct;
52     LPCWSTR pszTitle;
53     LPCWSTR pszText;
54     int ttiIcon;
55 };
56 
57 #define Edit_ShowBalloonTip(hwnd, pebt) \
58     (BOOL)::SendMessage((hwnd), 0x1503 /* EM_SHOWBALLOONTIP */, 0, (LPARAM)(pebt))
59 
60 #endif // !defined(Edit_ShowBalloonTip)
61 
62 // ============================================================================
63 // wxRichToolTipMSWImpl: the real implementation.
64 // ============================================================================
65 
66 class wxRichToolTipMSWImpl : public wxRichToolTipGenericImpl
67 {
68 public:
wxRichToolTipMSWImpl(const wxString & title,const wxString & message)69     wxRichToolTipMSWImpl(const wxString& title, const wxString& message) :
70         wxRichToolTipGenericImpl(title, message)
71     {
72         // So far so good...
73         m_canUseNative = true;
74 
75         m_ttiIcon = TTI_NONE;
76     }
77 
SetBackgroundColour(const wxColour & col,const wxColour & colEnd)78     virtual void SetBackgroundColour(const wxColour& col,
79                                      const wxColour& colEnd)
80     {
81         // Setting background colour is not supported neither.
82         m_canUseNative = false;
83 
84         wxRichToolTipGenericImpl::SetBackgroundColour(col, colEnd);
85     }
86 
SetCustomIcon(const wxIcon & icon)87     virtual void SetCustomIcon(const wxIcon& icon)
88     {
89         // Custom icons are not supported by EM_SHOWBALLOONTIP.
90         m_canUseNative = false;
91 
92         wxRichToolTipGenericImpl::SetCustomIcon(icon);
93     }
94 
SetStandardIcon(int icon)95     virtual void SetStandardIcon(int icon)
96     {
97         wxRichToolTipGenericImpl::SetStandardIcon(icon);
98         if ( !m_canUseNative )
99             return;
100 
101         switch ( icon & wxICON_MASK )
102         {
103             case wxICON_WARNING:
104                 m_ttiIcon = TTI_WARNING;
105                 break;
106 
107             case wxICON_ERROR:
108                 m_ttiIcon = TTI_ERROR;
109                 break;
110 
111             case wxICON_INFORMATION:
112                 m_ttiIcon = TTI_INFO;
113                 break;
114 
115             case wxICON_QUESTION:
116                 wxFAIL_MSG("Question icon doesn't make sense for a tooltip");
117                 break;
118 
119             case wxICON_NONE:
120                 m_ttiIcon = TTI_NONE;
121                 break;
122         }
123     }
124 
SetTimeout(unsigned millisecondsTimeout,unsigned millisecondsDelay)125     virtual void SetTimeout(unsigned millisecondsTimeout,
126                             unsigned millisecondsDelay)
127     {
128         // We don't support changing the timeout or the delay
129         // (maybe TTM_SETDELAYTIME could be used for this?).
130         m_canUseNative = false;
131 
132         wxRichToolTipGenericImpl::SetTimeout(millisecondsTimeout,
133                                              millisecondsDelay);
134     }
135 
SetTipKind(wxTipKind tipKind)136     virtual void SetTipKind(wxTipKind tipKind)
137     {
138         // Setting non-default tip is not supported.
139         if ( tipKind != wxTipKind_Auto )
140             m_canUseNative = false;
141 
142         wxRichToolTipGenericImpl::SetTipKind(tipKind);
143     }
144 
SetTitleFont(const wxFont & font)145     virtual void SetTitleFont(const wxFont& font)
146     {
147         // Setting non-default font is not supported.
148         m_canUseNative = false;
149 
150         wxRichToolTipGenericImpl::SetTitleFont(font);
151     }
152 
ShowFor(wxWindow * win,const wxRect * rect)153     virtual void ShowFor(wxWindow* win, const wxRect* rect)
154     {
155         // TODO: We could use native tooltip control to show native balloon
156         //       tooltips for any window but right now we use the simple
157         //       EM_SHOWBALLOONTIP API which can only be used with text
158         //       controls.
159         if ( m_canUseNative && !rect )
160         {
161             wxTextCtrl* const text = wxDynamicCast(win, wxTextCtrl);
162             if ( text )
163             {
164                 EDITBALLOONTIP ebt;
165                 ebt.cbStruct = sizeof(EDITBALLOONTIP);
166                 ebt.pszTitle = m_title.wc_str();
167                 ebt.pszText = m_message.wc_str();
168                 ebt.ttiIcon = m_ttiIcon;
169                 if ( Edit_ShowBalloonTip(GetHwndOf(text), &ebt) )
170                     return;
171             }
172         }
173 
174         // Don't set m_canUseNative to false here, we could be able to use the
175         // native tooltips if we're called for a different window the next
176         // time.
177         wxRichToolTipGenericImpl::ShowFor(win, rect);
178     }
179 
180 private:
181     // If this is false, we've been requested to do something that the native
182     // version doesn't support and so need to fall back to the generic one.
183     bool m_canUseNative;
184 
185     // One of TTI_NONE, TTI_INFO, TTI_WARNING or TTI_ERROR.
186     int m_ttiIcon;
187 };
188 
189 /* static */
190 wxRichToolTipImpl*
Create(const wxString & title,const wxString & message)191 wxRichToolTipImpl::Create(const wxString& title, const wxString& message)
192 {
193     // EM_SHOWBALLOONTIP is only implemented by comctl32.dll v6 so don't even
194     // bother using the native implementation if we're not using themes.
195     if ( wxUxThemeEngine::GetIfActive() )
196         return new wxRichToolTipMSWImpl(title, message);
197 
198     return new wxRichToolTipGenericImpl(title, message);
199 }
200 
201 #endif // wxUSE_RICHTOOLTIP
202