Firstborn/Library/PackageCache/com.unity.cinemachine@2.8.9/Editor/Utility/InspectorUtility.cs

202 lines
7.9 KiB
C#
Raw Normal View History

2023-03-28 13:24:16 -04:00
using UnityEngine;
using UnityEditor;
using System;
using System.Collections.Generic;
using System.IO;
namespace Cinemachine.Editor
{
/// <summary>
/// Collection of tools and helpers for drawing inspectors
/// </summary>
public class InspectorUtility
{
/// <summary>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.</summary>
/// <param name="rect">Rect in which to draw</param>
/// <param name="label">Main label</param>
/// <param name="props">Properties to place on the line</param>
/// <param name="subLabels">Sublabels for the properties</param>
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<GUIContent> actualLabels = new List<GUIContent>();
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;
}
/// <summary>
/// Normalize a curve so that each of X and Y axes ranges from 0 to 1
/// </summary>
/// <param name="curve">Curve to normalize</param>
/// <returns>The normalized curve</returns>
public static AnimationCurve NormalizeCurve(AnimationCurve curve)
{
return RuntimeUtility.NormalizeCurve(curve, true, true);
}
/// <summary>
/// Remove the "Cinemachine" prefix, then call the standard Unity Nicify.
/// </summary>
/// <param name="name">The name to nicify</param>
/// <returns>The nicified name</returns>
public static string NicifyClassName(string name)
{
if (name.StartsWith("Cinemachine"))
name = name.Substring(11); // Trim the prefix
return ObjectNames.NicifyVariableName(name);
}
/// <summary>
/// Add to a list all assets of a given type found in a given location
/// </summary>
/// <param name="type">The asset type to look for</param>
/// <param name="assets">The list to add found assets to</param>
/// <param name="path">The location in which to look. Path is relative to package root.</param>
public static void AddAssetsFromPackageSubDirectory(
Type type, List<ScriptableObject> 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
/// <summary>
/// Create a game object. Uses ObjectFactory if the Unity version is sufficient.
/// </summary>
/// <param name="name">Name to give the object</param>
/// <param name="types">Optional components to add</param>
/// <returns></returns>
public static GameObject CreateGameObject(string name, params Type[] types)
{
return ObjectFactory.CreateGameObject(name, types);
}
private static int m_lastRepaintFrame;
/// <summary>
/// Force a repaint of the Game View
/// </summary>
/// <param name="unused">Like it says</param>
public static void RepaintGameView(UnityEngine.Object unused = null)
{
if (m_lastRepaintFrame == Time.frameCount)
return;
m_lastRepaintFrame = Time.frameCount;
EditorApplication.QueuePlayerLoopUpdate();
UnityEditorInternal.InternalEditorUtility.RepaintAllViews();
}
/// <summary>
/// Try to get the name of the owning virtual camera oibject. If none then use
/// the object's name
/// </summary>
/// <param name="property"></param>
/// <returns></returns>
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<CinemachineVirtualCameraBase>();
if (vcam != null)
return vcam.Name;
return go.name;
}
return obj.name;
}
}
}