]> git.saurik.com Git - wxWidgets.git/commitdiff
Improve support for ribbon panel sizers: panels with sizers should now automatically...
authorPeter Cawley <corsix@corsix.org>
Wed, 20 Oct 2010 17:49:42 +0000 (17:49 +0000)
committerPeter Cawley <corsix@corsix.org>
Wed, 20 Oct 2010 17:49:42 +0000 (17:49 +0000)
Patch by johnr in trac issue #12580.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

include/wx/ribbon/panel.h
interface/wx/ribbon/panel.h
samples/ribbon/ribbondemo.cpp
src/ribbon/art_msw.cpp
src/ribbon/panel.cpp

index 8d167e59bf88b31dbd29ea6cba5ae6bd6885aa0f..0c9f5f887fc9f34e2385967a0ed8ca0b679c055f 100644 (file)
@@ -76,6 +76,8 @@ public:
 
 protected:
     virtual wxSize DoGetBestSize() const;
+    virtual wxSize GetPanelSizerBestSize() const;
+    wxSize  GetPanelSizerMinSize() const;
     wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
     wxSize GetMinNotMinimisedSize() const;
 
index 208290141cab8a5fa6d7655a6034ac23f7055391..627ddfcfae366631a5c4c1f865da1e567da8fe17 100644 (file)
     A panel adds a border and label to a group of controls, and can be
     minimised (either automatically to conserve space, or manually by the user).
 
-    Non ribbon controls can be placed on a panel using wxSizers to manage
-    layout. wxWrapSizer and AddStretchSpacer() are useful for proportional
-    vertical and horizontal positioning. Note that layout is done within the
-    constraints of the panel's client area and this is dictated by
-    wxRibbonArtProvider.
-
-    Mixing ribbon and non-ribbon controls in a RibbonPanel is not supported at
-    present.
+    Non ribbon controls can be placed on a panel using wxSizers to manage 
+    layout. Panel size is governed by the sizer's minimum calculated size and 
+    the parent wxRibbonPage's dimensions. For functional and aesthetic reasons 
+    it is recommended that ribbon and non ribbon controls are not mixed in one
+    panel.
     
     @sa wxRibbonPage
     
index f95b50c715be3ccf232170faae2acd48b122eae9..e85a3217cb9c649dbfcfe4e9e27882ff042c7e39 100644 (file)
@@ -212,7 +212,9 @@ MyFrame::MyFrame()
 
     {
         wxRibbonPage* home = new wxRibbonPage(m_ribbon, wxID_ANY, wxT("Examples"), ribbon_xpm);
-        wxRibbonPanel *toolbar_panel = new wxRibbonPanel(home, wxID_ANY, wxT("Toolbar"), wxNullBitmap, wxDefaultPosition, wxDefaultSize, wxRIBBON_PANEL_NO_AUTO_MINIMISE);
+        wxRibbonPanel *toolbar_panel = new wxRibbonPanel(home, wxID_ANY, wxT("Toolbar"), 
+                                            wxNullBitmap, wxDefaultPosition, wxDefaultSize, 
+                                            wxRIBBON_PANEL_NO_AUTO_MINIMISE);
         wxRibbonToolBar *toolbar = new wxRibbonToolBar(toolbar_panel, ID_MAIN_TOOLBAR);
         toolbar->AddTool(wxID_ANY, align_left_xpm);
         toolbar->AddTool(wxID_ANY, align_center_xpm);
@@ -229,44 +231,60 @@ MyFrame::MyFrame()
         toolbar->AddTool(wxID_ANY, wxArtProvider::GetBitmap(wxART_REPORT_VIEW, wxART_OTHER, wxSize(16, 15)));
         toolbar->AddTool(wxID_ANY, wxArtProvider::GetBitmap(wxART_LIST_VIEW, wxART_OTHER, wxSize(16, 15)));
         toolbar->AddSeparator();
-        toolbar->AddHybridTool(ID_POSITION_LEFT, position_left_xpm);
-        toolbar->AddHybridTool(ID_POSITION_TOP, position_top_xpm);
+        toolbar->AddHybridTool(ID_POSITION_LEFT, position_left_xpm, 
+                                "Align ribbonbar vertically\non the left\nfor demonstration purposes");
+        toolbar->AddHybridTool(ID_POSITION_TOP, position_top_xpm, 
+                                "Align the ribbonbar horizontally\nat the top\nfor demonstration purposes");
         toolbar->AddSeparator();
-        toolbar->AddHybridTool(wxID_PRINT, wxArtProvider::GetBitmap(wxART_PRINT, wxART_OTHER, wxSize(16, 15)));
+        toolbar->AddHybridTool(wxID_PRINT, wxArtProvider::GetBitmap(wxART_PRINT, wxART_OTHER, wxSize(16, 15)),
+                                "This is the Print button tooltip\ndemonstrating a tooltip");
         toolbar->SetRows(2, 3);
 
         wxRibbonPanel *selection_panel = new wxRibbonPanel(home, wxID_ANY, wxT("Selection"), wxBitmap(selection_panel_xpm));
         wxRibbonButtonBar *selection = new wxRibbonButtonBar(selection_panel);
-        selection->AddButton(ID_SELECTION_EXPAND_V, wxT("Expand Vertically"), wxBitmap(expand_selection_v_xpm), wxEmptyString);
+        selection->AddButton(ID_SELECTION_EXPAND_V, wxT("Expand Vertically"), wxBitmap(expand_selection_v_xpm),
+                                "This is a tooltip for Expand Vertically\ndemonstrating a tooltip");
         selection->AddButton(ID_SELECTION_EXPAND_H, wxT("Expand Horizontally"), wxBitmap(expand_selection_h_xpm), wxEmptyString);
         selection->AddButton(ID_SELECTION_CONTRACT, wxT("Contract"), wxBitmap(auto_crop_selection_xpm), wxBitmap(auto_crop_selection_small_xpm));
 
         wxRibbonPanel *shapes_panel = new wxRibbonPanel(home, wxID_ANY, wxT("Shapes"), wxBitmap(circle_small_xpm));
         wxRibbonButtonBar *shapes = new wxRibbonButtonBar(shapes_panel);
-        shapes->AddButton(ID_CIRCLE, wxT("Circle"), wxBitmap(circle_xpm), wxBitmap(circle_small_xpm));
+        shapes->AddButton(ID_CIRCLE, wxT("Circle"), wxBitmap(circle_xpm), wxBitmap(circle_small_xpm), 
+                            wxNullBitmap, wxNullBitmap, wxRIBBON_BUTTON_NORMAL,
+                            "This is a tooltip for the circle button\ndemonstrating another tooltip");
         shapes->AddButton(ID_CROSS, wxT("Cross"), wxBitmap(cross_xpm), wxEmptyString);
         shapes->AddHybridButton(ID_TRIANGLE, wxT("Triangle"), wxBitmap(triangle_xpm));
         shapes->AddButton(ID_SQUARE, wxT("Square"), wxBitmap(square_xpm), wxEmptyString);
         shapes->AddDropdownButton(ID_POLYGON, wxT("Other Polygon"), wxBitmap(hexagon_xpm), wxEmptyString);
 
-        wxRibbonPanel *sizer_panel = new wxRibbonPanel(home, wxID_ANY, wxT("Panel with Sizer"),
-                                        wxNullBitmap, wxDefaultPosition, wxDefaultSize,
-                                        wxRIBBON_PANEL_EXT_BUTTON);
+        wxRibbonPanel *sizer_panel = new wxRibbonPanel(home, wxID_ANY, wxT("Panel with Sizer"), 
+                                                    wxNullBitmap, wxDefaultPosition, wxDefaultSize, 
+                                                    wxRIBBON_PANEL_DEFAULT_STYLE);
 
         wxArrayString as;
-        as.Add("Item 1");
-        as.Add("Item 2");
-        wxComboBox* sizer_panelcombo = new wxComboBox(sizer_panel, wxID_ANY, wxEmptyString,
-                             wxDefaultPosition, wxDefaultSize, as, wxCB_READONLY);
-        wxComboBox* sizer_panelcombo2 = new wxComboBox(sizer_panel, wxID_ANY, wxEmptyString,
-                             wxDefaultPosition, wxDefaultSize, as, wxCB_READONLY);
-
+        as.Add("Item 1 using a box sizer now");
+        as.Add("Item 2 using a box sizer now");
+        wxComboBox* sizer_panelcombo = new wxComboBox(sizer_panel, wxID_ANY, 
+                                                    wxEmptyString, 
+                                                    wxDefaultPosition, wxDefaultSize, 
+                                                    as, wxCB_READONLY);
+
+        wxComboBox* sizer_panelcombo2 = new wxComboBox(sizer_panel, wxID_ANY, 
+                                                    wxEmptyString, 
+                                                    wxDefaultPosition, wxDefaultSize, 
+                                                    as, wxCB_READONLY);
+
+        sizer_panelcombo->Select(0);
+        sizer_panelcombo2->Select(1);
         sizer_panelcombo->SetMinSize(wxSize(150, -1));
         sizer_panelcombo2->SetMinSize(wxSize(150, -1));
 
-        wxSizer* sizer_panelsizer = new wxWrapSizer(wxHORIZONTAL);
-        sizer_panelsizer->Add(sizer_panelcombo, 2, wxALL|wxEXPAND, 2);
-        sizer_panelsizer->Add(sizer_panelcombo2, 2, wxALL|wxEXPAND, 2);
+        //not using wxWrapSizer(wxHORIZONTAL) as it reports an incorrect min height
+        wxSizer* sizer_panelsizer = new wxBoxSizer(wxVERTICAL);
+        sizer_panelsizer->AddStretchSpacer(1);
+        sizer_panelsizer->Add(sizer_panelcombo, 0, wxALL|wxEXPAND, 2);
+        sizer_panelsizer->Add(sizer_panelcombo2, 0, wxALL|wxEXPAND, 2);
+        sizer_panelsizer->AddStretchSpacer(1);
         sizer_panel->SetSizer(sizer_panelsizer);
 
         wxFont label_font(8, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_LIGHT);
index e659ed6bc6d4ca0a4f39554e15cfbd3da405ad0a..af5673864a4d2dcb7f5cbf00d8913376851272cb 100644 (file)
@@ -1144,12 +1144,27 @@ void wxRibbonMSWArtProvider::ReallyDrawTabSeparator(wxWindow* wnd, const wxRect&
 }
 
 void wxRibbonMSWArtProvider::DrawPartialPageBackground(wxDC& dc,
-        wxWindow* WXUNUSED(wnd), const wxRect& rect, wxRibbonPage* page,
+        wxWindow* wnd, const wxRect& rect, wxRibbonPage* page,
         wxPoint offset, bool hovered)
 {
-    wxRect background(page->GetSize());
-    page->AdjustRectToIncludeScrollButtons(&background);
-    background.height -= 2;
+    wxRect background;
+    // Expanded panels need a background - the expanded panel at
+    // best size may have a greater Y dimension higher than when 
+    // on the bar if it has a sizer. AUI art provider does not need this
+    // because it paints the panel without reference to its parent's size.
+    // Expanded panels use a wxFrame as parent (not a wxRibbonPage). 
+
+    if(wnd->GetSizer() && wnd->GetParent() != page)
+    {
+        background = wnd->GetParent()->GetSize();
+        offset = wxPoint(0,0);
+    }
+    else
+    {
+        background = page->GetSize();
+        page->AdjustRectToIncludeScrollButtons(&background);
+        background.height -= 2;
+    }
     // Page background isn't dependant upon the width of the page
     // (at least not the part of it intended to be painted by this
     // function). Set to wider than the page itself for when externally
index ca0af0601e737c6e437024c19c44aac180676275..05621a9a052739559b99959992351adf4f4662ed 100644 (file)
@@ -111,7 +111,7 @@ void wxRibbonPanel::CommonInit(const wxString& label, const wxBitmap& icon, long
     SetLabel(label);
 
     m_minimised_size = wxDefaultSize; // Unknown / none
-    m_smallest_unminimised_size = wxSize(INT_MAX, INT_MAX); // Unknown / none
+    m_smallest_unminimised_size = wxDefaultSize;// Unknown / none for IsFullySpecified()
     m_preferred_expand_direction = wxSOUTH;
     m_expanded_dummy = NULL;
     m_expanded_panel = NULL;
@@ -234,11 +234,13 @@ void wxRibbonPanel::DoSetSize(int x, int y, int width, int height, int sizeFlags
     // will refuse to grow any larger while in limbo between minimised and non.
 
     bool minimised = (m_flags & wxRIBBON_PANEL_NO_AUTO_MINIMISE) == 0 &&
-        IsMinimised(wxSize(width, height));
+        IsMinimised(wxSize(width, height)); // check if would be at this size
     if(minimised != m_minimised)
     {
         m_minimised = minimised;
-
+        // Note that for sizers, this routine disallows the use of mixed shown 
+        // and hidden controls
+        // TODO ? use some list of user set invisible children to restore status.
         for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
                   node;
                   node = node->GetNext())
@@ -252,8 +254,20 @@ void wxRibbonPanel::DoSetSize(int x, int y, int width, int height, int sizeFlags
     wxRibbonControl::DoSetSize(x, y, width, height, sizeFlags);
 }
 
+// Checks if panel would be minimised at (client size) at_size
 bool wxRibbonPanel::IsMinimised(wxSize at_size) const
 {
+    if(GetSizer())
+    {
+        // we have no information on size change direction 
+        // so check both
+        wxSize size = GetMinNotMinimisedSize();
+        if(size.x > at_size.x || size.y > at_size.y)
+            return true;
+
+        return false;
+    }
+
     if(!m_minimised_size.IsFullySpecified())
         return false;
 
@@ -302,46 +316,70 @@ wxSize wxRibbonPanel::DoGetNextSmallerSize(wxOrientation direction,
         return m_expanded_panel->DoGetNextSmallerSize(direction, relative_to);
     }
 
-    // TODO: Check for, and delegate to, a sizer
-
-    // Simple (and common) case of single ribbon child
-    if(GetChildren().GetCount() == 1)
+    if(m_art != NULL)
     {
-        wxWindow* child = GetChildren().Item(0)->GetData();
-        wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl);
-        if(m_art != NULL && ribbon_child != NULL)
+        wxClientDC dc((wxRibbonPanel*) this);
+        wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL);
+        wxSize smaller(-1, -1);
+        bool minimise = false;
+
+        if(GetSizer())
         {
-            wxClientDC dc((wxRibbonPanel*) this);
-            wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL);
-            wxSize smaller = ribbon_child->GetNextSmallerSize(direction, child_relative);
-            if(smaller == child_relative)
+            // Get smallest non minimised size
+            smaller = GetMinSize();
+            // and adjust to child_relative for parent page
+            if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
             {
-                if(CanAutoMinimise())
-                {
-                    wxSize minimised = m_minimised_size;
-                    switch(direction)
-                    {
-                    case wxHORIZONTAL:
-                        minimised.SetHeight(relative_to.GetHeight());
-                        break;
-                    case wxVERTICAL:
-                        minimised.SetWidth(relative_to.GetWidth());
-                        break;
-                    default:
-                        break;
-                    }
-                    return minimised;
-                }
-                else
+                 minimise = (child_relative.y <= smaller.y);
+                 if(smaller.x < child_relative.x)
+                    smaller.x = child_relative.x;
+            }
+            else
+            {
+                minimise = (child_relative.x <= smaller.x);
+                if(smaller.y < child_relative.y)
+                    smaller.y = child_relative.y;
+            }
+        }
+        else if(GetChildren().GetCount() == 1)
+        {
+            // Simple (and common) case of single ribbon child or Sizer
+            wxWindow* child = GetChildren().Item(0)->GetData();
+            wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl);
+            if(ribbon_child != NULL)
+            {
+                smaller = ribbon_child->GetNextSmallerSize(direction, child_relative);                
+                minimise = (smaller == child_relative);
+            }
+        }
+
+        if(minimise)
+        {
+            if(CanAutoMinimise())
+            {
+                wxSize minimised = m_minimised_size;
+                switch(direction)
                 {
-                    return relative_to;
+                case wxHORIZONTAL:
+                    minimised.SetHeight(relative_to.GetHeight());
+                    break;
+                case wxVERTICAL:
+                    minimised.SetWidth(relative_to.GetWidth());
+                    break;
+                default:
+                    break;
                 }
+                return minimised;
             }
             else
             {
-                return m_art->GetPanelSize(dc, this, smaller, NULL);
+                return relative_to;
             }
         }
+        else if(smaller.IsFullySpecified()) // Use fallback if !(sizer/child = 1)
+        {
+            return m_art->GetPanelSize(dc, this, smaller, NULL);
+        }
     }
 
     // Fallback: Decrease by 20% (or minimum size, whichever larger)
@@ -399,25 +437,47 @@ wxSize wxRibbonPanel::DoGetNextLargerSize(wxOrientation direction,
         }
     }
 
-    // TODO: Check for, and delegate to, a sizer
-
-    // Simple (and common) case of single ribbon child
-    if(GetChildren().GetCount() == 1)
+    if(m_art != NULL)
     {
-        wxWindow* child = GetChildren().Item(0)->GetData();
-        wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl);
-        if(ribbon_child != NULL)
+        wxClientDC dc((wxRibbonPanel*) this);
+        wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL);
+        wxSize larger(-1, -1);
+
+        if(GetSizer())
+        {
+            // We could just let the sizer expand in flow direction but see comment 
+            // in IsSizingContinuous()
+            larger = GetPanelSizerBestSize();
+            // and adjust for page in non flow direction
+            if(m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL)
+            {
+                 if(larger.x != child_relative.x)
+                    larger.x = child_relative.x;
+            }
+            else if(larger.y != child_relative.y)
+            {
+                larger.y = child_relative.y;
+            }
+        }
+        else if(GetChildren().GetCount() == 1)
+        {
+            // Simple (and common) case of single ribbon child
+            wxWindow* child = GetChildren().Item(0)->GetData();
+            wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl);
+            if(ribbon_child != NULL)
+            {
+                larger = ribbon_child->GetNextLargerSize(direction, child_relative);
+            }
+        }
+
+        if(larger.IsFullySpecified()) // Use fallback if !(sizer/child = 1)
         {
-            wxClientDC dc((wxRibbonPanel*) this);
-            wxSize child_relative = m_art->GetPanelClientSize(dc, this, relative_to, NULL);
-            wxSize larger = ribbon_child->GetNextLargerSize(direction, child_relative);
             if(larger == child_relative)
             {
                 return relative_to;
             }
             else
             {
-                wxClientDC dc((wxRibbonPanel*) this);
                 return m_art->GetPanelSize(dc, this, larger, NULL);
             }
         }
@@ -468,11 +528,15 @@ wxSize wxRibbonPanel::GetMinSize() const
 
 wxSize wxRibbonPanel::GetMinNotMinimisedSize() const
 {
-    // TODO: Ask sizer
-
-    // Common case of no sizer and single child taking up the entire panel
-    if(GetChildren().GetCount() == 1)
+    // Ask sizer if present
+    if(GetSizer())
     {
+        wxClientDC dc((wxRibbonPanel*) this);
+        return m_art->GetPanelSize(dc, this, GetPanelSizerMinSize(), NULL);
+    }
+    else if(GetChildren().GetCount() == 1)
+    {
+        // Common case of single child taking up the entire panel
         wxWindow* child = GetChildren().Item(0)->GetData();
         wxClientDC dc((wxRibbonPanel*) this);
         return m_art->GetPanelSize(dc, this, child->GetMinSize(), NULL);
@@ -481,13 +545,47 @@ wxSize wxRibbonPanel::GetMinNotMinimisedSize() const
     return wxRibbonControl::GetMinSize();
 }
 
-wxSize wxRibbonPanel::DoGetBestSize() const
+wxSize wxRibbonPanel::GetPanelSizerMinSize() const
+{
+    // Called from Realize() to set m_smallest_unminimised_size and from other
+    // functions to get the minimum size.
+    // The panel will be invisible when minimised and sizer calcs will be 0
+    // Uses m_smallest_unminimised_size in preference to GetSizer()->CalcMin()
+    // to eliminate flicker.
+
+    // Check if is visible and not previously calculated
+    if(IsShown() && !m_smallest_unminimised_size.IsFullySpecified())
+    {
+         return GetSizer()->CalcMin();
+    }
+    // else use previously calculated m_smallest_unminimised_size
+    wxClientDC dc((wxRibbonPanel*) this);
+    return m_art->GetPanelClientSize(dc, 
+                                    this, 
+                                    m_smallest_unminimised_size,
+                                    NULL);
+}
+
+wxSize wxRibbonPanel::GetPanelSizerBestSize() const
 {
-    // TODO: Ask sizer
+    wxSize size = GetPanelSizerMinSize();
+    // TODO allow panel to increase its size beyond minimum size
+    // by steps similarly to ribbon control panels (preferred for aesthetics)
+    // or continuously.
+    return size;
+}
 
-    // Common case of no sizer and single child taking up the entire panel
-    if(GetChildren().GetCount() == 1)
+wxSize wxRibbonPanel::DoGetBestSize() const
+{
+    // Ask sizer if present
+    if( GetSizer())
+    {
+        wxClientDC dc((wxRibbonPanel*) this);
+        return m_art->GetPanelSize(dc, this, GetPanelSizerBestSize(), NULL);
+    }
+    else if(GetChildren().GetCount() == 1)
     {
+        // Common case of no sizer and single child taking up the entire panel
         wxWindow* child = GetChildren().Item(0)->GetData();
         wxClientDC dc((wxRibbonPanel*) this);
         return m_art->GetPanelSize(dc, this, child->GetBestSize(), NULL);
@@ -516,8 +614,13 @@ bool wxRibbonPanel::Realize()
     }
 
     wxSize minimum_children_size(0, 0);
-    // TODO: Ask sizer if there is one
-    if(GetChildren().GetCount() == 1)
+
+    // Ask sizer if there is one present
+    if(GetSizer())
+    {
+        minimum_children_size = GetPanelSizerMinSize();
+    }
+    else if(GetChildren().GetCount() == 1)
     {
         minimum_children_size = GetChildren().GetFirst()->GetData()->GetMinSize();
     }
@@ -583,10 +686,10 @@ bool wxRibbonPanel::Layout()
     wxClientDC dc(this);
     wxSize size = m_art->GetPanelClientSize(dc, this, GetSize(), &position);
 
-    // If there is a sizer, use it instead
-    if ( GetSizer() )
+    // If there is a sizer, use it
+    if(GetSizer())
     {
-        GetSizer()->SetDimension(position.x, position.y, size.GetWidth(), size.GetHeight());
+        GetSizer()->SetDimension(position, size); // SetSize and Layout()
     }
     else if(GetChildren().GetCount() == 1)
     {
@@ -662,7 +765,13 @@ bool wxRibbonPanel::ShowExpanded()
         child->Show();
     }
 
-    // TODO: Move sizer to new panel
+    // Move sizer to new panel
+    if(GetSizer())    
+    {
+        wxSizer* sizer = GetSizer();
+        SetSizer(NULL, false); 
+        m_expanded_panel->SetSizer(sizer);
+    }
 
     m_expanded_panel->Realize();
     Refresh();
@@ -783,7 +892,13 @@ bool wxRibbonPanel::HideExpanded()
         child->Hide();
     }
 
-    // TODO: Move sizer back
+    // Move sizer back
+    if(GetSizer())
+    {
+        wxSizer* sizer = GetSizer();
+        SetSizer(NULL, false);
+        m_expanded_dummy->SetSizer(sizer);
+    }
 
     m_expanded_dummy->m_expanded_panel = NULL;
     m_expanded_dummy->Realize();