Editor/LineMaterialPicker.cs
using System;
using System.Linq;
using Editor;
using Editor.TerrainEditor;
using Sandbox;

namespace TerrainLines;

internal sealed class LineMaterialPicker : TerrainMaterialList
{
	private const string None = "None";
	private readonly Terrain _terrain;
	private readonly bool _allowNone;
	private readonly Func<int> _selected;
	private TerrainMaterial[] _materials = [];
	private int _lastSelection = int.MinValue;

	internal LineMaterialPicker( Widget parent, Terrain terrain, bool allowNone, Func<int> selected, Action<int> select ) : base( parent, terrain )
	{
		_terrain = terrain;
		_allowNone = allowNone;
		_selected = selected;
		FixedHeight = 180;
		AcceptDrops = false;
		ItemContextMenu = null;
		ItemSelected = value => select( value is TerrainMaterial material ? terrain.Storage.Materials.IndexOf( material ) : -1 );
		Refresh();
	}

	// This is a picker; asset management and material reordering stay in the terrain inspector.
	protected override bool OnDragItem( VirtualWidget item ) => false;

	internal void Refresh()
	{
		if ( !_terrain.IsValid() || _terrain.Storage is null ) return;
		var materials = _terrain.Storage.Materials.Take( 32 ).ToArray();
		if ( !_materials.SequenceEqual( materials ) || _lastSelection == int.MinValue )
		{
			_materials = materials;
			SetItems( _allowNone ? new object[] { None }.Concat( materials.Cast<object>() ) : materials.Cast<object>() );
			_lastSelection = int.MinValue;
		}
		int index = _selected();
		if ( index == _lastSelection ) return;
		_lastSelection = index;
		if ( index >= 0 && index < _materials.Length ) SelectItem( _materials[index] );
		else if ( _allowNone ) SelectItem( None );
	}

	protected override string GetTooltip( object item ) => item is TerrainMaterial material ? material.ResourceName : None;

	protected override void PaintItem( VirtualWidget item )
	{
		if ( item.Object is not string ) { base.PaintItem( item ); return; }
		Paint.ClearPen();
		Paint.SetBrush( item.Selected ? Theme.Blue.WithAlpha( 0.5f ) : Theme.ControlBackground );
		Paint.DrawRect( item.Rect, 4 );
		Paint.SetPen( Theme.Text );
		Paint.SetDefaultFont();
		Paint.DrawText( item.Rect, None, TextFlag.Center );
	}
}