Exemple #1
0
        // private because this may be moved to TimelineControl
        private bool Overlaps(TimelinePath path, float beginTime, float endTime)
        {
            IEvent e = (IEvent)path.Last;

            float start, length;

            using (Matrix localToWorld = D2dTimelineControl.CalculateLocalToWorld(path))
            {
                start  = GdiUtil.Transform(localToWorld, e.Start);
                length = GdiUtil.TransformVector(localToWorld, e.Length);
            }

            // If the length is zero, then count an exact match with beginTime or endTime as
            //  being an overlap.
            if (length == 0)
            {
                return(!(
                           start > endTime ||
                           start + length < beginTime));
            }

            // Otherwise, don't count an exact match.
            return(!(
                       start >= endTime ||
                       start + length <= beginTime));
        }
        private void owner_MouseMovePicked(object sender, HitEventArgs e)
        {
            string toolTipText = null;

            if (m_active)
            {
                e.Handled = true;

                if (e.HitRecord.Type == HitType.Interval &&
                    e.MouseEvent.Button == MouseButtons.None &&
                    !m_owner.IsUsingMouse &&
                    m_owner.IsEditable(e.HitRecord.HitPath))
                {
                    SetCursor();
                    TimelinePath hitPath   = e.HitRecord.HitPath;
                    IInterval    hitObject = (IInterval)e.HitRecord.HitTimelineObject;
                    float        worldX    = GdiUtil.InverseTransform(m_owner.Transform, e.MouseEvent.Location.X);

                    //Make sure the snap-to indicator line is drawn.
                    float delta = m_owner.GetSnapOffset(new[] { worldX }, s_snapOptions);

                    worldX += delta;
                    worldX  = m_owner.ConstrainFrameOffset(worldX);

                    using (Matrix localToWorld = D2dTimelineControl.CalculateLocalToWorld(hitPath))
                    {
                        if (worldX <= GdiUtil.Transform(localToWorld, hitObject.Start) ||
                            worldX >= GdiUtil.Transform(localToWorld, hitObject.Start + hitObject.Length))
                        {
                            // Clear the results since a split is impossible.
                            m_owner.GetSnapOffset(new float[] {}, s_snapOptions);
                        }
                        else
                        {
                            toolTipText = worldX.ToString();
                        }
                    }
                }
            }

            if (toolTipText != null)
            {
                m_toolTip.Show(toolTipText, m_owner, e.MouseEvent.Location);
            }
            else
            {
                m_toolTip.Hide(m_owner);
            }
        }
        private void owner_MouseDownPicked(object sender, HitEventArgs e)
        {
            TimelinePath hitPath     = e.HitRecord.HitPath;
            IInterval    hitInterval = e.HitRecord.HitTimelineObject as IInterval;

            if (m_active &&
                e.MouseEvent.Button == MouseButtons.Left &&
                !m_owner.IsUsingMouse &&
                m_owner.IsEditable(hitPath))
            {
                if (hitInterval != null &&
                    e.HitRecord.Type == HitType.Interval)
                {
                    PointF mouseLocation = e.MouseEvent.Location;
                    float  worldX        =
                        Sce.Atf.GdiUtil.InverseTransform(m_owner.Transform, mouseLocation.X);

                    worldX += m_owner.GetSnapOffset(new[] { worldX }, s_snapOptions);

                    float fraction;
                    using (Matrix localToWorld = D2dTimelineControl.CalculateLocalToWorld(hitPath))
                    {
                        fraction =
                            (worldX - GdiUtil.Transform(localToWorld, hitInterval.Start)) /
                            GdiUtil.TransformVector(localToWorld, hitInterval.Length);
                    }

                    if (m_owner.Selection.SelectionContains(hitInterval))
                    {
                        SplitSelectedIntervals(fraction);
                    }
                    else
                    {
                        SplitUnselectedInterval(hitInterval, fraction);
                    }
                }
                Active    = false;
                e.Handled = true; //don't let subsequent listeners get this event
            }
        }
Exemple #4
0
        /// <summary>
        /// Gets the offset from one of the world snap points to the closest non-selected object's edge</summary>
        /// <param name="movingPoints">The x-coordinates to snap "from", in world coordinates</param>
        /// <param name="options">The options to control the behavior. If null, the defaults are used.</param>
        /// <returns>The value to be added, to GetDragOffset().X, for example. Is in world coordinates.</returns>
        private float GetSnapOffset(IEnumerable <float> movingPoints, D2dTimelineControl.SnapOptions options)
        {
            //we want to recalculate m_snapInfo and reflect changes to the snap-to lines
            m_snapInfo.Clear();
            m_owner.Invalidate();

            if (options == null)
            {
                options = new D2dTimelineControl.SnapOptions();
            }

            // Check for user-forced snapping and no-snapping.
            if (options.CheckModifierKeys)
            {
                Keys modKeys = Control.ModifierKeys;
                if (s_deactivatorKeys != Keys.None &&
                    (modKeys & s_deactivatorKeys) == s_deactivatorKeys)
                {
                    return(0.0f);
                }
                if (s_activatorKeys != Keys.None &&
                    (modKeys & s_activatorKeys) != s_activatorKeys)
                {
                    return(0.0f);
                }
            }

            // Prepare helper object on each moving point.
            foreach (float snapping in movingPoints)
            {
                m_snapInfo.Add(new SnapOffsetInfo(snapping));
            }
            if (m_snapInfo.Count == 0)
            {
                return(0.0f);
            }

            // Find the closest IEvent.
            float worldSnapTolerance = GdiUtil.InverseTransformVector(m_owner.Transform, s_snapTolerance);

            List <TimelinePath> events = new List <TimelinePath>(
                D2dTimelineControl.GetObjects <IEvent>(m_owner.Timeline));

            // Allow for snapping to a scrubber manipulator.
            if (m_scrubber != null && options.IncludeScrubber)
            {
                events.Add(new TimelinePath(m_scrubber));
            }

            foreach (TimelinePath path in events)
            {
                if (options.IncludeSelected ||
                    !m_owner.Selection.SelectionContains(path))
                {
                    IEvent snapToEvent = (IEvent)path.Last;

                    if (options.Filter == null ||
                        options.Filter(snapToEvent, options))
                    {
                        Matrix localToWorld = D2dTimelineControl.CalculateLocalToWorld(path);
                        float  start, length;
                        GetEventDimensions(snapToEvent, localToWorld, out start, out length);

                        foreach (SnapOffsetInfo info in m_snapInfo)
                        {
                            info.Update(start, snapToEvent, worldSnapTolerance);
                            if (length > 0)
                            {
                                info.Update(start + length, snapToEvent, worldSnapTolerance);
                            }
                        }
                    }
                }
            }

            // Keep only the shortest distance snap-to points. Could be multiple in case of tie.
            SnapOffsetInfo.RemoveInvalid(m_snapInfo);
            if (m_snapInfo.Count == 0)
            {
                return(0.0f);
            }

            SnapOffsetInfo topInfo = m_snapInfo[0];

            return(topInfo.Offset);
        }
Exemple #5
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 = 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 = D2dTimelineControl.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 D2dTimelineControl.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);

            // Pretend that drag-drop objects are in the TimelineLayout object
            if (m_owner.DragDropObjects != null)
            {
                foreach (ITimelineObject dragDrop in m_owner.DragDropObjects)
                {
                    layout[dragDrop] = GetDragDropBounds(dragDrop);
                }
            }

            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;
                    valid &= m_owner.Constraints.IsStartValid(interval, ref start);
                    valid &= m_owner.Constraints.IsLengthValid(interval, ref length);

                    if (valid)
                    {
                        ITrack intervalTrack = interval.Track;
                        if (intervalTrack != null)
                        {
                            yOffset = layout[target].Y - layout[interval.Track].Y;
                        }
                        else
                        {
                            yOffset = layout[target].Y - bounds.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;
                    valid &= m_owner.Constraints.IsStartValid(key, ref start);

                    if (valid)
                    {
                        ITrack keyTrack = key.Track;
                        if (keyTrack != null)
                        {
                            yOffset = layout[targetTrack].Y - layout[key.Track].Y;
                        }
                        else
                        {
                            yOffset = layout[targetTrack].Y - bounds.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 =
                            (DragDelta.Y < 0) ? GetLastTrack() : GetFirstTrack();
                    }
                }
                else if (group != null)
                {
                    xOffset = 0;
                    if (target == null)
                    {
                        IList <IGroup> groups = m_owner.TimelineDocument.Timeline.Groups;
                        target = (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);
        }