using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.Timeline; namespace UnityEditor.Timeline { class Clipboard { class ExposedReferenceTable : IExposedPropertyTable { Dictionary m_ReferenceTable = new Dictionary(); public void SetReferenceValue(PropertyName id, Object value) { m_ReferenceTable[id] = value; } public Object GetReferenceValue(PropertyName id, out bool idValid) { Object reference; idValid = m_ReferenceTable.TryGetValue(id, out reference); return reference; } public void ClearReferenceValue(PropertyName id) { m_ReferenceTable.Remove(id); } public void Clear() { m_ReferenceTable.Clear(); } } public struct ClipboardTrackEntry { public TrackAsset item; public TrackAsset parent; public List bindings; } static readonly int kListInitialSize = 10; readonly List m_ItemsData = new List(kListInitialSize); readonly List m_trackData = new List(kListInitialSize); TimelineAsset rootTimeline; public readonly IExposedPropertyTable exposedPropertyTable = new ExposedReferenceTable(); public Clipboard() { rootTimeline = CreateTimeline(); EditorApplication.playModeStateChanged += OnPlayModeChanged; } public void CopyItems(IEnumerable items) { using (new TimelineUndo.DisableUndoGuard(true)) { var itemsByParent = items.ToLookup(i => i.parentTrack); foreach (var itemsGroup in itemsByParent) { var parent = itemsGroup.Key; var itemsList = new List(); foreach (var item in itemsGroup) { if (item is ClipItem) itemsList.Add(CopyItem((ClipItem)item)); else if (item is MarkerItem) itemsList.Add(CopyItem((MarkerItem)item)); } m_ItemsData.Add(new ItemsPerTrack(parent, itemsList)); } } } ClipItem CopyItem(ClipItem clipItem) { var newClip = TimelineHelpers.Clone(clipItem.clip, TimelineWindow.instance.state.editSequence.director, exposedPropertyTable, rootTimeline); return new ClipItem(newClip); } static MarkerItem CopyItem(MarkerItem markerItem) { var markerObject = markerItem.marker as Object; if (markerObject != null) { var newMarker = Object.Instantiate(markerObject); newMarker.name = markerObject.name; return new MarkerItem((IMarker)newMarker); } return null; } public void CopyTracks(IEnumerable tracks) { using (new TimelineUndo.DisableUndoGuard(true)) { foreach (var track in TrackExtensions.FilterTracks(tracks)) { var newTrack = track.Duplicate(TimelineEditor.inspectedDirector, TimelineEditor.clipboard.exposedPropertyTable, rootTimeline); var originalTracks = track.GetFlattenedChildTracks().Append(track); var newTracks = newTrack.GetFlattenedChildTracks().Append(newTrack); var toBind = new List(); // Collect all track bindings to duplicate var originalIt = originalTracks.GetEnumerator(); var newIt = newTracks.GetEnumerator(); while (originalIt.MoveNext() && newIt.MoveNext()) { toBind.Add(TimelineEditor.inspectedDirector != null ? TimelineEditor.inspectedDirector.GetGenericBinding(originalIt.Current) : null); } m_trackData.Add(new ClipboardTrackEntry { item = newTrack, parent = track.parent as TrackAsset, bindings = toBind }); } } } public IEnumerable GetTracks() { return m_trackData; } public IEnumerable GetCopiedItems() { return m_ItemsData; } public void Clear() { m_ItemsData.Clear(); m_trackData.Clear(); rootTimeline = CreateTimeline(); ((ExposedReferenceTable)exposedPropertyTable).Clear(); } private void OnPlayModeChanged(PlayModeStateChange state) { if (state == PlayModeStateChange.EnteredEditMode || state == PlayModeStateChange.EnteredPlayMode) Clear(); } static TimelineAsset CreateTimeline() { var timeline = ScriptableObject.CreateInstance(); timeline.hideFlags |= HideFlags.DontSave; timeline.name = "Clipboard"; return timeline; } } }