/// <summary> /// Compute the new location for a node, given another node that is controlling its movement. /// </summary> /// <param name="moving">the <see cref="Northwoods.GoXam.Node"/> being dragged</param> /// <param name="pt">the <c>Point</c> in model coordinates to which the node is being dragged</param> /// <param name="snapper">the <see cref="Northwoods.GoXam.Node"/>, typically a grid, which is controlling the drag snapping</param> /// <param name="draggedparts">a <c>Dictionary</c> of <see cref="Part"/>s being dragged</param> /// <returns>a new node location, in model coordinates</returns> /// <remarks> /// <para> /// This is called by <see cref="ComputeMove"/>. /// </para> /// <para> /// When there is a <paramref name="snapper"/>, /// if the <paramref name="snapper"/>'s <see cref="Part.DragOverSnapEnabled"/> property is false, /// this method just returns the unmodified <paramref name="pt"/> value. /// Otherwise this uses the <see cref="Part.DragOverSnapCellSize"/> and /// <see cref="Part.DragOverSnapCellSpot"/> /// to compute the nearest grid point that should be the location of the /// <paramref name="moving"/> node. /// </para> /// <para> /// If there is no <paramref name="snapper"/>, this uses the <see cref="Northwoods.GoXam.Diagram"/>'s /// <see cref="Northwoods.GoXam.Diagram.GridSnapCellSize"/>, /// <see cref="Northwoods.GoXam.Diagram.GridSnapCellSpot"/>, and /// <see cref="Northwoods.GoXam.Diagram.GridSnapOrigin"/> /// properties to calculate and return the nearest grid point. /// </para> /// </remarks> protected virtual Point SnapTo(Node moving, Point pt, Node snapper, Dictionary<Part, Info> draggedparts) { if (moving == null) return pt; if (snapper == null) { Diagram diagram = this.Diagram; if (diagram == null || !diagram.GridSnapEnabled) return pt; Size cell = diagram.GridSnapCellSize; Point origin = diagram.GridSnapOrigin; Point s = diagram.GridSnapCellSpot.PointInRect(new Rect(0, 0, cell.Width, cell.Height)); Point q = FindNearestInfiniteGridPoint(pt, s, origin, cell); return q; } else { if (!snapper.DragOverSnapEnabled) return pt; Rect r = snapper.GetElementBounds(snapper.LocationElement); if (Double.IsNaN(r.X) || Double.IsNaN(r.Y)) return pt; Rect mb = moving.Bounds; Point oldloc = moving.Location; //if (ds.KeepsOutside) { //??? // Point p = oldloc; // if (oldloc.X <= r.Left) { // p.X = r.Left - mb.Width + (oldloc.X-mb.X); // } else if (oldloc.X >= r.Right) { // p.X = r.Right + (oldloc.X-mb.X); // } // if (oldloc.Y <= r.Top) { // p.Y = r.Top - mb.Height + (oldloc.Y-mb.Y); // } else if (oldloc.Y >= r.Bottom) { // p.Y = r.Bottom + (oldloc.Y-mb.Y); // } // return p; //} double left = Math.Max(0, oldloc.X - mb.Left); double right = Math.Max(0, mb.Right - oldloc.X); double top = Math.Max(0, oldloc.Y - mb.Top); double bottom = Math.Max(0, mb.Bottom - oldloc.Y); Size cell = snapper.DragOverSnapCellSize; Point origin = snapper.DragOverSnapOrigin; r.X += origin.X; r.Y += origin.Y; Point s = snapper.DragOverSnapCellSpot.PointInRect(new Rect(0, 0, cell.Width, cell.Height)); Point q = FindNearestInfiniteGridPoint(pt, s, new Point(r.X, r.Y), cell); if (q.X - left < r.Left) { q.X += cell.Width * (int)Math.Ceiling((r.Left-(q.X-left))/cell.Width); } if (q.X + right > r.Right) { q.X -= cell.Width * (int)Math.Ceiling(((q.X+right)-r.Right)/cell.Width); } if (right > 0 && q.X - left < r.Left) { q.X += cell.Width * (int)Math.Ceiling((r.Left-(q.X-left))/cell.Width); } if (q.Y - top < r.Top) { q.Y += cell.Height * (int)Math.Ceiling((r.Top-(q.Y-top))/cell.Height); } if (q.Y + bottom > r.Bottom) { q.Y -= cell.Height * (int)Math.Ceiling(((q.Y+bottom)-r.Bottom)/cell.Height); } if (bottom > 0 && q.Y - top < r.Top) { q.Y += cell.Height * (int)Math.Ceiling((r.Top-(q.Y-top))/cell.Height); } return q; } }