Initial Commit

This commit is contained in:
Sebastian Cabrera 2021-08-02 05:44:37 -04:00
parent 53eb92e9af
commit 270ab7d11f
15341 changed files with 700234 additions and 0 deletions

View file

@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Timeline
{
interface IMoveItemMode
{
void OnTrackDetach(IEnumerable<ItemsPerTrack> itemsGroups);
void HandleTrackSwitch(IEnumerable<ItemsPerTrack> itemsGroups);
bool AllowTrackSwitch();
double AdjustStartTime(WindowState state, ItemsPerTrack itemsGroup, double time);
void OnModeClutchEnter(IEnumerable<ItemsPerTrack> itemsGroups);
void OnModeClutchExit(IEnumerable<ItemsPerTrack> itemsGroups);
void BeginMove(IEnumerable<ItemsPerTrack> itemsGroups);
void UpdateMove(IEnumerable<ItemsPerTrack> itemsGroups);
void FinishMove(IEnumerable<ItemsPerTrack> itemsGroups);
bool ValidateMove(ItemsPerTrack itemsGroup);
}
interface IMoveItemDrawer
{
void DrawGUI(WindowState state, IEnumerable<MovingItems> movingItems, Color color);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3ff3d24ea34f9f74cb138e435f5f491e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,311 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
class MoveItemHandler : IAttractable, IAttractionHandler
{
bool m_Grabbing;
MovingItems m_LeftMostMovingItems;
MovingItems m_RightMostMovingItems;
HashSet<TimelineItemGUI> m_ItemGUIs;
ItemsGroup m_ItemsGroup;
public TrackAsset targetTrack { get; private set; }
public bool allowTrackSwitch { get; private set; }
int m_GrabbedModalUndoGroup = -1;
readonly WindowState m_State;
public MovingItems[] movingItems { get; private set; }
public MoveItemHandler(WindowState state)
{
m_State = state;
}
public void Grab(IEnumerable<ITimelineItem> items, TrackAsset referenceTrack)
{
Grab(items, referenceTrack, Vector2.zero);
}
public void Grab(IEnumerable<ITimelineItem> items, TrackAsset referenceTrack, Vector2 mousePosition)
{
if (items == null) return;
items = items.ToArray(); // Cache enumeration result
if (!items.Any()) return;
m_GrabbedModalUndoGroup = Undo.GetCurrentGroup();
var trackItems = items.GroupBy(c => c.parentTrack).ToArray();
var trackItemsCount = trackItems.Length;
var tracks = items.Select(c => c.parentTrack).Where(x => x != null).Distinct();
movingItems = new MovingItems[trackItemsCount];
allowTrackSwitch = trackItemsCount == 1 && !trackItems.SelectMany(x => x).Any(x => x is MarkerItem); // For now, track switch is only supported when all items are on the same track and there are no items
// one push per track handles all the clips on the track
UndoExtensions.RegisterTracks(tracks, L10n.Tr("Move Items"));
foreach (var sourceTrack in tracks)
{
// push all markers on the track because of ripple
UndoExtensions.RegisterMarkers(sourceTrack.GetMarkers(), L10n.Tr("Move Items"));
}
for (var i = 0; i < trackItemsCount; ++i)
{
var track = trackItems[i].Key;
var grabbedItems = new MovingItems(m_State, track, trackItems[i].ToArray(), referenceTrack, mousePosition, allowTrackSwitch);
movingItems[i] = grabbedItems;
}
m_LeftMostMovingItems = null;
m_RightMostMovingItems = null;
foreach (var grabbedTrackItems in movingItems)
{
if (m_LeftMostMovingItems == null || m_LeftMostMovingItems.start > grabbedTrackItems.start)
m_LeftMostMovingItems = grabbedTrackItems;
if (m_RightMostMovingItems == null || m_RightMostMovingItems.end < grabbedTrackItems.end)
m_RightMostMovingItems = grabbedTrackItems;
}
m_ItemGUIs = new HashSet<TimelineItemGUI>();
m_ItemsGroup = new ItemsGroup(items);
foreach (var item in items)
m_ItemGUIs.Add(item.gui);
targetTrack = referenceTrack;
EditMode.BeginMove(this);
m_Grabbing = true;
}
public void Drop()
{
if (IsValidDrop())
{
foreach (var grabbedItems in movingItems)
{
var track = grabbedItems.targetTrack;
UndoExtensions.RegisterTrack(track, L10n.Tr("Move Items"));
if (EditModeUtils.IsInfiniteTrack(track) && grabbedItems.clips.Any())
((AnimationTrack)track).ConvertToClipMode();
}
EditMode.FinishMove();
Done();
}
else
{
Cancel();
}
EditMode.ClearEditMode();
}
bool IsValidDrop()
{
return movingItems.All(g => g.canDrop);
}
void Cancel()
{
if (!m_Grabbing)
return;
// TODO fix undo reselection persistency
// identify the clips by their playable asset, since that reference will survive the undo
// This is a workaround, until a more persistent fix for selection of clips across Undo can be found
var assets = movingItems.SelectMany(x => x.clips).Select(x => x.asset);
Undo.RevertAllDownToGroup(m_GrabbedModalUndoGroup);
// reselect the clips from the original clip
var clipsToSelect = movingItems.Select(x => x.originalTrack).SelectMany(x => x.GetClips()).Where(x => assets.Contains(x.asset)).ToArray();
SelectionManager.RemoveTimelineSelection();
foreach (var c in clipsToSelect)
SelectionManager.Add(c);
Done();
}
void Done()
{
foreach (var movingItem in movingItems)
{
foreach (var item in movingItem.items)
{
if (item.gui != null)
item.gui.isInvalid = false;
}
}
movingItems = null;
m_LeftMostMovingItems = null;
m_RightMostMovingItems = null;
m_Grabbing = false;
m_State.Refresh();
}
public double start { get { return m_ItemsGroup.start; } }
public double end { get { return m_ItemsGroup.end; } }
public bool ShouldSnapTo(ISnappable snappable)
{
var itemGUI = snappable as TimelineItemGUI;
return itemGUI != null && !m_ItemGUIs.Contains(itemGUI);
}
public void UpdateTrackTarget(TrackAsset track)
{
if (!EditMode.AllowTrackSwitch())
return;
targetTrack = track;
var targetTracksChanged = false;
foreach (var grabbedItem in movingItems)
{
var prevTrackGUI = grabbedItem.targetTrack;
grabbedItem.SetReferenceTrack(track);
targetTracksChanged = grabbedItem.targetTrack != prevTrackGUI;
}
if (targetTracksChanged)
EditMode.HandleTrackSwitch(movingItems);
RefreshPreviewItems();
m_State.rebuildGraph |= targetTracksChanged;
}
public void OnGUI(Event evt)
{
if (!m_Grabbing)
return;
if (evt.type != EventType.Repaint)
return;
var isValid = IsValidDrop();
using (new GUIViewportScope(m_State.GetWindow().sequenceContentRect))
{
foreach (var grabbedClip in movingItems)
{
grabbedClip.RefreshBounds(m_State, evt.mousePosition);
if (!grabbedClip.HasAnyDetachedParents())
continue;
grabbedClip.Draw(isValid);
}
if (isValid)
{
EditMode.DrawMoveGUI(m_State, movingItems);
}
else
{
TimelineCursors.ClearCursor();
}
}
}
public void OnAttractedEdge(IAttractable attractable, ManipulateEdges manipulateEdges, AttractedEdge edge, double time)
{
double offset;
if (edge == AttractedEdge.Right)
{
var duration = end - start;
var startTime = time - duration;
startTime = EditMode.AdjustStartTime(m_State, m_RightMostMovingItems, startTime);
offset = startTime + duration - end;
}
else
{
if (edge == AttractedEdge.Left)
time = EditMode.AdjustStartTime(m_State, m_LeftMostMovingItems, time);
offset = time - start;
}
if (start + offset < 0.0)
offset = -start;
if (!offset.Equals(0.0))
{
foreach (var grabbedClips in movingItems)
grabbedClips.start += offset;
EditMode.UpdateMove();
RefreshPreviewItems();
}
}
public void RefreshPreviewItems()
{
foreach (var movingItemsGroup in movingItems)
{
// Check validity
var valid = ValidateItemDrag(movingItemsGroup);
foreach (var item in movingItemsGroup.items)
{
if (item.gui != null)
item.gui.isInvalid = !valid;
}
movingItemsGroup.canDrop = valid;
}
}
static bool ValidateItemDrag(ItemsPerTrack itemsGroup)
{
//TODO-marker: this is to prevent the drag operation from being canceled when moving only markers
if (itemsGroup.clips.Any())
{
if (itemsGroup.targetTrack == null)
return false;
if (itemsGroup.targetTrack.lockedInHierarchy)
return false;
if (itemsGroup.items.Any(i => !i.IsCompatibleWithTrack(itemsGroup.targetTrack)))
return false;
return EditMode.ValidateDrag(itemsGroup);
}
return true;
}
public void OnTrackDetach()
{
EditMode.OnTrackDetach(movingItems);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6bd368ab00d75c459e2582e017191e6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,161 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
class MoveItemModeMix : IMoveItemMode, IMoveItemDrawer
{
TimelineClip[] m_ClipsMoved;
Dictionary<TimelineClip, double> m_OriginalEaseInDuration = new Dictionary<TimelineClip, double>();
Dictionary<TimelineClip, double> m_OriginalEaseOutDuration = new Dictionary<TimelineClip, double>();
public void OnTrackDetach(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public void HandleTrackSwitch(IEnumerable<ItemsPerTrack> itemsGroups)
{
foreach (var itemsGroup in itemsGroups)
{
var targetTrack = itemsGroup.targetTrack;
if (targetTrack != null && itemsGroup.items.Any())
{
var compatible = itemsGroup.items.First().IsCompatibleWithTrack(targetTrack) &&
!EditModeUtils.IsInfiniteTrack(targetTrack);
var track = compatible ? targetTrack : null;
UndoExtensions.RegisterTrack(track, L10n.Tr("Move Items"));
EditModeUtils.SetParentTrack(itemsGroup.items, track);
}
else
{
EditModeUtils.SetParentTrack(itemsGroup.items, null);
}
}
}
public bool AllowTrackSwitch()
{
return true;
}
public double AdjustStartTime(WindowState state, ItemsPerTrack itemsGroup, double time)
{
return time;
}
public void OnModeClutchEnter(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public void OnModeClutchExit(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public void BeginMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
m_ClipsMoved = itemsGroups.SelectMany(i => i.clips).ToArray();
foreach (var clip in m_ClipsMoved)
{
m_OriginalEaseInDuration[clip] = clip.easeInDuration;
m_OriginalEaseOutDuration[clip] = clip.easeOutDuration;
}
}
public void UpdateMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
//Compute Blends before updating ease values.
foreach(var t in itemsGroups.Select(i=>i.targetTrack).Where(t => t != null))
t.ComputeBlendsFromOverlaps();
//Reset to original ease values. The trim operation will calculate the proper blend values.
foreach(var clip in m_ClipsMoved)
{
clip.easeInDuration = m_OriginalEaseInDuration[clip];
clip.easeOutDuration = m_OriginalEaseOutDuration[clip];
EditorUtility.SetDirty(clip.asset);
}
}
public void FinishMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
var allClips = itemsGroups.Select(i=>i.targetTrack)
.Where(t=>t != null).SelectMany(t => t.clips);
// update easeIn easeOut durations to apply any modifications caused by blends created or modified by clip move.
foreach (var clip in allClips)
{
clip.easeInDuration = clip.easeInDuration;
clip.easeOutDuration = clip.easeOutDuration;
}
}
public bool ValidateMove(ItemsPerTrack itemsGroup)
{
var track = itemsGroup.targetTrack;
var items = itemsGroup.items;
if (EditModeUtils.IsInfiniteTrack(track))
{
double startTime;
double stopTime;
EditModeUtils.GetInfiniteClipBoundaries(track, out startTime, out stopTime);
return items.All(item =>
!EditModeUtils.IsItemWithinRange(item, startTime, stopTime) &&
!EditModeUtils.IsRangeWithinItem(startTime, stopTime, item));
}
var siblings = ItemsUtils.GetItemsExcept(itemsGroup.targetTrack, items);
return items.All(item => EditModeMixUtils.GetPlacementValidity(item, siblings) == PlacementValidity.Valid);
}
public void DrawGUI(WindowState state, IEnumerable<MovingItems> movingItems, Color color)
{
var selectionHasAnyBlendIn = false;
var selectionHasAnyBlendOut = false;
foreach (var grabbedItems in movingItems)
{
var bounds = grabbedItems.onTrackItemsBounds;
var counter = 0;
foreach (var item in grabbedItems.items.OfType<IBlendable>())
{
if (item.hasLeftBlend)
{
EditModeGUIUtils.DrawBoundsEdge(bounds[counter], color, TrimEdge.Start);
selectionHasAnyBlendIn = true;
}
if (item.hasRightBlend)
{
EditModeGUIUtils.DrawBoundsEdge(bounds[counter], color, TrimEdge.End);
selectionHasAnyBlendOut = true;
}
counter++;
}
}
if (selectionHasAnyBlendIn && selectionHasAnyBlendOut)
{
TimelineCursors.SetCursor(TimelineCursors.CursorType.MixBoth);
}
else if (selectionHasAnyBlendIn)
{
TimelineCursors.SetCursor(TimelineCursors.CursorType.MixLeft);
}
else if (selectionHasAnyBlendOut)
{
TimelineCursors.SetCursor(TimelineCursors.CursorType.MixRight);
}
else
{
TimelineCursors.ClearCursor();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a2a8aecb05814e644abbb070fbd91156
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,99 @@
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.Timeline
{
class MoveItemModeReplace : IMoveItemMode, IMoveItemDrawer
{
public void OnTrackDetach(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public void HandleTrackSwitch(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public bool AllowTrackSwitch()
{
return true;
}
public double AdjustStartTime(WindowState state, ItemsPerTrack itemsGroup, double time)
{
return time;
}
public void OnModeClutchEnter(IEnumerable<ItemsPerTrack> itemsGroups)
{
// TODO
}
public void OnModeClutchExit(IEnumerable<ItemsPerTrack> itemsGroups)
{
// TODO
}
public void BeginMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
foreach (var itemsGroup in itemsGroups)
{
EditModeUtils.SetParentTrack(itemsGroup.items, null);
}
}
public void UpdateMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public void FinishMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
EditModeReplaceUtils.Insert(itemsGroups);
}
public bool ValidateMove(ItemsPerTrack itemsGroup)
{
return true;
}
public void DrawGUI(WindowState state, IEnumerable<MovingItems> movingItems, Color color)
{
var operationWillReplace = false;
foreach (var itemsPerTrack in movingItems)
{
var bounds = itemsPerTrack.onTrackItemsBounds;
var counter = 0;
foreach (var item in itemsPerTrack.items)
{
if (EditModeUtils.GetFirstIntersectedItem(itemsPerTrack.items, item.start) != null)
{
EditModeGUIUtils.DrawBoundsEdge(bounds[counter], color, TrimEdge.Start);
operationWillReplace = true;
}
if (EditModeUtils.GetFirstIntersectedItem(itemsPerTrack.items, item.end) != null)
{
EditModeGUIUtils.DrawBoundsEdge(bounds[counter], color, TrimEdge.End);
operationWillReplace = true;
}
counter++;
// TODO Display swallowed clips?
}
}
if (operationWillReplace)
{
TimelineCursors.SetCursor(TimelineCursors.CursorType.Replace);
}
else
{
TimelineCursors.ClearCursor();
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ea5e2240e8a7d9046a651557deec40b2
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,271 @@
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Object = UnityEngine.Object;
namespace UnityEditor.Timeline
{
class MoveItemModeRipple : IMoveItemMode, IMoveItemDrawer
{
const float k_SnapToEdgeDistance = 30.0f;
class PrevItemInfo
{
public ITimelineItem item;
public ITimelineItem firstSelectedItem;
public bool blending;
public PrevItemInfo(ITimelineItem item, ITimelineItem firstSelectedItem)
{
this.item = item;
this.firstSelectedItem = firstSelectedItem;
blending = item != null && item.end > firstSelectedItem.start;
}
}
readonly Dictionary<Object, List<ITimelineItem>> m_NextItems = new Dictionary<Object, List<ITimelineItem>>();
readonly Dictionary<Object, PrevItemInfo> m_PreviousItem = new Dictionary<Object, PrevItemInfo>();
double m_PreviousEnd;
bool m_TrackLocked;
bool m_Detached;
public void OnTrackDetach(IEnumerable<ItemsPerTrack> itemsGroups)
{
if (m_TrackLocked)
return;
if (m_Detached)
return;
if (itemsGroups.Any(x => x.markers.Any()))
return;
// Ripple can either remove or not clips when detaching them from their track.
// Keep it off for now. TODO: add clutch key to toggle this feature?
//EditModeRippleUtils.Remove(manipulatedClipsList);
StartDetachMode(itemsGroups);
}
public void HandleTrackSwitch(IEnumerable<ItemsPerTrack> itemsGroups)
{
// Nothing
}
public bool AllowTrackSwitch()
{
return !m_TrackLocked;
}
public double AdjustStartTime(WindowState state, ItemsPerTrack itemsGroup, double time)
{
var track = itemsGroup.targetTrack;
if (track == null)
return time;
double start;
double end;
if (EditModeUtils.IsInfiniteTrack(track))
{
EditModeUtils.GetInfiniteClipBoundaries(track, out start, out end);
}
else
{
var siblings = ItemsUtils.GetItemsExcept(track, itemsGroup.items);
var firstIntersectedItem = EditModeUtils.GetFirstIntersectedItem(siblings, time);
if (firstIntersectedItem == null)
return time;
start = firstIntersectedItem.start;
end = firstIntersectedItem.end;
}
var closestTime = Math.Abs(time - start) < Math.Abs(time - end) ? start : end;
var pixelTime = state.TimeToPixel(time);
var pixelClosestTime = state.TimeToPixel(closestTime);
if (Math.Abs(pixelTime - pixelClosestTime) < k_SnapToEdgeDistance)
return closestTime;
return time;
}
void StartDetachMode(IEnumerable<ItemsPerTrack> itemsGroups)
{
m_Detached = true;
foreach (var itemsGroup in itemsGroups)
EditModeUtils.SetParentTrack(itemsGroup.items, null);
}
public void OnModeClutchEnter(IEnumerable<ItemsPerTrack> itemsGroups)
{
StartDetachMode(itemsGroups);
m_TrackLocked = false;
}
public void OnModeClutchExit(IEnumerable<ItemsPerTrack> itemsGroups)
{
m_Detached = false;
m_TrackLocked = false;
}
public void BeginMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
m_NextItems.Clear();
m_PreviousItem.Clear();
var itemTypes = ItemsUtils.GetItemTypes(itemsGroups).ToList();
foreach (var itemsGroup in itemsGroups)
{
//can only ripple items of the same type as those selected
var sortedSelectedItems = itemsGroup.items.OrderBy(i => i.start).ToList();
var siblings = itemsGroup.targetTrack.GetItemsExcept(itemsGroup.items);
var sortedSiblingsToRipple = siblings.Where(i => itemTypes.Contains(i.GetType())).OrderBy(i => i.start).ToList();
var start = sortedSelectedItems.First().start;
m_NextItems.Add(itemsGroup.targetTrack, sortedSiblingsToRipple.Where(i => i.start > start).ToList());
m_PreviousItem.Add(itemsGroup.targetTrack, CalculatePrevItemInfo(sortedSelectedItems, sortedSiblingsToRipple, itemTypes));
}
m_PreviousEnd = itemsGroups.Max(m => m.items.Max(c => c.end));
}
public void UpdateMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
if (m_Detached)
return;
m_TrackLocked = true;
var overlap = 0.0;
foreach (var itemsGroup in itemsGroups)
{
var track = itemsGroup.targetTrack;
if (track == null) continue;
var prevItemInfo = m_PreviousItem[track];
if (prevItemInfo.item != null)
{
var prevItem = prevItemInfo.item;
var firstItem = prevItemInfo.firstSelectedItem;
if (prevItemInfo.blending)
prevItemInfo.blending = prevItem.end > firstItem.start;
if (prevItemInfo.blending)
{
var b = EditModeUtils.BlendDuration(firstItem, TrimEdge.End);
overlap = Math.Max(overlap, Math.Max(prevItem.start, prevItem.end - firstItem.end + firstItem.start + b) - firstItem.start);
}
else
{
overlap = Math.Max(overlap, prevItem.end - firstItem.start);
}
}
}
if (overlap > 0)
{
foreach (var itemsGroup in itemsGroups)
{
foreach (var item in itemsGroup.items)
item.start += overlap;
}
}
var newEnd = itemsGroups.Max(m => m.items.Max(c => c.end));
var offset = newEnd - m_PreviousEnd;
m_PreviousEnd = newEnd;
foreach (var itemsGroup in itemsGroups)
{
foreach (var item in m_NextItems[itemsGroup.targetTrack])
item.start += offset;
}
}
static PrevItemInfo CalculatePrevItemInfo(List<ITimelineItem> orderedSelection, List<ITimelineItem> orderedSiblings, IEnumerable<Type> itemTypes)
{
ITimelineItem previousItem = null;
ITimelineItem firstSelectedItem = null;
var gap = double.PositiveInfinity;
foreach (var type in itemTypes)
{
var firstSelectedItemOfType = orderedSelection.FirstOrDefault(i => i.GetType() == type);
if (firstSelectedItemOfType == null) continue;
var previousItemOfType = orderedSiblings.LastOrDefault(i => i.GetType() == type && i.start < firstSelectedItemOfType.start);
if (previousItemOfType == null) continue;
var currentGap = firstSelectedItemOfType.start - previousItemOfType.end;
if (currentGap < gap)
{
gap = currentGap;
firstSelectedItem = firstSelectedItemOfType;
previousItem = previousItemOfType;
}
}
return new PrevItemInfo(previousItem, firstSelectedItem);
}
public bool ValidateMove(ItemsPerTrack itemsGroup)
{
return true;
}
public void FinishMove(IEnumerable<ItemsPerTrack> itemsGroups)
{
if (m_Detached)
EditModeRippleUtils.Insert(itemsGroups);
m_Detached = false;
m_TrackLocked = false;
}
public void DrawGUI(WindowState state, IEnumerable<MovingItems> movingItems, Color color)
{
if (m_Detached)
{
var xMin = float.MaxValue;
var xMax = float.MinValue;
foreach (var grabbedItems in movingItems)
{
xMin = Math.Min(xMin, grabbedItems.onTrackItemsBounds.Min(b => b.xMin)); // TODO Cache this?
xMax = Math.Max(xMax, grabbedItems.onTrackItemsBounds.Max(b => b.xMax));
}
foreach (var grabbedItems in movingItems)
{
var bounds = Rect.MinMaxRect(xMin, grabbedItems.onTrackItemsBounds[0].yMin,
xMax, grabbedItems.onTrackItemsBounds[0].yMax);
EditModeGUIUtils.DrawOverlayRect(bounds, new Color(1.0f, 1.0f, 1.0f, 0.5f));
EditModeGUIUtils.DrawBoundsEdge(bounds, color, TrimEdge.Start);
}
}
else
{
foreach (var grabbedItems in movingItems)
{
var bounds = Rect.MinMaxRect(grabbedItems.onTrackItemsBounds.Min(b => b.xMin), grabbedItems.onTrackItemsBounds[0].yMin,
grabbedItems.onTrackItemsBounds.Max(b => b.xMax), grabbedItems.onTrackItemsBounds[0].yMax);
EditModeGUIUtils.DrawBoundsEdge(bounds, color, TrimEdge.Start);
}
}
TimelineCursors.SetCursor(TimelineCursors.CursorType.Ripple);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: eebde5009793ce948bf5d4c4435b89b9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,137 @@
using System;
using System.Linq;
using UnityEngine;
using UnityEngine.Timeline;
namespace UnityEditor.Timeline
{
class MovingItems : ItemsPerTrack
{
TrackAsset m_ReferenceTrack;
readonly bool m_AllowTrackSwitch;
readonly Rect[] m_ItemsBoundsOnTrack;
readonly Vector2[] m_ItemsMouseOffsets;
static readonly Rect s_InvisibleBounds = new Rect(float.MaxValue, float.MaxValue, 0.0f, 0.0f);
public TrackAsset originalTrack { get; }
public override TrackAsset targetTrack
{
get
{
if (m_AllowTrackSwitch)
return m_ReferenceTrack;
return originalTrack;
}
}
public bool canDrop;
public double start
{
get { return m_ItemsGroup.start; }
set { m_ItemsGroup.start = value; }
}
public double end
{
get { return m_ItemsGroup.end; }
}
public Rect[] onTrackItemsBounds
{
get { return m_ItemsBoundsOnTrack; }
}
public MovingItems(WindowState state, TrackAsset parentTrack, ITimelineItem[] items, TrackAsset referenceTrack, Vector2 mousePosition, bool allowTrackSwitch)
: base(parentTrack, items)
{
originalTrack = parentTrack;
m_ReferenceTrack = referenceTrack;
m_AllowTrackSwitch = allowTrackSwitch;
m_ItemsBoundsOnTrack = new Rect[items.Length];
m_ItemsMouseOffsets = new Vector2[items.Length];
for (int i = 0; i < items.Length; ++i)
{
var itemGUi = items[i].gui;
if (itemGUi != null)
{
m_ItemsBoundsOnTrack[i] = itemGUi.rect;
m_ItemsMouseOffsets[i] = mousePosition - m_ItemsBoundsOnTrack[i].position;
}
}
canDrop = true;
}
public void SetReferenceTrack(TrackAsset track)
{
m_ReferenceTrack = track;
}
public bool HasAnyDetachedParents()
{
return m_ItemsGroup.items.Any(x => x.parentTrack == null);
}
public void RefreshBounds(WindowState state, Vector2 mousePosition)
{
for (int i = 0; i < m_ItemsGroup.items.Length; ++i)
{
var item = m_ItemsGroup.items[i];
var itemGUI = item.gui;
if (item.parentTrack != null)
{
m_ItemsBoundsOnTrack[i] = itemGUI.visible ? itemGUI.rect : s_InvisibleBounds;
}
else
{
if (targetTrack != null)
{
var trackGUI = (TimelineTrackGUI)TimelineWindow.instance.allTracks.FirstOrDefault(t => t.track == targetTrack);
if (trackGUI == null) return;
var trackRect = trackGUI.boundingRect;
m_ItemsBoundsOnTrack[i] = itemGUI.RectToTimeline(trackRect, state);
}
else
{
m_ItemsBoundsOnTrack[i].position = mousePosition - m_ItemsMouseOffsets[i];
}
}
}
}
public void Draw(bool isValid)
{
for (int i = 0; i < m_ItemsBoundsOnTrack.Length; ++i)
{
var rect = m_ItemsBoundsOnTrack[i];
DrawItemInternal(m_ItemsGroup.items[i], rect, isValid);
}
}
static void DrawItemInternal(ITimelineItem item, Rect rect, bool isValid)
{
var clipGUI = item.gui as TimelineClipGUI;
if (clipGUI != null)
{
if (isValid)
{
clipGUI.DrawGhostClip(rect);
}
else
{
clipGUI.DrawInvalidClip(rect);
}
}
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81a142c61a4e14d46bb21b02548ad24d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: