]> git.saurik.com Git - wxWidgets.git/blame - src/generic/tipwin.cpp
Optimized sizers to not call CalcMin more often than neccessary
[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>
65571936 9// Licence: wxWindows licence
01fa3fe7
VZ
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
14f355c2 20#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
01fa3fe7
VZ
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
654070ca
VZ
34#ifdef __WXGTK__
35 #include <gtk/gtk.h>
36#endif
01fa3fe7 37#include "wx/tipwin.h"
f38bcae5
VZ
38
39#if wxUSE_TIPWINDOW
40
173e8bbf 41#include "wx/timer.h"
8cb172b4 42#include "wx/settings.h"
01fa3fe7
VZ
43
44// ----------------------------------------------------------------------------
45// constants
46// ----------------------------------------------------------------------------
47
48static const wxCoord TEXT_MARGIN_X = 3;
49static const wxCoord TEXT_MARGIN_Y = 3;
50
01fa3fe7 51// ----------------------------------------------------------------------------
dafbe8c0 52// wxTipWindowView
01fa3fe7
VZ
53// ----------------------------------------------------------------------------
54
961c54c3 55// Viewer window to put in the frame
dafbe8c0 56class WXDLLEXPORT wxTipWindowView : public wxWindow
961c54c3
RD
57{
58public:
59 wxTipWindowView(wxWindow *parent);
60
61 // event handlers
62 void OnPaint(wxPaintEvent& event);
63 void OnMouseClick(wxMouseEvent& event);
dafbe8c0
VZ
64 void OnMouseMove(wxMouseEvent& event);
65
961c54c3
RD
66#if !wxUSE_POPUPWIN
67 void OnKillFocus(wxFocusEvent& event);
dafbe8c0
VZ
68#endif // wxUSE_POPUPWIN
69
961c54c3
RD
70 // calculate the client rect we need to display the text
71 void Adjust(const wxString& text, wxCoord maxLength);
72
73private:
961c54c3
RD
74 wxTipWindow* m_parent;
75
dafbe8c0
VZ
76#if !wxUSE_POPUPWIN
77 long m_creationTime;
78#endif // !wxUSE_POPUPWIN
79
80 DECLARE_EVENT_TABLE()
22f3361e 81 DECLARE_NO_COPY_CLASS(wxTipWindowView)
961c54c3
RD
82};
83
dafbe8c0
VZ
84// ============================================================================
85// implementation
86// ============================================================================
87
88// ----------------------------------------------------------------------------
89// event tables
90// ----------------------------------------------------------------------------
91
92BEGIN_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
101END_EVENT_TABLE()
102
961c54c3
RD
103BEGIN_EVENT_TABLE(wxTipWindowView, wxWindow)
104 EVT_PAINT(wxTipWindowView::OnPaint)
dafbe8c0 105
961c54c3
RD
106 EVT_LEFT_DOWN(wxTipWindowView::OnMouseClick)
107 EVT_RIGHT_DOWN(wxTipWindowView::OnMouseClick)
108 EVT_MIDDLE_DOWN(wxTipWindowView::OnMouseClick)
dafbe8c0
VZ
109
110 EVT_MOTION(wxTipWindowView::OnMouseMove)
111
961c54c3
RD
112#if !wxUSE_POPUPWIN
113 EVT_KILL_FOCUS(wxTipWindowView::OnKillFocus)
dafbe8c0 114#endif // !wxUSE_POPUPWIN
961c54c3
RD
115END_EVENT_TABLE()
116
01fa3fe7
VZ
117// ----------------------------------------------------------------------------
118// wxTipWindow
119// ----------------------------------------------------------------------------
120
121wxTipWindow::wxTipWindow(wxWindow *parent,
122 const wxString& text,
dafbe8c0
VZ
123 wxCoord maxLength,
124 wxTipWindow** windowPtr,
125 wxRect *rectBounds)
961c54c3 126#if wxUSE_POPUPWIN
8962e1d9 127 : wxPopupTransientWindow(parent)
961c54c3 128#else
ca65c044 129 : wxFrame(parent, wxID_ANY, wxEmptyString,
961c54c3
RD
130 wxDefaultPosition, wxDefaultSize,
131 wxNO_BORDER | wxFRAME_NO_TASKBAR )
132#endif
01fa3fe7 133{
dafbe8c0
VZ
134 SetTipWindowPtr(windowPtr);
135 if ( rectBounds )
136 {
137 SetBoundingRect(*rectBounds);
138 }
8962e1d9 139
01fa3fe7 140 // set colours
dafbe8c0
VZ
141 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
142 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
04ef50df 143
961c54c3 144 // set size, position and show it
dafbe8c0
VZ
145 m_view = new wxTipWindowView(this);
146 m_view->Adjust(text, maxLength);
147 m_view->SetFocus();
148
01fa3fe7
VZ
149 int x, y;
150 wxGetMousePosition(&x, &y);
dafbe8c0
VZ
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
961c54c3 159#if wxUSE_POPUPWIN
dafbe8c0
VZ
160 Position(wxPoint(x, y), wxSize(0, 0));
161 Popup(m_view);
654070ca
VZ
162 #ifdef __WXGTK__
163 if (!GTK_WIDGET_HAS_GRAB(m_widget))
164 gtk_grab_add( m_widget );
ca65c044 165 #endif
961c54c3 166#else
dafbe8c0 167 Move(x, y);
ca65c044 168 Show(true);
961c54c3 169#endif
173e8bbf
JS
170}
171
172wxTipWindow::~wxTipWindow()
173{
dafbe8c0 174 if ( m_windowPtr )
173e8bbf
JS
175 {
176 *m_windowPtr = NULL;
177 }
654070ca
VZ
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
173e8bbf
JS
184}
185
33ac7e6f 186void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event))
173e8bbf
JS
187{
188 Close();
189}
190
dafbe8c0
VZ
191#if wxUSE_POPUPWIN
192
193void wxTipWindow::OnDismiss()
194{
195 Close();
196}
197
198#else // !wxUSE_POPUPWIN
199
961c54c3 200void wxTipWindow::OnActivate(wxActivateEvent& event)
173e8bbf 201{
961c54c3
RD
202 if (!event.GetActive())
203 Close();
204}
8962e1d9 205
961c54c3
RD
206void 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}
8962e1d9 215
dafbe8c0
VZ
216#endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN
217
218void wxTipWindow::SetBoundingRect(const wxRect& rectBound)
219{
220 m_rectBound = rectBound;
221}
8962e1d9 222
961c54c3
RD
223void wxTipWindow::Close()
224{
dafbe8c0
VZ
225 if ( m_windowPtr )
226 {
227 *m_windowPtr = NULL;
228 m_windowPtr = NULL;
229 }
230
961c54c3 231#if wxUSE_POPUPWIN
ca65c044 232 Show(false);
654070ca
VZ
233 #ifdef __WXGTK__
234 if (GTK_WIDGET_HAS_GRAB(m_widget))
235 gtk_grab_remove( m_widget );
ca65c044 236 #endif
961c54c3
RD
237 Destroy();
238#else
239 wxFrame::Close();
240#endif
241}
8962e1d9 242
961c54c3
RD
243// ----------------------------------------------------------------------------
244// wxTipWindowView
245// ----------------------------------------------------------------------------
8962e1d9 246
961c54c3 247wxTipWindowView::wxTipWindowView(wxWindow *parent)
ca65c044 248 : wxWindow(parent, wxID_ANY,
dafbe8c0
VZ
249 wxDefaultPosition, wxDefaultSize,
250 wxNO_BORDER)
961c54c3
RD
251{
252 // set colours
dafbe8c0
VZ
253 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
254 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
dafbe8c0
VZ
255
256#if !wxUSE_POPUPWIN
961c54c3 257 m_creationTime = wxGetLocalTime();
dafbe8c0
VZ
258#endif // !wxUSE_POPUPWIN
259
961c54c3 260 m_parent = (wxTipWindow*)parent;
173e8bbf
JS
261}
262
961c54c3 263void wxTipWindowView::Adjust(const wxString& text, wxCoord maxLength)
173e8bbf 264{
8962e1d9
RD
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;
961c54c3 273 m_parent->m_heightLine = 0;
8962e1d9 274
ca65c044 275 bool breakLine = false;
8962e1d9
RD
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
961c54c3
RD
284 if ( height > m_parent->m_heightLine )
285 m_parent->m_heightLine = height;
8962e1d9 286
961c54c3 287 m_parent->m_textLines.Add(current);
8962e1d9
RD
288
289 if ( !*p )
290 {
291 // end of text
292 break;
293 }
294
295 current.clear();
ca65c044 296 breakLine = false;
8962e1d9
RD
297 }
298 else if ( breakLine && (*p == _T(' ') || *p == _T('\t')) )
299 {
300 // word boundary - break the line here
961c54c3 301 m_parent->m_textLines.Add(current);
8962e1d9 302 current.clear();
ca65c044 303 breakLine = false;
8962e1d9
RD
304 }
305 else // line goes on
306 {
307 current += *p;
308 dc.GetTextExtent(current, &width, &height);
309 if ( width > maxLength )
ca65c044 310 breakLine = true;
8962e1d9
RD
311
312 if ( width > widthMax )
313 widthMax = width;
314
961c54c3
RD
315 if ( height > m_parent->m_heightLine )
316 m_parent->m_heightLine = height;
8962e1d9
RD
317 }
318 }
319
320 // take into account the border size and the margins
961c54c3
RD
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);
173e8bbf
JS
325}
326
961c54c3
RD
327void wxTipWindowView::OnPaint(wxPaintEvent& WXUNUSED(event))
328{
329 wxPaintDC dc(this);
8962e1d9 330
961c54c3
RD
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
358void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event))
8962e1d9 359{
961c54c3 360 m_parent->Close();
8962e1d9
RD
361}
362
dafbe8c0
VZ
363void 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
961c54c3
RD
379#if !wxUSE_POPUPWIN
380void 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}
dafbe8c0 386#endif // !wxUSE_POPUPWIN
8962e1d9 387
dafbe8c0 388#endif // wxUSE_TIPWINDOW