A game about forced loneliness, made by TACStudios
1using System;
2using System.Linq;
3using UnityEngine.Assertions;
4
5namespace UnityEngine.Rendering
6{
7 /// <summary>
8 /// Debug UI Class
9 /// </summary>
10 public partial class DebugUI
11 {
12 /// <summary>
13 /// A column of checkboxes for enabling and disabling flags.
14 /// </summary>
15 [Flags]
16 public enum Flags
17 {
18 /// <summary>
19 /// None.
20 /// </summary>
21 None = 0,
22 /// <summary>
23 /// This widget is Editor only.
24 /// </summary>
25 EditorOnly = 1 << 1,
26 /// <summary>
27 /// This widget is Runtime only.
28 /// </summary>
29 RuntimeOnly = 1 << 2,
30 /// <summary>
31 /// This widget will force the Debug Editor Window refresh.
32 /// </summary>
33 EditorForceUpdate = 1 << 3,
34 /// <summary>
35 /// This widget will appear in the section "Frequently Used"
36 /// </summary>
37 FrequentlyUsed = 1 << 4
38
39 }
40
41 /// <summary>
42 /// Base class for all debug UI widgets.
43 /// </summary>
44 public abstract class Widget
45 {
46 // Set to null until it's added to a panel, be careful
47 /// <summary>
48 /// Panels containing the widget.
49 /// </summary>
50 protected Panel m_Panel;
51
52 /// <summary>
53 /// Panels containing the widget.
54 /// </summary>
55 public virtual Panel panel
56 {
57 get { return m_Panel; }
58 internal set { m_Panel = value; }
59 }
60
61 /// <summary>
62 /// Parent container.
63 /// </summary>
64 protected IContainer m_Parent;
65
66 /// <summary>
67 /// Parent container.
68 /// </summary>
69 public virtual IContainer parent
70 {
71 get { return m_Parent; }
72 internal set { m_Parent = value; }
73 }
74
75 /// <summary>
76 /// Flags for the widget.
77 /// </summary>
78 public Flags flags { get; set; }
79
80 /// <summary>
81 /// Display name.
82 /// </summary>
83 public string displayName { get; set; }
84
85 /// <summary>
86 /// Tooltip.
87 /// </summary>
88 public string tooltip { get; set; }
89
90 /// <summary>
91 /// Path of the widget.
92 /// </summary>
93 public string queryPath { get; private set; }
94
95 /// <summary>
96 /// True if the widget is Editor only.
97 /// </summary>
98 public bool isEditorOnly => flags.HasFlag(Flags.EditorOnly);
99
100 /// <summary>
101 /// True if the widget is Runtime only.
102 /// </summary>
103 public bool isRuntimeOnly => flags.HasFlag(Flags.RuntimeOnly);
104
105 /// <summary>
106 /// True if the widget is inactive in the editor (i.e. widget is runtime only and the application is not 'Playing').
107 /// </summary>
108 public bool isInactiveInEditor => (isRuntimeOnly && !Application.isPlaying);
109
110 /// <summary>
111 /// Optional delegate that can be used to conditionally hide widgets at runtime (e.g. due to state of other widgets).
112 /// </summary>
113 public Func<bool> isHiddenCallback;
114
115 /// <summary>
116 /// If <see cref="isHiddenCallback">shouldHideDelegate</see> has been set and returns true, the widget is hidden from the UI.
117 /// </summary>
118 public bool isHidden => isHiddenCallback?.Invoke() ?? false;
119
120 internal virtual void GenerateQueryPath()
121 {
122 queryPath = displayName.Trim();
123
124 if (m_Parent != null)
125 queryPath = m_Parent.queryPath + " -> " + queryPath;
126 }
127
128 /// <summary>
129 /// Returns the hash code of the widget.
130 /// </summary>
131 /// <returns>The hash code of the widget.</returns>
132 public override int GetHashCode()
133 {
134 return queryPath.GetHashCode() ^ isHidden.GetHashCode();
135 }
136
137 /// <summary>
138 /// Helper struct to allow more compact initialization of widgets.
139 /// </summary>
140 public struct NameAndTooltip
141 {
142 /// <summary>
143 /// The name
144 /// </summary>
145 public string name;
146 /// <summary>
147 /// The tooltip
148 /// </summary>
149 public string tooltip;
150 }
151
152 /// <summary>
153 /// Helper setter to allow more compact initialization of widgets.
154 /// </summary>
155 public NameAndTooltip nameAndTooltip
156 {
157 set
158 {
159 displayName = value.name;
160 tooltip = value.tooltip;
161 }
162 }
163 }
164
165 /// <summary>
166 /// Interface for widgets that can contain other widgets.
167 /// </summary>
168 public interface IContainer
169 {
170 /// <summary>
171 /// List of children of the container.
172 /// </summary>
173 ObservableList<Widget> children { get; }
174
175 /// <summary>
176 /// Display name of the container.
177 /// </summary>
178 string displayName { get; set; }
179
180 /// <summary>
181 /// Path of the container.
182 /// </summary>
183 string queryPath { get; }
184 }
185
186 /// <summary>
187 /// Any widget that implements this will be considered for serialization (only if the setter is set and thus is not read-only)
188 /// </summary>
189 public interface IValueField
190 {
191 /// <summary>
192 /// Return the value of the field.
193 /// </summary>
194 /// <returns>Value of the field.</returns>
195 object GetValue();
196
197 /// <summary>
198 /// Set the value of the field.
199 /// </summary>
200 /// <param name="value">Input value.</param>
201 void SetValue(object value);
202
203 /// <summary>
204 /// Function used to validate the value when setting it.
205 /// </summary>
206 /// <param name="value">Input value.</param>
207 /// <returns>Validated value.</returns>
208 object ValidateValue(object value);
209 }
210
211 // Miscellaneous
212 /// <summary>
213 /// Button widget.
214 /// </summary>
215 public class Button : Widget
216 {
217 /// <summary>
218 /// Action performed by the button.
219 /// </summary>
220 public Action action { get; set; }
221 }
222
223 /// <summary>
224 /// A field that displays a read-only value.
225 /// </summary>
226 public class Value : Widget
227 {
228 /// <summary>
229 /// Getter for the Value.
230 /// </summary>
231 public Func<object> getter { get; set; }
232
233 /// <summary>
234 /// Refresh rate for the read-only value (runtime only)
235 /// </summary>
236 public float refreshRate = 0.1f;
237
238 /// <summary>
239 /// Optional C# numeric format string, using following syntax: "{0[:numericFormatString]}"
240 /// See https://docs.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings
241 /// and https://docs.microsoft.com/en-us/dotnet/standard/base-types/composite-formatting
242 /// Example: 123.45678 with formatString "{0:F2} ms" --> "123.45 ms".
243 /// </summary>
244 public string formatString = null;
245
246 /// <summary>
247 /// Constructor.
248 /// </summary>
249 public Value()
250 {
251 displayName = "";
252 }
253
254 /// <summary>
255 /// Returns the value of the widget.
256 /// </summary>
257 /// <returns>The value of the widget.</returns>
258 public virtual object GetValue()
259 {
260 Assert.IsNotNull(getter);
261 return getter();
262 }
263
264 /// <summary>
265 /// Returns the formatted value string for display purposes.
266 /// </summary>
267 /// <param name="value">Value to be formatted.</param>
268 /// <returns>The formatted value string.</returns>
269 public virtual string FormatString(object value)
270 {
271 return string.IsNullOrEmpty(formatString) ? $"{value}" : string.Format(formatString, value);
272 }
273 }
274
275 /// <summary>
276 /// A progress bar that displays values between 0% and 100%.
277 /// </summary>
278 public class ProgressBarValue : Value
279 {
280 /// <summary>
281 /// Minimum value.
282 /// </summary>
283 public float min = 0f;
284 /// <summary>
285 /// Maximum value.
286 /// </summary>
287 public float max = 1f;
288
289 /// <summary>
290 /// Get the current progress string, remapped to [0, 1] range, representing the progress between min and max.
291 /// </summary>
292 /// <param name="value">Value to be formatted.</param>
293 /// <returns>Formatted progress percentage string between 0% and 100%.</returns>
294 public override string FormatString(object value)
295 {
296 static float Remap01(float v, float x0, float y0) => (v - x0) / (y0 - x0);
297
298 float clamped = Mathf.Clamp((float)value, min, max);
299 float percentage = Remap01(clamped, min, max);
300 return $"{percentage:P1}";
301 }
302 }
303
304 /// <summary>
305 /// An array of read-only values that Unity displays in a horizontal row.
306 /// </summary>
307 public class ValueTuple : Widget
308 {
309 /// <summary>
310 /// Number of elements in the tuple.
311 /// </summary>
312 public int numElements
313 {
314 get
315 {
316 Assert.IsTrue(values.Length > 0);
317 return values.Length;
318 }
319 }
320
321 /// <summary>
322 /// Value widgets.
323 /// </summary>
324 public Value[] values;
325
326 /// <summary>
327 /// Refresh rate for the read-only values (runtime only)
328 /// </summary>
329 public float refreshRate => values.FirstOrDefault()?.refreshRate ?? 0.1f;
330
331 /// <summary>
332 /// The currently pinned element index, or -1 if none are pinned.
333 /// </summary>
334 public int pinnedElementIndex = -1;
335 }
336 }
337}