using UnityEngine; using UnityEditor; using UnityEditorInternal; using System.Collections.Generic; namespace Cinemachine.Editor { [CustomEditor(typeof(CinemachineBlenderSettings))] internal sealed class CinemachineBlenderSettingsEditor : BaseEditor { private ReorderableList mBlendList; /// /// Called when building the Camera popup menus, to get the domain of possible /// cameras. If no delegate is set, will find all top-level (non-slave) /// virtual cameras in the scene. /// public GetAllVirtualCamerasDelegate GetAllVirtualCameras; public delegate CinemachineVirtualCameraBase[] GetAllVirtualCamerasDelegate(); /// Get the property names to exclude in the inspector. /// Add the names to this list protected override void GetExcludedPropertiesInInspector(List excluded) { base.GetExcludedPropertiesInInspector(excluded); excluded.Add(FieldPath(x => x.m_CustomBlends)); } public override void OnInspectorGUI() { BeginInspector(); if (mBlendList == null) SetupBlendList(); DrawRemainingPropertiesInInspector(); UpdateCameraCandidates(); mBlendList.DoLayoutList(); serializedObject.ApplyModifiedProperties(); } private const string kNoneLabel = "(none)"; private string[] mCameraCandidates; private Dictionary mCameraIndexLookup; private void UpdateCameraCandidates() { List vcams = new List(); mCameraIndexLookup = new Dictionary(); CinemachineVirtualCameraBase[] candidates; if (GetAllVirtualCameras != null) candidates = GetAllVirtualCameras(); else { // Get all top-level (i.e. non-slave) virtual cameras candidates = Resources.FindObjectsOfTypeAll( typeof(CinemachineVirtualCameraBase)) as CinemachineVirtualCameraBase[]; for (int i = 0; i < candidates.Length; ++i) if (candidates[i].ParentCamera != null) candidates[i] = null; } vcams.Add(kNoneLabel); vcams.Add(CinemachineBlenderSettings.kBlendFromAnyCameraLabel); foreach (CinemachineVirtualCameraBase c in candidates) if (c != null && !vcams.Contains(c.Name)) vcams.Add(c.Name); mCameraCandidates = vcams.ToArray(); for (int i = 0; i < mCameraCandidates.Length; ++i) mCameraIndexLookup[mCameraCandidates[i]] = i; } private int GetCameraIndex(string name) { if (name == null || mCameraIndexLookup == null) return 0; if (!mCameraIndexLookup.ContainsKey(name)) return 0; return mCameraIndexLookup[name]; } void DrawVcamSelector(Rect r, SerializedProperty prop) { r.width -= EditorGUIUtility.singleLineHeight; int current = GetCameraIndex(prop.stringValue); var oldColor = GUI.color; if (current == 0) GUI.color = new Color(1, 193.0f/255.0f, 7.0f/255.0f); // the "warning" icon color EditorGUI.PropertyField(r, prop, GUIContent.none); r.x += r.width; r.width = EditorGUIUtility.singleLineHeight; int sel = EditorGUI.Popup(r, current, mCameraCandidates); if (current != sel) prop.stringValue = (mCameraCandidates[sel] == kNoneLabel) ? string.Empty : mCameraCandidates[sel]; GUI.color = oldColor; } void SetupBlendList() { mBlendList = new ReorderableList(serializedObject, serializedObject.FindProperty(() => Target.m_CustomBlends), true, true, true, true); // Needed for accessing string names of fields CinemachineBlenderSettings.CustomBlend def = new CinemachineBlenderSettings.CustomBlend(); CinemachineBlendDefinition def2 = new CinemachineBlendDefinition(); float vSpace = 2; float hSpace = 3; float floatFieldWidth = EditorGUIUtility.singleLineHeight * 2.5f; mBlendList.drawHeaderCallback = (Rect rect) => { rect.width -= (EditorGUIUtility.singleLineHeight + 2 * hSpace); rect.width /= 3; rect.x += EditorGUIUtility.singleLineHeight; EditorGUI.LabelField(rect, "From"); rect.x += rect.width + hSpace; EditorGUI.LabelField(rect, "To"); rect.x += rect.width + hSpace; rect.width -= floatFieldWidth + hSpace; EditorGUI.LabelField(rect, "Style"); rect.x += rect.width + hSpace; rect.width = floatFieldWidth; EditorGUI.LabelField(rect, "Time"); }; mBlendList.drawElementCallback = (Rect rect, int index, bool isActive, bool isFocused) => { SerializedProperty element = mBlendList.serializedProperty.GetArrayElementAtIndex(index); rect.y += vSpace; rect.height = EditorGUIUtility.singleLineHeight; rect.width -= 2 * hSpace; rect.width /= 3; DrawVcamSelector(rect, element.FindPropertyRelative(() => def.m_From)); rect.x += rect.width + hSpace; DrawVcamSelector(rect, element.FindPropertyRelative(() => def.m_To)); SerializedProperty blendProp = element.FindPropertyRelative(() => def.m_Blend); rect.x += rect.width + hSpace; EditorGUI.PropertyField(rect, blendProp, GUIContent.none); }; mBlendList.onAddCallback = (ReorderableList l) => { var index = l.serializedProperty.arraySize; ++l.serializedProperty.arraySize; SerializedProperty blendProp = l.serializedProperty.GetArrayElementAtIndex( index).FindPropertyRelative(() => def.m_Blend); blendProp.FindPropertyRelative(() => def2.m_Style).enumValueIndex = (int)CinemachineBlendDefinition.Style.EaseInOut; blendProp.FindPropertyRelative(() => def2.m_Time).floatValue = 2f; }; } } }