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
This commit is contained in:
Julian Smart 2012-03-12 19:30:10 +00:00
parent 4f134f0cf8
commit 98742322cd
8 changed files with 169 additions and 24 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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().

View File

@ -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}

View File

@ -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)

View File

@ -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;

View File

@ -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,11 +823,28 @@ 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;
@ -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();