390 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
			
		
		
	
	
			390 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C#
		
	
	
	
using System.ComponentModel;
 | 
						|
 | 
						|
namespace SRDebugger.Editor
 | 
						|
{
 | 
						|
    using System;
 | 
						|
    using System.Collections.Generic;
 | 
						|
    using System.Linq;
 | 
						|
    using Internal;
 | 
						|
    using SRF;
 | 
						|
    using UI.Controls.Data;
 | 
						|
    using UnityEngine;
 | 
						|
    using UnityEditor;
 | 
						|
 | 
						|
    public class SROptionsWindow : EditorWindow
 | 
						|
    {
 | 
						|
        [MenuItem(SRDebugPaths.SROptionsMenuItemPath)]
 | 
						|
        public static void Open()
 | 
						|
        {
 | 
						|
            var window = GetWindow<SROptionsWindow>(false, "SROptions", true);
 | 
						|
            window.minSize = new Vector2(100, 100);
 | 
						|
            window.Show();
 | 
						|
        }
 | 
						|
 | 
						|
        [Serializable]
 | 
						|
        private class CategoryState
 | 
						|
        {
 | 
						|
            public string Name;
 | 
						|
            public bool IsOpen;
 | 
						|
        }
 | 
						|
 | 
						|
        [SerializeField]
 | 
						|
        private List<CategoryState> _categoryStates = new List<CategoryState>();
 | 
						|
 | 
						|
        private Dictionary<Type, Action<OptionDefinition>> _typeLookup;
 | 
						|
 | 
						|
        private Dictionary<string, List<OptionDefinition>> _options;
 | 
						|
 | 
						|
        private Vector2 _scrollPosition;
 | 
						|
        private bool _queueRefresh;
 | 
						|
 | 
						|
        [NonSerialized] private GUIStyle _divider;
 | 
						|
        [NonSerialized] private GUIStyle _foldout;
 | 
						|
 | 
						|
        public void OnInspectorUpdate()
 | 
						|
        {
 | 
						|
            if (EditorApplication.isPlaying && _options == null)
 | 
						|
            {
 | 
						|
                Populate();
 | 
						|
                _queueRefresh = true;
 | 
						|
            }
 | 
						|
            else if (!EditorApplication.isPlaying && _options != null)
 | 
						|
            {
 | 
						|
                _options = null;
 | 
						|
                _queueRefresh = true;
 | 
						|
            }
 | 
						|
 | 
						|
            if (_queueRefresh)
 | 
						|
            {
 | 
						|
                Repaint();
 | 
						|
            }
 | 
						|
 | 
						|
            _queueRefresh = false;
 | 
						|
        }
 | 
						|
 | 
						|
        void PopulateTypeLookup()
 | 
						|
        {
 | 
						|
            _typeLookup = new Dictionary<Type, Action<OptionDefinition>>()
 | 
						|
            {
 | 
						|
                {typeof(int), OnGUI_Int},
 | 
						|
                {typeof(float), OnGUI_Float},
 | 
						|
                {typeof(double), OnGUI_Double},
 | 
						|
                {typeof(string), OnGUI_String},
 | 
						|
                {typeof(bool), OnGUI_Boolean },
 | 
						|
                {typeof(uint), OnGUI_AnyInteger},
 | 
						|
                {typeof(ushort), OnGUI_AnyInteger},
 | 
						|
                {typeof(short), OnGUI_AnyInteger},
 | 
						|
                {typeof(sbyte), OnGUI_AnyInteger},
 | 
						|
                {typeof(byte), OnGUI_AnyInteger},
 | 
						|
                {typeof(long), OnGUI_AnyInteger},
 | 
						|
            };
 | 
						|
        }
 | 
						|
 | 
						|
        void Populate()
 | 
						|
        {
 | 
						|
            if (_typeLookup == null)
 | 
						|
            {
 | 
						|
                PopulateTypeLookup();
 | 
						|
            }
 | 
						|
 | 
						|
            _options = new Dictionary<string, List<OptionDefinition>>();
 | 
						|
            
 | 
						|
            foreach (var option in Service.Options.Options)
 | 
						|
            {
 | 
						|
                List<OptionDefinition> list;
 | 
						|
 | 
						|
                if (!_options.TryGetValue(option.Category, out list))
 | 
						|
                {
 | 
						|
                    list = new List<OptionDefinition>();
 | 
						|
                    _options[option.Category] = list;
 | 
						|
                }
 | 
						|
 | 
						|
                list.Add(option);
 | 
						|
            }
 | 
						|
 | 
						|
            foreach (var kv in _options)
 | 
						|
            {
 | 
						|
                kv.Value.Sort((d1, d2) => d1.SortPriority.CompareTo(d2.SortPriority));
 | 
						|
            }
 | 
						|
 | 
						|
            Service.Options.OptionsValueUpdated += OptionsOnOptionsValueUpdated;
 | 
						|
        }
 | 
						|
 | 
						|
        private void OptionsOnOptionsValueUpdated(object sender, PropertyChangedEventArgs e)
 | 
						|
        {
 | 
						|
            _queueRefresh = true;
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        void OnGUI()
 | 
						|
        {
 | 
						|
            EditorGUILayout.Space();
 | 
						|
 | 
						|
            if (!EditorApplication.isPlayingOrWillChangePlaymode || _options == null)
 | 
						|
            {
 | 
						|
                EditorGUILayout.BeginHorizontal();
 | 
						|
                GUILayout.FlexibleSpace();
 | 
						|
                GUILayout.Label("SROptions can only be edited in play-mode.");
 | 
						|
                GUILayout.FlexibleSpace();
 | 
						|
                EditorGUILayout.EndHorizontal();
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (_divider == null)
 | 
						|
            {
 | 
						|
                _divider = new GUIStyle(GUI.skin.box);
 | 
						|
                _divider.stretchWidth = true;
 | 
						|
                _divider.fixedHeight = 2;
 | 
						|
            }
 | 
						|
 | 
						|
            if (_foldout == null)
 | 
						|
            {
 | 
						|
                _foldout = new GUIStyle(EditorStyles.foldout);
 | 
						|
                _foldout.fontStyle = FontStyle.Bold;
 | 
						|
            }
 | 
						|
 | 
						|
            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
 | 
						|
 | 
						|
            foreach (var kv in _options)
 | 
						|
            {
 | 
						|
                var state = _categoryStates.FirstOrDefault(p => p.Name == kv.Key);
 | 
						|
 | 
						|
                if (state == null)
 | 
						|
                {
 | 
						|
                    state = new CategoryState()
 | 
						|
                    {
 | 
						|
                        Name = kv.Key,
 | 
						|
                        IsOpen = true
 | 
						|
                    };
 | 
						|
                    _categoryStates.Add(state);
 | 
						|
                }
 | 
						|
                
 | 
						|
                state.IsOpen = EditorGUILayout.Foldout(state.IsOpen, kv.Key, _foldout);
 | 
						|
 | 
						|
                if (!state.IsOpen)
 | 
						|
                    continue;
 | 
						|
 | 
						|
                EditorGUILayout.BeginVertical(EditorStyles.inspectorDefaultMargins);
 | 
						|
                OnGUI_Category(kv.Value);
 | 
						|
                EditorGUILayout.Space();
 | 
						|
                EditorGUILayout.EndHorizontal();
 | 
						|
            }
 | 
						|
 | 
						|
            EditorGUILayout.EndScrollView();
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Category(List<OptionDefinition> options)
 | 
						|
        {
 | 
						|
            for (var i = 0; i < options.Count; i++)
 | 
						|
            {
 | 
						|
                var op = options[i];
 | 
						|
 | 
						|
                if (op.Property != null)
 | 
						|
                {
 | 
						|
                    OnGUI_Property(op);
 | 
						|
                } else if (op.Method != null)
 | 
						|
                {
 | 
						|
                    OnGUI_Method(op);
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Method(OptionDefinition op)
 | 
						|
        {
 | 
						|
            if (GUILayout.Button(op.Name))
 | 
						|
            {
 | 
						|
                op.Method.Invoke(null);
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Property(OptionDefinition op)
 | 
						|
        {
 | 
						|
            Action<OptionDefinition> method;
 | 
						|
 | 
						|
            if (op.Property.PropertyType.IsEnum)
 | 
						|
            {
 | 
						|
                method = OnGUI_Enum;
 | 
						|
            }
 | 
						|
            else if (!_typeLookup.TryGetValue(op.Property.PropertyType, out method))
 | 
						|
            {
 | 
						|
                OnGUI_Unsupported(op);
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            if (!op.Property.CanWrite)
 | 
						|
            {
 | 
						|
                EditorGUI.BeginDisabledGroup(true);
 | 
						|
            }
 | 
						|
 | 
						|
            method(op);
 | 
						|
 | 
						|
            if (!op.Property.CanWrite)
 | 
						|
            {
 | 
						|
                EditorGUI.EndDisabledGroup();
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_String(OptionDefinition op)
 | 
						|
        {
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
            var newValue = EditorGUILayout.TextField(op.Name, (string) op.Property.GetValue());
 | 
						|
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Boolean(OptionDefinition op)
 | 
						|
        {
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
            var newValue = EditorGUILayout.Toggle(op.Name, (bool) op.Property.GetValue());
 | 
						|
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Enum(OptionDefinition op)
 | 
						|
        {
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
            var newValue = EditorGUILayout.EnumPopup(op.Name, (Enum)op.Property.GetValue());
 | 
						|
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Int(OptionDefinition op)
 | 
						|
        {
 | 
						|
            var range = op.Property.GetAttribute<NumberRangeAttribute>();
 | 
						|
 | 
						|
            int newValue;
 | 
						|
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
 | 
						|
            if (range != null)
 | 
						|
            {
 | 
						|
                newValue = EditorGUILayout.IntSlider(op.Name, (int)op.Property.GetValue(), (int)range.Min, (int)range.Max);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                newValue = EditorGUILayout.IntField(op.Name, (int) op.Property.GetValue());
 | 
						|
            }
 | 
						|
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Float(OptionDefinition op)
 | 
						|
        {
 | 
						|
            var range = op.Property.GetAttribute<NumberRangeAttribute>();
 | 
						|
 | 
						|
            float newValue;
 | 
						|
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
 | 
						|
            if (range != null)
 | 
						|
            {
 | 
						|
                newValue = EditorGUILayout.Slider(op.Name, (float)op.Property.GetValue(), (float)range.Min, (float)range.Max);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                newValue = EditorGUILayout.FloatField(op.Name, (float) op.Property.GetValue());
 | 
						|
            }
 | 
						|
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Double(OptionDefinition op)
 | 
						|
        {
 | 
						|
            var range = op.Property.GetAttribute<NumberRangeAttribute>();
 | 
						|
 | 
						|
            double newValue;
 | 
						|
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
 | 
						|
            if (range != null && range.Min > float.MinValue && range.Max < float.MaxValue)
 | 
						|
            {
 | 
						|
                newValue = EditorGUILayout.Slider(op.Name, (float)op.Property.GetValue(), (float)range.Min, (float)range.Max);
 | 
						|
            }
 | 
						|
            else
 | 
						|
            {
 | 
						|
                newValue = EditorGUILayout.DoubleField(op.Name, (double) op.Property.GetValue());
 | 
						|
 | 
						|
                if (range != null)
 | 
						|
                {
 | 
						|
                    if (newValue > range.Max)
 | 
						|
                    {
 | 
						|
                        newValue = range.Max;
 | 
						|
                    } else if (newValue < range.Min)
 | 
						|
                    {
 | 
						|
                        newValue = range.Min;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
 | 
						|
        void OnGUI_AnyInteger(OptionDefinition op)
 | 
						|
        {
 | 
						|
            NumberControl.ValueRange range;
 | 
						|
 | 
						|
            if (!NumberControl.ValueRanges.TryGetValue(op.Property.PropertyType, out range))
 | 
						|
            {
 | 
						|
                Debug.LogError("Unknown integer type: " + op.Property.PropertyType);
 | 
						|
                return;
 | 
						|
            }
 | 
						|
 | 
						|
            var userRange = op.Property.GetAttribute<NumberRangeAttribute>();
 | 
						|
 | 
						|
            EditorGUI.BeginChangeCheck();
 | 
						|
 | 
						|
            var oldValue = (long)Convert.ChangeType(op.Property.GetValue(), typeof(long));
 | 
						|
            var newValue = EditorGUILayout.LongField(op.Name, oldValue);
 | 
						|
 | 
						|
            if (newValue > range.MaxValue)
 | 
						|
            {
 | 
						|
                newValue = (long)range.MaxValue;
 | 
						|
            } else if (newValue < range.MinValue)
 | 
						|
            {
 | 
						|
                newValue = (long)range.MinValue;
 | 
						|
            }
 | 
						|
 | 
						|
            if (userRange != null)
 | 
						|
            {
 | 
						|
                if (newValue > userRange.Max)
 | 
						|
                {
 | 
						|
                    newValue = (long)userRange.Max;
 | 
						|
                } else if (newValue < userRange.Min)
 | 
						|
                {
 | 
						|
                    newValue = (long) userRange.Min;
 | 
						|
                }
 | 
						|
            }
 | 
						|
            
 | 
						|
            if (EditorGUI.EndChangeCheck())
 | 
						|
            {
 | 
						|
                op.Property.SetValue(Convert.ChangeType(newValue, op.Property.PropertyType));
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
        void OnGUI_Unsupported(OptionDefinition op)
 | 
						|
        {
 | 
						|
            EditorGUILayout.PrefixLabel(op.Name);
 | 
						|
            EditorGUILayout.LabelField("Unsupported Type: {0}".Fmt(op.Property.PropertyType));
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 |