using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Diagnostics; using Barotrauma; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; namespace QICrabUI { /// /// Resizing components to it's Width and placing them sequentially /// public class CUILayoutVerticalList : CUILayout { internal float TotalHeight; public CUIDirection Direction; public float Gap { get; set; } public bool ResizeToHostWidth { get; set; } = true; private class CUIComponentSize { public CUIComponent Component; public Vector2 Size; public CUIComponentSize(CUIComponent component, Vector2 size) { Component = component; Size = size; } } private List Sizes = new List(); private List Resizible = new List(); internal override void Update() { Stopwatch sw = new Stopwatch(); if (Changed) { Host.InvokeOnLayoutUpdated(); Sizes.Clear(); Resizible.Clear(); TotalHeight = 0; sw.Restart(); foreach (CUIComponent c in Host.Children) { float h = 0; float w = 0; if (ResizeToHostWidth) { w = Host.Real.Width; } else { if (c.Relative.Width.HasValue) w = c.Relative.Width.Value * Host.Real.Width; if (c.CrossRelative.Width.HasValue) w = c.CrossRelative.Width.Value * Host.Real.Height; if (c.Absolute.Width.HasValue) w = c.Absolute.Width.Value; if (c.RelativeMin.Width.HasValue) w = Math.Max(w, c.RelativeMin.Width.Value * Host.Real.Width); if (c.AbsoluteMin.Width.HasValue) w = Math.Max(w, c.AbsoluteMin.Width.Value); if (!c.RelativeMin.Width.HasValue && !c.AbsoluteMin.Width.HasValue && c.ForcedMinSize.X.HasValue) { w = Math.Max(w, c.ForcedMinSize.X.Value); } if (c.RelativeMax.Width.HasValue) w = Math.Min(w, c.RelativeMax.Width.Value * Host.Real.Width); if (c.AbsoluteMax.Width.HasValue) w = Math.Min(w, c.AbsoluteMax.Width.Value); } Vector2 s = new Vector2(w, h); if (!c.FillEmptySpace.Y && !c.Ghost.Y) { if (c.Relative.Height.HasValue) { h = c.Relative.Height.Value * Host.Real.Height; CUIDebug.Capture(Host, c, "VerticalList.Update", "Relative.Height", "h", h.ToString()); } if (c.CrossRelative.Height.HasValue) { h = c.CrossRelative.Height.Value * Host.Real.Width; CUIDebug.Capture(Host, c, "VerticalList.Update", "CrossRelative.Height", "h", h.ToString()); } if (c.Absolute.Height.HasValue) { h = c.Absolute.Height.Value; CUIDebug.Capture(Host, c, "VerticalList.Update", "Absolute.Height", "h", h.ToString()); } if (c.RelativeMin.Height.HasValue) { h = Math.Max(h, c.RelativeMin.Height.Value * Host.Real.Height); CUIDebug.Capture(Host, c, "VerticalList.Update", "RelativeMin.Height", "h", h.ToString()); } if (c.AbsoluteMin.Height.HasValue) { h = Math.Max(h, c.AbsoluteMin.Height.Value); CUIDebug.Capture(Host, c, "VerticalList.Update", "AbsoluteMin.Height", "h", h.ToString()); } if (!c.RelativeMin.Height.HasValue && !c.AbsoluteMin.Height.HasValue && c.ForcedMinSize.Y.HasValue) { h = Math.Max(h, c.ForcedMinSize.Y.Value); CUIDebug.Capture(Host, c, "VerticalList.Update", "ForcedMinSize.Y", "h", h.ToString()); } if (c.RelativeMax.Height.HasValue) { h = Math.Min(h, c.RelativeMax.Height.Value * Host.Real.Height); CUIDebug.Capture(Host, c, "VerticalList.Update", "RelativeMax.Height", "h", h.ToString()); } if (c.AbsoluteMax.Height.HasValue) { h = Math.Min(h, c.AbsoluteMax.Height.Value); CUIDebug.Capture(Host, c, "VerticalList.Update", "AbsoluteMax.Height", "h", h.ToString()); } s = new Vector2(w, h); Vector2 okSize = c.AmIOkWithThisSize(s); CUIDebug.Capture(Host, c, "VerticalList.Update", "AmIOkWithThisSize", "s", okSize.ToString()); s = okSize; if (!c.Fixed) s = new Vector2(s.X, s.Y / c.Scale); TotalHeight += s.Y; } CUIComponentSize size = new CUIComponentSize(c, s); Sizes.Add(size); if (c.FillEmptySpace.Y) Resizible.Add(size); } TotalHeight += Math.Max(0, Host.Children.Count - 1) * Gap; sw.Stop(); //CUI.Log($"{Host} vlist measuring {sw.ElapsedMilliseconds}"); float dif = Math.Max(0, Host.Real.Height - TotalHeight); Resizible.ForEach(c => { c.Size = c.Component.AmIOkWithThisSize(new Vector2(c.Size.X, (float)Math.Round(dif / Resizible.Count))); //c.Size = new Vector2(c.Size.X, dif / Resizible.Count); CUIDebug.Capture(Host, c.Component, "VerticalList.Update", "Resizible.ForEach", "c.Size", c.Size.ToString()); }); CUI3DOffset offset = Host.ChildOffsetBounds.Check(Host.ChildrenOffset); if (Direction == CUIDirection.Straight) { float y = 0; foreach (CUIComponentSize c in Sizes) { CUIRect real; if (Host.ChildrenBoundaries != null) real = Host.ChildrenBoundaries(Host.Real).Check(0, y, c.Size.X, c.Size.Y); else real = new CUIRect(0, y, c.Size.X, c.Size.Y); real = offset.Transform(real); real = real.Shift(Host.Real.Position); c.Component.SetReal(real, "VerticalList.Update"); y += c.Size.Y + Gap; } } if (Direction == CUIDirection.Reverse) { float y = Host.Real.Height; foreach (CUIComponentSize c in Sizes) { y -= c.Size.Y + Gap; CUIRect real; if (Host.ChildrenBoundaries != null) real = Host.ChildrenBoundaries(Host.Real).Check(0, y, c.Size.X, c.Size.Y); else real = new CUIRect(0, y, c.Size.X, c.Size.Y); real = offset.Transform(real); real = real.Shift(Host.Real.Position); c.Component.SetReal(real, "VerticalList.Update"); } } } base.Update(); } internal override void ResizeToContent() { if (AbsoluteChanged && Host.FitContent.X) { float tw = 0; foreach (CUIComponent c in Host.Children) { if (c.Ghost.X) continue; float w = 0; if (c.Absolute.Width.HasValue) w = c.Absolute.Width.Value; if (c.AbsoluteMin.Width.HasValue) w = Math.Max(w, c.AbsoluteMin.Width.Value); else if (c.ForcedMinSize.X.HasValue) w = Math.Max(w, c.ForcedMinSize.X.Value); if (c.AbsoluteMax.Width.HasValue) w = Math.Min(w, c.AbsoluteMax.Width.Value); tw = Math.Max(tw, w); } CUIDebug.Capture(null, Host, "VerticalList.ResizeToContent", "tw", "ForcedMinSize.W", tw.ToString()); Host.SetForcedMinSize(Host.ForcedMinSize with { X = tw }); } if (AbsoluteChanged && Host.FitContent.Y) { float th = 0; foreach (CUIComponent c in Host.Children) { if (c.Ghost.Y) continue; float h = 0; if (!c.FillEmptySpace.Y) { if (c.Absolute.Height.HasValue) h = c.Absolute.Height.Value; if (c.AbsoluteMin.Height.HasValue) h = Math.Max(h, c.AbsoluteMin.Height.Value); else if (c.ForcedMinSize.Y.HasValue) h = Math.Max(h, c.ForcedMinSize.Y.Value); if (c.AbsoluteMax.Height.HasValue) h = Math.Min(h, c.AbsoluteMax.Height.Value); th += h; } } CUIDebug.Capture(null, Host, "VerticalList.ResizeToContent", "th", "ForcedMinSize.Y", th.ToString()); Host.SetForcedMinSize(Host.ForcedMinSize with { Y = th }); } base.ResizeToContent(); } public CUILayoutVerticalList() : base() { } public CUILayoutVerticalList(CUIDirection d, CUIComponent host = null) : base(host) { Direction = d; } } }