Editor/ShaderGraphPlus/Widgets/ControlWidgets/DropdownControlWidgetPlus.cs
using Editor;

namespace ShaderGraphPlus;

/// <summary>
/// Abstract class to enable easily creating ControlWidgets with dropdowns.
/// </summary>
public abstract class DropdownControlWidgetPlus<T> : ControlWidget
{
	public override bool SupportsMultiEdit => true;

	public DropdownControlWidgetPlus( SerializedProperty property ) : base( property )
	{
		Layout = Layout.Row();
		Cursor = CursorShape.Finger;
	}

	public struct Entry
	{
		public T Value { get; set; }
		public string Label { get; set; }
		public string Icon { get; set; }
		public string Description { get; set; }
	}

	protected abstract IEnumerable<object> GetDropdownValues();

	protected override void PaintControl()
	{
		var value = SerializedProperty.GetValue<object>();
		var color = IsControlHovered ? Theme.Blue : Theme.TextControl;
		var rect = LocalRect;

		rect = rect.Shrink( 8, 0 );

		//var e = enumDesc.GetEntry( value );

		//if ( !string.IsNullOrEmpty( e.Icon ) )
		//{
		//	Paint.SetPen( color.WithAlpha( 0.5f ) );
		//	var i = Paint.DrawIcon( rect, e.Icon, 16, TextFlag.LeftCenter );
		//	rect.Left += i.Width + 8;
		//}

		Paint.SetPen( color );
		Paint.SetDefaultFont();

		if ( SerializedProperty.IsMultipleDifferentValues )
		{
			Paint.SetPen( Theme.MultipleValues );
			Paint.DrawText( rect, "Multiple Values", TextFlag.LeftCenter );
		}
		else
		{
			Paint.DrawText( rect, value?.ToString() ?? "None", TextFlag.LeftCenter );
		}

		Paint.SetPen( color );
		Paint.DrawIcon( rect, "Arrow_Drop_Down", 17, TextFlag.RightCenter );
	}

	PopupWidget _menu;

	public override void StartEditing()
	{
		if ( !_menu.IsValid )
		{
			OpenMenu();
		}
	}

	protected virtual void OnSelectItem( object item )
	{
		if ( item is Entry e )
		{
			SerializedProperty.SetValue( e.Value );
		}
		else
		{
			SerializedProperty.SetValue( item );
		}
	}

	protected override void OnMouseClick( MouseEvent e )
	{
		if ( e.LeftMouseButton && !_menu.IsValid() )
		{
			OpenMenu();
		}
	}

	protected override void OnDoubleClick( MouseEvent e )
	{
		// nothing
	}

	void OpenMenu()
	{
		_menu = new PopupWidget( null );

		_menu.Layout = Layout.Column();
		_menu.Width = ScreenRect.Width;

		var scroller = _menu.Layout.Add( new ScrollArea( this ), 1 );
		scroller.Canvas = new Widget( scroller )
		{
			Layout = Layout.Column(),
			VerticalSizeMode = SizeMode.CanGrow | SizeMode.Expand
		};

		object[] entries = GetDropdownValues().ToArray();

		foreach ( var o in entries )
		{
			var b = scroller.Canvas.Layout.Add( new MenuOption<T>( o, SerializedProperty ) );
			b.MouseLeftPress = () =>
			{
				OnSelectItem( o );

				_menu.Update();
				_menu.Close();
			};
		}

		_menu.Position = ScreenRect.BottomLeft;
		_menu.Visible = true;
		_menu.AdjustSize();
		_menu.ConstrainToScreen();
		_menu.OnPaintOverride = PaintMenuBackground;
	}

	bool PaintMenuBackground()
	{
		Paint.SetBrushAndPen( Theme.ControlBackground );
		Paint.DrawRect( Paint.LocalRect, 0 );
		return true;
	}

}

file class MenuOption<T> : Widget
{
	object info;
	SerializedProperty property;

	public MenuOption( object e, SerializedProperty p ) : base( null )
	{
		info = e;
		property = p;

		Layout = Layout.Row();
		Layout.Margin = 8;

		if ( e is DropdownControlWidget<T>.Entry entry )
		{
			if ( !string.IsNullOrWhiteSpace( entry.Icon ) )
			{
				Layout.Add( new IconButton( entry.Icon ) { Background = Color.Transparent, TransparentForMouseEvents = true, IconSize = 18 } );
			}

			Layout.AddSpacingCell( 8 );
			var c = Layout.AddColumn();
			var title = c.Add( new Label( entry.Label ) );
			title.SetStyles( "font-size: 12px; font-weight: bold; font-family: Poppins; color: white;" );

			if ( !string.IsNullOrWhiteSpace( entry.Description ) )
			{
				var desc = c.Add( new Label( entry.Description.Trim( '\n', '\r', '\t', ' ' ) ) );
				desc.WordWrap = true;
				desc.MinimumHeight = 1;
				desc.MinimumWidth = 400;
			}
		}
		else
		{
			Layout.AddSpacingCell( 8 );
			var c = Layout.AddColumn();

			var labelString = "";

			if ( e is DropdownControlWidgetPlus<T>.Entry entryObject )
			{
				labelString = entryObject.Label;
			}
			else
			{
				labelString = e.ToString();
			}

			var title = c.Add( new Label( labelString ) );
			title.SetStyles( "font-size: 12px; font-weight: bold; font-family: Poppins; color: white;" );
		}
	}

	bool HasValue()
	{
		if ( property.IsMultipleDifferentValues ) return false;

		var value = property.GetValue<object>( default );
		return value == info;
	}

	protected override void OnPaint()
	{
		if ( Paint.HasMouseOver || HasValue() )
		{
			Paint.SetBrushAndPen( Theme.Blue.WithAlpha( HasValue() ? 0.3f : 0.1f ) );
			Paint.DrawRect( LocalRect.Shrink( 2 ), 2 );
		}
	}
}