| @ -0,0 +1,307 @@ | ||||
| #include "CSNewProjectWizard.h" | ||||
|  | ||||
| #include "CSManager.h" | ||||
| #include "DesktopPlatformModule.h" | ||||
| #include "IDesktopPlatform.h" | ||||
| #include "Interfaces/IPluginManager.h" | ||||
| #include "Runtime/AppFramework/Public/Widgets/Workflow/SWizard.h" | ||||
| #include "UnrealSharpEditor/UnrealSharpEditor.h" | ||||
| #include "UnrealSharpProcHelper/CSProcHelper.h" | ||||
|  | ||||
| #define LOCTEXT_NAMESPACE "UnrealSharpEditor" | ||||
|  | ||||
| void SCSNewProjectDialog::Construct(const FArguments& InArgs) | ||||
| { | ||||
|     static FName ProjectDestination(TEXT("<ProjectDestination>")); | ||||
| 	const FString ScriptPath = FPaths::ConvertRelativePathToFull(FCSProcHelper::GetScriptFolderDirectory()); | ||||
|  | ||||
| 	FText ProjectDestinationName = FText::FromString(FString::Printf(TEXT("%s (This Project)"), FApp::GetProjectName())); | ||||
|     ProjectDestinations.Add(MakeShared<FCSProjectDestination>(ProjectDestination, ProjectDestinationName, FApp::GetProjectName(), ScriptPath, 0)); | ||||
| 	 | ||||
|     IPluginManager& PluginManager = IPluginManager::Get(); | ||||
|     TArray<TSharedRef<IPlugin>> EnabledPlugins = PluginManager.GetEnabledPlugins(); | ||||
|  | ||||
|     for (const TSharedRef<IPlugin>& Plugin : EnabledPlugins) | ||||
|     { | ||||
|         const FString PluginFilePath = FPaths::ConvertRelativePathToFull(Plugin->GetBaseDir()); | ||||
|         if (!FPaths::IsUnderDirectory(PluginFilePath, FCSProcHelper::GetPluginsDirectory()) || Plugin->GetName() == UE_PLUGIN_NAME) | ||||
|         { | ||||
|             continue; | ||||
|         } | ||||
|     	 | ||||
|         FString ScriptDirectory = PluginFilePath / "Script"; | ||||
|         ProjectDestinations.Add(MakeShared<FCSProjectDestination>(FName(Plugin->GetName()), | ||||
|             FText::FromString(Plugin->GetFriendlyName()), Plugin->GetName(), ScriptDirectory, ProjectDestinations.Num(), Plugin)); | ||||
|     } | ||||
|     SelectedProjectDestinationIndex = 0; | ||||
|  | ||||
| 	ChildSlot | ||||
| 	[ | ||||
| 		SNew(SWizard) | ||||
| 		.ShowPageList(false) | ||||
| 		.FinishButtonText(LOCTEXT("CreateProject", "Create C# Project")) | ||||
| 		.FinishButtonToolTip(LOCTEXT("CreateProjectTooltip", "Create a new C# project with the specified settings")) | ||||
| 		.OnCanceled(this, &SCSNewProjectDialog::OnCancel) | ||||
| 		.OnFinished(this, &SCSNewProjectDialog::OnFinish) | ||||
| 		.CanFinish(this, &SCSNewProjectDialog::CanFinish) | ||||
| 		+ SWizard::Page() | ||||
| 		[ | ||||
| 			SNew(SOverlay) | ||||
| 			+ SOverlay::Slot() | ||||
| 			.HAlign(HAlign_Center) | ||||
| 			.VAlign(VAlign_Center) | ||||
| 			[ | ||||
| 				SNew(SVerticalBox) | ||||
| 				+ SVerticalBox::Slot() | ||||
| 				.Padding(0, 0, 0, 10) | ||||
| 				[ | ||||
| 					SNew(SHorizontalBox) | ||||
| 					+ SHorizontalBox::Slot() | ||||
| 					.AutoWidth() | ||||
| 					.VAlign(VAlign_Center) | ||||
| 					.Padding(0, 0, 10, 0) | ||||
| 					[ | ||||
| 						SNew(STextBlock) | ||||
| 						.Text(LOCTEXT("NewProjectName", "Name")) | ||||
| 					] | ||||
| 					+ SHorizontalBox::Slot() | ||||
| 					.FillWidth(1) | ||||
| 					[ | ||||
| 						SAssignNew(NameTextBox, SEditableTextBox) | ||||
| 					] | ||||
| 				] | ||||
| 				+ SVerticalBox::Slot() | ||||
| 				.Padding(0, 0, 0, 10) | ||||
| 				[ | ||||
| 					SNew(SHorizontalBox) | ||||
| 					+ SHorizontalBox::Slot() | ||||
| 					.AutoWidth() | ||||
| 					.VAlign(VAlign_Center) | ||||
| 					.Padding(0, 0, 10, 0) | ||||
| 					[ | ||||
| 						SNew(STextBlock) | ||||
| 						.Text(LOCTEXT("NewProjectOwner", "Owner")) | ||||
| 					] | ||||
| 					+ SHorizontalBox::Slot() | ||||
| 					.FillWidth(1) | ||||
| 					[ | ||||
| 						SAssignNew(ProjectDestinationComboBox, SComboBox<TSharedRef<FCSProjectDestination>>) | ||||
| 					    .OptionsSource(&ProjectDestinations) | ||||
| 					    .InitiallySelectedItem(ProjectDestinations[SelectedProjectDestinationIndex]) | ||||
| 					    .OnSelectionChanged(this, &SCSNewProjectDialog::OnProjectDestinationChanged) | ||||
| 					    .OnGenerateWidget_Static(&SCSNewProjectDialog::OnGenerateProjectDestinationWidget) | ||||
| 					    .Content() | ||||
|                         [ | ||||
|                             SNew(STextBlock).Text_Lambda([this] | ||||
|                             { | ||||
|                                 if (SelectedProjectDestinationIndex == INDEX_NONE) | ||||
|                                 { | ||||
|                                     return FText(); | ||||
|                                 } | ||||
|  | ||||
|                                 return ProjectDestinations[SelectedProjectDestinationIndex]->GetDisplayName(); | ||||
|                             }) | ||||
|                         ] | ||||
| 					] | ||||
| 				] | ||||
| 			    + SVerticalBox::Slot() | ||||
|                 .Padding(0, 0, 0, 10) | ||||
|                 [ | ||||
|                     SNew(SHorizontalBox) | ||||
|                     + SHorizontalBox::Slot() | ||||
|                     .AutoWidth() | ||||
|                     .VAlign(VAlign_Center) | ||||
|                     .Padding(0, 0, 10, 0) | ||||
|                     [ | ||||
|                         SNew(STextBlock) | ||||
|                         .Text(LOCTEXT("NewProjectLocation", "Location")) | ||||
|                     ] | ||||
|                     + SHorizontalBox::Slot() | ||||
|                     .FillWidth(1) | ||||
|                     [ | ||||
|                         SAssignNew(PathTextBox, SEditableTextBox) | ||||
|                         .Text(FText::FromString(ScriptPath)) | ||||
|                     ] | ||||
|                     + SHorizontalBox::Slot() | ||||
|                     .AutoWidth() | ||||
|                     [ | ||||
|                         SNew(SButton) | ||||
|                         .VAlign(VAlign_Center) | ||||
|                         .ButtonStyle(FAppStyle::Get(), "SimpleButton") | ||||
|                         .OnClicked(this, &SCSNewProjectDialog::OnExplorerButtonClicked) | ||||
|                         [ | ||||
|                             SNew(SImage) | ||||
|                             .Image(FAppStyle::Get().GetBrush("Icons.FolderClosed")) | ||||
|                             .ColorAndOpacity(FSlateColor::UseForeground()) | ||||
|                         ] | ||||
|                     ] | ||||
|                 ] | ||||
| 			] | ||||
| 		] | ||||
| 	]; | ||||
|  | ||||
| 	OnProjectDestinationChanged(ProjectDestinations[SelectedProjectDestinationIndex], ESelectInfo::Direct); | ||||
| } | ||||
|  | ||||
| void SCSNewProjectDialog::OnProjectDestinationChanged(TSharedPtr<FCSProjectDestination> NewProjectDestination, ESelectInfo::Type) | ||||
| { | ||||
|     if (NewProjectDestination == nullptr) | ||||
|     { | ||||
|         SelectedProjectDestinationIndex = INDEX_NONE; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     SelectedProjectDestinationIndex = NewProjectDestination->GetIndex(); | ||||
|     PathTextBox->SetText(FText::FromString(NewProjectDestination->GetPath())); | ||||
| 	 | ||||
| 	FString ManagedName = TEXT("Managed") + NewProjectDestination->GetName(); | ||||
| 	NameTextBox->SetText(FText::FromString(ManagedName)); | ||||
| } | ||||
|  | ||||
| TSharedRef<SWidget> SCSNewProjectDialog::OnGenerateProjectDestinationWidget(TSharedRef<FCSProjectDestination> Destination) | ||||
| { | ||||
|     return SNew(STextBlock) | ||||
|         .Text(Destination->GetDisplayName()); | ||||
| } | ||||
|  | ||||
| void SCSNewProjectDialog::OnPathSelected(const FString& NewPath) | ||||
| { | ||||
| 	if (NewPath.IsEmpty()) | ||||
| 	{ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	PathTextBox->SetText(FText::FromString(NewPath)); | ||||
| } | ||||
|  | ||||
| FReply SCSNewProjectDialog::OnExplorerButtonClicked() | ||||
| { | ||||
| 	IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get(); | ||||
|  | ||||
| 	if (!DesktopPlatform) | ||||
| 	{ | ||||
| 		return FReply::Handled(); | ||||
| 	} | ||||
|  | ||||
| 	TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); | ||||
| 	void* ParentWindowWindowHandle = ParentWindow.IsValid() ? ParentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr; | ||||
|  | ||||
| 	FString FolderName; | ||||
| 	const FString Title = TEXT("Choose a location for new project"); | ||||
| 	if (DesktopPlatform->OpenDirectoryDialog(ParentWindowWindowHandle, Title,FCSProcHelper::GetScriptFolderDirectory(), FolderName)) | ||||
| 	{ | ||||
| 		if (!FolderName.EndsWith(TEXT("/")) ) | ||||
| 		{ | ||||
| 			FolderName += TEXT("/"); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if (FolderName.IsEmpty()) | ||||
| 	{ | ||||
| 		return FReply::Handled(); | ||||
| 	} | ||||
|  | ||||
| 	PathTextBox->SetText(FText::FromString(FolderName)); | ||||
|  | ||||
| 	return FReply::Handled(); | ||||
| } | ||||
|  | ||||
| void SCSNewProjectDialog::OnCancel() | ||||
| { | ||||
| 	CloseWindow(); | ||||
| } | ||||
|  | ||||
| void SCSNewProjectDialog::OnFinish() | ||||
| { | ||||
| 	TMap<FString, FString> Arguments; | ||||
| 	FString ModuleName = NameTextBox->GetText().ToString(); | ||||
| 	FString ProjectParentFolder = PathTextBox->GetText().ToString(); | ||||
|  | ||||
| 	FString ProjectRoot; | ||||
| 	FString GlueProjectLocation; | ||||
| 	FString GlueProjectName; | ||||
|  | ||||
| 	auto MakeGlueNameAndLocation = [](FString& GlueLocation, FString& GlueName, const FString& PluginName, const FString& CsProjFolder) | ||||
| 	{ | ||||
| 		GlueName = FString::Printf(TEXT("%s.Glue"), *PluginName); | ||||
| 		GlueLocation = FPaths::Combine(CsProjFolder, FString::Printf(TEXT("%s.csproj"), *GlueName)); | ||||
| 	}; | ||||
| 	 | ||||
|     if (ProjectDestinations.IsValidIndex(SelectedProjectDestinationIndex) && SelectedProjectDestinationIndex > 0) | ||||
|     { | ||||
|     	const TSharedRef<FCSProjectDestination>& Destination = ProjectDestinations[SelectedProjectDestinationIndex]; | ||||
|     	const TSharedPtr<IPlugin>& Plugin = Destination->GetPlugin(); | ||||
|  | ||||
|     	ProjectRoot = Plugin->GetBaseDir(); | ||||
|     	MakeGlueNameAndLocation(GlueProjectLocation, GlueProjectName, Plugin->GetName(), FPaths::Combine(Destination->GetPath(), GlueProjectName)); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|     	ProjectRoot = FPaths::ProjectDir(); | ||||
|     	MakeGlueNameAndLocation(GlueProjectLocation, GlueProjectName, FApp::GetProjectName(), FCSProcHelper::GetProjectGlueFolderPath()); | ||||
|     } | ||||
|  | ||||
| 	if (!FPaths::FileExists(GlueProjectLocation)) | ||||
| 	{ | ||||
| 		Arguments.Add(TEXT("SkipIncludeProjectGlue"), TEXT("true")); | ||||
| 	} | ||||
|  | ||||
| 	Arguments.Add(TEXT("GlueProjectName"), GlueProjectName); | ||||
| 	 | ||||
| 	FUnrealSharpEditorModule::Get().AddNewProject(ModuleName, ProjectParentFolder, ProjectRoot, Arguments); | ||||
| 	CloseWindow(); | ||||
| } | ||||
|  | ||||
| bool SCSNewProjectDialog::CanFinish() const | ||||
| { | ||||
| 	FString Name = NameTextBox->GetText().ToString(); | ||||
| 	FString Path = PathTextBox->GetText().ToString(); | ||||
| 	FString Filename = Name + ".csproj"; | ||||
| 	FString AbsolutePath = Path / Filename; | ||||
|  | ||||
| 	// Path can't be empty, name can't be empty, and path must contain the script path | ||||
| 	if (Path.IsEmpty() || Name.IsEmpty() || SelectedProjectDestinationIndex == INDEX_NONE | ||||
| 	    || !Path.Contains(ProjectDestinations[SelectedProjectDestinationIndex]->GetPath())) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// Name can't contain spaces | ||||
| 	if (Name.Contains(TEXT(" "))) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// Path must be a valid directory | ||||
| 	if (FPaths::DirectoryExists(Path / Name)) | ||||
| 	{ | ||||
| 		return false; | ||||
| 	} | ||||
|  | ||||
| 	// File must not already exist | ||||
| 	IFileManager& FileManager = IFileManager::Get(); | ||||
| 	TArray<FString> AssemblyPaths; | ||||
| 	FileManager.FindFiles(AssemblyPaths, *Path, TEXT(".csproj")); | ||||
|  | ||||
| 	for (const FString& AssemblyPath : AssemblyPaths) | ||||
| 	{ | ||||
| 		FString ProjectName = FPaths::GetBaseFilename(AssemblyPath); | ||||
| 		if (ProjectName == Name) | ||||
| 		{ | ||||
| 			return false; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return true; | ||||
| } | ||||
|  | ||||
| void SCSNewProjectDialog::CloseWindow() | ||||
| { | ||||
| 	TSharedPtr<SWindow> ContainingWindow = FSlateApplication::Get().FindWidgetWindow(AsShared()); | ||||
| 	if (ContainingWindow.IsValid()) | ||||
| 	{ | ||||
| 		ContainingWindow->RequestDestroyWindow(); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| #undef LOCTEXT_NAMESPACE | ||||
| @ -0,0 +1,63 @@ | ||||
| #pragma once | ||||
|  | ||||
| struct FCSProjectDestination | ||||
| { | ||||
|     FCSProjectDestination(const FName InKey, FText InDisplayName, FString InName, FString InPath, const int32 Index, TSharedPtr<IPlugin> Plugin = nullptr) : | ||||
|         Key(InKey), DisplayName(MoveTemp(InDisplayName)), Name(MoveTemp(InName)), Path(MoveTemp(InPath)), Index(Index), Plugin(MoveTemp(Plugin)) {} | ||||
|  | ||||
|     FName GetKey() const { return Key; } | ||||
|     const FText& GetDisplayName() const { return DisplayName; } | ||||
| 	const FString& GetName() const { return Name; } | ||||
|     const FString& GetPath() const { return Path; } | ||||
|     int32 GetIndex() const { return Index; } | ||||
|     const TSharedPtr<IPlugin>& GetPlugin() const { return Plugin; } | ||||
|  | ||||
| private: | ||||
|     FName Key; | ||||
|     FText DisplayName; | ||||
| 	FString Name; | ||||
|     FString Path; | ||||
|     int32 Index; | ||||
|     TSharedPtr<IPlugin> Plugin; | ||||
|  | ||||
|     friend uint32 GetTypeHash(const FCSProjectDestination& ProjectDestination) | ||||
|     { | ||||
|         return GetTypeHash(ProjectDestination.Key); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| class SCSNewProjectDialog : public SCompoundWidget | ||||
| { | ||||
|  | ||||
| public: | ||||
|  | ||||
| 	SLATE_BEGIN_ARGS(SCSNewProjectDialog) {} | ||||
| 	SLATE_END_ARGS() | ||||
|  | ||||
| 	void Construct(const FArguments& InArgs); | ||||
|  | ||||
| private: | ||||
|  | ||||
|     void OnProjectDestinationChanged(TSharedPtr<FCSProjectDestination> NewProjectDestination, ESelectInfo::Type SelectInfo); | ||||
|     static TSharedRef<SWidget> OnGenerateProjectDestinationWidget(TSharedRef<FCSProjectDestination> Destination); | ||||
| 	void OnPathSelected(const FString& NewPath); | ||||
| 	FReply OnExplorerButtonClicked(); | ||||
|  | ||||
| 	void OnCancel(); | ||||
| 	void OnFinish(); | ||||
|  | ||||
| 	bool CanFinish() const; | ||||
|  | ||||
| 	void CloseWindow(); | ||||
|  | ||||
| private: | ||||
|  | ||||
| 	TSharedPtr<SEditableTextBox> PathTextBox; | ||||
|     TSharedPtr<SComboBox<TSharedRef<FCSProjectDestination>>> ProjectDestinationComboBox; | ||||
| 	TSharedPtr<SEditableTextBox> NameTextBox; | ||||
|  | ||||
| 	FString SuggestedProjectName; | ||||
|     TArray<TSharedRef<FCSProjectDestination>> ProjectDestinations; | ||||
|     int32 SelectedProjectDestinationIndex = INDEX_NONE; | ||||
|  | ||||
| }; | ||||
		Reference in New Issue
	
	Block a user