public LayoutTransaction(Control controlToLayout, IArrangedElement controlCausingLayout, string property, bool resumeLayout) { CommonProperties.xClearPreferredSizeCache(controlCausingLayout); this._controlToLayout = controlToLayout; this._resumeLayout = resumeLayout; if (this._controlToLayout != null) { this._controlToLayout.SuspendLayout(); CommonProperties.xClearPreferredSizeCache(this._controlToLayout); if (resumeLayout) { this._controlToLayout.PerformLayout(new LayoutEventArgs(controlCausingLayout, property)); } } }
internal static void xClearAllPreferredSizeCaches(IArrangedElement start) { CommonProperties.xClearPreferredSizeCache(start); ArrangedElementCollection controlsCollection = start.Children; // This may have changed the sizes of our children. // PERFNOTE: This is more efficient than using Foreach. Foreach // forces the creation of an array subset enum each time we // enumerate for (int i = 0; i < controlsCollection.Count; i++) { xClearAllPreferredSizeCaches(controlsCollection[i]); } }
private static Size GetAnchorPreferredSize(IArrangedElement container) { Size empty = Size.Empty; for (int i = container.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 rectangle = LayoutUtils.InflateRect(GetCachedBounds(element), margin); if (IsAnchored(anchor, AnchorStyles.Left) && !IsAnchored(anchor, AnchorStyles.Right)) { empty.Width = Math.Max(empty.Width, rectangle.Right); } if (!IsAnchored(anchor, AnchorStyles.Bottom)) { empty.Height = Math.Max(empty.Height, rectangle.Bottom); } if (IsAnchored(anchor, AnchorStyles.Right)) { Rectangle rectangle2 = GetAnchorDestination(element, Rectangle.Empty, true); if (rectangle2.Width < 0) { empty.Width = Math.Max(empty.Width, rectangle.Right + rectangle2.Width); } else { empty.Width = Math.Max(empty.Width, rectangle2.Right); } } if (IsAnchored(anchor, AnchorStyles.Bottom)) { Rectangle rectangle3 = GetAnchorDestination(element, Rectangle.Empty, true); if (rectangle3.Height < 0) { empty.Height = Math.Max(empty.Height, rectangle.Bottom + rectangle3.Height); } else { empty.Height = Math.Max(empty.Height, rectangle3.Bottom); } } } } return(empty); }
internal static void UpdateSpecifiedBounds(IArrangedElement element, int x, int y, int width, int height, BoundsSpecified specified) { Rectangle originalBounds = CommonProperties.GetSpecifiedBounds(element); // PERF note: Bitwise operator usage intentional to optimize out branching. bool xChangedButNotSpecified = ((specified & BoundsSpecified.X) == BoundsSpecified.None) & x != originalBounds.X; bool yChangedButNotSpecified = ((specified & BoundsSpecified.Y) == BoundsSpecified.None) & y != originalBounds.Y; bool wChangedButNotSpecified = ((specified & BoundsSpecified.Width) == BoundsSpecified.None) & width != originalBounds.Width; bool hChangedButNotSpecified = ((specified & BoundsSpecified.Height) == BoundsSpecified.None) & height != originalBounds.Height; if (xChangedButNotSpecified | yChangedButNotSpecified | wChangedButNotSpecified | hChangedButNotSpecified) { // if any of them are changed and specified cache the new value. if (!xChangedButNotSpecified) { originalBounds.X = x; } if (!yChangedButNotSpecified) { originalBounds.Y = y; } if (!wChangedButNotSpecified) { originalBounds.Width = width; } if (!hChangedButNotSpecified) { originalBounds.Height = height; } element.Properties.SetRectangle(_specifiedBoundsProperty, originalBounds); } else { // SetBoundsCore is going to call this a lot with the same bounds. Avoid the set object // (which indirectly may causes an allocation) if we can. if (element.Properties.ContainsObject(_specifiedBoundsProperty)) { // use MaxRectangle instead of null so we can reuse the SizeWrapper in the property store. element.Properties.SetRectangle(_specifiedBoundsProperty, LayoutUtils.s_maxRectangle); } } }
private static void LayoutAutoSizedControls(IArrangedElement container) { ArrangedElementCollection children = container.Children; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = children[i]; if (CommonProperties.xGetAutoSizedAndAnchored(element)) { Rectangle bounds = GetCachedBounds(element); AnchorStyles anchor = GetAnchor(element); Size proposedConstraints = LayoutUtils.MaxSize; if ((anchor & (AnchorStyles.Left | AnchorStyles.Right)) == (AnchorStyles.Left | AnchorStyles.Right)) { proposedConstraints.Width = bounds.Width; } if ((anchor & (AnchorStyles.Top | AnchorStyles.Bottom)) == (AnchorStyles.Top | AnchorStyles.Bottom)) { proposedConstraints.Height = bounds.Height; } Size prefSize = element.GetPreferredSize(proposedConstraints); Rectangle newBounds = bounds; if (CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink) { // this is the case for simple things like radio button, checkbox, etc. newBounds = GetGrowthBounds(element, prefSize); } else { // we had whacked this check, but it turns out it causes undesirable // behavior in things like panel. a panel with no elements sizes to 0,0. if (bounds.Width < prefSize.Width || bounds.Height < prefSize.Height) { Size newSize = LayoutUtils.UnionSizes(bounds.Size, prefSize); newBounds = GetGrowthBounds(element, newSize); } } if (newBounds != bounds) { SetCachedBounds(element, newBounds); } } } }
public Size GetCachedPreferredSize(Size proposedConstraints, out bool isValid) { isValid = false; if (proposedConstraints.Height == 0 || proposedConstraints.Width == 0) { Size cachedSize = CommonProperties.xGetPreferredSizeCache(Container); if (!cachedSize.IsEmpty) { isValid = true; return(cachedSize); } } return(Size.Empty); }
private static void ApplyCachedBounds(IArrangedElement container) { if (CommonProperties.GetAutoSize(container)) { // Avoiding calling DisplayRectangle before checking AutoSize for Everett compat Rectangle displayRectangle = container.DisplayRectangle; if ((displayRectangle.Width == 0) || (displayRectangle.Height == 0)) { ClearCachedBounds(container); return; } } IDictionary dictionary = (IDictionary)container.Properties.GetObject(s_cachedBoundsProperty); if (dictionary != null) { #if DEBUG // In debug builds, we need to modify the collection, so we add a break and an // outer loop to prevent attempting to IEnumerator.MoveNext() on a modified // collection. while (dictionary.Count > 0) { #endif foreach (DictionaryEntry entry in dictionary) { IArrangedElement element = (IArrangedElement)entry.Key; Debug.Assert(element.Container == container, "We have non-children in our containers cached bounds store."); #if DEBUG // We are about to set the bounds to the cached value. We clear the cached value // before SetBounds because some controls fiddle with the bounds on SetBounds // and will callback InitLayout with a different bounds and BoundsSpecified. dictionary.Remove(entry.Key); #endif Rectangle bounds = (Rectangle)entry.Value; element.SetBounds(bounds, BoundsSpecified.None); #if DEBUG break; } #endif } ClearCachedBounds(container); } }
private static void LayoutAnchoredControls(IArrangedElement container) { Rectangle displayRectangle = container.DisplayRectangle; if (!CommonProperties.GetAutoSize(container) || ((displayRectangle.Width != 0) && (displayRectangle.Height != 0))) { ArrangedElementCollection children = container.Children; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = children[i]; if (CommonProperties.GetNeedsAnchorLayout(element)) { SetCachedBounds(element, GetAnchorDestination(element, displayRectangle, false)); } } } }
private static Size xGetDockedSize(IArrangedElement element, Size remainingSize, Size constraints, bool measureOnly) { Size desiredSize; if (CommonProperties.GetAutoSize(element)) { // Ask control for its desired size using the provided constraints. // (e.g., a control docked to top will constrain width to remaining width // and minimize height.) desiredSize = element.GetPreferredSize(constraints); } else { desiredSize = element.Bounds.Size; } Debug.Assert((desiredSize.Width >= 0 && desiredSize.Height >= 0), "Error detected in xGetDockSize: Element size was negative."); return(desiredSize); }
public static void SetAnchor(IArrangedElement element, AnchorStyles value) { AnchorStyles oldValue = GetAnchor(element); if (oldValue != value) { if (CommonProperties.GetNeedsDockLayout(element)) { // We set dock back to none to cause the element to size back to its original bounds. SetDock(element, DockStyle.None); } CommonProperties.xSetAnchor(element, value); // Updating AnchorInfo is only needed when control is ready for layout. Oneway to check this precondition is to // check if the control is parented. This helps avoid calculating AnchorInfo with default initial values of the Control. // AnchorInfo is recalculated everytime there is a layout change. if (CommonProperties.GetNeedsAnchorLayout(element) && element is Control control && control.Parent is not null) { UpdateAnchorInfo(element); } else { SetAnchorInfo(element, null); } if (element.Container is not null) { bool rightReleased = IsAnchored(oldValue, AnchorStyles.Right) && !IsAnchored(value, AnchorStyles.Right); bool bottomReleased = IsAnchored(oldValue, AnchorStyles.Bottom) && !IsAnchored(value, AnchorStyles.Bottom); if (element.Container.Container is not null && (rightReleased || bottomReleased)) { // If the right or bottom anchor is being released, we have a special case where the element's // margin may affect preferredSize where it didn't previously. Rather than do an expensive // check for this in OnLayout, we just detect the case her and force a relayout. LayoutTransaction.DoLayout(element.Container.Container, element, PropertyNames.Anchor); } LayoutTransaction.DoLayout(element.Container, element, PropertyNames.Anchor); } }
// Entry point from LayoutEngine internal override bool LayoutCore(IArrangedElement container, LayoutEventArgs args) { #if DEBUG if (CompModSwitches.FlowLayout.TraceInfo) { Debug.WriteLine("FlowLayout::Layout(" + "container=" + container.ToString() + ", " + "displayRect=" + container.DisplayRectangle.ToString() + ", " + "args=" + args.ToString() + ")"); } Debug.Indent(); #endif // ScrollableControl will first try to get the layoutbounds from the derived control when // trying to figure out if ScrollBars should be added. CommonProperties.SetLayoutBounds(container, xLayout(container, container.DisplayRectangle, /* measureOnly = */ false)); #if DEBUG Debug.Unindent(); #endif return(CommonProperties.GetAutoSize(container)); }
public LayoutTransaction(Control controlToLayout, IArrangedElement controlCausingLayout, string property, bool resumeLayout) { CommonProperties.xClearPreferredSizeCache(controlCausingLayout); _controlToLayout = controlToLayout; _resumeLayout = resumeLayout; if (_controlToLayout != null) { #if DEBUG _layoutSuspendCount = _controlToLayout.LayoutSuspendCount; #endif _controlToLayout.SuspendLayout(); CommonProperties.xClearPreferredSizeCache(_controlToLayout); // Same effect as calling performLayout on Dispose but then we would have to keep // controlCausingLayout and property around as state. if (resumeLayout) { _controlToLayout.PerformLayout(new LayoutEventArgs(controlCausingLayout, property)); } } }
private static void LayoutAutoSizedControls(IArrangedElement container) { ArrangedElementCollection children = container.Children; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = children[i]; if (CommonProperties.xGetAutoSizedAndAnchored(element)) { Rectangle cachedBounds = GetCachedBounds(element); AnchorStyles anchor = GetAnchor(element); Size preferredSize = element.DisplayRectangle.Size; //Size maxSize = cachedBounds.Size; if ((anchor & (AnchorStyles.Right | AnchorStyles.Left)) == (AnchorStyles.Right | AnchorStyles.Left)) { preferredSize.Width = cachedBounds.Width; } if ((anchor & (AnchorStyles.Bottom | AnchorStyles.Top)) == (AnchorStyles.Bottom | AnchorStyles.Top)) { preferredSize.Height = cachedBounds.Height; } Rectangle bounds = cachedBounds; if (CommonProperties.GetAutoSizeMode(element) == AutoSizeMode.GrowAndShrink) { bounds = GetGrowthBounds(element, preferredSize); } else if ((cachedBounds.Width < preferredSize.Width) || (cachedBounds.Height < preferredSize.Height)) { Size newSize = LayoutUtils.UnionSizes(cachedBounds.Size, preferredSize); bounds = GetGrowthBounds(element, newSize); } if (bounds != cachedBounds) { SetCachedBounds(element, bounds); } } } }
public static void SetAnchor(IArrangedElement container, IArrangedElement element, AnchorStyles value) { AnchorStyles oldValue = GetAnchor(element); if (oldValue != value) { if (CommonProperties.GetNeedsDockLayout(element)) { // We set dock back to none to cause the element to size back to its original bounds. SetDock(element, DockStyle.None); } CommonProperties.xSetAnchor(element, value); if (CommonProperties.GetNeedsAnchorLayout(element)) { UpdateAnchorInfo(element); } else { SetAnchorInfo(element, null); } if (element.Container != null) { bool rightReleased = IsAnchored(oldValue, AnchorStyles.Right) && !IsAnchored(value, AnchorStyles.Right); bool bottomReleased = IsAnchored(oldValue, AnchorStyles.Bottom) && !IsAnchored(value, AnchorStyles.Bottom); if (element.Container.Container != null && (rightReleased || bottomReleased)) { // If the right or bottom anchor is being released, we have a special case where the element's // margin may affect preferredSize where it didn't previously. Rather than do an expensive // check for this in OnLayout, we just detect the case her and force a relayout. LayoutTransaction.DoLayout(element.Container.Container, element, PropertyNames.Anchor); } LayoutTransaction.DoLayout(element.Container, element, PropertyNames.Anchor); } } }
private static void ApplyCachedBounds(IArrangedElement container) { if (CommonProperties.GetAutoSize(container)) { Rectangle displayRectangle = container.DisplayRectangle; if ((displayRectangle.Width == 0) || (displayRectangle.Height == 0)) { ClearCachedBounds(container); return; } } IDictionary dictionary = (IDictionary)container.Properties.GetObject(_cachedBoundsProperty); if (dictionary != null) { // Blazor supports keys properly #if BLAZOR foreach (DictionaryEntry entry in dictionary) { IArrangedElement key = (IArrangedElement)entry.Key; Rectangle bounds = (Rectangle)entry.Value; key.SetBounds(bounds, BoundsSpecified.None); } #elif BRIDGE foreach (dynamic entry in dictionary) { IArrangedElement key = (IArrangedElement)entry.key; Rectangle bounds = (Rectangle)entry.value; if (key != null) { key.SetBounds(bounds, BoundsSpecified.None); } } #endif ClearCachedBounds(container); } }
public static void SetDock(IArrangedElement element, DockStyle value) { Debug.Assert(!HasCachedBounds(element.Container), "Do not call this method with an active cached bounds list."); if (GetDock(element) != value) { if (!ClientUtils.IsEnumValid(value, (int)value, (int)DockStyle.None, (int)DockStyle.Fill)) { throw new InvalidEnumArgumentException(nameof(value), (int)value, typeof(DockStyle)); } bool dockNeedsLayout = CommonProperties.GetNeedsDockLayout(element); CommonProperties.xSetDock(element, value); using (new LayoutTransaction(element.Container as Control, element, PropertyNames.Dock)) { // if the item is autosized, calling setbounds performs a layout, which // if we havent set the anchor info properly yet makes dock/anchor layout cranky. if (value == DockStyle.None) { if (dockNeedsLayout) { // We are transitioning from docked to not docked, restore the original bounds. element.SetBounds(CommonProperties.GetSpecifiedBounds(element), BoundsSpecified.None); // Restore Anchor information as its now relevant again. UpdateAnchorInfo(element); } } else { // Now setup the new bounds. element.SetBounds(CommonProperties.GetSpecifiedBounds(element), BoundsSpecified.All); } } } Debug.Assert(GetDock(element) == value, "Error setting Dock value."); }
private static void ApplyCachedBounds(IArrangedElement container) { if (CommonProperties.GetAutoSize(container)) { Rectangle displayRectangle = container.DisplayRectangle; if ((displayRectangle.Width == 0) || (displayRectangle.Height == 0)) { ClearCachedBounds(container); return; } } IDict dictionary = (IDict)container.Properties.GetObject(_cachedBoundsProperty); if (dictionary != null) { foreach (dynamic entry in dictionary) { IArrangedElement key = (IArrangedElement)entry.Key; Rectangle bounds = (Rectangle)entry.Value; key.SetBounds(bounds, BoundsSpecified.None); } ClearCachedBounds(container); } }
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); }
internal override bool LayoutCore(IArrangedElement container, LayoutEventArgs args) { CommonProperties.SetLayoutBounds(container, this.xLayout(container, container.DisplayRectangle, false)); return(CommonProperties.GetAutoSize(container)); }
public static DockStyle GetDock(IArrangedElement element) => CommonProperties.xGetDock(element);
public static AnchorStyles GetAnchor(IArrangedElement element) => CommonProperties.xGetAnchor(element);
private static void UpdateAnchorInfo(IArrangedElement element) { Debug.Assert(!HasCachedBounds(element.Container), "Do not call this method with an active cached bounds list."); AnchorInfo anchorInfo = GetAnchorInfo(element); if (anchorInfo is null) { anchorInfo = new AnchorInfo(); SetAnchorInfo(element, anchorInfo); } Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Update anchor info"); Debug.Indent(); Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, element.Container is null ? "No parent" : "Parent"); if (CommonProperties.GetNeedsAnchorLayout(element) && element.Container != null) { Rectangle bounds = GetCachedBounds(element); AnchorInfo oldAnchorInfo = new AnchorInfo { Left = anchorInfo.Left, Top = anchorInfo.Top, Right = anchorInfo.Right, Bottom = anchorInfo.Bottom }; anchorInfo.Left = element.Bounds.Left; anchorInfo.Top = element.Bounds.Top; anchorInfo.Right = element.Bounds.Right; anchorInfo.Bottom = element.Bounds.Bottom; Rectangle parentDisplayRect = element.Container.DisplayRectangle; Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "Parent displayRectangle" + parentDisplayRect); int parentWidth = parentDisplayRect.Width; int parentHeight = parentDisplayRect.Height; // The anchor is relative to the parent DisplayRectangle, so offset the anchor // by the DisplayRect origin anchorInfo.Left -= parentDisplayRect.X; anchorInfo.Top -= parentDisplayRect.Y; anchorInfo.Right -= parentDisplayRect.X; anchorInfo.Bottom -= parentDisplayRect.Y; AnchorStyles anchor = GetAnchor(element); if (IsAnchored(anchor, AnchorStyles.Right)) { if (DpiHelper.IsScalingRequirementMet && (anchorInfo.Right - parentWidth > 0) && (oldAnchorInfo.Right < 0)) { // parent was resized to fit its parent, or screen, we need to reuse old anchor info to prevent losing control beyond right edge anchorInfo.Right = oldAnchorInfo.Right; // control might have been resized, update Left anchor anchorInfo.Left = oldAnchorInfo.Right - bounds.Width; } else { anchorInfo.Right -= parentWidth; if (!IsAnchored(anchor, AnchorStyles.Left)) { anchorInfo.Left -= parentWidth; } } } else if (!IsAnchored(anchor, AnchorStyles.Left)) { anchorInfo.Right -= (parentWidth / 2); anchorInfo.Left -= (parentWidth / 2); } if (IsAnchored(anchor, AnchorStyles.Bottom)) { if (DpiHelper.IsScalingRequirementMet && (anchorInfo.Bottom - parentHeight > 0) && (oldAnchorInfo.Bottom < 0)) { // parent was resized to fit its parent, or screen, we need to reuse old anchor info to prevent losing control beyond bottom edge anchorInfo.Bottom = oldAnchorInfo.Bottom; // control might have been resized, update Top anchor anchorInfo.Top = oldAnchorInfo.Bottom - bounds.Height; } else { anchorInfo.Bottom -= parentHeight; if (!IsAnchored(anchor, AnchorStyles.Top)) { anchorInfo.Top -= parentHeight; } } } else if (!IsAnchored(anchor, AnchorStyles.Top)) { anchorInfo.Bottom -= (parentHeight / 2); anchorInfo.Top -= (parentHeight / 2); } Debug.WriteLineIf(CompModSwitches.RichLayout.TraceInfo, "anchor info (l,t,r,b): (" + anchorInfo.Left + ", " + anchorInfo.Top + ", " + anchorInfo.Right + ", " + anchorInfo.Bottom + ")"); } Debug.Unindent(); }
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)); }
public static DockStyle GetDock(IArrangedElement element) { return(CommonProperties.xGetDock(element)); }
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); }
public static AnchorStyles GetAnchor(IArrangedElement element) { return(CommonProperties.xGetAnchor(element)); }
// LayoutRow and MeasureRow both forward to this method. The measureOnly flag determines which behavior we get. private Size xLayoutRow(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(Int32.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 xLayoutRow). 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 static bool xLayout(IArrangedElement container, bool measureOnly, out Size preferredSize) { ArrangedElementCollection children = container.Children; preferredSize = new Size(-7103, -7105); if (measureOnly || (children.Count != 0)) { bool flag = false; bool flag2 = false; bool flag3 = false; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element = children[i]; if (CommonProperties.GetNeedsDockAndAnchorLayout(element)) { if (!flag && CommonProperties.GetNeedsDockLayout(element)) { flag = true; } if (!flag2 && CommonProperties.GetNeedsAnchorLayout(element)) { flag2 = true; } if (!flag3 && CommonProperties.xGetAutoSizedAndAnchored(element)) { flag3 = true; } } } Size empty = Size.Empty; Size b = Size.Empty; if (flag) { empty = LayoutDockedControls(container, measureOnly); } if (flag2 && !measureOnly) { LayoutAnchoredControls(container); } if (flag3) { LayoutAutoSizedControls(container); } if (!measureOnly) { ApplyCachedBounds(container); } else { b = GetAnchorPreferredSize(container); Padding padding = Padding.Empty; Control control = container as Control; if (control != null) { padding = control.Padding; } else { padding = CommonProperties.GetPadding(container, Padding.Empty); } b.Width -= padding.Left; b.Height -= padding.Top; ClearCachedBounds(container); preferredSize = LayoutUtils.UnionSizes(empty, b); } } return(CommonProperties.GetAutoSize(container)); }
private static void UpdateAnchorInfo(IArrangedElement element) { AnchorInfo anchorInfo = GetAnchorInfo(element); if (anchorInfo == null) { anchorInfo = new AnchorInfo(); SetAnchorInfo(element, anchorInfo); } if (CommonProperties.GetNeedsAnchorLayout(element) && (element.Container != null)) { Rectangle cachedBounds = GetCachedBounds(element); AnchorInfo info2 = new AnchorInfo { Left = anchorInfo.Left, Top = anchorInfo.Top, Right = anchorInfo.Right, Bottom = anchorInfo.Bottom }; anchorInfo.Left = element.Bounds.Left; anchorInfo.Top = element.Bounds.Top; anchorInfo.Right = element.Bounds.Right; anchorInfo.Bottom = element.Bounds.Bottom; Rectangle displayRectangle = element.Container.DisplayRectangle; int width = displayRectangle.Width; int height = displayRectangle.Height; anchorInfo.Left -= displayRectangle.X; anchorInfo.Top -= displayRectangle.Y; anchorInfo.Right -= displayRectangle.X; anchorInfo.Bottom -= displayRectangle.Y; AnchorStyles anchor = GetAnchor(element); if (IsAnchored(anchor, AnchorStyles.Right)) { if ((System.Windows.Forms.DpiHelper.EnableAnchorLayoutHighDpiImprovements && ((anchorInfo.Right - width) > 0)) && (info2.Right < 0)) { anchorInfo.Right = info2.Right; anchorInfo.Left = info2.Right - cachedBounds.Width; } else { anchorInfo.Right -= width; if (!IsAnchored(anchor, AnchorStyles.Left)) { anchorInfo.Left -= width; } } } else if (!IsAnchored(anchor, AnchorStyles.Left)) { anchorInfo.Right -= width / 2; anchorInfo.Left -= width / 2; } if (IsAnchored(anchor, AnchorStyles.Bottom)) { if ((System.Windows.Forms.DpiHelper.EnableAnchorLayoutHighDpiImprovements && ((anchorInfo.Bottom - height) > 0)) && (info2.Bottom < 0)) { anchorInfo.Bottom = info2.Bottom; anchorInfo.Top = info2.Bottom - cachedBounds.Height; } else { anchorInfo.Bottom -= height; if (!IsAnchored(anchor, AnchorStyles.Top)) { anchorInfo.Top -= height; } } } else if (!IsAnchored(anchor, AnchorStyles.Top)) { anchorInfo.Bottom -= height / 2; anchorInfo.Top -= height / 2; } } }
private static Size LayoutDockedControls(IArrangedElement container, bool measureOnly) { Rectangle remainingBounds = measureOnly ? Rectangle.Empty : container.DisplayRectangle; Size empty = Size.Empty; IArrangedElement element = null; ArrangedElementCollection children = container.Children; for (int i = children.Count - 1; i >= 0; i--) { IArrangedElement element2 = children[i]; if (CommonProperties.GetNeedsDockLayout(element2)) { switch (GetDock(element2)) { case DockStyle.Top: { Size size2 = GetVerticalDockedSize(element2, remainingBounds.Size, measureOnly); Rectangle rectangle2 = new Rectangle(remainingBounds.X, remainingBounds.Y, size2.Width, size2.Height); xLayoutDockedControl(element2, rectangle2, measureOnly, ref empty, ref remainingBounds); remainingBounds.Y += element2.Bounds.Height; remainingBounds.Height -= element2.Bounds.Height; break; } case DockStyle.Bottom: { Size size3 = GetVerticalDockedSize(element2, remainingBounds.Size, measureOnly); Rectangle rectangle4 = new Rectangle(remainingBounds.X, remainingBounds.Bottom - size3.Height, size3.Width, size3.Height); xLayoutDockedControl(element2, rectangle4, measureOnly, ref empty, ref remainingBounds); remainingBounds.Height -= element2.Bounds.Height; break; } case DockStyle.Left: { Size size4 = GetHorizontalDockedSize(element2, remainingBounds.Size, measureOnly); Rectangle rectangle5 = new Rectangle(remainingBounds.X, remainingBounds.Y, size4.Width, size4.Height); xLayoutDockedControl(element2, rectangle5, measureOnly, ref empty, ref remainingBounds); remainingBounds.X += element2.Bounds.Width; remainingBounds.Width -= element2.Bounds.Width; break; } case DockStyle.Right: { Size size5 = GetHorizontalDockedSize(element2, remainingBounds.Size, measureOnly); Rectangle rectangle6 = new Rectangle(remainingBounds.Right - size5.Width, remainingBounds.Y, size5.Width, size5.Height); xLayoutDockedControl(element2, rectangle6, measureOnly, ref empty, ref remainingBounds); remainingBounds.Width -= element2.Bounds.Width; break; } case DockStyle.Fill: //if (!(element2 is MdiClient)) //{ // goto Label_025B; //} element = element2; break; } } goto Label_0295; // MDI SUPPORT.... Not Sure... #TODO - MDIClient# // Label_025B: //size6 = remainingBounds.Size; //Rectangle newElementBounds = new Rectangle(remainingBounds.X, remainingBounds.Y, size6.Width, size6.Height); //xLayoutDockedControl(element2, newElementBounds, measureOnly, ref empty, ref remainingBounds); Label_0295: if (element != null) { SetCachedBounds(element, remainingBounds); } } return(empty); }