using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using Cinemachine.Utility;
namespace Cinemachine.Editor
{
///
/// Base class for virtual camera editors.
/// Handles drawing the header and the basic properties.
///
/// The type of CinemachineVirtualCameraBase being edited
public class CinemachineVirtualCameraBaseEditor
: BaseEditor where T : CinemachineVirtualCameraBase
{
/// A collection of GUIContent for use in the inspector
public static class Styles
{
/// GUIContent for Add Extension
public static GUIContent addExtensionLabel = new GUIContent("Add Extension");
/// GUIContent for no-multi-select message
public static GUIContent virtualCameraChildrenInfoMsg
= new GUIContent("The Virtual Camera Children field is not available when multiple objects are selected.");
}
static Type[] sExtensionTypes; // First entry is null
static string[] sExtensionNames;
bool IsPrefabBase { get; set; }
/// Obsolete, do not use. Use the overload, which is more performant
/// List of property names to exclude
protected override List GetExcludedPropertiesInInspector()
{ return base.GetExcludedPropertiesInInspector(); }
/// Get the property names to exclude in the inspector.
/// Add the names to this list
protected override void GetExcludedPropertiesInInspector(List excluded)
{
base.GetExcludedPropertiesInInspector(excluded);
if (Target.m_ExcludedPropertiesInInspector != null)
excluded.AddRange(Target.m_ExcludedPropertiesInInspector);
}
/// Inspector panel is being enabled
protected virtual void OnEnable()
{
IsPrefabBase = Target.gameObject.scene.name == null; // causes a small GC alloc
if (sExtensionTypes == null)
{
// Populate the extension list
List exts = new List();
List names = new List();
exts.Add(null);
names.Add("(select)");
var allExtensions
= ReflectionHelpers.GetTypesInAllDependentAssemblies(
(Type t) => typeof(CinemachineExtension).IsAssignableFrom(t) && !t.IsAbstract);
foreach (Type t in allExtensions)
{
exts.Add(t);
names.Add(t.Name);
}
sExtensionTypes = exts.ToArray();
sExtensionNames = names.ToArray();
}
}
/// Inspector panel is being disabled
protected virtual void OnDisable()
{
if (CinemachineBrain.SoloCamera == (ICinemachineCamera)Target)
{
CinemachineBrain.SoloCamera = null;
InspectorUtility.RepaintGameView();
}
}
/// Create the contents of the inspector panel
public override void OnInspectorGUI()
{
BeginInspector();
DrawHeaderInInspector();
DrawRemainingPropertiesInInspector();
DrawExtensionsWidgetInInspector();
}
///
/// Draw the virtual camera header in the inspector.
/// This includes Solo button, Live status, and global settings
///
protected void DrawHeaderInInspector()
{
if (!IsPropertyExcluded("Header"))
{
DrawCameraStatusInInspector();
DrawGlobalControlsInInspector();
}
ExcludeProperty("Header");
}
///
/// Draw the LookAt and Follow targets in the inspector
///
/// Follow target property
/// LookAt target property
protected void DrawTargetsInInspector(
SerializedProperty followTarget, SerializedProperty lookAtTarget)
{
EditorGUI.BeginChangeCheck();
if (!IsPropertyExcluded(followTarget.name))
{
if (Target.ParentCamera == null || Target.ParentCamera.Follow == null)
EditorGUILayout.PropertyField(followTarget);
else
EditorGUILayout.PropertyField(followTarget,
new GUIContent(followTarget.displayName + " Override"));
ExcludeProperty(followTarget.name);
}
if (!IsPropertyExcluded(lookAtTarget.name))
{
if (Target.ParentCamera == null || Target.ParentCamera.LookAt == null)
EditorGUILayout.PropertyField(lookAtTarget);
else
EditorGUILayout.PropertyField(lookAtTarget,
new GUIContent(lookAtTarget.displayName + " Override"));
ExcludeProperty(lookAtTarget.name);
}
if (EditorGUI.EndChangeCheck())
serializedObject.ApplyModifiedProperties();
}
///
/// Draw the Extensions dropdown in the inspector
///
protected void DrawExtensionsWidgetInInspector()
{
if (!IsPropertyExcluded("Extensions"))
{
EditorGUILayout.Space();
EditorGUILayout.LabelField("Extensions", EditorStyles.boldLabel);
Rect rect = EditorGUILayout.GetControlRect(true, EditorGUIUtility.singleLineHeight);
rect = EditorGUI.PrefixLabel(rect, Styles.addExtensionLabel);
int selection = EditorGUI.Popup(rect, 0, sExtensionNames);
if (selection > 0)
{
Type extType = sExtensionTypes[selection];
for (int i = 0; i < targets.Length; i++)
{
var targetGO = (targets[i] as CinemachineVirtualCameraBase).gameObject;
if (targetGO != null && targetGO.GetComponent(extType) == null)
Undo.AddComponent(targetGO, extType);
}
}
ExcludeProperty("Extensions");
}
}
///
/// Draw the Live status in the inspector, and the Solo button
///
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;
}
}
///
/// Draw the global settings controls in the inspector
///
protected void DrawGlobalControlsInInspector()
{
CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides
= EditorGUILayout.Toggle(
new GUIContent(
"Game Window Guides",
"Enable the display of overlays in the Game window. You can adjust colours and opacity in Edit/Preferences/Cinemachine."),
CinemachineSettings.CinemachineCoreSettings.ShowInGameGuides);
SaveDuringPlay.SaveDuringPlay.Enabled
= EditorGUILayout.Toggle(
new GUIContent(
"Save During Play",
"If checked, Virtual Camera settings changes made during Play Mode will be propagated back to the scene when Play Mode is exited."),
SaveDuringPlay.SaveDuringPlay.Enabled);
if (Application.isPlaying && SaveDuringPlay.SaveDuringPlay.Enabled)
EditorGUILayout.HelpBox(
" Virtual Camera settings changes made during Play Mode will be propagated back to the scene when Play Mode is exited.",
MessageType.Info);
}
}
}