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(); 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 ISignalAssetProvider.AvailableSignalAssets() { var ret = SignalManager.assets.Except(m_CurrentReceiver.GetRegisteredSignals()); return signalAsset == null ? ret : ret.Union(new List { 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; } } }