263 lines
12 KiB
C#
263 lines
12 KiB
C#
using ImGuiNET;
|
|
using T3.Core.Model;
|
|
using T3.Core.Settings;
|
|
using T3.Core.SystemUi;
|
|
using T3.Editor.Compilation;
|
|
using T3.Editor.Gui.Input;
|
|
using T3.Editor.Gui.Styling;
|
|
using T3.Editor.Gui.UiHelpers;
|
|
using T3.Editor.SystemUi;
|
|
using T3.Editor.UiModel;
|
|
using GraphUtils = T3.Editor.UiModel.Helpers.GraphUtils;
|
|
|
|
namespace T3.Editor.Gui.Dialogs;
|
|
|
|
internal sealed class NewProjectDialog : ModalDialog
|
|
{
|
|
protected override void OnShowNextFrame()
|
|
{
|
|
_shareResources = true;
|
|
_newProjectName = "MyProject";
|
|
_userName = UserSettings.Config.UserName;
|
|
_newSubNamespace = "";
|
|
}
|
|
|
|
public void Draw()
|
|
{
|
|
DialogSize = new Vector2(550, 320);
|
|
|
|
// ProjectDirectories is normally populated at startup but can be empty
|
|
// on a corrupted user-settings file. Drawn every frame, so guard the indexer.
|
|
var projectDirectories = UserSettings.Config.ProjectDirectories;
|
|
var primaryProjectDirectory = projectDirectories.Count > 0
|
|
? projectDirectories[0]
|
|
: FileLocations.DefaultProjectFolder;
|
|
|
|
if (BeginDialog("Create new project"))
|
|
{
|
|
// Namespace
|
|
string namespaceWarningText = null;
|
|
bool namespaceCorrect = true;
|
|
if(!GraphUtils.IsNamespaceValid(_newSubNamespace, true, out _))
|
|
{
|
|
namespaceCorrect = false;
|
|
namespaceWarningText = "Namespace must be a valid and unique C# namespace";
|
|
}
|
|
|
|
FormInputs.AddStringInput("Namespace", ref _newSubNamespace,"(Optional)",
|
|
warning: namespaceWarningText,
|
|
tooltip:"An additional namespace withing your user area that can help to further group your projects.",
|
|
autoFocus: ImGui.IsWindowAppearing());
|
|
|
|
// ProjectName
|
|
var warning = string.Empty;
|
|
var nameCorrect = true;
|
|
|
|
if (!GraphUtils.IsIdentifierValid(_newProjectName))
|
|
{
|
|
warning = "Name must be a valid C# identifier.";
|
|
nameCorrect = false;
|
|
}
|
|
else if (_newProjectName.Contains('.'))
|
|
{
|
|
warning = "Name must not contain dots.";
|
|
nameCorrect = false;
|
|
}
|
|
else if (string.IsNullOrWhiteSpace(_newProjectName))
|
|
{
|
|
nameCorrect = false;
|
|
}
|
|
else if(DoesProjectWithNameExists(_newProjectName))
|
|
{
|
|
// Todo - can we actually just allow this provided the project namespaces are different?
|
|
warning = "A project with this name already exists.";
|
|
nameCorrect = false;
|
|
}
|
|
|
|
//ImGui.SetKeyboardFocusHere();
|
|
|
|
FormInputs.AddStringInput("Name", ref _newProjectName, "(mandatory)", warning,
|
|
"Is used to identify your project. Must not contain spaces or special characters.",
|
|
autoFocus: ImGui.IsWindowAppearing());
|
|
|
|
var allValid = namespaceCorrect && nameCorrect;
|
|
|
|
var subNameSpaceWithSeparator = string.IsNullOrEmpty(_newSubNamespace)
|
|
? ""
|
|
: _newSubNamespace + ".";
|
|
|
|
var fullName = $"{_userName}.{subNameSpaceWithSeparator}{_newProjectName}";
|
|
|
|
FormInputs.SetCursorToParameterEdit();
|
|
ImGui.TextColored(allValid ? UiColors.TextMuted : UiColors.StatusError, fullName);
|
|
|
|
|
|
FormInputs.AddCheckBox("Share Resources", ref _shareResources,
|
|
"""
|
|
Enabling this allows anyone with this package to reference shaders,
|
|
images, and other resources that belong to this package in other projects.
|
|
|
|
It is recommended that you leave this option enabled.
|
|
""");
|
|
|
|
if (_shareResources == false)
|
|
{
|
|
ImGui.TextColored(UiColors.StatusWarning, "Warning: there is no way to change this without editing the project code at this time.");
|
|
}
|
|
|
|
if (CustomComponents.DrawCtaButton("Create", isEnabled: allValid))
|
|
{
|
|
if (ProjectSetup.TryCreateProject(fullName, _shareResources, out var project, out var failureLog))
|
|
{
|
|
T3Ui.Save(false); // todo : this is probably not needed
|
|
ImGui.CloseCurrentPopup();
|
|
|
|
//GraphWindow.TryOpenPackage(project, false);
|
|
//Log.Warning("Not implemented yet.");
|
|
//BlockingWindow.Instance.ShowMessageBox($"Project \"{project.DisplayName}\"created successfully! It can be opened from the project list.");
|
|
Log.Debug($"Project \"{project.DisplayName}\"created successfully! It can be opened from the project list.");
|
|
}
|
|
else
|
|
{
|
|
var explanation = Compiler.ExplainBuildFailure(failureLog);
|
|
string message;
|
|
string caption;
|
|
|
|
if (explanation != null)
|
|
{
|
|
// Known cause (e.g. missing .NET targeting pack) — surface a
|
|
// useful next step instead of the generic "file a bug report".
|
|
caption = "Could not create new project";
|
|
message = $"""
|
|
Failed to create project "{_newProjectName}" in "{_newSubNamespace}".
|
|
|
|
{explanation}
|
|
|
|
The empty project folder has been left on disk; you may want to delete it before retrying.
|
|
""";
|
|
Log.Error(message);
|
|
BlockingWindow.Instance.ShowMessageBox(message, caption, "Ok");
|
|
}
|
|
else
|
|
{
|
|
caption = "Failed to create new project";
|
|
message = $"""
|
|
Failed to create project "{_newProjectName}" in "{_newSubNamespace}".
|
|
This should never happen - please file a bug report.
|
|
Currently this error is unhandled, so you may want to manually delete the project from disk if it still does not work after
|
|
an application restart.
|
|
""";
|
|
|
|
Log.Error(message);
|
|
|
|
const string button = "Copy error and go to report page";
|
|
const string buttonWithEnvironmentVariables = "Copy error + environment variables and go to report page\n" +
|
|
"(Most helpful, but check your list of variables before submitting to avoid leaking " +
|
|
"sensitive information)";
|
|
var result = BlockingWindow.Instance.ShowMessageBox(message, caption, buttons: button);
|
|
var hasResult = !string.IsNullOrWhiteSpace(result);
|
|
ReportError(report: hasResult,
|
|
includeEnvVars: result == buttonWithEnvironmentVariables || !hasResult,
|
|
failureLog, fullName, primaryProjectDirectory);
|
|
}
|
|
}
|
|
}
|
|
|
|
ImGui.SameLine();
|
|
if (CustomComponents.DrawCtaButton("Cancel", Icon.None, CustomComponents.ButtonStates.Emphasized))
|
|
{
|
|
ImGui.CloseCurrentPopup();
|
|
}
|
|
|
|
|
|
FormInputs.SetIndentToLeft();
|
|
var projectFolder = System.IO.Path.Combine(primaryProjectDirectory, _newProjectName);
|
|
FormInputs.AddHint($"""
|
|
Creates a new project. Projects are used to group operators and resources.
|
|
You can find your project in "{projectFolder}".
|
|
""");
|
|
|
|
|
|
FormInputs.SetIndentToParameters();
|
|
|
|
EndDialogContent();
|
|
}
|
|
|
|
EndDialog();
|
|
return;
|
|
|
|
void ReportError(bool report, bool includeEnvVars, string failureLog, string fullProjectName, string projectsDirectory)
|
|
{
|
|
var envVars = "\n\n## Environment variables:\n";
|
|
try
|
|
{
|
|
var environmentVariables = Environment.GetEnvironmentVariables();
|
|
envVars += string.Join('\n', environmentVariables);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
envVars += "Could not retrieve environment variables: " + e.Message;
|
|
}
|
|
|
|
var reportText = includeEnvVars ? failureLog + envVars : failureLog;
|
|
var detailsText = $"## Failure Log: {reportText} \n" +
|
|
"--- \n" +
|
|
"## Project details\n" +
|
|
$"Tixl username:{_userName}\n" +
|
|
$"Project namespace:{_newSubNamespace}\n" +
|
|
$"Project name:{_newProjectName}\n" +
|
|
$"Project full name:{fullProjectName}\n" +
|
|
$"Projects directory:{projectsDirectory}\n" +
|
|
"--- \n" +
|
|
"## Additional details" +
|
|
"<!--Insert any relevant additional details here, if any-->\n\n";
|
|
|
|
if (report)
|
|
{
|
|
EditorUi.Instance.SetClipboardText(detailsText);
|
|
|
|
const string issueUrl = "https://github.com/tixl3d/tixl/issues/738#:rps:";
|
|
EditorUi.Instance.OpenWithDefaultApplication(issueUrl);
|
|
}
|
|
else
|
|
{
|
|
Log.Debug(includeEnvVars ? detailsText : detailsText + envVars);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static bool DoesProjectWithNameExists(string name)
|
|
{
|
|
foreach (var package in SymbolPackage.AllPackages)
|
|
{
|
|
if (package is not EditorSymbolPackage symbolPackage)
|
|
continue;
|
|
|
|
if (!symbolPackage.HasHome)
|
|
continue;
|
|
|
|
// TODO: it would be great with SymbolPackage would have a "Name" field
|
|
if (DoesStringMatchesLastPathItem(name, symbolPackage.AssemblyInformation.Name))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static bool DoesStringMatchesLastPathItem(string name, ReadOnlySpan<char> path)
|
|
{
|
|
var lastDot = path.LastIndexOf('.');
|
|
if (lastDot < 0)
|
|
return false;
|
|
|
|
var lastSegment = path.Slice(lastDot + 1);
|
|
return lastSegment.Equals(name, StringComparison.OrdinalIgnoreCase);
|
|
}
|
|
|
|
private string _newProjectName = string.Empty;
|
|
private string _newSubNamespace = string.Empty;
|
|
private string _userName = string.Empty;
|
|
private bool _shareResources = true;
|
|
} |