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