Editor/TrimmedAssetInspector.cs
using System;
using Editor.Assets;
using System.IO;
using System.Linq;
using System.Text.Json.Serialization;
using Editor;
using Editor.Inspectors;
using Sandbox;
using FileSystem = Sandbox.FileSystem;

namespace ResourceEmbed.Editor;

public class TrimmedAssetInspector : Widget
{
	const float HeaderHeight = 64 + 8 + 8;

	public Asset Asset { get; set; }
	public Asset[] Assets { get; set; }

	ToolBar ToolBar;

	Option SaveOption;
	Widget Scroller;
	Layout ContentLayout;

	public TrimmedAssetInspector( SerializedObject so )
	{
		Asset = so.Targets.Cast<Asset>().First();
		Assets = so.Targets.Cast<Asset>().ToArray();

		SetContext( "asset", Asset );
		SetContext( "path", Asset.AbsolutePath );
		SetContext( "filename", System.IO.Path.GetFileName( Asset.AbsolutePath ) );
		SetContext( "folder", System.IO.Path.GetDirectoryName( Asset.AbsolutePath ) ); 

		Layout = Layout.Column();
		SetSizeMode( SizeMode.CanGrow, SizeMode.CanGrow );
		
		ToolBar = new ToolBar( this );
		ToolBar.SetIconSize( 23 );
		ToolBar.MaximumSize = new Vector2( Width, 26 );
		ToolBar.Size = new Vector2( Width, 26 );

		var Splitter = new Splitter( this );
		Splitter.IsVertical = true;

		Layout.Add(ToolBar);
		
		Layout.Add( Splitter, 1 );
		
		var mainWidget = new Widget( this );
		mainWidget.Layout = Layout.Column();
		
		if ( !so.IsMultipleTargets )
		{
			ToolBar.AddOption( new Option( "Open In Editor", "edit", () => Asset.OpenInEditor() ) );
			ToolBar.AddOption( new Option( "Open Asset Location", "folder", () => EditorUtility.OpenFileFolder( Asset.AbsolutePath ) ) );
			ToolBar.AddSeparator();
		}
		ToolBar.AddOption( new Option( "Full Recompile", "restart_alt", () => Asset.Compile( true ) ) );

		Scroller = new Widget( this );
		Scroller.Layout = Layout.Column();
		mainWidget.Layout.Add( Scroller );
		
		RebuildUI();

		Scroller.Layout.AddStretchCell();

		Splitter.AddWidget( mainWidget );

		Enabled = true;
	}

	[EditorEvent.Hotload]
	public void RebuildUI()
	{
		CreateContentUI( Asset );
	}

	private void CreateContentLayout()
	{
		if ( !(ContentLayout?.IsValid ?? false) )
		{
			ContentLayout = Layout.Column();
			Scroller.Layout.Add( ContentLayout );
			Scroller.Layout.AddStretchCell();
		}
		else
		{
			ContentLayout?.Clear( true );
		}
	}
	
	private void CreateSaveOption( Action saveAction )
	{
		if ( !(SaveOption?.IsValid ?? false) )
		{
			var option = new Option( "Save", "save", saveAction );
			option.ShortcutName = "editor.save";
			option.Enabled = false;

			ToolBar.AddOption( option );
			SaveOption = option;
		}
	}

	private void CreateContentUI( Asset target )
	{
		CreateContentLayout();

		if ( target.TryLoadResource<GameResource>( out var assetObject ) )
		{
			Action saveAction = () => SaveAsset( target, assetObject );
			
			var sheet = new ControlSheet();

			var so = assetObject.GetSerialized();

			so.OnPropertyChanged += x =>
			{
				if ( SaveOption.IsValid ) SaveOption.Enabled = true;
			};

			if ( AssetSystem.IsCloudInstalled( target.Package ) )
			{
				// todo  so = so.AsReadOnly();
			}

			sheet.AddObject( so, filter: FilterProperties );
			ContentLayout.Add( sheet );
			ContentLayout.AddStretchCell();
			
			CreateSaveOption( saveAction );
		}

		ContentLayout.AddStretchCell();
		Scroller?.Update();
	}

	bool FilterProperties( SerializedProperty prop )
	{
		// only show stuff that'll actually be serialised
		if ( !prop.IsProperty ) return false;
		if ( prop.HasAttribute<JsonIgnoreAttribute>() ) return false;

		return prop.IsPublic || prop.HasAttribute<JsonIncludeAttribute>();
	}
	
	protected void Save()
	{
		if ( !SaveOption.IsValid() )
			return;

		if ( !SaveOption.Enabled )
			return;

		SaveOption.Triggered?.Invoke();
	}

	public void SaveAsset( Asset target, Sandbox.GameResource assetObject )
	{
		if ( target.SaveToDisk( assetObject ) )
		{
			SaveOption.Enabled = false;
		}
	}

	protected override void OnMouseRightClick( MouseEvent e )
	{
		if ( e.LocalPosition.y <= HeaderHeight )
		{
			var m = new ContextMenu();
			m.AddOption( "Copy Asset Name", "content_copy", () => EditorUtility.Clipboard.Copy( Asset.Name ) );
			m.AddOption( "Copy Path", "file_copy", () => EditorUtility.Clipboard.Copy( Asset.RelativePath ) );
			m.OpenAt( e.ScreenPosition );
		}
		
		base.OnMouseRightClick( e );
	}
}