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
1110 lines
32 KiB
C++
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
|