Files
DeltaVR/Assets/Plugins/FMOD/src/Editor/EventRefDrawer.cs

500 lines
21 KiB
C#

using System;
using System.Linq;
using System.Text;
using UnityEngine;
using UnityEditor;
namespace FMODUnity
{
[CustomPropertyDrawer(typeof(EventReference))]
public class EventReferenceDrawer : PropertyDrawer
{
private static readonly Texture RepairIcon = EditorUtils.LoadImage("Wrench.png");
private static readonly Texture WarningIcon = EditorUtils.LoadImage("NotFound.png");
private static readonly GUIContent NotFoundWarning = new GUIContent(L10n.Tr("Event Not Found"), WarningIcon);
private static GUIStyle buttonStyle;
private static Vector2 WarningSize()
{
return GUI.skin.label.CalcSize(NotFoundWarning);
}
private static float GetBaseHeight()
{
return GUI.skin.textField.CalcSize(GUIContent.none).y;
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
if (buttonStyle == null)
{
buttonStyle = new GUIStyle(GUI.skin.button);
buttonStyle.padding.top = 1;
buttonStyle.padding.bottom = 1;
}
Texture browseIcon = EditorUtils.LoadImage("SearchIconBlack.png");
Texture openIcon = EditorUtils.LoadImage("BrowserIcon.png");
Texture addIcon = EditorUtils.LoadImage("AddIcon.png");
Texture copyIcon = EditorUtils.LoadImage("CopyIcon.png");
using (new EditorGUI.PropertyScope(position, label, property))
{
HandleDragEvents(position, property);
EventReference eventReference = property.GetEventReference();
EditorEventRef editorEventRef = GetEditorEventRef(eventReference);
float baseHeight = GetBaseHeight();
Rect headerRect = position;
headerRect.width = EditorGUIUtility.labelWidth;
headerRect.height = baseHeight;
property.isExpanded = EditorGUI.Foldout(headerRect, property.isExpanded, label, true);
Rect addRect = new Rect(position.xMax - addIcon.width - 7, position.y, addIcon.width + 7, baseHeight);
Rect openRect = new Rect(addRect.x - openIcon.width - 7, position.y, openIcon.width + 6, baseHeight);
Rect searchRect = new Rect(openRect.x - browseIcon.width - 9, position.y, browseIcon.width + 8, baseHeight);
Rect pathRect = position;
pathRect.xMin = headerRect.xMax;
pathRect.xMax = searchRect.x - 3;
pathRect.height = baseHeight;
SerializedProperty pathProperty = GetPathProperty(property);
using (var scope = new EditorGUI.ChangeCheckScope())
{
EditorGUI.PropertyField(pathRect, pathProperty, GUIContent.none);
if (scope.changed)
{
SetEvent(property, pathProperty.stringValue);
}
}
if (GUI.Button(searchRect, new GUIContent(browseIcon, L10n.Tr("Search")), buttonStyle))
{
var eventBrowser = ScriptableObject.CreateInstance<EventBrowser>();
eventBrowser.ChooseEvent(property);
var windowRect = position;
windowRect.xMin = pathRect.xMin;
windowRect.position = GUIUtility.GUIToScreenPoint(windowRect.position);
windowRect.height = openRect.height + 1;
windowRect.width = Mathf.Max(windowRect.width, 300f);
eventBrowser.ShowAsDropDown(windowRect, new Vector2(windowRect.width, 400));
}
if (GUI.Button(addRect, new GUIContent(addIcon, L10n.Tr("Create New Event in Studio")), buttonStyle))
{
var addDropdown = EditorWindow.CreateInstance<CreateEventPopup>();
addDropdown.SelectEvent(property);
var windowRect = position;
windowRect.xMin = pathRect.xMin;
windowRect.position = GUIUtility.GUIToScreenPoint(windowRect.position);
windowRect.height = openRect.height + 1;
windowRect.width = Mathf.Max(windowRect.width, 300f);
addDropdown.ShowAsDropDown(windowRect, new Vector2(windowRect.width, 500));
}
if (GUI.Button(openRect, new GUIContent(openIcon, L10n.Tr("Open In Browser")), buttonStyle))
{
EventBrowser.ShowWindow();
EventBrowser eventBrowser = EditorWindow.GetWindow<EventBrowser>();
eventBrowser.FrameEvent(pathProperty.stringValue);
}
if (editorEventRef != null)
{
float labelY = headerRect.y + baseHeight;
MismatchInfo mismatch = GetMismatch(eventReference, editorEventRef);
if (mismatch != null)
{
Rect warningRect = pathRect;
warningRect.xMax = position.xMax;
warningRect.y = labelY;
warningRect.height = WarningSize().y;
DrawMismatchUI(warningRect, openRect.x, openRect.width, mismatch, property);
labelY = warningRect.yMax;
}
if (property.isExpanded)
{
using (new EditorGUI.IndentLevelScope())
{
Rect labelRect = EditorGUI.IndentedRect(headerRect);
labelRect.y = labelY;
Rect valueRect = labelRect;
valueRect.xMin = labelRect.xMax;
valueRect.xMax = position.xMax - copyIcon.width - 7;
GUI.Label(labelRect, new GUIContent("GUID"));
GUI.Label(valueRect, eventReference.Guid.ToString());
Rect copyRect = valueRect;
copyRect.xMin = valueRect.xMax;
copyRect.xMax = position.xMax;
if (GUI.Button(copyRect, new GUIContent(copyIcon, L10n.Tr("Copy To Clipboard"))))
{
EditorGUIUtility.systemCopyBuffer = eventReference.Guid.ToString();
}
valueRect.xMax = position.xMax;
labelRect.y += baseHeight;
valueRect.y += baseHeight;
GUI.Label(labelRect, new GUIContent(L10n.Tr("Banks")));
GUI.Label(valueRect, string.Join(", ", editorEventRef.Banks.Select(x => x.Name).ToArray()));
labelRect.y += baseHeight;
valueRect.y += baseHeight;
GUI.Label(labelRect, new GUIContent(L10n.Tr("Panning")));
GUI.Label(valueRect, editorEventRef.Is3D ? "3D" : "2D");
labelRect.y += baseHeight;
valueRect.y += baseHeight;
GUI.Label(labelRect, new GUIContent(L10n.Tr("Stream")));
GUI.Label(valueRect, editorEventRef.IsStream.ToString());
labelRect.y += baseHeight;
valueRect.y += baseHeight;
GUI.Label(labelRect, new GUIContent(L10n.Tr("Oneshot")));
GUI.Label(valueRect, editorEventRef.IsOneShot.ToString());
labelRect.y += baseHeight;
valueRect.y += baseHeight;
}
}
}
else
{
EditorEventRef renamedEvent = GetRenamedEventRef(eventReference);
if (renamedEvent != null)
{
MismatchInfo mismatch = new MismatchInfo() {
Message = string.Format(L10n.Tr("Moved to {0}"), renamedEvent.Path),
HelpText = string.Format(
L10n.Tr("This event has been moved in FMOD Studio.\nYou can click the repair button to update the path to the new location, or run the <b>{0}</b> command to scan your project for similar issues and fix them all."),
EventReferenceUpdater.MenuPath),
RepairTooltip = string.Format(L10n.Tr("Repair: set path to {0}"), renamedEvent.Path),
RepairAction = (p) => {
p.FindPropertyRelative("Path").stringValue = renamedEvent.Path;
},
};
using (new EditorGUI.IndentLevelScope())
{
Rect mismatchRect = pathRect;
mismatchRect.xMin = position.xMin;
mismatchRect.xMax = position.xMax;
mismatchRect.y += baseHeight;
mismatchRect.height = baseHeight;
mismatchRect = EditorGUI.IndentedRect(mismatchRect);
DrawMismatchUI(mismatchRect, openRect.x, openRect.width, mismatch, property);
}
}
else
{
Rect labelRect = pathRect;
labelRect.xMax = position.xMax;
labelRect.y += baseHeight;
labelRect.height = WarningSize().y;
GUI.Label(labelRect, NotFoundWarning);
}
}
}
}
private static void HandleDragEvents(Rect position, SerializedProperty property)
{
Event e = Event.current;
if (e.type == EventType.DragPerform && position.Contains(e.mousePosition))
{
if (DragAndDrop.objectReferences.Length > 0 &&
DragAndDrop.objectReferences[0] != null &&
DragAndDrop.objectReferences[0].GetType() == typeof(EditorEventRef))
{
EditorEventRef eventRef = DragAndDrop.objectReferences[0] as EditorEventRef;
property.SetEventReference(eventRef.Guid, eventRef.Path);
GUI.changed = true;
e.Use();
}
}
if (e.type == EventType.DragUpdated && position.Contains(e.mousePosition))
{
if (DragAndDrop.objectReferences.Length > 0 &&
DragAndDrop.objectReferences[0] != null &&
DragAndDrop.objectReferences[0].GetType() == typeof(EditorEventRef))
{
DragAndDrop.visualMode = DragAndDropVisualMode.Move;
DragAndDrop.AcceptDrag();
e.Use();
}
}
}
private class MismatchInfo
{
public string Message;
public string HelpText;
public string RepairTooltip;
public Action<SerializedProperty> RepairAction;
}
private static void DrawMismatchUI(Rect rect, float repairButtonX, float repairButtonWidth,
MismatchInfo mismatch, SerializedProperty property)
{
rect = EditorUtils.DrawHelpButton(rect, () => new SimpleHelp(mismatch.HelpText, 400));
Rect repairRect = new Rect(repairButtonX, rect.y, repairButtonWidth, GetBaseHeight());
if (GUI.Button(repairRect, new GUIContent(RepairIcon, mismatch.RepairTooltip), buttonStyle))
{
mismatch.RepairAction(property);
}
Rect labelRect = rect;
labelRect.xMax = repairRect.xMin;
GUI.Label(labelRect, new GUIContent(mismatch.Message, WarningIcon));
}
private static MismatchInfo GetMismatch(EventReference eventReference, EditorEventRef editorEventRef)
{
if (EventManager.GetEventLinkage(eventReference) == EventLinkage.Path)
{
if (eventReference.Guid != editorEventRef.Guid)
{
return new MismatchInfo() {
Message = L10n.Tr("GUID doesn't match path"),
HelpText = string.Format(
L10n.Tr("The GUID on this EventReference doesn't match the path.\nYou can click the repair button to update the GUID to match the path, or run the <b>{0}</b> command to scan your project for similar issues and fix them all."),
EventReferenceUpdater.MenuPath),
RepairTooltip = string.Format(L10n.Tr("Repair: set GUID to {0}"), editorEventRef.Guid),
RepairAction = (property) => {
property.FindPropertyRelative("Guid").SetGuid(editorEventRef.Guid);
},
};
}
}
else // EventLinkage.GUID
{
if (eventReference.Path != editorEventRef.Path)
{
return new MismatchInfo() {
Message = L10n.Tr("Path doesn't match GUID"),
HelpText = string.Format(
L10n.Tr("The path on this EventReference doesn't match the GUID.\nYou can click the repair button to update the path to match the GUID, or run the <b>{0}</b> command to scan your project for similar issues and fix them all."),
EventReferenceUpdater.MenuPath),
RepairTooltip = string.Format(L10n.Tr("Repair: set path to '{0}'"), editorEventRef.Path),
RepairAction = (property) => {
property.FindPropertyRelative("Path").stringValue = editorEventRef.Path;
},
};
}
}
return null;
}
private static void SetEvent(SerializedProperty property, string path)
{
EditorEventRef eventRef = EventManager.EventFromPath(path);
if (eventRef != null)
{
property.SetEventReference(eventRef.Guid, eventRef.Path);
}
else
{
property.SetEventReference(new FMOD.GUID(), path);
}
}
private static SerializedProperty GetGuidProperty(SerializedProperty property)
{
return property.FindPropertyRelative("Guid");
}
private static SerializedProperty GetPathProperty(SerializedProperty property)
{
return property.FindPropertyRelative("Path");
}
private static EditorEventRef GetEditorEventRef(EventReference eventReference)
{
if (EventManager.GetEventLinkage(eventReference) == EventLinkage.Path)
{
return EventManager.EventFromPath(eventReference.Path);
}
else // Assume EventLinkage.GUID
{
return EventManager.EventFromGUID(eventReference.Guid);
}
}
private static EditorEventRef GetRenamedEventRef(EventReference eventReference)
{
if (Settings.Instance.EventLinkage == EventLinkage.Path && !eventReference.Guid.IsNull)
{
EditorEventRef editorEventRef = EventManager.EventFromGUID(eventReference.Guid);
if (editorEventRef != null && editorEventRef.Path != eventReference.Path)
{
return editorEventRef;
}
}
return null;
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
float baseHeight = GetBaseHeight();
EventReference eventReference = property.GetEventReference();
EditorEventRef editorEventRef = GetEditorEventRef(eventReference);
if (editorEventRef == null)
{
return baseHeight + WarningSize().y;
}
else
{
float height;
if (property.isExpanded)
{
height = baseHeight * 6; // 5 lines of info
}
else
{
height = baseHeight;
}
if (GetMismatch(eventReference, editorEventRef) != null)
{
height += WarningSize().y;
}
return height;
}
}
}
#pragma warning disable 0618 // Suppress the warning about using the obsolete EventRefAttribute class
[CustomPropertyDrawer(typeof(EventRefAttribute))]
#pragma warning restore 0618
public class LegacyEventRefDrawer : PropertyDrawer
{
private GUIStyle RichTextStyle;
private static readonly string HelpText =
string.Format(L10n.Tr("This field has the <b>[EventRef]</b> attribute, which is obsolete.\nTo resolve this issue:\n* Add a field of type <b>EventReference</b> to this class\nSet the <b>MigrateTo</b> property on the <b>[EventRef]</b> attribute: <b>[EventRef(MigrateTo=\"<fieldname>\")]</b>\n Run the <b>{0}</b> command to automatically migrate values from this field to the <b>EventReference</b> field"), EventReferenceUpdater.MenuPath);
private static readonly Texture InfoIcon = EditorGUIUtility.IconContent("console.infoicon.sml").image;
private static readonly Texture WarningIcon = EditorUtils.LoadImage("NotFound.png");
private void AffirmStyles()
{
if (RichTextStyle == null)
{
RichTextStyle = new GUIStyle(GUI.skin.label) { richText = true };
}
}
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
AffirmStyles();
label = EditorGUI.BeginProperty(position, label, property);
Rect pathRect = position;
pathRect.height = EditorGUIUtility.singleLineHeight;
pathRect = EditorGUI.PrefixLabel(pathRect, label);
EditorGUI.PropertyField(pathRect, property, GUIContent.none);
using (new EditorGUI.IndentLevelScope())
{
GUIContent content = StatusContent(property);
Rect infoRect = EditorGUI.IndentedRect(position);
infoRect.y = pathRect.yMax;
infoRect.height = StatusSize(content).y;
infoRect = EditorUtils.DrawHelpButton(infoRect, () => new SimpleHelp(HelpText, 400));
GUI.Label(infoRect, content, RichTextStyle);
}
EditorGUI.EndProperty();
}
private GUIContent StatusContent(SerializedProperty property)
{
#pragma warning disable 0618 // Suppress the warning about using the obsolete EventRefAttribute class
string migrationTarget = (attribute as EventRefAttribute).MigrateTo;
#pragma warning restore 0618
if (string.IsNullOrEmpty(migrationTarget))
{
return new GUIContent(L10n.Tr("<b>[EventRef]</b> is obsolete - use the <b>EventReference</b> type instead."),
WarningIcon);
}
else
{
int parentPathLength = property.propertyPath.LastIndexOf('.');
if (parentPathLength >= 0)
{
migrationTarget = string.Format("{0}.{1}", property.propertyPath.Remove(parentPathLength), migrationTarget);
}
SerializedProperty targetProperty = property.serializedObject.FindProperty(migrationTarget);
if (targetProperty != null)
{
return new GUIContent(string.Format(L10n.Tr("Will be migrated to <b>{0}</b>"), targetProperty.displayName),
InfoIcon);
}
else
{
return new GUIContent(string.Format(L10n.Tr("Migration target <b>{0}</b> is missing"), migrationTarget),
WarningIcon);
}
}
}
private Vector2 StatusSize(GUIContent content)
{
AffirmStyles();
return Vector2.Max(RichTextStyle.CalcSize(content), EditorUtils.GetHelpButtonSize());
}
public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUIUtility.singleLineHeight + StatusSize(StatusContent(property)).y;
}
}
}