Editor/HotCodeEditor/Ui/WelcomePage.cs
using Sandbox;
using Editor;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

/// <summary>
/// Shown in the editor area when no file is open: the project's name, recently opened files,
/// and a cheat sheet of HotCode's shortcuts.
/// </summary>
public class WelcomePage : Widget
{
	private static readonly (string Keys, string What)[] Shortcuts =
	{
		("Ctrl+S", "Save"),
		("Ctrl+W", "Close tab"),
		("Ctrl+F / Ctrl+H", "Find / Replace"),
		("Ctrl+G", "Go to line"),
		("F12 / Ctrl+Click", "Go to definition"),
		("Alt+Left / Alt+Right", "Back / Forward"),
		("Ctrl+Space", "Suggestions"),
		("Ctrl+Shift+Space", "Parameter hints"),
		("Ctrl+J", "Show / hide the bottom panel"),
		("Alt+Z", "Word wrap"),
	};

	private readonly string _root;
	private readonly Action<string> _open;
	private readonly Widget _recentList;

	public WelcomePage( Widget parent, string title, string root, Action<string> open ) : base( parent )
	{
		_root = root;
		_open = open;

		OnPaintOverride = () =>
		{
			Paint.ClearPen();
			Paint.SetBrush( Theme.TabBackground );
			Paint.DrawRect( LocalRect );
			return true;
		};

		// Centered column
		Layout = Layout.Row();
		Layout.AddStretchCell();

		var column = Layout.AddColumn();
		column.Spacing = 4;
		column.Margin = new Sandbox.UI.Margin( 0, 40, 0, 0 );

		var headingRow = column.AddRow();
		headingRow.Spacing = 14;
		headingRow.Add( new LogoWidget( this, 44, badge: true ) );
		var heading = headingRow.Add( new Label.Title( title, this ) );
		heading.MinimumWidth = 460;
		column.Add( new Label( root, this ) ).SetStyles( $"color: {Theme.TextLight.Hex};" );
		column.AddSpacingCell( 24 );

		var sections = column.AddRow();
		sections.Spacing = 40;

		// Left: recent files
		var recent = sections.AddColumn( 1 );
		recent.Spacing = 2;
		recent.Add( new Label.Subtitle( "Recent Files", this ) );
		_recentList = recent.Add( new Widget( this ) );
		_recentList.Layout = Layout.Column();
		_recentList.Layout.Spacing = 1;
		recent.AddStretchCell();

		// Right: shortcuts
		var keys = sections.AddColumn( 1 );
		keys.Spacing = 2;
		keys.Add( new Label.Subtitle( "Shortcuts", this ) );
		keys.Add( new ShortcutList( this, Shortcuts ) );
		keys.AddStretchCell();

		column.AddStretchCell();
		Layout.AddStretchCell();
	}

	public void SetRecentFiles( IEnumerable<string> files )
	{
		_recentList.Layout.Clear( true );

		var existing = files.Where( File.Exists ).Take( 10 ).ToList();
		if ( existing.Count == 0 )
		{
			_recentList.Layout.Add( new Label( "Files you open show up here.", _recentList ) ).SetStyles( $"color: {Theme.TextLight.Hex};" );
			return;
		}

		foreach ( var file in existing )
		{
			var folder = Path.GetDirectoryName( Path.GetRelativePath( _root, file ) );
			_recentList.Layout.Add( new LinkRow( _recentList, HotCodeStyle.FileIcon( file ), HotCodeStyle.FileIconColor( file ), Path.GetFileName( file ), folder, () => _open( file ) ) );
		}
	}

	/// <summary>
	/// "[icon] Player.cs  Code/Components" that highlights on hover and opens on click.
	/// </summary>
	private class LinkRow : Widget
	{
		private readonly string _icon;
		private readonly Color _iconColor;
		private readonly string _text;
		private readonly string _detail;
		private readonly Action _clicked;

		public LinkRow( Widget parent, string icon, Color iconColor, string text, string detail, Action clicked ) : base( parent )
		{
			_icon = icon;
			_iconColor = iconColor;
			_text = text;
			_detail = detail;
			_clicked = clicked;

			FixedHeight = Theme.RowHeight;
			Cursor = CursorShape.Finger;
			MouseTracking = true;
		}

		protected override void OnMouseEnter() { base.OnMouseEnter(); Update(); }
		protected override void OnMouseLeave() { base.OnMouseLeave(); Update(); }

		protected override void OnMousePress( MouseEvent e )
		{
			base.OnMousePress( e );
			if ( e.LeftMouseButton ) _clicked();
		}

		protected override void OnPaint()
		{
			if ( IsUnderMouse )
			{
				Paint.ClearPen();
				Paint.SetBrush( Theme.SurfaceLightBackground );
				Paint.DrawRect( LocalRect, Theme.ControlRadius );
			}

			Paint.SetPen( _iconColor );
			Paint.DrawIcon( new Rect( 6, 0, 18, Height ), _icon, 14, TextFlag.LeftCenter );

			Paint.SetDefaultFont( HotCodeStyle.FontSize, 500 );
			Paint.SetPen( IsUnderMouse ? Theme.Text : Theme.Text.WithAlpha( 0.9f ) );
			var nameWidth = Paint.MeasureText( _text ).x;
			Paint.DrawText( new Rect( 28, 0, Width - 28, Height ), _text, TextFlag.LeftCenter );

			if ( !string.IsNullOrEmpty( _detail ) )
			{
				Paint.SetDefaultFont( HotCodeStyle.FontSize );
				Paint.SetPen( Theme.TextLight );
				var rect = new Rect( 28 + nameWidth + 10, 0, Width - nameWidth - 44, Height );
				Paint.DrawText( rect, Paint.GetElidedText( _detail, rect.Width, ElideMode.Left ), TextFlag.LeftCenter );
			}
		}
	}

	/// <summary>
	/// Key "chips" on the left, what they do on the right.
	/// </summary>
	private class ShortcutList : Widget
	{
		private readonly (string Keys, string What)[] _items;

		public ShortcutList( Widget parent, (string Keys, string What)[] items ) : base( parent )
		{
			_items = items;
			FixedHeight = items.Length * Theme.RowHeight;
			MinimumWidth = 320;
		}

		protected override void OnPaint()
		{
			for ( int i = 0; i < _items.Length; i++ )
			{
				var y = i * Theme.RowHeight;
				var x = 0f;

				// Each key combination as its own chip: "Ctrl+F" "/" "Ctrl+H"
				foreach ( var part in _items[i].Keys.Split( " / " ) )
				{
					if ( x > 0 )
					{
						Paint.SetPen( Theme.TextLight );
						Paint.SetDefaultFont( HotCodeStyle.FontSize );
						Paint.DrawText( new Rect( x, y, 12, Theme.RowHeight ), "/", TextFlag.Center );
						x += 12;
					}

					Paint.SetDefaultFont( 7, 600 );
					var width = Paint.MeasureText( part ).x + 12;
					var chip = new Rect( x, y + 4, width, Theme.RowHeight - 8 );

					Paint.ClearPen();
					Paint.SetBrush( Theme.SurfaceLightBackground );
					Paint.DrawRect( chip, Theme.ControlRadius );
					Paint.SetPen( Theme.Text );
					Paint.DrawText( chip, part, TextFlag.Center );
					x += width;
				}

				Paint.SetDefaultFont( HotCodeStyle.FontSize );
				Paint.SetPen( Theme.TextLight );
				Paint.DrawText( new Rect( 170, y, Width - 170, Theme.RowHeight ), _items[i].What, TextFlag.LeftCenter );
			}
		}
	}
}