X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2f68106fa056bbbba9bd370161e9e72397803bf0..6a3f00bd6660d0326904d774d6e7a48a13af1f6f:/src/aui/framemanager.cpp diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 3079df6dba..7526cf6938 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -28,15 +28,19 @@ #include "wx/aui/framemanager.h" #include "wx/aui/dockart.h" #include "wx/aui/floatpane.h" +#include "wx/aui/tabmdi.h" +#include "wx/aui/auibar.h" +#include "wx/mdi.h" #ifndef WX_PRECOMP + #include "wx/panel.h" #include "wx/settings.h" #include "wx/app.h" #include "wx/dcclient.h" #include "wx/dcscreen.h" #include "wx/toolbar.h" - #include "wx/mdi.h" #include "wx/image.h" + #include "wx/statusbr.h" #endif WX_CHECK_BUILD_OPTIONS("wxAUI") @@ -44,25 +48,256 @@ WX_CHECK_BUILD_OPTIONS("wxAUI") #include "wx/arrimpl.cpp" WX_DECLARE_OBJARRAY(wxRect, wxAuiRectArray); WX_DEFINE_OBJARRAY(wxAuiRectArray) -WX_DEFINE_OBJARRAY(wxDockUIPartArray) -WX_DEFINE_OBJARRAY(wxDockInfoArray) -WX_DEFINE_OBJARRAY(wxPaneButtonArray) -WX_DEFINE_OBJARRAY(wxPaneInfoArray) - -wxPaneInfo wxNullPaneInfo; -wxDockInfo wxNullDockInfo; -DEFINE_EVENT_TYPE(wxEVT_AUI_PANEBUTTON) -DEFINE_EVENT_TYPE(wxEVT_AUI_PANECLOSE) -DEFINE_EVENT_TYPE(wxEVT_AUI_RENDER) +WX_DEFINE_OBJARRAY(wxAuiDockUIPartArray) +WX_DEFINE_OBJARRAY(wxAuiDockInfoArray) +WX_DEFINE_OBJARRAY(wxAuiPaneButtonArray) +WX_DEFINE_OBJARRAY(wxAuiPaneInfoArray) + +wxAuiPaneInfo wxAuiNullPaneInfo; +wxAuiDockInfo wxAuiNullDockInfo; +wxDEFINE_EVENT( wxEVT_AUI_PANE_BUTTON, wxAuiManagerEvent ); +wxDEFINE_EVENT( wxEVT_AUI_PANE_CLOSE, wxAuiManagerEvent ); +wxDEFINE_EVENT( wxEVT_AUI_PANE_MAXIMIZE, wxAuiManagerEvent ); +wxDEFINE_EVENT( wxEVT_AUI_PANE_RESTORE, wxAuiManagerEvent ); +wxDEFINE_EVENT( wxEVT_AUI_PANE_ACTIVATED, wxAuiManagerEvent ); +wxDEFINE_EVENT( wxEVT_AUI_RENDER, wxAuiManagerEvent ); +wxDEFINE_EVENT( wxEVT_AUI_FIND_MANAGER, wxAuiManagerEvent ); #ifdef __WXMAC__ // a few defines to avoid nameclashes #define __MAC_OS_X_MEMORY_MANAGER_CLEAN__ 1 #define __AIFF__ - #include "wx/mac/private.h" + #include "wx/osx/private.h" +#endif + +#ifdef __WXMSW__ + #include "wx/msw/wrapwin.h" + #include "wx/msw/private.h" + #include "wx/msw/dc.h" +#endif + +IMPLEMENT_DYNAMIC_CLASS(wxAuiManagerEvent, wxEvent) +IMPLEMENT_CLASS(wxAuiManager, wxEvtHandler) + + + +const int auiToolBarLayer = 10; + +#ifndef __WXGTK20__ + + +class wxPseudoTransparentFrame : public wxFrame +{ +public: + wxPseudoTransparentFrame(wxWindow* parent = NULL, + wxWindowID id = wxID_ANY, + const wxString& title = wxEmptyString, + const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, + long style = wxDEFAULT_FRAME_STYLE, + const wxString &name = wxT("frame")) + : wxFrame(parent, id, title, pos, size, style | wxFRAME_SHAPED, name) + { + SetBackgroundStyle(wxBG_STYLE_CUSTOM); + m_amount=0; + m_maxWidth=0; + m_maxHeight=0; + m_lastWidth=0; + m_lastHeight=0; +#ifdef __WXGTK__ + m_canSetShape = false; // have to wait for window create event on GTK +#else + m_canSetShape = true; +#endif + m_region = wxRegion(0, 0, 0, 0); + SetTransparent(0); + } + + virtual bool SetTransparent(wxByte alpha) + { + if (m_canSetShape) + { + int w=100; // some defaults + int h=100; + GetClientSize(&w, &h); + + m_maxWidth = w; + m_maxHeight = h; + m_amount = alpha; + m_region.Clear(); +// m_region.Union(0, 0, 1, m_maxWidth); + if (m_amount) + { + for (int y=0; y +#include "wx/gtk/private/gtk2-compat.h" + +static void +gtk_pseudo_window_realized_callback( GtkWidget *m_widget, void *WXUNUSED(win) ) +{ + wxSize disp = wxGetDisplaySize(); + int amount = 128; + wxRegion region; + for (int y=0; yAddChild(this); + + g_signal_connect( m_widget, "realize", + G_CALLBACK (gtk_pseudo_window_realized_callback), this ); + + GdkColor col; + col.red = 128 * 256; + col.green = 192 * 256; + col.blue = 255 * 256; + gtk_widget_modify_bg( m_widget, GTK_STATE_NORMAL, &col ); + } + + bool SetTransparent(wxByte WXUNUSED(alpha)) + { + return true; + } + +protected: + virtual void DoSetSizeHints( int minW, int minH, + int maxW, int maxH, + int incW, int incH) + { + // the real wxFrame method doesn't work for us because we're not really + // a top level window so skip it + wxWindow::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH); + } + +private: + DECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame) +}; + +IMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame) + #endif + // __WXGTK20__ -IMPLEMENT_DYNAMIC_CLASS(wxFrameManagerEvent, wxEvent) // -- static utility functions -- @@ -79,30 +314,35 @@ static void DrawResizeHint(wxDC& dc, const wxRect& rect) wxBitmap stipple = wxPaneCreateStippleBitmap(); wxBrush brush(stipple); dc.SetBrush(brush); +#ifdef __WXMSW__ + wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl(); + PatBlt(GetHdcOf(*impl), rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight(), PATINVERT); +#else dc.SetPen(*wxTRANSPARENT_PEN); dc.SetLogicalFunction(wxXOR); dc.DrawRectangle(rect); +#endif } // CopyDocksAndPanes() - this utility function creates copies of -// the dock and pane info. wxDockInfo's usually contain pointers -// to wxPaneInfo classes, thus this function is necessary to reliably +// the dock and pane info. wxAuiDockInfo's usually contain pointers +// to wxAuiPaneInfo classes, thus this function is necessary to reliably // reconstruct that relationship in the new dock info and pane info arrays -static void CopyDocksAndPanes(wxDockInfoArray& dest_docks, - wxPaneInfoArray& dest_panes, - const wxDockInfoArray& src_docks, - const wxPaneInfoArray& src_panes) +static void CopyDocksAndPanes(wxAuiDockInfoArray& dest_docks, + wxAuiPaneInfoArray& dest_panes, + const wxAuiDockInfoArray& src_docks, + const wxAuiPaneInfoArray& src_panes) { dest_docks = src_docks; dest_panes = src_panes; int i, j, k, dock_count, pc1, pc2; for (i = 0, dock_count = dest_docks.GetCount(); i < dock_count; ++i) { - wxDockInfo& dock = dest_docks.Item(i); + wxAuiDockInfo& dock = dest_docks.Item(i); for (j = 0, pc1 = dock.panes.GetCount(); j < pc1; ++j) for (k = 0, pc2 = src_panes.GetCount(); k < pc2; ++k) if (dock.panes.Item(j) == &src_panes.Item(k)) @@ -112,12 +352,13 @@ static void CopyDocksAndPanes(wxDockInfoArray& dest_docks, // GetMaxLayer() is an internal function which returns // the highest layer inside the specified dock -static int GetMaxLayer(const wxDockInfoArray& docks, int dock_direction) +static int GetMaxLayer(const wxAuiDockInfoArray& docks, + int dock_direction) { int i, dock_count, max_layer = 0; for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) { - wxDockInfo& dock = docks.Item(i); + wxAuiDockInfo& dock = docks.Item(i); if (dock.dock_direction == dock_direction && dock.dock_layer > max_layer && !dock.fixed) max_layer = dock.dock_layer; @@ -128,12 +369,12 @@ static int GetMaxLayer(const wxDockInfoArray& docks, int dock_direction) // GetMaxRow() is an internal function which returns // the highest layer inside the specified dock -static int GetMaxRow(const wxPaneInfoArray& panes, int direction, int layer) +static int GetMaxRow(const wxAuiPaneInfoArray& panes, int direction, int layer) { int i, pane_count, max_row = 0; for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& pane = panes.Item(i); + wxAuiPaneInfo& pane = panes.Item(i); if (pane.dock_direction == direction && pane.dock_layer == layer && pane.dock_row > max_row) @@ -146,14 +387,14 @@ static int GetMaxRow(const wxPaneInfoArray& panes, int direction, int layer) // DoInsertDockLayer() is an internal function that inserts a new dock // layer by incrementing all existing dock layer values by one -static void DoInsertDockLayer(wxPaneInfoArray& panes, +static void DoInsertDockLayer(wxAuiPaneInfoArray& panes, int dock_direction, int dock_layer) { int i, pane_count; for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& pane = panes.Item(i); + wxAuiPaneInfo& pane = panes.Item(i); if (!pane.IsFloating() && pane.dock_direction == dock_direction && pane.dock_layer >= dock_layer) @@ -163,7 +404,7 @@ static void DoInsertDockLayer(wxPaneInfoArray& panes, // DoInsertDockLayer() is an internal function that inserts a new dock // row by incrementing all existing dock row values by one -static void DoInsertDockRow(wxPaneInfoArray& panes, +static void DoInsertDockRow(wxAuiPaneInfoArray& panes, int dock_direction, int dock_layer, int dock_row) @@ -171,7 +412,7 @@ static void DoInsertDockRow(wxPaneInfoArray& panes, int i, pane_count; for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& pane = panes.Item(i); + wxAuiPaneInfo& pane = panes.Item(i); if (!pane.IsFloating() && pane.dock_direction == dock_direction && pane.dock_layer == dock_layer && @@ -182,7 +423,7 @@ static void DoInsertDockRow(wxPaneInfoArray& panes, // DoInsertDockLayer() is an internal function that inserts a space for // another dock pane by incrementing all existing dock row values by one -static void DoInsertPane(wxPaneInfoArray& panes, +static void DoInsertPane(wxAuiPaneInfoArray& panes, int dock_direction, int dock_layer, int dock_row, @@ -191,7 +432,7 @@ static void DoInsertPane(wxPaneInfoArray& panes, int i, pane_count; for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& pane = panes.Item(i); + wxAuiPaneInfo& pane = panes.Item(i); if (!pane.IsFloating() && pane.dock_direction == dock_direction && pane.dock_layer == dock_layer && @@ -204,11 +445,11 @@ static void DoInsertPane(wxPaneInfoArray& panes, // FindDocks() is an internal function that returns a list of docks which meet // the specified conditions in the parameters and returns a sorted array // (sorted by layer and then row) -static void FindDocks(wxDockInfoArray& docks, +static void FindDocks(wxAuiDockInfoArray& docks, int dock_direction, int dock_layer, int dock_row, - wxDockInfoPtrArray& arr) + wxAuiDockInfoPtrArray& arr) { int begin_layer = dock_layer; int end_layer = dock_layer; @@ -244,7 +485,7 @@ static void FindDocks(wxDockInfoArray& docks, for (row = begin_row; row <= end_row; ++row) for (i = 0; i < dock_count; ++i) { - wxDockInfo& d = docks.Item(i); + wxAuiDockInfo& d = docks.Item(i); if (dock_direction == -1 || dock_direction == d.dock_direction) { if (d.dock_layer == layer && d.dock_row == row) @@ -254,13 +495,13 @@ static void FindDocks(wxDockInfoArray& docks, } // FindPaneInDock() looks up a specified window pointer inside a dock. -// If found, the corresponding wxPaneInfo pointer is returned, otherwise NULL. -static wxPaneInfo* FindPaneInDock(const wxDockInfo& dock, wxWindow* window) +// If found, the corresponding wxAuiPaneInfo pointer is returned, otherwise NULL. +static wxAuiPaneInfo* FindPaneInDock(const wxAuiDockInfo& dock, wxWindow* window) { int i, count = dock.panes.GetCount(); for (i = 0; i < count; ++i) { - wxPaneInfo* p = dock.panes.Item(i); + wxAuiPaneInfo* p = dock.panes.Item(i); if (p->window == window) return p; } @@ -268,89 +509,126 @@ static wxPaneInfo* FindPaneInDock(const wxDockInfo& dock, wxWindow* window) } // RemovePaneFromDocks() removes a pane window from all docks -// with a possible exception specified by parameter "except" -static void RemovePaneFromDocks(wxDockInfoArray& docks, - wxPaneInfo& pane, - wxDockInfo* except = NULL) +// with a possible exception specified by parameter "ex_cept" +static void RemovePaneFromDocks(wxAuiDockInfoArray& docks, + wxAuiPaneInfo& pane, + wxAuiDockInfo* ex_cept = NULL ) { int i, dock_count; for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) { - wxDockInfo& d = docks.Item(i); - if (&d == except) + wxAuiDockInfo& d = docks.Item(i); + if (&d == ex_cept) continue; - wxPaneInfo* pi = FindPaneInDock(d, pane.window); + wxAuiPaneInfo* pi = FindPaneInDock(d, pane.window); if (pi) d.panes.Remove(pi); } } +/* +// This function works fine, and may be used in the future + // RenumberDockRows() takes a dock and assigns sequential numbers // to existing rows. Basically it takes out the gaps; so if a // dock has rows with numbers 0,2,5, they will become 0,1,2 -static void RenumberDockRows(wxDockInfoPtrArray& docks) +static void RenumberDockRows(wxAuiDockInfoPtrArray& docks) { - int i, dock_count, j, pane_count; + int i, dock_count; for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) { - wxDockInfo& dock = *docks.Item(i); + wxAuiDockInfo& dock = *docks.Item(i); dock.dock_row = i; + + int j, pane_count; for (j = 0, pane_count = dock.panes.GetCount(); j < pane_count; ++j) dock.panes.Item(j)->dock_row = i; } } +*/ // SetActivePane() sets the active pane, as well as cycles through // every other pane and makes sure that all others' active flags // are turned off -static void SetActivePane(wxPaneInfoArray& panes, wxWindow* active_pane) +void wxAuiManager::SetActivePane(wxWindow* active_pane) { int i, pane_count; - for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) + wxAuiPaneInfo* active_paneinfo = NULL; + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& pane = panes.Item(i); - pane.state &= ~wxPaneInfo::optionActive; + wxAuiPaneInfo& pane = m_panes.Item(i); + pane.state &= ~wxAuiPaneInfo::optionActive; if (pane.window == active_pane) - pane.state |= wxPaneInfo::optionActive; + { + pane.state |= wxAuiPaneInfo::optionActive; + active_paneinfo = &pane; + } + } + + // send the 'activated' event after all panes have been updated + if ( active_paneinfo ) + { + wxAuiManagerEvent evt(wxEVT_AUI_PANE_ACTIVATED); + evt.SetManager(this); + evt.SetPane(active_paneinfo); + ProcessMgrEvent(evt); } } // this function is used to sort panes by dock position -static int PaneSortFunc(wxPaneInfo** p1, wxPaneInfo** p2) +static int PaneSortFunc(wxAuiPaneInfo** p1, wxAuiPaneInfo** p2) { return ((*p1)->dock_pos < (*p2)->dock_pos) ? -1 : 1; } -// -- wxFrameManager class implementation -- - +bool wxAuiPaneInfo::IsValid() const +{ + // Should this RTTI and function call be rewritten as + // sending a new event type to allow other window types + // to check the pane settings? + wxAuiToolBar* toolbar = wxDynamicCast(window, wxAuiToolBar); + return !toolbar || toolbar->IsPaneValid(*this); +} -BEGIN_EVENT_TABLE(wxFrameManager, wxEvtHandler) - EVT_AUI_PANEBUTTON(wxFrameManager::OnPaneButton) - EVT_AUI_RENDER(wxFrameManager::OnRender) - EVT_PAINT(wxFrameManager::OnPaint) - EVT_ERASE_BACKGROUND(wxFrameManager::OnEraseBackground) - EVT_SIZE(wxFrameManager::OnSize) - EVT_SET_CURSOR(wxFrameManager::OnSetCursor) - EVT_LEFT_DOWN(wxFrameManager::OnLeftDown) - EVT_LEFT_UP(wxFrameManager::OnLeftUp) - EVT_MOTION(wxFrameManager::OnMotion) - EVT_LEAVE_WINDOW(wxFrameManager::OnLeaveWindow) - EVT_CHILD_FOCUS(wxFrameManager::OnChildFocus) - EVT_TIMER(101, wxFrameManager::OnHintFadeTimer) +// -- wxAuiManager class implementation -- + + +BEGIN_EVENT_TABLE(wxAuiManager, wxEvtHandler) + EVT_AUI_PANE_BUTTON(wxAuiManager::OnPaneButton) + EVT_AUI_RENDER(wxAuiManager::OnRender) + EVT_PAINT(wxAuiManager::OnPaint) + EVT_ERASE_BACKGROUND(wxAuiManager::OnEraseBackground) + EVT_SIZE(wxAuiManager::OnSize) + EVT_SET_CURSOR(wxAuiManager::OnSetCursor) + EVT_LEFT_DOWN(wxAuiManager::OnLeftDown) + EVT_LEFT_UP(wxAuiManager::OnLeftUp) + EVT_MOTION(wxAuiManager::OnMotion) + EVT_LEAVE_WINDOW(wxAuiManager::OnLeaveWindow) + EVT_MOUSE_CAPTURE_LOST(wxAuiManager::OnCaptureLost) + EVT_CHILD_FOCUS(wxAuiManager::OnChildFocus) + EVT_AUI_FIND_MANAGER(wxAuiManager::OnFindManager) END_EVENT_TABLE() -wxFrameManager::wxFrameManager(wxWindow* managed_wnd, unsigned int flags) +wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags) { m_action = actionNone; - m_last_mouse_move = wxPoint(); - m_hover_button = NULL; - m_art = new wxDefaultDockArt; - m_hint_wnd = NULL; + m_actionWindow = NULL; + m_lastMouseMove = wxPoint(); + m_hoverButton = NULL; + m_art = new wxAuiDefaultDockArt; + m_hintWnd = NULL; m_flags = flags; + m_skipping = false; + m_hasMaximized = false; + m_frame = NULL; + m_dockConstraintX = 0.3; + m_dockConstraintY = 0.3; + m_reserved = NULL; + m_currentDragItem = -1; if (managed_wnd) { @@ -358,48 +636,75 @@ wxFrameManager::wxFrameManager(wxWindow* managed_wnd, unsigned int flags) } } -wxFrameManager::~wxFrameManager() +wxAuiManager::~wxAuiManager() { + // NOTE: It's possible that the windows have already been destroyed by the + // time this dtor is called, so this loop can result in memory access via + // invalid pointers, resulting in a crash. So it will be disabled while + // waiting for a better solution. +#if 0 + for ( size_t i = 0; i < m_panes.size(); i++ ) + { + wxAuiPaneInfo& pinfo = m_panes[i]; + if (pinfo.window && !pinfo.window->GetParent()) + delete pinfo.window; + } +#endif + delete m_art; } -// GetPane() looks up a wxPaneInfo structure based +// creates a floating frame for the windows +wxAuiFloatingFrame* wxAuiManager::CreateFloatingFrame(wxWindow* parent, + const wxAuiPaneInfo& paneInfo) +{ + return new wxAuiFloatingFrame(parent, this, paneInfo); +} + +bool wxAuiManager::CanDockPanel(const wxAuiPaneInfo & WXUNUSED(p)) +{ + // if a key modifier is pressed while dragging the frame, + // don't dock the window + return !(wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT)); +} + +// GetPane() looks up a wxAuiPaneInfo structure based // on the supplied window pointer. Upon failure, GetPane() -// returns an empty wxPaneInfo, a condition which can be checked -// by calling wxPaneInfo::IsOk(). +// returns an empty wxAuiPaneInfo, a condition which can be checked +// by calling wxAuiPaneInfo::IsOk(). // // The pane info's structure may then be modified. Once a pane's -// info is modified, wxFrameManager::Update() must be called to +// info is modified, wxAuiManager::Update() must be called to // realize the changes in the UI. -wxPaneInfo& wxFrameManager::GetPane(wxWindow* window) +wxAuiPaneInfo& wxAuiManager::GetPane(wxWindow* window) { int i, pane_count; for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (p.window == window) return p; } - return wxNullPaneInfo; + return wxAuiNullPaneInfo; } // this version of GetPane() looks up a pane based on a // 'pane name', see above comment for more info -wxPaneInfo& wxFrameManager::GetPane(const wxString& name) +wxAuiPaneInfo& wxAuiManager::GetPane(const wxString& name) { int i, pane_count; for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (p.name == name) return p; } - return wxNullPaneInfo; + return wxAuiNullPaneInfo; } // GetAllPanes() returns a reference to all the pane info structures -wxPaneInfoArray& wxFrameManager::GetAllPanes() +wxAuiPaneInfoArray& wxAuiManager::GetAllPanes() { return m_panes; } @@ -407,31 +712,31 @@ wxPaneInfoArray& wxFrameManager::GetAllPanes() // HitTest() is an internal function which determines // which UI item the specified coordinates are over // (x,y) specify a position in client coordinates -wxDockUIPart* wxFrameManager::HitTest(int x, int y) +wxAuiDockUIPart* wxAuiManager::HitTest(int x, int y) { - wxDockUIPart* result = NULL; + wxAuiDockUIPart* result = NULL; int i, part_count; - for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i) { - wxDockUIPart* item = &m_uiparts.Item(i); + wxAuiDockUIPart* item = &m_uiParts.Item(i); // we are not interested in typeDock, because this space // isn't used to draw anything, just for measurements; // besides, the entire dock area is covered with other // rectangles, which we are interested in. - if (item->type == wxDockUIPart::typeDock) + if (item->type == wxAuiDockUIPart::typeDock) continue; // if we already have a hit on a more specific item, we are not // interested in a pane hit. If, however, we don't already have // a hit, returning a pane hit is necessary for some operations - if ((item->type == wxDockUIPart::typePane || - item->type == wxDockUIPart::typePaneBorder) && result) + if ((item->type == wxAuiDockUIPart::typePane || + item->type == wxAuiDockUIPart::typePaneBorder) && result) continue; // if the point is inside the rectangle, we have a hit - if (item->rect.Inside(x,y)) + if (item->rect.Contains(x,y)) result = item; } @@ -440,41 +745,167 @@ wxDockUIPart* wxFrameManager::HitTest(int x, int y) // SetFlags() and GetFlags() allow the owner to set various -// options which are global to wxFrameManager -void wxFrameManager::SetFlags(unsigned int flags) +// options which are global to wxAuiManager +void wxAuiManager::SetFlags(unsigned int flags) { + // find out if we have to call UpdateHintWindowConfig() + bool update_hint_wnd = false; + unsigned int hint_mask = wxAUI_MGR_TRANSPARENT_HINT | + wxAUI_MGR_VENETIAN_BLINDS_HINT | + wxAUI_MGR_RECTANGLE_HINT; + if ((flags & hint_mask) != (m_flags & hint_mask)) + update_hint_wnd = true; + + + // set the new flags m_flags = flags; + + if (update_hint_wnd) + { + UpdateHintWindowConfig(); + } } -unsigned int wxFrameManager::GetFlags() const +unsigned int wxAuiManager::GetFlags() const { return m_flags; } +// Convenience function +bool wxAuiManager_HasLiveResize(wxAuiManager& manager) +{ + // With Core Graphics on Mac, it's not possible to show sash feedback, + // so we'll always use live update instead. +#if defined(__WXMAC__) + wxUnusedVar(manager); + return true; +#else + return (manager.GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE; +#endif +} // don't use these anymore as they are deprecated // use Set/GetManagedFrame() instead -void wxFrameManager::SetFrame(wxFrame* frame) +void wxAuiManager::SetFrame(wxFrame* frame) { SetManagedWindow((wxWindow*)frame); } -wxFrame* wxFrameManager::GetFrame() const +wxFrame* wxAuiManager::GetFrame() const { return (wxFrame*)m_frame; } +// this function will return the aui manager for a given +// window. The |window| parameter should be any child window +// or grand-child window (and so on) of the frame/window +// managed by wxAuiManager. The |window| parameter does not +// need to be managed by the manager itself. +wxAuiManager* wxAuiManager::GetManager(wxWindow* window) +{ + wxAuiManagerEvent evt(wxEVT_AUI_FIND_MANAGER); + evt.SetManager(NULL); + evt.ResumePropagation(wxEVENT_PROPAGATE_MAX); + if (!window->GetEventHandler()->ProcessEvent(evt)) + return NULL; + + return evt.GetManager(); +} + + +void wxAuiManager::UpdateHintWindowConfig() +{ + // find out if the system can do transparent frames + bool can_do_transparent = false; + + wxWindow* w = m_frame; + while (w) + { + if (wxDynamicCast(w, wxFrame)) + { + wxFrame* f = static_cast(w); + can_do_transparent = f->CanSetTransparent(); + + break; + } + + w = w->GetParent(); + } + + // if there is an existing hint window, delete it + if (m_hintWnd) + { + m_hintWnd->Destroy(); + m_hintWnd = NULL; + } + + m_hintFadeMax = 50; + m_hintWnd = NULL; + + if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent) + { + // Make a window to use for a transparent hint + #if defined(__WXMSW__) || defined(__WXGTK__) + m_hintWnd = new wxFrame(m_frame, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxSize(1,1), + wxFRAME_TOOL_WINDOW | + wxFRAME_FLOAT_ON_PARENT | + wxFRAME_NO_TASKBAR | + wxNO_BORDER); + + m_hintWnd->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION)); + #elif defined(__WXMAC__) + // Using a miniframe with float and tool styles keeps the parent + // frame activated and highlighted as such... + m_hintWnd = new wxMiniFrame(m_frame, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxSize(1,1), + wxFRAME_FLOAT_ON_PARENT + | wxFRAME_TOOL_WINDOW ); + m_hintWnd->Connect(wxEVT_ACTIVATE, + wxActivateEventHandler(wxAuiManager::OnHintActivate), NULL, this); + + // Can't set the bg colour of a Frame in wxMac + wxPanel* p = new wxPanel(m_hintWnd); + + // The default wxSYS_COLOUR_ACTIVECAPTION colour is a light silver + // color that is really hard to see, especially transparent. + // Until a better system color is decided upon we'll just use + // blue. + p->SetBackgroundColour(*wxBLUE); + #endif + + } + else + { + if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) != 0 || + (m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) != 0) + { + // system can't support transparent fade, or the venetian + // blinds effect was explicitly requested + m_hintWnd = new wxPseudoTransparentFrame(m_frame, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(1,1), + wxFRAME_TOOL_WINDOW | + wxFRAME_FLOAT_ON_PARENT | + wxFRAME_NO_TASKBAR | + wxNO_BORDER); + m_hintFadeMax = 128; + } + } +} // SetManagedWindow() is usually called once when the frame // manager class is being initialized. "frame" specifies // the frame which should be managed by the frame mananger -void wxFrameManager::SetManagedWindow(wxWindow* frame) +void wxAuiManager::SetManagedWindow(wxWindow* wnd) { - wxASSERT_MSG(frame, wxT("specified frame must be non-NULL")); + wxASSERT_MSG(wnd, wxT("specified window must be non-NULL")); - m_frame = frame; + m_frame = wnd; m_frame->PushEventHandler(this); #if wxUSE_MDI @@ -482,92 +913,74 @@ void wxFrameManager::SetManagedWindow(wxWindow* frame) // we need to add the MDI client window as the default // center pane - if (frame->IsKindOf(CLASSINFO(wxMDIParentFrame))) + if (wxDynamicCast(m_frame, wxMDIParentFrame)) { - wxMDIParentFrame* mdi_frame = (wxMDIParentFrame*)frame; + wxMDIParentFrame* mdi_frame = (wxMDIParentFrame*)m_frame; wxWindow* client_window = mdi_frame->GetClientWindow(); wxASSERT_MSG(client_window, wxT("Client window is NULL!")); AddPane(client_window, - wxPaneInfo().Name(wxT("mdiclient")). + wxAuiPaneInfo().Name(wxT("mdiclient")). + CenterPane().PaneBorder(false)); + } + else if (wxDynamicCast(m_frame, wxAuiMDIParentFrame)) + { + wxAuiMDIParentFrame* mdi_frame = (wxAuiMDIParentFrame*)m_frame; + wxAuiMDIClientWindow* client_window = mdi_frame->GetClientWindow(); + wxASSERT_MSG(client_window, wxT("Client window is NULL!")); + + AddPane(client_window, + wxAuiPaneInfo().Name(wxT("mdiclient")). CenterPane().PaneBorder(false)); } -#endif - // Make a window to use for a translucent hint -#if defined(__WXMSW__) - m_hint_wnd = new wxFrame(m_frame, -1, wxEmptyString, wxDefaultPosition, wxSize(1,1), - wxFRAME_TOOL_WINDOW | - wxFRAME_FLOAT_ON_PARENT | - wxFRAME_NO_TASKBAR | - wxNO_BORDER); - - m_hint_wnd->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION)); - -#elif defined(__WXMAC__) - // Using a miniframe with float and tool styles keeps the parent - // frame activated and highlighted as such... - m_hint_wnd = new wxMiniFrame(m_frame, -1, wxEmptyString, wxDefaultPosition, wxSize(1,1), - wxFRAME_FLOAT_ON_PARENT - | wxFRAME_TOOL_WINDOW - | wxCAPTION ); - - // Can't set the bg colour of a Frame in wxMac - wxPanel* p = new wxPanel(m_hint_wnd); - - // The default wxSYS_COLOUR_ACTIVECAPTION colour is a light silver - // color that is really hard to see, especially transparent. - // Until a better system color is decided upon we'll just use - // blue. - p->SetBackgroundColour(*wxBLUE); #endif - if (m_hint_wnd && !m_hint_wnd->CanSetTranslucency()) - { - m_hint_wnd->Close(); - m_hint_wnd = NULL; - } + UpdateHintWindowConfig(); } // UnInit() must be called, usually in the destructor // of the frame class. If it is not called, usually this // will result in a crash upon program exit -void wxFrameManager::UnInit() +void wxAuiManager::UnInit() { - m_frame->RemoveEventHandler(this); + if (m_frame) + { + m_frame->RemoveEventHandler(this); + } } // GetManagedWindow() returns the window pointer being managed -wxWindow* wxFrameManager::GetManagedWindow() const +wxWindow* wxAuiManager::GetManagedWindow() const { return m_frame; } -wxDockArt* wxFrameManager::GetArtProvider() const +wxAuiDockArt* wxAuiManager::GetArtProvider() const { return m_art; } -void wxFrameManager::ProcessMgrEvent(wxFrameManagerEvent& event) +void wxAuiManager::ProcessMgrEvent(wxAuiManagerEvent& event) { // first, give the owner frame a chance to override if (m_frame) { - if (m_frame->ProcessEvent(event)) + if (m_frame->GetEventHandler()->ProcessEvent(event)) return; } ProcessEvent(event); } -// SetArtProvider() instructs wxFrameManager to use the +// SetArtProvider() instructs wxAuiManager to use the // specified art provider for all drawing calls. This allows // plugable look-and-feel features. The pointer that is -// passed to this method subsequently belongs to wxFrameManager, +// passed to this method subsequently belongs to wxAuiManager, // and is deleted in the frame manager destructor -void wxFrameManager::SetArtProvider(wxDockArt* art_provider) +void wxAuiManager::SetArtProvider(wxAuiDockArt* art_provider) { // delete the last art provider, if any delete m_art; @@ -577,28 +990,77 @@ void wxFrameManager::SetArtProvider(wxDockArt* art_provider) } -bool wxFrameManager::AddPane(wxWindow* window, const wxPaneInfo& pane_info) +bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& paneInfo) { + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + // check if the pane has a valid window if (!window) return false; - // check if the pane already exists - if (GetPane(pane_info.window).IsOk()) + // check if the window is already managed by us + if (GetPane(paneInfo.window).IsOk()) return false; - m_panes.Add(pane_info); + // check if the pane name already exists, this could reveal a + // bug in the library user's application + bool already_exists = false; + if (!paneInfo.name.empty() && GetPane(paneInfo.name).IsOk()) + { + wxFAIL_MSG(wxT("A pane with that name already exists in the manager!")); + already_exists = true; + } + + // if the new pane is docked then we should undo maximize + if (paneInfo.IsDocked()) + RestoreMaximizedPane(); + + // special case: wxAuiToolBar style interacts with docking flags + wxAuiPaneInfo test(paneInfo); + wxAuiToolBar* toolbar = wxDynamicCast(window, wxAuiToolBar); + if (toolbar) + { + // if pane has default docking flags + const unsigned int dockMask = wxAuiPaneInfo::optionLeftDockable | + wxAuiPaneInfo::optionRightDockable | + wxAuiPaneInfo::optionTopDockable | + wxAuiPaneInfo::optionBottomDockable; + const unsigned int defaultDock = wxAuiPaneInfo(). + DefaultPane().state & dockMask; + if ((test.state & dockMask) == defaultDock) + { + // set docking flags based on toolbar style + if (toolbar->GetWindowStyleFlag() & wxAUI_TB_VERTICAL) + { + test.TopDockable(false).BottomDockable(false); + } + else if (toolbar->GetWindowStyleFlag() & wxAUI_TB_HORIZONTAL) + { + test.LeftDockable(false).RightDockable(false); + } + } + else + { + // see whether non-default docking flags are valid + test.window = window; + wxCHECK_MSG(test.IsValid(), false, + "toolbar style and pane docking flags are incompatible"); + } + } + + m_panes.Add(test); - wxPaneInfo& pinfo = m_panes.Last(); + wxAuiPaneInfo& pinfo = m_panes.Last(); // set the pane window pinfo.window = window; + // if the pane's name identifier is blank, create a random string - if (pinfo.name.empty()) + if (pinfo.name.empty() || already_exists) { pinfo.name.Printf(wxT("%08lx%08x%08x%08lx"), - ((unsigned long)pinfo.window) & 0xffffffff, + (unsigned long)(wxPtrToUInt(pinfo.window) & 0xffffffff), (unsigned int)time(NULL), #ifdef __WXWINCE__ (unsigned int)GetTickCount(), @@ -612,33 +1074,57 @@ bool wxFrameManager::AddPane(wxWindow* window, const wxPaneInfo& pane_info) if (pinfo.dock_proportion == 0) pinfo.dock_proportion = 100000; - if (pinfo.HasCloseButton() && - pinfo.buttons.size() == 0) + if (pinfo.HasMaximizeButton()) + { + wxAuiPaneButton button; + button.button_id = wxAUI_BUTTON_MAXIMIZE_RESTORE; + pinfo.buttons.Add(button); + } + + if (pinfo.HasPinButton()) + { + wxAuiPaneButton button; + button.button_id = wxAUI_BUTTON_PIN; + pinfo.buttons.Add(button); + } + + if (pinfo.HasCloseButton()) { - wxPaneButton button; - button.button_id = wxPaneInfo::buttonClose; + wxAuiPaneButton button; + button.button_id = wxAUI_BUTTON_CLOSE; pinfo.buttons.Add(button); } + if (pinfo.HasGripper()) + { + if (wxDynamicCast(pinfo.window, wxAuiToolBar)) + { + // prevent duplicate gripper -- both wxAuiManager and wxAuiToolBar + // have a gripper control. The toolbar's built-in gripper + // meshes better with the look and feel of the control than ours, + // so turn wxAuiManager's gripper off, and the toolbar's on. + + wxAuiToolBar* tb = static_cast(pinfo.window); + pinfo.SetFlag(wxAuiPaneInfo::optionGripper, false); + tb->SetGripperVisible(true); + } + } + + if (pinfo.best_size == wxDefaultSize && pinfo.window) { pinfo.best_size = pinfo.window->GetClientSize(); - if (pinfo.window->IsKindOf(CLASSINFO(wxToolBar))) +#if wxUSE_TOOLBAR + if (wxDynamicCast(pinfo.window, wxToolBar)) { // GetClientSize() doesn't get the best size for // a toolbar under some newer versions of wxWidgets, // so use GetBestSize() pinfo.best_size = pinfo.window->GetBestSize(); - - // for some reason, wxToolBar::GetBestSize() is returning - // a size that is a pixel shy of the correct amount. - // I believe this to be the correct action, until - // wxToolBar::GetBestSize() is fixed. Is this assumption - // correct? - pinfo.best_size.y++; } +#endif // wxUSE_TOOLBAR if (pinfo.min_size != wxDefaultSize) { @@ -649,14 +1135,16 @@ bool wxFrameManager::AddPane(wxWindow* window, const wxPaneInfo& pane_info) } } + + return true; } -bool wxFrameManager::AddPane(wxWindow* window, - int direction, - const wxString& caption) +bool wxAuiManager::AddPane(wxWindow* window, + int direction, + const wxString& caption) { - wxPaneInfo pinfo; + wxAuiPaneInfo pinfo; pinfo.Caption(caption); switch (direction) { @@ -669,69 +1157,74 @@ bool wxFrameManager::AddPane(wxWindow* window, return AddPane(window, pinfo); } -bool wxFrameManager::AddPane(wxWindow* window, - const wxPaneInfo& pane_info, - const wxPoint& drop_pos) +bool wxAuiManager::AddPane(wxWindow* window, + const wxAuiPaneInfo& paneInfo, + const wxPoint& drop_pos) { - if (!AddPane(window, pane_info)) + if (!AddPane(window, paneInfo)) return false; - - wxPaneInfo& pane = GetPane(window); - + + wxAuiPaneInfo& pane = GetPane(window); + DoDrop(m_docks, m_panes, pane, drop_pos, wxPoint(0,0)); - + return true; } -bool wxFrameManager::InsertPane(wxWindow* window, const wxPaneInfo& pane_info, +bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& paneInfo, int insert_level) { + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + // shift the panes around, depending on the insert level switch (insert_level) { case wxAUI_INSERT_PANE: DoInsertPane(m_panes, - pane_info.dock_direction, - pane_info.dock_layer, - pane_info.dock_row, - pane_info.dock_pos); + paneInfo.dock_direction, + paneInfo.dock_layer, + paneInfo.dock_row, + paneInfo.dock_pos); break; case wxAUI_INSERT_ROW: DoInsertDockRow(m_panes, - pane_info.dock_direction, - pane_info.dock_layer, - pane_info.dock_row); + paneInfo.dock_direction, + paneInfo.dock_layer, + paneInfo.dock_row); break; case wxAUI_INSERT_DOCK: DoInsertDockLayer(m_panes, - pane_info.dock_direction, - pane_info.dock_layer); + paneInfo.dock_direction, + paneInfo.dock_layer); break; } // if the window already exists, we are basically just moving/inserting the // existing window. If it doesn't exist, we need to add it and insert it - wxPaneInfo& existing_pane = GetPane(window); + wxAuiPaneInfo& existing_pane = GetPane(window); if (!existing_pane.IsOk()) { - return AddPane(window, pane_info); + return AddPane(window, paneInfo); } else { - if (pane_info.IsFloating()) + if (paneInfo.IsFloating()) { existing_pane.Float(); - if (pane_info.floating_pos != wxDefaultPosition) - existing_pane.FloatingPosition(pane_info.floating_pos); - if (pane_info.floating_size != wxDefaultSize) - existing_pane.FloatingSize(pane_info.floating_size); + if (paneInfo.floating_pos != wxDefaultPosition) + existing_pane.FloatingPosition(paneInfo.floating_pos); + if (paneInfo.floating_size != wxDefaultSize) + existing_pane.FloatingSize(paneInfo.floating_size); } - else + else { - existing_pane.Direction(pane_info.dock_direction); - existing_pane.Layer(pane_info.dock_layer); - existing_pane.Row(pane_info.dock_row); - existing_pane.Position(pane_info.dock_pos); + // if the new pane is docked then we should undo maximize + RestoreMaximizedPane(); + + existing_pane.Direction(paneInfo.dock_direction); + existing_pane.Layer(paneInfo.dock_layer); + existing_pane.Row(paneInfo.dock_row); + existing_pane.Position(paneInfo.dock_pos); } } @@ -741,12 +1234,14 @@ bool wxFrameManager::InsertPane(wxWindow* window, const wxPaneInfo& pane_info, // DetachPane() removes a pane from the frame manager. This // method will not destroy the window that is removed. -bool wxFrameManager::DetachPane(wxWindow* window) +bool wxAuiManager::DetachPane(wxWindow* window) { + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + int i, count; for (i = 0, count = m_panes.GetCount(); i < count; ++i) { - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (p.window == window) { if (p.frame) @@ -756,32 +1251,39 @@ bool wxFrameManager::DetachPane(wxWindow* window) // reduce flicker p.window->SetSize(1,1); - p.frame->Show(false); + + if (p.frame->IsShown()) + p.frame->Show(false); // reparent to m_frame and destroy the pane + if (m_actionWindow == p.frame) + { + m_actionWindow = NULL; + } + p.window->Reparent(m_frame); p.frame->SetSizer(NULL); p.frame->Destroy(); p.frame = NULL; } - + // make sure there are no references to this pane in our uiparts, // just in case the caller doesn't call Update() immediately after // the DetachPane() call. This prevets obscure crashes which would // happen at window repaint if the caller forgets to call Update() int pi, part_count; - for (pi = 0, part_count = (int)m_uiparts.GetCount(); pi < part_count; ++pi) + for (pi = 0, part_count = (int)m_uiParts.GetCount(); pi < part_count; ++pi) { - wxDockUIPart& part = m_uiparts.Item(pi); + wxAuiDockUIPart& part = m_uiParts.Item(pi); if (part.pane == &p) { - m_uiparts.RemoveAt(pi); + m_uiParts.RemoveAt(pi); part_count--; pi--; continue; } } - + m_panes.RemoveAt(i); return true; } @@ -789,103 +1291,309 @@ bool wxFrameManager::DetachPane(wxWindow* window) return false; } - -// EscapeDelimiters() changes ";" into "\;" and "|" into "\|" -// in the input string. This is an internal functions which is -// used for saving perspectives -static wxString EscapeDelimiters(const wxString& s) +// ClosePane() destroys or hides the pane depending on its flags +void wxAuiManager::ClosePane(wxAuiPaneInfo& paneInfo) { - wxString result; - result.Alloc(s.length()); - const wxChar* ch = s.c_str(); - while (*ch) + // if we were maximized, restore + if (paneInfo.IsMaximized()) { - if (*ch == wxT(';') || *ch == wxT('|')) - result += wxT('\\'); - result += *ch; - ++ch; + RestorePane(paneInfo); } - return result; -} - - -// SavePerspective() saves all pane information as a single string. -// This string may later be fed into LoadPerspective() to restore -// all pane settings. This save and load mechanism allows an -// exact pane configuration to be saved and restored at a later time -wxString wxFrameManager::SavePerspective() -{ - wxString result; - result.Alloc(500); - result = wxT("layout1|"); - - int pane_i, pane_count = m_panes.GetCount(); - for (pane_i = 0; pane_i < pane_count; ++pane_i) + // first, hide the window + if (paneInfo.window && paneInfo.window->IsShown()) { - wxPaneInfo& pane = m_panes.Item(pane_i); - - result += wxT("name="); - result += EscapeDelimiters(pane.name); - result += wxT(";"); - - result += wxT("caption="); - result += EscapeDelimiters(pane.caption); - result += wxT(";"); - - result += wxString::Format(wxT("state=%u;"), pane.state); - result += wxString::Format(wxT("dir=%d;"), pane.dock_direction); - result += wxString::Format(wxT("layer=%d;"), pane.dock_layer); - result += wxString::Format(wxT("row=%d;"), pane.dock_row); - result += wxString::Format(wxT("pos=%d;"), pane.dock_pos); - result += wxString::Format(wxT("prop=%d;"), pane.dock_proportion); - result += wxString::Format(wxT("bestw=%d;"), pane.best_size.x); - result += wxString::Format(wxT("besth=%d;"), pane.best_size.y); - result += wxString::Format(wxT("minw=%d;"), pane.min_size.x); - result += wxString::Format(wxT("minh=%d;"), pane.min_size.y); - result += wxString::Format(wxT("maxw=%d;"), pane.max_size.x); - result += wxString::Format(wxT("maxh=%d;"), pane.max_size.y); - result += wxString::Format(wxT("floatx=%d;"), pane.floating_pos.x); - result += wxString::Format(wxT("floaty=%d;"), pane.floating_pos.y); - result += wxString::Format(wxT("floatw=%d;"), pane.floating_size.x); - result += wxString::Format(wxT("floath=%d"), pane.floating_size.y); - result += wxT("|"); + paneInfo.window->Show(false); } - int dock_i, dock_count = m_docks.GetCount(); - for (dock_i = 0; dock_i < dock_count; ++dock_i) + // make sure that we are the parent of this window + if (paneInfo.window && paneInfo.window->GetParent() != m_frame) { - wxDockInfo& dock = m_docks.Item(dock_i); - - result += wxString::Format(wxT("dock_size(%d,%d,%d)=%d|"), - dock.dock_direction, dock.dock_layer, - dock.dock_row, dock.size); + paneInfo.window->Reparent(m_frame); } - return result; -} + // if we have a frame, destroy it + if (paneInfo.frame) + { + paneInfo.frame->Destroy(); + paneInfo.frame = NULL; + } + + // now we need to either destroy or hide the pane + if (paneInfo.IsDestroyOnClose()) + { + wxWindow * window = paneInfo.window; + DetachPane(window); + if (window) + { + window->Destroy(); + } + } + else + { + paneInfo.Hide(); + } +} + +void wxAuiManager::MaximizePane(wxAuiPaneInfo& paneInfo) +{ + int i, pane_count; + + // un-maximize and hide all other panes + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (!p.IsToolbar() && !p.IsFloating()) + { + p.Restore(); + + // save hidden state + p.SetFlag(wxAuiPaneInfo::savedHiddenState, + p.HasFlag(wxAuiPaneInfo::optionHidden)); + + // hide the pane, because only the newly + // maximized pane should show + p.Hide(); + } + } + + // mark ourselves maximized + paneInfo.Maximize(); + paneInfo.Show(); + m_hasMaximized = true; + + // last, show the window + if (paneInfo.window && !paneInfo.window->IsShown()) + { + paneInfo.window->Show(true); + } +} + +void wxAuiManager::RestorePane(wxAuiPaneInfo& paneInfo) +{ + int i, pane_count; + + // restore all the panes + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (!p.IsToolbar() && !p.IsFloating()) + { + p.SetFlag(wxAuiPaneInfo::optionHidden, + p.HasFlag(wxAuiPaneInfo::savedHiddenState)); + } + } + + // mark ourselves non-maximized + paneInfo.Restore(); + m_hasMaximized = false; + + // last, show the window + if (paneInfo.window && !paneInfo.window->IsShown()) + { + paneInfo.window->Show(true); + } +} + +void wxAuiManager::RestoreMaximizedPane() +{ + int i, pane_count; + + // restore all the panes + for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) + { + wxAuiPaneInfo& p = m_panes.Item(i); + if (p.IsMaximized()) + { + RestorePane(p); + break; + } + } +} + +// EscapeDelimiters() changes ";" into "\;" and "|" into "\|" +// in the input string. This is an internal functions which is +// used for saving perspectives +static wxString EscapeDelimiters(const wxString& s) +{ + wxString result; + result.Alloc(s.length()); + const wxChar* ch = s.c_str(); + while (*ch) + { + if (*ch == wxT(';') || *ch == wxT('|')) + result += wxT('\\'); + result += *ch; + ++ch; + } + return result; +} + +wxString wxAuiManager::SavePaneInfo(wxAuiPaneInfo& pane) +{ + wxString result = wxT("name="); + result += EscapeDelimiters(pane.name); + result += wxT(";"); + + result += wxT("caption="); + result += EscapeDelimiters(pane.caption); + result += wxT(";"); + + result += wxString::Format(wxT("state=%u;"), pane.state); + result += wxString::Format(wxT("dir=%d;"), pane.dock_direction); + result += wxString::Format(wxT("layer=%d;"), pane.dock_layer); + result += wxString::Format(wxT("row=%d;"), pane.dock_row); + result += wxString::Format(wxT("pos=%d;"), pane.dock_pos); + result += wxString::Format(wxT("prop=%d;"), pane.dock_proportion); + result += wxString::Format(wxT("bestw=%d;"), pane.best_size.x); + result += wxString::Format(wxT("besth=%d;"), pane.best_size.y); + result += wxString::Format(wxT("minw=%d;"), pane.min_size.x); + result += wxString::Format(wxT("minh=%d;"), pane.min_size.y); + result += wxString::Format(wxT("maxw=%d;"), pane.max_size.x); + result += wxString::Format(wxT("maxh=%d;"), pane.max_size.y); + result += wxString::Format(wxT("floatx=%d;"), pane.floating_pos.x); + result += wxString::Format(wxT("floaty=%d;"), pane.floating_pos.y); + result += wxString::Format(wxT("floatw=%d;"), pane.floating_size.x); + result += wxString::Format(wxT("floath=%d"), pane.floating_size.y); + + return result; +} + +// Load a "pane" with the pane infor settings in pane_part +void wxAuiManager::LoadPaneInfo(wxString pane_part, wxAuiPaneInfo &pane) +{ + // replace escaped characters so we can + // split up the string easily + pane_part.Replace(wxT("\\|"), wxT("\a")); + pane_part.Replace(wxT("\\;"), wxT("\b")); + + while(1) + { + wxString val_part = pane_part.BeforeFirst(wxT(';')); + pane_part = pane_part.AfterFirst(wxT(';')); + wxString val_name = val_part.BeforeFirst(wxT('=')); + wxString value = val_part.AfterFirst(wxT('=')); + val_name.MakeLower(); + val_name.Trim(true); + val_name.Trim(false); + value.Trim(true); + value.Trim(false); + + if (val_name.empty()) + break; + + if (val_name == wxT("name")) + pane.name = value; + else if (val_name == wxT("caption")) + pane.caption = value; + else if (val_name == wxT("state")) + pane.state = (unsigned int)wxAtoi(value.c_str()); + else if (val_name == wxT("dir")) + pane.dock_direction = wxAtoi(value.c_str()); + else if (val_name == wxT("layer")) + pane.dock_layer = wxAtoi(value.c_str()); + else if (val_name == wxT("row")) + pane.dock_row = wxAtoi(value.c_str()); + else if (val_name == wxT("pos")) + pane.dock_pos = wxAtoi(value.c_str()); + else if (val_name == wxT("prop")) + pane.dock_proportion = wxAtoi(value.c_str()); + else if (val_name == wxT("bestw")) + pane.best_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("besth")) + pane.best_size.y = wxAtoi(value.c_str()); + else if (val_name == wxT("minw")) + pane.min_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("minh")) + pane.min_size.y = wxAtoi(value.c_str()); + else if (val_name == wxT("maxw")) + pane.max_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("maxh")) + pane.max_size.y = wxAtoi(value.c_str()); + else if (val_name == wxT("floatx")) + pane.floating_pos.x = wxAtoi(value.c_str()); + else if (val_name == wxT("floaty")) + pane.floating_pos.y = wxAtoi(value.c_str()); + else if (val_name == wxT("floatw")) + pane.floating_size.x = wxAtoi(value.c_str()); + else if (val_name == wxT("floath")) + pane.floating_size.y = wxAtoi(value.c_str()); + else { + wxFAIL_MSG(wxT("Bad Perspective String")); + } + } + + // replace escaped characters so we can + // split up the string easily + pane.name.Replace(wxT("\a"), wxT("|")); + pane.name.Replace(wxT("\b"), wxT(";")); + pane.caption.Replace(wxT("\a"), wxT("|")); + pane.caption.Replace(wxT("\b"), wxT(";")); + pane_part.Replace(wxT("\a"), wxT("|")); + pane_part.Replace(wxT("\b"), wxT(";")); + + return; +} + + +// SavePerspective() saves all pane information as a single string. +// This string may later be fed into LoadPerspective() to restore +// all pane settings. This save and load mechanism allows an +// exact pane configuration to be saved and restored at a later time + +wxString wxAuiManager::SavePerspective() +{ + wxString result; + result.Alloc(500); + result = wxT("layout2|"); + + int pane_i, pane_count = m_panes.GetCount(); + for (pane_i = 0; pane_i < pane_count; ++pane_i) + { + wxAuiPaneInfo& pane = m_panes.Item(pane_i); + result += SavePaneInfo(pane)+wxT("|"); + } + + int dock_i, dock_count = m_docks.GetCount(); + for (dock_i = 0; dock_i < dock_count; ++dock_i) + { + wxAuiDockInfo& dock = m_docks.Item(dock_i); + + result += wxString::Format(wxT("dock_size(%d,%d,%d)=%d|"), + dock.dock_direction, dock.dock_layer, + dock.dock_row, dock.size); + } + + return result; +} // LoadPerspective() loads a layout which was saved with SavePerspective() // If the "update" flag parameter is true, the GUI will immediately be updated -bool wxFrameManager::LoadPerspective(const wxString& layout, bool update) +bool wxAuiManager::LoadPerspective(const wxString& layout, bool update) { wxString input = layout; wxString part; // check layout string version + // 'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2 + // 'layout2' = wxAUI 0.9.2 (wxWidgets 2.8) part = input.BeforeFirst(wxT('|')); input = input.AfterFirst(wxT('|')); part.Trim(true); part.Trim(false); - if (part != wxT("layout1")) + if (part != wxT("layout2")) return false; - - // mark all panes currently managed as docked and hidden + // Mark all panes currently managed as hidden. Also, dock all panes that are dockable. int pane_i, pane_count = m_panes.GetCount(); for (pane_i = 0; pane_i < pane_count; ++pane_i) - m_panes.Item(pane_i).Dock().Hide(); + { + wxAuiPaneInfo& p = m_panes.Item(pane_i); + if(p.IsDockable()) + p.Dock(); + p.Hide(); + } // clear out the dock array; this will be reconstructed m_docks.Clear(); @@ -895,9 +1603,10 @@ bool wxFrameManager::LoadPerspective(const wxString& layout, bool update) input.Replace(wxT("\\|"), wxT("\a")); input.Replace(wxT("\\;"), wxT("\b")); + m_hasMaximized = false; while (1) { - wxPaneInfo pane; + wxAuiPaneInfo pane; wxString pane_part = input.BeforeFirst(wxT('|')); input = input.AfterFirst(wxT('|')); @@ -907,7 +1616,6 @@ bool wxFrameManager::LoadPerspective(const wxString& layout, bool update) if (pane_part.empty()) break; - if (pane_part.Left(9) == wxT("dock_size")) { wxString val_name = pane_part.BeforeFirst(wxT('=')); @@ -922,7 +1630,7 @@ bool wxFrameManager::LoadPerspective(const wxString& layout, bool update) piece.AfterFirst(wxT(',')).ToLong(&row); value.ToLong(&size); - wxDockInfo dock; + wxAuiDockInfo dock; dock.dock_direction = dir; dock.dock_layer = layer; dock.dock_row = row; @@ -931,81 +1639,25 @@ bool wxFrameManager::LoadPerspective(const wxString& layout, bool update) continue; } - while (1) - { - wxString val_part = pane_part.BeforeFirst(wxT(';')); - pane_part = pane_part.AfterFirst(wxT(';')); - wxString val_name = val_part.BeforeFirst(wxT('=')); - wxString value = val_part.AfterFirst(wxT('=')); - val_name.MakeLower(); - val_name.Trim(true); - val_name.Trim(false); - value.Trim(true); - value.Trim(false); - - if (val_name.empty()) - break; + // Undo our escaping as LoadPaneInfo needs to take an unescaped + // name so it can be called by external callers + pane_part.Replace(wxT("\a"), wxT("|")); + pane_part.Replace(wxT("\b"), wxT(";")); - if (val_name == wxT("name")) - pane.name = value; - else if (val_name == wxT("caption")) - pane.caption = value; - else if (val_name == wxT("state")) - pane.state = (unsigned int)wxAtoi(value.c_str()); - else if (val_name == wxT("dir")) - pane.dock_direction = wxAtoi(value.c_str()); - else if (val_name == wxT("layer")) - pane.dock_layer = wxAtoi(value.c_str()); - else if (val_name == wxT("row")) - pane.dock_row = wxAtoi(value.c_str()); - else if (val_name == wxT("pos")) - pane.dock_pos = wxAtoi(value.c_str()); - else if (val_name == wxT("prop")) - pane.dock_proportion = wxAtoi(value.c_str()); - else if (val_name == wxT("bestw")) - pane.best_size.x = wxAtoi(value.c_str()); - else if (val_name == wxT("besth")) - pane.best_size.y = wxAtoi(value.c_str()); - else if (val_name == wxT("minw")) - pane.min_size.x = wxAtoi(value.c_str()); - else if (val_name == wxT("minh")) - pane.min_size.y = wxAtoi(value.c_str()); - else if (val_name == wxT("maxw")) - pane.max_size.x = wxAtoi(value.c_str()); - else if (val_name == wxT("maxh")) - pane.max_size.y = wxAtoi(value.c_str()); - else if (val_name == wxT("floatx")) - pane.floating_pos.x = wxAtoi(value.c_str()); - else if (val_name == wxT("floaty")) - pane.floating_pos.y = wxAtoi(value.c_str()); - else if (val_name == wxT("floatw")) - pane.floating_size.x = wxAtoi(value.c_str()); - else if (val_name == wxT("floath")) - pane.floating_size.y = wxAtoi(value.c_str()); - else { - wxFAIL_MSG(wxT("Bad Perspective String")); - } - } + LoadPaneInfo(pane_part, pane); - // replace escaped characters so we can - // split up the string easily - pane.name.Replace(wxT("\a"), wxT("|")); - pane.name.Replace(wxT("\b"), wxT(";")); - pane.caption.Replace(wxT("\a"), wxT("|")); - pane.caption.Replace(wxT("\b"), wxT(";")); + if ( pane.IsMaximized() ) + m_hasMaximized = true; - wxPaneInfo& p = GetPane(pane.name); + wxAuiPaneInfo& p = GetPane(pane.name); if (!p.IsOk()) { // the pane window couldn't be found - // in the existing layout - return false; + // in the existing layout -- skip it + continue; } - pane.window = p.window; - pane.frame = p.frame; - pane.buttons = p.buttons; - p = pane; + p.SafeSet(pane); } if (update) @@ -1014,14 +1666,13 @@ bool wxFrameManager::LoadPerspective(const wxString& layout, bool update) return true; } - -void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock, - wxArrayInt& positions, - wxArrayInt& sizes) +void wxAuiManager::GetPanePositionsAndSizes(wxAuiDockInfo& dock, + wxArrayInt& positions, + wxArrayInt& sizes) { - int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE); - int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE); - int gripper_size = m_art->GetMetric(wxAUI_ART_GRIPPER_SIZE); + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int gripperSize = m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); positions.Empty(); sizes.Empty(); @@ -1032,9 +1683,9 @@ void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock, // find the pane marked as our action pane for (pane_i = 0; pane_i < pane_count; ++pane_i) { - wxPaneInfo& pane = *(dock.panes.Item(pane_i)); + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); - if (pane.state & wxPaneInfo::actionPane) + if (pane.HasFlag(wxAuiPaneInfo::actionPane)) { wxASSERT_MSG(action_pane==-1, wxT("Too many fixed action panes")); action_pane = pane_i; @@ -1046,23 +1697,23 @@ void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock, // on the dock's orientation) of each pane for (pane_i = 0; pane_i < pane_count; ++pane_i) { - wxPaneInfo& pane = *(dock.panes.Item(pane_i)); + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); positions.Add(pane.dock_pos); int size = 0; if (pane.HasBorder()) - size += (pane_border_size*2); + size += (pane_borderSize*2); if (dock.IsHorizontal()) { if (pane.HasGripper() && !pane.HasGripperTop()) - size += gripper_size; + size += gripperSize; size += pane.best_size.x; } - else + else { if (pane.HasGripper() && pane.HasGripperTop()) - size += gripper_size; + size += gripperSize; if (pane.HasCaption()) size += caption_size; @@ -1084,7 +1735,7 @@ void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock, if (amount >= 0) offset += amount; - else + else positions[pane_i] -= -amount; offset += sizes[pane_i]; @@ -1098,7 +1749,7 @@ void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock, int amount = positions[pane_i] - offset; if (amount >= 0) offset += amount; - else + else positions[pane_i] += -amount; offset += sizes[pane_i]; @@ -1106,26 +1757,26 @@ void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock, } -void wxFrameManager::LayoutAddPane(wxSizer* cont, - wxDockInfo& dock, - wxPaneInfo& pane, - wxDockUIPartArray& uiparts, - bool spacer_only) +void wxAuiManager::LayoutAddPane(wxSizer* cont, + wxAuiDockInfo& dock, + wxAuiPaneInfo& pane, + wxAuiDockUIPartArray& uiparts, + bool spacer_only) { - wxDockUIPart part; + wxAuiDockUIPart part; wxSizerItem* sizer_item; - int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE); - int gripper_size = m_art->GetMetric(wxAUI_ART_GRIPPER_SIZE); - int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE); - int pane_button_size = m_art->GetMetric(wxAUI_ART_PANE_BUTTON_SIZE); + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + int gripperSize = m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE); + int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int pane_button_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BUTTON_SIZE); // find out the orientation of the item (orientation for panes // is the same as the dock's orientation) int orientation; if (dock.IsHorizontal()) orientation = wxHORIZONTAL; - else + else orientation = wxVERTICAL; // this variable will store the proportion @@ -1138,11 +1789,11 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, if (pane.HasGripper()) { if (pane.HasGripperTop()) - sizer_item = vert_pane_sizer ->Add(1, gripper_size, 0, wxEXPAND); + sizer_item = vert_pane_sizer ->Add(1, gripperSize, 0, wxEXPAND); else - sizer_item = horz_pane_sizer ->Add(gripper_size, 1, 0, wxEXPAND); + sizer_item = horz_pane_sizer ->Add(gripperSize, 1, 0, wxEXPAND); - part.type = wxDockUIPart::typeGripper; + part.type = wxAuiDockUIPart::typeGripper; part.dock = &dock; part.pane = &pane; part.button = NULL; @@ -1159,7 +1810,7 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, sizer_item = caption_sizer->Add(1, caption_size, 1, wxEXPAND); - part.type = wxDockUIPart::typeCaption; + part.type = wxAuiDockUIPart::typeCaption; part.dock = &dock; part.pane = &pane; part.button = NULL; @@ -1174,13 +1825,13 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, for (i = 0, button_count = pane.buttons.GetCount(); i < button_count; ++i) { - wxPaneButton& button = pane.buttons.Item(i); + wxAuiPaneButton& button = pane.buttons.Item(i); sizer_item = caption_sizer->Add(pane_button_size, caption_size, 0, wxEXPAND); - part.type = wxDockUIPart::typePaneButton; + part.type = wxAuiDockUIPart::typePaneButton; part.dock = &dock; part.pane = &pane; part.button = &button; @@ -1190,6 +1841,13 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, uiparts.Add(part); } + // if we have buttons, add a little space to the right + // of them to ease visual crowding + if (button_count >= 1) + { + caption_sizer->Add(3,1); + } + // add the caption sizer sizer_item = vert_pane_sizer->Add(caption_sizer, 0, wxEXPAND); @@ -1210,7 +1868,7 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, vert_pane_sizer->SetItemMinSize(pane.window, 1, 1); } - part.type = wxDockUIPart::typePane; + part.type = wxAuiDockUIPart::typePane; part.dock = &dock; part.pane = &pane; part.button = NULL; @@ -1221,7 +1879,7 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, // determine if the pane should have a minimum size; if the pane is - // non-resizable (fixed) then we must set a minimum size. Alternitavely, + // non-resizable (fixed) then we must set a minimum size. Alternatively, // if the pane.min_size is set, we must use that value as well wxSize min_size = pane.min_size; @@ -1252,9 +1910,9 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, { // allowing space for the pane's border sizer_item = cont->Add(horz_pane_sizer, pane_proportion, - wxEXPAND | wxALL, pane_border_size); + wxEXPAND | wxALL, pane_borderSize); - part.type = wxDockUIPart::typePaneBorder; + part.type = wxAuiDockUIPart::typePaneBorder; part.dock = &dock; part.pane = &pane; part.button = NULL; @@ -1269,24 +1927,24 @@ void wxFrameManager::LayoutAddPane(wxSizer* cont, } } -void wxFrameManager::LayoutAddDock(wxSizer* cont, - wxDockInfo& dock, - wxDockUIPartArray& uiparts, - bool spacer_only) +void wxAuiManager::LayoutAddDock(wxSizer* cont, + wxAuiDockInfo& dock, + wxAuiDockUIPartArray& uiparts, + bool spacer_only) { wxSizerItem* sizer_item; - wxDockUIPart part; + wxAuiDockUIPart part; - int sash_size = m_art->GetMetric(wxAUI_ART_SASH_SIZE); + int sashSize = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); int orientation = dock.IsHorizontal() ? wxHORIZONTAL : wxVERTICAL; // resizable bottom and right docks have a sash before them - if (!dock.fixed && (dock.dock_direction == wxAUI_DOCK_BOTTOM || + if (!m_hasMaximized && !dock.fixed && (dock.dock_direction == wxAUI_DOCK_BOTTOM || dock.dock_direction == wxAUI_DOCK_RIGHT)) { - sizer_item = cont->Add(sash_size, sash_size, 0, wxEXPAND); + sizer_item = cont->Add(sashSize, sashSize, 0, wxEXPAND); - part.type = wxDockUIPart::typeDockSizer; + part.type = wxAuiDockUIPart::typeDockSizer; part.orientation = orientation; part.dock = &dock; part.pane = NULL; @@ -1300,6 +1958,7 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, wxSizer* dock_sizer = new wxBoxSizer(orientation); // add each pane to the dock + bool has_maximized_pane = false; int pane_i, pane_count = dock.panes.GetCount(); if (dock.fixed) @@ -1313,18 +1972,22 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, int offset = 0; for (pane_i = 0; pane_i < pane_count; ++pane_i) { - wxPaneInfo& pane = *(dock.panes.Item(pane_i)); + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); int pane_pos = pane_positions.Item(pane_i); + if (pane.IsMaximized()) + has_maximized_pane = true; + + int amount = pane_pos - offset; if (amount > 0) { if (dock.IsVertical()) sizer_item = dock_sizer->Add(1, amount, 0, wxEXPAND); - else + else sizer_item = dock_sizer->Add(amount, 1, 0, wxEXPAND); - part.type = wxDockUIPart::typeBackground; + part.type = wxAuiDockUIPart::typeBackground; part.dock = &dock; part.pane = NULL; part.button = NULL; @@ -1342,9 +2005,9 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, } // at the end add a very small stretchable background area - sizer_item = dock_sizer->Add(1,1, 1, wxEXPAND); + sizer_item = dock_sizer->Add(0,0, 1, wxEXPAND); - part.type = wxDockUIPart::typeBackground; + part.type = wxAuiDockUIPart::typeBackground; part.dock = &dock; part.pane = NULL; part.button = NULL; @@ -1357,15 +2020,18 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, { for (pane_i = 0; pane_i < pane_count; ++pane_i) { - wxPaneInfo& pane = *(dock.panes.Item(pane_i)); + wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); + + if (pane.IsMaximized()) + has_maximized_pane = true; // if this is not the first pane being added, // we need to add a pane sizer - if (pane_i > 0) + if (!m_hasMaximized && pane_i > 0) { - sizer_item = dock_sizer->Add(sash_size, sash_size, 0, wxEXPAND); + sizer_item = dock_sizer->Add(sashSize, sashSize, 0, wxEXPAND); - part.type = wxDockUIPart::typePaneSizer; + part.type = wxAuiDockUIPart::typePaneSizer; part.dock = &dock; part.pane = dock.panes.Item(pane_i-1); part.button = NULL; @@ -1379,12 +2045,12 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, } } - if (dock.dock_direction == wxAUI_DOCK_CENTER) + if (dock.dock_direction == wxAUI_DOCK_CENTER || has_maximized_pane) sizer_item = cont->Add(dock_sizer, 1, wxEXPAND); - else + else sizer_item = cont->Add(dock_sizer, 0, wxEXPAND); - part.type = wxDockUIPart::typeDock; + part.type = wxAuiDockUIPart::typeDock; part.dock = &dock; part.pane = NULL; part.button = NULL; @@ -1395,16 +2061,18 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, if (dock.IsHorizontal()) cont->SetItemMinSize(dock_sizer, 0, dock.size); - else + else cont->SetItemMinSize(dock_sizer, dock.size, 0); // top and left docks have a sash after them - if (!dock.fixed && (dock.dock_direction == wxAUI_DOCK_TOP || - dock.dock_direction == wxAUI_DOCK_LEFT)) + if (!m_hasMaximized && + !dock.fixed && + (dock.dock_direction == wxAUI_DOCK_TOP || + dock.dock_direction == wxAUI_DOCK_LEFT)) { - sizer_item = cont->Add(sash_size, sash_size, 0, wxEXPAND); + sizer_item = cont->Add(sashSize, sashSize, 0, wxEXPAND); - part.type = wxDockUIPart::typeDockSizer; + part.type = wxAuiDockUIPart::typeDockSizer; part.dock = &dock; part.pane = NULL; part.button = NULL; @@ -1415,43 +2083,58 @@ void wxFrameManager::LayoutAddDock(wxSizer* cont, } } -wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, - wxDockInfoArray& docks, - wxDockUIPartArray& uiparts, - bool spacer_only) +wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes, + wxAuiDockInfoArray& docks, + wxAuiDockUIPartArray& uiparts, + bool spacer_only) { wxBoxSizer* container = new wxBoxSizer(wxVERTICAL); - int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE); - int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE); + int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); wxSize cli_size = m_frame->GetClientSize(); int i, dock_count, pane_count; // empty all docks out for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) - docks.Item(i).panes.Empty(); + { + wxAuiDockInfo& dock = docks.Item(i); + + // empty out all panes, as they will be readded below + dock.panes.Empty(); + + if (dock.fixed) + { + // always reset fixed docks' sizes, because + // the contained windows may have been resized + dock.size = 0; + } + } + // iterate through all known panes, filing each // of them into the appropriate dock. If the // pane does not exist in the dock, add it for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& p = panes.Item(i); + wxAuiPaneInfo& p = panes.Item(i); - // find any docks in this layer - wxDockInfo* dock; - wxDockInfoPtrArray arr; + // find any docks with the same dock direction, dock layer, and + // dock row as the pane we are working on + wxAuiDockInfo* dock; + wxAuiDockInfoPtrArray arr; FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row, arr); if (arr.GetCount() > 0) { + // found the right dock dock = arr.Item(0); } - else + else { // dock was not found, so we need to create a new one - wxDockInfo d; + wxAuiDockInfo d; d.dock_direction = p.dock_direction; d.dock_layer = p.dock_layer; d.dock_row = p.dock_row; @@ -1470,7 +2153,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, if (!FindPaneInDock(*dock, p.window)) dock->panes.Add(&p); } - else + else { // remove the pane from any existing docks RemovePaneFromDocks(docks, p); @@ -1488,7 +2171,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, // configure the docks further for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) { - wxDockInfo& dock = docks.Item(i); + wxAuiDockInfo& dock = docks.Item(i); int j, dock_pane_count = dock.panes.GetCount(); // sort the dock pane array by the pane's @@ -1502,7 +2185,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, for (j = 0; j < dock_pane_count; ++j) { - wxPaneInfo& pane = *dock.panes.Item(j); + wxAuiPaneInfo& pane = *dock.panes.Item(j); wxSize pane_size = pane.best_size; if (pane_size == wxDefaultSize) pane_size = pane.min_size; @@ -1511,7 +2194,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, if (dock.IsHorizontal()) size = wxMax(pane_size.y, size); - else + else size = wxMax(pane_size.x, size); } @@ -1521,7 +2204,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, { if (dock.panes.Item(j)->HasBorder()) { - size += (pane_border_size*2); + size += (pane_borderSize*2); break; } } @@ -1540,14 +2223,22 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, } } - // new dock's size may not be more than 1/3 of the frame size + + // new dock's size may not be more than the dock constraint + // parameter specifies. See SetDockSizeConstraint() + + int max_dock_x_size = (int)(m_dockConstraintX * ((double)cli_size.x)); + int max_dock_y_size = (int)(m_dockConstraintY * ((double)cli_size.y)); + if (dock.IsHorizontal()) - size = wxMin(size, cli_size.y/3); - else - size = wxMin(size, cli_size.x/3); + size = wxMin(size, max_dock_y_size); + else + size = wxMin(size, max_dock_x_size); + // absolute minimum size for a dock is 10 pixels if (size < 10) size = 10; + dock.size = size; } @@ -1558,7 +2249,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, int dock_min_size = 0; for (j = 0; j < dock_pane_count; ++j) { - wxPaneInfo& pane = *dock.panes.Item(j); + wxAuiPaneInfo& pane = *dock.panes.Item(j); if (pane.min_size != wxDefaultSize) { if (pane.HasBorder()) @@ -1570,7 +2261,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, if (pane.min_size.y > dock_min_size) dock_min_size = pane.min_size.y; } - else + else { if (pane.min_size.x > dock_min_size) dock_min_size = pane.min_size.x; @@ -1579,7 +2270,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, } if (plus_border) - dock_min_size += (pane_border_size*2); + dock_min_size += (pane_borderSize*2); if (plus_caption && dock.IsHorizontal()) dock_min_size += (caption_size); @@ -1599,12 +2290,14 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, dock.toolbar = true; for (j = 0; j < dock_pane_count; ++j) { - wxPaneInfo& pane = *dock.panes.Item(j); + wxAuiPaneInfo& pane = *dock.panes.Item(j); if (!pane.IsFixed()) dock.fixed = false; if (!pane.IsToolbar()) dock.toolbar = false; - if (pane.state & wxPaneInfo::actionPane) + if (pane.HasFlag(wxAuiPaneInfo::optionDockFixed)) + dock.fixed = true; + if (pane.HasFlag(wxAuiPaneInfo::actionPane)) action_pane_marked = true; } @@ -1616,7 +2309,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, { for (j = 0; j < dock_pane_count; ++j) { - wxPaneInfo& pane = *dock.panes.Item(j); + wxAuiPaneInfo& pane = *dock.panes.Item(j); pane.dock_pos = j; } } @@ -1624,7 +2317,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, // if the dock mode is fixed, and none of the panes // are being moved right now, make sure the panes // do not overlap each other. If they do, we will - // adjust the panes' positions + // adjust the positions of the panes if (dock.fixed && !action_pane_marked) { wxArrayInt pane_positions, pane_sizes; @@ -1633,13 +2326,13 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, int offset = 0; for (j = 0; j < dock_pane_count; ++j) { - wxPaneInfo& pane = *(dock.panes.Item(j)); + wxAuiPaneInfo& pane = *(dock.panes.Item(j)); pane.dock_pos = pane_positions[j]; int amount = pane.dock_pos - offset; if (amount >= 0) offset += amount; - else + else pane.dock_pos += -amount; offset += pane_sizes[j]; @@ -1665,7 +2358,7 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, for (layer = 0; layer <= max_layer; ++layer) { - wxDockInfoPtrArray arr; + wxAuiDockInfoPtrArray arr; // find any docks in this layer FindDocks(docks, -1, layer, -1, arr); @@ -1683,7 +2376,6 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, // find any top docks in this layer FindDocks(docks, wxAUI_DOCK_TOP, layer, -1, arr); - RenumberDockRows(arr); if (!arr.IsEmpty()) { for (row = 0, row_count = arr.GetCount(); row < row_count; ++row) @@ -1698,7 +2390,6 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, // find any left docks in this layer FindDocks(docks, wxAUI_DOCK_LEFT, layer, -1, arr); - RenumberDockRows(arr); if (!arr.IsEmpty()) { for (row = 0, row_count = arr.GetCount(); row < row_count; ++row) @@ -1716,12 +2407,12 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, for (row = 0,row_count = arr.GetCount(); rowAdd(1,1, 1, wxEXPAND); - wxDockUIPart part; - part.type = wxDockUIPart::typeBackground; + wxAuiDockUIPart part; + part.type = wxAuiDockUIPart::typeBackground; part.pane = NULL; part.dock = NULL; part.button = NULL; @@ -1730,27 +2421,28 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, uiparts.Add(part); } } - else + else { middle->Add(old_cont, 1, wxEXPAND); } // find any right docks in this layer FindDocks(docks, wxAUI_DOCK_RIGHT, layer, -1, arr); - RenumberDockRows(arr); if (!arr.IsEmpty()) { for (row = arr.GetCount()-1; row >= 0; --row) LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only); } - cont->Add(middle, 1, wxEXPAND); + if (middle->GetChildren().GetCount() > 0) + cont->Add(middle, 1, wxEXPAND); + else + delete middle; // find any bottom docks in this layer FindDocks(docks, wxAUI_DOCK_BOTTOM, layer, -1, arr); - RenumberDockRows(arr); if (!arr.IsEmpty()) { for (row = arr.GetCount()-1; row >= 0; --row) @@ -1765,8 +2457,8 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, // therefore we will create a simple background area cont = new wxBoxSizer(wxVERTICAL); wxSizerItem* sizer_item = cont->Add(1,1, 1, wxEXPAND); - wxDockUIPart part; - part.type = wxDockUIPart::typeBackground; + wxAuiDockUIPart part; + part.type = wxAuiDockUIPart::typeBackground; part.pane = NULL; part.dock = NULL; part.button = NULL; @@ -1780,23 +2472,45 @@ wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes, } +// SetDockSizeConstraint() allows the dock constraints to be set. For example, +// specifying values of 0.5, 0.5 will mean that upon dock creation, a dock may +// not be larger than half of the window's size + +void wxAuiManager::SetDockSizeConstraint(double width_pct, double height_pct) +{ + m_dockConstraintX = wxMax(0.0, wxMin(1.0, width_pct)); + m_dockConstraintY = wxMax(0.0, wxMin(1.0, height_pct)); +} + +void wxAuiManager::GetDockSizeConstraint(double* width_pct, double* height_pct) const +{ + if (width_pct) + *width_pct = m_dockConstraintX; + + if (height_pct) + *height_pct = m_dockConstraintY; +} + + + // Update() updates the layout. Whenever changes are made to // one or more panes, this function should be called. It is the // external entry point for running the layout engine. -void wxFrameManager::Update() +void wxAuiManager::Update() { + m_hoverButton = NULL; + m_actionPart = NULL; + wxSizer* sizer; int i, pane_count = m_panes.GetCount(); - // delete old sizer first - m_frame->SetSizer(NULL); // destroy floating panes which have been // redocked or are becoming non-floating for (i = 0; i < pane_count; ++i) { - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (!p.IsFloating() && p.frame) { @@ -1805,9 +2519,32 @@ void wxFrameManager::Update() // reduce flicker p.window->SetSize(1,1); - p.frame->Show(false); + + + // the following block is a workaround for bug #1531361 + // (see wxWidgets sourceforge page). On wxGTK (only), when + // a frame is shown/hidden, a move event unfortunately + // also gets fired. Because we may be dragging around + // a pane, we need to cancel that action here to prevent + // a spurious crash. + if (m_actionWindow == p.frame) + { + if (wxWindow::GetCapture() == m_frame) + m_frame->ReleaseMouse(); + m_action = actionNone; + m_actionWindow = NULL; + } + + // hide the frame + if (p.frame->IsShown()) + p.frame->Show(false); // reparent to m_frame and destroy the pane + if (m_actionWindow == p.frame) + { + m_actionWindow = NULL; + } + p.window->Reparent(m_frame); p.frame->SetSizer(NULL); p.frame->Destroy(); @@ -1816,14 +2553,17 @@ void wxFrameManager::Update() } + // delete old sizer first + m_frame->SetSizer(NULL); + // create a layout for all of the panes - sizer = LayoutAll(m_panes, m_docks, m_uiparts, false); + sizer = LayoutAll(m_panes, m_docks, m_uiParts, false); // hide or show panes as necessary, // and float panes as necessary for (i = 0; i < pane_count; ++i) { - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (p.IsFloating()) { @@ -1831,50 +2571,64 @@ void wxFrameManager::Update() { // we need to create a frame for this // pane, which has recently been floated - wxFloatingPane* frame = new wxFloatingPane(m_frame, - this, - p); + wxAuiFloatingFrame* frame = CreateFloatingFrame(m_frame, p); // on MSW and Mac, if the owner desires transparent dragging, and // the dragging is happening right now, then the floating // window should have this style by default if (m_action == actionDragFloatingPane && (m_flags & wxAUI_MGR_TRANSPARENT_DRAG)) - frame->SetTranslucency(150); + frame->SetTransparent(150); frame->SetPaneWindow(p); p.frame = frame; - if (p.IsShown()) - { + if (p.IsShown() && !frame->IsShown()) frame->Show(); - } } - else + else { // frame already exists, make sure it's position - // and size reflect the information in wxPaneInfo - if (p.frame->GetPosition() != p.floating_pos) + // and size reflect the information in wxAuiPaneInfo + if ((p.frame->GetPosition() != p.floating_pos) || (p.frame->GetSize() != p.floating_size)) { + p.frame->SetSize(p.floating_pos.x, p.floating_pos.y, + p.floating_size.x, p.floating_size.y, + wxSIZE_USE_EXISTING); + /* p.frame->SetSize(p.floating_pos.x, p.floating_pos.y, wxDefaultCoord, wxDefaultCoord, wxSIZE_USE_EXISTING); //p.frame->Move(p.floating_pos.x, p.floating_pos.y); + */ } - p.frame->Show(p.IsShown()); + // update whether the pane is resizable or not + long style = p.frame->GetWindowStyleFlag(); + if (p.IsFixed()) + style &= ~wxRESIZE_BORDER; + else + style |= wxRESIZE_BORDER; + p.frame->SetWindowStyleFlag(style); + + if (p.frame->GetLabel() != p.caption) + p.frame->SetLabel(p.caption); + + if (p.frame->IsShown() != p.IsShown()) + p.frame->Show(p.IsShown()); } } - else + else { - p.window->Show(p.IsShown()); + if (p.window->IsShown() != p.IsShown()) + p.window->Show(p.IsShown()); } // if "active panes" are no longer allowed, clear // any optionActive values from the pane states if ((m_flags & wxAUI_MGR_ALLOW_ACTIVE_PANE) == 0) { - p.state &= ~wxPaneInfo::optionActive; + p.state &= ~wxAuiPaneInfo::optionActive; } } @@ -1885,7 +2639,7 @@ void wxFrameManager::Update() for (i = 0; i < pane_count; ++i) { wxRect r; - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (p.window && p.IsShown() && p.IsDocked()) r = p.rect; @@ -1909,7 +2663,7 @@ void wxFrameManager::Update() // changed, the corresponding panes must also be updated for (i = 0; i < pane_count; ++i) { - wxPaneInfo& p = m_panes.Item(i); + wxAuiPaneInfo& p = m_panes.Item(i); if (p.window && p.window->IsShown() && p.IsDocked()) { if (p.rect != old_pane_rects[i]) @@ -1951,14 +2705,14 @@ void wxFrameManager::Update() // and updates their internal rectangles. This should always be called // instead of calling m_frame->Layout() directly -void wxFrameManager::DoFrameLayout() +void wxAuiManager::DoFrameLayout() { m_frame->Layout(); int i, part_count; - for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i) { - wxDockUIPart& part = m_uiparts.Item(i); + wxAuiDockUIPart& part = m_uiParts.Item(i); // get the rectangle of the UI part // originally, this code looked like this: @@ -1991,9 +2745,9 @@ void wxFrameManager::DoFrameLayout() part.rect.width += border; - if (part.type == wxDockUIPart::typeDock) + if (part.type == wxAuiDockUIPart::typeDock) part.dock->rect = part.rect; - if (part.type == wxDockUIPart::typePane) + if (part.type == wxAuiDockUIPart::typePane) part.pane->rect = part.rect; } } @@ -2003,20 +2757,20 @@ void wxFrameManager::DoFrameLayout() // rectangle of the pane in question, including decorations like // caption and border (if any). -wxDockUIPart* wxFrameManager::GetPanePart(wxWindow* wnd) +wxAuiDockUIPart* wxAuiManager::GetPanePart(wxWindow* wnd) { int i, part_count; - for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i) { - wxDockUIPart& part = m_uiparts.Item(i); - if (part.type == wxDockUIPart::typePaneBorder && + wxAuiDockUIPart& part = m_uiParts.Item(i); + if (part.type == wxAuiDockUIPart::typePaneBorder && part.pane && part.pane->window == wnd) return ∂ } - for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i) + for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i) { - wxDockUIPart& part = m_uiparts.Item(i); - if (part.type == wxDockUIPart::typePane && + wxAuiDockUIPart& part = m_uiParts.Item(i); + if (part.type == wxAuiDockUIPart::typePane && part.pane && part.pane->window == wnd) return ∂ } @@ -2031,15 +2785,15 @@ wxDockUIPart* wxFrameManager::GetPanePart(wxWindow* wnd) // vertical docks). This value is necessary for calculating // fixel-pane/toolbar offsets when they are dragged. -int wxFrameManager::GetDockPixelOffset(wxPaneInfo& test) +int wxAuiManager::GetDockPixelOffset(wxAuiPaneInfo& test) { // the only way to accurately calculate the dock's // offset is to actually run a theoretical layout int i, part_count, dock_count; - wxDockInfoArray docks; - wxPaneInfoArray panes; - wxDockUIPartArray uiparts; + wxAuiDockInfoArray docks; + wxAuiPaneInfoArray panes; + wxAuiDockUIPartArray uiparts; CopyDocksAndPanes(docks, panes, m_docks, m_panes); panes.Add(test); @@ -2050,10 +2804,10 @@ int wxFrameManager::GetDockPixelOffset(wxPaneInfo& test) for (i = 0, part_count = uiparts.GetCount(); i < part_count; ++i) { - wxDockUIPart& part = uiparts.Item(i); + wxAuiDockUIPart& part = uiparts.Item(i); part.rect = wxRect(part.sizer_item->GetPosition(), part.sizer_item->GetSize()); - if (part.type == wxDockUIPart::typeDock) + if (part.type == wxAuiDockUIPart::typeDock) part.dock->rect = part.rect; } @@ -2061,13 +2815,13 @@ int wxFrameManager::GetDockPixelOffset(wxPaneInfo& test) for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i) { - wxDockInfo& dock = docks.Item(i); + wxAuiDockInfo& dock = docks.Item(i); if (test.dock_direction == dock.dock_direction && test.dock_layer==dock.dock_layer && test.dock_row==dock.dock_row) { if (dock.IsVertical()) return dock.rect.y; - else + else return dock.rect.x; } } @@ -2081,8 +2835,8 @@ int wxFrameManager::GetDockPixelOffset(wxPaneInfo& test) // if a dock operation is allowed, the new dock position is copied into // the target info. If the operation was allowed, the function returns true. -bool wxFrameManager::ProcessDockResult(wxPaneInfo& target, - const wxPaneInfo& new_pos) +bool wxAuiManager::ProcessDockResult(wxAuiPaneInfo& target, + const wxAuiPaneInfo& new_pos) { bool allowed = false; switch (new_pos.dock_direction) @@ -2094,7 +2848,22 @@ bool wxFrameManager::ProcessDockResult(wxPaneInfo& target, } if (allowed) + { target = new_pos; + // Should this RTTI and function call be rewritten as + // sending a new event type to allow other window types + // to vary size based on dock location? + wxAuiToolBar* toolbar = wxDynamicCast(target.window, wxAuiToolBar); + if (toolbar) + { + wxSize hintSize = toolbar->GetHintSize(target.dock_direction); + if (target.best_size != hintSize) + { + target.best_size = hintSize; + target.floating_size = wxDefaultSize; + } + } + } return allowed; } @@ -2105,7 +2874,7 @@ bool wxFrameManager::ProcessDockResult(wxPaneInfo& target, // dropped, it performs the drop operation using the specified dock and pane // arrays. By specifying copied dock and pane arrays when calling, a "what-if" // scenario can be performed, giving precise coordinates for drop hints. -// If, however, wxFrameManager:m_docks and wxFrameManager::m_panes are specified +// If, however, wxAuiManager:m_docks and wxAuiManager::m_panes are specified // as parameters, the changes will be made to the main state arrays const int auiInsertRowPixels = 10; @@ -2113,15 +2882,15 @@ const int auiNewRowPixels = 40; const int auiLayerInsertPixels = 40; const int auiLayerInsertOffset = 5; -bool wxFrameManager::DoDrop(wxDockInfoArray& docks, - wxPaneInfoArray& panes, - wxPaneInfo& target, - const wxPoint& pt, - const wxPoint& offset) +bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, + wxAuiPaneInfoArray& panes, + wxAuiPaneInfo& target, + const wxPoint& pt, + const wxPoint& offset) { wxSize cli_size = m_frame->GetClientSize(); - wxPaneInfo drop = target; + wxAuiPaneInfo drop = target; // The result should always be shown @@ -2133,15 +2902,22 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, int layer_insert_offset = auiLayerInsertOffset; - if (target.IsToolbar()) + if (drop.IsToolbar()) layer_insert_offset = 0; + if (pt.x < layer_insert_offset && - pt.x > layer_insert_offset-auiLayerInsertPixels) + pt.x > layer_insert_offset-auiLayerInsertPixels && + pt.y > 0 && + pt.y < cli_size.y) { int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT), - GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)), - GetMaxLayer(docks, wxAUI_DOCK_TOP)) + 1; + GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)), + GetMaxLayer(docks, wxAUI_DOCK_TOP)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + drop.Dock().Left(). Layer(new_layer). Row(0). @@ -2149,11 +2925,17 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, return ProcessDockResult(target, drop); } else if (pt.y < layer_insert_offset && - pt.y > layer_insert_offset-auiLayerInsertPixels) + pt.y > layer_insert_offset-auiLayerInsertPixels && + pt.x > 0 && + pt.x < cli_size.x) { int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP), - GetMaxLayer(docks, wxAUI_DOCK_LEFT)), - GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1; + GetMaxLayer(docks, wxAUI_DOCK_LEFT)), + GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + drop.Dock().Top(). Layer(new_layer). Row(0). @@ -2161,11 +2943,17 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, return ProcessDockResult(target, drop); } else if (pt.x >= cli_size.x - layer_insert_offset && - pt.x < cli_size.x - layer_insert_offset + auiLayerInsertPixels) + pt.x < cli_size.x - layer_insert_offset + auiLayerInsertPixels && + pt.y > 0 && + pt.y < cli_size.y) { int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT), - GetMaxLayer(docks, wxAUI_DOCK_TOP)), - GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)) + 1; + GetMaxLayer(docks, wxAUI_DOCK_TOP)), + GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + drop.Dock().Right(). Layer(new_layer). Row(0). @@ -2173,11 +2961,17 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, return ProcessDockResult(target, drop); } else if (pt.y >= cli_size.y - layer_insert_offset && - pt.y < cli_size.y - layer_insert_offset + auiLayerInsertPixels) + pt.y < cli_size.y - layer_insert_offset + auiLayerInsertPixels && + pt.x > 0 && + pt.x < cli_size.x) { - int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_BOTTOM), - GetMaxLayer(docks, wxAUI_DOCK_LEFT)), - GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1; + int new_layer = wxMax( wxMax( GetMaxLayer(docks, wxAUI_DOCK_BOTTOM), + GetMaxLayer(docks, wxAUI_DOCK_LEFT)), + GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1; + + if (drop.IsToolbar()) + new_layer = auiToolBarLayer; + drop.Dock().Bottom(). Layer(new_layer). Row(0). @@ -2186,7 +2980,7 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, } - wxDockUIPart* part = HitTest(pt.x, pt.y); + wxAuiDockUIPart* part = HitTest(pt.x, pt.y); if (drop.IsToolbar()) @@ -2194,32 +2988,47 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, if (!part || !part->dock) return false; - // calculate the offset from where the dock begins // to the point where the user dropped the pane int dock_drop_offset = 0; if (part->dock->IsHorizontal()) dock_drop_offset = pt.x - part->dock->rect.x - offset.x; - else + else dock_drop_offset = pt.y - part->dock->rect.y - offset.y; // toolbars may only be moved in and to fixed-pane docks, // otherwise we will try to float the pane. Also, the pane // should float if being dragged over center pane windows - if (!part->dock->fixed || part->dock->dock_direction == wxAUI_DOCK_CENTER) + if (!part->dock->fixed || part->dock->dock_direction == wxAUI_DOCK_CENTER || + pt.x >= cli_size.x || pt.x <= 0 || pt.y >= cli_size.y || pt.y <= 0) { - if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && - (drop.IsFloatable() || - (part->dock->dock_direction != wxAUI_DOCK_CENTER && - part->dock->dock_direction != wxAUI_DOCK_NONE))) + if (m_lastRect.IsEmpty() || m_lastRect.Contains(pt.x, pt.y )) { - drop.Float(); + m_skipping = true; + } + else + { + if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && drop.IsFloatable()) + { + drop.Float(); + } + + m_skipping = false; + + return ProcessDockResult(target, drop); } + drop.Position(pt.x - GetDockPixelOffset(drop) - offset.x); + return ProcessDockResult(target, drop); } + m_skipping = false; + + m_lastRect = part->dock->rect; + m_lastRect.Inflate( 15, 15 ); + drop.Dock(). Direction(part->dock->dock_direction). Layer(part->dock->dock_layer). @@ -2227,15 +3036,26 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, Position(dock_drop_offset); if (( - ((pt.y < part->dock->rect.y + 2) && part->dock->IsHorizontal()) || - ((pt.x < part->dock->rect.x + 2) && part->dock->IsVertical()) + ((pt.y < part->dock->rect.y + 1) && part->dock->IsHorizontal()) || + ((pt.x < part->dock->rect.x + 1) && part->dock->IsVertical()) ) && part->dock->panes.GetCount() > 1) { - int row = drop.dock_row; - DoInsertDockRow(panes, part->dock->dock_direction, - part->dock->dock_layer, - part->dock->dock_row); - drop.dock_row = row; + if ((part->dock->dock_direction == wxAUI_DOCK_TOP) || + (part->dock->dock_direction == wxAUI_DOCK_LEFT)) + { + int row = drop.dock_row; + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row); + drop.dock_row = row; + } + else + { + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row+1); + drop.dock_row = part->dock->dock_row+1; + } } if (( @@ -2243,10 +3063,22 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, ((pt.x > part->dock->rect.x + part->dock->rect.width - 2 ) && part->dock->IsVertical()) ) && part->dock->panes.GetCount() > 1) { - DoInsertDockRow(panes, part->dock->dock_direction, - part->dock->dock_layer, - part->dock->dock_row+1); - drop.dock_row = part->dock->dock_row+1; + if ((part->dock->dock_direction == wxAUI_DOCK_TOP) || + (part->dock->dock_direction == wxAUI_DOCK_LEFT)) + { + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row+1); + drop.dock_row = part->dock->dock_row+1; + } + else + { + int row = drop.dock_row; + DoInsertDockRow(panes, part->dock->dock_direction, + part->dock->dock_layer, + part->dock->dock_row); + drop.dock_row = row; + } } return ProcessDockResult(target, drop); @@ -2258,16 +3090,16 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, if (!part) return false; - if (part->type == wxDockUIPart::typePaneBorder || - part->type == wxDockUIPart::typeCaption || - part->type == wxDockUIPart::typeGripper || - part->type == wxDockUIPart::typePaneButton || - part->type == wxDockUIPart::typePane || - part->type == wxDockUIPart::typePaneSizer || - part->type == wxDockUIPart::typeDockSizer || - part->type == wxDockUIPart::typeBackground) + if (part->type == wxAuiDockUIPart::typePaneBorder || + part->type == wxAuiDockUIPart::typeCaption || + part->type == wxAuiDockUIPart::typeGripper || + part->type == wxAuiDockUIPart::typePaneButton || + part->type == wxAuiDockUIPart::typePane || + part->type == wxAuiDockUIPart::typePaneSizer || + part->type == wxAuiDockUIPart::typeDockSizer || + part->type == wxAuiDockUIPart::typeBackground) { - if (part->type == wxDockUIPart::typeDockSizer) + if (part->type == wxAuiDockUIPart::typeDockSizer) { if (part->dock->panes.GetCount() != 1) return false; @@ -2373,23 +3205,19 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, insert_layer = 0; insert_dock_row = true; - if (pt.x >= part->rect.x && - pt.x < part->rect.x+new_row_pixels_x) - insert_dir = wxAUI_DOCK_LEFT; - else - if (pt.y >= part->rect.y && - pt.y < part->rect.y+new_row_pixels_y) - insert_dir = wxAUI_DOCK_TOP; - else - if (pt.x >= part->rect.x + part->rect.width-new_row_pixels_x && - pt.x < part->rect.x + part->rect.width) - insert_dir = wxAUI_DOCK_RIGHT; - else - if (pt.y >= part->rect.y+ part->rect.height-new_row_pixels_y && - pt.y < part->rect.y + part->rect.height) - insert_dir = wxAUI_DOCK_BOTTOM; - else - return false; + const wxRect& pr = part->rect; + if (pt.x >= pr.x && pt.x < pr.x + new_row_pixels_x) + insert_dir = wxAUI_DOCK_LEFT; + else if (pt.y >= pr.y && pt.y < pr.y + new_row_pixels_y) + insert_dir = wxAUI_DOCK_TOP; + else if (pt.x >= pr.x + pr.width - new_row_pixels_x && + pt.x < pr.x + pr.width) + insert_dir = wxAUI_DOCK_RIGHT; + else if (pt.y >= pr.y+ pr.height - new_row_pixels_y && + pt.y < pr.y + pr.height) + insert_dir = wxAUI_DOCK_BOTTOM; + else + return false; insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1; } @@ -2415,7 +3243,7 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, offset = pt.y - part->rect.y; size = part->rect.GetHeight(); } - else + else { offset = pt.x - part->rect.x; size = part->rect.GetWidth(); @@ -2459,59 +3287,69 @@ bool wxFrameManager::DoDrop(wxDockInfoArray& docks, } -void wxFrameManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event)) +void wxAuiManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event)) { - if (!m_hint_wnd || m_hint_fadeamt >= 50) + if (!m_hintWnd || m_hintFadeAmt >= m_hintFadeMax) { - m_hint_fadetimer.Stop(); + m_hintFadeTimer.Stop(); + Disconnect(m_hintFadeTimer.GetId(), wxEVT_TIMER, + wxTimerEventHandler(wxAuiManager::OnHintFadeTimer)); return; } - m_hint_fadeamt += 5; - m_hint_wnd->SetTranslucency(m_hint_fadeamt); + m_hintFadeAmt += 4; + m_hintWnd->SetTransparent(m_hintFadeAmt); } -void wxFrameManager::ShowHint(const wxRect& rect) +void wxAuiManager::ShowHint(const wxRect& rect) { - if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) != 0 && m_hint_wnd) + if (m_hintWnd) { - if (m_last_hint == rect) + // if the hint rect is the same as last time, don't do anything + if (m_lastHint == rect) return; - m_last_hint = rect; + m_lastHint = rect; - int initial_fade = 50; - if (m_flags & wxAUI_MGR_TRANSPARENT_HINT_FADE) - initial_fade = 0; + m_hintFadeAmt = m_hintFadeMax; - if (! m_hint_wnd->IsShown()) - m_hint_wnd->Show(); + if ((m_flags & wxAUI_MGR_HINT_FADE) + && !((wxDynamicCast(m_hintWnd, wxPseudoTransparentFrame)) && + (m_flags & wxAUI_MGR_NO_VENETIAN_BLINDS_FADE)) + ) + m_hintFadeAmt = 0; + + m_hintWnd->SetSize(rect); + m_hintWnd->SetTransparent(m_hintFadeAmt); + + if (!m_hintWnd->IsShown()) + m_hintWnd->Show(); // if we are dragging a floating pane, set the focus // back to that floating pane (otherwise it becomes unfocused) - if (m_action == actionDragFloatingPane && m_action_window) - m_action_window->SetFocus(); + if (m_action == actionDragFloatingPane && m_actionWindow) + m_actionWindow->SetFocus(); - m_hint_wnd->SetTranslucency(initial_fade); - m_hint_wnd->SetSize(rect); - m_hint_wnd->Raise(); - + m_hintWnd->Raise(); - if (m_flags & wxAUI_MGR_TRANSPARENT_HINT_FADE) + + if (m_hintFadeAmt != m_hintFadeMax) // Only fade if we need to { // start fade in timer - m_hint_fadeamt = 0; - m_hint_fadetimer.SetOwner(this, 101); - m_hint_fadetimer.Start(5); + m_hintFadeTimer.SetOwner(this); + m_hintFadeTimer.Start(5); + Connect(m_hintFadeTimer.GetId(), wxEVT_TIMER, + wxTimerEventHandler(wxAuiManager::OnHintFadeTimer)); } } - - else // Not using a translucent hint window... + else // Not using a transparent hint window... { - - if (m_last_hint != rect) + if (!(m_flags & wxAUI_MGR_RECTANGLE_HINT)) + return; + + if (m_lastHint != rect) { // remove the last hint rectangle - m_last_hint = rect; + m_lastHint = rect; m_frame->Refresh(); m_frame->Update(); } @@ -2523,10 +3361,11 @@ void wxFrameManager::ShowHint(const wxRect& rect) int i, pane_count; for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) { - wxPaneInfo& pane = m_panes.Item(i); + wxAuiPaneInfo& pane = m_panes.Item(i); if (pane.IsFloating() && - pane.frame->IsShown()) + pane.frame && + pane.frame->IsShown()) { wxRect rect = pane.frame->GetRect(); #ifdef __WXGTK__ @@ -2540,7 +3379,12 @@ void wxFrameManager::ShowHint(const wxRect& rect) } } - screendc.SetClippingRegion(clip); + // As we can only hide the hint by redrawing the managed window, we + // need to clip the region to the managed window too or we get + // nasty redrawn problems. + clip.Intersect(m_frame->GetRect()); + + screendc.SetDeviceClippingRegion(clip); wxBitmap stipple = wxPaneCreateStippleBitmap(); wxBrush brush(stipple); @@ -2554,55 +3398,107 @@ void wxFrameManager::ShowHint(const wxRect& rect) } } -void wxFrameManager::HideHint() +void wxAuiManager::HideHint() { // hides a transparent window hint, if there is one - if (m_hint_wnd) + if (m_hintWnd) { - m_hint_wnd->SetTranslucency(0); - m_hint_fadetimer.Stop(); - m_last_hint = wxRect(); + if (m_hintWnd->IsShown()) + m_hintWnd->Show(false); + m_hintWnd->SetTransparent(0); + m_hintFadeTimer.Stop(); + // In case this is called while a hint fade is going, we need to + // disconnect the event handler. + Disconnect(m_hintFadeTimer.GetId(), wxEVT_TIMER, + wxTimerEventHandler(wxAuiManager::OnHintFadeTimer)); + m_lastHint = wxRect(); return; } // hides a painted hint by redrawing the frame window - if (!m_last_hint.IsEmpty()) + if (!m_lastHint.IsEmpty()) { m_frame->Refresh(); m_frame->Update(); - m_last_hint = wxRect(); + m_lastHint = wxRect(); } } +void wxAuiManager::OnHintActivate(wxActivateEvent& WXUNUSED(event)) +{ + // Do nothing so this event isn't handled in the base handlers. + // Letting the hint window activate without this handler can lead to + // weird behaviour on Mac where the menu is switched out to the top + // window's menu in MDI applications when it shouldn't be. So since + // we don't want user interaction with the hint window anyway, we just + // prevent it from activating here. +} -// DrawHintRect() draws a drop hint rectangle. First calls DoDrop() to -// determine the exact position the pane would be at were if dropped. If -// the pame would indeed become docked at the specified drop point, -// DrawHintRect() then calls ShowHint() to indicate this drop rectangle. -// "pane_window" is the window pointer of the pane being dragged, pt is -// the mouse position, in client coordinates -void wxFrameManager::DrawHintRect(wxWindow* pane_window, - const wxPoint& pt, - const wxPoint& offset) -{ - wxRect rect; - // we need to paint a hint rectangle; to find out the exact hint rectangle, + +void wxAuiManager::StartPaneDrag(wxWindow* pane_window, + const wxPoint& offset) +{ + wxAuiPaneInfo& pane = GetPane(pane_window); + if (!pane.IsOk()) + return; + + if (pane.IsToolbar()) + { + m_action = actionDragToolbarPane; + } + else + { + m_action = actionDragFloatingPane; + } + + m_actionWindow = pane_window; + m_actionOffset = offset; + m_frame->CaptureMouse(); + + if (pane.frame) + { + wxRect window_rect = pane.frame->GetRect(); + wxRect client_rect = pane.frame->GetClientRect(); + wxPoint client_pt = pane.frame->ClientToScreen(client_rect.GetTopLeft()); + wxPoint origin_pt = client_pt - window_rect.GetTopLeft(); + m_actionOffset += origin_pt; + } +} + + +// CalculateHintRect() calculates the drop hint rectangle. The method +// first calls DoDrop() to determine the exact position the pane would +// be at were if dropped. If the pane would indeed become docked at the +// specified drop point, the rectangle hint will be returned in +// screen coordinates. Otherwise, an empty rectangle is returned. +// |pane_window| is the window pointer of the pane being dragged, |pt| is +// the mouse position, in client coordinates. |offset| describes the offset +// that the mouse is from the upper-left corner of the item being dragged + +wxRect wxAuiManager::CalculateHintRect(wxWindow* pane_window, + const wxPoint& pt, + const wxPoint& offset) +{ + wxRect rect; + + // we need to paint a hint rectangle; to find out the exact hint rectangle, // we will create a new temporary layout and then measure the resulting // rectangle; we will create a copy of the docking structures (m_dock) // so that we don't modify the real thing on screen int i, pane_count, part_count; - wxDockInfoArray docks; - wxPaneInfoArray panes; - wxDockUIPartArray uiparts; - wxPaneInfo hint = GetPane(pane_window); + wxAuiDockInfoArray docks; + wxAuiPaneInfoArray panes; + wxAuiDockUIPartArray uiparts; + wxAuiPaneInfo hint = GetPane(pane_window); hint.name = wxT("__HINT__"); + hint.PaneBorder(true); hint.Show(); if (!hint.IsOk()) - return; + return rect; CopyDocksAndPanes(docks, panes, m_docks, m_panes); @@ -2621,8 +3517,7 @@ void wxFrameManager::DrawHintRect(wxWindow* pane_window, // find out where the new pane would be if (!DoDrop(docks, panes, hint, pt, offset)) { - HideHint(); - return; + return rect; } panes.Add(hint); @@ -2635,9 +3530,9 @@ void wxFrameManager::DrawHintRect(wxWindow* pane_window, for (i = 0, part_count = uiparts.GetCount(); i < part_count; ++i) { - wxDockUIPart& part = uiparts.Item(i); + wxAuiDockUIPart& part = uiparts.Item(i); - if (part.type == wxDockUIPart::typePaneBorder && + if (part.type == wxAuiDockUIPart::typePaneBorder && part.pane && part.pane->name == wxT("__HINT__")) { rect = wxRect(part.sizer_item->GetPosition(), @@ -2650,32 +3545,101 @@ void wxFrameManager::DrawHintRect(wxWindow* pane_window, if (rect.IsEmpty()) { - HideHint(); - return; + return rect; } // actually show the hint rectangle on the screen m_frame->ClientToScreen(&rect.x, &rect.y); - ShowHint(rect); + + if ( m_frame->GetLayoutDirection() == wxLayout_RightToLeft ) + { + // Mirror rectangle in RTL mode + rect.x -= rect.GetWidth(); + } + + return rect; +} + +// DrawHintRect() calculates the hint rectangle by calling +// CalculateHintRect(). If there is a rectangle, it shows it +// by calling ShowHint(), otherwise it hides any hint +// rectangle currently shown +void wxAuiManager::DrawHintRect(wxWindow* pane_window, + const wxPoint& pt, + const wxPoint& offset) +{ + wxRect rect = CalculateHintRect(pane_window, pt, offset); + + if (rect.IsEmpty()) + { + HideHint(); + } + else + { + ShowHint(rect); + } } -void wxFrameManager::OnFloatingPaneMoveStart(wxWindow* wnd) +void wxAuiManager::OnFloatingPaneMoveStart(wxWindow* wnd) { // try to find the pane - wxPaneInfo& pane = GetPane(wnd); + wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + if(!pane.frame) + return; + if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG) - pane.frame->SetTranslucency(150); + pane.frame->SetTransparent(150); } -void wxFrameManager::OnFloatingPaneMoving(wxWindow* wnd) +void wxAuiManager::OnFloatingPaneMoving(wxWindow* wnd, wxDirection dir) { // try to find the pane - wxPaneInfo& pane = GetPane(wnd); + wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + if(!pane.frame) + return; + wxPoint pt = ::wxGetMousePosition(); + +#if 0 + // Adapt pt to direction + if (dir == wxNORTH) + { + // move to pane's upper border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + // and some more pixels for the title bar + pt.y -= 5; + } + else if (dir == wxWEST) + { + // move to pane's left border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } + else if (dir == wxEAST) + { + // move to pane's right border + wxPoint pos( wnd->GetSize().x, 0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } + else if (dir == wxSOUTH) + { + // move to pane's bottom border + wxPoint pos( 0, wnd->GetSize().y ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + } +#else + wxUnusedVar(dir); +#endif + wxPoint client_pt = m_frame->ScreenToClient(pt); // calculate the offset from the upper left-hand corner @@ -2686,27 +3650,24 @@ void wxFrameManager::OnFloatingPaneMoving(wxWindow* wnd) // no hint for toolbar floating windows if (pane.IsToolbar() && m_action == actionDragFloatingPane) { - if (m_action == actionDragFloatingPane) - { - wxDockInfoArray docks; - wxPaneInfoArray panes; - wxDockUIPartArray uiparts; - wxPaneInfo hint = pane; + wxAuiDockInfoArray docks; + wxAuiPaneInfoArray panes; + wxAuiDockUIPartArray uiparts; + wxAuiPaneInfo hint = pane; - CopyDocksAndPanes(docks, panes, m_docks, m_panes); + CopyDocksAndPanes(docks, panes, m_docks, m_panes); - // find out where the new pane would be - if (!DoDrop(docks, panes, hint, client_pt)) - return; - if (hint.IsFloating()) - return; + // find out where the new pane would be + if (!DoDrop(docks, panes, hint, client_pt)) + return; + if (hint.IsFloating()) + return; - pane = hint; - m_action = actionDragToolbarPane; - m_action_window = pane.window; + pane = hint; + m_action = actionDragToolbarPane; + m_actionWindow = pane.window; - Update(); - } + Update(); return; } @@ -2714,7 +3675,7 @@ void wxFrameManager::OnFloatingPaneMoving(wxWindow* wnd) // if a key modifier is pressed while dragging the frame, // don't dock the window - if (wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT)) + if (!CanDockPanel(pane)) { HideHint(); return; @@ -2735,13 +3696,53 @@ void wxFrameManager::OnFloatingPaneMoving(wxWindow* wnd) m_frame->Update(); } -void wxFrameManager::OnFloatingPaneMoved(wxWindow* wnd) +void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir) { // try to find the pane - wxPaneInfo& pane = GetPane(wnd); + wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + if(!pane.frame) + return; + wxPoint pt = ::wxGetMousePosition(); + +#if 0 + // Adapt pt to direction + if (dir == wxNORTH) + { + // move to pane's upper border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + // and some more pixels for the title bar + pt.y -= 10; + } + else if (dir == wxWEST) + { + // move to pane's left border + wxPoint pos( 0,0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } + else if (dir == wxEAST) + { + // move to pane's right border + wxPoint pos( wnd->GetSize().x, 0 ); + pos = wnd->ClientToScreen( pos ); + pt.x = pos.x; + } + else if (dir == wxSOUTH) + { + // move to pane's bottom border + wxPoint pos( 0, wnd->GetSize().y ); + pos = wnd->ClientToScreen( pos ); + pt.y = pos.y; + } +#else + wxUnusedVar(dir); +#endif + wxPoint client_pt = m_frame->ScreenToClient(pt); // calculate the offset from the upper left-hand corner @@ -2749,15 +3750,14 @@ void wxFrameManager::OnFloatingPaneMoved(wxWindow* wnd) wxPoint frame_pos = pane.frame->GetPosition(); wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y); - // if a key modifier is pressed while dragging the frame, // don't dock the window - if (!wxGetKeyState(WXK_CONTROL) && !wxGetKeyState(WXK_ALT)) + if (CanDockPanel(pane)) { // do the drop calculation DoDrop(m_docks, m_panes, pane, client_pt, action_offset); } - + // if the pane is still floating, update it's floating // position (that we store) if (pane.IsFloating()) @@ -2765,7 +3765,11 @@ void wxFrameManager::OnFloatingPaneMoved(wxWindow* wnd) pane.floating_pos = pane.frame->GetPosition(); if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG) - pane.frame->SetTranslucency(255); + pane.frame->SetTransparent(255); + } + else if (m_hasMaximized) + { + RestoreMaximizedPane(); } Update(); @@ -2773,25 +3777,28 @@ void wxFrameManager::OnFloatingPaneMoved(wxWindow* wnd) HideHint(); } -void wxFrameManager::OnFloatingPaneResized(wxWindow* wnd, const wxSize& size) +void wxAuiManager::OnFloatingPaneResized(wxWindow* wnd, const wxRect& rect) { // try to find the pane - wxPaneInfo& pane = GetPane(wnd); + wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); - pane.floating_size = size; + pane.FloatingSize(rect.GetWidth(), rect.GetHeight()); + + // the top-left position may change as well as the size + pane.FloatingPosition(rect.x, rect.y); } -void wxFrameManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt) +void wxAuiManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt) { // try to find the pane - wxPaneInfo& pane = GetPane(wnd); + wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); // fire pane close event - wxFrameManagerEvent e(wxEVT_AUI_PANECLOSE); + wxAuiManagerEvent e(wxEVT_AUI_PANE_CLOSE); e.SetPane(&pane); e.SetCanVeto(evt.CanVeto()); ProcessMgrEvent(e); @@ -2801,27 +3808,27 @@ void wxFrameManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt) evt.Veto(); return; } - else + else { - // reparent the pane window back to us and - // prepare the frame window for destruction - pane.window->Show(false); - pane.window->Reparent(m_frame); - pane.frame = NULL; - pane.Hide(); + // close the pane, but check that it + // still exists in our pane array first + // (the event handler above might have removed it) + + wxAuiPaneInfo& check = GetPane(wnd); + if (check.IsOk()) + { + ClosePane(pane); + } } } -void wxFrameManager::OnFloatingPaneActivated(wxWindow* wnd) +void wxAuiManager::OnFloatingPaneActivated(wxWindow* wnd) { - if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) + if ((GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) && GetPane(wnd).IsOk()) { - // try to find the pane - wxASSERT_MSG(GetPane(wnd).IsOk(), wxT("Pane window not found")); - - SetActivePane(m_panes, wnd); + SetActivePane(wnd); Repaint(); } } @@ -2830,43 +3837,47 @@ void wxFrameManager::OnFloatingPaneActivated(wxWindow* wnd) // backgrounds, captions, grippers, pane borders and buttons. // It renders the entire user interface. -void wxFrameManager::OnRender(wxFrameManagerEvent& evt) +void wxAuiManager::OnRender(wxAuiManagerEvent& evt) { + // if the frame is about to be deleted, don't bother + if (!m_frame || wxPendingDelete.Member(m_frame)) + return; + wxDC* dc = evt.GetDC(); - + #ifdef __WXMAC__ dc->Clear() ; #endif int i, part_count; - for (i = 0, part_count = m_uiparts.GetCount(); + for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i) { - wxDockUIPart& part = m_uiparts.Item(i); + wxAuiDockUIPart& part = m_uiParts.Item(i); - // don't draw hidden pane items - if (part.sizer_item && !part.sizer_item->IsShown()) + // don't draw hidden pane items or items that aren't windows + if (part.sizer_item && ((!part.sizer_item->IsWindow() && !part.sizer_item->IsSpacer() && !part.sizer_item->IsSizer()) || !part.sizer_item->IsShown())) continue; switch (part.type) { - case wxDockUIPart::typeDockSizer: - case wxDockUIPart::typePaneSizer: - m_art->DrawSash(*dc, part.orientation, part.rect); + case wxAuiDockUIPart::typeDockSizer: + case wxAuiDockUIPart::typePaneSizer: + m_art->DrawSash(*dc, m_frame, part.orientation, part.rect); break; - case wxDockUIPart::typeBackground: - m_art->DrawBackground(*dc, part.orientation, part.rect); + case wxAuiDockUIPart::typeBackground: + m_art->DrawBackground(*dc, m_frame, part.orientation, part.rect); break; - case wxDockUIPart::typeCaption: - m_art->DrawCaption(*dc, part.pane->caption, part.rect, *part.pane); + case wxAuiDockUIPart::typeCaption: + m_art->DrawCaption(*dc, m_frame, part.pane->caption, part.rect, *part.pane); break; - case wxDockUIPart::typeGripper: - m_art->DrawGripper(*dc, part.rect, *part.pane); + case wxAuiDockUIPart::typeGripper: + m_art->DrawGripper(*dc, m_frame, part.rect, *part.pane); break; - case wxDockUIPart::typePaneBorder: - m_art->DrawBorder(*dc, part.rect, *part.pane); + case wxAuiDockUIPart::typePaneBorder: + m_art->DrawBorder(*dc, m_frame, part.rect, *part.pane); break; - case wxDockUIPart::typePaneButton: - m_art->DrawPaneButton(*dc, part.button->button_id, + case wxAuiDockUIPart::typePaneButton: + m_art->DrawPaneButton(*dc, m_frame, part.button->button_id, wxAUI_BUTTON_STATE_NORMAL, part.rect, *part.pane); break; } @@ -2875,21 +3886,22 @@ void wxFrameManager::OnRender(wxFrameManagerEvent& evt) // Render() fire a render event, which is normally handled by -// wxFrameManager::OnRender(). This allows the render function to +// wxAuiManager::OnRender(). This allows the render function to // be overridden via the render event. This can be useful for paintin -// custom graphics in the main window. Default behavior can be +// custom graphics in the main window. Default behaviour can be // invoked in the overridden function by calling OnRender() -void wxFrameManager::Render(wxDC* dc) +void wxAuiManager::Render(wxDC* dc) { - wxFrameManagerEvent e(wxEVT_AUI_RENDER); + wxAuiManagerEvent e(wxEVT_AUI_RENDER); + e.SetManager(this); e.SetDC(dc); ProcessMgrEvent(e); } -void wxFrameManager::Repaint(wxDC* dc) +void wxAuiManager::Repaint(wxDC* dc) { -#ifdef __WXMAC__ +#ifdef __WXMAC__ if ( dc == NULL ) { m_frame->Refresh() ; @@ -2924,13 +3936,13 @@ void wxFrameManager::Repaint(wxDC* dc) delete client_dc; } -void wxFrameManager::OnPaint(wxPaintEvent& WXUNUSED(event)) +void wxAuiManager::OnPaint(wxPaintEvent& WXUNUSED(event)) { wxPaintDC dc(m_frame); Repaint(&dc); } -void wxFrameManager::OnEraseBackground(wxEraseEvent& event) +void wxAuiManager::OnEraseBackground(wxEraseEvent& event) { #ifdef __WXMAC__ event.Skip() ; @@ -2939,30 +3951,63 @@ void wxFrameManager::OnEraseBackground(wxEraseEvent& event) #endif } -void wxFrameManager::OnSize(wxSizeEvent& WXUNUSED(event)) +void wxAuiManager::OnSize(wxSizeEvent& event) { if (m_frame) { DoFrameLayout(); Repaint(); + +#if wxUSE_MDI + if (wxDynamicCast(m_frame, wxMDIParentFrame)) + { + // for MDI parent frames, this event must not + // be "skipped". In other words, the parent frame + // must not be allowed to resize the client window + // after we are finished processing sizing changes + return; + } +#endif } + event.Skip(); } +void wxAuiManager::OnFindManager(wxAuiManagerEvent& evt) +{ + // get the window we are managing, if none, return NULL + wxWindow* window = GetManagedWindow(); + if (!window) + { + evt.SetManager(NULL); + return; + } + + // if we are managing a child frame, get the 'real' manager + if (wxDynamicCast(window, wxAuiFloatingFrame)) + { + wxAuiFloatingFrame* float_frame = static_cast(window); + evt.SetManager(float_frame->GetOwnerManager()); + return; + } -void wxFrameManager::OnSetCursor(wxSetCursorEvent& event) + // return pointer to ourself + evt.SetManager(this); +} + +void wxAuiManager::OnSetCursor(wxSetCursorEvent& event) { // determine cursor - wxDockUIPart* part = HitTest(event.GetX(), event.GetY()); + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); wxCursor cursor = wxNullCursor; if (part) { - if (part->type == wxDockUIPart::typeDockSizer || - part->type == wxDockUIPart::typePaneSizer) + if (part->type == wxAuiDockUIPart::typeDockSizer || + part->type == wxAuiDockUIPart::typePaneSizer) { // a dock may not be resized if it has a single // pane which is not resizable - if (part->type == wxDockUIPart::typeDockSizer && part->dock && + if (part->type == wxAuiDockUIPart::typeDockSizer && part->dock && part->dock->panes.GetCount() == 1 && part->dock->panes.Item(0)->IsFixed()) return; @@ -2973,10 +4018,10 @@ void wxFrameManager::OnSetCursor(wxSetCursorEvent& event) if (part->orientation == wxVERTICAL) cursor = wxCursor(wxCURSOR_SIZEWE); - else + else cursor = wxCursor(wxCURSOR_SIZENS); } - else if (part->type == wxDockUIPart::typeGripper) + else if (part->type == wxAuiDockUIPart::typeGripper) { cursor = wxCursor(wxCURSOR_SIZING); } @@ -2987,10 +4032,12 @@ void wxFrameManager::OnSetCursor(wxSetCursorEvent& event) -void wxFrameManager::UpdateButtonOnScreen(wxDockUIPart* button_ui_part, - const wxMouseEvent& event) +void wxAuiManager::UpdateButtonOnScreen(wxAuiDockUIPart* button_ui_part, + const wxMouseEvent& event) { - wxDockUIPart* hit_test = HitTest(event.GetX(), event.GetY()); + wxAuiDockUIPart* hit_test = HitTest(event.GetX(), event.GetY()); + if (!hit_test || !button_ui_part) + return; int state = wxAUI_BUTTON_STATE_NORMAL; @@ -2998,7 +4045,7 @@ void wxFrameManager::UpdateButtonOnScreen(wxDockUIPart* button_ui_part, { if (event.LeftDown()) state = wxAUI_BUTTON_STATE_PRESSED; - else + else state = wxAUI_BUTTON_STATE_HOVER; } else @@ -3016,27 +4063,33 @@ void wxFrameManager::UpdateButtonOnScreen(wxDockUIPart* button_ui_part, if (pt.x != 0 || pt.y != 0) cdc.SetDeviceOrigin(pt.x, pt.y); - m_art->DrawPaneButton(cdc, - button_ui_part->button->button_id, - state, - button_ui_part->rect, - *hit_test->pane); + if (hit_test->pane) + { + m_art->DrawPaneButton(cdc, m_frame, + button_ui_part->button->button_id, + state, + button_ui_part->rect, + *hit_test->pane); + } } -void wxFrameManager::OnLeftDown(wxMouseEvent& event) +void wxAuiManager::OnLeftDown(wxMouseEvent& event) { - wxDockUIPart* part = HitTest(event.GetX(), event.GetY()); + m_currentDragItem = -1; + + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); if (part) { - if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) - return; - - if (part->type == wxDockUIPart::typeDockSizer || - part->type == wxDockUIPart::typePaneSizer) + if (part->type == wxAuiDockUIPart::typeDockSizer || + part->type == wxAuiDockUIPart::typePaneSizer) { + // Removing this restriction so that a centre pane can be resized + //if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) + // return; + // a dock may not be resized if it has a single // pane which is not resizable - if (part->type == wxDockUIPart::typeDockSizer && part->dock && + if (part->type == wxAuiDockUIPart::typeDockSizer && part->dock && part->dock->panes.GetCount() == 1 && part->dock->panes.Item(0)->IsFixed()) return; @@ -3046,36 +4099,59 @@ void wxFrameManager::OnLeftDown(wxMouseEvent& event) return; m_action = actionResize; - m_action_part = part; - m_action_hintrect = wxRect(); - m_action_start = wxPoint(event.m_x, event.m_y); - m_action_offset = wxPoint(event.m_x - part->rect.x, + m_actionPart = part; + m_actionHintRect = wxRect(); + m_actionStart = wxPoint(event.m_x, event.m_y); + m_actionOffset = wxPoint(event.m_x - part->rect.x, event.m_y - part->rect.y); m_frame->CaptureMouse(); } - else if (part->type == wxDockUIPart::typePaneButton) + else if (part->type == wxAuiDockUIPart::typePaneButton) { m_action = actionClickButton; - m_action_part = part; - m_action_start = wxPoint(event.m_x, event.m_y); + m_actionPart = part; + m_actionStart = wxPoint(event.m_x, event.m_y); m_frame->CaptureMouse(); UpdateButtonOnScreen(part, event); } - else if (part->type == wxDockUIPart::typeCaption || - part->type == wxDockUIPart::typeGripper) + else if (part->type == wxAuiDockUIPart::typeCaption || + part->type == wxAuiDockUIPart::typeGripper) { + // if we are managing a wxAuiFloatingFrame window, then + // we are an embedded wxAuiManager inside the wxAuiFloatingFrame. + // We want to initiate a toolbar drag in our owner manager + wxWindow* managed_wnd = GetManagedWindow(); + + if (part->pane && + part->pane->window && + managed_wnd && + wxDynamicCast(managed_wnd, wxAuiFloatingFrame)) + { + wxAuiFloatingFrame* floating_frame = (wxAuiFloatingFrame*)managed_wnd; + wxAuiManager* owner_mgr = floating_frame->GetOwnerManager(); + owner_mgr->StartPaneDrag(part->pane->window, + wxPoint(event.m_x - part->rect.x, + event.m_y - part->rect.y)); + return; + } + + + if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) { // set the caption as active - SetActivePane(m_panes, part->pane->window); + SetActivePane(part->pane->window); Repaint(); } + if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) + return; + m_action = actionClickCaption; - m_action_part = part; - m_action_start = wxPoint(event.m_x, event.m_y); - m_action_offset = wxPoint(event.m_x - part->rect.x, + m_actionPart = part; + m_actionStart = wxPoint(event.m_x, event.m_y); + m_actionOffset = wxPoint(event.m_x - part->rect.x, event.m_y - part->rect.y); m_frame->CaptureMouse(); } @@ -3096,211 +4172,310 @@ void wxFrameManager::OnLeftDown(wxMouseEvent& event) #endif } - -void wxFrameManager::OnLeftUp(wxMouseEvent& event) +/// Ends a resize action, or for live update, resizes the sash +bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event) { - if (m_action == actionResize) + // resize the dock or the pane + if (m_actionPart && m_actionPart->type==wxAuiDockUIPart::typeDockSizer) { - m_frame->ReleaseMouse(); + // first, we must calculate the maximum size the dock may be + int sashSize = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); - // get rid of the hint rectangle - wxScreenDC dc; - DrawResizeHint(dc, m_action_hintrect); + int used_width = 0, used_height = 0; - // resize the dock or the pane - if (m_action_part && m_action_part->type==wxDockUIPart::typeDockSizer) + wxSize client_size = m_frame->GetClientSize(); + + size_t dock_i, dock_count = m_docks.GetCount(); + for (dock_i = 0; dock_i < dock_count; ++dock_i) { - wxRect& rect = m_action_part->dock->rect; + wxAuiDockInfo& dock = m_docks.Item(dock_i); + if (dock.dock_direction == wxAUI_DOCK_TOP || + dock.dock_direction == wxAUI_DOCK_BOTTOM) + { + used_height += dock.size; + } + if (dock.dock_direction == wxAUI_DOCK_LEFT || + dock.dock_direction == wxAUI_DOCK_RIGHT) + { + used_width += dock.size; + } + if (dock.resizable) + used_width += sashSize; + } - wxPoint new_pos(event.m_x - m_action_offset.x, - event.m_y - m_action_offset.y); - switch (m_action_part->dock->dock_direction) + int available_width = client_size.GetWidth() - used_width; + int available_height = client_size.GetHeight() - used_height; + + +#if wxUSE_STATUSBAR + // if there's a status control, the available + // height decreases accordingly + if (wxDynamicCast(m_frame, wxFrame)) + { + wxFrame* frame = static_cast(m_frame); + wxStatusBar* status = frame->GetStatusBar(); + if (status) { - case wxAUI_DOCK_LEFT: - m_action_part->dock->size = new_pos.x - rect.x; - break; - case wxAUI_DOCK_TOP: - m_action_part->dock->size = new_pos.y - rect.y; - break; - case wxAUI_DOCK_RIGHT: - m_action_part->dock->size = rect.x + rect.width - - new_pos.x - m_action_part->rect.GetWidth(); - break; - case wxAUI_DOCK_BOTTOM: - m_action_part->dock->size = rect.y + rect.height - - new_pos.y - m_action_part->rect.GetHeight(); - break; + wxSize status_client_size = status->GetClientSize(); + available_height -= status_client_size.GetHeight(); } - - Update(); - Repaint(NULL); } - else if (m_action_part && - m_action_part->type == wxDockUIPart::typePaneSizer) +#endif + + wxRect& rect = m_actionPart->dock->rect; + + wxPoint new_pos(event.m_x - m_actionOffset.x, + event.m_y - m_actionOffset.y); + int new_size, old_size = m_actionPart->dock->size; + + switch (m_actionPart->dock->dock_direction) { - wxDockInfo& dock = *m_action_part->dock; - wxPaneInfo& pane = *m_action_part->pane; + case wxAUI_DOCK_LEFT: + new_size = new_pos.x - rect.x; + if (new_size-old_size > available_width) + new_size = old_size+available_width; + m_actionPart->dock->size = new_size; + break; + case wxAUI_DOCK_TOP: + new_size = new_pos.y - rect.y; + if (new_size-old_size > available_height) + new_size = old_size+available_height; + m_actionPart->dock->size = new_size; + break; + case wxAUI_DOCK_RIGHT: + new_size = rect.x + rect.width - new_pos.x - + m_actionPart->rect.GetWidth(); + if (new_size-old_size > available_width) + new_size = old_size+available_width; + m_actionPart->dock->size = new_size; + break; + case wxAUI_DOCK_BOTTOM: + new_size = rect.y + rect.height - + new_pos.y - m_actionPart->rect.GetHeight(); + if (new_size-old_size > available_height) + new_size = old_size+available_height; + m_actionPart->dock->size = new_size; + break; + } - int total_proportion = 0; - int dock_pixels = 0; - int new_pixsize = 0; + Update(); + Repaint(NULL); + } + else if (m_actionPart && + m_actionPart->type == wxAuiDockUIPart::typePaneSizer) + { + wxAuiDockInfo& dock = *m_actionPart->dock; + wxAuiPaneInfo& pane = *m_actionPart->pane; - int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE); - int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE); - int sash_size = m_art->GetMetric(wxAUI_ART_SASH_SIZE); + int total_proportion = 0; + int dock_pixels = 0; + int new_pixsize = 0; - wxPoint new_pos(event.m_x - m_action_offset.x, - event.m_y - m_action_offset.y); + int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); + int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int sashSize = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); - // determine the pane rectangle by getting the pane part - wxDockUIPart* pane_part = GetPanePart(pane.window); - wxASSERT_MSG(pane_part, - wxT("Pane border part not found -- shouldn't happen")); + wxPoint new_pos(event.m_x - m_actionOffset.x, + event.m_y - m_actionOffset.y); - // determine the new pixel size that the user wants; - // this will help us recalculate the pane's proportion - if (dock.IsHorizontal()) - new_pixsize = new_pos.x - pane_part->rect.x; - else - new_pixsize = new_pos.y - pane_part->rect.y; + // determine the pane rectangle by getting the pane part + wxAuiDockUIPart* pane_part = GetPanePart(pane.window); + wxASSERT_MSG(pane_part, + wxT("Pane border part not found -- shouldn't happen")); - // determine the size of the dock, based on orientation - if (dock.IsHorizontal()) - dock_pixels = dock.rect.GetWidth(); - else - dock_pixels = dock.rect.GetHeight(); + // determine the new pixel size that the user wants; + // this will help us recalculate the pane's proportion + if (dock.IsHorizontal()) + new_pixsize = new_pos.x - pane_part->rect.x; + else + new_pixsize = new_pos.y - pane_part->rect.y; - // determine the total proportion of all resizable panes, - // and the total size of the dock minus the size of all - // the fixed panes - int i, dock_pane_count = dock.panes.GetCount(); - int pane_position = -1; - for (i = 0; i < dock_pane_count; ++i) + // determine the size of the dock, based on orientation + if (dock.IsHorizontal()) + dock_pixels = dock.rect.GetWidth(); + else + dock_pixels = dock.rect.GetHeight(); + + // determine the total proportion of all resizable panes, + // and the total size of the dock minus the size of all + // the fixed panes + int i, dock_pane_count = dock.panes.GetCount(); + int pane_position = -1; + for (i = 0; i < dock_pane_count; ++i) + { + wxAuiPaneInfo& p = *dock.panes.Item(i); + if (p.window == pane.window) + pane_position = i; + + // while we're at it, subtract the pane sash + // width from the dock width, because this would + // skew our proportion calculations + if (i > 0) + dock_pixels -= sashSize; + + // also, the whole size (including decorations) of + // all fixed panes must also be subtracted, because they + // are not part of the proportion calculation + if (p.IsFixed()) { - wxPaneInfo& p = *dock.panes.Item(i); - if (p.window == pane.window) - pane_position = i; - - // while we're at it, subtract the pane sash - // width from the dock width, because this would - // skew our proportion calculations - if (i > 0) - dock_pixels -= sash_size; - - // also, the whole size (including decorations) of - // all fixed panes must also be subtracted, because they - // are not part of the proportion calculation - if (p.IsFixed()) - { - if (dock.IsHorizontal()) - dock_pixels -= p.best_size.x; - else - dock_pixels -= p.best_size.y; - } - else - { - total_proportion += p.dock_proportion; - } + if (dock.IsHorizontal()) + dock_pixels -= p.best_size.x; + else + dock_pixels -= p.best_size.y; } - - // find a pane in our dock to 'steal' space from or to 'give' - // space to -- this is essentially what is done when a pane is - // resized; the pane should usually be the first non-fixed pane - // to the right of the action pane - int borrow_pane = -1; - for (i = pane_position+1; i < dock_pane_count; ++i) + else { - wxPaneInfo& p = *dock.panes.Item(i); - if (!p.IsFixed()) - { - borrow_pane = i; - break; - } + total_proportion += p.dock_proportion; } + } + // new size can never be more than the number of dock pixels + if (new_pixsize > dock_pixels) + new_pixsize = dock_pixels; - // demand that the pane being resized is found in this dock - // (this assert really never should be raised) - wxASSERT_MSG(pane_position != -1, wxT("Pane not found in dock")); - // prevent division by zero - if (dock_pixels == 0 || total_proportion == 0 || borrow_pane == -1) + // find a pane in our dock to 'steal' space from or to 'give' + // space to -- this is essentially what is done when a pane is + // resized; the pane should usually be the first non-fixed pane + // to the right of the action pane + int borrow_pane = -1; + for (i = pane_position+1; i < dock_pane_count; ++i) + { + wxAuiPaneInfo& p = *dock.panes.Item(i); + if (!p.IsFixed()) { - m_action = actionNone; - return; + borrow_pane = i; + break; } + } - // calculate the new proportion of the pane - int new_proportion = (new_pixsize*total_proportion)/dock_pixels; - // default minimum size - int min_size = 0; + // demand that the pane being resized is found in this dock + // (this assert really never should be raised) + wxASSERT_MSG(pane_position != -1, wxT("Pane not found in dock")); - // check against the pane's minimum size, if specified. please note - // that this is not enough to ensure that the minimum size will - // not be violated, because the whole frame might later be shrunk, - // causing the size of the pane to violate it's minimum size - if (pane.min_size.IsFullySpecified()) - { - min_size = 0; + // prevent division by zero + if (dock_pixels == 0 || total_proportion == 0 || borrow_pane == -1) + { + m_action = actionNone; + return false; + } - if (pane.HasBorder()) - min_size += (pane_border_size*2); + // calculate the new proportion of the pane + int new_proportion = (new_pixsize*total_proportion)/dock_pixels; - // calculate minimum size with decorations (border,caption) - if (pane_part->orientation == wxVERTICAL) - { - min_size += pane.min_size.y; - if (pane.HasCaption()) - min_size += caption_size; - } - else - { - min_size += pane.min_size.x; - } + // default minimum size + int min_size = 0; + + // check against the pane's minimum size, if specified. please note + // that this is not enough to ensure that the minimum size will + // not be violated, because the whole frame might later be shrunk, + // causing the size of the pane to violate it's minimum size + if (pane.min_size.IsFullySpecified()) + { + min_size = 0; + + if (pane.HasBorder()) + min_size += (pane_borderSize*2); + + // calculate minimum size with decorations (border,caption) + if (pane_part->orientation == wxVERTICAL) + { + min_size += pane.min_size.y; + if (pane.HasCaption()) + min_size += caption_size; } + else + { + min_size += pane.min_size.x; + } + } - // for some reason, an arithmatic error somewhere is causing - // the proportion calculations to always be off by 1 pixel; - // for now we will add the 1 pixel on, but we really should - // determine what's causing this. - min_size++; + // for some reason, an arithmatic error somewhere is causing + // the proportion calculations to always be off by 1 pixel; + // for now we will add the 1 pixel on, but we really should + // determine what's causing this. + min_size++; - int min_proportion = (min_size*total_proportion)/dock_pixels; + int min_proportion = (min_size*total_proportion)/dock_pixels; - if (new_proportion < min_proportion) - new_proportion = min_proportion; + if (new_proportion < min_proportion) + new_proportion = min_proportion; - int prop_diff = new_proportion - pane.dock_proportion; + int prop_diff = new_proportion - pane.dock_proportion; - // borrow the space from our neighbor pane to the - // right or bottom (depending on orientation) - dock.panes.Item(borrow_pane)->dock_proportion -= prop_diff; - pane.dock_proportion = new_proportion; + // borrow the space from our neighbor pane to the + // right or bottom (depending on orientation); + // also make sure we don't make the neighbor too small + int prop_borrow = dock.panes.Item(borrow_pane)->dock_proportion; - // repaint - Update(); - Repaint(NULL); + if (prop_borrow - prop_diff < 0) + { + // borrowing from other pane would make it too small, + // so cancel the resize operation + prop_borrow = min_proportion; } + else + { + prop_borrow -= prop_diff; + } + + + dock.panes.Item(borrow_pane)->dock_proportion = prop_borrow; + pane.dock_proportion = new_proportion; + + + // repaint + Update(); + Repaint(NULL); + } + + return true; +} + +void wxAuiManager::OnLeftUp(wxMouseEvent& event) +{ + if (m_action == actionResize) + { + m_frame->ReleaseMouse(); + + if (!wxAuiManager_HasLiveResize(*this)) + { + // get rid of the hint rectangle + wxScreenDC dc; + DrawResizeHint(dc, m_actionHintRect); + } + if (m_currentDragItem != -1 && wxAuiManager_HasLiveResize(*this)) + m_actionPart = & (m_uiParts.Item(m_currentDragItem)); + + DoEndResizeAction(event); + + m_currentDragItem = -1; + } else if (m_action == actionClickButton) { - m_hover_button = NULL; + m_hoverButton = NULL; m_frame->ReleaseMouse(); - UpdateButtonOnScreen(m_action_part, event); - // make sure we're still over the item that was originally clicked - if (m_action_part == HitTest(event.GetX(), event.GetY())) + if (m_actionPart) { - // fire button-click event - wxFrameManagerEvent e(wxEVT_AUI_PANEBUTTON); - e.SetPane(m_action_part->pane); - e.SetButton(m_action_part->button->button_id); - ProcessMgrEvent(e); + UpdateButtonOnScreen(m_actionPart, event); + + // make sure we're still over the item that was originally clicked + if (m_actionPart == HitTest(event.GetX(), event.GetY())) + { + // fire button-click event + wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON); + e.SetManager(this); + e.SetPane(m_actionPart->pane); + e.SetButton(m_actionPart->button->button_id); + ProcessMgrEvent(e); + } } } else if (m_action == actionClickCaption) @@ -3315,16 +4490,16 @@ void wxFrameManager::OnLeftUp(wxMouseEvent& event) { m_frame->ReleaseMouse(); - wxPaneInfo& pane = GetPane(m_action_window); + wxAuiPaneInfo& pane = GetPane(m_actionWindow); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); // save the new positions - wxDockInfoPtrArray docks; + wxAuiDockInfoPtrArray docks; FindDocks(m_docks, pane.dock_direction, pane.dock_layer, pane.dock_row, docks); if (docks.GetCount() == 1) { - wxDockInfo& dock = *docks.Item(0); + wxAuiDockInfo& dock = *docks.Item(0); wxArrayInt pane_positions, pane_sizes; GetPanePositionsAndSizes(dock, pane_positions, pane_sizes); @@ -3334,7 +4509,7 @@ void wxFrameManager::OnLeftUp(wxMouseEvent& event) dock.panes.Item(i)->dock_pos = pane_positions[i]; } - pane.state &= ~wxPaneInfo::actionPane; + pane.state &= ~wxAuiPaneInfo::actionPane; Update(); } else @@ -3343,11 +4518,11 @@ void wxFrameManager::OnLeftUp(wxMouseEvent& event) } m_action = actionNone; - m_last_mouse_move = wxPoint(); // see comment in OnMotion() + m_lastMouseMove = wxPoint(); // see comment in OnMotion() } -void wxFrameManager::OnMotion(wxMouseEvent& event) +void wxAuiManager::OnMotion(wxMouseEvent& event) { // sometimes when Update() is called from inside this method, // a spurious mouse move event is generated; this check will make @@ -3356,27 +4531,56 @@ void wxFrameManager::OnMotion(wxMouseEvent& event) // mouse move event is being generated. only verified on MSW wxPoint mouse_pos = event.GetPosition(); - if (m_last_mouse_move == mouse_pos) + if (m_lastMouseMove == mouse_pos) return; - m_last_mouse_move = mouse_pos; + m_lastMouseMove = mouse_pos; if (m_action == actionResize) { - wxPoint pos = m_action_part->rect.GetPosition(); - if (m_action_part->orientation == wxHORIZONTAL) - pos.y = wxMax(0, event.m_y - m_action_offset.y); - else - pos.x = wxMax(0, event.m_x - m_action_offset.x); + // It's necessary to reset m_actionPart since it destroyed + // by the Update within DoEndResizeAction. + if (m_currentDragItem != -1) + m_actionPart = & (m_uiParts.Item(m_currentDragItem)); + else + m_currentDragItem = m_uiParts.Index(* m_actionPart); - wxRect rect(m_frame->ClientToScreen(pos), - m_action_part->rect.GetSize()); + if (m_actionPart) + { + wxPoint pos = m_actionPart->rect.GetPosition(); + if (m_actionPart->orientation == wxHORIZONTAL) + pos.y = wxMax(0, event.m_y - m_actionOffset.y); + else + pos.x = wxMax(0, event.m_x - m_actionOffset.x); - wxScreenDC dc; - if (!m_action_hintrect.IsEmpty()) - DrawResizeHint(dc, m_action_hintrect); - DrawResizeHint(dc, rect); - m_action_hintrect = rect; + if (wxAuiManager_HasLiveResize(*this)) + { + m_frame->ReleaseMouse(); + DoEndResizeAction(event); + m_frame->CaptureMouse(); + } + else + { + wxRect rect(m_frame->ClientToScreen(pos), + m_actionPart->rect.GetSize()); + wxScreenDC dc; + + if (!m_actionHintRect.IsEmpty()) + { + // remove old resize hint + DrawResizeHint(dc, m_actionHintRect); + m_actionHintRect = wxRect(); + } + + // draw new resize hint, if it's inside the managed frame + wxRect frameScreenRect = m_frame->GetScreenRect(); + if (frameScreenRect.Contains(rect)) + { + DrawResizeHint(dc, rect); + m_actionHintRect = rect; + } + } + } } else if (m_action == actionClickCaption) { @@ -3386,68 +4590,84 @@ void wxFrameManager::OnMotion(wxMouseEvent& event) // caption has been clicked. we need to check if the mouse // is now being dragged. if it is, we need to change the // mouse action to 'drag' - if (abs(event.m_x - m_action_start.x) > drag_x_threshold || - abs(event.m_y - m_action_start.y) > drag_y_threshold) + if (m_actionPart && + (abs(event.m_x - m_actionStart.x) > drag_x_threshold || + abs(event.m_y - m_actionStart.y) > drag_y_threshold)) { - wxPaneInfo* pane_info = m_action_part->pane; + wxAuiPaneInfo* paneInfo = m_actionPart->pane; - if (!pane_info->IsToolbar()) + if (!paneInfo->IsToolbar()) { if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && - pane_info->IsFloatable()) + paneInfo->IsFloatable()) { m_action = actionDragFloatingPane; // set initial float position wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); - pane_info->floating_pos = wxPoint(pt.x - m_action_offset.x, - pt.y - m_action_offset.y); + paneInfo->floating_pos = wxPoint(pt.x - m_actionOffset.x, + pt.y - m_actionOffset.y); + // float the window - pane_info->Float(); + if (paneInfo->IsMaximized()) + RestorePane(*paneInfo); + paneInfo->Float(); Update(); - m_action_window = pane_info->frame; + m_actionWindow = paneInfo->frame; // action offset is used here to make it feel "natural" to the user // to drag a docked pane and suddenly have it become a floating frame. // Sometimes, however, the offset where the user clicked on the docked // caption is bigger than the width of the floating frame itself, so // in that case we need to set the action offset to a sensible value - wxSize frame_size = m_action_window->GetSize(); - if (frame_size.x <= m_action_offset.x) - m_action_offset.x = 30; + wxSize frame_size = m_actionWindow->GetSize(); + if (frame_size.x <= m_actionOffset.x) + m_actionOffset.x = 30; } } - else + else { m_action = actionDragToolbarPane; - m_action_window = pane_info->window; + m_actionWindow = paneInfo->window; } } } else if (m_action == actionDragFloatingPane) { - wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); - m_action_window->Move(pt.x - m_action_offset.x, - pt.y - m_action_offset.y); + if (m_actionWindow) + { + // We can't move the child window so we need to get the frame that + // we want to be really moving. This is probably not the best place + // to do this but at least it fixes the bug (#13177) for now. + if (!wxDynamicCast(m_actionWindow, wxAuiFloatingFrame)) + { + wxAuiPaneInfo& pane = GetPane(m_actionWindow); + m_actionWindow = pane.frame; + } + + wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); + m_actionWindow->Move(pt.x - m_actionOffset.x, + pt.y - m_actionOffset.y); + } } else if (m_action == actionDragToolbarPane) { - wxPaneInfo& pane = GetPane(m_action_window); + wxAuiPaneInfo& pane = GetPane(m_actionWindow); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); - pane.state |= wxPaneInfo::actionPane; + pane.SetFlag(wxAuiPaneInfo::actionPane, true); wxPoint pt = event.GetPosition(); - DoDrop(m_docks, m_panes, pane, pt, m_action_offset); + DoDrop(m_docks, m_panes, pane, pt, m_actionOffset); // if DoDrop() decided to float the pane, set up // the floating pane's initial position if (pane.IsFloating()) { wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); - pane.floating_pos = wxPoint(pt.x - m_action_offset.x, - pt.y - m_action_offset.y); + pane.floating_pos = wxPoint(pt.x - m_actionOffset.x, + pt.y - m_actionOffset.y); } // this will do the actiual move operation; @@ -3461,36 +4681,40 @@ void wxFrameManager::OnMotion(wxMouseEvent& event) // EVT_MOTION() events will move the floating pane if (pane.IsFloating()) { - pane.state &= ~wxPaneInfo::actionPane; + pane.state &= ~wxAuiPaneInfo::actionPane; m_action = actionDragFloatingPane; - m_action_window = pane.frame; + m_actionWindow = pane.frame; } } else { - wxDockUIPart* part = HitTest(event.GetX(), event.GetY()); - if (part && part->type == wxDockUIPart::typePaneButton) + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); + if (part && part->type == wxAuiDockUIPart::typePaneButton) { - if (part != m_hover_button) + if (part != m_hoverButton) { // make the old button normal - if (m_hover_button) - UpdateButtonOnScreen(m_hover_button, event); + if (m_hoverButton) + { + UpdateButtonOnScreen(m_hoverButton, event); + Repaint(); + } // mouse is over a button, so repaint the // button in hover mode UpdateButtonOnScreen(part, event); - m_hover_button = part; + m_hoverButton = part; + } } - else + else { - if (m_hover_button) + if (m_hoverButton) { - m_hover_button = NULL; + m_hoverButton = NULL; Repaint(); } - else + else { event.Skip(); } @@ -3498,53 +4722,104 @@ void wxFrameManager::OnMotion(wxMouseEvent& event) } } -void wxFrameManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(event)) +void wxAuiManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(event)) { - if (m_hover_button) + if (m_hoverButton) { - m_hover_button = NULL; + m_hoverButton = NULL; Repaint(); } } -void wxFrameManager::OnChildFocus(wxChildFocusEvent& event) +void wxAuiManager::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event)) +{ + // cancel the operation in progress, if any + if ( m_action != actionNone ) + { + m_action = actionNone; + HideHint(); + } +} + +void wxAuiManager::OnChildFocus(wxChildFocusEvent& event) { // when a child pane has it's focus set, we should change the // pane's active state to reflect this. (this is only true if // active panes are allowed by the owner) if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) { - if (GetPane(event.GetWindow()).IsOk()) + wxAuiPaneInfo& pane = GetPane(event.GetWindow()); + if (pane.IsOk() && (pane.state & wxAuiPaneInfo::optionActive) == 0) { - SetActivePane(m_panes, event.GetWindow()); + SetActivePane(event.GetWindow()); m_frame->Refresh(); } } + + event.Skip(); } // OnPaneButton() is an event handler that is called // when a pane button has been pressed. -void wxFrameManager::OnPaneButton(wxFrameManagerEvent& evt) +void wxAuiManager::OnPaneButton(wxAuiManagerEvent& evt) { - wxASSERT_MSG(evt.pane, wxT("Pane Info passed to wxFrameManager::OnPaneButton must be non-null")); + wxASSERT_MSG(evt.pane, wxT("Pane Info passed to wxAuiManager::OnPaneButton must be non-null")); + + wxAuiPaneInfo& pane = *(evt.pane); + + if (evt.button == wxAUI_BUTTON_CLOSE) + { + // fire pane close event + wxAuiManagerEvent e(wxEVT_AUI_PANE_CLOSE); + e.SetManager(this); + e.SetPane(evt.pane); + ProcessMgrEvent(e); - wxPaneInfo& pane = *(evt.pane); + if (!e.GetVeto()) + { + // close the pane, but check that it + // still exists in our pane array first + // (the event handler above might have removed it) + + wxAuiPaneInfo& check = GetPane(pane.window); + if (check.IsOk()) + { + ClosePane(pane); + } + + Update(); + } + } + else if (evt.button == wxAUI_BUTTON_MAXIMIZE_RESTORE && !pane.IsMaximized()) + { + // fire pane close event + wxAuiManagerEvent e(wxEVT_AUI_PANE_MAXIMIZE); + e.SetManager(this); + e.SetPane(evt.pane); + ProcessMgrEvent(e); - if (evt.button == wxPaneInfo::buttonClose) + if (!e.GetVeto()) + { + MaximizePane(pane); + Update(); + } + } + else if (evt.button == wxAUI_BUTTON_MAXIMIZE_RESTORE && pane.IsMaximized()) { // fire pane close event - wxFrameManagerEvent e(wxEVT_AUI_PANECLOSE); + wxAuiManagerEvent e(wxEVT_AUI_PANE_RESTORE); + e.SetManager(this); e.SetPane(evt.pane); ProcessMgrEvent(e); if (!e.GetVeto()) { - pane.Hide(); + RestorePane(pane); Update(); } } - else if (evt.button == wxPaneInfo::buttonPin) + else if (evt.button == wxAUI_BUTTON_PIN) { if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && pane.IsFloatable())