using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using System.IO;
namespace Cinemachine.Editor
{
///
/// Collection of tools and helpers for drawing inspectors
///
public class InspectorUtility
{
/// Put multiple properties on a single inspector line, with
/// optional label overrides. Passing null as a label (or sublabel) override will
/// cause the property's displayName to be used as a label. For no label at all,
/// pass GUIContent.none.
/// Rect in which to draw
/// Main label
/// Properties to place on the line
/// Sublabels for the properties
public static void MultiPropertyOnLine(
Rect rect,
GUIContent label,
SerializedProperty[] props, GUIContent[] subLabels)
{
if (props == null || props.Length == 0)
return;
const int hSpace = 2;
int indentLevel = EditorGUI.indentLevel;
float labelWidth = EditorGUIUtility.labelWidth;
float totalSubLabelWidth = 0;
int numBoolColumns = 0;
List actualLabels = new List();
for (int i = 0; i < props.Length; ++i)
{
GUIContent sublabel = new GUIContent(props[i].displayName, props[i].tooltip);
if (subLabels != null && subLabels.Length > i && subLabels[i] != null)
sublabel = subLabels[i];
actualLabels.Add(sublabel);
totalSubLabelWidth += GUI.skin.label.CalcSize(sublabel).x;
if (i > 0)
totalSubLabelWidth += hSpace;
// Special handling for toggles, or it looks stupid
if (props[i].propertyType == SerializedPropertyType.Boolean)
{
totalSubLabelWidth += rect.height;
++numBoolColumns;
}
}
float subFieldWidth = rect.width - labelWidth - totalSubLabelWidth;
float numCols = props.Length - numBoolColumns;
float colWidth = numCols == 0 ? 0 : subFieldWidth / numCols;
// Main label. If no first sublabel, then main label must take on that
// role, for mouse dragging value-scrolling support
int subfieldStartIndex = 0;
if (label == null)
label = new GUIContent(props[0].displayName, props[0].tooltip);
if (actualLabels[0] != GUIContent.none)
rect = EditorGUI.PrefixLabel(rect, label);
else
{
rect.width = labelWidth + colWidth;
EditorGUI.PropertyField(rect, props[0], label);
rect.x += rect.width + hSpace;
subfieldStartIndex = 1;
}
for (int i = subfieldStartIndex; i < props.Length; ++i)
{
EditorGUI.indentLevel = 0;
EditorGUIUtility.labelWidth = GUI.skin.label.CalcSize(actualLabels[i]).x;
if (props[i].propertyType == SerializedPropertyType.Boolean)
{
rect.width = EditorGUIUtility.labelWidth + rect.height;
props[i].boolValue = EditorGUI.ToggleLeft(rect, actualLabels[i], props[i].boolValue);
}
else
{
rect.width = EditorGUIUtility.labelWidth + colWidth;
EditorGUI.PropertyField(rect, props[i], actualLabels[i]);
}
rect.x += rect.width + hSpace;
}
EditorGUIUtility.labelWidth = labelWidth;
EditorGUI.indentLevel = indentLevel;
}
///
/// Normalize a curve so that each of X and Y axes ranges from 0 to 1
///
/// Curve to normalize
/// The normalized curve
public static AnimationCurve NormalizeCurve(AnimationCurve curve)
{
return RuntimeUtility.NormalizeCurve(curve, true, true);
}
///
/// Remove the "Cinemachine" prefix, then call the standard Unity Nicify.
///
/// The name to nicify
/// The nicified name
public static string NicifyClassName(string name)
{
if (name.StartsWith("Cinemachine"))
name = name.Substring(11); // Trim the prefix
return ObjectNames.NicifyVariableName(name);
}
///
/// Add to a list all assets of a given type found in a given location
///
/// The asset type to look for
/// The list to add found assets to
/// The location in which to look. Path is relative to package root.
public static void AddAssetsFromPackageSubDirectory(
Type type, List assets, string path)
{
try
{
path = "/" + path;
var info = new DirectoryInfo(ScriptableObjectUtility.CinemachineInstallPath + path);
path = ScriptableObjectUtility.kPackageRoot + path + "/";
var fileInfo = info.GetFiles();
foreach (var file in fileInfo)
{
if (file.Extension != ".asset")
continue;
string name = path + file.Name;
ScriptableObject a = AssetDatabase.LoadAssetAtPath(name, type) as ScriptableObject;
if (a != null)
assets.Add(a);
}
}
catch
{
}
}
// Temporarily here
///
/// Create a game object. Uses ObjectFactory if the Unity version is sufficient.
///
/// Name to give the object
/// Optional components to add
///
public static GameObject CreateGameObject(string name, params Type[] types)
{
return ObjectFactory.CreateGameObject(name, types);
}
private static int m_lastRepaintFrame;
///
/// Force a repaint of the Game View
///
/// Like it says
public static void RepaintGameView(UnityEngine.Object unused = null)
{
if (m_lastRepaintFrame == Time.frameCount)
return;
m_lastRepaintFrame = Time.frameCount;
EditorApplication.QueuePlayerLoopUpdate();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
///
/// Try to get the name of the owning virtual camera oibject. If none then use
/// the object's name
///
///
///
internal static string GetVirtualCameraObjectName(SerializedProperty property)
{
// A little hacky here, as we favour virtual cameras...
var obj = property.serializedObject.targetObject;
GameObject go = obj as GameObject;
if (go == null)
{
var component = obj as Component;
if (component != null)
go = component.gameObject;
}
if (go != null)
{
var vcam = go.GetComponentInParent();
if (vcam != null)
return vcam.Name;
return go.name;
}
return obj.name;
}
}
}