]> git.saurik.com Git - wxWidgets.git/blob - src/common/toplvcmn.cpp
ea6992d636e00d9d35fc334f0209bcfe7ae31556
[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 UpdateInternalSize(child, clientH);
165 #endif
166 }
167 }
168 }
169
170 // The default implementation for the close window event.
171 void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
172 {
173 Destroy();
174 }
175
176 bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized)
177 {
178 wxIconizeEvent event(GetId(), iconized);
179 event.SetEventObject(this);
180
181 return GetEventHandler()->ProcessEvent(event);
182 }
183
184 // ----------------------------------------------------------------------------
185 // interactive manipulation
186 // ----------------------------------------------------------------------------
187
188 #ifdef __WXUNIVERSAL__
189
190 #define wxINTERACTIVE_RESIZE_DIR \
191 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
192 wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
193
194 struct wxInteractiveMoveData
195 {
196 wxTopLevelWindowBase *m_window;
197 wxEventLoop *m_evtLoop;
198 int m_flags;
199 wxRect m_rect;
200 wxRect m_rectOrig;
201 wxPoint m_pos;
202 wxSize m_minSize, m_maxSize;
203 };
204
205 class wxInteractiveMoveHandler : public wxEvtHandler
206 {
207 public:
208 wxInteractiveMoveHandler(wxInteractiveMoveData& data) : m_data(data) {}
209
210 private:
211 DECLARE_EVENT_TABLE()
212 void OnMouseMove(wxMouseEvent& event);
213 void OnMouseDown(wxMouseEvent& event);
214 void OnMouseUp(wxMouseEvent& event);
215 void OnKeyDown(wxKeyEvent& event);
216
217 wxInteractiveMoveData& m_data;
218 };
219
220 BEGIN_EVENT_TABLE(wxInteractiveMoveHandler, wxEvtHandler)
221 EVT_MOTION(wxInteractiveMoveHandler::OnMouseMove)
222 EVT_LEFT_DOWN(wxInteractiveMoveHandler::OnMouseDown)
223 EVT_LEFT_UP(wxInteractiveMoveHandler::OnMouseUp)
224 EVT_KEY_DOWN(wxInteractiveMoveHandler::OnKeyDown)
225 END_EVENT_TABLE()
226
227
228 static inline LINKAGEMODE
229 void wxApplyResize(wxInteractiveMoveData& data, const wxPoint& diff)
230 {
231 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
232 {
233 data.m_rect.x += diff.x;
234 data.m_rect.width -= diff.x;
235 }
236 else if ( data.m_flags & wxINTERACTIVE_RESIZE_E )
237 {
238 data.m_rect.width += diff.x;
239 }
240 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
241 {
242 data.m_rect.y += diff.y;
243 data.m_rect.height -= diff.y;
244 }
245 else if ( data.m_flags & wxINTERACTIVE_RESIZE_S )
246 {
247 data.m_rect.height += diff.y;
248 }
249
250 if ( data.m_minSize.x != -1 && data.m_rect.width < data.m_minSize.x )
251 {
252 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
253 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
254 data.m_rect.width = data.m_minSize.x;
255 }
256 if ( data.m_maxSize.x != -1 && data.m_rect.width > data.m_maxSize.x )
257 {
258 if ( data.m_flags & wxINTERACTIVE_RESIZE_W )
259 data.m_rect.x -= data.m_minSize.x - data.m_rect.width;
260 data.m_rect.width = data.m_maxSize.x;
261 }
262 if ( data.m_minSize.y != -1 && data.m_rect.height < data.m_minSize.y )
263 {
264 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
265 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
266 data.m_rect.height = data.m_minSize.y;
267 }
268 if ( data.m_maxSize.y != -1 && data.m_rect.height > data.m_maxSize.y )
269 {
270 if ( data.m_flags & wxINTERACTIVE_RESIZE_N )
271 data.m_rect.y -= data.m_minSize.y - data.m_rect.height;
272 data.m_rect.height = data.m_maxSize.y;
273 }
274 }
275
276 void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent& event)
277 {
278 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
279 event.Skip();
280
281 else if ( m_data.m_flags & wxINTERACTIVE_MOVE )
282 {
283 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
284 m_data.m_rect = m_data.m_rectOrig;
285 m_data.m_rect.Offset(diff);
286 m_data.m_window->Move(m_data.m_rect.GetPosition());
287 }
288
289 else if ( m_data.m_flags & wxINTERACTIVE_RESIZE )
290 {
291 wxPoint diff = wxGetMousePosition() - m_data.m_pos;
292 m_data.m_rect = m_data.m_rectOrig;
293 wxApplyResize(m_data, diff);
294 m_data.m_window->SetSize(m_data.m_rect);
295 }
296 }
297
298 void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent& event)
299 {
300 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
301 {
302 m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
303 m_data.m_pos = wxGetMousePosition();
304 }
305 }
306
307 void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent& event)
308 {
309 if ( m_data.m_flags & wxINTERACTIVE_WAIT_FOR_INPUT )
310 {
311 m_data.m_flags &= ~wxINTERACTIVE_WAIT_FOR_INPUT;
312 m_data.m_pos = wxGetMousePosition();
313 }
314
315 wxPoint diff(-1,-1);
316
317 switch ( event.GetKeyCode() )
318 {
319 case WXK_UP: diff = wxPoint(0, -16); break;
320 case WXK_DOWN: diff = wxPoint(0, 16); break;
321 case WXK_LEFT: diff = wxPoint(-16, 0); break;
322 case WXK_RIGHT: diff = wxPoint(16, 0); break;
323 case WXK_ESCAPE:
324 m_data.m_window->SetSize(m_data.m_rectOrig);
325 m_data.m_evtLoop->Exit();
326 return;
327 case WXK_RETURN:
328 m_data.m_evtLoop->Exit();
329 return;
330 }
331
332 if ( diff.x != -1 )
333 {
334 if ( m_data.m_flags & wxINTERACTIVE_MOVE )
335 {
336 m_data.m_rect.Offset(diff);
337 m_data.m_window->Move(m_data.m_rect.GetPosition());
338 }
339 else /* wxINTERACTIVE_RESIZE */
340 {
341 if ( !(m_data.m_flags & wxINTERACTIVE_RESIZE_DIR) )
342 {
343 if ( diff.y < 0 )
344 m_data.m_flags |= wxINTERACTIVE_RESIZE_N;
345 else if ( diff.y > 0 )
346 m_data.m_flags |= wxINTERACTIVE_RESIZE_S;
347 if ( diff.x < 0 )
348 m_data.m_flags |= wxINTERACTIVE_RESIZE_W;
349 else if ( diff.x > 0 )
350 m_data.m_flags |= wxINTERACTIVE_RESIZE_E;
351 }
352
353 wxApplyResize(m_data, diff);
354 m_data.m_window->SetSize(m_data.m_rect);
355 }
356 }
357 }
358
359 void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& event)
360 {
361 m_data.m_evtLoop->Exit();
362 }
363
364
365 void wxTopLevelWindowBase::InteractiveMove(int flags)
366 {
367 wxASSERT_MSG( !((flags & wxINTERACTIVE_MOVE) && (flags & wxINTERACTIVE_RESIZE)),
368 wxT("can't move and resize window at the same time") );
369
370 wxASSERT_MSG( !(flags & wxINTERACTIVE_RESIZE) ||
371 (flags & wxINTERACTIVE_WAIT_FOR_INPUT) ||
372 (flags & wxINTERACTIVE_RESIZE_DIR),
373 wxT("direction of resizing not specified") );
374
375 wxInteractiveMoveData data;
376 wxEventLoop loop;
377 wxWindow *focus = FindFocus();
378
379 // FIXME - display resize cursor if waiting for initial input
380
381 data.m_window = this;
382 data.m_evtLoop = &loop;
383 data.m_flags = flags;
384 data.m_rect = data.m_rectOrig = GetRect();
385 data.m_pos = wxGetMousePosition();
386 data.m_minSize = wxSize(GetMinWidth(), GetMinHeight());
387 data.m_maxSize = wxSize(GetMaxWidth(), GetMaxHeight());
388
389 this->PushEventHandler(new wxInteractiveMoveHandler(data));
390 if ( focus )
391 focus->PushEventHandler(new wxInteractiveMoveHandler(data));
392
393 CaptureMouse();
394 loop.Run();
395 ReleaseMouse();
396
397 this->PopEventHandler(TRUE/*delete*/);
398 if ( focus )
399 focus->PopEventHandler(TRUE/*delete*/);
400 }
401
402 #endif // __WXUNIVERSAL__