Editor/Tileset/TilesetTools/TilesetToolInspector.cs
using Editor;
using Sandbox;
using System;
using System.Linq;
using System.Reflection;

namespace SpriteTools.TilesetTool;

[Inspector( typeof( TilesetTool ) )]
public class TilesetToolInspector : InspectorWidget
{
	public static TilesetToolInspector Active { get; private set; }
	internal TilesetTool Tool;
	StatusWidget Header;

	ScrollArea scrollArea;
	ControlSheet toolSheet;
	ControlSheet mainSheet;
	ControlSheet selectedSheet;

	public TilesetToolInspector ( SerializedObject so ) : base( so )
	{
		if ( so.Targets.FirstOrDefault() is not TilesetTool tool ) return;

		Tool = tool;
		// Tool.UpdateInspector += UpdateHeader;
		// Tool.UpdateInspector += UpdateSelectedSheet;

		Layout = Layout.Column();
		Layout.Margin = 4;
		Layout.Spacing = 8;

		Active = this;
		Rebuild();
	}

	int lastBuildHash = 0;
	[EditorEvent.Frame]
	void Frame ()
	{
		int buildHash = 0;
		if ( Tool.SelectedComponent.IsValid() )
		{
			buildHash += Tool.SelectedComponent.Layers.IndexOf( Tool?.SelectedLayer );
			buildHash += Tool?.SelectedLayer?.TilesetResource?.ResourceId ?? 0;
		}
		if ( buildHash != lastBuildHash )
		{
			lastBuildHash = buildHash;
			Rebuild();
		}
	}

	[EditorEvent.Hotload]
	void Rebuild ()
	{
		if ( Layout is null ) return;
		Layout.Clear( true );

		scrollArea = new ScrollArea( this );
		scrollArea.Canvas = new Widget();
		scrollArea.Canvas.Layout = Layout.Column();
		scrollArea.Canvas.VerticalSizeMode = SizeMode.CanGrow;
		scrollArea.Canvas.HorizontalSizeMode = SizeMode.Flexible;
		scrollArea.Canvas.Layout.Spacing = 8;
		Layout.Add( scrollArea );

		Header = new StatusWidget( this );
		scrollArea.Canvas.Layout.Add( Header );
		UpdateHeader();

		mainSheet = new ControlSheet();
		scrollArea.Canvas.Layout.Add( mainSheet );
		UpdateMainSheet();

		selectedSheet = null;
		UpdateSelectedSheet();

		toolSheet = new ControlSheet();
		scrollArea.Canvas.Layout.Add( toolSheet );
		UpdateToolSheet();

		// Preview = new Preview.Preview(this);
		// scrollArea.Canvas.Layout.Add(Preview);

		scrollArea.Canvas.Layout.AddStretchCell();

	}

	internal void UpdateHeader ()
	{
		Header.Text = "Paint Tiles";
		Header.Color = ( false ) ? Theme.Red : Theme.Blue;
		Header.Icon = ( false ) ? "warning" : "dashboard";
		Header.Update();
	}

	internal void UpdateToolSheet ()
	{
		if ( !( Layout?.IsValid ?? false ) ) return;
		if ( toolSheet is null ) return;

		toolSheet?.Clear( true );

		if ( Tool?.Settings is not null )
		{
			toolSheet.AddObject( Tool.Settings.GetSerialized(), x =>
			{
				return x.HasAttribute<PropertyAttribute>() && x.PropertyType != typeof( Action );
			} );
		}
	}

	internal void UpdateMainSheet ()
	{
		if ( !( Layout?.IsValid ?? false ) ) return;
		if ( mainSheet is null ) return;

		mainSheet?.Clear( true );

		if ( Tool?.CurrentTool is not null )
		{
			var toolName = ( Tool.CurrentTool.GetType()?.GetCustomAttribute<TitleAttribute>()?.Value ?? "Unknown" ) + " Tool";
			mainSheet.AddObject( Tool.CurrentTool.GetSerialized(), x => x.HasAttribute<PropertyAttribute>() && x.PropertyType != typeof( Action ) );
		}
		if ( Tool.SelectedComponent.IsValid() )
		{
			mainSheet.AddObject( Tool.SelectedComponent.GetSerialized(), x =>
			{
				if ( x.Name == nameof( TilesetComponent.Layers ) ) return true;
				if ( !x.HasAttribute<PropertyAttribute>() ) return false;
				if ( x.TryGetAttribute<FeatureAttribute>( out var feature ) && feature.Title == "Collision" ) return false;
				if ( x.PropertyType == typeof( Action ) ) return false;
				if ( x.PropertyType == typeof( TilesetComponent.ComponentControls ) ) return false;

				return true;
			} );
		}
	}

	internal void UpdateSelectedSheet ()
	{
		if ( !( Layout?.IsValid ?? false ) ) return;

		if ( selectedSheet is null || !( selectedSheet?.IsValid ?? false ) )
		{
			selectedSheet = new ControlSheet();
			scrollArea.Canvas.Layout.Add( selectedSheet );
		}

		selectedSheet?.Clear( true );
		if ( Tool.SelectedLayer is not null )
		{
			selectedSheet.AddObject( Tool.SelectedLayer.GetSerialized(), x => x.HasAttribute<PropertyAttribute>() && x.PropertyType != typeof( Action ) );
		}
	}

	private class StatusWidget : Widget
	{
		public string Icon { get; set; }
		public string Text { get; set; }
		public string LeadText { get; set; }
		public Color Color { get; set; }

		TilesetToolInspector Inspector;

		public StatusWidget ( TilesetToolInspector parent ) : base( parent )
		{
			Inspector = parent;
			MinimumSize = 48;
			Cursor = CursorShape.Finger;
			SetSizeMode( SizeMode.Default, SizeMode.CanShrink );
		}

		protected override void OnPaint ()
		{
			var rect = new Rect( 0, Size );

			Paint.ClearPen();
			Paint.SetBrush( Theme.WindowBackground.Lighten( 0.9f ) );
			Paint.DrawRect( rect );

			rect.Left += 8;

			Paint.SetPen( Color );
			var iconRect = Paint.DrawIcon( rect, Icon, 24, TextFlag.LeftCenter );

			rect.Top += 8;
			rect.Left = iconRect.Right + 8;

			Paint.SetPen( Color );
			Paint.SetDefaultFont( 10, 500 );
			var titleRect = Paint.DrawText( rect, Text, TextFlag.LeftTop );

			rect.Top = titleRect.Bottom + 2;

			Paint.SetPen( Color.WithAlpha( 0.6f ) );
			Paint.SetDefaultFont( 8, 400 );
			var preText = "Selected Component:";
			if ( !Inspector.Tool.SelectedComponent.IsValid() )
				preText = "No Tileset Component";
			var selectedRect = Paint.DrawText( rect, preText, TextFlag.LeftTop );
			if ( Inspector.Tool.SelectedComponent.IsValid() )
			{
				var name = Inspector.Tool.SelectedComponent.GameObject.Name;
				var textPos = selectedRect.TopRight + new Vector2( 8, 0 );
				var textRect = new Rect( textPos, Paint.MeasureText( name ) );
				var boxRect = textRect.Grow( 4, 2, 18, 2 );
				var isHovering = Paint.HasMouseOver;
				var boxCol = isHovering ? Theme.ControlBackground.Lighten( 0.3f ) : Theme.ControlBackground.Darken( 0.2f );
				var color = isHovering ? Color.Lighten( 0.2f ) : Color;
				Paint.SetBrushAndPen( boxCol, Color.Transparent );
				Paint.DrawRect( boxRect );
				Paint.SetPen( color );
				var drawnRect = Paint.DrawText( textPos, name );
				var iconPos = drawnRect.TopRight + new Vector2( 2, 0 );
				Paint.DrawIcon( Rect.FromPoints( iconPos, iconPos + 14 ), "expand_more", 14 );

			}
		}

		protected override void OnMouseClick ( MouseEvent e )
		{
			base.OnMouseClick( e );

			var components = SceneEditorSession.Active.Scene.GetAllComponents<TilesetComponent>();
			Log.Info( components.Count() );
			if ( components.Count() == 0 ) return;

			var menu = new Menu();

			foreach ( var tileset in components )
			{
				var option = menu.AddOption( tileset.GameObject.Name, null, () =>
				{
					Inspector.Tool.SelectedComponent = tileset;
					Inspector.Tool.SelectedLayer = tileset.Layers.FirstOrDefault();
				} );
				option.Checkable = true;
				option.Checked = tileset == Inspector.Tool.SelectedComponent;
			}

			menu.OpenAtCursor();
		}
	}
}