Files
UnrealEngineUWP/Engine/Source/Editor/DetailCustomizations/Private/DirectoryPathStructCustomization.cpp
Jamie Dale 3ea331525b UAT now uses the game INI files to add additional directories to cook and stage.
TTP# 335070 - Add GUI based way to specify additional non-asset files or paths to package

CookCommandlet now uses the project settings to work out which additional directories it should cook (this removes the need for the editor to pass this information to that UAT via the command line). I've left the COOKDIR option in the UAT/CookCommandlet as, while non of our projects seem to be using it, I'm not comfortable removing it in case any scripts are using it.

CopyBuildToStagingDirectory also uses these project settings to work out which additional directories it should stage when producing the staging manifest (these are split into UFS and non-UFS directories). This allows users to define additional directories in the editor (or directly in the settings file) which will always be staged regardless of how UAT is invoked.

All of these paths are specified in the settings file as relative to the project Content directory, and the editor will enforce this fact when using the directory picker.

Also mirrored the meta-data interface from UField on IPropertyHandle. This takes care of accessing the meta-data from the correct property, even when you're accessing an element inside an array (MattK approved!).

ReviewedBy Thomas.Sarkanen, Robert.Manuszewski, Max.Preussner

[CL 2088172 by Jamie Dale in Main branch]
2014-05-29 17:38:00 -04:00

135 lines
4.5 KiB
C++

// Copyright 1998-2014 Epic Games, Inc. All Rights Reserved.
#include "DetailCustomizationsPrivatePCH.h"
#include "DirectoryPathStructCustomization.h"
#include "DesktopPlatformModule.h"
#include "ContentBrowserDelegates.h"
#define LOCTEXT_NAMESPACE "DirectoryPathStructCustomization"
TSharedRef<IStructCustomization> FDirectoryPathStructCustomization::MakeInstance()
{
return MakeShareable(new FDirectoryPathStructCustomization());
}
void FDirectoryPathStructCustomization::CustomizeStructHeader( TSharedRef<IPropertyHandle> StructPropertyHandle, class FDetailWidgetRow& HeaderRow, IStructCustomizationUtils& StructCustomizationUtils )
{
TSharedPtr<IPropertyHandle> PathProperty = StructPropertyHandle->GetChildHandle("Path");
const bool bRelativeToGameContentDir = StructPropertyHandle->HasMetaData( TEXT("RelativeToGameContentDir") );
const bool bUseRelativePath = StructPropertyHandle->HasMetaData( TEXT("RelativePath") );
AbsoluteGameContentDir = FPaths::ConvertRelativePathToFull(FPaths::GameContentDir());
if(PathProperty.IsValid())
{
HeaderRow.ValueContent()
.MinDesiredWidth(125.0f)
.MaxDesiredWidth(600.0f)
[
SNew(SHorizontalBox)
+SHorizontalBox::Slot()
.FillWidth(1.0f)
.VAlign(VAlign_Center)
[
PathProperty->CreatePropertyValueWidget()
]
+SHorizontalBox::Slot()
.AutoWidth()
.Padding(FMargin(4.0f, 0.0f, 0.0f, 0.0f))
.VAlign(VAlign_Center)
[
SAssignNew(BrowseButton, SButton)
.ButtonStyle( FEditorStyle::Get(), "HoverHintOnly" )
.ToolTipText( LOCTEXT( "FolderButtonToolTipText", "Choose a directory from this computer").ToString() )
.OnClicked( FOnClicked::CreateSP(this, &FDirectoryPathStructCustomization::OnPickDirectory, PathProperty.ToSharedRef(), bRelativeToGameContentDir, bUseRelativePath) )
.ContentPadding( 2.0f )
.ForegroundColor( FSlateColor::UseForeground() )
.IsFocusable( false )
[
SNew( SImage )
.Image( FEditorStyle::GetBrush("PropertyWindow.Button_Ellipsis") )
.ColorAndOpacity( FSlateColor::UseForeground() )
]
]
]
.NameContent()
[
StructPropertyHandle->CreatePropertyNameWidget()
];
}
}
void FDirectoryPathStructCustomization::CustomizeStructChildren( TSharedRef<IPropertyHandle> StructPropertyHandle, class IDetailChildrenBuilder& StructBuilder, IStructCustomizationUtils& StructCustomizationUtils )
{
}
FReply FDirectoryPathStructCustomization::OnPickDirectory(TSharedRef<IPropertyHandle> PropertyHandle, const bool bRelativeToGameContentDir, const bool bUseRelativePath) const
{
FString Directory;
IDesktopPlatform* DesktopPlatform = FDesktopPlatformModule::Get();
if ( DesktopPlatform )
{
TSharedPtr<SWindow> ParentWindow = FSlateApplication::Get().FindWidgetWindow(BrowseButton.ToSharedRef());
void* ParentWindowHandle = (ParentWindow.IsValid() && ParentWindow->GetNativeWindow().IsValid()) ? ParentWindow->GetNativeWindow()->GetOSWindowHandle() : nullptr;
FString StartDirectory = FEditorDirectories::Get().GetLastDirectory(ELastDirectory::GENERIC_IMPORT);
if(bRelativeToGameContentDir && !IsValidPath(StartDirectory, bRelativeToGameContentDir))
{
StartDirectory = AbsoluteGameContentDir;
}
// Loop until; a) the user cancels (OpenDirectoryDialog returns false), or, b) the chosen path is valid (IsValidPath returns true)
for(;;)
{
if( DesktopPlatform->OpenDirectoryDialog(ParentWindowHandle, LOCTEXT("FolderDialogTitle", "Choose a directory").ToString(), StartDirectory, Directory) )
{
FText FailureReason;
if( IsValidPath(Directory, bRelativeToGameContentDir, &FailureReason) )
{
FEditorDirectories::Get().SetLastDirectory(ELastDirectory::GENERIC_IMPORT, Directory);
if( bRelativeToGameContentDir )
{
Directory = Directory.RightChop(AbsoluteGameContentDir.Len());
}
if( bUseRelativePath )
{
Directory = IFileManager::Get().ConvertToRelativePath(*Directory);
}
PropertyHandle->SetValue(Directory);
}
else
{
StartDirectory = Directory;
FMessageDialog::Open(EAppMsgType::Ok, FailureReason);
continue;
}
}
break;
}
}
return FReply::Handled();
}
bool FDirectoryPathStructCustomization::IsValidPath(const FString& AbsolutePath, const bool bRelativeToGameContentDir, FText* const OutReason) const
{
if(bRelativeToGameContentDir)
{
if(!AbsolutePath.StartsWith(AbsoluteGameContentDir))
{
if(OutReason)
{
*OutReason = FText::Format(LOCTEXT("Error_InvalidRootPath", "The chosen directory must be within {0}"), FText::FromString(AbsoluteGameContentDir));
}
return false;
}
}
return true;
}
#undef LOCTEXT_NAMESPACE