예제 #1
0
        /// <summary>
        /// Moves the objects represented by the current ghosts to be at the position of
        /// the ghosts</summary>
        protected virtual void MoveSelection()
        {
            // To avoid setting the dirty bit in custom applications.
            // http://sf.ship.scea.com/sf/go/artf22506
            PointF dragOffset = m_owner.GetDragOffset();

            if ((dragOffset.X == 0.0f) && (dragOffset.Y == 0.0f))
            {
                return;
            }

            // If we're dragging up, then don't create new tracks
            if (dragOffset.Y < 0)
            {
                foreach (GhostInfo ghost in m_ghosts)
                {
                    if (!ghost.Valid)
                    {
                        return;
                    }
                }
            }

            // If Control key is being held down, then we're in copy mode.
            bool tryToCopy = (Control.ModifierKeys == Keys.Control);

            m_owner.TransactionContext.DoTransaction(delegate
            {
                ITimeline timeline = m_owner.TimelineDocument.Timeline;
                Dictionary <ITrack, ITrack> newTrackMap     = new Dictionary <ITrack, ITrack>();
                List <Sce.Atf.Pair <ITrack, IEvent> > toAdd = new List <Sce.Atf.Pair <ITrack, IEvent> >();

                for (int i = 0; i < m_ghosts.Length; i++)
                {
                    GhostInfo ghost = m_ghosts[i];

                    ITimelineObject ghostCopy = null;
                    if (tryToCopy)
                    {
                        ICloneable cloneable = ghost.Object as ICloneable;
                        if (cloneable != null)
                        {
                            ghostCopy = cloneable.Clone() as ITimelineObject;
                        }
                    }

                    ITimelineReference reference = ghost.Object as ITimelineReference;
                    if (reference != null)
                    {
                        if (ghostCopy != null)
                        {
                            reference = (ITimelineReference)ghostCopy;
                        }
                        reference.Start = ghost.Start;
                        if (ghostCopy != null && timeline is IHierarchicalTimelineList)
                        {
                            ((IHierarchicalTimelineList)timeline).References.Add(reference);
                        }
                        continue;
                    }

                    IInterval interval = ghost.Object as IInterval;
                    if (interval != null)
                    {
                        if (ghostCopy != null)
                        {
                            interval = (IInterval)ghostCopy;
                        }
                        interval.Start  = ghost.Start;
                        interval.Length = ghost.Length;
                        ITrack target   = (ITrack)ghost.Target;
                        if (target != interval.Track)
                        {
                            if (target == null)
                            {
                                target = CreateTargetTrack(interval.Track, newTrackMap);
                            }
                            if (ghostCopy == null)
                            {
                                interval.Track.Intervals.Remove(interval);
                            }
                            toAdd.Add(new Sce.Atf.Pair <ITrack, IEvent>(target, interval));
                        }
                        continue;
                    }

                    IKey key = ghost.Object as IKey;
                    if (key != null)
                    {
                        if (ghostCopy != null)
                        {
                            key = (IKey)ghostCopy;
                        }
                        key.Start     = ghost.Start;
                        ITrack target = (ITrack)ghost.Target;
                        if (target != key.Track)
                        {
                            if (target == null)
                            {
                                target = CreateTargetTrack(key.Track, newTrackMap);
                            }
                            if (ghostCopy == null)
                            {
                                key.Track.Keys.Remove(key);
                            }
                            toAdd.Add(new Sce.Atf.Pair <ITrack, IEvent>(target, key));
                        }
                        continue;
                    }

                    IMarker marker = ghost.Object as IMarker;
                    if (marker != null)
                    {
                        if (ghost.Valid &&
                            marker.Start != ghost.Start)
                        {
                            if (ghostCopy != null)
                            {
                                IMarker markerCopy = (IMarker)ghostCopy;
                                markerCopy.Start   = ghost.Start;
                                marker.Timeline.Markers.Add(markerCopy);
                            }
                            else
                            {
                                marker.Start = ghost.Start;
                            }
                        }
                        continue;
                    }

                    ITrack track = ghost.Object as ITrack;
                    if (track != null)
                    {
                        ITrack target = (ITrack)ghost.Target;
                        if (target != null &&
                            target != track)
                        {
                            if (ghostCopy != null)
                            {
                                track = (ITrack)ghostCopy;
                            }
                            int index = target.Group.Tracks.IndexOf(target);
                            if (ghostCopy == null)
                            {
                                track.Group.Tracks.Remove(track);
                            }
                            target.Group.Tracks.Insert(index, track);
                        }
                        continue;
                    }

                    IGroup group = ghost.Object as IGroup;
                    if (group != null)
                    {
                        IGroup target = (IGroup)ghost.Target;
                        if (target != null &&
                            target != group)
                        {
                            if (ghostCopy != null)
                            {
                                group = (IGroup)ghostCopy;
                            }
                            int index = m_owner.TimelineDocument.Timeline.Groups.IndexOf(target);
                            if (ghostCopy == null)
                            {
                                m_owner.TimelineDocument.Timeline.Groups.Remove(group);
                            }
                            m_owner.TimelineDocument.Timeline.Groups.Insert(index, group);
                        }
                        continue;
                    }
                }

                // So that when multiple intervals from multiple tracks are relocated to a different
                //  set of tracks, we need to remove them all and then add them all. If the remove and
                //  adds are done in pairs, one by one, then the events can step on each other. artf32260
                foreach (Sce.Atf.Pair <ITrack, IEvent> trackEventPair in toAdd)
                {
                    if (trackEventPair.Second is IInterval)
                    {
                        trackEventPair.First.Intervals.Add((IInterval)trackEventPair.Second);
                    }
                    else
                    {
                        trackEventPair.First.Keys.Add((IKey)trackEventPair.Second);
                    }
                }
            },
                                                     "Move Events".Localize("Move Manipulator's undo / redo description for moving timeline events"));
        }
예제 #2
0
        // gets move information, for drawing ghosts and for performing actual move operation
        private GhostInfo[] GetMoveGhostInfo(Matrix worldToView, TimelineLayout layout)
        {
            // get start and y offsets in timeline space
            PointF dragOffset = m_owner.GetDragOffset();

            // Get snapping points along the timeline (in world coordinates).
            List<float> movingPoints = new List<float>(2);
            TimelinePath snapperPath;
            if (m_mouseMoveHitRecord != null)
                snapperPath = m_mouseMoveHitRecord.HitPath;//use the last clicked event (interval, key or marker)
            else
                snapperPath = m_owner.Selection.LastSelected as TimelinePath;//moving a group or track, for example
            IEvent snapperEvent = snapperPath != null ? snapperPath.Last as IEvent : null;

            if (snapperEvent != null)
            {
                Matrix localToWorld = TimelineControl.CalculateLocalToWorld(snapperPath);
                float worldStart = GdiUtil.Transform(localToWorld, snapperEvent.Start + dragOffset.X);
                movingPoints.Add(worldStart);
                if (snapperEvent.Length > 0.0f)
                    movingPoints.Add(GdiUtil.Transform(localToWorld, snapperEvent.Start + dragOffset.X + snapperEvent.Length));
            }

            // Get the offset from one of the world snap points to the closest non-selected object.
            float snapOffset;
            try
            {
                s_snapOptions.FilterContext = snapperEvent;
                s_snapOptions.Filter = new TimelineControl.SnapFilter(MoveSnapFilter);
                snapOffset = m_owner.GetSnapOffset(movingPoints, s_snapOptions);
            }
            finally
            {
                s_snapOptions.FilterContext = null;
                s_snapOptions.Filter = null;
            }

            // adjust dragOffset to "snap-to" nearest event
            dragOffset.X += snapOffset;

            // get offsets in client space
            float xOffset = dragOffset.X * worldToView.Elements[0];
            float yOffset = dragOffset.Y * worldToView.Elements[3];

            TimelinePath[] targets = GetMoveTargets(layout);

            GhostInfo[] ghosts = new GhostInfo[targets.Length];
            int i = -1;
            foreach(TimelinePath path in m_owner.Selection.Selection)
            {
                i++;

                ITimelineObject timelineObject = path.Last;
                RectangleF bounds = layout[path];

                TimelinePath targetPath = targets[i];
                ITimelineObject target = targetPath != null ? targetPath.Last : null;

                float start = 0;
                float length = 0;
                bool valid = true;

                IInterval interval = timelineObject as IInterval;
                IKey key = timelineObject as IKey;
                IMarker marker = timelineObject as IMarker;
                ITrack track = timelineObject as ITrack;
                IGroup group = timelineObject as IGroup;
                ITimelineReference reference = timelineObject as ITimelineReference;

                if (interval != null)
                {
                    ITrack targetTrack = target as ITrack;
                    start = interval.Start + dragOffset.X;
                    length = interval.Length;
                    valid =
                        targetTrack != null &&
                        m_owner.Constraints.IsStartValid(interval, ref start) &&
                        m_owner.Constraints.IsLengthValid(interval, ref length);

                    if (valid)
                    {
                        yOffset = layout[target].Y - layout[interval.Track].Y;
                        TimelinePath testPath = new TimelinePath(targetPath);
                        foreach (IInterval other in targetTrack.Intervals)
                        {
                            // skip selected intervals, since they are moving too
                            testPath.Last = other;
                            if (m_owner.Selection.SelectionContains(testPath))
                                continue;

                            if (!m_owner.Constraints.IsIntervalValid(interval, ref start, ref length, other))
                            {
                                valid = false;
                                break;
                            }
                        }
                    }
                }
                else if (reference != null)
                {
                    // don't allow for vertical repositioning yet
                    start = reference.Start + dragOffset.X;
                    valid = true;
                }
                else if (key != null)
                {
                    start = key.Start + dragOffset.X;
                    ITrack targetTrack = target as ITrack;
                    valid =
                        targetTrack != null &&
                        m_owner.Constraints.IsStartValid(key, ref start);

                    if (valid)
                    {
                        yOffset = layout[targetTrack].Y - layout[key.Track].Y;
                    }
                }
                else if (marker != null)
                {
                    start = marker.Start + dragOffset.X;
                    yOffset = 0;
                    valid = m_owner.Constraints.IsStartValid(marker, ref start);
                }
                else if (track != null)
                {
                    xOffset = 0;
                    if (target == null)
                    {
                        target =
                            (m_owner.DragDelta.Y < 0) ? GetLastTrack() : GetFirstTrack();
                    }
                }
                else if (group != null)
                {
                    xOffset = 0;
                    if (target == null)
                    {
                        IList<IGroup> groups = m_owner.TimelineDocument.Timeline.Groups;
                        target = (m_owner.DragDelta.Y < 0) ? groups[0] : groups[groups.Count - 1];
                    }
                }

                bounds.Offset(xOffset, yOffset);

                ghosts[i] = new GhostInfo(timelineObject, target, start, length, bounds, valid);
            }
            return ghosts;
        }
예제 #3
0
        // gets move information, for drawing ghosts and for performing actual move operation
        private GhostInfo[] GetMoveGhostInfo(Matrix worldToView, TimelineLayout layout)
        {
            // get start and y offsets in timeline space
            PointF dragOffset = m_owner.GetDragOffset();

            // Get snapping points along the timeline (in world coordinates).
            List <float> movingPoints = new List <float>(2);
            TimelinePath snapperPath;

            if (m_mouseMoveHitRecord != null)
            {
                snapperPath = m_mouseMoveHitRecord.HitPath;//use the last clicked event (interval, key or marker)
            }
            else
            {
                snapperPath = m_owner.Selection.LastSelected as TimelinePath;//moving a group or track, for example
            }
            IEvent snapperEvent = snapperPath != null ? snapperPath.Last as IEvent : null;

            if (snapperEvent != null)
            {
                Matrix localToWorld = TimelineControl.CalculateLocalToWorld(snapperPath);
                float  worldStart   = GdiUtil.Transform(localToWorld, snapperEvent.Start + dragOffset.X);
                movingPoints.Add(worldStart);
                if (snapperEvent.Length > 0.0f)
                {
                    movingPoints.Add(GdiUtil.Transform(localToWorld, snapperEvent.Start + dragOffset.X + snapperEvent.Length));
                }
            }

            // Get the offset from one of the world snap points to the closest non-selected object.
            float snapOffset;

            try
            {
                s_snapOptions.FilterContext = snapperEvent;
                s_snapOptions.Filter        = new TimelineControl.SnapFilter(MoveSnapFilter);
                snapOffset = m_owner.GetSnapOffset(movingPoints, s_snapOptions);
            }
            finally
            {
                s_snapOptions.FilterContext = null;
                s_snapOptions.Filter        = null;
            }

            // adjust dragOffset to "snap-to" nearest event
            dragOffset.X += snapOffset;

            // get offsets in client space
            float xOffset = dragOffset.X * worldToView.Elements[0];
            float yOffset = dragOffset.Y * worldToView.Elements[3];

            TimelinePath[] targets = GetMoveTargets(layout);

            GhostInfo[] ghosts = new GhostInfo[targets.Length];
            int         i      = -1;

            foreach (TimelinePath path in m_owner.Selection.Selection)
            {
                i++;

                ITimelineObject timelineObject = path.Last;
                RectangleF      bounds         = layout[path];

                TimelinePath    targetPath = targets[i];
                ITimelineObject target     = targetPath != null ? targetPath.Last : null;

                float start  = 0;
                float length = 0;
                bool  valid  = true;

                IInterval          interval  = timelineObject as IInterval;
                IKey               key       = timelineObject as IKey;
                IMarker            marker    = timelineObject as IMarker;
                ITrack             track     = timelineObject as ITrack;
                IGroup             group     = timelineObject as IGroup;
                ITimelineReference reference = timelineObject as ITimelineReference;

                if (interval != null)
                {
                    ITrack targetTrack = target as ITrack;
                    start  = interval.Start + dragOffset.X;
                    length = interval.Length;
                    valid  =
                        targetTrack != null &&
                        m_owner.Constraints.IsStartValid(interval, ref start) &&
                        m_owner.Constraints.IsLengthValid(interval, ref length);

                    if (valid)
                    {
                        yOffset = layout[target].Y - layout[interval.Track].Y;
                        TimelinePath testPath = new TimelinePath(targetPath);
                        foreach (IInterval other in targetTrack.Intervals)
                        {
                            // skip selected intervals, since they are moving too
                            testPath.Last = other;
                            if (m_owner.Selection.SelectionContains(testPath))
                            {
                                continue;
                            }

                            if (!m_owner.Constraints.IsIntervalValid(interval, ref start, ref length, other))
                            {
                                valid = false;
                                break;
                            }
                        }
                    }
                }
                else if (reference != null)
                {
                    // don't allow for vertical repositioning yet
                    start = reference.Start + dragOffset.X;
                    valid = true;
                }
                else if (key != null)
                {
                    start = key.Start + dragOffset.X;
                    ITrack targetTrack = target as ITrack;
                    valid =
                        targetTrack != null &&
                        m_owner.Constraints.IsStartValid(key, ref start);

                    if (valid)
                    {
                        yOffset = layout[targetTrack].Y - layout[key.Track].Y;
                    }
                }
                else if (marker != null)
                {
                    start   = marker.Start + dragOffset.X;
                    yOffset = 0;
                    valid   = m_owner.Constraints.IsStartValid(marker, ref start);
                }
                else if (track != null)
                {
                    xOffset = 0;
                    if (target == null)
                    {
                        target =
                            (m_owner.DragDelta.Y < 0) ? GetLastTrack() : GetFirstTrack();
                    }
                }
                else if (group != null)
                {
                    xOffset = 0;
                    if (target == null)
                    {
                        IList <IGroup> groups = m_owner.TimelineDocument.Timeline.Groups;
                        target = (m_owner.DragDelta.Y < 0) ? groups[0] : groups[groups.Count - 1];
                    }
                }

                bounds.Offset(xOffset, yOffset);

                ghosts[i] = new GhostInfo(timelineObject, target, start, length, bounds, valid);
            }
            return(ghosts);
        }
예제 #4
0
            /// <summary>
            /// Creates and caches resize information, for drawing ghosts and for performing
            /// actual resize operations</summary>
            /// <param name="layout">TimelineLayout</param>
            /// <param name="worldDrag">Drag offset</param>
            /// <param name="worldToView">World to view transformation matrix</param>
            /// <returns>Array of GhostInfo</returns>
            internal GhostInfo[] CreateGhostInfo(TimelineLayout layout, float worldDrag, Matrix worldToView)
            {
                // Get snap-from point in world coordinates.
                float[] movingPoints = new[] { worldDrag + m_originalBoundary };
                float   snapOffset   = m_owner.GetSnapOffset(movingPoints, null);

                // adjust dragOffset to snap-to nearest event
                worldDrag         += snapOffset;
                DragOffsetWithSnap = worldDrag;

                GhostInfo[] ghosts = new GhostInfo[m_selection.Count];
                IEnumerator <TimelinePath> events = m_selection.GetEnumerator();

                m_worldGhostMin = float.MaxValue;
                m_worldGhostMax = float.MinValue;

                for (int i = 0; i < ghosts.Length; i++)
                {
                    events.MoveNext();
                    IEvent     curr       = (IEvent)events.Current.Last;
                    RectangleF bounds     = layout[events.Current];
                    float      viewStart  = bounds.Left;
                    float      viewEnd    = viewStart + bounds.Width;
                    float      worldStart = curr.Start;
                    float      worldEnd   = worldStart + curr.Length;

                    Resize(
                        worldDrag,
                        worldToView,
                        ref viewStart, ref viewEnd,
                        ref worldStart, ref worldEnd);

                    float worldLength = worldEnd - worldStart;
                    bounds = new RectangleF(viewStart, bounds.Y, viewEnd - viewStart, bounds.Height);
                    if (m_worldGhostMin > worldStart)
                    {
                        m_worldGhostMin = worldStart;
                    }
                    if (m_worldGhostMax < worldEnd)
                    {
                        m_worldGhostMax = worldEnd;
                    }

                    bool valid = true;

                    IInterval interval = curr as IInterval;
                    if (interval != null)
                    {
                        TimelinePath testPath = new TimelinePath(events.Current);
                        foreach (IInterval other in interval.Track.Intervals)
                        {
                            // Skip this interval if it's part of the selection because we have to assume
                            //  that the track began in a valid state and that all of the selected objects
                            //  will still be valid relative to each other. We only need to check that the
                            //  scaled objects are valid relative to the stationary objects.
                            testPath.Last = other;
                            if (Mode == ScaleMode.TimePeriod &&
                                m_selection.Contains(testPath))
                            {
                                continue;
                            }
                            else if (other == interval)
                            {
                                continue;
                            }

                            if (!m_owner.Constraints.IsIntervalValid(interval, ref worldStart, ref worldLength, other))
                            {
                                valid = false;
                                break;
                            }
                        }
                    }

                    ghosts[i] = new GhostInfo(curr, null, worldStart, worldLength, bounds, valid);
                }

                m_ghosts = ghosts;
                return(ghosts);
            }