123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245 |
- using UnityEngine;
- using System.Collections.Generic;
- using UnityEditor;
- namespace Pathfinding {
- /// <summary>Simple GUI utility functions</summary>
- public static class GUIUtilityx {
- static Stack<Color> colors = new Stack<Color>();
- public static void PushTint (Color tint) {
- colors.Push(GUI.color);
- GUI.color *= tint;
- }
- public static void PopTint () {
- GUI.color = colors.Pop();
- }
- }
- /// <summary>
- /// Editor helper for hiding and showing a group of GUI elements.
- /// Call order in OnInspectorGUI should be:
- /// - Begin
- /// - Header/HeaderLabel (optional)
- /// - BeginFade
- /// - [your gui elements] (if BeginFade returns true)
- /// - End
- /// </summary>
- public class FadeArea {
- Rect lastRect;
- float value;
- float lastUpdate;
- GUIStyle labelStyle;
- GUIStyle areaStyle;
- bool visible;
- Editor editor;
- /// <summary>
- /// Is this area open.
- /// This is not the same as if any contents are visible, use <see cref="BeginFade"/> for that.
- /// </summary>
- public bool open;
- /// <summary>Animate dropdowns when they open and close</summary>
- public static bool fancyEffects;
- const float animationSpeed = 100f;
- public FadeArea (bool open, Editor editor, GUIStyle areaStyle, GUIStyle labelStyle = null) {
- this.areaStyle = areaStyle;
- this.labelStyle = labelStyle;
- this.editor = editor;
- visible = this.open = open;
- value = open ? 1 : 0;
- }
- void Tick () {
- if (Event.current.type == EventType.Repaint) {
- float deltaTime = Time.realtimeSinceStartup-lastUpdate;
- // Right at the start of a transition the deltaTime will
- // not be reliable, so use a very small value instead
- // until the next repaint
- if (value == 0f || value == 1f) deltaTime = 0.001f;
- deltaTime = Mathf.Clamp(deltaTime, 0.00001F, 0.1F);
- // Larger regions fade slightly slower
- deltaTime /= Mathf.Sqrt(Mathf.Max(lastRect.height, 100));
- lastUpdate = Time.realtimeSinceStartup;
- float targetValue = open ? 1F : 0F;
- if (!Mathf.Approximately(targetValue, value)) {
- value += deltaTime*animationSpeed*Mathf.Sign(targetValue-value);
- value = Mathf.Clamp01(value);
- editor.Repaint();
- if (!fancyEffects) {
- value = targetValue;
- }
- } else {
- value = targetValue;
- }
- }
- }
- public void Begin () {
- if (areaStyle != null) {
- lastRect = EditorGUILayout.BeginVertical(areaStyle);
- } else {
- lastRect = EditorGUILayout.BeginVertical();
- }
- }
- public void HeaderLabel (string label) {
- GUILayout.Label(label, labelStyle);
- }
- public void Header (string label) {
- Header(label, ref open);
- }
- public void Header (string label, ref bool open) {
- if (GUILayout.Button(label, labelStyle)) {
- open = !open;
- editor.Repaint();
- }
- this.open = open;
- }
- /// <summary>Hermite spline interpolation</summary>
- static float Hermite (float start, float end, float value) {
- return Mathf.Lerp(start, end, value * value * (3.0f - 2.0f * value));
- }
- public bool BeginFade () {
- var hermite = Hermite(0, 1, value);
- visible = EditorGUILayout.BeginFadeGroup(hermite);
- GUIUtilityx.PushTint(new Color(1, 1, 1, hermite));
- Tick();
- // Another vertical group is necessary to work around
- // a kink of the BeginFadeGroup implementation which
- // causes the padding to change when value!=0 && value!=1
- EditorGUILayout.BeginVertical();
- return visible;
- }
- public void End () {
- EditorGUILayout.EndVertical();
- if (visible) {
- // Some space that cannot be placed in the GUIStyle unfortunately
- GUILayout.Space(4);
- }
- EditorGUILayout.EndFadeGroup();
- EditorGUILayout.EndVertical();
- GUIUtilityx.PopTint();
- }
- }
- /// <summary>Handles fading effects and also some custom GUI functions such as LayerMaskField</summary>
- public static class EditorGUILayoutx {
- static Dictionary<int, string[]> layerNames = new Dictionary<int, string[]>();
- static long lastUpdateTick;
- /// <summary>
- /// Tag names and an additional 'Edit Tags...' entry.
- /// Used for SingleTagField
- /// </summary>
- static string[] tagNamesAndEditTagsButton;
- /// <summary>
- /// Last time tagNamesAndEditTagsButton was updated.
- /// Uses EditorApplication.timeSinceStartup
- /// </summary>
- static double timeLastUpdatedTagNames;
- public static int TagField (string label, int value, System.Action editCallback) {
- // Make sure the tagNamesAndEditTagsButton is relatively up to date
- if (tagNamesAndEditTagsButton == null || EditorApplication.timeSinceStartup - timeLastUpdatedTagNames > 1) {
- timeLastUpdatedTagNames = EditorApplication.timeSinceStartup;
- var tagNames = AstarPath.FindTagNames();
- tagNamesAndEditTagsButton = new string[tagNames.Length+1];
- tagNames.CopyTo(tagNamesAndEditTagsButton, 0);
- tagNamesAndEditTagsButton[tagNamesAndEditTagsButton.Length-1] = "Edit Tags...";
- }
- // Tags are between 0 and 31
- value = Mathf.Clamp(value, 0, 31);
- var newValue = EditorGUILayout.IntPopup(label, value, tagNamesAndEditTagsButton, new [] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, -1 });
- // Last element corresponds to the 'Edit Tags...' entry. Open the tag editor
- if (newValue == -1) {
- editCallback();
- } else {
- value = newValue;
- }
- return value;
- }
- public static bool UnityTagMaskList (GUIContent label, bool foldout, List<string> tagMask) {
- if (tagMask == null) throw new System.ArgumentNullException("tagMask");
- if (EditorGUILayout.Foldout(foldout, label)) {
- EditorGUI.indentLevel++;
- GUILayout.BeginVertical();
- for (int i = 0; i < tagMask.Count; i++) {
- tagMask[i] = EditorGUILayout.TagField(tagMask[i]);
- }
- GUILayout.BeginHorizontal();
- if (GUILayout.Button("Add Tag")) tagMask.Add("Untagged");
- EditorGUI.BeginDisabledGroup(tagMask.Count == 0);
- if (GUILayout.Button("Remove Last")) tagMask.RemoveAt(tagMask.Count-1);
- EditorGUI.EndDisabledGroup();
- GUILayout.EndHorizontal();
- GUILayout.EndVertical();
- EditorGUI.indentLevel--;
- return true;
- }
- return false;
- }
- /// <summary>Displays a LayerMask field.</summary>
- /// <param name="label">Label to display</param>
- /// <param name="selected">Current LayerMask</param>
- public static LayerMask LayerMaskField (string label, LayerMask selected) {
- if (Event.current.type == EventType.Layout && System.DateTime.UtcNow.Ticks - lastUpdateTick > 10000000L) {
- layerNames.Clear();
- lastUpdateTick = System.DateTime.UtcNow.Ticks;
- }
- string[] currentLayerNames;
- if (!layerNames.TryGetValue(selected.value, out currentLayerNames)) {
- var layers = Pathfinding.Util.ListPool<string>.Claim();
- int emptyLayers = 0;
- for (int i = 0; i < 32; i++) {
- string layerName = LayerMask.LayerToName(i);
- if (layerName != "") {
- for (; emptyLayers > 0; emptyLayers--) layers.Add("Layer "+(i-emptyLayers));
- layers.Add(layerName);
- } else {
- emptyLayers++;
- if (((selected.value >> i) & 1) != 0 && selected.value != -1) {
- for (; emptyLayers > 0; emptyLayers--) layers.Add("Layer "+(i+1-emptyLayers));
- }
- }
- }
- currentLayerNames = layerNames[selected.value] = layers.ToArray();
- Pathfinding.Util.ListPool<string>.Release(ref layers);
- }
- selected.value = EditorGUILayout.MaskField(label, selected.value, currentLayerNames);
- return selected;
- }
- }
- }
|