A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEngine;
5using UnityEngine.Rendering;
6
7namespace UnityEditor.Rendering
8{
9 /// <summary>
10 /// Builtin Drawer for Value Debug Items.
11 /// </summary>
12 [DebugUIDrawer(typeof(DebugUI.Value))]
13 public sealed class DebugUIDrawerValue : DebugUIWidgetDrawer<DebugUI.Value>
14 {
15 /// <summary>
16 /// Does the field of the given type
17 /// </summary>
18 /// <param name="rect">The rect to draw the field</param>
19 /// <param name="label">The label for the field</param>
20 /// <param name="field">The widget</param>
21 protected override void DoGUI(Rect rect, GUIContent label, DebugUI.Value field)
22 {
23 EditorGUI.LabelField(rect, label, EditorGUIUtility.TrTextContent(field.FormatString(field.GetValue())));
24 }
25 }
26
27 /// <summary>
28 /// Builtin Drawer for ValueTuple Debug Items.
29 /// </summary>
30 [DebugUIDrawer(typeof(DebugUI.ValueTuple))]
31 public sealed class DebugUIDrawerValueTuple : DebugUIWidgetDrawer<DebugUI.ValueTuple>
32 {
33 /// <summary>
34 /// Does the field of the given type
35 /// </summary>
36 /// <param name="rect">The rect to draw the field</param>
37 /// <param name="label">The label for the field</param>
38 /// <param name="field">The widget</param>
39 protected override void DoGUI(Rect rect, GUIContent label, DebugUI.ValueTuple field)
40 {
41 EditorGUI.PrefixLabel(rect, label);
42
43 // Following layout should match DebugUIDrawerFoldout to make column labels align
44 Rect drawRect = GUILayoutUtility.GetLastRect();
45
46 int indent = EditorGUI.indentLevel;
47 EditorGUI.indentLevel = 0; //be at left of rects
48 for (int i = 0; i < field.numElements; i++)
49 {
50 var columnRect = drawRect;
51 columnRect.x += EditorGUIUtility.labelWidth + i * DebugWindow.Styles.foldoutColumnWidth;
52 columnRect.width = DebugWindow.Styles.foldoutColumnWidth;
53 var value = field.values[i].GetValue();
54
55 var style = EditorStyles.label;
56 if (Convert.ToSingle(value) == 0)
57 style = DebugWindow.Styles.labelWithZeroValueStyle;
58
59 EditorGUI.LabelField(columnRect, field.values[i].FormatString(value), style);
60 }
61 EditorGUI.indentLevel = indent;
62 }
63 }
64
65 /// <summary>
66 /// Builtin Drawer for ProgressBarValue Debug Items.
67 /// </summary>
68 [DebugUIDrawer(typeof(DebugUI.ProgressBarValue))]
69 public sealed class DebugUIDrawerProgressBarValue : DebugUIWidgetDrawer<DebugUI.ProgressBarValue>
70 {
71 /// <summary>
72 /// Does the field of the given type
73 /// </summary>
74 /// <param name="rect">The rect to draw the field</param>
75 /// <param name="label">The label for the field</param>
76 /// <param name="field">The widget</param>
77 protected override void DoGUI(Rect rect, GUIContent label, DebugUI.ProgressBarValue field)
78 {
79 var progressBarRect = EditorGUI.PrefixLabel(rect, label);
80 float value = (float)field.GetValue();
81 EditorGUI.ProgressBar(progressBarRect, value, field.FormatString(value));
82 }
83 }
84
85 /// <summary>
86 /// Builtin Drawer for Button Debug Items.
87 /// </summary>
88 [DebugUIDrawer(typeof(DebugUI.Button))]
89 public sealed class DebugUIDrawerButton : DebugUIWidgetDrawer<DebugUI.Button>
90 {
91 /// <summary>
92 /// Does the field of the given type
93 /// </summary>
94 /// <param name="rect">The rect to draw the field</param>
95 /// <param name="label">The label for the field</param>
96 /// <param name="field">The widget</param>
97 protected override void DoGUI(Rect rect, GUIContent label, DebugUI.Button field)
98 {
99 rect = EditorGUI.IndentedRect(rect);
100 if (GUI.Button(rect, label, EditorStyles.miniButton))
101 {
102 if (field.action != null)
103 field.action();
104 }
105 }
106 }
107
108 /// <summary>
109 /// Builtin Drawer for Boolean Debug Items.
110 /// </summary>
111 [DebugUIDrawer(typeof(DebugUI.BoolField))]
112 public sealed class DebugUIDrawerBoolField : DebugUIFieldDrawer<bool, DebugUI.BoolField, DebugStateBool>
113 {
114 /// <summary>
115 /// Does the field of the given type
116 /// </summary>
117 /// <param name="rect">The rect to draw the field</param>
118 /// <param name="label">The label for the field</param>
119 /// <param name="field">The field</param>
120 /// <param name="state">The state</param>
121 /// <returns>The value</returns>
122 protected override bool DoGUI(Rect rect, GUIContent label, DebugUI.BoolField field, DebugStateBool state)
123 {
124 return EditorGUI.Toggle(rect, label, field.GetValue());
125 }
126 }
127
128 /// <summary>
129 /// Builtin Drawer for History Boolean Debug Items.
130 /// </summary>
131 [DebugUIDrawer(typeof(DebugUI.HistoryBoolField))]
132 public sealed class DebugUIDrawerHistoryBoolField : DebugUIFieldDrawer<bool, DebugUI.HistoryBoolField, DebugStateBool>
133 {
134 /// <summary>
135 /// Does the field of the given type
136 /// </summary>
137 /// <param name="rect">The rect to draw the field</param>
138 /// <param name="label">The label for the field</param>
139 /// <param name="field">The field</param>
140 /// <param name="state">The state</param>
141 /// <returns>The current value from the UI</returns>
142 protected override bool DoGUI(Rect rect, GUIContent label, DebugUI.HistoryBoolField field, DebugStateBool state)
143 {
144 var labelRect = rect;
145 labelRect.width = EditorGUIUtility.labelWidth;
146 const int oneValueWidth = 70;
147 var valueRects = new Rect[field.historyDepth + 1];
148 for (int i = 0; i < field.historyDepth + 1; i++)
149 {
150 valueRects[i] = rect;
151 valueRects[i].x += EditorGUIUtility.labelWidth + i * oneValueWidth;
152 valueRects[i].width = oneValueWidth;
153 }
154 EditorGUI.LabelField(labelRect, label);
155 int indent = EditorGUI.indentLevel;
156 EditorGUI.indentLevel = 0; //be at left of rects
157 bool value = EditorGUI.Toggle(valueRects[0], field.GetValue());
158 using (new EditorGUI.DisabledScope(true))
159 {
160 for (int i = 0; i < field.historyDepth; i++)
161 EditorGUI.Toggle(valueRects[i + 1], field.GetHistoryValue(i));
162 }
163 EditorGUI.indentLevel = indent;
164 return value;
165 }
166 }
167
168 /// <summary>
169 /// Builtin Drawer for Integer Debug Items.
170 /// </summary>
171 [DebugUIDrawer(typeof(DebugUI.IntField))]
172 public sealed class DebugUIDrawerIntField : DebugUIFieldDrawer<int, DebugUI.IntField, DebugStateInt>
173 {
174 /// <summary>
175 /// Does the field of the given type
176 /// </summary>
177 /// <param name="rect">The rect to draw the field</param>
178 /// <param name="label">The label for the field</param>
179 /// <param name="field">The field</param>
180 /// <param name="state">The state</param>
181 /// <returns>The current value from the UI</returns>
182 protected override int DoGUI(Rect rect, GUIContent label, DebugUI.IntField field, DebugStateInt state)
183 {
184 return field.min != null && field.max != null
185 ? EditorGUI.IntSlider(rect, label, field.GetValue(), field.min(), field.max())
186 : EditorGUI.IntField(rect, label, field.GetValue());
187 }
188 }
189
190 /// <summary>
191 /// Builtin Drawer for Unsigned Integer Debug Items.
192 /// </summary>
193 [DebugUIDrawer(typeof(DebugUI.UIntField))]
194 public sealed class DebugUIDrawerUIntField : DebugUIFieldDrawer<uint, DebugUI.UIntField, DebugStateUInt>
195 {
196 /// <summary>
197 /// Does the field of the given type
198 /// </summary>
199 /// <param name="rect">The rect to draw the field</param>
200 /// <param name="label">The label for the field</param>
201 /// <param name="field">The field</param>
202 /// <param name="state">The state</param>
203 /// <returns>The current value from the UI</returns>
204 protected override uint DoGUI(Rect rect, GUIContent label, DebugUI.UIntField field, DebugStateUInt state)
205 {
206 // No UIntField so we need to max to 0 ourselves or the value will wrap around
207 int tmp = field.min != null && field.max != null
208 ? EditorGUI.IntSlider(rect, label, Mathf.Max(0, (int)field.GetValue()), Mathf.Max(0, (int)field.min()), Mathf.Max(0, (int)field.max()))
209 : EditorGUI.IntField(rect, label, Mathf.Max(0, (int)field.GetValue()));
210
211 return (uint)Mathf.Max(0, tmp);
212 }
213 }
214
215 /// <summary>
216 /// Builtin Drawer for Float Debug Items.
217 /// </summary>
218 [DebugUIDrawer(typeof(DebugUI.FloatField))]
219 public sealed class DebugUIDrawerFloatField : DebugUIFieldDrawer<float, DebugUI.FloatField, DebugStateFloat>
220 {
221 /// <summary>
222 /// Does the field of the given type
223 /// </summary>
224 /// <param name="rect">The rect to draw the field</param>
225 /// <param name="label">The label for the field</param>
226 /// <param name="field">The field</param>
227 /// <param name="state">The state</param>
228 /// <returns>The current value from the UI</returns>
229 protected override float DoGUI(Rect rect, GUIContent label, DebugUI.FloatField field, DebugStateFloat state)
230 {
231 return field.min != null && field.max != null
232 ? EditorGUI.Slider(rect, label, field.GetValue(), field.min(), field.max())
233 : EditorGUI.FloatField(rect, label, field.GetValue());
234 }
235 }
236
237 /// <summary>
238 /// Builtin Drawer for Enum Debug Items.
239 /// </summary>
240 [DebugUIDrawer(typeof(DebugUI.EnumField))]
241 public sealed class DebugUIDrawerEnumField : DebugUIFieldDrawer<int, DebugUI.EnumField, DebugStateEnum>
242 {
243 /// <summary>
244 /// Does the field of the given type
245 /// </summary>
246 /// <param name="rect">The rect to draw the field</param>
247 /// <param name="label">The label for the field</param>
248 /// <param name="field">The field</param>
249 /// <param name="state">The state</param>
250 /// <returns>The current value from the UI</returns>
251 protected override int DoGUI(Rect rect, GUIContent label, DebugUI.EnumField field, DebugStateEnum state)
252 {
253 int index = Mathf.Max(0, field.currentIndex); // Fallback just in case, we may be handling sub/sectioned enums here
254 int value = field.GetValue();
255
256 if (field.enumNames == null || field.enumValues == null)
257 {
258 EditorGUI.LabelField(rect, label, "Can't draw an empty enumeration.");
259 }
260 else if (field.enumNames.Length != field.enumValues.Length)
261 {
262 EditorGUI.LabelField(rect, label, "Invalid data");
263 }
264 else
265 {
266 index = EditorGUI.IntPopup(rect, label, index, field.enumNames, field.indexes);
267 value = field.enumValues[index];
268 }
269
270 return value;
271 }
272 }
273
274 /// <summary>
275 /// Builtin Drawer for Object Popup Fields Items.
276 /// </summary>
277 [DebugUIDrawer(typeof(DebugUI.ObjectPopupField))]
278 public sealed class DebugUIDrawerObjectPopupField : DebugUIFieldDrawer<UnityEngine.Object, DebugUI.ObjectPopupField, DebugStateObject>
279 {
280 /// <summary>
281 /// Does the field of the given type
282 /// </summary>
283 /// <param name="rect">The rect to draw the field</param>
284 /// <param name="label">The label for the field</param>
285 /// <param name="field">The field</param>
286 /// <param name="state">The state</param>
287 /// <returns>The current value from the UI</returns>
288 protected override UnityEngine.Object DoGUI(Rect rect, GUIContent label, DebugUI.ObjectPopupField field, DebugStateObject state)
289 {
290 var selectedValue = field.GetValue();
291
292 rect = EditorGUI.PrefixLabel(rect, label);
293
294 var elements = field.getObjects();
295 if (elements?.Any() ?? false)
296 {
297 var elementsArrayNames = elements.Select(e => e.name).ToArray();
298 var elementsArrayIndices = Enumerable.Range(0, elementsArrayNames.Length).ToArray();
299 var selectedIndex = selectedValue != null ? Array.IndexOf(elementsArrayNames, selectedValue.name) : 0;
300 var newSelectedIndex = EditorGUI.IntPopup(rect, selectedIndex, elementsArrayNames, elementsArrayIndices);
301 if (selectedIndex != newSelectedIndex)
302 selectedValue = elements.ElementAt(newSelectedIndex);
303 }
304 else
305 {
306 EditorGUI.LabelField(rect, "Can't draw an empty enumeration.");
307 }
308
309 return selectedValue;
310 }
311 }
312
313 /// <summary>
314 /// Builtin Drawer for History Enum Debug Items.
315 /// </summary>
316 [DebugUIDrawer(typeof(DebugUI.HistoryEnumField))]
317 public sealed class DebugUIDrawerHistoryEnumField : DebugUIFieldDrawer<int, DebugUI.HistoryEnumField, DebugStateEnum>
318 {
319 /// <summary>
320 /// Does the field of the given type
321 /// </summary>
322 /// <param name="rect">The rect to draw the field</param>
323 /// <param name="label">The label for the field</param>
324 /// <param name="field">The field</param>
325 /// <param name="state">The state</param>
326 /// <returns>The current value from the UI</returns>
327 protected override int DoGUI(Rect rect, GUIContent label, DebugUI.HistoryEnumField field, DebugStateEnum state)
328 {
329 int index = -1;
330 int value = field.GetValue();
331 if (field.enumNames == null || field.enumValues == null)
332 {
333 EditorGUILayout.LabelField("Can't draw an empty enumeration.");
334 }
335 else
336 {
337 index = field.currentIndex;
338
339 // Fallback just in case, we may be handling sub/sectionned enums here
340 if (index < 0)
341 index = 0;
342
343 var labelRect = rect;
344 labelRect.width = EditorGUIUtility.labelWidth;
345 const int oneValueWidth = 70;
346 var valueRects = new Rect[field.historyDepth + 1];
347 for (int i = 0; i < field.historyDepth + 1; i++)
348 {
349 valueRects[i] = rect;
350 valueRects[i].x += EditorGUIUtility.labelWidth + i * oneValueWidth;
351 valueRects[i].width = oneValueWidth;
352 }
353 EditorGUI.LabelField(labelRect, label);
354 int indent = EditorGUI.indentLevel;
355 EditorGUI.indentLevel = 0; //be at left of rects
356 index = EditorGUI.IntPopup(valueRects[0], index, field.enumNames, field.indexes);
357 value = field.enumValues[index];
358 using (new EditorGUI.DisabledScope(true))
359 {
360 for (int i = 0; i < field.historyDepth; i++)
361 EditorGUI.IntPopup(valueRects[i + 1], field.GetHistoryValue(i), field.enumNames, field.indexes);
362 }
363 EditorGUI.indentLevel = indent;
364
365 value = field.enumValues[index];
366 }
367
368 return value;
369 }
370 }
371
372 /// <summary>
373 /// Builtin Drawer for Bitfield Debug Items.
374 /// </summary>
375 [DebugUIDrawer(typeof(DebugUI.BitField))]
376 public sealed class DebugUIDrawerBitField : DebugUIFieldDrawer<Enum, DebugUI.BitField, DebugStateFlags>
377 {
378 /// <summary>
379 /// Does the field of the given type
380 /// </summary>
381 /// <param name="rect">The rect to draw the field</param>
382 /// <param name="label">The label for the field</param>
383 /// <param name="field">The field</param>
384 /// <param name="state">The state</param>
385 /// <returns>The current value from the UI</returns>
386 protected override Enum DoGUI(Rect rect, GUIContent label, DebugUI.BitField field, DebugStateFlags state)
387 {
388 Enum value = field.GetValue();
389
390 // Skip first element (with value 0) because EditorGUI.MaskField adds a 'Nothing' field anyway
391 var enumNames = new string[field.enumNames.Length - 1];
392 for (int i = 0; i < enumNames.Length; i++)
393 enumNames[i] = field.enumNames[i + 1].text;
394 var index = EditorGUI.MaskField(rect, label, (int)Convert.ToInt32(value), enumNames);
395 value = Enum.Parse(value.GetType(), index.ToString()) as Enum;
396
397 return value;
398 }
399 }
400
401
402 /// <summary>
403 /// Builtin Drawer for Maskfield Debug Items.
404 /// </summary>
405 [DebugUIDrawer(typeof(DebugUI.MaskField))]
406 public sealed class DebugUIDrawerMaskField : DebugUIFieldDrawer<uint, DebugUI.MaskField, DebugStateUInt>
407 {
408 /// <summary>
409 /// Does the field of the given type
410 /// </summary>
411 /// <param name="rect">The rect to draw the field</param>
412 /// <param name="label">The label for the field</param>
413 /// <param name="field">The field</param>
414 /// <param name="state">The state</param>
415 /// <returns>The current value from the UI</returns>
416 protected override uint DoGUI(Rect rect, GUIContent label, DebugUI.MaskField field, DebugStateUInt state)
417 {
418 uint value = field.GetValue();
419
420 var enumNames = new string[field.enumNames.Length];
421 for (int i = 0; i < enumNames.Length; i++)
422 enumNames[i] = field.enumNames[i].text;
423 var mask = EditorGUI.MaskField(rect, label, (int)value, enumNames);
424
425 return (uint)mask;
426 }
427 }
428
429 /// <summary>
430 /// Builtin Drawer for Foldout Debug Items.
431 /// </summary>
432 [DebugUIDrawer(typeof(DebugUI.Foldout))]
433 public sealed class DebugUIDrawerFoldout : DebugUIDrawer
434 {
435 const int k_HeaderVerticalMargin = 2;
436 static void DisplayColumns(Rect drawRect, List<GUIContent> rowContents)
437 {
438 drawRect.x += EditorGUIUtility.labelWidth;
439 drawRect.width = DebugWindow.Styles.foldoutColumnWidth;
440
441 int indent = EditorGUI.indentLevel;
442 EditorGUI.indentLevel = 0; //be at left of rects
443 for (int i = 0; i < rowContents.Count; i++)
444 {
445 EditorGUI.LabelField(drawRect, rowContents[i], EditorStyles.miniBoldLabel);
446
447 // Offset the rect to the next possible column
448 drawRect.x += DebugWindow.Styles.foldoutColumnWidth;
449 }
450 EditorGUI.indentLevel = indent;
451 }
452
453 /// <summary>
454 /// Implement this to execute processing before UI rendering.
455 /// </summary>
456 /// <param name="widget">Widget that is going to be rendered.</param>
457 /// <param name="state">Debug State associated with the Debug Item.</param>
458 public override void Begin(DebugUI.Widget widget, DebugState state)
459 {
460 var w = Cast<DebugUI.Foldout>(widget);
461 var s = Cast<DebugStateBool>(state);
462
463 var title = EditorGUIUtility.TrTextContent(w.displayName, w.tooltip);
464
465 Action<GenericMenu> fillContextMenuAction = null;
466
467 if (w.contextMenuItems != null)
468 {
469 fillContextMenuAction = menu =>
470 {
471 foreach (var item in w.contextMenuItems)
472 {
473 menu.AddItem(EditorGUIUtility.TrTextContent(item.displayName), false, () => item.action.Invoke());
474 }
475 };
476 }
477
478 bool previousValue = (bool)w.GetValue();
479 bool value = CoreEditorUtils.DrawHeaderFoldout(title, previousValue, isTitleHeader: w.isHeader, customMenuContextAction: fillContextMenuAction);
480 if (previousValue != value)
481 Apply(w, s, value);
482
483 EditorGUI.indentLevel++;
484 }
485
486 /// <summary>
487 /// OnGUI implementation for Foldout DebugUIDrawer.
488 /// </summary>
489 /// <param name="widget">DebugUI Widget.</param>
490 /// <param name="state">Debug State associated with the Debug Item.</param>
491 /// <returns>The state of the widget.</returns>
492 public override bool OnGUI(DebugUI.Widget widget, DebugState state)
493 {
494 var w = Cast<DebugUI.Foldout>(widget);
495 if (w.opened && w.columnLabels != null)
496 {
497 var drawRect = PrepareControlRect(EditorGUIUtility.singleLineHeight);
498 drawRect.x = 0;
499 DisplayColumns(drawRect, w.rowContents);
500 }
501 return w.opened;
502 }
503
504 /// <summary>
505 /// End implementation for Foldout DebugUIDrawer.
506 /// </summary>
507 /// <param name="widget">DebugUI Widget.</param>
508 /// <param name="state">Debug State associated with the Debug Item.</param>
509 public override void End(DebugUI.Widget widget, DebugState state)
510 {
511 EditorGUI.indentLevel--;
512 var w = Cast<DebugUI.Foldout>(widget);
513 if (w.isHeader)
514 GUILayout.Space(k_HeaderVerticalMargin);
515 }
516 }
517
518 /// <summary>
519 /// Builtin Drawer for Color Debug Items.
520 /// </summary>
521 [DebugUIDrawer(typeof(DebugUI.ColorField))]
522 public sealed class DebugUIDrawerColorField : DebugUIFieldDrawer<Color, DebugUI.ColorField, DebugStateColor>
523 {
524 /// <summary>
525 /// Does the field of the given type
526 /// </summary>
527 /// <param name="rect">The rect to draw the field</param>
528 /// <param name="label">The label for the field</param>
529 /// <param name="field">The field</param>
530 /// <param name="state">The state</param>
531 /// <returns>The current value from the UI</returns>
532 protected override Color DoGUI(Rect rect, GUIContent label, DebugUI.ColorField field, DebugStateColor state)
533 {
534 return EditorGUI.ColorField(rect, label, field.GetValue(), field.showPicker, field.showAlpha, field.hdr);
535 }
536 }
537
538 /// <summary>
539 /// Builtin Drawer for Vector2 Debug Items.
540 /// </summary>
541 [DebugUIDrawer(typeof(DebugUI.Vector2Field))]
542 public sealed class DebugUIDrawerVector2Field : DebugUIFieldDrawer<Vector2, DebugUI.Vector2Field, DebugStateVector2>
543 {
544 /// <summary>
545 /// Does the field of the given type
546 /// </summary>
547 /// <param name="rect">The rect to draw the field</param>
548 /// <param name="label">The label for the field</param>
549 /// <param name="field">The field</param>
550 /// <param name="state">The state</param>
551 /// <returns>The current value from the UI</returns>
552 protected override Vector2 DoGUI(Rect rect, GUIContent label, DebugUI.Vector2Field field, DebugStateVector2 state)
553 {
554 return EditorGUILayout.Vector2Field(label, field.GetValue());
555 }
556 }
557
558 /// <summary>
559 /// Builtin Drawer for Vector3 Debug Items.
560 /// </summary>
561 [DebugUIDrawer(typeof(DebugUI.Vector3Field))]
562 public sealed class DebugUIDrawerVector3Field : DebugUIFieldDrawer<Vector3, DebugUI.Vector3Field, DebugStateVector3>
563 {
564 /// <summary>
565 /// Does the field of the given type
566 /// </summary>
567 /// <param name="rect">The rect to draw the field</param>
568 /// <param name="label">The label for the field</param>
569 /// <param name="field">The field</param>
570 /// <param name="state">The state</param>
571 /// <returns>The current value from the UI</returns>
572 protected override Vector3 DoGUI(Rect rect, GUIContent label, DebugUI.Vector3Field field, DebugStateVector3 state)
573 {
574 return EditorGUILayout.Vector3Field(label, field.GetValue());
575 }
576 }
577
578 /// <summary>
579 /// Builtin Drawer for Vector4 Debug Items.
580 /// </summary>
581 [DebugUIDrawer(typeof(DebugUI.Vector4Field))]
582 public sealed class DebugUIDrawerVector4Field : DebugUIFieldDrawer<Vector4, DebugUI.Vector4Field, DebugStateVector4>
583 {
584 /// <summary>
585 /// Does the field of the given type
586 /// </summary>
587 /// <param name="rect">The rect to draw the field</param>
588 /// <param name="label">The label for the field</param>
589 /// <param name="field">The field</param>
590 /// <param name="state">The state</param>
591 /// <returns>The current value from the UI</returns>
592 protected override Vector4 DoGUI(Rect rect, GUIContent label, DebugUI.Vector4Field field, DebugStateVector4 state)
593 {
594 return EditorGUILayout.Vector4Field(label, field.GetValue());
595 }
596 }
597
598 /// <summary>
599 /// Builtin Drawer for <see cref="DebugUI.ObjectField"/> items.
600 /// </summary>
601 [DebugUIDrawer(typeof(DebugUI.ObjectField))]
602 public sealed class DebugUIDrawerObjectField : DebugUIFieldDrawer<UnityEngine.Object, DebugUI.ObjectField, DebugStateObject>
603 {
604 /// <summary>
605 /// Does the field of the given type
606 /// </summary>
607 /// <param name="rect">The rect to draw the field</param>
608 /// <param name="label">The label for the field</param>
609 /// <param name="field">The field</param>
610 /// <param name="state">The state</param>
611 /// <returns>The current value from the UI</returns>
612 protected override UnityEngine.Object DoGUI(Rect rect, GUIContent label, DebugUI.ObjectField field, DebugStateObject state)
613 {
614 return EditorGUI.ObjectField(rect, label, field.GetValue(), field.type, true);
615 }
616 }
617
618 /// <summary>
619 /// Builtin Drawer for <see cref="DebugUI.ObjectListField"/> Items.
620 /// </summary>
621 [DebugUIDrawer(typeof(DebugUI.ObjectListField))]
622 public sealed class DebugUIDrawerObjectListField : DebugUIDrawer
623 {
624 /// <summary>
625 /// Implement this to execute UI rendering.
626 /// </summary>
627 /// <param name="widget">Widget that is going to be rendered.</param>
628 /// <param name="state">Debug State associated with the Debug Item.</param>
629 /// <returns>Returns the state of the widget.</returns>
630 public override bool OnGUI(DebugUI.Widget widget, DebugState state)
631 {
632 var w = Cast<DebugUI.ObjectListField>(widget);
633 var objects = w.GetValue();
634
635 float height = Math.Max(objects != null ? objects.Length : 0, 1) * DebugWindow.Styles.singleRowHeight;
636 var rect = PrepareControlRect(height);
637
638 rect = EditorGUI.PrefixLabel(rect, EditorGUIUtility.TrTextContent(widget.displayName));
639
640 EditorGUI.BeginChangeCheck();
641 DoObjectList(rect, w, objects);
642 if (EditorGUI.EndChangeCheck())
643 Apply(w, state, objects);
644
645 return true;
646 }
647
648 internal static void DoObjectList(Rect rect, DebugUI.ObjectListField widget, UnityEngine.Object[] objects)
649 {
650 if (objects == null || objects.Length == 0)
651 {
652 EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContent("Empty"));
653 return;
654 }
655
656 rect.height = EditorGUIUtility.singleLineHeight;
657 for (int i = 0; i < objects.Length; i++)
658 {
659 objects[i] = EditorGUI.ObjectField(rect, GUIContent.none, objects[i], widget.type, true);
660 rect.y += DebugWindow.Styles.singleRowHeight;
661 }
662 }
663 }
664
665 /// <summary>
666 /// Builtin Drawer for MessageBox Items.
667 /// </summary>
668 [DebugUIDrawer(typeof(DebugUI.MessageBox))]
669 public sealed class DebugUIDrawerMessageBox : DebugUIDrawer
670 {
671 /// <summary>
672 /// Implement this to execute UI rendering.
673 /// </summary>
674 /// <param name="widget">Widget that is going to be rendered.</param>
675 /// <param name="state">Debug State associated with the Debug Item.</param>
676 /// <returns>Returns the state of the widget.</returns>
677 public override bool OnGUI(DebugUI.Widget widget, DebugState state)
678 {
679 var w = Cast<DebugUI.MessageBox>(widget);
680
681 var type = w.style switch
682 {
683 DebugUI.MessageBox.Style.Info => MessageType.Info,
684 DebugUI.MessageBox.Style.Warning => MessageType.Warning,
685 DebugUI.MessageBox.Style.Error => MessageType.Error,
686 _ => MessageType.None
687 };
688
689 EditorGUILayout.HelpBox(w.message, type);
690
691 return true;
692 }
693 }
694
695 /// <summary>
696 /// Builtin Drawer for Container Debug Items.
697 /// </summary>
698 [DebugUIDrawer(typeof(DebugUI.Container))]
699 public sealed class DebugUIDrawerContainer : DebugUIDrawer
700 {
701 /// <summary>
702 /// Implement this to execute processing before UI rendering.
703 /// </summary>
704 /// <param name="widget">Widget that is going to be rendered.</param>
705 /// <param name="state">Debug State associated with the Debug Item.</param>
706 public override void Begin(DebugUI.Widget widget, DebugState state)
707 {
708 var w = Cast<DebugUI.Container>(widget);
709 if (!w.hideDisplayName)
710 EditorGUILayout.LabelField(EditorGUIUtility.TrTextContent(widget.displayName, widget.tooltip), EditorStyles.boldLabel);
711
712 EditorGUI.indentLevel++;
713 }
714
715 /// <summary>
716 /// Implement this to execute processing after UI rendering.
717 /// </summary>
718 /// <param name="widget">Widget that is going to be rendered.</param>
719 /// <param name="state">Debug State associated with the Debug Item.</param>
720 public override void End(DebugUI.Widget widget, DebugState state)
721 {
722 EditorGUI.indentLevel--;
723 }
724 }
725
726 /// <summary>
727 /// Builtin Drawer for Horizontal Box Debug Items.
728 /// </summary>
729 [DebugUIDrawer(typeof(DebugUI.HBox))]
730 public sealed class DebugUIDrawerHBox : DebugUIDrawer
731 {
732 /// <summary>
733 /// Implement this to execute processing before UI rendering.
734 /// </summary>
735 /// <param name="widget">Widget that is going to be rendered.</param>
736 /// <param name="state">Debug State associated with the Debug Item.</param>
737 public override void Begin(DebugUI.Widget widget, DebugState state)
738 {
739 EditorGUILayout.BeginHorizontal();
740 }
741 /// <summary>
742 /// Implement this to execute processing after UI rendering.
743 /// </summary>
744 /// <param name="widget">Widget that is going to be rendered.</param>
745 /// <param name="state">Debug State associated with the Debug Item.</param>
746 public override void End(DebugUI.Widget widget, DebugState state)
747 {
748 EditorGUILayout.EndHorizontal();
749 }
750 }
751
752 /// <summary>
753 /// Builtin Drawer for Vertical Box Debug Items.
754 /// </summary>
755 [DebugUIDrawer(typeof(DebugUI.VBox))]
756 public sealed class DebugUIDrawerVBox : DebugUIDrawer
757 {
758 /// <summary>
759 /// Implement this to execute processing before UI rendering.
760 /// </summary>
761 /// <param name="widget">Widget that is going to be rendered.</param>
762 /// <param name="state">Debug State associated with the Debug Item.</param>
763 public override void Begin(DebugUI.Widget widget, DebugState state)
764 {
765 EditorGUILayout.BeginVertical();
766 }
767
768 /// <summary>
769 /// Implement this to execute processing after UI rendering.
770 /// </summary>
771 /// <param name="widget">Widget that is going to be rendered.</param>
772 /// <param name="state">Debug State associated with the Debug Item.</param>
773 public override void End(DebugUI.Widget widget, DebugState state)
774 {
775 EditorGUILayout.EndVertical();
776 }
777 }
778
779 /// <summary>
780 /// Builtin Drawer for Table Debug Items.
781 /// </summary>
782 [DebugUIDrawer(typeof(DebugUI.Table))]
783 public sealed class DebugUIDrawerTable : DebugUIDrawer
784 {
785 /// <summary>
786 /// Implement this to execute UI rendering.
787 /// </summary>
788 /// <param name="widget">Widget that is going to be rendered.</param>
789 /// <param name="state">Debug State associated with the Debug Item.</param>
790 /// <returns>Returns the state of the widget.</returns>
791 public override bool OnGUI(DebugUI.Widget widget, DebugState state)
792 {
793 const float k_ScrollBarHeight = 15;
794
795 var w = Cast<DebugUI.Table>(widget);
796 var header = w.Header;
797 var visible = header.state.visibleColumns;
798
799 float contentHeight = 0.0f;
800 foreach (DebugUI.Table.Row row in w.children)
801 contentHeight += row != null ? GetRowHeight(row, visible) : EditorGUIUtility.singleLineHeight;
802
803 // Put some space before the array
804 PrepareControlRect(EditorGUIUtility.singleLineHeight * 0.5f);
805
806 // Draw an outline around the table
807 var rect = EditorGUI.IndentedRect(PrepareControlRect(header.height + contentHeight + k_ScrollBarHeight));
808 rect = DrawOutline(rect);
809
810 // Compute rects
811 var headerRect = new Rect(rect.x, rect.y, rect.width, header.height);
812 var contentRect = new Rect(rect.x, headerRect.yMax, rect.width, rect.height - headerRect.height);
813 var viewRect = new Rect(contentRect.x, contentRect.y, header.state.widthOfAllVisibleColumns, contentRect.height);
814 var rowRect = contentRect;
815 viewRect.height -= k_ScrollBarHeight;
816
817 // Show header
818 header.OnGUI(headerRect, Mathf.Max(w.scroll.x, 0f));
819
820 // Show array content
821 w.scroll = GUI.BeginScrollView(contentRect, w.scroll, viewRect);
822 {
823 var columns = header.state.columns;
824 for (int r = 0; r < w.children.Count; r++)
825 {
826 var row = Cast<DebugUI.Container>(w.children[r]);
827 rowRect.x = contentRect.x;
828 rowRect.width = columns[0].width;
829 rowRect.height = (row is DebugUI.Table.Row tableRow) ? GetRowHeight(tableRow, visible) : EditorGUIUtility.singleLineHeight;
830
831 rowRect.xMin += 2;
832 rowRect.xMax -= 2;
833 EditorGUI.LabelField(rowRect, GUIContent.none, EditorGUIUtility.TrTextContent(row.displayName), DebugWindow.Styles.centeredLeft);
834 rowRect.xMin -= 2;
835 rowRect.xMax += 2;
836
837 using (new EditorGUI.DisabledScope(w.isReadOnly))
838 {
839 for (int c = 1; c < visible.Length; c++)
840 {
841 rowRect.x += rowRect.width;
842 rowRect.width = columns[visible[c]].width;
843 if (!row.isHidden)
844 DisplayChild(rowRect, row.children[visible[c] - 1]);
845 }
846 rowRect.y += rowRect.height;
847 }
848 }
849 }
850 GUI.EndScrollView(false);
851
852 return false;
853 }
854
855 internal float GetRowHeight(DebugUI.Table.Row row, int[] visibleColumns)
856 {
857 float height = EditorGUIUtility.singleLineHeight;
858 for (int c = 1; c < visibleColumns.Length; c++)
859 {
860 var child = row.children[visibleColumns[c] - 1] as DebugUI.ObjectListField;
861 if (child == null || child.GetValue() == null)
862 continue;
863 height = Mathf.Max(height, child.GetValue().Length * DebugWindow.Styles.singleRowHeight);
864 }
865 return height;
866 }
867
868 internal Rect DrawOutline(Rect rect)
869 {
870 if (Event.current.type != EventType.Repaint)
871 return rect;
872
873 float size = 1.0f;
874 var color = EditorGUIUtility.isProSkin ? new Color(0.12f, 0.12f, 0.12f, 1.333f) : new Color(0.6f, 0.6f, 0.6f, 1.333f);
875
876 Color orgColor = GUI.color;
877 GUI.color = GUI.color * color;
878 GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, size), EditorGUIUtility.whiteTexture);
879 GUI.DrawTexture(new Rect(rect.x, rect.yMax - size, rect.width, size), EditorGUIUtility.whiteTexture);
880 GUI.DrawTexture(new Rect(rect.x, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
881 GUI.DrawTexture(new Rect(rect.xMax - size, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
882
883 GUI.color = orgColor;
884 return new Rect(rect.x + size, rect.y + size, rect.width - 2 * size, rect.height - 2 * size);
885 }
886
887 internal void DisplayChild(Rect rect, DebugUI.Widget child)
888 {
889 rect.xMin += 2;
890 rect.xMax -= 2;
891
892 if (child.isHidden)
893 {
894 EditorGUI.LabelField(rect, "-");
895 }
896 else
897 {
898 if (child.GetType() == typeof(DebugUI.Value))
899 {
900 var widget = Cast<DebugUI.Value>(child);
901 EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContent(widget.GetValue().ToString()));
902 }
903 else if (child.GetType() == typeof(DebugUI.ColorField))
904 {
905 var widget = Cast<DebugUI.ColorField>(child);
906 EditorGUI.ColorField(rect, GUIContent.none, widget.GetValue(), false, widget.showAlpha, widget.hdr);
907 }
908 else if (child.GetType() == typeof(DebugUI.BoolField))
909 {
910 var widget = Cast<DebugUI.BoolField>(child);
911 EditorGUI.Toggle(rect, GUIContent.none, widget.GetValue());
912 }
913 else if (child.GetType() == typeof(DebugUI.ObjectField))
914 {
915 var widget = Cast<DebugUI.ObjectField>(child);
916 EditorGUI.ObjectField(rect, GUIContent.none, widget.GetValue(), widget.type, true);
917 }
918 else if (child.GetType() == typeof(DebugUI.ObjectListField))
919 {
920 var widget = Cast<DebugUI.ObjectListField>(child);
921 DebugUIDrawerObjectListField.DoObjectList(rect, widget, widget.GetValue());
922 }
923 }
924 }
925 }
926}