Files
sbox-public/engine/Launcher/StandaloneTest/Widgets/ProjectCreator.cs
s&box team 71f266059a Open source release
This commit imports the C# engine code and game files, excluding C++ source code.

[Source-Commit: ceb3d758046e50faa6258bc3b658a30c97743268]
2025-11-24 09:05:18 +00:00

237 lines
5.9 KiB
C#

using Sandbox.DataModel;
using System.IO;
namespace Editor;
public class ProjectCreator : Dialog
{
public Action<string> OnProjectCreated { get; set; }
private Button OkayButton;
private LineEdit TitleEdit;
private LineEdit IdentEdit;
private Checkbox CreateGitIgnore;
private Checkbox SetDefaultProjectLocation;
private FolderEdit FolderEdit;
private FieldSubtitle FolderFullPath;
private ProjectTemplate ActiveTemplate;
private ProjectTemplates Templates;
private ErrorBox FolderError;
private bool identEdited;
public ProjectCreator( Widget parent = null ) : base( null )
{
Window.Size = new Vector2( 800, 500 );
Window.MaximumSize = Window.Size;
Window.MinimumSize = Window.Size;
Window.SetModal( true, true );
Window.Title = "Create New Project";
Window.SetWindowIcon( "sports_esports" );
Layout = Layout.Row();
Layout.Spacing = 4;
// Template List
{
var column = Layout.AddColumn( 3 );
column.Margin = 20;
column.AddSpacingCell( 8.0f );
column.Add( new FieldTitle( "Templates" ) );
column.AddSpacingCell( 18.0f );
var templates = column.Add( new ProjectTemplates( this ) );
Templates = templates;
}
Layout.AddSeparator();
// Body
{
var body = Layout.AddColumn( 2 );
body.Margin = 20;
body.Spacing = 8;
body.AddSpacingCell( 8.0f );
body.Add( new FieldTitle( "Project Setup" ) );
body.AddSpacingCell( 12.0f );
body.Add( new FieldTitle( "Title" ) );
TitleEdit = body.Add( new LineEdit( "" ) { PlaceholderText = "Garry's Project" } );
TitleEdit.Text = DefaultProjectName();
TitleEdit.TextEdited += ( x ) => Validate();
body.AddSpacingCell( 8 );
body.Add( new FieldTitle( "Ident" ) );
body.Add( new FieldSubtitle( "Lowercase version of addon name, no special characters" ) );
IdentEdit = body.Add( new LineEdit( "" ) { PlaceholderText = "garrysproject" } );
IdentEdit.TextEdited += ( x ) => Validate();
IdentEdit.TextEdited += ( x ) => identEdited = true;
IdentEdit.SetValidator( "[a-z0-9_]{2,32}" );
body.AddSpacingCell( 8 );
body.Add( new FieldTitle( "Location" ) );
FolderEdit = body.Add( new FolderEdit( null ) );
FolderEdit.PlaceholderText = LauncherPreferences.DefaultProjectLocation.NormalizeFilename( false );
FolderEdit.Text = LauncherPreferences.DefaultProjectLocation.NormalizeFilename( false );
FolderEdit.TextEdited += ( x ) =>
{
Validate();
};
FolderEdit.FolderSelected += ( x ) =>
{
Validate();
};
FolderError = body.Add( new ErrorBox() );
FolderError.Visible = false;
FolderError.MinimumHeight = 34;
FolderError.WordWrap = true;
body.AddSpacingCell( 8 );
body.Add( new FieldTitle( "Other" ) );
CreateGitIgnore = body.Add( new Checkbox() );
CreateGitIgnore.Value = true;
CreateGitIgnore.Text = "Create .gitignore";
SetDefaultProjectLocation = body.Add( new Checkbox() );
SetDefaultProjectLocation.Value = false;
SetDefaultProjectLocation.Text = "Set as Default Project Location";
body.AddStretchCell( 1 );
var footer = body.AddRow();
footer.Spacing = 8;
FolderFullPath = footer.Add( new FieldSubtitle( "" ) );
footer.AddStretchCell();
OkayButton = footer.Add( new Button.Primary( "Create", "add_box" ) { Clicked = CreateProject } );
}
Templates.ListView.ItemSelected += ( object item ) => { ActiveTemplate = item as ProjectTemplate; };
ActiveTemplate = Templates.ListView.SelectedItems.First() as ProjectTemplate;
Validate();
}
static string DefaultProjectName()
{
string name = "My Project";
// If Location/my_project already exists, append 1, 2, etc.
int i = 1;
while ( Path.Exists( Path.Combine( LauncherPreferences.DefaultProjectLocation, ConvertToIdent( name ) ) ) )
{
name = $"My Project {i++}";
}
return name;
}
static string ConvertToIdent( string title )
{
return System.Text.RegularExpressions.Regex.Replace( title.ToLower(), "[^A-Za-z0-9_]", "_" ).Trim( '_' );
}
void Validate()
{
if ( !identEdited )
{
IdentEdit.Text = ConvertToIdent( TitleEdit.Text );
}
bool enabled = true;
if ( string.IsNullOrWhiteSpace( FolderEdit.Text ) ) enabled = false;
if ( string.IsNullOrWhiteSpace( TitleEdit.Text ) ) enabled = false;
if ( string.IsNullOrWhiteSpace( IdentEdit.Text ) ) enabled = false;
FolderError.Visible = false;
string fullPath = Path.Combine( FolderEdit.Text, IdentEdit.Text );
FolderFullPath.Text = fullPath.NormalizeFilename( false );
if ( Path.Exists( fullPath ) )
{
FolderError.Text = $"{FolderFullPath.Text} already exists";
FolderError.Visible = true;
enabled = false;
}
// Max 32 characters
if ( IdentEdit.Text.Length >= 32 )
IdentEdit.Text = IdentEdit.Text[..Math.Min( IdentEdit.Text.Length, 32 )];
OkayButton.Enabled = enabled;
}
void CreateProject()
{
var addonPath = Path.Combine( FolderEdit.Text, IdentEdit.Text );
Directory.CreateDirectory( addonPath );
var config = new ProjectConfig();
config.Ident = IdentEdit.Text;
config.Title = TitleEdit.Text;
config.Org = "local";
config.Type = "game";
config.Schema = 1;
var pt = Templates.ListView.ChosenTemplate;
if ( pt != null )
pt.Apply( addonPath, ref config );
var configPath = System.IO.Path.Combine( addonPath, $"{config.Ident}.sbproj" );
var txt = config.ToJson();
System.IO.File.WriteAllText( configPath, txt );
if ( CreateGitIgnore.Value )
{
if ( !File.Exists( Path.Combine( addonPath, ".gitignore" ) ) )
{
File.Copy( FileSystem.Root.GetFullPath( "/templates/template.gitignore" ), Path.Combine( addonPath, ".gitignore" ) );
}
}
if ( SetDefaultProjectLocation.Value )
{
LauncherPreferences.DefaultProjectLocation = FolderEdit.Text;
}
Close();
OnProjectCreated?.Invoke( configPath );
}
}
// Don't use these form things
internal class ErrorBox : Label
{
}
internal class FieldTitle : Label
{
public FieldTitle( string title ) : base( title )
{
}
}
internal class FieldSubtitle : Label
{
public FieldSubtitle( string title ) : base( title )
{
WordWrap = true;
}
}