]> git.saurik.com Git - wxWidgets.git/blame - src/common/popupcmn.cpp
added WXTRACE env. variable
[wxWidgets.git] / src / common / popupcmn.cpp
CommitLineData
c02ee97f
VZ
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__
6522713c 21 #pragma implementation "popupwinbase.h"
c02ee97f
VZ
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
45f22d48 31#if wxUSE_POPUPWIN && !defined(__WXMOTIF__)
c02ee97f
VZ
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
159960c0 43// there is no src/{msw,mgl}/popupwin.cpp to put this in, so we do it here - BTW we
eb729cd3 44// probably could do it for all ports here just as well
159960c0 45#if defined(__WXMSW__) || defined(__WXMGL__)
eb729cd3
VZ
46 IMPLEMENT_DYNAMIC_CLASS(wxPopupWindow, wxWindow)
47#endif // __WXMSW__
48
6c3422e9 49IMPLEMENT_DYNAMIC_CLASS(wxPopupTransientWindow, wxPopupWindow)
761df41e
VZ
50
51#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
52 IMPLEMENT_DYNAMIC_CLASS(wxPopupComboWindow, wxPopupTransientWindow)
53#endif
6c3422e9 54
c02ee97f
VZ
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);
60178eb4 84 void OnKeyUp(wxKeyEvent& event);
c02ee97f
VZ
85
86private:
87 wxPopupTransientWindow *m_popup;
88
89 DECLARE_EVENT_TABLE()
90};
91
92// ----------------------------------------------------------------------------
93// event tables
94// ----------------------------------------------------------------------------
95
96BEGIN_EVENT_TABLE(wxPopupWindowHandler, wxEvtHandler)
97 EVT_LEFT_DOWN(wxPopupWindowHandler::OnLeftDown)
98END_EVENT_TABLE()
99
100BEGIN_EVENT_TABLE(wxPopupFocusHandler, wxEvtHandler)
101 EVT_KILL_FOCUS(wxPopupFocusHandler::OnKillFocus)
60178eb4 102 EVT_KEY_UP(wxPopupFocusHandler::OnKeyUp)
c02ee97f
VZ
103END_EVENT_TABLE()
104
105// ============================================================================
106// implementation
107// ============================================================================
108
109// ----------------------------------------------------------------------------
110// wxPopupWindowBase
111// ----------------------------------------------------------------------------
112
799ea011
GD
113wxPopupWindowBase::~wxPopupWindowBase()
114{
115 // this destructor is required for Darwin
116}
117
c02ee97f
VZ
118bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags))
119{
120 return TRUE;
121}
122
123void wxPopupWindowBase::Position(const wxPoint& ptOrigin,
124 const wxSize& size)
125{
126 wxSize sizeScreen = wxGetDisplaySize(),
127 sizeSelf = GetSize();
128
129 // is there enough space to put the popup below the window (where we put it
130 // by default)?
131 wxCoord y = ptOrigin.y + size.y;
132 if ( y + sizeSelf.y > sizeScreen.y )
133 {
134 // check if there is enough space above
135 if ( ptOrigin.y > sizeSelf.y )
136 {
137 // do position the control above the window
138 y -= size.y + sizeSelf.y;
139 }
140 //else: not enough space below nor above, leave below
141 }
142
143 // now check left/right too
144 wxCoord x = ptOrigin.x + size.x;
145 if ( x + sizeSelf.x > sizeScreen.x )
146 {
147 // check if there is enough space to the left
148 if ( ptOrigin.x > sizeSelf.x )
149 {
150 // do position the control to the left
151 x -= size.x + sizeSelf.x;
152 }
153 //else: not enough space there neither, leave in default position
154 }
155
156 Move(x, y, wxSIZE_NO_ADJUSTMENTS);
157}
158
159// ----------------------------------------------------------------------------
160// wxPopupTransientWindow
161// ----------------------------------------------------------------------------
162
163void wxPopupTransientWindow::Init()
164{
165 m_child =
166 m_focus = (wxWindow *)NULL;
167}
168
758bce95 169wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style)
c02ee97f
VZ
170{
171 Init();
172
758bce95 173 (void)Create(parent, style);
c02ee97f
VZ
174}
175
176wxPopupTransientWindow::~wxPopupTransientWindow()
177{
178 PopHandlers();
179}
180
181void wxPopupTransientWindow::PopHandlers()
182{
183 if ( m_child )
184 {
185 m_child->PopEventHandler(TRUE /* delete it */);
186 m_child->ReleaseMouse();
187 m_child = NULL;
188 }
189
190 if ( m_focus )
191 {
192 m_focus->PopEventHandler(TRUE /* delete it */);
193 m_focus = NULL;
194 }
195}
196
197void wxPopupTransientWindow::Popup(wxWindow *winFocus)
198{
199 const wxWindowList& children = GetChildren();
200 if ( children.GetCount() )
201 {
202 m_child = children.GetFirst()->GetData();
203 }
204 else
205 {
206 m_child = this;
207 }
208
60178eb4 209 // we can't capture mouse before the window is shown in wxGTK
e4606ed9
VZ
210#ifdef __WXGTK__
211 Show();
212#endif
213
c02ee97f
VZ
214 m_child->CaptureMouse();
215 m_child->PushEventHandler(new wxPopupWindowHandler(this));
216
e4606ed9 217#ifndef __WXGTK__
c02ee97f 218 Show();
e4606ed9 219#endif
c02ee97f
VZ
220
221 m_focus = winFocus ? winFocus : this;
c02ee97f 222 m_focus->SetFocus();
60178eb4
VZ
223
224 // FIXME: I don't know why does this happen but sometimes SetFocus() simply
225 // refuses to work under MSW - no error happens but the focus is not
226 // given to the window, i.e. the assert below is triggered
227 //
228 // Try work around this as we can...
229#if 0
230 wxASSERT_MSG( FindFocus() == m_focus, _T("setting focus failed") );
231#else
232 m_focus = FindFocus();
233#endif
234
235 if ( m_focus )
236 {
237 m_focus->PushEventHandler(new wxPopupFocusHandler(this));
238 }
c02ee97f
VZ
239}
240
241void wxPopupTransientWindow::Dismiss()
242{
243 PopHandlers();
244
245 Hide();
246}
247
248void wxPopupTransientWindow::DismissAndNotify()
249{
250 Dismiss();
251
252 OnDismiss();
253}
254
255void wxPopupTransientWindow::OnDismiss()
256{
257 // nothing to do here - but it may be interesting for derived class
258}
259
260bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event))
261{
262 // no special processing here
263 return FALSE;
264}
265
a8132cd4 266#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
c02ee97f
VZ
267
268// ----------------------------------------------------------------------------
269// wxPopupComboWindow
270// ----------------------------------------------------------------------------
271
272wxPopupComboWindow::wxPopupComboWindow(wxComboControl *parent)
273 : wxPopupTransientWindow(parent)
274{
275 m_combo = parent;
276}
277
278bool wxPopupComboWindow::Create(wxComboControl *parent)
279{
280 m_combo = parent;
281
282 return wxPopupWindow::Create(parent);
283}
284
285void wxPopupComboWindow::PositionNearCombo()
286{
287 // the origin point must be in screen coords
288 wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0, 0));
289
89e7a223 290#if 0 //def __WXUNIVERSAL__
c02ee97f
VZ
291 // account for the fact that (0, 0) is not the top left corner of the
292 // window: there is also the border
293 wxRect rectBorders = m_combo->GetRenderer()->
294 GetBorderDimensions(m_combo->GetBorder());
295 ptOrigin.x -= rectBorders.x;
296 ptOrigin.y -= rectBorders.y;
297#endif // __WXUNIVERSAL__
298
299 // position below or above the combobox: the width is 0 to put it exactly
300 // below us, not to the left or to the right
301 Position(ptOrigin, wxSize(0, m_combo->GetSize().y));
302}
303
304void wxPopupComboWindow::OnDismiss()
305{
306 m_combo->OnDismiss();
307}
308
a8132cd4 309#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
c02ee97f
VZ
310
311// ----------------------------------------------------------------------------
312// wxPopupWindowHandler
313// ----------------------------------------------------------------------------
314
315void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event)
316{
317 // let the window have it first (we're the first event handler in the chain
318 // of handlers for this window)
319 if ( m_popup->ProcessLeftDown(event) )
320 {
321 return;
322 }
323
324 wxPoint pos = event.GetPosition();
325
326 // scrollbar on which the click occured
327 wxWindow *sbar = NULL;
328
329 wxWindow *win = (wxWindow *)event.GetEventObject();
330 switch ( win->HitTest(pos.x, pos.y) )
331 {
332 case wxHT_WINDOW_OUTSIDE:
333 // clicking outside a popup dismisses it
334 m_popup->DismissAndNotify();
335 break;
336
a8132cd4 337#ifdef __WXUNIVERSAL__
c02ee97f
VZ
338 case wxHT_WINDOW_HORZ_SCROLLBAR:
339 sbar = win->GetScrollbar(wxHORIZONTAL);
340 break;
341
342 case wxHT_WINDOW_VERT_SCROLLBAR:
343 sbar = win->GetScrollbar(wxVERTICAL);
344 break;
a8132cd4 345#endif
c02ee97f
VZ
346
347 default:
348 // forgot to update the switch after adding a new hit test code?
349 wxFAIL_MSG( _T("unexpected HitTest() return value") );
350 // fall through
351
352 case wxHT_WINDOW_CORNER:
353 // don't actually know if this one is good for anything, but let it
354 // pass just in case
355
356 case wxHT_WINDOW_INSIDE:
357 // let the normal processing take place
358 event.Skip();
359 break;
360 }
361
362 if ( sbar )
363 {
364 // translate the event coordinates to the scrollbar ones
365 pos = sbar->ScreenToClient(win->ClientToScreen(pos));
366
367 // and give the event to it
368 wxMouseEvent event2 = event;
369 event2.m_x = pos.x;
370 event2.m_y = pos.y;
371
372 (void)sbar->GetEventHandler()->ProcessEvent(event2);
373 }
374}
375
376// ----------------------------------------------------------------------------
377// wxPopupFocusHandler
378// ----------------------------------------------------------------------------
379
380void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event)
381{
60178eb4
VZ
382 // when we lose focus we always disappear - unless it goes to the popup (in
383 // which case we don't really lose it)
384 if ( event.GetWindow() != m_popup )
385 m_popup->DismissAndNotify();
386}
54800df8 387
60178eb4
VZ
388void wxPopupFocusHandler::OnKeyUp(wxKeyEvent& event)
389{
390 // let the window have it first, it might process the keys
391 if ( !m_popup->ProcessEvent(event) )
392 {
393 // by default, dismiss the popup
54800df8 394 m_popup->DismissAndNotify();
60178eb4 395 }
c02ee97f
VZ
396}
397
398#endif // wxUSE_POPUPWIN
eb729cd3 399