Editor/Tileset/TilesetEditor/Autotile/AutotileBrushListControl.cs
using Sandbox;
using Editor;
using System.Collections.Generic;
using System.Linq;
using System;

namespace SpriteTools.TilesetEditor;


[CustomEditor(typeof(List<AutotileBrush>))]
public class AutotileBrushListControl : ControlWidget
{
    public override bool SupportsMultiEdit => false;
    public override bool IncludeLabel => false;

    internal MainWindow MainWindow;

    internal AutotileBrushControl SelectedBrush;
    internal AutotileBrush.Tile SelectedTile;
    internal List<AutotileBrushControl> Buttons = new();

    internal Layout content;
    ScrollArea scrollArea;
    Button btnNewBrush;
    TilesetResource lastInheritedFrom;

    KeyboardModifiers modifiers;

    public AutotileBrushListControl(SerializedProperty property) : base(property)
    {
        Layout = Layout.Column();
        Layout.Spacing = 8;

        if (property.IsNull)
        {
            property.SetValue(new List<AutotileBrush>());
        }

        scrollArea = new ScrollArea(this);
        scrollArea.Canvas = new Widget();
        scrollArea.Canvas.Layout = Layout.Column();
        scrollArea.Canvas.VerticalSizeMode = SizeMode.CanShrink;
        scrollArea.Canvas.HorizontalSizeMode = SizeMode.CanGrow;
        scrollArea.MinimumHeight = 300;
        scrollArea.MaximumHeight = 300;
        scrollArea.FixedHeight = 300;
        Layout.Add(scrollArea);

        // Content list
        content = Layout.Column();
        content.Margin = 4;
        content.AddStretchCell();
        scrollArea.Canvas.Layout.Add(content);

        // Buttons
        var row = Layout.AddRow();
        row.AddStretchCell();
        row.Spacing = 8;
        btnNewBrush = row.Add(new Button.Primary("New Autotile Brush", "add"));
        btnNewBrush.ToolTip = "Create a new autotile brush";
        btnNewBrush.Clicked += NewBrushPopup;

        scrollArea.Canvas.Layout.AddStretchCell();

        SetSizeMode(SizeMode.Default, SizeMode.CanShrink);

        UpdateList();
    }

    protected override void OnPaint()
    {
        if (MainWindow is null)
        {
            foreach (var window in MainWindow.OpenWindows)
            {
                if (IsDescendantOf(window.inspector))
                {
                    MainWindow = window;
                    window.inspector.autotileBrushList = this;
                    break;
                }
            }
            if (MainWindow is null)
            {
                btnNewBrush.Visible = false;
            }
        }
        else
        {
            if (MainWindow.Tileset.InheritAutotileFrom != lastInheritedFrom)
            {
                lastInheritedFrom = MainWindow.Tileset.InheritAutotileFrom;
                UpdateList();
            }
        }

        Paint.SetBrush(Theme.ControlBackground);
        Paint.SetPen(Theme.ControlBackground);
        Paint.DrawRect(scrollArea.LocalRect, 4);
    }

    public void UpdateList()
    {
        content.Clear(true);
        Buttons.Clear();

        var brushes = SerializedProperty.GetValue<List<AutotileBrush>>();
        var allBrushes = new List<AutotileBrush>();
        var firstBrush = brushes.FirstOrDefault();

        foreach (var brush in brushes)
        {
            allBrushes.Add(brush);
        }

        if (firstBrush is not null)
        {
            var allTilesets = ResourceLibrary.GetAll<TilesetResource>();
            foreach (var tileset in allTilesets)
            {
                if (tileset.AutotileBrushes.Contains(firstBrush))
                {
                    if (tileset.InheritAutotileFrom is not null)
                    {
                        foreach (var inheritedBrush in tileset.InheritAutotileFrom.GetAllAutotileBrushes())
                        {
                            allBrushes.Add(inheritedBrush);
                        }
                    }
                    break;
                }
            }
        }

        foreach (var brush in allBrushes)
        {
            var button = content.Add(new AutotileBrushControl(this, brush));
            if (!brushes.Contains(brush))
            {
                button.Enabled = false;
            }
            Buttons.Add(button);
        }
    }

    internal void SelectBrush(AutotileBrushControl button)
    {
        if (MainWindow is null) return;
        if (SelectedBrush == button && SelectedTile is null) return;

        SelectedBrush = button;
        SelectedTile = null;
        MainWindow.inspector.UpdateSelectedAutotileSheet();
    }

    internal void SelectTile(AutotileTileControl button)
    {
        if (MainWindow is null) return;
        if (SelectedBrush != button.ParentBrush)
        {
            SelectedBrush = button.ParentBrush;
        }
        if (SelectedTile == button.Tile) return;

        SelectedTile = button.Tile;
        MainWindow.inspector.UpdateSelectedAutotileSheet();
    }

    public void DeleteAll()
    {
        var brushes = new List<AutotileBrush>();
        SerializedProperty.SetValue(brushes);
        UpdateList();
    }

    public void DeleteBrush(AutotileBrush brush)
    {
        if (SelectedBrush?.Brush == brush)
        {
            SelectedBrush = null;
            SelectedTile = null;
        }
        var brushes = SerializedProperty.GetValue<List<AutotileBrush>>();
        brushes.Remove(brush);
        SerializedProperty.SetValue(brushes);
        UpdateList();
        MainWindow?.inspector?.UpdateSelectedAutotileSheet();
    }

    void NewBrushPopup()
    {
        var menu = new PopupWidget(null);
        menu.Layout = Layout.Column();
        menu.MinimumWidth = ScreenRect.Width;
        menu.MaximumWidth = ScreenRect.Width;

        ScrollArea scrollArea = menu.Layout.Add(new ScrollArea(this), 1);
        scrollArea.Canvas = new Widget(scrollArea)
        {
            Layout = Layout.Column(),
            VerticalSizeMode = (SizeMode)3,
            HorizontalSizeMode = (SizeMode)3
        };

        IEnumerable<EnumDescription.Entry> enumerableList = EditorTypeLibrary.GetEnumDescription(typeof(AutotileType));
        foreach (var entry in enumerableList)
        {
            var button = scrollArea.Canvas.Layout.Add(new MenuOption(entry));
            button.MouseLeftPress += () =>
            {
                NewBrush((AutotileType)entry.IntegerValue);
                menu?.Close();
            };
        }

        menu.Position = ScreenRect.BottomLeft;
        menu.Visible = true;
        menu.AdjustSize();
        menu.ConstrainToScreen();
        menu.OnPaintOverride = () =>
        {
            Paint.SetBrushAndPen(Theme.ControlBackground);
            Rect rect = Paint.LocalRect;
            Paint.DrawRect(in rect, 0f);
            return true;
        };
    }

    void NewBrush(AutotileType autotileType)
    {
        var layers = SerializedProperty.GetValue<List<AutotileBrush>>();
        layers.Add(new AutotileBrush(autotileType){Tileset = MainWindow.Tileset});
        SerializedProperty.SetValue(layers);
        UpdateList();
        MainWindow?.inspector?.UpdateSelectedAutotileSheet();
    }

    protected override void OnKeyPress(KeyEvent e)
    {
        base.OnKeyPress(e);
        modifiers = e.KeyboardModifiers;
    }

    protected override void OnKeyRelease(KeyEvent e)
    {
        base.OnKeyRelease(e);
        modifiers = e.KeyboardModifiers;
    }

}

file class MenuOption : Widget
{
    EnumDescription.Entry info;

    public MenuOption(EnumDescription.Entry e) : base(null)
    {
        info = e;

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

        if (!string.IsNullOrWhiteSpace(e.Icon))
        {
            Layout.Add(new IconButton(e.Icon) { Background = Color.Transparent, TransparentForMouseEvents = true, IconSize = 18 });
        }

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

        if (!string.IsNullOrWhiteSpace(e.Description))
        {
            var desc = c.Add(new Label(e.Description.Trim('\n', '\r', '\t', ' ')));
            desc.WordWrap = true;
            desc.MinimumHeight = 1;
            desc.MinimumWidth = 200;
        }
    }

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