using System; using UnityEngine.SceneManagement; using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEngine; using Newtonsoft.Json; using UnityEngine.UI; using UltraCombos; using ListOfRectTrans = System.Collections.Generic.List; using MapOfGroup = System.Collections.Generic.Dictionary>; using MapOfBindInfo = System.Collections.Generic.Dictionary; public class AutoUIManager : Singleton, ISerializationCallbackReceiver { List parameters; bool show = false; public bool Show { get { return show; } } private DirectoryInfo root; public string filename = "settings"; Transform template_trans; RectTransform scrollView; RectTransform layoutRoot; List layout_groups = new List(); MapOfGroup map_of_layout_group = new MapOfGroup(); List layout_actions = new List(); Dropdown preset_dropdown; InputField preset_input; [Serializable] public class BindInfo { public string key; public string gameobject_name; public string component_name; public string member_name; public bool is_property; public bool is_serializable; public bool has_range; public Vector2 minmax; } [SerializeField] private List bindinfos; MapOfBindInfo map_bindinfo; public bool AddBindInfo(Component compoment, string member_name, bool is_property, bool is_serializable, RangeAttribute range) { if (map_bindinfo == null) { map_bindinfo = new MapOfBindInfo(); } string key = GetUniqueKey(compoment, member_name); if (map_bindinfo.ContainsKey(key)) { return false; } BindInfo info = new BindInfo(); info.key = key; info.gameobject_name = compoment.gameObject.name; info.component_name = compoment.GetType().FullName.Replace("UnityEngine.", ""); info.member_name = member_name; info.is_property = is_property; info.is_serializable = is_serializable; if (range == null) { info.has_range = false; } else { info.has_range = true; info.minmax.x = range.min; info.minmax.y = range.max; } map_bindinfo.Add(key, info); return true; } public void RemoveBindInfo(Component compoment, string member_name) { if (map_bindinfo == null) { return; } string key = GetUniqueKey(compoment, member_name); map_bindinfo.Remove(key); } public IEnumerable GetBindInfos() { if (map_bindinfo != null) { return map_bindinfo.Values; } return null; } public bool TryGetBindInfo(string key, out BindInfo bind_info) { if (map_bindinfo == null) { bind_info = null; return false; } return map_bindinfo.TryGetValue(key, out bind_info); } public bool TryGetBindInfo(Component compoment, string member_name, out BindInfo bind_info) { if (map_bindinfo == null) { bind_info = null; return false; } string key = GetUniqueKey(compoment, member_name); return map_bindinfo.TryGetValue(key, out bind_info); } public bool IsContainedBindInfo(string key) { if (map_bindinfo == null) { return false; } return map_bindinfo.ContainsKey(key); } public bool IsContainedBindInfo(Component compoment, string member_name) { if (map_bindinfo == null) { return false; } string key = GetUniqueKey(compoment, member_name); return map_bindinfo.ContainsKey(key); } void ISerializationCallbackReceiver.OnBeforeSerialize() { if (map_bindinfo == null) { return; } if (bindinfos == null) { bindinfos = new List(); } else { bindinfos.Clear(); } bindinfos.AddRange(map_bindinfo.Values); } void ISerializationCallbackReceiver.OnAfterDeserialize() { if (bindinfos == null) { return; } if (map_bindinfo == null) { map_bindinfo = new MapOfBindInfo(); } else { map_bindinfo.Clear(); } foreach (BindInfo info in bindinfos) { map_bindinfo.Add(info.key, info); } } class CoreSetting { public List presets = new List(); public int value; } const string module = "AutoUI"; string currentPresetName { get { string res = ""; if (preset_dropdown != null) { res = preset_dropdown.options[preset_dropdown.value].text; res = string.Format("{0}-{1}.json", filename, res); } return res; } } string coreSettingFilename { get { return filename + "-core.json"; } } void mf_SetupBindInfoFromScene(Scene scene) { GameObject[] objs = scene.GetRootGameObjects(); foreach (BindInfo bindinfo in map_bindinfo.Values) { foreach (GameObject obj in objs) { if (obj.name != bindinfo.gameobject_name) { continue; } Component compos = obj.GetComponent(bindinfo.component_name); if (compos == null) { continue; } RangeAttribute range = null; if (bindinfo.has_range) { range = new RangeAttribute(bindinfo.minmax.x, bindinfo.minmax.y); } if (bindinfo.is_property) { BindProperty(compos, bindinfo.member_name, bindinfo.is_serializable, range); } else { BindField(compos, bindinfo.member_name, bindinfo.is_serializable, range); } } } } #region MonoBehaviour Functions void Start() { #if UNITY_EDITOR #if UNITY_5_6_OR_NEWER if (UnityEditor.PlayerSettings.GetApiCompatibilityLevel(UnityEditor.BuildTargetGroup.Standalone) == UnityEditor.ApiCompatibilityLevel.NET_2_0_Subset) #else if (UnityEditor.PlayerSettings.apiCompatibilityLevel == UnityEditor.ApiCompatibilityLevel.NET_2_0_Subset) #endif Misc.Verbose(module, "require Api Compatibility Level to be .NET 2.0", 2); #endif root = Directory.GetParent(Application.dataPath); template_trans = transform.Find("Template"); scrollView = transform.Find("Scroll View") as RectTransform; layoutRoot = scrollView.Find("Viewport").Find("Content") as RectTransform; FindAttributes(); preset_input = layout_groups[0][0].GetComponentInChildren(); preset_dropdown = layout_groups[0][0].GetComponentInChildren(); preset_dropdown.ClearOptions(); if (map_bindinfo != null && map_bindinfo.Count > 0) { mf_SetupBindInfoFromScene(SceneManager.GetActiveScene()); //Scene scene = SceneManager.GetSceneByName("DontDestroyOnLoad"); //if (scene != null) //{ // mf_SetupBindInfoFromScene(scene); //} } var data_list = new List(); string path = Path.Combine(root.FullName, coreSettingFilename); if (File.Exists(path)) { var sr = File.OpenText(path); var json = sr.ReadToEnd(); sr.Close(); var cs = JsonUtility.FromJson(json); foreach (var preset in cs.presets) { var option_data = new Dropdown.OptionData(); option_data.text = preset; data_list.Add(option_data); } preset_dropdown.options = data_list; preset_dropdown.value = cs.value; } else { Misc.Verbose(module, "File " + coreSettingFilename + " is not found, save default settings instead.", 1); var option_data = new Dropdown.OptionData(); option_data.text = "default"; data_list.Add(option_data); preset_dropdown.options = data_list; preset_dropdown.value = 0; SaveSettings(); } LoadSettings(); } bool cursorVisiable = false; void Update() { if (Input.GetKeyDown(KeyCode.F1)) { if (show == false) { cursorVisiable = Cursor.visible; } else { Cursor.visible = cursorVisiable; } show = !show; scrollView.gameObject.SetActive(show); } if (scrollView.gameObject.activeSelf) { int x = 15; int y = 25; int field_offset = 36; int section_offset = 10; for (int i = 0; i < layout_groups.Count; i++) { var group = layout_groups[i]; bool is_expand = group[0].GetComponentInChildren(true).isOn; for (int j = 0; j < group.Count; j++) { group[j].anchoredPosition = new Vector2(x, -y); // offset more for main buttons float offset = (i == 0) ? 2.5f : 1.0f; if (j > 0) { group[j].gameObject.SetActive(is_expand); offset *= is_expand ? field_offset : 0.0f; } else { offset *= field_offset; } y += (int)offset; } y += section_offset; } int approx_height = y; layoutRoot.sizeDelta = new Vector2(layoutRoot.sizeDelta.x, approx_height); approx_height = Mathf.Min(approx_height, Screen.height); scrollView.sizeDelta = new Vector2(scrollView.sizeDelta.x, approx_height); foreach (var act in layout_actions) act.Invoke(); } } #endregion public string PresetName { set { var index = preset_dropdown.options.FindIndex( delegate (Dropdown.OptionData data) { return (data.text == value); }); if (index > -1) { Misc.Verbose(module, "Set preset: " + value); preset_dropdown.value = index; LoadSettings(); } else { Misc.Verbose(module, "Preset " + value + " is not exist.", 1); } } get { return preset_dropdown.options[preset_dropdown.value].text; } } public void AddPreset() { var option_data = new Dropdown.OptionData(); option_data.text = preset_input.text; preset_dropdown.options.Add(option_data); preset_input.text = ""; preset_dropdown.value = preset_dropdown.options.Count - 1; } public void RemovePreset() { if (preset_dropdown.options.Count > 1) { int v = preset_dropdown.value - 1; preset_dropdown.options.RemoveAt(preset_dropdown.value); preset_dropdown.value = v; } } public void SaveSettings() { Misc.Verbose(module, "Save settings."); var values = new Dictionary(); foreach (var obj in parameters) { if (obj.isSerialized == false) continue; values[obj.path] = obj.val; } // save preset setting string res = JsonConvert.SerializeObject(values, Formatting.Indented); string path = Path.Combine(root.FullName, currentPresetName); File.WriteAllText(path, res); // save core setting CoreSetting cs = new CoreSetting(); foreach (var opt in preset_dropdown.options) cs.presets.Add(opt.text); cs.value = preset_dropdown.value; res = JsonUtility.ToJson(cs, true); path = Path.Combine(root.FullName, coreSettingFilename); File.WriteAllText(path, res); } public void LoadSettings() { string path = Path.Combine(root.FullName, currentPresetName); if (File.Exists(path)) { Misc.Verbose(module, "Load settings."); var sr = File.OpenText(path); var json = sr.ReadToEnd(); sr.Close(); JsonSerializerSettings setting = new JsonSerializerSettings(); setting.MissingMemberHandling = MissingMemberHandling.Ignore; setting.DefaultValueHandling = DefaultValueHandling.Include; setting.NullValueHandling = NullValueHandling.Ignore; var res = JsonConvert.DeserializeObject>(json, setting); foreach (var obj in parameters) { string obj_path = obj.path; if (res.ContainsKey(obj.path)) { obj.val = res[obj_path]; } } } else { Misc.Verbose(module, "Could not Open the file: " + path + " for reading.", 1); } } public void Close() { show = false; } public bool BindProperty(object obj, string propertyName, bool isSerialized, RangeAttribute range) { Component compoment = obj as Component; if (compoment == null) { return false; } if (propertyName == null || propertyName.Equals("")) { return false; } var labelLayout = template_trans.Find("Label") as RectTransform; ListOfRectTrans layouts; string key = sf_GetMapKey(compoment); bool need_to_add = false; if (!map_of_layout_group.TryGetValue(key, out layouts)) { layouts = new ListOfRectTrans(); need_to_add = true; } BindingFlags bindingFlag = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; bool yes = mf_FindPropertyAndCreateParameter(labelLayout, bindingFlag, obj, propertyName, isSerialized, range, layouts); if (!yes) { return false; } if (need_to_add) { mf_AddLayoutsToGroups(labelLayout, layouts, key); } else { mf_UpdateLayout(layouts, key); } return false; } public bool BindField(object obj, string fieldName, bool isSerialized, RangeAttribute range) { Component compoment = obj as Component; if (compoment == null) { return false; } if (fieldName == null || fieldName.Equals("")) { return false; } var labelLayout = template_trans.Find("Label") as RectTransform; ListOfRectTrans layouts; string key = sf_GetMapKey(compoment); bool need_to_add = false; if (!map_of_layout_group.TryGetValue(key, out layouts)) { layouts = new ListOfRectTrans(); need_to_add = true; } BindingFlags bindingFlag = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; bool yes = mf_FindFieldAndCreateParameter(labelLayout, bindingFlag, obj, fieldName, isSerialized, range, layouts); if (!yes) { return false; } if (need_to_add) { mf_AddLayoutsToGroups(labelLayout, layouts, key); } else { mf_UpdateLayout(layouts, key); } return false; } void FindAttributes() { var labelLayout = template_trans.Find("Label") as RectTransform; var mainButtons = template_trans.Find("Main") as RectTransform; parameters = new List(); layout_groups.Add(new List() { Instantiate(mainButtons, layoutRoot) }); //var bs = Resources.FindObjectsOfTypeAll(typeof(MonoBehaviour)) as MonoBehaviour[]; var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene(); var root_objects = new List(); scene.GetRootGameObjects(root_objects); root_objects.Sort(delegate (GameObject a, GameObject b) { return a.transform.GetSiblingIndex().CompareTo(b.transform.GetSiblingIndex()); }); foreach (var obj in root_objects) { var monos = obj.GetComponentsInChildren(true); foreach (MonoBehaviour mono in monos) { // if script reference is missing, mono will be null if (mono == null) continue; BindingFlags bindingFlag = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public; ListOfRectTrans layouts = new ListOfRectTrans(); mf_FindAttributeFromFields(labelLayout, bindingFlag, mono, layouts); if (layouts.Count > 0) { mf_AddLayoutsToGroups(labelLayout, layouts, sf_GetMapKey(mono)); } } } #if false // no longer need to sort parameters // may use better sort method parameters.Sort(delegate (ParameterInfo a, ParameterInfo b) { return a.index.CompareTo(b.index); }); #endif } void TrySetInputField(InputField input_field, string value) { if (input_field.isFocused == false) input_field.text = value; } public static string GetUniqueKey(Component component, string memberName) { return sf_GetMapKey(component) + ":" + memberName; } #region Private Method private static string sf_GetMapKey(Component component) { var parent_names = new Stack(); parent_names.Push(component.ToString()); var parent_trans = component.transform.parent; while (parent_trans != null) { parent_names.Push(parent_trans.name); parent_trans = parent_trans.parent; } string label_name = ""; label_name = parent_names.Peek(); parent_names.Pop(); while (parent_names.Count > 0) { string format = (parent_names.Count == 1) ? "{0}.[{1}]" : "{0}.{1}"; label_name = string.Format(format, label_name, parent_names.Peek()); parent_names.Pop(); } return label_name; } private static AutoUIAttribute sf_CheckAutoUIAttribute(MemberInfo memberInfo) { foreach (object attribute in memberInfo.GetCustomAttributes(true)) { var attr = attribute as AutoUIAttribute; if (attr == null) { continue; } return attr; } return null; } private void mf_AddLayoutsToGroups(RectTransform labelLayout, ListOfRectTrans layouts, string key) { string label_name = key; label_name += string.Format(": {0}", layouts.Count); var rt = Instantiate(labelLayout, layoutRoot); var text = rt.GetComponentInChildren(); text.text = label_name; layouts.Insert(0, rt); layout_groups.Add(layouts); map_of_layout_group.Add(key, layouts); } private void mf_UpdateLayout(ListOfRectTrans layouts, string key) { string label_name = key; label_name += string.Format(": {0}", (layouts.Count - 1)); var text = layouts[0].GetComponentInChildren(); text.text = label_name; } private bool mf_CreateParameter(T obj_info, Type obj_type, object obj, bool is_serialized, RangeAttribute range, out Parameterizable parameter, out RectTransform rt) { parameter = null; rt = null; try { if (obj_type.Equals(typeof(float))) { ParameterFloat param = new ParameterFloat(obj_info, obj, is_serialized, range); rt = createFloatLayout(param); parameter = param; } else if (obj_type.Equals(typeof(int))) { ParameterInt param = new ParameterInt(obj_info, obj, is_serialized, range); rt = createIntLayout(param); parameter = param; } else if (obj_type.Equals(typeof(string))) { ParameterString param = new ParameterString(obj_info, obj, is_serialized, range); rt = createStringLayout(param); parameter = param; } else if (obj_type.Equals(typeof(bool))) { ParameterBool param = new ParameterBool(obj_info, obj, is_serialized, range); rt = createBoolLayout(param); parameter = param; } else if (obj_type.Equals(typeof(Vector2))) { ParameterVector2 param = new ParameterVector2(obj_info, obj, is_serialized, range); rt = createVec2Layout(param); parameter = param; } else if (obj_type.Equals(typeof(Vector3))) { ParameterVector3 param = new ParameterVector3(obj_info, obj, is_serialized, range); rt = createVec3Layout(param); parameter = param; } else if (obj_type.Equals(typeof(Vector4))) { ParameterVector4 param = new ParameterVector4(obj_info, obj, is_serialized, range); rt = createVec4Layout(param); parameter = param; } else if (obj_type.BaseType.Equals(typeof(Enum))) { ParameterEnum param = new ParameterEnum(obj_info, obj, is_serialized, range); rt = createEnumLayout(param); parameter = param; } else { Misc.Verbose(module, "Field Type of " + obj_type + " is not supported yet... (used in " + obj.ToString() + ")", 1); } } catch (Exception e) { Misc.Verbose(module, e.Message, 1); return false; } return true; } private void mf_SetupParameter(Parameterizable parameter, RectTransform rt, ListOfRectTrans layouts) { parameters.Add(parameter); rt.gameObject.name = parameter.name; var title = rt.Find("Title"); if (title != null) { var text = title.GetComponent(); if (text != null) text.text = parameter.name; } layouts.Add(rt); } private bool mf_FindFieldAndCreateParameter(RectTransform labelLayout, BindingFlags bindingFlag, object obj, string targetName, bool is_serialized, RangeAttribute range, ListOfRectTrans layouts) { foreach (FieldInfo field in (obj.GetType().GetFields(bindingFlag))) { if (field.Name != targetName) { continue; } Parameterizable parameter; RectTransform rt; mf_CreateParameter(field, field.FieldType, obj, is_serialized, range, out parameter, out rt); if (parameter == null) { continue; } mf_SetupParameter(parameter, rt, layouts); return true; } return false; } private bool mf_FindPropertyAndCreateParameter(RectTransform labelLayout, BindingFlags bindingFlag, object obj, string targetName, bool isSerialized, RangeAttribute range, ListOfRectTrans layouts) { foreach (PropertyInfo property in (obj.GetType().GetProperties(bindingFlag))) { if (property.Name != targetName) { continue; } if (property.GetGetMethod() == null) { Debug.LogWarning("[Property]:" + property.Name + " has no GetMethod"); return false; } if (property.GetSetMethod() == null) { Debug.LogWarning("[Property]:" + property.Name + " has no SetMethod"); return false; } Parameterizable parameter; RectTransform rt; mf_CreateParameter(property, property.PropertyType, obj, isSerialized, range, out parameter, out rt); if (parameter == null) { continue; } mf_SetupParameter(parameter, rt, layouts); return true; } return false; } private void mf_FindAttributeFromProperties(RectTransform labelLayout, BindingFlags bindingFlag, object obj, ListOfRectTrans layouts) { foreach (PropertyInfo property in (obj.GetType().GetProperties(bindingFlag))) { AutoUIAttribute attr = sf_CheckAutoUIAttribute(property); if (attr == null) { continue; } if (property.GetGetMethod() == null) { Debug.LogWarning("[Property]:" + property.Name + " has no GetMethod"); continue; } if (property.GetSetMethod() == null) { Debug.LogWarning("[Property]:" + property.Name + " has no SetMethod"); continue; } bool is_serialized = (attr.flag != AutoUIAttribute.BindingFlag.NonSerialized); Parameterizable parameter; RectTransform rt; mf_CreateParameter(property, property.PropertyType, obj, is_serialized, null, out parameter, out rt); if (parameter == null) { continue; } mf_SetupParameter(parameter, rt, layouts); } } private void mf_FindAttributeFromFields(RectTransform labelLayout, BindingFlags bindingFlag, object obj, ListOfRectTrans layouts) { foreach (FieldInfo field in (obj.GetType().GetFields(bindingFlag))) { AutoUIAttribute attr = sf_CheckAutoUIAttribute(field); if (attr == null) { continue; } bool is_serialized = (attr.flag != AutoUIAttribute.BindingFlag.NonSerialized); Parameterizable parameter; RectTransform rt; mf_CreateParameter(field, field.FieldType, obj, is_serialized, null, out parameter, out rt); if (parameter == null) { continue; } mf_SetupParameter(parameter, rt, layouts); } } #endregion #region Parameter Base interface Parameterizable { string name { get; } object val { get; set; } Type valType { get; } string path { get; set; } bool isSerialized { get; set; } bool hasRange { get; set; } Vector2 minmax { get; set; } } class ParameterInfo < T > : Parameterizable { protected object m_object_info; protected MemberInfo m_member_info; protected MethodInfo m_get_method; protected MethodInfo m_set_method; protected object m_object; protected string m_path; protected bool m_isSerialized; protected bool m_hasRange; protected Vector2 m_minmax; protected Type m_val_type; protected float m_index; private object[] m_get_method_params; private object[] m_set_method_params; protected ParameterInfo(T info, object obj, bool isSerialized, RangeAttribute range) { Type info_type = typeof(T); if (info_type == typeof(FieldInfo)) { FieldInfo field = info as FieldInfo; m_get_method = info_type.GetMethod("GetValue", new Type[] { typeof(object) }); m_get_method_params = new object[1]; m_set_method = info_type.GetMethod("SetValue", new Type[] { typeof(object), typeof(object) }); m_set_method_params = new object[2]; m_val_type = field.FieldType; } else if (info_type == typeof(PropertyInfo)) { PropertyInfo property = info as PropertyInfo; m_get_method = info_type.GetMethod("GetValue", new Type[] { typeof(object), typeof(object[]) }); m_get_method_params = new object[2]; m_set_method = info_type.GetMethod("SetValue", new Type[] { typeof(object), typeof(object), typeof(object[]) }); m_set_method_params = new object[3]; m_val_type = property.PropertyType; } else { throw new Exception("ParameterInfo() failed: The info_type = " + info_type.ToString() + ", is not support."); } if (m_set_method == null) { throw new Exception("ParameterInfo() failed: Can not get SetMethod"); } if (m_get_method == null) { throw new Exception("ParameterInfo() failed: Can not get GetMethod"); } m_object_info = info; mf_Setup(info as MemberInfo, obj, isSerialized, range); m_get_method_params[0] = m_object; m_set_method_params[0] = m_object; } private void mf_Setup(MemberInfo info, object obj, bool isSerialized, RangeAttribute range) { m_member_info = info; m_object = obj; m_isSerialized = isSerialized; if (range == null) { var attrs = (RangeAttribute[])m_member_info.GetCustomAttributes(typeof(RangeAttribute), false); if(m_hasRange = attrs.Length > 0) { range = attrs[0]; } } else { m_hasRange = true; } if (m_hasRange) { m_minmax = new Vector2(range.min, range.max); } string res = ""; Component comp = obj as Component; if (comp != null) { Stack tree = new Stack(); tree.Push(comp.name); m_index = comp.transform.GetSiblingIndex() + 1.0f; var parent = comp.transform.parent; while (parent != null) { m_index = m_index * 0.1f + parent.GetSiblingIndex() + 1.0f; tree.Push(parent.name); parent = parent.parent; } while (tree.Count > 0) { res += string.Format("{0}/", tree.Peek()); tree.Pop(); } } res += m_member_info.Name; m_path = res; } public string name { get { return m_member_info.Name; } } public virtual object val { get { return GetValue(); } set { SetValue(value); } } public Type valType { get { return m_val_type; } } public string path { get { return m_path; } set { path = value; } } public bool isSerialized { get { return m_isSerialized; } set { m_isSerialized = value; } } public bool hasRange { get { return m_hasRange; } set { m_hasRange = value; } } public Vector2 minmax { get { return m_minmax; } set { m_minmax = value; } } protected object GetValue() { return m_get_method.Invoke(m_object_info, m_get_method_params); } protected void SetValue(object object_value) { m_set_method_params[1] = object_value; m_set_method.Invoke(m_object_info, m_set_method_params); } } // just for copy past template class ParameterTemplate < T > : ParameterInfo < T > { public ParameterTemplate(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { get { return null; } set { } } } #endregion #region Parameter Float class ParameterFloat : ParameterInfo { public ParameterFloat(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { set { float v; if (float.TryParse(value.ToString(), out v)) { SetValue(v); } } } public void onValueChanged(string value) { val = value; } public void onValueChanged(float value) { val = value; } } RectTransform createFloatLayout (ParameterFloat param) { var floatLayout = template_trans.Find("ParameterFloat") as RectTransform; var floatRangeLayout = template_trans.Find("ParameterFloatRange") as RectTransform; var rt = Instantiate(param.hasRange ? floatRangeLayout : floatLayout, layoutRoot); if (param.hasRange) { var slider = rt.GetComponentInChildren(); if (slider != null) { slider.minValue = param.minmax.x; slider.maxValue = param.minmax.y; slider.onValueChanged.AddListener((v) => param.onValueChanged(v)); layout_actions.Add(() => { slider.value = (float)param.val; }); } } { var input_field = rt.GetComponentInChildren(); if (input_field != null) { input_field.onEndEdit.AddListener((v) => param.onValueChanged(v)); layout_actions.Add(() => TrySetInputField(input_field, param.val.ToString())); } } return rt; } #endregion #region Parameter Int class ParameterInt : ParameterInfo { public ParameterInt(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { set { int v; if (int.TryParse(value.ToString(), out v)) { SetValue(v); } } } public void onValueChanged(string value) { val = value; } public void onValueChanged(float value) { val = value; } } RectTransform createIntLayout(ParameterInt param) { var intLayout = template_trans.Find("ParameterInt") as RectTransform; var intRangeLayout = template_trans.Find("ParameterIntRange") as RectTransform; var rt = Instantiate(param.hasRange ? intRangeLayout : intLayout, layoutRoot); if (param.hasRange) { var slider = rt.GetComponentInChildren(); if (slider != null) { slider.minValue = param.minmax.x; slider.maxValue = param.minmax.y; slider.onValueChanged.AddListener((v) => param.onValueChanged(v)); slider.wholeNumbers = true; layout_actions.Add(() => { slider.value = (int)param.val; }); } } { var input_field = rt.GetComponentInChildren(); if (input_field != null) { input_field.onEndEdit.AddListener((v) => param.onValueChanged(v)); layout_actions.Add(() => TrySetInputField(input_field, param.val.ToString())); } } return rt; } #endregion #region Parameter String class ParameterString : ParameterInfo { public ParameterString(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { set { SetValue(value.ToString()); } } public void onValueChanged(string value) { val = value; } } RectTransform createStringLayout(ParameterString param) { var stringLayout = template_trans.Find("ParameterString") as RectTransform; var rt = Instantiate(stringLayout, layoutRoot); var input_field = rt.GetComponentInChildren(); if (input_field != null) { input_field.onEndEdit.AddListener((v) => param.onValueChanged(v)); layout_actions.Add(() => TrySetInputField(input_field, param.val.ToString())); } return rt; } #endregion #region Parameter Bool class ParameterBool : ParameterInfo { public ParameterBool(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { set { bool v; if (bool.TryParse(value.ToString(), out v)) { SetValue(v); } } } public void onValueChanged(bool value) { val = value; } } RectTransform createBoolLayout(ParameterBool param) { var boolLayout = template_trans.Find("ParameterBool") as RectTransform; var rt = Instantiate(boolLayout, layoutRoot); var toggle = rt.GetComponentInChildren(); if (toggle != null) { toggle.onValueChanged.AddListener((v) => param.onValueChanged(v)); layout_actions.Add(() => { toggle.isOn = (bool)param.val; }); } return rt; } #endregion #region Parameter Vector2 class ParameterVector2 : ParameterInfo { public ParameterVector2(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { get { var value = (Vector2)GetValue(); List array = new List(); array.Add(value.x); array.Add(value.y); return array; } set { if (value is Newtonsoft.Json.Linq.JArray) { var array = value as Newtonsoft.Json.Linq.JArray; if (array.Count != 2) return; SetValue( new Vector2(array[0].ToObject(), array[1].ToObject())); } } } public void onValueXChanged(string value) { var v = (Vector2)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector2(res, v.y)); } } public void onValueYChanged(string value) { var v = (Vector2)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector2(v.x, res)); } } } RectTransform createVec2Layout(ParameterVector2 param) { var vec2Layout = template_trans.Find("ParameterVector2") as RectTransform; var rt = Instantiate(vec2Layout, layoutRoot); var inputs = rt.GetComponentsInChildren(); inputs[0].onEndEdit.AddListener((v) => param.onValueXChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[0], ((List)param.val)[0].ToString())); inputs[1].onEndEdit.AddListener((v) => param.onValueYChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[1], ((List)param.val)[1].ToString())); return rt; } #endregion #region Parameter Vector3 class ParameterVector3 : ParameterInfo { public ParameterVector3(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { get { var value = (Vector3)GetValue(); List array = new List(); array.Add(value.x); array.Add(value.y); array.Add(value.z); return array; } set { if (value is Newtonsoft.Json.Linq.JArray) { var array = value as Newtonsoft.Json.Linq.JArray; if (array.Count != 3) return; SetValue(new Vector3(array[0].ToObject(), array[1].ToObject(), array[2].ToObject())); } } } public void onValueXChanged(string value) { var v = (Vector3)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector3(res, v.y, v.z)); } } public void onValueYChanged(string value) { var v = (Vector3)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector3(v.x, res, v.z)); } } public void onValueZChanged(string value) { var v = (Vector3)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector3(v.x, v.y, res)); } } } RectTransform createVec3Layout(ParameterVector3 param) { var vec3Layout = template_trans.Find("ParameterVector3") as RectTransform; var rt = Instantiate(vec3Layout, layoutRoot); var inputs = rt.GetComponentsInChildren(); inputs[0].onEndEdit.AddListener((v) => param.onValueXChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[0], ((List)param.val)[0].ToString())); inputs[1].onEndEdit.AddListener((v) => param.onValueYChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[1], ((List)param.val)[1].ToString())); inputs[2].onEndEdit.AddListener((v) => param.onValueZChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[2], ((List)param.val)[2].ToString())); return rt; } #endregion #region Parameter Vector4 class ParameterVector4 : ParameterInfo { public ParameterVector4(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { } public override object val { get { var value = (Vector4)GetValue(); List array = new List(); array.Add(value.x); array.Add(value.y); array.Add(value.z); array.Add(value.w); return array; } set { if (value is Newtonsoft.Json.Linq.JArray) { var array = value as Newtonsoft.Json.Linq.JArray; if (array.Count != 4) return; SetValue(new Vector4(array[0].ToObject(), array[1].ToObject(), array[2].ToObject(), array[3].ToObject())); } } } public void onValueXChanged(string value) { var v = (Vector4)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector4(res, v.y, v.z, v.w)); } } public void onValueYChanged(string value) { var v = (Vector4)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector4(v.x, res, v.z, v.w)); } } public void onValueZChanged(string value) { var v = (Vector4)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector4(v.x, v.y, res, v.w)); } } public void onValueWChanged(string value) { var v = (Vector4)GetValue(); float res; if (float.TryParse(value, out res)) { SetValue(new Vector4(v.x, v.y, v.z, res)); } } } RectTransform createVec4Layout(ParameterVector4 param) { var vec4Layout = template_trans.Find("ParameterVector4") as RectTransform; var rt = Instantiate(vec4Layout, layoutRoot); var inputs = rt.GetComponentsInChildren(); inputs[0].onEndEdit.AddListener((v) => param.onValueXChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[0], ((List)param.val)[0].ToString())); inputs[1].onEndEdit.AddListener((v) => param.onValueYChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[1], ((List)param.val)[1].ToString())); inputs[2].onEndEdit.AddListener((v) => param.onValueZChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[2], ((List)param.val)[2].ToString())); inputs[3].onEndEdit.AddListener((v) => param.onValueWChanged(v)); layout_actions.Add(() => TrySetInputField(inputs[3], ((List)param.val)[3].ToString())); return rt; } #endregion #region Parameter Enum class ParameterEnum : ParameterInfo { public ParameterEnum(T field, object obj, bool isSerialized, RangeAttribute range) : base(field, obj, isSerialized, range) { foreach (Enum e in Enum.GetValues(valType)) { _enumerator_list.Add(new GUIContent(e.ToString())); } } public override object val { set { trySetValue(value.ToString()); } } List _enumerator_list = new List(); void trySetValue(string s) { try { Enum v = (Enum)Enum.Parse(valType, s); if (Enum.IsDefined(valType, v)) { SetValue(v); } else Debug.LogWarning(s + " is not an underlying value of the " + valType + " enumeration."); } catch (ArgumentException) { Debug.LogWarning(s + " is not a member of the " + valType + " enumeration."); } } public Dictionary data_table = new Dictionary(); public void onValueChanged(int value) { val = _enumerator_list[value].text; } } RectTransform createEnumLayout(ParameterEnum param) { var enumLayout = template_trans.Find("ParameterEnum") as RectTransform; var rt = Instantiate(enumLayout, layoutRoot); var data_list = new List(); foreach (Enum e in Enum.GetValues(param.valType)) { param.data_table.Add(Convert.ToInt32(e), data_list.Count); var data = new Dropdown.OptionData(); data.text = e.ToString(); data_list.Add(data); } var drop_down = rt.GetComponentInChildren(); if (drop_down != null) { drop_down.ClearOptions(); drop_down.options = data_list; drop_down.onValueChanged.AddListener((v) => param.onValueChanged(v)); layout_actions.Add(() => { drop_down.value = param.data_table[(int)param.val]; }); } return rt; } #endregion }