File: cdf\src\NetFx40\Tools\System.Activities.Presentation\System\Activities\Presentation\FreeFormEditing\AutoSplitHelper.cs
Project: ndp\System.Data.csproj (System.Data)
//----------------------------------------------------------------
// <copyright company="Microsoft Corporation">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//----------------------------------------------------------------
 
namespace System.Activities.Presentation.FreeFormEditing
{
    using System.Collections.Generic;
    using System.Windows;
 
    internal static class AutoSplitHelper
    {
        private const double ShapeMargin = 40;
 
        public static void CalculateEntryExitEdges(Point mousePosition, Connector connector, out EdgeLocation entryEdge, out EdgeLocation exitEdge)
        {
            UIElement srcShape = FreeFormPanel.GetSourceConnectionPoint(connector).ParentDesigner;
            UIElement destShape = FreeFormPanel.GetDestinationConnectionPoint(connector).ParentDesigner;
            Point srcLocation = FreeFormPanel.GetLocation(srcShape);
            Point destLocation = FreeFormPanel.GetLocation(destShape);
            Size srcSize = FreeFormPanel.GetChildSize(srcShape);
            Size destSize = FreeFormPanel.GetChildSize(destShape);
 
            Point srcCenter = new Point(srcLocation.X + (srcSize.Width / 2), srcLocation.Y + (srcSize.Height / 2));
            Point destCenter = new Point(destLocation.X + (destSize.Width / 2), destLocation.Y + (destSize.Height / 2));
 
            entryEdge = CalculateEdgeLocation(mousePosition, srcCenter);
            exitEdge = CalculateEdgeLocation(mousePosition, destCenter);
 
            if (exitEdge == entryEdge)
            {
                switch (entryEdge)
                {
                    case EdgeLocation.Top:
                        exitEdge = EdgeLocation.Bottom;
                        break;
 
                    case EdgeLocation.Bottom:
                        exitEdge = EdgeLocation.Top;
                        break;
 
                    case EdgeLocation.Left:
                        exitEdge = EdgeLocation.Right;
                        break;
 
                    case EdgeLocation.Right:
                        exitEdge = EdgeLocation.Left;
                        break;
                }
            }
        }
 
        public static Point CalculateDropLocation(Point mousePosition, Point originalDropLocation, Connector connector, Size droppedSize, HashSet<Point> shapeLocations)
        {
            UIElement srcShape = FreeFormPanel.GetSourceConnectionPoint(connector).ParentDesigner;
            UIElement destShape = FreeFormPanel.GetDestinationConnectionPoint(connector).ParentDesigner;
            Point srcLocation = FreeFormPanel.GetLocation(srcShape);
            Point destLocation = FreeFormPanel.GetLocation(destShape);
            Size srcSize = FreeFormPanel.GetChildSize(srcShape);
            Size destSize = FreeFormPanel.GetChildSize(destShape);
 
            return CalculateDropLocation(mousePosition, originalDropLocation, droppedSize, srcLocation, destLocation, srcSize, destSize, shapeLocations);
        }
 
        internal static Point CalculateDropLocation(Point mousePosition, Point originalDropLocation, Size droppedSize, Point srcLocation, Point destLocation, Size srcSize, Size destSize, HashSet<Point> shapeLocations)
        {
            Point dropLocation = originalDropLocation;
 
            double distToSrc = DesignerGeometryHelper.ManhattanDistanceBetweenPoints(mousePosition, new Point(srcLocation.X + (srcSize.Width / 2), srcLocation.Y + (srcSize.Height / 2)));
            double distToDest = DesignerGeometryHelper.ManhattanDistanceBetweenPoints(mousePosition, new Point(destLocation.X + (destSize.Width / 2), destLocation.Y + (destSize.Height / 2)));
 
            AutoSplitAlignment srcAlignment = GetAlignment(mousePosition, srcLocation, srcSize);
            AutoSplitAlignment destAlignment = GetAlignment(mousePosition, destLocation, destSize);
 
            if ((distToSrc <= distToDest || destAlignment == AutoSplitAlignment.None) && srcAlignment == AutoSplitAlignment.Vertical)
            {
                dropLocation = CalculateDropLocationToAlignVertically(dropLocation, droppedSize, srcLocation, srcSize);
            }
            else if ((distToSrc <= distToDest || destAlignment == AutoSplitAlignment.None) && srcAlignment == AutoSplitAlignment.Horizontal)
            {
                dropLocation = CalculateDropLocationToAlignHorizontally(dropLocation, droppedSize, srcLocation, srcSize);
            }
            else if ((distToSrc >= distToDest || srcAlignment == AutoSplitAlignment.None) && destAlignment == AutoSplitAlignment.Vertical)
            {
                dropLocation = CalculateDropLocationToAlignVertically(dropLocation, droppedSize, destLocation, destSize);
            }
            else if ((distToSrc >= distToDest || srcAlignment == AutoSplitAlignment.None) && destAlignment == AutoSplitAlignment.Horizontal)
            {
                dropLocation = CalculateDropLocationToAlignHorizontally(dropLocation, droppedSize, destLocation, destSize);
            }
 
            dropLocation.X = dropLocation.X < 0 ? 0 : dropLocation.X;
            dropLocation.Y = dropLocation.Y < 0 ? 0 : dropLocation.Y;
 
            // To avoid overlaps with existing shapes
            if (shapeLocations != null)
            {
                while (shapeLocations.Contains(dropLocation))
                {
                    dropLocation.Offset(FreeFormPanel.GridSize, FreeFormPanel.GridSize);
                }
            }
 
            return dropLocation;
        }
 
        internal static AutoSplitAlignment GetAlignment(Point mousePosition, Point targetLocation, Size targetSize)
        {
            AutoSplitAlignment alignment = AutoSplitAlignment.None;
            if (mousePosition.X >= targetLocation.X && mousePosition.X <= targetLocation.X + targetSize.Width)
            {
                alignment = AutoSplitAlignment.Vertical;
            }
            else if (mousePosition.Y >= targetLocation.Y && mousePosition.Y <= targetLocation.Y + targetSize.Height)
            {
                alignment = AutoSplitAlignment.Horizontal;
            }
 
            return alignment;
        }
 
        internal static Point CalculateDropLocationToAlignVertically(Point originalDropLocation, Size droppedSize, Point targetLocation, Size targetSize)
        {
            Point dropLocation = originalDropLocation;
            dropLocation.X = targetLocation.X + ((targetSize.Width - droppedSize.Width) / 2);
            if (dropLocation.Y >= targetLocation.Y && dropLocation.Y <= targetLocation.Y + targetSize.Height + ShapeMargin)
            {
                dropLocation.Y = targetLocation.Y + targetSize.Height + ShapeMargin;
            }
            else if (dropLocation.Y + droppedSize.Height + ShapeMargin >= targetLocation.Y && dropLocation.Y <= targetLocation.Y)
            {
                dropLocation.Y = targetLocation.Y - droppedSize.Height - ShapeMargin;
            }
 
            return dropLocation;
        }
 
        internal static Point CalculateDropLocationToAlignHorizontally(Point originalDropLocation, Size droppedSize, Point targetLocation, Size targetSize)
        {
            Point dropLocation = originalDropLocation;
            dropLocation.Y = targetLocation.Y + ((targetSize.Height - droppedSize.Height) / 2);
            if (dropLocation.X >= targetLocation.X && dropLocation.X <= targetLocation.X + targetSize.Width + ShapeMargin)
            {
                dropLocation.X = targetLocation.X + targetSize.Width + ShapeMargin;
            }
            else if (dropLocation.X + droppedSize.Width + ShapeMargin >= targetLocation.X && dropLocation.X <= targetLocation.X)
            {
                dropLocation.X = targetLocation.X - droppedSize.Width - ShapeMargin;
            }
 
            return dropLocation;
        }
 
        internal static EdgeLocation CalculateEdgeLocation(Point mousePosition, Point shapeCenter)
        {
            double distX = Math.Abs(shapeCenter.X - mousePosition.X);
            double distY = Math.Abs(shapeCenter.Y - mousePosition.Y);
            if (distX > distY)
            {
                return shapeCenter.X < mousePosition.X ? EdgeLocation.Left : EdgeLocation.Right;
            }
            else
            {
                return shapeCenter.Y < mousePosition.Y ? EdgeLocation.Top : EdgeLocation.Bottom;
            }
        }
    }
}