]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/popupcmn.cpp
fix for Sun CC bug with not calling temporary objects dtor
[wxWidgets.git] / src / common / popupcmn.cpp
... / ...
CommitLineData
1///////////////////////////////////////////////////////////////////////////////
2// Name: common/popupcmn.cpp
3// Purpose: implementation of wxPopupTransientWindow
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 06.01.01
7// RCS-ID: $Id$
8// Copyright: (c) 2001 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
9// License: wxWindows license
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#ifdef __GNUG__
21 #pragma implementation "popupwinbase.h"
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
28 #pragma hdrstop
29#endif
30
31#if wxUSE_POPUPWIN && !defined(__WXMOTIF__)
32
33#include "wx/popupwin.h"
34
35#ifndef WX_PRECOMP
36 #include "wx/combobox.h" // wxComboControl
37#endif //WX_PRECOMP
38
39#ifdef __WXUNIVERSAL__
40 #include "wx/univ/renderer.h"
41#endif // __WXUNIVERSAL__
42
43// there is no src/{msw,mgl}/popupwin.cpp to put this in, so we do it here - BTW we
44// probably could do it for all ports here just as well
45#if defined(__WXMSW__) || defined(__WXMGL__)
46 IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow)
47#endif // __WXMSW__
48
49IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow)
50
51#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
52 IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow)
53#endif
54
55// ----------------------------------------------------------------------------
56// private classes
57// ----------------------------------------------------------------------------
58
59// event handlers which we use to intercept events which cause the popup to
60// disappear
61class wxPopupWindowHandler : public wxEvtHandler
62{
63public:
64 wxPopupWindowHandler(wxPopupTransientWindow *popup) { m_popup = popup; }
65
66protected:
67 // event handlers
68 void OnLeftDown(wxMouseEvent& event);
69
70private:
71 wxPopupTransientWindow *m_popup;
72
73 DECLARE_EVENT_TABLE()
74};
75
76class wxPopupFocusHandler : public wxEvtHandler
77{
78public:
79 wxPopupFocusHandler(wxPopupTransientWindow *popup) { m_popup = popup; }
80
81protected:
82 // event handlers
83 void OnKillFocus(wxFocusEvent& event);
84
85private:
86 wxPopupTransientWindow *m_popup;
87
88 DECLARE_EVENT_TABLE()
89};
90
91// ----------------------------------------------------------------------------
92// event tables
93// ----------------------------------------------------------------------------
94
95BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler)
96 EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown)
97END_EVENT_TABLE()
98
99BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler)
100 EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus)
101END_EVENT_TABLE()
102
103// ============================================================================
104// implementation
105// ============================================================================
106
107// ----------------------------------------------------------------------------
108// wxPopupWindowBase
109// ----------------------------------------------------------------------------
110
111wxPopupWindowBase::~wxPopupWindowBase()
112{
113 // this destructor is required for Darwin
114}
115
116bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags))
117{
118 return TRUE;
119}
120
121void wxPopupWindowBase::Position(const wxPoint& ptOrigin,
122 const wxSize& size)
123{
124 wxSize sizeScreen = wxGetDisplaySize(),
125 sizeSelf = GetSize();
126
127 // is there enough space to put the popup below the window (where we put it
128 // by default)?
129 wxCoord y = ptOrigin.y + size.y;
130 if ( y + sizeSelf.y > sizeScreen.y )
131 {
132 // check if there is enough space above
133 if ( ptOrigin.y > sizeSelf.y )
134 {
135 // do position the control above the window
136 y -= size.y + sizeSelf.y;
137 }
138 //else: not enough space below nor above, leave below
139 }
140
141 // now check left/right too
142 wxCoord x = ptOrigin.x + size.x;
143 if ( x + sizeSelf.x > sizeScreen.x )
144 {
145 // check if there is enough space to the left
146 if ( ptOrigin.x > sizeSelf.x )
147 {
148 // do position the control to the left
149 x -= size.x + sizeSelf.x;
150 }
151 //else: not enough space there neither, leave in default position
152 }
153
154 Move(x, y, wxSIZE_NO_ADJUSTMENTS);
155}
156
157// ----------------------------------------------------------------------------
158// wxPopupTransientWindow
159// ----------------------------------------------------------------------------
160
161void wxPopupTransientWindow::Init()
162{
163 m_child =
164 m_focus = (wxWindow *)NULL;
165}
166
167wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style)
168{
169 Init();
170
171 (void)Create(parent, style);
172}
173
174wxPopupTransientWindow::~wxPopupTransientWindow()
175{
176 PopHandlers();
177}
178
179void wxPopupTransientWindow::PopHandlers()
180{
181 if ( m_child )
182 {
183 m_child->PopEventHandler(TRUE /* delete it */);
184 m_child->ReleaseMouse();
185 m_child = NULL;
186 }
187
188 if ( m_focus )
189 {
190 m_focus->PopEventHandler(TRUE /* delete it */);
191 m_focus = NULL;
192 }
193}
194
195void wxPopupTransientWindow::Popup(wxWindow *winFocus)
196{
197 const wxWindowList& children = GetChildren();
198 if ( children.GetCount() )
199 {
200 m_child = children.GetFirst()->GetData();
201 }
202 else
203 {
204 m_child = this;
205 }
206
207 // we can't capture mouse before the window is shown in wxGTL
208#ifdef __WXGTK__
209 Show();
210#endif
211
212 m_child->CaptureMouse();
213 m_child->PushEventHandler(new wxPopupWindowHandler(this));
214
215#ifndef __WXGTK__
216 Show();
217#endif
218
219 m_focus = winFocus ? winFocus : this;
220 m_focus->PushEventHandler(new wxPopupFocusHandler(this));
221 m_focus->SetFocus();
222}
223
224void wxPopupTransientWindow::Dismiss()
225{
226 PopHandlers();
227
228 Hide();
229}
230
231void wxPopupTransientWindow::DismissAndNotify()
232{
233 Dismiss();
234
235 OnDismiss();
236}
237
238void wxPopupTransientWindow::OnDismiss()
239{
240 // nothing to do here - but it may be interesting for derived class
241}
242
243bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event))
244{
245 // no special processing here
246 return FALSE;
247}
248
249#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
250
251// ----------------------------------------------------------------------------
252// wxPopupComboWindow
253// ----------------------------------------------------------------------------
254
255wxPopupComboWindow::wxPopupComboWindow(wxComboControl *parent)
256 : wxPopupTransientWindow(parent)
257{
258 m_combo = parent;
259}
260
261bool wxPopupComboWindow::Create(wxComboControl *parent)
262{
263 m_combo = parent;
264
265 return wxPopupWindow::Create(parent);
266}
267
268void wxPopupComboWindow::PositionNearCombo()
269{
270 // the origin point must be in screen coords
271 wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0, 0));
272
273#if 0 //def __WXUNIVERSAL__
274 // account for the fact that (0, 0) is not the top left corner of the
275 // window: there is also the border
276 wxRect rectBorders = m_combo->GetRenderer()->
277 GetBorderDimensions(m_combo->GetBorder());
278 ptOrigin.x -= rectBorders.x;
279 ptOrigin.y -= rectBorders.y;
280#endif // __WXUNIVERSAL__
281
282 // position below or above the combobox: the width is 0 to put it exactly
283 // below us, not to the left or to the right
284 Position(ptOrigin, wxSize(0, m_combo->GetSize().y));
285}
286
287void wxPopupComboWindow::OnDismiss()
288{
289 m_combo->OnDismiss();
290}
291
292#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
293
294// ----------------------------------------------------------------------------
295// wxPopupWindowHandler
296// ----------------------------------------------------------------------------
297
298void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event)
299{
300 // let the window have it first (we're the first event handler in the chain
301 // of handlers for this window)
302 if ( m_popup->ProcessLeftDown(event) )
303 {
304 return;
305 }
306
307 wxPoint pos = event.GetPosition();
308
309 // scrollbar on which the click occured
310 wxWindow *sbar = NULL;
311
312 wxWindow *win = (wxWindow *)event.GetEventObject();
313 switch ( win->HitTest(pos.x, pos.y) )
314 {
315 case wxHT_WINDOW_OUTSIDE:
316 // clicking outside a popup dismisses it
317 m_popup->DismissAndNotify();
318 break;
319
320#ifdef __WXUNIVERSAL__
321 case wxHT_WINDOW_HORZ_SCROLLBAR:
322 sbar = win->GetScrollbar(wxHORIZONTAL);
323 break;
324
325 case wxHT_WINDOW_VERT_SCROLLBAR:
326 sbar = win->GetScrollbar(wxVERTICAL);
327 break;
328#endif
329
330 default:
331 // forgot to update the switch after adding a new hit test code?
332 wxFAIL_MSG( _T("unexpected HitTest() return value") );
333 // fall through
334
335 case wxHT_WINDOW_CORNER:
336 // don't actually know if this one is good for anything, but let it
337 // pass just in case
338
339 case wxHT_WINDOW_INSIDE:
340 // let the normal processing take place
341 event.Skip();
342 break;
343 }
344
345 if ( sbar )
346 {
347 // translate the event coordinates to the scrollbar ones
348 pos = sbar->ScreenToClient(win->ClientToScreen(pos));
349
350 // and give the event to it
351 wxMouseEvent event2 = event;
352 event2.m_x = pos.x;
353 event2.m_y = pos.y;
354
355 (void)sbar->GetEventHandler()->ProcessEvent(event2);
356 }
357}
358
359// ----------------------------------------------------------------------------
360// wxPopupFocusHandler
361// ----------------------------------------------------------------------------
362
363void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event)
364{
365 // when we lose focus we always disappear
366
367 // But if m_popup was about to get the focus,
368 // don't disappear.
369 if (event.GetWindow() != m_popup)
370 m_popup->DismissAndNotify();
371}
372
373#endif // wxUSE_POPUPWIN
374