Client LuaCsForBarotrauma
GUILayoutGroup.cs
1 using Microsoft.Xna.Framework;
2 using System;
3 using System.Linq;
4 
5 namespace Barotrauma
6 {
7  public class GUILayoutGroup : GUIComponent
8  {
9  private bool isHorizontal;
10  public bool IsHorizontal
11  {
12  get { return isHorizontal; }
13  set
14  {
15  isHorizontal = value;
16  needsToRecalculate = true;
17  }
18  }
19 
20  private bool stretch;
24  public bool Stretch
25  {
26  get { return stretch; }
27  set
28  {
29  stretch = value;
30  needsToRecalculate = true;
31  }
32  }
33 
34  private int absoluteSpacing;
35  public int AbsoluteSpacing
36  {
37  get { return absoluteSpacing; }
38  set
39  {
40  absoluteSpacing = MathHelper.Clamp(value, 0, int.MaxValue);
41  needsToRecalculate = true;
42  }
43  }
44 
45  private float relativeSpacing;
46  public float RelativeSpacing
47  {
48  get { return relativeSpacing; }
49  set
50  {
51  relativeSpacing = MathHelper.Clamp(value, -1, 1);
52  needsToRecalculate = true;
53  }
54  }
55 
56  private Anchor childAnchor;
58  {
59  get { return childAnchor; }
60  set
61  {
62  childAnchor = value;
63  needsToRecalculate = true;
64  }
65  }
66 
67  private bool needsToRecalculate;
68  public bool NeedsToRecalculate
69  {
70  get { return needsToRecalculate; }
71  set
72  {
73  if (value) { needsToRecalculate = true; }
74  }
75  }
76 
77  public GUILayoutGroup(RectTransform rectT, bool isHorizontal = false, Anchor childAnchor = Anchor.TopLeft) : base(null, rectT)
78  {
79  CanBeFocused = false;
80  this.isHorizontal = isHorizontal;
81  this.childAnchor = childAnchor;
82  rectT.ChildrenChanged += (child) => needsToRecalculate = true;
83  rectT.ScaleChanged += () => needsToRecalculate = true;
84  rectT.SizeChanged += () => needsToRecalculate = true;
85  }
86 
87  public void Recalculate()
88  {
89  float stretchFactor = 1.0f;
90  if (stretch && RectTransform.Children.Count() > 0)
91  {
92  foreach (RectTransform child in RectTransform.Children)
93  {
94  if (child.GUIComponent.IgnoreLayoutGroups) { continue; }
95 
96  switch (child.ScaleBasis)
97  {
98  case ScaleBasis.BothHeight:
99  case ScaleBasis.Smallest when Rect.Height <= Rect.Width:
100  case ScaleBasis.Largest when Rect.Height > Rect.Width:
101  child.MinSize = new Point((int)((child.Rect.Height * child.RelativeSize.X) / child.RelativeSize.Y), child.MinSize.Y);
102  break;
103  case ScaleBasis.BothWidth:
104  case ScaleBasis.Smallest when Rect.Width <= Rect.Height:
105  case ScaleBasis.Largest when Rect.Width > Rect.Height:
106  child.MinSize = new Point(child.MinSize.X, (int)((child.Rect.Width * child.RelativeSize.Y) / child.RelativeSize.X));
107  break;
108  }
109  }
110 
111  float minSize = RectTransform.Children
112  .Where(c => !c.GUIComponent.IgnoreLayoutGroups)
113  .Sum(c => isHorizontal ? (c.IsFixedSize ? c.NonScaledSize.X : c.MinSize.X) : (c.IsFixedSize ? c.NonScaledSize.Y : c.MinSize.Y));
114 
115  float totalSize = RectTransform.Children
116  .Where(c => !c.GUIComponent.IgnoreLayoutGroups)
117  .Sum(c => isHorizontal ?
118  (c.IsFixedSize ? c.Rect.Width : MathHelper.Clamp(c.Rect.Width, c.MinSize.X, c.MaxSize.X)) :
119  (c.IsFixedSize ? c.Rect.Height : MathHelper.Clamp(c.Rect.Height, c.MinSize.Y, c.MaxSize.Y)));
120 
121  float thisSize = (isHorizontal ? Rect.Width : Rect.Height);
122 
123  totalSize +=
124  (RectTransform.Children.Count(c => !c.GUIComponent.IgnoreLayoutGroups) - 1) *
125  (absoluteSpacing + relativeSpacing * thisSize);
126 
127  stretchFactor = totalSize <= 0.0f || minSize >= thisSize || totalSize == minSize ?
128  1.0f :
129  (thisSize - minSize) / (totalSize - minSize);
130  }
131 
132  int absPos = 0;
133  float relPos = 0;
134  foreach (var child in RectTransform.Children)
135  {
136  if (child.GUIComponent.IgnoreLayoutGroups) { continue; }
137 
138  float currentStretchFactor = child.ScaleBasis == ScaleBasis.Normal ? stretchFactor : 1.0f;
139  child.SetPosition(childAnchor);
140 
141  void advancePositionsAndCalculateChildSizes(
142  ref int childNonScaledSize,
143  ref float childRelativeSize,
144  int childMinSize,
145  int childMaxSize,
146  int childRectSize,
147  int selfRectSize)
148  {
149  if (child.IsFixedSize)
150  {
151  absPos += childNonScaledSize + absoluteSpacing;
152  }
153  else
154  {
155  absPos += (int)Math.Round(MathHelper.Clamp(childRectSize * currentStretchFactor, childMinSize, childMaxSize) + (absoluteSpacing * currentStretchFactor));
156  if (stretch)
157  {
158  float relativeSize =
159  MathF.Round(childRelativeSize * currentStretchFactor * selfRectSize) / selfRectSize;
160  childRelativeSize = relativeSize;
161  }
162  }
163  }
164 
165  Point childNonScaledSize = child.NonScaledSize;
166  Vector2 childRelativeSize = child.RelativeSize;
167  if (isHorizontal)
168  {
169  child.RelativeOffset = new Vector2(relPos, child.RelativeOffset.Y);
170  child.AbsoluteOffset = new Point(absPos, child.AbsoluteOffset.Y);
171  advancePositionsAndCalculateChildSizes(
172  ref childNonScaledSize.X,
173  ref childRelativeSize.X,
174  child.MinSize.X,
175  child.MaxSize.X,
176  child.Rect.Width,
177  Rect.Width);
178  }
179  else
180  {
181  child.RelativeOffset = new Vector2(child.RelativeOffset.X, relPos);
182  child.AbsoluteOffset = new Point(child.AbsoluteOffset.X, absPos);
183  advancePositionsAndCalculateChildSizes(
184  ref childNonScaledSize.Y,
185  ref childRelativeSize.Y,
186  child.MinSize.Y,
187  child.MaxSize.Y,
188  child.Rect.Height,
189  Rect.Height);
190  }
191  child.NonScaledSize = childNonScaledSize;
192  child.RelativeSize = childRelativeSize;
193  relPos += relativeSpacing * stretchFactor;
194  if (isHorizontal) { relPos = MathF.Round(relPos * Rect.Width) / Rect.Width; }
195  else { relPos = MathF.Round(relPos * Rect.Height) / Rect.Height; }
196  }
197  needsToRecalculate = false;
198  }
199 
200  protected override void Update(float deltaTime)
201  {
202  base.Update(deltaTime);
203  if (needsToRecalculate)
204  {
205  Recalculate();
206  }
207  }
208 
209  public override void ForceLayoutRecalculation()
210  {
211  Recalculate();
212  base.ForceLayoutRecalculation();
213  }
214  }
215 }
virtual Rectangle Rect
bool Stretch
Note that stretching cannot be undone, because the previous child sizes are not stored.
override void Update(float deltaTime)
GUILayoutGroup(RectTransform rectT, bool isHorizontal=false, Anchor childAnchor=Anchor.TopLeft)
override void ForceLayoutRecalculation()
GUIComponent GUIComponent
Should be assigned only by GUIComponent. Note that RectTransform is created first and the GUIComponen...
Vector2 RelativeSize
Relative to the parent rect.
IEnumerable< RectTransform > Children
Action< RectTransform > ChildrenChanged
The element provided as the argument is the changed child. It may be new in the hierarchy or just rep...
Point?? MinSize
Min size in pixels. Does not affect scaling.