123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400 |
- using System;
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEngine.U2D;
-
- namespace UnityEditor.U2D.SpriteShape
- {
- internal interface IAngleRangeCache
- {
- List<AngleRange> angleRanges { get; }
- int selectedIndex { get; set; }
- float previewAngle { get; set; }
- void RegisterUndo(string name);
- }
-
- internal class AngleRangeController
- {
- public event Action selectionChanged = () => { };
- public IAngleRangeCache cache { get; set; }
- public IAngleRangeView view { get; set; }
- public float angleOffset { get; set; }
- public float radius { get; set; }
- public Rect rect { get; set; }
- public bool snap { get; set; }
- public Color gradientMin { get; set; }
- public Color gradientMid { get; set; }
- public Color gradientMax { get; set; }
-
- public AngleRange selectedAngleRange
- {
- get
- {
- Debug.Assert(cache != null);
-
- AngleRange angleRange = null;
-
- if (cache.selectedIndex >= 0 && cache.selectedIndex < cache.angleRanges.Count)
- return cache.angleRanges[cache.selectedIndex];
-
- return angleRange;
- }
- }
-
- private AngleRange hoveredAngleRange
- {
- get
- {
- Debug.Assert(cache != null);
- Debug.Assert(view != null);
-
- AngleRange angleRange = null;
-
- if (view.hoveredRangeIndex >= 0 && view.hoveredRangeIndex < cache.angleRanges.Count)
- return cache.angleRanges[view.hoveredRangeIndex];
-
- return angleRange;
- }
- }
-
- public void OnGUI()
- {
- Debug.Assert(cache != null);
-
- view.SetupLayout(rect, angleOffset, radius);
-
- DoAngleRanges();
- HandleSelectAngleRange();
- HandleCreateRange();
- HandlePreviewSelector();
- HandleRemoveRange();
- }
-
- private void DoAngleRanges()
- {
- var removeInvalid = false;
-
- if (view.IsActionTriggering(AngleRangeAction.ModifyRange))
- cache.RegisterUndo("Modify Range");
-
- if (view.IsActionFinishing(AngleRangeAction.ModifyRange))
- removeInvalid = true;
-
- var index = 0;
- foreach (var angleRange in cache.angleRanges)
- {
- var start = angleRange.start;
- var end = angleRange.end;
- var isSelected = selectedAngleRange != null && selectedAngleRange == angleRange;
-
- if (view.DoAngleRange(index, rect, radius, angleOffset, ref start, ref end, snap, !isSelected, gradientMin, gradientMid, gradientMax))
- SetRange(angleRange, start, end);
-
- ++index;
- }
-
- if (removeInvalid)
- RemoveInvalidRanges();
- }
-
- public void RemoveInvalidRanges()
- {
- var toDelete = new List<AngleRange>();
-
- foreach (var angleRange in cache.angleRanges)
- {
- var start = angleRange.start;
- var end = angleRange.end;
-
- if (start >= end)
- toDelete.Add(angleRange);
- }
-
- foreach (var angleRange in toDelete)
- cache.angleRanges.Remove(angleRange);
-
- if (toDelete.Count > 0)
- {
- SetSelectedIndexFromPreviewAngle();
- view.Repaint();
- }
- }
-
- private void HandleSelectAngleRange()
- {
- int newSelected;
- if (view.DoSelectAngleRange(cache.selectedIndex, out newSelected))
- {
- cache.RegisterUndo("Select Angle Range");
- cache.previewAngle = view.GetAngleFromPosition(rect, angleOffset);
- SelectIndex(newSelected);
- }
-
- if (view.IsActionActive(AngleRangeAction.SelectRange))
- {
- if (hoveredAngleRange == null)
- return;
-
- view.DrawAngleRangeOutline(rect, hoveredAngleRange.start, hoveredAngleRange.end, angleOffset, radius);
- }
- }
-
- private void HandleCreateRange()
- {
- if (!view.IsActionActive(AngleRangeAction.CreateRange))
- return;
-
- var angle = view.GetAngleFromPosition(rect, angleOffset);
- var start = 0f;
- var end = 0f;
- var canCreate = GetNewRangeBounds(angle, out start, out end);
-
- if (canCreate && view.DoCreateRange(rect, radius, angleOffset, start, end))
- {
- CreateRangeAtAngle(angle);
- cache.previewAngle = angle;
- SetSelectedIndexFromPreviewAngle();
- }
- }
-
- private void HandlePreviewSelector()
- {
- if (view.IsActionTriggering(AngleRangeAction.ModifySelector))
- cache.RegisterUndo("Set Preview Angle");
-
- float newAngle;
- if (view.DoSelector(rect, angleOffset, radius, cache.previewAngle, out newAngle))
- {
- if (selectedAngleRange == null)
- newAngle = Mathf.Repeat(newAngle + 180f, 360f) - 180f;
-
- cache.previewAngle = newAngle;
- SetSelectedIndexFromPreviewAngle();
- }
- }
-
- private void SetSelectedIndexFromPreviewAngle()
- {
- var index = SpriteShapeEditorUtility.GetRangeIndexFromAngle(cache.angleRanges, cache.previewAngle);
- SelectIndex(index);
- }
-
- private void SelectIndex(int index)
- {
- view.RequestFocusIndex(index);
-
- if (cache.selectedIndex == index)
- return;
-
- cache.selectedIndex = index;
- selectionChanged();
- }
-
- private void ClampPreviewAngle(float start, float end, float prevStart, float prevEnd)
- {
- var angle = cache.previewAngle;
-
- if (prevStart < start)
- {
- var a1 = Mathf.Repeat(angle - prevStart, 360f);
- var a2 = Mathf.Repeat(angle - start, 360f);
-
- if (a1 < a2)
- angle = Mathf.Min(start, end);
- }
- else if (prevEnd > end)
- {
- var a1 = Mathf.Repeat(prevEnd - angle, 360f);
- var a2 = Mathf.Repeat(end - angle, 360f);
-
- if (a1 < a2)
- angle = Mathf.Max(start, end);
- }
-
- cache.previewAngle = angle;
- }
-
- private void HandleRemoveRange()
- {
- if (view.DoRemoveRange())
- {
- cache.RegisterUndo("Remove Range");
- cache.angleRanges.RemoveAt(cache.selectedIndex);
- SelectIndex(-1);
- }
- }
-
- public void CreateRange()
- {
- CreateRangeAtAngle(cache.previewAngle);
- }
-
- private void CreateRangeAtAngle(float angle)
- {
- var start = 0f;
- var end = 0f;
-
- if (GetNewRangeBounds(angle, out start, out end))
- {
- cache.RegisterUndo("Create Range");
-
- var angleRange = new AngleRange();
- angleRange.start = start;
- angleRange.end = end;
-
- cache.angleRanges.Add(angleRange);
-
- ValidateRange(angleRange);
- SetSelectedIndexFromPreviewAngle();
- }
- }
-
- public void SetRange(AngleRange angleRange, float start, float end)
- {
- var prevStart = angleRange.start;
- var prevEnd = angleRange.end;
-
- angleRange.start = start;
- angleRange.end = end;
-
- ValidateRange(angleRange, prevStart, prevEnd);
-
- if (angleRange == selectedAngleRange)
- ClampPreviewAngle(start, end, prevStart, prevEnd);
- }
-
- private bool GetNewRangeBounds(float angle, out float emptyRangeStart, out float emptyRangeEnd)
- {
- angle = Mathf.Repeat(angle + 180f, 360f) - 180f;
-
- emptyRangeStart = float.MinValue;
- emptyRangeEnd = float.MaxValue;
-
- if (GetAngleRangeAt(angle) != null)
- return false;
-
- FindMinMax(out emptyRangeEnd, out emptyRangeStart);
-
- if (angle < emptyRangeStart)
- emptyRangeStart -= 360f;
-
- if (angle > emptyRangeEnd)
- emptyRangeEnd += 360f;
-
- foreach (var angleRange in cache.angleRanges)
- {
- var start = angleRange.start;
- var end = angleRange.end;
-
- if (angle > end)
- emptyRangeStart = Mathf.Max(emptyRangeStart, end);
-
- if (angle < start)
- emptyRangeEnd = Mathf.Min(emptyRangeEnd, start);
- }
-
- var rangeLength = emptyRangeEnd - emptyRangeStart;
-
- if (rangeLength > 90f)
- {
- emptyRangeStart = Mathf.Max(angle - 45f, emptyRangeStart);
- emptyRangeEnd = Mathf.Min(angle + 45f, emptyRangeEnd);
- }
-
- return true;
- }
-
- private AngleRange GetAngleRangeAt(float angle)
- {
- foreach (var angleRange in cache.angleRanges)
- {
- var start = angleRange.start;
- var end = angleRange.end;
- var range = end - start;
-
- var angle2 = Mathf.Repeat(angle - start, 360f);
-
- if (angle2 >= 0f && angle2 <= range)
- return angleRange;
- }
-
- return null;
- }
-
- private void FindMinMax(out float min, out float max)
- {
- min = float.MaxValue;
- max = float.MinValue;
-
- foreach (var angleRange in cache.angleRanges)
- {
- min = Mathf.Min(angleRange.start, min);
- max = Mathf.Max(angleRange.end, max);
- }
- }
-
- private void ValidateRange(AngleRange range)
- {
- ValidateRange(range, range.start, range.end);
- }
-
- private void ValidateRange(AngleRange angleRange, float prevStart, float prevEnd)
- {
- var start = angleRange.start;
- var end = angleRange.end;
-
- foreach (var otherRange in cache.angleRanges)
- {
- var otherStart = otherRange.start;
- var otherEnd = otherRange.end;
-
- if (otherRange == angleRange)
- {
- if ((start > 180f && end > 180f) || (start < -180f && end < -180f))
- {
- start = Mathf.Repeat(start + 180f, 360f) - 180f;
- end = Mathf.Repeat(end + 180f, 360f) - 180f;
- }
-
- otherStart = start + 360f;
- otherEnd = end - 360f;
- }
-
- ValidateRangeStartEnd(ref start, ref end, prevStart, prevEnd, otherStart, otherEnd);
- }
-
- angleRange.start = start;
- angleRange.end = end;
- }
-
- private void ValidateRangeStartEnd(ref float start, ref float end, float prevStart, float prevEnd, float otherStart, float otherEnd)
- {
- var min = Mathf.Min(start, otherStart);
- var max = Mathf.Max(end, otherEnd);
-
- start -= min;
- end -= min;
- otherStart -= min;
- otherEnd -= min;
- prevStart -= min;
- prevEnd -= min;
-
- if (prevEnd != end)
- end = Mathf.Clamp(end, start, otherStart >= start ? otherStart : 360f);
-
- start += min - max;
- end += min - max;
- otherStart += min - max;
- otherEnd += min - max;
- prevStart += min - max;
- prevEnd += min - max;
-
- if (prevStart != start)
- start = Mathf.Clamp(start, otherEnd <= end ? otherEnd : -360f, end);
-
- start += max;
- end += max;
- }
- }
- }
|