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