1 ///////////////////////////////////////////////////////////////////////////////
2 // Name: src/aui/floatpane.cpp
3 // Purpose: wxaui: wx advanced user interface - docking window manager
4 // Author: Benjamin I. Williams
5 // Modified by:
6 // Created: 2005-05-17
7 // Copyright: (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved
8 // Licence: wxWindows Library Licence, Version 3.1
9 ///////////////////////////////////////////////////////////////////////////////
10
11 // ============================================================================
12 // declarations
13 // ============================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 #include "wx/wxprec.h"
20
21
22 #if wxUSE_AUI
23
24 #include "wx/aui/framemanager.h"
25 #include "wx/aui/floatpane.h"
26 #include "wx/aui/dockart.h"
27
28 #ifndef WX_PRECOMP
29 #endif
30
31 #ifdef __WXMSW__
32 #include "wx/msw/private.h"
33 #endif
34
35 wxIMPLEMENT_CLASS(wxAuiFloatingFrame, wxAuiFloatingFrameBaseClass);
36
wxAuiFloatingFrame(wxWindow * parent,wxAuiManager * owner_mgr,const wxAuiPaneInfo & pane,wxWindowID id,long style)37 wxAuiFloatingFrame::wxAuiFloatingFrame(wxWindow* parent,
38 wxAuiManager* owner_mgr,
39 const wxAuiPaneInfo& pane,
40 wxWindowID id /*= wxID_ANY*/,
41 long style /*=wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION |
42 wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT |
43 wxCLIP_CHILDREN
44 */)
45 : wxAuiFloatingFrameBaseClass(parent, id, wxEmptyString,
46 pane.floating_pos, pane.floating_size,
47 style |
48 (pane.HasCloseButton()?wxCLOSE_BOX:0) |
49 (pane.HasMaximizeButton()?wxMAXIMIZE_BOX:0) |
50 (pane.IsFixed()?0:wxRESIZE_BORDER)
51 )
52 , m_ownerMgr(owner_mgr)
53 {
54 m_moving = false;
55 m_mgr.SetManagedWindow(this);
56 m_mgr.SetArtProvider(owner_mgr->GetArtProvider()->Clone());
57 m_solidDrag = true;
58
59 // find out if the system supports solid window drag.
60 // on non-msw systems, this is assumed to be the case
61 #ifdef __WXMSW__
62 BOOL b = TRUE;
63 SystemParametersInfo(38 /*SPI_GETDRAGFULLWINDOWS*/, 0, &b, 0);
64 m_solidDrag = b ? true : false;
65 #endif
66
67 SetExtraStyle(wxWS_EX_PROCESS_IDLE);
68 }
69
~wxAuiFloatingFrame()70 wxAuiFloatingFrame::~wxAuiFloatingFrame()
71 {
72 // if we do not do this, then we can crash...
73 if (m_ownerMgr && m_ownerMgr->m_actionWindow == this)
74 {
75 m_ownerMgr->m_actionWindow = NULL;
76 }
77
78 m_mgr.UnInit();
79 }
80
SetPaneWindow(const wxAuiPaneInfo & pane)81 void wxAuiFloatingFrame::SetPaneWindow(const wxAuiPaneInfo& pane)
82 {
83 m_paneWindow = pane.window;
84 m_paneWindow->Reparent(this);
85
86 wxAuiPaneInfo contained_pane = pane;
87 contained_pane.Dock().Center().Show().
88 CaptionVisible(false).
89 PaneBorder(false).
90 Layer(0).Row(0).Position(0);
91
92 // Carry over the minimum size
93 wxSize pane_min_size = pane.window->GetMinSize();
94
95 // if the frame window's max size is greater than the min size
96 // then set the max size to the min size as well
97 wxSize cur_max_size = GetMaxSize();
98 if (cur_max_size.IsFullySpecified() &&
99 (cur_max_size.x < pane.min_size.x ||
100 cur_max_size.y < pane.min_size.y)
101 )
102 {
103 SetMaxSize(pane_min_size);
104 }
105
106 SetMinSize(pane.window->GetMinSize());
107
108 m_mgr.AddPane(m_paneWindow, contained_pane);
109 m_mgr.Update();
110
111 if (pane.min_size.IsFullySpecified())
112 {
113 // because SetSizeHints() calls Fit() too (which sets the window
114 // size to its minimum allowed), we keep the size before calling
115 // SetSizeHints() and reset it afterwards...
116 wxSize tmp = GetSize();
117 GetSizer()->SetSizeHints(this);
118 SetSize(tmp);
119 }
120
121 SetTitle(pane.caption);
122
123 // This code is slightly awkward because we need to reset wxRESIZE_BORDER
124 // before calling SetClientSize() below as doing it after setting the
125 // client size would actually change it, at least under MSW, where the
126 // total window size doesn't change and hence, as the borders size changes,
127 // the client size does change.
128 //
129 // So we must call it first but doing it generates a size event and updates
130 // pane.floating_size from inside it so we must also record its original
131 // value before doing it.
132 const bool hasFloatingSize = pane.floating_size != wxDefaultSize;
133 if (pane.IsFixed())
134 {
135 SetWindowStyleFlag(GetWindowStyleFlag() & ~wxRESIZE_BORDER);
136 }
137
138 if ( hasFloatingSize )
139 {
140 SetSize(pane.floating_size);
141 }
142 else
143 {
144 wxSize size = pane.best_size;
145 if (size == wxDefaultSize)
146 size = pane.min_size;
147 if (size == wxDefaultSize)
148 size = m_paneWindow->GetSize();
149 if (m_ownerMgr && pane.HasGripper())
150 {
151 if (pane.HasGripperTop())
152 size.y += m_ownerMgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE);
153 else
154 size.x += m_ownerMgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE);
155 }
156
157 SetClientSize(size);
158 }
159 }
160
GetOwnerManager() const161 wxAuiManager* wxAuiFloatingFrame::GetOwnerManager() const
162 {
163 return m_ownerMgr;
164 }
165
IsTopNavigationDomain(NavigationKind kind) const166 bool wxAuiFloatingFrame::IsTopNavigationDomain(NavigationKind kind) const
167 {
168 switch ( kind )
169 {
170 case Navigation_Tab:
171 break;
172
173 case Navigation_Accel:
174 // Floating frames are often used as tool palettes and it's
175 // convenient for the accelerators defined in the parent frame to
176 // work in them, so don't block their propagation.
177 return false;
178 }
179
180 return wxAuiFloatingFrameBaseClass::IsTopNavigationDomain(kind);
181 }
182
OnSize(wxSizeEvent & WXUNUSED (event))183 void wxAuiFloatingFrame::OnSize(wxSizeEvent& WXUNUSED(event))
184 {
185 if (m_ownerMgr)
186 {
187 m_ownerMgr->OnFloatingPaneResized(m_paneWindow, GetRect());
188 }
189 }
190
OnClose(wxCloseEvent & evt)191 void wxAuiFloatingFrame::OnClose(wxCloseEvent& evt)
192 {
193 if (m_ownerMgr)
194 {
195 m_ownerMgr->OnFloatingPaneClosed(m_paneWindow, evt);
196 }
197 if (!evt.GetVeto())
198 {
199 m_mgr.DetachPane(m_paneWindow);
200 Destroy();
201 }
202 }
203
OnMoveEvent(wxMoveEvent & event)204 void wxAuiFloatingFrame::OnMoveEvent(wxMoveEvent& event)
205 {
206 if (!m_solidDrag)
207 {
208 // systems without solid window dragging need to be
209 // handled slightly differently, due to the lack of
210 // the constant stream of EVT_MOVING events
211 if (!isMouseDown())
212 return;
213 OnMoveStart();
214 OnMoving(event.GetRect(), wxNORTH);
215 m_moving = true;
216 return;
217 }
218
219
220 wxRect winRect = GetRect();
221
222 if (winRect == m_lastRect)
223 return;
224
225 // skip the first move event
226 if (m_lastRect.IsEmpty())
227 {
228 m_lastRect = winRect;
229 return;
230 }
231
232 // as on OSX moving windows are not getting all move events, only sporadically, this difference
233 // is almost always big on OSX, so avoid this early exit opportunity
234 #ifndef __WXOSX__
235 // skip if moving too fast to avoid massive redraws and
236 // jumping hint windows
237 // TODO: Should 3x3px threshold increase on Retina displays?
238 if ((abs(winRect.x - m_lastRect.x) > 3) ||
239 (abs(winRect.y - m_lastRect.y) > 3))
240 {
241 m_last3Rect = m_last2Rect;
242 m_last2Rect = m_lastRect;
243 m_lastRect = winRect;
244
245 // However still update the internally stored position to avoid
246 // snapping back to the old one later.
247 if (m_ownerMgr)
248 {
249 m_ownerMgr->GetPane(m_paneWindow).
250 floating_pos = winRect.GetPosition();
251 }
252
253 return;
254 }
255 #endif
256
257 // prevent frame redocking during resize
258 if (m_lastRect.GetSize() != winRect.GetSize())
259 {
260 m_last3Rect = m_last2Rect;
261 m_last2Rect = m_lastRect;
262 m_lastRect = winRect;
263 return;
264 }
265
266 wxDirection dir = wxALL;
267
268 int horiz_dist = abs(winRect.x - m_last3Rect.x);
269 int vert_dist = abs(winRect.y - m_last3Rect.y);
270
271 if (vert_dist >= horiz_dist)
272 {
273 if (winRect.y < m_last3Rect.y)
274 dir = wxNORTH;
275 else
276 dir = wxSOUTH;
277 }
278 else
279 {
280 if (winRect.x < m_last3Rect.x)
281 dir = wxWEST;
282 else
283 dir = wxEAST;
284 }
285
286 m_last3Rect = m_last2Rect;
287 m_last2Rect = m_lastRect;
288 m_lastRect = winRect;
289
290 if (!isMouseDown())
291 return;
292
293 if (!m_moving)
294 {
295 OnMoveStart();
296 m_moving = true;
297 }
298
299 if (m_last3Rect.IsEmpty())
300 return;
301
302 if ( event.GetEventType() == wxEVT_MOVING )
303 OnMoving(event.GetRect(), dir);
304 else
305 OnMoving(wxRect(event.GetPosition(),GetSize()), dir);
306 }
307
OnIdle(wxIdleEvent & event)308 void wxAuiFloatingFrame::OnIdle(wxIdleEvent& event)
309 {
310 if (m_moving)
311 {
312 if (!isMouseDown())
313 {
314 m_moving = false;
315 OnMoveFinished();
316 }
317 else
318 {
319 event.RequestMore();
320 }
321 }
322 }
323
OnMoveStart()324 void wxAuiFloatingFrame::OnMoveStart()
325 {
326 // notify the owner manager that the pane has started to move
327 if (m_ownerMgr)
328 {
329 m_ownerMgr->OnFloatingPaneMoveStart(m_paneWindow);
330 }
331 }
332
OnMoving(const wxRect & WXUNUSED (window_rect),wxDirection dir)333 void wxAuiFloatingFrame::OnMoving(const wxRect& WXUNUSED(window_rect), wxDirection dir)
334 {
335 // notify the owner manager that the pane is moving
336 if (m_ownerMgr)
337 {
338 m_ownerMgr->OnFloatingPaneMoving(m_paneWindow, dir);
339 }
340 m_lastDirection = dir;
341 }
342
OnMoveFinished()343 void wxAuiFloatingFrame::OnMoveFinished()
344 {
345 // notify the owner manager that the pane has finished moving
346 if (m_ownerMgr)
347 {
348 m_ownerMgr->OnFloatingPaneMoved(m_paneWindow, m_lastDirection);
349 }
350 }
351
OnActivate(wxActivateEvent & event)352 void wxAuiFloatingFrame::OnActivate(wxActivateEvent& event)
353 {
354 if (m_ownerMgr && event.GetActive())
355 {
356 m_ownerMgr->OnFloatingPaneActivated(m_paneWindow);
357 }
358 }
359
360 // utility function which determines the state of the mouse button
361 // (independent of having a wxMouseEvent handy) - utimately a better
362 // mechanism for this should be found (possibly by adding the
363 // functionality to wxWidgets itself)
isMouseDown()364 bool wxAuiFloatingFrame::isMouseDown()
365 {
366 return wxGetMouseState().LeftIsDown();
367 }
368
369
370 wxBEGIN_EVENT_TABLE(wxAuiFloatingFrame, wxAuiFloatingFrameBaseClass)
371 EVT_SIZE(wxAuiFloatingFrame::OnSize)
372 EVT_MOVE(wxAuiFloatingFrame::OnMoveEvent)
373 EVT_MOVING(wxAuiFloatingFrame::OnMoveEvent)
374 EVT_CLOSE(wxAuiFloatingFrame::OnClose)
375 EVT_IDLE(wxAuiFloatingFrame::OnIdle)
376 EVT_ACTIVATE(wxAuiFloatingFrame::OnActivate)
377 wxEND_EVENT_TABLE()
378
379
380 #endif // wxUSE_AUI
381