Editor/ControlWidgets/GenericTypeSelectControlWidget.cs
using Editor;
using ExtendedEditor.Attributes;
using ExtendedEditor.TypeLibraryFixes;
using Sandbox;
using System;
using System.Linq;
namespace ExtendedEditor.ControlWidgets;
[CustomEditor(typeof(Type), WithAllAttributes = [typeof(TypeSelectAttribute)])]
public class GenericTypeSelectControlWidget : ControlWidget
{
private readonly bool _whitelistedOnly;
private Type? _lastRecordededDefinition;
private Type[] _genericArguments = [];
private Type? Value
{
get => SerializedProperty.GetValue<Type>();
set
{
var currentValue = SerializedProperty.GetValue<Type>();
if(object.Equals(currentValue, value))
return;
PropertyStartEdit();
SerializedProperty.SetValue(value);
PropertyFinishEdit();
SignalValuesChanged();
}
}
public GenericTypeSelectControlWidget(SerializedProperty property) : this(property, true)
{
}
public GenericTypeSelectControlWidget(SerializedProperty property, bool whitelistedOnly) : base(property.Fix())
{
_whitelistedOnly = whitelistedOnly;
Layout = Layout.Column();
Layout.Spacing = 2;
OnValueChanged();
}
private void RebuildLayout()
{
Layout.Clear(true);
var baseControl = new TypeSelectControlWidget(SerializedProperty, _whitelistedOnly);
Layout.Add(baseControl);
var value = Value;
if(value is not null && value.IsGenericType)
{
var grid = Layout.Grid();
grid.SetMinimumColumnWidth(0, 40);
Layout.Add(grid);
var genericParameters = _lastRecordededDefinition!.GetGenericArguments();
for(int i = 0; i < _genericArguments.Length; i++)
{
int index = i;
var attributes = SerializedProperty.GetAttributes().ToList();
attributes.RemoveAll(x => x is TypeSelectAttribute);
attributes.Add(new TypeSelectAttribute()
{
Validator = t => t is null || t.CanBeGenericParameter(genericParameters[index], _genericArguments)
});
var property = EditorTypeLibrary.CreatePropertyFixed($"<{genericParameters[index].Name}>",
() => GetGenericArgument(index), t => SetGenericArgument(index, t),
[.. attributes]);
var widget = new GenericTypeSelectControlWidget(property, _whitelistedOnly);
grid.AddCell(0, i, new Editor.Label(property.Name) { Alignment = TextFlag.Center });
grid.AddCell(1, i, widget);
}
}
}
protected override void OnValueChanged()
{
var value = Value;
Type? definition = value;
if(definition is not null && definition.IsGenericType && !definition.IsGenericTypeDefinition)
definition = definition.GetGenericTypeDefinition();
if(!object.Equals(_lastRecordededDefinition, definition))
_genericArguments = (value?.IsGenericType ?? false) ? value.GetGenericArguments() : [];
_lastRecordededDefinition = definition;
RebuildLayout();
}
private Type GetGenericArgument(int index)
{
return _genericArguments[index];
}
private void SetGenericArgument(int index, Type type)
{
_genericArguments[index] = type;
if(_genericArguments.All(x => x is not null))
{
var value = Value;
var newValue = value!.IsGenericTypeDefinition ? value : value.GetGenericTypeDefinition();
newValue = newValue.MakeGenericType(_genericArguments);
Value = newValue;
}
else
{
Value = _lastRecordededDefinition;
}
}
protected override void OnPaint()
{
}
}