Merge branch 'auto-module' of https://github.com/Tryibion/FlaxEngine into Tryibion-auto-module

# Conflicts:
#	Source/Editor/Windows/ContentWindow.ContextMenu.cs
This commit is contained in:
Wojtek Figat
2023-10-08 13:43:28 +02:00
2 changed files with 221 additions and 2 deletions

View File

@@ -1,11 +1,13 @@
// Copyright (c) 2012-2023 Wojciech Figat. All rights reserved.
using System;
using System.IO;
using FlaxEditor.Content;
using FlaxEditor.GUI.ContextMenu;
using FlaxEditor.Scripting;
using FlaxEngine;
using FlaxEngine.Assertions;
using FlaxEngine.GUI;
using FlaxEngine.Json;
namespace FlaxEditor.Windows
@@ -145,9 +147,152 @@ namespace FlaxEditor.Windows
cm.AddButton("Refresh all thumbnails", RefreshViewItemsThumbnails);
}
cm.AddSeparator();
// Check if is source folder to add new module
if (item is ContentFolder sourceFolder && sourceFolder.ParentFolder.Node is ProjectTreeNode node)
{
if (sourceFolder.Node == node.Source)
{
var button = cm.AddButton("New Module");
button.CloseMenuOnClick = false;
button.Clicked += () =>
{
var popup = new ContextMenuBase
{
Size = new Float2(230, 125),
ClipChildren = false,
CullChildren = false,
};
popup.Show(button, new Float2(button.Width, 0));
var nameLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Name",
HorizontalAlignment = TextAlignment.Near,
};
nameLabel.LocalX += 10;
nameLabel.LocalY += 10;
var nameTextBox = new TextBox
{
Parent = popup,
WatermarkText = "Module Name",
AnchorPreset = AnchorPresets.TopLeft,
IsMultiline = false,
};
nameTextBox.LocalX += 100;
nameTextBox.LocalY += 10;
var defaultTextBoxBorderColor = nameTextBox.BorderColor;
var defaultTextBoxBorderSelectedColor = nameTextBox.BorderSelectedColor;
nameTextBox.TextChanged += () =>
{
if (string.IsNullOrEmpty(nameTextBox.Text))
{
nameTextBox.BorderColor = defaultTextBoxBorderColor;
nameTextBox.BorderSelectedColor = defaultTextBoxBorderSelectedColor;
return;
}
var pluginPath = Path.Combine(Globals.ProjectFolder, "Source", nameTextBox.Text);
if (Directory.Exists(pluginPath))
{
nameTextBox.BorderColor = Color.Red;
nameTextBox.BorderSelectedColor = Color.Red;
}
else
{
nameTextBox.BorderColor = defaultTextBoxBorderColor;
nameTextBox.BorderSelectedColor = defaultTextBoxBorderSelectedColor;
}
};
var editorLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Editor",
HorizontalAlignment = TextAlignment.Near,
};
editorLabel.LocalX += 10;
editorLabel.LocalY += 35;
var editorCheckBox = new CheckBox()
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
};
editorCheckBox.LocalY += 35;
editorCheckBox.LocalX += 100;
var cppLabel = new Label
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "C++",
HorizontalAlignment = TextAlignment.Near,
};
cppLabel.LocalX += 10;
cppLabel.LocalY += 60;
var cppCheckBox = new CheckBox()
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
};
cppCheckBox.LocalY += 60;
cppCheckBox.LocalX += 100;
var submitButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Create",
Width = 70,
};
submitButton.LocalX += 40;
submitButton.LocalY += 90;
submitButton.Clicked += () =>
{
// TODO: Check all modules in project including plugins
if (Directory.Exists(Path.Combine(Globals.ProjectFolder, "Source", nameTextBox.Text)))
{
Editor.LogWarning("Cannot create module due to name conflict.");
return;
}
CreateModule(node.Source.Path, nameTextBox.Text, editorCheckBox.Checked, cppCheckBox.Checked);
nameTextBox.Clear();
editorCheckBox.Checked = false;
cppCheckBox.Checked = false;
popup.Hide();
};
var cancelButton = new Button
{
Parent = popup,
AnchorPreset = AnchorPresets.TopLeft,
Text = "Cancel",
Width = 70,
};
cancelButton.LocalX += 120;
cancelButton.LocalY += 90;
cancelButton.Clicked += () =>
{
nameTextBox.Clear();
editorCheckBox.Checked = false;
cppCheckBox.Checked = false;
popup.Hide();
};
};
}
}
if (!isRootFolder && !(item is ContentFolder projectFolder && projectFolder.Node is ProjectTreeNode))
{
cm.AddSeparator();
cm.AddButton("New folder", NewFolder);
}

View File

@@ -5,6 +5,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml;
using FlaxEditor.Content;
using FlaxEditor.Content.GUI;
@@ -756,7 +757,80 @@ namespace FlaxEditor.Windows
}
/// <summary>
/// Stars creating the folder.
/// Starts creating a new module
/// </summary>
private async void CreateModule(string path, string moduleName, bool editorModule, bool cpp)
{
if (string.IsNullOrEmpty(moduleName) || string.IsNullOrEmpty(path))
{
Editor.LogWarning("Failed to create module due to no name");
return;
}
// Create folder
var moduleFolderPath = Path.Combine(path, moduleName);
Directory.CreateDirectory(moduleFolderPath);
// Create module
var moduleText = "using Flax.Build;\n" +
"using Flax.Build.NativeCpp;\n" +
$"\npublic class {moduleName} : Game{(editorModule ? "Editor" : "")}Module\n" +
"{\n " +
"/// <inheritdoc />\n" +
" public override void Init()\n" +
" {\n" +
" base.Init();\n" +
"\n" +
" // C#-only scripting if false\n" +
$" BuildNativeCode = {(cpp ? "true" : "false")};\n" +
" }\n" +
"\n" +
" /// <inheritdoc />\n" +
" public override void Setup(BuildOptions options)\n" +
" {" +
"\n" +
" base.Setup(options);\n" +
"\n" +
" options.ScriptingAPI.IgnoreMissingDocumentationWarnings = true;\n" +
"\n" +
" // Here you can modify the build options for your game module\n" +
" // To reference another module use: options.PublicDependencies.Add(\"Audio\");\n" +
" // To add C++ define use: options.PublicDefinitions.Add(\"COMPILE_WITH_FLAX\");\n" +
" // To learn more see scripting documentation.\n" +
" }\n" +
"}";
moduleText = Encoding.UTF8.GetString(Encoding.Default.GetBytes(moduleText));
var modulePath = Path.Combine(moduleFolderPath, $"{moduleName}.Build.cs");
await File.WriteAllTextAsync(modulePath, moduleText);
Editor.Log($"Module created at {modulePath}");
// Get editor target and target files and add module
var files = Directory.GetFiles(path);
var targetModuleText = $"Modules.Add(\"{moduleName}\");\n ";
foreach (var file in files)
{
if (!file.Contains(".Build.cs", StringComparison.OrdinalIgnoreCase))
continue;
var targetText = await File.ReadAllTextAsync(file);
// Skip game project if it is suppose to be an editor module
if (editorModule && targetText.Contains("GameProjectTarget", StringComparison.Ordinal))
continue;
// TODO: Handle edge case when there are no modules in a target
var index = targetText.IndexOf("Modules.Add");
if (index != -1)
{
var newText = targetText.Insert(index, targetModuleText);
await File.WriteAllTextAsync(file, newText);
Editor.Log($"Module added to Target: {file}");
}
}
}
/// <summary>
/// Starts creating the folder.
/// </summary>
public void NewFolder()
{