]> git.saurik.com Git - wxWidgets.git/blob - src/generic/tipwin.cpp
adapting for dual implementation native and composited
[wxWidgets.git] / src / generic / tipwin.cpp
1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/generic/tipwin.cpp
3 // Purpose:     implementation of wxTipWindow
4 // Author:      Vadim Zeitlin
5 // Modified by:
6 // Created:     10.09.00
7 // RCS-ID:      $Id$
8 // Copyright:   (c) 2000 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9 // Licence:     wxWindows licence
10 ///////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
21     #pragma implementation "tipwin.h"
22 #endif
23
24 // For compilers that support precompilatixon, includes "wx/wx.h".
25 #include "wx/wxprec.h"
26
27 #ifdef __BORLANDC__
28     #pragma hdrstop
29 #endif
30
31 #ifndef WX_PRECOMP
32     #include "wx/dcclient.h"
33 #endif // WX_PRECOMP
34 #ifdef __WXGTK__
35     #include <gtk/gtk.h>
36 #endif
37 #include "wx/tipwin.h"
38
39 #if wxUSE_TIPWINDOW
40
41 #include "wx/timer.h"
42 #include "wx/settings.h"
43
44 // ----------------------------------------------------------------------------
45 // constants
46 // ----------------------------------------------------------------------------
47
48 static const wxCoord TEXT_MARGIN_X = 3;
49 static const wxCoord TEXT_MARGIN_Y = 3;
50
51 // ----------------------------------------------------------------------------
52 // wxTipWindowView
53 // ----------------------------------------------------------------------------
54
55 // Viewer window to put in the frame
56 class WXDLLEXPORT wxTipWindowView : public wxWindow
57 {
58 public:
59     wxTipWindowView(wxWindow *parent);
60
61     // event handlers
62     void OnPaint(wxPaintEvent& event);
63     void OnMouseClick(wxMouseEvent& event);
64     void OnMouseMove(wxMouseEvent& event);
65
66 #if !wxUSE_POPUPWIN
67     void OnKillFocus(wxFocusEvent& event);
68 #endif // wxUSE_POPUPWIN
69
70     // calculate the client rect we need to display the text
71     void Adjust(const wxString& text, wxCoord maxLength);
72
73 private:
74     wxTipWindow* m_parent;
75
76 #if !wxUSE_POPUPWIN
77     long m_creationTime;
78 #endif // !wxUSE_POPUPWIN
79
80     DECLARE_EVENT_TABLE()
81     DECLARE_NO_COPY_CLASS(wxTipWindowView)
82 };
83
84 // ============================================================================
85 // implementation
86 // ============================================================================
87
88 // ----------------------------------------------------------------------------
89 // event tables
90 // ----------------------------------------------------------------------------
91
92 BEGIN_EVENT_TABLE(wxTipWindow, wxTipWindowBase)
93     EVT_LEFT_DOWN(wxTipWindow::OnMouseClick)
94     EVT_RIGHT_DOWN(wxTipWindow::OnMouseClick)
95     EVT_MIDDLE_DOWN(wxTipWindow::OnMouseClick)
96
97 #if !wxUSE_POPUPWIN
98     EVT_KILL_FOCUS(wxTipWindow::OnKillFocus)
99     EVT_ACTIVATE(wxTipWindow::OnActivate)
100 #endif // !wxUSE_POPUPWIN
101 END_EVENT_TABLE()
102
103 BEGIN_EVENT_TABLE(wxTipWindowView, wxWindow)
104     EVT_PAINT(wxTipWindowView::OnPaint)
105
106     EVT_LEFT_DOWN(wxTipWindowView::OnMouseClick)
107     EVT_RIGHT_DOWN(wxTipWindowView::OnMouseClick)
108     EVT_MIDDLE_DOWN(wxTipWindowView::OnMouseClick)
109
110     EVT_MOTION(wxTipWindowView::OnMouseMove)
111
112 #if !wxUSE_POPUPWIN
113     EVT_KILL_FOCUS(wxTipWindowView::OnKillFocus)
114 #endif // !wxUSE_POPUPWIN
115 END_EVENT_TABLE()
116
117 // ----------------------------------------------------------------------------
118 // wxTipWindow
119 // ----------------------------------------------------------------------------
120
121 wxTipWindow::wxTipWindow(wxWindow *parent,
122                          const wxString& text,
123                          wxCoord maxLength,
124                          wxTipWindow** windowPtr,
125                          wxRect *rectBounds)
126 #if wxUSE_POPUPWIN
127            : wxPopupTransientWindow(parent)
128 #else
129            : wxFrame(parent, -1, _T(""),
130                      wxDefaultPosition, wxDefaultSize,
131                      wxNO_BORDER | wxFRAME_NO_TASKBAR )
132 #endif
133 {
134     SetTipWindowPtr(windowPtr);
135     if ( rectBounds )
136     {
137         SetBoundingRect(*rectBounds);
138     }
139
140     // set colours
141     SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
142     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
143
144     // set size, position and show it
145     m_view = new wxTipWindowView(this);
146     m_view->Adjust(text, maxLength);
147     m_view->SetFocus();
148
149     int x, y;
150     wxGetMousePosition(&x, &y);
151
152     // we want to show the tip below the mouse, not over it
153     //
154     // NB: the reason we use "/ 2" here is that we don't know where the current
155     //     cursors hot spot is... it would be nice if we could find this out
156     //     though
157     y += wxSystemSettings::GetMetric(wxSYS_CURSOR_Y) / 2;
158
159 #if wxUSE_POPUPWIN
160     Position(wxPoint(x, y), wxSize(0, 0));
161     Popup(m_view);
162     #ifdef __WXGTK__
163         if (!GTK_WIDGET_HAS_GRAB(m_widget))
164             gtk_grab_add( m_widget );
165     #endif   
166 #else
167     Move(x, y);
168     Show(TRUE);
169 #endif
170 }
171
172 wxTipWindow::~wxTipWindow()
173 {
174     if ( m_windowPtr )
175     {
176         *m_windowPtr = NULL;
177     }
178     #ifdef wxUSE_POPUPWIN
179         #ifdef __WXGTK__
180             if (GTK_WIDGET_HAS_GRAB(m_widget))
181                 gtk_grab_remove( m_widget );
182         #endif
183     #endif
184 }
185
186 void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event))
187 {
188     Close();
189 }
190
191 #if wxUSE_POPUPWIN
192
193 void wxTipWindow::OnDismiss()
194 {
195     Close();
196 }
197
198 #else // !wxUSE_POPUPWIN
199
200 void wxTipWindow::OnActivate(wxActivateEvent& event)
201 {
202     if (!event.GetActive())
203         Close();
204 }
205
206 void wxTipWindow::OnKillFocus(wxFocusEvent& WXUNUSED(event))
207 {
208     // Under Windows at least, we will get this immediately
209     // because when the view window is focussed, the
210     // tip window goes out of focus.
211 #ifdef __WXGTK__
212     Close();
213 #endif
214 }
215
216 #endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN
217
218 void wxTipWindow::SetBoundingRect(const wxRect& rectBound)
219 {
220     m_rectBound = rectBound;
221 }
222
223 void wxTipWindow::Close()
224 {
225     if ( m_windowPtr )
226     {
227         *m_windowPtr = NULL;
228         m_windowPtr = NULL;
229     }
230
231 #if wxUSE_POPUPWIN
232     Show(FALSE);
233     #ifdef __WXGTK__
234         if (GTK_WIDGET_HAS_GRAB(m_widget))
235             gtk_grab_remove( m_widget );
236     #endif   
237     Destroy();
238 #else
239     wxFrame::Close();
240 #endif
241 }
242
243 // ----------------------------------------------------------------------------
244 // wxTipWindowView
245 // ----------------------------------------------------------------------------
246
247 wxTipWindowView::wxTipWindowView(wxWindow *parent)
248                : wxWindow(parent, -1,
249                           wxDefaultPosition, wxDefaultSize,
250                           wxNO_BORDER)
251 {
252     // set colours
253     SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
254     SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
255
256 #if !wxUSE_POPUPWIN
257     m_creationTime = wxGetLocalTime();
258 #endif // !wxUSE_POPUPWIN
259
260     m_parent = (wxTipWindow*)parent;
261 }
262
263 void wxTipWindowView::Adjust(const wxString& text, wxCoord maxLength)
264 {
265     wxClientDC dc(this);
266     dc.SetFont(GetFont());
267
268     // calculate the length: we want each line be no longer than maxLength
269     // pixels and we only break lines at words boundary
270     wxString current;
271     wxCoord height, width,
272             widthMax = 0;
273     m_parent->m_heightLine = 0;
274
275     bool breakLine = FALSE;
276     for ( const wxChar *p = text.c_str(); ; p++ )
277     {
278         if ( *p == _T('\n') || *p == _T('\0') )
279         {
280             dc.GetTextExtent(current, &width, &height);
281             if ( width > widthMax )
282                 widthMax = width;
283
284             if ( height > m_parent->m_heightLine )
285                 m_parent->m_heightLine = height;
286
287             m_parent->m_textLines.Add(current);
288
289             if ( !*p )
290             {
291                 // end of text
292                 break;
293             }
294
295             current.clear();
296             breakLine = FALSE;
297         }
298         else if ( breakLine && (*p == _T(' ') || *p == _T('\t')) )
299         {
300             // word boundary - break the line here
301             m_parent->m_textLines.Add(current);
302             current.clear();
303             breakLine = FALSE;
304         }
305         else // line goes on
306         {
307             current += *p;
308             dc.GetTextExtent(current, &width, &height);
309             if ( width > maxLength )
310                 breakLine = TRUE;
311
312             if ( width > widthMax )
313                 widthMax = width;
314
315             if ( height > m_parent->m_heightLine )
316                 m_parent->m_heightLine = height;
317         }
318     }
319
320     // take into account the border size and the margins
321     width  = 2*(TEXT_MARGIN_X + 1) + widthMax;
322     height = 2*(TEXT_MARGIN_Y + 1) + m_parent->m_textLines.GetCount()*m_parent->m_heightLine;
323     m_parent->SetClientSize(width, height);
324     SetSize(0, 0, width, height);
325 }
326
327 void wxTipWindowView::OnPaint(wxPaintEvent& WXUNUSED(event))
328 {
329     wxPaintDC dc(this);
330
331     wxRect rect;
332     wxSize size = GetClientSize();
333     rect.width = size.x;
334     rect.height = size.y;
335
336     // first filll the background
337     dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
338     dc.SetPen( wxPen(GetForegroundColour(), 1, wxSOLID) );
339     dc.DrawRectangle(rect);
340
341     // and then draw the text line by line
342     dc.SetTextBackground(GetBackgroundColour());
343     dc.SetTextForeground(GetForegroundColour());
344     dc.SetFont(GetFont());
345
346     wxPoint pt;
347     pt.x = TEXT_MARGIN_X;
348     pt.y = TEXT_MARGIN_Y;
349     size_t count = m_parent->m_textLines.GetCount();
350     for ( size_t n = 0; n < count; n++ )
351     {
352         dc.DrawText(m_parent->m_textLines[n], pt);
353
354         pt.y += m_parent->m_heightLine;
355     }
356 }
357
358 void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event))
359 {
360     m_parent->Close();
361 }
362
363 void wxTipWindowView::OnMouseMove(wxMouseEvent& event)
364 {
365     const wxRect& rectBound = m_parent->m_rectBound;
366
367     if ( rectBound.width &&
368             !rectBound.Inside(ClientToScreen(event.GetPosition())) )
369     {
370         // mouse left the bounding rect, disappear
371         m_parent->Close();
372     }
373     else
374     {
375         event.Skip();
376     }
377 }
378
379 #if !wxUSE_POPUPWIN
380 void wxTipWindowView::OnKillFocus(wxFocusEvent& WXUNUSED(event))
381 {
382     // Workaround the kill focus event happening just after creation in wxGTK
383     if (wxGetLocalTime() > m_creationTime + 1)
384         m_parent->Close();
385 }
386 #endif // !wxUSE_POPUPWIN
387
388 #endif // wxUSE_TIPWINDOW