Editor/ChitChat/CustomWidgets/DialogueListView.cs
using Editor;
using System.Collections.Generic;

using System;
using System.Linq;

public class DialogueListView<T> : ScrollArea
{
	public Action<T> itemSelected;

	private IEnumerable<T> _items;
	private List<Widget> _uiItems = new();

	private Func<T, Widget> _onCreateItemUI;

	private Widget _hovered;

	public DialogueListView(Widget parent, IEnumerable<T> items, Func<T, Widget> onCreateItemUI) : base(parent)
	{
		_items = items;

		if (onCreateItemUI != null)
			_onCreateItemUI = onCreateItemUI;
		else
		{
			Log.Error(nameof(DialogueListView<T>) + " requires an " + nameof(onCreateItemUI) + " function!");
			return;
		}

		MouseLeftPress += OnMouseLeftPress;
		Canvas = new Widget(parent);
		Canvas.Layout = Layout.Column();

		Draw();
	}

	private void Draw()
	{
		foreach (T item in _items)
		{
			Widget uiItem = _onCreateItemUI?.Invoke(item);
			uiItem.Parent = this;
			_uiItems.Add(uiItem);

			Canvas.Layout.Add(uiItem);
			Canvas.Layout.AddSeparator(8, Color.Transparent);
		}
	}

	private void OnMouseLeftPress()
	{
		UpdateHovered(out int itemIndex);
		Log.Info( itemIndex );

		if ( _hovered != null )
		{
			OnItemClicked(_items.ElementAt(itemIndex));
		}
	}

	public void Clear()
	{
		Layout.Clear(true);
		_uiItems.Clear();
	}

	public void Redraw()
	{
		Clear();
		Draw();
	}

	private void OnItemClicked(T item) => itemSelected?.Invoke(item);

	private void UpdateHovered(out int itemIndex)
	{
		Vector2 pos = FromScreen(Editor.Application.CursorPosition);
		if (_hovered == null || !_hovered.ContentRect.IsInside(in pos) || !_uiItems.Contains(_hovered))
		{
			_hovered = GetItemAt(pos, out itemIndex);
		}

		itemIndex = -1;
	}

	public Widget GetItemAt(Vector2 localPosition, out int index)
	{
		for (int i = 0; i < _uiItems.Count; i++)
		{
			if (_uiItems[i].ContentRect.IsInside(in localPosition))
			{
				index = i;
				return _uiItems[i];
			}
		}

		index = -1;
		return null;
	}
}