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