testss
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEditor.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialized state of a Debug Item.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class DebugState : ScriptableObject
|
||||
{
|
||||
/// <summary>
|
||||
/// Path of the Debug Item.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected string m_QueryPath;
|
||||
|
||||
// We need this to keep track of the state modified in the current frame.
|
||||
// This helps reduces the cost of re-applying states to original widgets and is also needed
|
||||
// when two states point to the same value (e.g. when using split enums like HDRP does for
|
||||
// the `fullscreenDebugMode`.
|
||||
internal static DebugState m_CurrentDirtyState;
|
||||
|
||||
/// <summary>
|
||||
/// Path of the Debug Item.
|
||||
/// </summary>
|
||||
public string queryPath
|
||||
{
|
||||
get { return m_QueryPath; }
|
||||
internal set { m_QueryPath = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the Debug Item.
|
||||
/// </summary>
|
||||
/// <returns>Value of the Debug Item.</returns>
|
||||
public abstract object GetValue();
|
||||
|
||||
/// <summary>
|
||||
/// Set the value of the Debug Item.
|
||||
/// </summary>
|
||||
/// <param name="value">Input value.</param>
|
||||
/// <param name="field">Debug Item field.</param>
|
||||
public abstract void SetValue(object value, DebugUI.IValueField field);
|
||||
|
||||
/// <summary>
|
||||
/// OnEnable implementation.
|
||||
/// </summary>
|
||||
public virtual void OnEnable()
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generic serialized state of a Debug Item.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
[Serializable]
|
||||
public class DebugState<T> : DebugState
|
||||
{
|
||||
/// <summary>
|
||||
/// Value of the Debug Item.
|
||||
/// </summary>
|
||||
[SerializeField]
|
||||
protected T m_Value;
|
||||
|
||||
/// <summary>
|
||||
/// Value of the Debug Item
|
||||
/// </summary>
|
||||
public virtual T value
|
||||
{
|
||||
get { return m_Value; }
|
||||
set { m_Value = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value of the Debug Item.
|
||||
/// </summary>
|
||||
/// <returns>Value of the Debug Item.</returns>
|
||||
public override object GetValue()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the value of the Debug Item.
|
||||
/// </summary>
|
||||
/// <param name="value">Input value.</param>
|
||||
/// <param name="field">Debug Item field.</param>
|
||||
public override void SetValue(object value, DebugUI.IValueField field)
|
||||
{
|
||||
this.value = (T)field.ValidateValue(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the hash code of the Debug Item.
|
||||
/// </summary>
|
||||
/// <returns>Hash code of the Debug Item</returns>
|
||||
public override int GetHashCode()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 13;
|
||||
hash = hash * 23 + m_QueryPath.GetHashCode();
|
||||
hash = hash * 23 + m_Value.GetHashCode();
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attribute specifying which types should be save as this Debug State.
|
||||
/// </summary>
|
||||
public sealed class DebugStateAttribute : Attribute
|
||||
{
|
||||
internal readonly Type[] types;
|
||||
|
||||
/// <summary>
|
||||
/// Debug State Attribute constructor
|
||||
/// </summary>
|
||||
/// <param name="types">List of types of the Debug State.</param>
|
||||
public DebugStateAttribute(params Type[] types)
|
||||
{
|
||||
this.types = types;
|
||||
}
|
||||
}
|
||||
|
||||
// Builtins
|
||||
/// <summary>
|
||||
/// Boolean Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.BoolField), typeof(DebugUI.Foldout), typeof(DebugUI.HistoryBoolField))]
|
||||
public sealed class DebugStateBool : DebugState<bool> {}
|
||||
|
||||
/// <summary>
|
||||
/// Integer Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.IntField), typeof(DebugUI.EnumField), typeof(DebugUI.HistoryEnumField))]
|
||||
public sealed class DebugStateInt : DebugState<int> {}
|
||||
|
||||
/// <summary>
|
||||
/// Flags Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.BitField))]
|
||||
public sealed class DebugStateFlags : DebugState<Enum> {}
|
||||
|
||||
/// <summary>
|
||||
/// Unsigned Integer Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.UIntField))]
|
||||
public sealed class DebugStateUInt : DebugState<uint> {}
|
||||
|
||||
/// <summary>
|
||||
/// Float Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.FloatField))]
|
||||
public sealed class DebugStateFloat : DebugState<float> {}
|
||||
|
||||
/// <summary>
|
||||
/// Color Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.ColorField))]
|
||||
public sealed class DebugStateColor : DebugState<Color> {}
|
||||
|
||||
/// <summary>
|
||||
/// Vector2 Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.Vector2Field))]
|
||||
public sealed class DebugStateVector2 : DebugState<Vector2> {}
|
||||
|
||||
/// <summary>
|
||||
/// Vector3 Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.Vector3Field))]
|
||||
public sealed class DebugStateVector3 : DebugState<Vector3> {}
|
||||
|
||||
/// <summary>
|
||||
/// Vector4 Debug State.
|
||||
/// </summary>
|
||||
[Serializable, DebugState(typeof(DebugUI.Vector4Field))]
|
||||
public sealed class DebugStateVector4 : DebugState<Vector4> {}
|
||||
}
|
@@ -0,0 +1,758 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEditor.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Value Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Value))]
|
||||
public sealed class DebugUIDrawerValue : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Value DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Value>(widget);
|
||||
var rect = PrepareControlRect();
|
||||
EditorGUI.LabelField(rect, EditorGUIUtility.TrTextContent(w.displayName), EditorGUIUtility.TrTextContent(w.GetValue().ToString()));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Button Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Button))]
|
||||
public sealed class DebugUIDrawerButton : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Button DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Button>(widget);
|
||||
|
||||
var rect = EditorGUI.IndentedRect(EditorGUILayout.GetControlRect());
|
||||
if (GUI.Button(rect, w.displayName, EditorStyles.miniButton))
|
||||
{
|
||||
if (w.action != null)
|
||||
w.action();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Boolean Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.BoolField))]
|
||||
public sealed class DebugUIDrawerBoolField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Boolean DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.BoolField>(widget);
|
||||
var s = Cast<DebugStateBool>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var rect = PrepareControlRect();
|
||||
bool value = EditorGUI.Toggle(rect, EditorGUIUtility.TrTextContent(w.displayName), w.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for History Boolean Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.HistoryBoolField))]
|
||||
public sealed class DebugUIDrawerHistoryBoolField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for History Boolean DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.HistoryBoolField>(widget);
|
||||
var s = Cast<DebugStateBool>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var rect = PrepareControlRect();
|
||||
var labelRect = rect;
|
||||
labelRect.width = EditorGUIUtility.labelWidth;
|
||||
const int oneValueWidth = 70;
|
||||
var valueRects = new Rect[w.historyDepth + 1];
|
||||
for (int i = 0; i < w.historyDepth + 1; i++)
|
||||
{
|
||||
valueRects[i] = rect;
|
||||
valueRects[i].x += EditorGUIUtility.labelWidth + i * oneValueWidth;
|
||||
valueRects[i].width = oneValueWidth;
|
||||
}
|
||||
EditorGUI.LabelField(labelRect, EditorGUIUtility.TrTextContent(w.displayName));
|
||||
int indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0; //be at left of rects
|
||||
bool value = EditorGUI.Toggle(valueRects[0], w.GetValue());
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
for (int i = 0; i < w.historyDepth; i++)
|
||||
EditorGUI.Toggle(valueRects[i + 1], w.GetHistoryValue(i));
|
||||
}
|
||||
EditorGUI.indentLevel = indent;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Integer Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.IntField))]
|
||||
public sealed class DebugUIDrawerIntField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Integer DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.IntField>(widget);
|
||||
var s = Cast<DebugStateInt>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var rect = PrepareControlRect();
|
||||
int value = w.min != null && w.max != null
|
||||
? EditorGUI.IntSlider(rect, EditorGUIUtility.TrTextContent(w.displayName), w.GetValue(), w.min(), w.max())
|
||||
: EditorGUI.IntField(rect, EditorGUIUtility.TrTextContent(w.displayName), w.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Unsigned Integer Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.UIntField))]
|
||||
public sealed class DebugUIDrawerUIntField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Unsigned Integer DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.UIntField>(widget);
|
||||
var s = Cast<DebugStateUInt>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
// No UIntField so we need to max to 0 ourselves or the value will wrap around
|
||||
var rect = PrepareControlRect();
|
||||
int tmp = w.min != null && w.max != null
|
||||
? EditorGUI.IntSlider(rect, EditorGUIUtility.TrTextContent(w.displayName), Mathf.Max(0, (int)w.GetValue()), Mathf.Max(0, (int)w.min()), Mathf.Max(0, (int)w.max()))
|
||||
: EditorGUI.IntField(rect, EditorGUIUtility.TrTextContent(w.displayName), Mathf.Max(0, (int)w.GetValue()));
|
||||
|
||||
uint value = (uint)Mathf.Max(0, tmp);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Float Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.FloatField))]
|
||||
public sealed class DebugUIDrawerFloatField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Float DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.FloatField>(widget);
|
||||
var s = Cast<DebugStateFloat>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var rect = PrepareControlRect();
|
||||
float value = w.min != null && w.max != null
|
||||
? EditorGUI.Slider(rect, EditorGUIUtility.TrTextContent(w.displayName), w.GetValue(), w.min(), w.max())
|
||||
: EditorGUI.FloatField(rect, EditorGUIUtility.TrTextContent(w.displayName), w.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Enum Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.EnumField))]
|
||||
public sealed class DebugUIDrawerEnumField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Enum DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.EnumField>(widget);
|
||||
var s = Cast<DebugStateInt>(state);
|
||||
|
||||
if (w.indexes == null)
|
||||
w.InitIndexes();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
int index = -1;
|
||||
int value = w.GetValue();
|
||||
if (w.enumNames == null || w.enumValues == null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Can't draw an empty enumeration.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var rect = PrepareControlRect();
|
||||
|
||||
index = w.currentIndex;
|
||||
|
||||
// Fallback just in case, we may be handling sub/sectionned enums here
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
index = EditorGUI.IntPopup(rect, EditorGUIUtility.TrTextContent(w.displayName), index, w.enumNames, w.indexes);
|
||||
value = w.enumValues[index];
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Apply(w, s, value);
|
||||
if (index > -1)
|
||||
w.currentIndex = index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for History Enum Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.HistoryEnumField))]
|
||||
public sealed class DebugUIDrawerHistoryEnumField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for History Enum DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.HistoryEnumField>(widget);
|
||||
var s = Cast<DebugStateInt>(state);
|
||||
|
||||
if (w.indexes == null)
|
||||
w.InitIndexes();
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
int index = -1;
|
||||
int value = w.GetValue();
|
||||
if (w.enumNames == null || w.enumValues == null)
|
||||
{
|
||||
EditorGUILayout.LabelField("Can't draw an empty enumeration.");
|
||||
}
|
||||
else
|
||||
{
|
||||
var rect = PrepareControlRect();
|
||||
index = w.currentIndex;
|
||||
|
||||
// Fallback just in case, we may be handling sub/sectionned enums here
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
var labelRect = rect;
|
||||
labelRect.width = EditorGUIUtility.labelWidth;
|
||||
const int oneValueWidth = 70;
|
||||
var valueRects = new Rect[w.historyDepth + 1];
|
||||
for (int i = 0; i < w.historyDepth + 1; i++)
|
||||
{
|
||||
valueRects[i] = rect;
|
||||
valueRects[i].x += EditorGUIUtility.labelWidth + i * oneValueWidth;
|
||||
valueRects[i].width = oneValueWidth;
|
||||
}
|
||||
EditorGUI.LabelField(labelRect, EditorGUIUtility.TrTextContent(w.displayName));
|
||||
int indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0; //be at left of rects
|
||||
index = EditorGUI.IntPopup(valueRects[0], index, w.enumNames, w.indexes);
|
||||
value = w.enumValues[index];
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
for (int i = 0; i < w.historyDepth; i++)
|
||||
EditorGUI.IntPopup(valueRects[i + 1], w.GetHistoryValue(i), w.enumNames, w.indexes);
|
||||
}
|
||||
EditorGUI.indentLevel = indent;
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Apply(w, s, value);
|
||||
if (index > -1)
|
||||
w.currentIndex = index;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Bitfield Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.BitField))]
|
||||
public sealed class DebugUIDrawerBitField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Bitfield DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.BitField>(widget);
|
||||
var s = Cast<DebugStateFlags>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
Enum value = w.GetValue();
|
||||
var rect = PrepareControlRect();
|
||||
|
||||
// Skip first element (with value 0) because EditorGUI.MaskField adds a 'Nothing' field anyway
|
||||
var enumNames = new string[w.enumNames.Length - 1];
|
||||
for (int i = 0; i < enumNames.Length; i++)
|
||||
enumNames[i] = w.enumNames[i + 1].text;
|
||||
var index = EditorGUI.MaskField(rect, EditorGUIUtility.TrTextContent(w.displayName), (int)Convert.ToInt32(value), enumNames);
|
||||
value = Enum.Parse(value.GetType(), index.ToString()) as Enum;
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Foldout Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Foldout))]
|
||||
public sealed class DebugUIDrawerFoldout : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Begin implementation for Foldout DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void Begin(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Foldout>(widget);
|
||||
var s = Cast<DebugStateBool>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
Rect rect = PrepareControlRect();
|
||||
bool value = EditorGUI.Foldout(rect, w.GetValue(), EditorGUIUtility.TrTextContent(w.displayName), true);
|
||||
|
||||
Rect drawRect = GUILayoutUtility.GetLastRect();
|
||||
if (w.columnLabels != null && value)
|
||||
{
|
||||
const int oneColumnWidth = 70;
|
||||
int indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0; //be at left of rects
|
||||
for (int i = 0; i < w.columnLabels.Length; i++)
|
||||
{
|
||||
var columnRect = drawRect;
|
||||
columnRect.x += EditorGUIUtility.labelWidth + i * oneColumnWidth;
|
||||
columnRect.width = oneColumnWidth;
|
||||
EditorGUI.LabelField(columnRect, w.columnLabels[i] ?? "", EditorStyles.miniBoldLabel);
|
||||
}
|
||||
EditorGUI.indentLevel = indent;
|
||||
}
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Foldout DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var s = Cast<DebugStateBool>(state);
|
||||
return s.value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End implementation for Foldout DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void End(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Color Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.ColorField))]
|
||||
public sealed class DebugUIDrawerColorField : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Color DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.ColorField>(widget);
|
||||
var s = Cast<DebugStateColor>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var rect = PrepareControlRect();
|
||||
var value = EditorGUI.ColorField(rect, EditorGUIUtility.TrTextContent(w.displayName), w.GetValue(), w.showPicker, w.showAlpha, w.hdr);
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Vector2 Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Vector2Field))]
|
||||
public sealed class DebugUIDrawerVector2Field : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Vector2 DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Vector2Field>(widget);
|
||||
var s = Cast<DebugStateVector2>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var value = EditorGUILayout.Vector2Field(w.displayName, w.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Vector3 Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Vector3Field))]
|
||||
public sealed class DebugUIDrawerVector3Field : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Vector3 DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Vector3Field>(widget);
|
||||
var s = Cast<DebugStateVector3>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var value = EditorGUILayout.Vector3Field(w.displayName, w.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Vector4 Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Vector4Field))]
|
||||
public sealed class DebugUIDrawerVector4Field : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Vector4 DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Vector4Field>(widget);
|
||||
var s = Cast<DebugStateVector4>(state);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
var value = EditorGUILayout.Vector4Field(w.displayName, w.GetValue());
|
||||
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
Apply(w, s, value);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Container Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Container))]
|
||||
public sealed class DebugUIDrawerContainer : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Begin implementation for Container DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void Begin(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(widget.displayName))
|
||||
EditorGUILayout.LabelField(widget.displayName, EditorStyles.boldLabel);
|
||||
|
||||
EditorGUI.indentLevel++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End implementation for Container DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void End(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
EditorGUI.indentLevel--;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Horizontal Box Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.HBox))]
|
||||
public sealed class DebugUIDrawerHBox : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Begin implementation for Horizontal Box DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void Begin(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End implementation for Horizontal Box DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void End(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
EditorGUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Vertical Box Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.VBox))]
|
||||
public sealed class DebugUIDrawerVBox : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Begin implementation for Vertical Box DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void Begin(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
EditorGUILayout.BeginVertical();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// End implementation for Vertical Box DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public override void End(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
EditorGUILayout.EndVertical();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builtin Drawer for Table Debug Items.
|
||||
/// </summary>
|
||||
[DebugUIDrawer(typeof(DebugUI.Table))]
|
||||
public sealed class DebugUIDrawerTable : DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// OnGUI implementation for Table DebugUIDrawer.
|
||||
/// </summary>
|
||||
/// <param name="widget">DebugUI Widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>The state of the widget.</returns>
|
||||
public override bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
var w = Cast<DebugUI.Table>(widget);
|
||||
var header = w.Header;
|
||||
|
||||
// Put some space before the array
|
||||
PrepareControlRect(EditorGUIUtility.singleLineHeight * 0.5f);
|
||||
|
||||
// Draw an outline around the table
|
||||
var rect = EditorGUI.IndentedRect(PrepareControlRect(header.height + (w.children.Count + 1) * EditorGUIUtility.singleLineHeight));
|
||||
rect = DrawOutline(rect);
|
||||
|
||||
// Compute rects
|
||||
var headerRect = new Rect(rect.x, rect.y, rect.width, header.height);
|
||||
var contentRect = new Rect(rect.x, headerRect.yMax, rect.width, rect.height - headerRect.height);
|
||||
var viewRect = new Rect(contentRect.x, contentRect.y, header.state.widthOfAllVisibleColumns, contentRect.height);
|
||||
var rowRect = contentRect;
|
||||
rowRect.height = EditorGUIUtility.singleLineHeight;
|
||||
viewRect.height -= EditorGUIUtility.singleLineHeight;
|
||||
|
||||
// Show header
|
||||
header.OnGUI(headerRect, Mathf.Max(w.scroll.x, 0f));
|
||||
|
||||
// Show array content
|
||||
w.scroll = GUI.BeginScrollView(contentRect, w.scroll, viewRect);
|
||||
{
|
||||
var columns = header.state.columns;
|
||||
var visible = header.state.visibleColumns;
|
||||
for (int r = 0; r < w.children.Count; r++)
|
||||
{
|
||||
var row = Cast<DebugUI.Container>(w.children[r]);
|
||||
rowRect.x = contentRect.x;
|
||||
rowRect.width = columns[0].width;
|
||||
|
||||
rowRect.xMin += 2;
|
||||
rowRect.xMax -= 2;
|
||||
EditorGUI.LabelField(rowRect, GUIContent.none, EditorGUIUtility.TrTextContent(row.displayName));
|
||||
rowRect.xMin -= 2;
|
||||
rowRect.xMax += 2;
|
||||
|
||||
for (int c = 1; c < visible.Length; c++)
|
||||
{
|
||||
rowRect.x += rowRect.width;
|
||||
rowRect.width = columns[visible[c]].width;
|
||||
DisplayChild(rowRect, row.children[visible[c] - 1], w.isReadOnly);
|
||||
}
|
||||
rowRect.y += rowRect.height;
|
||||
}
|
||||
}
|
||||
GUI.EndScrollView(false);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal Rect DrawOutline(Rect rect)
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint)
|
||||
return rect;
|
||||
|
||||
float size = 1.0f;
|
||||
var color = EditorGUIUtility.isProSkin ? new Color(0.12f, 0.12f, 0.12f, 1.333f) : new Color(0.6f, 0.6f, 0.6f, 1.333f);
|
||||
|
||||
Color orgColor = GUI.color;
|
||||
GUI.color = GUI.color * color;
|
||||
GUI.DrawTexture(new Rect(rect.x, rect.y, rect.width, size), EditorGUIUtility.whiteTexture);
|
||||
GUI.DrawTexture(new Rect(rect.x, rect.yMax - size, rect.width, size), EditorGUIUtility.whiteTexture);
|
||||
GUI.DrawTexture(new Rect(rect.x, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
|
||||
GUI.DrawTexture(new Rect(rect.xMax - size, rect.y + 1, size, rect.height - 2 * size), EditorGUIUtility.whiteTexture);
|
||||
|
||||
GUI.color = orgColor;
|
||||
return new Rect(rect.x + size, rect.y + size, rect.width - 2 * size, rect.height - 2 * size);
|
||||
}
|
||||
|
||||
internal void DisplayChild(Rect rect, DebugUI.Widget child, bool disable)
|
||||
{
|
||||
rect.xMin += 2;
|
||||
rect.xMax -= 2;
|
||||
if (child.GetType() == typeof(DebugUI.Value))
|
||||
{
|
||||
var widget = Cast<DebugUI.Value>(child);
|
||||
EditorGUI.LabelField(rect, GUIContent.none, EditorGUIUtility.TrTextContent(widget.GetValue().ToString()));
|
||||
}
|
||||
else if (child.GetType() == typeof(DebugUI.ColorField))
|
||||
{
|
||||
var widget = Cast<DebugUI.ColorField>(child);
|
||||
using (new EditorGUI.DisabledScope(disable))
|
||||
EditorGUI.ColorField(rect, GUIContent.none, widget.GetValue(), false, widget.showAlpha, widget.hdr);
|
||||
}
|
||||
else if (child.GetType() == typeof(DebugUI.BoolField))
|
||||
{
|
||||
var widget = Cast<DebugUI.BoolField>(child);
|
||||
using (new EditorGUI.DisabledScope(disable))
|
||||
EditorGUI.Toggle(rect, GUIContent.none, widget.GetValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEditor.Rendering
|
||||
{
|
||||
/// <summary>
|
||||
/// Attribute specifying wich type of Debug Item should this drawer be used with.
|
||||
/// </summary>
|
||||
public class DebugUIDrawerAttribute : Attribute
|
||||
{
|
||||
internal readonly Type type;
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for DebugUIDraw Attribute
|
||||
/// </summary>
|
||||
/// <param name="type">Type of Debug Item this draw should be used with.</param>
|
||||
public DebugUIDrawerAttribute(Type type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Debug Item Drawer
|
||||
/// </summary>
|
||||
public class DebugUIDrawer
|
||||
{
|
||||
/// <summary>
|
||||
/// Cast into the proper type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the drawer</typeparam>
|
||||
/// <param name="o">Object to be cast</param>
|
||||
/// <returns>Returns o cast to type T</returns>
|
||||
protected T Cast<T>(object o)
|
||||
where T : class
|
||||
{
|
||||
var casted = o as T;
|
||||
|
||||
if (casted == null)
|
||||
{
|
||||
string typeName = o == null ? "null" : o.GetType().ToString();
|
||||
throw new InvalidOperationException("Can't cast " + typeName + " to " + typeof(T));
|
||||
}
|
||||
|
||||
return casted;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this to execute processing before UI rendering.
|
||||
/// </summary>
|
||||
/// <param name="widget">Widget that is going to be rendered.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public virtual void Begin(DebugUI.Widget widget, DebugState state)
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this to execute UI rendering.
|
||||
/// </summary>
|
||||
/// <param name="widget">Widget that is going to be rendered.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
/// <returns>Returns the state of the widget.</returns>
|
||||
public virtual bool OnGUI(DebugUI.Widget widget, DebugState state)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implement this to execute processing after UI rendering.
|
||||
/// </summary>
|
||||
/// <param name="widget">Widget that is going to be rendered.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item.</param>
|
||||
public virtual void End(DebugUI.Widget widget, DebugState state)
|
||||
{}
|
||||
|
||||
/// <summary>
|
||||
/// Applies a value to the widget and the Debug State of the Debug Item.
|
||||
/// </summary>
|
||||
/// <param name="widget">Debug Item widget.</param>
|
||||
/// <param name="state">Debug State associated with the Debug Item</param>
|
||||
/// <param name="value">Input value.</param>
|
||||
protected void Apply(DebugUI.IValueField widget, DebugState state, object value)
|
||||
{
|
||||
Undo.RegisterCompleteObjectUndo(state, "Debug Property Change");
|
||||
state.SetValue(value, widget);
|
||||
widget.SetValue(value);
|
||||
EditorUtility.SetDirty(state);
|
||||
DebugState.m_CurrentDirtyState = state;
|
||||
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the rendering Rect of the Drawer/
|
||||
/// </summary>
|
||||
/// <param name="height">Height of the rect.</param>
|
||||
/// <returns>Appropriate Rect for drawing.</returns>
|
||||
protected Rect PrepareControlRect(float height = -1)
|
||||
{
|
||||
if (height < 0)
|
||||
height = EditorGUIUtility.singleLineHeight;
|
||||
var rect = GUILayoutUtility.GetRect(1f, 1f, height, height);
|
||||
rect.width -= 2f;
|
||||
rect.xMin += 2f;
|
||||
EditorGUIUtility.labelWidth = rect.width / 2f;
|
||||
return rect;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,79 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Rendering;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEngine.Rendering.UI
|
||||
{
|
||||
[CustomEditor(typeof(DebugUIHandlerCanvas))]
|
||||
sealed class DebugUIHandlerCanvasEditor : Editor
|
||||
{
|
||||
SerializedProperty m_PanelPrefab;
|
||||
SerializedProperty m_Prefabs;
|
||||
ReorderableList m_PrefabList;
|
||||
|
||||
static string[] s_Types; // Assembly qualified names
|
||||
static string[] s_DisplayTypes; // Pretty names
|
||||
|
||||
static DebugUIHandlerCanvasEditor()
|
||||
{
|
||||
s_Types = CoreUtils.GetAllTypesDerivedFrom<DebugUI.Widget>()
|
||||
.Where(t => !t.IsAbstract)
|
||||
.Select(t => t.AssemblyQualifiedName)
|
||||
.ToArray();
|
||||
|
||||
s_DisplayTypes = new string[s_Types.Length];
|
||||
for (int i = 0; i < s_Types.Length; i++)
|
||||
s_DisplayTypes[i] = Type.GetType(s_Types[i]).Name;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var o = new PropertyFetcher<DebugUIHandlerCanvas>(serializedObject);
|
||||
m_PanelPrefab = o.Find(x => x.panelPrefab);
|
||||
m_Prefabs = o.Find(x => x.prefabs);
|
||||
|
||||
m_PrefabList = new ReorderableList(serializedObject, m_Prefabs, true, true, true, true)
|
||||
{
|
||||
drawHeaderCallback = rect => EditorGUI.LabelField(rect, "Widget Prefabs"),
|
||||
drawElementCallback = (rect, index, isActive, isFocused) =>
|
||||
{
|
||||
var element = m_PrefabList.serializedProperty.GetArrayElementAtIndex(index);
|
||||
rect.y += 2f;
|
||||
const float kTypeWidth = 100f;
|
||||
|
||||
// Type selector
|
||||
var typeProp = element.FindPropertyRelative("type");
|
||||
int typeIndex = ArrayUtility.IndexOf(s_Types, typeProp.stringValue);
|
||||
typeIndex = Mathf.Max(typeIndex, 0);
|
||||
typeIndex = EditorGUI.Popup(new Rect(rect.x, rect.y, kTypeWidth, EditorGUIUtility.singleLineHeight), typeIndex, s_DisplayTypes);
|
||||
typeProp.stringValue = s_Types[typeIndex];
|
||||
|
||||
// Prefab
|
||||
EditorGUI.PropertyField(
|
||||
new Rect(rect.x + kTypeWidth + 2f, rect.y, rect.width - kTypeWidth - 2f, EditorGUIUtility.singleLineHeight),
|
||||
element.FindPropertyRelative("prefab"), GUIContent.none);
|
||||
},
|
||||
onSelectCallback = list =>
|
||||
{
|
||||
var prefab = list.serializedProperty.GetArrayElementAtIndex(list.index).FindPropertyRelative("prefab").objectReferenceValue as GameObject;
|
||||
if (prefab)
|
||||
EditorGUIUtility.PingObject(prefab.gameObject);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_PanelPrefab);
|
||||
EditorGUILayout.Space();
|
||||
m_PrefabList.DoLayoutList();
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,584 @@
|
||||
#if ENABLE_INPUT_SYSTEM && ENABLE_INPUT_SYSTEM_PACKAGE
|
||||
#define USE_INPUT_SYSTEM
|
||||
#endif
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.Callbacks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace UnityEditor.Rendering
|
||||
{
|
||||
#pragma warning disable 414
|
||||
|
||||
[Serializable]
|
||||
sealed class WidgetStateDictionary : SerializedDictionary<string, DebugState> {}
|
||||
|
||||
sealed class DebugWindowSettings : ScriptableObject
|
||||
{
|
||||
// Keep these settings in a separate scriptable object so we can handle undo/redo on them
|
||||
// without the rest of the debug window interfering
|
||||
public int currentStateHash;
|
||||
public int selectedPanel;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
hideFlags = HideFlags.HideAndDontSave;
|
||||
}
|
||||
}
|
||||
|
||||
sealed class DebugWindow : EditorWindow
|
||||
{
|
||||
static readonly GUIContent k_ResetButtonContent = new GUIContent("Reset");
|
||||
//static readonly GUIContent k_SaveButtonContent = new GUIContent("Save");
|
||||
//static readonly GUIContent k_LoadButtonContent = new GUIContent("Load");
|
||||
|
||||
//static bool isMultiview = false;
|
||||
|
||||
static Styles s_Styles;
|
||||
static GUIStyle s_SplitterLeft;
|
||||
|
||||
static float splitterPos = 150f;
|
||||
const float minSideBarWidth = 100;
|
||||
const float minContentWidth = 100;
|
||||
bool dragging = false;
|
||||
|
||||
[SerializeField]
|
||||
WidgetStateDictionary m_WidgetStates;
|
||||
|
||||
[SerializeField]
|
||||
DebugWindowSettings m_Settings;
|
||||
|
||||
[SerializeField]
|
||||
int m_DebugTreeState;
|
||||
|
||||
bool m_IsDirty;
|
||||
|
||||
Vector2 m_PanelScroll;
|
||||
Vector2 m_ContentScroll;
|
||||
|
||||
static bool s_TypeMapDirty;
|
||||
static Dictionary<Type, Type> s_WidgetStateMap; // DebugUI.Widget type -> DebugState type
|
||||
static Dictionary<Type, DebugUIDrawer> s_WidgetDrawerMap; // DebugUI.Widget type -> DebugUIDrawer
|
||||
|
||||
static bool s_Open;
|
||||
public static bool open
|
||||
{
|
||||
get => s_Open;
|
||||
private set
|
||||
{
|
||||
if (s_Open ^ value)
|
||||
OnDebugWindowToggled?.Invoke(value);
|
||||
s_Open = value;
|
||||
}
|
||||
}
|
||||
static event Action<bool> OnDebugWindowToggled;
|
||||
|
||||
[DidReloadScripts]
|
||||
static void OnEditorReload()
|
||||
{
|
||||
s_TypeMapDirty = true;
|
||||
|
||||
//find if it where open, relink static event end propagate the info
|
||||
open = (Resources.FindObjectsOfTypeAll<DebugWindow>()?.Length ?? 0) > 0;
|
||||
if (OnDebugWindowToggled == null)
|
||||
OnDebugWindowToggled += DebugManager.instance.ToggleEditorUI;
|
||||
DebugManager.instance.ToggleEditorUI(open);
|
||||
}
|
||||
|
||||
static void RebuildTypeMaps()
|
||||
{
|
||||
// Map states to widget (a single state can map to several widget types if the value to
|
||||
// serialize is the same)
|
||||
var attrType = typeof(DebugStateAttribute);
|
||||
var stateTypes = CoreUtils.GetAllTypesDerivedFrom<DebugState>()
|
||||
.Where(
|
||||
t => t.IsDefined(attrType, false)
|
||||
&& !t.IsAbstract
|
||||
);
|
||||
|
||||
s_WidgetStateMap = new Dictionary<Type, Type>();
|
||||
|
||||
foreach (var stateType in stateTypes)
|
||||
{
|
||||
var attr = (DebugStateAttribute)stateType.GetCustomAttributes(attrType, false)[0];
|
||||
|
||||
foreach (var t in attr.types)
|
||||
s_WidgetStateMap.Add(t, stateType);
|
||||
}
|
||||
|
||||
// Drawers
|
||||
attrType = typeof(DebugUIDrawerAttribute);
|
||||
var types = CoreUtils.GetAllTypesDerivedFrom<DebugUIDrawer>()
|
||||
.Where(
|
||||
t => t.IsDefined(attrType, false)
|
||||
&& !t.IsAbstract
|
||||
);
|
||||
|
||||
s_WidgetDrawerMap = new Dictionary<Type, DebugUIDrawer>();
|
||||
|
||||
foreach (var t in types)
|
||||
{
|
||||
var attr = (DebugUIDrawerAttribute)t.GetCustomAttributes(attrType, false)[0];
|
||||
var inst = (DebugUIDrawer)Activator.CreateInstance(t);
|
||||
s_WidgetDrawerMap.Add(attr.type, inst);
|
||||
}
|
||||
|
||||
// Done
|
||||
s_TypeMapDirty = false;
|
||||
}
|
||||
|
||||
[MenuItem("Window/Render Pipeline/Render Pipeline Debug", priority = 10005)] // 112 is hardcoded number given by the UxTeam to fit correctly in the Windows menu
|
||||
static void Init()
|
||||
{
|
||||
var window = GetWindow<DebugWindow>();
|
||||
window.titleContent = new GUIContent("Debug");
|
||||
if (OnDebugWindowToggled == null)
|
||||
OnDebugWindowToggled += DebugManager.instance.ToggleEditorUI;
|
||||
open = true;
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
DebugManager.instance.refreshEditorRequested = false;
|
||||
|
||||
hideFlags = HideFlags.HideAndDontSave;
|
||||
autoRepaintOnSceneChange = true;
|
||||
|
||||
if (m_Settings == null)
|
||||
m_Settings = CreateInstance<DebugWindowSettings>();
|
||||
|
||||
// States are ScriptableObjects (necessary for Undo/Redo) but are not saved on disk so when the editor is closed then reopened, any existing debug window will have its states set to null
|
||||
// Since we don't care about persistance in this case, we just re-init everything.
|
||||
if (m_WidgetStates == null || !AreWidgetStatesValid())
|
||||
m_WidgetStates = new WidgetStateDictionary();
|
||||
|
||||
if (s_WidgetStateMap == null || s_WidgetDrawerMap == null || s_TypeMapDirty)
|
||||
RebuildTypeMaps();
|
||||
|
||||
Undo.undoRedoPerformed += OnUndoRedoPerformed;
|
||||
DebugManager.instance.onSetDirty += MarkDirty;
|
||||
|
||||
// First init
|
||||
m_DebugTreeState = DebugManager.instance.GetState();
|
||||
UpdateWidgetStates();
|
||||
|
||||
EditorApplication.update -= Repaint;
|
||||
var panels = DebugManager.instance.panels;
|
||||
var selectedPanelIndex = m_Settings.selectedPanel;
|
||||
if (selectedPanelIndex >= 0
|
||||
&& selectedPanelIndex < panels.Count
|
||||
&& panels[selectedPanelIndex].editorForceUpdate)
|
||||
EditorApplication.update += Repaint;
|
||||
}
|
||||
|
||||
// Note: this won't get called if the window is opened when the editor itself is closed
|
||||
void OnDestroy()
|
||||
{
|
||||
open = false;
|
||||
DebugManager.instance.onSetDirty -= MarkDirty;
|
||||
Undo.ClearUndo(m_Settings);
|
||||
|
||||
DestroyWidgetStates();
|
||||
}
|
||||
|
||||
public void DestroyWidgetStates()
|
||||
{
|
||||
if (m_WidgetStates != null)
|
||||
{
|
||||
// Clear all the states from memory
|
||||
foreach (var state in m_WidgetStates)
|
||||
{
|
||||
var s = state.Value;
|
||||
Undo.ClearUndo(s); // Don't leave dangling states in the global undo/redo stack
|
||||
DestroyImmediate(s);
|
||||
}
|
||||
|
||||
m_WidgetStates.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool AreWidgetStatesValid()
|
||||
{
|
||||
foreach (var state in m_WidgetStates)
|
||||
{
|
||||
if (state.Value == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MarkDirty()
|
||||
{
|
||||
m_IsDirty = true;
|
||||
}
|
||||
|
||||
// We use item states to keep a cached value of each serializable debug items in order to
|
||||
// handle domain reloads, play mode entering/exiting and undo/redo
|
||||
// Note: no removal of orphan states
|
||||
void UpdateWidgetStates()
|
||||
{
|
||||
foreach (var panel in DebugManager.instance.panels)
|
||||
UpdateWidgetStates(panel);
|
||||
}
|
||||
|
||||
void UpdateWidgetStates(DebugUI.IContainer container)
|
||||
{
|
||||
// Skip runtime only containers, we won't draw them so no need to serialize them either
|
||||
var actualWidget = container as DebugUI.Widget;
|
||||
if (actualWidget != null && actualWidget.isInactiveInEditor)
|
||||
return;
|
||||
|
||||
// Recursively update widget states
|
||||
foreach (var widget in container.children)
|
||||
{
|
||||
// Skip non-serializable widgets but still traverse them in case one of their
|
||||
// children needs serialization support
|
||||
var valueField = widget as DebugUI.IValueField;
|
||||
if (valueField != null)
|
||||
{
|
||||
// Skip runtime & readonly only items
|
||||
if (widget.isInactiveInEditor)
|
||||
return;
|
||||
|
||||
var widgetType = widget.GetType();
|
||||
string guid = widget.queryPath;
|
||||
Type stateType;
|
||||
s_WidgetStateMap.TryGetValue(widgetType, out stateType);
|
||||
|
||||
// Create missing states & recreate the ones that are null
|
||||
if (stateType != null)
|
||||
{
|
||||
if (!m_WidgetStates.ContainsKey(guid) || m_WidgetStates[guid] == null)
|
||||
{
|
||||
var inst = (DebugState)CreateInstance(stateType);
|
||||
inst.queryPath = guid;
|
||||
inst.SetValue(valueField.GetValue(), valueField);
|
||||
m_WidgetStates[guid] = inst;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Recurse if the widget is a container
|
||||
var containerField = widget as DebugUI.IContainer;
|
||||
if (containerField != null)
|
||||
UpdateWidgetStates(containerField);
|
||||
}
|
||||
}
|
||||
|
||||
public void ApplyStates(bool forceApplyAll = false)
|
||||
{
|
||||
if (!forceApplyAll && DebugState.m_CurrentDirtyState != null)
|
||||
{
|
||||
ApplyState(DebugState.m_CurrentDirtyState.queryPath, DebugState.m_CurrentDirtyState);
|
||||
DebugState.m_CurrentDirtyState = null;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var state in m_WidgetStates)
|
||||
ApplyState(state.Key, state.Value);
|
||||
|
||||
DebugState.m_CurrentDirtyState = null;
|
||||
}
|
||||
|
||||
void ApplyState(string queryPath, DebugState state)
|
||||
{
|
||||
var widget = DebugManager.instance.GetItem(queryPath) as DebugUI.IValueField;
|
||||
|
||||
if (widget == null)
|
||||
return;
|
||||
|
||||
widget.SetValue(state.GetValue());
|
||||
}
|
||||
|
||||
void OnUndoRedoPerformed()
|
||||
{
|
||||
int stateHash = ComputeStateHash();
|
||||
|
||||
// Something has been undone / redone, re-apply states to the debug tree
|
||||
if (stateHash != m_Settings.currentStateHash)
|
||||
{
|
||||
ApplyStates(true);
|
||||
m_Settings.currentStateHash = stateHash;
|
||||
}
|
||||
|
||||
Repaint();
|
||||
}
|
||||
|
||||
int ComputeStateHash()
|
||||
{
|
||||
unchecked
|
||||
{
|
||||
int hash = 13;
|
||||
|
||||
foreach (var state in m_WidgetStates)
|
||||
hash = hash * 23 + state.Value.GetHashCode();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// If the render pipeline asset has been reloaded we force-refresh widget states in case
|
||||
// some debug values need to be refresh/recreated as well (e.g. frame settings on HD)
|
||||
if (DebugManager.instance.refreshEditorRequested)
|
||||
{
|
||||
DestroyWidgetStates();
|
||||
DebugManager.instance.refreshEditorRequested = false;
|
||||
}
|
||||
|
||||
int treeState = DebugManager.instance.GetState();
|
||||
|
||||
if (m_DebugTreeState != treeState || m_IsDirty)
|
||||
{
|
||||
UpdateWidgetStates();
|
||||
ApplyStates();
|
||||
m_DebugTreeState = treeState;
|
||||
m_IsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (s_Styles == null)
|
||||
{
|
||||
s_Styles = new Styles();
|
||||
s_SplitterLeft = new GUIStyle();
|
||||
}
|
||||
|
||||
var panels = DebugManager.instance.panels;
|
||||
int itemCount = panels.Count(x => !x.isInactiveInEditor && x.children.Count(w => !w.isInactiveInEditor) > 0);
|
||||
|
||||
if (itemCount == 0)
|
||||
{
|
||||
EditorGUILayout.HelpBox("No debug item found.", MessageType.Info);
|
||||
return;
|
||||
}
|
||||
|
||||
// Background color
|
||||
var wrect = position;
|
||||
wrect.x = 0;
|
||||
wrect.y = 0;
|
||||
var oldColor = GUI.color;
|
||||
GUI.color = s_Styles.skinBackgroundColor;
|
||||
GUI.DrawTexture(wrect, EditorGUIUtility.whiteTexture);
|
||||
GUI.color = oldColor;
|
||||
|
||||
|
||||
GUILayout.BeginHorizontal(EditorStyles.toolbar);
|
||||
//isMultiview = GUILayout.Toggle(isMultiview, "multiview", EditorStyles.toolbarButton);
|
||||
//if (isMultiview)
|
||||
// EditorGUILayout.Popup(0, new[] { new GUIContent("SceneView 1"), new GUIContent("SceneView 2") }, EditorStyles.toolbarDropDown, GUILayout.Width(100f));
|
||||
GUILayout.FlexibleSpace();
|
||||
//GUILayout.Button(k_LoadButtonContent, EditorStyles.toolbarButton);
|
||||
//GUILayout.Button(k_SaveButtonContent, EditorStyles.toolbarButton);
|
||||
if (GUILayout.Button(k_ResetButtonContent, EditorStyles.toolbarButton))
|
||||
DebugManager.instance.Reset();
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
using (new EditorGUILayout.HorizontalScope())
|
||||
{
|
||||
// Side bar
|
||||
using (var scrollScope = new EditorGUILayout.ScrollViewScope(m_PanelScroll, s_Styles.sectionScrollView, GUILayout.Width(splitterPos)))
|
||||
{
|
||||
GUILayout.Space(40f);
|
||||
|
||||
if (m_Settings.selectedPanel >= panels.Count)
|
||||
m_Settings.selectedPanel = 0;
|
||||
|
||||
// Validate container id
|
||||
while (panels[m_Settings.selectedPanel].isInactiveInEditor || panels[m_Settings.selectedPanel].children.Count(x => !x.isInactiveInEditor) == 0)
|
||||
{
|
||||
m_Settings.selectedPanel++;
|
||||
|
||||
if (m_Settings.selectedPanel >= panels.Count)
|
||||
m_Settings.selectedPanel = 0;
|
||||
}
|
||||
|
||||
// Root children are containers
|
||||
for (int i = 0; i < panels.Count; i++)
|
||||
{
|
||||
var panel = panels[i];
|
||||
|
||||
if (panel.isInactiveInEditor)
|
||||
continue;
|
||||
|
||||
if (panel.children.Count(x => !x.isInactiveInEditor) == 0)
|
||||
continue;
|
||||
|
||||
var elementRect = GUILayoutUtility.GetRect(EditorGUIUtility.TrTextContent(panel.displayName), s_Styles.sectionElement, GUILayout.ExpandWidth(true));
|
||||
|
||||
if (m_Settings.selectedPanel == i && Event.current.type == EventType.Repaint)
|
||||
s_Styles.selected.Draw(elementRect, false, false, false, false);
|
||||
|
||||
EditorGUI.BeginChangeCheck();
|
||||
GUI.Toggle(elementRect, m_Settings.selectedPanel == i, panel.displayName, s_Styles.sectionElement);
|
||||
if (EditorGUI.EndChangeCheck())
|
||||
{
|
||||
Undo.RegisterCompleteObjectUndo(m_Settings, "Debug Panel Selection");
|
||||
var previousPanel = m_Settings.selectedPanel >= 0 && m_Settings.selectedPanel < panels.Count
|
||||
? panels[m_Settings.selectedPanel]
|
||||
: null;
|
||||
if (previousPanel != null && previousPanel.editorForceUpdate && !panel.editorForceUpdate)
|
||||
EditorApplication.update -= Repaint;
|
||||
else if ((previousPanel == null || !previousPanel.editorForceUpdate) && panel.editorForceUpdate)
|
||||
EditorApplication.update += Repaint;
|
||||
m_Settings.selectedPanel = i;
|
||||
}
|
||||
}
|
||||
|
||||
m_PanelScroll = scrollScope.scrollPosition;
|
||||
}
|
||||
|
||||
Rect splitterRect = new Rect(splitterPos - 3, 0, 6, Screen.height);
|
||||
GUI.Box(splitterRect, "", s_SplitterLeft);
|
||||
|
||||
GUILayout.Space(10f);
|
||||
|
||||
// Main section - traverse current container
|
||||
using (var changedScope = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
using (new EditorGUILayout.VerticalScope())
|
||||
{
|
||||
var selectedPanel = panels[m_Settings.selectedPanel];
|
||||
|
||||
GUILayout.Label(selectedPanel.displayName, s_Styles.sectionHeader);
|
||||
GUILayout.Space(10f);
|
||||
|
||||
using (var scrollScope = new EditorGUILayout.ScrollViewScope(m_ContentScroll))
|
||||
{
|
||||
TraverseContainerGUI(selectedPanel);
|
||||
m_ContentScroll = scrollScope.scrollPosition;
|
||||
}
|
||||
}
|
||||
|
||||
if (changedScope.changed)
|
||||
{
|
||||
m_Settings.currentStateHash = ComputeStateHash();
|
||||
DebugManager.instance.ReDrawOnScreenDebug();
|
||||
}
|
||||
}
|
||||
|
||||
// Splitter events
|
||||
if (Event.current != null)
|
||||
{
|
||||
switch (Event.current.rawType)
|
||||
{
|
||||
case EventType.MouseDown:
|
||||
if (splitterRect.Contains(Event.current.mousePosition))
|
||||
{
|
||||
dragging = true;
|
||||
}
|
||||
break;
|
||||
case EventType.MouseDrag:
|
||||
if (dragging)
|
||||
{
|
||||
splitterPos += Event.current.delta.x;
|
||||
splitterPos = Mathf.Clamp(splitterPos, minSideBarWidth, Screen.width - minContentWidth);
|
||||
Repaint();
|
||||
}
|
||||
break;
|
||||
case EventType.MouseUp:
|
||||
if (dragging)
|
||||
{
|
||||
dragging = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
EditorGUIUtility.AddCursorRect(splitterRect, MouseCursor.ResizeHorizontal);
|
||||
}
|
||||
}
|
||||
|
||||
void OnWidgetGUI(DebugUI.Widget widget)
|
||||
{
|
||||
if (widget.isInactiveInEditor)
|
||||
return;
|
||||
|
||||
DebugState state; // State will be null for stateless widget
|
||||
m_WidgetStates.TryGetValue(widget.queryPath, out state);
|
||||
|
||||
DebugUIDrawer drawer;
|
||||
|
||||
if (!s_WidgetDrawerMap.TryGetValue(widget.GetType(), out drawer))
|
||||
{
|
||||
EditorGUILayout.LabelField("Drawer not found (" + widget.GetType() + ").");
|
||||
}
|
||||
else
|
||||
{
|
||||
drawer.Begin(widget, state);
|
||||
|
||||
if (drawer.OnGUI(widget, state))
|
||||
{
|
||||
var container = widget as DebugUI.IContainer;
|
||||
|
||||
if (container != null)
|
||||
TraverseContainerGUI(container);
|
||||
}
|
||||
|
||||
drawer.End(widget, state);
|
||||
}
|
||||
}
|
||||
|
||||
void TraverseContainerGUI(DebugUI.IContainer container)
|
||||
{
|
||||
// /!\ SHAAAAAAAME ALERT /!\
|
||||
// A container can change at runtime because of the way IMGUI works and how we handle
|
||||
// onValueChanged on widget so we have to take this into account while iterating
|
||||
try
|
||||
{
|
||||
foreach (var widget in container.children)
|
||||
OnWidgetGUI(widget);
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
Repaint();
|
||||
}
|
||||
}
|
||||
|
||||
public class Styles
|
||||
{
|
||||
public static float s_DefaultLabelWidth = 0.5f;
|
||||
|
||||
public readonly GUIStyle sectionScrollView = "PreferencesSectionBox";
|
||||
public readonly GUIStyle sectionElement = new GUIStyle("PreferencesSection");
|
||||
public readonly GUIStyle selected = "OL SelectedRow";
|
||||
public readonly GUIStyle sectionHeader = new GUIStyle(EditorStyles.largeLabel);
|
||||
public readonly Color skinBackgroundColor;
|
||||
|
||||
public Styles()
|
||||
{
|
||||
sectionScrollView = new GUIStyle(sectionScrollView);
|
||||
sectionScrollView.overflow.bottom += 1;
|
||||
|
||||
sectionElement.alignment = TextAnchor.MiddleLeft;
|
||||
|
||||
sectionHeader.fontStyle = FontStyle.Bold;
|
||||
sectionHeader.fontSize = 18;
|
||||
sectionHeader.margin.top = 10;
|
||||
sectionHeader.margin.left += 1;
|
||||
sectionHeader.normal.textColor = !EditorGUIUtility.isProSkin
|
||||
? new Color(0.4f, 0.4f, 0.4f, 1.0f)
|
||||
: new Color(0.7f, 0.7f, 0.7f, 1.0f);
|
||||
|
||||
if (EditorGUIUtility.isProSkin)
|
||||
{
|
||||
sectionHeader.normal.textColor = new Color(0.7f, 0.7f, 0.7f, 1.0f);
|
||||
skinBackgroundColor = Color.gray * new Color(0.3f, 0.3f, 0.3f, 0.5f);
|
||||
}
|
||||
else
|
||||
{
|
||||
sectionHeader.normal.textColor = new Color(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
skinBackgroundColor = Color.gray * new Color(1f, 1f, 1f, 0.32f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma warning restore 414
|
||||
}
|
@@ -0,0 +1,34 @@
|
||||
using UnityEngine.Rendering.UI;
|
||||
|
||||
namespace UnityEditor.Rendering.UI
|
||||
{
|
||||
[CustomEditor(typeof(UIFoldout), true)]
|
||||
sealed class UIFoldoutEditor : Editor
|
||||
{
|
||||
SerializedProperty m_IsOn;
|
||||
SerializedProperty m_Content;
|
||||
SerializedProperty m_ArrowClosed;
|
||||
SerializedProperty m_ArrowOpened;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
var o = new PropertyFetcher<UIFoldout>(serializedObject);
|
||||
m_IsOn = o.Find("m_IsOn");
|
||||
m_Content = o.Find(x => x.content);
|
||||
m_ArrowClosed = o.Find(x => x.arrowClosed);
|
||||
m_ArrowOpened = o.Find(x => x.arrowOpened);
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_IsOn);
|
||||
EditorGUILayout.PropertyField(m_Content);
|
||||
EditorGUILayout.PropertyField(m_ArrowClosed);
|
||||
EditorGUILayout.PropertyField(m_ArrowOpened);
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user