Ejemplo n.º 1
0
        /// <summary>
        /// This basically just sets the value of <see cref="Northwoods.GoXam.Node.Position"/>,
        /// but with animated movement.
        /// </summary>
        /// <param name="node"></param>
        /// <param name="newpos">a new position in model coordinates</param>
        /// <remarks>
        /// There is no animation if <see cref="Animated"/> is false,
        /// if the <see cref="AnimationTime"/> is very small, or
        /// if the original position and the new position are very near to each other
        /// or offscreen.
        /// </remarks>
        public void MoveAnimated(Node node, Point newpos)
        {
            if (node == null)
            {
                return;
            }
            VerifyAccess();
            Point oldloc = node.Location;
            Rect  oldb   = node.Bounds;

            //Diagram.Debug("LayoutManager.MoveAnimated: " + Diagram.Str(node) + "  " + Diagram.Str(node.Position) + " -- > " + Diagram.Str(newpos));
            // always move the node
            node.Position = newpos;
            if (this.Story != null)
            {
                // if MoveAnimated is called more than once for a Node, remove any previous saved animation
                PointAnimation anim = null;
                if (this.Animations.TryGetValue(node, out anim))
                {
                    //Diagram.Debug("  removed animation for " + node.ToString());
                    this.Story.Children.Remove(anim);
                }
            }

            // try not to bother with animations that won't be visibly useful
            if (!this.Animated)
            {
                return;
            }
            if (this.AnimationTime <= 10)
            {
                return;
            }
            // two pixels or more (but that's in model coordinates)
            if (Math.Abs(newpos.X - oldb.X) < 2 && Math.Abs(newpos.Y - oldb.Y) < 2)
            {
                return;
            }
            FrameworkElement elt = node.VisualElement;

            if (elt == null)
            {
                return;
            }

            // only do animation for nodes whose new or old bounds are visible in the view
            //?? this doesn't work reliably:
            Diagram diagram = this.Diagram;

            if (diagram == null || diagram.Panel == null)
            {
                return;
            }
            Rect nearRect = diagram.Panel.InflatedViewportBounds;
            Rect newb     = new Rect(newpos.X, newpos.Y, oldb.Width, oldb.Height);

            if (!Geo.Intersects(nearRect, oldb) && !Geo.Intersects(nearRect, newb))
            {
                return;
            }

            // start an animation
            //Diagram.Debug("  MoveAnimated " + Diagram.Str(new Point(oldb.X, oldb.Y)) + Diagram.Str(node.Position));
            if (Double.IsNaN(oldloc.X))
            {
                oldloc.X = this.DefaultLocation.X;
            }
            if (Double.IsNaN(oldloc.Y))
            {
                oldloc.Y = this.DefaultLocation.Y;
            }
            PointAnimation a = new PointAnimation();

            a.From     = oldloc;
            a.Duration = this.AnimationDuration;

            Storyboard.SetTarget(a, elt);
            Storyboard.SetTargetProperty(a, new PropertyPath(Node.LocationProperty));
            Storyboard story = this.Story;

            if (story == null) // when called from outside of DoLayoutDiagram
            {
                Storyboard singlestory = new Storyboard();
                singlestory.Children.Add(a);
                StartStoryboard(singlestory);
            }
            else
            {
                StartingLayoutAnimation();
                story.Children.Add(a); // collect animations for later action, all at once
                this.Animations[node] = a;
            }
        }