]> git.saurik.com Git - wxWidgets.git/blobdiff - src/aui/framemanager.cpp
rename ARRAYSIZE to CELLSARRAYSIZE to avoid conflict with a macro with the same name...
[wxWidgets.git] / src / aui / framemanager.cpp
index af264592a2566dda2eb756c2ea76f19a985a486e..62b3281b91394671ad6e7a74ea9c155adb396c1d 100644 (file)
@@ -40,6 +40,7 @@
     #include "wx/dcscreen.h"
     #include "wx/toolbar.h"
     #include "wx/image.h"
+    #include "wx/statusbr.h"
 #endif
 
 WX_CHECK_BUILD_OPTIONS("wxAUI")
@@ -558,6 +559,136 @@ static int PaneSortFunc(wxAuiPaneInfo** p1, wxAuiPaneInfo** p2)
 }
 
 
+
+
+// this utility class implements a proportional sizer
+// as it existed in wxWidgets 2.8 and before.
+
+class wxAuiProportionalBoxSizer : public wxBoxSizer
+{
+public:
+    wxAuiProportionalBoxSizer(int orientation) : wxBoxSizer(orientation) { }
+    
+    void RecalcSizes()
+    {
+        if (m_children.GetCount() == 0)
+            return;
+
+        int fixed_height = 0;
+        int fixed_width = 0;
+        int stretchable = 0;
+        wxSizerItemList::compatibility_iterator node;
+        
+        // find fixed width and height, as well
+        // as the total stretchable proportions
+        node = m_children.GetFirst();
+        while (node)
+        {
+            wxSizerItem *item = node->GetData();
+            
+            if (item->IsShown())
+            {
+                stretchable += item->GetProportion();
+                
+                wxSize size(item->GetMinSizeWithBorder());
+                if (item->GetProportion() == 0)
+                {
+                    if (m_orient == wxVERTICAL)
+                    {
+                        fixed_height += size.y;
+                        fixed_width = wxMax(fixed_width, size.x);
+                    }
+                     else
+                    {
+                        fixed_width += size.x;
+                        fixed_height = wxMax(fixed_height, size.y);
+                    }
+                }
+            }
+            
+            node = node->GetNext();
+        }
+
+
+        // delta specifies the total amount to be allocated to stretch spaces
+        int delta = 0;
+        if (stretchable)
+        {
+            if (m_orient == wxHORIZONTAL)
+                delta = m_size.x - fixed_width;
+                 else
+                delta = m_size.y - fixed_height;
+        }
+
+        // go through each item and assign sizes
+        wxPoint pt(m_position);
+        node = m_children.GetFirst();
+        while (node)
+        {
+            wxSizerItem* item = node->GetData();
+
+            if (item->IsShown())
+            {
+                wxSize size(item->GetMinSizeWithBorder());
+
+                if (m_orient == wxVERTICAL)
+                {
+                    wxCoord height = size.y;
+                    if (item->GetProportion())
+                    {
+                        height = (delta * item->GetProportion()) / stretchable;
+                        delta -= height;
+                        stretchable -= item->GetProportion();
+                    }
+
+                    wxPoint child_pos(pt);
+                    wxSize child_size(size.x, height);
+
+                    if (item->GetFlag() & (wxEXPAND | wxSHAPED))
+                        child_size.x = m_size.x;
+                    else if (item->GetFlag() & wxALIGN_RIGHT)
+                        child_pos.x += m_size.x - size.x;
+                    else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_HORIZONTAL))
+                        child_pos.x += (m_size.x - size.x) / 2;
+
+                    item->SetDimension(child_pos, child_size);
+
+                    pt.y += height;
+                }
+                 else
+                {
+                    wxCoord width = size.x;
+                    if (item->GetProportion())
+                    {
+                        width = (delta * item->GetProportion()) / stretchable;
+                        delta -= width;
+                        stretchable -= item->GetProportion();
+                    }
+
+                    wxPoint child_pos(pt);
+                    wxSize child_size(width, size.y);
+
+                    if (item->GetFlag() & (wxEXPAND | wxSHAPED))
+                        child_size.y = m_size.y;
+                    else if (item->GetFlag() & wxALIGN_BOTTOM)
+                        child_pos.y += m_size.y - size.y;
+                    else if (item->GetFlag() & (wxCENTER | wxALIGN_CENTER_VERTICAL))
+                        child_pos.y += (m_size.y - size.y) / 2;
+
+                    item->SetDimension(child_pos, child_size);
+                    
+                    pt.x += width;
+                }
+            }
+
+            node = node->GetNext();
+        }
+    }
+};
+
+
+
+
 // -- wxAuiManager class implementation --
 
 
@@ -1712,8 +1843,8 @@ void wxAuiManager::LayoutAddPane(wxSizer* cont,
     // value that the pane will receive
     int pane_proportion = pane.dock_proportion;
 
-    wxBoxSizer* horz_pane_sizer = new wxBoxSizer(wxHORIZONTAL);
-    wxBoxSizer* vert_pane_sizer = new wxBoxSizer(wxVERTICAL);
+    wxAuiProportionalBoxSizer* horz_pane_sizer = new wxAuiProportionalBoxSizer(wxHORIZONTAL);
+    wxAuiProportionalBoxSizer* vert_pane_sizer = new wxAuiProportionalBoxSizer(wxVERTICAL);
 
     if (pane.HasGripper())
     {
@@ -1735,7 +1866,7 @@ void wxAuiManager::LayoutAddPane(wxSizer* cont,
     if (pane.HasCaption())
     {
         // create the caption sizer
-        wxBoxSizer* caption_sizer = new wxBoxSizer(wxHORIZONTAL);
+        wxAuiProportionalBoxSizer* caption_sizer = new wxAuiProportionalBoxSizer(wxHORIZONTAL);
 
         sizer_item = caption_sizer->Add(1, caption_size, 1, wxEXPAND);
 
@@ -1884,7 +2015,7 @@ void wxAuiManager::LayoutAddDock(wxSizer* cont,
     }
 
     // create the sizer for the dock
-    wxSizer* dock_sizer = new wxBoxSizer(orientation);
+    wxSizer* dock_sizer = new wxAuiProportionalBoxSizer(orientation);
 
     // add each pane to the dock
     bool has_maximized_pane = false;
@@ -2017,7 +2148,7 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
                                  wxAuiDockUIPartArray& uiparts,
                                  bool spacer_only)
 {
-    wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
+    wxAuiProportionalBoxSizer* container = new wxAuiProportionalBoxSizer(wxVERTICAL);
 
     int pane_border_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
     int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
@@ -2300,7 +2431,7 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
 
         // create a container which will hold this layer's
         // docks (top, bottom, left, right)
-        cont = new wxBoxSizer(wxVERTICAL);
+        cont = new wxAuiProportionalBoxSizer(wxVERTICAL);
 
 
         // find any top docks in this layer
@@ -2315,7 +2446,7 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
         // fill out the middle layer (which consists
         // of left docks, content area and right docks)
 
-        middle = new wxBoxSizer(wxHORIZONTAL);
+        middle = new wxAuiProportionalBoxSizer(wxHORIZONTAL);
 
         // find any left docks in this layer
         FindDocks(docks, wxAUI_DOCK_LEFT, layer, -1, arr);
@@ -2384,7 +2515,7 @@ wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
     {
         // no sizer available, because there are no docks,
         // therefore we will create a simple background area
-        cont = new wxBoxSizer(wxVERTICAL);
+        cont = new wxAuiProportionalBoxSizer(wxVERTICAL);
         wxSizerItem* sizer_item = cont->Add(1,1, 1, wxEXPAND);
         wxAuiDockUIPart part;
         part.type = wxAuiDockUIPart::typeBackground;
@@ -2895,7 +3026,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 ))
             {
@@ -2903,13 +3035,9 @@ 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())
                 {
-                    if (drop.IsFloatable())
-                        drop.Float();
+                    drop.Float();
                 }
 
                 m_skipping = false;
@@ -3476,6 +3604,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
@@ -3576,6 +3707,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
@@ -4046,26 +4180,84 @@ bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event)
     // resize the dock or the pane
     if (m_action_part && m_action_part->type==wxAuiDockUIPart::typeDockSizer)
     {
+        // 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;
+
+        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)
+        {
+            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;
+        }
+        
+        
+        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 (m_frame && m_frame->IsKindOf(CLASSINFO(wxFrame)))
+        {
+            wxFrame* frame = static_cast<wxFrame*>(m_frame);
+            wxStatusBar* status = frame->GetStatusBar();
+            if (status)
+            {
+                wxSize status_client_size = status->GetClientSize();
+                available_height -= status_client_size.GetHeight();
+            }
+        }
+#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)
         {
         case wxAUI_DOCK_LEFT:
-            m_action_part->dock->size = new_pos.x - rect.x;
+            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:
-            m_action_part->dock->size = new_pos.y - rect.y;
+            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:
-            m_action_part->dock->size = rect.x + rect.width -
-                new_pos.x - m_action_part->rect.GetWidth();
+            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:
-            m_action_part->dock->size = rect.y + rect.height -
+            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;
         }
 
@@ -4140,6 +4332,11 @@ bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event)
             }
         }
 
+        // new size can never be more than the number of dock pixels
+        if (new_pixsize > dock_pixels)
+            new_pixsize = dock_pixels;
+
+
         // 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
@@ -4166,7 +4363,7 @@ bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event)
             m_action = actionNone;
             return false;
         }
-
+        
         // calculate the new proportion of the pane
         int new_proportion = (new_pixsize*total_proportion)/dock_pixels;
 
@@ -4214,10 +4411,26 @@ bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event)
         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;
+        // 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;
+
+        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);
@@ -4355,9 +4568,19 @@ void wxAuiManager::OnMotion(wxMouseEvent& event)
                 wxScreenDC dc;
 
                 if (!m_action_hintrect.IsEmpty())
+                {
+                    // remove old resize hint
                     DrawResizeHint(dc, m_action_hintrect);
-                DrawResizeHint(dc, rect);
-                m_action_hintrect = rect;
+                    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;
+                }
             }
         }
     }