// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #include "CoreMinimal.h" #include "SlateFwd.h" #include "Misc/Paths.h" #include "Layout/Visibility.h" #include "Layout/Margin.h" #include "Widgets/SNullWidget.h" #include "Fonts/SlateFontInfo.h" #include "Input/Reply.h" #include "Widgets/DeclarativeSyntaxSupport.h" #include "Widgets/SWidget.h" #include "Widgets/SCompoundWidget.h" #include "Widgets/SBoxPanel.h" #include "SlateOptMacros.h" #include "Widgets/Input/SComboBox.h" #include "Widgets/Images/SImage.h" #include "Widgets/Text/STextBlock.h" #include "Widgets/Views/STableViewBase.h" #include "Widgets/Views/STableRow.h" #include "Widgets/Views/SListView.h" #include "SlateFileDialogsStyles.h" #include "IDirectoryWatcher.h" #define LOCTEXT_NAMESPACE "SlateFileDialogsNamespace" class SButton; class SSlateFileOpenDlg; class SWindow; //----------------------------------------------------------------------------- struct FFileEntry { FString Label; FString ModDate; FString FileSize; bool bIsSelected; bool bIsDirectory; FFileEntry() { } FFileEntry(FString InLabel, FString InModDate, FString InFileSize, bool InIsDirectory) : Label(MoveTemp(InLabel)) , ModDate(MoveTemp(InModDate)) , FileSize(MoveTemp(InFileSize)) , bIsSelected(false) , bIsDirectory(InIsDirectory) { } inline static bool ConstPredicate ( const TSharedPtr Entry1, const TSharedPtr Entry2) { return (Entry1->Label.Compare( Entry2->Label ) < 0); } }; typedef TSharedPtr SSlateFileDialogItemPtr; //----------------------------------------------------------------------------- class FSlateFileDlgWindow { public: enum EResult { Cancel = 0, Accept = 1, Engine = 2, Project = 3 }; FSlateFileDlgWindow(FSlateFileDialogsStyle *InStyleSet); bool OpenFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex, int32 DefaultFilterIndex = 0); bool OpenFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames); bool OpenDirectoryDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, FString& OutFoldername); bool SaveFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames, int32& OutFilterIndex, int32 DefaultFilterIndex = 0); bool SaveFileDialog(const void* ParentWindowHandle, const FString& DialogTitle, const FString& DefaultPath, const FString& DefaultFile, const FString& FileTypes, uint32 Flags, TArray& OutFilenames); private: TSharedPtr DialogWidget; FString CurrentDirectory; FSlateFileDialogsStyle* StyleSet; void TrimFilenameFromPath(FString &Path); }; //----------------------------------------------------------------------------- class SSlateFileOpenDlg : public SCompoundWidget { public: struct FDirNode { FString Label; TSharedPtr TextBlock; TSharedPtr Button; FDirNode() { } FDirNode(FString InLabel, TSharedPtr InTextBlock) { Label = InLabel; TextBlock = InTextBlock; } }; SLATE_BEGIN_ARGS(SSlateFileOpenDlg) : _CurrentPath(TEXT("")), _Filters(TEXT("")), _bMultiSelectEnabled(false), _WindowTitleText(TEXT("")), _AcceptText(LOCTEXT("SlateDialogOpen","Open")), _bDirectoriesOnly(false), _bSaveFile(false), _OutNames(nullptr), _OutFilterIndex(nullptr), _ParentWindow(nullptr), _StyleSet(nullptr) {} SLATE_ARGUMENT(FString, CurrentPath) SLATE_ARGUMENT(FString, Filters) SLATE_ARGUMENT(bool, bMultiSelectEnabled) SLATE_ARGUMENT(FString, WindowTitleText) SLATE_ARGUMENT(FText, AcceptText) SLATE_ARGUMENT(bool, bDirectoriesOnly) SLATE_ARGUMENT(bool, bSaveFile) SLATE_ARGUMENT(TArray*, OutNames) SLATE_ARGUMENT(int32*, OutFilterIndex) SLATE_ARGUMENT(TWeakPtr, ParentWindow) SLATE_ARGUMENT(FSlateFileDialogsStyle*, StyleSet) SLATE_END_ARGS() ~SSlateFileOpenDlg(); void Construct(const FArguments& InArgs); FSlateFileDlgWindow::EResult GetResponse() { return UserResponse; } void SetOutNames(TArray* Ptr) { OutNames = Ptr; } void SetOutFilterIndex(int32* InOutFilterIndex) { OutFilterIndex = InOutFilterIndex; } void SetDefaultFilterIndex(int32 DefaultFilterIndex) { FilterIndex = DefaultFilterIndex; } void SetDefaultFile(FString DefaultFile); private: void OnPathClicked( const FString& CrumbData ); TSharedRef OnGetCrumbDelimiterContent(const FString& CrumbData) const; void RebuildFileTable(); void BuildDirectoryPath(); void ReadDir(bool bIsRefresh = false); void RefreshCrumbs(); void OnPathMenuItemClicked( FString ClickedPath ); void OnItemSelected(TSharedPtr Item, ESelectInfo::Type SelectInfo); void ParseTextField(TArray &FilenameArray, FString Files); void Tick(const FGeometry &AllottedGeometry, const double InCurrentTime, const float InDeltaTime); TSharedRef OnGenerateWidgetForList(TSharedPtr Item, const TSharedRef &OwnerTable); void OnItemDoubleClicked(TSharedPtr Item); void OnFilterChanged(TSharedPtr NewValue, ESelectInfo::Type SelectInfo); bool IsAcceptEnabled() const; FReply OnAcceptCancelClick(FSlateFileDlgWindow::EResult ButtonID); FReply OnQuickLinkClick(FSlateFileDlgWindow::EResult ButtonID); FReply OnDirSublevelClick(int32 Level); void OnDirectoryChanged(const TArray &FileChanges); void OnFileNameCommitted(const FText& InText, ETextCommit::Type InCommitType); void OnNewDirectoryCommitted(const FText& InText, ETextCommit::Type InCommitType); FReply OnNewDirectoryClick(); bool OnNewDirectoryTextChanged(const FText &InText, FText &ErrorMsg); FReply OnNewDirectoryAcceptCancelClick(FSlateFileDlgWindow::EResult ButtonID); FReply OnGoForwardClick(); FReply OnGoBackClick(); /** Collects the output files. */ void SetOutputFiles(); bool GetFilterExtensions(TArray< FString >& OutExtensions); void ParseFilters(); /** @return true if the extension filter contains a wildcard or not */ bool IsWildcardExtension(const FString& Extension); /** @return ptr to directory if only one directory and zero files are selected, else nullptr */ TSharedPtr GetSoloDirectorySelected() const; TArray< FDirNode > DirectoryNodesArray; TArray> FoldersArray; TArray> FilesArray; TArray> LineItemArray; TSharedPtr>> FilterCombo; TSharedPtr FilterComboBoxTitleBlock; TSharedPtr FilterHBox; TSharedPtr SaveFilenameEditBox; TSharedPtr NewDirectoryEditBox; TSharedPtr SaveFilenameSizeBox; TSharedPtr WindowTitle; TSharedPtr>> ListView; TSharedPtr> PathBreadcrumbTrail; TSharedPtr NewDirCancelButton; TSharedPtr NewDirectorySizeBox; TSharedPtr DirErrorMsg; TArray> FilterNameArray; TArray FilterListArray; int32 FilterIndex; FSlateFileDlgWindow::EResult UserResponse; bool bNeedsBuilding; bool bRebuildDirPath; bool bDirectoryHasChanged; int32 DirNodeIndex; FString SaveFilename; TWeakPtr ParentWindow; FString CurrentPath; FString Filters; FString WindowTitleText; bool bMultiSelectEnabled; TArray* OutNames; int32* OutFilterIndex; bool bDirectoriesOnly; bool bSaveFile; FText AcceptText; FSlateFileDialogsStyle* StyleSet; IDirectoryWatcher *DirectoryWatcher; FDelegateHandle OnDialogDirectoryChangedDelegateHandle; FString RegisteredPath; FString NewDirectoryName; TArray History; int32 HistoryIndex; }; //----------------------------------------------------------------------------- class SSlateFileDialogRow : public SMultiColumnTableRow { public: SLATE_BEGIN_ARGS(SSlateFileDialogRow) { } SLATE_ARGUMENT(SSlateFileDialogItemPtr, DialogItem) SLATE_ARGUMENT(FSlateFileDialogsStyle *, StyleSet) SLATE_END_ARGS() void Construct(const FArguments& InArgs, const TSharedRef &InOwnerTableView) { check(InArgs._DialogItem.IsValid()); DialogItem = InArgs._DialogItem; StyleSet = InArgs._StyleSet; SMultiColumnTableRow::Construct(FSuperRowType::FArguments(), InOwnerTableView); } BEGIN_SLATE_FUNCTION_BUILD_OPTIMIZATION virtual TSharedRef GenerateWidgetForColumn( const FName& ColumnName ) override { FSlateFontInfo ItemFont = StyleSet->GetFontStyle("SlateFileDialogs.Dialog"); struct EVisibility FolderIconVisibility = EVisibility::Visible; const FSlateBrush *Icon; if (DialogItem->bIsDirectory) { Icon = StyleSet->GetBrush("SlateFileDialogs.Folder16"); } else { FString Extension = FPaths::GetExtension(DialogItem->Label, false); if (Extension.Equals(TEXT("uasset"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.UAsset16"); } else if (Extension.Equals(TEXT("uproject"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.UProject16"); } else if (Extension.Equals(TEXT("fbx"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.Model3D"); } else if (Extension.Equals(TEXT("cpp"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("h"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("txt"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("log"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.TextFile"); } else if (Extension.Equals(TEXT("wav"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("mp3"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("ogg"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.Audio"); } else if (Extension.Equals(TEXT("mp4"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("webm"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.Video"); } else if (Extension.Equals(TEXT("png"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("jpg"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("tga"), ESearchCase::IgnoreCase) || Extension.Equals(TEXT("bmp"), ESearchCase::IgnoreCase)) { Icon = StyleSet->GetBrush("SlateFileDialogs.Image"); } else { Icon = StyleSet->GetBrush("SlateFileDialogs.PlaceHolder"); FolderIconVisibility = EVisibility::Hidden; } } if (ColumnName == TEXT("Pathname")) { return SNew(SHorizontalBox) + SHorizontalBox::Slot() .HAlign(HAlign_Left) .VAlign(VAlign_Top) .AutoWidth() .Padding(FMargin(5.0f, 2.0f)) [ SNew(SImage) .Image(Icon) .Visibility(FolderIconVisibility) ] + SHorizontalBox::Slot() .HAlign(HAlign_Left) .VAlign(VAlign_Top) .AutoWidth() .Padding(FMargin(5.0f, 0.0f, 0.0f, 0.0f)) [ SNew(STextBlock) .Text(FText::FromString(DialogItem->Label)) .Font(ItemFont) ]; } else if (ColumnName == TEXT("ModDate")) { return SNew(STextBlock) .Text(FText::FromString(DialogItem->ModDate)) .Font(ItemFont); } else if (ColumnName == TEXT("FileSize")) { return SNew(STextBlock) .Text(FText::FromString(DialogItem->FileSize)) .Font(ItemFont); } else { return SNullWidget::NullWidget; } } END_SLATE_FUNCTION_BUILD_OPTIMIZATION private: SSlateFileDialogItemPtr DialogItem; FSlateFileDialogsStyle* StyleSet; }; #undef LOCTEXT_NAMESPACE