1 /////////////////////////////////////////////////////////////////////////////
2 // Name: common/toplvcmn.cpp
3 // Purpose: common (for all platforms) wxTopLevelWindow functions
4 // Author: Julian Smart, Vadim Zeitlin
7 // Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
20 #pragma implementation "toplevelbase.h"
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
31 #include "wx/toplevel.h"
32 #include "wx/dcclient.h"
35 #include "wx/evtloop.h"
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 BEGIN_EVENT_TABLE(wxTopLevelWindowBase
, wxWindow
)
42 EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow
)
43 EVT_SIZE(wxTopLevelWindowBase::OnSize
)
46 // ============================================================================
48 // ============================================================================
50 // FIXME: some platforms don't have wxTopLevelWindow yet
51 #ifdef wxTopLevelWindowNative
52 IMPLEMENT_DYNAMIC_CLASS(wxTopLevelWindow
, wxWindow
)
55 // ----------------------------------------------------------------------------
56 // construction/destruction
57 // ----------------------------------------------------------------------------
59 wxTopLevelWindowBase::wxTopLevelWindowBase()
63 bool wxTopLevelWindowBase::Destroy()
65 // delayed destruction: the frame will be deleted during the next idle
67 if ( !wxPendingDelete
.Member(this) )
68 wxPendingDelete
.Append(this);
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 // ----------------------------------------------------------------------------
79 void wxTopLevelWindowBase::DoScreenToClient(int *x
, int *y
) const
81 wxWindow::DoScreenToClient(x
, y
);
83 // translate the wxWindow client coords to our client coords
84 wxPoint
pt(GetClientAreaOrigin());
91 void wxTopLevelWindowBase::DoClientToScreen(int *x
, int *y
) const
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());
101 wxWindow::DoClientToScreen(x
, y
);
105 // ----------------------------------------------------------------------------
107 // ----------------------------------------------------------------------------
109 // default resizing behaviour - if only ONE subwindow, resize to fill the
111 void wxTopLevelWindowBase::OnSize(wxSizeEvent
& WXUNUSED(event
))
113 // if we're using constraints - do use them
114 #if wxUSE_CONSTRAINTS
115 if ( GetAutoLayout() )
120 #endif // wxUSE_CONSTRAINTS
122 // do we have _exactly_ one child?
123 wxWindow
*child
= (wxWindow
*)NULL
;
124 for ( wxWindowList::Node
*node
= GetChildren().GetFirst();
126 node
= node
->GetNext() )
128 wxWindow
*win
= node
->GetData();
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
) )
137 return; // it's our second subwindow - nothing to do
144 // do we have any children at all?
147 // exactly one child - set it's size to fill the whole frame
148 int clientW
, clientH
;
149 DoGetClientSize(&clientW
, &clientH
);
151 // for whatever reasons, wxGTK wants to have a small offset - it
152 // probably looks better with it?
154 static const int ofs
= 1;
156 static const int ofs
= 0;
159 child
->SetSize(ofs
, ofs
, clientW
- 2*ofs
, clientH
- 2*ofs
);
164 // The default implementation for the close window event.
165 void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent
& WXUNUSED(event
))
170 bool wxTopLevelWindowBase::SendIconizeEvent(bool iconized
)
172 wxIconizeEvent
event(GetId(), iconized
);
173 event
.SetEventObject(this);
175 return GetEventHandler()->ProcessEvent(event
);
179 // ----------------------------------------------------------------------------
180 // interactive manipulation
181 // ----------------------------------------------------------------------------
183 #ifdef __WXUNIVERSAL__
185 #define wxINTERACTIVE_RESIZE_DIR \
186 (wxINTERACTIVE_RESIZE_W | wxINTERACTIVE_RESIZE_E | \
187 wxINTERACTIVE_RESIZE_S | wxINTERACTIVE_RESIZE_N)
189 struct wxInteractiveMoveData
191 wxTopLevelWindowBase
*m_window
;
192 wxEventLoop
*m_evtLoop
;
197 wxSize m_minSize
, m_maxSize
;
200 class wxInteractiveMoveHandler
: public wxEvtHandler
203 wxInteractiveMoveHandler(wxInteractiveMoveData
& data
) : m_data(data
) {}
206 DECLARE_EVENT_TABLE()
207 void OnMouseMove(wxMouseEvent
& event
);
208 void OnMouseDown(wxMouseEvent
& event
);
209 void OnMouseUp(wxMouseEvent
& event
);
210 void OnKeyDown(wxKeyEvent
& event
);
212 wxInteractiveMoveData
& m_data
;
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
)
223 static inline LINKAGEMODE
224 void wxApplyResize(wxInteractiveMoveData
& data
, const wxPoint
& diff
)
226 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_W
)
228 data
.m_rect
.x
+= diff
.x
;
229 data
.m_rect
.width
-= diff
.x
;
231 else if ( data
.m_flags
& wxINTERACTIVE_RESIZE_E
)
233 data
.m_rect
.width
+= diff
.x
;
235 if ( data
.m_flags
& wxINTERACTIVE_RESIZE_N
)
237 data
.m_rect
.y
+= diff
.y
;
238 data
.m_rect
.height
-= diff
.y
;
240 else if ( data
.m_flags
& wxINTERACTIVE_RESIZE_S
)
242 data
.m_rect
.height
+= diff
.y
;
245 if ( data
.m_minSize
.x
!= -1 && data
.m_rect
.width
< data
.m_minSize
.x
)
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
;
251 if ( data
.m_maxSize
.x
!= -1 && data
.m_rect
.width
> data
.m_maxSize
.x
)
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
;
257 if ( data
.m_minSize
.y
!= -1 && data
.m_rect
.height
< data
.m_minSize
.y
)
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
;
263 if ( data
.m_maxSize
.y
!= -1 && data
.m_rect
.height
> data
.m_maxSize
.y
)
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
;
271 void wxInteractiveMoveHandler::OnMouseMove(wxMouseEvent
& event
)
273 if ( m_data
.m_flags
& wxINTERACTIVE_WAIT_FOR_INPUT
)
276 else if ( m_data
.m_flags
& wxINTERACTIVE_MOVE
)
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());
284 else if ( m_data
.m_flags
& wxINTERACTIVE_RESIZE
)
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
);
293 void wxInteractiveMoveHandler::OnMouseDown(wxMouseEvent
& event
)
295 if ( m_data
.m_flags
& wxINTERACTIVE_WAIT_FOR_INPUT
)
297 m_data
.m_flags
&= ~wxINTERACTIVE_WAIT_FOR_INPUT
;
298 m_data
.m_pos
= wxGetMousePosition();
302 void wxInteractiveMoveHandler::OnKeyDown(wxKeyEvent
& event
)
304 if ( m_data
.m_flags
& wxINTERACTIVE_WAIT_FOR_INPUT
)
306 m_data
.m_flags
&= ~wxINTERACTIVE_WAIT_FOR_INPUT
;
307 m_data
.m_pos
= wxGetMousePosition();
312 switch ( event
.GetKeyCode() )
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;
319 m_data
.m_window
->SetSize(m_data
.m_rectOrig
);
320 m_data
.m_evtLoop
->Exit();
323 m_data
.m_evtLoop
->Exit();
329 if ( m_data
.m_flags
& wxINTERACTIVE_MOVE
)
331 m_data
.m_rect
.Offset(diff
);
332 m_data
.m_window
->Move(m_data
.m_rect
.GetPosition());
334 else /* wxINTERACTIVE_RESIZE */
336 if ( !(m_data
.m_flags
& wxINTERACTIVE_RESIZE_DIR
) )
339 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_N
;
340 else if ( diff
.y
> 0 )
341 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_S
;
343 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_W
;
344 else if ( diff
.x
> 0 )
345 m_data
.m_flags
|= wxINTERACTIVE_RESIZE_E
;
348 wxApplyResize(m_data
, diff
);
349 m_data
.m_window
->SetSize(m_data
.m_rect
);
354 void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent
& event
)
356 m_data
.m_evtLoop
->Exit();
360 void wxTopLevelWindowBase::InteractiveMove(int flags
)
362 wxASSERT_MSG( !((flags
& wxINTERACTIVE_MOVE
) && (flags
& wxINTERACTIVE_RESIZE
)),
363 wxT("can't move and resize window at the same time") );
365 wxASSERT_MSG( !(flags
& wxINTERACTIVE_RESIZE
) ||
366 (flags
& wxINTERACTIVE_WAIT_FOR_INPUT
) ||
367 (flags
& wxINTERACTIVE_RESIZE_DIR
),
368 wxT("direction of resizing not specified") );
370 wxInteractiveMoveData data
;
372 wxWindow
*focus
= FindFocus();
374 // FIXME - display resize cursor if waiting for initial input
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());
384 this->PushEventHandler(new wxInteractiveMoveHandler(data
));
386 focus
->PushEventHandler(new wxInteractiveMoveHandler(data
));
392 this->PopEventHandler(TRUE
/*delete*/);
394 focus
->PopEventHandler(TRUE
/*delete*/);
397 #endif // __WXUNIVERSAL__