Files
wxWidgets/src/ribbon/page.cpp
Vadim Zeitlin b31d6326be Fix ribbon bar scroll buttons visibility bug.
Fix scroll buttons update code in wxRibbonPage.

Closes #14844.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@72998 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
2012-11-23 14:34:31 +00:00

1110 lines
32 KiB
C++

///////////////////////////////////////////////////////////////////////////////
// Name: src/ribbon/page.cpp
// Purpose: Container for ribbon-bar-style interface panels
// Author: Peter Cawley
// Modified by:
// Created: 2009-05-25
// RCS-ID: $Id$
// Copyright: (C) Peter Cawley
// Licence: wxWindows licence
///////////////////////////////////////////////////////////////////////////////
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#if wxUSE_RIBBON
#include "wx/ribbon/page.h"
#include "wx/ribbon/art.h"
#include "wx/ribbon/bar.h"
#include "wx/dcbuffer.h"
#ifndef WX_PRECOMP
#endif
#ifdef __WXMSW__
#include "wx/msw/private.h"
#endif
static int GetSizeInOrientation(wxSize size, wxOrientation orientation);
// As scroll buttons need to be rendered on top of a page's child windows, the
// buttons themselves have to be proper child windows (rather than just painted
// onto the page). In order to get proper clipping of a page's children (with
// regard to the scroll button), the scroll buttons are created as children of
// the ribbon bar rather than children of the page. This could not have been
// achieved by creating buttons as children of the page and then doing some Z-order
// manipulation, as this causes problems on win32 due to ribbon panels having the
// transparent flag set.
class wxRibbonPageScrollButton : public wxRibbonControl
{
public:
wxRibbonPageScrollButton(wxRibbonPage* sibling,
wxWindowID id = wxID_ANY,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize,
long style = 0);
virtual ~wxRibbonPageScrollButton();
protected:
virtual wxBorder GetDefaultBorder() const { return wxBORDER_NONE; }
void OnEraseBackground(wxEraseEvent& evt);
void OnPaint(wxPaintEvent& evt);
void OnMouseEnter(wxMouseEvent& evt);
void OnMouseLeave(wxMouseEvent& evt);
void OnMouseDown(wxMouseEvent& evt);
void OnMouseUp(wxMouseEvent& evt);
wxRibbonPage* m_sibling;
long m_flags;
DECLARE_CLASS(wxRibbonPageScrollButton)
DECLARE_EVENT_TABLE()
};
IMPLEMENT_CLASS(wxRibbonPageScrollButton, wxRibbonControl)
BEGIN_EVENT_TABLE(wxRibbonPageScrollButton, wxRibbonControl)
EVT_ENTER_WINDOW(wxRibbonPageScrollButton::OnMouseEnter)
EVT_ERASE_BACKGROUND(wxRibbonPageScrollButton::OnEraseBackground)
EVT_LEAVE_WINDOW(wxRibbonPageScrollButton::OnMouseLeave)
EVT_LEFT_DOWN(wxRibbonPageScrollButton::OnMouseDown)
EVT_LEFT_UP(wxRibbonPageScrollButton::OnMouseUp)
EVT_PAINT(wxRibbonPageScrollButton::OnPaint)
END_EVENT_TABLE()
wxRibbonPageScrollButton::wxRibbonPageScrollButton(wxRibbonPage* sibling,
wxWindowID id,
const wxPoint& pos,
const wxSize& size,
long style) : wxRibbonControl(sibling->GetParent(), id, pos, size, wxBORDER_NONE)
{
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
m_sibling = sibling;
m_flags = (style & wxRIBBON_SCROLL_BTN_DIRECTION_MASK) | wxRIBBON_SCROLL_BTN_FOR_PAGE;
}
wxRibbonPageScrollButton::~wxRibbonPageScrollButton()
{
}
void wxRibbonPageScrollButton::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
{
// Do nothing - all painting done in main paint handler
}
void wxRibbonPageScrollButton::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
wxAutoBufferedPaintDC dc(this);
if(m_art)
{
m_art->DrawScrollButton(dc, this, GetSize(), m_flags);
}
}
void wxRibbonPageScrollButton::OnMouseEnter(wxMouseEvent& WXUNUSED(evt))
{
m_flags |= wxRIBBON_SCROLL_BTN_HOVERED;
Refresh(false);
}
void wxRibbonPageScrollButton::OnMouseLeave(wxMouseEvent& WXUNUSED(evt))
{
m_flags &= ~wxRIBBON_SCROLL_BTN_HOVERED;
m_flags &= ~wxRIBBON_SCROLL_BTN_ACTIVE;
Refresh(false);
}
void wxRibbonPageScrollButton::OnMouseDown(wxMouseEvent& WXUNUSED(evt))
{
m_flags |= wxRIBBON_SCROLL_BTN_ACTIVE;
Refresh(false);
}
void wxRibbonPageScrollButton::OnMouseUp(wxMouseEvent& WXUNUSED(evt))
{
if(m_flags & wxRIBBON_SCROLL_BTN_ACTIVE)
{
m_flags &= ~wxRIBBON_SCROLL_BTN_ACTIVE;
Refresh(false);
switch(m_flags & wxRIBBON_SCROLL_BTN_DIRECTION_MASK)
{
case wxRIBBON_SCROLL_BTN_DOWN:
case wxRIBBON_SCROLL_BTN_RIGHT:
m_sibling->ScrollLines(1);
break;
case wxRIBBON_SCROLL_BTN_UP:
case wxRIBBON_SCROLL_BTN_LEFT:
m_sibling->ScrollLines(-1);
break;
default:
break;
}
}
}
IMPLEMENT_CLASS(wxRibbonPage, wxRibbonControl)
BEGIN_EVENT_TABLE(wxRibbonPage, wxRibbonControl)
EVT_ERASE_BACKGROUND(wxRibbonPage::OnEraseBackground)
EVT_PAINT(wxRibbonPage::OnPaint)
EVT_SIZE(wxRibbonPage::OnSize)
END_EVENT_TABLE()
wxRibbonPage::wxRibbonPage()
{
m_scroll_left_btn = NULL;
m_scroll_right_btn = NULL;
m_scroll_amount = 0;
m_scroll_buttons_visible = false;
}
wxRibbonPage::wxRibbonPage(wxRibbonBar* parent,
wxWindowID id,
const wxString& label,
const wxBitmap& icon,
long WXUNUSED(style))
: wxRibbonControl(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE)
{
CommonInit(label, icon);
}
wxRibbonPage::~wxRibbonPage()
{
delete[] m_size_calc_array;
}
bool wxRibbonPage::Create(wxRibbonBar* parent,
wxWindowID id,
const wxString& label,
const wxBitmap& icon,
long WXUNUSED(style))
{
if(!wxRibbonControl::Create(parent, id, wxDefaultPosition, wxDefaultSize, wxBORDER_NONE))
return false;
CommonInit(label, icon);
return true;
}
void wxRibbonPage::CommonInit(const wxString& label, const wxBitmap& icon)
{
SetName(label);
SetLabel(label);
m_old_size = wxSize(0, 0);
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;
SetBackgroundStyle(wxBG_STYLE_CUSTOM);
wxDynamicCast(GetParent(), wxRibbonBar)->AddPage(this);
}
void wxRibbonPage::SetArtProvider(wxRibbonArtProvider* art)
{
m_art = art;
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow* child = node->GetData();
wxRibbonControl* ribbon_child = wxDynamicCast(child, wxRibbonControl);
if(ribbon_child)
{
ribbon_child->SetArtProvider(art);
}
}
}
void wxRibbonPage::AdjustRectToIncludeScrollButtons(wxRect* rect) const
{
if(m_scroll_buttons_visible)
{
if(GetMajorAxis() == wxVERTICAL)
{
if(m_scroll_left_btn)
{
rect->SetY(rect->GetY() -
m_scroll_left_btn->GetSize().GetHeight());
rect->SetHeight(rect->GetHeight() +
m_scroll_left_btn->GetSize().GetHeight());
}
if(m_scroll_right_btn)
{
rect->SetHeight(rect->GetHeight() +
m_scroll_right_btn->GetSize().GetHeight());
}
}
else
{
if(m_scroll_left_btn)
{
rect->SetX(rect->GetX() -
m_scroll_left_btn->GetSize().GetWidth());
rect->SetWidth(rect->GetWidth() +
m_scroll_left_btn->GetSize().GetWidth());
}
if(m_scroll_right_btn)
{
rect->SetWidth(rect->GetWidth() +
m_scroll_right_btn->GetSize().GetWidth());
}
}
}
}
void wxRibbonPage::OnEraseBackground(wxEraseEvent& WXUNUSED(evt))
{
// All painting done in main paint handler to minimise flicker
}
void wxRibbonPage::OnPaint(wxPaintEvent& WXUNUSED(evt))
{
// No foreground painting done by the page itself, but a paint DC
// must be created anyway.
wxAutoBufferedPaintDC dc(this);
wxRect rect(GetSize());
AdjustRectToIncludeScrollButtons(&rect);
m_art->DrawPageBackground(dc, this, rect);
}
wxOrientation wxRibbonPage::GetMajorAxis() const
{
if(m_art && (m_art->GetFlags() & wxRIBBON_BAR_FLOW_VERTICAL))
{
return wxVERTICAL;
}
else
{
return wxHORIZONTAL;
}
}
bool wxRibbonPage::ScrollLines(int lines)
{
return ScrollPixels(lines * 8);
}
bool wxRibbonPage::ScrollPixels(int pixels)
{
if(pixels < 0)
{
if(m_scroll_amount == 0)
return false;
if(m_scroll_amount < -pixels)
pixels = -m_scroll_amount;
}
else if(pixels > 0)
{
if(m_scroll_amount == m_scroll_amount_limit)
return false;
if(m_scroll_amount + pixels > m_scroll_amount_limit)
pixels = m_scroll_amount_limit - m_scroll_amount;
}
else
return false;
m_scroll_amount += pixels;
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow* child = node->GetData();
int x, y;
child->GetPosition(&x, &y);
if(GetMajorAxis() == wxHORIZONTAL)
x -= pixels;
else
y -= pixels;
child->SetPosition(wxPoint(x, y));
}
ShowScrollButtons();
Refresh();
return true;
}
void wxRibbonPage::SetSizeWithScrollButtonAdjustment(int x, int y, int width, int height)
{
if(m_scroll_buttons_visible)
{
if(GetMajorAxis() == wxHORIZONTAL)
{
if(m_scroll_left_btn)
{
int w = m_scroll_left_btn->GetSize().GetWidth();
m_scroll_left_btn->SetPosition(wxPoint(x, y));
x += w;
width -= w;
}
if(m_scroll_right_btn)
{
int w = m_scroll_right_btn->GetSize().GetWidth();
width -= w;
m_scroll_right_btn->SetPosition(wxPoint(x + width, y));
}
}
else
{
if(m_scroll_left_btn)
{
int h = m_scroll_left_btn->GetSize().GetHeight();
m_scroll_left_btn->SetPosition(wxPoint(x, y));
y += h;
height -= h;
}
if(m_scroll_right_btn)
{
int h = m_scroll_right_btn->GetSize().GetHeight();
height -= h;
m_scroll_right_btn->SetPosition(wxPoint(x, y + height));
}
}
}
if (width < 0) width = 0;
if (height < 0) height = 0;
SetSize(x, y, width, height);
}
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.
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);
}
void wxRibbonPage::OnSize(wxSizeEvent& evt)
{
wxSize new_size = evt.GetSize();
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;
if(new_size.GetX() > 0 && new_size.GetY() > 0)
{
Layout();
}
else
{
// Simplify other calculations by pretending new size is zero in both
// X and Y
new_size.Set(0, 0);
// When size == 0, no point in doing any layout
}
evt.Skip();
}
void wxRibbonPage::RemoveChild(wxWindowBase *child)
{
// Remove all references to the child from the collapse stack
size_t count = m_collapse_stack.GetCount();
size_t src, dst;
for(src = 0, dst = 0; src < count; ++src, ++dst)
{
wxRibbonControl *item = m_collapse_stack.Item(src);
if(item == child)
{
++src;
if(src == count)
{
break;
}
}
if(src != dst)
{
m_collapse_stack.Item(dst) = item;
}
}
if(src > dst)
{
m_collapse_stack.RemoveAt(dst, src - dst);
}
// ... and then proceed as normal
wxRibbonControl::RemoveChild(child);
}
bool wxRibbonPage::Realize()
{
bool status = true;
m_collapse_stack.Clear();
for (wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext())
{
wxRibbonControl* child = wxDynamicCast(node->GetData(), wxRibbonControl);
if(child == NULL)
{
continue;
}
if(!child->Realize())
{
status = false;
}
}
PopulateSizeCalcArray(&wxWindow::GetMinSize);
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())
{
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();
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()
{
if(GetChildren().GetCount() == 0)
{
return true;
}
else
{
PopulateSizeCalcArray(&wxWindow::GetSize);
return DoActualLayout();
}
}
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;
}
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)
{
if(major_axis == wxHORIZONTAL)
{
available_space -= m_size_calc_array[size_index].GetWidth();
m_size_calc_array[size_index].SetHeight(minor_axis_size);
}
else
{
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)
{
m_scroll_amount = m_scroll_amount_limit;
todo_show_scroll_buttons = true;
}
}
else
{
if(!CollapsePanels(major_axis, -available_space))
{
m_scroll_amount = 0;
m_scroll_amount_limit = -available_space;
todo_show_scroll_buttons = true;
}
}
}
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;
}
bool wxRibbonPage::Show(bool show)
{
if(m_scroll_left_btn)
m_scroll_left_btn->Show(show);
if(m_scroll_right_btn)
m_scroll_right_btn->Show(show);
return wxRibbonControl::Show(show);
}
void wxRibbonPage::HideScrollButtons()
{
m_scroll_amount = 0;
m_scroll_amount_limit = 0;
ShowScrollButtons();
}
void wxRibbonPage::ShowScrollButtons()
{
bool show_left = true;
bool show_right = true;
bool reposition = false;
if(m_scroll_amount == 0)
{
show_left = false;
}
if(m_scroll_amount >= m_scroll_amount_limit)
{
show_right = false;
m_scroll_amount = m_scroll_amount_limit;
}
m_scroll_buttons_visible = show_left || show_right;
if(show_left)
{
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());
}
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
{
if(m_scroll_left_btn != NULL)
{
m_scroll_left_btn->Destroy();
m_scroll_left_btn = NULL;
reposition = true;
}
}
if(show_right)
{
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;
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
{
if(m_scroll_right_btn != NULL)
{
m_scroll_right_btn->Destroy();
m_scroll_right_btn = NULL;
reposition = true;
}
}
if(reposition)
{
wxDynamicCast(GetParent(), wxRibbonBar)->RepositionPage(this);
}
}
static int GetSizeInOrientation(wxSize size, wxOrientation orientation)
{
switch(orientation)
{
case wxHORIZONTAL: return size.GetWidth();
case wxVERTICAL: return size.GetHeight();
case wxBOTH: return size.GetWidth() * size.GetHeight();
default: return 0;
}
}
bool wxRibbonPage::ExpandPanels(wxOrientation direction, int maximum_amount)
{
bool expanded_something = false;
while(maximum_amount > 0)
{
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(), ++panel_size )
{
wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
if(panel == NULL)
{
continue;
}
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)
{
smallest_size = size;
smallest_panel = panel;
smallest_panel_size = panel_size;
}
}
else
{
int size = GetSizeInOrientation(*panel_size, direction);
if(size < smallest_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;
}
}
}
}
if(smallest_panel != NULL)
{
if(smallest_panel->IsSizingContinuous())
{
int amount = maximum_amount;
if(amount > 32)
{
// For "large" growth, grow this panel a bit, and then re-allocate
// the remainder (which may come to this panel again anyway)
amount = 32;
}
if(direction & wxHORIZONTAL)
{
smallest_panel_size->x += amount;
}
if(direction & wxVERTICAL)
{
smallest_panel_size->y += amount;
}
maximum_amount -= amount;
m_collapse_stack.Add(smallest_panel);
expanded_something = true;
}
else
{
wxSize larger = smallest_panel->GetNextLargerSize(direction, *smallest_panel_size);
wxSize delta = larger - (*smallest_panel_size);
if(GetSizeInOrientation(delta, direction) <= maximum_amount)
{
*smallest_panel_size = larger;
maximum_amount -= GetSizeInOrientation(delta, direction);
m_collapse_stack.Add(smallest_panel);
expanded_something = true;
}
else
{
break;
}
}
}
else
{
break;
}
}
return expanded_something;
}
bool wxRibbonPage::CollapsePanels(wxOrientation direction, int minimum_amount)
{
bool collapsed_something = false;
while(minimum_amount > 0)
{
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(), ++panel_size )
{
wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
if(panel == NULL)
{
continue;
}
if(panel->IsSizingContinuous())
{
int size = GetSizeInOrientation(*panel_size, direction);
if(size > largest_size)
{
largest_size = size;
largest_panel = panel;
largest_panel_size = panel_size;
}
}
else
{
int size = GetSizeInOrientation(*panel_size, direction);
if(size > largest_size)
{
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;
}
}
}
}
}
if(largest_panel != NULL)
{
if(largest_panel->IsSizingContinuous())
{
int amount = minimum_amount;
if(amount > 32)
{
// For "large" contraction, reduce this panel a bit, and
// then re-allocate the remainder of the quota (which may
// come to this panel again anyway)
amount = 32;
}
if(direction & wxHORIZONTAL)
{
largest_panel_size->x -= amount;
}
if(direction & wxVERTICAL)
{
largest_panel_size->y -= amount;
}
minimum_amount -= amount;
collapsed_something = true;
}
else
{
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;
}
}
else
{
break;
}
}
return collapsed_something;
}
bool wxRibbonPage::DismissExpandedPanel()
{
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxRibbonPanel* panel = wxDynamicCast(node->GetData(), wxRibbonPanel);
if(panel == NULL)
{
continue;
}
if(panel->GetExpandedPanel() != NULL)
{
return panel->HideExpanded();
}
}
return false;
}
wxSize wxRibbonPage::GetMinSize() const
{
wxSize min(wxDefaultCoord, wxDefaultCoord);
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow* child = node->GetData();
wxSize child_min(child->GetMinSize());
min.x = wxMax(min.x, child_min.x);
min.y = wxMax(min.y, child_min.y);
}
if(GetMajorAxis() == wxHORIZONTAL)
{
min.x = wxDefaultCoord;
if(min.y != wxDefaultCoord)
{
min.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
}
}
else
{
if(min.x != wxDefaultCoord)
{
min.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
}
min.y = wxDefaultCoord;
}
return min;
}
wxSize wxRibbonPage::DoGetBestSize() const
{
wxSize best(0, 0);
size_t count = 0;
if(GetMajorAxis() == wxHORIZONTAL)
{
best.y = wxDefaultCoord;
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow* child = node->GetData();
wxSize child_best(child->GetBestSize());
if(child_best.x != wxDefaultCoord)
{
best.IncBy(child_best.x, 0);
}
best.y = wxMax(best.y, child_best.y);
++count;
}
if(count > 1)
{
best.IncBy((count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_X_SEPARATION_SIZE), 0);
}
}
else
{
best.x = wxDefaultCoord;
for ( wxWindowList::compatibility_iterator node = GetChildren().GetFirst();
node;
node = node->GetNext() )
{
wxWindow* child = node->GetData();
wxSize child_best(child->GetBestSize());
best.x = wxMax(best.x, child_best.x);
if(child_best.y != wxDefaultCoord)
{
best.IncBy(0, child_best.y);
}
++count;
}
if(count > 1)
{
best.IncBy(0, (count - 1) * m_art->GetMetric(wxRIBBON_ART_PANEL_Y_SEPARATION_SIZE));
}
}
if(best.x != wxDefaultCoord)
{
best.x += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_LEFT_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_RIGHT_SIZE);
}
if(best.y != wxDefaultCoord)
{
best.y += m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_TOP_SIZE) + m_art->GetMetric(wxRIBBON_ART_PAGE_BORDER_BOTTOM_SIZE);
}
return best;
}
void wxRibbonPage::HideIfExpanded()
{
wxStaticCast(m_parent, wxRibbonBar)->HideIfExpanded();
}
#endif // wxUSE_RIBBON