]> git.saurik.com Git - wxWidgets.git/blobdiff - src/ribbon/page.cpp
Use correct extensions in wxDynamicLibrary::CanonicalizeName() on OS X.
[wxWidgets.git] / src / ribbon / page.cpp
index 812d0da69c9597dba49240b9b15411f8d6cf6201..9440dddd9fff3f1477568246c3bf67878dc9f9e5 100644 (file)
     #pragma hdrstop
 #endif
 
-#include "wx/ribbon/page.h"
-
 #if wxUSE_RIBBON
 
+#include "wx/ribbon/page.h"
 #include "wx/ribbon/art.h"
 #include "wx/ribbon/bar.h"
 #include "wx/dcbuffer.h"
@@ -136,11 +135,11 @@ void wxRibbonPageScrollButton::OnMouseUp(wxMouseEvent& WXUNUSED(evt))
         {
         case wxRIBBON_SCROLL_BTN_DOWN:
         case wxRIBBON_SCROLL_BTN_RIGHT:
-            m_sibling->ScrollLines(1);
+            m_sibling->ScrollSections(1);
             break;
         case wxRIBBON_SCROLL_BTN_UP:
         case wxRIBBON_SCROLL_BTN_LEFT:
-            m_sibling->ScrollLines(-1);
+            m_sibling->ScrollSections(-1);
             break;
         default:
             break;
@@ -176,6 +175,7 @@ wxRibbonPage::wxRibbonPage(wxRibbonBar* parent,
 
 wxRibbonPage::~wxRibbonPage()
 {
+    delete[] m_size_calc_array;
 }
 
 bool wxRibbonPage::Create(wxRibbonBar* parent,
@@ -201,6 +201,8 @@ void wxRibbonPage::CommonInit(const wxString& label, const wxBitmap& icon)
     m_icon = icon;
     m_scroll_left_btn = NULL;
     m_scroll_right_btn = NULL;
+    m_size_calc_array = NULL;
+    m_size_calc_array_size = 0;
     m_scroll_amount = 0;
     m_scroll_buttons_visible = false;
 
@@ -334,6 +336,124 @@ bool wxRibbonPage::ScrollPixels(int pixels)
     return true;
 }
 
+bool wxRibbonPage::ScrollSections(int sections)
+{
+    // Currently the only valid values are -1 and 1 for scrolling left and
+    // right, respectively.
+    const bool scrollForward = sections >= 1;
+
+    // Determine by how many pixels to scroll. If something on the page
+    // is partially visible, scroll to make it fully visible. Otherwise
+    // find the next item that will become visible and scroll to make it
+    // fully visible. The ScrollPixel call will correct if we scroll too
+    // much if the available width is smaller than the items.
+
+    // Scroll at minimum the same amount as ScrollLines(1):
+    int minscroll = sections * 8;
+    // How many pixels to scroll:
+    int pixels = 0;
+
+    // Determine the scroll position, that is, the page border where items
+    // are appearing.
+    int scrollpos = 0;
+
+    wxOrientation major_axis = GetMajorAxis();
+    int gap = 0;
+
+    int width = 0;
+    int height = 0;
+    int x = 0;
+    int y = 0;
+    GetSize(&width, &height);
+    GetPosition(&x, &y);
+    if(major_axis == wxHORIZONTAL)
+    {
+        gap = m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE);
+        if (scrollForward)
+        {
+            scrollpos = width - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
+        }
+        else
+        {
+            scrollpos = m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE);
+        }
+    }
+    else
+    {
+        gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE);
+        if (scrollForward)
+        {
+            scrollpos = width - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
+        }
+        else
+        {
+            scrollpos = m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE);
+        }
+    }
+
+    // Find the child that is partially shown or just beyond the scroll position
+    for(wxWindowList::compatibility_iterator
+            node = scrollForward ? GetChildren().GetFirst()
+                                 : GetChildren().GetLast();
+        node;
+        node = scrollForward ? node->GetNext()
+                             : node->GetPrevious())
+    {
+        wxWindow* child = node->GetData();
+        child->GetSize(&width, &height);
+        child->GetPosition(&x, &y);
+        int pos0 = 0;
+        int pos1 = 0;
+        if (major_axis == wxHORIZONTAL)
+        {
+            pos0 = x;
+            pos1 = x + width + gap;
+        }
+        else
+        {
+            pos0 = y;
+            pos1 = y + height + gap;
+        }
+        if (scrollpos >= pos0 && scrollpos <= pos1)
+        {
+            // This section is partially visible, scroll to make it fully visible.
+            if (scrollForward)
+            {
+                pixels += pos1 - scrollpos;
+            }
+            else
+            {
+                pixels += pos0 - scrollpos;
+            }
+            if (abs(pixels) >= abs(minscroll))
+                break;
+        }
+        if (scrollpos <= pos0 && scrollForward)
+        {
+            // This section is next, scroll the entire section width
+            pixels += (pos1 - pos0);
+            break;
+        }
+        if (scrollpos >= pos1 && !scrollForward)
+        {
+            // This section is next, scroll the entire section width
+            pixels += (pos0 - pos1);
+            break;
+        }
+    }
+    // Do a final safety sanity check, should not be necessary, but will not hurt either.
+    if (pixels == 0)
+    {
+        pixels = minscroll;
+    }
+    if (pixels * minscroll < 0)
+    {
+        pixels = -pixels;
+    }
+
+    return ScrollPixels(pixels);
+}
+
 void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x, int y, int width, int height)
 {
     if(m_scroll_buttons_visible)
@@ -371,6 +491,8 @@ void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x, int y, int width, in
             }
         }
     }
+    if (width < 0) width = 0;
+    if (height < 0) height = 0;
     SetSize(x, y, width, height);
 }
 
@@ -379,12 +501,30 @@ void wxRibbonPage::DoSetSize(int x, int y, int width, int height, int sizeFlags)
     // When a resize triggers the scroll buttons to become visible, the page is resized.
     // This resize from within a resize event can cause (MSW) wxWidgets some confusion,
     // and report the 1st size to the 2nd size event. Hence the most recent size is
-    // remembered internally and used in Layout() where appropiate.
+    // remembered internally and used in Layout() where appropriate.
 
     if(GetMajorAxis() == wxHORIZONTAL)
+    {
         m_size_in_major_axis_for_children = width;
+        if(m_scroll_buttons_visible)
+        {
+            if(m_scroll_left_btn)
+                m_size_in_major_axis_for_children += m_scroll_left_btn->GetSize().GetWidth();
+            if(m_scroll_right_btn)
+                m_size_in_major_axis_for_children += m_scroll_right_btn->GetSize().GetWidth();
+        }
+    }
     else
+    {
         m_size_in_major_axis_for_children = height;
+        if(m_scroll_buttons_visible)
+        {
+            if(m_scroll_left_btn)
+                m_size_in_major_axis_for_children += m_scroll_left_btn->GetSize().GetHeight();
+            if(m_scroll_right_btn)
+                m_size_in_major_axis_for_children += m_scroll_right_btn->GetSize().GetHeight();
+        }
+    }
 
     wxRibbonControl::DoSetSize(x, y, width, height, sizeFlags);
 }
@@ -393,9 +533,12 @@ void wxRibbonPage::OnSize(wxSizeEvent& evt)
 {
     wxSize new_size = evt.GetSize();
 
-    wxMemoryDC temp_dc;
-    wxRect invalid_rect = m_art->GetPageBackgroundRedrawArea(temp_dc, this, m_old_size, new_size);
-    Refresh(true, &invalid_rect);
+    if (m_art)
+    {
+        wxMemoryDC temp_dc;
+        wxRect invalid_rect = m_art->GetPageBackgroundRedrawArea(temp_dc, this, m_old_size, new_size);
+        Refresh(true, &invalid_rect);
+    }
 
     m_old_size = new_size;
 
@@ -462,15 +605,39 @@ bool wxRibbonPage::Realize()
         {
             status = false;
         }
-        child->SetSize(child->GetMinSize());
     }
+    PopulateSizeCalcArray(&wxWindow::GetMinSize);
 
-    if(GetSize().GetX() > 0 && GetSize().GetY() > 0)
+    return DoActualLayout() && status;
+}
+
+void wxRibbonPage::PopulateSizeCalcArray(wxSize (wxWindow::*get_size)(void) const)
+{
+    wxSize parentSize = GetSize();
+    parentSize.x -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE);
+    parentSize.x -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
+    parentSize.y -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE);
+    parentSize.y -= m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
+
+    if(m_size_calc_array_size != GetChildren().GetCount())
     {
-        status = Layout() && status;
+        delete[] m_size_calc_array;
+        m_size_calc_array_size = GetChildren().GetCount();
+        m_size_calc_array = new wxSize[m_size_calc_array_size];
     }
 
-    return status;
+    wxSize* node_size = m_size_calc_array;
+    for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+          node;
+          node = node->GetNext(), ++node_size )
+    {
+        wxWindow* child = node->GetData();
+        wxRibbonPanel* panel = wxDynamicCast(child, wxRibbonPanel);
+        if (panel && panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)
+            *node_size = panel->GetBestSizeForParentSize(parentSize);
+        else
+            *node_size = (child->*get_size)();
+    }
 }
 
 bool wxRibbonPage::Layout()
@@ -479,112 +646,122 @@ bool wxRibbonPage::Layout()
     {
         return true;
     }
-
-    wxPoint origin_(m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE), m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE));
-    wxOrientation major_axis = GetMajorAxis();
-    if(m_scroll_buttons_visible)
+    else
     {
-        if(major_axis == wxHORIZONTAL)
-        {
-            origin_.x -= m_scroll_amount;
-            if(m_scroll_left_btn)
-                origin_.x -= m_scroll_left_btn->GetSize().GetWidth();
-        }
-        else
-        {
-            origin_.y -= m_scroll_amount;
-            if(m_scroll_left_btn)
-                origin_.y -= m_scroll_left_btn->GetSize().GetHeight();
-        }
+        PopulateSizeCalcArray(&wxWindow::GetSize);
+        return DoActualLayout();
     }
-    wxPoint origin(origin_);
+}
+
+bool wxRibbonPage::DoActualLayout()
+{
+    wxPoint origin(m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE), m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE));
+    wxOrientation major_axis = GetMajorAxis();
     int gap;
     int minor_axis_size;
+    int available_space;
     if(major_axis == wxHORIZONTAL)
     {
         gap = m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE);
         minor_axis_size = GetSize().GetHeight() - origin.y - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
+        available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE) - origin.x;
     }
     else
     {
         gap = m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE);
         minor_axis_size = GetSize().GetWidth() - origin.x - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
+        available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE) - origin.y;
     }
-
-    for(int iteration = 1; iteration <= 2; ++iteration)
+    if (minor_axis_size < 0) minor_axis_size = 0;
+    size_t size_index;
+    for(size_index = 0; size_index < m_size_calc_array_size; ++size_index)
     {
-        for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
-              node;
-              node = node->GetNext() )
+        if(major_axis == wxHORIZONTAL)
         {
-            wxWindow* child = node->GetData();
-            int w, h;
-            child->GetSize(&w, &h);
-            if(major_axis == wxHORIZONTAL)
-            {
-                child->SetSize(origin.x, origin.y, w, minor_axis_size);
-                origin.x += w + gap;
-            }
-            else
-            {
-                child->SetSize(origin.x, origin.y, minor_axis_size, h);
-                origin.y += h + gap;
-            }
+            available_space -= m_size_calc_array[size_index].GetWidth();
+            m_size_calc_array[size_index].SetHeight(minor_axis_size);
         }
-        if(iteration == 1)
+        else
         {
-            int available_space;
-            if(major_axis == wxHORIZONTAL)
-                available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE) - origin.x + gap;
-            else
-                available_space = m_size_in_major_axis_for_children - m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE) - origin.y + gap;
-            if(m_scroll_buttons_visible)
-            {
-                available_space -= m_scroll_amount;
-                if(m_scroll_right_btn != NULL)
-                    available_space += GetSizeInOrientation(m_scroll_right_btn->GetSize(), major_axis);
-            }
-            if(available_space > 0)
-            {
-                if(m_scroll_buttons_visible)
-                {
-                    HideScrollButtons();
-                    break;
-                }
-
-                if(!ExpandPanels(major_axis, available_space))
-                    break;
-            }
-            else if(available_space < 0)
+            available_space -= m_size_calc_array[size_index].GetHeight();
+            m_size_calc_array[size_index].SetWidth(minor_axis_size);
+        }
+        if(size_index != 0)
+            available_space -= gap;
+    }
+    bool todo_hide_scroll_buttons = false;
+    bool todo_show_scroll_buttons = false;
+    if(available_space >= 0)
+    {
+        if(m_scroll_buttons_visible)
+            todo_hide_scroll_buttons = true;
+        if(available_space > 0)
+            ExpandPanels(major_axis, available_space);
+    }
+    else
+    {
+        if(m_scroll_buttons_visible)
+        {
+            // Scroll buttons already visible - not going to be able to downsize any more
+            m_scroll_amount_limit = -available_space;
+            if(m_scroll_amount > m_scroll_amount_limit)
             {
-                if(m_scroll_buttons_visible)
-                {
-                    // Scroll buttons already visible - not going to be able to downsize any more
-                    m_scroll_amount_limit = -available_space;
-                    if(m_scroll_amount > m_scroll_amount_limit)
-                    {
-                        ScrollPixels(m_scroll_amount_limit - m_scroll_amount);
-                    }
-                }
-                else
-                {
-                    if(!CollapsePanels(major_axis, -available_space))
-                    {
-                        m_scroll_amount = 0;
-                        m_scroll_amount_limit = -available_space;
-                        ShowScrollButtons();
-                        break;
-                    }
-                }
+                m_scroll_amount = m_scroll_amount_limit;
+                todo_show_scroll_buttons = true;
             }
-            else
+        }
+        else
+        {
+            if(!CollapsePanels(major_axis, -available_space))
             {
-                break;
+                m_scroll_amount = 0;
+                m_scroll_amount_limit = -available_space;
+                todo_show_scroll_buttons = true;
             }
-            origin = origin_; // Reset the origin
+        }
+    }
+    if(m_scroll_buttons_visible)
+    {
+        if(major_axis == wxHORIZONTAL)
+        {
+            origin.x -= m_scroll_amount;
+            if(m_scroll_left_btn)
+                origin.x -= m_scroll_left_btn->GetSize().GetWidth();
+        }
+        else
+        {
+            origin.y -= m_scroll_amount;
+            if(m_scroll_left_btn)
+                origin.y -= m_scroll_left_btn->GetSize().GetHeight();
+        }
+    }
+    size_index = 0;
+    for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+        node;
+        node = node->GetNext(), ++size_index )
+    {
+        wxWindow* child = node->GetData();
+        int w = m_size_calc_array[size_index].GetWidth();
+        int h = m_size_calc_array[size_index].GetHeight();
+        child->SetSize(origin.x, origin.y, w, h);
+        if(major_axis == wxHORIZONTAL)
+        {
+            origin.x += w + gap;
+        }
+        else
+        {
+            origin.y += h + gap;
         }
     }
 
+    if(todo_show_scroll_buttons)
+        ShowScrollButtons();
+    else if(todo_hide_scroll_buttons)
+        HideScrollButtons();
+    else if(m_scroll_buttons_visible)
+        ShowScrollButtons();
+
+    Refresh();
     return true;
 }
 
@@ -622,29 +799,33 @@ void wxRibbonPage::ShowScrollButtons()
 
     if(show_left)
     {
-        if(m_scroll_left_btn == NULL)
+        wxMemoryDC temp_dc;
+        wxSize size;
+        long direction;
+        if(GetMajorAxis() == wxHORIZONTAL)
         {
-            wxMemoryDC temp_dc;
-            wxSize size;
-            long direction;
-            if(GetMajorAxis() == wxHORIZONTAL)
-            {
-                direction = wxRIBBON_SCROLL_BTN_LEFT;
-                size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
-                size.SetHeight(GetSize().GetHeight());
-            }
-            else
-            {
-                direction = wxRIBBON_SCROLL_BTN_UP;
-                size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
-                size.SetWidth(GetSize().GetWidth());
-            }
-            m_scroll_left_btn = new wxRibbonPageScrollButton(this, wxID_ANY, GetPosition(), size, direction);
-            if(!IsShown())
-            {
-                m_scroll_left_btn->Hide();
-            }
-            reposition = true;
+              direction = wxRIBBON_SCROLL_BTN_LEFT;
+              size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
+              size.SetHeight(GetSize().GetHeight());
+        }
+        else
+        {
+              direction = wxRIBBON_SCROLL_BTN_UP;
+              size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
+              size.SetWidth(GetSize().GetWidth());
+        }
+        if (m_scroll_left_btn)
+        {
+              m_scroll_left_btn->SetSize(size);
+        }
+        else
+        {
+              m_scroll_left_btn = new wxRibbonPageScrollButton(this, wxID_ANY, GetPosition(), size, direction);
+              reposition = true;
+        }
+        if(!IsShown())
+        {
+              m_scroll_left_btn->Hide();
         }
     }
     else
@@ -659,30 +840,34 @@ void wxRibbonPage::ShowScrollButtons()
 
     if(show_right)
     {
-        if(m_scroll_right_btn == NULL)
+        wxMemoryDC temp_dc;
+        wxSize size;
+        long direction;
+        if(GetMajorAxis() == wxHORIZONTAL)
         {
-            wxMemoryDC temp_dc;
-            wxSize size;
-            long direction;
-            if(GetMajorAxis() == wxHORIZONTAL)
-            {
-                direction = wxRIBBON_SCROLL_BTN_RIGHT;
-                size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
-                size.SetHeight(GetSize().GetHeight());
-            }
-            else
-            {
-                direction = wxRIBBON_SCROLL_BTN_DOWN;
-                size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
-                size.SetWidth(GetSize().GetWidth());
-            }
-            wxPoint initial_pos = GetPosition() + GetSize() - size;
-            m_scroll_right_btn = new wxRibbonPageScrollButton(this, wxID_ANY, initial_pos, size, direction);
-            if(!IsShown())
-            {
-                m_scroll_right_btn->Hide();
-            }
-            reposition = true;
+              direction = wxRIBBON_SCROLL_BTN_RIGHT;
+              size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
+              size.SetHeight(GetSize().GetHeight());
+        }
+        else
+        {
+              direction = wxRIBBON_SCROLL_BTN_DOWN;
+              size = m_art->GetScrollButtonMinimumSize(temp_dc, GetParent(), direction);
+              size.SetWidth(GetSize().GetWidth());
+        }
+        wxPoint initial_pos = GetPosition() + GetSize() - size;
+        if (m_scroll_right_btn)
+        {
+              m_scroll_right_btn->SetSize(size);
+        }
+        else
+        {
+              m_scroll_right_btn = new wxRibbonPageScrollButton(this, wxID_ANY, initial_pos, size, direction);
+              reposition = true;
+        }
+        if(!IsShown())
+        {
+              m_scroll_right_btn->Hide();
         }
     }
     else
@@ -719,35 +904,43 @@ bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
     {
         int smallest_size = INT_MAX;
         wxRibbonPanel* smallest_panel = NULL;
+        wxSize* smallest_panel_size = NULL;
+        wxSize* panel_size = m_size_calc_array;
         for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
                   node;
-                  node = node->GetNext() )
+                  node = node->GetNext(), ++panel_size )
         {
             wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
             if(panel == NULL)
             {
                 continue;
             }
-            if(panel->IsSizingContinuous())
+            if (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)
+            {
+                // Don't change if it's flexible since we already calculated the
+                // correct size for the panel.
+            }
+            else if(panel->IsSizingContinuous())
             {
-                int size = GetSizeInOrientation(panel->GetSize(), direction);
+                int size = GetSizeInOrientation(*panel_size, direction);
                 if(size < smallest_size)
                 {
                     smallest_size = size;
                     smallest_panel = panel;
+                    smallest_panel_size = panel_size;
                 }
             }
             else
             {
-                wxSize current = panel->GetSize();
-                int size = GetSizeInOrientation(current, direction);
+                int size = GetSizeInOrientation(*panel_size, direction);
                 if(size < smallest_size)
                 {
-                    wxSize larger = panel->GetNextLargerSize(direction);
-                    if(larger != current && GetSizeInOrientation(larger, direction) > size)
+                    wxSize larger = panel->GetNextLargerSize(direction, *panel_size);
+                    if(larger != (*panel_size) && GetSizeInOrientation(larger, direction) > size)
                     {
                         smallest_size = size;
                         smallest_panel = panel;
+                        smallest_panel_size = panel_size;
                     }
                 }
             }
@@ -756,7 +949,6 @@ bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
         {
             if(smallest_panel->IsSizingContinuous())
             {
-                wxSize size = smallest_panel->GetSize();
                 int amount = maximum_amount;
                 if(amount > 32)
                 {
@@ -766,25 +958,23 @@ bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
                 }
                 if(direction & wxHORIZONTAL)
                 {
-                    size.x += amount;
+                    smallest_panel_size->x += amount;
                 }
                 if(direction & wxVERTICAL)
                 {
-                    size.y += amount;
+                    smallest_panel_size->y += amount;
                 }
-                smallest_panel->SetSize(size);
                 maximum_amount -= amount;
                 m_collapse_stack.Add(smallest_panel);
                 expanded_something = true;
             }
             else
             {
-                wxSize current = smallest_panel->GetSize();
-                wxSize larger = smallest_panel->GetNextLargerSize(direction);
-                wxSize delta = larger - current;
+                wxSize larger = smallest_panel->GetNextLargerSize(direction, *smallest_panel_size);
+                wxSize delta = larger - (*smallest_panel_size);
                 if(GetSizeInOrientation(delta, direction) <= maximum_amount)
                 {
-                    smallest_panel->SetSize(larger);
+                    *smallest_panel_size = larger;
                     maximum_amount -= GetSizeInOrientation(delta, direction);
                     m_collapse_stack.Add(smallest_panel);
                     expanded_something = true;
@@ -800,15 +990,7 @@ bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
             break;
         }
     }
-    if(expanded_something)
-    {
-        Refresh();
-        return true;
-    }
-    else
-    {
-        return false;
-    }
+    return expanded_something;
 }
 
 bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
@@ -818,18 +1000,31 @@ bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
     {
         int largest_size = 0;
         wxRibbonPanel* largest_panel = NULL;
+        wxSize* largest_panel_size = NULL;
+        wxSize* panel_size = m_size_calc_array;
         if(!m_collapse_stack.IsEmpty())
         {
             // For a more consistent panel layout, try to collapse panels which
             // were recently expanded.
             largest_panel = wxDynamicCast(m_collapse_stack.Last(), wxRibbonPanel);
             m_collapse_stack.RemoveAt(m_collapse_stack.GetCount() - 1);
+            for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
+                      node;
+                      node = node->GetNext(), ++panel_size )
+            {
+                wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
+                if(panel == largest_panel)
+                {
+                    largest_panel_size = panel_size;
+                    break;
+                }
+            }
         }
         else
         {
             for(wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
                       node;
-                      node = node->GetNext() )
+                      node = node->GetNext(), ++panel_size )
             {
                 wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
                 if(panel == NULL)
@@ -838,25 +1033,26 @@ bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
                 }
                 if(panel->IsSizingContinuous())
                 {
-                    int size = GetSizeInOrientation(panel->GetSize(), direction);
+                    int size = GetSizeInOrientation(*panel_size, direction);
                     if(size > largest_size)
                     {
                         largest_size = size;
                         largest_panel = panel;
+                        largest_panel_size = panel_size;
                     }
                 }
                 else
                 {
-                    wxSize current = panel->GetSize();
-                    int size = GetSizeInOrientation(current, direction);
+                    int size = GetSizeInOrientation(*panel_size, direction);
                     if(size > largest_size)
                     {
-                        wxSize smaller = panel->GetNextSmallerSize(direction);
-                        if(smaller != current &&
+                        wxSize smaller = panel->GetNextSmallerSize(direction, *panel_size);
+                        if(smaller != (*panel_size) &&
                             GetSizeInOrientation(smaller, direction) < size)
                         {
                             largest_size = size;
                             largest_panel = panel;
+                            largest_panel_size = panel_size;
                         }
                     }
                 }
@@ -866,7 +1062,6 @@ bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
         {
             if(largest_panel->IsSizingContinuous())
             {
-                wxSize size = largest_panel->GetSize();
                 int amount = minimum_amount;
                 if(amount > 32)
                 {
@@ -877,22 +1072,20 @@ bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
                 }
                 if(direction & wxHORIZONTAL)
                 {
-                    size.x -= amount;
+                    largest_panel_size->x -= amount;
                 }
                 if(direction & wxVERTICAL)
                 {
-                    size.y -= amount;
+                    largest_panel_size->y -= amount;
                 }
-                largest_panel->SetSize(size);
                 minimum_amount -= amount;
                 collapsed_something = true;
             }
             else
             {
-                wxSize current = largest_panel->GetSize();
-                wxSize smaller = largest_panel->GetNextSmallerSize(direction);
-                wxSize delta = current - smaller;
-                largest_panel->SetSize(smaller);
+                wxSize smaller = largest_panel->GetNextSmallerSize(direction, *largest_panel_size);
+                wxSize delta = (*largest_panel_size) - smaller;
+                *largest_panel_size = smaller;
                 minimum_amount -= GetSizeInOrientation(delta, direction);
                 collapsed_something = true;
             }
@@ -902,15 +1095,7 @@ bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
             break;
         }
     }
-    if(collapsed_something)
-    {
-        Refresh();
-        return true;
-    }
-    else
-    {
-        return false;
-    }
+    return collapsed_something;
 }
 
 bool wxRibbonPage::DismissExpandedPanel()
@@ -1034,4 +1219,9 @@ wxSize wxRibbonPage::DoGetBestSize() const
     return best;
 }
 
+void wxRibbonPage::HideIfExpanded()
+{
+    wxStaticCast(m_parent, wxRibbonBar)->HideIfExpanded();
+}
+
 #endif // wxUSE_RIBBON