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