2014-03-14 14:13:41 -04:00
// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
# include "GameProjectGenerationPrivatePCH.h"
# include "MainFrame.h"
# include "DesktopPlatformModule.h"
# include "SourceCodeNavigation.h"
# include "SScrollBorder.h"
2014-08-18 06:48:04 -04:00
# include "TemplateCategory.h"
2014-08-19 06:33:39 -04:00
# include "GameProjectGenerationModule.h"
2014-08-27 21:25:34 -04:00
# include "SWizard.h"
2014-09-09 12:16:36 -04:00
# include "HardwareTargetingModule.h"
2014-10-01 06:07:53 -04:00
# include "SDecoratedEnumCombo.h"
2014-09-19 18:16:03 -04:00
# include "Editor/Documentation/Public/IDocumentation.h"
2014-10-01 06:08:05 -04:00
# include "BreakIterator.h"
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "NewProjectWizard"
FName SNewProjectWizard : : TemplatePageName = TEXT ( " Template " ) ;
FName SNewProjectWizard : : NameAndLocationPageName = TEXT ( " NameAndLocation " ) ;
2014-08-27 21:25:34 -04:00
2014-08-18 06:48:04 -04:00
namespace
{
const float ThumbnailSize = 64.f , ThumbnailPadding = 5.f ;
const float ItemWidth = ThumbnailSize + 2 * ThumbnailPadding ;
const float ItemHeight = ItemWidth + 30 ;
}
/** Struct describing a single template project */
2014-03-14 14:13:41 -04:00
struct FTemplateItem
{
2014-08-18 06:48:04 -04:00
FText Name ;
FText Description ;
bool bGenerateCode ;
FName Type ;
2014-03-14 14:13:41 -04:00
2014-08-18 06:48:04 -04:00
FString SortKey ;
FString ProjectFile ;
TSharedPtr < FSlateBrush > Thumbnail ;
TSharedPtr < FSlateBrush > PreviewImage ;
FTemplateItem ( FText InName , FText InDescription , bool bInGenerateCode , FName InType , FString InSortKey , FString InProjectFile , TSharedPtr < FSlateBrush > InThumbnail , TSharedPtr < FSlateBrush > InPreviewImage )
: Name ( InName ) , Description ( InDescription ) , bGenerateCode ( bInGenerateCode ) , Type ( InType ) , SortKey ( MoveTemp ( InSortKey ) ) , ProjectFile ( MoveTemp ( InProjectFile ) ) , Thumbnail ( InThumbnail ) , PreviewImage ( InPreviewImage )
2014-03-14 14:13:41 -04:00
{ }
} ;
2014-08-18 06:48:04 -04:00
/**
* Simple widget used to display a folder path , and a name of a file :
* __________________________ ____________________
* | C : \ Users \ Joe . Bloggs | | SomeFile . txt |
* | - - - - - - - - Folder - - - - - - - - | | - - - - - - Name - - - - - - |
*/
class SFilepath : public SCompoundWidget
2014-07-03 10:48:59 -04:00
{
2014-08-18 06:48:04 -04:00
public :
SLATE_BEGIN_ARGS ( SFilepath )
: _LabelBackgroundColor ( FLinearColor : : Black )
, _LabelBackgroundBrush ( FEditorStyle : : GetBrush ( " WhiteBrush " ) )
{ }
/** Attribute specifying the text to display in the folder input */
SLATE_ATTRIBUTE ( FText , FolderPath )
/** Attribute specifying the text to display in the name input */
SLATE_ATTRIBUTE ( FText , Name )
/** Background label tint for the folder/name labels */
SLATE_ATTRIBUTE ( FSlateColor , LabelBackgroundColor )
/** Background label brush for the folder/name labels */
SLATE_ATTRIBUTE ( const FSlateBrush * , LabelBackgroundBrush )
/** Event that is triggered when the browser for folder button is clicked */
SLATE_EVENT ( FOnClicked , OnBrowseForFolder )
/** Events for when the name field is manipulated */
SLATE_EVENT ( FOnTextChanged , OnNameChanged )
SLATE_EVENT ( FOnTextCommitted , OnNameCommitted )
/** Events for when the folder field is manipulated */
SLATE_EVENT ( FOnTextChanged , OnFolderChanged )
SLATE_EVENT ( FOnTextCommitted , OnFolderCommitted )
SLATE_END_ARGS ( )
/** Constructs this widget with InArgs */
void Construct ( const FArguments & InArgs )
2014-07-03 10:48:59 -04:00
{
2014-08-18 06:48:04 -04:00
ChildSlot
[
SNew ( SGridPanel )
. FillColumn ( 0 , 2.f )
. FillColumn ( 1 , 1.f )
// Folder input
+ SGridPanel : : Slot ( 0 , 0 )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
[
SNew ( SEditableTextBox )
. Text ( InArgs . _FolderPath )
// Large right hand padding to make room for the browse button
. Padding ( FMargin ( 5.f , 3.f , 25.f , 3.f ) )
. OnTextChanged ( InArgs . _OnFolderChanged )
. OnTextCommitted ( InArgs . _OnFolderCommitted )
]
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Right )
[
SNew ( SButton )
. ButtonStyle ( FEditorStyle : : Get ( ) , " FilePath.FolderButton " )
. ContentPadding ( FMargin ( 4.f , 0.f ) )
. OnClicked ( InArgs . _OnBrowseForFolder )
. ToolTipText ( LOCTEXT ( " BrowseForFolder " , " Browse for a folder " ) )
. Text ( LOCTEXT ( " ... " , " ... " ) )
]
]
// Folder label
+ SGridPanel : : Slot ( 0 , 1 )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
. HeightOverride ( 3 )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " FilePath.GroupIndicator " ) )
. BorderBackgroundColor ( FLinearColor ( 1.f , 1.f , 1.f , 0.5f ) )
. Padding ( FMargin ( 150.f , 0.f ) )
]
]
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
SNew ( SBorder )
. Padding ( 5.f )
. BorderImage ( InArgs . _LabelBackgroundBrush )
. BorderBackgroundColor ( InArgs . _LabelBackgroundColor )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " Folder " , " Folder " ) )
]
]
]
// Name input
+ SGridPanel : : Slot ( 1 , 0 )
. Padding ( FMargin ( 5.f , 0.f , 0.f , 0.f ) )
. VAlign ( VAlign_Center )
[
SNew ( SEditableTextBox )
. Text ( InArgs . _Name )
. Padding ( FMargin ( 5.f , 3.f ) )
. OnTextChanged ( InArgs . _OnNameChanged )
. OnTextCommitted ( InArgs . _OnNameCommitted )
]
// Name label
+ SGridPanel : : Slot ( 1 , 1 )
. Padding ( FMargin ( 5.f , 0.f , 0.f , 0.f ) )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
. HeightOverride ( 3 )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " FilePath.GroupIndicator " ) )
. BorderBackgroundColor ( FLinearColor ( 1.f , 1.f , 1.f , 0.5f ) )
. Padding ( FMargin ( 75.f , 0.f ) )
]
]
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Center )
[
SNew ( SBorder )
. Padding ( 5.f )
. BorderImage ( InArgs . _LabelBackgroundBrush )
. BorderBackgroundColor ( InArgs . _LabelBackgroundColor )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " Name " , " Name " ) )
]
]
]
] ;
2014-07-03 10:48:59 -04:00
}
} ;
2014-08-18 06:48:04 -04:00
/** Slate tile widget for template projects */
class STemplateTile : public STableRow < TSharedPtr < FTemplateItem > >
{
public :
SLATE_BEGIN_ARGS ( STemplateTile ) { }
SLATE_ARGUMENT ( TSharedPtr < FTemplateItem > , Item )
SLATE_END_ARGS ( )
private :
TWeakPtr < FTemplateItem > Item ;
public :
/** Static build function */
static TSharedRef < ITableRow > BuildTile ( TSharedPtr < FTemplateItem > Item , const TSharedRef < STableViewBase > & OwnerTable )
{
if ( ! ensure ( Item . IsValid ( ) ) )
{
return SNew ( STableRow < TSharedPtr < FTemplateItem > > , OwnerTable ) ;
}
return SNew ( STemplateTile , OwnerTable ) . Item ( Item ) ;
}
/** Constructs this widget with InArgs */
void Construct ( const FArguments & InArgs , const TSharedRef < STableViewBase > & OwnerTable )
{
check ( InArgs . _Item . IsValid ( ) )
Item = InArgs . _Item ;
STableRow : : Construct (
STableRow : : FArguments ( )
. Style ( FEditorStyle : : Get ( ) , " GameProjectDialog.TemplateListView.TableRow " )
. Content ( )
[
SNew ( SVerticalBox )
// Thumbnail
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. HAlign ( HAlign_Center )
2014-09-09 12:16:36 -04:00
. Padding ( ThumbnailPadding )
2014-08-18 06:48:04 -04:00
[
SNew ( SBox )
. WidthOverride ( ThumbnailSize )
. HeightOverride ( ThumbnailSize )
[
SNew ( SImage )
. Image ( this , & STemplateTile : : GetThumbnail )
]
]
// Name
+ SVerticalBox : : Slot ( )
. HAlign ( HAlign_Center )
. VAlign ( VAlign_Top )
2014-09-09 12:16:36 -04:00
. Padding ( FMargin ( ThumbnailPadding , 0 ) )
2014-08-18 06:48:04 -04:00
[
2014-10-01 06:08:05 -04:00
SNew ( STextBlock )
2014-09-09 12:16:36 -04:00
. AutoWrapText ( true )
2014-08-18 06:48:04 -04:00
. Justification ( ETextJustify : : Center )
2014-10-01 06:08:05 -04:00
. LineBreakPolicy ( FBreakIterator : : CreateCamelCaseBreakIterator ( ) )
2014-08-18 06:48:04 -04:00
//.HighlightText(this, &SNewProjectWizard::GetItemHighlightText)
. Text ( InArgs . _Item - > Name )
]
] ,
OwnerTable
) ;
}
private :
/** Get this item's thumbnail or return the default */
const FSlateBrush * GetThumbnail ( ) const
{
auto ItemPtr = Item . Pin ( ) ;
if ( ItemPtr . IsValid ( ) & & ItemPtr - > Thumbnail . IsValid ( ) )
{
return ItemPtr - > Thumbnail . Get ( ) ;
}
2014-09-09 12:16:36 -04:00
return FEditorStyle : : GetBrush ( " GameProjectDialog.DefaultGameThumbnail.Small " ) ;
2014-08-18 06:48:04 -04:00
}
} ;
2014-03-14 14:13:41 -04:00
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SNewProjectWizard : : Construct ( const FArguments & InArgs )
{
LastValidityCheckTime = 0 ;
ValidityCheckFrequency = 4 ;
bLastGlobalValidityCheckSuccessful = true ;
bLastNameAndLocationValidityCheckSuccessful = true ;
bPreventPeriodicValidityChecksUntilNextChange = false ;
2014-09-09 12:16:36 -04:00
IHardwareTargetingModule & HardwareTargeting = IHardwareTargetingModule : : Get ( ) ;
SelectedHardwareClassTarget = EHardwareClass : : Desktop ;
SelectedGraphicsPreset = EGraphicsPreset : : Maximum ;
2014-03-14 14:13:41 -04:00
// Find all template projects
FindTemplateProjects ( ) ;
SetDefaultProjectLocation ( ) ;
2014-08-18 06:48:04 -04:00
SAssignNew ( TemplateListView , STileView < TSharedPtr < FTemplateItem > > )
. ListItemsSource ( & FilteredTemplateList )
2014-03-14 14:13:41 -04:00
. SelectionMode ( ESelectionMode : : Single )
. ClearSelectionOnClick ( false )
2014-08-18 06:48:04 -04:00
. OnGenerateTile_Static ( & STemplateTile : : BuildTile )
. ItemHeight ( ItemHeight )
. ItemWidth ( ItemWidth )
2014-03-14 14:13:41 -04:00
. OnMouseButtonDoubleClick ( this , & SNewProjectWizard : : HandleTemplateListViewDoubleClick )
. OnSelectionChanged ( this , & SNewProjectWizard : : HandleTemplateListViewSelectionChanged ) ;
2014-08-18 06:48:04 -04:00
const EVisibility StarterContentVisiblity = GameProjectUtils : : IsStarterContentAvailableForNewProjects ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
2014-09-09 12:16:36 -04:00
TSharedRef < SSeparator > Separator = SNew ( SSeparator ) . Orientation ( EOrientation : : Orient_Vertical ) ;
Separator - > SetBorderBackgroundColor ( FLinearColor : : White . CopyWithNewOpacity ( 0.25f ) ) ;
2014-10-01 06:07:53 -04:00
TSharedPtr < SWidget > StartContentCombo ;
{
TArray < SDecoratedEnumCombo < int32 > : : FComboOption > StarterContentInfo ;
StarterContentInfo . Add ( SDecoratedEnumCombo < int32 > : : FComboOption (
0 , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " GameProjectDialog.NoStarterContent " ) , LOCTEXT ( " NoStarterContent " , " No Starter Content " ) ) ) ;
StarterContentInfo . Add ( SDecoratedEnumCombo < int32 > : : FComboOption (
1 , FSlateIcon ( FEditorStyle : : GetStyleSetName ( ) , " GameProjectDialog.IncludeStarterContent " ) , LOCTEXT ( " IncludeStarterContent " , " With Starter Content " ) ) ) ;
StartContentCombo = SNew ( SDecoratedEnumCombo < int32 > , MoveTemp ( StarterContentInfo ) )
. SelectedEnum ( this , & SNewProjectWizard : : GetCopyStarterContentIndex )
. OnEnumChanged ( this , & SNewProjectWizard : : OnSetCopyStarterContent )
. ToolTipText ( LOCTEXT ( " CopyStarterContent_ToolTip " , " Enable to include an additional content pack containing simple placeable meshes with basic materials and textures. \n You can opt out of including this to create a project that only has the bare essentials for the selected project template. " ) ) ;
}
2014-09-09 12:16:36 -04:00
const float UniformPadding = 16.f ;
2014-03-14 14:13:41 -04:00
ChildSlot
[
2014-09-09 12:16:36 -04:00
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
2014-03-14 14:13:41 -04:00
[
2014-09-09 12:16:36 -04:00
SNew ( SOverlay )
2014-03-14 14:13:41 -04:00
2014-09-09 12:16:36 -04:00
// Wizard
+ SOverlay : : Slot ( )
. Padding ( UniformPadding / 2 )
2014-03-14 14:13:41 -04:00
[
2014-09-09 12:16:36 -04:00
SAssignNew ( MainWizard , SWizard )
. ShowPageList ( false )
. ShowCancelButton ( false )
. CanFinish ( this , & SNewProjectWizard : : HandleCreateProjectWizardCanFinish )
. FinishButtonText ( LOCTEXT ( " FinishButtonText " , " Create Project " ) )
. FinishButtonToolTip ( LOCTEXT ( " FinishButtonToolTip " , " Creates your new project in the specified location with the specified template and name. " ) )
. OnFinished ( this , & SNewProjectWizard : : HandleCreateProjectWizardFinished )
. OnFirstPageBackClicked ( InArgs . _OnBackRequested )
2014-03-14 14:13:41 -04:00
2014-09-09 12:16:36 -04:00
// Choose Template
+ SWizard : : Page ( )
. OnEnter ( this , & SNewProjectWizard : : OnPageVisited , TemplatePageName )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " NoBorder " ) )
. Padding ( FMargin ( UniformPadding / 2 , UniformPadding / 2 , UniformPadding / 2 , 0 ) )
2014-03-14 14:13:41 -04:00
[
SNew ( SVerticalBox )
2014-09-09 12:16:36 -04:00
+ SVerticalBox : : Slot ( )
. Padding ( FMargin ( 0 , 0 , 0 , 15 ) )
2014-03-14 14:13:41 -04:00
. AutoHeight ( )
[
2014-09-09 12:16:36 -04:00
SNew ( STextBlock )
2014-09-19 18:16:03 -04:00
. Text ( LOCTEXT ( " ProjectTemplateDescription " , " First, choose a template to use as a starting point for your new project: " ) )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip ( LOCTEXT ( " TemplateChoiceTooltip " , " A template consists of a little bit of player control logic (either as a Blueprint or in C++), input bindings, and appropriate prototyping assets. " ) , NULL , TEXT ( " Shared/Editor/NewProjectWizard " ) , TEXT ( " TemplateChoice " ) ) )
2014-03-14 14:13:41 -04:00
]
2014-08-18 06:48:04 -04:00
+ SVerticalBox : : Slot ( )
[
2014-09-09 12:16:36 -04:00
// Template category tabs
2014-08-18 06:48:04 -04:00
SNew ( SVerticalBox )
2014-09-09 12:16:36 -04:00
+ SVerticalBox : : Slot ( )
. Padding ( FMargin ( 8.f , 0.f ) )
2014-08-18 06:48:04 -04:00
. AutoHeight ( )
[
2014-09-09 12:16:36 -04:00
BuildCategoryTabs ( )
2014-08-18 06:48:04 -04:00
]
2014-09-09 12:16:36 -04:00
// Templates list
2014-08-18 06:48:04 -04:00
+ SVerticalBox : : Slot ( )
2014-09-09 12:16:36 -04:00
. FillHeight ( 1.0f )
2014-08-18 06:48:04 -04:00
[
SNew ( SBorder )
2014-09-09 12:16:36 -04:00
. Padding ( UniformPadding )
. BorderImage ( FEditorStyle : : GetBrush ( " GameProjectDialog.TabBackground " ) )
2014-08-18 06:48:04 -04:00
[
2014-09-09 12:16:36 -04:00
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
[
SNew ( SScrollBorder , TemplateListView . ToSharedRef ( ) )
[
TemplateListView . ToSharedRef ( )
]
]
+ SHorizontalBox : : Slot ( )
. Padding ( UniformPadding , 0 )
. AutoWidth ( )
[
Separator
]
// Selected template details
+ SHorizontalBox : : Slot ( )
[
SNew ( SScrollBox )
+ SScrollBox : : Slot ( )
. Padding ( UniformPadding , 0 )
[
SNew ( SVerticalBox )
// Preview image
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. HAlign ( HAlign_Center )
. Padding ( FMargin ( 0 , 0 , 0 , 15.f ) )
[
SNew ( SBox )
. Visibility ( this , & SNewProjectWizard : : GetSelectedTemplatePreviewVisibility )
. WidthOverride ( 400 )
. HeightOverride ( 200 )
[
SNew ( SOverlay )
+ SOverlay : : Slot ( )
[
SNew ( SBorder )
2014-09-15 05:59:46 -04:00
. Padding ( FMargin ( 0 , 0 , 0 , 4.f ) )
2014-09-09 12:16:36 -04:00
. BorderImage ( FEditorStyle : : GetBrush ( " ContentBrowser.ThumbnailShadow " ) )
[
SNew ( SImage )
. Image ( this , & SNewProjectWizard : : GetSelectedTemplatePreviewImage )
]
]
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Right )
. VAlign ( VAlign_Top )
. Padding ( 10 )
[
SNew ( SBox )
. WidthOverride ( 48 )
. HeightOverride ( 48 )
[
SNew ( SImage )
. Image ( this , & SNewProjectWizard : : GetSelectedTemplateTypeImage )
]
]
]
]
// Template Name
+ SVerticalBox : : Slot ( )
. Padding ( FMargin ( 0 , 0 , 0 , 10 ) )
. AutoHeight ( )
[
SNew ( STextBlock )
. AutoWrapText ( true )
. TextStyle ( FEditorStyle : : Get ( ) , " GameProjectDialog.FeatureText " )
. Text ( this , & SNewProjectWizard : : GetSelectedTemplateProperty < FText > , & FTemplateItem : : Name )
]
// Template Description
+ SVerticalBox : : Slot ( )
[
SNew ( STextBlock )
. AutoWrapText ( true )
. Text ( this , & SNewProjectWizard : : GetSelectedTemplateProperty < FText > , & FTemplateItem : : Description )
]
]
]
2014-08-18 06:48:04 -04:00
]
]
2014-09-09 12:16:36 -04:00
]
2014-08-18 06:48:04 -04:00
2014-09-09 12:16:36 -04:00
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( FMargin ( 0 , 15 , 0 , 0 ) )
[
SNew ( SScrollBox )
+ SScrollBox : : Slot ( )
2014-08-18 06:48:04 -04:00
[
2014-09-09 12:16:36 -04:00
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
2014-09-19 18:16:03 -04:00
. Padding ( FMargin ( 0 , 0 , 0 , 15.f ) )
2014-09-09 12:16:36 -04:00
[
SNew ( STextBlock )
2014-09-19 18:16:03 -04:00
. Text ( LOCTEXT ( " ProjectSettingsDescription " , " Next, choose some settings for your project. Don't worry, you can choose later or change these at any time in [Project Settings - Target Hardware]: " ) )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip ( LOCTEXT ( " HardwareTargetTooltip " , " These settings will choose good defaults for a number of other settings in the project such as post-processing flags and touch input emulation using the mouse. " ) , NULL , TEXT ( " Shared/Editor/NewProjectWizard " ) , TEXT ( " TargetHardware " ) ) )
2014-09-09 12:16:36 -04:00
]
+ SVerticalBox : : Slot ( )
. HAlign ( HAlign_Center )
. AutoHeight ( )
[
SNew ( SBox )
. WidthOverride ( 650 )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. HAlign ( HAlign_Center )
. Padding ( FMargin ( 0 , 0 , 0 , 25.f ) )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
HardwareTargeting . MakeHardwareClassTargetCombo (
FOnHardwareClassChanged : : CreateSP ( this , & SNewProjectWizard : : SetHardwareClassTarget ) ,
TAttribute < EHardwareClass : : Type > ( this , & SNewProjectWizard : : GetHardwareClassTarget )
)
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( FMargin ( 30 , 0 ) )
[
HardwareTargeting . MakeGraphicsPresetTargetCombo (
FOnGraphicsPresetChanged : : CreateSP ( this , & SNewProjectWizard : : SetGraphicsPreset ) ,
TAttribute < EGraphicsPreset : : Type > ( this , & SNewProjectWizard : : GetGraphicsPreset )
)
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
2014-09-25 22:44:16 -04:00
SNew ( SOverlay )
+ SOverlay : : Slot ( )
2014-09-09 12:16:36 -04:00
[
2014-10-01 06:07:53 -04:00
StartContentCombo . ToSharedRef ( )
2014-09-25 22:44:16 -04:00
]
2014-09-09 12:16:36 -04:00
2014-09-25 22:44:16 -04:00
// Warning when enabled for mobile, since the current starter content is bad for mobile
+ SOverlay : : Slot ( )
//.Visibility(EVisibility::SelfHitTestInvisible)
. HAlign ( HAlign_Right )
. VAlign ( VAlign_Top )
. Padding ( 4 )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " Icons.Warning " ) )
. ToolTipText ( this , & SNewProjectWizard : : GetStarterContentWarningTooltip )
. Visibility ( this , & SNewProjectWizard : : GetStarterContentWarningVisibility )
2014-09-09 12:16:36 -04:00
]
]
]
]
]
2014-09-19 18:16:03 -04:00
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( FMargin ( 0 , 0 , 0 , 15.f ) )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " ProjectPathDescription " , " Finally, choose a location for your project to be stored: " ) )
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip ( LOCTEXT ( " ProjectPathDescriptionTooltip " , " All of your project content and code will be stored here. " ) , NULL , TEXT ( " Shared/Editor/NewProjectWizard " ) , TEXT ( " ProjectPath " ) ) )
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. HAlign ( HAlign_Center )
[
// File path widget
SNew ( SFilepath )
. OnBrowseForFolder ( this , & SNewProjectWizard : : HandleBrowseButtonClicked )
. LabelBackgroundBrush ( FEditorStyle : : GetBrush ( " ProjectBrowser.Background " ) )
. LabelBackgroundColor ( FLinearColor : : White )
. FolderPath ( this , & SNewProjectWizard : : GetCurrentProjectFilePath )
. Name ( this , & SNewProjectWizard : : GetCurrentProjectFileName )
. OnFolderChanged ( this , & SNewProjectWizard : : OnCurrentProjectFilePathChanged )
. OnNameChanged ( this , & SNewProjectWizard : : OnCurrentProjectFileNameChanged )
]
2014-08-18 06:48:04 -04:00
]
]
]
2014-03-14 14:13:41 -04:00
]
]
2014-09-09 12:16:36 -04:00
// Global Error label
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Bottom )
. Padding ( UniformPadding / 2 )
2014-03-14 14:13:41 -04:00
[
SNew ( SBorder )
. Visibility ( this , & SNewProjectWizard : : GetGlobalErrorLabelVisibility )
. BorderImage ( FEditorStyle : : GetBrush ( " GameProjectDialog.ErrorLabelBorder " ) )
2014-09-09 12:16:36 -04:00
. Padding ( UniformPadding / 2 )
2014-03-14 14:13:41 -04:00
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. FillWidth ( 1.0f )
[
SNew ( STextBlock )
. Text ( this , & SNewProjectWizard : : GetGlobalErrorLabelText )
. TextStyle ( FEditorStyle : : Get ( ) , TEXT ( " GameProjectDialog.ErrorLabelFont " ) )
]
// A link to a platform-specific IDE, only shown when a compiler is not available
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( SHyperlink )
. Text ( FText : : Format ( LOCTEXT ( " IDEDownloadLinkText " , " Download {0} " ) , FSourceCodeNavigation : : GetSuggestedSourceCodeIDE ( ) ) )
. OnNavigate ( this , & SNewProjectWizard : : OnDownloadIDEClicked , FSourceCodeNavigation : : GetSuggestedSourceCodeIDEDownloadURL ( ) )
. Visibility ( this , & SNewProjectWizard : : GetGlobalErrorLabelIDELinkVisibility )
]
// A button to close the persistent global error text
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
[
SNew ( SButton )
. ButtonStyle ( FEditorStyle : : Get ( ) , " NoBorder " )
. ContentPadding ( 0.0f )
. OnClicked ( this , & SNewProjectWizard : : OnCloseGlobalErrorLabelClicked )
. Visibility ( this , & SNewProjectWizard : : GetGlobalErrorLabelCloseButtonVisibility )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " GameProjectDialog.ErrorLabelCloseButton " ) )
]
]
]
]
2014-09-09 12:16:36 -04:00
// Project filename error
+ SOverlay : : Slot ( )
. HAlign ( HAlign_Left )
. VAlign ( VAlign_Bottom )
. Padding ( UniformPadding / 2 )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " GameProjectDialog.ErrorLabelBorder " ) )
. Visibility ( this , & SNewProjectWizard : : GetNameAndLocationErrorLabelVisibility )
. Padding ( UniformPadding / 2 )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. FillWidth ( 1.0f )
[
SNew ( STextBlock )
. AutoWrapText ( true )
. Text ( this , & SNewProjectWizard : : GetNameAndLocationErrorLabelText )
. TextStyle ( FEditorStyle : : Get ( ) , " GameProjectDialog.ErrorLabelFont " )
]
]
]
2014-03-14 14:13:41 -04:00
]
] ;
// Initialize the current page name. Assuming the template page.
CurrentPageName = TemplatePageName ;
2014-08-18 06:48:04 -04:00
HandleCategoryChanged ( ESlateCheckBoxState : : Checked , ActiveCategory ) ;
2014-03-14 14:13:41 -04:00
UpdateProjectFileValidity ( ) ;
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
2014-08-18 06:48:04 -04:00
TSharedRef < SWidget > SNewProjectWizard : : BuildCategoryTabs ( )
{
TSharedRef < SHorizontalBox > TabStrip = SNew ( SHorizontalBox ) ;
TArray < FName > Categories ;
Templates . GenerateKeyArray ( Categories ) ;
for ( const FName & CategoryName : Categories )
{
TSharedPtr < const FTemplateCategory > Category = FGameProjectGenerationModule : : Get ( ) . GetCategory ( CategoryName ) ;
TSharedPtr < SHorizontalBox > HorizontalBox ;
TabStrip - > AddSlot ( ) . AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( FMargin ( 0 , 0 , 2.f , 0 ) )
[
SNew ( SBox )
// Constrain the height to 32px (for the image) plus 5px padding vertically
. HeightOverride ( 32.f + 5.f * 2 )
[
SNew ( SCheckBox )
. Style ( FEditorStyle : : Get ( ) , " GameProjectDialog.Tab " )
. OnCheckStateChanged ( this , & SNewProjectWizard : : HandleCategoryChanged , CategoryName )
. IsChecked ( this , & SNewProjectWizard : : GetCategoryTabCheckState , CategoryName )
. ToolTipText ( Category . IsValid ( ) ? Category - > Description : FText ( ) )
. Padding ( FMargin ( 5.f ) )
[
SAssignNew ( HorizontalBox , SHorizontalBox )
]
]
] ;
if ( Category . IsValid ( ) )
{
HorizontalBox - > AddSlot ( )
. AutoWidth ( )
[
SNew ( SBox )
. WidthOverride ( 32 )
. HeightOverride ( 32 )
[
SNew ( SImage )
2014-08-28 06:52:46 -04:00
. Image ( Category - > Icon )
2014-08-18 06:48:04 -04:00
]
] ;
}
HorizontalBox - > AddSlot ( )
. Padding ( 5.f , 0.f )
. VAlign ( VAlign_Center )
. AutoWidth ( )
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " GameProjectDialog.FeatureText " )
. Text ( Category . IsValid ( ) ? Category - > Name : FText : : FromString ( CategoryName . ToString ( ) ) )
] ;
}
return TabStrip ;
}
2014-10-01 06:07:53 -04:00
void SNewProjectWizard : : OnSetCopyStarterContent ( int32 InCopyStarterContent )
2014-03-14 14:13:41 -04:00
{
2014-10-01 06:07:53 -04:00
bCopyStarterContent = InCopyStarterContent ! = 0 ;
2014-03-14 14:13:41 -04:00
}
2014-09-25 22:44:16 -04:00
EVisibility SNewProjectWizard : : GetStarterContentWarningVisibility ( ) const
{
return ( bCopyStarterContent & & ( SelectedHardwareClassTarget = = EHardwareClass : : Mobile ) ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
FText SNewProjectWizard : : GetStarterContentWarningTooltip ( ) const
{
if ( SelectedGraphicsPreset = = EGraphicsPreset : : Maximum )
{
return LOCTEXT ( " StarterContentMobileWarning_Maximum " , " Note: Starter content can increase the packaged size significantly, removing the example maps will result in only packaging content that is actually used " ) ;
}
else
{
return LOCTEXT ( " StarterContentMobileWarning_Scalable " , " Warning: Starter content is not optimized for scalable mobile projects " ) ;
}
}
2014-03-14 14:13:41 -04:00
void SNewProjectWizard : : Tick ( const FGeometry & AllottedGeometry , const double InCurrentTime , const float InDeltaTime )
{
SCompoundWidget : : Tick ( AllottedGeometry , InCurrentTime , InDeltaTime ) ;
// Every few seconds, the project file path is checked for validity in case the disk contents changed and the location is now valid or invalid.
// After project creation, periodic checks are disabled to prevent a brief message indicating that the project you created already exists.
// This feature is re-enabled if the user did not restart and began editing parameters again.
if ( ! bPreventPeriodicValidityChecksUntilNextChange & & ( InCurrentTime > LastValidityCheckTime + ValidityCheckFrequency ) )
{
UpdateProjectFileValidity ( ) ;
}
}
void SNewProjectWizard : : HandleTemplateListViewSelectionChanged ( TSharedPtr < FTemplateItem > TemplateItem , ESelectInfo : : Type SelectInfo )
{
UpdateProjectFileValidity ( ) ;
}
TSharedPtr < FTemplateItem > SNewProjectWizard : : GetSelectedTemplateItem ( ) const
{
TArray < TSharedPtr < FTemplateItem > > SelectedItems = TemplateListView - > GetSelectedItems ( ) ;
if ( SelectedItems . Num ( ) > 0 )
{
return SelectedItems [ 0 ] ;
}
return NULL ;
}
2014-08-18 06:48:04 -04:00
const FSlateBrush * SNewProjectWizard : : GetSelectedTemplatePreviewImage ( ) const
{
auto PreviewImage = GetSelectedTemplateProperty ( & FTemplateItem : : PreviewImage ) ;
return PreviewImage . IsValid ( ) ? PreviewImage . Get ( ) : nullptr ;
}
2014-03-14 14:13:41 -04:00
2014-09-09 12:16:36 -04:00
EVisibility SNewProjectWizard : : GetSelectedTemplatePreviewVisibility ( ) const
{
auto PreviewImage = GetSelectedTemplateProperty ( & FTemplateItem : : PreviewImage ) ;
return PreviewImage . IsValid ( ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
2014-08-18 06:48:04 -04:00
const FSlateBrush * SNewProjectWizard : : GetSelectedTemplateTypeImage ( ) const
2014-03-14 14:13:41 -04:00
{
TSharedPtr < FTemplateItem > SelectedItem = GetSelectedTemplateItem ( ) ;
2014-08-18 06:48:04 -04:00
if ( SelectedItem . IsValid ( ) )
2014-03-14 14:13:41 -04:00
{
2014-08-18 06:48:04 -04:00
auto Category = FGameProjectGenerationModule : : Get ( ) . GetCategory ( SelectedItem - > Type ) ;
if ( Category . IsValid ( ) )
{
2014-08-28 06:52:46 -04:00
return Category - > Image ;
2014-08-18 06:48:04 -04:00
}
2014-03-14 14:13:41 -04:00
}
2014-08-18 06:48:04 -04:00
return nullptr ;
2014-03-14 14:13:41 -04:00
}
FText SNewProjectWizard : : GetCurrentProjectFileName ( ) const
{
2014-08-18 06:48:04 -04:00
return FText : : FromString ( CurrentProjectFileName ) ;
2014-03-14 14:13:41 -04:00
}
FString SNewProjectWizard : : GetCurrentProjectFileNameStringWithExtension ( ) const
{
2014-09-08 13:51:36 -04:00
return CurrentProjectFileName + TEXT ( " . " ) + FProjectDescriptor : : GetExtension ( ) ;
2014-03-14 14:13:41 -04:00
}
void SNewProjectWizard : : OnCurrentProjectFileNameChanged ( const FText & InValue )
{
CurrentProjectFileName = InValue . ToString ( ) ;
UpdateProjectFileValidity ( ) ;
}
FText SNewProjectWizard : : GetCurrentProjectFilePath ( ) const
{
return FText : : FromString ( CurrentProjectFilePath ) ;
}
FString SNewProjectWizard : : GetCurrentProjectFileParentFolder ( ) const
{
if ( CurrentProjectFilePath . EndsWith ( TEXT ( " / " ) ) | | CurrentProjectFilePath . EndsWith ( " \\ " ) )
{
return FPaths : : GetCleanFilename ( CurrentProjectFilePath . LeftChop ( 1 ) ) ;
}
else
{
return FPaths : : GetCleanFilename ( CurrentProjectFilePath ) ;
}
}
void SNewProjectWizard : : OnCurrentProjectFilePathChanged ( const FText & InValue )
{
CurrentProjectFilePath = InValue . ToString ( ) ;
2014-04-23 19:09:13 -04:00
FPaths : : MakePlatformFilename ( CurrentProjectFilePath ) ;
2014-03-14 14:13:41 -04:00
UpdateProjectFileValidity ( ) ;
}
FString SNewProjectWizard : : GetProjectFilenameWithPathLabelText ( ) const
{
return GetProjectFilenameWithPath ( ) ;
}
FString SNewProjectWizard : : GetProjectFilenameWithPath ( ) const
{
if ( CurrentProjectFilePath . IsEmpty ( ) )
{
// Don't even try to assemble the path or else it may be relative to the binaries folder!
return TEXT ( " " ) ;
}
else
{
const FString ProjectName = CurrentProjectFileName ;
const FString ProjectPath = IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForWrite ( * CurrentProjectFilePath ) ;
2014-09-08 13:51:36 -04:00
const FString Filename = ProjectName + TEXT ( " . " ) + FProjectDescriptor : : GetExtension ( ) ;
2014-04-23 19:09:13 -04:00
FString ProjectFilename = FPaths : : Combine ( * ProjectPath , * ProjectName , * Filename ) ;
FPaths : : MakePlatformFilename ( ProjectFilename ) ;
2014-03-14 14:13:41 -04:00
return ProjectFilename ;
}
}
FReply SNewProjectWizard : : HandleBrowseButtonClicked ( )
{
IDesktopPlatform * DesktopPlatform = FDesktopPlatformModule : : Get ( ) ;
if ( DesktopPlatform )
{
void * ParentWindowWindowHandle = NULL ;
IMainFrameModule & MainFrameModule = FModuleManager : : LoadModuleChecked < IMainFrameModule > ( TEXT ( " MainFrame " ) ) ;
const TSharedPtr < SWindow > & MainFrameParentWindow = MainFrameModule . GetParentWindow ( ) ;
if ( MainFrameParentWindow . IsValid ( ) & & MainFrameParentWindow - > GetNativeWindow ( ) . IsValid ( ) )
{
ParentWindowWindowHandle = MainFrameParentWindow - > GetNativeWindow ( ) - > GetOSWindowHandle ( ) ;
}
FString FolderName ;
const FString Title = LOCTEXT ( " NewProjectBrowseTitle " , " Choose a project location " ) . ToString ( ) ;
const bool bFolderSelected = DesktopPlatform - > OpenDirectoryDialog (
ParentWindowWindowHandle ,
Title ,
LastBrowsePath ,
FolderName
) ;
if ( bFolderSelected )
{
if ( ! FolderName . EndsWith ( TEXT ( " / " ) ) )
{
FolderName + = TEXT ( " / " ) ;
}
2014-04-23 19:09:13 -04:00
FPaths : : MakePlatformFilename ( FolderName ) ;
2014-03-14 14:13:41 -04:00
LastBrowsePath = FolderName ;
CurrentProjectFilePath = FolderName ;
}
}
return FReply : : Handled ( ) ;
}
void SNewProjectWizard : : OnDownloadIDEClicked ( FString URL )
{
FPlatformProcess : : LaunchURL ( * URL , NULL , NULL ) ;
}
void SNewProjectWizard : : HandleTemplateListViewDoubleClick ( TSharedPtr < FTemplateItem > TemplateItem )
{
// Advance to the name/location page
const int32 NamePageIdx = 1 ;
if ( MainWizard - > CanShowPage ( NamePageIdx ) )
{
MainWizard - > ShowPage ( NamePageIdx ) ;
}
}
bool SNewProjectWizard : : IsCreateProjectEnabled ( ) const
{
if ( CurrentPageName = = NAME_None ) //|| CurrentPageName == TemplatePageName )
{
return false ;
}
return bLastGlobalValidityCheckSuccessful & & bLastNameAndLocationValidityCheckSuccessful ;
}
bool SNewProjectWizard : : HandlePageCanShow ( FName PageName ) const
{
if ( PageName = = NameAndLocationPageName )
{
return bLastGlobalValidityCheckSuccessful ;
}
return true ;
}
void SNewProjectWizard : : OnPageVisited ( FName NewPageName )
{
CurrentPageName = NewPageName ;
}
EVisibility SNewProjectWizard : : GetGlobalErrorLabelVisibility ( ) const
{
2014-09-09 12:16:36 -04:00
const bool bIsVisible = GetNameAndLocationErrorLabelText ( ) . IsEmpty ( ) & & ! GetGlobalErrorLabelText ( ) . IsEmpty ( ) ;
return bIsVisible ? EVisibility : : Visible : EVisibility : : Hidden ;
2014-03-14 14:13:41 -04:00
}
EVisibility SNewProjectWizard : : GetGlobalErrorLabelCloseButtonVisibility ( ) const
{
return PersistentGlobalErrorLabelText . IsEmpty ( ) ? EVisibility : : Collapsed : EVisibility : : Visible ;
}
EVisibility SNewProjectWizard : : GetGlobalErrorLabelIDELinkVisibility ( ) const
{
return ( IsCompilerRequired ( ) & & ! FSourceCodeNavigation : : IsCompilerAvailable ( ) ) ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
FText SNewProjectWizard : : GetGlobalErrorLabelText ( ) const
{
if ( ! PersistentGlobalErrorLabelText . IsEmpty ( ) )
{
return PersistentGlobalErrorLabelText ;
}
if ( ! bLastGlobalValidityCheckSuccessful )
{
return LastGlobalValidityErrorText ;
}
return FText : : GetEmpty ( ) ;
}
FReply SNewProjectWizard : : OnCloseGlobalErrorLabelClicked ( )
{
PersistentGlobalErrorLabelText = FText ( ) ;
return FReply : : Handled ( ) ;
}
EVisibility SNewProjectWizard : : GetNameAndLocationErrorLabelVisibility ( ) const
{
2014-08-18 06:48:04 -04:00
return GetNameAndLocationErrorLabelText ( ) . IsEmpty ( ) ? EVisibility : : Collapsed : EVisibility : : Visible ;
2014-03-14 14:13:41 -04:00
}
FText SNewProjectWizard : : GetNameAndLocationErrorLabelText ( ) const
{
if ( ! bLastNameAndLocationValidityCheckSuccessful )
{
return LastNameAndLocationValidityErrorText ;
}
return FText : : GetEmpty ( ) ;
}
void SNewProjectWizard : : FindTemplateProjects ( )
{
2014-08-18 06:48:04 -04:00
// Default to showing the blueprint category
ActiveCategory = FTemplateCategory : : BlueprintCategoryName ;
2014-03-14 14:13:41 -04:00
// Add some default non-data driven templates
2014-08-18 06:48:04 -04:00
Templates . FindOrAdd ( FTemplateCategory : : BlueprintCategoryName ) . Add ( MakeShareable ( new FTemplateItem (
2014-03-14 14:13:41 -04:00
LOCTEXT ( " BlankProjectName " , " Blank " ) ,
LOCTEXT ( " BlankProjectDescription " , " A clean empty project with no code. " ) ,
2014-08-18 06:48:04 -04:00
false , FTemplateCategory : : BlueprintCategoryName ,
2014-07-03 10:48:59 -04:00
TEXT ( " _1 " ) , // SortKey
2014-08-18 06:48:04 -04:00
TEXT ( " " ) , // No filename, this is a generation template
MakeShareable ( new FSlateBrush ( * FEditorStyle : : GetBrush ( " GameProjectDialog.BlankProjectThumbnail " ) ) ) ,
MakeShareable ( new FSlateBrush ( * FEditorStyle : : GetBrush ( " GameProjectDialog.BlankProjectPreview " ) ) )
2014-03-14 14:13:41 -04:00
) ) ) ;
2014-08-18 06:48:04 -04:00
Templates . FindOrAdd ( FTemplateCategory : : CodeCategoryName ) . Add ( MakeShareable ( new FTemplateItem (
2014-03-14 14:13:41 -04:00
LOCTEXT ( " BasicCodeProjectName " , " Basic Code " ) ,
LOCTEXT ( " BasicCodeProjectDescription " , " An empty project with some basic game framework code classes created. " ) ,
2014-08-18 06:48:04 -04:00
true , FTemplateCategory : : CodeCategoryName ,
2014-07-03 10:48:59 -04:00
TEXT ( " _2 " ) , // SortKey
2014-08-18 06:48:04 -04:00
TEXT ( " " ) , // No filename, this is a generation template
MakeShareable ( new FSlateBrush ( * FEditorStyle : : GetBrush ( " GameProjectDialog.BasicCodeThumbnail " ) ) ) ,
MakeShareable ( new FSlateBrush ( * FEditorStyle : : GetBrush ( " GameProjectDialog.BlankProjectPreview " ) ) )
2014-03-14 14:13:41 -04:00
) ) ) ;
// Now discover and all data driven templates
TArray < FString > TemplateRootFolders ;
// @todo rocket make template folder locations extensible.
TemplateRootFolders . Add ( FPaths : : RootDir ( ) + TEXT ( " Templates " ) ) ;
2014-07-02 07:33:17 -04:00
// allow plugins to define templates
TArray < FPluginStatus > PluginStatuses = IPluginManager : : Get ( ) . QueryStatusForAllPlugins ( ) ;
for ( const auto & PluginStatus : PluginStatuses )
{
if ( PluginStatus . bIsEnabled & & ! PluginStatus . PluginDirectory . IsEmpty ( ) )
{
const FString PluginTemplatesDirectory = FPaths : : Combine ( * PluginStatus . PluginDirectory , TEXT ( " Templates " ) ) ;
if ( IFileManager : : Get ( ) . DirectoryExists ( * PluginTemplatesDirectory ) )
{
TemplateRootFolders . Add ( PluginTemplatesDirectory ) ;
}
}
}
2014-03-14 14:13:41 -04:00
// Form a list of all folders that could contain template projects
TArray < FString > AllTemplateFolders ;
for ( auto TemplateRootFolderIt = TemplateRootFolders . CreateConstIterator ( ) ; TemplateRootFolderIt ; + + TemplateRootFolderIt )
{
const FString Root = * TemplateRootFolderIt ;
const FString SearchString = Root / TEXT ( " * " ) ;
TArray < FString > TemplateFolders ;
IFileManager : : Get ( ) . FindFiles ( TemplateFolders , * SearchString , /*Files=*/ false , /*Directories=*/ true ) ;
for ( auto TemplateFolderIt = TemplateFolders . CreateConstIterator ( ) ; TemplateFolderIt ; + + TemplateFolderIt )
{
AllTemplateFolders . Add ( Root / ( * TemplateFolderIt ) ) ;
}
}
// Add a template item for every discovered project
for ( auto TemplateFolderIt = AllTemplateFolders . CreateConstIterator ( ) ; TemplateFolderIt ; + + TemplateFolderIt )
{
2014-09-08 13:51:36 -04:00
const FString SearchString = ( * TemplateFolderIt ) / TEXT ( " *. " ) + FProjectDescriptor : : GetExtension ( ) ;
2014-03-14 14:13:41 -04:00
TArray < FString > FoundProjectFiles ;
IFileManager : : Get ( ) . FindFiles ( FoundProjectFiles , * SearchString , /*Files=*/ true , /*Directories=*/ false ) ;
if ( FoundProjectFiles . Num ( ) > 0 )
{
if ( ensure ( FoundProjectFiles . Num ( ) = = 1 ) )
{
// Make sure a TemplateDefs ini file exists
const FString Root = * TemplateFolderIt ;
UTemplateProjectDefs * TemplateDefs = GameProjectUtils : : LoadTemplateDefs ( Root ) ;
if ( TemplateDefs )
{
// Found a template. Add it to the template items list.
const FString ProjectFilename = Root / FoundProjectFiles [ 0 ] ;
FText TemplateName = TemplateDefs - > GetDisplayNameText ( ) ;
FText TemplateDescription = TemplateDefs - > GetLocalizedDescription ( ) ;
// If no template name was specified for the current culture, just use the project name
if ( TemplateName . IsEmpty ( ) )
{
TemplateName = FText : : FromString ( FPaths : : GetBaseFilename ( ProjectFilename ) ) ;
}
// Only generate code if the template has a source folder
2014-08-11 17:14:26 -04:00
const bool bGenerateCode = TemplateDefs - > GeneratesCode ( Root ) ;
2014-03-14 14:13:41 -04:00
2014-08-18 06:48:04 -04:00
TSharedPtr < FSlateDynamicImageBrush > ThumbnailBrush ;
2014-03-14 14:13:41 -04:00
const FString ThumbnailPNGFile = FPaths : : GetBaseFilename ( ProjectFilename , false ) + TEXT ( " .png " ) ;
if ( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * ThumbnailPNGFile ) )
{
const FName BrushName = FName ( * ThumbnailPNGFile ) ;
2014-08-18 06:48:04 -04:00
ThumbnailBrush = MakeShareable ( new FSlateDynamicImageBrush ( BrushName , FVector2D ( 128 , 128 ) ) ) ;
}
TSharedPtr < FSlateDynamicImageBrush > PreviewBrush ;
const FString PreviewPNGFile = FPaths : : GetBaseFilename ( ProjectFilename , false ) + TEXT ( " _Preview.png " ) ;
if ( FPlatformFileManager : : Get ( ) . GetPlatformFile ( ) . FileExists ( * PreviewPNGFile ) )
{
const FName BrushName = FName ( * PreviewPNGFile ) ;
PreviewBrush = MakeShareable ( new FSlateDynamicImageBrush ( BrushName , FVector2D ( 512 , 256 ) ) ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-03 10:48:59 -04:00
// Get the sort key
FString SortKey = TemplateDefs - > SortKey ;
if ( SortKey . Len ( ) = = 0 )
{
SortKey = FPaths : : GetCleanFilename ( ProjectFilename ) ;
}
2014-03-14 14:13:41 -04:00
if ( FPaths : : GetCleanFilename ( ProjectFilename ) = = GameProjectUtils : : GetDefaultProjectTemplateFilename ( ) )
{
2014-07-03 10:48:59 -04:00
SortKey = TEXT ( " _0 " ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-03 10:48:59 -04:00
2014-08-18 06:48:04 -04:00
// Assign the template to the correct category. If the template has no explicit category assigned, we assign it to either C++ or blueprint
FName Category = TemplateDefs - > Category ;
if ( Category . IsNone ( ) )
{
Category = bGenerateCode ? FTemplateCategory : : CodeCategoryName : FTemplateCategory : : BlueprintCategoryName ;
}
Templates . FindOrAdd ( Category ) . Add ( MakeShareable ( new FTemplateItem (
TemplateName ,
TemplateDescription ,
bGenerateCode ,
Category ,
MoveTemp ( SortKey ) ,
MoveTemp ( ProjectFilename ) ,
ThumbnailBrush ,
PreviewBrush
) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
else
{
// More than one project file in this template? This is not legal, skip it.
continue ;
}
}
}
}
void SNewProjectWizard : : SetDefaultProjectLocation ( )
{
FString DefaultProjectFilePath ;
2014-04-02 18:09:23 -04:00
// First, try and use the first previously used path that still exists
for ( const FString & CreatedProjectPath : GEditor - > GetGameAgnosticSettings ( ) . CreatedProjectPaths )
{
if ( IFileManager : : Get ( ) . DirectoryExists ( * CreatedProjectPath ) )
{
DefaultProjectFilePath = CreatedProjectPath ;
break ;
}
}
if ( DefaultProjectFilePath . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
// No previously used path, decide a default path.
2014-06-04 18:06:57 -04:00
DefaultProjectFilePath = FDesktopPlatformModule : : Get ( ) - > GetDefaultProjectCreationPath ( ) ;
2014-03-14 14:13:41 -04:00
IFileManager : : Get ( ) . MakeDirectory ( * DefaultProjectFilePath , true ) ;
}
if ( ! DefaultProjectFilePath . IsEmpty ( ) & & DefaultProjectFilePath . Right ( 1 ) = = TEXT ( " / " ) )
{
DefaultProjectFilePath . LeftChop ( 1 ) ;
}
FPaths : : NormalizeFilename ( DefaultProjectFilePath ) ;
2014-04-23 19:09:13 -04:00
FPaths : : MakePlatformFilename ( DefaultProjectFilePath ) ;
2014-03-14 14:13:41 -04:00
const FString GenericProjectName = LOCTEXT ( " DefaultProjectName " , " MyProject " ) . ToString ( ) ;
FString ProjectName = GenericProjectName ;
// Check to make sure the project file doesn't already exist
FText FailReason ;
2014-09-08 13:51:36 -04:00
if ( ! GameProjectUtils : : IsValidProjectFileForCreation ( DefaultProjectFilePath / ProjectName / ProjectName + TEXT ( " . " ) + FProjectDescriptor : : GetExtension ( ) , FailReason ) )
2014-03-14 14:13:41 -04:00
{
// If it exists, find an appropriate numerical suffix
const int MaxSuffix = 1000 ;
int32 Suffix ;
for ( Suffix = 2 ; Suffix < MaxSuffix ; + + Suffix )
{
ProjectName = GenericProjectName + FString : : Printf ( TEXT ( " %d " ) , Suffix ) ;
2014-09-08 13:51:36 -04:00
if ( GameProjectUtils : : IsValidProjectFileForCreation ( DefaultProjectFilePath / ProjectName / ProjectName + TEXT ( " . " ) + FProjectDescriptor : : GetExtension ( ) , FailReason ) )
2014-03-14 14:13:41 -04:00
{
// Found a name that is not taken. Break out.
break ;
}
}
if ( Suffix > = MaxSuffix )
{
UE_LOG ( LogGameProjectGeneration , Warning , TEXT ( " Failed to find a suffix for the default project name " ) ) ;
ProjectName = TEXT ( " " ) ;
}
}
if ( ! DefaultProjectFilePath . IsEmpty ( ) )
{
CurrentProjectFileName = ProjectName ;
CurrentProjectFilePath = DefaultProjectFilePath ;
2014-04-23 19:09:13 -04:00
FPaths : : MakePlatformFilename ( CurrentProjectFilePath ) ;
2014-03-14 14:13:41 -04:00
LastBrowsePath = CurrentProjectFilePath ;
}
}
void SNewProjectWizard : : UpdateProjectFileValidity ( )
{
// Global validity
{
bLastGlobalValidityCheckSuccessful = true ;
TSharedPtr < FTemplateItem > SelectedTemplate = GetSelectedTemplateItem ( ) ;
if ( ! SelectedTemplate . IsValid ( ) )
{
bLastGlobalValidityCheckSuccessful = false ;
LastGlobalValidityErrorText = LOCTEXT ( " NoTemplateSelected " , " No Template Selected " ) ;
}
2014-08-11 17:14:26 -04:00
else
2014-03-14 14:13:41 -04:00
{
2014-08-11 17:14:26 -04:00
if ( IsCompilerRequired ( ) )
2014-03-14 14:13:41 -04:00
{
2014-08-11 17:14:26 -04:00
if ( ! FSourceCodeNavigation : : IsCompilerAvailable ( ) )
{
bLastGlobalValidityCheckSuccessful = false ;
LastGlobalValidityErrorText = FText : : Format ( LOCTEXT ( " NoCompilerFound " , " No compiler was found. In order to use a C++ template, you must first install {0}. " ) , FSourceCodeNavigation : : GetSuggestedSourceCodeIDE ( ) ) ;
}
2014-09-05 13:31:22 -04:00
else if ( ! FDesktopPlatformModule : : Get ( ) - > IsUnrealBuildToolAvailable ( ) )
2014-08-11 17:14:26 -04:00
{
bLastGlobalValidityCheckSuccessful = false ;
LastGlobalValidityErrorText = LOCTEXT ( " UBTNotFound " , " Engine source code was not found. In order to use a C++ template, you must have engine source code in Engine/Source. " ) ;
}
2014-03-14 14:13:41 -04:00
}
}
}
// Name and Location Validity
{
2014-07-14 18:22:08 -04:00
bLastNameAndLocationValidityCheckSuccessful = true ;
2014-03-14 14:13:41 -04:00
if ( ! FPlatformMisc : : IsValidAbsolutePathFormat ( CurrentProjectFilePath ) )
{
bLastNameAndLocationValidityCheckSuccessful = false ;
LastNameAndLocationValidityErrorText = LOCTEXT ( " InvalidFolderPath " , " The folder path is invalid " ) ;
}
else
{
FText FailReason ;
2014-07-14 18:22:08 -04:00
if ( ! GameProjectUtils : : IsValidProjectFileForCreation ( GetProjectFilenameWithPath ( ) , FailReason ) )
2014-03-14 14:13:41 -04:00
{
2014-07-14 18:22:08 -04:00
bLastNameAndLocationValidityCheckSuccessful = false ;
LastNameAndLocationValidityErrorText = FailReason ;
}
}
if ( CurrentProjectFileName . Contains ( TEXT ( " / " ) ) | | CurrentProjectFileName . Contains ( TEXT ( " \\ " ) ) )
{
bLastNameAndLocationValidityCheckSuccessful = false ;
LastNameAndLocationValidityErrorText = LOCTEXT ( " SlashOrBackslashInProjectName " , " The project name may not contain a slash or backslash " ) ;
}
else
{
FText FailReason ;
if ( ! GameProjectUtils : : IsValidProjectFileForCreation ( GetProjectFilenameWithPath ( ) , FailReason ) )
{
bLastNameAndLocationValidityCheckSuccessful = false ;
2014-03-14 14:13:41 -04:00
LastNameAndLocationValidityErrorText = FailReason ;
}
}
}
LastValidityCheckTime = FSlateApplication : : Get ( ) . GetCurrentTime ( ) ;
// Since this function was invoked, periodic validity checks should be re-enabled if they were disabled.
bPreventPeriodicValidityChecksUntilNextChange = false ;
}
bool SNewProjectWizard : : IsCompilerRequired ( ) const
{
TSharedPtr < FTemplateItem > SelectedTemplate = GetSelectedTemplateItem ( ) ;
return SelectedTemplate . IsValid ( ) & & SelectedTemplate - > bGenerateCode ;
}
bool SNewProjectWizard : : CreateProject ( const FString & ProjectFile )
{
// Get the selected template
TSharedPtr < FTemplateItem > SelectedTemplate = GetSelectedTemplateItem ( ) ;
if ( ! ensure ( SelectedTemplate . IsValid ( ) ) )
{
// A template must be selected.
return false ;
}
FText FailReason ;
2014-09-09 12:16:36 -04:00
FProjectInformation ProjectInfo ( ProjectFile , SelectedTemplate - > bGenerateCode , bCopyStarterContent , SelectedTemplate - > ProjectFile ) ;
ProjectInfo . TargetedHardware = SelectedHardwareClassTarget ;
ProjectInfo . DefaultGraphicsPerformance = SelectedGraphicsPreset ;
if ( ! GameProjectUtils : : CreateProject ( ProjectInfo , FailReason ) )
2014-03-14 14:13:41 -04:00
{
DisplayError ( FailReason ) ;
return false ;
}
// Successfully created the project. Update the last created location string.
FString CreatedProjectPath = FPaths : : GetPath ( FPaths : : GetPath ( ProjectFile ) ) ;
// if the original path was the drives root (ie: C:/) the double path call strips the last /
if ( CreatedProjectPath . EndsWith ( " : " ) )
{
CreatedProjectPath . AppendChar ( ' / ' ) ;
}
GEditor - > AccessGameAgnosticSettings ( ) . CreatedProjectPaths . Remove ( CreatedProjectPath ) ;
GEditor - > AccessGameAgnosticSettings ( ) . CreatedProjectPaths . Insert ( CreatedProjectPath , 0 ) ;
GEditor - > AccessGameAgnosticSettings ( ) . bCopyStarterContentPreference = bCopyStarterContent ;
GEditor - > AccessGameAgnosticSettings ( ) . PostEditChange ( ) ;
return true ;
}
void SNewProjectWizard : : CreateAndOpenProject ( )
{
if ( IsCreateProjectEnabled ( ) )
{
FString ProjectFile = GetProjectFilenameWithPath ( ) ;
if ( CreateProject ( ProjectFile ) )
{
// Prevent periodic validity checks. This is to prevent a brief error message about the project already existing while you are exiting.
bPreventPeriodicValidityChecksUntilNextChange = true ;
const bool bCodeAdded = GetSelectedTemplateItem ( ) - > bGenerateCode ;
if ( bCodeAdded )
{
// In non-rocket, the engine executable may need to be built in order to build the game binaries,
// just open the code editing ide now instead of automatically building for them since it is not safe to do so.
const bool bPromptForConfirmation = FApp : : HasGameName ( ) ; /** Only prompt for project switching if we are already in a project */
OpenCodeIDE ( ProjectFile , bPromptForConfirmation ) ;
}
else
{
// Successfully created a content only project. Now open it.
const bool bPromptForConfirmation = false ;
OpenProject ( ProjectFile , bPromptForConfirmation ) ;
}
}
}
}
bool SNewProjectWizard : : OpenProject ( const FString & ProjectFile , bool bPromptForConfirmation )
{
if ( bPromptForConfirmation )
{
// Notify the user of the success, and ask to switch projects.
FText SuccessMessage = FText : : Format ( LOCTEXT ( " NewProjectSuccessful " , " Project '{0}' was successfully created. Would you like to open it now? " ) , FText : : FromString ( FPaths : : GetBaseFilename ( ProjectFile ) ) ) ;
if ( FMessageDialog : : Open ( EAppMsgType : : YesNo , SuccessMessage ) = = EAppReturnType : : No )
{
// The user opted out of opening the new project. Just close the window.
CloseWindowIfAppropriate ( ) ;
return false ;
}
}
FText FailReason ;
if ( GameProjectUtils : : OpenProject ( ProjectFile , FailReason ) )
{
// Successfully opened the project, the editor is closing.
// Close this window in case something prevents the editor from closing (save dialog, quit confirmation, etc)
CloseWindowIfAppropriate ( ) ;
return true ;
}
DisplayError ( FailReason ) ;
return false ;
}
bool SNewProjectWizard : : OpenCodeIDE ( const FString & ProjectFile , bool bPromptForConfirmation )
{
if ( bPromptForConfirmation )
{
// Notify the user of the success, and ask to switch projects.
FText SuccessMessage = FText : : Format ( LOCTEXT ( " NewProjectSuccessfulIDE " , " Project '{0}' was successfully created. Would you like to open it in {1}? " ) , FText : : FromString ( FPaths : : GetBaseFilename ( ProjectFile ) ) , FSourceCodeNavigation : : GetSuggestedSourceCodeIDE ( ) ) ;
if ( FMessageDialog : : Open ( EAppMsgType : : YesNo , SuccessMessage ) = = EAppReturnType : : No )
{
// The user opted out of opening the new project. Just close the window.
CloseWindowIfAppropriate ( true ) ;
return false ;
}
}
FText FailReason ;
if ( GameProjectUtils : : OpenCodeIDE ( ProjectFile , FailReason ) )
{
// Successfully opened code editing IDE, the editor is closing
// Close this window in case something prevents the editor from closing (save dialog, quit confirmation, etc)
CloseWindowIfAppropriate ( true ) ;
return true ;
}
DisplayError ( FailReason ) ;
return false ;
}
void SNewProjectWizard : : CloseWindowIfAppropriate ( bool ForceClose )
{
if ( ForceClose | | FApp : : HasGameName ( ) )
{
FWidgetPath WidgetPath ;
TSharedPtr < SWindow > ContainingWindow = FSlateApplication : : Get ( ) . FindWidgetWindow ( AsShared ( ) , WidgetPath ) ;
if ( ContainingWindow . IsValid ( ) )
{
ContainingWindow - > RequestDestroyWindow ( ) ;
}
}
}
void SNewProjectWizard : : DisplayError ( const FText & ErrorText )
{
2014-08-22 08:33:51 -04:00
FString ErrorString = ErrorText . ToString ( ) ;
UE_LOG ( LogGameProjectGeneration , Log , TEXT ( " %s " ) , * ErrorString ) ;
if ( ErrorString . Contains ( " \n " ) )
{
FMessageDialog : : Open ( EAppMsgType : : Ok , ErrorText ) ;
}
else
{
PersistentGlobalErrorLabelText = ErrorText ;
}
2014-03-14 14:13:41 -04:00
}
/* SNewProjectWizard event handlers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool SNewProjectWizard : : HandleCreateProjectWizardCanFinish ( ) const
{
return IsCreateProjectEnabled ( ) ;
}
void SNewProjectWizard : : HandleCreateProjectWizardFinished ( )
{
CreateAndOpenProject ( ) ;
}
2014-08-18 06:48:04 -04:00
ESlateCheckBoxState : : Type SNewProjectWizard : : GetCategoryTabCheckState ( FName Category ) const
2014-03-14 14:13:41 -04:00
{
2014-08-18 06:48:04 -04:00
return Category = = ActiveCategory ? ESlateCheckBoxState : : Checked : ESlateCheckBoxState : : Unchecked ;
}
void SNewProjectWizard : : HandleCategoryChanged ( ESlateCheckBoxState : : Type CheckState , FName Category )
{
if ( CheckState ! = ESlateCheckBoxState : : Checked )
2014-03-14 14:13:41 -04:00
{
2014-08-18 06:48:04 -04:00
return ;
2014-03-14 14:13:41 -04:00
}
2014-08-18 06:48:04 -04:00
ActiveCategory = Category ;
FilteredTemplateList = Templates . FindRef ( Category ) ;
2014-03-14 14:13:41 -04:00
2014-08-18 06:48:04 -04:00
// Sort the template folders
FilteredTemplateList . Sort ( [ ] ( const TSharedPtr < FTemplateItem > & A , const TSharedPtr < FTemplateItem > & B ) {
return A - > SortKey < B - > SortKey ;
} ) ;
2014-03-14 14:13:41 -04:00
2014-08-18 06:48:04 -04:00
if ( FilteredTemplateList . Num ( ) > 0 )
{
TemplateListView - > SetSelection ( FilteredTemplateList [ 0 ] ) ;
}
TemplateListView - > RequestListRefresh ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-09-09 12:16:36 -04:00
void SNewProjectWizard : : SetHardwareClassTarget ( EHardwareClass : : Type InHardwareClass )
{
SelectedHardwareClassTarget = InHardwareClass ;
}
void SNewProjectWizard : : SetGraphicsPreset ( EGraphicsPreset : : Type InGraphicsPreset )
{
SelectedGraphicsPreset = InGraphicsPreset ;
}
2014-03-14 14:13:41 -04:00
# undef LOCTEXT_NAMESPACE