A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using UnityEditor.IMGUI.Controls;
5using UnityEngine;
6using UnityEngine.Events;
7using UnityEngine.Timeline;
8using Object = UnityEngine.Object;
9
10namespace UnityEditor.Timeline.Signals
11{
12 class SignalReceiverItem : TreeViewItem, ISignalAssetProvider
13 {
14 static readonly SignalEventDrawer k_EvtDrawer = new SignalEventDrawer();
15
16 readonly SerializedProperty m_Asset;
17 readonly SerializedProperty m_Evt;
18 readonly SignalReceiverTreeView m_TreeView;
19
20 int m_CurrentRowIdx;
21 SignalReceiver m_CurrentReceiver;
22
23 internal readonly bool enabled;
24 internal readonly bool readonlySignal;
25
26 internal const string SignalName = "SignalName";
27 internal const string SignalNameReadOnly = "SignalNameReadOnly";
28 internal const string SignalOptions = "SignalOptions";
29
30 public SignalReceiverItem(SerializedProperty signalAsset, SerializedProperty eventListEntry, int id, bool readonlySignal, bool enabled, SignalReceiverTreeView treeView)
31 : base(id, 0)
32 {
33 m_Asset = signalAsset;
34 m_Evt = eventListEntry;
35 this.enabled = enabled;
36 this.readonlySignal = readonlySignal;
37 m_TreeView = treeView;
38 }
39
40 public SignalAsset signalAsset
41 {
42 get { return m_CurrentReceiver.GetSignalAssetAtIndex(m_CurrentRowIdx); }
43 set
44 {
45 Undo.RecordObject(m_CurrentReceiver, Styles.UndoCreateSignalAsset);
46 m_CurrentReceiver.ChangeSignalAtIndex(m_CurrentRowIdx, value);
47 PrefabUtility.RecordPrefabInstancePropertyModifications(m_CurrentReceiver);
48 }
49 }
50
51 public float GetHeight()
52 {
53 return k_EvtDrawer.GetPropertyHeight(m_Evt, GUIContent.none);
54 }
55
56 public void Draw(Rect rect, int colIdx, int rowIdx, float padding, SignalReceiver target)
57 {
58 switch (colIdx)
59 {
60 case 0:
61 DrawSignalNameColumn(rect, padding, target, rowIdx);
62 break;
63 case 1:
64 DrawReactionColumn(rect, rowIdx);
65 break;
66 default:
67 throw new ArgumentOutOfRangeException();
68 }
69 }
70
71 void DrawSignalNameColumn(Rect rect, float padding, SignalReceiver target, int rowIdx)
72 {
73 using (new EditorGUI.DisabledScope(!enabled))
74 {
75 if (!readonlySignal)
76 {
77 m_CurrentRowIdx = rowIdx;
78 m_CurrentReceiver = target;
79
80 rect.x += padding;
81 rect.width -= padding;
82 rect.height = EditorGUIUtility.singleLineHeight;
83 GUI.SetNextControlName(SignalName);
84 SignalUtility.DrawSignalNames(this, rect, GUIContent.none, false);
85 }
86 else
87 {
88 GUI.SetNextControlName(SignalNameReadOnly);
89 var signalAsset = m_Asset.objectReferenceValue;
90 GUI.Label(rect,
91 signalAsset != null
92 ? EditorGUIUtility.TempContent(signalAsset.name)
93 : Styles.EmptySignalList);
94 }
95 }
96 }
97
98 void DrawReactionColumn(Rect rect, int rowIdx)
99 {
100 if (!readonlySignal)
101 {
102 var optionButtonSize = GetOptionButtonSize();
103 rect.width -= optionButtonSize.x;
104
105 var optionButtonRect = new Rect
106 {
107 x = rect.xMax,
108 y = rect.y,
109 width = optionButtonSize.x,
110 height = optionButtonSize.y
111 };
112 DrawOptionsButton(optionButtonRect, rowIdx, m_CurrentReceiver);
113 }
114
115 using (new EditorGUI.DisabledScope(!enabled))
116 {
117 var nameAsString = m_Asset.objectReferenceValue == null ? "Null" : m_Asset.objectReferenceValue.name;
118 using (var change = new EditorGUI.ChangeCheckScope())
119 {
120 EditorGUI.PropertyField(rect, m_Evt, EditorGUIUtility.TempContent(nameAsString));
121 if (change.changed)
122 m_TreeView.dirty = true;
123 }
124 }
125 }
126
127 static Vector2 GetOptionButtonSize()
128 {
129 EditorGUIUtility.SetIconSize(Vector2.zero);
130 return EditorStyles.iconButton.CalcSize(EditorGUI.GUIContents.titleSettingsIcon);
131 }
132
133 void DrawOptionsButton(Rect rect, int rowIdx, SignalReceiver target)
134 {
135 GUI.SetNextControlName(SignalOptions);
136 if (EditorGUI.DropdownButton(rect, EditorGUI.GUIContents.titleSettingsIcon, FocusType.Passive, EditorStyles.iconButton))
137 {
138 var menu = new GenericMenu();
139 menu.AddItem(new GUIContent(Styles.SignalListDuplicateOption), false, () =>
140 {
141 Undo.RecordObject(target, Styles.UndoDuplicateRow);
142 var evtCloner = ScriptableObject.CreateInstance<UnityEventCloner>();
143 evtCloner.evt = target.GetReactionAtIndex(rowIdx);
144 var clone = Object.Instantiate(evtCloner);
145 target.AddEmptyReaction(clone.evt);
146 m_TreeView.dirty = true;
147 PrefabUtility.RecordPrefabInstancePropertyModifications(target);
148 });
149 menu.AddItem(new GUIContent(Styles.SignalListDeleteOption), false, () =>
150 {
151 Undo.RecordObject(target, Styles.UndoDeleteRow);
152 target.RemoveAtIndex(rowIdx);
153 m_TreeView.dirty = true;
154 PrefabUtility.RecordPrefabInstancePropertyModifications(target);
155 });
156 menu.ShowAsContext();
157 }
158 }
159
160 IEnumerable<SignalAsset> ISignalAssetProvider.AvailableSignalAssets()
161 {
162 var ret = SignalManager.assets.Except(m_CurrentReceiver.GetRegisteredSignals());
163 return signalAsset == null ? ret : ret.Union(new List<SignalAsset> { signalAsset }).ToList();
164 }
165
166 void ISignalAssetProvider.CreateNewSignalAsset(string path)
167 {
168 var newSignalAsset = SignalManager.CreateSignalAssetInstance(path);
169 Undo.RecordObject(m_CurrentReceiver, Styles.UndoCreateSignalAsset);
170
171 // case 1241170 - overwriting an existing signal with throw an exception. Instead, clear the old key
172 int index = m_CurrentReceiver.GetRegisteredSignals().ToList().IndexOf(newSignalAsset);
173 if (index != -1)
174 m_CurrentReceiver.ChangeSignalAtIndex(index, null);
175
176 m_CurrentReceiver.ChangeSignalAtIndex(m_CurrentRowIdx, newSignalAsset);
177 PrefabUtility.RecordPrefabInstancePropertyModifications(m_CurrentReceiver);
178 }
179
180 class UnityEventCloner : ScriptableObject
181 {
182 public UnityEvent evt;
183 }
184 }
185}