Files
UnrealEngineUWP/Engine/Source/Developer/SlateFileDialogs/Private/SlateFileDlgWindow.cpp
Ben Marsh 4ba423868f Copying //UE4/Dev-Build to //UE4/Dev-Main (Source: //UE4/Dev-Build @ 3209340)
#lockdown Nick.Penwarden
#rb none

==========================
MAJOR FEATURES + CHANGES
==========================

Change 3209340 on 2016/11/23 by Ben.Marsh

	Convert UE4 codebase to an "include what you use" model - where every header just includes the dependencies it needs, rather than every source file including large monolithic headers like Engine.h and UnrealEd.h.

	Measured full rebuild times around 2x faster using XGE on Windows, and improvements of 25% or more for incremental builds and full rebuilds on most other platforms.

	  * Every header now includes everything it needs to compile.
	        * There's a CoreMinimal.h header that gets you a set of ubiquitous types from Core (eg. FString, FName, TArray, FVector, etc...). Most headers now include this first.
	        * There's a CoreTypes.h header that sets up primitive UE4 types and build macros (int32, PLATFORM_WIN64, etc...). All headers in Core include this first, as does CoreMinimal.h.
	  * Every .cpp file includes its matching .h file first.
	        * This helps validate that each header is including everything it needs to compile.
	  * No engine code includes a monolithic header such as Engine.h or UnrealEd.h any more.
	        * You will get a warning if you try to include one of these from the engine. They still exist for compatibility with game projects and do not produce warnings when included there.
	        * There have only been minor changes to our internal games down to accommodate these changes. The intent is for this to be as seamless as possible.
	  * No engine code explicitly includes a precompiled header any more.
	        * We still use PCHs, but they're force-included on the compiler command line by UnrealBuildTool instead. This lets us tune what they contain without breaking any existing include dependencies.
	        * PCHs are generated by a tool to get a statistical amount of coverage for the source files using it, and I've seeded the new shared PCHs to contain any header included by > 15% of source files.

	Tool used to generate this transform is at Engine\Source\Programs\IncludeTool.

[CL 3209342 by Ben Marsh in Main branch]
2016-11-23 15:48:37 -05:00

1681 lines
41 KiB
C++

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#include "SlateFileDlgWindow.h"
#include "SlateFileDialogsPrivate.h"
#include "HAL/PlatformProcess.h"
#include "GenericPlatform/GenericPlatformFile.h"
#include "HAL/PlatformFilemanager.h"
#include "HAL/FileManager.h"
#include "Modules/ModuleManager.h"
#include "Widgets/SWindow.h"
#include "Framework/Application/SlateApplication.h"
#include "Textures/SlateIcon.h"
#include "Framework/Commands/UIAction.h"
#include "Widgets/Layout/SSpacer.h"
#include "Framework/MultiBox/MultiBoxBuilder.h"
#include "Widgets/Input/SButton.h"
#include "Widgets/Input/STextComboBox.h"
#include "Widgets/Navigation/SBreadcrumbTrail.h"
#include "Widgets/Text/SInlineEditableTextBlock.h"
#include "DirectoryWatcherModule.h"
#if PLATFORM_WINDOWS
#include "WindowsHWrapper.h"
#endif
#define LOCTEXT_NAMESPACE "SlateFileDialogsNamespace"
DEFINE_LOG_CATEGORY_STATIC(LogSlateFileDialogs, Log, All);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
class FSlateFileDialogVisitor : public IPlatformFile::FDirectoryVisitor
{
public:
FSlateFileDialogVisitor(TArray<TSharedPtr<FFileEntry>> &InFileList,
TArray<TSharedPtr<FFileEntry>> &InFolderList, TSharedPtr<FString> InFilterList)
: FileList(InFileList),
FolderList(InFolderList),
FilterList(InFilterList)
{}
virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
{
int32 i;
// break filename from path
for (i = FCString::Strlen(FilenameOrDirectory) - 1; i >= 0; i--)
{
if (FilenameOrDirectory[i] == TCHAR('/'))
break;
}
#if HIDE_HIDDEN_FILES
if (FilenameOrDirectory[i + 1] == TCHAR('.'))
{
return true;
}
#endif
FDateTime stamp = IFileManager::Get().GetTimeStamp(FilenameOrDirectory);
FString ModDate = "";
FString FileSize = "";
if (bIsDirectory)
{
FolderList.Add(MakeShareable(new FFileEntry(FString(&FilenameOrDirectory[i + 1]), ModDate, FileSize, true)));
}
else
{
if (PassesFilterTest(&FilenameOrDirectory[i + 1]))
{
int64 size = IFileManager::Get().FileSize(FilenameOrDirectory);
if (size < 1048576)
{
size = (size + 1023) / 1024;
FileSize = FString::FromInt(size) + " KB";
}
else
{
size /= 1024;
if (size < 1048576)
{
size = (size + 1023) / 1024;
FileSize = FString::FromInt(size) + " MB";
}
else
{
size /= 1024;
size = (size + 1023) / 1024;
FileSize = FString::FromInt(size) + " GB";
}
}
ModDate = FString::Printf(TEXT("%02d/%02d/%04d "), stamp.GetMonth(), stamp.GetDay(), stamp.GetYear());
if (stamp.GetHour() == 0)
{
ModDate = ModDate + FString::Printf(TEXT("12:%02d AM"), stamp.GetMinute());
}
else if (stamp.GetHour() < 12)
{
ModDate = ModDate + FString::Printf(TEXT("%2d:%02d AM"), stamp.GetHour12(), stamp.GetMinute());
}
else
{
ModDate = ModDate + FString::Printf(TEXT("%2d:%02d PM"), stamp.GetHour12(), stamp.GetMinute());
}
FileList.Add(MakeShareable(new FFileEntry(FString(&FilenameOrDirectory[i + 1]), ModDate, FileSize, false)));
}
}
return true;
}
bool PassesFilterTest(const TCHAR *Filename)
{
if (!FilterList.IsValid())
{
return true; // no filters. everything passes.
}
int32 i;
const TCHAR *Extension = NULL;
// get extension
for (i = FCString::Strlen(Filename) - 1; i >= 0; i--)
{
if (Filename[i] == TCHAR('.'))
{
Extension = &Filename[i];
break;
}
}
if (Extension == NULL)
{
return false; // file has no extension. it fails filter test.
}
TCHAR Temp[MAX_FILTER_LENGTH];
FCString::Strcpy(Temp, FilterList->Len(), *(*FilterList.Get()));
// break path into tokens
TCHAR *ContextStr = nullptr;
TCHAR *FilterExt = FCString::Strtok(Temp, TEXT(";"), &ContextStr);
bool RC = false;
while (FilterExt)
{
// strip leading spaces and '*' from beginning.
FilterExt = FCString::Strchr(FilterExt, '.');
// strip any trailing spaces
for (i = FCString::Strlen(FilterExt) - 1; i >= 0 && FilterExt[i] == TCHAR(' '); i--)
{
FilterExt[i] = 0;
}
if (FCString::Strcmp(FilterExt, TEXT(".*")) == 0)
{
// *.* matches all
RC = true;
break;
}
if (FCString::Strcmp(FilterExt, Extension) == 0)
{
// positive hit.
RC = true;
break;
}
// next filter entry
FilterExt = FCString::Strtok(nullptr, TEXT(";"), &ContextStr);
}
// cleanup and return failed.
return RC;
}
private:
TArray<TSharedPtr<FFileEntry>>& FileList;
TArray<TSharedPtr<FFileEntry>>& FolderList;
TSharedPtr<FString> FilterList;
};
class FSlateFileDialogDirVisitor : public IPlatformFile::FDirectoryVisitor
{
public:
FSlateFileDialogDirVisitor(TArray<FString> *InDirectoryNames)
: DirectoryNames(InDirectoryNames)
{}
void SetResultPath(TArray<FString> *InDirectoryNames) { DirectoryNames = InDirectoryNames; }
virtual bool Visit(const TCHAR* FilenameOrDirectory, bool bIsDirectory) override
{
int32 i;
// break filename from path
for (i = FCString::Strlen(FilenameOrDirectory) - 1; i >= 0; i--)
{
if (FilenameOrDirectory[i] == TCHAR('/'))
break;
}
#if HIDE_HIDDEN_FILES
if (FilenameOrDirectory[i + 1] == TCHAR('.'))
{
return true;
}
#endif
if (bIsDirectory)
{
DirectoryNames->Add(FString(&FilenameOrDirectory[i + 1]));
}
return true;
}
private:
TArray<FString> *DirectoryNames;
};
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
FSlateFileDlgWindow::FSlateFileDlgWindow(FSlateFileDialogsStyle *InStyleSet)
{
StyleSet = InStyleSet;
}
bool FSlateFileDlgWindow::OpenFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath,
const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray<FString>& OutFilenames, int32& OutFilterIndex)
{
FString StartDirectory = DefaultPath;
TrimStartDirectory(StartDirectory);
TSharedRef<SWindow> ModalWindow = SNew(SWindow)
.SupportsMinimize(false)
.SupportsMaximize(false)
.Title(LOCTEXT("SlateFileDialogsOpenFile","Open File"))
.CreateTitleBar(true)
.MinHeight(400.0f)
.MinWidth(600.0f)
.ActivateWhenFirstShown(true)
.ClientSize(FVector2D(800, 500));
DialogWidget = SNew(SSlateFileOpenDlg)
.bMultiSelectEnabled(Flags == 1)
.ParentWindow(ModalWindow)
.CurrentPath(StartDirectory)
.Filters(FileTypes)
.WindowTitleText(DialogTitle)
.StyleSet(StyleSet);
DialogWidget->SetOutNames(&OutFilenames);
DialogWidget->SetOutFilterIndex(&OutFilterIndex);
ModalWindow->SetContent( DialogWidget.ToSharedRef() );
FSlateApplication::Get().AddModalWindow(ModalWindow, NULL);
return (DialogWidget->GetResponse() == EResult::Accept && OutFilenames.Num() > 0);
}
bool FSlateFileDlgWindow::OpenFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath,
const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray<FString>& OutFilenames)
{
int32 DummyIndex;
return OpenFileDialog(ParentWindowHandle, DialogTitle, DefaultPath, DefaultFile, FileTypes, Flags, OutFilenames, DummyIndex);
}
bool FSlateFileDlgWindow::OpenDirectoryDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath,
FString& OutFoldername)
{
int32 DummyIndex;
TArray<FString> TempOut;
FString Filters = "";
FString StartDirectory = DefaultPath;
TrimStartDirectory(StartDirectory);
TSharedRef<SWindow> ModalWindow = SNew(SWindow)
.SupportsMinimize(false)
.SupportsMaximize(false)
.Title(LOCTEXT("SlateFileDialogsOpenDirectory","Open Directory"))
.CreateTitleBar(true)
.MinHeight(400.0f)
.MinWidth(600.0f)
.ActivateWhenFirstShown(true)
.ClientSize(FVector2D(800, 500));
DialogWidget = SNew(SSlateFileOpenDlg)
.bMultiSelectEnabled(false)
.ParentWindow(ModalWindow)
.bDirectoriesOnly(true)
.CurrentPath(StartDirectory)
.WindowTitleText(DialogTitle)
.StyleSet(StyleSet);
DialogWidget->SetOutNames(&TempOut);
DialogWidget->SetOutFilterIndex(&DummyIndex);
ModalWindow->SetContent( DialogWidget.ToSharedRef() );
FSlateApplication::Get().AddModalWindow(ModalWindow, NULL);
bool RC = (DialogWidget->GetResponse() == EResult::Accept && TempOut.Num() > 0);
if (TempOut.Num() > 0)
{
OutFoldername = FPaths::ConvertRelativePathToFull(TempOut[0]);
if (!OutFoldername.EndsWith(TEXT("/")))
{
OutFoldername += TEXT("/");
}
}
return RC;
}
bool FSlateFileDlgWindow::SaveFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath,
const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray<FString>& OutFilenames)
{
int32 DummyIndex;
FString StartDirectory = DefaultPath;
TrimStartDirectory(StartDirectory);
TSharedRef<SWindow> ModalWindow = SNew(SWindow)
.SupportsMinimize(false)
.SupportsMaximize(false)
.Title(LOCTEXT("SlateFileDialogsSaveFile","Save File"))
.CreateTitleBar(true)
.MinHeight(400.0f)
.MinWidth(600.0f)
.ActivateWhenFirstShown(true)
.ClientSize(FVector2D(800, 500));
DialogWidget = SNew(SSlateFileOpenDlg)
.bMultiSelectEnabled(false)
.ParentWindow(ModalWindow)
.bSaveFile(true)
.AcceptText(LOCTEXT("SlateFileDialogsSave","Save"))
.CurrentPath(StartDirectory)
.Filters(FileTypes)
.WindowTitleText(DialogTitle)
.StyleSet(StyleSet);
DialogWidget->SetOutNames(&OutFilenames);
DialogWidget->SetOutFilterIndex(&DummyIndex);
DialogWidget->SetDefaultFile(DefaultFile);
ModalWindow->SetContent( DialogWidget.ToSharedRef() );
FSlateApplication::Get().AddModalWindow(ModalWindow, NULL);
return (DialogWidget->GetResponse() == EResult::Accept && OutFilenames.Num() > 0);
}
void FSlateFileDlgWindow::TrimStartDirectory(FString &InPath)
{
if (InPath.Len() == 0)
{
// no path given. nothing to do.
return;
}
FPaths::CollapseRelativeDirectories(InPath);
FString PathPart;
FString FileNamePart;
FString ExtensionPart;
FPaths::Split(InPath, PathPart, FileNamePart, ExtensionPart);
InPath = PathPart;
}
//-----------------------------------------------------------------------------
// custom file dialog widget
//-----------------------------------------------------------------------------
BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlateFileOpenDlg::Construct(const FArguments& InArgs)
{
CurrentPath = InArgs._CurrentPath;
Filters = InArgs._Filters;
bMultiSelectEnabled = InArgs._bMultiSelectEnabled;
bDirectoriesOnly = InArgs._bDirectoriesOnly;
bSaveFile = InArgs._bSaveFile;
WindowTitleText = InArgs._WindowTitleText;
OutNames = InArgs._OutNames;
OutFilterIndex = InArgs._OutFilterIndex;
UserResponse = FSlateFileDlgWindow::Cancel;
ParentWindow = InArgs._ParentWindow;
StyleSet = InArgs._StyleSet;
AcceptText = InArgs._AcceptText;
DirNodeIndex = -1;
FilterIndex = 0;
ESelectionMode::Type SelectMode = bMultiSelectEnabled ? ESelectionMode::Multi : ESelectionMode::Single;
struct EVisibility SaveFilenameVisibility = bDirectoriesOnly ? EVisibility::Collapsed : EVisibility::Visible;
this->ChildSlot
[
SNew(SBorder)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.Padding(FMargin(20.0f,20.0f))
.BorderImage(StyleSet->GetBrush("SlateFileDialogs.GroupBorder"))
[
SNew(SVerticalBox)
+ SVerticalBox::Slot() // window title
.HAlign(HAlign_Left)
.VAlign(VAlign_Fill)
.AutoHeight()
.Padding(FMargin(0.0f, 0.0f, 0.0f, 20.0f))
[
SAssignNew(WindowTitle, STextBlock)
.Text(FText::FromString(WindowTitleText))
.Font(StyleSet->GetFontStyle("SlateFileDialogs.DialogLarge"))
.Justification(ETextJustify::Center)
]
+ SVerticalBox::Slot() // Path breadcrumbs
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.AutoHeight()
.Padding(FMargin(0.0f, 0.0f, 0.0f, 10.0f))
[
SAssignNew(PathBreadcrumbTrail, SBreadcrumbTrail<FString>)
.ButtonContentPadding(FMargin(2.0f, 2.0f))
.ButtonStyle(StyleSet->Get(), "SlateFileDialogs.FlatButton")
.DelimiterImage(StyleSet->GetBrush("SlateFileDialogs.PathDelimiter"))
.TextStyle(StyleSet->Get(), "SlateFileDialogs.PathText")
.ShowLeadingDelimiter(false)
.InvertTextColorOnHover(false)
.OnCrumbClicked(this, &SSlateFileOpenDlg::OnPathClicked)
.GetCrumbMenuContent(this, &SSlateFileOpenDlg::OnGetCrumbDelimiterContent)
.AddMetaData<FTagMetaData>(FTagMetaData(TEXT("ContentBrowserPath")))
]
+ SVerticalBox::Slot() // new directory
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.AutoHeight()
.Padding(FMargin(0.0f, 0.0f, 0.0f, 10.0f))
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(0.0f, 0.0f, 10.0f, 0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.OnClicked(this, &SSlateFileOpenDlg::OnGoBackClick)
.ContentPadding(FMargin(0.0f))
[
SNew(SImage)
.Image(StyleSet->GetBrush("SlateFileDialogs.BrowseBack24"))
]
]
+ SHorizontalBox::Slot()
.Padding(FMargin(0.0f, 0.0f, 40.0f, 0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.OnClicked(this, &SSlateFileOpenDlg::OnGoForwardClick)
.ContentPadding(FMargin(0.0f))
[
SNew(SImage)
.Image(StyleSet->GetBrush("SlateFileDialogs.BrowseForward24"))
]
]
+ SHorizontalBox::Slot()
.Padding(FMargin(0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.OnClicked(this, &SSlateFileOpenDlg::OnNewDirectoryClick)
.ContentPadding(FMargin(0.0f))
[
SNew(SImage)
.Image(StyleSet->GetBrush("SlateFileDialogs.NewFolder24"))
]
]
+ SHorizontalBox::Slot()
.Padding(FMargin(20.0f, 0.0f, 0.0f, 0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SAssignNew(NewDirectorySizeBox, SBox)
.Padding(FMargin(0.0f))
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.WidthOverride(300.0f)
.Visibility(EVisibility::Hidden)
[
SNew(SBorder)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.Padding(FMargin(5.0f,0.0f))
.BorderBackgroundColor(FLinearColor(0.1f, 0.1f, 0.1f, 1.0f))
.BorderImage(StyleSet->GetBrush("SlateFileDialogs.WhiteBackground"))
[
SAssignNew(NewDirectoryEditBox, SInlineEditableTextBlock)
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.IsReadOnly(false)
.Text(FText::GetEmpty())
.OnTextCommitted(this, &SSlateFileOpenDlg::OnNewDirectoryCommitted)
.OnVerifyTextChanged(this, &SSlateFileOpenDlg::OnNewDirectoryTextChanged)
]
]
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.Padding(FMargin(20.0f, 0.0f, 0.0f, 0.0f))
.AutoWidth()
[
SAssignNew(NewDirCancelButton, SButton)
.ContentPadding(FMargin(5.0f, 5.0f))
.OnClicked(this, &SSlateFileOpenDlg::OnNewDirectoryAcceptCancelClick, FSlateFileDlgWindow::Cancel)
.Text(LOCTEXT("SlateFileDialogsCancel","Cancel"))
.Visibility(EVisibility::Hidden)
]
]
+ SVerticalBox::Slot() // new directory
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.AutoHeight()
.Padding(FMargin(0.0f, 0.0f, 0.0f, 10.0f))
[
SAssignNew(DirErrorMsg, STextBlock)
.Font(StyleSet->GetFontStyle("SlateFileDialogs.DialogBold"))
.Justification(ETextJustify::Left)
.ColorAndOpacity(FLinearColor::Yellow)
.Text(LOCTEXT("SlateFileDialogsDirError", "Unable to create directory!"))
.Visibility(EVisibility::Collapsed)
]
+ SVerticalBox::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.FillHeight(1.0f)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SVerticalBox)
+ SVerticalBox::Slot()
.Padding(FMargin(10.0f))
.AutoHeight()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.OnClicked(this, &SSlateFileOpenDlg::OnQuickLinkClick, FSlateFileDlgWindow::Project)
.ContentPadding(FMargin(2.0f))
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SImage)
.Image(StyleSet->GetBrush("SlateFileDialogs.Folder24"))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("ProjectsLabel", "Projects"))
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.Justification(ETextJustify::Left)
]
]
]
+ SVerticalBox::Slot()
.Padding(FMargin(10.0f))
.AutoHeight()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SButton)
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.OnClicked(this, &SSlateFileOpenDlg::OnQuickLinkClick, FSlateFileDlgWindow::Engine)
.ContentPadding(FMargin(2.0f))
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(SImage)
.Image(StyleSet->GetBrush("SlateFileDialogs.Folder24"))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.AutoWidth()
[
SNew(STextBlock)
.Text(LOCTEXT("EngineLabel", "Engine"))
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.Justification(ETextJustify::Left)
]
]
]
]
+ SHorizontalBox::Slot() // spacer
.Padding(FMargin(0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SSpacer)
.Size(FVector2D(20.0f, 1.0f))
]
+ SHorizontalBox::Slot() // file list area
.Padding(FMargin(0.0f, 0.0f, 20.0f, 0.0f))
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.FillWidth(1.0f)
[
SNew(SBorder)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.Padding(FMargin(10.0f))
.BorderBackgroundColor(FLinearColor(0.10f, 0.10f, 0.10f, 1.0f))
.BorderImage(StyleSet->GetBrush("SlateFileDialogs.WhiteBackground"))
[
SAssignNew(ListView, SListView<TSharedPtr<FFileEntry>>) // file list scroll
.ListItemsSource(&LineItemArray)
.SelectionMode(SelectMode)
.OnGenerateRow(this, &SSlateFileOpenDlg::OnGenerateWidgetForList)
.OnMouseButtonDoubleClick(this, &SSlateFileOpenDlg::OnItemDoubleClicked)
.OnSelectionChanged(this, &SSlateFileOpenDlg::OnItemSelected)
.HeaderRow
(
SNew(SHeaderRow)
.Visibility(EVisibility::Visible)
+ SHeaderRow::Column("Pathname")
.DefaultLabel(LOCTEXT("SlateFileDialogsNameHeader", "Name"))
.FillWidth(1.0f)
+ SHeaderRow::Column("ModDate")
.DefaultLabel(LOCTEXT("SlateFileDialogsModDateHeader", "Date Modified"))
.FixedWidth(170.0f)
+ SHeaderRow::Column("FileSize")
.DefaultLabel(LOCTEXT("SlateFileDialogsFileSizeHeader", "File Size"))
.FixedWidth(70.0f)
)
]
]
]
+ SVerticalBox::Slot() // save filename entry
.HAlign(HAlign_Right)
.VAlign(VAlign_Bottom)
.Padding(FMargin(0.0f, 10.0f, 50.0f, 0.0f))
.AutoHeight()
[
SAssignNew(SaveFilenameSizeBox, SBox)
.Padding(FMargin(0.0f))
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.MinDesiredHeight(20.0f)
.Visibility(SaveFilenameVisibility)
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(STextBlock)
.Text(LOCTEXT("FilenameLabel", "Filename:"))
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.Justification(ETextJustify::Left)
]
+ SHorizontalBox::Slot()
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
.AutoWidth()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
[
SNew(SBox)
.Padding(FMargin(0.0f))
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.WidthOverride(300.0f)
[
SNew(SBorder)
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.Padding(FMargin(5.0f,0.0f))
.BorderBackgroundColor(FLinearColor(0.1f, 0.1f, 0.1f, 1.0f))
.BorderImage(StyleSet->GetBrush("SlateFileDialogs.WhiteBackground"))
[
SAssignNew(SaveFilenameEditBox, SInlineEditableTextBlock)
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.IsReadOnly(false)
.Text(FText::GetEmpty())
.OnTextCommitted(this, &SSlateFileOpenDlg::OnFileNameCommitted)
]
]
]
]
]
+ SVerticalBox::Slot() // cancel:accept buttons
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.AutoHeight()
.Padding(FMargin(0.0f, 10.0f, 0.0f, 0.0f))
[
SNew(SHorizontalBox)
+ SHorizontalBox::Slot()
.Padding(FMargin(0.0f))
.AutoWidth()
.HAlign(HAlign_Left)
.VAlign(VAlign_Top)
[
SAssignNew(FilterHBox, SHorizontalBox)
+ SHorizontalBox::Slot()
.HAlign(HAlign_Left)
.VAlign(VAlign_Bottom)
.AutoWidth()
.Padding(FMargin(0.0f))
[
SNew(STextBlock)
.Text(LOCTEXT("FilterLabel", "Filter:"))
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.Justification(ETextJustify::Left)
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.AutoWidth()
.Padding(FMargin(10.0f, 0.0f, 0.0f, 0.0f))
[
SNew(SBox)
.MinDesiredWidth(200.0f)
.MaxDesiredWidth(200.0f)
.Padding(FMargin(0.0f))
[
SAssignNew(FilterCombo, STextComboBox)
.ContentPadding(FMargin(4.0f, 2.0f))
//.MaxListHeight(100.0f)
.OptionsSource(&FilterNameArray)
.Font(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"))
.OnSelectionChanged(this, &SSlateFileOpenDlg::OnFilterChanged)
]
]
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Fill)
.VAlign(VAlign_Fill)
.FillWidth(1.0f)
[
SNew(SSpacer)
.Size(FVector2D(1.0f, 1.0f))
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.Padding(FMargin(0.0f, 0.0f, 20.0f, 0.0f))
.AutoWidth()
[
SNew(SButton)
.ContentPadding(FMargin(5.0f, 5.0f))
.OnClicked(this, &SSlateFileOpenDlg::OnAcceptCancelClick, FSlateFileDlgWindow::Accept)
.Text(AcceptText)
]
+ SHorizontalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
.Padding(FMargin(0.0f))
.AutoWidth()
[
SNew(SButton)
.ContentPadding(FMargin(5.0f, 5.0f))
.OnClicked(this, &SSlateFileOpenDlg::OnAcceptCancelClick, FSlateFileDlgWindow::Cancel)
.Text(LOCTEXT("SlateFileDialogsCancel","Cancel"))
]
]
]
];
SaveFilename = "";
bNeedsBuilding = true;
bRebuildDirPath = true;
bDirectoryHasChanged = false;
DirectoryWatcher = nullptr;
if (CurrentPath.Len() > 0 && !CurrentPath.EndsWith("/"))
{
CurrentPath = CurrentPath + TEXT("/");
}
HistoryIndex = 0;
History.Add(CurrentPath);
#if ENABLE_DIRECTORY_WATCHER
if (!FModuleManager::Get().IsModuleLoaded("DirectoryWatcher"))
{
FModuleManager::Get().LoadModule("DirectoryWatcher");
}
FDirectoryWatcherModule &DirWatcherModule = FModuleManager::LoadModuleChecked<FDirectoryWatcherModule>(TEXT("DirectoryWatcher"));
DirectoryWatcher = DirWatcherModule.Get();
#endif
}
END_SLATE_FUNCTION_BUILD_OPTIMIZATION
void SSlateFileOpenDlg::BuildDirectoryPath()
{
// Clean up path as needed. Fix slashes and convert to absolute path.
FString NormPath = CurrentPath;
FPaths::NormalizeFilename(NormPath);
FPaths::RemoveDuplicateSlashes(NormPath);
FString AbsPath = FPaths::ConvertRelativePathToFull(NormPath);
TCHAR Temp[MAX_PATH_LENGTH];
DirectoryNodesArray.Empty();
FString BuiltPath;
if (PLATFORM_WINDOWS)
{
int32 Idx;
if (AbsPath.FindChar(TCHAR('/'), Idx))
{
BuiltPath = BuiltPath + TEXT("/") + AbsPath.Left(Idx);
}
FCString::Strcpy(Temp, ARRAY_COUNT(Temp), &AbsPath[Idx < AbsPath.Len() - 1 ? Idx + 1 : Idx]);
DirectoryNodesArray.Add(FDirNode(AbsPath.Left(Idx), nullptr));
}
else if (PLATFORM_LINUX)
{
// start with system base directory
FCString::Strcpy(Temp, ARRAY_COUNT(Temp), *AbsPath);
BuiltPath = "/";
DirectoryNodesArray.Add(FDirNode(FString(TEXT("/")), nullptr));
}
else
{
checkf(false, TEXT("SlateDialogs will not work on this platform (modify SSlateFileOpenDlg::BuildDirectoryPath())"));
}
// break path into tokens
TCHAR *ContextStr = nullptr;
TCHAR *DirNode = FCString::Strtok(Temp, TEXT("/"), &ContextStr);
while (DirNode)
{
FString Label = DirNode;
DirectoryNodesArray.Add(FDirNode(Label, nullptr));
BuiltPath = BuiltPath + Label + TEXT("/");
DirNode = FCString::Strtok(nullptr, TEXT("/"), &ContextStr);
}
RefreshCrumbs();
}
void SSlateFileOpenDlg::RefreshCrumbs()
{
// refresh crumb list
if (PathBreadcrumbTrail.IsValid())
{
PathBreadcrumbTrail->ClearCrumbs();
FString BuiltPath;
if (PLATFORM_WINDOWS)
{
PathBreadcrumbTrail->PushCrumb(LOCTEXT("SlateFileDialogsSystem", "System"), FString("SYSTEM"));
for (int32 i = 0; i < DirectoryNodesArray.Num(); i++)
{
BuiltPath = BuiltPath + DirectoryNodesArray[i].Label + TEXT("/");
PathBreadcrumbTrail->PushCrumb(FText::FromString(DirectoryNodesArray[i].Label), BuiltPath);
}
}
else if (PLATFORM_LINUX)
{
BuiltPath = "/";
PathBreadcrumbTrail->PushCrumb(FText::FromString(BuiltPath), BuiltPath);
for (int32 i = 1; i < DirectoryNodesArray.Num(); i++)
{
BuiltPath = BuiltPath + DirectoryNodesArray[i].Label + TEXT("/");
PathBreadcrumbTrail->PushCrumb(FText::FromString(DirectoryNodesArray[i].Label), BuiltPath);
}
}
}
}
void SSlateFileOpenDlg::OnPathClicked(const FString& NewPath)
{
if (NewPath.Compare("SYSTEM") == 0)
{
// Ignore clicks on the virtual root. (Only happens for Windows systems.)
return;
}
// set new current path and flag that we need to update directory display
CurrentPath = NewPath;
bRebuildDirPath = true;
bNeedsBuilding = true;
if ((History.Num()-HistoryIndex-1) > 0)
{
History.RemoveAt(HistoryIndex+1, History.Num()-HistoryIndex-1, true);
}
History.Add(CurrentPath);
HistoryIndex++;
RefreshCrumbs();
}
void SSlateFileOpenDlg::OnPathMenuItemClicked( FString ClickedPath )
{
CurrentPath = ClickedPath;
bRebuildDirPath = true;
bNeedsBuilding = true;
if ((History.Num()-HistoryIndex-1) > 0)
{
History.RemoveAt(HistoryIndex+1, History.Num()-HistoryIndex-1, true);
}
History.Add(CurrentPath);
HistoryIndex++;
RefreshCrumbs();
}
TSharedPtr<SWidget> SSlateFileOpenDlg::OnGetCrumbDelimiterContent(const FString& CrumbData) const
{
TSharedPtr<SWidget> Widget = SNullWidget::NullWidget;
TArray<FString> SubDirs;
IFileManager& FileManager = IFileManager::Get();
FSlateFileDialogDirVisitor DirVisitor(&SubDirs);
if (PLATFORM_WINDOWS)
{
if (CrumbData.Compare("SYSTEM") == 0)
{
// Windows doesn't have a root file system. So we need to provide a way to select system drives.
// This is done by creating a virtual root using 'System' as the top node.
int32 DrivesMask =
#if PLATFORM_WINDOWS
(int32)GetLogicalDrives()
#else
0
#endif // PLATFORM_WINDOWS
;
FMenuBuilder MenuBuilder(true, NULL);
const TCHAR *DriveLetters = TEXT("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
FString Drive = TEXT("A:");
for (int32 i = 0; i < 26; i++)
{
if (DrivesMask & 0x01)
{
Drive[0] = DriveLetters[i];
MenuBuilder.AddMenuEntry(
FText::FromString(Drive),
FText::GetEmpty(),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SSlateFileOpenDlg::OnPathMenuItemClicked, Drive + TEXT("/"))));
}
DrivesMask >>= 1;
}
return SNew(SVerticalBox)
+ SVerticalBox::Slot()
.MaxHeight(400.0f)
[
MenuBuilder.MakeWidget()
];
}
}
FileManager.IterateDirectory(*CrumbData, DirVisitor);
if (SubDirs.Num() > 0)
{
SubDirs.Sort();
FMenuBuilder MenuBuilder( true, NULL );
for (int32 i = 0; i < SubDirs.Num(); i++)
{
const FString& SubDir = SubDirs[i];
MenuBuilder.AddMenuEntry(
FText::FromString(SubDir),
FText::GetEmpty(),
FSlateIcon(),
FUIAction(FExecuteAction::CreateSP(this, &SSlateFileOpenDlg::OnPathMenuItemClicked, CrumbData + SubDir + TEXT("/"))));
}
Widget =
SNew( SVerticalBox )
+SVerticalBox::Slot()
.MaxHeight(400.0f)
[
MenuBuilder.MakeWidget()
];
}
return Widget;
}
FReply SSlateFileOpenDlg::OnQuickLinkClick(FSlateFileDlgWindow::EResult ButtonID)
{
if (ButtonID == FSlateFileDlgWindow::Project)
{
// Taken from DesktopPlatform. We have to do this to avoid a circular dependency.
const FString DefaultProjectSubFolder =TEXT("Unreal Projects");
CurrentPath = FString(FPlatformProcess::UserDir()) + DefaultProjectSubFolder + TEXT("/");
}
if (ButtonID == FSlateFileDlgWindow::Engine)
{
CurrentPath = FPaths::EngineDir();
}
if ((History.Num()-HistoryIndex-1) > 0)
{
History.RemoveAt(HistoryIndex+1, History.Num()-HistoryIndex-1, true);
}
History.Add(CurrentPath);
HistoryIndex++;
bNeedsBuilding = true;
bRebuildDirPath = true;
return FReply::Handled();
}
void SSlateFileOpenDlg::SetOutputFiles()
{
if (OutNames != nullptr)
{
TArray<FString> NamesArray;
ParseTextField(NamesArray, SaveFilename);
OutNames->Empty();
if (bDirectoriesOnly)
{
if (NamesArray.Num() > 0)
{
FString Path = CurrentPath + NamesArray[0];
OutNames->Add(Path);
}
else
{
// select the current directory
OutNames->Add(CurrentPath);
}
}
else
{
for (int32 i=0; i < NamesArray.Num(); i++)
{
FString Path = CurrentPath + NamesArray[i];
OutNames->Add(Path);
}
if (OutFilterIndex != nullptr)
{
*(OutFilterIndex) = FilterIndex;
}
}
}
}
FReply SSlateFileOpenDlg::OnAcceptCancelClick(FSlateFileDlgWindow::EResult ButtonID)
{
if (ButtonID == FSlateFileDlgWindow::Accept)
{
SetOutputFiles();
}
else
{
if (OutNames != nullptr)
{
OutNames->Empty();
}
}
UserResponse = ButtonID;
ParentWindow.Pin()->RequestDestroyWindow();
return FReply::Handled();
}
FReply SSlateFileOpenDlg::OnDirSublevelClick(int32 Level)
{
DirectoryNodesArray[DirNodeIndex].TextBlock->SetFont(StyleSet->GetFontStyle("SlateFileDialogs.Dialog"));
FString NewPath = TEXT("/");
for (int32 i = 1; i <= Level; i++)
{
NewPath += DirectoryNodesArray[i].Label + TEXT("/");
}
CurrentPath = NewPath;
bRebuildDirPath = false;
bNeedsBuilding = true;
DirNodeIndex = Level;
DirectoryNodesArray[DirNodeIndex].TextBlock->SetFont(StyleSet->GetFontStyle("SlateFileDialogs.DialogBold"));
return FReply::Handled();
}
void SSlateFileOpenDlg::Tick(const FGeometry &AllottedGeometry, const double InCurrentTime, const float InDeltaTime)
{
SCompoundWidget::Tick(AllottedGeometry, InCurrentTime, InDeltaTime);
if (DirectoryWatcher)
{
DirectoryWatcher->Tick(InDeltaTime);
}
if (bDirectoryHasChanged && !bNeedsBuilding)
{
ReadDir(true);
RebuildFileTable();
ListView->RequestListRefresh();
bDirectoryHasChanged = false;
}
if (bNeedsBuilding)
{
// quick-link buttons to directory sublevels
if (bRebuildDirPath)
{
BuildDirectoryPath();
}
// Get directory contents and rebuild list
ParseFilters();
ReadDir();
RebuildFileTable();
ListView->RequestListRefresh();
}
bNeedsBuilding = false;
bRebuildDirPath = false;
}
void SSlateFileOpenDlg::ReadDir(bool bIsRefresh)
{
if (DirectoryWatcher && RegisteredPath.Len() > 0 && !bIsRefresh)
{
DirectoryWatcher->UnregisterDirectoryChangedCallback_Handle(RegisteredPath, OnDialogDirectoryChangedDelegateHandle);
RegisteredPath = TEXT("");
}
IFileManager& FileManager = IFileManager::Get();
FilesArray.Empty();
FoldersArray.Empty();
TSharedPtr<FString> FilterList = nullptr;
if (FilterListArray.Num() > 0 && FilterIndex >= 0)
{
FilterList = FilterListArray[FilterIndex];
}
FSlateFileDialogVisitor DirVisitor(FilesArray, FoldersArray, FilterList);
FileManager.IterateDirectory(*CurrentPath, DirVisitor);
FilesArray.Sort(FFileEntry::ConstPredicate);
FoldersArray.Sort(FFileEntry::ConstPredicate);
if (DirectoryWatcher && !bIsRefresh)
{
DirectoryWatcher->RegisterDirectoryChangedCallback_Handle(CurrentPath,
IDirectoryWatcher::FDirectoryChanged::CreateRaw(this, &SSlateFileOpenDlg::OnDirectoryChanged),
OnDialogDirectoryChangedDelegateHandle, IDirectoryWatcher::WatchOptions::IncludeDirectoryChanges | IDirectoryWatcher::WatchOptions::IgnoreChangesInSubtree);
RegisteredPath = CurrentPath;
}
}
void SSlateFileOpenDlg::OnDirectoryChanged(const TArray <FFileChangeData> &FileChanges)
{
bDirectoryHasChanged = true;
}
void SSlateFileOpenDlg::RebuildFileTable()
{
LineItemArray.Empty();
// directory entries
for (int32 i = 0; i < FoldersArray.Num(); i++)
{
LineItemArray.Add(FoldersArray[i]);
}
// file entries
if (bDirectoriesOnly == false)
{
for (int32 i = 0; i < FilesArray.Num(); i++)
{
LineItemArray.Add(FilesArray[i]);
}
}
}
TSharedRef<ITableRow> SSlateFileOpenDlg::OnGenerateWidgetForList(TSharedPtr<FFileEntry> Item,
const TSharedRef<STableViewBase> &OwnerTable)
{
return SNew(SSlateFileDialogRow, OwnerTable)
.DialogItem(Item)
.StyleSet(StyleSet);
}
void SSlateFileOpenDlg::OnItemDoubleClicked(TSharedPtr<FFileEntry> Item)
{
if (Item->bIsDirectory)
{
SetDefaultFile(FString(""));
CurrentPath = CurrentPath + Item->Label + TEXT("/");
bNeedsBuilding = true;
bRebuildDirPath = true;
if ((History.Num()-HistoryIndex-1) > 0)
{
History.RemoveAt(HistoryIndex+1, History.Num()-HistoryIndex-1, true);
}
History.Add(CurrentPath);
HistoryIndex++;
}
else
{
SetOutputFiles();
UserResponse = FSlateFileDlgWindow::Accept;
ParentWindow.Pin()->RequestDestroyWindow();
}
}
void SSlateFileOpenDlg::OnFilterChanged(TSharedPtr<FString> NewValue, ESelectInfo::Type SelectInfo)
{
for (int32 i = 0; i < FilterNameArray.Num(); i++)
{
if (FilterNameArray[i].Get()->Compare(*NewValue.Get(), ESearchCase::CaseSensitive) == 0)
{
FilterIndex = i;
break;
}
}
bNeedsBuilding = true;
}
void SSlateFileOpenDlg::ParseTextField(TArray<FString> &FilenameArray, FString Files)
{
FString FileList = Files;
FileList.Trim();
FileList.TrimTrailing();
FilenameArray.Empty();
if (FileList.Len() > 0 && FileList[0] == TCHAR('"'))
{
FString TempName;
SaveFilename.Empty();
for (int32 i = 0; i < FileList.Len(); )
{
// find opening quote (")
for (; i < FileList.Len() && FileList[i] != TCHAR('"'); i++);
if (i >= FileList.Len())
{
break;
}
// copy name until closing quote is found.
TempName.Empty();
for (i++; i < FileList.Len() && FileList[i] != TCHAR('"'); i++)
{
TempName.AppendChar(FileList[i]);
}
if (i >= FileList.Len())
{
break;
}
// check to see if file exists or if we're trying to save a file. if so, add it to list.
if (FPaths::FileExists(CurrentPath + TempName) || bSaveFile)
{
FilenameArray.Add(TempName);
}
// if multiselect is off, don't bother parsing out any additional file names.
if (!bMultiSelectEnabled)
{
break;
}
i++;
}
}
else
{
FilenameArray.Add(Files);
}
}
void SSlateFileOpenDlg::SetDefaultFile(FString DefaultFile)
{
FString FileList = DefaultFile;
FileList.Trim();
FileList.TrimTrailing();
if (FileList.Len() > 0 && FileList[0] == TCHAR('"'))
{
TArray<FString> NamesArray;
ParseTextField(NamesArray, FileList);
SaveFilename.Empty();
for (int32 i = 0; i < NamesArray.Num(); i++)
{
SaveFilename = SaveFilename + TEXT("\"") + NamesArray[i] + TEXT("\" ");
// if multiselect is off, don't bother adding any additional file names.
if (!bMultiSelectEnabled)
{
break;
}
}
}
else
{
SaveFilename = FileList;
}
SaveFilenameEditBox->SetText(SaveFilename);
}
void SSlateFileOpenDlg::OnFileNameCommitted(const FText& InText, ETextCommit::Type InCommitType)
{
// update edit box unless user choose to escape out
if (InCommitType != ETextCommit::OnCleared)
{
FString Extension;
SaveFilename = InText.ToString();
// get current filter extension
if (!bDirectoriesOnly && GetFilterExtension(Extension))
{
// append extension to filename if user left it off
if (!SaveFilename.EndsWith(Extension, ESearchCase::CaseSensitive) && Extension.Compare(".*") != 0)
{
SaveFilename = SaveFilename + Extension;
}
}
ListView->ClearSelection();
SetDefaultFile(SaveFilename);
}
}
void SSlateFileOpenDlg::OnItemSelected(TSharedPtr<FFileEntry> Item, ESelectInfo::Type SelectInfo)
{
if (Item.IsValid())
{
FString FileList;
if (!bDirectoriesOnly)
{
TArray<TSharedPtr<FFileEntry>> SelectedItems = ListView->GetSelectedItems();
for (int32 i = 0; i < SelectedItems.Num(); i++)
{
if (SelectedItems[i]->bIsDirectory)
{
ListView->SetItemSelection(SelectedItems[i], false, ESelectInfo::Direct);
}
else
{
FileList = FileList + TEXT("\"") + SelectedItems[i]->Label + TEXT("\" ");
}
}
}
else
{
FileList = Item->Label;
}
if (bDirectoriesOnly == Item->bIsDirectory)
{
SetDefaultFile(FileList);
}
}
}
void SSlateFileOpenDlg::ParseFilters()
{
if (FilterCombo.IsValid() && FilterHBox.IsValid())
{
if (Filters.Len() > 0)
{
if (FilterNameArray.Num() == 0)
{
TCHAR Temp[MAX_FILTER_LENGTH];
FCString::Strcpy(Temp, Filters.Len(), *Filters);
// break path into tokens
TCHAR *ContextStr = nullptr;
TCHAR *FilterDescription = FCString::Strtok(Temp, TEXT("|"), &ContextStr);
TCHAR *FilterList;
while (FilterDescription)
{
// filter wild cards
FilterList = FCString::Strtok(nullptr, TEXT("|"), &ContextStr);
FilterNameArray.Add(MakeShareable(new FString(FilterDescription)));
FilterListArray.Add(MakeShareable(new FString(FilterList)));
// next filter entry
FilterDescription = FCString::Strtok(nullptr, TEXT("|"), &ContextStr);
}
}
FilterCombo->SetSelectedItem(FilterNameArray[FilterIndex]);
}
else
{
FilterNameArray.Empty();
FilterHBox->SetVisibility(EVisibility::Hidden);
}
}
}
bool SSlateFileOpenDlg::GetFilterExtension(FString &OutString)
{
// check to see if filters were given
if (Filters.Len() == 0)
{
OutString = "";
return false;
}
// make a copy of filter string that we can modify
TCHAR Temp[MAX_FILTER_LENGTH];
FCString::Strcpy(Temp, FilterNameArray[FilterIndex]->Len(), *(*FilterNameArray[FilterIndex].Get()));
// find start of extension
TCHAR *FilterExt = FCString::Strchr(Temp, '.');
// strip any trailing junk
int32 i;
for (i = 0; i < FCString::Strlen(FilterExt); i++)
{
if (FilterExt[i] == ' ' || FilterExt[i] == ')' || FilterExt[i] == ';')
{
FilterExt[i] = 0;
break;
}
}
// store result and clean up
OutString = FString(FilterExt);
return (i > 0);
}
void SSlateFileOpenDlg::OnNewDirectoryCommitted(const FText & InText, ETextCommit::Type InCommitType)
{
if (InCommitType == ETextCommit::OnEnter)
{
OnNewDirectoryAcceptCancelClick(FSlateFileDlgWindow::Accept);
}
else
{
OnNewDirectoryAcceptCancelClick(FSlateFileDlgWindow::Cancel);
}
}
FReply SSlateFileOpenDlg::OnNewDirectoryClick()
{
NewDirectorySizeBox->SetVisibility(EVisibility::Visible);
NewDirCancelButton->SetVisibility(EVisibility::Visible);
NewDirectoryEditBox->SetText(FString(""));
FSlateApplication::Get().SetKeyboardFocus(NewDirectoryEditBox);
NewDirectoryEditBox->EnterEditingMode();
DirErrorMsg->SetVisibility(EVisibility::Collapsed);
return FReply::Handled().SetUserFocus(NewDirectoryEditBox.ToSharedRef(), EFocusCause::SetDirectly);
}
bool SSlateFileOpenDlg::OnNewDirectoryTextChanged(const FText &InText, FText &ErrorMsg)
{
NewDirectoryName = InText.ToString();
return true;
}
FReply SSlateFileOpenDlg::OnNewDirectoryAcceptCancelClick(FSlateFileDlgWindow::EResult ButtonID)
{
if (ButtonID == FSlateFileDlgWindow::Accept)
{
NewDirectoryName.Trim();
NewDirectoryName.TrimTrailing();
if (NewDirectoryName.Len() > 0)
{
IPlatformFile &PlatformFile = FPlatformFileManager::Get().GetPlatformFile();
FString DirPath = CurrentPath + NewDirectoryName;
if (!PlatformFile.CreateDirectory(*DirPath))
{
DirErrorMsg->SetVisibility(EVisibility::Visible);
return FReply::Handled();
}
bDirectoryHasChanged = true;
}
}
NewDirectorySizeBox->SetVisibility(EVisibility::Hidden);
NewDirCancelButton->SetVisibility(EVisibility::Hidden);
DirErrorMsg->SetVisibility(EVisibility::Collapsed);
NewDirectoryEditBox->SetText(FString(""));
return FReply::Handled();
}
FReply SSlateFileOpenDlg::OnGoForwardClick()
{
if ((HistoryIndex+1) < History.Num())
{
SetDefaultFile(FString(""));
HistoryIndex++;
CurrentPath = History[HistoryIndex];
bNeedsBuilding = true;
bRebuildDirPath = true;
bDirectoryHasChanged = false;
}
return FReply::Handled();
}
FReply SSlateFileOpenDlg::OnGoBackClick()
{
if (HistoryIndex > 0)
{
SetDefaultFile(FString(""));
HistoryIndex--;
CurrentPath = History[HistoryIndex];
bNeedsBuilding = true;
bRebuildDirPath = true;
bDirectoryHasChanged = false;
}
return FReply::Handled();
}
#undef LOCTEXT_NAMESPACE