Editor/PathTool.UI.cs
namespace PathTool.Editor;

[CanEdit( typeof( PathTool ) )]
public partial class PathToolInspector : InspectorWidget
{
	public PathToolInspector( SerializedObject so ) : base( so )
	{
		if ( so.Targets.FirstOrDefault() is not PathTool tool )
			return;

		Layout = Layout.Column();
		Layout.Add( tool.BuildUI() );
	}
}
public partial class PathTool
{
	private StatusWidget Header { get; set; }
	private Layout ControlLayout { get; set; }

	public Widget BuildUI()
	{
		var widget = new Widget( null );
		widget.Layout = Layout.Column();
		widget.Layout.Margin = 4;

		Header = new StatusWidget( widget );
		UpdateStatus();
		widget.Layout.Add( Header );
		widget.Layout.AddSpacingCell( 8 );

		{
			var layout = widget.Layout.AddRow();
			layout.Spacing = 4;

			var pathTypeComboBox = new ComboBox();
			pathTypeComboBox.MinimumHeight = 40f;
			foreach ( var type in GetPathTypes() )
			{
				var displayInfo = DisplayInfo.ForType( type.TargetType );
				if ( !displayInfo.Browsable ) continue;

				pathTypeComboBox.AddItem( displayInfo.Name, displayInfo.Icon ?? "square", () => SelectPathType(type) );
			}

			layout.Add( pathTypeComboBox, 1 );
		}

		widget.Layout.AddSpacingCell( 8 );

		ControlLayout = widget.Layout.AddColumn();
		BuildControlSheet();

		widget.Layout.AddSpacingCell( 8 );
		widget.Layout.AddStretchCell();

		return widget;
	}
	public void OnEdited( SerializedProperty property )
	{
		
	}
	private void SelectPathType(TypeDescription t)
	{
		var target = t.TargetType;
		if ( !target.IsAssignableTo( typeof( Path ) ) )
		{
			Log.Warning( $"Type {t} isnt a path!" );
			return;
		}

		pathType = target;
		if(t.IsGenericType)
		{
			nodeType = target.GetGenericArguments()[0];
		}
		else
		{
			nodeType = typeof( PathNode );
		}

		var nodes = path?.Nodes ?? new List<PathNode>();
		path = EditorTypeLibrary.Create<Path>( pathType );
		path.Nodes = nodes;
	}

	private void BuildControlSheet()
	{
		if ( !ControlLayout.IsValid() )
			return;

		ControlLayout.Clear( true );

		var props = path.GetSerialized().Where( ShowPathProperty );

		if(props.Any())
		{
			var pathHeader = new Label( "Properties" )
			{
				Margin = 2f
			};
			var pathSheet = new ControlSheet();

			foreach(var prop in props)
			{
				pathSheet.AddRow( prop );
			}

			ControlLayout.Add( pathHeader );
			ControlLayout.Add( pathSheet );
		}

		if ( selectedNode != null )
		{
			var selectedHeader = new Label( "Selected Node" )
			{
				Margin = 2f
			};

			var so = selectedNode.GetSerialized();
			so.OnPropertyChanged += OnEdited;

			var selectedSheet = new ControlSheet();
			selectedSheet.AddObject( so );

			ControlLayout.Add( selectedHeader );
			ControlLayout.Add( selectedSheet );
		}
	}

	private static readonly string[] ignoredProperties = new string[] { "Enabled", "Nodes" };
	private bool ShowPathProperty(SerializedProperty prop)
	{
		if ( !EditorTypeLibrary.TryGetType( prop.PropertyType, out var type ) )
			return false;

		var description = EditorTypeLibrary.GetType( prop.Parent.TypeName ).GetProperty( prop.Name );
		if ( description == null ) return false;

		bool show = prop.IsEditable && description.IsGetMethodPublic && description.IsSetMethodPublic && 
										!ignoredProperties.Contains(prop.Name);
		if(show)
		{
			Log.Info($"Prop: {prop.Name} ({type})");
		}

		return show;
	}

	private void UpdateStatus()
	{
		Header.Text = $"{(InProgress ? "Placing" : "Create")} Path";
		Header.LeadText = InProgress ? "Place nodes to create a path." : "Press Enter to complete the path.";
		Header.Color = InProgress ? Theme.Blue : Theme.Green;
		Header.Icon = InProgress ? "check_circle_outline" : "view_in_ar";
		Header.Update();
	}

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

		public StatusWidget( Widget parent ) : base( parent )
		{
			MinimumSize = 48;
			SetSizeMode( SizeMode.Default, SizeMode.CanShrink );
		}

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

			Paint.ClearPen();
			Paint.SetBrush( Theme.Black.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 );
			Paint.DrawText( rect, LeadText, TextFlag.LeftTop );
		}
	}
}