2014-12-07 19:09:38 -05:00
// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved.
2014-03-14 14:13:41 -04:00
# include "GameProjectGenerationPrivatePCH.h"
# include "SourceCodeNavigation.h"
# include "ClassViewerModule.h"
# include "ClassViewerFilter.h"
2015-02-16 04:29:11 -05:00
# include "Editor/ContentBrowser/Public/ContentBrowserModule.h"
2014-03-14 14:13:41 -04:00
# include "Editor/ClassViewer/Private/SClassViewer.h"
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
# include "DesktopPlatformModule.h"
2014-07-14 21:16:56 -04:00
# include "Editor/Documentation/Public/IDocumentation.h"
2014-07-21 17:31:27 -04:00
# include "EditorClassUtils.h"
2014-08-27 21:25:34 -04:00
# include "SWizard.h"
2014-10-14 22:50:06 -04:00
# include "SHyperlink.h"
2014-10-23 13:16:00 -04:00
# include "TutorialMetaData.h"
2014-11-12 04:58:53 -05:00
# include "GameFramework/GameMode.h"
# include "GameFramework/GameState.h"
# include "GameFramework/Pawn.h"
# include "GameFramework/WorldSettings.h"
# include "GameFramework/PlayerController.h"
# include "GameFramework/Character.h"
# include "GameFramework/Actor.h"
# include "Camera/PlayerCameraManager.h"
# include "GameFramework/HUD.h"
# include "GameFramework/PlayerState.h"
# include "Kismet/BlueprintFunctionLibrary.h"
2015-02-16 04:29:11 -05:00
# include "Kismet2/KismetEditorUtilities.h"
# include "AssetRegistryModule.h"
2015-03-11 11:54:24 -04:00
# include "AssetEditorManager.h"
# include "ContentBrowserModule.h"
2015-01-26 20:14:10 -05:00
# include "SNotificationList.h"
# include "NotificationManager.h"
2015-04-10 03:30:54 -04:00
# include "Engine/BlueprintGeneratedClass.h"
2014-08-27 21:25:34 -04:00
2014-03-14 14:13:41 -04:00
# define LOCTEXT_NAMESPACE "GameProjectGeneration"
2014-08-27 21:25:34 -04:00
2014-03-14 14:13:41 -04:00
struct FParentClassItem
{
2015-02-16 04:29:11 -05:00
FNewClassInfo ParentClassInfo ;
2014-03-14 14:13:41 -04:00
2015-02-16 04:29:11 -05:00
FParentClassItem ( const FNewClassInfo & InParentClassInfo )
2014-05-16 07:26:51 -04:00
: ParentClassInfo ( InParentClassInfo )
2014-03-14 14:13:41 -04:00
{ }
} ;
class FNativeClassParentFilter : public IClassViewerFilter
{
public :
2015-01-16 15:39:47 -05:00
FNativeClassParentFilter ( )
2014-08-04 18:21:05 -04:00
{
2015-01-16 15:39:47 -05:00
ProjectModules = GameProjectUtils : : GetCurrentProjectModules ( ) ;
2014-08-04 18:21:05 -04:00
}
2014-06-13 06:14:46 -04:00
virtual bool IsClassAllowed ( const FClassViewerInitializationOptions & InInitOptions , const UClass * InClass , TSharedRef < FClassViewerFilterFuncs > InFilterFuncs ) override
2014-03-14 14:13:41 -04:00
{
2015-01-16 15:39:47 -05:00
// We allow a class that belongs to any module in the current project, as you don't actually choose the destination module until after you've selected your parent class
return GameProjectUtils : : IsValidBaseClassForCreation ( InClass , ProjectModules ) ;
2014-03-14 14:13:41 -04:00
}
2014-06-13 06:14:46 -04:00
virtual bool IsUnloadedClassAllowed ( const FClassViewerInitializationOptions & InInitOptions , const TSharedRef < const IUnloadedBlueprintData > InUnloadedClassData , TSharedRef < FClassViewerFilterFuncs > InFilterFuncs ) override
2014-03-14 14:13:41 -04:00
{
return false ;
}
2014-08-04 18:21:05 -04:00
private :
2015-01-16 15:39:47 -05:00
/** The list of currently available modules for this project */
TArray < FModuleContextInfo > ProjectModules ;
2014-03-14 14:13:41 -04:00
} ;
2014-11-12 11:31:40 -05:00
static void FindPublicEngineHeaderFiles ( TArray < FString > & OutFiles , const FString & Path )
{
TArray < FString > ModuleDirs ;
IFileManager : : Get ( ) . FindFiles ( ModuleDirs , * ( Path / TEXT ( " * " ) ) , false , true ) ;
for ( const FString & ModuleDir : ModuleDirs )
{
IFileManager : : Get ( ) . FindFilesRecursive ( OutFiles , * ( Path / ModuleDir / TEXT ( " Classes " ) ) , TEXT ( " *.h " ) , true , false , false ) ;
IFileManager : : Get ( ) . FindFilesRecursive ( OutFiles , * ( Path / ModuleDir / TEXT ( " Public " ) ) , TEXT ( " *.h " ) , true , false , false ) ;
}
}
2014-03-14 14:13:41 -04:00
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SNewClassDialog : : Construct ( const FArguments & InArgs )
{
2015-02-16 04:29:11 -05:00
ClassDomain = InArgs . _ClassDomain ;
2014-08-04 18:21:05 -04:00
{
2014-10-13 11:47:21 -04:00
TArray < FModuleContextInfo > CurrentModules = GameProjectUtils : : GetCurrentProjectModules ( ) ;
2014-08-04 18:21:05 -04:00
check ( CurrentModules . Num ( ) ) ; // this should never happen since GetCurrentProjectModules is supposed to add a dummy runtime module if the project currently has no modules
2014-05-16 10:47:37 -04:00
2014-08-04 18:21:05 -04:00
AvailableModules . Reserve ( CurrentModules . Num ( ) ) ;
2014-10-13 11:47:21 -04:00
for ( const FModuleContextInfo & ModuleInfo : CurrentModules )
2014-08-04 18:21:05 -04:00
{
2014-10-13 11:47:21 -04:00
AvailableModules . Emplace ( MakeShareable ( new FModuleContextInfo ( ModuleInfo ) ) ) ;
2014-08-04 18:21:05 -04:00
}
}
2015-01-16 15:39:47 -05:00
// If we've been given an initial path that maps to a valid project module, use that as our initial module and path
2015-02-16 04:29:11 -05:00
if ( ClassDomain = = EClassDomain : : Blueprint )
{
NewClassPath = InArgs . _InitialPath . IsEmpty ( ) ? TEXT ( " /Game " ) : InArgs . _InitialPath ;
}
else if ( ! InArgs . _InitialPath . IsEmpty ( ) )
2015-01-16 15:39:47 -05:00
{
const FString AbsoluteInitialPath = FPaths : : ConvertRelativePathToFull ( InArgs . _InitialPath ) ;
for ( const auto & AvailableModule : AvailableModules )
{
if ( AbsoluteInitialPath . StartsWith ( AvailableModule - > ModuleSourcePath ) )
{
SelectedModuleInfo = AvailableModule ;
NewClassPath = AbsoluteInitialPath ;
break ;
}
}
}
2015-01-30 10:35:05 -05:00
DefaultClassPrefix = InArgs . _DefaultClassPrefix ;
DefaultClassName = InArgs . _DefaultClassName ;
2015-01-16 15:39:47 -05:00
// If we didn't get given a valid path override (see above), try and automatically work out the best default module
2014-08-04 18:21:05 -04:00
// If we have a runtime module with the same name as our project, then use that
// Otherwise, set out default target module as the first runtime module in the list
2015-02-16 04:29:11 -05:00
if ( ClassDomain = = EClassDomain : : Native & & ! SelectedModuleInfo . IsValid ( ) )
2014-08-04 18:21:05 -04:00
{
const FString ProjectName = FApp : : GetGameName ( ) ;
for ( const auto & AvailableModule : AvailableModules )
{
if ( AvailableModule - > ModuleName = = ProjectName )
{
SelectedModuleInfo = AvailableModule ;
break ;
}
if ( AvailableModule - > ModuleType = = EHostType : : Runtime )
{
SelectedModuleInfo = AvailableModule ;
// keep going in case we find a better match
}
}
if ( ! SelectedModuleInfo . IsValid ( ) )
{
// No runtime modules? Just take the first available module then
SelectedModuleInfo = AvailableModules [ 0 ] ;
}
2015-01-16 15:39:47 -05:00
NewClassPath = SelectedModuleInfo - > ModuleSourcePath ;
2014-08-04 18:21:05 -04:00
}
2014-05-14 06:47:25 -04:00
ClassLocation = GameProjectUtils : : EClassLocation : : UserDefined ; // the first call to UpdateInputValidity will set this correctly based on NewClassPath
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
2015-02-16 04:29:11 -05:00
ParentClassInfo = FNewClassInfo ( InArgs . _Class ) ;
2014-03-14 14:13:41 -04:00
bShowFullClassTree = false ;
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
LastPeriodicValidityCheckTime = 0 ;
PeriodicValidityCheckFrequency = 4 ;
bLastInputValidityCheckSuccessful = true ;
2014-03-14 14:13:41 -04:00
bPreventPeriodicValidityChecksUntilNextChange = false ;
FClassViewerInitializationOptions Options ;
Options . Mode = EClassViewerMode : : ClassPicker ;
Options . DisplayMode = EClassViewerDisplayMode : : TreeView ;
Options . bIsActorsOnly = false ;
Options . bIsPlaceableOnly = false ;
Options . bIsBlueprintBaseOnly = false ;
Options . bShowUnloadedBlueprints = false ;
Options . bShowNoneOption = false ;
Options . bShowObjectRootClass = true ;
2015-02-19 08:07:13 -05:00
Options . bExpandRootNodes = true ;
2014-03-14 14:13:41 -04:00
2015-02-16 04:29:11 -05:00
if ( InArgs . _ClassViewerFilter . IsValid ( ) )
{
Options . ClassFilter = InArgs . _ClassViewerFilter ;
}
else if ( InArgs . _ClassDomain = = EClassDomain : : Native )
{
// Prevent creating native classes based on blueprint classes
Options . ClassFilter = MakeShareable ( new FNativeClassParentFilter ( ) ) ;
}
2014-03-14 14:13:41 -04:00
2015-02-19 08:07:13 -05:00
// Only show the Object root class if it's a valid base (this helps keep the tree clean)
if ( Options . ClassFilter . IsValid ( ) & & ! Options . ClassFilter - > IsClassAllowed ( Options , UObject : : StaticClass ( ) , MakeShareable ( new FClassViewerFilterFuncs ) ) )
{
Options . bShowObjectRootClass = false ;
}
2014-03-14 14:13:41 -04:00
ClassViewer = StaticCastSharedRef < SClassViewer > ( FModuleManager : : LoadModuleChecked < FClassViewerModule > ( " ClassViewer " ) . CreateClassViewer ( Options , FOnClassPicked : : CreateSP ( this , & SNewClassDialog : : OnAdvancedClassSelected ) ) ) ;
2015-02-17 10:07:24 -05:00
// Make sure the featured classes all pass the active class filter
TArray < FNewClassInfo > ValidatedFeaturedClasses ;
ValidatedFeaturedClasses . Reserve ( InArgs . _FeaturedClasses . Num ( ) ) ;
for ( const FNewClassInfo & FeaturedClassInfo : InArgs . _FeaturedClasses )
{
if ( FeaturedClassInfo . ClassType ! = FNewClassInfo : : EClassType : : UObject | | ClassViewer - > IsClassAllowed ( FeaturedClassInfo . BaseClass ) )
{
ValidatedFeaturedClasses . Add ( FeaturedClassInfo ) ;
}
}
SetupParentClassItems ( ValidatedFeaturedClasses ) ;
2015-02-16 04:29:11 -05:00
UpdateInputValidity ( ) ;
2014-07-21 17:31:27 -04:00
TSharedRef < SWidget > DocWidget = IDocumentation : : Get ( ) - > CreateAnchor ( TAttribute < FString > ( this , & SNewClassDialog : : GetSelectedParentDocLink ) ) ;
DocWidget - > SetVisibility ( TAttribute < EVisibility > ( this , & SNewClassDialog : : GetDocLinkVisibility ) ) ;
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
const float EditableTextHeight = 26.0f ;
2015-02-16 04:29:11 -05:00
IContentBrowserSingleton & ContentBrowser = FModuleManager : : LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) . Get ( ) ;
FPathPickerConfig BlueprintPathConfig ;
if ( ClassDomain = = EClassDomain : : Blueprint )
{
BlueprintPathConfig . DefaultPath = InArgs . _InitialPath ;
BlueprintPathConfig . bFocusSearchBoxWhenOpened = false ;
BlueprintPathConfig . bAllowContextMenu = false ;
BlueprintPathConfig . bAllowClassesFolder = false ;
BlueprintPathConfig . OnPathSelected = FOnPathSelected : : CreateSP ( this , & SNewClassDialog : : OnBlueprintPathSelected ) ;
}
OnAddedToProject = InArgs . _OnAddedToProject ;
2015-01-26 20:16:24 -05:00
2014-03-14 14:13:41 -04:00
ChildSlot
[
SNew ( SBorder )
2015-01-16 15:39:47 -05:00
. Padding ( 18 )
2014-03-14 14:13:41 -04:00
. BorderImage ( FEditorStyle : : GetBrush ( " Docking.Tab.ContentAreaBrush " ) )
[
2014-05-14 07:07:29 -04:00
SNew ( SVerticalBox )
2014-10-23 13:16:00 -04:00
. AddMetaData < FTutorialMetaData > ( TEXT ( " AddCodeMajorAnchor " ) )
2014-05-14 07:07:29 -04:00
+ SVerticalBox : : Slot ( )
2014-03-14 14:13:41 -04:00
[
2014-05-14 07:07:29 -04:00
SAssignNew ( MainWizard , SWizard )
. ShowPageList ( false )
2015-04-17 23:22:28 -04:00
. ButtonStyle ( FEditorStyle : : Get ( ) , " FlatButton.Default " )
2015-04-20 14:25:22 -04:00
. CancelButtonStyle ( FEditorStyle : : Get ( ) , " FlatButton.Default " )
2015-04-17 23:22:28 -04:00
. FinishButtonStyle ( FEditorStyle : : Get ( ) , " FlatButton.Success " )
. ButtonTextStyle ( FEditorStyle : : Get ( ) , " LargeText " )
. ForegroundColor ( FEditorStyle : : Get ( ) . GetSlateColor ( " WhiteBrush " ) )
2014-05-14 07:07:29 -04:00
. CanFinish ( this , & SNewClassDialog : : CanFinish )
2015-02-16 04:29:11 -05:00
. FinishButtonText ( ClassDomain = = EClassDomain : : Native ? LOCTEXT ( " FinishButtonText_Native " , " Create Class " ) : LOCTEXT ( " FinishButtonText_Blueprint " , " Create Blueprint Class " ) )
. FinishButtonToolTip (
ClassDomain = = EClassDomain : : Native ?
LOCTEXT ( " FinishButtonToolTip_Native " , " Creates the code files to add your new class. " ) :
LOCTEXT ( " FinishButtonToolTip_Blueprint " , " Creates the new Blueprint class based on the specified parent class. " )
)
2014-05-14 07:07:29 -04:00
. OnCanceled ( this , & SNewClassDialog : : CancelClicked )
. OnFinished ( this , & SNewClassDialog : : FinishClicked )
2014-05-16 07:26:51 -04:00
. InitialPageIndex ( ParentClassInfo . IsSet ( ) ? 1 : 0 )
2015-01-16 15:39:47 -05:00
. PageFooter ( )
[
// Get IDE information
SNew ( SBorder )
. Visibility ( this , & SNewClassDialog : : GetGlobalErrorLabelVisibility )
. BorderImage ( FEditorStyle : : GetBrush ( " NewClassDialog.ErrorLabelBorder " ) )
. Padding ( FMargin ( 0 , 5 ) )
. Content ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. Padding ( 2.f )
. AutoWidth ( )
[
SNew ( SImage )
. Image ( FEditorStyle : : GetBrush ( " MessageLog.Warning " ) )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. Text ( this , & SNewClassDialog : : GetGlobalErrorLabelText )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.ErrorLabelFont " )
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Center )
. AutoWidth ( )
. Padding ( 5.f , 0.f )
[
SNew ( SGetSuggestedIDEWidget )
]
]
]
2014-03-14 14:13:41 -04:00
2014-05-14 07:07:29 -04:00
// Choose parent class
+ SWizard : : Page ( )
2015-01-16 15:39:47 -05:00
. CanShow ( ! ParentClassInfo . IsSet ( ) ) // We can't move to this widget page if we've been given a parent class to use
2014-05-14 07:07:29 -04:00
[
SNew ( SVerticalBox )
2014-03-14 14:13:41 -04:00
2014-05-14 07:07:29 -04:00
// Title
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
2015-01-16 15:39:47 -05:00
. Padding ( 0 )
2014-05-14 07:07:29 -04:00
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.PageTitle " )
. Text ( LOCTEXT ( " ParentClassTitle " , " Choose Parent Class " ) )
]
// Title spacer
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 , 2 , 0 , 8 )
[
SNew ( SSeparator )
]
// Page description and view options
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 , 10 )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. FillWidth ( 1.f )
. VAlign ( VAlign_Center )
2014-03-14 14:13:41 -04:00
[
SNew ( STextBlock )
2015-02-16 04:29:11 -05:00
. Text (
ClassDomain = = EClassDomain : : Native ?
LOCTEXT ( " ChooseParentClassDescription_Native " , " This will add a C++ header and source code file to your game project. " ) :
LOCTEXT ( " ChooseParentClassDescription_Blueprint " , " This will add a new Blueprint class to your game project. " )
)
2014-03-14 14:13:41 -04:00
]
2014-05-14 07:07:29 -04:00
// Full tree checkbox
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( 4 , 0 , 0 , 0 )
2014-03-14 14:13:41 -04:00
[
2014-05-14 07:07:29 -04:00
SNew ( SCheckBox )
. IsChecked ( this , & SNewClassDialog : : IsFullClassTreeChecked )
. OnCheckStateChanged ( this , & SNewClassDialog : : OnFullClassTreeChanged )
2014-03-14 14:13:41 -04:00
[
SNew ( STextBlock )
2014-05-14 07:07:29 -04:00
. Text ( LOCTEXT ( " FullClassTree " , " Show All Classes " ) )
2014-03-14 14:13:41 -04:00
]
]
]
2014-05-14 07:07:29 -04:00
// Add Code list
+ SVerticalBox : : Slot ( )
. FillHeight ( 1.f )
. Padding ( 0 , 10 )
2014-03-14 14:13:41 -04:00
[
2014-05-14 07:07:29 -04:00
SNew ( SBorder )
2014-10-23 13:16:00 -04:00
. AddMetaData < FTutorialMetaData > ( TEXT ( " AddCodeOptions " ) )
2014-05-14 07:07:29 -04:00
. BorderImage ( FEditorStyle : : GetBrush ( " ToolPanel.GroupBorder " ) )
2014-03-14 14:13:41 -04:00
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
[
2014-05-14 07:07:29 -04:00
// Basic view
SAssignNew ( ParentClassListView , SListView < TSharedPtr < FParentClassItem > > )
. ListItemsSource ( & ParentClassItemsSource )
. SelectionMode ( ESelectionMode : : Single )
. ClearSelectionOnClick ( false )
. OnGenerateRow ( this , & SNewClassDialog : : MakeParentClassListViewWidget )
. OnMouseButtonDoubleClick ( this , & SNewClassDialog : : OnParentClassItemDoubleClicked )
. OnSelectionChanged ( this , & SNewClassDialog : : OnClassSelected )
. Visibility ( this , & SNewClassDialog : : GetBasicParentClassVisibility )
2014-03-14 14:13:41 -04:00
]
+ SVerticalBox : : Slot ( )
[
2014-05-14 07:07:29 -04:00
// Advanced view
SNew ( SBox )
. Visibility ( this , & SNewClassDialog : : GetAdvancedParentClassVisibility )
2014-03-14 14:13:41 -04:00
[
2014-05-14 07:07:29 -04:00
ClassViewer . ToSharedRef ( )
2014-03-14 14:13:41 -04:00
]
]
2014-05-14 07:07:29 -04:00
]
]
2014-03-14 14:13:41 -04:00
2014-05-14 07:07:29 -04:00
// Class selection
+ SVerticalBox : : Slot ( )
. Padding ( 30 , 2 )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
2014-10-23 13:16:00 -04:00
2014-05-14 07:07:29 -04:00
// Class label
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
2014-07-14 16:50:34 -04:00
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. VAlign ( VAlign_Center )
. Padding ( 0 , 0 , 12 , 0 )
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.SelectedParentClassLabel " )
. Text ( LOCTEXT ( " ParentClassLabel " , " Selected Class " ) )
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. VAlign ( VAlign_Center )
. Padding ( 0 , 0 , 12 , 0 )
[
SNew ( STextBlock )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-07-14 16:50:34 -04:00
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.SelectedParentClassLabel " )
. Text ( LOCTEXT ( " ParentClassSourceLabel " , " Selected Class Source " ) )
]
2014-05-14 07:07:29 -04:00
]
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
2014-05-14 07:07:29 -04:00
// Class selection preview
+ SHorizontalBox : : Slot ( )
[
2014-07-14 16:50:34 -04:00
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. VAlign ( VAlign_Center )
. Padding ( 0 , 0 , 12 , 0 )
[
2014-07-21 17:31:27 -04:00
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
2015-02-16 04:29:11 -05:00
. VAlign ( VAlign_Center )
2014-07-21 17:31:27 -04:00
. AutoWidth ( )
[
SNew ( STextBlock )
. Text ( this , & SNewClassDialog : : GetSelectedParentClassName )
]
+ SHorizontalBox : : Slot ( )
2015-02-16 04:29:11 -05:00
. VAlign ( VAlign_Center )
2014-07-21 17:31:27 -04:00
. AutoWidth ( )
[
DocWidget
]
2014-07-14 16:50:34 -04:00
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. VAlign ( VAlign_Bottom )
. HAlign ( HAlign_Left )
. Padding ( 0.0f , 0.0f , 0.0f , 0.0f )
[
SNew ( SHyperlink )
2015-02-16 08:38:28 -05:00
. Style ( FEditorStyle : : Get ( ) , " Common.GotoNativeCodeHyperlink " )
2014-07-14 16:50:34 -04:00
. OnNavigate ( this , & SNewClassDialog : : OnEditCodeClicked )
. Text ( this , & SNewClassDialog : : GetSelectedParentClassFilename )
2015-02-10 13:26:26 -05:00
. ToolTipText ( FText : : Format ( LOCTEXT ( " GoToCode_ToolTip " , " Click to open this source file in {0} " ) , FSourceCodeNavigation : : GetSuggestedSourceCodeIDE ( ) ) )
2014-07-14 16:50:34 -04:00
. Visibility ( this , & SNewClassDialog : : GetSourceHyperlinkVisibility )
]
2014-03-14 14:13:41 -04:00
]
]
]
2014-05-14 07:07:29 -04:00
// Name class
+ SWizard : : Page ( )
. OnEnter ( this , & SNewClassDialog : : OnNamePageEntered )
[
SNew ( SVerticalBox )
2014-03-14 14:13:41 -04:00
2014-05-14 07:07:29 -04:00
// Title
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
2015-01-16 15:39:47 -05:00
. Padding ( 0 )
2014-05-14 07:07:29 -04:00
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.PageTitle " )
. Text ( this , & SNewClassDialog : : GetNameClassTitle )
]
// Title spacer
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 , 2 , 0 , 8 )
[
SNew ( SSeparator )
]
+ SVerticalBox : : Slot ( )
. FillHeight ( 1.f )
. Padding ( 0 , 10 )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 , 0 , 0 , 5 )
[
SNew ( STextBlock )
2015-02-16 04:29:11 -05:00
. Text ( LOCTEXT ( " ClassNameDescription " , " Enter a name for your new class. Class names may only contain alphanumeric characters, and may not contain a space. " ) )
2014-05-14 07:07:29 -04:00
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 , 0 , 0 , 2 )
[
SNew ( STextBlock )
2015-02-16 04:29:11 -05:00
. Text ( ClassDomain = = EClassDomain : : Native ?
LOCTEXT ( " ClassNameDetails_Native " , " When you click the \" Create \" button below, a header (.h) file and a source (.cpp) file will be made using this name. " ) :
LOCTEXT ( " ClassNameDetails_Blueprint " , " When you click the \" Create \" button below, a new Blueprint class will be created. " )
)
2014-05-14 07:07:29 -04:00
]
// Name Error label
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 , 5 )
[
// Constant height, whether the label is visible or not
SNew ( SBox ) . HeightOverride ( 20 )
[
SNew ( SBorder )
. Visibility ( this , & SNewClassDialog : : GetNameErrorLabelVisibility )
. BorderImage ( FEditorStyle : : GetBrush ( " NewClassDialog.ErrorLabelBorder " ) )
. Content ( )
[
SNew ( STextBlock )
. Text ( this , & SNewClassDialog : : GetNameErrorLabelText )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.ErrorLabelFont " )
]
]
]
// Properties
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
[
SNew ( SBorder )
. BorderImage ( FEditorStyle : : GetBrush ( " DetailsView.CategoryTop " ) )
. BorderBackgroundColor ( FLinearColor ( 0.6f , 0.6f , 0.6f , 1.0f ) )
. Padding ( FMargin ( 6.0f , 4.0f , 7.0f , 4.0f ) )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0 )
[
SNew ( SGridPanel )
. FillColumn ( 1 , 1.0f )
// Name label
+ SGridPanel : : Slot ( 0 , 0 )
2014-03-14 14:13:41 -04:00
. VAlign ( VAlign_Center )
2014-05-14 07:07:29 -04:00
. Padding ( 0 , 0 , 12 , 0 )
2014-03-14 14:13:41 -04:00
[
SNew ( STextBlock )
2014-05-14 07:07:29 -04:00
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.SelectedParentClassLabel " )
. Text ( LOCTEXT ( " NameLabel " , " Name " ) )
2014-03-14 14:13:41 -04:00
]
2014-05-14 07:07:29 -04:00
// Name edit box
+ SGridPanel : : Slot ( 1 , 0 )
. Padding ( 0.0f , 3.0f )
2014-03-14 14:13:41 -04:00
. VAlign ( VAlign_Center )
[
2014-05-14 07:07:29 -04:00
SNew ( SBox )
. HeightOverride ( EditableTextHeight )
2014-10-23 13:16:00 -04:00
. AddMetaData < FTutorialMetaData > ( TEXT ( " ClassName " ) )
2014-05-14 07:07:29 -04:00
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. FillWidth ( 1.0f )
[
SAssignNew ( ClassNameEditBox , SEditableTextBox )
. Text ( this , & SNewClassDialog : : OnGetClassNameText )
. OnTextChanged ( this , & SNewClassDialog : : OnClassNameTextChanged )
]
2014-08-04 18:21:05 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 6.0f , 0.0f , 0.0f , 0.0f )
[
2014-10-13 11:47:21 -04:00
SAssignNew ( AvailableModulesCombo , SComboBox < TSharedPtr < FModuleContextInfo > > )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-08-04 18:21:05 -04:00
. ToolTipText ( LOCTEXT ( " ModuleComboToolTip " , " Choose the target module for your new class " ) )
. OptionsSource ( & AvailableModules )
. InitiallySelectedItem ( SelectedModuleInfo )
. OnSelectionChanged ( this , & SNewClassDialog : : SelectedModuleComboBoxSelectionChanged )
. OnGenerateWidget ( this , & SNewClassDialog : : MakeWidgetForSelectedModuleCombo )
[
SNew ( STextBlock )
. Text ( this , & SNewClassDialog : : GetSelectedModuleComboText )
]
]
2015-02-16 04:29:11 -05:00
// Native C++ properties
2014-05-14 07:07:29 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 6.0f , 0.0f , 0.0f , 0.0f )
[
SNew ( SHorizontalBox )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-05-14 07:07:29 -04:00
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SCheckBox )
. Style ( FEditorStyle : : Get ( ) , " Property.ToggleButton.Start " )
. IsChecked ( this , & SNewClassDialog : : IsClassLocationActive , GameProjectUtils : : EClassLocation : : Public )
. OnCheckStateChanged ( this , & SNewClassDialog : : OnClassLocationChanged , GameProjectUtils : : EClassLocation : : Public )
2015-03-12 10:06:48 -04:00
. ToolTipText ( LOCTEXT ( " ClassLocation_Public " , " A public class can be included and used inside other modules in addition to the module it resides in " ) )
2014-05-14 07:07:29 -04:00
[
SNew ( SBox )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Left )
. Padding ( FMargin ( 4.0f , 0.0f , 3.0f , 0.0f ) )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " Public " , " Public " ) )
. ColorAndOpacity ( this , & SNewClassDialog : : GetClassLocationTextColor , GameProjectUtils : : EClassLocation : : Public )
]
]
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
[
SNew ( SCheckBox )
. Style ( FEditorStyle : : Get ( ) , " Property.ToggleButton.End " )
. IsChecked ( this , & SNewClassDialog : : IsClassLocationActive , GameProjectUtils : : EClassLocation : : Private )
. OnCheckStateChanged ( this , & SNewClassDialog : : OnClassLocationChanged , GameProjectUtils : : EClassLocation : : Private )
2015-03-12 10:06:48 -04:00
. ToolTipText ( LOCTEXT ( " ClassLocation_Private " , " A private class can only be included and used within the module it resides in " ) )
2014-05-14 07:07:29 -04:00
[
SNew ( SBox )
. VAlign ( VAlign_Center )
. HAlign ( HAlign_Right )
. Padding ( FMargin ( 3.0f , 0.0f , 4.0f , 0.0f ) )
[
SNew ( STextBlock )
. Text ( LOCTEXT ( " Private " , " Private " ) )
. ColorAndOpacity ( this , & SNewClassDialog : : GetClassLocationTextColor , GameProjectUtils : : EClassLocation : : Private )
]
]
]
]
]
2014-03-14 14:13:41 -04:00
]
2014-05-14 07:07:29 -04:00
// Path label
+ SGridPanel : : Slot ( 0 , 1 )
2015-02-16 04:29:11 -05:00
. VAlign ( ClassDomain = = EClassDomain : : Blueprint ? VAlign_Top : VAlign_Center )
2014-05-14 07:07:29 -04:00
. Padding ( 0 , 0 , 12 , 0 )
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.SelectedParentClassLabel " )
2015-01-07 09:52:40 -05:00
. Text ( LOCTEXT ( " PathLabel " , " Path " ) )
2014-05-14 07:07:29 -04:00
]
// Path edit box
+ SGridPanel : : Slot ( 1 , 1 )
. Padding ( 0.0f , 3.0f )
. VAlign ( VAlign_Center )
[
2015-02-16 04:29:11 -05:00
SNew ( SVerticalBox )
// Blueprint Class asset path
+ SVerticalBox : : Slot ( )
. Padding ( 0 )
2014-05-14 07:07:29 -04:00
[
2015-02-16 04:29:11 -05:00
SNew ( SBox )
// Height override to force the visibility of a scrollbar (our parent is autoheight)
. HeightOverride ( 200 )
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Visible : EVisibility : : Collapsed )
2014-05-14 07:07:29 -04:00
[
2015-02-16 04:29:11 -05:00
ContentBrowser . CreatePathPicker ( BlueprintPathConfig )
2014-05-14 07:07:29 -04:00
]
2015-02-16 04:29:11 -05:00
]
2014-05-14 07:07:29 -04:00
2015-02-16 04:29:11 -05:00
// Native C++ path
+ SVerticalBox : : Slot ( )
. Padding ( 0 )
. AutoHeight ( )
[
SNew ( SBox )
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
. HeightOverride ( EditableTextHeight )
. AddMetaData < FTutorialMetaData > ( TEXT ( " Path " ) )
2014-05-14 07:07:29 -04:00
[
2015-02-16 04:29:11 -05:00
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. FillWidth ( 1.0f )
[
SNew ( SEditableTextBox )
. Text ( this , & SNewClassDialog : : OnGetClassPathText )
. OnTextChanged ( this , & SNewClassDialog : : OnClassPathTextChanged )
]
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. Padding ( 6.0f , 1.0f , 0.0f , 0.0f )
[
SNew ( SButton )
. VAlign ( VAlign_Center )
. OnClicked ( this , & SNewClassDialog : : HandleChooseFolderButtonClicked )
. Text ( LOCTEXT ( " BrowseButtonText " , " Choose Folder " ) )
]
2014-05-14 07:07:29 -04:00
]
]
]
// Header output label
+ SGridPanel : : Slot ( 0 , 2 )
. VAlign ( VAlign_Center )
. Padding ( 0 , 0 , 12 , 0 )
[
SNew ( STextBlock )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-05-14 07:07:29 -04:00
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.SelectedParentClassLabel " )
2015-01-07 09:52:40 -05:00
. Text ( LOCTEXT ( " HeaderFileLabel " , " Header File " ) )
2014-05-14 07:07:29 -04:00
]
// Header output text
+ SGridPanel : : Slot ( 1 , 2 )
. Padding ( 0.0f , 3.0f )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-05-14 07:07:29 -04:00
. VAlign ( VAlign_Center )
. HeightOverride ( EditableTextHeight )
[
SNew ( STextBlock )
. Text ( this , & SNewClassDialog : : OnGetClassHeaderFileText )
]
]
// Source output label
+ SGridPanel : : Slot ( 0 , 3 )
. VAlign ( VAlign_Center )
. Padding ( 0 , 0 , 12 , 0 )
[
SNew ( STextBlock )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-05-14 07:07:29 -04:00
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.SelectedParentClassLabel " )
2015-01-07 09:52:40 -05:00
. Text ( LOCTEXT ( " SourceFileLabel " , " Source File " ) )
2014-05-14 07:07:29 -04:00
]
// Source output text
+ SGridPanel : : Slot ( 1 , 3 )
. Padding ( 0.0f , 3.0f )
. VAlign ( VAlign_Center )
[
SNew ( SBox )
2015-02-16 04:29:11 -05:00
. Visibility ( ClassDomain = = EClassDomain : : Blueprint ? EVisibility : : Collapsed : EVisibility : : Visible )
2014-05-14 07:07:29 -04:00
. VAlign ( VAlign_Center )
. HeightOverride ( EditableTextHeight )
[
SNew ( STextBlock )
. Text ( this , & SNewClassDialog : : OnGetClassSourceFileText )
]
]
]
2014-03-14 14:13:41 -04:00
]
2014-05-14 07:07:29 -04:00
]
+ SVerticalBox : : Slot ( )
. AutoHeight ( )
. Padding ( 0.0f )
[
SNew ( SBorder )
. Padding ( FMargin ( 0.0f , 3.0f , 0.0f , 0.0f ) )
. BorderImage ( FEditorStyle : : GetBrush ( " DetailsView.CategoryBottom " ) )
. BorderBackgroundColor ( FLinearColor ( 0.6f , 0.6f , 0.6f , 1.0f ) )
]
2014-03-14 14:13:41 -04:00
]
2014-05-14 07:07:29 -04:00
]
]
2014-03-14 14:13:41 -04:00
]
] ;
// Select the first item
if ( InArgs . _Class = = NULL & & ParentClassItemsSource . Num ( ) > 0 )
{
ParentClassListView - > SetSelection ( ParentClassItemsSource [ 0 ] , ESelectInfo : : Direct ) ;
}
}
void SNewClassDialog : : Tick ( const FGeometry & AllottedGeometry , const double InCurrentTime , const float InDeltaTime )
{
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
// Every few seconds, the class name/path is checked for validity in case the disk contents changed and the location is now valid or invalid.
2014-03-14 14:13:41 -04:00
// After class creation, periodic checks are disabled to prevent a brief message indicating that the class you created already exists.
// This feature is re-enabled if the user did not restart and began editing parameters again.
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
if ( ! bPreventPeriodicValidityChecksUntilNextChange & & ( InCurrentTime > LastPeriodicValidityCheckTime + PeriodicValidityCheckFrequency ) )
2014-03-14 14:13:41 -04:00
{
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
UpdateInputValidity ( ) ;
2014-03-14 14:13:41 -04:00
}
}
TSharedRef < ITableRow > SNewClassDialog : : MakeParentClassListViewWidget ( TSharedPtr < FParentClassItem > ParentClassItem , const TSharedRef < STableViewBase > & OwnerTable )
{
if ( ! ensure ( ParentClassItem . IsValid ( ) ) )
{
return SNew ( STableRow < TSharedPtr < FParentClassItem > > , OwnerTable ) ;
}
2014-05-16 07:26:51 -04:00
if ( ! ParentClassItem - > ParentClassInfo . IsSet ( ) )
2014-03-14 14:13:41 -04:00
{
return SNew ( STableRow < TSharedPtr < FParentClassItem > > , OwnerTable ) ;
}
2014-05-16 07:26:51 -04:00
const FString ClassName = ParentClassItem - > ParentClassInfo . GetClassName ( ) ;
const FString ClassDescription = ParentClassItem - > ParentClassInfo . GetClassDescription ( ) ;
const FSlateBrush * const ClassBrush = ParentClassItem - > ParentClassInfo . GetClassIcon ( ) ;
2014-07-30 13:01:03 -04:00
const UClass * Class = ParentClassItem - > ParentClassInfo . BaseClass ;
2014-03-14 14:13:41 -04:00
2014-05-14 07:07:29 -04:00
const int32 ItemHeight = 64 ;
const int32 DescriptionIndent = 32 ;
2014-03-14 14:13:41 -04:00
return
SNew ( STableRow < TSharedPtr < FParentClassItem > > , OwnerTable )
. Style ( FEditorStyle : : Get ( ) , " NewClassDialog.ParentClassListView.TableRow " )
2014-07-30 13:01:03 -04:00
. ToolTip ( IDocumentation : : Get ( ) - > CreateToolTip ( FText : : FromString ( ClassDescription ) , nullptr , FEditorClassUtils : : GetDocumentationPage ( Class ) , FEditorClassUtils : : GetDocumentationExcerpt ( Class ) ) )
2014-03-14 14:13:41 -04:00
[
SNew ( SBox ) . HeightOverride ( ItemHeight )
[
SNew ( SVerticalBox )
+ SVerticalBox : : Slot ( )
. Padding ( 8 )
. AutoHeight ( )
[
SNew ( SHorizontalBox )
+ SHorizontalBox : : Slot ( )
. AutoWidth ( )
. VAlign ( VAlign_Center )
. Padding ( 0 , 0 , 4 , 0 )
[
SNew ( SImage )
2015-02-16 04:29:11 -05:00
. Image ( ClassBrush )
2014-03-14 14:13:41 -04:00
]
+ SHorizontalBox : : Slot ( )
. VAlign ( VAlign_Center )
[
SNew ( STextBlock )
. TextStyle ( FEditorStyle : : Get ( ) , " NewClassDialog.ParentClassItemTitle " )
2015-01-07 09:52:40 -05:00
. Text ( FText : : FromString ( ClassName ) )
2014-03-14 14:13:41 -04:00
]
]
+ SVerticalBox : : Slot ( )
. FillHeight ( 1.f )
. Padding ( DescriptionIndent , 0 , 0 , 0 )
[
SNew ( STextBlock )
2014-05-14 07:07:29 -04:00
//.AutoWrapText(true)
2015-01-07 09:52:40 -05:00
. Text ( FText : : FromString ( ClassDescription ) )
2014-03-14 14:13:41 -04:00
]
]
] ;
}
2014-11-26 13:56:07 -05:00
FText SNewClassDialog : : GetSelectedParentClassName ( ) const
2014-03-14 14:13:41 -04:00
{
2014-11-26 13:56:07 -05:00
return ParentClassInfo . IsSet ( ) ? FText : : FromString ( ParentClassInfo . GetClassName ( ) ) : FText : : GetEmpty ( ) ;
2014-03-14 14:13:41 -04:00
}
2014-07-14 16:50:34 -04:00
FString GetClassHeaderPath ( const UClass * Class )
{
if ( Class )
{
FString ClassHeaderPath ;
if ( FSourceCodeNavigation : : FindClassHeaderPath ( Class , ClassHeaderPath ) & & IFileManager : : Get ( ) . FileSize ( * ClassHeaderPath ) ! = INDEX_NONE )
{
return ClassHeaderPath ;
}
}
return FString ( ) ;
}
EVisibility SNewClassDialog : : GetSourceHyperlinkVisibility ( ) const
{
2015-02-16 04:29:11 -05:00
if ( ClassDomain = = EClassDomain : : Blueprint )
{
return EVisibility : : Collapsed ;
}
2015-03-17 09:34:18 -04:00
return ( ParentClassInfo . GetBaseClassHeaderFilename ( ) . Len ( ) > 0 ? EVisibility : : Visible : EVisibility : : Hidden ) ;
2014-07-14 16:50:34 -04:00
}
2014-11-26 13:56:07 -05:00
FText SNewClassDialog : : GetSelectedParentClassFilename ( ) const
2014-07-14 16:50:34 -04:00
{
2015-03-17 09:34:18 -04:00
const FString ClassHeaderPath = ParentClassInfo . GetBaseClassHeaderFilename ( ) ;
2014-07-14 16:50:34 -04:00
if ( ClassHeaderPath . Len ( ) > 0 )
{
2014-11-26 13:56:07 -05:00
return FText : : FromString ( FPaths : : GetCleanFilename ( * ClassHeaderPath ) ) ;
2014-07-14 16:50:34 -04:00
}
2014-11-26 13:56:07 -05:00
return FText : : GetEmpty ( ) ;
2014-07-14 16:50:34 -04:00
}
2014-07-21 17:31:27 -04:00
EVisibility SNewClassDialog : : GetDocLinkVisibility ( ) const
{
return ( ParentClassInfo . BaseClass = = nullptr | | FEditorClassUtils : : GetDocumentationLink ( ParentClassInfo . BaseClass ) . IsEmpty ( ) ? EVisibility : : Hidden : EVisibility : : Visible ) ;
}
FString SNewClassDialog : : GetSelectedParentDocLink ( ) const
{
return FEditorClassUtils : : GetDocumentationLink ( ParentClassInfo . BaseClass ) ;
}
2014-07-14 16:50:34 -04:00
void SNewClassDialog : : OnEditCodeClicked ( )
{
2015-03-17 09:34:18 -04:00
const FString ClassHeaderPath = ParentClassInfo . GetBaseClassHeaderFilename ( ) ;
2014-07-14 16:50:34 -04:00
if ( ClassHeaderPath . Len ( ) > 0 )
{
const FString AbsoluteHeaderPath = IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * ClassHeaderPath ) ;
FSourceCodeNavigation : : OpenSourceFile ( AbsoluteHeaderPath ) ;
}
}
2014-03-14 14:13:41 -04:00
void SNewClassDialog : : OnParentClassItemDoubleClicked ( TSharedPtr < FParentClassItem > TemplateItem )
{
// Advance to the name page
const int32 NamePageIdx = 1 ;
if ( MainWizard - > CanShowPage ( NamePageIdx ) )
{
MainWizard - > ShowPage ( NamePageIdx ) ;
}
}
void SNewClassDialog : : OnClassSelected ( TSharedPtr < FParentClassItem > Item , ESelectInfo : : Type SelectInfo )
{
if ( Item . IsValid ( ) )
{
ClassViewer - > ClearSelection ( ) ;
2014-05-16 07:26:51 -04:00
ParentClassInfo = Item - > ParentClassInfo ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-02-16 04:29:11 -05:00
ParentClassInfo = FNewClassInfo ( ) ;
2014-03-14 14:13:41 -04:00
}
}
void SNewClassDialog : : OnAdvancedClassSelected ( UClass * Class )
{
ParentClassListView - > ClearSelection ( ) ;
2015-02-16 04:29:11 -05:00
ParentClassInfo = FNewClassInfo ( Class ) ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 14:24:09 -05:00
ECheckBoxState SNewClassDialog : : IsFullClassTreeChecked ( ) const
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
return bShowFullClassTree ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-03-14 14:13:41 -04:00
}
2014-12-10 14:24:09 -05:00
void SNewClassDialog : : OnFullClassTreeChanged ( ECheckBoxState NewCheckedState )
2014-03-14 14:13:41 -04:00
{
2014-12-10 14:24:09 -05:00
bShowFullClassTree = ( NewCheckedState = = ECheckBoxState : : Checked ) ;
2014-03-14 14:13:41 -04:00
}
EVisibility SNewClassDialog : : GetBasicParentClassVisibility ( ) const
{
return bShowFullClassTree ? EVisibility : : Collapsed : EVisibility : : Visible ;
}
EVisibility SNewClassDialog : : GetAdvancedParentClassVisibility ( ) const
{
return bShowFullClassTree ? EVisibility : : Visible : EVisibility : : Collapsed ;
}
EVisibility SNewClassDialog : : GetNameErrorLabelVisibility ( ) const
{
return GetNameErrorLabelText ( ) . IsEmpty ( ) ? EVisibility : : Hidden : EVisibility : : Visible ;
}
2014-11-26 13:56:07 -05:00
FText SNewClassDialog : : GetNameErrorLabelText ( ) const
2014-03-14 14:13:41 -04:00
{
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
if ( ! bLastInputValidityCheckSuccessful )
2014-03-14 14:13:41 -04:00
{
2014-11-26 13:56:07 -05:00
return LastInputValidityErrorText ;
2014-03-14 14:13:41 -04:00
}
2014-11-26 13:56:07 -05:00
return FText : : GetEmpty ( ) ;
2014-03-14 14:13:41 -04:00
}
EVisibility SNewClassDialog : : GetGlobalErrorLabelVisibility ( ) const
{
2015-01-16 13:29:54 -05:00
return GetGlobalErrorLabelText ( ) . IsEmpty ( ) ? EVisibility : : Collapsed : EVisibility : : Visible ;
2014-03-14 14:13:41 -04:00
}
2015-01-07 09:52:40 -05:00
FText SNewClassDialog : : GetGlobalErrorLabelText ( ) const
2014-03-14 14:13:41 -04:00
{
if ( ! FSourceCodeNavigation : : IsCompilerAvailable ( ) )
{
2015-01-07 09:52:40 -05:00
return FText : : Format ( LOCTEXT ( " NoCompilerFound " , " No compiler was found. In order to use C++ code, you must first install {0}. " ) , FSourceCodeNavigation : : GetSuggestedSourceCodeIDE ( ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-01-07 09:52:40 -05:00
return FText : : GetEmpty ( ) ;
2014-03-14 14:13:41 -04:00
}
void SNewClassDialog : : OnNamePageEntered ( )
{
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
// Set the default class name based on the selected parent class, eg MyActor
2014-05-16 07:26:51 -04:00
const FString ParentClassName = ParentClassInfo . GetClassNameCPP ( ) ;
2015-01-30 10:35:05 -05:00
const FString PotentialNewClassName = FString : : Printf ( TEXT ( " %s%s " ) ,
DefaultClassPrefix . IsEmpty ( ) ? TEXT ( " My " ) : * DefaultClassPrefix ,
DefaultClassName . IsEmpty ( ) ? ( ParentClassName . IsEmpty ( ) ? TEXT ( " Class " ) : * ParentClassName ) : * DefaultClassName ) ;
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
// Only set the default if the user hasn't changed the class name from the previous default
if ( LastAutoGeneratedClassName . IsEmpty ( ) | | NewClassName = = LastAutoGeneratedClassName )
{
NewClassName = PotentialNewClassName ;
LastAutoGeneratedClassName = PotentialNewClassName ;
}
2014-05-16 07:26:51 -04:00
UpdateInputValidity ( ) ;
2014-03-14 14:13:41 -04:00
// Steal keyboard focus to accelerate name entering
2014-10-30 12:29:36 -04:00
FSlateApplication : : Get ( ) . SetKeyboardFocus ( ClassNameEditBox , EFocusCause : : SetDirectly ) ;
2014-03-14 14:13:41 -04:00
}
2014-11-26 13:56:07 -05:00
FText SNewClassDialog : : GetNameClassTitle ( ) const
2014-03-14 14:13:41 -04:00
{
2014-11-26 13:56:07 -05:00
static const FString NoneString = TEXT ( " None " ) ;
const FText ParentClassName = GetSelectedParentClassName ( ) ;
if ( ! ParentClassName . IsEmpty ( ) & & ParentClassName . ToString ( ) ! = NoneString )
2014-05-16 07:26:51 -04:00
{
2014-11-26 13:56:07 -05:00
return FText : : Format ( LOCTEXT ( " NameClassTitle " , " Name Your New {0} " ) , ParentClassName ) ;
2014-05-16 07:26:51 -04:00
}
2014-11-26 13:56:07 -05:00
return LOCTEXT ( " NameClassGenericTitle " , " Name Your New Class " ) ;
2014-03-14 14:13:41 -04:00
}
FText SNewClassDialog : : OnGetClassNameText ( ) const
{
return FText : : FromString ( NewClassName ) ;
}
void SNewClassDialog : : OnClassNameTextChanged ( const FText & NewText )
{
NewClassName = NewText . ToString ( ) ;
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
UpdateInputValidity ( ) ;
}
FText SNewClassDialog : : OnGetClassPathText ( ) const
{
return FText : : FromString ( NewClassPath ) ;
}
void SNewClassDialog : : OnClassPathTextChanged ( const FText & NewText )
{
NewClassPath = NewText . ToString ( ) ;
2014-08-04 18:21:05 -04:00
// If the user has selected a path which matches the root of a known module, then update our selected module to be that module
for ( const auto & AvailableModule : AvailableModules )
{
if ( NewClassPath . StartsWith ( AvailableModule - > ModuleSourcePath ) )
{
SelectedModuleInfo = AvailableModule ;
AvailableModulesCombo - > SetSelectedItem ( SelectedModuleInfo ) ;
break ;
}
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
UpdateInputValidity ( ) ;
}
2015-02-16 04:29:11 -05:00
void SNewClassDialog : : OnBlueprintPathSelected ( const FString & NewPath )
{
NewClassPath = NewPath ;
UpdateInputValidity ( ) ;
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
FText SNewClassDialog : : OnGetClassHeaderFileText ( ) const
{
return FText : : FromString ( CalculatedClassHeaderName ) ;
}
FText SNewClassDialog : : OnGetClassSourceFileText ( ) const
{
return FText : : FromString ( CalculatedClassSourceName ) ;
2014-03-14 14:13:41 -04:00
}
void SNewClassDialog : : CancelClicked ( )
{
CloseContainingWindow ( ) ;
}
bool SNewClassDialog : : CanFinish ( ) const
{
2014-05-16 07:26:51 -04:00
return bLastInputValidityCheckSuccessful & & ParentClassInfo . IsSet ( ) & & FSourceCodeNavigation : : IsCompilerAvailable ( ) ;
2014-03-14 14:13:41 -04:00
}
void SNewClassDialog : : FinishClicked ( )
{
check ( CanFinish ( ) ) ;
2015-02-16 04:29:11 -05:00
if ( ClassDomain = = EClassDomain : : Blueprint )
2014-03-14 14:13:41 -04:00
{
2015-02-16 04:29:11 -05:00
FString PackagePath = NewClassPath / NewClassName ;
2015-01-26 20:16:24 -05:00
2015-02-16 04:29:11 -05:00
if ( ! ParentClassInfo . BaseClass )
2015-01-26 20:14:10 -05:00
{
2015-02-16 04:29:11 -05:00
// @todo show fail reason in error label
FMessageDialog : : Open ( EAppMsgType : : Ok , LOCTEXT ( " AddCodeFailed_Blueprint_NoBase " , " No parent class has been specified. Failed to generate new Blueprint class. " ) ) ;
2015-01-26 20:14:10 -05:00
}
2015-02-16 04:29:11 -05:00
else if ( FindObject < UBlueprint > ( ANY_PACKAGE , * PackagePath ) )
2014-03-14 14:13:41 -04:00
{
2015-02-16 04:29:11 -05:00
// @todo show fail reason in error label
FMessageDialog : : Open ( EAppMsgType : : Ok , LOCTEXT ( " AddCodeFailed_Blueprint_AlreadyExists " , " The chosen Blueprint class already exists, please try again with a different name. " ) ) ;
2014-03-14 14:13:41 -04:00
}
2015-02-16 04:29:11 -05:00
else if ( ! NewClassPath . IsEmpty ( ) & & ! NewClassName . IsEmpty ( ) )
2014-03-14 14:13:41 -04:00
{
2015-02-16 04:29:11 -05:00
UPackage * Package = CreatePackage ( NULL , * PackagePath ) ;
if ( Package )
2015-01-26 20:14:10 -05:00
{
2015-02-16 04:29:11 -05:00
// Create and init a new Blueprint
UBlueprint * NewBP = FKismetEditorUtilities : : CreateBlueprint ( const_cast < UClass * > ( ParentClassInfo . BaseClass ) , Package , FName ( * NewClassName ) , BPTYPE_Normal , UBlueprint : : StaticClass ( ) , UBlueprintGeneratedClass : : StaticClass ( ) ) ;
if ( NewBP )
{
// Notify the asset registry
FAssetRegistryModule : : AssetCreated ( NewBP ) ;
2015-01-26 20:14:10 -05:00
2015-02-16 04:29:11 -05:00
// Mark the package dirty...
Package - > MarkPackageDirty ( ) ;
2014-03-14 14:13:41 -04:00
2015-02-16 04:29:11 -05:00
OnAddedToProject . ExecuteIfBound ( NewClassName , PackagePath , FString ( ) ) ;
2015-03-11 11:54:24 -04:00
// Sync the content browser to the new asset
TArray < UObject * > SyncAssets ;
SyncAssets . Add ( NewBP ) ;
FContentBrowserModule & ContentBrowserModule = FModuleManager : : LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) ;
ContentBrowserModule . Get ( ) . SyncBrowserToAssets ( SyncAssets ) ;
// Open the editor for the new asset
FAssetEditorManager : : Get ( ) . OpenEditorForAsset ( NewBP ) ;
2015-02-16 04:29:11 -05:00
// Successfully created the code and potentially opened the IDE. Close the dialog.
CloseContainingWindow ( ) ;
return ;
}
2014-03-14 14:13:41 -04:00
}
}
2015-02-16 04:29:11 -05:00
// @todo show fail reason in error label
// Failed to add blueprint
const FText Message = FText : : Format ( LOCTEXT ( " AddCodeFailed_Blueprint " , " Failed to create package for class {0}. Please try again with a different name. " ) , FText : : FromString ( NewClassName ) ) ;
FMessageDialog : : Open ( EAppMsgType : : Ok , Message ) ;
2014-03-14 14:13:41 -04:00
}
else
{
2015-02-16 04:29:11 -05:00
FString HeaderFilePath ;
FString CppFilePath ;
FText FailReason ;
const TSet < FString > & DisallowedHeaderNames = FSourceCodeNavigation : : GetSourceFileDatabase ( ) . GetDisallowedHeaderNames ( ) ;
2015-04-17 10:02:43 -04:00
const GameProjectUtils : : EAddCodeToProjectResult AddCodeResult = GameProjectUtils : : AddCodeToProject ( NewClassName , NewClassPath , * SelectedModuleInfo , ParentClassInfo , DisallowedHeaderNames , HeaderFilePath , CppFilePath , FailReason ) ;
if ( AddCodeResult = = GameProjectUtils : : EAddCodeToProjectResult : : Succeeded )
2015-02-16 04:29:11 -05:00
{
OnAddedToProject . ExecuteIfBound ( NewClassName , NewClassPath , SelectedModuleInfo - > ModuleName ) ;
// Prevent periodic validity checks. This is to prevent a brief error message about the class already existing while you are exiting.
bPreventPeriodicValidityChecksUntilNextChange = true ;
// Display a nag if we didn't automatically hot-reload for the newly added class
2015-04-20 10:12:55 -04:00
const bool bWasHotReloaded = GetDefault < UEditorPerProjectUserSettings > ( ) - > bAutomaticallyHotReloadNewClasses ;
2015-02-16 04:29:11 -05:00
if ( bWasHotReloaded )
{
FNotificationInfo Notification ( FText : : Format ( LOCTEXT ( " AddedClassSuccessNotification " , " Added new class {0} " ) , FText : : FromString ( NewClassName ) ) ) ;
FSlateNotificationManager : : Get ( ) . AddNotification ( Notification ) ;
}
if ( HeaderFilePath . IsEmpty ( ) | | CppFilePath . IsEmpty ( ) | | ! FSlateApplication : : Get ( ) . SupportsSourceAccess ( ) )
{
if ( ! bWasHotReloaded )
{
// Code successfully added, notify the user. We are either running on a platform that does not support source access or a file was not given so don't ask about editing the file
const FText Message = FText : : Format (
2015-04-17 10:02:43 -04:00
LOCTEXT ( " AddCodeSuccessWithHotReload " , " Successfully added class '{0}', however you must recompile the '{1}' module before it will appear in the Content Browser. " )
2015-02-16 04:29:11 -05:00
, FText : : FromString ( NewClassName ) , FText : : FromString ( SelectedModuleInfo - > ModuleName ) ) ;
FMessageDialog : : Open ( EAppMsgType : : Ok , Message ) ;
}
else
{
// Code was added and hot reloaded into the editor, but the user doesn't have a code IDE installed so we can't open the file to edit it now
}
}
else
{
bool bEditSourceFilesNow = false ;
if ( bWasHotReloaded )
{
// Code was hot reloaded, so always edit the new classes now
bEditSourceFilesNow = true ;
}
else
{
// Code successfully added, notify the user and ask about opening the IDE now
const FText Message = FText : : Format (
2015-04-17 10:02:43 -04:00
LOCTEXT ( " AddCodeSuccessWithHotReloadAndSync " , " Successfully added class '{0}', however you must recompile the '{1}' module before it will appear in the Content Browser. \n \n Would you like to edit the code now? " )
2015-02-16 04:29:11 -05:00
, FText : : FromString ( NewClassName ) , FText : : FromString ( SelectedModuleInfo - > ModuleName ) ) ;
bEditSourceFilesNow = ( FMessageDialog : : Open ( EAppMsgType : : YesNo , Message ) = = EAppReturnType : : Yes ) ;
}
if ( bEditSourceFilesNow )
{
TArray < FString > SourceFiles ;
SourceFiles . Add ( IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * HeaderFilePath ) ) ;
SourceFiles . Add ( IFileManager : : Get ( ) . ConvertToAbsolutePathForExternalAppForRead ( * CppFilePath ) ) ;
FSourceCodeNavigation : : OpenSourceFiles ( SourceFiles ) ;
}
}
2015-03-11 11:54:24 -04:00
// Sync the content browser to the new class
UPackage * const ClassPackage = FindPackage ( nullptr , * ( FString ( " /Script/ " ) + SelectedModuleInfo - > ModuleName ) ) ;
if ( ClassPackage )
{
UClass * const NewClass = static_cast < UClass * > ( FindObjectWithOuter ( ClassPackage , UClass : : StaticClass ( ) , * NewClassName ) ) ;
if ( NewClass )
{
TArray < UObject * > SyncAssets ;
SyncAssets . Add ( NewClass ) ;
FContentBrowserModule & ContentBrowserModule = FModuleManager : : LoadModuleChecked < FContentBrowserModule > ( " ContentBrowser " ) ;
ContentBrowserModule . Get ( ) . SyncBrowserToAssets ( SyncAssets ) ;
}
}
2015-02-16 04:29:11 -05:00
// Successfully created the code and potentially opened the IDE. Close the dialog.
CloseContainingWindow ( ) ;
}
2015-04-17 10:02:43 -04:00
else if ( AddCodeResult = = GameProjectUtils : : EAddCodeToProjectResult : : FailedToHotReload )
2015-02-16 04:29:11 -05:00
{
2015-04-17 10:02:43 -04:00
OnAddedToProject . ExecuteIfBound ( NewClassName , NewClassPath , SelectedModuleInfo - > ModuleName ) ;
// Prevent periodic validity checks. This is to prevent a brief error message about the class already existing while you are exiting.
bPreventPeriodicValidityChecksUntilNextChange = true ;
// Failed to compile new code
const FText Message = FText : : Format (
LOCTEXT ( " AddCodeFailed_HotReloadFailed " , " Successfully added class '{0}', however you must recompile the '{1}' module before it will appear in the Content Browser. {2} \n \n Would you like to open the Output Log to see more details? " )
, FText : : FromString ( NewClassName ) , FText : : FromString ( SelectedModuleInfo - > ModuleName ) , FailReason ) ;
2015-03-09 15:38:57 -04:00
if ( FMessageDialog : : Open ( EAppMsgType : : YesNo , Message ) = = EAppReturnType : : Yes )
{
FGlobalTabmanager : : Get ( ) - > InvokeTab ( FName ( " OutputLog " ) ) ;
}
2015-04-17 10:02:43 -04:00
// We did manage to add the code itself, so we can close the dialog.
CloseContainingWindow ( ) ;
}
else
{
// @todo show fail reason in error label
// Failed to add code
const FText Message = FText : : Format ( LOCTEXT ( " AddCodeFailed_AddCodeFailed " , " Failed to add class '{0}'. {1} " ) , FText : : FromString ( NewClassName ) , FailReason ) ;
FMessageDialog : : Open ( EAppMsgType : : Ok , Message ) ;
2015-02-16 04:29:11 -05:00
}
2014-03-14 14:13:41 -04:00
}
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
FReply SNewClassDialog : : HandleChooseFolderButtonClicked ( )
2014-03-14 14:13:41 -04:00
{
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
IDesktopPlatform * DesktopPlatform = FDesktopPlatformModule : : Get ( ) ;
if ( DesktopPlatform )
2014-03-14 14:13:41 -04:00
{
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
TSharedPtr < SWindow > ParentWindow = FSlateApplication : : Get ( ) . FindWidgetWindow ( AsShared ( ) ) ;
void * ParentWindowWindowHandle = ( ParentWindow . IsValid ( ) ) ? ParentWindow - > GetNativeWindow ( ) - > GetOSWindowHandle ( ) : nullptr ;
FString FolderName ;
const FString Title = LOCTEXT ( " NewClassBrowseTitle " , " Choose a source location " ) . ToString ( ) ;
const bool bFolderSelected = DesktopPlatform - > OpenDirectoryDialog (
ParentWindowWindowHandle ,
Title ,
NewClassPath ,
FolderName
) ;
if ( bFolderSelected )
{
if ( ! FolderName . EndsWith ( TEXT ( " / " ) ) )
{
FolderName + = TEXT ( " / " ) ;
}
NewClassPath = FolderName ;
2014-08-04 18:21:05 -04:00
// If the user has selected a path which matches the root of a known module, then update our selected module to be that module
for ( const auto & AvailableModule : AvailableModules )
{
if ( NewClassPath . StartsWith ( AvailableModule - > ModuleSourcePath ) )
{
SelectedModuleInfo = AvailableModule ;
AvailableModulesCombo - > SetSelectedItem ( SelectedModuleInfo ) ;
break ;
}
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
UpdateInputValidity ( ) ;
}
2014-03-14 14:13:41 -04:00
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
return FReply : : Handled ( ) ;
}
2014-08-04 18:21:05 -04:00
FText SNewClassDialog : : GetSelectedModuleComboText ( ) const
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ModuleName " ) , FText : : FromString ( SelectedModuleInfo - > ModuleName ) ) ;
Args . Add ( TEXT ( " ModuleType " ) , FText : : FromString ( EHostType : : ToString ( SelectedModuleInfo - > ModuleType ) ) ) ;
return FText : : Format ( LOCTEXT ( " ModuleComboEntry " , " {ModuleName} ({ModuleType}) " ) , Args ) ;
}
2014-10-13 11:47:21 -04:00
void SNewClassDialog : : SelectedModuleComboBoxSelectionChanged ( TSharedPtr < FModuleContextInfo > Value , ESelectInfo : : Type SelectInfo )
2014-08-04 18:21:05 -04:00
{
const FString & OldModulePath = SelectedModuleInfo - > ModuleSourcePath ;
const FString & NewModulePath = Value - > ModuleSourcePath ;
SelectedModuleInfo = Value ;
// Update the class path to be rooted to the new module location
const FString AbsoluteClassPath = FPaths : : ConvertRelativePathToFull ( NewClassPath ) / " " ; // Ensure trailing /
if ( AbsoluteClassPath . StartsWith ( OldModulePath ) )
{
NewClassPath = AbsoluteClassPath . Replace ( * OldModulePath , * NewModulePath ) ;
}
UpdateInputValidity ( ) ;
}
2014-10-13 11:47:21 -04:00
TSharedRef < SWidget > SNewClassDialog : : MakeWidgetForSelectedModuleCombo ( TSharedPtr < FModuleContextInfo > Value )
2014-08-04 18:21:05 -04:00
{
FFormatNamedArguments Args ;
Args . Add ( TEXT ( " ModuleName " ) , FText : : FromString ( Value - > ModuleName ) ) ;
Args . Add ( TEXT ( " ModuleType " ) , FText : : FromString ( EHostType : : ToString ( Value - > ModuleType ) ) ) ;
return SNew ( STextBlock )
. Text ( FText : : Format ( LOCTEXT ( " ModuleComboEntry " , " {ModuleName} ({ModuleType}) " ) , Args ) ) ;
}
2014-05-14 06:47:25 -04:00
FSlateColor SNewClassDialog : : GetClassLocationTextColor ( GameProjectUtils : : EClassLocation InLocation ) const
{
return ( ClassLocation = = InLocation ) ? FSlateColor ( FLinearColor ( 0 , 0 , 0 ) ) : FSlateColor ( FLinearColor ( 0.72f , 0.72f , 0.72f , 1.f ) ) ;
}
2014-12-10 14:24:09 -05:00
ECheckBoxState SNewClassDialog : : IsClassLocationActive ( GameProjectUtils : : EClassLocation InLocation ) const
2014-05-14 06:47:25 -04:00
{
2014-12-10 14:24:09 -05:00
return ( ClassLocation = = InLocation ) ? ECheckBoxState : : Checked : ECheckBoxState : : Unchecked ;
2014-05-14 06:47:25 -04:00
}
2014-12-10 14:24:09 -05:00
void SNewClassDialog : : OnClassLocationChanged ( ECheckBoxState InCheckedState , GameProjectUtils : : EClassLocation InLocation )
2014-05-14 06:47:25 -04:00
{
2014-12-10 14:24:09 -05:00
if ( InCheckedState = = ECheckBoxState : : Checked )
2014-05-14 06:47:25 -04:00
{
const FString AbsoluteClassPath = FPaths : : ConvertRelativePathToFull ( NewClassPath ) / " " ; // Ensure trailing /
GameProjectUtils : : EClassLocation TmpClassLocation = GameProjectUtils : : EClassLocation : : UserDefined ;
2014-08-04 18:21:05 -04:00
GameProjectUtils : : GetClassLocation ( AbsoluteClassPath , * SelectedModuleInfo , TmpClassLocation ) ;
2014-05-14 06:47:25 -04:00
2014-08-04 18:21:05 -04:00
const FString RootPath = SelectedModuleInfo - > ModuleSourcePath ;
2014-05-14 06:47:25 -04:00
const FString PublicPath = RootPath / " Public " / " " ; // Ensure trailing /
const FString PrivatePath = RootPath / " Private " / " " ; // Ensure trailing /
// Update the class path to be rooted to the Public or Private folder based on InVisibility
switch ( InLocation )
{
case GameProjectUtils : : EClassLocation : : Public :
if ( AbsoluteClassPath . StartsWith ( PrivatePath ) )
{
NewClassPath = AbsoluteClassPath . Replace ( * PrivatePath , * PublicPath ) ;
}
else if ( AbsoluteClassPath . StartsWith ( RootPath ) )
{
NewClassPath = AbsoluteClassPath . Replace ( * RootPath , * PublicPath ) ;
}
2015-03-12 10:06:48 -04:00
else
{
NewClassPath = PublicPath ;
}
2014-05-14 06:47:25 -04:00
break ;
case GameProjectUtils : : EClassLocation : : Private :
if ( AbsoluteClassPath . StartsWith ( PublicPath ) )
{
NewClassPath = AbsoluteClassPath . Replace ( * PublicPath , * PrivatePath ) ;
}
else if ( AbsoluteClassPath . StartsWith ( RootPath ) )
{
NewClassPath = AbsoluteClassPath . Replace ( * RootPath , * PrivatePath ) ;
}
2015-03-12 10:06:48 -04:00
else
{
NewClassPath = PrivatePath ;
}
2014-05-14 06:47:25 -04:00
break ;
default :
break ;
}
// Will update ClassVisibility correctly
UpdateInputValidity ( ) ;
}
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
void SNewClassDialog : : UpdateInputValidity ( )
{
bLastInputValidityCheckSuccessful = true ;
2015-02-16 04:29:11 -05:00
if ( ClassDomain = = EClassDomain : : Blueprint )
2014-05-14 06:47:25 -04:00
{
2015-02-16 04:29:11 -05:00
bLastInputValidityCheckSuccessful = GameProjectUtils : : IsValidClassNameForCreation ( NewClassName , LastInputValidityErrorText ) ;
ClassLocation = GameProjectUtils : : EClassLocation : : UserDefined ;
if ( bLastInputValidityCheckSuccessful )
2014-05-14 06:47:25 -04:00
{
2015-02-16 04:29:11 -05:00
IAssetRegistry & AssetRegistry = FModuleManager : : LoadModuleChecked < FAssetRegistryModule > ( AssetRegistryConstants : : ModuleName ) . Get ( ) ;
if ( AssetRegistry . GetAssetByObjectPath ( * ( NewClassPath / NewClassName ) ) . IsValid ( ) )
{
bLastInputValidityCheckSuccessful = false ;
LastInputValidityErrorText = FText : : Format ( LOCTEXT ( " AssetAlreadyExists " , " An asset called {0} already exists in {1}. " ) , FText : : FromString ( NewClassName ) , FText : : FromString ( NewClassPath ) ) ;
}
2014-05-14 06:47:25 -04:00
}
}
else
{
2015-02-16 04:29:11 -05:00
// Validate the path first since this has the side effect of updating the UI
bLastInputValidityCheckSuccessful = GameProjectUtils : : CalculateSourcePaths ( NewClassPath , * SelectedModuleInfo , CalculatedClassHeaderName , CalculatedClassSourceName , & LastInputValidityErrorText ) ;
CalculatedClassHeaderName / = ParentClassInfo . GetHeaderFilename ( NewClassName ) ;
CalculatedClassSourceName / = ParentClassInfo . GetSourceFilename ( NewClassName ) ;
2014-05-14 06:47:25 -04:00
2015-02-16 04:29:11 -05:00
// If the source paths check as succeeded, check to see if we're using a Public/Private class
if ( bLastInputValidityCheckSuccessful )
2015-01-16 15:39:47 -05:00
{
2015-02-16 04:29:11 -05:00
GameProjectUtils : : GetClassLocation ( NewClassPath , * SelectedModuleInfo , ClassLocation ) ;
// We only care about the Public and Private folders
if ( ClassLocation ! = GameProjectUtils : : EClassLocation : : Public & & ClassLocation ! = GameProjectUtils : : EClassLocation : : Private )
{
ClassLocation = GameProjectUtils : : EClassLocation : : UserDefined ;
}
}
else
{
ClassLocation = GameProjectUtils : : EClassLocation : : UserDefined ;
}
// Validate the class name only if the path is valid
if ( bLastInputValidityCheckSuccessful )
{
const TSet < FString > & DisallowedHeaderNames = FSourceCodeNavigation : : GetSourceFileDatabase ( ) . GetDisallowedHeaderNames ( ) ;
bLastInputValidityCheckSuccessful = GameProjectUtils : : IsValidClassNameForCreation ( NewClassName , * SelectedModuleInfo , DisallowedHeaderNames , LastInputValidityErrorText ) ;
}
// Validate that the class is valid for the currently selected module
// As a project can have multiple modules, this lets us update the class validity as the user changes the target module
if ( bLastInputValidityCheckSuccessful & & ParentClassInfo . BaseClass )
{
bLastInputValidityCheckSuccessful = GameProjectUtils : : IsValidBaseClassForCreation ( ParentClassInfo . BaseClass , * SelectedModuleInfo ) ;
if ( ! bLastInputValidityCheckSuccessful )
{
LastInputValidityErrorText = FText : : Format (
LOCTEXT ( " NewClassError_InvalidBaseClassForModule " , " {0} cannot be used as a base class in the {1} module. Please make sure that {0} is API exported. " ) ,
FText : : FromString ( ParentClassInfo . BaseClass - > GetName ( ) ) ,
FText : : FromString ( SelectedModuleInfo - > ModuleName )
) ;
}
2015-01-16 15:39:47 -05:00
}
}
#ttp 322244 - LIVE: Feature Request: During "Add Code to Project", allow user to select path where files go
#proj UE4
#branch UE4
#summary You can now choose where to place a class added via the New Class Wizard
#extra This tries to be smart about your placement if you have Public and Private folders for your project.
- By default the header would go into Public, and the source file would go into Private.
- If you select the Public/Classes folder for the path, the source file will still go into Private.
- If you have a sub-path, eg) /Public/MyStuff/MyClass.h, this will be mirrored in the placement of the source file, eg) /Private/MyStuff/MyClass.cpp
#extra If you're not using Public or Private folders it will just place the source at whatever path you specified.
#extra It will verify that your source code is going to a valid module folder for your game, and also allows matching of modules that start with your game name, eg) MyGame, MyGameEditor.
#reviewedby Thomas.Sarkanen, Max.Preussner
[CL 2046528 by Jamie Dale in Main branch]
2014-04-23 18:50:08 -04:00
LastPeriodicValidityCheckTime = FSlateApplication : : Get ( ) . GetCurrentTime ( ) ;
2014-03-14 14:13:41 -04:00
// Since this function was invoked, periodic validity checks should be re-enabled if they were disabled.
bPreventPeriodicValidityChecksUntilNextChange = false ;
}
2015-02-16 04:29:11 -05:00
const FNewClassInfo & SNewClassDialog : : GetSelectedParentClassInfo ( ) const
2014-03-14 14:13:41 -04:00
{
2014-05-16 07:26:51 -04:00
return ParentClassInfo ;
2014-03-14 14:13:41 -04:00
}
2015-02-16 04:29:11 -05:00
void SNewClassDialog : : SetupParentClassItems ( const TArray < FNewClassInfo > & UserSpecifiedFeaturedClasses )
2014-03-14 14:13:41 -04:00
{
2015-02-16 04:29:11 -05:00
TArray < FNewClassInfo > DefaultFeaturedClasses ;
const TArray < FNewClassInfo > * ArrayToUse = & UserSpecifiedFeaturedClasses ;
2014-05-16 07:26:51 -04:00
2015-02-16 04:29:11 -05:00
// Setup the featured classes list
if ( ArrayToUse - > Num ( ) = = 0 )
2014-03-14 14:13:41 -04:00
{
2015-02-16 04:29:11 -05:00
DefaultFeaturedClasses = ClassDomain = = EClassDomain : : Native ? FFeaturedClasses : : AllNativeClasses ( ) : FFeaturedClasses : : ActorClasses ( ) ;
ArrayToUse = & DefaultFeaturedClasses ;
}
for ( const auto & Featured : * ArrayToUse )
{
ParentClassItemsSource . Add ( MakeShareable ( new FParentClassItem ( Featured ) ) ) ;
2014-03-14 14:13:41 -04:00
}
}
void SNewClassDialog : : CloseContainingWindow ( )
{
FWidgetPath WidgetPath ;
TSharedPtr < SWindow > ContainingWindow = FSlateApplication : : Get ( ) . FindWidgetWindow ( AsShared ( ) , WidgetPath ) ;
if ( ContainingWindow . IsValid ( ) )
{
ContainingWindow - > RequestDestroyWindow ( ) ;
}
}
# undef LOCTEXT_NAMESPACE