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 );
}
}
}
}