public override IDisposable LayoutContent(ViewLayoutContext context,
Rectangle availableRect,
IPaletteContent palette,
IContentValues values,
VisualOrientation orientation,
PaletteState state,
bool composition)
{
Debug.Assert(context != null);
Debug.Assert(palette != null);
Debug.Assert(values != null);
// Validate parameter references
if (context == null) throw new ArgumentNullException("context");
if (palette == null) throw new ArgumentNullException("palette");
Debug.Assert(context.Control != null);
Debug.Assert(!context.Control.IsDisposed);
// Remember the original value, for use later
Rectangle cacheDisplayRect = availableRect;
// Grab the padding for the content
Padding borderPadding = palette.GetContentPadding(state);
// Is the content intended for a vertical drawing orientation?
bool vertical = (orientation == VisualOrientation.Left) ||
(orientation == VisualOrientation.Right);
// If we need to apply in a vertical orientation
if (vertical)
{
// Our algorithm only works by assuming a left to right horizontal
// orientation, so we adjust the display rect to that orientation
// and then at the end adjust the memento produced back to the
// required orientation again. 'AdjustForOrientation'
int temp = availableRect.Width;
availableRect.Width = availableRect.Height;
availableRect.Height = temp;
}
// Apply padding to the rectangle
availableRect.X += borderPadding.Left;
availableRect.Y += borderPadding.Top;
availableRect.Width -= borderPadding.Horizontal;
availableRect.Height -= borderPadding.Vertical;
// If we need to apply in a vertical orientation
if (vertical)
{
// This is the display rect we need to use in 'AdjustForOrientation'
// and cache it for later. The displayRect itself is modified during
// the below process and so cannot be used directly.
int temp = cacheDisplayRect.Width;
cacheDisplayRect.Width = cacheDisplayRect.Height;
cacheDisplayRect.Height = temp;
}
// Track the allocated space in each grid position
Size[,] allocation = new Size[3, 3] { { Size.Empty, Size.Empty, Size.Empty },
{ Size.Empty, Size.Empty, Size.Empty },
{ Size.Empty, Size.Empty, Size.Empty } };
// Create a memento to return to caller
StandardContentMemento memento = new StandardContentMemento();
// Cache the size of a spacing gap
int spacingGap = palette.GetContentAdjacentGap(state);
// Drawing vertical means we can ignore right to left, otherwise get value from control
RightToLeft rtl = (vertical ? RightToLeft.No : context.Control.RightToLeft);
// Allocate space for each required content in turn
AllocateImageSpace(memento, palette, values, state, availableRect, rtl, ref allocation);
AllocateShortTextSpace(context, context.Graphics, memento, palette, values, state, availableRect, rtl, spacingGap, ref allocation, composition);
AllocateLongTextSpace(context, context.Graphics, memento, palette, values, state, availableRect, rtl, spacingGap, ref allocation, composition);
// Find the width of the columns and heights of the rows
int[] colWidths = AllocatedColumnWidths(allocation, -1);
int[] rowHeights = AllocatedRowHeights(allocation);
// Add up total allocated for rows and columns
int allocatedWidth = AllocatedTotalWidth(allocation, -1, -1, spacingGap);
int allocatedHeight = AllocatedTotalHeight(allocation);
// Excess width to allocate?
if (allocatedWidth < availableRect.Width)
ApplyExcessSpace(availableRect.Width - allocatedWidth, ref colWidths);
// Excess height to allocate?
if (allocatedHeight < availableRect.Height)
rowHeights[1] += (availableRect.Height - allocatedHeight);
// Find x positions and y positions
int col0 = availableRect.Left;
int col1 = col0 + colWidths[0];
// Do we need to add a spacing gap after the first column?
if (((colWidths[0] > 0) && (colWidths[1] > 0)) ||
((colWidths[0] > 0) && (colWidths[1] == 0) && (colWidths[2] > 0)))
col1 += spacingGap;
int col2 = col1 + colWidths[1];
// Do we need to add a spacing gap after the second column?
if ((colWidths[1] > 0) && (colWidths[2] > 0))
col2 += spacingGap;
int row0 = availableRect.Top;
int row1 = row0 + rowHeights[0];
int row2 = row1 + rowHeights[1];
// Decide on the ordering of the alignment to position
PaletteRelativeAlign aAlign = (rtl == RightToLeft.Yes ? PaletteRelativeAlign.Far : PaletteRelativeAlign.Near);
PaletteRelativeAlign bAlign = PaletteRelativeAlign.Center;
PaletteRelativeAlign cAlign = (rtl == RightToLeft.Yes ? PaletteRelativeAlign.Near : PaletteRelativeAlign.Far);
// Size and position the contents of each aligned cell
PositionAlignContent(memento, palette, state, rtl, aAlign, PaletteRelativeAlign.Near, col0, row0, colWidths[0], rowHeights[0], spacingGap);
PositionAlignContent(memento, palette, state, rtl, aAlign, PaletteRelativeAlign.Center, col0, row1, colWidths[0], rowHeights[1], spacingGap);
PositionAlignContent(memento, palette, state, rtl, aAlign, PaletteRelativeAlign.Far, col0, row2, colWidths[0], rowHeights[2], spacingGap);
PositionAlignContent(memento, palette, state, rtl, bAlign, PaletteRelativeAlign.Near, col1, row0, colWidths[1], rowHeights[0], spacingGap);
PositionAlignContent(memento, palette, state, rtl, bAlign, PaletteRelativeAlign.Center, col1, row1, colWidths[1], rowHeights[1], spacingGap);
PositionAlignContent(memento, palette, state, rtl, bAlign, PaletteRelativeAlign.Far, col1, row2, colWidths[1], rowHeights[2], spacingGap);
PositionAlignContent(memento, palette, state, rtl, cAlign, PaletteRelativeAlign.Near, col2, row0, colWidths[2], rowHeights[0], spacingGap);
PositionAlignContent(memento, palette, state, rtl, cAlign, PaletteRelativeAlign.Center, col2, row1, colWidths[2], rowHeights[1], spacingGap);
PositionAlignContent(memento, palette, state, rtl, cAlign, PaletteRelativeAlign.Far, col2, row2, colWidths[2], rowHeights[2], spacingGap);
// Ask the memento to adjust itself for the required orientation
memento.AdjustForOrientation(orientation, cacheDisplayRect);
return memento;
}