namespace EasyLayoutNS { using System; using System.Collections.Generic; using System.ComponentModel; using UIWidgets; using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; using UnityEngine.UI; /// /// EasyLayout. /// Warning: using RectTransform relative size with positive size delta (like 100% + 10) with ContentSizeFitter can lead to infinite increased size. /// [ExecuteInEditMode] [RequireComponent(typeof(RectTransform))] [AddComponentMenu("UI/New UI Widgets/Layout/EasyLayout")] public class EasyLayout : LayoutGroup, IObservable, INotifyPropertyChanged { readonly List elements = new List(); readonly Stack elementsCache = new Stack(); /// /// Occurs when a property value changes. /// public event OnChange OnChange; /// /// Occurs when a property value changes. /// public event PropertyChangedEventHandler PropertyChanged; /// /// Occurs when a properties values changed except PaddingInner property. /// [SerializeField] public UnityEvent SettingsChanged = new UnityEvent(); [SerializeField] [FormerlySerializedAs("GroupPosition")] Anchors groupPosition = Anchors.UpperLeft; /// /// The group position. /// public Anchors GroupPosition { get { return groupPosition; } set { if (groupPosition != value) { groupPosition = value; NotifyPropertyChanged("GroupPosition"); } } } [SerializeField] [FormerlySerializedAs("Stacking")] Axis mainAxis = Axis.Horizontal; /// /// The stacking type. /// [Obsolete("Replaced with MainAxis.")] public Stackings Stacking { get { if (MainAxis == Axis.Horizontal) { return Stackings.Horizontal; } return Stackings.Vertical; } set { MainAxis = (value == Stackings.Horizontal) ? Axis.Horizontal : Axis.Vertical; } } /// /// Main axis. /// public Axis MainAxis { get { return mainAxis; } set { if (mainAxis != value) { mainAxis = value; NotifyPropertyChanged("Axis"); } } } [SerializeField] [FormerlySerializedAs("LayoutType")] LayoutTypes layoutType = LayoutTypes.Compact; /// /// The type of the layout. /// public LayoutTypes LayoutType { get { return layoutType; } set { if (layoutType != value) { LayoutGroup = null; layoutType = value; NotifyPropertyChanged("LayoutType"); } } } EasyLayoutBaseType layoutGroup; /// /// Layout group. /// protected EasyLayoutBaseType LayoutGroup { get { if (layoutGroup == null) { layoutGroup = GetLayoutGroup(); layoutGroup.OnElementChanged += ElementChanged; } return layoutGroup; } set { if (layoutGroup != null) { layoutGroup.OnElementChanged -= ElementChanged; } layoutGroup = value; if (layoutGroup != null) { layoutGroup.OnElementChanged += ElementChanged; } } } [SerializeField] [FormerlySerializedAs("CompactConstraint")] CompactConstraints compactConstraint = CompactConstraints.Flexible; /// /// Which constraint to use for the Grid layout. /// public CompactConstraints CompactConstraint { get { return compactConstraint; } set { if (compactConstraint != value) { compactConstraint = value; NotifyPropertyChanged("CompactConstraint"); } } } [SerializeField] [FormerlySerializedAs("CompactConstraintCount")] int compactConstraintCount = 1; /// /// How many elements there should be along the constrained axis. /// public int CompactConstraintCount { get { return Mathf.Max(1, compactConstraintCount); } set { if (compactConstraintCount != value) { compactConstraintCount = value; NotifyPropertyChanged("CompactConstraintCount"); } } } [SerializeField] [FormerlySerializedAs("GridConstraint")] GridConstraints gridConstraint = GridConstraints.Flexible; /// /// Which constraint to use for the Grid layout. /// public GridConstraints GridConstraint { get { return gridConstraint; } set { if (gridConstraint != value) { gridConstraint = value; NotifyPropertyChanged("GridConstraint"); } } } [SerializeField] [FormerlySerializedAs("GridConstraintCount")] int gridConstraintCount = 1; /// /// How many cells there should be along the constrained axis. /// public int GridConstraintCount { get { return Mathf.Max(1, gridConstraintCount); } set { if (gridConstraintCount != value) { gridConstraintCount = value; NotifyPropertyChanged("GridConstraintCount"); } } } /// /// Constraint count. /// public int ConstraintCount { get { if (LayoutType == LayoutTypes.Compact) { return CompactConstraintCount; } else { return GridConstraintCount; } } } [SerializeField] [FormerlySerializedAs("RowAlign")] HorizontalAligns rowAlign = HorizontalAligns.Left; /// /// The row align. /// public HorizontalAligns RowAlign { get { return rowAlign; } set { if (rowAlign != value) { rowAlign = value; NotifyPropertyChanged("RowAlign"); } } } [SerializeField] [FormerlySerializedAs("InnerAlign")] InnerAligns innerAlign = InnerAligns.Top; /// /// The inner align. /// public InnerAligns InnerAlign { get { return innerAlign; } set { if (innerAlign != value) { innerAlign = value; NotifyPropertyChanged("InnerAlign"); } } } [SerializeField] [FormerlySerializedAs("CellAlign")] Anchors cellAlign = Anchors.UpperLeft; /// /// The cell align. /// public Anchors CellAlign { get { return cellAlign; } set { if (cellAlign != value) { cellAlign = value; NotifyPropertyChanged("CellAlign"); } } } [SerializeField] [FormerlySerializedAs("Spacing")] Vector2 spacing = new Vector2(5, 5); /// /// The spacing. /// public Vector2 Spacing { get { return spacing; } set { if (spacing != value) { spacing = value; NotifyPropertyChanged("Spacing"); } } } [SerializeField] [FormerlySerializedAs("Symmetric")] bool symmetric = true; /// /// Symmetric margin. /// public bool Symmetric { get { return symmetric; } set { if (symmetric != value) { symmetric = value; NotifyPropertyChanged("Symmetric"); } } } [SerializeField] [FormerlySerializedAs("Margin")] Vector2 margin = new Vector2(5, 5); /// /// The margin. /// public Vector2 Margin { get { return margin; } set { if (margin != value) { margin = value; NotifyPropertyChanged("Margin"); } } } [SerializeField] [HideInInspector] Padding marginInner; /// /// The margin. /// Should be used by ListView related scripts. /// public Padding MarginInner { get { return marginInner; } set { if (marginInner != value) { marginInner = value; NotifyPropertyChanged("MarginInner"); } } } [SerializeField] [FormerlySerializedAs("PaddingInner")] [HideInInspector] Padding paddingInner; /// /// The padding. /// Should be used by ListView related scripts. /// public Padding PaddingInner { get { return paddingInner; } set { if (paddingInner != value) { paddingInner = value; NotifyPropertyChanged("PaddingInner", false); } } } [SerializeField] [FormerlySerializedAs("MarginTop")] float marginTop = 5f; /// /// The margin top. /// public float MarginTop { get { return marginTop; } set { if (marginTop != value) { marginTop = value; NotifyPropertyChanged("MarginTop"); } } } [SerializeField] [FormerlySerializedAs("MarginBottom")] float marginBottom = 5f; /// /// The margin bottom. /// public float MarginBottom { get { return marginBottom; } set { if (marginBottom != value) { marginBottom = value; NotifyPropertyChanged("MarginBottom"); } } } [SerializeField] [FormerlySerializedAs("MarginLeft")] float marginLeft = 5f; /// /// The margin left. /// public float MarginLeft { get { return marginLeft; } set { if (marginLeft != value) { marginLeft = value; NotifyPropertyChanged("MarginLeft"); } } } [SerializeField] [FormerlySerializedAs("MarginRight")] float marginRight = 5f; /// /// The margin right. /// public float MarginRight { get { return marginRight; } set { if (marginRight != value) { marginRight = value; NotifyPropertyChanged("MarginRight"); } } } [SerializeField] [FormerlySerializedAs("RightToLeft")] bool rightToLeft = false; /// /// The right to left stacking. /// public bool RightToLeft { get { return rightToLeft; } set { if (rightToLeft != value) { rightToLeft = value; NotifyPropertyChanged("RightToLeft"); } } } [SerializeField] [FormerlySerializedAs("TopToBottom")] bool topToBottom = true; /// /// The top to bottom stacking. /// public bool TopToBottom { get { return topToBottom; } set { if (topToBottom != value) { topToBottom = value; NotifyPropertyChanged("TopToBottom"); } } } [SerializeField] [FormerlySerializedAs("SkipInactive")] bool skipInactive = true; /// /// The skip inactive. /// public bool SkipInactive { get { return skipInactive; } set { if (skipInactive != value) { skipInactive = value; NotifyPropertyChanged("SkipInactive"); } } } [SerializeField] bool resetRotation; /// /// Reset rotation for the controlled elements. /// public bool ResetRotation { get { return resetRotation; } set { if (resetRotation != value) { resetRotation = value; NotifyPropertyChanged("ResetRotation"); } } } /// /// The filter. /// [Obsolete("Replaced with ShouldIgnore")] public Func, IEnumerable> Filter { get { throw new NotSupportedException("Obsolete."); } set { throw new NotSupportedException("Obsolete."); } } Func shouldIgnore; /// /// The filter. /// public Func ShouldIgnore { get { return shouldIgnore; } set { if (shouldIgnore != value) { shouldIgnore = value; NotifyPropertyChanged("ShouldIgnore"); } } } [SerializeField] [FormerlySerializedAs("ChildrenWidth")] ChildrenSize childrenWidth; /// /// How to control width of the children. /// public ChildrenSize ChildrenWidth { get { return childrenWidth; } set { if (childrenWidth != value) { childrenWidth = value; NotifyPropertyChanged("ChildrenWidth"); } } } [SerializeField] [FormerlySerializedAs("ChildrenHeight")] ChildrenSize childrenHeight; /// /// How to control height of the children. /// public ChildrenSize ChildrenHeight { get { return childrenHeight; } set { if (childrenHeight != value) { childrenHeight = value; NotifyPropertyChanged("ChildrenHeight"); } } } [SerializeField] EasyLayoutFlexSettings flexSettings = new EasyLayoutFlexSettings(); /// /// Settings for the Flex layout type. /// public EasyLayoutFlexSettings FlexSettings { get { return flexSettings; } set { if (flexSettings != value) { flexSettings.OnChange -= FlexSettingsChanged; flexSettings = value; flexSettings.OnChange += FlexSettingsChanged; NotifyPropertyChanged("FlexSettings"); } } } [SerializeField] EasyLayoutStaggeredSettings staggeredSettings = new EasyLayoutStaggeredSettings(); /// /// Settings for the Staggered layout type. /// public EasyLayoutStaggeredSettings StaggeredSettings { get { return staggeredSettings; } set { if (staggeredSettings != value) { staggeredSettings.OnChange -= StaggeredSettingsChanged; staggeredSettings = value; staggeredSettings.OnChange += StaggeredSettingsChanged; NotifyPropertyChanged("StaggeredSettings"); } } } [SerializeField] EasyLayoutEllipseSettings ellipseSettings = new EasyLayoutEllipseSettings(); /// /// Settings for the Ellipse layout type. /// public EasyLayoutEllipseSettings EllipseSettings { get { return ellipseSettings; } set { if (ellipseSettings != value) { ellipseSettings.OnChange -= EllipseSettingsChanged; ellipseSettings = value; ellipseSettings.OnChange += EllipseSettingsChanged; NotifyPropertyChanged("EllipseSettings"); } } } /// /// Control width of children. /// [SerializeField] [HideInInspector] [Obsolete("Use ChildrenWidth with ChildrenSize.SetPreferred instead.")] public bool ControlWidth; /// /// Control height of children. /// [SerializeField] [HideInInspector] [Obsolete("Use ChildrenHeight with ChildrenSize.SetPreferred instead.")] [FormerlySerializedAs("ControlHeight")] public bool ControlHeight; /// /// Sets width of the children to maximum width from them. /// [SerializeField] [HideInInspector] [Obsolete("Use ChildrenWidth with ChildrenSize.SetMaxFromPreferred instead.")] [FormerlySerializedAs("MaxWidth")] public bool MaxWidth; /// /// Sets height of the children to maximum height from them. /// [SerializeField] [HideInInspector] [Obsolete("Use ChildrenHeight with ChildrenSize.SetMaxFromPreferred instead.")] [FormerlySerializedAs("MaxHeight")] public bool MaxHeight; /// /// Internal size. /// public Vector2 InternalSize { get { var size = rectTransform.rect.size; var padding = PaddingInner; size.x -= MarginFullHorizontal + padding.Horizontal; size.y -= MarginFullVertical + padding.Vertical; return size; } } /// /// Current sizes info. /// public GroupSize CurrentSize { get; protected set; } /// /// Gets or sets the size of the inner block. /// /// The size of the inner block. public Vector2 BlockSize { get; protected set; } /// /// Gets or sets the UI size. /// /// The UI size. public Vector2 UISize { get; protected set; } /// /// Size in elements. /// public Vector2 Size { get; protected set; } /// /// Gets the minimum width. /// /// The minimum width. public override float minWidth { get { return (ChildrenWidth == ChildrenSize.DoNothing) ? CurrentSize.Width : CurrentSize.MinWidth; } } /// /// Gets the minimum height. /// /// The minimum height. public override float minHeight { get { return (ChildrenHeight == ChildrenSize.DoNothing) ? CurrentSize.Height : CurrentSize.MinHeight; } } /// /// Gets the preferred width. /// /// The preferred width. public override float preferredWidth { get { return (ChildrenWidth == ChildrenSize.DoNothing) ? CurrentSize.Width : CurrentSize.PreferredWidth; } } /// /// Gets the preferred height. /// /// The preferred height. public override float preferredHeight { get { return (ChildrenHeight == ChildrenSize.DoNothing) ? CurrentSize.Height : CurrentSize.PreferredHeight; } } /// /// Summary horizontal margin. /// public float MarginHorizontal { get { return Symmetric ? (Margin.x + Margin.x) : (MarginLeft + MarginRight); } } /// /// Summary vertical margin. /// public float MarginVertical { get { return Symmetric ? (Margin.y + Margin.y) : (MarginTop + MarginBottom); } } /// /// Summary horizontal margin with MarginInner. /// public float MarginFullHorizontal { get { var margin_external = Symmetric ? (Margin.x + Margin.x) : (MarginLeft + MarginRight); return margin_external + MarginInner.Horizontal; } } /// /// Summary vertical margin with MarginInner. /// public float MarginFullVertical { get { var margin_external = Symmetric ? (Margin.y + Margin.y) : (MarginTop + MarginBottom); return margin_external + MarginInner.Vertical; } } /// /// Is horizontal stacking? /// public bool IsHorizontal { get { return MainAxis == Axis.Horizontal; } } /// /// Size of the main axis. /// public float MainAxisSize { get { return IsHorizontal ? rectTransform.rect.width - MarginFullHorizontal : rectTransform.rect.height - MarginFullVertical; } } /// /// Size of the sub axis. /// public float SubAxisSize { get { return !IsHorizontal ? rectTransform.rect.width - MarginFullHorizontal : rectTransform.rect.height - MarginFullVertical; } } /// /// Properties tracker. /// protected DrivenRectTransformTracker PropertiesTracker; /// /// Children list. /// Used if SkipInactive disabled. /// protected List Children = new List(); /// /// Property changed. /// /// Property name. /// Should invoke SettingsChanged event? protected void NotifyPropertyChanged(string propertyName, bool invokeSettingsChanged = true) { SetDirty(); var c_handlers = OnChange; if (c_handlers != null) { c_handlers(); } var handlers = PropertyChanged; if (handlers != null) { handlers(this, new PropertyChangedEventArgs(propertyName)); } if (invokeSettingsChanged) { SettingsChanged.Invoke(); } } void FlexSettingsChanged() { NotifyPropertyChanged("FlexSettings"); } void StaggeredSettingsChanged() { NotifyPropertyChanged("StaggeredSettings"); } void EllipseSettingsChanged() { NotifyPropertyChanged("EllipseSettings"); } /// /// Start this instance. /// protected override void Start() { flexSettings.OnChange += FlexSettingsChanged; staggeredSettings.OnChange += StaggeredSettingsChanged; ellipseSettings.OnChange += EllipseSettingsChanged; } /// /// Process the disable event. /// protected override void OnDisable() { PropertiesTracker.Clear(); base.OnDisable(); } /// /// Process the destroy event. /// protected override void OnDestroy() { if (flexSettings != null) { flexSettings.OnChange -= FlexSettingsChanged; } if (ellipseSettings != null) { ellipseSettings.OnChange -= EllipseSettingsChanged; } if (staggeredSettings != null) { staggeredSettings.OnChange -= StaggeredSettingsChanged; } LayoutGroup = null; base.OnDestroy(); } /// /// Process the RectTransform removed event. /// protected virtual void OnRectTransformRemoved() { SetDirty(); } /// /// Sets the layout horizontal. /// public override void SetLayoutHorizontal() { UpdateElements(); PerformLayout(true, ResizeType.Horizontal); } /// /// Sets the layout vertical. /// public override void SetLayoutVertical() { UpdateElements(); PerformLayout(true, ResizeType.Vertical); } /// /// Calculates the layout input horizontal. /// public override void CalculateLayoutInputHorizontal() { base.CalculateLayoutInputHorizontal(); UpdateElements(); PerformLayout(false, ResizeType.None); } /// /// Calculates the layout input vertical. /// public override void CalculateLayoutInputVertical() { UpdateElements(); PerformLayout(false, ResizeType.None); } /// /// Marks layout to update. /// public void NeedUpdateLayout() { SetDirty(); } /// /// Calculates the size of the layout. /// public void CalculateLayoutSize() { UpdateElements(); PerformLayout(false); } /// /// Updates the layout. /// public void UpdateLayout() { LayoutRebuilder.ForceRebuildLayoutImmediate(rectTransform); } /// /// Get children. /// /// Children. protected List GetChildren() { if (SkipInactive) { return rectChildren; } Children.Clear(); for (int i = 0; i < rectTransform.childCount; i++) { Children.Add(rectTransform.GetChild(i) as RectTransform); } return Children; } /// /// Update LayoutElements. /// protected void UpdateElements() { ClearElements(); var children = GetChildren(); var ignore = ShouldIgnore != null; foreach (var rt in children) { if (ignore && ShouldIgnore(rt)) { continue; } elements.Add(CreateElement(rt)); } } /// /// Reset layout elements list. /// protected void ClearElements() { for (int i = 0; i < elements.Count; i++) { elementsCache.Push(elements[i]); } elements.Clear(); } /// /// Create layout element. /// /// Element. /// Element data. protected LayoutElementInfo CreateElement(RectTransform elem) { var info = (elementsCache.Count > 0) ? elementsCache.Pop() : new LayoutElementInfo(); var active = SkipInactive || elem.gameObject.activeInHierarchy; info.SetElement(elem, active, this); if (ResetRotation && (LayoutType != LayoutTypes.Ellipse)) { info.NewEulerAngles = Vector3.zero; } return info; } /// /// Gets the margin top. /// /// Top margin. public float GetMarginTop() { return Symmetric ? Margin.y : MarginTop; } /// /// Gets the margin bottom. /// /// Bottom margin. public float GetMarginBottom() { return Symmetric ? Margin.y : MarginBottom; } /// /// Gets the margin left. /// /// Left margin. public float GetMarginLeft() { return Symmetric ? Margin.x : MarginLeft; } /// /// Gets the margin right. /// /// Right margin. public float GetMarginRight() { return Symmetric ? Margin.x : MarginRight; } /// /// Get layout group. /// /// Layout group. protected EasyLayoutBaseType GetLayoutGroup() { switch (LayoutType) { case LayoutTypes.Compact: return new EasyLayoutCompact(); case LayoutTypes.Grid: return new EasyLayoutGrid(); case LayoutTypes.Flex: return new EasyLayoutFlex(); case LayoutTypes.Staggered: return new EasyLayoutStaggered(); case LayoutTypes.Ellipse: return new EasyLayoutEllipse(); default: Debug.LogWarning(string.Format("Unknown layout type: {0}", EnumHelper.ToString(LayoutType))); break; } return null; } /// /// Perform layout. /// /// Is need to set elements position? /// Resize type. protected void PerformLayout(bool setPositions, ResizeType resizeType = ResizeType.Horizontal | ResizeType.Vertical) { if (LayoutGroup == null) { Debug.LogWarning(string.Format("Layout group not found: {0}", EnumHelper.ToString(LayoutType))); return; } PropertiesTracker.Clear(); LayoutGroup.LoadSettings(this); CurrentSize = LayoutGroup.PerformLayout(elements, setPositions, resizeType); BlockSize = elements.Count > 0 ? new Vector2(CurrentSize.Width, CurrentSize.Height) : Vector2.zero; CurrentSize += new Vector2(MarginFullHorizontal, MarginFullVertical); UISize = new Vector2(CurrentSize.Width, CurrentSize.Height); } /// /// Process element changed event. /// /// Element. /// Properties. protected virtual void ElementChanged(RectTransform element, DrivenTransformProperties properties) { PropertiesTracker.Add(this, element, properties); } /// /// Set element size. /// /// Element. [Obsolete("No more used.")] public void SetElementSize(LayoutElementInfo element) { var driven_properties = DrivenTransformProperties.AnchoredPosition | DrivenTransformProperties.AnchoredPositionZ; if (ChildrenWidth != ChildrenSize.DoNothing) { driven_properties |= DrivenTransformProperties.SizeDeltaX; element.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, element.NewWidth); } if (ChildrenHeight != ChildrenSize.DoNothing) { driven_properties |= DrivenTransformProperties.SizeDeltaY; element.Rect.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, element.NewHeight); } if (LayoutType == LayoutTypes.Ellipse || ResetRotation) { driven_properties |= DrivenTransformProperties.Rotation; element.Rect.localEulerAngles = element.NewEulerAngles; } if (LayoutType == LayoutTypes.Ellipse) { driven_properties |= DrivenTransformProperties.Pivot; element.Rect.pivot = element.NewPivot; } PropertiesTracker.Add(this, element.Rect, driven_properties); } /// /// Get element position in the group. /// /// Element. /// Position. public EasyLayoutPosition GetElementPosition(RectTransform element) { return LayoutGroup.GetElementPosition(element); } /// /// Awake this instance. /// protected override void Awake() { base.Awake(); Upgrade(); } #if UNITY_EDITOR /// /// Update layout when parameters changed. /// protected override void OnValidate() { LayoutGroup = null; SetDirty(); } #endif [SerializeField] [HideInInspector] int version = 0; /// /// Upgrade to keep compatibility between versions. /// public virtual void Upgrade() { #pragma warning disable 0618 if (version == 0) { if (ControlWidth) { ChildrenWidth = MaxWidth ? ChildrenSize.SetMaxFromPreferred : ChildrenSize.SetPreferred; } if (ControlHeight) { ChildrenHeight = MaxHeight ? ChildrenSize.SetMaxFromPreferred : ChildrenSize.SetPreferred; } version = 1; } #pragma warning restore 0618 } /// /// Get debug information. /// /// Debug information. public virtual string GetDebugInfo() { var sb = new System.Text.StringBuilder(); GetDebugInfo(sb); return sb.ToString(); } /// /// Get debug information. /// /// String builder. public virtual void GetDebugInfo(System.Text.StringBuilder sb) { sb.Append("RectTransform.size: "); sb.Append(rectTransform.rect.size.ToString()); sb.AppendLine(); sb.Append("localScale: "); sb.Append(rectTransform.localScale.ToString()); sb.AppendLine(); sb.Append("Main Axis: "); sb.Append(EnumHelper.ToString(MainAxis)); sb.AppendLine(); sb.Append("Type: "); sb.Append(EnumHelper.ToString(LayoutType)); sb.AppendLine(); switch (LayoutType) { case LayoutTypes.Compact: sb.Append("\tGroup Position: "); sb.Append(EnumHelper.ToString(GroupPosition)); sb.AppendLine(); sb.Append("\tRow Align: "); sb.Append(EnumHelper.ToString(RowAlign)); sb.AppendLine(); sb.Append("\tInner Align: "); sb.Append(EnumHelper.ToString(InnerAlign)); sb.AppendLine(); sb.Append("\tCompact Constraint: "); sb.Append(EnumHelper.ToString(CompactConstraint)); sb.AppendLine(); sb.Append("\tCompact Constraint Count: "); sb.Append(CompactConstraintCount); sb.AppendLine(); break; case LayoutTypes.Grid: sb.Append("\tGroup Position: "); sb.Append(EnumHelper.ToString(GroupPosition)); sb.AppendLine(); sb.Append("\tCell Align: "); sb.Append(EnumHelper.ToString(CellAlign)); sb.AppendLine(); sb.Append("\tGrid Constraint: "); sb.Append(EnumHelper.ToString(GridConstraint)); sb.AppendLine(); sb.Append("\tGrid Constraint Count: "); sb.Append(GridConstraintCount); sb.AppendLine(); break; case LayoutTypes.Flex: FlexSettings.GetDebugInfo(sb); break; case LayoutTypes.Staggered: StaggeredSettings.GetDebugInfo(sb); break; case LayoutTypes.Ellipse: EllipseSettings.GetDebugInfo(sb); break; default: sb.AppendLine("\tUnknown type: no details"); break; } sb.Append("PaddingInner: "); sb.Append(PaddingInner.ToString()); sb.AppendLine(); sb.Append("Spacing: "); sb.Append(Spacing.ToString()); sb.AppendLine(); sb.Append("Margin Symmetric: "); sb.Append(Symmetric); sb.AppendLine(); if (Symmetric) { sb.Append("Margin: "); sb.Append(Margin.ToString()); sb.AppendLine(); } else { sb.Append("Margin Left: "); sb.Append(MarginLeft); sb.AppendLine(); sb.Append("Margin Right: "); sb.Append(MarginRight); sb.AppendLine(); sb.Append("Margin Top: "); sb.Append(MarginTop); sb.AppendLine(); sb.Append("Margin Bottom: "); sb.Append(MarginBottom); sb.AppendLine(); } sb.Append("TopToBottom: "); sb.Append(TopToBottom); sb.AppendLine(); sb.Append("RightToLeft: "); sb.Append(RightToLeft); sb.AppendLine(); sb.Append("Skip Inactive: "); sb.Append(SkipInactive); sb.AppendLine(); sb.Append("Reset Rotation: "); sb.Append(ResetRotation); sb.AppendLine(); sb.Append("Children Width: "); sb.Append(EnumHelper.ToString(ChildrenWidth)); sb.AppendLine(); sb.Append("Children Height: "); sb.Append(EnumHelper.ToString(ChildrenHeight)); sb.AppendLine(); sb.Append("Children: "); foreach (var c in elements) { sb.Append(c.Rect.name); sb.Append(": "); sb.Append(c.Rect.rect.size.ToString()); sb.AppendLine(); } } } }