Added context menu entry to create C#-Scripts.

Allow entering file name before creation
This commit is contained in:
Simon Lübeß
2023-10-19 19:27:01 +02:00
parent bad7b08046
commit 3d8756ec42
2 changed files with 203 additions and 13 deletions
@@ -18,19 +18,22 @@ namespace GlitchyEditor.EditWindows
{ {
private String _name ~ delete _; private String _name ~ delete _;
private String _defaultFileName ~ delete _; private String _defaultFileName ~ delete _;
private String _fileExtension ~ delete _;
private CreateAssetFunc _doCreateAsset ~ delete _; private CreateAssetFunc _doCreateAsset ~ delete _;
public delegate void CreateAssetFunc(StringView outputPath); public delegate void CreateAssetFunc(StringView outputPath);
public StringView Name => _name; public StringView Name => _name;
public StringView DefaultFileName => _defaultFileName; public StringView DefaultFileName => _defaultFileName;
public StringView FileExtension => _fileExtension;
public CreateAssetFunc CreateAsset => _doCreateAsset; public CreateAssetFunc CreateAsset => _doCreateAsset;
public this(StringView name, StringView defaultFileName, CreateAssetFunc createAsset) public this(StringView name, StringView defaultFileName, StringView fileExtension, CreateAssetFunc createAsset)
{ {
_name = new String(name); _name = new String(name);
_defaultFileName = new String(defaultFileName); _defaultFileName = new String(defaultFileName);
_fileExtension = new String(fileExtension);
_doCreateAsset = createAsset; _doCreateAsset = createAsset;
} }
} }
@@ -59,6 +62,10 @@ namespace GlitchyEditor.EditWindows
public StringView SelectedFile => _selectedFile; public StringView SelectedFile => _selectedFile;
char8[256] _newFileName = .();
bool _showNewFile = false;
AssetCreator _newFileCreator = null;
public this(EditorContentManager contentManager) public this(EditorContentManager contentManager)
{ {
_manager = contentManager; _manager = contentManager;
@@ -106,6 +113,7 @@ namespace GlitchyEditor.EditWindows
bool alt_pressed = ImGui.GetIO().KeyAlt; bool alt_pressed = ImGui.GetIO().KeyAlt;
// Table with two columns, one for Directory-Sidebar and one for File-Browser
if (ImGui.BeginTable("table", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX)) if (ImGui.BeginTable("table", 2, .BordersInnerV | .Resizable | .Reorderable | .NoPadOuterX))
{ {
if (alt_pressed) if (alt_pressed)
@@ -178,6 +186,13 @@ namespace GlitchyEditor.EditWindows
ImGui.Separator(); ImGui.Separator();
ShowCreateContextMenu(_creatorTree); ShowCreateContextMenu(_creatorTree);
ImGui.Separator();
if (ImGui.MenuItem("Open C# Project..."))
{
// TODO
}
} }
/// Shows the menu for the given asset creator tree. /// Shows the menu for the given asset creator tree.
@@ -187,7 +202,7 @@ namespace GlitchyEditor.EditWindows
{ {
if (ImGui.MenuItem(subtree->Name.ToScopeCStr!())) if (ImGui.MenuItem(subtree->Name.ToScopeCStr!()))
{ {
CreateAsset(subtree->Creator); ShowNewFile(subtree->Creator);
} }
} }
else else
@@ -204,8 +219,24 @@ namespace GlitchyEditor.EditWindows
} }
} }
/// Shows a dummy file in the asset browser where the user can enter a file name and create an asset.
private void ShowNewFile(AssetCreator creator)
{
_newFileCreator = creator;
creator.DefaultFileName.CopyTo(_newFileName);
_showNewFile = true;
}
/// Hides the dummy file.
private void HideNewFile()
{
_newFileCreator = null;
_showNewFile = false;
_newFileName = .();
}
/// Creates a new asset with the given creator /// Creates a new asset with the given creator
private void CreateAsset(AssetCreator creator) private void CreateAsset()
{ {
if (!Directory.Exists(_currentDirectory)) if (!Directory.Exists(_currentDirectory))
{ {
@@ -214,23 +245,29 @@ namespace GlitchyEditor.EditWindows
} }
String currentFile = scope String(); String currentFile = scope String();
Path.Combine(currentFile, _currentDirectory, creator.DefaultFileName); Path.Combine(currentFile, _currentDirectory, StringView(&_newFileName));
String fileExtension = scope String(); // Add file extension, if necessary
Path.GetExtension(currentFile, fileExtension); if (!currentFile.EndsWith(_newFileCreator.FileExtension))
{
currentFile.Append(_newFileCreator.FileExtension);
}
StringView fileWithoutExtension = currentFile[0...^(fileExtension.Length + 1)]; StringView fileWithoutExtension = currentFile[0...^(_newFileCreator.FileExtension.Length + 1)];
// If the file already exists find a unused number to attach to the end.
int i = 0; int i = 0;
while (File.Exists(currentFile)) while (File.Exists(currentFile))
{ {
i++; i++;
currentFile.Set(fileWithoutExtension); currentFile.Set(fileWithoutExtension);
currentFile.AppendF($"({i})"); currentFile.AppendF($"({i})");
currentFile.Append(fileExtension); currentFile.Append(_newFileCreator.FileExtension);
} }
creator.CreateAsset(currentFile); _newFileCreator.CreateAsset(currentFile);
HideNewFile();
} }
/// Renders a sidebar that shows a tree of all directories in the asset folder. /// Renders a sidebar that shows a tree of all directories in the asset folder.
@@ -367,6 +404,15 @@ namespace GlitchyEditor.EditWindows
ImGui.PopID(); ImGui.PopID();
} }
if (_showNewFile)
{
ImGui.PushID("New File");
ShowNewFile();
ImGui.PopID();
}
} }
float _zoom = 1.0f; float _zoom = 1.0f;
@@ -600,6 +646,59 @@ namespace GlitchyEditor.EditWindows
ImGui.AttachTooltip(entry->Name); ImGui.AttachTooltip(entry->Name);
} }
/// Renders the button for the given directory item.
private void ShowNewFile()
{
ImGui.PushStyleVar(.WindowPadding, .(0, 0));
ImGui.PushStyleVar(.FramePadding, .(0, 0));
ImGui.PushStyleVar(.ItemSpacing, .(0, 0));
defer { ImGui.PopStyleVar(3); }
float2 DirectoryItemSize = IconSize + (float2)ImGui.GetStyle().WindowPadding * 2 + float2(0, ImGui.GetFontSize());
ImGui.BeginChild("item", (.)DirectoryItemSize, false, .NoScrollbar);
ImGui.PushStyleColor(.Button, ImGui.Vec4(0, 0, 0, 0));
// TODO: preview images
SubTexture2D image = s_FileTexture;
ImGui.ImageButton("FileImage", image, (.)IconSize);
ImGui.PopStyleColor();
ImGui.PushItemWidth((.)IconSize.X);
ImGui.InputText("##newFileNameBox", &_newFileName, _newFileName.Count - 1, .AutoSelectAll);
ImGui.PopItemWidth();
ImGui.SetKeyboardFocusHere(-1);
void CreateFile()
{
CreateAsset();
}
if (ImGui.IsKeyDown(.Escape))
{
// Abort
HideNewFile();
}
else if (ImGui.IsItemDeactivatedAfterEdit())
{
CreateFile();
}
else if (ImGui.IsItemDeactivated())
{
// Abort
HideNewFile();
}
ImGui.EndChild();
}
private void DeleteItemPopup(TreeNode<AssetNode> fileOrFolder) private void DeleteItemPopup(TreeNode<AssetNode> fileOrFolder)
{ {
// Always center this window when appearing // Always center this window when appearing
+94 -3
View File
@@ -144,7 +144,7 @@ namespace GlitchyEditor
private void RegisterAssetCreators() private void RegisterAssetCreators()
{ {
Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Folder", "New Folder", new (path) => Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Folder", "New Folder", "", new (path) =>
{ {
if (Directory.CreateDirectory(path) case .Err(let error)) if (Directory.CreateDirectory(path) case .Err(let error))
{ {
@@ -152,7 +152,7 @@ namespace GlitchyEditor
} }
})); }));
Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Scene", "New Scene.scene", new (path) => Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Scene", "New Scene", ".scene", new (path) =>
{ {
using (Scene newScene = CreateNewScene()) using (Scene newScene = CreateNewScene())
{ {
@@ -160,13 +160,104 @@ namespace GlitchyEditor
} }
})); }));
Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Material", "New Material.mat", new (path) => Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Material", "New Material", ".mat", new (path) =>
{ {
using (Material newMaterial = new Material()) using (Material newMaterial = new Material())
{ {
_contentManager.SaveAssetToFile(newMaterial, path); _contentManager.SaveAssetToFile(newMaterial, path);
} }
})); }));
Editor.Instance.ContentBrowserWindow.RegisterAssetCreator(new AssetCreator("Script", "New Entity", ".cs", new (path) =>
{
String templatePath = scope .();
Directory.GetCurrentDirectory(templatePath);
Path.Combine(templatePath, "Resources/Templates/ScriptTemplate.cs");
String scriptContent = scope .();
if (File.ReadAllText(templatePath, scriptContent, true) case .Err(let error))
{
Log.EngineLogger.Error($"Failed to read template file from \"{templatePath}\". Error: {error}");
return;
}
scriptContent.Replace("[ProjectName]", CurrentProject.Name);
String fileName = scope .();
Path.GetFileName(path, fileName);
Log.EngineLogger.AssertDebug(fileName.EndsWith(".cs"));
if (fileName.EndsWith(".cs"))
fileName.RemoveFromEnd(3);
String pascalFileName = scope .(fileName.Length);
ToPascalCase(fileName, pascalFileName);
String cSharpClassName = scope .(pascalFileName.Length);
ToCSharpName(pascalFileName, cSharpClassName);
scriptContent.Replace("[EntityName]", cSharpClassName);
if (File.WriteAllText(path, scriptContent, false) case .Err)
{
Log.EngineLogger.Error($"Failed to save script file to \"{path}\".");
return;
}
}));
}
private void ToCSharpName(String input, String output)
{
for (char32 c in input.DecodedChars)
{
if (c.IsLetterOrDigit || c == '_' || c == '@')
{
output.Append(c);
}
}
let decode = System.Text.UTF8.Decode(output.Ptr, output.Length);
// Make sure the name starts with a letter or _ or @
if (!(decode.c.IsLetter || decode.c == '_' || decode.c == '@'))
{
output.Insert(0, '@');
}
}
private void ToPascalCase(String input, String output)
{
bool newWord = true;
for (char32 c in input.DecodedChars)
{
if (c.IsLetter)
{
if (newWord)
{
output.Append(c.ToUpper);
newWord = false;
}
else
{
output.Append(c);
}
}
else
{
newWord = true;
if (c.IsWhiteSpace || c == '_')
{
continue;
}
else
{
output.Append(c);
}
}
}
} }
private void InitGraphics() private void InitGraphics()