/// <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); } } } }