Unity-jump-proj
This commit is contained in:
@ -0,0 +1,28 @@
|
||||
using JetBrains.Annotations;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
[CustomEditor(typeof(SignalAsset))]
|
||||
class SignalAssetInspector : Editor
|
||||
{
|
||||
[MenuItem("Assets/Create/Signal", false, 451)]
|
||||
[UsedImplicitly]
|
||||
public static void CreateNewSignal()
|
||||
{
|
||||
var icon = EditorGUIUtility.IconContent("SignalAsset Icon").image as Texture2D;
|
||||
ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, CreateInstance<DoCreateSignalAsset>(), "New Signal.signal", icon, null);
|
||||
}
|
||||
|
||||
class DoCreateSignalAsset : ProjectWindowCallback.EndNameEditAction
|
||||
{
|
||||
public override void Action(int instanceId, string pathName, string resourceFile)
|
||||
{
|
||||
var signalAsset = CreateInstance<SignalAsset>();
|
||||
AssetDatabase.CreateAsset(signalAsset, pathName);
|
||||
ProjectWindowUtil.ShowCreatedAsset(signalAsset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58004290eb3aab44e9823d1f25c4ed73
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,23 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
[CustomTimelineEditor(typeof(SignalEmitter))]
|
||||
class SignalEmitterEditor : MarkerEditor
|
||||
{
|
||||
static readonly string MissingAssetError = L10n.Tr("No signal assigned");
|
||||
|
||||
public override MarkerDrawOptions GetMarkerOptions(IMarker marker)
|
||||
{
|
||||
var options = base.GetMarkerOptions(marker);
|
||||
SignalEmitter emitter = (SignalEmitter)marker;
|
||||
if (emitter.asset != null)
|
||||
options.tooltip = emitter.asset.name;
|
||||
else
|
||||
options.errorText = MissingAssetError;
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51a7878f6c989394782db73339e90e46
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,377 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Timeline;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
[CustomEditor(typeof(SignalEmitter), true)]
|
||||
[CanEditMultipleObjects]
|
||||
class SignalEmitterInspector : MarkerInspector, ISignalAssetProvider
|
||||
{
|
||||
SerializedProperty m_RetroactiveProperty;
|
||||
SerializedProperty m_EmitOnceProperty;
|
||||
|
||||
SignalEmitter m_Signal;
|
||||
GameObject m_BoundGameObject;
|
||||
PlayableDirector m_AssociatedDirector;
|
||||
bool m_TargetsHaveTheSameBinding;
|
||||
|
||||
readonly Dictionary<Component, Editor> m_Editors = new Dictionary<Component, Editor>();
|
||||
readonly Dictionary<Component, bool> m_Foldouts = new Dictionary<Component, bool>();
|
||||
List<Component> m_Receivers = new List<Component>();
|
||||
|
||||
static GUIStyle s_FoldoutStyle;
|
||||
internal static GUIStyle foldoutStyle
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_FoldoutStyle == null)
|
||||
{
|
||||
s_FoldoutStyle = new GUIStyle(EditorStyles.foldout) { fontStyle = FontStyle.Bold };
|
||||
}
|
||||
|
||||
return s_FoldoutStyle;
|
||||
}
|
||||
}
|
||||
|
||||
public SignalAsset signalAsset
|
||||
{
|
||||
get
|
||||
{
|
||||
var emitter = target as SignalEmitter;
|
||||
return signalAssetSameValue ? emitter.asset : null;
|
||||
}
|
||||
set
|
||||
{
|
||||
AssignSignalAsset(value);
|
||||
}
|
||||
}
|
||||
|
||||
bool signalAssetSameValue
|
||||
{
|
||||
get
|
||||
{
|
||||
var emitters = targets.Cast<SignalEmitter>().ToList();
|
||||
return emitters.Select(x => x.asset).Distinct().Count() == 1;
|
||||
}
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
Undo.undoRedoPerformed += OnUndoRedo; // subscribe to the event
|
||||
m_Signal = target as SignalEmitter;
|
||||
m_RetroactiveProperty = serializedObject.FindProperty("m_Retroactive");
|
||||
m_EmitOnceProperty = serializedObject.FindProperty("m_EmitOnce");
|
||||
// In a vast majority of the cases, when this becomes enabled,
|
||||
// the timeline window will be focused on the correct timeline
|
||||
// in which case TimelineEditor.inspectedDirector is safe to use
|
||||
m_AssociatedDirector = TimelineEditor.inspectedDirector;
|
||||
UpdateState();
|
||||
}
|
||||
|
||||
internal override bool IsEnabled()
|
||||
{
|
||||
return TimelineUtility.IsCurrentSequenceValid() && !IsCurrentSequenceReadOnly() && base.IsEnabled();
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
using (var changeScope = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
var property = serializedObject.GetIterator();
|
||||
var expanded = true;
|
||||
while (property.NextVisible(expanded))
|
||||
{
|
||||
expanded = false;
|
||||
if (SkipField(property.propertyPath))
|
||||
continue;
|
||||
EditorGUILayout.PropertyField(property, true);
|
||||
}
|
||||
|
||||
DrawSignalFlags();
|
||||
UpdateState();
|
||||
DrawNameSelectorAndSignalList();
|
||||
|
||||
if (changeScope.changed)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
TimelineEditor.Refresh(RefreshReason.ContentsModified | RefreshReason.WindowNeedsRedraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnHeaderIconGUI(Rect iconRect)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(!TimelineUtility.IsCurrentSequenceValid() || IsCurrentSequenceReadOnly()))
|
||||
{
|
||||
GUI.Label(iconRect, Styles.SignalEmitterIcon);
|
||||
}
|
||||
}
|
||||
|
||||
internal override Rect DrawHeaderHelpAndSettingsGUI(Rect r)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(!TimelineUtility.IsCurrentSequenceValid() || IsCurrentSequenceReadOnly()))
|
||||
{
|
||||
var helpSize = EditorStyles.iconButton.CalcSize(EditorGUI.GUIContents.helpIcon);
|
||||
const int kTopMargin = 5;
|
||||
return EditorGUIUtility.DrawEditorHeaderItems(new Rect(r.xMax - helpSize.x, r.y + kTopMargin, helpSize.x, helpSize.y), targets);
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<SignalAsset> ISignalAssetProvider.AvailableSignalAssets()
|
||||
{
|
||||
return SignalManager.assets;
|
||||
}
|
||||
|
||||
void ISignalAssetProvider.CreateNewSignalAsset(string path)
|
||||
{
|
||||
var newSignalAsset = SignalManager.CreateSignalAssetInstance(path);
|
||||
AssignSignalAsset(newSignalAsset);
|
||||
var receivers = m_Receivers.OfType<SignalReceiver>().ToList();
|
||||
if (signalAsset != null && receivers.Count == 1 && !receivers.Any(r => r.IsSignalAssetHandled(newSignalAsset))) // Only when one receiver is present
|
||||
{
|
||||
receivers[0].AddNewReaction(newSignalAsset); // Add reaction on the first receiver from the list
|
||||
ApplyChangesAndRefreshReceivers();
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateState()
|
||||
{
|
||||
m_BoundGameObject = GetBoundGameObject(m_Signal.parent, m_AssociatedDirector);
|
||||
m_Receivers = m_BoundGameObject == null || m_BoundGameObject.Equals(null)
|
||||
? new List<Component>()
|
||||
: m_BoundGameObject.GetComponents<Component>().Where(t => t is INotificationReceiver).ToList();
|
||||
|
||||
m_TargetsHaveTheSameBinding = targets.Cast<SignalEmitter>()
|
||||
.Select(x => GetBoundGameObject(x.parent, m_AssociatedDirector))
|
||||
.Distinct().Count() == 1;
|
||||
}
|
||||
|
||||
Editor GetOrCreateReceiverEditor(Component c)
|
||||
{
|
||||
Editor ret;
|
||||
if (m_Editors.TryGetValue(c, out ret))
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = CreateEditorWithContext(new Object[] { c }, target);
|
||||
m_Editors[c] = ret;
|
||||
if (!m_Foldouts.ContainsKey(c))
|
||||
{
|
||||
m_Foldouts[c] = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
Undo.undoRedoPerformed -= OnUndoRedo;
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
foreach (var editor in m_Editors)
|
||||
{
|
||||
DestroyImmediate(editor.Value);
|
||||
}
|
||||
m_Editors.Clear();
|
||||
}
|
||||
|
||||
void OnUndoRedo()
|
||||
{
|
||||
ApplyChangesAndRefreshReceivers();
|
||||
}
|
||||
|
||||
void ApplyChangesAndRefreshReceivers()
|
||||
{
|
||||
foreach (var receiverInspector in m_Editors.Values.OfType<SignalReceiverInspector>())
|
||||
{
|
||||
receiverInspector.SetAssetContext(signalAsset);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawNameSelectorAndSignalList()
|
||||
{
|
||||
using (var change = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
DrawSignal();
|
||||
DrawReceivers();
|
||||
|
||||
if (change.changed)
|
||||
{
|
||||
ApplyChangesAndRefreshReceivers();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawReceivers()
|
||||
{
|
||||
if (!m_TargetsHaveTheSameBinding)
|
||||
{
|
||||
EditorGUILayout.HelpBox(Styles.MultiEditNotSupportedOnDifferentBindings, MessageType.None);
|
||||
return;
|
||||
}
|
||||
|
||||
if (targets.OfType<SignalEmitter>().Select(x => x.asset).Distinct().Count() > 1)
|
||||
{
|
||||
EditorGUILayout.HelpBox(Styles.MultiEditNotSupportedOnDifferentSignals, MessageType.None);
|
||||
return;
|
||||
}
|
||||
|
||||
//do not display the receiver if the current timeline is not the same as the emitter's timeline
|
||||
//can happen if the inspector is locked
|
||||
if (m_Signal.parent != null && m_Signal.parent.timelineAsset != TimelineEditor.inspectedAsset)
|
||||
return;
|
||||
|
||||
if (m_BoundGameObject != null)
|
||||
{
|
||||
if (!m_Receivers.Any(x => x is SignalReceiver))
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
var message = string.Format(Styles.NoSignalReceiverComponent, m_BoundGameObject.name);
|
||||
SignalUtility.DrawCenteredMessage(message);
|
||||
if (SignalUtility.DrawCenteredButton(Styles.AddSignalReceiverComponent))
|
||||
AddReceiverComponent();
|
||||
}
|
||||
|
||||
foreach (var receiver in m_Receivers)
|
||||
{
|
||||
var editor = GetOrCreateReceiverEditor(receiver);
|
||||
if (DrawReceiverHeader(receiver))
|
||||
{
|
||||
editor.OnInspectorGUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (m_AssociatedDirector != null) //not in asset mode
|
||||
{
|
||||
EditorGUILayout.HelpBox(Styles.NoBoundGO, MessageType.None);
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSignalFlags()
|
||||
{
|
||||
EditorGUILayout.PropertyField(m_RetroactiveProperty, Styles.RetroactiveLabel);
|
||||
EditorGUILayout.PropertyField(m_EmitOnceProperty, Styles.EmitOnceLabel);
|
||||
}
|
||||
|
||||
void DrawSignal()
|
||||
{
|
||||
//should show button to create new signal if there are no signals asset in the project
|
||||
if (!SignalManager.assets.Any())
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(true))
|
||||
{
|
||||
DrawNameSelector();
|
||||
}
|
||||
|
||||
EditorGUILayout.Separator();
|
||||
SignalUtility.DrawCenteredMessage(Styles.ProjectHasNoSignalAsset);
|
||||
if (SignalUtility.DrawCenteredButton(Styles.CreateNewSignal))
|
||||
CreateNewSignalAsset(SignalUtility.GetNewSignalPath());
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
else
|
||||
{
|
||||
DrawNameSelector();
|
||||
}
|
||||
}
|
||||
|
||||
internal void CreateNewSignalAsset(string path)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
((ISignalAssetProvider)this).CreateNewSignalAsset(path);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
|
||||
void AssignSignalAsset(SignalAsset newAsset)
|
||||
{
|
||||
foreach (var o in targets)
|
||||
{
|
||||
var signalEmitter = (SignalEmitter)o;
|
||||
UndoExtensions.RegisterMarker(signalEmitter, Styles.UndoCreateSignalAsset);
|
||||
signalEmitter.asset = newAsset;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawNameSelector()
|
||||
{
|
||||
SignalUtility.DrawSignalNames(this, EditorGUILayout.GetControlRect(), Styles.EmitSignalLabel, !signalAssetSameValue);
|
||||
}
|
||||
|
||||
bool DrawReceiverHeader(Component receiver)
|
||||
{
|
||||
EditorGUILayout.Space();
|
||||
var lineRect = GUILayoutUtility.GetRect(10, 4, EditorStyles.inspectorTitlebar);
|
||||
DrawSplitLine(lineRect.y);
|
||||
|
||||
var style = EditorGUIUtility.TrTextContentWithIcon(
|
||||
ObjectNames.NicifyVariableName(receiver.GetType().Name),
|
||||
AssetPreview.GetMiniThumbnail(receiver));
|
||||
|
||||
m_Foldouts[receiver] =
|
||||
EditorGUILayout.Foldout(m_Foldouts[receiver], style, true, foldoutStyle);
|
||||
if (m_Foldouts[receiver])
|
||||
{
|
||||
DrawReceiverObjectField();
|
||||
}
|
||||
|
||||
return m_Foldouts[receiver];
|
||||
}
|
||||
|
||||
void DrawReceiverObjectField()
|
||||
{
|
||||
EditorGUI.BeginDisabledGroup(true);
|
||||
EditorGUILayout.ObjectField(Styles.ObjectLabel, m_BoundGameObject, typeof(GameObject), false);
|
||||
EditorGUI.EndDisabledGroup();
|
||||
}
|
||||
|
||||
void AddReceiverComponent()
|
||||
{
|
||||
var receiver = Undo.AddComponent<SignalReceiver>(m_BoundGameObject);
|
||||
receiver.AddNewReaction(signalAsset);
|
||||
}
|
||||
|
||||
static bool SkipField(string fieldName)
|
||||
{
|
||||
return fieldName == "m_Script" || fieldName == "m_Asset" || fieldName == "m_Retroactive" || fieldName == "m_EmitOnce";
|
||||
}
|
||||
|
||||
static void DrawSplitLine(float y)
|
||||
{
|
||||
if (Event.current.type != EventType.Repaint) return;
|
||||
|
||||
var width = EditorGUIUtility.currentViewWidth;
|
||||
var position = new Rect(0, y, width + 1, 1);
|
||||
|
||||
if (EditorStyles.inspectorTitlebar != null)
|
||||
EditorStyles.inspectorTitlebar.Draw(position, false, false, false, false);
|
||||
}
|
||||
|
||||
static GameObject GetBoundGameObject(TrackAsset track, PlayableDirector associatedDirector)
|
||||
{
|
||||
if (associatedDirector == null || track == null) //if in asset mode, no bound object for you
|
||||
return null;
|
||||
|
||||
var boundObj = TimelineUtility.GetSceneGameObject(associatedDirector, track);
|
||||
|
||||
//if the signal is on the timeline marker track and user did not set a binding, assume it's bound to PlayableDirector
|
||||
if (boundObj == null && track.timelineAsset.markerTrack == track)
|
||||
boundObj = associatedDirector.gameObject;
|
||||
|
||||
return boundObj;
|
||||
}
|
||||
|
||||
static bool IsCurrentSequenceReadOnly()
|
||||
{
|
||||
return TimelineWindow.instance.state.editSequence.isReadOnly;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 970e7735a0864fd40842a36d053d08fe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,39 @@
|
||||
using System;
|
||||
using JetBrains.Annotations;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
[CustomPropertyDrawer(typeof(CustomSignalEventDrawer))]
|
||||
[UsedImplicitly]
|
||||
class SignalEventDrawer : UnityEventDrawer
|
||||
{
|
||||
static GameObject FindBoundObject(SerializedProperty property)
|
||||
{
|
||||
var component = property.serializedObject.targetObject as Component;
|
||||
return component != null ? component.gameObject : null;
|
||||
}
|
||||
|
||||
protected override void OnAddEvent(ReorderableList list)
|
||||
{
|
||||
base.OnAddEvent(list);
|
||||
var listProperty = list.serializedProperty;
|
||||
if (listProperty.arraySize > 0)
|
||||
{
|
||||
var lastCall = list.serializedProperty.GetArrayElementAtIndex(listProperty.arraySize - 1);
|
||||
var targetProperty = lastCall.FindPropertyRelative(kInstancePath);
|
||||
targetProperty.objectReferenceValue = FindBoundObject(listProperty);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void DrawEventHeader(Rect headerRect) { }
|
||||
|
||||
protected override void SetupReorderableList(ReorderableList list)
|
||||
{
|
||||
base.SetupReorderableList(list);
|
||||
list.headerHeight = 4;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ba7805325c426c43b8e85b5be4eae36
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
class SignalManager : IDisposable
|
||||
{
|
||||
static SignalManager m_Instance;
|
||||
readonly List<SignalAsset> m_assets = new List<SignalAsset>();
|
||||
|
||||
internal static SignalManager instance
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Instance == null)
|
||||
{
|
||||
m_Instance = new SignalManager();
|
||||
m_Instance.Refresh();
|
||||
}
|
||||
|
||||
return m_Instance;
|
||||
}
|
||||
|
||||
set { m_Instance = value; }
|
||||
}
|
||||
|
||||
internal SignalManager()
|
||||
{
|
||||
SignalAsset.OnEnableCallback += Register;
|
||||
}
|
||||
|
||||
public static IEnumerable<SignalAsset> assets
|
||||
{
|
||||
get
|
||||
{
|
||||
foreach (var asset in instance.m_assets)
|
||||
{
|
||||
if (asset != null)
|
||||
yield return asset;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static SignalAsset CreateSignalAssetInstance(string path)
|
||||
{
|
||||
var newSignal = ScriptableObject.CreateInstance<SignalAsset>();
|
||||
newSignal.name = Path.GetFileNameWithoutExtension(path);
|
||||
|
||||
var asset = AssetDatabase.LoadMainAssetAtPath(path) as SignalAsset;
|
||||
if (asset != null)
|
||||
{
|
||||
TimelineUndo.PushUndo(asset, Styles.UndoCreateSignalAsset);
|
||||
EditorUtility.CopySerialized(newSignal, asset);
|
||||
Object.DestroyImmediate(newSignal);
|
||||
return asset;
|
||||
}
|
||||
|
||||
AssetDatabase.CreateAsset(newSignal, path);
|
||||
return newSignal;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
SignalAsset.OnEnableCallback -= Register;
|
||||
}
|
||||
|
||||
void Register(SignalAsset a)
|
||||
{
|
||||
m_assets.Add(a);
|
||||
}
|
||||
|
||||
void Refresh()
|
||||
{
|
||||
var guids = AssetDatabase.FindAssets("t:SignalAsset");
|
||||
foreach (var g in guids)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(g);
|
||||
var asset = AssetDatabase.LoadAssetAtPath<SignalAsset>(path);
|
||||
m_assets.Add(asset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 255b0c6d400fd964dab3029c8abc53f4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,15 @@
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
class SignalReceiverHeader : MultiColumnHeader
|
||||
{
|
||||
public SignalReceiverHeader(MultiColumnHeaderState state) : base(state) { }
|
||||
|
||||
protected override void AddColumnHeaderContextMenuItems(GenericMenu menu)
|
||||
{
|
||||
menu.AddItem(L10n.TextContent("Resize to Fit"), false, ResizeToFit);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 423cd382a7804414d9bfdb2e7fb7bb62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,116 @@
|
||||
using UnityEngine;
|
||||
using UnityObject = UnityEngine.Object;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
[CustomEditor(typeof(SignalReceiver))]
|
||||
class SignalReceiverInspector : Editor
|
||||
{
|
||||
SignalReceiver m_Target;
|
||||
|
||||
[SerializeField] TreeViewState m_TreeState;
|
||||
[SerializeField] MultiColumnHeaderState m_MultiColumnHeaderState;
|
||||
internal SignalReceiverTreeView m_TreeView;
|
||||
|
||||
SignalEmitter signalEmitterContext
|
||||
{
|
||||
get { return m_Context as SignalEmitter; }
|
||||
}
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
m_Target = target as SignalReceiver;
|
||||
InitTreeView(serializedObject);
|
||||
|
||||
Undo.undoRedoPerformed += OnUndoRedo;
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
Undo.undoRedoPerformed -= OnUndoRedo;
|
||||
}
|
||||
|
||||
void OnUndoRedo()
|
||||
{
|
||||
m_TreeView.dirty = true;
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
using (var changeCheck = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
m_TreeView.RefreshIfDirty();
|
||||
DrawEmitterControls(); // Draws buttons coming from the Context (SignalEmitter)
|
||||
|
||||
EditorGUILayout.Space();
|
||||
m_TreeView.Draw();
|
||||
|
||||
if (signalEmitterContext == null)
|
||||
DrawAddRemoveButtons();
|
||||
|
||||
if (changeCheck.changed)
|
||||
{
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
m_TreeView.dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEmitterControls()
|
||||
{
|
||||
var context = signalEmitterContext;
|
||||
if (context != null)
|
||||
{
|
||||
var currentSignal = context.asset;
|
||||
if (currentSignal != null && !m_Target.IsSignalAssetHandled(currentSignal))
|
||||
{
|
||||
EditorGUILayout.Separator();
|
||||
var message = string.Format(Styles.NoReaction, currentSignal.name);
|
||||
SignalUtility.DrawCenteredMessage(message);
|
||||
if (SignalUtility.DrawCenteredButton(Styles.AddReactionButton))
|
||||
m_Target.AddNewReaction(currentSignal); // Add reaction on the first
|
||||
EditorGUILayout.Separator();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void SetAssetContext(SignalAsset asset)
|
||||
{
|
||||
m_TreeView.SetSignalContext(asset);
|
||||
}
|
||||
|
||||
void DrawAddRemoveButtons()
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
if (GUILayout.Button(Styles.AddReactionButton))
|
||||
{
|
||||
Undo.RecordObject(m_Target, Styles.UndoAddReaction);
|
||||
m_Target.AddEmptyReaction(new UnityEvent());
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(m_Target);
|
||||
}
|
||||
GUILayout.Space(18.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void InitTreeView(SerializedObject so)
|
||||
{
|
||||
m_TreeState = SignalListFactory.CreateViewState();
|
||||
m_MultiColumnHeaderState = SignalListFactory.CreateHeaderState();
|
||||
var header = SignalListFactory.CreateHeader(m_MultiColumnHeaderState, SignalReceiverUtility.headerHeight);
|
||||
|
||||
var context = signalEmitterContext;
|
||||
m_TreeView = SignalListFactory.CreateSignalInspectorList(m_TreeState, header, m_Target, so);
|
||||
m_TreeView.readonlySignals = context != null;
|
||||
|
||||
if (context != null)
|
||||
m_TreeView.SetSignalContext(context.asset);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 70b265ed18dc14041bedc0263d4578ef
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
interface ISignalAssetProvider
|
||||
{
|
||||
SignalAsset signalAsset { get; set; }
|
||||
IEnumerable<SignalAsset> AvailableSignalAssets();
|
||||
void CreateNewSignalAsset(string path);
|
||||
}
|
||||
|
||||
static class SignalUtility
|
||||
{
|
||||
const string k_SignalExtension = "signal";
|
||||
|
||||
public static void DrawSignalNames(ISignalAssetProvider assetProvider, Rect position, GUIContent label, bool multipleValues)
|
||||
{
|
||||
var assets = assetProvider.AvailableSignalAssets().ToList();
|
||||
var index = assets.IndexOf(assetProvider.signalAsset);
|
||||
|
||||
var availableNames = new List<string>();
|
||||
using (new GUIMixedValueScope(multipleValues))
|
||||
{
|
||||
availableNames.Add(Styles.EmptySignalList.text);
|
||||
|
||||
availableNames.AddRange(assets.Select(x => x.name));
|
||||
availableNames.Add(Styles.CreateNewSignal.text);
|
||||
|
||||
var curValue = index + 1;
|
||||
var selected = EditorGUI.Popup(position, label, curValue, availableNames.ToArray());
|
||||
|
||||
if (selected != curValue)
|
||||
{
|
||||
var noneEntryIdx = 0;
|
||||
if (selected == noneEntryIdx) // None
|
||||
assetProvider.signalAsset = null;
|
||||
else if (selected == availableNames.Count - 1) // "Create New Asset"
|
||||
{
|
||||
var path = GetNewSignalPath();
|
||||
if (!string.IsNullOrEmpty(path))
|
||||
assetProvider.CreateNewSignalAsset(path);
|
||||
GUIUtility.ExitGUI();
|
||||
}
|
||||
else
|
||||
assetProvider.signalAsset = assets[selected - 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetNewSignalPath()
|
||||
{
|
||||
return EditorUtility.SaveFilePanelInProject(
|
||||
Styles.NewSignalWindowTitle.text,
|
||||
Styles.NewSignalDefaultName.text,
|
||||
k_SignalExtension,
|
||||
Styles.NewSignalWindowMessage.text);
|
||||
}
|
||||
|
||||
public static bool IsSignalAssetHandled(this SignalReceiver receiver, SignalAsset asset)
|
||||
{
|
||||
return receiver != null && asset != null && receiver.GetRegisteredSignals().Contains(asset);
|
||||
}
|
||||
|
||||
public static void AddNewReaction(this SignalReceiver receiver, SignalAsset signalAsset)
|
||||
{
|
||||
if (signalAsset != null && receiver != null)
|
||||
{
|
||||
Undo.RecordObject(receiver, Styles.UndoAddReaction);
|
||||
var newEvent = new UnityEvent();
|
||||
newEvent.AddPersistentListener();
|
||||
var evtIndex = newEvent.GetPersistentEventCount() - 1;
|
||||
newEvent.RegisterVoidPersistentListenerWithoutValidation(evtIndex, receiver.gameObject, string.Empty);
|
||||
receiver.AddReaction(signalAsset, newEvent);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(receiver);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DrawCenteredMessage(string message)
|
||||
{
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
GUILayout.Label(message);
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
}
|
||||
|
||||
public static bool DrawCenteredButton(GUIContent buttonLabel)
|
||||
{
|
||||
bool buttonClicked;
|
||||
using (new GUILayout.HorizontalScope())
|
||||
{
|
||||
GUILayout.FlexibleSpace();
|
||||
buttonClicked = GUILayout.Button(buttonLabel);
|
||||
GUILayout.FlexibleSpace();
|
||||
}
|
||||
return buttonClicked;
|
||||
}
|
||||
}
|
||||
|
||||
static class SignalReceiverUtility
|
||||
{
|
||||
const int k_DefaultTreeviewHeaderHeight = 20;
|
||||
|
||||
public static int headerHeight
|
||||
{
|
||||
get { return k_DefaultTreeviewHeaderHeight; }
|
||||
}
|
||||
|
||||
public static SerializedProperty FindSignalsProperty(SerializedObject obj)
|
||||
{
|
||||
return obj.FindProperty("m_Events.m_Signals");
|
||||
}
|
||||
|
||||
public static SerializedProperty FindEventsProperty(SerializedObject obj)
|
||||
{
|
||||
return obj.FindProperty("m_Events.m_Events");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b33687803b08daf418e5315de17658b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,39 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
static class Styles
|
||||
{
|
||||
public static readonly GUIContent RetroactiveLabel = L10n.TextContent("Retroactive", "Use retroactive to emit this signal even if playback starts afterwards.");
|
||||
public static readonly GUIContent EmitOnceLabel = L10n.TextContent("Emit Once", "Emit the signal once during loops.");
|
||||
public static readonly GUIContent EmitSignalLabel = L10n.TextContent("Emit Signal", "Select which Signal Asset to emit.");
|
||||
public static readonly GUIContent ObjectLabel = L10n.TextContent("Receiver Component on", "The Signal Receiver Component on the bound GameObject.");
|
||||
|
||||
public static readonly GUIContent CreateNewSignal = L10n.TextContent("Create Signal...");
|
||||
public static readonly GUIContent AddSignalReceiverComponent = L10n.TextContent("Add Signal Receiver", "Creates a Signal Receiver component on the track binding and the reaction for the current signal.");
|
||||
public static readonly GUIContent EmptySignalList = L10n.TextContent("None");
|
||||
public static readonly GUIContent AddReactionButton = L10n.TextContent("Add Reaction");
|
||||
|
||||
public static readonly GUIContent NewSignalWindowTitle = L10n.TextContent("Create Signal Key");
|
||||
public static readonly GUIContent NewSignalDefaultName = L10n.TextContent("New Signal");
|
||||
public static readonly GUIContent NewSignalWindowMessage = L10n.TextContent("Create Signal Key");
|
||||
|
||||
public static readonly string SignalListDuplicateOption = L10n.Tr("Duplicate");
|
||||
public static readonly string SignalListDeleteOption = L10n.Tr("Delete");
|
||||
public static readonly string NoBoundGO = L10n.Tr("Track has no bound GameObject.");
|
||||
public static readonly string MultiEditNotSupportedOnDifferentBindings = L10n.Tr("Multi-edit not supported for SignalReceivers on tracks bound to different GameObjects.");
|
||||
public static readonly string MultiEditNotSupportedOnDifferentSignals = L10n.Tr("Multi-edit not supported for SignalReceivers when SignalEmitters use different Signals.");
|
||||
|
||||
public static readonly string UndoCreateSignalAsset = L10n.Tr("Create New Signal Asset");
|
||||
public static readonly string UndoDuplicateRow = L10n.Tr("Duplicate Row");
|
||||
public static readonly string UndoDeleteRow = L10n.Tr("Delete Row");
|
||||
public static readonly string UndoAddReaction = L10n.Tr("Add Signal Receiver Reaction");
|
||||
public static readonly string NoReaction = L10n.Tr("No reaction for {0} has been defined in this receiver");
|
||||
public static readonly string NoSignalReceiverComponent = L10n.Tr("There is no Signal Receiver component on {0}");
|
||||
public static readonly string ProjectHasNoSignalAsset = L10n.Tr("Your project contains no Signal assets");
|
||||
|
||||
//Icons
|
||||
public static readonly GUIStyle OptionsStyle = DirectorStyles.GetGUIStyle("Icon.Options");
|
||||
public static readonly GUIContent SignalEmitterIcon = EditorGUIUtility.IconContent("SignalEmitter Icon");
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 685f63932bebd0c4db02ee14845191e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5ba130fc1db953547a50bcf5c162a3e8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,31 @@
|
||||
using System;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
static class SignalListFactory
|
||||
{
|
||||
public static SignalReceiverTreeView CreateSignalInspectorList(TreeViewState state, SignalReceiverHeader header, SignalReceiver target, SerializedObject so)
|
||||
{
|
||||
return new SignalReceiverTreeView(state, header, target, so);
|
||||
}
|
||||
|
||||
public static SignalReceiverHeader CreateHeader(MultiColumnHeaderState state, int columnHeight)
|
||||
{
|
||||
var header = new SignalReceiverHeader(state) { height = columnHeight };
|
||||
header.ResizeToFit();
|
||||
return header;
|
||||
}
|
||||
|
||||
public static MultiColumnHeaderState CreateHeaderState()
|
||||
{
|
||||
return new MultiColumnHeaderState(SignalReceiverTreeView.GetColumns());
|
||||
}
|
||||
|
||||
public static TreeViewState CreateViewState()
|
||||
{
|
||||
return new TreeViewState();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 01cd96d8687272f4898cfd1562079dd7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,185 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.Timeline;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
class SignalReceiverItem : TreeViewItem, ISignalAssetProvider
|
||||
{
|
||||
static readonly SignalEventDrawer k_EvtDrawer = new SignalEventDrawer();
|
||||
|
||||
readonly SerializedProperty m_Asset;
|
||||
readonly SerializedProperty m_Evt;
|
||||
readonly SignalReceiverTreeView m_TreeView;
|
||||
|
||||
int m_CurrentRowIdx;
|
||||
SignalReceiver m_CurrentReceiver;
|
||||
|
||||
internal readonly bool enabled;
|
||||
internal readonly bool readonlySignal;
|
||||
|
||||
internal const string SignalName = "SignalName";
|
||||
internal const string SignalNameReadOnly = "SignalNameReadOnly";
|
||||
internal const string SignalOptions = "SignalOptions";
|
||||
|
||||
public SignalReceiverItem(SerializedProperty signalAsset, SerializedProperty eventListEntry, int id, bool readonlySignal, bool enabled, SignalReceiverTreeView treeView)
|
||||
: base(id, 0)
|
||||
{
|
||||
m_Asset = signalAsset;
|
||||
m_Evt = eventListEntry;
|
||||
this.enabled = enabled;
|
||||
this.readonlySignal = readonlySignal;
|
||||
m_TreeView = treeView;
|
||||
}
|
||||
|
||||
public SignalAsset signalAsset
|
||||
{
|
||||
get { return m_CurrentReceiver.GetSignalAssetAtIndex(m_CurrentRowIdx); }
|
||||
set
|
||||
{
|
||||
Undo.RecordObject(m_CurrentReceiver, Styles.UndoCreateSignalAsset);
|
||||
m_CurrentReceiver.ChangeSignalAtIndex(m_CurrentRowIdx, value);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(m_CurrentReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
public float GetHeight()
|
||||
{
|
||||
return k_EvtDrawer.GetPropertyHeight(m_Evt, GUIContent.none);
|
||||
}
|
||||
|
||||
public void Draw(Rect rect, int colIdx, int rowIdx, float padding, SignalReceiver target)
|
||||
{
|
||||
switch (colIdx)
|
||||
{
|
||||
case 0:
|
||||
DrawSignalNameColumn(rect, padding, target, rowIdx);
|
||||
break;
|
||||
case 1:
|
||||
DrawReactionColumn(rect, rowIdx);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSignalNameColumn(Rect rect, float padding, SignalReceiver target, int rowIdx)
|
||||
{
|
||||
using (new EditorGUI.DisabledScope(!enabled))
|
||||
{
|
||||
if (!readonlySignal)
|
||||
{
|
||||
m_CurrentRowIdx = rowIdx;
|
||||
m_CurrentReceiver = target;
|
||||
|
||||
rect.x += padding;
|
||||
rect.width -= padding;
|
||||
rect.height = EditorGUIUtility.singleLineHeight;
|
||||
GUI.SetNextControlName(SignalName);
|
||||
SignalUtility.DrawSignalNames(this, rect, GUIContent.none, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
GUI.SetNextControlName(SignalNameReadOnly);
|
||||
var signalAsset = m_Asset.objectReferenceValue;
|
||||
GUI.Label(rect,
|
||||
signalAsset != null
|
||||
? EditorGUIUtility.TempContent(signalAsset.name)
|
||||
: Styles.EmptySignalList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawReactionColumn(Rect rect, int rowIdx)
|
||||
{
|
||||
if (!readonlySignal)
|
||||
{
|
||||
var optionButtonSize = GetOptionButtonSize();
|
||||
rect.width -= optionButtonSize.x;
|
||||
|
||||
var optionButtonRect = new Rect
|
||||
{
|
||||
x = rect.xMax,
|
||||
y = rect.y,
|
||||
width = optionButtonSize.x,
|
||||
height = optionButtonSize.y
|
||||
};
|
||||
DrawOptionsButton(optionButtonRect, rowIdx, m_CurrentReceiver);
|
||||
}
|
||||
|
||||
using (new EditorGUI.DisabledScope(!enabled))
|
||||
{
|
||||
var nameAsString = m_Asset.objectReferenceValue == null ? "Null" : m_Asset.objectReferenceValue.name;
|
||||
using (var change = new EditorGUI.ChangeCheckScope())
|
||||
{
|
||||
EditorGUI.PropertyField(rect, m_Evt, EditorGUIUtility.TempContent(nameAsString));
|
||||
if (change.changed)
|
||||
m_TreeView.dirty = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Vector2 GetOptionButtonSize()
|
||||
{
|
||||
EditorGUIUtility.SetIconSize(Vector2.zero);
|
||||
return EditorStyles.iconButton.CalcSize(EditorGUI.GUIContents.titleSettingsIcon);
|
||||
}
|
||||
|
||||
void DrawOptionsButton(Rect rect, int rowIdx, SignalReceiver target)
|
||||
{
|
||||
GUI.SetNextControlName(SignalOptions);
|
||||
if (EditorGUI.DropdownButton(rect, EditorGUI.GUIContents.titleSettingsIcon, FocusType.Passive, EditorStyles.iconButton))
|
||||
{
|
||||
var menu = new GenericMenu();
|
||||
menu.AddItem(new GUIContent(Styles.SignalListDuplicateOption), false, () =>
|
||||
{
|
||||
Undo.RecordObject(target, Styles.UndoDuplicateRow);
|
||||
var evtCloner = ScriptableObject.CreateInstance<UnityEventCloner>();
|
||||
evtCloner.evt = target.GetReactionAtIndex(rowIdx);
|
||||
var clone = Object.Instantiate(evtCloner);
|
||||
target.AddEmptyReaction(clone.evt);
|
||||
m_TreeView.dirty = true;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(target);
|
||||
});
|
||||
menu.AddItem(new GUIContent(Styles.SignalListDeleteOption), false, () =>
|
||||
{
|
||||
Undo.RecordObject(target, Styles.UndoDeleteRow);
|
||||
target.RemoveAtIndex(rowIdx);
|
||||
m_TreeView.dirty = true;
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(target);
|
||||
});
|
||||
menu.ShowAsContext();
|
||||
}
|
||||
}
|
||||
|
||||
IEnumerable<SignalAsset> ISignalAssetProvider.AvailableSignalAssets()
|
||||
{
|
||||
var ret = SignalManager.assets.Except(m_CurrentReceiver.GetRegisteredSignals());
|
||||
return signalAsset == null ? ret : ret.Union(new List<SignalAsset> { signalAsset }).ToList();
|
||||
}
|
||||
|
||||
void ISignalAssetProvider.CreateNewSignalAsset(string path)
|
||||
{
|
||||
var newSignalAsset = SignalManager.CreateSignalAssetInstance(path);
|
||||
Undo.RecordObject(m_CurrentReceiver, Styles.UndoCreateSignalAsset);
|
||||
|
||||
// case 1241170 - overwriting an existing signal with throw an exception. Instead, clear the old key
|
||||
int index = m_CurrentReceiver.GetRegisteredSignals().ToList().IndexOf(newSignalAsset);
|
||||
if (index != -1)
|
||||
m_CurrentReceiver.ChangeSignalAtIndex(index, null);
|
||||
|
||||
m_CurrentReceiver.ChangeSignalAtIndex(m_CurrentRowIdx, newSignalAsset);
|
||||
PrefabUtility.RecordPrefabInstancePropertyModifications(m_CurrentReceiver);
|
||||
}
|
||||
|
||||
class UnityEventCloner : ScriptableObject
|
||||
{
|
||||
public UnityEvent evt;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9bc2b69915879416f8df18971dc98e2e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,155 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor.IMGUI.Controls;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Timeline;
|
||||
|
||||
namespace UnityEditor.Timeline.Signals
|
||||
{
|
||||
class SignalReceiverTreeView : TreeView
|
||||
{
|
||||
public bool dirty { private get; set; }
|
||||
|
||||
SerializedProperty signals { get; set; }
|
||||
SerializedProperty events { get; set; }
|
||||
|
||||
readonly SignalReceiver m_Target;
|
||||
|
||||
const float k_VerticalPadding = 5;
|
||||
const float k_HorizontalPadding = 5;
|
||||
|
||||
public SignalReceiverTreeView(TreeViewState state, MultiColumnHeader multiColumnHeader, SignalReceiver receiver, SerializedObject serializedObject)
|
||||
: base(state, multiColumnHeader)
|
||||
{
|
||||
m_Target = receiver;
|
||||
useScrollView = true;
|
||||
SetSerializedProperties(serializedObject);
|
||||
getNewSelectionOverride = (item, selection, shift) => new List<int>(); // Disable Selection
|
||||
}
|
||||
|
||||
SignalAsset signalAssetContext { get; set; }
|
||||
public bool readonlySignals { get; set; }
|
||||
|
||||
public void SetSignalContext(SignalAsset assetContext = null)
|
||||
{
|
||||
signalAssetContext = assetContext;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void SetSerializedProperties(SerializedObject serializedObject)
|
||||
{
|
||||
signals = SignalReceiverUtility.FindSignalsProperty(serializedObject);
|
||||
events = SignalReceiverUtility.FindEventsProperty(serializedObject);
|
||||
Reload();
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var rect = EditorGUILayout.GetControlRect(true, GetTotalHeight());
|
||||
OnGUI(rect);
|
||||
}
|
||||
|
||||
public void RefreshIfDirty()
|
||||
{
|
||||
var signalsListSizeHasChanged = signals.arraySize != GetRows().Count;
|
||||
if (dirty || signalsListSizeHasChanged)
|
||||
Reload();
|
||||
dirty = false;
|
||||
}
|
||||
|
||||
public static MultiColumnHeaderState.Column[] GetColumns()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
new MultiColumnHeaderState.Column
|
||||
{
|
||||
headerContent = L10n.TextContent("Signal"),
|
||||
contextMenuText = "",
|
||||
headerTextAlignment = TextAlignment.Center,
|
||||
width = 50, minWidth = 50,
|
||||
autoResize = true,
|
||||
allowToggleVisibility = false,
|
||||
canSort = false
|
||||
},
|
||||
new MultiColumnHeaderState.Column
|
||||
{
|
||||
headerContent = L10n.TextContent("Reaction"),
|
||||
contextMenuText = "",
|
||||
headerTextAlignment = TextAlignment.Center,
|
||||
width = 120, minWidth = 120,
|
||||
autoResize = true,
|
||||
allowToggleVisibility = false,
|
||||
canSort = false
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override TreeViewItem BuildRoot()
|
||||
{
|
||||
var root = new TreeViewItem(-1, -1) { children = new List<TreeViewItem>() };
|
||||
|
||||
var matchingId = signalAssetContext != null && readonlySignals ? FindIdForSignal(signals, signalAssetContext) : -1;
|
||||
if (matchingId >= 0)
|
||||
AddItem(root, matchingId);
|
||||
|
||||
for (var i = 0; i < signals.arraySize; ++i)
|
||||
{
|
||||
if (i == matchingId) continue;
|
||||
AddItem(root, i, !readonlySignals);
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
protected override void RowGUI(RowGUIArgs args)
|
||||
{
|
||||
var item = (SignalReceiverItem)args.item;
|
||||
for (var i = 0; i < args.GetNumVisibleColumns(); ++i)
|
||||
{
|
||||
var rect = args.GetCellRect(i);
|
||||
rect.y += k_VerticalPadding;
|
||||
item.Draw(rect, args.GetColumn(i), args.row, k_HorizontalPadding, m_Target);
|
||||
}
|
||||
}
|
||||
|
||||
protected override float GetCustomRowHeight(int row, TreeViewItem treeItem)
|
||||
{
|
||||
var item = treeItem as SignalReceiverItem;
|
||||
return item.GetHeight() + k_VerticalPadding;
|
||||
}
|
||||
|
||||
void AddItem(TreeViewItem root, int id, bool enabled = true)
|
||||
{
|
||||
var signal = signals.GetArrayElementAtIndex(id);
|
||||
var evt = events.GetArrayElementAtIndex(id);
|
||||
root.children.Add(new SignalReceiverItem(signal, evt, id, readonlySignals, enabled, this));
|
||||
}
|
||||
|
||||
float GetTotalHeight()
|
||||
{
|
||||
var height = 0.0f;
|
||||
foreach (var item in GetRows())
|
||||
{
|
||||
var signalListItem = item as SignalReceiverItem;
|
||||
height += signalListItem.GetHeight() + k_VerticalPadding;
|
||||
}
|
||||
|
||||
var scrollbarPadding = showingHorizontalScrollBar ? GUI.skin.horizontalScrollbar.fixedHeight : k_VerticalPadding;
|
||||
return height + multiColumnHeader.height + scrollbarPadding;
|
||||
}
|
||||
|
||||
static int FindIdForSignal(SerializedProperty signals, SignalAsset signalToFind)
|
||||
{
|
||||
for (var i = 0; i < signals.arraySize; ++i)
|
||||
{
|
||||
//signal in the receiver that matches the current signal asset will be displayed first
|
||||
var serializedProperty = signals.GetArrayElementAtIndex(i);
|
||||
var signalReferenceValue = serializedProperty.objectReferenceValue;
|
||||
var signalToFindRefValue = signalToFind;
|
||||
if (signalReferenceValue != null && signalReferenceValue == signalToFindRefValue)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 698b660e9477f4f16abad03ec00ce38c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Reference in New Issue
Block a user