From: Peter Cawley Date: Wed, 20 Oct 2010 17:49:42 +0000 (+0000) Subject: Improve support for ribbon panel sizers: panels with sizers should now automatically... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/140091e55c98abbb7616f613f95cb2a736fc5f25 Improve support for ribbon panel sizers: panels with sizers should now automatically minimise at small sizes, and behave properly when popping up from a minimised state. Patch by johnr in trac issue #12580. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@65852 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/ribbon/panel.h b/include/wx/ribbon/panel.h index 8d167e59bf..0c9f5f887f 100644 --- a/include/wx/ribbon/panel.h +++ b/include/wx/ribbon/panel.h @@ -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; diff --git a/interface/wx/ribbon/panel.h b/interface/wx/ribbon/panel.h index 208290141c..627ddfcfae 100644 --- a/interface/wx/ribbon/panel.h +++ b/interface/wx/ribbon/panel.h @@ -16,14 +16,11 @@ 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 diff --git a/samples/ribbon/ribbondemo.cpp b/samples/ribbon/ribbondemo.cpp index f95b50c715..e85a3217cb 100644 --- a/samples/ribbon/ribbondemo.cpp +++ b/samples/ribbon/ribbondemo.cpp @@ -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); diff --git a/src/ribbon/art_msw.cpp b/src/ribbon/art_msw.cpp index e659ed6bc6..af5673864a 100644 --- a/src/ribbon/art_msw.cpp +++ b/src/ribbon/art_msw.cpp @@ -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 diff --git a/src/ribbon/panel.cpp b/src/ribbon/panel.cpp index ca0af0601e..05621a9a05 100644 --- a/src/ribbon/panel.cpp +++ b/src/ribbon/panel.cpp @@ -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();