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