Editor/Widgets/SuiAnchorPicker.cs
using System;
using Editor;
using Sandbox;
using SboxUiDesigner.Runtime;

namespace SboxUiDesigner.EditorUi.Widgets;

/// <summary>
/// Visual anchor preset picker — 3×3 grid representing the 9 standard anchor
/// positions (TopLeft / TopCenter / TopRight / MiddleLeft / MiddleCenter /
/// MiddleRight / BottomLeft / BottomCenter / BottomRight). Replaces the
/// dropdown for the common case; stretch variants stay in the dropdown.
///
/// Click a cell → fire <see cref="AnchorSelected"/>. Currently selected cell
/// highlighted in accent blue.
/// </summary>
public sealed class SuiAnchorPicker : Widget
{
	private SuiAnchor _current;
	private Rect _hoverRect;

	public Action<SuiAnchor> AnchorSelected;

	public SuiAnchorPicker( Widget parent ) : base( parent )
	{
		FixedSize = new Vector2( 78, 78 );
		MouseTracking = true;
		Cursor = CursorShape.Finger;
	}

	public void SetCurrent( SuiAnchor a )
	{
		_current = a;
		Update();
	}

	protected override void OnPaint()
	{
		var rect = LocalRect;
		var cellSize = (rect.Width - 8) / 3f;

		var darkSquare = new Color( 70 / 255f, 72 / 255f, 78 / 255f );
		var blueSquare = new Color( 0f, 0.55f, 1.0f );
		var selectedBg = new Color( 0f, 0.55f, 1.0f, 0.18f );
		var hoverBg = new Color( 1f, 1f, 1f, 0.06f );
		var selectedOutline = new Color( 0f, 0.55f, 1.0f );

		for ( int cellRow = 0; cellRow < 3; cellRow++ )
		{
			for ( int cellCol = 0; cellCol < 3; cellCol++ )
			{
				var cellRect = CellRect( cellRow, cellCol, cellSize );
				var anchor = AnchorAt( cellRow, cellCol );
				var isCurrent = _current == anchor;
				var isHover = _hoverRect == cellRect;

				// Cell background — selected cell gets a soft blue tint +
				// a 1px blue outline; hover gets a faint white tint.
				if ( isCurrent )
				{
					Paint.SetBrush( selectedBg );
					Paint.SetPen( selectedOutline, 1f );
					Paint.DrawRect( cellRect, 3f );
				}
				else if ( isHover )
				{
					Paint.SetBrushAndPen( hoverBg );
					Paint.DrawRect( cellRect, 3f );
				}

				// Mini 3×3 grid inside this cell. The mini-square at
				// position (cellRow, cellCol) is blue — its position within
				// the mini grid mirrors the cell's position in the outer
				// grid, so the icon visually says "this is the X anchor".
				const float pad = 4f;
				const float gap = 1f;
				var miniSize = (cellRect.Width - pad * 2 - gap * 2) / 3f;

				for ( int mr = 0; mr < 3; mr++ )
				{
					for ( int mc = 0; mc < 3; mc++ )
					{
						var miniRect = new Rect(
							cellRect.Left + pad + mc * (miniSize + gap),
							cellRect.Top + pad + mr * (miniSize + gap),
							miniSize, miniSize );

						bool isAnchorIndicator = (mr == cellRow && mc == cellCol);
						Paint.SetBrush( isAnchorIndicator ? blueSquare : darkSquare );
						Paint.ClearPen();
						Paint.DrawRect( miniRect, 1f );
					}
				}
			}
		}
	}

	private Rect CellRect( int row, int col, float cellSize )
	{
		var x = LocalRect.Left + 2 + col * (cellSize + 2);
		var y = LocalRect.Top + 2 + row * (cellSize + 2);
		return new Rect( x, y, cellSize, cellSize );
	}

	private static SuiAnchor AnchorAt( int row, int col )
	{
		return (row, col) switch
		{
			(0, 0) => SuiAnchor.TopLeft,
			(0, 1) => SuiAnchor.TopCenter,
			(0, 2) => SuiAnchor.TopRight,
			(1, 0) => SuiAnchor.MiddleLeft,
			(1, 1) => SuiAnchor.MiddleCenter,
			(1, 2) => SuiAnchor.MiddleRight,
			(2, 0) => SuiAnchor.BottomLeft,
			(2, 1) => SuiAnchor.BottomCenter,
			(2, 2) => SuiAnchor.BottomRight,
			_ => SuiAnchor.TopLeft,
		};
	}

	protected override void OnMouseMove( MouseEvent e )
	{
		var cellSize = (LocalRect.Width - 8) / 3f;
		Rect newHover = default;
		for ( int row = 0; row < 3; row++ )
		{
			for ( int col = 0; col < 3; col++ )
			{
				var cellRect = CellRect( row, col, cellSize );
				if ( PointInside( cellRect, e.LocalPosition ) ) { newHover = cellRect; break; }
			}
		}
		if ( newHover != _hoverRect )
		{
			_hoverRect = newHover;
			Update();
		}
	}

	protected override void OnMouseLeave()
	{
		base.OnMouseLeave();
		_hoverRect = default;
		Update();
	}

	protected override void OnMousePress( MouseEvent e )
	{
		if ( !e.LeftMouseButton ) return;
		var cellSize = (LocalRect.Width - 8) / 3f;
		for ( int row = 0; row < 3; row++ )
		{
			for ( int col = 0; col < 3; col++ )
			{
				var cellRect = CellRect( row, col, cellSize );
				if ( PointInside( cellRect, e.LocalPosition ) )
				{
					var picked = AnchorAt( row, col );
					_current = picked;
					AnchorSelected?.Invoke( picked );
					Update();
					return;
				}
			}
		}
	}

	private static bool PointInside( Rect r, Vector2 p )
		=> p.x >= r.Left && p.x <= r.Right && p.y >= r.Top && p.y <= r.Bottom;
}