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();
        }
        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();
            m_State.analytics.SendManipulationEndedEvent();
        }
        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
            foreach (var sourceTrack in tracks)
            {
                // one push per track handles all the clips on the track
                TimelineUndo.PushUndo(sourceTrack, "Move Items");

                // push all markers on the track because of ripple
                foreach (var marker in sourceTrack.GetMarkers().OfType <ScriptableObject>())
                {
                    TimelineUndo.PushUndo(marker, "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 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;

            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
            foreach (var item in referenceTrack.GetItems())                                                      // Ripple changes other items
            {
                item.PushUndo("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;
        }