using Sandbox.Resources;
namespace Editor;
///
/// A control widget that shows a ResourceGenerator. This will either be a dropdown which
/// will pop up the config editor for the generator, or will be an inline editor with the
/// key properties, with an edit button on the side.
///
public class ResourceGeneratorControlWidget : ControlWidget
{
GenericControlWidget Editor { get; set; }
protected ResourceGenerator Generator { get; set; }
bool _isDirty = false;
bool _isGenerating = false;
public ResourceGeneratorControlWidget( ResourceGenerator generator, SerializedProperty property ) : base( property )
{
Layout = Layout.Row();
Layout.Spacing = 2;
MouseTracking = true;
AcceptDrops = true;
IsDraggable = true;
var generatorObject = generator.GetSerialized();
Generator = generator;
LoadFromResource( property.GetValue() );
var prop = EditorTypeLibrary.CreateProperty( "Generator", generatorObject );
Editor = new GenericControlWidget( prop );
generatorObject.OnPropertyChanged = x => MakeDirty();
BuildContent();
_ = UpdateGenerator();
}
protected virtual void BuildContent()
{
var col = Layout.AddColumn();
col.Add( Editor );
col.AddStretchCell();
Layout.AddStretchCell();
}
///
/// We might want existing data from an embedded resource - in that case, deserialize it
///
///
void LoadFromResource( Resource resource )
{
var embeddedResource = resource?.EmbeddedResource;
if ( embeddedResource is null )
{
return;
}
// Not a matching compiler
if ( embeddedResource.Value.ResourceGenerator != EditorTypeLibrary.GetType( Generator.GetType() ).ClassName )
{
return;
}
Generator.Deserialize( embeddedResource.Value.Data );
}
void MakeDirty()
{
_isDirty = true;
}
async Task UpdateGenerator()
{
_isGenerating = true;
try
{
var resource = await Generator.FindOrCreateObjectAsync( ResourceGenerator.Options.Default, default );
SerializedProperty.SetValue( resource );
OnResourceChanged( resource );
Update();
}
finally
{
_isGenerating = false;
}
}
protected virtual void OnResourceChanged( Resource resource )
{
}
[EditorEvent.Frame]
public void FrameUpdate()
{
if ( _isGenerating ) return;
if ( !_isDirty ) return;
if ( Generator is not null )
{
_isDirty = false;
_ = UpdateGenerator();
}
}
protected override void PaintUnder()
{
// nothing
}
///
/// Create a ResourceGeneratorControlWidget for a specific generator
///
internal static Widget Create( ResourceGenerator generator, SerializedProperty serializedProperty )
{
var allTypes = EditorTypeLibrary.GetTypes();
var editor = allTypes.OrderByDescending( x => Score( generator, x ) ).FirstOrDefault();
return editor.Create( [generator, serializedProperty] );
}
///
/// score a ResourceGeneratorControlWidget based on how well it matches the target ResourceGenerator
///
private static int Score( ResourceGenerator target, TypeDescription targetEditor )
{
var editorTarget = targetEditor.GetAttribute()?.Type;
//
// Target editor doesn't have a CanEdit
//
if ( editorTarget == null ) return 100;
int score = 1000;
var targetType = target.GetType();
while ( targetType != null )
{
if ( editorTarget.IsAssignableFrom( targetType ) )
{
return score;
}
score -= 100;
targetType = targetType.BaseType;
}
return 0;
}
}