Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 63 additions & 34 deletions Assets/Plugins/Source/Editor/Utility/GUIEditorUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ namespace PlayEveryWare.EpicOnlineServices.Editor.Utility
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text;
using UnityEditor;
using UnityEditorInternal;
using UnityEngine;
Expand Down Expand Up @@ -245,7 +246,7 @@ public static void AssigningEnumField<T>(string label, ref T value, float labelW
.OrderBy(group => group.Key);
}

private static IOrderedEnumerable<IGrouping<int, (MemberInfo MemberInfo, ConfigFieldAttribute FieldDetails)>> GetMembersByGroup<T>()
private static IOrderedEnumerable<IGrouping<int, (MemberInfo MemberInfo, ConfigFieldAttribute FieldDetails, IEnumerable<FieldValidatorAttribute> FieldValidators)>> GetMembersByGroup<T>()
{
var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
Expand All @@ -254,7 +255,8 @@ public static void AssigningEnumField<T>(string label, ref T value, float labelW

return members
.Where(member => member.GetCustomAttribute<ConfigFieldAttribute>() != null)
.Select(member => (MemberInfo: member, FieldDetails: member.GetCustomAttribute<ConfigFieldAttribute>()))
.Select(member => (MemberInfo: member, FieldDetails: member.GetCustomAttribute<ConfigFieldAttribute>(),
FieldValidators: member.GetCustomAttributes<FieldValidatorAttribute>()))
.GroupBy(r => r.FieldDetails.Group)
.OrderBy(group => group.Key);
}
Expand All @@ -271,7 +273,6 @@ public static void AssigningEnumField<T>(string label, ref T value, float labelW
{ typeof(float), (attr, val, width) => RenderInput(attr, (float)val, width) },
{ typeof(double), (attr, val, width) => RenderInput(attr, (double)val, width) },
{ typeof(bool), (attr, val, width) => RenderInput(attr, (bool)val, width) },
{ typeof(Version), (attr, val, width) => RenderInput(attr, (Version)val, width) },
{ typeof(Guid), (attr, val, width) => RenderInput(attr, (Guid)val, width)},
{ typeof(List<string>), (attr, val, width) => RenderInput(attr, (List<string>)val, width)},
#if !EOS_DISABLE
Expand Down Expand Up @@ -500,6 +501,9 @@ public static void RenderInputs<T>(ref T value)
{
continue; // Skip if MemberInfo is neither FieldInfo nor PropertyInfo
}

// Assign the validators
member.FieldDetails.Validators = member.FieldValidators;

// Use the handler from the dictionary
if (FieldHandlers.TryGetValue(member.FieldDetails.FieldType, out var handler))
Expand Down Expand Up @@ -1126,7 +1130,7 @@ public static WrappedInitializeThreadAffinity RenderInput(ConfigFieldAttribute a
#endif
private static Guid RenderInput(ConfigFieldAttribute configFieldDetails, Guid value, float labelWidth)
{
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value,
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, configFieldDetails.Validators,
GuidField);
}

Expand Down Expand Up @@ -1212,22 +1216,13 @@ public static Deployment RenderInput(ConfigFieldAttribute configFieldAttribute,
public static TEnum RenderEnumInput<TEnum>(ConfigFieldAttribute configFieldAttribute, TEnum value, float labelWidth) where TEnum : Enum
{
return InputRendererWrapper(configFieldAttribute.Label, configFieldAttribute.ToolTip, labelWidth, value,
EnumFlagsField, configFieldAttribute.HelpURL);
configFieldAttribute.Validators, EnumFlagsField, configFieldAttribute.HelpURL);
}

private static TEnum EnumFlagsField<TEnum>(GUIContent label, TEnum value, params GUILayoutOption[] options) where TEnum : Enum
{
return (TEnum)EditorGUILayout.EnumFlagsField(label, value, options);
}
private static Version RenderInput(ConfigFieldAttribute configFieldAttribute, Version value, float labelWidth)
{
return RenderInput(value, configFieldAttribute.Label, configFieldAttribute.ToolTip, labelWidth);
}

public static Version RenderInput(Version value, string label, string tooltip, float labelWidth)
{
return InputRendererWrapper(label, tooltip, labelWidth, value, VersionField);
}

public static ProductionEnvironments RenderInput(ConfigFieldAttribute configFieldAttribute,
ProductionEnvironments value, float labelWidth)
Expand Down Expand Up @@ -1306,7 +1301,7 @@ public static string RenderInput(DirectoryPathFieldAttribute configFieldAttribut
{
EditorGUILayout.BeginHorizontal();

string filePath = InputRendererWrapper(configFieldAttributeDetails.Label, value, labelWidth, tooltip, EditorGUILayout.TextField, configFieldAttributeDetails.HelpURL);
string filePath = InputRendererWrapper(configFieldAttributeDetails.Label, value, labelWidth, tooltip, configFieldAttributeDetails.Validators, EditorGUILayout.TextField, configFieldAttributeDetails.HelpURL);

if (GUILayout.Button("Select", GUILayout.MaxWidth(MAXIMUM_BUTTON_WIDTH)))
{
Expand All @@ -1327,7 +1322,7 @@ public static string RenderInput(FilePathFieldAttribute configFieldAttributeDeta
{
EditorGUILayout.BeginHorizontal();

string filePath = InputRendererWrapper(configFieldAttributeDetails.Label, value, labelWidth, tooltip, EditorGUILayout.TextField, configFieldAttributeDetails.HelpURL);
string filePath = InputRendererWrapper(configFieldAttributeDetails.Label, value, labelWidth, tooltip, configFieldAttributeDetails.Validators, EditorGUILayout.TextField, configFieldAttributeDetails.HelpURL);

if (GUILayout.Button("Select", GUILayout.MaxWidth(MAXIMUM_BUTTON_WIDTH)))
{
Expand All @@ -1347,35 +1342,25 @@ public static string RenderInput(FilePathFieldAttribute configFieldAttributeDeta

public static double RenderInput(ConfigFieldAttribute configFieldDetails, double value, float labelWidth)
{
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, EditorGUILayout.DoubleField, configFieldDetails.HelpURL);
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, configFieldDetails.Validators, EditorGUILayout.DoubleField, configFieldDetails.HelpURL);
}

public static float RenderInput(ConfigFieldAttribute configFieldDetails, float value, float labelWidth)
{
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, EditorGUILayout.FloatField, configFieldDetails.HelpURL);
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, configFieldDetails.Validators, EditorGUILayout.FloatField, configFieldDetails.HelpURL);
}

public static string RenderInput(ConfigFieldAttribute configFieldDetails, string value, float labelWidth)
{
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, EditorGUILayout.TextField, configFieldDetails.HelpURL);
return InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, value, configFieldDetails.Validators, EditorGUILayout.TextField, configFieldDetails.HelpURL);
}

public static ulong RenderInput(ConfigFieldAttribute configFieldDetails, ulong value, float labelWidth)
{
_ = SafeTranslatorUtility.TryConvert(value, out long temp);

long longValue = InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth,
temp, EditorGUILayout.LongField);

return SafeTranslatorUtility.TryConvert(longValue, out ulong newValue) ? newValue : value;
}

private static ulong RenderInput(string label, string tooltip, ulong value, float labelWidth)
{
_ = SafeTranslatorUtility.TryConvert(value, out long temp);

long longValue = InputRendererWrapper(label, tooltip, labelWidth,
temp, EditorGUILayout.LongField);
temp, configFieldDetails.Validators, EditorGUILayout.LongField);

return SafeTranslatorUtility.TryConvert(longValue, out ulong newValue) ? newValue : value;
}
Expand All @@ -1384,7 +1369,7 @@ public static uint RenderInput(ConfigFieldAttribute configFieldDetails, uint val
{
_ = SafeTranslatorUtility.TryConvert(value, out int temp);

int intValue = InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, temp,
int intValue = InputRendererWrapper(configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth, temp, configFieldDetails.Validators,
EditorGUILayout.IntField);

return SafeTranslatorUtility.TryConvert(intValue, out uint newValue) ? newValue : value;
Expand All @@ -1394,10 +1379,10 @@ public static bool RenderInput(ConfigFieldAttribute configFieldDetails, bool val
{
return InputRendererWrapper(
configFieldDetails.Label, configFieldDetails.ToolTip, labelWidth,
value, EditorGUILayout.Toggle);
value, configFieldDetails.Validators, EditorGUILayout.Toggle);
}

public delegate T TestDelegate<T>(GUIContent label, T value, params GUILayoutOption[] options);
public delegate T InputRendererDelegate<T>(GUIContent label, T value, params GUILayoutOption[] options);

private static T InputRendererWithAlignedLabel<T>(float labelWidth, Func<T> renderFn)
{
Expand All @@ -1412,10 +1397,50 @@ private static T InputRendererWithAlignedLabel<T>(float labelWidth, Func<T> rend
return newValue;
}

private static T InputRendererWrapper<T>(string label, string toolTip, float labelWidth, T value, TestDelegate<T> renderFn, string helpURL = null)
private static void RunValidators(IEnumerable<FieldValidatorAttribute> validators, object value, out bool isValid)
{
isValid = true;
StringBuilder errorMessageBuilder = new();
foreach (var validator in validators)
{
// If field is valid then go to the next validator.
if (validator.FieldValueIsValid(value, out string errorMessage))
{
continue;
}

// Otherwise append message from the validator.
errorMessageBuilder.AppendLine(errorMessage);
}

// If there are no error messages, then stop here
if (errorMessageBuilder.Length == 0)
{
return;
}

isValid = false;
EditorGUILayout.HelpBox(errorMessageBuilder.ToString(), MessageType.Warning);
}

private static T InputRendererWrapper<T>(string label, string toolTip, float labelWidth, T value, IEnumerable<FieldValidatorAttribute> validators, InputRendererDelegate<T> renderFn, string helpURL = null)
{
return InputRendererWithAlignedLabel(labelWidth, () =>
{
// Run validators for the config field.
RunValidators(validators, value, out bool isCurrentValueValid);

// Store the previous background color so that it can be
// restored if need be.
Color previousBackgroundColor = GUI.backgroundColor;
if (!isCurrentValueValid)
{
// This sets the background color for the input field that
// is about to be rendered to red - further highlighting the
// field that has invalid values.
GUI.backgroundColor = Color.red;
}

if (!string.IsNullOrEmpty(helpURL))
{
EditorGUILayout.BeginHorizontal();
Expand All @@ -1429,6 +1454,10 @@ private static T InputRendererWrapper<T>(string label, string toolTip, float lab
EditorGUILayout.EndHorizontal();
}

// Restore the background color that was set before the field
// was rendered.
GUI.backgroundColor = previousBackgroundColor;

return newValue;
});
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
namespace PlayEveryWare.EpicOnlineServices
{
using System;
using System.Collections.Generic;

[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class ConfigFieldAttribute : Attribute
Expand Down Expand Up @@ -58,31 +59,31 @@ public class ConfigFieldAttribute : Attribute
/// </summary>
public PlatformManager.Platform PlatformsEnabledOn { get; }

public IEnumerable<FieldValidatorAttribute> Validators { get; set; }

public ConfigFieldAttribute(
PlatformManager.Platform enabledOn,
string label,
ConfigFieldType type,
string tooltip = null,
int group = -1,
string helpUrl = null) : this(label, type, tooltip, group, helpUrl)
string helpUrl = null)
{
PlatformsEnabledOn = enabledOn;
Label = label;
FieldType = type;
ToolTip = tooltip;
Group = group;
HelpURL = helpUrl;
}

public ConfigFieldAttribute(
string label,
ConfigFieldType type,
string tooltip = null,
int group = -1,
string helpUrl = null)
{
PlatformsEnabledOn = PlatformManager.Platform.Any;
HelpURL = helpUrl;
Label = label;
ToolTip = tooltip;
Group = group;
FieldType = type;
}
string helpUrl = null) : this(PlatformManager.Platform.Any, label, type, tooltip, group, helpUrl)
{ }
}
}

Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,9 @@ namespace PlayEveryWare.EpicOnlineServices
using System;
using System.Reflection;

[AttributeUsage(AttributeTargets.Field)]

[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
public abstract class FieldValidatorAttribute : Attribute
{
public abstract bool FieldValueIsValid(object toValidate, out string configurationProblemMessage);
public abstract bool FieldValueIsValid(object value, out string errorMessage);
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading