Editor/BehaviorTreeVisualizer/BehaviorTreeNode.cs
using System;
using System.Linq;
using System.Text;
using Editor;
using NPBehave;
using Sandbox.Utils;

namespace Sandbox.BehaviorTreeVisualizer;

public class BehaviorTreeNode : TreeNode<Node>
{
	private Color _nodeColor;
	
	Color NodeColor
	{
		get => _nodeColor;
		set
		{
			if( _nodeColor == value )
				return;
			_nodeColor = value;
			Dirty();
		}
	}

	public BehaviorTreeNode( Node dir ) : base( dir )
	{
		Height = 40;
	}

	protected override void BuildChildren()
	{
		Clear();
		
		if ( Value is Container container )
		{
			foreach ( var child in container.DebugChildren )
			{
				AddItem( CreateChildFor( child ) );
			}
		}
	}

	protected virtual TreeNode CreateChildFor( Node child ) => new BehaviorTreeNode( child );


	public override void OnSelectionChanged( bool state )
	{
		if ( state )
		{
			TreeView?.Toggle( this );
		}
		base.OnSelectionChanged( state );
	}

	public override bool OnContextMenu()
	{
		var m = new Editor.Menu( TreeView );
		if ( Value.CurrentState == Node.State.Active )
		{
			m.AddOption( "Stop", action: () =>
			{
				Value.Stop();
			} );
		}
		else if(Value is Root root && Value.CurrentState == Node.State.Inactive )
		{
			m.AddOption( "Start", action: () => root.Start() );
		}
		
		m.OpenAtCursor( false );
		return true;
	}

	public override int GetHashCode()
	{
		return HashCode.Combine(Value.GetHashCode(), Value.CurrentState, Value.IsActive, Value.Name, Value.ComputedLabel) ;
	}

	public override int ValueHash => GetHashCode();

	protected override void Think()
	{
		Color newColor = Theme.Black;

		if ( Value.IsActive )
		{
			newColor = Theme.Green;
		}
		
		else if ( Value.DebugLastSuccessAt < 0.5f )
		{
			newColor = Theme.Green;
		}
		else if ( Value.DebugLastFailureAt < 0.5f )
		{
			newColor = Theme.Red;
		}
		
		NodeColor = newColor;
			
		
		base.Think();
	}

	protected override void RebuildOnDirty()
	{
		TreeView?.Update();
		if(Value is Container container && container.DebugChildren.Length != Children.Count() )
		{
			BuildChildren();
		}
		//base.RebuildOnDirty();
	}

	protected override void OnHashChanged()
	{
		Dirty();
		if(Value is Container container && container.DebugChildren.Length != Children.Count() )
		{
			BuildChildren();
		}
	}

	public override void OnPaint( VirtualWidget item )
	{
		var open = item.IsOpen;
		
		var backgroundRect = item.Rect;
		backgroundRect.Bottom -= 1;
		
		if ( item.Selected )
		{
			Paint.SetPen( Theme.Primary.WithAlpha( 0.9f ) );
			Paint.SetBrush( NodeColor.WithAlpha( 0.6f ) );
			Paint.DrawRect( backgroundRect.Shrink( 2 ) );
		}
		else if ( item.Hovered )
		{
			Paint.SetPen( Theme.Primary.WithAlpha( 0.9f ) );
			Paint.SetBrush( NodeColor.WithAlpha( 0.7f ) );
			Paint.DrawRect( backgroundRect.Shrink( 1 ) );
		}
		else
		{
			Paint.ClearPen();
			Paint.SetBrush( NodeColor.WithAlpha( 0.7f ) );
			Paint.DrawRect( backgroundRect );
		}
		
		var rect = backgroundRect.Shrink( 8 );

		if ( !string.IsNullOrWhiteSpace( Value.DebugIcon ) )
		{
			Paint.SetPen( Theme.Yellow.WithAlphaMultiplied( 1.0f) );
			var i = Paint.DrawIcon( rect, Value.DebugIcon, 22, TextFlag.LeftCenter );
			rect.Left = i.Right + 8;
		}


		Paint.SetPen( Theme.White.WithAlpha(1.0f));
		Paint.SetFont( "Poppins", 12, 450 );

		StringBuilder text = new StringBuilder();

		if ( !string.IsNullOrWhiteSpace( Value.Label ) )
		{
			text.Append( $" {Value.Label}" );
		}
		if( !string.IsNullOrWhiteSpace( Value.ComputedLabel ) )
		{
			text.Append( $" {Value.ComputedLabel}" );
		}
		if ( text.Length == 0 )
		{
			text.Append( Value.Name.AddSpacesToSentence( ) );
		}
		else
		{
			text.Append( $" ({Value.Name.AddSpacesToSentence( )})" );
		}
		
		
		var textRect = Paint.DrawText( rect, text.ToString(), TextFlag.LeftCenter );
	}
}