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; } }