using UnityEngine; using UnityEditor; using System; using System.Linq; using UnityEditor.SceneManagement; using UnityEngine.SceneManagement; namespace MLAgents { /// /// PropertyDrawer for ResetParameters. Defines how ResetParameters are displayed in the /// Inspector. /// [CustomPropertyDrawer(typeof(ResetParameters))] public class ResetParameterDrawer : PropertyDrawer { private ResetParameters m_Parameters; // The height of a line in the Unity Inspectors private const float k_LineHeight = 17f; // This is the prefix for the key when you add a reset parameter private const string k_NewKeyPrefix = "Param-"; /// /// Computes the height of the Drawer depending on the property it is showing /// /// The property that is being drawn. /// The label of the property being drawn. /// The vertical space needed to draw the property. public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { LazyInitializeParameters(property); return (m_Parameters.Count + 2) * k_LineHeight; } /// public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { LazyInitializeParameters(property); position.height = k_LineHeight; EditorGUI.LabelField(position, label); position.y += k_LineHeight; var width = position.width / 2 - 24; var keyRect = new Rect(position.x + 20, position.y, width, position.height); var valueRect = new Rect(position.x + width + 30, position.y, width, position.height); DrawAddRemoveButtons(keyRect, valueRect); EditorGUI.BeginProperty(position, label, property); foreach (var parameter in m_Parameters) { var key = parameter.Key; var value = parameter.Value; keyRect.y += k_LineHeight; valueRect.y += k_LineHeight; EditorGUI.BeginChangeCheck(); var newKey = EditorGUI.TextField(keyRect, key); if (EditorGUI.EndChangeCheck()) { MarkSceneAsDirty(); try { m_Parameters.Remove(key); m_Parameters.Add(newKey, value); } catch (Exception e) { Debug.Log(e.Message); } break; } EditorGUI.BeginChangeCheck(); value = EditorGUI.FloatField(valueRect, value); if (EditorGUI.EndChangeCheck()) { MarkSceneAsDirty(); m_Parameters[key] = value; break; } } EditorGUI.EndProperty(); } /// /// Draws the Add and Remove buttons. /// /// The rectangle for the Add New button. /// The rectangle for the Remove Last button. private void DrawAddRemoveButtons(Rect addRect, Rect removeRect) { // This is the Add button if (m_Parameters.Count == 0) { addRect.width *= 2; } if (GUI.Button(addRect, new GUIContent("Add New", "Add a new item to the default reset parameters"), EditorStyles.miniButton)) { MarkSceneAsDirty(); AddParameter(); } // If there are no items in the ResetParameters, Hide the Remove button if (m_Parameters.Count == 0) { return; } // This is the Remove button if (GUI.Button(removeRect, new GUIContent( "Remove Last", "Remove the last item from the default reset parameters"), EditorStyles.miniButton)) { MarkSceneAsDirty(); RemoveLastParameter(); } } /// /// Signals that the property has been modified and requires the scene to be saved for /// the changes to persist. Only works when the Editor is not playing. /// private static void MarkSceneAsDirty() { if (!EditorApplication.isPlaying) { EditorSceneManager.MarkSceneDirty(SceneManager.GetActiveScene()); } } /// /// Ensures that the state of the Drawer is synchronized with the property. /// /// The SerializedProperty of the ResetParameters /// to make the custom GUI for. private void LazyInitializeParameters(SerializedProperty property) { if (m_Parameters != null) { return; } var target = property.serializedObject.targetObject; m_Parameters = fieldInfo.GetValue(target) as ResetParameters; if (m_Parameters == null) { m_Parameters = new ResetParameters(); fieldInfo.SetValue(target, m_Parameters); } } /// /// Removes the last ResetParameter from the ResetParameters /// private void RemoveLastParameter() { if (m_Parameters.Count > 0) { var key = m_Parameters.Keys.ToList()[m_Parameters.Count - 1]; m_Parameters.Remove(key); } } /// /// Adds a new ResetParameter to the ResetParameters with a default name. /// private void AddParameter() { var key = k_NewKeyPrefix + m_Parameters.Count; var value = default(float); try { m_Parameters.Add(key, value); } catch (Exception e) { Debug.Log(e.Message); } } } }