Files
sbox-public/game/addons/tools/Code/Widgets/ControlWidgets/ResourceGeneratorControlWidget.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

157 lines
3.5 KiB
C#

using Sandbox.Resources;
namespace Editor;
/// <summary>
/// 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.
/// </summary>
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<Resource>() );
var prop = EditorTypeLibrary.CreateProperty<ResourceGenerator>( "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();
}
/// <summary>
/// We might want existing data from an embedded resource - in that case, deserialize it
/// </summary>
/// <param name="resource"></param>
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
}
/// <summary>
/// Create a ResourceGeneratorControlWidget for a specific generator
/// </summary>
internal static Widget Create( ResourceGenerator generator, SerializedProperty serializedProperty )
{
var allTypes = EditorTypeLibrary.GetTypes<ResourceGeneratorControlWidget>();
var editor = allTypes.OrderByDescending( x => Score( generator, x ) ).FirstOrDefault();
return editor.Create<Widget>( [generator, serializedProperty] );
}
/// <summary>
/// score a ResourceGeneratorControlWidget based on how well it matches the target ResourceGenerator
/// </summary>
private static int Score( ResourceGenerator target, TypeDescription targetEditor )
{
var editorTarget = targetEditor.GetAttribute<CanEditAttribute>()?.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;
}
}