namespace UIWidgets { using System.Collections.Generic; using UnityEngine; using UnityEngine.Events; using UnityEngine.Serialization; /// /// Base class for the SnapGrid. /// #if UNITY_2018_4_OR_NEWER [ExecuteAlways] #else [ExecuteInEditMode] #endif public abstract partial class SnapGridBase : UIBehaviourConditional { /// /// Lines at X axis. /// protected List LinesX = new List(); /// /// Lines at Y axis. /// protected List LinesY = new List(); [SerializeField] [FormerlySerializedAs("snapBorderInside")] Border snapBorderInner; /// /// Allow snapping to the inner side of the border. /// public Border SnapBorderInnner { get { return snapBorderInner; } set { if (snapBorderInner != value) { snapBorderInner = value; UpdateLines(); } } } [SerializeField] [FormerlySerializedAs("snapBorderOutside")] Border snapBorderOuter; /// /// Allow snapping to the outer side of the border. /// public Border SnapBorderOuter { get { return snapBorderOuter; } set { if (snapBorderOuter != value) { snapBorderOuter = value; UpdateLines(); } } } /// /// Event on lines changed. /// [SerializeField] public UnityEvent OnLinesChanged = new UnityEvent(); /// /// Snap lines at X axis. /// protected List SnapLinesX = new List(); /// /// Snap lines at Y axis. /// protected List SnapLinesY = new List(); RectTransform rectTransform; /// /// RectTransform. /// public RectTransform RectTransform { get { if (rectTransform == null) { rectTransform = transform as RectTransform; } return rectTransform; } } /// /// Process the Start event. /// protected override void Start() { base.Start(); Init(); } /// /// Init this instance. /// public virtual void Init() { UpdateLines(); } /// /// Process dimensions changed event. /// protected override void OnRectTransformDimensionsChange() { base.OnRectTransformDimensionsChange(); UpdateLines(); } #if UNITY_EDITOR /// /// Process validate event. /// protected override void OnValidate() { base.OnValidate(); UpdateLines(); } #endif /// /// Update lines. /// protected abstract void UpdateLines(); /// /// Get lines at X axis. /// /// Include borders if snap borders enabled. /// Result. public virtual void GetLinesX(bool includeBorders, List output) { if (includeBorders && (SnapBorderInnner.Left || SnapBorderOuter.Left)) { output.Add(0f); } foreach (var line in LinesX) { output.Add(line.X); } if (includeBorders && (SnapBorderInnner.Right || SnapBorderOuter.Right)) { output.Add(RectTransform.rect.width); } } /// /// Get lines at Y axis. /// /// Include borders if snap borders enabled. /// Result. public void GetLinesY(bool includeBorders, List output) { if (includeBorders && (SnapBorderInnner.Bottom || SnapBorderOuter.Bottom)) { output.Add(0f); } foreach (var line in LinesY) { output.Add(line.Y); } if (includeBorders && (SnapBorderInnner.Top || SnapBorderOuter.Top)) { output.Add(RectTransform.rect.height); } } /// /// Get lines at X axis. /// /// Result. public virtual void GetLinesX(List output) { if (SnapBorderInnner.Left || SnapBorderOuter.Left) { output.Add(new LineX(0f, SnapBorderInnner.Left, SnapBorderOuter.Left)); } output.AddRange(LinesX); if (SnapBorderInnner.Right || SnapBorderOuter.Right) { output.Add(new LineX(RectTransform.rect.width, SnapBorderOuter.Right, SnapBorderInnner.Right)); } } /// /// Get grid position. /// /// Position. protected virtual Vector2 GridPosition() { var size = RectTransform.rect.size; var pivot = RectTransform.pivot; var position = RectTransform.position; var scale = RectTransform.lossyScale; position.x = (position.x / scale.x) - (size.x * pivot.x); position.y = (position.y / scale.y) - (size.y * pivot.y); return position; } /// /// Get lines at Y axis. /// /// Result. public virtual void GetLinesY(List output) { if (SnapBorderInnner.Bottom || SnapBorderOuter.Bottom) { output.Add(new LineY(0f, SnapBorderInnner.Bottom, SnapBorderOuter.Bottom)); } output.AddRange(LinesY); if (SnapBorderInnner.Top || SnapBorderOuter.Top) { output.Add(new LineY(RectTransform.rect.height, SnapBorderOuter.Top, SnapBorderInnner.Top)); } } /// /// Snap point. /// /// Point. /// Maximum distance to snap. /// Distance to the nearest line or lines. public virtual Result Snap(Point point, Vector2 snapDistance) { var distance = new Distance(float.MaxValue); Snap(point, ref distance); return distance.Snap(snapDistance); } /// /// Snap point. /// /// Point. /// Distance. public virtual void Snap(Point point, ref Distance distance) { var current_position = GridPosition(); foreach (var line in SnapLinesX) { var x = current_position.x + line.X - point.X; if (line.SnapLeft && point.Left) { distance.Left(x); } if (line.SnapRight && point.Right) { distance.Right(x); } } foreach (var line in SnapLinesY) { var y = current_position.y + line.Y - point.Y; if (line.SnapTop && point.Top) { distance.Top(y); } if (line.SnapBottom && point.Bottom) { distance.Bottom(y); } } } /// /// Snap points. /// /// Points. /// Maximum distance to snap. /// Distance to the nearest line or lines. public virtual Result Snap(List points, Vector2 snapDistance) { var distance = new Distance(float.MaxValue); Snap(points, ref distance); return distance.Snap(snapDistance); } /// /// Snap points. /// /// Points. /// Distance. public virtual void Snap(List points, ref Distance distance) { SnapLinesX.Clear(); GetLinesX(SnapLinesX); SnapLinesY.Clear(); GetLinesY(SnapLinesY); var current_position = GridPosition(); foreach (var point in points) { foreach (var line in SnapLinesX) { var x = current_position.x + line.X - point.X; if (line.SnapLeft && point.Left) { distance.Left(x); } if (line.SnapRight && point.Right) { distance.Right(x); } } foreach (var line in SnapLinesY) { var y = current_position.y + line.Y - point.Y; if (line.SnapTop && point.Top) { distance.Top(y); } if (line.SnapBottom && point.Bottom) { distance.Bottom(y); } } } } List tempPoints = new List(4); /// /// Snap target. /// /// Target. /// Maximum distance to snap. /// Distance to the nearest line or lines. public virtual Result Snap(RectTransform target, Vector2 snapDistance) { tempPoints.Add(new Point(target, this, true, true)); tempPoints.Add(new Point(target, this, true, false)); tempPoints.Add(new Point(target, this, false, true)); tempPoints.Add(new Point(target, this, false, false)); var result = Snap(tempPoints, snapDistance); tempPoints.Clear(); return result; } /// /// Snap target. /// /// Target. /// Distance. public virtual void Snap(RectTransform target, ref Distance distance) { tempPoints.Add(new Point(target, this, true, true)); tempPoints.Add(new Point(target, this, true, false)); tempPoints.Add(new Point(target, this, false, true)); tempPoints.Add(new Point(target, this, false, false)); Snap(tempPoints, ref distance); tempPoints.Clear(); } /// /// Snap target. /// /// Snap grids. /// Snap distance. /// Target. /// Distance to the nearest line or lines. public static Result Snap(List snapGrids, Vector2 snapDistance, RectTransform target) { if (snapGrids == null) { return default(Result); } if (snapGrids.Count == 0) { return default(Result); } var distance = new Distance(float.MaxValue); foreach (var snap_grid in snapGrids) { if (snap_grid == null) { continue; } snap_grid.Snap(target, ref distance); } return distance.Snap(snapDistance); } } }