]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/common/toplvcmn.cpp
Smooth Aqua buttons in wxTreeCtrl.
[wxWidgets.git] / src / common / toplvcmn.cpp
... / ...
CommitLineData
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
41BEGIN_EVENT_TABLE(wxTopLevelWindowBase, wxWindow)
42 EVT_CLOSE(wxTopLevelWindowBase::OnCloseWindow)
43 EVT_SIZE(wxTopLevelWindowBase::OnSize)
44END_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
59wxTopLevelWindowBase::wxTopLevelWindowBase()
60{
61}
62
63bool 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
79void 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
91void 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
111void 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.
165void wxTopLevelWindowBase::OnCloseWindow(wxCloseEvent& WXUNUSED(event))
166{
167 Destroy();
168}
169
170bool 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
189struct 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
200class wxInteractiveMoveHandler : public wxEvtHandler
201{
202public:
203 wxInteractiveMoveHandler(wxInteractiveMoveData& data) : m_data(data) {}
204
205private:
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
215BEGIN_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)
220END_EVENT_TABLE()
221
222
223static inline LINKAGEMODE
224void 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
271void 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
293void 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
302void 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
354void wxInteractiveMoveHandler::OnMouseUp(wxMouseEvent& event)
355{
356 m_data.m_evtLoop->Exit();
357}
358
359
360void 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__