/// <summary>
/// Perform a layout of the elements.
/// </summary>
/// <param name="context">Layout context.</param>
public override void Layout(ViewLayoutContext context)
{
Debug.Assert(context != null);
// Out enabled state is the same as that of the ribbon itself
Enabled = _ribbon.Enabled;
// We take on all the available display area
ClientRectangle = context.DisplayRectangle;
Rectangle layoutRect = ClientRectangle;
Rectangle controlRect = new Rectangle(Point.Empty, ClientSize);
// Reset the the view control layout offset to be zero again
_viewControl.LayoutOffset = Point.Empty;
// Ask the view control the size it would like to be, this is the requested filler
// size of the control. If it wants more than we can give then scroll buttons are
// needed, otherwise we can give it the requested size and any extra available.
_ribbon.GetViewManager().DoNotLayoutControls = true;
_viewControl.GetPreferredSize(context);
// Ensure context has the correct control
if ((_viewControl.ChildControl != null) && !_viewControl.ChildControl.IsDisposed)
{
using (CorrectContextControl ccc = new CorrectContextControl(context, _viewControl.ChildControl))
_viewFiller.Layout(context);
}
_ribbon.GetViewManager().DoNotLayoutControls = false;
Size fillerSize = _viewFiller.ClientSize;
// Limit check the scroll offset
_scrollOffset = Math.Max(_scrollOffset, 0);
// Did it fit fully into our space?
if (((Orientation == Orientation.Horizontal) && (fillerSize.Width <= ClientWidth)) ||
((Orientation == Orientation.Vertical) && (fillerSize.Height <= ClientHeight)))
{
// Filler rectangle is used for clipping
_viewClipRect = controlRect;
// Default back to left hand scroll position
_scrollOffset = 0;
// Then make the scrollers invisible and nothing more to do
_nearScroller.Visible = false;
_farScroller.Visible = false;
// We need to layout again but this time we do layout the actual children
_viewControl.Layout(context);
}
else
{
// We only need the near scroller if we are not at the left scroll position
if (_scrollOffset > 0)
{
_nearScroller.Visible = true;
// Find size requirements of the near scroller
Size nearSize = _nearScroller.GetPreferredSize(context);
// Find layout position of the near scroller
if (Orientation == Orientation.Horizontal)
{
context.DisplayRectangle = new Rectangle(layoutRect.X, layoutRect.Y, nearSize.Width, layoutRect.Height);
layoutRect.Width -= nearSize.Width;
layoutRect.X += nearSize.Width;
controlRect.Width -= nearSize.Width;
controlRect.X += nearSize.Width;
}
else
{
context.DisplayRectangle = new Rectangle(layoutRect.X, layoutRect.Y, layoutRect.Width, nearSize.Height);
layoutRect.Height -= nearSize.Height;
layoutRect.Y += nearSize.Height;
controlRect.Height -= nearSize.Height;
controlRect.Y += nearSize.Height;
}
_nearScroller.Layout(context);
}
else
{
_nearScroller.Visible = false;
}
int maxOffset = 0;
// Work out the maximum scroll offset needed to show all of the filler
if (Orientation == Orientation.Horizontal)
{
maxOffset = fillerSize.Width - layoutRect.Width;
}
else
{
maxOffset = fillerSize.Height - layoutRect.Height;
}
// We only need the far scroller if we are not at the right scroll position
if (_scrollOffset < maxOffset)
{
_farScroller.Visible = true;
// Find size requirements of the near scroller
Size farSize = _nearScroller.GetPreferredSize(context);
// Find layout position of the far scroller
if (Orientation == Orientation.Horizontal)
{
context.DisplayRectangle = new Rectangle(layoutRect.Right - farSize.Width, layoutRect.Y, farSize.Width, layoutRect.Height);
layoutRect.Width -= farSize.Width;
controlRect.Width -= farSize.Width;
}
else
{
context.DisplayRectangle = new Rectangle(layoutRect.X, layoutRect.Bottom - farSize.Height, layoutRect.Width, farSize.Height);
layoutRect.Height -= farSize.Height;
controlRect.Height -= farSize.Height;
}
_farScroller.Layout(context);
}
else
{
_farScroller.Visible = false;
}
// Calculate the maximum offset again with all scrollers positioned
if (Orientation == Orientation.Horizontal)
{
maxOffset = fillerSize.Width - layoutRect.Width;
}
else
{
maxOffset = fillerSize.Height - layoutRect.Height;
}
// Limit check the current offset
_scrollOffset = Math.Min(_scrollOffset, maxOffset);
// Filler rectangle is used for clipping
_viewClipRect = controlRect;
// Apply the offset to the display of the view filler
if (Orientation == Orientation.Horizontal)
{
_viewControl.LayoutOffset = new Point(-_scrollOffset, 0);
}
else
{
_viewControl.LayoutOffset = new Point(0, -_scrollOffset);
}
// Position the filler in the remaining space
context.DisplayRectangle = layoutRect;
_viewControl.GetPreferredSize(context);
_viewControl.Layout(context);
}
// Put back the original display value now we have finished
context.DisplayRectangle = ClientRectangle;
// If we are the scroller for the tab headers
if (_ribbon.InKeyboardMode && (_viewFiller is ViewLayoutRibbonTabs))
{
// Cast to correct type
ViewLayoutRibbonTabs layoutTabs = (ViewLayoutRibbonTabs)_viewFiller;
// If we have a selected tab, then ensure it is visible
if (_ribbon.SelectedTab != null)
{
// Cast to correct type
ViewBase viewTab = layoutTabs.GetViewForRibbonTab(_ribbon.SelectedTab);
// If a scroll change is required to bring it into view
if (ScrollIntoView(viewTab.ClientRectangle, false))
{
// Call ourself again to take change into account
Layout(context);
}
}
}
}