diff SilverlightGlimpse/SilverFlow.Controls/Controllers/SnapinController.cs @ 63:536498832a79

Latest version before changing bindings to Listbox
author Steven Hollidge <stevenhollidge@hotmail.com>
date Sun, 22 Apr 2012 13:33:42 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SilverlightGlimpse/SilverFlow.Controls/Controllers/SnapinController.cs	Sun Apr 22 13:33:42 2012 +0100
@@ -0,0 +1,333 @@
+using System.Collections.Generic;
+using System.Windows;
+using SilverFlow.Controls.Extensions;
+using SilverFlow.Geometry;
+
+namespace SilverFlow.Controls.Controllers
+{
+    /// <summary>
+    /// Provides helpers methods for calculating window position 
+    /// during movement and resizing.
+    /// </summary>
+    public class SnapinController : ISnapinController
+    {
+        /// <summary>
+        /// Distance on which snapping works.
+        /// </summary>
+        private const double SnapinDistanceDefaultValue = 5;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether snap in is enabled.
+        /// </summary>
+        /// <value><c>true</c> if snap in is enabled; otherwise, <c>false</c>.</value>
+        public bool SnapinEnabled { get; set; }
+
+        /// <summary>
+        /// Gets or sets snap in bounds.
+        /// </summary>
+        /// <value>Snap in bounds.</value>
+        public IEnumerable<Rect> SnapinBounds { get; set; }
+
+        /// <summary>
+        /// Gets or sets snap in distance.
+        /// </summary>
+        /// <value>Snap in distance.</value>
+        public double SnapinDistance { get; set; }
+
+        /// <summary>
+        /// Gets or sets a value snap in margin - distance between adjacent edges.
+        /// </summary>
+        /// <value>Snap in margin.</value>
+        public double SnapinMargin { get; set; }
+
+        /// <summary>
+        /// Gets calculations accuracy.
+        /// </summary>
+        /// <value>Accuracy.</value>
+        private double Accuracy 
+        {
+            get { return SnapinDistance + SnapinMargin;  }
+        }
+
+        /// <summary>
+        /// Returns new position of the specified rectangle
+        /// taking into account bounds the rectangle can be attracted to.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <returns>New position.</returns>
+        public Point SnapRectangle(Rect rect)
+        {
+            Point point = rect.Position();
+
+            if (SnapinEnabled)
+            {
+                Distance minDistance = new Distance();
+                foreach (var bound in SnapinBounds)
+                {
+                    Distance distance = DistanceBetweenRectangles(rect, bound);
+                    minDistance = Distance.Min(distance, minDistance);
+                }
+
+                point = point.Add(minDistance);
+            }
+
+            return point;
+        }
+
+        /// <summary>
+        /// Snaps the bottom right corner of the specified rectangle to the nearest bounds.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <returns>New position.</returns>
+        public Point SnapBottomRightCorner(Rect rect)
+        {
+            Point point = rect.BottomRight();
+
+            if (SnapinEnabled)
+            {
+                Distance minDistance = new Distance();
+                foreach (var bound in SnapinBounds)
+                {
+                    Distance distance = new Distance()
+                    {
+                        X = DistanceBetweenRightEdgeAndRectangle(rect, bound),
+                        Y = DistanceBetweenBottomEdgeAndRectangle(rect, bound)
+                    };
+
+                    minDistance = Distance.Min(distance, minDistance);
+                }
+
+                point = point.Add(minDistance);
+            }
+
+            return point;
+        }
+
+        /// <summary>
+        /// Snaps the upper left corner of the specified rectangle to the nearest bounds.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <returns>New position.</returns>
+        public Point SnapTopLeftCorner(Rect rect)
+        {
+            Point point = rect.Position();
+
+            if (SnapinEnabled)
+            {
+                Distance minDistance = new Distance();
+                foreach (var bound in SnapinBounds)
+                {
+                    Distance distance = new Distance()
+                    {
+                        X = DistanceBetweenLeftEdgeAndRectangle(rect, bound),
+                        Y = DistanceBetweenTopEdgeAndRectangle(rect, bound)
+                    };
+
+                    minDistance = Distance.Min(distance, minDistance);
+                }
+
+                point = point.Add(minDistance);
+            }
+
+            return point;
+        }
+
+        /// <summary>
+        /// Snaps the lower left corner of the specified rectangle to the nearest bounds.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <returns>New position.</returns>
+        public Point SnapBottomLeftCorner(Rect rect)
+        {
+            Point point = rect.BottomLeft();
+
+            if (SnapinEnabled)
+            {
+                Distance minDistance = new Distance();
+                foreach (var bound in SnapinBounds)
+                {
+                    Distance distance = new Distance()
+                    {
+                        X = DistanceBetweenLeftEdgeAndRectangle(rect, bound),
+                        Y = DistanceBetweenBottomEdgeAndRectangle(rect, bound)
+                    };
+
+                    minDistance = Distance.Min(distance, minDistance);
+                }
+
+                point = point.Add(minDistance);
+            }
+
+            return point;
+        }
+
+        /// <summary>
+        /// Snaps the upper right corner of the specified rectangle to the nearest bounds.
+        /// </summary>
+        /// <param name="rect">The rectangle.</param>
+        /// <returns>New position.</returns>
+        public Point SnapTopRightCorner(Rect rect)
+        {
+            Point point = rect.TopRight();
+
+            if (SnapinEnabled)
+            {
+                Distance minDistance = new Distance();
+                foreach (var bound in SnapinBounds)
+                {
+                    Distance distance = new Distance()
+                    {
+                        X = DistanceBetweenRightEdgeAndRectangle(rect, bound),
+                        Y = DistanceBetweenTopEdgeAndRectangle(rect, bound)
+                    };
+
+                    minDistance = Distance.Min(distance, minDistance);
+                }
+
+                point = point.Add(minDistance);
+            }
+
+            return point;
+        }
+
+        /// <summary>
+        /// Returns mininal distance between two rectangles.
+        /// </summary>
+        /// <param name="first">First rectangle.</param>
+        /// <param name="second">Second rectangle.</param>
+        /// <returns>Minimal distance.</returns>
+        private Distance DistanceBetweenRectangles(Rect first, Rect second)
+        {
+            double x1 = DistanceBetweenRightEdgeAndRectangle(first, second);
+            double x2 = DistanceBetweenLeftEdgeAndRectangle(first, second);
+            double y1 = DistanceBetweenBottomEdgeAndRectangle(first, second);
+            double y2 = DistanceBetweenTopEdgeAndRectangle(first, second);
+
+            Distance distance = new Distance()
+            {
+                X = MathExtensions.AbsMin(x1, x2),
+                Y = MathExtensions.AbsMin(y1, y2)
+            };
+
+            return distance;
+        }
+
+        /// <summary>
+        /// Returns distance between the right edge of the rectangle and another rectangle.
+        /// </summary>
+        /// <param name="first">First rectangle.</param>
+        /// <param name="second">Second rectangle.</param>
+        /// <returns>Minimal distance.</returns>
+        private double DistanceBetweenRightEdgeAndRectangle(Rect first, Rect second)
+        {
+            double snap;
+            double distance = double.NaN;
+            double x = first.X + first.Width - 1;
+
+            if (first.OverlapsVertically(second, Accuracy))
+            {
+                snap = second.X - 1 - SnapinMargin;
+                if (x.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - x, distance);
+                }
+
+                snap = second.X + second.Width - 1;
+                if (x.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - x, distance);
+                }
+            }
+
+            return distance;
+        }
+
+        /// <summary>
+        /// Returns distance between the left edge of the rectangle and another rectangle.
+        /// </summary>
+        /// <param name="first">First rectangle.</param>
+        /// <param name="second">Second rectangle.</param>
+        /// <returns>Minimal distance.</returns>
+        private double DistanceBetweenLeftEdgeAndRectangle(Rect first, Rect second)
+        {
+            double snap;
+            double distance = double.NaN;
+
+            if (first.OverlapsVertically(second, Accuracy))
+            {
+                snap = second.X;
+                if (first.X.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - first.X, distance);
+                }
+
+                snap = second.X + second.Width + SnapinMargin;
+                if (first.X.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - first.X, distance);
+                }
+            }
+
+            return distance;
+        }
+
+        /// <summary>
+        /// Returns distance between the bottom edge of the rectangle and another rectangle.
+        /// </summary>
+        /// <param name="first">First rectangle.</param>
+        /// <param name="second">Second rectangle.</param>
+        /// <returns>Minimal distance.</returns>
+        private double DistanceBetweenBottomEdgeAndRectangle(Rect first, Rect second)
+        {
+            double snap;
+            double distance = double.NaN;
+            double y = first.Y + first.Height - 1;
+
+            if (first.OverlapsHorizontally(second, Accuracy))
+            {
+                snap = second.Y - 1 - SnapinMargin;
+                if (y.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - y, distance);
+                }
+
+                snap = second.Y + second.Height - 1;
+                if (y.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - y, distance);
+                }
+            }
+
+            return distance;
+        }
+
+        /// <summary>
+        /// Returns distance between the top edge of the rectangle and another rectangle.
+        /// </summary>
+        /// <param name="first">First rectangle.</param>
+        /// <param name="second">Second rectangle.</param>
+        /// <returns>Minimal distance.</returns>
+        private double DistanceBetweenTopEdgeAndRectangle(Rect first, Rect second)
+        {
+            double snap;
+            double distance = double.NaN;
+
+            if (first.OverlapsHorizontally(second, Accuracy))
+            {
+                snap = second.Y;
+                if (first.Y.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - first.Y, distance);
+                }
+
+                snap = second.Y + second.Height + SnapinMargin;
+                if (first.Y.IsNear(snap, SnapinDistance))
+                {
+                    distance = MathExtensions.AbsMin(snap - first.Y, distance);
+                }
+            }
+
+            return distance;
+        }
+    }
+}