forked from Unity-Technologies/UnityCsReference
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathLayoutEntry.cs
More file actions
329 lines (286 loc) · 14 KB
/
LayoutEntry.cs
File metadata and controls
329 lines (286 loc) · 14 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
// Unity C# reference source
// Copyright (c) Unity Technologies. For terms of use, see
// https://unity3d.com/legal/licenses/Unity_Reference_Only_License
using System;
using System.Collections.Generic;
using System.Security;
using UnityEngine.Scripting;
using UnityEngineInternal;
using UnityEngine.Bindings;
namespace UnityEngine
{
// Basic layout element
[VisibleToOtherModules("UnityEngine.UIElementsModule")]
internal class GUILayoutEntry
{
// The min and max sizes. Used during calculations...
public float minWidth, maxWidth, minHeight, maxHeight;
// The rectangle that this element ends up having
public Rect rect = new Rect(0, 0, 0, 0);
// Can this element stretch?
public int stretchWidth, stretchHeight;
// The style to use.
GUIStyle m_Style = GUIStyle.none;
public GUIStyle style
{
get { return m_Style; }
set { m_Style = value; ApplyStyleSettings(value); }
}
internal static Rect kDummyRect = new Rect(0, 0, 1, 1);
// The margins of this element.
public virtual RectOffset margin { get { return style.margin; } }
public GUILayoutEntry(float _minWidth, float _maxWidth, float _minHeight, float _maxHeight, GUIStyle _style)
{
minWidth = _minWidth;
maxWidth = _maxWidth;
minHeight = _minHeight;
maxHeight = _maxHeight;
if (_style == null)
_style = GUIStyle.none;
style = _style;
}
public GUILayoutEntry(float _minWidth, float _maxWidth, float _minHeight, float _maxHeight, GUIStyle _style, GUILayoutOption[] options)
{
minWidth = _minWidth;
maxWidth = _maxWidth;
minHeight = _minHeight;
maxHeight = _maxHeight;
style = _style;
ApplyOptions(options);
}
public virtual void CalcWidth() {}
public virtual void CalcHeight() {}
public virtual void SetHorizontal(float x, float width) { rect.x = x; rect.width = width; }
public virtual void SetVertical(float y, float height) { rect.y = y; rect.height = height; }
protected virtual void ApplyStyleSettings(GUIStyle style)
{
stretchWidth = (style.fixedWidth == 0 && style.stretchWidth) ? 1 : 0;
stretchHeight = (style.fixedHeight == 0 && style.stretchHeight) ? 1 : 0;
m_Style = style;
}
public virtual void ApplyOptions(GUILayoutOption[] options)
{
if (options == null)
return;
foreach (GUILayoutOption i in options)
{
switch (i.type)
{
case GUILayoutOption.Type.fixedWidth: minWidth = maxWidth = (float)i.value; stretchWidth = 0; break;
case GUILayoutOption.Type.fixedHeight: minHeight = maxHeight = (float)i.value; stretchHeight = 0; break;
case GUILayoutOption.Type.minWidth: minWidth = (float)i.value; if (maxWidth < minWidth) maxWidth = minWidth; break;
case GUILayoutOption.Type.maxWidth: maxWidth = (float)i.value; if (minWidth > maxWidth) minWidth = maxWidth; stretchWidth = 0; break;
case GUILayoutOption.Type.minHeight: minHeight = (float)i.value; if (maxHeight < minHeight) maxHeight = minHeight; break;
case GUILayoutOption.Type.maxHeight: maxHeight = (float)i.value; if (minHeight > maxHeight) minHeight = maxHeight; stretchHeight = 0; break;
case GUILayoutOption.Type.stretchWidth: stretchWidth = (int)i.value; break;
case GUILayoutOption.Type.stretchHeight: stretchHeight = (int)i.value; break;
}
}
if (maxWidth != 0 && maxWidth < minWidth)
maxWidth = minWidth;
if (maxHeight != 0 && maxHeight < minHeight)
maxHeight = minHeight;
}
protected static int indent = 0;
public override string ToString()
{
string space = "";
for (int i = 0; i < indent; i++)
space += " ";
return space + UnityString.Format("{1}-{0} (x:{2}-{3}, y:{4}-{5})", style != null ? style.name : "NULL", GetType(), rect.x, rect.xMax, rect.y, rect.yMax) +
" - W: " + minWidth + "-" + maxWidth + (stretchWidth != 0 ? "+" : "") + ", H: " + minHeight + "-" + maxHeight + (stretchHeight != 0 ? "+" : "");
}
}
// Layouter that makes elements which sizes will always conform to a specific aspect ratio.
internal sealed class GUIAspectSizer : GUILayoutEntry
{
float aspect;
public GUIAspectSizer(float aspect, GUILayoutOption[] options) : base(0, 0, 0, 0, GUIStyle.none)
{
this.aspect = aspect;
ApplyOptions(options);
}
public override void CalcHeight()
{
minHeight = maxHeight = rect.width / aspect;
}
}
// Will layout a button grid so it can fit within the given rect.
// *undocumented*
internal sealed class GUIGridSizer : GUILayoutEntry
{
// Helper: Create the layout group and scale it to fit
public static Rect GetRect(GUIContent[] contents, int xCount, GUIStyle style, GUILayoutOption[] options)
{
Rect r = new Rect(0, 0, 0, 0);
switch (Event.current.type)
{
case EventType.Layout:
GUILayoutUtility.current.topLevel.Add(new GUIGridSizer(contents, xCount, style, options));
break;
case EventType.Used:
return kDummyRect;
default:
r = GUILayoutUtility.current.topLevel.GetNext().rect;
break;
}
return r;
}
readonly int m_Count;
readonly int m_XCount;
readonly float m_MinButtonWidth = -1;
readonly float m_MaxButtonWidth = -1;
readonly float m_MinButtonHeight = -1;
readonly float m_MaxButtonHeight = -1;
private GUIGridSizer(GUIContent[] contents, int xCount, GUIStyle buttonStyle, GUILayoutOption[] options) : base(0, 0, 0, 0, GUIStyle.none)
{
m_Count = contents.Length;
m_XCount = xCount;
// Most settings comes from the button style (can we stretch, etc). Hence, I apply the style here
ApplyStyleSettings(buttonStyle);
// We can have custom options coming from userland. We apply this last so it overrides
ApplyOptions(options);
if (xCount == 0 || contents.Length == 0)
return;
// internal horizontal spacing
float totalHorizSpacing = Mathf.Max(buttonStyle.margin.left, buttonStyle.margin.right) * (m_XCount - 1);
// Debug.Log (String.Format ("margins: {0}, {1} totalHoriz: {2}", buttonStyle.margin.left, buttonStyle.margin.right, totalHorizSpacing));
// internal horizontal margins
float totalVerticalSpacing = Mathf.Max(buttonStyle.margin.top, buttonStyle.margin.bottom) * (rows - 1);
// Handle fixedSize buttons
if (buttonStyle.fixedWidth != 0)
m_MinButtonWidth = m_MaxButtonWidth = buttonStyle.fixedWidth;
// Debug.Log ("buttonStyle.fixedHeight " + buttonStyle.fixedHeight);
if (buttonStyle.fixedHeight != 0)
m_MinButtonHeight = m_MaxButtonHeight = buttonStyle.fixedHeight;
// Apply GUILayout.Width/Height/whatever properties.
if (m_MinButtonWidth == -1)
{
if (minWidth != 0)
m_MinButtonWidth = (minWidth - totalHorizSpacing) / m_XCount;
if (maxWidth != 0)
m_MaxButtonWidth = (maxWidth - totalHorizSpacing) / m_XCount;
}
if (m_MinButtonHeight == -1)
{
if (minHeight != 0)
m_MinButtonHeight = (minHeight - totalVerticalSpacing) / rows;
if (maxHeight != 0)
m_MaxButtonHeight = (maxHeight - totalVerticalSpacing) / rows;
}
// Debug.Log (String.Format ("minButtonWidth {0}, maxButtonWidth {1}, minButtonHeight {2}, maxButtonHeight{3}", minButtonWidth, maxButtonWidth, minButtonHeight, maxButtonHeight));
// if anything is left unknown, we need to iterate over all elements and figure out the sizes.
if (m_MinButtonHeight == -1 || m_MaxButtonHeight == -1 || m_MinButtonWidth == -1 || m_MaxButtonWidth == -1)
{
// figure out the max size. Since the buttons are in a grid, the max size determines stuff.
float calcHeight = 0, calcWidth = 0;
foreach (GUIContent i in contents)
{
Vector2 size = buttonStyle.CalcSize(i);
calcWidth = Mathf.Max(calcWidth, size.x);
calcHeight = Mathf.Max(calcHeight, size.y);
}
// If the user didn't supply minWidth, we need to calculate that
if (m_MinButtonWidth == -1)
{
// if the user has supplied a maxButtonWidth, the buttons can never get larger.
if (m_MaxButtonWidth != -1)
m_MinButtonWidth = Mathf.Min(calcWidth, m_MaxButtonWidth);
else
m_MinButtonWidth = calcWidth;
}
// If the user didn't supply maxWidth, we need to calculate that
if (m_MaxButtonWidth == -1)
{
// if the user has supplied a minButtonWidth, the buttons can never get smaller.
if (m_MinButtonWidth != -1)
m_MaxButtonWidth = Mathf.Max(calcWidth, m_MinButtonWidth);
else
m_MaxButtonWidth = calcWidth;
}
// If the user didn't supply minWidth, we need to calculate that
if (m_MinButtonHeight == -1)
{
// if the user has supplied a maxButtonWidth, the buttons can never get larger.
if (m_MaxButtonHeight != -1)
m_MinButtonHeight = Mathf.Min(calcHeight, m_MaxButtonHeight);
else
m_MinButtonHeight = calcHeight;
}
// If the user didn't supply maxWidth, we need to calculate that
if (m_MaxButtonHeight == -1)
{
// if the user has supplied a minButtonWidth, the buttons can never get smaller.
if (m_MinButtonHeight != -1)
maxHeight = Mathf.Max(maxHeight, m_MinButtonHeight);
m_MaxButtonHeight = maxHeight;
}
}
// We now know the button sizes. Calculate min & max values from that
minWidth = m_MinButtonWidth * m_XCount + totalHorizSpacing;
maxWidth = m_MaxButtonWidth * m_XCount + totalHorizSpacing;
minHeight = m_MinButtonHeight * rows + totalVerticalSpacing;
maxHeight = m_MaxButtonHeight * rows + totalVerticalSpacing;
// Debug.Log (String.Format ("minWidth {0}, maxWidth {1}, minHeight {2}, maxHeight{3}", minWidth, maxWidth, minHeight, maxHeight));
}
int rows
{
get
{
int rows = m_Count / m_XCount;
if (m_Count % m_XCount != 0)
rows++;
return rows;
}
}
}
// Class that can handle word-wrap sizing. this is specialcased as setting width can make the text wordwrap, which would then increase height...
internal sealed class GUIWordWrapSizer : GUILayoutEntry
{
readonly GUIContent m_Content;
// We need to differentiate between min & maxHeight we calculate for ourselves and one that is forced by the user
// (When inside a scrollview, we can be told to layout twice, so we need to know the difference)
readonly float m_ForcedMinHeight;
readonly float m_ForcedMaxHeight;
public GUIWordWrapSizer(GUIStyle style, GUIContent content, GUILayoutOption[] options) : base(0, 0, 0, 0, style)
{
m_Content = new GUIContent(content);
ApplyOptions(options);
m_ForcedMinHeight = minHeight;
m_ForcedMaxHeight = maxHeight;
}
public override void CalcWidth()
{
if (minWidth == 0 || maxWidth == 0)
{
float _minWidth, _maxWidth;
style.CalcMinMaxWidth(m_Content, out _minWidth, out _maxWidth);
// Further layout calculations might round this value to nearest which could force the text over several lines
// when rounding down. Make sure to actual give enough space by always rounding up (case 1047812).
_minWidth = Mathf.Ceil(_minWidth);
_maxWidth = Mathf.Ceil(_maxWidth);
if (minWidth == 0)
minWidth = _minWidth;
if (maxWidth == 0)
maxWidth = _maxWidth;
}
}
public override void CalcHeight()
{
// When inside a scrollview, this can get called twice (as vertical scrollbar reduces width, which causes a reflow).
// Hence, we need to use the separately cached values for min & maxHeight coming from the user...
if (m_ForcedMinHeight == 0 || m_ForcedMaxHeight == 0)
{
float height = style.CalcHeight(m_Content, rect.width);
if (m_ForcedMinHeight == 0)
minHeight = height;
else
minHeight = m_ForcedMinHeight;
if (m_ForcedMaxHeight == 0)
maxHeight = height;
else
maxHeight = m_ForcedMaxHeight;
}
}
}
}