A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using System.Text; 4using UnityEditor.Rendering.Analytics; 5using UnityEngine; 6using UnityEngine.Rendering; 7 8namespace UnityEditor.Rendering 9{ 10 /// <summary> 11 /// Attribute specifying wich type of Debug Item should this drawer be used with. 12 /// </summary> 13 public class DebugUIDrawerAttribute : Attribute 14 { 15 internal readonly Type type; 16 17 /// <summary> 18 /// Constructor for DebugUIDraw Attribute 19 /// </summary> 20 /// <param name="type">Type of Debug Item this draw should be used with.</param> 21 public DebugUIDrawerAttribute(Type type) 22 { 23 this.type = type; 24 } 25 } 26 27 /// <summary> 28 /// Debug Item Drawer 29 /// </summary> 30 public class DebugUIDrawer 31 { 32 /// <summary> 33 /// Cast into the proper type. 34 /// </summary> 35 /// <typeparam name="T">Type of the drawer</typeparam> 36 /// <param name="o">Object to be cast</param> 37 /// <returns>Returns o cast to type T</returns> 38 protected T Cast<T>(object o) 39 where T : class 40 { 41 if (o == null) return null; 42 43 if (o is T casted) 44 return casted; 45 46 StringBuilder info = new StringBuilder("Cast Exception:"); 47 switch (o) 48 { 49 case DebugUI.Widget value: 50 info.AppendLine($"Query Path : {value.queryPath}"); 51 break; 52 case DebugState state: 53 info.AppendLine($"Query Path : {state.queryPath}"); 54 break; 55 } 56 info.AppendLine($"Object to Cast Type : {o.GetType().AssemblyQualifiedName}"); 57 info.AppendLine($"Target Cast Type : {typeof(T).AssemblyQualifiedName}"); 58 59 throw new InvalidCastException(info.ToString()); 60 } 61 62 /// <summary> 63 /// Implement this to execute processing before UI rendering. 64 /// </summary> 65 /// <param name="widget">Widget that is going to be rendered.</param> 66 /// <param name="state">Debug State associated with the Debug Item.</param> 67 public virtual void Begin(DebugUI.Widget widget, DebugState state) 68 { } 69 70 /// <summary> 71 /// Implement this to execute UI rendering. 72 /// </summary> 73 /// <param name="widget">Widget that is going to be rendered.</param> 74 /// <param name="state">Debug State associated with the Debug Item.</param> 75 /// <returns>Returns the state of the widget.</returns> 76 public virtual bool OnGUI(DebugUI.Widget widget, DebugState state) 77 { 78 return true; 79 } 80 81 /// <summary> 82 /// Implement this to execute processing after UI rendering. 83 /// </summary> 84 /// <param name="widget">Widget that is going to be rendered.</param> 85 /// <param name="state">Debug State associated with the Debug Item.</param> 86 public virtual void End(DebugUI.Widget widget, DebugState state) 87 { } 88 89 /// <summary> 90 /// Applies a value to the widget and the Debug State of the Debug Item. 91 /// </summary> 92 /// <param name="widget">Debug Item widget.</param> 93 /// <param name="state">Debug State associated with the Debug Item</param> 94 /// <param name="value">Input value.</param> 95 protected void Apply(DebugUI.IValueField widget, DebugState state, object value) 96 { 97 Undo.RegisterCompleteObjectUndo(state, $"Modified Value '{state.queryPath}'"); 98 state.SetValue(value, widget); 99 widget.SetValue(value); 100 EditorUtility.SetDirty(state); 101 DebugState.m_CurrentDirtyState = state; 102 UnityEditorInternal.InternalEditorUtility.RepaintAllViews(); 103 } 104 105 /// <summary> 106 /// Prepares the rendering Rect of the Drawer. 107 /// </summary> 108 /// <param name="height">Height of the rect.</param> 109 /// <param name="fullWidth">Whether to reserve full width for the element.</param> 110 /// <returns>Appropriate Rect for drawing.</returns> 111 protected Rect PrepareControlRect(float height = -1, bool fullWidth = false) 112 { 113 if (height < 0) 114 height = EditorGUIUtility.singleLineHeight; 115 var rect = GUILayoutUtility.GetRect(1f, 1f, height, height); 116 117 const float paddingLeft = 4f; 118 rect.width -= paddingLeft; 119 rect.xMin += paddingLeft; 120 121 EditorGUIUtility.labelWidth = fullWidth ? rect.width : rect.width / 2f; 122 123 return rect; 124 } 125 } 126 127 /// <summary> 128 /// Common class to help drawing fields 129 /// </summary> 130 /// <typeparam name="TValue">The internal value of the field</typeparam> 131 /// <typeparam name="TField">The type of the field widget</typeparam> 132 /// <typeparam name="TState">The state of the field</typeparam> 133 public abstract class DebugUIFieldDrawer<TValue, TField, TState> : DebugUIDrawer 134 where TField : DebugUI.Field<TValue> 135 where TState : DebugState 136 { 137 private TValue value { get; set; } 138 139 /// <summary> 140 /// Implement this to execute processing before UI rendering. 141 /// </summary> 142 /// <param name="widget">Widget that is going to be rendered.</param> 143 /// <param name="state">Debug State associated with the Debug Item.</param> 144 public override void Begin(DebugUI.Widget widget, DebugState state) 145 { 146 EditorGUI.BeginChangeCheck(); 147 } 148 149 /// <summary> 150 /// Implement this to execute UI rendering. 151 /// </summary> 152 /// <param name="widget">Widget that is going to be rendered.</param> 153 /// <param name="state">Debug State associated with the Debug Item.</param> 154 /// <returns>Returns the state of the widget.</returns> 155 public override bool OnGUI(DebugUI.Widget widget, DebugState state) 156 { 157 value = DoGUI( 158 PrepareControlRect(), 159 EditorGUIUtility.TrTextContent(widget.displayName, widget.tooltip), 160 Cast<TField>(widget), 161 Cast<TState>(state) 162 ); 163 164 return true; 165 } 166 167 /// <summary> 168 /// Does the field of the given type 169 /// </summary> 170 /// <param name="rect">The rect to draw the field</param> 171 /// <param name="label">The label for the field</param> 172 /// <param name="field">The field</param> 173 /// <param name="state">The state</param> 174 /// <returns>The current value from the UI</returns> 175 protected abstract TValue DoGUI(Rect rect, GUIContent label, TField field, TState state); 176 177 struct WidgetChangedAction 178 { 179 public string query_path; 180 public TValue previous_value; 181 public TValue new_value; 182 } 183 184 static List<WidgetChangedAction> s_Analytic = new List<WidgetChangedAction>(); 185 /// <summary> 186 /// Implement this to execute processing after UI rendering. 187 /// </summary> 188 /// <param name="widget">Widget that is going to be rendered.</param> 189 /// <param name="state">Debug State associated with the Debug Item.</param> 190 public override void End(DebugUI.Widget widget, DebugState state) 191 { 192 if (EditorGUI.EndChangeCheck()) 193 { 194 var w = Cast<TField>(widget); 195 var s = Cast<TState>(state); 196 197 s_Analytic.Clear(); 198 s_Analytic.Add(new() 199 { 200 query_path = widget.queryPath, 201 previous_value = w.GetValue(), 202 new_value = value 203 }); 204 205 Apply(w, s, value); 206 GraphicsToolUsageAnalytic.ActionPerformed<DebugWindow>("Widget Value Changed", s_Analytic.ToNestedColumn()); 207 } 208 } 209 } 210 211 /// <summary> 212 /// Common class to help drawing widgets 213 /// </summary> 214 /// <typeparam name="TWidget">The widget</typeparam> 215 public abstract class DebugUIWidgetDrawer<TWidget> : DebugUIDrawer 216 where TWidget : DebugUI.Widget 217 { 218 /// <summary> 219 /// Implement this to execute processing before UI rendering. 220 /// </summary> 221 /// <param name="widget">Widget that is going to be rendered.</param> 222 /// <param name="state">Debug State associated with the Debug Item.</param> 223 public override void Begin(DebugUI.Widget widget, DebugState state) 224 { 225 } 226 227 /// <summary> 228 /// Implement this to execute UI rendering. 229 /// </summary> 230 /// <param name="widget">Widget that is going to be rendered.</param> 231 /// <param name="state">Debug State associated with the Debug Item.</param> 232 /// <returns>Returns the state of the widget.</returns> 233 public override bool OnGUI(DebugUI.Widget widget, DebugState state) 234 { 235 DoGUI( 236 PrepareControlRect(), 237 EditorGUIUtility.TrTextContent(widget.displayName, widget.tooltip), 238 Cast<TWidget>(widget) 239 ); 240 241 return true; 242 } 243 244 /// <summary> 245 /// Does the field of the given type 246 /// </summary> 247 /// <param name="rect">The rect to draw the field</param> 248 /// <param name="label">The label for the field</param> 249 /// <param name="w">The widget</param> 250 protected abstract void DoGUI(Rect rect, GUIContent label, TWidget w); 251 252 /// <summary> 253 /// Implement this to execute processing after UI rendering. 254 /// </summary> 255 /// <param name="widget">Widget that is going to be rendered.</param> 256 /// <param name="state">Debug State associated with the Debug Item.</param> 257 public override void End(DebugUI.Widget widget, DebugState state) 258 { 259 } 260 } 261}