From: Julian Smart Date: Mon, 12 Mar 2012 19:30:10 +0000 (+0000) Subject: Added wxRIBBON_PANEL_FLEXIBLE flag to allow toolbars to wrap, taking up the optimum... X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/98742322cdecc1f91bb90d9c804318058722eab0?ds=sidebyside Added wxRIBBON_PANEL_FLEXIBLE flag to allow toolbars to wrap, taking up the optimum amount of space when used in a vertical palette. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@70885 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/ribbon/control.h b/include/wx/ribbon/control.h index 35cfd5777c..f0f3d12089 100644 --- a/include/wx/ribbon/control.h +++ b/include/wx/ribbon/control.h @@ -55,6 +55,9 @@ public: virtual bool Realize(); bool Realise() {return Realize();} + // Finds the best width and height given the parent's width and height + virtual wxSize GetBestSizeForParentSize(const wxSize& WXUNUSED(parentSize)) const { return GetBestSize(); } + protected: wxRibbonArtProvider* m_art; diff --git a/include/wx/ribbon/panel.h b/include/wx/ribbon/panel.h index 8a48c836fb..51d49c7964 100644 --- a/include/wx/ribbon/panel.h +++ b/include/wx/ribbon/panel.h @@ -24,6 +24,7 @@ enum wxRibbonPanelOption wxRIBBON_PANEL_EXT_BUTTON = 1 << 3, wxRIBBON_PANEL_MINIMISE_BUTTON = 1 << 4, wxRIBBON_PANEL_STRETCH = 1 << 5, + wxRIBBON_PANEL_FLEXIBLE = 1 << 6, wxRIBBON_PANEL_DEFAULT_STYLE = 0 }; @@ -75,6 +76,11 @@ public: wxRibbonPanel* GetExpandedDummy(); wxRibbonPanel* GetExpandedPanel(); + // Finds the best width and height given the parent's width and height + virtual wxSize GetBestSizeForParentSize(const wxSize& parentSize) const; + + long GetFlags() { return m_flags; } + protected: virtual wxSize DoGetBestSize() const; virtual wxSize GetPanelSizerBestSize() const; diff --git a/include/wx/ribbon/toolbar.h b/include/wx/ribbon/toolbar.h index a31f5aef48..da6c2624b7 100644 --- a/include/wx/ribbon/toolbar.h +++ b/include/wx/ribbon/toolbar.h @@ -155,6 +155,9 @@ public: virtual void EnableTool(int tool_id, bool enable = true); virtual void ToggleTool(int tool_id, bool checked); + // Finds the best width and height given the parent's width and height + virtual wxSize GetBestSizeForParentSize(const wxSize& parentSize) const; + protected: friend class wxRibbonToolBarEvent; virtual wxSize DoGetBestSize() const; diff --git a/interface/wx/ribbon/control.h b/interface/wx/ribbon/control.h index 8f497ef614..4a79b47354 100644 --- a/interface/wx/ribbon/control.h +++ b/interface/wx/ribbon/control.h @@ -13,7 +13,7 @@ ribbon characteristics of having a ribbon art provider, and (optionally) non-continuous resizing. Despite what the name may imply, it is not the top-level control for creating a ribbon interface - that is wxRibbonBar. - + Ribbon controls often have a region which is "transparent", and shows the contents of the ribbon page or panel behind it. If implementing a new ribbon control, then it may be useful to realise that this effect is done @@ -36,7 +36,7 @@ public: /** Constructor. - + If @a parent is a wxRibbonControl with a non-NULL art provider, then the art provider of new control is set to that of @a parent. */ @@ -50,12 +50,12 @@ public: Set the art provider to be used. In many cases, setting the art provider will also set the art provider on all child windows which extend wxRibbonControl. - + In most cases, controls will not take ownership of the given pointer, with the notable exception being wxRibbonBar::SetArtProvider(). */ virtual void SetArtProvider(wxRibbonArtProvider* art); - + /** Get the art provider to be used. Note that until an art provider has been set in some way, this function may return NULL. @@ -65,31 +65,31 @@ public: /** @return @true if this window can take any size (greater than its minimum size), @false if it can only take certain sizes. - + @see GetNextSmallerSize() @see GetNextLargerSize() */ virtual bool IsSizingContinuous() const; - + /** If sizing is not continuous, then return a suitable size for the control which is smaller than the current size. - + @param direction The direction(s) in which the size should reduce. @return The current size if there is no smaller size, otherwise a suitable size which is smaller in the given direction(s), and the same as the current size in the other direction (if any). - + @see IsSizingContinuous() */ wxSize GetNextSmallerSize(wxOrientation direction) const; - + /** If sizing is not continuous, then return a suitable size for the control which is smaller than the given size. - + @param direction The direction(s) in which the size should reduce. @param relative_to @@ -98,31 +98,31 @@ public: @a relative_to if there is no smaller size, otherwise a suitable size which is smaller in the given direction(s), and the same as @a relative_to in the other direction (if any). - + @see IsSizingContinuous() @see DoGetNextSmallerSize() */ wxSize GetNextSmallerSize(wxOrientation direction, wxSize relative_to) const; - + /** If sizing is not continuous, then return a suitable size for the control which is larger than the current size. - + @param direction The direction(s) in which the size should increase. @return The current size if there is no larger size, otherwise a suitable size which is larger in the given direction(s), and the same as the current size in the other direction (if any). - + @see IsSizingContinuous() */ wxSize GetNextLargerSize(wxOrientation direction) const; - + /** If sizing is not continuous, then return a suitable size for the control which is larger than the given size. - + @param direction The direction(s) in which the size should increase. @param relative_to @@ -131,23 +131,28 @@ public: @a relative_to if there is no larger size, otherwise a suitable size which is larger in the given direction(s), and the same as @a relative_to in the other direction (if any). - + @see IsSizingContinuous() @see DoGetNextLargerSize() */ wxSize GetNextLargerSize(wxOrientation direction, wxSize relative_to) const; - + /** Perform initial size and layout calculations after children have been added, and/or realize children. */ virtual bool Realize(); - + /** Alias for Realize(). */ bool Realise(); - + + /** + Finds the best width and height given the parent's width and height. + Used to implement the wxRIBBON_PANEL_FLEXIBLE panel style. + */ + virtual wxSize GetBestSizeForParentSize(const wxSize& parentSize) const; protected: /** Implementation of GetNextSmallerSize(). diff --git a/interface/wx/ribbon/panel.h b/interface/wx/ribbon/panel.h index fd455fe32a..0f91684637 100644 --- a/interface/wx/ribbon/panel.h +++ b/interface/wx/ribbon/panel.h @@ -45,6 +45,12 @@ minimises. @style{wxRIBBON_PANEL_STRETCH} Stretches a single panel to fit the parent page. + @style{wxRIBBON_PANEL_FLEXIBLE} + Allows the panel to size in both directions; currently only useful + when a single wxRibbonToolBar is the child of the panel, particularly + in vertical orientation where the number of rows is dependent on the + amount of horizontal space available. Set the minimum and maximum + toolbar rows to take full advantage of this wrapping behaviour. @endStyleTable @library{wxribbon} diff --git a/src/ribbon/page.cpp b/src/ribbon/page.cpp index 3448462420..17d8c316dc 100644 --- a/src/ribbon/page.cpp +++ b/src/ribbon/page.cpp @@ -495,19 +495,30 @@ bool wxRibbonPage::Realize() 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()) { delete[] m_size_calc_array; m_size_calc_array_size = GetChildren().GetCount(); m_size_calc_array = new wxSize[m_size_calc_array_size]; } + wxSize* node_size = m_size_calc_array; for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst(); node; node = node->GetNext(), ++node_size ) { wxWindow* child = node->GetData(); - *node_size = (child->*get_size)(); + wxRibbonPanel* panel = wxDynamicCast(child, wxRibbonPanel); + if (panel && panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE) + *node_size = panel->GetBestSizeForParentSize(parentSize); + else + *node_size = (child->*get_size)(); } } @@ -776,7 +787,12 @@ bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount) { 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_size, direction); if(size < smallest_size) diff --git a/src/ribbon/panel.cpp b/src/ribbon/panel.cpp index a14bb7336b..f8f26f1e89 100644 --- a/src/ribbon/panel.cpp +++ b/src/ribbon/panel.cpp @@ -311,6 +311,24 @@ bool wxRibbonPanel::IsSizingContinuous() const return (m_flags & wxRIBBON_PANEL_STRETCH) != 0; } +// Finds the best width and height given the parent's width and height +wxSize wxRibbonPanel::GetBestSizeForParentSize(const wxSize& parentSize) const +{ + if (GetChildren().GetCount() == 1) + { + wxWindow* win = GetChildren().GetFirst()->GetData(); + wxRibbonControl* control = wxDynamicCast(win, wxRibbonControl); + if (control) + { + wxClientDC temp_dc((wxRibbonPanel*) this); + wxSize childSize = control->GetBestSizeForParentSize(parentSize); + wxSize overallSize = m_art->GetPanelSize(temp_dc, this, childSize, NULL); + return overallSize; + } + } + return GetSize(); +} + wxSize wxRibbonPanel::DoGetNextSmallerSize(wxOrientation direction, wxSize relative_to) const { @@ -742,6 +760,13 @@ bool wxRibbonPanel::ShowExpanded() } wxSize size = GetBestSize(); + + // Special case for flexible panel layout, where GetBestSize doesn't work + if (GetFlags() & wxRIBBON_PANEL_FLEXIBLE) + { + size = GetBestSizeForParentSize(wxSize(400, 1000)); + } + wxPoint pos = GetExpandedPosition(wxRect(GetScreenPosition(), GetSize()), size, m_preferred_expand_direction).GetTopLeft(); @@ -750,7 +775,7 @@ bool wxRibbonPanel::ShowExpanded() pos, size, wxFRAME_NO_TASKBAR | wxBORDER_NONE); m_expanded_panel = new wxRibbonPanel(container, wxID_ANY, - GetLabel(), m_minimised_icon, wxPoint(0, 0), size, m_flags); + GetLabel(), m_minimised_icon, wxPoint(0, 0), size, (m_flags /* & ~wxRIBBON_PANEL_FLEXIBLE */)); m_expanded_panel->SetArtProvider(m_art); m_expanded_panel->m_expanded_dummy = this; diff --git a/src/ribbon/toolbar.cpp b/src/ribbon/toolbar.cpp index 4c4b14cdac..6c6c8b7f5a 100644 --- a/src/ribbon/toolbar.cpp +++ b/src/ribbon/toolbar.cpp @@ -781,7 +781,21 @@ bool wxRibbonToolBar::Realize() wxSize* row_sizes = new wxSize[m_nrows_max]; wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ? wxVERTICAL : wxHORIZONTAL; + SetMinSize(wxSize(0, 0)); + wxSize minSize(INT_MAX, INT_MAX); + + // See if we're sizing flexibly (i.e. wrapping), and set min size differently + bool sizingFlexibly = false; + wxRibbonPanel* panel = wxDynamicCast(GetParent(), wxRibbonPanel); + if (panel && (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)) + sizingFlexibly = true; + + // Without this, there will be redundant horizontal space because SetMinSize will + // use the smallest possible height (and therefore largest width). + if (sizingFlexibly) + major_axis = wxHORIZONTAL; + for(nrows = m_nrows_min; nrows <= m_nrows_max; ++nrows) { for(r = 0; r < nrows; ++r) @@ -809,12 +823,29 @@ bool wxRibbonToolBar::Realize() size.IncBy(0, row_sizes[r].y); } m_sizes[nrows - m_nrows_min] = size; + if(GetSizeInOrientation(size, major_axis) < smallest_area) { - SetMinSize(size); smallest_area = GetSizeInOrientation(size, major_axis); + SetMinSize(size); + } + + if (sizingFlexibly) + { + if (size.x < minSize.x) + minSize.x = size.x; + if (size.y < minSize.y) + minSize.y = size.y; } } + + if (sizingFlexibly) + { + // Give it the min size in either direction regardless of row, + // so that we're able to vary the size of the panel according to + // the space the toolbar takes up. + SetMinSize(minSize); + } delete[] row_sizes; // Position the groups @@ -834,6 +865,20 @@ void wxRibbonToolBar::OnSize(wxSizeEvent& evt) int row_count = m_nrows_max; wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ? wxVERTICAL : wxHORIZONTAL; + + // See if we're sizing flexibly, and set min size differently + bool sizingFlexibly = false; + wxRibbonPanel* panel = wxDynamicCast(GetParent(), wxRibbonPanel); + if (panel && (panel->GetFlags() & wxRIBBON_PANEL_FLEXIBLE)) + sizingFlexibly = true; + + // Without this, there will be redundant horizontal space because SetMinSize will + // use the smallest possible height (and therefore largest width). + if (sizingFlexibly) + major_axis = wxHORIZONTAL; + + wxSize bestSize = m_sizes[0]; + if(m_nrows_max != m_nrows_min) { int area = 0; @@ -844,6 +889,7 @@ void wxRibbonToolBar::OnSize(wxSizeEvent& evt) { area = GetSizeInOrientation(m_sizes[i], major_axis); row_count = m_nrows_min + i; + bestSize = m_sizes[i]; } } } @@ -895,6 +941,41 @@ void wxRibbonToolBar::OnSize(wxSizeEvent& evt) delete[] row_sizes; } +// Finds the best width and height given the parents' width and height +wxSize wxRibbonToolBar::GetBestSizeForParentSize(const wxSize& parentSize) const +{ + if (!m_sizes) + return GetMinSize(); + + // Choose row count with largest possible area + wxSize size = parentSize; + int row_count = m_nrows_max; + wxOrientation major_axis = m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL ? + wxVERTICAL : wxHORIZONTAL; + + // A toolbar should maximize its width whether vertical or horizontal, so + // force the major axis to be horizontal. Without this, there will be + // redundant horizontal space. + major_axis = wxHORIZONTAL; + wxSize bestSize = m_sizes[0]; + + if(m_nrows_max != m_nrows_min) + { + int area = 0; + for(int i = 0; i <= m_nrows_max - m_nrows_min; ++i) + { + if(m_sizes[i].x <= size.x && m_sizes[i].y <= size.y && + GetSizeInOrientation(m_sizes[i], major_axis) > area) + { + area = GetSizeInOrientation(m_sizes[i], major_axis); + row_count = m_nrows_min + i; + bestSize = m_sizes[i]; + } + } + } + return bestSize; +} + wxSize wxRibbonToolBar::DoGetBestSize() const { return GetMinSize();