Editor/WeaponImporter/Tool/UI/Widgets/NavList.cs
using Editor;
using Sandbox;

namespace WeaponImporter.Tool.UI;

/// <summary>
/// The editor's page list: one clickable row per page (icon, name, a status dot when something
/// needs attention). Rows are the controls; there are no separate buttons.
/// </summary>
public sealed class NavList : Widget
{
	public const float RowHeight = 34;

	private readonly List<(string Icon, string Title, string Tip)> _pages = new();
	private readonly Dictionary<int, Color?> _status = new();
	private int _hover = -1;

	public int Selected { get; private set; }
	public Action<int> OnSelected { get; set; }

	public NavList( Widget parent ) : base( parent )
	{
		MouseTracking = true;
		Cursor = CursorShape.Finger;
		FixedWidth = 176;
	}

	public void Add( string icon, string title, string tooltip )
	{
		_pages.Add( (icon, title, tooltip) );
		MinimumHeight = _pages.Count * RowHeight + 8;
		Update();
	}

	/// <summary>Dot beside a page: null hides it (all good), otherwise its colour (yellow, red).</summary>
	public void SetStatus( int page, Color? color )
	{
		if ( _status.TryGetValue( page, out var old ) && old == color )
			return;
		_status[page] = color;
		Update();
	}

	/// <summary>The dot colour of a page (null = none), for tests.</summary>
	public Color? StatusOf( int page ) => _status.TryGetValue( page, out var c ) ? c : null;

	public void Select( int page, bool notify = true )
	{
		page = Math.Clamp( page, 0, Math.Max( 0, _pages.Count - 1 ) );
		Selected = page;
		Update();
		if ( notify )
			OnSelected?.Invoke( page );
	}

	private int RowAt( float y ) => y < 4 ? -1 : (int)((y - 4) / RowHeight) is var i && i < _pages.Count ? i : -1;

	protected override void OnMouseMove( MouseEvent e )
	{
		var row = RowAt( e.LocalPosition.y );
		if ( row != _hover )
		{
			_hover = row;
			ToolTip = row >= 0 ? _pages[row].Tip : null;
			Update();
		}
	}

	protected override void OnMouseLeave()
	{
		_hover = -1;
		Update();
	}

	protected override void OnMousePress( MouseEvent e )
	{
		if ( !e.LeftMouseButton )
			return;
		var row = RowAt( e.LocalPosition.y );
		if ( row >= 0 )
			Select( row );
		e.Accepted = true;
	}

	protected override void OnPaint()
	{
		Paint.Antialiasing = true;
		for ( var i = 0; i < _pages.Count; i++ )
		{
			var (icon, title, _) = _pages[i];
			var rect = new Rect( 0, 4 + i * RowHeight, Width, RowHeight - 2 );
			var selected = i == Selected;
			if ( selected || i == _hover )
			{
				Paint.ClearPen();
				Paint.SetBrush( selected ? Theme.ControlBackground.Lighten( .35f ) : Theme.ControlBackground.Lighten( .15f ) );
				Paint.DrawRect( rect, 5 );
			}
			if ( selected )
			{
				Paint.ClearPen();
				Paint.SetBrush( Theme.Green );
				Paint.DrawRect( new Rect( rect.Left, rect.Top + 7, 3, rect.Height - 14 ), 1.5f );
			}
			Paint.SetPen( selected ? Theme.Green : Theme.TextLight );
			Paint.DrawIcon( new Rect( rect.Left + 12, rect.Top, 20, rect.Height ), icon, 16 );
			Paint.SetPen( selected ? Theme.Text : Theme.Text.WithAlpha( .8f ) );
			Paint.SetDefaultFont( 9, selected ? 600 : 400 );
			Paint.DrawText( new Rect( rect.Left + 40, rect.Top, rect.Width - 60, rect.Height ), title, TextFlag.LeftCenter );
			if ( _status.TryGetValue( i, out var status ) && status is { } dot )
			{
				Paint.ClearPen();
				Paint.SetBrush( dot );
				Paint.DrawRect( new Rect( rect.Right - 18, rect.Center.y - 4, 8, 8 ), 4 );
			}
		}
	}
}