CrabUI
Loading...
Searching...
No Matches
CUILayoutHorizontalList.cs
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Reflection;
5
6using Barotrauma;
7using Microsoft.Xna.Framework;
8using Microsoft.Xna.Framework.Input;
9using Microsoft.Xna.Framework.Graphics;
10
11namespace CrabUI
12{
13 /// <summary>
14 /// Resizing components to it's Height and placing them sequentially
15 /// </summary>
17 {
18 //public CUIComponent Host;
19 internal float TotalWidth;
20 public CUIDirection Direction;
21 public float Gap { get; set; }
22 public bool ResizeToHostHeight { get; set; } = true;
23
24 private class CUIComponentSize
25 {
26 public CUIComponent Component;
27 public Vector2 Size;
28 public CUIComponentSize(CUIComponent component, Vector2 size)
29 {
30 Component = component;
31 Size = size;
32 }
33 }
34 private List<CUIComponentSize> Sizes = new List<CUIComponentSize>();
35 private List<CUIComponentSize> Resizible = new List<CUIComponentSize>();
36
37 internal override void Update()
38 {
39 if (Changed)
40 {
41 Host.InvokeOnLayoutUpdated();
42
43 Sizes.Clear();
44 Resizible.Clear();
45
46 TotalWidth = 0;
47
48
49 foreach (CUIComponent c in Host.Children)
50 {
51 float h = 0;
52 float w = 0;
53
54 if (ResizeToHostHeight)
55 {
56 h = Host.Real.Height;
57 }
58 else
59 {
60 if (c.Relative.Height.HasValue) h = c.Relative.Height.Value * Host.Real.Height;
61 if (c.CrossRelative.Height.HasValue) h = c.CrossRelative.Height.Value * Host.Real.Width;
62 if (c.Absolute.Height.HasValue) h = c.Absolute.Height.Value;
63
64 if (c.RelativeMin.Height.HasValue) h = Math.Max(h, c.RelativeMin.Height.Value * Host.Real.Height);
65 if (c.AbsoluteMin.Height.HasValue) h = Math.Max(h, c.AbsoluteMin.Height.Value);
66
67 if (!c.RelativeMin.Height.HasValue && !c.AbsoluteMin.Height.HasValue && c.ForcedMinSize.Y.HasValue)
68 {
69 h = Math.Max(h, c.ForcedMinSize.Y.Value);
70 }
71
72 if (c.RelativeMax.Height.HasValue) h = Math.Min(h, c.RelativeMax.Height.Value * Host.Real.Height);
73 if (c.AbsoluteMax.Height.HasValue) h = Math.Min(h, c.AbsoluteMax.Height.Value);
74 }
75
76 Vector2 s = new Vector2(w, h);
77
78
79 if (!c.FillEmptySpace.X && !c.Ghost.X)
80 {
81 if (c.Relative.Width.HasValue)
82 {
83 w = c.Relative.Width.Value * Host.Real.Width;
84 CUIDebug.Capture(Host, c, "HorizontalList.Update", "Relative.Width", "w", w.ToString());
85 }
86 if (c.CrossRelative.Width.HasValue)
87 {
88 w = c.CrossRelative.Width.Value * Host.Real.Height;
89 CUIDebug.Capture(Host, c, "HorizontalList.Update", "CrossRelative.Width", "w", w.ToString());
90 }
91 if (c.Absolute.Width.HasValue)
92 {
93 w = c.Absolute.Width.Value;
94 CUIDebug.Capture(Host, c, "HorizontalList.Update", "Absolute.Width", "w", w.ToString());
95 }
96
97 if (c.RelativeMin.Width.HasValue)
98 {
99 w = Math.Max(w, c.RelativeMin.Width.Value * Host.Real.Width);
100 CUIDebug.Capture(Host, c, "HorizontalList.Update", "RelativeMin.Width", "w", w.ToString());
101 }
102 if (c.AbsoluteMin.Width.HasValue)
103 {
104 w = Math.Max(w, c.AbsoluteMin.Width.Value);
105 CUIDebug.Capture(Host, c, "HorizontalList.Update", "AbsoluteMin.Width", "w", w.ToString());
106 }
107 if (!c.RelativeMin.Width.HasValue && !c.AbsoluteMin.Width.HasValue && c.ForcedMinSize.X.HasValue)
108 {
109 w = Math.Max(w, c.ForcedMinSize.X.Value);
110 CUIDebug.Capture(Host, c, "HorizontalList.Update", "ForcedMinSize.X", "w", w.ToString());
111 }
112
113 if (c.RelativeMax.Width.HasValue)
114 {
115 w = Math.Min(w, c.RelativeMax.Width.Value * Host.Real.Width);
116 CUIDebug.Capture(Host, c, "HorizontalList.Update", "RelativeMax.Width", "w", w.ToString());
117 }
118 if (c.AbsoluteMax.Width.HasValue)
119 {
120 w = Math.Min(w, c.AbsoluteMax.Width.Value);
121 CUIDebug.Capture(Host, c, "HorizontalList.Update", "AbsoluteMax.Width", "w", w.ToString());
122 }
123
124 s = new Vector2(w, h);
125 Vector2 okSize = c.AmIOkWithThisSize(s);
126 CUIDebug.Capture(Host, c, "HorizontalList.Update", "AmIOkWithThisSize", "s", okSize.ToString());
127
128 s = okSize;
129
130 if (!c.Fixed) s = new Vector2(s.X / c.Scale, s.Y);
131
132 TotalWidth += s.X;
133 }
134
135 CUIComponentSize size = new CUIComponentSize(c, s);
136 Sizes.Add(size);
137
138 if (c.FillEmptySpace.X) Resizible.Add(size);
139 }
140
141 TotalWidth += Math.Max(0, Host.Children.Count - 1) * Gap;
142
143 float dif = Math.Max(0, Host.Real.Width - TotalWidth);
144
145 Resizible.ForEach(c =>
146 {
147 float available = dif / Resizible.Count;
148 //TODO
149 // if (c.Component.RelativeMin.Width.HasValue)
150 // {
151 // available = Math.Max(available, c.Component.RelativeMin.Width.Value * Host.Real.Width);
152 // }
153 // if (c.Component.AbsoluteMin.Width.HasValue)
154 // {
155 // available = Math.Max(available, c.Component.AbsoluteMin.Width.Value);
156 // }
157
158 // if (c.Component.RelativeMax.Width.HasValue)
159 // {
160 // available = Math.Min(available, c.Component.RelativeMax.Width.Value * Host.Real.Width);
161 // }
162 // if (c.Component.AbsoluteMax.Width.HasValue)
163 // {
164 // available = Math.Min(available, c.Component.AbsoluteMax.Width.Value);
165 // }
166
167 c.Size = c.Component.AmIOkWithThisSize(new Vector2((float)Math.Round(available), c.Size.Y));
168 //c.Size = new Vector2(dif / Resizible.Count, c.Size.Y);
169 CUIDebug.Capture(Host, c.Component, "HorizontalList.Update", "Resizible.ForEach", "c.Size", c.Size.ToString());
170 });
171
172
173 CUI3DOffset offset = Host.ChildOffsetBounds.Check(Host.ChildrenOffset);
174
175 if (Direction == CUIDirection.Straight)
176 {
177 float x = 0;
178 foreach (CUIComponentSize c in Sizes)
179 {
180 CUIRect real;
181 if (Host.ChildrenBoundaries != null)
182 {
183 real = Host.ChildrenBoundaries(Host.Real).Check(x, 0, c.Size.X, c.Size.Y);
184 }
185 else
186 {
187 real = new CUIRect(x, 0, c.Size.X, c.Size.Y);
188 }
189
190 real = offset.Transform(real);
191 real = real.Shift(Host.Real.Position);
192
193 c.Component.SetReal(real, "HorizontalList layout update");
194
195 x += c.Size.X + Gap;
196 }
197 }
198
199 if (Direction == CUIDirection.Reverse)
200 {
201 float x = Host.Real.Width;
202 foreach (CUIComponentSize c in Sizes)
203 {
204 x -= c.Size.X + Gap;
205
206 CUIRect real;
207 if (Host.ChildrenBoundaries != null)
208 {
209 real = Host.ChildrenBoundaries(Host.Real).Check(x, 0, c.Size.X, c.Size.Y);
210 }
211 else
212 {
213 real = new CUIRect(x, 0, c.Size.X, c.Size.Y);
214 }
215 real = offset.Transform(real);
216 real = real.Shift(Host.Real.Position);
217
218 c.Component.SetReal(real, "HorizontalList layout update");
219 }
220 }
221
222 }
223
224 base.Update();
225 }
226
227 //TODO sync with vlist
228 internal override void ResizeToContent()
229 {
230 if (AbsoluteChanged && Host.FitContent.X)
231 {
232 float tw = 0;
233 foreach (CUIComponent c in Host.Children)
234 {
235 if (c.Ghost.X) continue;
236
237 float w = 0;
238 //TODO mb i should let FillEmptySpace components have min size, mb in different layout
239 if (!c.FillEmptySpace.X)
240 {
241 if (c.Absolute.Width.HasValue) w = c.Absolute.Width.Value;
242 if (c.AbsoluteMin.Width.HasValue) w = Math.Max(w, c.AbsoluteMin.Width.Value);
243 else if (c.ForcedMinSize.X.HasValue) w = Math.Max(w, c.ForcedMinSize.X.Value);
244 if (c.AbsoluteMax.Width.HasValue) w = Math.Min(w, c.AbsoluteMax.Width.Value);
245 }
246
247 tw += w;
248 }
249
250 tw += Math.Max(0, Host.Children.Count - 1) * Gap;
251
252 CUIDebug.Capture(null, Host, "HorizontalList ResizeToContent", "tw", "ForcedMinSize.X", tw.ToString());
253 Host.SetForcedMinSize(Host.ForcedMinSize with { X = tw });
254 }
255
256 if (AbsoluteChanged && Host.FitContent.Y)
257 {
258 float th = 0;
259 foreach (CUIComponent c in Host.Children)
260 {
261 if (c.Ghost.Y) continue;
262
263 float h = 0;
264 if (c.Absolute.Height.HasValue) h = c.Absolute.Height.Value;
265 if (c.AbsoluteMin.Height.HasValue) h = Math.Max(h, c.AbsoluteMin.Height.Value);
266 else if (c.ForcedMinSize.Y.HasValue) h = Math.Max(h, c.ForcedMinSize.Y.Value);
267 if (c.AbsoluteMax.Height.HasValue) h = Math.Min(h, c.AbsoluteMax.Height.Value);
268 th = Math.Max(th, h);
269 }
270
271 CUIDebug.Capture(null, Host, "HorizontalList ResizeToContent", "th", "ForcedMinSize.Y", th.ToString());
272 Host.SetForcedMinSize(Host.ForcedMinSize with { Y = th });
273 }
274
275 base.ResizeToContent();
276 }
277 public CUILayoutHorizontalList() : base() { }
278 public CUILayoutHorizontalList(CUIDirection d, CUIComponent host = null) : base(host)
279 {
280 Direction = d;
281 }
282 }
283}
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.
Resizing components to it's Height and placing them sequentially.
Base class for all layouts.
Definition CUILayout.cs:18
Offset of child components with X, Y, Z.
Rectangle with float.
Definition CUIRect.cs:17