]> git.saurik.com Git - wxWidgets.git/blame - src/generic/tipwin.cpp
Fix setting the clipping region for a DC when the region is an
[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
95427194 20// For compilers that support precompilation, includes "wx/wx.h".
01fa3fe7
VZ
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
c0badb70
WS
27#if wxUSE_TIPWINDOW
28
29#include "wx/tipwin.h"
30
01fa3fe7
VZ
31#ifndef WX_PRECOMP
32 #include "wx/dcclient.h"
c0badb70 33 #include "wx/timer.h"
9eddec69 34 #include "wx/settings.h"
01fa3fe7 35#endif // WX_PRECOMP
c0badb70 36
654070ca
VZ
37#ifdef __WXGTK__
38 #include <gtk/gtk.h>
39#endif
f38bcae5 40
01fa3fe7
VZ
41// ----------------------------------------------------------------------------
42// constants
43// ----------------------------------------------------------------------------
44
45static const wxCoord TEXT_MARGIN_X = 3;
46static const wxCoord TEXT_MARGIN_Y = 3;
47
01fa3fe7 48// ----------------------------------------------------------------------------
dafbe8c0 49// wxTipWindowView
01fa3fe7
VZ
50// ----------------------------------------------------------------------------
51
961c54c3 52// Viewer window to put in the frame
dafbe8c0 53class WXDLLEXPORT wxTipWindowView : public wxWindow
961c54c3
RD
54{
55public:
56 wxTipWindowView(wxWindow *parent);
57
58 // event handlers
59 void OnPaint(wxPaintEvent& event);
60 void OnMouseClick(wxMouseEvent& event);
dafbe8c0
VZ
61 void OnMouseMove(wxMouseEvent& event);
62
961c54c3
RD
63#if !wxUSE_POPUPWIN
64 void OnKillFocus(wxFocusEvent& event);
dafbe8c0
VZ
65#endif // wxUSE_POPUPWIN
66
961c54c3
RD
67 // calculate the client rect we need to display the text
68 void Adjust(const wxString& text, wxCoord maxLength);
69
70private:
961c54c3
RD
71 wxTipWindow* m_parent;
72
dafbe8c0
VZ
73#if !wxUSE_POPUPWIN
74 long m_creationTime;
75#endif // !wxUSE_POPUPWIN
76
77 DECLARE_EVENT_TABLE()
22f3361e 78 DECLARE_NO_COPY_CLASS(wxTipWindowView)
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 125#else
ca65c044 126 : wxFrame(parent, wxID_ANY, wxEmptyString,
961c54c3
RD
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
c47addef 157 Position(wxPoint(x, y), wxSize(0,0));
dafbe8c0 158 Popup(m_view);
654070ca
VZ
159 #ifdef __WXGTK__
160 if (!GTK_WIDGET_HAS_GRAB(m_widget))
161 gtk_grab_add( m_widget );
ca65c044 162 #endif
961c54c3 163#else
dafbe8c0 164 Move(x, y);
ca65c044 165 Show(true);
961c54c3 166#endif
173e8bbf
JS
167}
168
169wxTipWindow::~wxTipWindow()
170{
dafbe8c0 171 if ( m_windowPtr )
173e8bbf
JS
172 {
173 *m_windowPtr = NULL;
174 }
654070ca
VZ
175 #ifdef wxUSE_POPUPWIN
176 #ifdef __WXGTK__
177 if (GTK_WIDGET_HAS_GRAB(m_widget))
178 gtk_grab_remove( m_widget );
179 #endif
180 #endif
173e8bbf
JS
181}
182
33ac7e6f 183void wxTipWindow::OnMouseClick(wxMouseEvent& WXUNUSED(event))
173e8bbf
JS
184{
185 Close();
186}
187
dafbe8c0
VZ
188#if wxUSE_POPUPWIN
189
190void wxTipWindow::OnDismiss()
191{
192 Close();
193}
194
195#else // !wxUSE_POPUPWIN
196
961c54c3 197void wxTipWindow::OnActivate(wxActivateEvent& event)
173e8bbf 198{
961c54c3
RD
199 if (!event.GetActive())
200 Close();
201}
8962e1d9 202
961c54c3
RD
203void wxTipWindow::OnKillFocus(wxFocusEvent& WXUNUSED(event))
204{
205 // Under Windows at least, we will get this immediately
206 // because when the view window is focussed, the
207 // tip window goes out of focus.
208#ifdef __WXGTK__
209 Close();
210#endif
211}
8962e1d9 212
dafbe8c0
VZ
213#endif // wxUSE_POPUPWIN // !wxUSE_POPUPWIN
214
215void wxTipWindow::SetBoundingRect(const wxRect& rectBound)
216{
217 m_rectBound = rectBound;
218}
8962e1d9 219
961c54c3
RD
220void wxTipWindow::Close()
221{
dafbe8c0
VZ
222 if ( m_windowPtr )
223 {
224 *m_windowPtr = NULL;
225 m_windowPtr = NULL;
226 }
227
961c54c3 228#if wxUSE_POPUPWIN
ca65c044 229 Show(false);
654070ca
VZ
230 #ifdef __WXGTK__
231 if (GTK_WIDGET_HAS_GRAB(m_widget))
232 gtk_grab_remove( m_widget );
ca65c044 233 #endif
961c54c3
RD
234 Destroy();
235#else
236 wxFrame::Close();
237#endif
238}
8962e1d9 239
961c54c3
RD
240// ----------------------------------------------------------------------------
241// wxTipWindowView
242// ----------------------------------------------------------------------------
8962e1d9 243
961c54c3 244wxTipWindowView::wxTipWindowView(wxWindow *parent)
ca65c044 245 : wxWindow(parent, wxID_ANY,
dafbe8c0
VZ
246 wxDefaultPosition, wxDefaultSize,
247 wxNO_BORDER)
961c54c3
RD
248{
249 // set colours
dafbe8c0
VZ
250 SetForegroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOTEXT));
251 SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_INFOBK));
dafbe8c0
VZ
252
253#if !wxUSE_POPUPWIN
961c54c3 254 m_creationTime = wxGetLocalTime();
dafbe8c0
VZ
255#endif // !wxUSE_POPUPWIN
256
961c54c3 257 m_parent = (wxTipWindow*)parent;
173e8bbf
JS
258}
259
961c54c3 260void wxTipWindowView::Adjust(const wxString& text, wxCoord maxLength)
173e8bbf 261{
8962e1d9
RD
262 wxClientDC dc(this);
263 dc.SetFont(GetFont());
264
265 // calculate the length: we want each line be no longer than maxLength
266 // pixels and we only break lines at words boundary
267 wxString current;
268 wxCoord height, width,
269 widthMax = 0;
961c54c3 270 m_parent->m_heightLine = 0;
8962e1d9 271
ca65c044 272 bool breakLine = false;
8962e1d9
RD
273 for ( const wxChar *p = text.c_str(); ; p++ )
274 {
275 if ( *p == _T('\n') || *p == _T('\0') )
276 {
277 dc.GetTextExtent(current, &width, &height);
278 if ( width > widthMax )
279 widthMax = width;
280
961c54c3
RD
281 if ( height > m_parent->m_heightLine )
282 m_parent->m_heightLine = height;
8962e1d9 283
961c54c3 284 m_parent->m_textLines.Add(current);
8962e1d9
RD
285
286 if ( !*p )
287 {
288 // end of text
289 break;
290 }
291
292 current.clear();
ca65c044 293 breakLine = false;
8962e1d9
RD
294 }
295 else if ( breakLine && (*p == _T(' ') || *p == _T('\t')) )
296 {
297 // word boundary - break the line here
961c54c3 298 m_parent->m_textLines.Add(current);
8962e1d9 299 current.clear();
ca65c044 300 breakLine = false;
8962e1d9
RD
301 }
302 else // line goes on
303 {
304 current += *p;
305 dc.GetTextExtent(current, &width, &height);
306 if ( width > maxLength )
ca65c044 307 breakLine = true;
8962e1d9
RD
308
309 if ( width > widthMax )
310 widthMax = width;
311
961c54c3
RD
312 if ( height > m_parent->m_heightLine )
313 m_parent->m_heightLine = height;
8962e1d9
RD
314 }
315 }
316
317 // take into account the border size and the margins
961c54c3 318 width = 2*(TEXT_MARGIN_X + 1) + widthMax;
4a10ea8b 319 height = 2*(TEXT_MARGIN_Y + 1) + wx_truncate_cast(wxCoord, m_parent->m_textLines.GetCount())*m_parent->m_heightLine;
961c54c3
RD
320 m_parent->SetClientSize(width, height);
321 SetSize(0, 0, width, height);
173e8bbf
JS
322}
323
961c54c3
RD
324void wxTipWindowView::OnPaint(wxPaintEvent& WXUNUSED(event))
325{
326 wxPaintDC dc(this);
8962e1d9 327
961c54c3
RD
328 wxRect rect;
329 wxSize size = GetClientSize();
330 rect.width = size.x;
331 rect.height = size.y;
332
333 // first filll the background
334 dc.SetBrush(wxBrush(GetBackgroundColour(), wxSOLID));
335 dc.SetPen( wxPen(GetForegroundColour(), 1, wxSOLID) );
336 dc.DrawRectangle(rect);
337
338 // and then draw the text line by line
339 dc.SetTextBackground(GetBackgroundColour());
340 dc.SetTextForeground(GetForegroundColour());
341 dc.SetFont(GetFont());
342
343 wxPoint pt;
344 pt.x = TEXT_MARGIN_X;
345 pt.y = TEXT_MARGIN_Y;
346 size_t count = m_parent->m_textLines.GetCount();
347 for ( size_t n = 0; n < count; n++ )
348 {
349 dc.DrawText(m_parent->m_textLines[n], pt);
350
351 pt.y += m_parent->m_heightLine;
352 }
353}
354
355void wxTipWindowView::OnMouseClick(wxMouseEvent& WXUNUSED(event))
8962e1d9 356{
961c54c3 357 m_parent->Close();
8962e1d9
RD
358}
359
dafbe8c0
VZ
360void wxTipWindowView::OnMouseMove(wxMouseEvent& event)
361{
362 const wxRect& rectBound = m_parent->m_rectBound;
363
364 if ( rectBound.width &&
22a35096 365 !rectBound.Contains(ClientToScreen(event.GetPosition())) )
dafbe8c0
VZ
366 {
367 // mouse left the bounding rect, disappear
368 m_parent->Close();
369 }
370 else
371 {
372 event.Skip();
373 }
374}
375
961c54c3
RD
376#if !wxUSE_POPUPWIN
377void wxTipWindowView::OnKillFocus(wxFocusEvent& WXUNUSED(event))
378{
379 // Workaround the kill focus event happening just after creation in wxGTK
380 if (wxGetLocalTime() > m_creationTime + 1)
381 m_parent->Close();
382}
dafbe8c0 383#endif // !wxUSE_POPUPWIN
8962e1d9 384
dafbe8c0 385#endif // wxUSE_TIPWINDOW