// This code is part of the Fungus library (http://fungusgames.com) maintained by Chris Gregan (http://twitter.com/gofungus). // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) using UnityEditor; using UnityEngine; using System.Collections.Generic; using Rotorz.ReorderableList; namespace Fungus.EditorUtils { [CustomEditor (typeof(Command), true)] public class CommandEditor : Editor { public static Command selectedCommand; public static CommandInfoAttribute GetCommandInfo(System.Type commandType) { object[] attributes = commandType.GetCustomAttributes(typeof(CommandInfoAttribute), false); foreach (object obj in attributes) { CommandInfoAttribute commandInfoAttr = obj as CommandInfoAttribute; if (commandInfoAttr != null) { return commandInfoAttr; } } return null; } public virtual void DrawCommandInspectorGUI() { Command t = target as Command; if (t == null) { return; } var flowchart = (Flowchart)t.GetFlowchart(); if (flowchart == null) { return; } CommandInfoAttribute commandInfoAttr = CommandEditor.GetCommandInfo(t.GetType()); if (commandInfoAttr == null) { return; } GUILayout.BeginVertical(GUI.skin.box); if (t.enabled) { if (flowchart.ColorCommands) { GUI.backgroundColor = t.GetButtonColor(); } else { GUI.backgroundColor = Color.white; } } else { GUI.backgroundColor = Color.grey; } GUILayout.BeginHorizontal(GUI.skin.button); string commandName = commandInfoAttr.CommandName; GUILayout.Label(commandName, GUILayout.MinWidth(80), GUILayout.ExpandWidth(true)); GUILayout.FlexibleSpace(); GUILayout.Label(new GUIContent("(" + t.ItemId + ")")); GUILayout.Space(10); GUI.backgroundColor = Color.white; bool enabled = t.enabled; enabled = GUILayout.Toggle(enabled, new GUIContent()); if (t.enabled != enabled) { Undo.RecordObject(t, "Set Enabled"); t.enabled = enabled; } GUILayout.EndHorizontal(); GUI.backgroundColor = Color.white; EditorGUILayout.Separator(); DrawCommandGUI(); EditorGUILayout.Separator(); if (t.ErrorMessage.Length > 0) { GUIStyle style = new GUIStyle(GUI.skin.label); style.normal.textColor = new Color(1,0,0); EditorGUILayout.LabelField(new GUIContent("Error: " + t.ErrorMessage), style); } GUILayout.EndVertical(); // Display help text CommandInfoAttribute infoAttr = CommandEditor.GetCommandInfo(t.GetType()); if (infoAttr != null) { EditorGUILayout.HelpBox(infoAttr.HelpText, MessageType.Info, true); } } public virtual void DrawCommandGUI() { Command t = target as Command; // Code below was copied from here // http://answers.unity3d.com/questions/550829/how-to-add-a-script-field-in-custom-inspector.html // Users should not be able to change the MonoScript for the command using the usual Script field. // Doing so could cause block.commandList to contain null entries. // To avoid this we manually display all properties, except for m_Script. serializedObject.Update(); SerializedProperty iterator = serializedObject.GetIterator(); bool enterChildren = true; while (iterator.NextVisible(enterChildren)) { enterChildren = false; if (iterator.name == "m_Script") { continue; } if (!t.IsPropertyVisible(iterator.name)) { continue; } if (iterator.isArray && t.IsReorderableArray(iterator.name)) { ReorderableListGUI.Title(new GUIContent(iterator.displayName, iterator.tooltip)); ReorderableListGUI.ListField(iterator); } else { EditorGUILayout.PropertyField(iterator, true, new GUILayoutOption[0]); } } serializedObject.ApplyModifiedProperties(); } static public void ObjectField(SerializedProperty property, GUIContent label, GUIContent nullLabel, List objectList) where T : Object { if (property == null) { return; } List objectNames = new List(); T selectedObject = property.objectReferenceValue as T; int selectedIndex = -1; // Invalid index // First option in list is objectNames.Add(nullLabel); if (selectedObject == null) { selectedIndex = 0; } for (int i = 0; i < objectList.Count; ++i) { if (objectList[i] == null) continue; objectNames.Add(new GUIContent(objectList[i].name)); if (selectedObject == objectList[i]) { selectedIndex = i + 1; } } T result; selectedIndex = EditorGUILayout.Popup(label, selectedIndex, objectNames.ToArray()); if (selectedIndex == -1) { // Currently selected object is not in list, but nothing else was selected so no change. return; } else if (selectedIndex == 0) { result = null; // Null option } else { result = objectList[selectedIndex - 1]; } property.objectReferenceValue = result; } // When modifying custom editor code you can occasionally end up with orphaned editor instances. // When this happens, you'll get a null exception error every time the scene serializes / deserialized. // Once this situation occurs, the only way to fix it is to restart the Unity editor. // // As a workaround, this function detects if this command editor is an orphan and deletes it. // To use it, just call this function at the top of the OnEnable() method in your custom editor. protected virtual bool NullTargetCheck() { try { // The serializedObject accessor create a new SerializedObject if needed. // However, this will fail with a null exception if the target object no longer exists. #pragma warning disable 0219 SerializedObject so = serializedObject; } catch (System.NullReferenceException) { DestroyImmediate(this); return true; } return false; } } }