CrabUI
Loading...
Searching...
No Matches
CUILayoutVerticalList.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5using System.Diagnostics;
6
7using Barotrauma;
8using Microsoft.Xna.Framework;
9using Microsoft.Xna.Framework.Input;
10using Microsoft.Xna.Framework.Graphics;
11
12namespace CrabUI
13{
14 /// <summary>
15 /// Resizing components to it's Width and placing them sequentially
16 /// </summary>
18 {
19 // public CUIComponent Host;
20 internal float TotalHeight;
21 public CUIDirection Direction;
22
23 public float Gap { get; set; }
24
25 public bool ResizeToHostWidth { get; set; } = true;
26
27
28 private class CUIComponentSize
29 {
30 public CUIComponent Component;
31 public Vector2 Size;
32 public CUIComponentSize(CUIComponent component, Vector2 size)
33 {
34 Component = component;
35 Size = size;
36 }
37 }
38 private List<CUIComponentSize> Sizes = new List<CUIComponentSize>();
39 private List<CUIComponentSize> Resizible = new List<CUIComponentSize>();
40
41 internal override void Update()
42 {
43 Stopwatch sw = new Stopwatch();
44
45 if (Changed)
46 {
47 Host.InvokeOnLayoutUpdated();
48
49 Sizes.Clear();
50 Resizible.Clear();
51
52 TotalHeight = 0;
53
54 sw.Restart();
55 foreach (CUIComponent c in Host.Children)
56 {
57 float h = 0;
58 float w = 0;
59
60 if (ResizeToHostWidth)
61 {
62 w = Host.Real.Width;
63 }
64 else
65 {
66 if (c.Relative.Width.HasValue) w = c.Relative.Width.Value * Host.Real.Width;
67 if (c.CrossRelative.Width.HasValue) w = c.CrossRelative.Width.Value * Host.Real.Height;
68 if (c.Absolute.Width.HasValue) w = c.Absolute.Width.Value;
69
70 if (c.RelativeMin.Width.HasValue) w = Math.Max(w, c.RelativeMin.Width.Value * Host.Real.Width);
71 if (c.AbsoluteMin.Width.HasValue) w = Math.Max(w, c.AbsoluteMin.Width.Value);
72
73 if (!c.RelativeMin.Width.HasValue && !c.AbsoluteMin.Width.HasValue && c.ForcedMinSize.X.HasValue)
74 {
75 w = Math.Max(w, c.ForcedMinSize.X.Value);
76 }
77
78 if (c.RelativeMax.Width.HasValue) w = Math.Min(w, c.RelativeMax.Width.Value * Host.Real.Width);
79 if (c.AbsoluteMax.Width.HasValue) w = Math.Min(w, c.AbsoluteMax.Width.Value);
80 }
81
82 Vector2 s = new Vector2(w, h);
83
84
85 if (!c.FillEmptySpace.Y && !c.Ghost.Y)
86 {
87 if (c.Relative.Height.HasValue)
88 {
89 h = c.Relative.Height.Value * Host.Real.Height;
90 CUIDebug.Capture(Host, c, "VerticalList.Update", "Relative.Height", "h", h.ToString());
91 }
92 if (c.CrossRelative.Height.HasValue)
93 {
94 h = c.CrossRelative.Height.Value * Host.Real.Width;
95 CUIDebug.Capture(Host, c, "VerticalList.Update", "CrossRelative.Height", "h", h.ToString());
96 }
97 if (c.Absolute.Height.HasValue)
98 {
99 h = c.Absolute.Height.Value;
100 CUIDebug.Capture(Host, c, "VerticalList.Update", "Absolute.Height", "h", h.ToString());
101 }
102
103 if (c.RelativeMin.Height.HasValue)
104 {
105 h = Math.Max(h, c.RelativeMin.Height.Value * Host.Real.Height);
106 CUIDebug.Capture(Host, c, "VerticalList.Update", "RelativeMin.Height", "h", h.ToString());
107 }
108 if (c.AbsoluteMin.Height.HasValue)
109 {
110 h = Math.Max(h, c.AbsoluteMin.Height.Value);
111 CUIDebug.Capture(Host, c, "VerticalList.Update", "AbsoluteMin.Height", "h", h.ToString());
112 }
113 if (!c.RelativeMin.Height.HasValue && !c.AbsoluteMin.Height.HasValue && c.ForcedMinSize.Y.HasValue)
114 {
115 h = Math.Max(h, c.ForcedMinSize.Y.Value);
116 CUIDebug.Capture(Host, c, "VerticalList.Update", "ForcedMinSize.Y", "h", h.ToString());
117 }
118
119 if (c.RelativeMax.Height.HasValue)
120 {
121 h = Math.Min(h, c.RelativeMax.Height.Value * Host.Real.Height);
122 CUIDebug.Capture(Host, c, "VerticalList.Update", "RelativeMax.Height", "h", h.ToString());
123 }
124 if (c.AbsoluteMax.Height.HasValue)
125 {
126 h = Math.Min(h, c.AbsoluteMax.Height.Value);
127 CUIDebug.Capture(Host, c, "VerticalList.Update", "AbsoluteMax.Height", "h", h.ToString());
128 }
129
130 s = new Vector2(w, h);
131 Vector2 okSize = c.AmIOkWithThisSize(s);
132 CUIDebug.Capture(Host, c, "VerticalList.Update", "AmIOkWithThisSize", "s", okSize.ToString());
133
134 s = okSize;
135
136 if (!c.Fixed) s = new Vector2(s.X, s.Y / c.Scale);
137
138 TotalHeight += s.Y;
139 }
140
141 CUIComponentSize size = new CUIComponentSize(c, s);
142 Sizes.Add(size);
143
144 if (c.FillEmptySpace.Y) Resizible.Add(size);
145 }
146
147 TotalHeight += Math.Max(0, Host.Children.Count - 1) * Gap;
148
149 sw.Stop();
150 //CUI.Log($"{Host} vlist measuring {sw.ElapsedMilliseconds}");
151
152 float dif = Math.Max(0, Host.Real.Height - TotalHeight);
153
154 Resizible.ForEach(c =>
155 {
156 c.Size = c.Component.AmIOkWithThisSize(new Vector2(c.Size.X, (float)Math.Round(dif / Resizible.Count)));
157 //c.Size = new Vector2(c.Size.X, dif / Resizible.Count);
158
159 CUIDebug.Capture(Host, c.Component, "VerticalList.Update", "Resizible.ForEach", "c.Size", c.Size.ToString());
160 });
161
162
163 CUI3DOffset offset = Host.ChildOffsetBounds.Check(Host.ChildrenOffset);
164
165
166
167 if (Direction == CUIDirection.Straight)
168 {
169 float y = 0;
170 foreach (CUIComponentSize c in Sizes)
171 {
172 CUIRect real;
173
174 if (Host.ChildrenBoundaries != null) real = Host.ChildrenBoundaries(Host.Real).Check(0, y, c.Size.X, c.Size.Y);
175 else real = new CUIRect(0, y, c.Size.X, c.Size.Y);
176
177 real = offset.Transform(real);
178 real = real.Shift(Host.Real.Position);
179
180 c.Component.SetReal(real, "VerticalList.Update");
181
182 y += c.Size.Y + Gap;
183 }
184 }
185
186 if (Direction == CUIDirection.Reverse)
187 {
188 float y = Host.Real.Height;
189 foreach (CUIComponentSize c in Sizes)
190 {
191 y -= c.Size.Y + Gap;
192 CUIRect real;
193 if (Host.ChildrenBoundaries != null) real = Host.ChildrenBoundaries(Host.Real).Check(0, y, c.Size.X, c.Size.Y);
194 else real = new CUIRect(0, y, c.Size.X, c.Size.Y);
195
196 real = offset.Transform(real);
197 real = real.Shift(Host.Real.Position);
198
199 c.Component.SetReal(real, "VerticalList.Update");
200 }
201 }
202 }
203
204 base.Update();
205 }
206
207 internal override void ResizeToContent()
208 {
209 if (AbsoluteChanged && Host.FitContent.X)
210 {
211 float tw = 0;
212 foreach (CUIComponent c in Host.Children)
213 {
214 if (c.Ghost.X) continue;
215
216 float w = 0;
217 if (c.Absolute.Width.HasValue) w = c.Absolute.Width.Value;
218 if (c.AbsoluteMin.Width.HasValue) w = Math.Max(w, c.AbsoluteMin.Width.Value);
219 else if (c.ForcedMinSize.X.HasValue) w = Math.Max(w, c.ForcedMinSize.X.Value);
220 if (c.AbsoluteMax.Width.HasValue) w = Math.Min(w, c.AbsoluteMax.Width.Value);
221
222 tw = Math.Max(tw, w);
223 }
224
225 CUIDebug.Capture(null, Host, "VerticalList.ResizeToContent", "tw", "ForcedMinSize.W", tw.ToString());
226 Host.SetForcedMinSize(Host.ForcedMinSize with { X = tw });
227 }
228
229 if (AbsoluteChanged && Host.FitContent.Y)
230 {
231 float th = 0;
232 foreach (CUIComponent c in Host.Children)
233 {
234 if (c.Ghost.Y) continue;
235
236 float h = 0;
237 if (!c.FillEmptySpace.Y)
238 {
239 if (c.Absolute.Height.HasValue) h = c.Absolute.Height.Value;
240 if (c.AbsoluteMin.Height.HasValue) h = Math.Max(h, c.AbsoluteMin.Height.Value);
241 else if (c.ForcedMinSize.Y.HasValue) h = Math.Max(h, c.ForcedMinSize.Y.Value);
242 if (c.AbsoluteMax.Height.HasValue) h = Math.Min(h, c.AbsoluteMax.Height.Value);
243 th += h;
244 }
245 }
246
247 th += Math.Max(0, Host.Children.Count - 1) * Gap;
248
249 CUIDebug.Capture(null, Host, "VerticalList.ResizeToContent", "th", "ForcedMinSize.Y", th.ToString());
250 Host.SetForcedMinSize(Host.ForcedMinSize with { Y = th });
251 }
252
253 base.ResizeToContent();
254 }
255
256 public CUILayoutVerticalList() : base() { }
257
258 public CUILayoutVerticalList(CUIDirection d, CUIComponent host = null) : base(host)
259 {
260 Direction = d;
261 }
262 }
263}
Base class for all components.
CUIBool2 FillEmptySpace
Will be resized to fill empty space in list components.
CUINullRect Relative
Relative to parent size and position, [0..1].
CUI3DOffset ChildrenOffset
Will shift all children by this much, e.g. this is how scroll works It's also 3D.
CUINullVector2 ForcedMinSize
This is used by text to prevent resizing beyond that and works as AbsoluteMin.
CUIBool2 FitContent
Will resize itself to fit components with absolute size, e.g. text.
CUIRect Real
Calculated prop, position on real screen in pixels Should be fully calculated after CUIMainComponent....
bool Fixed
Should it ignore child offset?
CUINullRect CrossRelative
It's like Relative, but to the opposite dimension E.g. Real.Width = CrossRelative....
Func< CUIRect, CUIBoundaries > ChildrenBoundaries
Limits to children positions.
float Scale
This is set by ChildrenOffset when zooming, and iirc consumed by text to adjust text scale.
CUIBool2 Ghost
Ghost components don't affect layout.
CUINullRect Absolute
Absolute size and position in pixels.
Base class for all layouts.
Definition CUILayout.cs:18
Resizing components to it's Width and placing them sequentially.
Offset of child components with X, Y, Z.
Rectangle with float.
Definition CUIRect.cs:17