private static void Copy(ArrangedElementCollection sourceList, int sourceIndex, ArrangedElementCollection destinationList, int destinationIndex, int length) { if (sourceIndex < destinationIndex) { sourceIndex += length; destinationIndex += length; while (length > 0) { destinationList.InnerList[--destinationIndex] = sourceList.InnerList[--sourceIndex]; length--; } } else { while (length > 0) { destinationList.InnerList[destinationIndex++] = sourceList.InnerList[sourceIndex++]; length--; } } }
private static void Copy (ArrangedElementCollection sourceList, int sourceIndex, ArrangedElementCollection destinationList, int destinationIndex, int length) { if(sourceIndex < destinationIndex) { // We need to copy from the back forward to prevent overwrite if source and // destination lists are the same, so we need to flip the source/dest indices // to point at the end of the spans to be copied. sourceIndex = sourceIndex + length; destinationIndex = destinationIndex + length; for(;length > 0; length--) { destinationList.InnerList[--destinationIndex] = sourceList.InnerList[--sourceIndex]; } } else { for(;length > 0; length--) { destinationList.InnerList[destinationIndex++] = sourceList.InnerList[sourceIndex++]; } } }
private Size TryCalculatePreferredSizeRow(ContainerProxy containerProxy, ElementProxy elementProxy, int startIndex, int endIndex, Rectangle rowBounds, out int breakIndex, bool measureOnly) { Debug.Assert(startIndex < endIndex, "Loop should be in forward Z-order."); Point location = rowBounds.Location; Size rowSize = Size.Empty; int laidOutItems = 0; breakIndex = startIndex; bool wrapContents = GetWrapContents(containerProxy.Container); bool breakOnNextItem = false; ArrangedElementCollection collection = containerProxy.Container.Children; for (int i = startIndex; i < endIndex; i++, breakIndex++) { elementProxy.Element = collection[i]; if (!elementProxy.ParticipatesInLayout) { continue; } // Figure out how much space this element is going to need (requiredSize) Size prefSize; if (elementProxy.AutoSize) { Size elementConstraints = new Size(int.MaxValue, rowBounds.Height - elementProxy.Margin.Size.Height); if (i == startIndex) { // If the element is the first in the row, attempt to pack it to the row width. (If its not 1st, it will wrap // to the first on the next row if its too long and then be packed if needed by the next call to TryCalculatePreferredSizeRow). elementConstraints.Width = rowBounds.Width - rowSize.Width - elementProxy.Margin.Size.Width; } // Make sure that subtracting the margins does not cause width/height to be <= 0, or we will // size as if we had infinite space when in fact we are trying to be as small as possible. elementConstraints = LayoutUtils.UnionSizes(new Size(1, 1), elementConstraints); prefSize = elementProxy.GetPreferredSize(elementConstraints); } else { // If autosizing is turned off, we just use the element's current size as its preferred size. prefSize = elementProxy.SpecifiedSize; // except if it is stretching - then ignore the affect of the height dimension. if (elementProxy.Stretches) { prefSize.Height = 0; } // Enforce MinimumSize if (prefSize.Height < elementProxy.MinimumSize.Height) { prefSize.Height = elementProxy.MinimumSize.Height; } } Size requiredSize = prefSize + elementProxy.Margin.Size; // Position the element (if applicable). if (!measureOnly) { // If measureOnly = false, rowBounds.Height = measured row hieght // (otherwise its the remaining displayRect of the container) Rectangle cellBounds = new Rectangle(location, new Size(requiredSize.Width, rowBounds.Height)); // We laid out the rows with the elementProxy's margins included. // We now deflate the rect to get the actual elementProxy bounds. cellBounds = LayoutUtils.DeflateRect(cellBounds, elementProxy.Margin); AnchorStyles anchorStyles = elementProxy.AnchorStyles; containerProxy.Bounds = LayoutUtils.AlignAndStretch(prefSize, cellBounds, anchorStyles); } // Keep track of how much space is being used in this row location.X += requiredSize.Width; if (laidOutItems > 0) { // If control does not fit on this row, exclude it from row and stop now. // Exception: If row is empty, allow this control to fit on it. So controls // that exceed the maximum row width will end up occupying their own rows. if (location.X > rowBounds.Right) { break; } } // Control fits on this row, so update the row size. // rowSize.Width != location.X because with a scrollable control // we could have started with a location like -100. rowSize.Width = location.X - rowBounds.X; rowSize.Height = Math.Max(rowSize.Height, requiredSize.Height); // check for line breaks. if (wrapContents) { if (breakOnNextItem) { break; } else if (i + 1 < endIndex && CommonProperties.GetFlowBreak(elementProxy.Element)) { if (laidOutItems == 0) { breakOnNextItem = true; } else { breakIndex++; break; } } } laidOutItems++; } return(rowSize); }
private Size xLayoutRow(ContainerProxy containerProxy, ElementProxy elementProxy, int startIndex, int endIndex, Rectangle rowBounds, out int breakIndex, bool measureOnly) { Point location = rowBounds.Location; Size empty = Size.Empty; int num = 0; breakIndex = startIndex; bool wrapContents = GetWrapContents(containerProxy.Container); bool flag2 = false; ArrangedElementCollection children = containerProxy.Container.Children; int num2 = startIndex; while (num2 < endIndex) { elementProxy.Element = children[num2]; if (elementProxy.ParticipatesInLayout) { Size preferredSize; if (elementProxy.AutoSize) { Size b = new Size(0x7fffffff, rowBounds.Height - elementProxy.Margin.Size.Height); if (num2 == startIndex) { b.Width = (rowBounds.Width - empty.Width) - elementProxy.Margin.Size.Width; } b = LayoutUtils.UnionSizes(new Size(1, 1), b); preferredSize = elementProxy.GetPreferredSize(b); } else { preferredSize = elementProxy.SpecifiedSize; if (elementProxy.Stretches) { preferredSize.Height = 0; } if (preferredSize.Height < elementProxy.MinimumSize.Height) { preferredSize.Height = elementProxy.MinimumSize.Height; } } Size size4 = preferredSize + elementProxy.Margin.Size; if (!measureOnly) { Rectangle rect = new Rectangle(location, new Size(size4.Width, rowBounds.Height)); rect = LayoutUtils.DeflateRect(rect, elementProxy.Margin); AnchorStyles anchorStyles = elementProxy.AnchorStyles; containerProxy.Bounds = LayoutUtils.AlignAndStretch(preferredSize, rect, anchorStyles); } location.X += size4.Width; if ((num > 0) && (location.X > rowBounds.Right)) { return(empty); } empty.Width = location.X - rowBounds.X; empty.Height = Math.Max(empty.Height, size4.Height); if (wrapContents) { if (flag2) { return(empty); } if (((num2 + 1) < endIndex) && CommonProperties.GetFlowBreak(elementProxy.Element)) { if (num == 0) { flag2 = true; } else { breakIndex++; return(empty); } } } num++; } num2++; breakIndex++; } return(empty); }
private static Size GetAnchorPreferredSize(IArrangedElement container) { Size prefSize = Size.Empty; ArrangedElementCollection children = container.Children; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = container.Children[i]; if (!CommonProperties.GetNeedsDockLayout(element) && element.ParticipatesInLayout) { AnchorStyles anchor = GetAnchor(element); Padding margin = CommonProperties.GetMargin(element); Rectangle elementSpace = LayoutUtils.InflateRect(GetCachedBounds(element), margin); if (IsAnchored(anchor, AnchorStyles.Left) && !IsAnchored(anchor, AnchorStyles.Right)) { // If we are anchored to the left we make sure the container is large enough not to clip us // (unless we are right anchored, in which case growing the container will just resize us.) prefSize.Width = Math.Max(prefSize.Width, elementSpace.Right); } if (!IsAnchored(anchor, AnchorStyles.Bottom)) { // If we are anchored to the top we make sure the container is large enough not to clip us // (unless we are bottom anchored, in which case growing the container will just resize us.) prefSize.Height = Math.Max(prefSize.Height, elementSpace.Bottom); } if (IsAnchored(anchor, AnchorStyles.Right)) { // If we are right anchored, see what the anchor distance between our right edge and // the container is, and make sure our container is large enough to accomodate us. Rectangle anchorDest = GetAnchorDestination(element, Rectangle.Empty, /*measureOnly=*/ true); if (anchorDest.Width < 0) { prefSize.Width = Math.Max(prefSize.Width, elementSpace.Right + anchorDest.Width); } else { prefSize.Width = Math.Max(prefSize.Width, anchorDest.Right); } } if (IsAnchored(anchor, AnchorStyles.Bottom)) { // If we are right anchored, see what the anchor distance between our right edge and // the container is, and make sure our container is large enough to accomodate us. Rectangle anchorDest = GetAnchorDestination(element, Rectangle.Empty, /*measureOnly=*/ true); if (anchorDest.Height < 0) { prefSize.Height = Math.Max(prefSize.Height, elementSpace.Bottom + anchorDest.Height); } else { prefSize.Height = Math.Max(prefSize.Height, anchorDest.Bottom); } } } } return(prefSize); }
private static bool TryCalculatePreferredSize(IArrangedElement container, bool measureOnly, out Size preferredSize) { ArrangedElementCollection children = container.Children; // PreferredSize is garbage unless measureOnly is specified preferredSize = new Size(-7103, -7105); // Short circuit for items with no children if (!measureOnly && children.Count == 0) { return(CommonProperties.GetAutoSize(container)); } bool dock = false; bool anchor = false; bool autoSize = false; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = children[i]; if (CommonProperties.GetNeedsDockAndAnchorLayout(element)) { if (!dock && CommonProperties.GetNeedsDockLayout(element)) { dock = true; } if (!anchor && CommonProperties.GetNeedsAnchorLayout(element)) { anchor = true; } if (!autoSize && CommonProperties.xGetAutoSizedAndAnchored(element)) { autoSize = true; } } } Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tanchor : " + anchor.ToString()); Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tdock : " + dock.ToString()); Size preferredSizeForDocking = Size.Empty; Size preferredSizeForAnchoring = Size.Empty; if (dock) { preferredSizeForDocking = LayoutDockedControls(container, measureOnly); } if (anchor && !measureOnly) { // In the case of anchor, where we currently are defines the preferred size, // so dont recalculate the positions of everything. LayoutAnchoredControls(container); } if (autoSize) { LayoutAutoSizedControls(container); } if (!measureOnly) { // Set the anchored controls to their computed positions. ApplyCachedBounds(container); } else { // Finish the preferredSize computation and clear cached anchored positions. preferredSizeForAnchoring = GetAnchorPreferredSize(container); Padding containerPadding = Padding.Empty; if (container is Control control) { // Calling this will respect Control.DefaultPadding. containerPadding = control.Padding; } else { // Not likely to happen but handle this gracefully. containerPadding = CommonProperties.GetPadding(container, Padding.Empty); } preferredSizeForAnchoring.Width -= containerPadding.Left; preferredSizeForAnchoring.Height -= containerPadding.Top; ClearCachedBounds(container); preferredSize = LayoutUtils.UnionSizes(preferredSizeForDocking, preferredSizeForAnchoring); } return(CommonProperties.GetAutoSize(container)); }
private static Size LayoutDockedControls(IArrangedElement container, bool measureOnly) { Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "\tDock Processing"); Debug.Assert(!HasCachedBounds(container), "Do not call this method with an active cached bounds list."); // If measuring, we start with an empty rectangle and add as needed. // If doing actual layout, we start with the container's rect and subtract as we layout. Rectangle remainingBounds = measureOnly ? Rectangle.Empty : container.DisplayRectangle; Size preferredSize = Size.Empty; IArrangedElement mdiClient = null; // Docking layout is order dependent. After much debate, we decided to use z-order as the // docking order. (Introducing a DockOrder property was a close second) ArrangedElementCollection children = container.Children; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = children[i]; Debug.Assert(element.Bounds == GetCachedBounds(element), "Why do we have cachedBounds for a docked element?"); if (CommonProperties.GetNeedsDockLayout(element)) { // Some controls modify their bounds when you call SetBoundsCore. We // therefore need to read the value of bounds back when adjusting our layout rectangle. switch (GetDock(element)) { case DockStyle.Top: { Size elementSize = GetVerticalDockedSize(element, remainingBounds.Size, measureOnly); Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height); TryCalculatePreferredSizeDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); // What we are really doing here: top += element.Bounds.Height; remainingBounds.Y += element.Bounds.Height; remainingBounds.Height -= element.Bounds.Height; break; } case DockStyle.Bottom: { Size elementSize = GetVerticalDockedSize(element, remainingBounds.Size, measureOnly); Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Bottom - elementSize.Height, elementSize.Width, elementSize.Height); TryCalculatePreferredSizeDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); // What we are really doing here: bottom -= element.Bounds.Height; remainingBounds.Height -= element.Bounds.Height; break; } case DockStyle.Left: { Size elementSize = GetHorizontalDockedSize(element, remainingBounds.Size, measureOnly); Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height); TryCalculatePreferredSizeDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); // What we are really doing here: left += element.Bounds.Width; remainingBounds.X += element.Bounds.Width; remainingBounds.Width -= element.Bounds.Width; break; } case DockStyle.Right: { Size elementSize = GetHorizontalDockedSize(element, remainingBounds.Size, measureOnly); Rectangle newElementBounds = new Rectangle(remainingBounds.Right - elementSize.Width, remainingBounds.Y, elementSize.Width, elementSize.Height); TryCalculatePreferredSizeDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); // What we are really doing here: right -= element.Bounds.Width; remainingBounds.Width -= element.Bounds.Width; break; } case DockStyle.Fill: if (element is MdiClient) { Debug.Assert(mdiClient is null, "How did we end up with multiple MdiClients?"); mdiClient = element; } else { Size elementSize = remainingBounds.Size; Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, elementSize.Width, elementSize.Height); TryCalculatePreferredSizeDockedControl(element, newElementBounds, measureOnly, ref preferredSize, ref remainingBounds); } break; default: Debug.Fail("Unsupported value for dock."); break; } } // Treat the MDI client specially, since it's supposed to blend in with the parent form if (mdiClient != null) { SetCachedBounds(mdiClient, remainingBounds); } } return(preferredSize); }
private static void Copy(ArrangedElementCollection sourceList, int sourceIndex, ArrangedElementCollection destinationList, int destinationIndex, int length) { if (sourceIndex < destinationIndex) { // We need to copy from the back forward to prevent overwrite if source and // destination lists are the same, so we need to flip the source/dest indices // to point at the end of the spans to be copied. sourceIndex = sourceIndex + length; destinationIndex = destinationIndex + length; for (; length > 0; length--) { destinationList.InnerList[--destinationIndex] = sourceList.InnerList[--sourceIndex]; } } else { for (; length > 0; length--) { destinationList.InnerList[destinationIndex++] = sourceList.InnerList[sourceIndex++]; } } }