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// RCS-ID:      $Id: floatpane.cpp 54904 2008-08-01 16:07:46Z BIW $
8// Copyright:   (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved
9// Licence:     wxWindows Library Licence, Version 3.1
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20#include "wx/wxprec.h"
21
22#ifdef __BORLANDC__
23    #pragma hdrstop
24#endif
25
26#if wxUSE_AUI
27
28#include "wx/aui/framemanager.h"
29#include "wx/aui/floatpane.h"
30#include "wx/aui/dockart.h"
31
32#ifndef WX_PRECOMP
33#endif
34
35#ifdef __WXMSW__
36#include "wx/msw/private.h"
37#endif
38
39IMPLEMENT_CLASS(wxAuiFloatingFrame, wxAuiFloatingFrameBaseClass)
40
41wxAuiFloatingFrame::wxAuiFloatingFrame(wxWindow* parent,
42                wxAuiManager* owner_mgr,
43                const wxAuiPaneInfo& pane,
44                wxWindowID id /*= wxID_ANY*/,
45                long style /*=wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION |
46                              wxFRAME_NO_TASKBAR | wxFRAME_FLOAT_ON_PARENT |
47                              wxCLIP_CHILDREN
48                           */)
49                : wxAuiFloatingFrameBaseClass(parent, id, wxEmptyString,
50                        pane.floating_pos, pane.floating_size,
51                        style |
52                        (pane.HasCloseButton()?wxCLOSE_BOX:0) |
53                        (pane.HasMaximizeButton()?wxMAXIMIZE_BOX:0) |
54                        (pane.IsFixed()?0:wxRESIZE_BORDER)
55                        )
56{
57    m_owner_mgr = owner_mgr;
58    m_moving = false;
59    m_mgr.SetManagedWindow(this);
60    m_solid_drag = true;
61
62    // find out if the system supports solid window drag.
63    // on non-msw systems, this is assumed to be the case
64#ifdef __WXMSW__
65    BOOL b = TRUE;
66    SystemParametersInfo(38 /*SPI_GETDRAGFULLWINDOWS*/, 0, &b, 0);
67    m_solid_drag = b ? true : false;
68#endif
69
70    SetExtraStyle(wxWS_EX_PROCESS_IDLE);
71}
72
73wxAuiFloatingFrame::~wxAuiFloatingFrame()
74{
75    // if we do not do this, then we can crash...
76    if(m_owner_mgr && m_owner_mgr->m_action_window == this)
77    {
78        m_owner_mgr->m_action_window = NULL;
79    }
80    m_mgr.UnInit();
81}
82
83void wxAuiFloatingFrame::SetPaneWindow(const wxAuiPaneInfo& pane)
84{
85    m_pane_window = pane.window;
86    m_pane_window->Reparent(this);
87
88    wxAuiPaneInfo contained_pane = pane;
89    contained_pane.Dock().Center().Show().
90                    CaptionVisible(false).
91                    PaneBorder(false).
92                    Layer(0).Row(0).Position(0);
93
94    // Carry over the minimum size
95    wxSize pane_min_size = pane.window->GetMinSize();
96
97    // if the frame window's max size is greater than the min size
98    // then set the max size to the min size as well
99    wxSize cur_max_size = GetMaxSize();
100    if (cur_max_size.IsFullySpecified() &&
101          (cur_max_size.x < pane.min_size.x ||
102           cur_max_size.y < pane.min_size.y)
103       )
104    {
105        SetMaxSize(pane_min_size);
106    }
107
108    SetMinSize(pane.window->GetMinSize());
109
110    m_mgr.AddPane(m_pane_window, contained_pane);
111    m_mgr.Update();
112
113    if (pane.min_size.IsFullySpecified())
114    {
115        // because SetSizeHints() calls Fit() too (which sets the window
116        // size to its minimum allowed), we keep the size before calling
117        // SetSizeHints() and reset it afterwards...
118        wxSize tmp = GetSize();
119        GetSizer()->SetSizeHints(this);
120        SetSize(tmp);
121    }
122
123    SetTitle(pane.caption);
124
125    if (pane.floating_size != wxDefaultSize)
126    {
127        SetSize(pane.floating_size);
128    }
129        else
130    {
131        wxSize size = pane.best_size;
132        if (size == wxDefaultSize)
133            size = pane.min_size;
134        if (size == wxDefaultSize)
135            size = m_pane_window->GetSize();
136        if (pane.HasGripper())
137        {
138            if (pane.HasGripperTop())
139                size.y += m_owner_mgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE);
140            else
141                size.x += m_owner_mgr->m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE);
142        }
143
144        SetClientSize(size);
145    }
146
147    if (pane.IsFixed())
148    {
149        SetWindowStyleFlag(GetWindowStyleFlag() & ~wxRESIZE_BORDER);
150    }
151}
152
153wxAuiManager* wxAuiFloatingFrame::GetOwnerManager() const
154{
155    return m_owner_mgr;
156}
157
158
159void wxAuiFloatingFrame::OnSize(wxSizeEvent& event)
160{
161    m_owner_mgr->OnFloatingPaneResized(m_pane_window, event.GetSize());
162}
163
164void wxAuiFloatingFrame::OnClose(wxCloseEvent& evt)
165{
166    m_owner_mgr->OnFloatingPaneClosed(m_pane_window, evt);
167    if (!evt.GetVeto()) {
168	m_mgr.DetachPane(m_pane_window);
169        Destroy();
170    }
171}
172
173void wxAuiFloatingFrame::OnMoveEvent(wxMoveEvent& event)
174{
175    if (!m_solid_drag)
176    {
177        // systems without solid window dragging need to be
178        // handled slightly differently, due to the lack of
179        // the constant stream of EVT_MOVING events
180        if (!isMouseDown())
181            return;
182        OnMoveStart();
183        OnMoving(event.GetRect(), wxNORTH);
184        m_moving = true;
185        return;
186    }
187
188
189    wxRect win_rect = GetRect();
190
191    if (win_rect == m_last_rect)
192        return;
193
194    // skip the first move event
195    if (m_last_rect.IsEmpty())
196    {
197        m_last_rect = win_rect;
198        return;
199    }
200
201    // skip if moving too fast to avoid massive redraws and
202    // jumping hint windows
203    if ((abs(win_rect.x - m_last_rect.x) > 3) ||
204        (abs(win_rect.y - m_last_rect.y) > 3))
205    {
206        m_last3_rect = m_last2_rect;
207        m_last2_rect = m_last_rect;
208        m_last_rect = win_rect;
209        return;
210    }
211
212    // prevent frame redocking during resize
213    if (m_last_rect.GetSize() != win_rect.GetSize())
214    {
215        m_last3_rect = m_last2_rect;
216        m_last2_rect = m_last_rect;
217        m_last_rect = win_rect;
218        return;
219    }
220
221    wxDirection dir = wxALL;
222
223    int horiz_dist = abs(win_rect.x - m_last3_rect.x);
224    int vert_dist = abs(win_rect.y - m_last3_rect.y);
225
226    if (vert_dist >= horiz_dist)
227    {
228        if (win_rect.y < m_last3_rect.y)
229            dir = wxNORTH;
230        else
231            dir = wxSOUTH;
232    }
233    else
234    {
235        if (win_rect.x < m_last3_rect.x)
236            dir = wxWEST;
237        else
238            dir = wxEAST;
239    }
240
241    m_last3_rect = m_last2_rect;
242    m_last2_rect = m_last_rect;
243    m_last_rect = win_rect;
244
245    if (!isMouseDown())
246        return;
247
248    if (!m_moving)
249    {
250        OnMoveStart();
251        m_moving = true;
252    }
253
254    if (m_last3_rect.IsEmpty())
255        return;
256
257    OnMoving(event.GetRect(), dir);
258}
259
260void wxAuiFloatingFrame::OnIdle(wxIdleEvent& event)
261{
262    if (m_moving)
263    {
264        if (!isMouseDown())
265        {
266            m_moving = false;
267            OnMoveFinished();
268        }
269         else
270        {
271            event.RequestMore();
272        }
273    }
274}
275
276void wxAuiFloatingFrame::OnMoveStart()
277{
278    // notify the owner manager that the pane has started to move
279    m_owner_mgr->OnFloatingPaneMoveStart(m_pane_window);
280}
281
282void wxAuiFloatingFrame::OnMoving(const wxRect& WXUNUSED(window_rect), wxDirection dir)
283{
284    // notify the owner manager that the pane is moving
285    m_owner_mgr->OnFloatingPaneMoving(m_pane_window, dir);
286    m_lastDirection = dir;
287}
288
289void wxAuiFloatingFrame::OnMoveFinished()
290{
291    // notify the owner manager that the pane has finished moving
292    m_owner_mgr->OnFloatingPaneMoved(m_pane_window, m_lastDirection);
293}
294
295void wxAuiFloatingFrame::OnActivate(wxActivateEvent& event)
296{
297    if (event.GetActive())
298    {
299        m_owner_mgr->OnFloatingPaneActivated(m_pane_window);
300    }
301}
302
303// utility function which determines the state of the mouse button
304// (independant of having a wxMouseEvent handy) - utimately a better
305// mechanism for this should be found (possibly by adding the
306// functionality to wxWidgets itself)
307bool wxAuiFloatingFrame::isMouseDown()
308{
309    return wxGetMouseState().LeftDown();
310}
311
312
313BEGIN_EVENT_TABLE(wxAuiFloatingFrame, wxAuiFloatingFrameBaseClass)
314    EVT_SIZE(wxAuiFloatingFrame::OnSize)
315    EVT_MOVE(wxAuiFloatingFrame::OnMoveEvent)
316    EVT_MOVING(wxAuiFloatingFrame::OnMoveEvent)
317    EVT_CLOSE(wxAuiFloatingFrame::OnClose)
318    EVT_IDLE(wxAuiFloatingFrame::OnIdle)
319    EVT_ACTIVATE(wxAuiFloatingFrame::OnActivate)
320END_EVENT_TABLE()
321
322
323#endif // wxUSE_AUI
324