]> git.saurik.com Git - wxWidgets.git/blobdiff - src/aui/framemanager.cpp
Fix AdjustForOverflow to use item->CalcMin, not item->GetSize
[wxWidgets.git] / src / aui / framemanager.cpp
index 6009b040d8b65b1c2b41613e6500784fd43bc5c5..9ceabbf8dcbfaa72a1e31ce56bfb108ea38d814e 100644 (file)
@@ -67,6 +67,12 @@ DEFINE_EVENT_TYPE(wxEVT_AUI_FIND_MANAGER)
     #include "wx/mac/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)
 
@@ -74,6 +80,8 @@ IMPLEMENT_CLASS(wxAuiManager, wxEvtHandler)
 
 const int auiToolBarLayer = 10;
 
+#ifndef __WXGTK20__
+
 
 class wxPseudoTransparentFrame : public wxFrame
 {
@@ -152,7 +160,7 @@ public:
             wxRect rect(upd.GetRect());
             dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
 
-            upd++;
+            ++upd;
         }
     }
 
@@ -209,6 +217,72 @@ BEGIN_EVENT_TABLE(wxPseudoTransparentFrame, wxFrame)
 END_EVENT_TABLE()
 
 
+#else
+  // __WXGTK20__
+
+#include <gtk/gtk.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; y<disp.y; y++)
+                {
+                    // Reverse the order of the bottom 4 bits
+                    int j=((y&8)?1:0)|((y&4)?2:0)|((y&2)?4:0)|((y&1)?8:0);
+                    if ((j*16+8)<amount)
+                        region.Union(0, y, disp.x, 1);
+                }
+        gdk_window_shape_combine_region(m_widget->window, region.GetRegion(), 0, 0);
+}
+
+
+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"))
+    {
+         if (!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
+            return;
+
+        m_title = title;
+
+        m_widget = gtk_window_new( GTK_WINDOW_POPUP );
+
+        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;
+    }
+
+private:
+    DECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame)
+};
+
+IMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame)
+
+#endif
+ // __WXGTK20__
+
+
+
 // -- static utility functions --
 
 static wxBitmap wxPaneCreateStippleBitmap()
@@ -223,10 +297,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
 }
 
 
@@ -430,20 +509,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
@@ -512,12 +597,29 @@ 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
+
+    // We need to remove any reference to this wxAuiManager in any of the
+    // wxAuiFloatingFrames associated with this manager in case they haven't
+    // been deleted just yet.
+    // We need an array copy since Unregister removes the items.
+    wxAuiFloatingFramePtrArray array_copy = m_floating_frames;
+    int i, count = array_copy.GetCount();
+    for (i = 0; i < count; ++i)
+    {
+        UnregisterFloatingFrame(array_copy.Item(i));
+    }
 
     delete m_art;
 }
@@ -526,7 +628,47 @@ wxAuiManager::~wxAuiManager()
 wxAuiFloatingFrame* wxAuiManager::CreateFloatingFrame(wxWindow* parent,
                                                       const wxAuiPaneInfo& pane_info)
 {
-    return new wxAuiFloatingFrame(parent, this, pane_info);
+    wxAuiFloatingFrame* frame = new wxAuiFloatingFrame(parent, this, pane_info);
+    RegisterFloatingFrame(frame);
+    return frame;
+}
+
+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));
+}
+
+// registers a floating frame with this manager (see header)
+void wxAuiManager::RegisterFloatingFrame(wxAuiFloatingFrame* frame)
+{
+    frame->SetOwnerManager(this);
+    int i, count = m_floating_frames.GetCount();
+    for (i = 0; i < count; ++i)
+    {
+        wxAuiFloatingFrame* f = m_floating_frames.Item(i);
+        if (f == frame)
+            // this frame is already registered
+            return;
+    }
+    m_floating_frames.Add(frame);
+}
+
+// unregisters a floating frame from this manager (see header)
+void wxAuiManager::UnregisterFloatingFrame(wxAuiFloatingFrame* frame)
+{
+    frame->SetOwnerManager(NULL);
+    int i, count = m_floating_frames.GetCount();
+    for (i = 0; i < count; ++i)
+    {
+        wxAuiFloatingFrame* f = m_floating_frames.Item(i);
+        if (f == frame)
+        {
+            m_floating_frames.Remove(f);
+            return;
+        }
+    }
 }
 
 // GetPane() looks up a wxAuiPaneInfo structure based
@@ -675,6 +817,7 @@ void wxAuiManager::UpdateHintWindowConfig()
         {
             wxFrame* f = static_cast<wxFrame*>(w);
             can_do_transparent = f->CanSetTransparent();
+            
             break;
         }
 
@@ -770,7 +913,7 @@ void wxAuiManager::SetManagedWindow(wxWindow* wnd)
                 wxAuiPaneInfo().Name(wxT("mdiclient")).
                 CenterPane().PaneBorder(false));
     }
-        else if (m_frame->IsKindOf(CLASSINFO(wxAuiMDIParentFrame)))
+    else if (m_frame->IsKindOf(CLASSINFO(wxAuiMDIParentFrame)))
     {
         wxAuiMDIParentFrame* mdi_frame = (wxAuiMDIParentFrame*)m_frame;
         wxAuiMDIClientWindow* client_window = mdi_frame->GetClientWindow();
@@ -871,7 +1014,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,
+             wxPtrToUInt(pinfo.window) & 0xffffffff,
              (unsigned int)time(NULL),
 #ifdef __WXWINCE__
              (unsigned int)GetTickCount(),
@@ -923,7 +1066,8 @@ bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& pane_info)
             // I believe this to be the correct action, until
             // wxToolBar::GetBestSize() is fixed.  Is this assumption
             // correct?
-            pinfo.best_size.y++;
+            // commented out by JACS 2007-9-08 after having added a pixel in wxMSW's wxToolBar::DoGetBestSize()
+            // pinfo.best_size.y++;
         }
 
         if (pinfo.min_size != wxDefaultSize)
@@ -1085,8 +1229,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
@@ -1439,12 +1582,11 @@ bool wxAuiManager::LoadPerspective(const wxString& layout, bool update)
         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)
@@ -2082,6 +2224,8 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
                 dock.fixed = false;
             if (!pane.IsToolbar())
                 dock.toolbar = false;
+            if (pane.HasFlag(wxAuiPaneInfo::optionDockFixed))
+                dock.fixed = true;
             if (pane.state & wxAuiPaneInfo::actionPane)
                 action_pane_marked = true;
         }
@@ -2161,7 +2305,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)
@@ -2176,7 +2319,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)
@@ -2215,20 +2357,19 @@ 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);
 
 
 
         // 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)
@@ -2285,6 +2426,8 @@ void wxAuiManager::GetDockSizeConstraint(double* width_pct, double* height_pct)
 
 void wxAuiManager::Update()
 {
+    m_hover_button = NULL;
+
     wxSizer* sizer;
     int i, pane_count = m_panes.GetCount();
 
@@ -2304,21 +2447,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);
 
@@ -2373,7 +2516,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,
@@ -2774,16 +2917,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).
@@ -3371,27 +3509,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;
     }
@@ -3399,7 +3534,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;
@@ -3474,7 +3609,7 @@ void wxAuiManager::OnFloatingPaneMoved(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))
     {
         // do the drop calculation
         DoDrop(m_docks, m_panes, pane, client_pt, action_offset);
@@ -3529,7 +3664,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);
+        }
     }
 }
 
@@ -3537,11 +3680,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();
     }
@@ -3555,8 +3695,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__
@@ -3568,8 +3708,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)
@@ -3795,8 +3935,9 @@ void wxAuiManager::OnLeftDown(wxMouseEvent& event)
         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
@@ -3849,9 +3990,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
@@ -3859,6 +3997,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);
@@ -4312,7 +4453,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();
@@ -4341,7 +4483,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();
         }
     }