using UnityEngine; using UnityEditor; using System; using System.Linq; using UnityEditor.SceneManagement; namespace MLAgents { /// /// PropertyDrawer for ResetParameters. Defines how ResetParameters are displayed in the /// Inspector. /// [CustomPropertyDrawer(typeof(ResetParameters))] public class ResetParameterDrawer : PropertyDrawer { private ResetParameters _parameters; // The height of a line in the Unity Inspectors private const float LineHeight = 17f; // This is the prefix for the key when you add a reset parameter private const string 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, label); return (_parameters.Count + 2) * LineHeight; } /// public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { LazyInitializeParameters(property, label); position.height = LineHeight; EditorGUI.LabelField(position, label); position.y += 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 _parameters) { var key = parameter.Key; var value = parameter.Value; keyRect.y += LineHeight; valueRect.y += LineHeight; EditorGUI.BeginChangeCheck(); var newKey = EditorGUI.TextField(keyRect, key); if (EditorGUI.EndChangeCheck()) { MarkSceneAsDirty(); try { _parameters.Remove(key); _parameters.Add(newKey, value); } catch (Exception e) { Debug.Log(e.Message); } break; } EditorGUI.BeginChangeCheck(); value = EditorGUI.FloatField(valueRect, value); if (EditorGUI.EndChangeCheck()) { MarkSceneAsDirty(); _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 (_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 (_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(EditorSceneManager.GetActiveScene()); } } /// /// Ensures that the state of the Drawer is synchronized with the property. /// /// The SerializedProperty of the ResetParameters /// to make the custom GUI for. /// The label of this property. private void LazyInitializeParameters(SerializedProperty property, GUIContent label) { if (_parameters != null) { return; } var target = property.serializedObject.targetObject; _parameters = fieldInfo.GetValue(target) as ResetParameters; if (_parameters == null) { _parameters = new ResetParameters(); fieldInfo.SetValue(target, _parameters); } } /// /// Removes the last ResetParameter from the ResetParameters /// private void RemoveLastParameter() { if (_parameters.Count > 0) { string key = _parameters.Keys.ToList()[_parameters.Count - 1]; _parameters.Remove(key); } } /// /// Adds a new ResetParameter to the ResetParameters with a default name. /// private void AddParameter() { string key = NewKeyPrefix + _parameters.Count; var value = default(float); try { _parameters.Add(key, value); } catch (Exception e) { Debug.Log(e.Message); } } } }