]> git.saurik.com Git - wxWidgets.git/blame - src/common/popupcmn.cpp
copyright update
[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
eb729cd3
VZ
43// there is no src/msw/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#ifdef __WXMSW__
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);
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
111bool wxPopupWindowBase::Create(wxWindow* WXUNUSED(parent), int WXUNUSED(flags))
112{
113 return TRUE;
114}
115
116void wxPopupWindowBase::Position(const wxPoint& ptOrigin,
117 const wxSize& size)
118{
119 wxSize sizeScreen = wxGetDisplaySize(),
120 sizeSelf = GetSize();
121
122 // is there enough space to put the popup below the window (where we put it
123 // by default)?
124 wxCoord y = ptOrigin.y + size.y;
125 if ( y + sizeSelf.y > sizeScreen.y )
126 {
127 // check if there is enough space above
128 if ( ptOrigin.y > sizeSelf.y )
129 {
130 // do position the control above the window
131 y -= size.y + sizeSelf.y;
132 }
133 //else: not enough space below nor above, leave below
134 }
135
136 // now check left/right too
137 wxCoord x = ptOrigin.x + size.x;
138 if ( x + sizeSelf.x > sizeScreen.x )
139 {
140 // check if there is enough space to the left
141 if ( ptOrigin.x > sizeSelf.x )
142 {
143 // do position the control to the left
144 x -= size.x + sizeSelf.x;
145 }
146 //else: not enough space there neither, leave in default position
147 }
148
149 Move(x, y, wxSIZE_NO_ADJUSTMENTS);
150}
151
152// ----------------------------------------------------------------------------
153// wxPopupTransientWindow
154// ----------------------------------------------------------------------------
155
156void wxPopupTransientWindow::Init()
157{
158 m_child =
159 m_focus = (wxWindow *)NULL;
160}
161
758bce95 162wxPopupTransientWindow::wxPopupTransientWindow(wxWindow *parent, int style)
c02ee97f
VZ
163{
164 Init();
165
758bce95 166 (void)Create(parent, style);
c02ee97f
VZ
167}
168
169wxPopupTransientWindow::~wxPopupTransientWindow()
170{
171 PopHandlers();
172}
173
174void wxPopupTransientWindow::PopHandlers()
175{
176 if ( m_child )
177 {
178 m_child->PopEventHandler(TRUE /* delete it */);
179 m_child->ReleaseMouse();
180 m_child = NULL;
181 }
182
183 if ( m_focus )
184 {
185 m_focus->PopEventHandler(TRUE /* delete it */);
186 m_focus = NULL;
187 }
188}
189
190void wxPopupTransientWindow::Popup(wxWindow *winFocus)
191{
192 const wxWindowList& children = GetChildren();
193 if ( children.GetCount() )
194 {
195 m_child = children.GetFirst()->GetData();
196 }
197 else
198 {
199 m_child = this;
200 }
201
e4606ed9
VZ
202 // we can't capture mouse before the window is shown in wxGTL
203#ifdef __WXGTK__
204 Show();
205#endif
206
c02ee97f
VZ
207 m_child->CaptureMouse();
208 m_child->PushEventHandler(new wxPopupWindowHandler(this));
209
e4606ed9 210#ifndef __WXGTK__
c02ee97f 211 Show();
e4606ed9 212#endif
c02ee97f
VZ
213
214 m_focus = winFocus ? winFocus : this;
215 m_focus->PushEventHandler(new wxPopupFocusHandler(this));
216 m_focus->SetFocus();
217}
218
219void wxPopupTransientWindow::Dismiss()
220{
221 PopHandlers();
222
223 Hide();
224}
225
226void wxPopupTransientWindow::DismissAndNotify()
227{
228 Dismiss();
229
230 OnDismiss();
231}
232
233void wxPopupTransientWindow::OnDismiss()
234{
235 // nothing to do here - but it may be interesting for derived class
236}
237
238bool wxPopupTransientWindow::ProcessLeftDown(wxMouseEvent& WXUNUSED(event))
239{
240 // no special processing here
241 return FALSE;
242}
243
a8132cd4 244#if wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
c02ee97f
VZ
245
246// ----------------------------------------------------------------------------
247// wxPopupComboWindow
248// ----------------------------------------------------------------------------
249
250wxPopupComboWindow::wxPopupComboWindow(wxComboControl *parent)
251 : wxPopupTransientWindow(parent)
252{
253 m_combo = parent;
254}
255
256bool wxPopupComboWindow::Create(wxComboControl *parent)
257{
258 m_combo = parent;
259
260 return wxPopupWindow::Create(parent);
261}
262
263void wxPopupComboWindow::PositionNearCombo()
264{
265 // the origin point must be in screen coords
266 wxPoint ptOrigin = m_combo->ClientToScreen(wxPoint(0, 0));
267
89e7a223 268#if 0 //def __WXUNIVERSAL__
c02ee97f
VZ
269 // account for the fact that (0, 0) is not the top left corner of the
270 // window: there is also the border
271 wxRect rectBorders = m_combo->GetRenderer()->
272 GetBorderDimensions(m_combo->GetBorder());
273 ptOrigin.x -= rectBorders.x;
274 ptOrigin.y -= rectBorders.y;
275#endif // __WXUNIVERSAL__
276
277 // position below or above the combobox: the width is 0 to put it exactly
278 // below us, not to the left or to the right
279 Position(ptOrigin, wxSize(0, m_combo->GetSize().y));
280}
281
282void wxPopupComboWindow::OnDismiss()
283{
284 m_combo->OnDismiss();
285}
286
a8132cd4 287#endif // wxUSE_COMBOBOX && defined(__WXUNIVERSAL__)
c02ee97f
VZ
288
289// ----------------------------------------------------------------------------
290// wxPopupWindowHandler
291// ----------------------------------------------------------------------------
292
293void wxPopupWindowHandler::OnLeftDown(wxMouseEvent& event)
294{
295 // let the window have it first (we're the first event handler in the chain
296 // of handlers for this window)
297 if ( m_popup->ProcessLeftDown(event) )
298 {
299 return;
300 }
301
302 wxPoint pos = event.GetPosition();
303
304 // scrollbar on which the click occured
305 wxWindow *sbar = NULL;
306
307 wxWindow *win = (wxWindow *)event.GetEventObject();
308 switch ( win->HitTest(pos.x, pos.y) )
309 {
310 case wxHT_WINDOW_OUTSIDE:
311 // clicking outside a popup dismisses it
312 m_popup->DismissAndNotify();
313 break;
314
a8132cd4 315#ifdef __WXUNIVERSAL__
c02ee97f
VZ
316 case wxHT_WINDOW_HORZ_SCROLLBAR:
317 sbar = win->GetScrollbar(wxHORIZONTAL);
318 break;
319
320 case wxHT_WINDOW_VERT_SCROLLBAR:
321 sbar = win->GetScrollbar(wxVERTICAL);
322 break;
a8132cd4 323#endif
c02ee97f
VZ
324
325 default:
326 // forgot to update the switch after adding a new hit test code?
327 wxFAIL_MSG( _T("unexpected HitTest() return value") );
328 // fall through
329
330 case wxHT_WINDOW_CORNER:
331 // don't actually know if this one is good for anything, but let it
332 // pass just in case
333
334 case wxHT_WINDOW_INSIDE:
335 // let the normal processing take place
336 event.Skip();
337 break;
338 }
339
340 if ( sbar )
341 {
342 // translate the event coordinates to the scrollbar ones
343 pos = sbar->ScreenToClient(win->ClientToScreen(pos));
344
345 // and give the event to it
346 wxMouseEvent event2 = event;
347 event2.m_x = pos.x;
348 event2.m_y = pos.y;
349
350 (void)sbar->GetEventHandler()->ProcessEvent(event2);
351 }
352}
353
354// ----------------------------------------------------------------------------
355// wxPopupFocusHandler
356// ----------------------------------------------------------------------------
357
358void wxPopupFocusHandler::OnKillFocus(wxFocusEvent& event)
359{
360 // when we lose focus we always disappear
54800df8
JS
361
362 // But if m_popup was about to get the focus,
363 // don't disappear.
364 if (event.GetWindow() != m_popup)
365 m_popup->DismissAndNotify();
c02ee97f
VZ
366}
367
368#endif // wxUSE_POPUPWIN
eb729cd3 369