/// <summary> /// [0.18.0] /// </summary> public static void DrawFields <T>(ref T container, ModEntry mod, DrawFieldMask defaultMask, Action onChange = null) where T : new() { object obj = container; var changed = Draw(obj, typeof(T), mod, defaultMask); if (changed) { container = (T)obj; if (onChange != null) { try { onChange(); } catch (Exception e) { mod.Logger.LogException(e); } } } }
public DrawFieldsAttribute(DrawFieldMask Mask) { this.Mask = Mask; }
private static bool Draw(object container, Type type, ModEntry mod, DrawFieldMask defaultMask) { bool changed = false; var options = new List <GUILayoutOption>(); DrawFieldMask mask = defaultMask; foreach (DrawFieldsAttribute attr in type.GetCustomAttributes(typeof(DrawFieldsAttribute), false)) { mask = attr.Mask; } var fields = type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); foreach (var f in fields) { DrawAttribute a = new DrawAttribute(); var attributes = f.GetCustomAttributes(typeof(DrawAttribute), false); if (attributes.Length > 0) { foreach (DrawAttribute a_ in attributes) { a = a_; a.Width = a.Width != 0 ? Scale(a.Width) : 0; a.Height = a.Height != 0 ? Scale(a.Height) : 0; } if (a.Type == DrawType.Ignore) { continue; } //if (!string.IsNullOrEmpty(a.DependsOn)) //{ // var field = type.GetField(a.DependsOn, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance); // if (field == null) // { // } // else // { // var value = field.GetValue(container); // } //} } else { if ((mask & DrawFieldMask.OnlyDrawAttr) == 0 && ((mask & DrawFieldMask.SkipNotSerialized) == 0 || !f.IsNotSerialized) && ((mask & DrawFieldMask.Public) > 0 && f.IsPublic || (mask & DrawFieldMask.Serialized) > 0 && f.GetCustomAttributes(typeof(SerializeField), false).Length > 0 || (mask & DrawFieldMask.Public) == 0 && (mask & DrawFieldMask.Serialized) == 0)) { foreach (RangeAttribute a_ in f.GetCustomAttributes(typeof(RangeAttribute), false)) { a.Type = DrawType.Slider; a.Min = a_.min; a.Max = a_.max; break; } foreach (HeaderAttribute a_ in f.GetCustomAttributes(typeof(HeaderAttribute), false)) { a.Label = a_.header; break; } } else { continue; } } foreach (SpaceAttribute a_ in f.GetCustomAttributes(typeof(SpaceAttribute), false)) { GUILayout.Space(Scale((int)a_.height)); } var fieldName = string.IsNullOrEmpty(a.Label) ? f.Name : a.Label; if (f.FieldType.IsClass || f.FieldType.IsValueType && !f.FieldType.IsPrimitive && !f.FieldType.IsEnum && !Array.Exists(specialTypes, x => x == f.FieldType)) { defaultMask = mask; foreach (DrawFieldsAttribute attr in f.GetCustomAttributes(typeof(DrawFieldsAttribute), false)) { defaultMask = attr.Mask; } var horizontal = f.GetCustomAttributes(typeof(HorizontalAttribute), false).Length > 0; if (horizontal) { GUILayout.BeginHorizontal(); } GUILayout.Label($"{fieldName}", GUILayout.ExpandWidth(false)); var val = f.GetValue(container); if (Draw(val, f.FieldType, mod, defaultMask)) { changed = true; f.SetValue(container, val); } if (horizontal) { GUILayout.EndHorizontal(); } continue; } options.Clear(); if (a.Type == DrawType.Auto) { if (Array.Exists(fieldTypes, x => x == f.FieldType)) { a.Type = DrawType.Field; } else if (Array.Exists(toggleTypes, x => x == f.FieldType)) { a.Type = DrawType.Toggle; } else if (f.FieldType.IsEnum) { if (f.GetCustomAttributes(typeof(FlagsAttribute), false).Length == 0) { a.Type = DrawType.PopupList; } } } if (a.Type == DrawType.Field) { if (!Array.Exists(fieldTypes, x => x == f.FieldType)) { mod.Logger.Error($"Type {f.FieldType} can't be drawed as {DrawType.Field}"); break; } options.Add(a.Width != 0 ? GUILayout.Width(a.Width) : GUILayout.Width(Scale(100))); options.Add(a.Height != 0 ? GUILayout.Height(a.Height) : GUILayout.Height(Scale((int)drawHeight))); if (f.FieldType == typeof(Vector2)) { GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var vec = (Vector2)f.GetValue(container); if (DrawVector(ref vec, null, options.ToArray())) { f.SetValue(container, vec); changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } else if (f.FieldType == typeof(Vector3)) { GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var vec = (Vector3)f.GetValue(container); if (DrawVector(ref vec, null, options.ToArray())) { f.SetValue(container, vec); changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } else if (f.FieldType == typeof(Vector4)) { GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var vec = (Vector4)f.GetValue(container); if (DrawVector(ref vec, null, options.ToArray())) { f.SetValue(container, vec); changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } else if (f.FieldType == typeof(Color)) { GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var vec = (Color)f.GetValue(container); if (DrawColor(ref vec, null, options.ToArray())) { f.SetValue(container, vec); changed = true; } GUILayout.FlexibleSpace(); GUILayout.EndHorizontal(); } else { GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var val = f.GetValue(container).ToString(); if (a.Precision >= 0 && (f.FieldType == typeof(float) || f.FieldType == typeof(double))) { if (Double.TryParse(val, System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out var num)) { val = num.ToString($"f{a.Precision}"); } } var result = f.FieldType == typeof(string) ? GUILayout.TextField(val, a.MaxLength, options.ToArray()) : GUILayout.TextField(val, options.ToArray()); GUILayout.EndHorizontal(); if (result != val) { if (string.IsNullOrEmpty(result)) { if (f.FieldType != typeof(string)) { result = "0"; } } else { if (Double.TryParse(result, System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out var num)) { num = Math.Max(num, a.Min); num = Math.Min(num, a.Max); result = num.ToString(); } else { result = "0"; } } f.SetValue(container, Convert.ChangeType(result, f.FieldType)); changed = true; } } } else if (a.Type == DrawType.Slider) { if (!Array.Exists(sliderTypes, x => x == f.FieldType)) { mod.Logger.Error($"Type {f.FieldType} can't be drawed as {DrawType.Slider}"); break; } options.Add(a.Width != 0 ? GUILayout.Width(a.Width) : GUILayout.Width(Scale(200))); options.Add(a.Height != 0 ? GUILayout.Height(a.Height) : GUILayout.Height(Scale((int)drawHeight))); GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var val = f.GetValue(container).ToString(); if (!Double.TryParse(val, System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out var num)) { mod.Logger.Error($"Field {fieldName} can't be parsed as number"); break; } var fnum = (float)num; var result = GUILayout.HorizontalSlider(fnum, (float)a.Min, (float)a.Max, options.ToArray()); GUILayout.Space(Scale(5)); GUILayout.Label(result.ToString(), GUILayout.ExpandWidth(false), GUILayout.Height(Scale((int)drawHeight))); GUILayout.EndHorizontal(); if (result != fnum) { if ((f.FieldType == typeof(float) || f.FieldType == typeof(double)) && a.Precision >= 0) { result = (float)Math.Round(result, a.Precision); } f.SetValue(container, Convert.ChangeType(result, f.FieldType)); changed = true; } } else if (a.Type == DrawType.Toggle) { if (!Array.Exists(toggleTypes, x => x == f.FieldType)) { mod.Logger.Error($"Type {f.FieldType} can't be drawed as {DrawType.Toggle}"); break; } options.Add(GUILayout.ExpandWidth(false)); options.Add(a.Height != 0 ? GUILayout.Height(a.Height) : GUILayout.Height(Scale((int)drawHeight))); GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); var val = (bool)f.GetValue(container); var result = GUILayout.Toggle(val, "", options.ToArray()); GUILayout.EndHorizontal(); if (result != val) { f.SetValue(container, Convert.ChangeType(result, f.FieldType)); changed = true; } } else if (a.Type == DrawType.ToggleGroup) { if (!f.FieldType.IsEnum || f.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0) { mod.Logger.Error($"Type {f.FieldType} can't be drawed as {DrawType.ToggleGroup}"); break; } options.Add(GUILayout.ExpandWidth(false)); options.Add(a.Height != 0 ? GUILayout.Height(a.Height) : GUILayout.Height(Scale((int)drawHeight))); GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var values = Enum.GetNames(f.FieldType); var val = (int)f.GetValue(container); if (ToggleGroup(ref val, values, null, options.ToArray())) { var v = Enum.Parse(f.FieldType, values[val]); f.SetValue(container, v); changed = true; } GUILayout.EndHorizontal(); } else if (a.Type == DrawType.PopupList) { if (!f.FieldType.IsEnum || f.GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0) { mod.Logger.Error($"Type {f.FieldType} can't be drawed as {DrawType.PopupList}"); break; } options.Add(GUILayout.ExpandWidth(false)); options.Add(a.Height != 0 ? GUILayout.Height(a.Height) : GUILayout.Height(Scale((int)drawHeight))); GUILayout.BeginHorizontal(); GUILayout.Label(fieldName, GUILayout.ExpandWidth(false)); GUILayout.Space(Scale(5)); var values = Enum.GetNames(f.FieldType); var val = (int)f.GetValue(container); if (PopupToggleGroup(ref val, values, null, options.ToArray())) { var v = Enum.Parse(f.FieldType, values[val]); f.SetValue(container, v); changed = true; } GUILayout.EndHorizontal(); } } return(changed); }