Mercurial > silverbladetech
view 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 source
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; } } }