You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1604 lines
48 KiB

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<UnityEngine.RectTransform>;
using MapOfGroup = System.Collections.Generic.Dictionary<string, System.Collections.Generic.List<UnityEngine.RectTransform>>;
using MapOfBindInfo = System.Collections.Generic.Dictionary<string, AutoUIManager.BindInfo >;
public class AutoUIManager : Singleton<AutoUIManager>, ISerializationCallbackReceiver
{
List<Parameterizable> 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<ListOfRectTrans> layout_groups = new List<ListOfRectTrans>();
MapOfGroup map_of_layout_group = new MapOfGroup();
List<Action> layout_actions = new List<Action>();
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<BindInfo> 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<BindInfo> 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<BindInfo>();
}
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<string> presets = new List<string>();
public int value;
}
const string module = "<color=teal>AutoUI</color>";
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<InputField>();
preset_dropdown = layout_groups[0][0].GetComponentInChildren<Dropdown>();
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<Dropdown.OptionData>();
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<CoreSetting>(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<Toggle>(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<string, object>();
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<Dictionary<string, object>>(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<Parameterizable>();
layout_groups.Add(new List<RectTransform>() { Instantiate(mainButtons, layoutRoot) });
//var bs = Resources.FindObjectsOfTypeAll(typeof(MonoBehaviour)) as MonoBehaviour[];
var scene = UnityEngine.SceneManagement.SceneManager.GetActiveScene();
var root_objects = new List<GameObject>();
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<MonoBehaviour>(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<string>();
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.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.text = label_name;
}
private bool mf_CreateParameter<T>(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<T> param = new ParameterFloat<T>(obj_info, obj, is_serialized, range);
rt = createFloatLayout(param);
parameter = param;
}
else if (obj_type.Equals(typeof(int)))
{
ParameterInt<T> param = new ParameterInt<T>(obj_info, obj, is_serialized, range);
rt = createIntLayout(param);
parameter = param;
}
else if (obj_type.Equals(typeof(string)))
{
ParameterString<T> param = new ParameterString<T>(obj_info, obj, is_serialized, range);
rt = createStringLayout(param);
parameter = param;
}
else if (obj_type.Equals(typeof(bool)))
{
ParameterBool<T> param = new ParameterBool<T>(obj_info, obj, is_serialized, range);
rt = createBoolLayout(param);
parameter = param;
}
else if (obj_type.Equals(typeof(Vector2)))
{
ParameterVector2<T> param = new ParameterVector2<T>(obj_info, obj, is_serialized, range);
rt = createVec2Layout(param);
parameter = param;
}
else if (obj_type.Equals(typeof(Vector3)))
{
ParameterVector3<T> param = new ParameterVector3<T>(obj_info, obj, is_serialized, range);
rt = createVec3Layout(param);
parameter = param;
}
else if (obj_type.Equals(typeof(Vector4)))
{
ParameterVector4<T> param = new ParameterVector4<T>(obj_info, obj, is_serialized, range);
rt = createVec4Layout(param);
parameter = param;
}
else if (obj_type.BaseType.Equals(typeof(Enum)))
{
ParameterEnum<T> param = new ParameterEnum<T>(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<Text>();
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<string> tree = new Stack<string>();
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<T> : ParameterInfo<T>
{
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<T> (ParameterFloat <T> 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<Slider>();
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<InputField>();
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<T> : ParameterInfo<T>
{
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<T>(ParameterInt<T> 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<Slider>();
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<InputField>();
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<T> : ParameterInfo<T>
{
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<T>(ParameterString<T> param)
{
var stringLayout = template_trans.Find("ParameterString") as RectTransform;
var rt = Instantiate(stringLayout, layoutRoot);
var input_field = rt.GetComponentInChildren<InputField>();
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<T> : ParameterInfo<T>
{
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<T>(ParameterBool<T> param)
{
var boolLayout = template_trans.Find("ParameterBool") as RectTransform;
var rt = Instantiate(boolLayout, layoutRoot);
var toggle = rt.GetComponentInChildren<Toggle>();
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<T> : ParameterInfo<T>
{
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<float> array = new List<float>();
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<float>(), array[1].ToObject<float>()));
}
}
}
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<T>(ParameterVector2<T> param)
{
var vec2Layout = template_trans.Find("ParameterVector2") as RectTransform;
var rt = Instantiate(vec2Layout, layoutRoot);
var inputs = rt.GetComponentsInChildren<InputField>();
inputs[0].onEndEdit.AddListener((v) => param.onValueXChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[0], ((List<float>)param.val)[0].ToString()));
inputs[1].onEndEdit.AddListener((v) => param.onValueYChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[1], ((List<float>)param.val)[1].ToString()));
return rt;
}
#endregion
#region Parameter Vector3
class ParameterVector3<T> : ParameterInfo<T>
{
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<float> array = new List<float>();
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<float>(), array[1].ToObject<float>(), array[2].ToObject<float>()));
}
}
}
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<T>(ParameterVector3<T> param)
{
var vec3Layout = template_trans.Find("ParameterVector3") as RectTransform;
var rt = Instantiate(vec3Layout, layoutRoot);
var inputs = rt.GetComponentsInChildren<InputField>();
inputs[0].onEndEdit.AddListener((v) => param.onValueXChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[0], ((List<float>)param.val)[0].ToString()));
inputs[1].onEndEdit.AddListener((v) => param.onValueYChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[1], ((List<float>)param.val)[1].ToString()));
inputs[2].onEndEdit.AddListener((v) => param.onValueZChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[2], ((List<float>)param.val)[2].ToString()));
return rt;
}
#endregion
#region Parameter Vector4
class ParameterVector4<T> : ParameterInfo<T>
{
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<float> array = new List<float>();
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<float>(), array[1].ToObject<float>(), array[2].ToObject<float>(), array[3].ToObject<float>()));
}
}
}
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<T>(ParameterVector4<T> param)
{
var vec4Layout = template_trans.Find("ParameterVector4") as RectTransform;
var rt = Instantiate(vec4Layout, layoutRoot);
var inputs = rt.GetComponentsInChildren<InputField>();
inputs[0].onEndEdit.AddListener((v) => param.onValueXChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[0], ((List<float>)param.val)[0].ToString()));
inputs[1].onEndEdit.AddListener((v) => param.onValueYChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[1], ((List<float>)param.val)[1].ToString()));
inputs[2].onEndEdit.AddListener((v) => param.onValueZChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[2], ((List<float>)param.val)[2].ToString()));
inputs[3].onEndEdit.AddListener((v) => param.onValueWChanged(v));
layout_actions.Add(() => TrySetInputField(inputs[3], ((List<float>)param.val)[3].ToString()));
return rt;
}
#endregion
#region Parameter Enum
class ParameterEnum<T> : ParameterInfo<T>
{
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<GUIContent> _enumerator_list = new List<GUIContent>();
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<int, int> data_table = new Dictionary<int, int>();
public void onValueChanged(int value)
{
val = _enumerator_list[value].text;
}
}
RectTransform createEnumLayout<T>(ParameterEnum<T> param)
{
var enumLayout = template_trans.Find("ParameterEnum") as RectTransform;
var rt = Instantiate(enumLayout, layoutRoot);
var data_list = new List<Dropdown.OptionData>();
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<Dropdown>();
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
}