/// <summary>
        /// Draw the Live status in the inspector, and the Solo button
        /// </summary>
        protected void DrawCameraStatusInInspector()
        {
            if (Selection.objects.Length > 1)
            {
                return;
            }

            // Is the camera navel-gazing?
            CameraState state = Target.State;

            if (state.HasLookAt && (state.ReferenceLookAt - state.CorrectedPosition).AlmostZero())
            {
                EditorGUILayout.HelpBox(
                    "The camera is positioned on the same point at which it is trying to look.",
                    MessageType.Warning);
            }

            // No status and Solo for prefabs
            if (IsPrefabBase)
            {
                return;
            }

            // Active status and Solo button
            Rect rect      = EditorGUILayout.GetControlRect(true);
            Rect rectLabel = new Rect(rect.x, rect.y, EditorGUIUtility.labelWidth, rect.height);

            rect.width -= rectLabel.width;
            rect.x     += rectLabel.width;

            Color color  = GUI.color;
            bool  isSolo = (CinemachineBrain.SoloCamera == (ICinemachineCamera)Target);

            if (isSolo)
            {
                GUI.color = CinemachineBrain.GetSoloGUIColor();
            }

            bool isLive = CinemachineCore.Instance.IsLive(Target);

            GUI.enabled = isLive;
            GUI.Label(rectLabel, isLive ? "Status: Live"
                : (Target.isActiveAndEnabled ? "Status: Standby" : "Status: Disabled"));
            GUI.enabled = true;

            float      labelWidth = 0;
            GUIContent updateText = GUIContent.none;

            UpdateTracker.UpdateClock updateMode = CinemachineCore.Instance.GetVcamUpdateStatus(Target);
            if (Application.isPlaying)
            {
                updateText = new GUIContent(
                    updateMode == UpdateTracker.UpdateClock.Fixed ? " Fixed Update" : " Late Update");
                var textDimensions = GUI.skin.label.CalcSize(updateText);
                labelWidth = textDimensions.x;
            }
            rect.width -= labelWidth;
            if (GUI.Button(rect, "Solo", "Button"))
            {
                isSolo = !isSolo;
                CinemachineBrain.SoloCamera = isSolo ? Target : null;
                InspectorUtility.RepaintGameView();
            }
            GUI.color = color;
            if (isSolo && !Application.isPlaying)
            {
                InspectorUtility.RepaintGameView();
            }

            if (labelWidth > 0)
            {
                GUI.enabled = false;
                rect.x     += rect.width; rect.width = labelWidth;
                GUI.Label(rect, updateText);
                GUI.enabled = true;
            }
        }
        protected void DrawPipelineInInspector()
        {
            UpdateInstanceData();
            foreach (CinemachineCore.Stage stage in Enum.GetValues(typeof(CinemachineCore.Stage)))
            {
                int index = (int)stage;

                // Skip pipeline stages that have no implementations
                if (index < 0 || sStageData[index].PopupOptions.Length <= 1)
                {
                    continue;
                }

                const float indentOffset = 4;

                GUIStyle stageBoxStyle = GUI.skin.box;
                EditorGUILayout.BeginVertical(stageBoxStyle);
                Rect rect = EditorGUILayout.GetControlRect(true);

                // Don't use PrefixLabel() because it will link the enabled status of field and label
                GUIContent label = new GUIContent(InspectorUtility.NicifyClassName(stage.ToString()));
                if (m_stageError[index])
                {
                    label.image = EditorGUIUtility.IconContent("console.warnicon.sml").image;
                }
                float labelWidth = EditorGUIUtility.labelWidth - (indentOffset + EditorGUI.indentLevel * 15);
                Rect  r          = rect; r.width = labelWidth;
                EditorGUI.LabelField(r, label);
                r           = rect; r.width -= labelWidth; r.x += labelWidth;
                GUI.enabled = !StageIsLocked(stage);
                int newSelection = EditorGUI.Popup(r, m_stageState[index], sStageData[index].PopupOptions);
                GUI.enabled = true;

                Type type = sStageData[index].types[newSelection];
                if (newSelection != m_stageState[index])
                {
                    SetPipelineStage(stage, type);
                    if (newSelection != 0)
                    {
                        sStageData[index].IsExpanded = true;
                    }
                    UpdateInstanceData(); // because we changed it
                    return;
                }
                if (type != null)
                {
                    Rect stageRect = new Rect(
                        rect.x - indentOffset, rect.y, rect.width + indentOffset, rect.height);
                    sStageData[index].IsExpanded = EditorGUI.Foldout(
                        stageRect, sStageData[index].IsExpanded, GUIContent.none, true);
                    if (sStageData[index].IsExpanded)
                    {
                        // Make the editor for that stage
                        UnityEditor.Editor e = GetEditorForPipelineStage(stage);
                        if (e != null)
                        {
                            ++EditorGUI.indentLevel;
                            EditorGUILayout.Separator();
                            e.OnInspectorGUI();
                            EditorGUILayout.Separator();
                            --EditorGUI.indentLevel;
                        }
                    }
                }
                EditorGUILayout.EndVertical();
            }
        }
        AxisState def    = new AxisState(); // to access name strings

        public override void OnGUI(Rect rect, SerializedProperty property, GUIContent label)
        {
            float height = EditorGUIUtility.singleLineHeight;

            rect.height = height;
            mExpanded   = EditorGUI.Foldout(rect, mExpanded, label, true);
            if (mExpanded)
            {
                ++EditorGUI.indentLevel;

                rect.y += height + vSpace;
                EditorGUI.PropertyField(rect, property.FindPropertyRelative(() => def.Value));

                if (!ValueRangeIsLocked(property))
                {
                    rect.y += height + vSpace;
                    InspectorUtility.MultiPropertyOnLine(rect, new GUIContent("Value Range"),
                                                         new [] { property.FindPropertyRelative(() => def.m_MinValue),
                                                                  property.FindPropertyRelative(() => def.m_MaxValue),
                                                                  property.FindPropertyRelative(() => def.m_Wrap) },
                                                         new [] { GUIContent.none, new GUIContent("to "), null });
                }

                rect.y += height + vSpace;
                InspectorUtility.MultiPropertyOnLine(rect, new GUIContent("Speed"),
                                                     new [] { property.FindPropertyRelative(() => def.m_MaxSpeed),
                                                              property.FindPropertyRelative(() => def.m_SpeedMode) },
                                                     new [] { GUIContent.none, new GUIContent("as") });

                rect.y += height + vSpace;
                InspectorUtility.MultiPropertyOnLine(
                    rect, null,
                    new [] { property.FindPropertyRelative(() => def.m_AccelTime),
                             property.FindPropertyRelative(() => def.m_DecelTime) },
                    new [] { GUIContent.none, null });

                if (HasRecentering(property))
                {
                    var rDef        = new AxisState.Recentering();
                    var recentering = property.FindPropertyRelative(() => def.m_Recentering);
                    rect.y += height + vSpace;
                    InspectorUtility.MultiPropertyOnLine(
                        rect, new GUIContent(recentering.displayName, recentering.tooltip),
                        new [] {
                        recentering.FindPropertyRelative(() => rDef.m_enabled),
                        recentering.FindPropertyRelative(() => rDef.m_WaitTime),
                        recentering.FindPropertyRelative(() => rDef.m_RecenteringTime)
                    },
                        new [] { new GUIContent(""),
                                 new GUIContent("Wait"),
                                 new GUIContent("Time") });
                }

                rect.y += height + vSpace;
                EditorGUI.PropertyField(rect, property.FindPropertyRelative(() => def.m_InputAxisName));

                rect.y += height + vSpace;
                InspectorUtility.MultiPropertyOnLine(rect, null,
                                                     new [] { property.FindPropertyRelative(() => def.m_InputAxisValue),
                                                              property.FindPropertyRelative(() => def.m_InvertInput) },
                                                     new [] { GUIContent.none, new GUIContent("Invert") });

                --EditorGUI.indentLevel;
            }
        }
        bool DrawActionSettings(SerializedProperty property, bool expanded)
        {
            if (mFoldoutStyle == null)
            {
                mFoldoutStyle = new GUIStyle(EditorStyles.foldout)
                {
                    fontStyle = FontStyle.Bold
                }
            }
            ;

            Rect r = EditorGUILayout.GetControlRect();

            expanded = EditorGUI.Foldout(r, expanded, property.displayName, true, mFoldoutStyle);
            if (expanded)
            {
                SerializedProperty actionProp = property.FindPropertyRelative(() => def.m_Action);
                EditorGUILayout.PropertyField(actionProp);

                SerializedProperty targetProp = property.FindPropertyRelative(() => def.m_Target);
                bool isCustom = (actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.Custom);
                if (!isCustom)
                {
                    EditorGUILayout.PropertyField(targetProp);
                }

                bool isBoost = actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.PriorityBoost;
                if (isBoost)
                {
                    EditorGUILayout.PropertyField(property.FindPropertyRelative(() => def.m_BoostAmount));
                }

                bool isPlay = actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.Play;
                if (isPlay)
                {
                    SerializedProperty[] props = new SerializedProperty[2]
                    {
                        property.FindPropertyRelative(() => def.m_StartTime),
                        property.FindPropertyRelative(() => def.m_Mode)
                    };
                    GUIContent[] sublabels = new GUIContent[2]
                    {
                        GUIContent.none, new GUIContent("s", props[1].tooltip)
                    };
                    InspectorUtility.MultiPropertyOnLine(
                        EditorGUILayout.GetControlRect(), null, props, sublabels);
                }

                if (actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.Custom)
                {
                    EditorGUILayout.HelpBox("Use the Event() list below to call custom methods", MessageType.Info);
                }

                if (isBoost)
                {
                    if (GetTargetComponent <CinemachineVirtualCameraBase>(targetProp.objectReferenceValue) == null)
                    {
                        EditorGUILayout.HelpBox("Target must be a CinemachineVirtualCameraBase in order to boost priority", MessageType.Warning);
                    }
                }

                bool isEnableDisable = (actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.Enable ||
                                        actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.Disable);
                if (isEnableDisable)
                {
                    var value = targetProp.objectReferenceValue;
                    if (value != null && (value as Behaviour) == null)
                    {
                        EditorGUILayout.HelpBox("Target must be a Behaviour in order to Enable/Disable", MessageType.Warning);
                    }
                }

                bool isPlayStop = isPlay ||
                                  actionProp.intValue == (int)CinemachineTriggerAction.ActionSettings.Mode.Stop;
                if (isPlayStop)
                {
                    if (GetTargetComponent <Animator>(targetProp.objectReferenceValue) == null &&
                        GetTargetComponent <PlayableDirector>(targetProp.objectReferenceValue) == null)
                    {
                        EditorGUILayout.HelpBox("Target must have a PlayableDirector or Animator in order to Play/Stop", MessageType.Warning);
                    }
                }

                if (!isCustom && targetProp.objectReferenceValue == null)
                {
                    EditorGUILayout.HelpBox("No action will be taken because target is not valid", MessageType.Info);
                }

                EditorGUILayout.Space();
                EditorGUILayout.LabelField("This event will be invoked.  Add calls to custom methods here:");
                EditorGUILayout.PropertyField(property.FindPropertyRelative(() => def.m_Event));
            }
            property.serializedObject.ApplyModifiedProperties();
            return(expanded);
        }

        T GetTargetComponent <T>(UnityEngine.Object obj) where T : Behaviour
        {
            UnityEngine.Object currentTarget = obj;
            if (currentTarget != null)
            {
                GameObject targetGameObject = currentTarget as GameObject;
                Behaviour  targetBehaviour  = currentTarget as Behaviour;
                if (targetBehaviour != null)
                {
                    targetGameObject = targetBehaviour.gameObject;
                }
                if (targetBehaviour is T)
                {
                    return(targetBehaviour as T);
                }
                if (targetGameObject != null)
                {
                    return(targetGameObject.GetComponent <T>());
                }
            }
            return(null);
        }
    }
        private void DrawComponentInspector()
        {
            const float indentSize = 15; // GML wtf get rid of this
            int         index      = (int)m_Stage;
            Rect        rect       = EditorGUILayout.GetControlRect(true);

            // Don't use PrefixLabel() because it will link the enabled status of field and label
            GUIContent label = new GUIContent(InspectorUtility.NicifyClassName(m_Stage.ToString()));

            if (m_StageError)
            {
                label.image = EditorGUIUtility.IconContent("console.warnicon.sml").image;
            }
            float labelWidth = EditorGUIUtility.labelWidth - EditorGUI.indentLevel * indentSize;
            Rect  r          = rect; r.width = labelWidth;

            EditorGUI.LabelField(r, label);

            r = rect; r.width -= labelWidth; r.x += labelWidth;

            EditorGUI.BeginChangeCheck();
            bool wasEnabled = GUI.enabled;

            if (TypeIsLocked)
            {
                GUI.enabled = false;
            }
            EditorGUI.showMixedValue = m_IsMixedType;
            m_StageSelection         = EditorGUI.Popup(r, m_StageSelection, sStageData[index].PopupOptions);
            EditorGUI.showMixedValue = false;
            GUI.enabled = wasEnabled;
            Type type = sStageData[index].types[m_StageSelection];

            if (EditorGUI.EndChangeCheck())
            {
                SetComponent(m_Stage, type);
                if (m_StageSelection != 0)
                {
                    sStageData[index].IsExpanded = true;
                }
                GUIUtility.ExitGUI();
                return; // let the component editor be recreated
            }

            // Draw the embedded editor
            if (type != null)
            {
                r = new Rect(rect.x, rect.y, labelWidth, rect.height);
                var isExpanded = m_IsMixedType ? false : EditorGUI.Foldout(
                    r, sStageData[index].IsExpanded, GUIContent.none, true);
                if (isExpanded || isExpanded != sStageData[index].IsExpanded)
                {
                    // Make the editor for that stage
                    ActiveEditorRegistry.SetActiveEditor(m_ComponentEditor, isExpanded);
                    if (isExpanded && m_ComponentEditor != null)
                    {
                        ++EditorGUI.indentLevel;
                        m_ComponentEditor.OnInspectorGUI();
                        --EditorGUI.indentLevel;
                    }
                }
                sStageData[index].IsExpanded = isExpanded;
            }
        }
 private void OnEnable()
 {
     m_BlendsEditor           = new EmbeddeAssetEditor <CinemachineBlenderSettings>(FieldPath(x => x.m_CustomBlends), this);
     m_BlendsEditor.OnChanged = (CinemachineBlenderSettings b) => { InspectorUtility.RepaintGameView(); };
 }
 protected virtual void OnDisable()
 {
     CinemachineDebug.OnGUIHandlers -= OnGUI;
     InspectorUtility.RepaintGameView(Target);
 }