Skip to content

Commit 108a86b

Browse files
committed
[ADD] : add feature #156 for modify the file infos during scan. add a new callback to use in the FileDialogConfig
1 parent ab335ef commit 108a86b

2 files changed

Lines changed: 112 additions & 32 deletions

File tree

ImGuiFileDialog.cpp

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ class FileSystemDirent : public IGFD::IFileSystem {
692692
#ifdef _IGFD_WIN_
693693
auto filePath = vPath + ent->d_name;
694694
#else
695-
auto filePath = vPath + std::string(1u, PATH_SEP) + ent->d_name;
695+
auto filePath = vPath + IGFD::Utils::GetPathSeparator() + ent->d_name;
696696
#endif
697697
if (!stat(filePath.c_str(), &sb)) {
698698
if (sb.st_mode & S_IFLNK) {
@@ -905,6 +905,10 @@ size_t IGFD::Utils::GetLastCharPosWithMinCharCount(const std::string& vString, c
905905
return std::string::npos;
906906
}
907907

908+
std::string IGFD::Utils::GetPathSeparator() {
909+
return std::string(1U, PATH_SEP);
910+
}
911+
908912
#pragma endregion
909913

910914
#pragma region FileStyle
@@ -1533,7 +1537,6 @@ bool IGFD::FileType::operator>(const FileType& rhs) const {
15331537
bool IGFD::FileInfos::SearchForTag(const std::string& vTag) const {
15341538
if (!vTag.empty()) {
15351539
if (fileNameExt_optimized == "..") return true;
1536-
15371540
return fileNameExt_optimized.find(vTag) != std::string::npos || // first try without case and accents
15381541
fileNameExt.find(vTag) != std::string::npos; // second if searched with case and accents
15391542
}
@@ -1586,6 +1589,8 @@ bool IGFD::FileInfos::FinalizeFileTypeParsing(const size_t& vMaxDotToExtract) {
15861589
}
15871590
if (lpt != std::string::npos) {
15881591
size_t lvl = 0U;
1592+
fileNameLevels[lvl] = fileNameExt.substr(0, lpt);
1593+
fileNameLevels[lvl] = Utils::LowerCaseString(fileNameLevels[lvl]);
15891594
fileExtLevels[lvl] = fileNameExt.substr(lpt);
15901595
fileExtLevels_optimized[lvl] = Utils::LowerCaseString(fileExtLevels[lvl]);
15911596
if (countExtDot > 1U) { // multi layer ext
@@ -1595,6 +1600,8 @@ bool IGFD::FileInfos::FinalizeFileTypeParsing(const size_t& vMaxDotToExtract) {
15951600
if (fileNameExt.size() > lpt) {
15961601
lpt = fileNameExt.find_first_of('.', lpt);
15971602
if (lpt != std::string::npos) {
1603+
fileNameLevels[lvl] = fileNameExt.substr(0, lpt);
1604+
fileNameLevels[lvl] = Utils::LowerCaseString(fileNameLevels[lvl]);
15981605
fileExtLevels[lvl] = fileNameExt.substr(lpt);
15991606
fileExtLevels_optimized[lvl] = Utils::LowerCaseString(fileExtLevels[lvl]);
16001607
}
@@ -1612,7 +1619,7 @@ bool IGFD::FileInfos::FinalizeFileTypeParsing(const size_t& vMaxDotToExtract) {
16121619
#pragma region FileManager
16131620

16141621
IGFD::FileManager::FileManager() {
1615-
fsRoot = std::string(1u, PATH_SEP);
1622+
fsRoot = IGFD::Utils::GetPathSeparator();
16161623
m_FileSystemName = typeid(FILE_SYSTEM_OVERRIDE).name();
16171624
// std::make_unique is not available un cpp11
16181625
m_FileSystemPtr = std::unique_ptr<FILE_SYSTEM_OVERRIDE>(new FILE_SYSTEM_OVERRIDE());
@@ -1793,6 +1800,19 @@ void IGFD::FileManager::m_SortFields(const FileDialogInternal& vFileDialogIntern
17931800
m_ApplyFilteringOnFileList(vFileDialogInternal, vFileInfosList, vFileInfosFilteredList);
17941801
}
17951802

1803+
bool IGFD::FileManager::m_CompleteFileInfosWithUserFileAttirbutes(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr<FileInfos>& vInfos) {
1804+
if (vFileDialogInternal.getDialogConfig().userFileAttributes != nullptr) {
1805+
if (!vFileDialogInternal.getDialogConfig().userFileAttributes(vInfos.get(), vFileDialogInternal.getDialogConfig().userDatas)) {
1806+
return false; // the file will be ignored, so not added to the file list, so not displayed
1807+
} else {
1808+
if (!vInfos->fileType.isDir()) {
1809+
vInfos->formatedFileSize = m_FormatFileSize(vInfos->fileSize);
1810+
}
1811+
}
1812+
}
1813+
return true; // file will be added to file list, so displayed
1814+
}
1815+
17961816
void IGFD::FileManager::ClearFileLists() {
17971817
m_FilteredFileList.clear();
17981818
m_FileList.clear();
@@ -1830,7 +1850,10 @@ void IGFD::FileManager::m_AddFile(const FileDialogInternal& vFileDialogInternal,
18301850
vFileDialogInternal.filterManager.m_FillFileStyle(infos);
18311851

18321852
m_CompleteFileInfos(infos);
1833-
m_FileList.push_back(infos);
1853+
1854+
if (m_CompleteFileInfosWithUserFileAttirbutes(vFileDialogInternal, infos)) {
1855+
m_FileList.push_back(infos);
1856+
}
18341857
}
18351858

18361859
void IGFD::FileManager::m_AddPath(const FileDialogInternal& vFileDialogInternal, const std::string& vPath, const std::string& vFileName, const FileType& vFileType) {
@@ -1856,7 +1879,10 @@ void IGFD::FileManager::m_AddPath(const FileDialogInternal& vFileDialogInternal,
18561879
vFileDialogInternal.filterManager.m_FillFileStyle(infos);
18571880

18581881
m_CompleteFileInfos(infos);
1859-
m_PathList.push_back(infos);
1882+
1883+
if (m_CompleteFileInfosWithUserFileAttirbutes(vFileDialogInternal, infos)) {
1884+
m_PathList.push_back(infos);
1885+
}
18601886
}
18611887

18621888
void IGFD::FileManager::ScanDir(const FileDialogInternal& vFileDialogInternal, const std::string& vPath) {
@@ -1868,7 +1894,7 @@ void IGFD::FileManager::ScanDir(const FileDialogInternal& vFileDialogInternal, c
18681894

18691895
if (!m_CurrentPathDecomposition.empty()) {
18701896
#ifdef _IGFD_WIN_
1871-
if (path == fsRoot) path += std::string(1u, PATH_SEP);
1897+
if (path == fsRoot) path += IGFD::Utils::GetPathSeparator();
18721898
#endif // _IGFD_WIN_
18731899

18741900
ClearFileLists();
@@ -1887,7 +1913,7 @@ void IGFD::FileManager::m_ScanDirForPathSelection(const FileDialogInternal& vFil
18871913

18881914
if (!path.empty()) {
18891915
#ifdef _IGFD_WIN_
1890-
if (path == fsRoot) path += std::string(1u, PATH_SEP);
1916+
if (path == fsRoot) path += IGFD::Utils::GetPathSeparator();
18911917
#endif // _IGFD_WIN_
18921918

18931919
ClearPathLists();
@@ -2069,7 +2095,9 @@ void IGFD::FileManager::m_CompleteFileInfos(const std::shared_ptr<FileInfos>& vI
20692095
std::string fpn;
20702096

20712097
// FIXME: so the condition is always true?
2072-
if (vInfos->fileType.isFile() || vInfos->fileType.isLinkToUnknown() || vInfos->fileType.isDir()) fpn = vInfos->filePath + std::string(1u, PATH_SEP) + vInfos->fileNameExt;
2098+
if (vInfos->fileType.isFile() || vInfos->fileType.isLinkToUnknown() || vInfos->fileType.isDir()) {
2099+
fpn = vInfos->filePath + IGFD::Utils::GetPathSeparator() + vInfos->fileNameExt;
2100+
}
20732101

20742102
struct stat statInfos = {};
20752103
char timebuf[100];
@@ -2121,7 +2149,7 @@ void IGFD::FileManager::m_m_AddFileNameInSelection(const std::string& vFileName,
21212149
void IGFD::FileManager::SetCurrentDir(const std::string& vPath) {
21222150
std::string path = vPath;
21232151
#ifdef _IGFD_WIN_
2124-
if (fsRoot == path) path += std::string(1u, PATH_SEP);
2152+
if (fsRoot == path) path += IGFD::Utils::GetPathSeparator();
21252153
#endif // _IGFD_WIN_
21262154

21272155
bool dir_opened = m_FileSystemPtr->IsDirectory(path);
@@ -2153,7 +2181,7 @@ void IGFD::FileManager::SetCurrentDir(const std::string& vPath) {
21532181
IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
21542182
m_CurrentPathDecomposition = IGFD::Utils::SplitStringToVector(m_CurrentPath, PATH_SEP, false);
21552183
#ifdef _IGFD_UNIX_ // _IGFD_UNIX_ is _IGFD_WIN_ or APPLE
2156-
m_CurrentPathDecomposition.insert(m_CurrentPathDecomposition.begin(), std::string(1u, PATH_SEP));
2184+
m_CurrentPathDecomposition.insert(m_CurrentPathDecomposition.begin(), IGFD::Utils::GetPathSeparator());
21572185
#endif // _IGFD_UNIX_
21582186
if (!m_CurrentPathDecomposition.empty()) {
21592187
#ifdef _IGFD_WIN_
@@ -2166,7 +2194,7 @@ void IGFD::FileManager::SetCurrentDir(const std::string& vPath) {
21662194

21672195
bool IGFD::FileManager::CreateDir(const std::string& vPath) {
21682196
if (!vPath.empty()) {
2169-
std::string path = m_CurrentPath + std::string(1u, PATH_SEP) + vPath;
2197+
std::string path = m_CurrentPath + IGFD::Utils::GetPathSeparator() + vPath;
21702198
return m_FileSystemPtr->CreateDirectoryIfNotExist(path);
21712199
}
21722200
return false;
@@ -2178,7 +2206,7 @@ std::string IGFD::FileManager::ComposeNewPath(std::vector<std::string>::iterator
21782206
while (true) {
21792207
if (!res.empty()) {
21802208
#ifdef _IGFD_WIN_
2181-
res = *vIter + std::string(1u, PATH_SEP) + res;
2209+
res = *vIter + IGFD::Utils::GetPathSeparator() + res;
21822210
#elif defined(_IGFD_UNIX_) // _IGFD_UNIX_ is _IGFD_WIN_ or APPLE
21832211
if (*vIter == fsRoot)
21842212
res = *vIter + res;
@@ -2239,14 +2267,14 @@ bool IGFD::FileManager::SelectDirectory(const std::shared_ptr<FileInfos>& vInfos
22392267
std::string newPath;
22402268

22412269
if (showDrives) {
2242-
newPath = vInfos->fileNameExt + std::string(1u, PATH_SEP);
2270+
newPath = vInfos->fileNameExt + IGFD::Utils::GetPathSeparator();
22432271
} else {
22442272
#ifdef __linux__
22452273
if (fsRoot == m_CurrentPath)
22462274
newPath = m_CurrentPath + vInfos->fileNameExt;
22472275
else
22482276
#endif // __linux__
2249-
newPath = m_CurrentPath + std::string(1u, PATH_SEP) + vInfos->fileNameExt;
2277+
newPath = m_CurrentPath + IGFD::Utils::GetPathSeparator() + vInfos->fileNameExt;
22502278
}
22512279

22522280
if (m_FileSystemPtr->IsDirectoryCanBeOpened(newPath)) {
@@ -2365,7 +2393,7 @@ void IGFD::FileManager::DrawDirectoryCreation(const FileDialogInternal& vFileDia
23652393
if (IMGUI_BUTTON(okButtonString)) {
23662394
std::string newDir = std::string(directoryNameBuffer);
23672395
if (CreateDir(newDir)) {
2368-
SetCurrentPath(m_CurrentPath + std::string(1u, PATH_SEP) + newDir);
2396+
SetCurrentPath(m_CurrentPath + IGFD::Utils::GetPathSeparator() + newDir);
23692397
OpenCurrentPath(vFileDialogInternal);
23702398
}
23712399

@@ -2488,7 +2516,7 @@ std::string IGFD::FileManager::GetResultingPath() {
24882516
std::string selectedDirectory = fileNameBuffer;
24892517
std::string path = m_CurrentPath;
24902518
if (!selectedDirectory.empty() && selectedDirectory != ".") {
2491-
path += std::string(1u, PATH_SEP) + selectedDirectory;
2519+
path += IGFD::Utils::GetPathSeparator() + selectedDirectory;
24922520
}
24932521
return path;
24942522
}
@@ -2512,7 +2540,7 @@ std::string IGFD::FileManager::GetResultingFilePathName(FileDialogInternal& vFil
25122540
if (fsRoot != result)
25132541
#endif // _IGFD_UNIX_
25142542
{
2515-
result += std::string(1u, PATH_SEP);
2543+
result += IGFD::Utils::GetPathSeparator();
25162544
}
25172545
result += filename;
25182546
}
@@ -2530,7 +2558,7 @@ std::map<std::string, std::string> IGFD::FileManager::GetResultingSelection(File
25302558
if (fsRoot != result)
25312559
#endif // _IGFD_UNIX_
25322560
{
2533-
result += std::string(1u, PATH_SEP);
2561+
result += IGFD::Utils::GetPathSeparator();
25342562
}
25352563
result += vFileDialogInternal.filterManager.ReplaceExtentionWithCurrentFilterIfNeeded(selectedFileName, vFlag);
25362564
res[selectedFileName] = result;
@@ -2726,7 +2754,7 @@ void IGFD::ThumbnailFeature::m_ThreadThumbnailFileDatasExtractionFunc() {
27262754
{
27272755
//|| file->fileExtLevels == ".hdr" => format float so in few times
27282756
if (file->SearchForExts(".png,.bmp,.tga,.jpg,.jpeg,.gif,.psd,.pic,.ppm,.pgm", true)) {
2729-
auto fpn = file->filePath + std::string(1u, PATH_SEP) + file->fileNameExt;
2757+
auto fpn = file->filePath + IGFD::Utils::GetPathSeparator() + file->fileNameExt;
27302758

27312759
int w = 0;
27322760
int h = 0;

ImGuiFileDialog.h

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1030,6 +1030,50 @@ by ex for android, emscripten, or boost
10301030
10311031
you can check the DemoApp who is using an override for the Boost::filesystem
10321032
1033+
################################################################
1034+
## Modify file infos during scan by a callback
1035+
################################################################
1036+
1037+
in some case, it can be unsefull for modify file infos
1038+
so you can define your callback and attached it in the FileDialogConfig struct in the field userFileAttributes
1039+
1040+
the callback stamp is :
1041+
```cpp
1042+
bool (IGFD::FileInfos* vFileInfosPtr, IGFD::UserDatas vUserDatas)
1043+
```
1044+
if the callback is returning false, the file is ignored, so not displayed by the dailog
1045+
1046+
example in the gltf separated files : (see the branch DemoApp for example use)
1047+
1048+
A gltf file can have data description and datas files separated.
1049+
in this case only the file with description will be shown in the dialog, so with not the full size of all attached datas
1050+
1051+
With the file format .gltf who is containing datas in a separate .bin
1052+
1053+
syntax :
1054+
```cpp
1055+
config.userFileAttributes = [](IGFD::FileInfos* vFileInfosPtr, IGFD::UserDatas vUserDatas) -> bool {
1056+
if (vFileInfosPtr != nullptr) {
1057+
// this demo not take into account .gltf who have data insise. besauce keepd easy just for demo
1058+
if (vFileInfosPtr->SearchForExt(".gltf", true)) {
1059+
auto bin_file_path_name = vFileInfosPtr->filePath + IGFD::Utils::GetPathSeparator() + vFileInfosPtr->fileNameLevels[0] + ".bin";
1060+
struct stat statInfos = {};
1061+
char timebuf[100];
1062+
int result = stat(bin_file_path_name.c_str(), &statInfos);
1063+
if (!result) {
1064+
vFileInfosPtr->fileSize = (size_t)statInfos.st_size;
1065+
} else {
1066+
// no bin, so escaped.
1067+
// normally we must parse the file and check the uri for get the buffer file
1068+
// but here we keep the example as easy for demo.
1069+
return false;
1070+
}
1071+
}
1072+
}
1073+
return true;
1074+
};
1075+
```
1076+
10331077
################################################################
10341078
## How to Integrate ImGuiFileDialog in your project
10351079
################################################################
@@ -1456,6 +1500,7 @@ class IGFD_API Utils {
14561500
static std::string LowerCaseString(const std::string& vString); // turn all text in lower case for search facilitie
14571501
static size_t GetCharCountInString(const std::string& vString, const char& vChar);
14581502
static size_t GetLastCharPosWithMinCharCount(const std::string& vString, const char& vChar, const size_t& vMinCharCount);
1503+
static std::string GetPathSeparator(); // return the slash for any OS ( \\ win, / unix)
14591504
};
14601505

14611506
#pragma endregion
@@ -1621,10 +1666,14 @@ class IGFD_API FileInfos {
16211666
// 10 level max are sufficient i guess. the others levels will be checked if countExtDot > 1
16221667
std::array<std::string, EXT_MAX_LEVEL> fileExtLevels;
16231668
std::array<std::string, EXT_MAX_LEVEL> fileExtLevels_optimized; // optimized for search => insensitivecase
1669+
// same for file name, can be sued in userFileAttributesFun
1670+
std::array<std::string, EXT_MAX_LEVEL> fileNameLevels;
1671+
std::array<std::string, EXT_MAX_LEVEL> fileNameLevels_optimized; // optimized for search => insensitivecase
16241672
size_t countExtDot = 0U; // count dots in file extention. this count will give the levels in fileExtLevels
16251673
FileType fileType; // fileType
16261674
std::string filePath; // path of the file
1627-
std::string fileNameExt; // filename of the file (file name + extention) (but no pat
1675+
std::string fileName; // file name only
1676+
std::string fileNameExt; // filename of the file (file name + extention) (but no path)
16281677
std::string fileNameExt_optimized; // optimized for search => insensitivecase
16291678
size_t fileSize = 0U; // for sorting operations
16301679
std::string formatedFileSize; // file size formated (10 o, 10 ko, 10 mo, 10 go)
@@ -1740,7 +1789,7 @@ class IGFD_API FileManager {
17401789
#endif
17411790
static std::string m_RoundNumber(double vvalue, int n); // custom rounding number
17421791
static std::string m_FormatFileSize(size_t vByteSize); // format file size field
1743-
static void m_CompleteFileInfos(const std::shared_ptr<FileInfos>& FileInfos); // set time and date infos of a file (detail view mode)
1792+
static void m_CompleteFileInfos(const std::shared_ptr<FileInfos>& vInfos); // set time and date infos of a file (detail view mode)
17441793
void m_RemoveFileNameInSelection(const std::string& vFileName); // selection : remove a file name
17451794
void m_m_AddFileNameInSelection(const std::string& vFileName, bool vSetLastSelectionFileName); // selection : add a file name
17461795
void m_AddFile(const FileDialogInternal& vFileDialogInternal,
@@ -1762,6 +1811,7 @@ class IGFD_API FileManager {
17621811
void m_SortFields(const FileDialogInternal& vFileDialogInternal,
17631812
std::vector<std::shared_ptr<FileInfos>>& vFileInfosList,
17641813
std::vector<std::shared_ptr<FileInfos>>& vFileInfosFilteredList); // will sort a column
1814+
bool m_CompleteFileInfosWithUserFileAttirbutes(const FileDialogInternal& vFileDialogInternal, const std::shared_ptr<FileInfos>& vInfos);
17651815

17661816
public:
17671817
FileManager();
@@ -1824,6 +1874,7 @@ class IGFD_API FileManager {
18241874

18251875
typedef void* UserDatas;
18261876
typedef std::function<void(const char*, UserDatas, bool*)> PaneFun; // side pane function binding
1877+
typedef std::function<bool(FileInfos*, UserDatas)> UserFileAttributesFun; // custom file Attributes call back, reject file if false
18271878

18281879
struct IGFD_API FileDialogConfig {
18291880
std::string path; // path
@@ -1834,6 +1885,7 @@ struct IGFD_API FileDialogConfig {
18341885
ImGuiFileDialogFlags flags = ImGuiFileDialogFlags_None; // ImGuiFileDialogFlags
18351886
PaneFun sidePane; // side pane callback
18361887
float sidePaneWidth = 250.0f; // side pane width
1888+
UserFileAttributesFun userFileAttributes; // user file Attibutes callback
18371889
};
18381890

18391891
class IGFD_API FileDialogInternal {
@@ -2063,11 +2115,11 @@ class IGFD_API FileDialog : public BookMarkFeature, public KeyExplorerFeature, p
20632115
virtual ~FileDialog(); // ImGuiFileDialog Destructor
20642116

20652117
// standard dialog
2066-
virtual void OpenDialog( // open simple dialog
2067-
const std::string& vKey, // key dialog
2068-
const std::string& vTitle, // title
2069-
const char* vFilters, // filters, if null, will display only directories
2070-
const FileDialogConfig& vConfig); // FileDialogConfig
2118+
virtual void OpenDialog( // open simple dialog
2119+
const std::string& vKey, // key dialog
2120+
const std::string& vTitle, // title
2121+
const char* vFilters, // filters, if null, will display only directories
2122+
const FileDialogConfig& vConfig = {}); // FileDialogConfig
20712123

20722124
// Display / Close dialog form
20732125
bool Display( // Display the dialog. return true if a result was obtained (Ok or not)
@@ -2244,12 +2296,12 @@ typedef void (*IGFD_CreateThumbnailFun)(IGFD_Thumbnail_Info*); // callback fun
22442296
typedef void (*IGFD_DestroyThumbnailFun)(IGFD_Thumbnail_Info*); // callback fucntion for destroy thumbnail texture
22452297
#endif // USE_THUMBNAILS
22462298

2247-
IGFD_C_API void IGFD_OpenDialog( // open a standard dialog
2248-
ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context
2249-
const char* vKey, // key dialog
2250-
const char* vTitle, // title
2251-
const char* vFilters, // filters/filter collections. set it to null for directory mode
2252-
const IGFD_FileDialog_Config vConfig = {}); // config
2299+
IGFD_C_API void IGFD_OpenDialog( // open a standard dialog
2300+
ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context
2301+
const char* vKey, // key dialog
2302+
const char* vTitle, // title
2303+
const char* vFilters, // filters/filter collections. set it to null for directory mode
2304+
const IGFD_FileDialog_Config vConfig); // config
22532305

22542306
IGFD_C_API bool IGFD_DisplayDialog( // Display the dialog
22552307
ImGuiFileDialog* vContextPtr, // ImGuiFileDialog context

0 commit comments

Comments
 (0)