X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/befda04080305959a15ef6ce400f49549b101c6a..e6db07c3ef23cdec32eecd824117e4c47a5b8f3a:/src/aui/framemanager.cpp diff --git a/src/aui/framemanager.cpp b/src/aui/framemanager.cpp index 5ae4d181a1..bdb37e182c 100644 --- a/src/aui/framemanager.cpp +++ b/src/aui/framemanager.cpp @@ -28,6 +28,9 @@ #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" @@ -36,8 +39,8 @@ #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") @@ -52,18 +55,24 @@ WX_DEFINE_OBJARRAY(wxAuiPaneInfoArray) wxAuiPaneInfo wxAuiNullPaneInfo; wxAuiDockInfo wxAuiNullDockInfo; -DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_BUTTON) -DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_CLOSE) -DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_MAXIMIZE) -DEFINE_EVENT_TYPE(wxEVT_AUI_PANE_RESTORE) -DEFINE_EVENT_TYPE(wxEVT_AUI_RENDER) -DEFINE_EVENT_TYPE(wxEVT_AUI_FIND_MANAGER) +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_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) @@ -73,6 +82,8 @@ IMPLEMENT_CLASS(wxAuiManager, wxEvtHandler) const int auiToolBarLayer = 10; +#ifndef __WXGTK20__ + class wxPseudoTransparentFrame : public wxFrame { @@ -151,7 +162,7 @@ public: wxRect rect(upd.GetRect()); dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height); - upd++; + ++upd; } } @@ -208,6 +219,86 @@ BEGIN_EVENT_TABLE(wxPseudoTransparentFrame, wxFrame) END_EVENT_TABLE() +#else + // __WXGTK20__ + +#include +#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__ + + + // -- static utility functions -- static wxBitmap wxPaneCreateStippleBitmap() @@ -222,10 +313,15 @@ 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 } @@ -429,20 +525,26 @@ static void RemovePaneFromDocks(wxAuiDockInfoArray& docks, } } +/* +// 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(wxAuiDockInfoPtrArray& docks) { - int i, dock_count, j, pane_count; + int i, dock_count; for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++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 @@ -468,6 +570,15 @@ static int PaneSortFunc(wxAuiPaneInfo** p1, wxAuiPaneInfo** p2) } +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); +} + // -- wxAuiManager class implementation -- @@ -482,15 +593,16 @@ BEGIN_EVENT_TABLE(wxAuiManager, wxEvtHandler) 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) - EVT_TIMER(101, wxAuiManager::OnHintFadeTimer) END_EVENT_TABLE() wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags) { m_action = actionNone; + m_action_window = NULL; m_last_mouse_move = wxPoint(); m_hover_button = NULL; m_art = new wxAuiDefaultDockArt; @@ -502,6 +614,7 @@ wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags) m_dock_constraint_x = 0.3; m_dock_constraint_y = 0.3; m_reserved = NULL; + m_currentDragItem = -1; if (managed_wnd) { @@ -511,12 +624,18 @@ wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags) 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; } @@ -528,6 +647,13 @@ wxAuiFloatingFrame* wxAuiManager::CreateFloatingFrame(wxWindow* parent, return new wxAuiFloatingFrame(parent, this, pane_info); } +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 wxAuiPaneInfo, a condition which can be checked @@ -631,6 +757,18 @@ 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 @@ -655,7 +793,7 @@ wxAuiManager* wxAuiManager::GetManager(wxWindow* window) wxAuiManagerEvent evt(wxEVT_AUI_FIND_MANAGER); evt.SetManager(NULL); evt.ResumePropagation(wxEVENT_PROPAGATE_MAX); - if (!window->ProcessEvent(evt)) + if (!window->GetEventHandler()->ProcessEvent(evt)) return NULL; return evt.GetManager(); @@ -664,7 +802,7 @@ wxAuiManager* wxAuiManager::GetManager(wxWindow* window) void wxAuiManager::UpdateHintWindowConfig() { - // find out if the the system can do transparent frames + // find out if the system can do transparent frames bool can_do_transparent = false; wxWindow* w = m_frame; @@ -674,6 +812,7 @@ void wxAuiManager::UpdateHintWindowConfig() { wxFrame* f = static_cast(w); can_do_transparent = f->CanSetTransparent(); + break; } @@ -709,6 +848,8 @@ void wxAuiManager::UpdateHintWindowConfig() wxDefaultPosition, wxSize(1,1), wxFRAME_FLOAT_ON_PARENT | wxFRAME_TOOL_WINDOW ); + m_hint_wnd->Connect(wxEVT_ACTIVATE, + wxActivateEventHandler(wxAuiManager::OnHintActivate), NULL, this); // Can't set the bg colour of a Frame in wxMac wxPanel* p = new wxPanel(m_hint_wnd); @@ -769,6 +910,17 @@ void wxAuiManager::SetManagedWindow(wxWindow* wnd) wxAuiPaneInfo().Name(wxT("mdiclient")). CenterPane().PaneBorder(false)); } + else if (m_frame->IsKindOf(CLASSINFO(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 UpdateHintWindowConfig(); @@ -802,7 +954,7 @@ 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; } @@ -826,6 +978,8 @@ void wxAuiManager::SetArtProvider(wxAuiDockArt* art_provider) bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info) { + wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed")); + // check if the pane has a valid window if (!window) return false; @@ -847,7 +1001,40 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info) if (pane_info.IsDocked()) RestoreMaximizedPane(); - m_panes.Add(pane_info); + // special case: wxAuiToolBar style interacts with docking flags + wxAuiPaneInfo test(pane_info); + 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); wxAuiPaneInfo& pinfo = m_panes.Last(); @@ -859,7 +1046,7 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info) 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(), @@ -894,25 +1081,36 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info) pinfo.buttons.Add(button); } + if (pinfo.HasGripper()) + { + if (pinfo.window->IsKindOf(CLASSINFO(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 wxUSE_TOOLBAR if (pinfo.window->IsKindOf(CLASSINFO(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) { @@ -923,6 +1121,8 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info) } } + + return true; } @@ -960,6 +1160,8 @@ bool wxAuiManager::AddPane(wxWindow* window, bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& pane_info, 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) { @@ -1020,6 +1222,8 @@ bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& pane_info, // method will not destroy the window that is removed. 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) { @@ -1073,8 +1277,7 @@ bool wxAuiManager::DetachPane(wxWindow* window) return false; } -// ClosePane() destroys or hides the pane depending on its -// flags +// ClosePane() destroys or hides the pane depending on its flags void wxAuiManager::ClosePane(wxAuiPaneInfo& pane_info) { // if we were maximized, restore @@ -1126,7 +1329,7 @@ void wxAuiManager::MaximizePane(wxAuiPaneInfo& pane_info) for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) { wxAuiPaneInfo& p = m_panes.Item(i); - if (!p.IsToolbar()) + if (!p.IsToolbar() && !p.IsFloating()) { p.Restore(); @@ -1160,7 +1363,7 @@ void wxAuiManager::RestorePane(wxAuiPaneInfo& pane_info) for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i) { wxAuiPaneInfo& p = m_panes.Item(i); - if (!p.IsToolbar()) + if (!p.IsToolbar() && !p.IsFloating()) { p.SetFlag(wxAuiPaneInfo::optionHidden, p.HasFlag(wxAuiPaneInfo::savedHiddenState)); @@ -1368,10 +1571,15 @@ bool wxAuiManager::LoadPerspective(const wxString& layout, bool update) 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(); @@ -1381,6 +1589,7 @@ bool wxAuiManager::LoadPerspective(const wxString& layout, bool update) input.Replace(wxT("\\|"), wxT("\a")); input.Replace(wxT("\\;"), wxT("\b")); + m_has_maximized = false; while (1) { wxAuiPaneInfo pane; @@ -1423,16 +1632,18 @@ bool wxAuiManager::LoadPerspective(const wxString& layout, bool update) LoadPaneInfo(pane_part, pane); + if ( pane.IsMaximized() ) + m_has_maximized = true; + 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; } p.SafeSet(pane); - } if (update) @@ -1460,7 +1671,7 @@ void wxAuiManager::GetPanePositionsAndSizes(wxAuiDockInfo& dock, { wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i)); - if (pane.state & wxAuiPaneInfo::actionPane) + if (pane.HasFlag(wxAuiPaneInfo::actionPane)) { wxASSERT_MSG(action_pane==-1, wxT("Too many fixed action panes")); action_pane = pane_i; @@ -2070,7 +2281,9 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes, dock.fixed = false; if (!pane.IsToolbar()) dock.toolbar = false; - if (pane.state & wxAuiPaneInfo::actionPane) + if (pane.HasFlag(wxAuiPaneInfo::optionDockFixed)) + dock.fixed = true; + if (pane.HasFlag(wxAuiPaneInfo::actionPane)) action_pane_marked = true; } @@ -2149,7 +2362,6 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& 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) @@ -2164,7 +2376,6 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& 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) @@ -2203,20 +2414,21 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes, // 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) @@ -2273,6 +2485,9 @@ void wxAuiManager::GetDockSizeConstraint(double* width_pct, double* height_pct) void wxAuiManager::Update() { + m_hover_button = NULL; + m_action_part = NULL; + wxSizer* sizer; int i, pane_count = m_panes.GetCount(); @@ -2292,21 +2507,21 @@ void wxAuiManager::Update() p.window->SetSize(1,1); - // 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_action_window == p.frame) - { - if (wxWindow::GetCapture() == m_frame) + // 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_action_window == p.frame) + { + if (wxWindow::GetCapture() == m_frame) m_frame->ReleaseMouse(); m_action = actionNone; - m_action_window = NULL; - } + m_action_window = NULL; + } - // hide the frame + // hide the frame if (p.frame->IsShown()) p.frame->Show(false); @@ -2361,7 +2576,7 @@ void wxAuiManager::Update() { // frame already exists, make sure it's position // and size reflect the information in wxAuiPaneInfo - if (p.frame->GetPosition() != p.floating_pos) + 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, @@ -2374,6 +2589,17 @@ void wxAuiManager::Update() */ } + // 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()); } @@ -2608,7 +2834,22 @@ bool wxAuiManager::ProcessDockResult(wxAuiPaneInfo& 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; } @@ -2652,7 +2893,9 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, 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)), @@ -2668,7 +2911,9 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& 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)), @@ -2684,7 +2929,9 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& 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)), @@ -2700,7 +2947,9 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& 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)), @@ -2737,7 +2986,8 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, // 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_last_rect.IsEmpty() || m_last_rect.Contains(pt.x, pt.y )) { @@ -2745,10 +2995,7 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, } else { - 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_flags & wxAUI_MGR_ALLOW_FLOATING) && drop.IsFloatable()) { drop.Float(); } @@ -2762,16 +3009,11 @@ bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks, return ProcessDockResult(target, drop); } - else - { - m_skipping = false; - } - if (!m_skipping) - { - m_last_rect = part->dock->rect; - m_last_rect.Inflate( 15, 15 ); - } + m_skipping = false; + + m_last_rect = part->dock->rect; + m_last_rect.Inflate( 15, 15 ); drop.Dock(). Direction(part->dock->dock_direction). @@ -3036,6 +3278,8 @@ void wxAuiManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event)) if (!m_hint_wnd || m_hint_fadeamt >= m_hint_fademax) { m_hint_fadetimer.Stop(); + Disconnect(m_hint_fadetimer.GetId(), wxEVT_TIMER, + wxTimerEventHandler(wxAuiManager::OnHintFadeTimer)); return; } @@ -3061,6 +3305,7 @@ void wxAuiManager::ShowHint(const wxRect& rect) m_hint_fadeamt = 0; m_hint_wnd->SetSize(rect); + m_hint_wnd->SetTransparent(m_hint_fadeamt); if (!m_hint_wnd->IsShown()) m_hint_wnd->Show(); @@ -3070,15 +3315,16 @@ void wxAuiManager::ShowHint(const wxRect& rect) if (m_action == actionDragFloatingPane && m_action_window) m_action_window->SetFocus(); - m_hint_wnd->SetTransparent(m_hint_fadeamt); m_hint_wnd->Raise(); if (m_hint_fadeamt != m_hint_fademax) // Only fade if we need to { // start fade in timer - m_hint_fadetimer.SetOwner(this, 101); + m_hint_fadetimer.SetOwner(this); m_hint_fadetimer.Start(5); + Connect(m_hint_fadetimer.GetId(), wxEVT_TIMER, + wxTimerEventHandler(wxAuiManager::OnHintFadeTimer)); } } else // Not using a transparent hint window... @@ -3104,7 +3350,8 @@ void wxAuiManager::ShowHint(const wxRect& rect) wxAuiPaneInfo& pane = m_panes.Item(i); if (pane.IsFloating() && - pane.frame->IsShown()) + pane.frame && + pane.frame->IsShown()) { wxRect rect = pane.frame->GetRect(); #ifdef __WXGTK__ @@ -3123,7 +3370,7 @@ void wxAuiManager::ShowHint(const wxRect& rect) // nasty redrawn problems. clip.Intersect(m_frame->GetRect()); - screendc.SetClippingRegion(clip); + screendc.SetDeviceClippingRegion(clip); wxBitmap stipple = wxPaneCreateStippleBitmap(); wxBrush brush(stipple); @@ -3146,6 +3393,10 @@ void wxAuiManager::HideHint() m_hint_wnd->Show(false); m_hint_wnd->SetTransparent(0); m_hint_fadetimer.Stop(); + // In case this is called while a hint fade is going, we need to + // disconnect the event handler. + Disconnect(m_hint_fadetimer.GetId(), wxEVT_TIMER, + wxTimerEventHandler(wxAuiManager::OnHintFadeTimer)); m_last_hint = wxRect(); return; } @@ -3159,6 +3410,17 @@ void wxAuiManager::HideHint() } } +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. +} + void wxAuiManager::StartPaneDrag(wxWindow* pane_window, @@ -3180,13 +3442,22 @@ void wxAuiManager::StartPaneDrag(wxWindow* pane_window, m_action_window = pane_window; m_action_offset = 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_action_offset += 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 the rectangle hint will be returned in +// 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 @@ -3209,6 +3480,7 @@ wxRect wxAuiManager::CalculateHintRect(wxWindow* pane_window, wxAuiDockUIPartArray uiparts; wxAuiPaneInfo hint = GetPane(pane_window); hint.name = wxT("__HINT__"); + hint.PaneBorder(true); hint.Show(); if (!hint.IsOk()) @@ -3300,6 +3572,9 @@ void wxAuiManager::OnFloatingPaneMoveStart(wxWindow* 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->SetTransparent(150); } @@ -3310,6 +3585,9 @@ void wxAuiManager::OnFloatingPaneMoving(wxWindow* wnd, wxDirection dir) wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + if(!pane.frame) + return; + wxPoint pt = ::wxGetMousePosition(); #if 0 @@ -3358,27 +3636,24 @@ void wxAuiManager::OnFloatingPaneMoving(wxWindow* wnd, wxDirection dir) // no hint for toolbar floating windows if (pane.IsToolbar() && m_action == actionDragFloatingPane) { - if (m_action == actionDragFloatingPane) - { - wxAuiDockInfoArray docks; - wxAuiPaneInfoArray panes; - wxAuiDockUIPartArray uiparts; - wxAuiPaneInfo 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_action_window = pane.window; - Update(); - } + Update(); return; } @@ -3386,7 +3661,7 @@ void wxAuiManager::OnFloatingPaneMoving(wxWindow* wnd, wxDirection dir) // 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; @@ -3413,6 +3688,9 @@ void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir) wxAuiPaneInfo& pane = GetPane(wnd); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); + if(!pane.frame) + return; + wxPoint pt = ::wxGetMousePosition(); #if 0 @@ -3458,10 +3736,9 @@ void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir) 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); @@ -3486,13 +3763,16 @@ void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir) HideHint(); } -void wxAuiManager::OnFloatingPaneResized(wxWindow* wnd, const wxSize& size) +void wxAuiManager::OnFloatingPaneResized(wxWindow* wnd, const wxRect& rect) { // try to find the pane 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); } @@ -3516,7 +3796,15 @@ void wxAuiManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt) } else { - ClosePane(pane); + // 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); + } } } @@ -3524,11 +3812,8 @@ void wxAuiManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt) 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); Repaint(); } @@ -3542,8 +3827,8 @@ void wxAuiManager::OnRender(wxAuiManagerEvent& evt) { // if the frame is about to be deleted, don't bother if (!m_frame || wxPendingDelete.Member(m_frame)) - return; - + return; + wxDC* dc = evt.GetDC(); #ifdef __WXMAC__ @@ -3555,8 +3840,8 @@ void wxAuiManager::OnRender(wxAuiManagerEvent& evt) { 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) @@ -3589,7 +3874,7 @@ void wxAuiManager::OnRender(wxAuiManagerEvent& evt) // Render() fire a render event, which is normally handled by // 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 wxAuiManager::Render(wxDC* dc) @@ -3776,14 +4061,17 @@ void wxAuiManager::UpdateButtonOnScreen(wxAuiDockUIPart* button_ui_part, void wxAuiManager::OnLeftDown(wxMouseEvent& event) { + m_currentDragItem = -1; + wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY()); if (part) { if (part->type == wxAuiDockUIPart::typeDockSizer || part->type == wxAuiDockUIPart::typePaneSizer) { - if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) - return; + // 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 @@ -3836,9 +4124,6 @@ void wxAuiManager::OnLeftDown(wxMouseEvent& event) - if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER) - return; - if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) { // set the caption as active @@ -3846,6 +4131,9 @@ void wxAuiManager::OnLeftDown(wxMouseEvent& event) 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); @@ -3870,212 +4158,310 @@ void wxAuiManager::OnLeftDown(wxMouseEvent& event) #endif } - -void wxAuiManager::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_action_part && m_action_part->type==wxAuiDockUIPart::typeDockSizer) { - m_frame->ReleaseMouse(); + // first, we must calculate the maximum size the dock may be + int sash_size = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); + + int used_width = 0, used_height = 0; - // get rid of the hint rectangle - wxScreenDC dc; - DrawResizeHint(dc, m_action_hintrect); + wxSize client_size = m_frame->GetClientSize(); - // resize the dock or the pane - if (m_action_part && m_action_part->type==wxAuiDockUIPart::typeDockSizer) + 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 += sash_size; + } + - wxPoint new_pos(event.m_x - m_action_offset.x, - event.m_y - m_action_offset.y); + int available_width = client_size.GetWidth() - used_width; + int available_height = client_size.GetHeight() - used_height; - switch (m_action_part->dock->dock_direction) + +#if wxUSE_STATUSBAR + // if there's a status control, the available + // height decreases accordingly + if (m_frame && m_frame->IsKindOf(CLASSINFO(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 == wxAuiDockUIPart::typePaneSizer) +#endif + + wxRect& rect = m_action_part->dock->rect; + + wxPoint new_pos(event.m_x - m_action_offset.x, + event.m_y - m_action_offset.y); + int new_size, old_size = m_action_part->dock->size; + + switch (m_action_part->dock->dock_direction) { - wxAuiDockInfo& dock = *m_action_part->dock; - wxAuiPaneInfo& 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_action_part->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_action_part->dock->size = new_size; + break; + case wxAUI_DOCK_RIGHT: + new_size = rect.x + rect.width - new_pos.x - + m_action_part->rect.GetWidth(); + if (new_size-old_size > available_width) + new_size = old_size+available_width; + m_action_part->dock->size = new_size; + break; + case wxAUI_DOCK_BOTTOM: + new_size = rect.y + rect.height - + new_pos.y - m_action_part->rect.GetHeight(); + if (new_size-old_size > available_height) + new_size = old_size+available_height; + m_action_part->dock->size = new_size; + break; + } - int total_proportion = 0; - int dock_pixels = 0; - int new_pixsize = 0; + Update(); + Repaint(NULL); + } + else if (m_action_part && + m_action_part->type == wxAuiDockUIPart::typePaneSizer) + { + wxAuiDockInfo& dock = *m_action_part->dock; + wxAuiPaneInfo& pane = *m_action_part->pane; - int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE); - int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); - int sash_size = m_art->GetMetric(wxAUI_DOCKART_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_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE); + int sash_size = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE); - // 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")); + wxPoint new_pos(event.m_x - m_action_offset.x, + event.m_y - m_action_offset.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 -= 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()) { - 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 -= 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; - } + if (dock.IsHorizontal()) + dock_pixels -= p.best_size.x; else - { - total_proportion += p.dock_proportion; - } + 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 { - wxAuiPaneInfo& 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_border_size*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_action_hintrect); + } + if (m_currentDragItem != -1 && wxAuiManager_HasLiveResize(*this)) + m_action_part = & (m_uiparts.Item(m_currentDragItem)); + + DoEndResizeAction(event); + + m_currentDragItem = -1; + } else if (m_action == actionClickButton) { m_hover_button = 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_action_part) { - // fire button-click event - wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON); - e.SetManager(this); - e.SetPane(m_action_part->pane); - e.SetButton(m_action_part->button->button_id); - ProcessMgrEvent(e); + 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())) + { + // fire button-click event + wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON); + e.SetManager(this); + e.SetPane(m_action_part->pane); + e.SetButton(m_action_part->button->button_id); + ProcessMgrEvent(e); + } } } else if (m_action == actionClickCaption) @@ -4138,20 +4524,49 @@ void wxAuiManager::OnMotion(wxMouseEvent& event) 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); + // It's necessary to reset m_action_part since it destroyed + // by the Update within DoEndResizeAction. + if (m_currentDragItem != -1) + m_action_part = & (m_uiparts.Item(m_currentDragItem)); else - pos.x = wxMax(0, event.m_x - m_action_offset.x); + m_currentDragItem = m_uiparts.Index(* m_action_part); - wxRect rect(m_frame->ClientToScreen(pos), + if (m_action_part) + { + 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); + + if (wxAuiManager_HasLiveResize(*this)) + { + m_frame->ReleaseMouse(); + DoEndResizeAction(event); + m_frame->CaptureMouse(); + } + else + { + wxRect rect(m_frame->ClientToScreen(pos), m_action_part->rect.GetSize()); + wxScreenDC dc; - wxScreenDC dc; - if (!m_action_hintrect.IsEmpty()) - DrawResizeHint(dc, m_action_hintrect); - DrawResizeHint(dc, rect); - m_action_hintrect = rect; + if (!m_action_hintrect.IsEmpty()) + { + // remove old resize hint + DrawResizeHint(dc, m_action_hintrect); + m_action_hintrect = wxRect(); + } + + // draw new resize hint, if it's inside the managed frame + wxRect frame_screen_rect = m_frame->GetScreenRect(); + if (frame_screen_rect.Contains(rect)) + { + DrawResizeHint(dc, rect); + m_action_hintrect = rect; + } + } + } } else if (m_action == actionClickCaption) { @@ -4161,8 +4576,9 @@ void wxAuiManager::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_action_part && + (abs(event.m_x - m_action_start.x) > drag_x_threshold || + abs(event.m_y - m_action_start.y) > drag_y_threshold)) { wxAuiPaneInfo* pane_info = m_action_part->pane; @@ -4207,6 +4623,15 @@ void wxAuiManager::OnMotion(wxMouseEvent& event) { if (m_action_window) { + // 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 (!m_action_window->IsKindOf(CLASSINFO(wxAuiFloatingFrame))) + { + wxAuiPaneInfo& pane = GetPane(m_action_window); + m_action_window = pane.frame; + } + wxPoint pt = m_frame->ClientToScreen(event.GetPosition()); m_action_window->Move(pt.x - m_action_offset.x, pt.y - m_action_offset.y); @@ -4217,7 +4642,7 @@ void wxAuiManager::OnMotion(wxMouseEvent& event) wxAuiPaneInfo& pane = GetPane(m_action_window); wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found")); - pane.state |= wxAuiPaneInfo::actionPane; + pane.SetFlag(wxAuiPaneInfo::actionPane, true); wxPoint pt = event.GetPosition(); DoDrop(m_docks, m_panes, pane, pt, m_action_offset); @@ -4292,6 +4717,16 @@ void wxAuiManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(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 @@ -4299,7 +4734,8 @@ void wxAuiManager::OnChildFocus(wxChildFocusEvent& event) // 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()); m_frame->Refresh(); @@ -4328,7 +4764,16 @@ void wxAuiManager::OnPaneButton(wxAuiManagerEvent& evt) if (!e.GetVeto()) { - ClosePane(pane); + // 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(); } }