]> git.saurik.com Git - wxWidgets.git/blob - src/common/toplvcmn.cpp
Some things needed in the base class of OS/2
[wxWidgets.git] / src / common / toplvcmn.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/toplvcmn.cpp
3 // Purpose: common (for all platforms) wxTopLevelWindow functions
4 // Author: Julian Smart, Vadim Zeitlin
5 // Created: 01/02/97
6 // Id: $Id$
7 // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #ifdef __GNUG__
20 #pragma implementation "toplevelbase.h"
21 #endif
22
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx/toplevel.h"
32 #include "wx/dcclient.h"
33 #endif // WX_PRECOMP
34
35 #include "wx/evtloop.h"
36
37 // ----------------------------------------------------------------------------
38 // event table
39 // ----------------------------------------------------------------------------
40
41 BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow)
42 EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow)
43 EVT_SIZE(wxTopLevelWindowBase::OnSize)
44 END_EVENT_TABLE()
45
46 // ============================================================================
47 // implementation
48 // ============================================================================
49
50 // FIXME: some platforms don't have wxTopLevelWindow yet
51 #ifdef wxTopLevelWindowNative
52 IMPLEMENT_DYNAMIC_CLASS(wxTopLevelWindow, wxWindow)
53 #endif
54
55 // ----------------------------------------------------------------------------
56 // construction/destruction
57 // ----------------------------------------------------------------------------
58
59 wxTopLevelWindowBase::wxTopLevelWindowBase()
60 {
61 }
62
63 bool wxTopLevelWindowBase::Destroy()
64 {
65 // delayed destruction: the frame will be deleted during the next idle
66 // loop iteration
67 if ( !wxPendingDelete.Member(this) )
68 wxPendingDelete.Append(this);
69
70 return TRUE;
71 }
72
73 // ----------------------------------------------------------------------------
74 // wxTopLevelWindow size management: we exclude the areas taken by
75 // menu/status/toolbars from the client area, so the client area is what's
76 // really available for the frame contents
77 // ----------------------------------------------------------------------------
78
79 void wxTopLevelWindowBase::DoScreenToClient(int *x, int *y) const
80 {
81 wxWindow::DoScreenToClient(x, y);
82
83 // translate the wxWindow client coords to our client coords
84 wxPoint pt(GetClientAreaOrigin());
85 if ( x )
86 *x -= pt.x;
87 if ( y )
88 *y -= pt.y;
89 }
90
91 void wxTopLevelWindowBase::DoClientToScreen(int *x, int *y) const
92 {
93 // our client area origin (0, 0) may be really something like (0, 30) for
94 // wxWindow if we have a toolbar, account for it before translating
95 wxPoint pt(GetClientAreaOrigin());
96 if ( x )
97 *x += pt.x;
98 if ( y )
99 *y += pt.y;
100
101 wxWindow::DoClientToScreen(x, y);
102 }
103
104
105 // ----------------------------------------------------------------------------
106 // event handlers
107 // ----------------------------------------------------------------------------
108
109 // default resizing behaviour - if only ONE subwindow, resize to fill the
110 // whole client area
111 void wxTopLevelWindowBase::OnSize(wxSizeEvent& WXUNUSED(event))
112 {
113 // if we're using constraints - do use them
114 #if wxUSE_CONSTRAINTS
115 if ( GetAutoLayout() )
116 {
117 Layout();
118 }
119 else
120 #endif // wxUSE_CONSTRAINTS
121 {
122 // do we have _exactly_ one child?
123 wxWindow *child = (wxWindow *)NULL;
124 for ( wxWindowList::Node *node = GetChildren().GetFirst();
125 node;
126 node = node->GetNext() )
127 {
128 wxWindow *win = node->GetData();
129
130 // exclude top level and managed windows (status bar isn't
131 // currently in the children list except under wxMac anyhow, but
132 // it makes no harm to test for it)
133 if ( !win->IsTopLevel() && !IsOneOfBars(win) )
134 {
135 if ( child )
136 {
137 #ifdef __WXPM__
138 AlterChildPos();
139 #endif
140 return; // it's our second subwindow - nothing to do
141 }
142
143 child = win;
144 }
145 }
146
147 // do we have any children at all?
148 if ( child )
149 {
150 // exactly one child - set it's size to fill the whole frame
151 int clientW, clientH;
152 DoGetClientSize(&clientW, &clientH);
153
154 // for whatever reasons, wxGTK wants to have a small offset - it
155 // probably looks better with it?
156 #ifdef __WXGTK__
157 static const int ofs = 1;
158 #else
159 static const int ofs = 0;
160 #endif
161
162 child->SetSize(ofs, ofs, clientW - 2*ofs, clientH - 2*ofs);
163 #ifdef __WXPM__
164 child->MoveChildren(m_vSwpClient.cy - clientH);
165 ::WinQueryWindowPos(GetHwnd(), &m_vSwpClient);
166 #endif
167 }
168 }
169 }
170
171 // The default implementation for the close window event.
172 void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
173 {
174 Destroy();
175 }
176
177 bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized)
178 {
179 wxIconizeEvent event(GetId(), iconized);
180 event.SetEventObject(this);
181
182 return GetEventHandler()->ProcessEvent(event);
183 }
184
185
186 // ----------------------------------------------------------------------------
187 // interactive manipulation
188 // ----------------------------------------------------------------------------
189
190 #ifdef __WXUNIVERSAL__
191
192 #define wxINTERACTIVE_RESIZE_DIR \
193 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
194 wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
195
196 struct wxInteractiveMoveData
197 {
198 wxTopLevelWindowBase *m_window;
199 wxEventLoop *m_evtLoop;
200 int m_flags;
201 wxRect m_rect;
202 wxRect m_rectOrig;
203 wxPoint m_pos;
204 wxSize m_minSize, m_maxSize;
205 };
206
207 class wxInteractiveMoveHandler : public wxEvtHandler
208 {
209 public:
210 wxInteractiveMoveHandler(wxInteractiveMoveData& data) : m_data(data) {}
211
212 private:
213 DECLARE_EVENT_TABLE()
214 void OnMouseMove(wxMouseEvent& event);
215 void OnMouseDown(wxMouseEvent& event);
216 void OnMouseUp(wxMouseEvent& event);
217 void OnKeyDown(wxKeyEvent& event);
218
219 wxInteractiveMoveData& m_data;
220 };
221
222 BEGIN_EVENT_TABLE(wxInteractiveMoveHandler, wxEvtHandler)
223 EVT_MOTION(wxInteractiveMoveHandler::OnMouseMove)
224 EVT_LEFT_DOWN(wxInteractiveMoveHandler::OnMouseDown)
225 EVT_LEFT_UP(wxInteractiveMoveHandler::OnMouseUp)
226 EVT_KEY_DOWN(wxInteractiveMoveHandler::OnKeyDown)
227 END_EVENT_TABLE()
228
229
230 static inline LINKAGEMODE
231 void wxApplyResize(wxInteractiveMoveData& data, const wxPoint& diff)
232 {
233 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
234 {
235 data.m_rect.x += diff.x;
236 data.m_rect.width -= diff.x;
237 }
238 else if ( data.m_flags & wxINTERACTIVE_RESIZE_E )
239 {
240 data.m_rect.width += diff.x;
241 }
242 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
243 {
244 data.m_rect.y += diff.y;
245 data.m_rect.height -= diff.y;
246 }
247 else if ( data.m_flags & wxINTERACTIVE_RESIZE_S )
248 {
249 data.m_rect.height += diff.y;
250 }
251
252 if ( data.m_minSize.x != -1 && data.m_rect.width < data.m_minSize.x )
253 {
254 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
255 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
256 data.m_rect.width = data.m_minSize.x;
257 }
258 if ( data.m_maxSize.x != -1 && data.m_rect.width > data.m_maxSize.x )
259 {
260 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
261 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
262 data.m_rect.width = data.m_maxSize.x;
263 }
264 if ( data.m_minSize.y != -1 && data.m_rect.height < data.m_minSize.y )
265 {
266 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
267 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
268 data.m_rect.height = data.m_minSize.y;
269 }
270 if ( data.m_maxSize.y != -1 && data.m_rect.height > data.m_maxSize.y )
271 {
272 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
273 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
274 data.m_rect.height = data.m_maxSize.y;
275 }
276 }
277
278 void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent& event)
279 {
280 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
281 event.Skip();
282
283 else if ( m_data.m_flags & wxINTERACTIVE_MOVE )
284 {
285 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
286 m_data.m_rect = m_data.m_rectOrig;
287 m_data.m_rect.Offset(diff);
288 m_data.m_window->Move(m_data.m_rect.GetPosition());
289 }
290
291 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE )
292 {
293 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
294 m_data.m_rect = m_data.m_rectOrig;
295 wxApplyResize(m_data, diff);
296 m_data.m_window->SetSize(m_data.m_rect);
297 }
298 }
299
300 void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent& event)
301 {
302 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
303 {
304 m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
305 m_data.m_pos = wxGetMousePosition();
306 }
307 }
308
309 void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
310 {
311 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
312 {
313 m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
314 m_data.m_pos = wxGetMousePosition();
315 }
316
317 wxPoint diff(-1,-1);
318
319 switch ( event.GetKeyCode() )
320 {
321 case WXK_UP: diff = wxPoint(0, -16); break;
322 case WXK_DOWN: diff = wxPoint(0, 16); break;
323 case WXK_LEFT: diff = wxPoint(-16, 0); break;
324 case WXK_RIGHT: diff = wxPoint(16, 0); break;
325 case WXK_ESCAPE:
326 m_data.m_window->SetSize(m_data.m_rectOrig);
327 m_data.m_evtLoop->Exit();
328 return;
329 case WXK_RETURN:
330 m_data.m_evtLoop->Exit();
331 return;
332 }
333
334 if ( diff.x != -1 )
335 {
336 if ( m_data.m_flags & wxINTERACTIVE_MOVE )
337 {
338 m_data.m_rect.Offset(diff);
339 m_data.m_window->Move(m_data.m_rect.GetPosition());
340 }
341 else /* wxINTERACTIVE_RESIZE */
342 {
343 if ( !(m_data.m_flags & wxINTERACTIVE_RESIZE_DIR) )
344 {
345 if ( diff.y < 0 )
346 m_data.m_flags |= wxINTERACTIVE_RESIZE_N;
347 else if ( diff.y > 0 )
348 m_data.m_flags |= wxINTERACTIVE_RESIZE_S;
349 if ( diff.x < 0 )
350 m_data.m_flags |= wxINTERACTIVE_RESIZE_W;
351 else if ( diff.x > 0 )
352 m_data.m_flags |= wxINTERACTIVE_RESIZE_E;
353 }
354
355 wxApplyResize(m_data, diff);
356 m_data.m_window->SetSize(m_data.m_rect);
357 }
358 }
359 }
360
361 void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& event)
362 {
363 m_data.m_evtLoop->Exit();
364 }
365
366
367 void wxTopLevelWindowBase::InteractiveMove(int flags)
368 {
369 wxASSERT_MSG( !((flags & wxINTERACTIVE_MOVE) && (flags & wxINTERACTIVE_RESIZE)),
370 wxT("can't move and resize window at the same time") );
371
372 wxASSERT_MSG( !(flags & wxINTERACTIVE_RESIZE) ||
373 (flags & wxINTERACTIVE_WAIT_FOR_INPUT) ||
374 (flags & wxINTERACTIVE_RESIZE_DIR),
375 wxT("direction of resizing not specified") );
376
377 wxInteractiveMoveData data;
378 wxEventLoop loop;
379 wxWindow *focus = FindFocus();
380
381 // FIXME - display resize cursor if waiting for initial input
382
383 data.m_window = this;
384 data.m_evtLoop = &loop;
385 data.m_flags = flags;
386 data.m_rect = data.m_rectOrig = GetRect();
387 data.m_pos = wxGetMousePosition();
388 data.m_minSize = wxSize(GetMinWidth(), GetMinHeight());
389 data.m_maxSize = wxSize(GetMaxWidth(), GetMaxHeight());
390
391 this->PushEventHandler(new wxInteractiveMoveHandler(data));
392 if ( focus )
393 focus->PushEventHandler(new wxInteractiveMoveHandler(data));
394
395 CaptureMouse();
396 loop.Run();
397 ReleaseMouse();
398
399 this->PopEventHandler(TRUE/*delete*/);
400 if ( focus )
401 focus->PopEventHandler(TRUE/*delete*/);
402 }
403
404 #endif // __WXUNIVERSAL__