]> git.saurik.com Git - wxWidgets.git/blame - src/generic/tipwin.cpp
fix crash when the user code refuses to validate the new text when editing the item...
[wxWidgets.git] / src / generic / tipwin.cpp
CommitLineData
01fa3fe7
VZ
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"
f38bcae5
VZ
36
37#if wxUSE_TIPWINDOW
38
173e8bbf 39#include "wx/timer.h"
8cb172b4 40#include "wx/settings.h"
01fa3fe7
VZ
41
42// ----------------------------------------------------------------------------
43// constants
44// ----------------------------------------------------------------------------
45
46static const wxCoord TEXT_MARGIN_X = 3;
47static const wxCoord TEXT_MARGIN_Y = 3;
48
01fa3fe7 49// ----------------------------------------------------------------------------
dafbe8c0 50// wxTipWindowView
01fa3fe7
VZ
51// ----------------------------------------------------------------------------
52
961c54c3 53// Viewer window to put in the frame
dafbe8c0 54class WXDLLEXPORT wxTipWindowView : public wxWindow
961c54c3
RD
55{
56public:
57 wxTipWindowView(wxWindow *parent);
58
59 // event handlers
60 void OnPaint(wxPaintEvent& event);
61 void OnMouseClick(wxMouseEvent& event);
dafbe8c0
VZ
62 void OnMouseMove(wxMouseEvent& event);
63
961c54c3
RD
64#if !wxUSE_POPUPWIN
65 void OnKillFocus(wxFocusEvent& event);
dafbe8c0
VZ
66#endif // wxUSE_POPUPWIN
67
961c54c3
RD
68 // calculate the client rect we need to display the text
69 void Adjust(const wxString& text, wxCoord maxLength);
70
71private:
961c54c3
RD
72 wxTipWindow* m_parent;
73
dafbe8c0
VZ
74#if !wxUSE_POPUPWIN
75 long m_creationTime;
76#endif // !wxUSE_POPUPWIN
77
78 DECLARE_EVENT_TABLE()
961c54c3
RD
79};
80
dafbe8c0
VZ
81// ============================================================================
82// implementation
83// ============================================================================
84
85// ----------------------------------------------------------------------------
86// event tables
87// ----------------------------------------------------------------------------
88
89BEGIN_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
98END_EVENT_TABLE()
99
961c54c3
RD
100BEGIN_EVENT_TABLE(wxTipWindowView, wxWindow)
101 EVT_PAINT(wxTipWindowView::OnPaint)
dafbe8c0 102
961c54c3
RD
103 EVT_LEFT_DOWN(wxTipWindowView::OnMouseClick)
104 EVT_RIGHT_DOWN(wxTipWindowView::OnMouseClick)
105 EVT_MIDDLE_DOWN(wxTipWindowView::OnMouseClick)
dafbe8c0
VZ
106
107 EVT_MOTION(wxTipWindowView::OnMouseMove)
108
961c54c3
RD
109#if !wxUSE_POPUPWIN
110 EVT_KILL_FOCUS(wxTipWindowView::OnKillFocus)
dafbe8c0 111#endif // !wxUSE_POPUPWIN
961c54c3
RD
112END_EVENT_TABLE()
113
01fa3fe7
VZ
114// ----------------------------------------------------------------------------
115// wxTipWindow
116// ----------------------------------------------------------------------------
117
118wxTipWindow::wxTipWindow(wxWindow *parent,
119 const wxString& text,
dafbe8c0
VZ
120 wxCoord maxLength,
121 wxTipWindow** windowPtr,
122 wxRect *rectBounds)
961c54c3 123#if wxUSE_POPUPWIN
8962e1d9 124 : wxPopupTransientWindow(parent)
961c54c3
RD
125#else
126 : wxFrame(parent, -1, _T(""),
127 wxDefaultPosition, wxDefaultSize,
128 wxNO_BORDER | wxFRAME_NO_TASKBAR )
129#endif
01fa3fe7 130{
dafbe8c0
VZ
131 SetTipWindowPtr(windowPtr);
132 if ( rectBounds )
133 {
134 SetBoundingRect(*rectBounds);
135 }
8962e1d9 136
01fa3fe7 137 // set colours
dafbe8c0
VZ
138 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
139 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
04ef50df 140
961c54c3 141 // set size, position and show it
dafbe8c0
VZ
142 m_view = new wxTipWindowView(this);
143 m_view->Adjust(text, maxLength);
144 m_view->SetFocus();
145
01fa3fe7
VZ
146 int x, y;
147 wxGetMousePosition(&x, &y);
dafbe8c0
VZ
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
961c54c3 156#if wxUSE_POPUPWIN
dafbe8c0
VZ
157 Position(wxPoint(x, y), wxSize(0, 0));
158 Popup(m_view);
961c54c3 159#else
dafbe8c0 160 Move(x, y);
961c54c3
RD
161 Show(TRUE);
162#endif
173e8bbf
JS
163}
164
165wxTipWindow::~wxTipWindow()
166{
dafbe8c0 167 if ( m_windowPtr )
173e8bbf
JS
168 {
169 *m_windowPtr = NULL;
170 }
171}
172
33ac7e6f 173void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event))
173e8bbf
JS
174{
175 Close();
176}
177
dafbe8c0
VZ
178#if wxUSE_POPUPWIN
179
180void wxTipWindow::OnDismiss()
181{
182 Close();
183}
184
185#else // !wxUSE_POPUPWIN
186
961c54c3 187void wxTipWindow::OnActivate(wxActivateEvent& event)
173e8bbf 188{
961c54c3
RD
189 if (!event.GetActive())
190 Close();
191}
8962e1d9 192
961c54c3
RD
193void 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}
8962e1d9 202
dafbe8c0
VZ
203#endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN
204
205void wxTipWindow::SetBoundingRect(const wxRect& rectBound)
206{
207 m_rectBound = rectBound;
208}
8962e1d9 209
961c54c3
RD
210void wxTipWindow::Close()
211{
dafbe8c0
VZ
212 if ( m_windowPtr )
213 {
214 *m_windowPtr = NULL;
215 m_windowPtr = NULL;
216 }
217
961c54c3
RD
218#if wxUSE_POPUPWIN
219 Show(FALSE);
220 Destroy();
221#else
222 wxFrame::Close();
223#endif
224}
8962e1d9 225
961c54c3
RD
226// ----------------------------------------------------------------------------
227// wxTipWindowView
228// ----------------------------------------------------------------------------
8962e1d9 229
961c54c3 230wxTipWindowView::wxTipWindowView(wxWindow *parent)
dafbe8c0
VZ
231 : wxWindow(parent, -1,
232 wxDefaultPosition, wxDefaultSize,
233 wxNO_BORDER)
961c54c3
RD
234{
235 // set colours
dafbe8c0
VZ
236 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
237 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
dafbe8c0
VZ
238
239#if !wxUSE_POPUPWIN
961c54c3 240 m_creationTime = wxGetLocalTime();
dafbe8c0
VZ
241#endif // !wxUSE_POPUPWIN
242
961c54c3 243 m_parent = (wxTipWindow*)parent;
173e8bbf
JS
244}
245
961c54c3 246void wxTipWindowView::Adjust(const wxString& text, wxCoord maxLength)
173e8bbf 247{
8962e1d9
RD
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;
961c54c3 256 m_parent->m_heightLine = 0;
8962e1d9
RD
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
961c54c3
RD
267 if ( height > m_parent->m_heightLine )
268 m_parent->m_heightLine = height;
8962e1d9 269
961c54c3 270 m_parent->m_textLines.Add(current);
8962e1d9
RD
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
961c54c3 284 m_parent->m_textLines.Add(current);
8962e1d9
RD
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
961c54c3
RD
298 if ( height > m_parent->m_heightLine )
299 m_parent->m_heightLine = height;
8962e1d9
RD
300 }
301 }
302
303 // take into account the border size and the margins
961c54c3
RD
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);
173e8bbf
JS
308}
309
961c54c3
RD
310void wxTipWindowView::OnPaint(wxPaintEvent& WXUNUSED(event))
311{
312 wxPaintDC dc(this);
8962e1d9 313
961c54c3
RD
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
341void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event))
8962e1d9 342{
961c54c3 343 m_parent->Close();
8962e1d9
RD
344}
345
dafbe8c0
VZ
346void 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
961c54c3
RD
362#if !wxUSE_POPUPWIN
363void 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}
dafbe8c0 369#endif // !wxUSE_POPUPWIN
8962e1d9 370
dafbe8c0 371#endif // wxUSE_TIPWINDOW