36#include "ImGuiFileDialog.h"
54#ifdef USE_STD_FILESYSTEM
60#include <emscripten.h>
65#define IGFD_DEBUG_BREAK \
66 if (IsDebuggerPresent()) __debugbreak()
68#define IGFD_DEBUG_BREAK
71#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(__WIN64__) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER)
74#define stricmp _stricmp
77#ifdef USE_STD_FILESYSTEM
80#include "dirent/dirent.h"
86#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
88#define stricmp strcasecmp
91#ifndef USE_STD_FILESYSTEM
98#include "imgui_internal.h"
102#define IM_TRUNC IM_FLOOR
114#ifndef DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION
115#ifndef STB_IMAGE_IMPLEMENTATION
116#define STB_IMAGE_IMPLEMENTATION
119#include "stb/stb_image.h"
120#ifndef DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION
121#ifndef STB_IMAGE_RESIZE_IMPLEMENTATION
122#define STB_IMAGE_RESIZE_IMPLEMENTATION
125#include "stb/stb_image_resize.h"
129#ifndef IS_FLOAT_DIFFERENT
130#define IS_FLOAT_DIFFERENT(a, b) (fabs((a) - (b)) > FLT_EPSILON)
132#ifndef IS_FLOAT_EQUAL
133#define IS_FLOAT_EQUAL(a, b) (fabs((a) - (b)) < FLT_EPSILON)
145#ifndef FILTER_COMBO_AUTO_SIZE
146#define FILTER_COMBO_AUTO_SIZE 1
148#ifndef FILTER_COMBO_MIN_WIDTH
149#define FILTER_COMBO_MIN_WIDTH 150.0f
151#ifndef IMGUI_BEGIN_COMBO
152#define IMGUI_BEGIN_COMBO ImGui::BeginCombo
159#ifndef IMGUI_PATH_BUTTON
160#define IMGUI_PATH_BUTTON ImGui::Button
163#define IMGUI_BUTTON ImGui::Button
168#ifndef createDirButtonString
169#define createDirButtonString "+"
171#ifndef okButtonString
172#define okButtonString "OK"
175#define okButtonWidth 0.0f
177#ifndef cancelButtonString
178#define cancelButtonString "Cancel"
180#ifndef cancelButtonWidth
181#define cancelButtonWidth 0.0f
183#ifndef okCancelButtonAlignement
184#define okCancelButtonAlignement 0.0f
186#ifndef invertOkAndCancelButtons
188#define invertOkAndCancelButtons 0
190#ifndef resetButtonString
191#define resetButtonString "R"
193#ifndef drivesButtonString
194#define drivesButtonString "Drives"
196#ifndef editPathButtonString
197#define editPathButtonString "E"
200#define searchString "Search :"
202#ifndef dirEntryString
203#define dirEntryString "[Dir]"
205#ifndef linkEntryString
206#define linkEntryString "[Link]"
208#ifndef fileEntryString
209#define fileEntryString "[File]"
211#ifndef fileNameString
212#define fileNameString "File Name:"
215#define dirNameString "Directory Path:"
217#ifndef buttonResetSearchString
218#define buttonResetSearchString "Reset search"
220#ifndef buttonDriveString
221#define buttonDriveString "Drives"
223#ifndef buttonEditPathString
224#define buttonEditPathString "Edit path\nYou can also right click on path buttons"
226#ifndef buttonResetPathString
227#define buttonResetPathString "Reset to current directory"
229#ifndef buttonCreateDirString
230#define buttonCreateDirString "Create Directory"
232#ifndef tableHeaderAscendingIcon
233#define tableHeaderAscendingIcon "A|"
235#ifndef tableHeaderDescendingIcon
236#define tableHeaderDescendingIcon "D|"
238#ifndef tableHeaderFileNameString
239#define tableHeaderFileNameString "File name"
241#ifndef tableHeaderFileTypeString
242#define tableHeaderFileTypeString "Type"
244#ifndef tableHeaderFileSizeString
245#define tableHeaderFileSizeString "Size"
247#ifndef tableHeaderFileDateString
248#define tableHeaderFileDateString "Date"
251#define fileSizeBytes "o"
253#ifndef fileSizeKiloBytes
254#define fileSizeKiloBytes "Ko"
256#ifndef fileSizeMegaBytes
257#define fileSizeMegaBytes "Mo"
259#ifndef fileSizeGigaBytes
260#define fileSizeGigaBytes "Go"
262#ifndef OverWriteDialogTitleString
263#define OverWriteDialogTitleString "The selected file already exists!"
265#ifndef OverWriteDialogMessageString
266#define OverWriteDialogMessageString "Are you sure you want to overwrite it?"
268#ifndef OverWriteDialogConfirmButtonString
269#define OverWriteDialogConfirmButtonString "Confirm"
271#ifndef OverWriteDialogCancelButtonString
272#define OverWriteDialogCancelButtonString "Cancel"
274#ifndef DateTimeFormat
276#define DateTimeFormat "%Y/%m/%d %H:%M"
282#ifndef tableHeaderFileThumbnailsString
283#define tableHeaderFileThumbnailsString "Thumbnails"
285#ifndef DisplayMode_FilesList_ButtonString
286#define DisplayMode_FilesList_ButtonString "FL"
288#ifndef DisplayMode_FilesList_ButtonHelp
289#define DisplayMode_FilesList_ButtonHelp "File List"
291#ifndef DisplayMode_ThumbailsList_ButtonString
292#define DisplayMode_ThumbailsList_ButtonString "TL"
294#ifndef DisplayMode_ThumbailsList_ButtonHelp
295#define DisplayMode_ThumbailsList_ButtonHelp "Thumbnails List"
297#ifndef DisplayMode_ThumbailsGrid_ButtonString
298#define DisplayMode_ThumbailsGrid_ButtonString "TG"
300#ifndef DisplayMode_ThumbailsGrid_ButtonHelp
301#define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid"
303#ifndef DisplayMode_ThumbailsList_ImageHeight
304#define DisplayMode_ThumbailsList_ImageHeight 32.0f
306#ifndef IMGUI_RADIO_BUTTON
307inline bool inRadioButton(
const char* vLabel,
bool vToggled) {
308 bool pressed =
false;
310 ImVec4 bua = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
311 ImVec4 te = ImGui::GetStyleColorVec4(ImGuiCol_Text);
312 ImGui::PushStyleColor(ImGuiCol_Button, te);
313 ImGui::PushStyleColor(ImGuiCol_ButtonActive, te);
314 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, te);
315 ImGui::PushStyleColor(ImGuiCol_Text, bua);
317 pressed = IMGUI_BUTTON(vLabel);
319 ImGui::PopStyleColor(4);
323#define IMGUI_RADIO_BUTTON inRadioButton
330#ifndef defaultBookmarkPaneWith
331#define defaultBookmarkPaneWith 150.0f
333#ifndef bookmarksButtonString
334#define bookmarksButtonString "Bookmark"
336#ifndef bookmarksButtonHelpString
337#define bookmarksButtonHelpString "Bookmark"
339#ifndef addBookmarkButtonString
340#define addBookmarkButtonString "+"
342#ifndef removeBookmarkButtonString
343#define removeBookmarkButtonString "-"
345#ifndef IMGUI_TOGGLE_BUTTON
346inline bool inToggleButton(
const char* vLabel,
bool* vToggled) {
347 bool pressed =
false;
349 if (vToggled && *vToggled) {
350 ImVec4 bua = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
353 ImVec4 te = ImGui::GetStyleColorVec4(ImGuiCol_Text);
354 ImGui::PushStyleColor(ImGuiCol_Button, te);
355 ImGui::PushStyleColor(ImGuiCol_ButtonActive, te);
356 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, te);
357 ImGui::PushStyleColor(ImGuiCol_Text, bua);
360 pressed = IMGUI_BUTTON(vLabel);
362 if (vToggled && *vToggled) {
363 ImGui::PopStyleColor(4);
366 if (vToggled && pressed) *vToggled = !*vToggled;
370#define IMGUI_TOGGLE_BUTTON inToggleButton
380class IGFDException :
public std::exception {
382 std::string m_Message;
385 IGFDException(
const std::string& vMessage) : m_Message(vMessage) {
388 return m_Message.c_str();
396#ifndef CUSTOM_FILESYSTEM_INCLUDE
397#ifdef USE_STD_FILESYSTEM
399static std::filesystem::path stringToPath(
const std::string& str)
402 return std::filesystem::path(IGFD::Utils::UTF8Decode(str));
404 return std::filesystem::path(str);
408static std::string pathToString(
const std::filesystem::path& path)
411 return IGFD::Utils::UTF8Encode(path.wstring());
413 return path.string();
417class FileSystemStd :
public IGFD::IFileSystem {
419 bool IsDirectoryCanBeOpened(
const std::string& vName)
override {
420 bool bExists =
false;
421 if (!vName.empty()) {
422 namespace fs = std::filesystem;
423 auto pathName = stringToPath(vName);
427 bExists = fs::is_directory(pathName);
430 const auto dir_iter = fs::directory_iterator(pathName);
432 }
catch (
const std::exception& ) {
439 bool IsDirectoryExist(
const std::string& vName)
override {
440 if (!vName.empty()) {
441 namespace fs = std::filesystem;
442 return fs::is_directory(stringToPath(vName));
446 bool IsFileExist(
const std::string& vName)
override {
447 namespace fs = std::filesystem;
448 return fs::is_regular_file(stringToPath(vName));
450 bool CreateDirectoryIfNotExist(
const std::string& vName)
override {
451 if (vName.empty())
return false;
452 if (IsDirectoryExist(vName))
return false;
454#if defined(__EMSCRIPTEN__)
455 std::string str = std::string(
"FS.mkdir('") + vName +
"');";
456 emscripten_run_script(str.c_str());
459 namespace fs = std::filesystem;
460 bool res = fs::create_directories(stringToPath(vName));
463 std::cout <<
"Error creating directory " << vName << std::endl;
467 std::vector<std::string> GetDrivesList()
override {
468 std::vector<std::string> res;
470 const DWORD mydrives = 2048;
472#define mini(a, b) (((a) < (b)) ? (a) : (b))
473 const DWORD countChars = mini(GetLogicalDriveStringsA(mydrives, lpBuffer), 2047);
475 if (countChars > 0U && countChars < 2049U) {
476 std::string var = std::string(lpBuffer, (
size_t)countChars);
477 IGFD::Utils::ReplaceString(var,
"\\",
"");
478 res = IGFD::Utils::SplitStringToVector(var,
'\0',
false);
484 IGFD::Utils::PathStruct ParsePathFileName(
const std::string& vPathFileName)
override {
486 namespace fs = std::filesystem;
487 IGFD::Utils::PathStruct res;
488 if (vPathFileName.empty())
return res;
489 auto fsPath = stringToPath(vPathFileName);
490 if (fs::is_directory(fsPath)) {
492 res.path = pathToString(fsPath);
494 }
else if (fs::is_regular_file(fsPath)) {
495 res.name = pathToString(fsPath.filename());
496 res.path = pathToString(fsPath.parent_path());
502 std::vector<IGFD::FileInfos> ScanDirectory(
const std::string& vPath)
override {
503 std::vector<IGFD::FileInfos> res;
505 namespace fs = std::filesystem;
506 auto fspath = stringToPath(vPath);
507 const auto dir_iter = fs::directory_iterator(fspath);
508 IGFD::FileType fstype = IGFD::FileType(IGFD::FileType::ContentType::Directory, fs::is_symlink(fs::status(fspath)));
510 IGFD::FileInfos file_two_dot;
511 file_two_dot.filePath = vPath;
512 file_two_dot.fileNameExt =
"..";
513 file_two_dot.fileType = fstype;
514 res.push_back(file_two_dot);
516 for (
const auto& file : dir_iter) {
517 IGFD::FileType fileType;
518 if (file.is_symlink()) {
519 fileType.SetSymLink(file.is_symlink());
520 fileType.SetContent(IGFD::FileType::ContentType::LinkToUnknown);
522 if (file.is_directory()) {
523 fileType.SetContent(IGFD::FileType::ContentType::Directory);
525 else if (file.is_regular_file()) {
526 fileType.SetContent(IGFD::FileType::ContentType::File);
528 if (fileType.isValid()) {
529 auto fileNameExt = pathToString(file.path().filename());
531 IGFD::FileInfos _file;
532 _file.filePath = vPath;
533 _file.fileNameExt = fileNameExt;
534 _file.fileType = fileType;
535 res.push_back(_file);
539 }
catch (
const std::exception& ex) {
540 printf(
"%s", ex.what());
544 bool IsDirectory(
const std::string& vFilePathName)
override {
545 namespace fs = std::filesystem;
546 return fs::is_directory(stringToPath(vFilePathName));
549#define FILE_SYSTEM_OVERRIDE FileSystemStd
551class FileSystemDirent :
public IGFD::IFileSystem {
553 bool IsDirectoryCanBeOpened(
const std::string& vName)
override {
554 if (!vName.empty()) {
558 pDir = opendir(vName.c_str());
559 if (pDir !=
nullptr) {
560 (void)closedir(pDir);
566 bool IsDirectoryExist(
const std::string& vName)
override {
567 bool bExists =
false;
568 if (!vName.empty()) {
570 pDir = opendir(vName.c_str());
574 }
else if (ENOENT == errno) {
586 bool IsFileExist(
const std::string& vName)
override {
587 std::ifstream docFile(vName, std::ios::in);
588 if (docFile.is_open()) {
594 bool CreateDirectoryIfNotExist(
const std::string& vName)
override {
596 if (!vName.empty()) {
597 if (!IsDirectoryExist(vName)) {
599 std::wstring wname = IGFD::Utils::UTF8Decode(vName);
600 if (CreateDirectoryW(wname.c_str(),
nullptr)) {
603#elif defined(__EMSCRIPTEN__)
604 std::string str = std::string(
"FS.mkdir('") + vName +
"');";
605 emscripten_run_script(str.c_str());
607#elif defined(_IGFD_UNIX_)
608 char buffer[PATH_MAX] = {};
609 snprintf(buffer, PATH_MAX,
"mkdir -p \"%s\"", vName.c_str());
610 const int dir_err = std::system(buffer);
616 std::cout <<
"Error creating directory " << vName << std::endl;
624 std::vector<std::string> GetDrivesList()
override {
625 std::vector<std::string> res;
627 const DWORD mydrives = 2048;
629#define mini(a, b) (((a) < (b)) ? (a) : (b))
630 const DWORD countChars = mini(GetLogicalDriveStringsA(mydrives, lpBuffer), 2047);
632 if (countChars > 0U && countChars < 2049U) {
633 std::string var = std::string(lpBuffer, (
size_t)countChars);
634 IGFD::Utils::ReplaceString(var,
"\\",
"");
635 res = IGFD::Utils::SplitStringToVector(var,
'\0',
false);
641 IGFD::Utils::PathStruct ParsePathFileName(
const std::string& vPathFileName)
override {
642 IGFD::Utils::PathStruct res;
643 if (!vPathFileName.empty()) {
644 std::string pfn = vPathFileName;
645 std::string separator(1u, PATH_SEP);
646 IGFD::Utils::ReplaceString(pfn,
"\\", separator);
647 IGFD::Utils::ReplaceString(pfn,
"/", separator);
648 size_t lastSlash = pfn.find_last_of(separator);
649 if (lastSlash != std::string::npos) {
650 res.name = pfn.substr(lastSlash + 1);
651 res.path = pfn.substr(0, lastSlash);
654 size_t lastPoint = pfn.find_last_of(
'.');
655 if (lastPoint != std::string::npos) {
660 res.ext = pfn.substr(lastPoint + 1);
661 IGFD::Utils::ReplaceString(res.name,
"." + res.ext,
"");
664 res.name = std::move(pfn);
671 std::vector<IGFD::FileInfos> ScanDirectory(
const std::string& vPath)
override {
672 std::vector<IGFD::FileInfos> res;
673 struct dirent** files =
nullptr;
674 size_t n = scandir(vPath.c_str(), &files,
nullptr,
675 [](
const struct dirent** a,
const struct dirent** b) {
676 return strcoll((*a)->d_name, (*b)->d_name);
679 for (
size_t i = 0; i < n; ++i) {
680 struct dirent* ent = files[i];
681 IGFD::FileType fileType;
682 switch (ent->d_type) {
683 case DT_DIR: fileType.SetContent(IGFD::FileType::ContentType::Directory);
break;
684 case DT_REG: fileType.SetContent(IGFD::FileType::ContentType::File);
break;
685#if defined(_IGFD_UNIX_) || (DT_LNK != DT_UNKNOWN)
691 auto filePath = vPath + ent->d_name;
693 auto filePath = vPath + IGFD::Utils::GetPathSeparator() + ent->d_name;
695 if (!stat(filePath.c_str(), &sb)) {
696 if (sb.st_mode & S_IFLNK) {
697 fileType.SetSymLink(
true);
699 fileType.SetContent(IGFD::FileType::ContentType::LinkToUnknown);
701 if (sb.st_mode & S_IFREG) {
702 fileType.SetContent(IGFD::FileType::ContentType::File);
704 }
else if (sb.st_mode & S_IFDIR) {
705 fileType.SetContent(IGFD::FileType::ContentType::Directory);
713 if (fileType.isValid()) {
714 IGFD::FileInfos _file;
715 _file.filePath = vPath;
716 _file.fileNameExt = ent->d_name;
717 _file.fileType = fileType;
718 res.push_back(_file);
721 for (
size_t i = 0; i < n; ++i) {
728 bool IsDirectory(
const std::string& vFilePathName)
override {
729 DIR *pDir = opendir(vFilePathName.c_str());
731 (void)closedir(pDir);
737#define FILE_SYSTEM_OVERRIDE FileSystemDirent
740#include CUSTOM_FILESYSTEM_INCLUDE
748bool IGFD::Utils::ImSplitter(
bool split_vertically,
float thickness,
float* size1,
float* size2,
float min_size1,
float min_size2,
float splitter_long_axis_size) {
749 using namespace ImGui;
751 ImGuiWindow* window =
g.CurrentWindow;
752 ImGuiID
id = window->GetID(
"##Splitter");
754 bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
755 bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f);
756 return SplitterBehavior(bb,
id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 1.0f);
760std::string IGFD::Utils::UTF8Encode(
const std::wstring& wstr) {
764 int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (
int)wstr.size(), NULL, 0, NULL, NULL);
766 res = std::string(size_needed, 0);
767 WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (
int)wstr.size(), &res[0], size_needed, NULL, NULL);
778std::wstring IGFD::Utils::UTF8Decode(
const std::string& str) {
782 int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (
int)str.size(), NULL, 0);
784 res = std::wstring(size_needed, 0);
785 MultiByteToWideChar(CP_UTF8, 0, &str[0], (
int)str.size(), &res[0], size_needed);
795bool IGFD::Utils::ReplaceString(std::string& str, const ::std::string& oldStr, const ::std::string& newStr,
const size_t& vMaxRecursion) {
796 if (!str.empty() && oldStr != newStr) {
800 size_t max_recursion = vMaxRecursion;
802 pos = str.find(oldStr, pos);
803 if (pos != std::string::npos) {
805 str.replace(pos, oldStr.length(), newStr);
806 pos += newStr.length();
807 }
else if (found && max_recursion > 0) {
812 }
while (pos != std::string::npos);
818std::vector<std::string> IGFD::Utils::SplitStringToVector(
const std::string& vText,
const char& vDelimiter,
const bool& vPushEmpty) {
819 std::vector<std::string> arr;
820 if (!vText.empty()) {
822 size_t end = vText.find(vDelimiter, start);
823 while (
end != std::string::npos) {
824 auto token = vText.substr(start,
end - start);
825 if (!token.empty() || (token.empty() && vPushEmpty)) {
826 arr.push_back(token);
829 end = vText.find(vDelimiter, start);
831 auto token = vText.substr(start);
832 if (!token.empty() || (token.empty() && vPushEmpty)) {
833 arr.push_back(token);
839void IGFD::Utils::AppendToBuffer(
char* vBuffer,
size_t vBufferLen,
const std::string& vStr) {
840 std::string st = vStr;
841 size_t len = vBufferLen - 1u;
842 size_t slen = strlen(vBuffer);
844 if (!st.empty() && st !=
"\n") {
845 IGFD::Utils::ReplaceString(st,
"\n",
"");
846 IGFD::Utils::ReplaceString(st,
"\r",
"");
848 vBuffer[slen] =
'\0';
849 std::string str = std::string(vBuffer);
852 if (len > str.size()) {
856 strncpy_s(vBuffer, vBufferLen, str.c_str(), len);
858 strncpy(vBuffer, str.c_str(), len);
863void IGFD::Utils::ResetBuffer(
char* vBuffer) {
867void IGFD::Utils::SetBuffer(
char* vBuffer,
size_t vBufferLen,
const std::string& vStr) {
868 ResetBuffer(vBuffer);
869 AppendToBuffer(vBuffer, vBufferLen, vStr);
872std::string IGFD::Utils::LowerCaseString(
const std::string& vString) {
876 for (
char& c : str) {
877 c = (char)std::tolower(c);
883size_t IGFD::Utils::GetCharCountInString(
const std::string& vString,
const char& vChar) {
885 for (
const auto& c : vString) {
893size_t IGFD::Utils::GetLastCharPosWithMinCharCount(
const std::string& vString,
const char& vChar,
const size_t& vMinCharCount) {
895 size_t last_dot_pos = vString.size() + 1U;
896 size_t count_dots = vMinCharCount;
897 while (count_dots > 0U && last_dot_pos > 0U && last_dot_pos != std::string::npos) {
898 auto new_dot = vString.rfind(vChar, last_dot_pos - 1U);
899 if (new_dot != std::string::npos) {
900 last_dot_pos = new_dot;
908 return std::string::npos;
911std::string IGFD::Utils::GetPathSeparator() {
912 return std::string(1U, PATH_SEP);
915std::string IGFD::Utils::RoundNumber(
double vvalue,
int n) {
916 std::stringstream tmp;
917 tmp << std::setprecision(n) << std::fixed << vvalue;
921std::string IGFD::Utils::FormatFileSize(
size_t vByteSize) {
922 if (vByteSize != 0) {
923 static double lo = 1024.0;
924 static double ko = 1024.0 * 1024.0;
925 static double mo = 1024.0 * 1024.0 * 1024.0;
927 auto v = (double)vByteSize;
930 return RoundNumber(v, 0) +
" " + fileSizeBytes;
932 return RoundNumber(v / lo, 2) +
" " + fileSizeKiloBytes;
934 return RoundNumber(v / ko, 2) +
" " + fileSizeMegaBytes;
936 return RoundNumber(v / mo, 2) +
" " + fileSizeGigaBytes;
939 return "0 " fileSizeBytes;
946IGFD::FileStyle::FileStyle() : color(0, 0, 0, 0) {
949IGFD::FileStyle::FileStyle(
const FileStyle& vStyle) {
950 color = vStyle.color;
953 flags = vStyle.flags;
956IGFD::FileStyle::FileStyle(
const ImVec4& vColor,
const std::string& vIcon, ImFont* vFont) : color(vColor), icon(vIcon), font(vFont) {
963void IGFD::SearchManager::Clear() {
965 IGFD::Utils::ResetBuffer(searchBuffer);
968void IGFD::SearchManager::DrawSearchBar(FileDialogInternal& vFileDialogInternal) {
970 if (IMGUI_BUTTON(resetButtonString
"##BtnImGuiFileDialogSearchField")) {
972 vFileDialogInternal.fileManager.ApplyFilteringOnFileList(vFileDialogInternal);
974 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonResetSearchString);
976 ImGui::Text(searchString);
978 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
979 bool edited = ImGui::InputText(
"##InputImGuiFileDialogSearchField", searchBuffer, MAX_FILE_DIALOG_NAME_BUFFER);
980 if (ImGui::GetItemID() == ImGui::GetActiveID()) searchInputIsActive =
true;
981 ImGui::PopItemWidth();
983 searchTag = searchBuffer;
984 vFileDialogInternal.fileManager.ApplyFilteringOnFileList(vFileDialogInternal);
992void IGFD::FilterInfos::setCollectionTitle(
const std::string& vTitle) {
996void IGFD::FilterInfos::addFilter(
const std::string& vFilter,
const bool& vIsRegex) {
997 setCollectionTitle(vFilter);
998 addCollectionFilter(vFilter, vIsRegex);
1001void IGFD::FilterInfos::addCollectionFilter(
const std::string& vFilter,
const bool& vIsRegex) {
1003 if (vFilter.find(
'*') != std::string::npos) {
1004 const auto& regex_string = transformAsteriskBasedFilterToRegex(vFilter);
1005 addCollectionFilter(regex_string,
true);
1008 filters.try_add(vFilter);
1009 filters_optimized.try_add(Utils::LowerCaseString(vFilter));
1010 auto _count_dots = Utils::GetCharCountInString(vFilter,
'.');
1011 if (_count_dots > count_dots) {
1012 count_dots = _count_dots;
1016 auto rx = std::regex(vFilter);
1017 filters.try_add(vFilter);
1018 filters_regex.emplace_back(rx);
1019 }
catch (std::exception&) {
1025void IGFD::FilterInfos::clear() {
1028 filters_optimized.clear();
1029 filters_regex.clear();
1032bool IGFD::FilterInfos::empty()
const {
1033 return filters.empty() || filters.begin()->empty();
1036const std::string& IGFD::FilterInfos::getFirstFilter()
const {
1037 if (!filters.empty()) {
1038 return *filters.begin();
1040 return empty_string;
1043bool IGFD::FilterInfos::exist(
const FileInfos& vFileInfos,
bool vIsCaseInsensitive)
const {
1044 for (
const auto& filter : filters) {
1045 if (vFileInfos.SearchForExt(filter, vIsCaseInsensitive, count_dots)) {
1052bool IGFD::FilterInfos::regexExist(
const std::string& vFilter)
const {
1053 for (
auto regex : filters_regex) {
1054 if (std::regex_search(vFilter, regex)) {
1061std::string IGFD::FilterInfos::transformAsteriskBasedFilterToRegex(
const std::string& vFilter) {
1063 if (!vFilter.empty() && vFilter.find(
'*') != std::string::npos) {
1065 for (
const auto& c : vFilter) {
1068 }
else if (c ==
'*') {
1083const IGFD::FilterInfos& IGFD::FilterManager::GetSelectedFilter()
const {
1084 return m_SelectedFilter;
1087void IGFD::FilterManager::ParseFilters(
const char* vFilters) {
1088 m_ParsedFilters.clear();
1091 dLGFilters = vFilters;
1096 if (!dLGFilters.empty()) {
1108 bool current_filter_found =
false;
1109 bool started =
false;
1110 bool regex_started =
false;
1111 bool parenthesis_started =
false;
1114 std::string filter_name;
1116 char last_split_char = 0;
1117 for (
char c : dLGFilters) {
1119 if (regex_started) {
1123 m_ParsedFilters.emplace_back();
1124 m_ParsedFilters.back().setCollectionTitle(filter_name);
1125 filter_name.clear();
1128 last_split_char = c;
1129 }
else if (c ==
'}') {
1130 if (regex_started) {
1134 if (
word.size() > 1U && word[0] ==
'.') {
1135 if (m_ParsedFilters.empty()) {
1136 m_ParsedFilters.emplace_back();
1138 m_ParsedFilters.back().addCollectionFilter(word,
false);
1141 filter_name.clear();
1145 last_split_char = c;
1146 }
else if (c ==
'(') {
1148 if (last_split_char ==
'(') {
1149 regex_started =
true;
1151 parenthesis_started =
true;
1155 last_split_char = c;
1156 }
else if (c ==
')') {
1158 if (last_split_char ==
')') {
1159 if (regex_started) {
1161 m_ParsedFilters.back().addCollectionFilter(word,
true);
1163 m_ParsedFilters.emplace_back();
1164 m_ParsedFilters.back().addFilter(word,
true);
1167 filter_name.clear();
1168 regex_started =
false;
1171 if (!m_ParsedFilters.empty()) {
1172 m_ParsedFilters.erase(m_ParsedFilters.begin() + m_ParsedFilters.size() - 1U);
1174 m_ParsedFilters.clear();
1178 filter_name.clear();
1181 parenthesis_started =
false;
1185 last_split_char = c;
1186 }
else if (c ==
'.') {
1191 last_split_char = c;
1192 }
else if (c ==
',') {
1193 if (regex_started) {
1194 regex_started =
false;
1196 filter_name.clear();
1199 if (
word.size() > 1U && word[0] ==
'.') {
1200 m_ParsedFilters.back().addCollectionFilter(word,
false);
1202 filter_name.clear();
1205 if (
word.size() > 1U && word[0] ==
'.') {
1206 m_ParsedFilters.emplace_back();
1207 m_ParsedFilters.back().addFilter(word,
false);
1209 filter_name.clear();
1211 if (parenthesis_started) {
1227 if (!m_ParsedFilters.empty()) {
1228 m_ParsedFilters.erase(m_ParsedFilters.begin() + m_ParsedFilters.size() - 1U);
1230 m_ParsedFilters.clear();
1232 }
else if (
word.size() > 1U && word[0] ==
'.') {
1233 m_ParsedFilters.emplace_back();
1234 m_ParsedFilters.back().addFilter(word,
false);
1238 for (
const auto& it : m_ParsedFilters) {
1239 if (it.title == m_SelectedFilter.title) {
1240 m_SelectedFilter = it;
1241 current_filter_found =
true;
1246 if (!current_filter_found) {
1247 if (!m_ParsedFilters.empty()) {
1248 m_SelectedFilter = *m_ParsedFilters.begin();
1254void IGFD::FilterManager::SetSelectedFilterWithExt(
const std::string& vFilter) {
1255 if (!m_ParsedFilters.empty()) {
1256 if (!vFilter.empty()) {
1257 for (
const auto& infos : m_ParsedFilters) {
1258 for (
const auto& filter : infos.filters) {
1259 if (vFilter == filter) {
1260 m_SelectedFilter = infos;
1266 if (m_SelectedFilter.empty()) {
1267 m_SelectedFilter = *m_ParsedFilters.begin();
1272void IGFD::FilterManager::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const FileStyle& vInfos) {
1273 std::string _criteria = (vCriteria !=
nullptr) ? std::string(vCriteria) :
"";
1274 m_FilesStyle[vFlags][_criteria] = std::make_shared<FileStyle>(vInfos);
1275 m_FilesStyle[vFlags][_criteria]->flags = vFlags;
1280bool IGFD::FilterManager::m_FillFileStyle(std::shared_ptr<FileInfos> vFileInfos)
const {
1284 if (vFileInfos.use_count() && !m_FilesStyle.empty()) {
1285 for (
const auto& _flag : m_FilesStyle) {
1286 for (
const auto& _file : _flag.second) {
1287 if ((_flag.first & IGFD_FileStyleByTypeDir && _flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType.isDir() && vFileInfos->fileType.isSymLink()) ||
1288 (_flag.first & IGFD_FileStyleByTypeFile && _flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType.isFile() && vFileInfos->fileType.isSymLink()) ||
1289 (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType.isSymLink()) || (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos->fileType.isDir()) ||
1290 (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos->fileType.isFile())) {
1291 if (_file.first.empty()) {
1292 vFileInfos->fileStyle = _file.second;
1293 }
else if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileNameExt,
1294 std::regex(_file.first))) {
1295 vFileInfos->fileStyle = _file.second;
1296 }
else if (_file.first == vFileInfos->fileNameExt) {
1297 vFileInfos->fileStyle = _file.second;
1301 if (_flag.first & IGFD_FileStyleByExtention) {
1302 if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileExtLevels[0], std::regex(_file.first))) {
1303 vFileInfos->fileStyle = _file.second;
1304 }
else if (vFileInfos->SearchForExt(_file.first,
false)) {
1305 vFileInfos->fileStyle = _file.second;
1309 if (_flag.first & IGFD_FileStyleByFullName) {
1310 if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileNameExt, std::regex(_file.first))) {
1311 vFileInfos->fileStyle = _file.second;
1312 }
else if (_file.first == vFileInfos->fileNameExt) {
1313 vFileInfos->fileStyle = _file.second;
1317 if (_flag.first & IGFD_FileStyleByContainedInFullName) {
1318 if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileNameExt, std::regex(_file.first))) {
1319 vFileInfos->fileStyle = _file.second;
1320 }
else if (vFileInfos->fileNameExt.find(_file.first) != std::string::npos) {
1321 vFileInfos->fileStyle = _file.second;
1325 for (
auto& functor : m_FilesStyleFunctors) {
1328 if (functor(*(vFileInfos.get()), result)) {
1329 vFileInfos->fileStyle = std::make_shared<FileStyle>(std::move(result));
1334 if (vFileInfos->fileStyle.use_count()) {
1344void IGFD::FilterManager::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const ImVec4& vColor,
const std::string& vIcon, ImFont* vFont) {
1345 std::string _criteria;
1346 if (vCriteria) _criteria = std::string(vCriteria);
1347 m_FilesStyle[vFlags][_criteria] = std::make_shared<FileStyle>(vColor, vIcon, vFont);
1348 m_FilesStyle[vFlags][_criteria]->flags = vFlags;
1351void IGFD::FilterManager::SetFileStyle(FileStyle::FileStyleFunctor vFunctor) {
1353 m_FilesStyleFunctors.push_back(vFunctor);
1358bool IGFD::FilterManager::GetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const std::string& vCriteria, ImVec4* vOutColor, std::string* vOutIcon, ImFont** vOutFont) {
1360 if (!m_FilesStyle.empty()) {
1361 if (m_FilesStyle.find(vFlags) != m_FilesStyle.end()) {
1362 if (vFlags & IGFD_FileStyleByContainedInFullName) {
1364 for (
const auto& _file : m_FilesStyle.at(vFlags)) {
1365 if (vCriteria.find(_file.first) != std::string::npos) {
1366 if (_file.second.use_count()) {
1367 *vOutColor = _file.second->color;
1368 if (vOutIcon) *vOutIcon = _file.second->icon;
1369 if (vOutFont) *vOutFont = _file.second->font;
1375 if (m_FilesStyle.at(vFlags).find(vCriteria) != m_FilesStyle.at(vFlags).end()) {
1376 *vOutColor = m_FilesStyle[vFlags][vCriteria]->color;
1377 if (vOutIcon) *vOutIcon = m_FilesStyle[vFlags][vCriteria]->icon;
1378 if (vOutFont) *vOutFont = m_FilesStyle[vFlags][vCriteria]->font;
1384 for (
const auto& _flag : m_FilesStyle) {
1385 if (_flag.first & vFlags) {
1386 if (_flag.first & IGFD_FileStyleByContainedInFullName) {
1388 for (
const auto& _file : m_FilesStyle.at(_flag.first)) {
1389 if (vCriteria.find(_file.first) != std::string::npos) {
1390 if (_file.second.use_count()) {
1391 *vOutColor = _file.second->color;
1392 if (vOutIcon) *vOutIcon = _file.second->icon;
1393 if (vOutFont) *vOutFont = _file.second->font;
1399 if (m_FilesStyle.at(_flag.first).find(vCriteria) != m_FilesStyle.at(_flag.first).end()) {
1400 *vOutColor = m_FilesStyle[_flag.first][vCriteria]->color;
1401 if (vOutIcon) *vOutIcon = m_FilesStyle[_flag.first][vCriteria]->icon;
1402 if (vOutFont) *vOutFont = m_FilesStyle[_flag.first][vCriteria]->font;
1414void IGFD::FilterManager::ClearFilesStyle() {
1415 m_FilesStyle.clear();
1418bool IGFD::FilterManager::IsCoveredByFilters(
const FileInfos& vFileInfos,
bool vIsCaseInsensitive)
const {
1419 if (!dLGFilters.empty() && !m_SelectedFilter.empty()) {
1420 return (m_SelectedFilter.exist(vFileInfos, vIsCaseInsensitive) || m_SelectedFilter.regexExist(vFileInfos.fileNameExt));
1426float IGFD::FilterManager::GetFilterComboBoxWidth()
const {
1427#if FILTER_COMBO_AUTO_SIZE
1428 const auto& combo_width =
ImGui::CalcTextSize(m_SelectedFilter.title.c_str()).x + ImGui::GetFrameHeight() + ImGui::GetStyle().ItemInnerSpacing.x;
1429 return ImMax(combo_width, FILTER_COMBO_MIN_WIDTH);
1431 return FILTER_COMBO_MIN_WIDTH;
1435bool IGFD::FilterManager::DrawFilterComboBox(FileDialogInternal& vFileDialogInternal) {
1436 if (!dLGFilters.empty()) {
1438 bool needToApllyNewFilter =
false;
1439 ImGui::PushItemWidth(GetFilterComboBoxWidth());
1440 if (IMGUI_BEGIN_COMBO(
"##Filters", m_SelectedFilter.title.c_str(), ImGuiComboFlags_None)) {
1442 for (
const auto& filter : m_ParsedFilters) {
1443 const bool item_selected = (
filter.title == m_SelectedFilter.title);
1444 ImGui::PushID((
void*)(intptr_t)i++);
1445 if (ImGui::Selectable(
filter.title.c_str(), item_selected)) {
1446 m_SelectedFilter =
filter;
1447 needToApllyNewFilter =
true;
1453 ImGui::PopItemWidth();
1454 if (needToApllyNewFilter) {
1455 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
1457 return needToApllyNewFilter;
1462std::string IGFD::FilterManager::ReplaceExtentionWithCurrentFilterIfNeeded(
const std::string& vFileName, IGFD_ResultMode vFlag)
const {
1463 auto result = vFileName;
1464 if (!result.empty()) {
1465 const auto& current_filter = m_SelectedFilter.getFirstFilter();
1466 if (!current_filter.empty()) {
1467 Utils::ReplaceString(result,
"..",
".");
1470 if (current_filter.find(
"((") != std::string::npos) {
1475 if (current_filter.find(
".*") != std::string::npos) {
1480 case IGFD_ResultMode_KeepInputFile: {
1483 case IGFD_ResultMode_OverwriteFileExt: {
1484 const auto& count_dots = Utils::GetCharCountInString(vFileName,
'.');
1485 const auto& min_dots = ImMin<size_t>(count_dots, m_SelectedFilter.count_dots);
1486 const auto& lp = Utils::GetLastCharPosWithMinCharCount(vFileName,
'.', min_dots);
1487 if (lp != std::string::npos) {
1488 const auto& file_name_without_user_ext = vFileName.substr(0, lp);
1489 result = file_name_without_user_ext + current_filter;
1491 result = vFileName + current_filter;
1495 case IGFD_ResultMode_AddIfNoFileExt: {
1496 const auto& count_dots = Utils::GetCharCountInString(vFileName,
'.');
1497 const auto& min_dots = ImMin<size_t>(count_dots, m_SelectedFilter.count_dots);
1498 const auto& lp = Utils::GetLastCharPosWithMinCharCount(vFileName,
'.', min_dots);
1499 if (lp == std::string::npos ||
1500 lp == (vFileName.size() - 1U)) {
1501 const auto& file_name_without_user_ext = vFileName.substr(0, lp);
1502 result = file_name_without_user_ext + current_filter;
1508 Utils::ReplaceString(result,
"..",
".");
1514void IGFD::FilterManager::SetDefaultFilterIfNotDefined() {
1515 if (m_SelectedFilter.empty() &&
1516 !m_ParsedFilters.empty()) {
1517 m_SelectedFilter = *m_ParsedFilters.begin();
1525IGFD::FileType::FileType() =
default;
1526IGFD::FileType::FileType(
const ContentType& vContentType,
const bool& vIsSymlink) : m_Content(vContentType), m_Symlink(vIsSymlink) {
1528void IGFD::FileType::SetContent(
const ContentType& vContentType) {
1529 m_Content = vContentType;
1531void IGFD::FileType::SetSymLink(
const bool& vIsSymlink) {
1532 m_Symlink = vIsSymlink;
1534bool IGFD::FileType::isValid()
const {
1535 return m_Content != ContentType::Invalid;
1537bool IGFD::FileType::isDir()
const {
1538 return m_Content == ContentType::Directory;
1540bool IGFD::FileType::isFile()
const {
1541 return m_Content == ContentType::File;
1543bool IGFD::FileType::isLinkToUnknown()
const {
1544 return m_Content == ContentType::LinkToUnknown;
1546bool IGFD::FileType::isSymLink()
const {
1550bool IGFD::FileType::operator==(
const FileType& rhs)
const {
1551 return m_Content == rhs.m_Content;
1553bool IGFD::FileType::operator!=(
const FileType& rhs)
const {
1554 return m_Content != rhs.m_Content;
1556bool IGFD::FileType::operator<(
const FileType& rhs)
const {
1557 return m_Content < rhs.m_Content;
1559bool IGFD::FileType::operator>(
const FileType& rhs)
const {
1560 return m_Content > rhs.m_Content;
1567bool IGFD::FileInfos::SearchForTag(
const std::string& vTag)
const {
1568 if (!vTag.empty()) {
1569 if (fileNameExt_optimized ==
"..")
return true;
1570 return fileNameExt_optimized.find(vTag) != std::string::npos ||
1571 fileNameExt.find(vTag) != std::string::npos;
1578bool IGFD::FileInfos::SearchForExt(
const std::string& vExt,
const bool& vIsCaseInsensitive,
const size_t& vMaxLevel)
const {
1579 if (!vExt.empty()) {
1580 const auto& ext_to_check = vIsCaseInsensitive ? Utils::LowerCaseString(vExt) : vExt;
1581 const auto& ext_levels = vIsCaseInsensitive ? fileExtLevels_optimized : fileExtLevels;
1582 if (vMaxLevel >= 1 && countExtDot >= vMaxLevel) {
1583 for (
const auto& ext : ext_levels) {
1584 if (!ext.empty() && ext == ext_to_check) {
1589 return (fileExtLevels[0] == vExt);
1595bool IGFD::FileInfos::SearchForExts(
const std::string& vComaSepExts,
const bool& vIsCaseInsensitive,
const size_t& vMaxLevel)
const {
1596 if (!vComaSepExts.empty()) {
1597 const auto& arr = Utils::SplitStringToVector(vComaSepExts,
',',
false);
1598 for (
const auto& a : arr) {
1599 if (SearchForExt(a, vIsCaseInsensitive, vMaxLevel)) {
1607bool IGFD::FileInfos::FinalizeFileTypeParsing(
const size_t& vMaxDotToExtract) {
1608 if (fileType.isFile() || fileType.isLinkToUnknown()) {
1609 countExtDot = Utils::GetCharCountInString(fileNameExt,
'.');
1611 if (countExtDot > 1U) {
1612 size_t max_dot_to_extract = vMaxDotToExtract;
1613 if (max_dot_to_extract > countExtDot) {
1614 max_dot_to_extract = countExtDot;
1616 lpt = Utils::GetLastCharPosWithMinCharCount(fileNameExt,
'.', max_dot_to_extract);
1618 lpt = fileNameExt.find_first_of(
'.');
1620 if (lpt != std::string::npos) {
1622 fileNameLevels[lvl] = fileNameExt.substr(0, lpt);
1623 fileNameLevels[lvl] = Utils::LowerCaseString(fileNameLevels[lvl]);
1624 fileExtLevels[lvl] = fileNameExt.substr(lpt);
1625 fileExtLevels_optimized[lvl] = Utils::LowerCaseString(fileExtLevels[lvl]);
1626 if (countExtDot > 1U) {
1627 auto count = countExtDot;
1628 while (count > 0 && lpt != std::string::npos && lvl < fileExtLevels.size()) {
1630 if (fileNameExt.size() > lpt) {
1631 lpt = fileNameExt.find_first_of(
'.', lpt);
1632 if (lpt != std::string::npos) {
1633 fileNameLevels[lvl] = fileNameExt.substr(0, lpt);
1634 fileNameLevels[lvl] = Utils::LowerCaseString(fileNameLevels[lvl]);
1635 fileExtLevels[lvl] = fileNameExt.substr(lpt);
1636 fileExtLevels_optimized[lvl] = Utils::LowerCaseString(fileExtLevels[lvl]);
1651IGFD::FileManager::FileManager() {
1652 fsRoot = IGFD::Utils::GetPathSeparator();
1653 m_FileSystemName =
typeid(FILE_SYSTEM_OVERRIDE).name();
1655 m_FileSystemPtr = std::unique_ptr<FILE_SYSTEM_OVERRIDE>(
new FILE_SYSTEM_OVERRIDE());
1659void IGFD::FileManager::OpenCurrentPath(
const FileDialogInternal& vFileDialogInternal) {
1663 if (dLGDirectoryMode) {
1664 SetDefaultFileName(
".");
1666 SetDefaultFileName(dLGDefaultFileName);
1668 ScanDir(vFileDialogInternal, GetCurrentPath());
1671void IGFD::FileManager::SortFields(
const FileDialogInternal& vFileDialogInternal) {
1672 m_SortFields(vFileDialogInternal, m_FileList, m_FilteredFileList);
1675void IGFD::FileManager::m_SortFields(
const FileDialogInternal& vFileDialogInternal, std::vector<std::shared_ptr<FileInfos> >& vFileInfosList, std::vector<std::shared_ptr<FileInfos> >& vFileInfosFilteredList) {
1676 static constexpr const char* defaultHeaderString[] = {
1677 tableHeaderFileNameString,
1678 tableHeaderFileTypeString,
1679 tableHeaderFileSizeString,
1680 tableHeaderFileDateString,
1681#ifdef USE_THUMBNAILS
1682 tableHeaderFileThumbnailsString,
1685 for (
int i = 0; i < SortingFieldEnum::NUM_FIELDS; ++i) {
1686 header[i] = defaultHeaderString[i];
1688 bool ascending = sortingDirection[sortingField];
1689#ifdef USE_CUSTOM_SORTING_ICON
1690 header[sortingField] = (ascending ? tableHeaderAscendingIcon : tableHeaderDescendingIcon)
1691 + header[sortingField];
1694 std::stable_sort(vFileInfosList.begin(), vFileInfosList.end(), [&](
const std::shared_ptr<FileInfos>& a,
const std::shared_ptr<FileInfos>& b) ->
bool {
1695 bool a_used = a.use_count() != 0;
1696 bool b_used = b.use_count() != 0;
1697 if (a_used != b_used) return a_used < b_used;
1698 if (!a_used) return true;
1701 bool a_not_dotdot = a->fileNameExt !=
"..";
1702 bool b_not_dotdot = b->fileNameExt !=
"..";
1703 if (a_not_dotdot != b_not_dotdot) return a_not_dotdot < b_not_dotdot;
1705 auto compare = [&](auto extractor) {
1707 auto a_type = a->fileType;
1708 auto b_type = a->fileType;
1709 if (a_type != b_type) return ascending ? a_type < b_type : b_type < a_type;
1712 auto a_properties = extractor(a);
1713 auto b_properties = extractor(b);
1714 return ascending ? a_properties < b_properties : b_properties < a_properties;
1716 switch (sortingField) {
1717 case SortingFieldEnum::FIELD_FILENAME:
1718 return compare([](
const auto& x) {
return x->fileNameExt_optimized; });
1719 case SortingFieldEnum::FIELD_TYPE:
1720 return compare([](
const auto& x) {
return x->fileExtLevels_optimized[0]; });
1721 case SortingFieldEnum::FIELD_SIZE:
1722 return compare([](
const auto& x) {
return x->fileSize; });
1723 case SortingFieldEnum::FIELD_DATE:
1724 return compare([](
const auto& x) {
return x->fileModifDate; });
1725#ifdef USE_THUMBNAILS
1726 case SortingFieldEnum::FIELD_THUMBNAILS:
1727 return compare([](
const auto& x) {
return std::make_tuple(x->thumbnailInfo.textureWidth, x->thumbnailInfo.textureHeight); });
1734 m_ApplyFilteringOnFileList(vFileDialogInternal, vFileInfosList, vFileInfosFilteredList);
1737bool IGFD::FileManager::m_CompleteFileInfosWithUserFileAttirbutes(
const FileDialogInternal& vFileDialogInternal,
const std::shared_ptr<FileInfos>& vInfos) {
1738 if (vFileDialogInternal.getDialogConfig().userFileAttributes !=
nullptr) {
1739 if (!vFileDialogInternal.getDialogConfig().userFileAttributes(vInfos.get(), vFileDialogInternal.getDialogConfig().userDatas)) {
1742 if (!vInfos->fileType.isDir()) {
1743 vInfos->formatedFileSize = IGFD::Utils::FormatFileSize(vInfos->fileSize);
1750void IGFD::FileManager::ClearFileLists() {
1751 m_FilteredFileList.clear();
1755void IGFD::FileManager::ClearPathLists() {
1756 m_FilteredPathList.clear();
1760void IGFD::FileManager::m_AddFile(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath,
const std::string& vFileName,
const FileType& vFileType) {
1761 auto infos = std::make_shared<FileInfos>();
1763 infos->filePath = vPath;
1764 infos->fileNameExt = vFileName;
1765 infos->fileNameExt_optimized = Utils::LowerCaseString(infos->fileNameExt);
1766 infos->fileType = vFileType;
1768 if (infos->fileNameExt.empty() || (infos->fileNameExt ==
"." && !vFileDialogInternal.filterManager.dLGFilters.empty())) {
1772 if (infos->fileNameExt !=
".." && (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DontShowHiddenFiles) && infos->fileNameExt[0] ==
'.') {
1773 if (!vFileDialogInternal.filterManager.dLGFilters.empty() || (vFileDialogInternal.filterManager.dLGFilters.empty() && infos->fileNameExt !=
".")) {
1778 if (infos->FinalizeFileTypeParsing(vFileDialogInternal.filterManager.GetSelectedFilter().count_dots)) {
1779 if (!vFileDialogInternal.filterManager.IsCoveredByFilters(*infos.get(), (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_CaseInsensitiveExtention) != 0)) {
1784 vFileDialogInternal.filterManager.m_FillFileStyle(infos);
1786 m_CompleteFileInfos(infos);
1788 if (m_CompleteFileInfosWithUserFileAttirbutes(vFileDialogInternal, infos)) {
1789 m_FileList.push_back(infos);
1793void IGFD::FileManager::m_AddPath(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath,
const std::string& vFileName,
const FileType& vFileType) {
1794 if (!vFileType.isDir())
return;
1796 auto infos = std::make_shared<FileInfos>();
1798 infos->filePath = vPath;
1799 infos->fileNameExt = vFileName;
1800 infos->fileNameExt_optimized = Utils::LowerCaseString(infos->fileNameExt);
1801 infos->fileType = vFileType;
1803 if (infos->fileNameExt.empty() || (infos->fileNameExt ==
"." && !vFileDialogInternal.filterManager.dLGFilters.empty())) {
1807 if (infos->fileNameExt !=
".." && (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DontShowHiddenFiles) && infos->fileNameExt[0] ==
'.') {
1808 if (!vFileDialogInternal.filterManager.dLGFilters.empty() || (vFileDialogInternal.filterManager.dLGFilters.empty() && infos->fileNameExt !=
".")) {
1813 vFileDialogInternal.filterManager.m_FillFileStyle(infos);
1815 m_CompleteFileInfos(infos);
1817 if (m_CompleteFileInfosWithUserFileAttirbutes(vFileDialogInternal, infos)) {
1818 m_PathList.push_back(infos);
1822void IGFD::FileManager::ScanDir(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath) {
1823 std::string path = vPath;
1825 if (m_CurrentPathDecomposition.empty()) {
1826 SetCurrentDir(path);
1829 if (!m_CurrentPathDecomposition.empty()) {
1831 if (path == fsRoot) path += IGFD::Utils::GetPathSeparator();
1836 const auto& files = m_FileSystemPtr->ScanDirectory(vPath);
1837 for (
const auto& file : files) {
1838 m_AddFile(vFileDialogInternal, path, file.fileNameExt, file.fileType);
1841 m_SortFields(vFileDialogInternal, m_FileList, m_FilteredFileList);
1845void IGFD::FileManager::m_ScanDirForPathSelection(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath) {
1846 std::string path = vPath;
1848 if (!path.empty()) {
1850 if (path == fsRoot) path += IGFD::Utils::GetPathSeparator();
1855 const auto& files = m_FileSystemPtr->ScanDirectory(path);
1856 for (
const auto& file : files) {
1857 if (file.fileType.isDir()) {
1858 m_AddPath(vFileDialogInternal, path, file.fileNameExt, file.fileType);
1862 m_SortFields(vFileDialogInternal, m_PathList, m_FilteredPathList);
1866void IGFD::FileManager::m_OpenPathPopup(
const FileDialogInternal& vFileDialogInternal, std::vector<std::string>::iterator vPathIter) {
1867 const auto path = ComposeNewPath(vPathIter);
1868 m_ScanDirForPathSelection(vFileDialogInternal, path);
1869 m_PopupComposedPath = vPathIter;
1870 ImGui::OpenPopup(
"IGFD_Path_Popup");
1873bool IGFD::FileManager::GetDrives() {
1874 auto drives = m_FileSystemPtr->GetDrivesList();
1875 if (!drives.empty()) {
1876 m_CurrentPath.clear();
1877 m_CurrentPathDecomposition.clear();
1879 for (
auto& drive : drives) {
1880 auto info = std::make_shared<FileInfos>();
1881 info->fileNameExt = drive;
1882 info->fileNameExt_optimized = Utils::LowerCaseString(drive);
1883 info->fileType.SetContent(FileType::ContentType::Directory);
1885 if (!info->fileNameExt.empty()) {
1886 m_FileList.push_back(info);
1895bool IGFD::FileManager::IsComposerEmpty() {
1896 return m_CurrentPathDecomposition.empty();
1899size_t IGFD::FileManager::GetComposerSize() {
1900 return m_CurrentPathDecomposition.size();
1903bool IGFD::FileManager::IsFileListEmpty() {
1904 return m_FileList.empty();
1907bool IGFD::FileManager::IsPathListEmpty() {
1908 return m_PathList.empty();
1911size_t IGFD::FileManager::GetFullFileListSize() {
1912 return m_FileList.size();
1915std::shared_ptr<IGFD::FileInfos> IGFD::FileManager::GetFullFileAt(
size_t vIdx) {
1916 if (vIdx < m_FileList.size())
return m_FileList[vIdx];
1920bool IGFD::FileManager::IsFilteredListEmpty() {
1921 return m_FilteredFileList.empty();
1924bool IGFD::FileManager::IsPathFilteredListEmpty() {
1925 return m_FilteredPathList.empty();
1928size_t IGFD::FileManager::GetFilteredListSize() {
1929 return m_FilteredFileList.size();
1932size_t IGFD::FileManager::GetPathFilteredListSize() {
1933 return m_FilteredPathList.size();
1936std::shared_ptr<IGFD::FileInfos> IGFD::FileManager::GetFilteredFileAt(
size_t vIdx) {
1937 if (vIdx < m_FilteredFileList.size())
return m_FilteredFileList[vIdx];
1941std::shared_ptr<IGFD::FileInfos> IGFD::FileManager::GetFilteredPathAt(
size_t vIdx) {
1942 if (vIdx < m_FilteredPathList.size())
return m_FilteredPathList[vIdx];
1946std::vector<std::string>::iterator IGFD::FileManager::GetCurrentPopupComposedPath() {
1947 return m_PopupComposedPath;
1950bool IGFD::FileManager::IsFileNameSelected(
const std::string& vFileName) {
1951 return m_SelectedFileNames.find(vFileName) != m_SelectedFileNames.end();
1954std::string IGFD::FileManager::GetBack() {
1955 return m_CurrentPathDecomposition.back();
1958void IGFD::FileManager::ClearComposer() {
1959 m_CurrentPathDecomposition.clear();
1962void IGFD::FileManager::ClearAll() {
1967void IGFD::FileManager::ApplyFilteringOnFileList(
const FileDialogInternal& vFileDialogInternal) {
1968 m_ApplyFilteringOnFileList(vFileDialogInternal, m_FileList, m_FilteredFileList);
1971void IGFD::FileManager::m_ApplyFilteringOnFileList(
const FileDialogInternal& vFileDialogInternal, std::vector<std::shared_ptr<FileInfos> >& vFileInfosList, std::vector<std::shared_ptr<FileInfos> >& vFileInfosFilteredList) {
1972 vFileInfosFilteredList.clear();
1973 for (
const auto& file : vFileInfosList) {
1974 if (!file.use_count())
continue;
1976 if (!file->SearchForTag(vFileDialogInternal.searchManager.searchTag))
1978 if (dLGDirectoryMode && !file->fileType.isDir()) show =
false;
1979 if (show) vFileInfosFilteredList.push_back(file);
1983void IGFD::FileManager::m_CompleteFileInfos(
const std::shared_ptr<FileInfos>& vInfos) {
1984 if (!vInfos.use_count())
return;
1986 if (vInfos->fileNameExt !=
"." && vInfos->fileNameExt !=
"..") {
2005 if (vInfos->fileType.isFile() || vInfos->fileType.isLinkToUnknown() || vInfos->fileType.isDir()) {
2006 fpn = vInfos->filePath + IGFD::Utils::GetPathSeparator() + vInfos->fileNameExt;
2009 struct stat statInfos = {};
2011 int result = stat(fpn.c_str(), &statInfos);
2013 if (!vInfos->fileType.isDir()) {
2014 vInfos->fileSize = (size_t)statInfos.st_size;
2015 vInfos->formatedFileSize = IGFD::Utils::FormatFileSize(vInfos->fileSize);
2021 errno_t err = localtime_s(&_tm, &statInfos.st_mtime);
2022 if (!err) len = strftime(timebuf, 99, DateTimeFormat, &_tm);
2024 struct tm* _tm = localtime(&statInfos.st_mtime);
2025 if (_tm) len = strftime(timebuf, 99, DateTimeFormat, _tm);
2028 vInfos->fileModifDate = std::string(timebuf, len);
2034void IGFD::FileManager::m_RemoveFileNameInSelection(
const std::string& vFileName) {
2035 m_SelectedFileNames.erase(vFileName);
2037 if (m_SelectedFileNames.size() == 1) {
2038 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%s", vFileName.c_str());
2040 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%zu files Selected", m_SelectedFileNames.size());
2044void IGFD::FileManager::m_m_AddFileNameInSelection(
const std::string& vFileName,
bool vSetLastSelectionFileName) {
2045 m_SelectedFileNames.emplace(vFileName);
2047 if (m_SelectedFileNames.size() == 1) {
2048 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%s", vFileName.c_str());
2050 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%zu files Selected", m_SelectedFileNames.size());
2053 if (vSetLastSelectionFileName) m_LastSelectedFileName = vFileName;
2056void IGFD::FileManager::SetCurrentDir(
const std::string& vPath) {
2057 std::string path = vPath;
2059 if (fsRoot == path) path += IGFD::Utils::GetPathSeparator();
2062 bool dir_opened = m_FileSystemPtr->IsDirectory(path);
2065 dir_opened = m_FileSystemPtr->IsDirectory(path);
2070 std::wstring wpath = IGFD::Utils::UTF8Decode(path);
2071 numchar = GetFullPathNameW(wpath.c_str(), 0,
nullptr,
nullptr);
2072 std::wstring fpath(numchar, 0);
2073 GetFullPathNameW(wpath.c_str(), numchar, (
wchar_t*)fpath.data(),
nullptr);
2074 std::string real_path = IGFD::Utils::UTF8Encode(fpath);
2075 while (real_path.back() ==
'\0')
2076 real_path = real_path.substr(0, real_path.size() - 1U);
2077 if (!real_path.empty())
2078#elif defined(_IGFD_UNIX_)
2079 char real_path[PATH_MAX];
2080 char* numchar = realpath(path.c_str(), real_path);
2081 if (numchar !=
nullptr)
2084 m_CurrentPath = std::move(real_path);
2085 if (m_CurrentPath[m_CurrentPath.size() - 1] == PATH_SEP) {
2086 m_CurrentPath = m_CurrentPath.substr(0, m_CurrentPath.size() - 1);
2088 IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
2089 m_CurrentPathDecomposition = IGFD::Utils::SplitStringToVector(m_CurrentPath, PATH_SEP,
false);
2091 m_CurrentPathDecomposition.insert(m_CurrentPathDecomposition.begin(), IGFD::Utils::GetPathSeparator());
2093 if (!m_CurrentPathDecomposition.empty()) {
2095 fsRoot = m_CurrentPathDecomposition[0];
2102bool IGFD::FileManager::CreateDir(
const std::string& vPath) {
2103 if (!vPath.empty()) {
2104 std::string path = m_CurrentPath + IGFD::Utils::GetPathSeparator() + vPath;
2105 return m_FileSystemPtr->CreateDirectoryIfNotExist(path);
2110std::string IGFD::FileManager::ComposeNewPath(std::vector<std::string>::iterator vIter) {
2116 res = *vIter + IGFD::Utils::GetPathSeparator() + res;
2117#elif defined(_IGFD_UNIX_)
2118 if (*vIter == fsRoot)
2121 res = *vIter + PATH_SEP + res;
2126 if (vIter == m_CurrentPathDecomposition.begin()) {
2128 if (res[0] != PATH_SEP) res = PATH_SEP + res;
2130 if (res.back() != PATH_SEP) res.push_back(PATH_SEP);
2141bool IGFD::FileManager::SetPathOnParentDirectoryIfAny() {
2142 if (m_CurrentPathDecomposition.size() > 1) {
2143 m_CurrentPath = ComposeNewPath(m_CurrentPathDecomposition.end() - 2);
2149std::string IGFD::FileManager::GetCurrentPath() {
2150 if (m_CurrentPath.empty()) m_CurrentPath =
".";
2151 return m_CurrentPath;
2154void IGFD::FileManager::SetCurrentPath(
const std::string& vCurrentPath) {
2155 if (vCurrentPath.empty())
2156 m_CurrentPath =
".";
2158 m_CurrentPath = vCurrentPath;
2161void IGFD::FileManager::SetDefaultFileName(
const std::string& vFileName) {
2162 dLGDefaultFileName = vFileName;
2163 IGFD::Utils::SetBuffer(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER, vFileName);
2166bool IGFD::FileManager::SelectDirectory(
const std::shared_ptr<FileInfos>& vInfos) {
2167 if (!vInfos.use_count())
return false;
2169 bool pathClick =
false;
2171 if (vInfos->fileNameExt ==
"..") {
2172 pathClick = SetPathOnParentDirectoryIfAny();
2174 std::string newPath;
2177 newPath = vInfos->fileNameExt + IGFD::Utils::GetPathSeparator();
2180 if (fsRoot == m_CurrentPath)
2181 newPath = m_CurrentPath + vInfos->fileNameExt;
2184 newPath = m_CurrentPath + IGFD::Utils::GetPathSeparator() + vInfos->fileNameExt;
2187 if (m_FileSystemPtr->IsDirectoryCanBeOpened(newPath)) {
2189 m_CurrentPath = vInfos->fileNameExt;
2190 fsRoot = m_CurrentPath;
2192 m_CurrentPath = newPath;
2201void IGFD::FileManager::SelectFileName(
const FileDialogInternal& vFileDialogInternal,
const std::shared_ptr<FileInfos>& vInfos) {
2202 if (!vInfos.use_count())
return;
2204 if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) {
2205 if (dLGcountSelectionMax == 0)
2207 if (m_SelectedFileNames.find(vInfos->fileNameExt) == m_SelectedFileNames.end())
2209 m_m_AddFileNameInSelection(vInfos->fileNameExt,
true);
2211 m_RemoveFileNameInSelection(vInfos->fileNameExt);
2215 if (m_SelectedFileNames.size() < dLGcountSelectionMax) {
2216 if (m_SelectedFileNames.find(vInfos->fileNameExt) == m_SelectedFileNames.end())
2218 m_m_AddFileNameInSelection(vInfos->fileNameExt,
true);
2220 m_RemoveFileNameInSelection(vInfos->fileNameExt);
2224 }
else if (ImGui::IsKeyDown(ImGuiMod_Shift)) {
2225 if (dLGcountSelectionMax != 1) {
2226 m_SelectedFileNames.clear();
2228 bool startMultiSelection =
false;
2229 std::string fileNameToSelect = vInfos->fileNameExt;
2230 std::string savedLastSelectedFileName;
2231 for (
const auto& file : m_FileList) {
2232 if (!file.use_count())
continue;
2234 bool canTake =
true;
2235 if (!file->SearchForTag(vFileDialogInternal.searchManager.searchTag)) canTake =
false;
2238 if (file->fileNameExt == m_LastSelectedFileName) {
2239 startMultiSelection =
true;
2240 m_m_AddFileNameInSelection(m_LastSelectedFileName,
false);
2241 }
else if (startMultiSelection) {
2242 if (dLGcountSelectionMax == 0)
2244 m_m_AddFileNameInSelection(file->fileNameExt,
false);
2246 if (m_SelectedFileNames.size() < dLGcountSelectionMax) {
2247 m_m_AddFileNameInSelection(file->fileNameExt,
false);
2249 startMultiSelection =
false;
2250 if (!savedLastSelectedFileName.empty()) m_LastSelectedFileName = savedLastSelectedFileName;
2256 if (file->fileNameExt == fileNameToSelect) {
2257 if (!startMultiSelection)
2259 savedLastSelectedFileName = m_LastSelectedFileName;
2260 m_LastSelectedFileName = fileNameToSelect;
2261 fileNameToSelect = savedLastSelectedFileName;
2262 startMultiSelection =
true;
2263 m_m_AddFileNameInSelection(m_LastSelectedFileName,
false);
2265 startMultiSelection =
false;
2266 if (!savedLastSelectedFileName.empty()) m_LastSelectedFileName = savedLastSelectedFileName;
2274 m_SelectedFileNames.clear();
2275 IGFD::Utils::ResetBuffer(fileNameBuffer);
2276 m_m_AddFileNameInSelection(vInfos->fileNameExt,
true);
2280void IGFD::FileManager::DrawDirectoryCreation(
const FileDialogInternal& vFileDialogInternal) {
2281 if (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableCreateDirectoryButton)
return;
2283 if (IMGUI_BUTTON(createDirButtonString)) {
2284 if (!m_CreateDirectoryMode) {
2285 m_CreateDirectoryMode =
true;
2286 IGFD::Utils::ResetBuffer(directoryNameBuffer);
2289 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonCreateDirString);
2291 if (m_CreateDirectoryMode) {
2294 ImGui::PushItemWidth(100.0f);
2295 ImGui::InputText(
"##DirectoryFileName", directoryNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER);
2296 ImGui::PopItemWidth();
2300 if (IMGUI_BUTTON(okButtonString)) {
2301 std::string newDir = std::string(directoryNameBuffer);
2302 if (CreateDir(newDir)) {
2303 SetCurrentPath(m_CurrentPath + IGFD::Utils::GetPathSeparator() + newDir);
2304 OpenCurrentPath(vFileDialogInternal);
2307 m_CreateDirectoryMode =
false;
2312 if (IMGUI_BUTTON(cancelButtonString)) {
2313 m_CreateDirectoryMode =
false;
2320void IGFD::FileManager::DrawPathComposer(
const FileDialogInternal& vFileDialogInternal) {
2321 if (IMGUI_BUTTON(resetButtonString)) {
2322 SetCurrentPath(
".");
2323 OpenCurrentPath(vFileDialogInternal);
2325 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonResetPathString);
2330 if (IMGUI_BUTTON(drivesButtonString)) {
2331 drivesClicked =
true;
2333 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonDriveString);
2338 if (IMGUI_BUTTON(editPathButtonString)) {
2339 inputPathActivated = !inputPathActivated;
2340 if (inputPathActivated) {
2341 if (!m_CurrentPathDecomposition.empty()) {
2342 auto endIt = m_CurrentPathDecomposition.end();
2343 m_CurrentPath = ComposeNewPath(--endIt);
2344 IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
2348 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonEditPathString);
2352 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
2355 if (!m_CurrentPathDecomposition.empty()) {
2358 if (inputPathActivated) {
2359 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
2360 ImGui::InputText(
"##pathedition", inputPathBuffer, MAX_PATH_BUFFER_SIZE);
2361 ImGui::PopItemWidth();
2364 for (
auto itPathDecomp = m_CurrentPathDecomposition.begin(); itPathDecomp != m_CurrentPathDecomposition.end(); ++itPathDecomp) {
2365 if (itPathDecomp != m_CurrentPathDecomposition.begin()) {
2366#if defined(CUSTOM_PATH_SPACING)
2367 ImGui::SameLine(0, CUSTOM_PATH_SPACING);
2371 if (!(vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableQuickPathSelection)) {
2372#if defined(_IGFD_WIN_)
2373 const char* sep =
"\\";
2374#elif defined(_IGFD_UNIX_)
2375 const char* sep =
"/";
2376 if (itPathDecomp != m_CurrentPathDecomposition.begin() + 1)
2379 ImGui::PushID(_id++);
2380 bool click = IMGUI_PATH_BUTTON(sep);
2383#if defined(CUSTOM_PATH_SPACING)
2384 ImGui::SameLine(0, CUSTOM_PATH_SPACING);
2390 m_OpenPathPopup(vFileDialogInternal, itPathDecomp - 1);
2391 }
else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
2392 m_SetCurrentPath(itPathDecomp - 1);
2399 ImGui::PushID(_id++);
2400 bool click = IMGUI_PATH_BUTTON((*itPathDecomp).c_str());
2403 m_CurrentPath = ComposeNewPath(itPathDecomp);
2404 puPathClicked =
true;
2406 }
else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
2407 m_SetCurrentPath(itPathDecomp);
2415void IGFD::FileManager::m_SetCurrentPath(std::vector<std::string>::iterator vPathIter) {
2416 m_CurrentPath = ComposeNewPath(vPathIter);
2417 IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
2418 inputPathActivated =
true;
2421std::string IGFD::FileManager::GetResultingPath() {
2422 if (dLGDirectoryMode && m_SelectedFileNames.size() == 1) {
2423 std::string selectedDirectory = fileNameBuffer;
2424 std::string path = m_CurrentPath;
2425 if (!selectedDirectory.empty() && selectedDirectory !=
".") {
2426 path += IGFD::Utils::GetPathSeparator() + selectedDirectory;
2430 return m_CurrentPath;
2433std::string IGFD::FileManager::GetResultingFileName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag) {
2434 if (!dLGDirectoryMode) {
2435 const auto& filename = std::string(fileNameBuffer);
2436 return vFileDialogInternal.filterManager.ReplaceExtentionWithCurrentFilterIfNeeded(filename, vFlag);
2441std::string IGFD::FileManager::GetResultingFilePathName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag) {
2442 if (!dLGDirectoryMode) {
2443 auto result = GetResultingPath();
2444 const auto& filename = GetResultingFileName(vFileDialogInternal, vFlag);
2445 if (!filename.empty()) {
2446 if (m_FileSystemPtr !=
nullptr && m_FileSystemPtr->IsFileExist(filename)) {
2450 if (fsRoot != result)
2453 result += IGFD::Utils::GetPathSeparator();
2464std::map<std::string, std::string> IGFD::FileManager::GetResultingSelection(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag) {
2465 std::map<std::string, std::string> res;
2466 for (
const auto& selectedFileName : m_SelectedFileNames) {
2467 auto result = GetResultingPath();
2469 if (fsRoot != result)
2472 result += IGFD::Utils::GetPathSeparator();
2474 result += vFileDialogInternal.filterManager.ReplaceExtentionWithCurrentFilterIfNeeded(selectedFileName, vFlag);
2475 res[selectedFileName] = result;
2484void IGFD::FileDialogInternal::NewFrame() {
2485 canWeContinue =
true;
2487 fileManager.drivesClicked =
false;
2488 fileManager.puPathClicked =
false;
2490 needToExitDialog =
false;
2492#ifdef USE_DIALOG_EXIT_WITH_KEY
2493 if (ImGui::IsKeyPressed(IGFD_EXIT_KEY)) {
2497 if (!(fileManager.inputPathActivated || searchManager.searchInputIsActive || fileInputIsActive || fileListViewIsActive)) {
2498 needToExitDialog =
true;
2503 searchManager.searchInputIsActive =
false;
2504 fileInputIsActive =
false;
2505 fileListViewIsActive =
false;
2509void IGFD::FileDialogInternal::EndFrame() {
2511 if (fileManager.puPathClicked) {
2512 fileManager.OpenCurrentPath(*
this);
2515 if (fileManager.drivesClicked) {
2516 if (fileManager.GetDrives()) {
2517 fileManager.ApplyFilteringOnFileList(*
this);
2521 if (fileManager.inputPathActivated) {
2522 auto gio = ImGui::GetIO();
2523 if (ImGui::IsKeyReleased(ImGuiKey_Enter)) {
2524 fileManager.SetCurrentPath(std::string(fileManager.inputPathBuffer));
2525 fileManager.OpenCurrentPath(*
this);
2526 fileManager.inputPathActivated =
false;
2528 if (ImGui::IsKeyReleased(ImGuiKey_Escape)) {
2529 fileManager.inputPathActivated =
false;
2534void IGFD::FileDialogInternal::ResetForNewDialog() {
2537void IGFD::FileDialogInternal::configureDialog(
const std::string& vKey,
const std::string& vTitle,
const char* vFilters,
const FileDialogConfig& vConfig) {
2538 m_DialogConfig = vConfig;
2539 ResetForNewDialog();
2544 if (m_DialogConfig.sidePane ==
nullptr) {
2545 m_DialogConfig.sidePaneWidth = 0.0f;
2548 if (m_DialogConfig.filePathName.empty()) {
2549 if (m_DialogConfig.path.empty()) {
2550 fileManager.dLGpath = fileManager.GetCurrentPath();
2552 fileManager.dLGpath = m_DialogConfig.path;
2554 fileManager.SetCurrentPath(m_DialogConfig.path);
2555 fileManager.dLGcountSelectionMax = (size_t)m_DialogConfig.countSelectionMax;
2556 fileManager.SetDefaultFileName(m_DialogConfig.fileName);
2558 auto ps = fileManager.GetFileSystemInstance()->ParsePathFileName(m_DialogConfig.filePathName);
2560 fileManager.dLGpath = ps.path;
2561 fileManager.SetDefaultFileName(ps.name);
2562 filterManager.dLGdefaultExt =
"." + ps.ext;
2564 fileManager.dLGpath = fileManager.GetCurrentPath();
2565 fileManager.SetDefaultFileName(
"");
2566 filterManager.dLGdefaultExt.clear();
2570 filterManager.dLGdefaultExt.clear();
2571 filterManager.ParseFilters(vFilters);
2572 filterManager.SetSelectedFilterWithExt(filterManager.dLGdefaultExt);
2573 fileManager.SetCurrentPath(fileManager.dLGpath);
2574 fileManager.dLGDirectoryMode = (vFilters ==
nullptr);
2575 fileManager.dLGcountSelectionMax = m_DialogConfig.countSelectionMax;
2576 fileManager.ClearAll();
2580const IGFD::FileDialogConfig& IGFD::FileDialogInternal::getDialogConfig()
const {
2581 return m_DialogConfig;
2584IGFD::FileDialogConfig& IGFD::FileDialogInternal::getDialogConfigRef() {
2585 return m_DialogConfig;
2596IGFD::ThumbnailFeature::ThumbnailFeature() {
2597#ifdef USE_THUMBNAILS
2598 m_DisplayMode = DisplayModeEnum::FILE_LIST;
2602IGFD::ThumbnailFeature::~ThumbnailFeature() =
default;
2604void IGFD::ThumbnailFeature::m_NewThumbnailFrame(FileDialogInternal& ) {
2605#ifdef USE_THUMBNAILS
2606 m_StartThumbnailFileDatasExtraction();
2610void IGFD::ThumbnailFeature::m_EndThumbnailFrame(FileDialogInternal& vFileDialogInternal) {
2611#ifdef USE_THUMBNAILS
2612 m_ClearThumbnails(vFileDialogInternal);
2614 (void)vFileDialogInternal;
2618void IGFD::ThumbnailFeature::m_QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal) {
2619#ifdef USE_THUMBNAILS
2620 m_StopThumbnailFileDatasExtraction();
2621 m_ClearThumbnails(vFileDialogInternal);
2623 (void)vFileDialogInternal;
2627#ifdef USE_THUMBNAILS
2628void IGFD::ThumbnailFeature::m_StartThumbnailFileDatasExtraction() {
2629 const bool res = m_ThumbnailGenerationThread.use_count() && m_ThumbnailGenerationThread->joinable();
2633 m_ThumbnailGenerationThread = std::shared_ptr<std::thread>(
new std::thread(&IGFD::ThumbnailFeature::m_ThreadThumbnailFileDatasExtractionFunc,
this), [
this](std::thread* obj) {
2634 m_IsWorking =
false;
2636 m_ThumbnailFileDatasToGetCv.notify_all();
2643bool IGFD::ThumbnailFeature::m_StopThumbnailFileDatasExtraction() {
2644 const bool res = m_ThumbnailGenerationThread.use_count() && m_ThumbnailGenerationThread->joinable();
2646 m_ThumbnailGenerationThread.reset();
2652void IGFD::ThumbnailFeature::m_ThreadThumbnailFileDatasExtractionFunc() {
2657 while (m_IsWorking) {
2658 std::unique_lock<std::mutex> thumbnailFileDatasToGetLock(m_ThumbnailFileDatasToGetMutex);
2659 m_ThumbnailFileDatasToGetCv.wait(thumbnailFileDatasToGetLock);
2660 if (!m_ThumbnailFileDatasToGet.empty()) {
2661 std::shared_ptr<FileInfos> file =
nullptr;
2663 file = (*m_ThumbnailFileDatasToGet.begin());
2664 m_ThumbnailFileDatasToGet.pop_front();
2665 thumbnailFileDatasToGetLock.unlock();
2668 if (file.use_count()) {
2669 if (file->fileType.isFile())
2672 if (file->SearchForExts(
".png,.bmp,.tga,.jpg,.jpeg,.gif,.psd,.pic,.ppm,.pgm",
true)) {
2673 auto fpn = file->filePath + IGFD::Utils::GetPathSeparator() + file->fileNameExt;
2678 uint8_t* datas = stbi_load(fpn.c_str(), &w, &h, &chans, STBI_rgb_alpha);
2682 const float ratioX = (float)w / (
float)h;
2683 const float newX = DisplayMode_ThumbailsList_ImageHeight * ratioX;
2684 float newY = w / ratioX;
2685 if (newX < w) newY = DisplayMode_ThumbailsList_ImageHeight;
2687 const auto newWidth = (int)newX;
2688 const auto newHeight = (int)newY;
2689 const auto newBufSize = (size_t)(newWidth * newHeight * 4U);
2690 auto resizedData =
new uint8_t[newBufSize];
2692 const int resizeSucceeded = stbir_resize_uint8(datas, w, h, 0, resizedData, newWidth, newHeight, 0,
2695 if (resizeSucceeded) {
2696 auto th = &file->thumbnailInfo;
2698 th->textureFileDatas = resizedData;
2699 th->textureWidth = newWidth;
2700 th->textureHeight = newHeight;
2701 th->textureChannels = 4;
2705 th->isReadyToUpload =
true;
2708 m_AddThumbnailToCreate(file);
2711 printf(
"image loading fail : w:%i h:%i c:%i\n", w, h, 4);
2714 stbi_image_free(datas);
2720 thumbnailFileDatasToGetLock.unlock();
2725void IGFD::ThumbnailFeature::m_VariadicProgressBar(
float fraction,
const ImVec2& size_arg,
const char* fmt, ...) {
2727 va_start(args, fmt);
2728 char TempBuffer[512];
2729 const int w = vsnprintf(TempBuffer, 511, fmt, args);
2732 ImGui::ProgressBar(fraction, size_arg, TempBuffer);
2736void IGFD::ThumbnailFeature::m_DrawThumbnailGenerationProgress() {
2737 if (m_ThumbnailGenerationThread.use_count() && m_ThumbnailGenerationThread->joinable()) {
2738 if (!m_ThumbnailFileDatasToGet.empty()) {
2739 const auto p = (float)((
double)m_CountFiles / (double)m_ThumbnailFileDatasToGet.size());
2740 m_VariadicProgressBar(p, ImVec2(50, 0),
"%u/%u", m_CountFiles,
2741 (uint32_t)m_ThumbnailFileDatasToGet.size());
2747void IGFD::ThumbnailFeature::m_AddThumbnailToLoad(
const std::shared_ptr<FileInfos>& vFileInfos) {
2748 if (vFileInfos.use_count()) {
2749 if (vFileInfos->fileType.isFile()) {
2751 if (vFileInfos->SearchForExts(
".png,.bmp,.tga,.jpg,.jpeg,.gif,.psd,.pic,.ppm,.pgm",
true)) {
2753 m_ThumbnailFileDatasToGetMutex.lock();
2754 m_ThumbnailFileDatasToGet.push_back(vFileInfos);
2755 vFileInfos->thumbnailInfo.isLoadingOrLoaded =
true;
2756 m_ThumbnailFileDatasToGetMutex.unlock();
2757 m_ThumbnailFileDatasToGetCv.notify_all();
2763void IGFD::ThumbnailFeature::m_AddThumbnailToCreate(
const std::shared_ptr<FileInfos>& vFileInfos) {
2764 if (vFileInfos.use_count()) {
2766 m_ThumbnailToCreateMutex.lock();
2767 m_ThumbnailToCreate.push_back(vFileInfos);
2768 m_ThumbnailToCreateMutex.unlock();
2772void IGFD::ThumbnailFeature::m_AddThumbnailToDestroy(
const IGFD_Thumbnail_Info& vIGFD_Thumbnail_Info) {
2774 m_ThumbnailToDestroyMutex.lock();
2775 m_ThumbnailToDestroy.push_back(vIGFD_Thumbnail_Info);
2776 m_ThumbnailToDestroyMutex.unlock();
2779void IGFD::ThumbnailFeature::m_DrawDisplayModeToolBar() {
2780 if (IMGUI_RADIO_BUTTON(DisplayMode_FilesList_ButtonString, m_DisplayMode == DisplayModeEnum::FILE_LIST)) m_DisplayMode = DisplayModeEnum::FILE_LIST;
2781 if (ImGui::IsItemHovered()) ImGui::SetTooltip(DisplayMode_FilesList_ButtonHelp);
2783 if (IMGUI_RADIO_BUTTON(DisplayMode_ThumbailsList_ButtonString, m_DisplayMode == DisplayModeEnum::THUMBNAILS_LIST)) m_DisplayMode = DisplayModeEnum::THUMBNAILS_LIST;
2784 if (ImGui::IsItemHovered()) ImGui::SetTooltip(DisplayMode_ThumbailsList_ButtonHelp);
2793 m_DrawThumbnailGenerationProgress();
2796void IGFD::ThumbnailFeature::m_ClearThumbnails(FileDialogInternal& vFileDialogInternal) {
2798 if (vFileDialogInternal.fileManager.puPathClicked) {
2799 size_t count = vFileDialogInternal.fileManager.GetFullFileListSize();
2800 for (
size_t idx = 0U; idx <
count; idx++) {
2801 auto file = vFileDialogInternal.fileManager.GetFullFileAt(idx);
2802 if (file.use_count()) {
2803 if (file->thumbnailInfo.isReadyToDisplay)
2805 m_AddThumbnailToDestroy(file->thumbnailInfo);
2812void IGFD::ThumbnailFeature::SetCreateThumbnailCallback(
const CreateThumbnailFun& vCreateThumbnailFun) {
2813 m_CreateThumbnailFun = vCreateThumbnailFun;
2816void IGFD::ThumbnailFeature::SetDestroyThumbnailCallback(
const DestroyThumbnailFun& vCreateThumbnailFun) {
2817 m_DestroyThumbnailFun = vCreateThumbnailFun;
2820void IGFD::ThumbnailFeature::ManageGPUThumbnails() {
2821 if (m_CreateThumbnailFun) {
2822 m_ThumbnailToCreateMutex.lock();
2823 if (!m_ThumbnailToCreate.empty()) {
2824 for (
const auto& file : m_ThumbnailToCreate) {
2825 if (file.use_count()) {
2826 m_CreateThumbnailFun(&file->thumbnailInfo);
2829 m_ThumbnailToCreate.clear();
2831 m_ThumbnailToCreateMutex.unlock();
2834 "No Callback found for create texture\nYou need to define the callback with a call to "
2835 "SetCreateThumbnailCallback\n");
2838 if (m_DestroyThumbnailFun) {
2839 m_ThumbnailToDestroyMutex.lock();
2840 if (!m_ThumbnailToDestroy.empty()) {
2841 for (
auto thumbnail : m_ThumbnailToDestroy) {
2842 m_DestroyThumbnailFun(&thumbnail);
2844 m_ThumbnailToDestroy.clear();
2846 m_ThumbnailToDestroyMutex.unlock();
2849 "No Callback found for destroy texture\nYou need to define the callback with a call to "
2850 "SetCreateThumbnailCallback\n");
2860IGFD::BookMarkFeature::BookMarkFeature() {
2862 m_BookmarkWidth = defaultBookmarkPaneWith;
2867void IGFD::BookMarkFeature::m_DrawBookmarkButton() {
2868 IMGUI_TOGGLE_BUTTON(bookmarksButtonString, &m_BookmarkPaneShown);
2870 if (ImGui::IsItemHovered()) ImGui::SetTooltip(bookmarksButtonHelpString);
2873bool IGFD::BookMarkFeature::m_DrawBookmarkPane(FileDialogInternal& vFileDialogInternal,
const ImVec2& vSize) {
2876 ImGui::BeginChild(
"##bookmarkpane", vSize);
2878 static int selectedBookmarkForEdition = -1;
2880 if (IMGUI_BUTTON(addBookmarkButtonString
"##ImGuiFileDialogAddBookmark")) {
2881 if (!vFileDialogInternal.fileManager.IsComposerEmpty()) {
2882 BookmarkStruct bookmark;
2883 bookmark.name = vFileDialogInternal.fileManager.GetBack();
2884 bookmark.path = vFileDialogInternal.fileManager.GetCurrentPath();
2885 m_Bookmarks.push_back(bookmark);
2888 if (selectedBookmarkForEdition >= 0 && selectedBookmarkForEdition < (
int)m_Bookmarks.size()) {
2890 if (IMGUI_BUTTON(removeBookmarkButtonString
"##ImGuiFileDialogAddBookmark")) {
2891 m_Bookmarks.erase(m_Bookmarks.begin() + selectedBookmarkForEdition);
2892 if (selectedBookmarkForEdition == (
int)m_Bookmarks.size()) selectedBookmarkForEdition--;
2895 if (selectedBookmarkForEdition >= 0 && selectedBookmarkForEdition < (
int)m_Bookmarks.size()) {
2898 ImGui::PushItemWidth(vSize.x - ImGui::GetCursorPosX());
2899 if (ImGui::InputText(
"##ImGuiFileDialogBookmarkEdit", m_BookmarkEditBuffer, MAX_FILE_DIALOG_NAME_BUFFER)) {
2900 m_Bookmarks[(size_t)selectedBookmarkForEdition].name = std::string(m_BookmarkEditBuffer);
2902 ImGui::PopItemWidth();
2908 if (!m_Bookmarks.empty()) {
2909 m_BookmarkClipper.Begin((
int)m_Bookmarks.size(), ImGui::GetTextLineHeightWithSpacing());
2910 while (m_BookmarkClipper.Step()) {
2911 for (
int i = m_BookmarkClipper.DisplayStart; i < m_BookmarkClipper.DisplayEnd; i++) {
2912 if (i < 0)
continue;
2913 const BookmarkStruct& bookmark = m_Bookmarks[(size_t)i];
2915 if (ImGui::Selectable(bookmark.name.c_str(), selectedBookmarkForEdition == i,
2916 ImGuiSelectableFlags_AllowDoubleClick) ||
2917 (selectedBookmarkForEdition == -1 && bookmark.path == vFileDialogInternal.fileManager.GetCurrentPath()))
2919 selectedBookmarkForEdition = i;
2920 IGFD::Utils::ResetBuffer(m_BookmarkEditBuffer);
2921 IGFD::Utils::AppendToBuffer(m_BookmarkEditBuffer, MAX_FILE_DIALOG_NAME_BUFFER, bookmark.name);
2923 if (ImGui::IsMouseDoubleClicked(0))
2925 vFileDialogInternal.fileManager.SetCurrentPath(bookmark.path);
2926 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
2931 if (ImGui::IsItemHovered()) ImGui::SetTooltip(
"%s", bookmark.path.c_str());
2934 m_BookmarkClipper.End();
2942std::string IGFD::BookMarkFeature::SerializeBookmarks(
const bool& vDontSerializeCodeBasedBookmarks) {
2946 for (
auto& it : m_Bookmarks) {
2947 if (vDontSerializeCodeBasedBookmarks && it.defined_by_code)
continue;
2949 if (idx++ != 0) res +=
"##";
2951 res += it.name +
"##" + it.path;
2957void IGFD::BookMarkFeature::DeserializeBookmarks(
const std::string& vBookmarks) {
2958 if (!vBookmarks.empty()) {
2959 m_Bookmarks.clear();
2960 auto arr = IGFD::Utils::SplitStringToVector(vBookmarks,
'#',
false);
2961 for (
size_t i = 0; i < arr.size(); i += 2) {
2962 if (i + 1 < arr.size())
2964 BookmarkStruct bookmark;
2965 bookmark.name = arr[i];
2967 bookmark.path = arr[i + 1];
2968 m_Bookmarks.push_back(bookmark);
2974void IGFD::BookMarkFeature::AddBookmark(
const std::string& vBookMarkName,
const std::string& vBookMarkPath) {
2975 if (vBookMarkName.empty() || vBookMarkPath.empty())
return;
2977 BookmarkStruct bookmark;
2978 bookmark.name = vBookMarkName;
2979 bookmark.path = vBookMarkPath;
2980 bookmark.defined_by_code =
true;
2981 m_Bookmarks.push_back(bookmark);
2984bool IGFD::BookMarkFeature::RemoveBookmark(
const std::string& vBookMarkName) {
2985 if (vBookMarkName.empty())
return false;
2987 for (
auto bookmark_it = m_Bookmarks.begin(); bookmark_it != m_Bookmarks.end(); ++bookmark_it) {
2988 if ((*bookmark_it).name == vBookMarkName) {
2989 m_Bookmarks.erase(bookmark_it);
3002IGFD::KeyExplorerFeature::KeyExplorerFeature() =
default;
3004#ifdef USE_EXPLORATION_BY_KEYS
3005bool IGFD::KeyExplorerFeature::m_LocateItem_Loop(FileDialogInternal& vFileDialogInternal, ImWchar vC) {
3008 auto& fdi = vFileDialogInternal.fileManager;
3009 if (!fdi.IsFilteredListEmpty()) {
3010 auto countFiles = fdi.GetFilteredListSize();
3011 for (
size_t i = m_LocateFileByInputChar_lastFileIdx; i < countFiles; i++) {
3012 auto nfo = fdi.GetFilteredFileAt(i);
3013 if (nfo.use_count()) {
3014 if (nfo->fileNameExt_optimized[0] == vC ||
3015 nfo->fileNameExt[0] == vC)
3018 float p = (float)((
double)i / (double)countFiles) * ImGui::GetScrollMaxY();
3019 ImGui::SetScrollY(p);
3020 m_LocateFileByInputChar_lastFound =
true;
3021 m_LocateFileByInputChar_lastFileIdx = i;
3022 m_StartFlashItem(m_LocateFileByInputChar_lastFileIdx);
3024 auto infos = fdi.GetFilteredFileAt(m_LocateFileByInputChar_lastFileIdx);
3025 if (infos.use_count()) {
3026 if (infos->fileType.isDir())
3028 if (fdi.dLGDirectoryMode)
3030 fdi.SelectFileName(vFileDialogInternal, infos);
3033 fdi.SelectFileName(vFileDialogInternal, infos);
3047void IGFD::KeyExplorerFeature::m_LocateByInputKey(FileDialogInternal& vFileDialogInternal) {
3049 auto& fdi = vFileDialogInternal.fileManager;
3050 if (!
g.ActiveId && !fdi.IsFilteredListEmpty()) {
3051 auto& queueChar = ImGui::GetIO().InputQueueCharacters;
3052 auto countFiles = fdi.GetFilteredListSize();
3055 if (!queueChar.empty()) {
3056 ImWchar c = queueChar.back();
3057 if (m_LocateFileByInputChar_InputQueueCharactersSize != queueChar.size()) {
3058 if (c == m_LocateFileByInputChar_lastChar)
3060 if (m_LocateFileByInputChar_lastFileIdx < countFiles - 1U)
3061 m_LocateFileByInputChar_lastFileIdx++;
3063 m_LocateFileByInputChar_lastFileIdx = 0;
3066 if (!m_LocateItem_Loop(vFileDialogInternal, c)) {
3068 m_LocateFileByInputChar_lastFileIdx = 0;
3069 m_LocateItem_Loop(vFileDialogInternal, c);
3072 m_LocateFileByInputChar_lastChar = c;
3076 m_LocateFileByInputChar_InputQueueCharactersSize = queueChar.size();
3080void IGFD::KeyExplorerFeature::m_ExploreWithkeys(FileDialogInternal& vFileDialogInternal, ImGuiID vListViewID) {
3081 auto& fdi = vFileDialogInternal.fileManager;
3082 if (!fdi.IsFilteredListEmpty()) {
3083 bool canWeExplore =
false;
3084 bool hasNav = (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
3087 if (!hasNav && !
g.ActiveId)
3088 canWeExplore =
true;
3090 if (
g.NavId &&
g.NavId == vListViewID) {
3091 if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter) || ImGui::IsKeyPressed(ImGuiKey_Space)) {
3092 ImGui::ActivateItemByID(vListViewID);
3093 ImGui::SetActiveID(vListViewID,
g.CurrentWindow);
3097 if (vListViewID ==
g.LastActiveId - 1)
3098 canWeExplore =
true;
3100 if (canWeExplore && ImGui::IsWindowFocused()) {
3101 if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
3102 ImGui::ClearActiveID();
3106 auto countFiles = fdi.GetFilteredListSize();
3109 bool exploreByKey =
false;
3110 bool enterInDirectory =
false;
3111 bool exitDirectory =
false;
3113 if ((hasNav && ImGui::IsKeyPressed(ImGuiKey_UpArrow)) || (!hasNav && ImGui::IsKeyPressed(ImGuiKey_UpArrow))) {
3114 exploreByKey =
true;
3115 if (m_LocateFileByInputChar_lastFileIdx > 0)
3116 m_LocateFileByInputChar_lastFileIdx--;
3118 m_LocateFileByInputChar_lastFileIdx = countFiles - 1U;
3119 }
else if ((hasNav && ImGui::IsKeyPressed(ImGuiKey_DownArrow)) || (!hasNav && ImGui::IsKeyPressed(ImGuiKey_DownArrow))) {
3120 exploreByKey =
true;
3121 if (m_LocateFileByInputChar_lastFileIdx < countFiles - 1U)
3122 m_LocateFileByInputChar_lastFileIdx++;
3124 m_LocateFileByInputChar_lastFileIdx = 0U;
3125 }
else if (ImGui::IsKeyReleased(ImGuiKey_Enter)) {
3126 exploreByKey =
true;
3127 enterInDirectory =
true;
3128 }
else if (ImGui::IsKeyReleased(ImGuiKey_Backspace)) {
3129 exploreByKey =
true;
3130 exitDirectory =
true;
3135 float p = (float)((
double)m_LocateFileByInputChar_lastFileIdx / (double)(countFiles - 1U)) * ImGui::GetScrollMaxY();
3137 ImGui::SetScrollY(p);
3138 m_StartFlashItem(m_LocateFileByInputChar_lastFileIdx);
3140 auto infos = fdi.GetFilteredFileAt(m_LocateFileByInputChar_lastFileIdx);
3141 if (infos.use_count()) {
3142 if (infos->fileType.isDir())
3144 if (!fdi.dLGDirectoryMode || enterInDirectory) {
3145 if (enterInDirectory) {
3146 if (fdi.SelectDirectory(infos)) {
3148 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
3149 if (m_LocateFileByInputChar_lastFileIdx > countFiles - 1U) {
3150 m_LocateFileByInputChar_lastFileIdx = 0;
3156 fdi.SelectFileName(vFileDialogInternal, infos);
3159 fdi.SelectFileName(vFileDialogInternal, infos);
3161 if (enterInDirectory) {
3162 vFileDialogInternal.isOk =
true;
3166 if (exitDirectory) {
3167 auto nfo = std::make_shared<FileInfos>();
3168 nfo->fileNameExt =
"..";
3170 if (fdi.SelectDirectory(nfo)) {
3172 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
3173 if (m_LocateFileByInputChar_lastFileIdx > countFiles - 1U) {
3174 m_LocateFileByInputChar_lastFileIdx = 0;
3179 if (fdi.GetComposerSize() == 1U) {
3180 if (fdi.GetDrives()) {
3181 fdi.ApplyFilteringOnFileList(vFileDialogInternal);
3193bool IGFD::KeyExplorerFeature::m_FlashableSelectable(
const char* label,
bool selected, ImGuiSelectableFlags flags,
bool vFlashing,
const ImVec2& size_arg) {
3194 using namespace ImGui;
3196 ImGuiWindow* window = GetCurrentWindow();
3197 if (window->SkipItems)
return false;
3200 const ImGuiStyle& style =
g.Style;
3203 ImGuiID
id = window->GetID(label);
3205 ImVec2
size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
3206 ImVec2 pos = window->DC.CursorPos;
3207 pos.y += window->DC.CurrLineTextBaseOffset;
3208 ItemSize(size, 0.0f);
3213 const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0;
3214 const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x;
3215 const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
3216 if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth))
size.x = ImMax(label_size.x, max_x - min_x);
3219 const ImVec2 text_min = pos;
3220 const ImVec2 text_max(min_x +
size.x, pos.y +
size.y);
3223 ImRect bb(min_x, pos.y, text_max.x, text_max.y);
3224 if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) {
3225 const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x;
3226 const float spacing_y = style.ItemSpacing.y;
3227 const float spacing_L = IM_TRUNC(spacing_x * 0.50f);
3228 const float spacing_U = IM_TRUNC(spacing_y * 0.50f);
3229 bb.Min.x -= spacing_L;
3230 bb.Min.y -= spacing_U;
3231 bb.Max.x += (spacing_x - spacing_L);
3232 bb.Max.y += (spacing_y - spacing_U);
3237 const float backup_clip_rect_min_x = window->ClipRect.Min.x;
3238 const float backup_clip_rect_max_x = window->ClipRect.Max.x;
3239 if (span_all_columns) {
3240 window->ClipRect.Min.x = window->ParentWorkRect.Min.x;
3241 window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
3244 const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
3245 const bool item_add = ItemAdd(bb,
id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None);
3246 if (span_all_columns) {
3247 window->ClipRect.Min.x = backup_clip_rect_min_x;
3248 window->ClipRect.Max.x = backup_clip_rect_max_x;
3251 if (!item_add)
return false;
3253 const bool disabled_global = (
g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
3254 if (disabled_item && !disabled_global)
3259 if (span_all_columns && window->DC.CurrentColumns)
3260 PushColumnsBackground();
3261 else if (span_all_columns &&
g.CurrentTable)
3262 TablePushBackgroundChannel();
3265 ImGuiButtonFlags button_flags = 0;
3266 if (flags & ImGuiSelectableFlags_NoHoldingActiveID) {
3267 button_flags |= ImGuiButtonFlags_NoHoldingActiveId;
3269 if (flags & ImGuiSelectableFlags_NoSetKeyOwner) {
3270 button_flags |= ImGuiButtonFlags_NoSetKeyOwner;
3272 if (flags & ImGuiSelectableFlags_SelectOnClick) {
3273 button_flags |= ImGuiButtonFlags_PressedOnClick;
3275 if (flags & ImGuiSelectableFlags_SelectOnRelease) {
3276 button_flags |= ImGuiButtonFlags_PressedOnRelease;
3278 if (flags & ImGuiSelectableFlags_AllowDoubleClick) {
3279 button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
3281 if ((flags & ImGuiSelectableFlags_AllowOverlap) || (
g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) {
3282 button_flags |= ImGuiButtonFlags_AllowOverlap;
3285 const bool was_selected = selected;
3287 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, button_flags);
3296 if ((flags & ImGuiSelectableFlags_SelectOnNav) &&
g.NavJustMovedToId != 0 &&
g.NavJustMovedToFocusScopeId ==
g.CurrentFocusScopeId)
3297 if (
g.NavJustMovedToId ==
id) selected = pressed =
true;
3300 if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) {
3301 if (!
g.NavDisableMouseHover &&
g.NavWindow == window &&
g.NavLayer == window->DC.NavLayerCurrent) {
3302 SetNavID(
id, window->DC.NavLayerCurrent,
g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb));
3303 g.NavDisableHighlight =
true;
3306 if (pressed) MarkItemEdited(
id);
3309 if (selected != was_selected)
3310 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
3314 hovered |= vFlashing;
3318 if (hovered || selected) {
3319 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
3320 RenderFrame(bb.Min, bb.Max, col,
false, 0.0f);
3322 if (
g.NavId ==
id) RenderNavHighlight(bb,
id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
3324 if (span_all_columns && window->DC.CurrentColumns)
3325 PopColumnsBackground();
3326 else if (span_all_columns &&
g.CurrentTable)
3327 TablePopBackgroundChannel();
3329 RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
3332 if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(
g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup)) CloseCurrentPopup();
3334 if (disabled_item && !disabled_global) EndDisabled();
3336 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags);
3340void IGFD::KeyExplorerFeature::m_StartFlashItem(
size_t vIdx) {
3341 m_FlashAlpha = 1.0f;
3342 m_FlashedItem = vIdx;
3345bool IGFD::KeyExplorerFeature::m_BeginFlashItem(
size_t vIdx) {
3348 if (m_FlashedItem == vIdx && std::abs(m_FlashAlpha - 0.0f) > 0.00001f) {
3349 m_FlashAlpha -= m_FlashAlphaAttenInSecs * ImGui::GetIO().DeltaTime;
3350 if (m_FlashAlpha < 0.0f) m_FlashAlpha = 0.0f;
3352 ImVec4 hov = ImGui::GetStyleColorVec4(ImGuiCol_HeaderHovered);
3353 hov.w = m_FlashAlpha;
3354 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hov);
3361void IGFD::KeyExplorerFeature::m_EndFlashItem() {
3362 ImGui::PopStyleColor();
3365void IGFD::KeyExplorerFeature::SetFlashingAttenuationInSeconds(
float vAttenValue) {
3366 m_FlashAlphaAttenInSecs = 1.0f / ImMax(vAttenValue, 0.01f);
3376IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {
3378IGFD::FileDialog::~FileDialog() =
default;
3385void IGFD::FileDialog::OpenDialog(
const std::string& vKey,
const std::string& vTitle,
const char* vFilters,
const FileDialogConfig& vConfig) {
3386 if (m_FileDialogInternal.showDialog)
3388 m_FileDialogInternal.configureDialog(vKey, vTitle, vFilters, vConfig);
3395bool IGFD::FileDialog::Display(
const std::string& vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize) {
3398 if (m_FileDialogInternal.showDialog && m_FileDialogInternal.dLGkey == vKey) {
3399 if (m_FileDialogInternal.puUseCustomLocale) setlocale(m_FileDialogInternal.localeCategory, m_FileDialogInternal.localeBegin.c_str());
3401 auto& fdFile = m_FileDialogInternal.fileManager;
3402 auto& fdFilter = m_FileDialogInternal.filterManager;
3404 static ImGuiWindowFlags flags;
3408 if (
g.FrameCount == m_FileDialogInternal.lastImGuiFrameCount)
3411 m_FileDialogInternal.lastImGuiFrameCount =
g.FrameCount;
3413 std::string name = m_FileDialogInternal.dLGtitle +
"##" + m_FileDialogInternal.dLGkey;
3414 if (m_FileDialogInternal.name != name) {
3415 fdFile.ClearComposer();
3416 fdFile.ClearFileLists();
3422#ifdef IMGUI_HAS_VIEWPORT
3423 if (!ImGui::GetIO().ConfigViewportsNoDecoration) {
3425 ImGuiWindowClass window_class;
3426 window_class.ViewportFlagsOverrideClear = ImGuiViewportFlags_NoDecoration;
3427 ImGui::SetNextWindowClass(&window_class);
3432 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_NoDialog)
3436 ImGui::SetNextWindowSizeConstraints(vMinSize, vMaxSize);
3438 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_Modal && !m_FileDialogInternal.okResultToConfirm)
3441 ImGui::OpenPopup(name.c_str());
3442 beg = ImGui::BeginPopupModal(name.c_str(), (
bool*)
nullptr, flags | ImGuiWindowFlags_NoScrollbar);
3444 beg = ImGui::Begin(name.c_str(), (
bool*)
nullptr, flags | ImGuiWindowFlags_NoScrollbar);
3448#ifdef IMGUI_HAS_VIEWPORT
3450 if (ImGui::GetIO().ConfigViewportsNoDecoration) {
3453 auto win = ImGui::GetCurrentWindowRead();
3454 if (win->Viewport->Idx != 0)
3455 flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar;
3461 ImGuiID _frameId = ImGui::GetID(name.c_str());
3462 ImVec2 frameSize = ImVec2(0, 0);
3463 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_NoDialog) frameSize = vMaxSize;
3464 if (ImGui::BeginChild(_frameId, frameSize,
false, flags | ImGuiWindowFlags_NoScrollbar)) {
3465 m_FileDialogInternal.name = name;
3467 if (fdFile.dLGpath.empty()) fdFile.dLGpath =
".";
3469 fdFilter.SetDefaultFilterIfNotDefined();
3472 if (fdFile.IsFileListEmpty() && !fdFile.showDrives) {
3473 if (fdFile.dLGpath !=
".")
3474 IGFD::Utils::ReplaceString(fdFile.dLGDefaultFileName, fdFile.dLGpath,
"");
3476 if (!fdFile.dLGDefaultFileName.empty()) {
3477 fdFile.SetDefaultFileName(fdFile.dLGDefaultFileName);
3478 fdFilter.SetSelectedFilterWithExt(fdFilter.dLGdefaultExt);
3479 }
else if (fdFile.dLGDirectoryMode)
3480 fdFile.SetDefaultFileName(
".");
3481 fdFile.ScanDir(m_FileDialogInternal, fdFile.dLGpath);
3487 res = m_DrawFooter();
3494 m_FileDialogInternal.dialogCenterPos = ImGui::GetCurrentWindowRead()->ContentRegionRect.GetCenter();
3499 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_Modal && !m_FileDialogInternal.okResultToConfirm) {
3504 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_NoDialog) {
3507 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_Modal) || m_FileDialogInternal.okResultToConfirm) {
3512 res = m_Confirm_Or_OpenOverWriteFileDialog_IfNeeded(res, vFlags);
3514 if (m_FileDialogInternal.puUseCustomLocale) setlocale(m_FileDialogInternal.localeCategory, m_FileDialogInternal.localeEnd.c_str());
3520void IGFD::FileDialog::m_NewFrame() {
3521 m_FileDialogInternal.NewFrame();
3522 m_NewThumbnailFrame(m_FileDialogInternal);
3525void IGFD::FileDialog::m_EndFrame() {
3526 m_EndThumbnailFrame(m_FileDialogInternal);
3527 m_FileDialogInternal.EndFrame();
3529void IGFD::FileDialog::m_QuitFrame() {
3530 m_QuitThumbnailFrame(m_FileDialogInternal);
3533void IGFD::FileDialog::m_DrawHeader() {
3535 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableBookmarkMode)) {
3536 m_DrawBookmarkButton();
3542 m_FileDialogInternal.fileManager.DrawDirectoryCreation(m_FileDialogInternal);
3546 !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableBookmarkMode) ||
3548 !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableCreateDirectoryButton)) {
3549 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
3552 m_FileDialogInternal.fileManager.DrawPathComposer(m_FileDialogInternal);
3554#ifdef USE_THUMBNAILS
3555 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableThumbnailMode)) {
3556 m_DrawDisplayModeToolBar();
3558 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
3563 m_FileDialogInternal.searchManager.DrawSearchBar(m_FileDialogInternal);
3566void IGFD::FileDialog::m_DrawContent() {
3567 ImVec2
size = ImGui::GetContentRegionAvail() - ImVec2(0.0f, m_FileDialogInternal.footerHeight);
3570 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableBookmarkMode)) {
3571 if (m_BookmarkPaneShown) {
3573 float otherWidth =
size.x - m_BookmarkWidth;
3574 ImGui::PushID(
"##splitterbookmark");
3575 IGFD::Utils::ImSplitter(
true, 4.0f, &m_BookmarkWidth, &otherWidth, 10.0f, 10.0f + m_FileDialogInternal.getDialogConfig().sidePaneWidth,
size.y);
3577 size.x -= otherWidth;
3578 m_DrawBookmarkPane(m_FileDialogInternal, size);
3584 size.x = ImGui::GetContentRegionAvail().x - m_FileDialogInternal.getDialogConfig().sidePaneWidth;
3586 if (m_FileDialogInternal.getDialogConfig().sidePane) {
3587 ImGui::PushID(
"##splittersidepane");
3588 IGFD::Utils::ImSplitter(
true, 4.0f, &
size.x, &m_FileDialogInternal.getDialogConfigRef().sidePaneWidth, 10.0f, 10.0f,
size.y);
3592#ifdef USE_THUMBNAILS
3593 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableThumbnailMode) {
3594 m_DrawFileListView(size);
3596 switch (m_DisplayMode) {
3597 case DisplayModeEnum::FILE_LIST: m_DrawFileListView(size);
break;
3598 case DisplayModeEnum::THUMBNAILS_LIST: m_DrawThumbnailsListView(size);
break;
3599 case DisplayModeEnum::THUMBNAILS_GRID: m_DrawThumbnailsGridView(size);
3603 m_DrawFileListView(size);
3606 if (m_FileDialogInternal.getDialogConfig().sidePane) {
3607 m_DrawSidePane(
size.y);
3610 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableQuickPathSelection)) {
3611 m_DisplayPathPopup(size);
3615void IGFD::FileDialog::m_DisplayPathPopup(ImVec2 vSize) {
3616 ImVec2
size = ImVec2(vSize.x * 0.5f, vSize.y * 0.5f);
3617 if (ImGui::BeginPopup(
"IGFD_Path_Popup")) {
3618 auto& fdi = m_FileDialogInternal.fileManager;
3620 ImGui::PushID(
this);
3622 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY;
3623 auto listViewID = ImGui::GetID(
"##FileDialog_pathTable");
3624 if (ImGui::BeginTableEx(
"##FileDialog_pathTable", listViewID, 1, flags, size, 0.0f))
3626 ImGui::TableSetupScrollFreeze(0, 1);
3627 ImGui::TableSetupColumn(tableHeaderFileNameString, ImGuiTableColumnFlags_WidthStretch | (defaultSortOrderFilename ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 0);
3629 ImGui::TableHeadersRow();
3631 if (!fdi.IsPathFilteredListEmpty()) {
3633 ImFont* _font =
nullptr;
3634 bool _showColor =
false;
3636 m_PathListClipper.Begin((
int)fdi.GetPathFilteredListSize(), ImGui::GetTextLineHeightWithSpacing());
3637 while (m_PathListClipper.Step()) {
3638 for (
int i = m_PathListClipper.DisplayStart; i < m_PathListClipper.DisplayEnd; i++) {
3639 if (i < 0)
continue;
3641 auto infos = fdi.GetFilteredPathAt((
size_t)i);
3642 if (!infos.use_count())
continue;
3644 m_BeginFileColorIconStyle(infos, _showColor, _str, &_font);
3646 bool selected = fdi.IsFileNameSelected(infos->fileNameExt);
3648 ImGui::TableNextRow();
3650 if (ImGui::TableNextColumn())
3652 if (ImGui::Selectable(infos->fileNameExt.c_str(), &selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth)) {
3653 fdi.SetCurrentPath(fdi.ComposeNewPath(fdi.GetCurrentPopupComposedPath()));
3654 fdi.puPathClicked = fdi.SelectDirectory(infos);
3655 ImGui::CloseCurrentPopup();
3659 m_EndFileColorIconStyle(_showColor, _font);
3662 m_PathListClipper.End();
3674bool IGFD::FileDialog::m_DrawOkButton() {
3675 auto& fdFile = m_FileDialogInternal.fileManager;
3676 if (m_FileDialogInternal.canWeContinue && strlen(fdFile.fileNameBuffer)) {
3677 if (IMGUI_BUTTON(okButtonString
"##validationdialog", ImVec2(okButtonWidth, 0.0f)) || m_FileDialogInternal.isOk) {
3678 m_FileDialogInternal.isOk =
true;
3682#if !invertOkAndCancelButtons
3690bool IGFD::FileDialog::m_DrawCancelButton() {
3691 if (IMGUI_BUTTON(cancelButtonString
"##validationdialog", ImVec2(cancelButtonWidth, 0.0f)) || m_FileDialogInternal.needToExitDialog)
3693 m_FileDialogInternal.isOk =
false;
3697#if invertOkAndCancelButtons
3704bool IGFD::FileDialog::m_DrawValidationButtons() {
3707 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (ImGui::GetContentRegionAvail().x - prOkCancelButtonWidth) * okCancelButtonAlignement);
3709 ImGui::BeginGroup();
3711 if (invertOkAndCancelButtons) {
3712 res |= m_DrawCancelButton();
3713 res |= m_DrawOkButton();
3715 res |= m_DrawOkButton();
3716 res |= m_DrawCancelButton();
3721 prOkCancelButtonWidth = ImGui::GetItemRectSize().x;
3726bool IGFD::FileDialog::m_DrawFooter() {
3727 auto& fdFile = m_FileDialogInternal.fileManager;
3729 float posY = ImGui::GetCursorPos().y;
3730 ImGui::AlignTextToFramePadding();
3731 if (!fdFile.dLGDirectoryMode)
3732 ImGui::Text(fileNameString);
3734 ImGui::Text(dirNameString);
3738 float width = ImGui::GetContentRegionAvail().x;
3739 if (!fdFile.dLGDirectoryMode) {
3741 width -= m_FileDialogInternal.filterManager.GetFilterComboBoxWidth() +
g.Style.ItemSpacing.x;
3744 ImGui::PushItemWidth(width);
3745 ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
3746 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_ReadOnlyFileNameField) {
3747 flags |= ImGuiInputTextFlags_ReadOnly;
3749 if (ImGui::InputText(
"##FileName", fdFile.fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER, flags)) {
3750 m_FileDialogInternal.isOk =
true;
3752 if (ImGui::GetItemID() == ImGui::GetActiveID()) m_FileDialogInternal.fileInputIsActive =
true;
3753 ImGui::PopItemWidth();
3756 m_FileDialogInternal.filterManager.DrawFilterComboBox(m_FileDialogInternal);
3758 bool res = m_DrawValidationButtons();
3759 m_FileDialogInternal.footerHeight = ImGui::GetCursorPosY() - posY;
3763void IGFD::FileDialog::m_SelectableItem(
int vidx, std::shared_ptr<FileInfos> vInfos,
bool vSelected,
const char* vFmt, ...) {
3764 if (!vInfos.use_count())
return;
3766 auto& fdi = m_FileDialogInternal.fileManager;
3768 static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth;
3771 va_start(args, vFmt);
3772 vsnprintf(fdi.variadicBuffer, MAX_FILE_DIALOG_NAME_BUFFER, vFmt, args);
3776#ifdef USE_THUMBNAILS
3777 if (m_DisplayMode == DisplayModeEnum::THUMBNAILS_LIST && !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableThumbnailMode)) {
3778 h = DisplayMode_ThumbailsList_ImageHeight;
3781#ifdef USE_EXPLORATION_BY_KEYS
3782 bool flashed = m_BeginFlashItem((
size_t)vidx);
3783 bool res = m_FlashableSelectable(fdi.variadicBuffer, vSelected, selectableFlags, flashed, ImVec2(-1.0f, h));
3784 if (flashed) m_EndFlashItem();
3788 bool res = ImGui::Selectable(fdi.variadicBuffer, vSelected, selectableFlags, ImVec2(-1.0f, h));
3791 if (vInfos->fileType.isDir()) {
3793 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) {
3795 if (ImGui::IsMouseDoubleClicked(0))
3797 fdi.puPathClicked = fdi.SelectDirectory(vInfos);
3798 }
else if (fdi.dLGDirectoryMode)
3800 fdi.SelectFileName(m_FileDialogInternal, vInfos);
3802 fdi.puPathClicked = fdi.SelectDirectory(vInfos);
3806 if (ImGui::IsMouseDoubleClicked(0))
3808 fdi.puPathClicked = fdi.SelectDirectory(vInfos);
3809 }
else if (fdi.dLGDirectoryMode)
3811 fdi.SelectFileName(m_FileDialogInternal, vInfos);
3815 fdi.SelectFileName(m_FileDialogInternal, vInfos);
3817 if (ImGui::IsMouseDoubleClicked(0)) {
3818 m_FileDialogInternal.isOk =
true;
3824void IGFD::FileDialog::m_DisplayFileInfosTooltip(
const int32_t& vRowIdx,
const int32_t& vColumnIdx, std::shared_ptr<FileInfos> vFileInfos) {
3825 if (ImGui::IsItemHovered()) {
3826 if (vFileInfos !=
nullptr && vFileInfos->tooltipColumn == vColumnIdx) {
3827 if (!vFileInfos->tooltipMessage.empty()) {
3828 ImGui::SetTooltip(
"%s", vFileInfos->tooltipMessage.c_str());
3834void IGFD::FileDialog::m_BeginFileColorIconStyle(std::shared_ptr<FileInfos> vFileInfos,
bool& vOutShowColor, std::string& vOutStr, ImFont** vOutFont) {
3836 vOutShowColor =
false;
3838 if (vFileInfos->fileStyle.use_count())
3840 vOutShowColor =
true;
3842 *vOutFont = vFileInfos->fileStyle->font;
3845 if (vOutShowColor && !vFileInfos->fileStyle->icon.empty())
3846 vOutStr = vFileInfos->fileStyle->icon;
3847 else if (vFileInfos->fileType.isDir())
3848 vOutStr = dirEntryString;
3849 else if (vFileInfos->fileType.isLinkToUnknown())
3850 vOutStr = linkEntryString;
3851 else if (vFileInfos->fileType.isFile())
3852 vOutStr = fileEntryString;
3854 vOutStr +=
" " + vFileInfos->fileNameExt;
3856 if (vOutShowColor) ImGui::PushStyleColor(ImGuiCol_Text, vFileInfos->fileStyle->color);
3857 if (*vOutFont) ImGui::PushFont(*vOutFont);
3860void IGFD::FileDialog::m_EndFileColorIconStyle(
const bool& vShowColor, ImFont* vFont) {
3861 if (vFont) ImGui::PopFont();
3862 if (vShowColor) ImGui::PopStyleColor();
3865void IGFD::FileDialog::m_DrawFileListView(ImVec2 vSize) {
3866 auto& fdi = m_FileDialogInternal.fileManager;
3868 ImGui::PushID(
this);
3870 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY
3871#ifndef USE_CUSTOM_SORTING_ICON
3872 | ImGuiTableFlags_Sortable
3875 auto listViewID = ImGui::GetID(
"##FileDialog_fileTable");
3876 if (ImGui::BeginTableEx(
"##FileDialog_fileTable", listViewID, 4, flags, vSize, 0.0f))
3878 ImGui::TableSetupScrollFreeze(0, 1);
3879 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_FILENAME].c_str(), ImGuiTableColumnFlags_WidthStretch | (defaultSortOrderFilename ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 0);
3880 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_TYPE].c_str(),
3881 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderType ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
3882 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnType) ? ImGuiTableColumnFlags_DefaultHide : 0),
3884 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_SIZE].c_str(),
3885 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderSize ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
3886 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnSize) ? ImGuiTableColumnFlags_DefaultHide : 0),
3888 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_DATE].c_str(),
3889 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderDate ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
3890 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnDate) ? ImGuiTableColumnFlags_DefaultHide : 0),
3893#ifndef USE_CUSTOM_SORTING_ICON
3895 if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) {
3896 if (sorts_specs->SpecsDirty && !fdi.IsFileListEmpty()) {
3897 bool direction = sorts_specs->Specs->SortDirection == ImGuiSortDirection_Ascending;
3899 if (sorts_specs->Specs->ColumnUserID == 0) {
3900 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
3901 fdi.sortingDirection[0] = direction;
3902 fdi.SortFields(m_FileDialogInternal);
3903 }
else if (sorts_specs->Specs->ColumnUserID == 1) {
3904 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
3905 fdi.sortingDirection[1] = direction;
3906 fdi.SortFields(m_FileDialogInternal);
3907 }
else if (sorts_specs->Specs->ColumnUserID == 2) {
3908 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
3909 fdi.sortingDirection[2] = direction;
3910 fdi.SortFields(m_FileDialogInternal);
3914 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
3915 fdi.sortingDirection[3] = direction;
3916 fdi.SortFields(m_FileDialogInternal);
3919 sorts_specs->SpecsDirty =
false;
3923 ImGui::TableHeadersRow();
3925 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
3926 for (
int column = 0; column < 4; column++)
3928 ImGui::TableSetColumnIndex(column);
3929 const char* column_name = ImGui::TableGetColumnName(column);
3930 ImGui::PushID(column);
3931 ImGui::TableHeader(column_name);
3933 if (ImGui::IsItemClicked()) {
3935 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME)
3936 fdi.sortingDirection[0] = !fdi.sortingDirection[0];
3938 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
3940 fdi.SortFields(m_FileDialogInternal);
3941 }
else if (column == 1) {
3942 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_TYPE)
3943 fdi.sortingDirection[1] = !fdi.sortingDirection[1];
3945 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
3947 fdi.SortFields(m_FileDialogInternal);
3948 }
else if (column == 2) {
3949 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_SIZE)
3950 fdi.sortingDirection[2] = !fdi.sortingDirection[2];
3952 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
3954 fdi.SortFields(m_FileDialogInternal);
3957 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_DATE)
3958 fdi.sortingDirection[3] = !fdi.sortingDirection[3];
3960 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
3962 fdi.SortFields(m_FileDialogInternal);
3967 if (!fdi.IsFilteredListEmpty()) {
3969 ImFont* _font =
nullptr;
3970 bool _showColor =
false;
3973 m_FileListClipper.Begin((
int)fdi.GetFilteredListSize(), ImGui::GetTextLineHeightWithSpacing());
3974 while (m_FileListClipper.Step()) {
3975 for (
int i = m_FileListClipper.DisplayStart; i < m_FileListClipper.DisplayEnd; i++) {
3976 if (i < 0)
continue;
3978 auto infos = fdi.GetFilteredFileAt((
size_t)i);
3979 if (!infos.use_count())
continue;
3981 m_BeginFileColorIconStyle(infos, _showColor, _str, &_font);
3983 bool selected = fdi.IsFileNameSelected(infos->fileNameExt);
3985 ImGui::TableNextRow();
3988 if (ImGui::TableNextColumn())
3990 m_SelectableItem(i, infos, selected, _str.c_str());
3991 m_DisplayFileInfosTooltip(i, column_id++, infos);
3993 if (ImGui::TableNextColumn())
3995 ImGui::Text(
"%s", infos->fileExtLevels[0].c_str());
3996 m_DisplayFileInfosTooltip(i, column_id++, infos);
3998 if (ImGui::TableNextColumn())
4000 if (!infos->fileType.isDir()) {
4001 ImGui::Text(
"%s ", infos->formatedFileSize.c_str());
4005 m_DisplayFileInfosTooltip(i, column_id++, infos);
4007 if (ImGui::TableNextColumn())
4009 ImGui::Text(
"%s", infos->fileModifDate.c_str());
4010 m_DisplayFileInfosTooltip(i, column_id++, infos);
4013 m_EndFileColorIconStyle(_showColor, _font);
4016 m_FileListClipper.End();
4019#ifdef USE_EXPLORATION_BY_KEYS
4020 if (!fdi.inputPathActivated) {
4021 m_LocateByInputKey(m_FileDialogInternal);
4022 m_ExploreWithkeys(m_FileDialogInternal, listViewID);
4027 if (
g.LastActiveId - 1 == listViewID ||
g.LastActiveId == listViewID) {
4028 m_FileDialogInternal.fileListViewIsActive =
true;
4037#ifdef USE_THUMBNAILS
4038void IGFD::FileDialog::m_DrawThumbnailsListView(ImVec2 vSize) {
4039 auto& fdi = m_FileDialogInternal.fileManager;
4041 ImGui::PushID(
this);
4043 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY
4044#ifndef USE_CUSTOM_SORTING_ICON
4045 | ImGuiTableFlags_Sortable
4048 auto listViewID = ImGui::GetID(
"##FileDialog_fileTable");
4049 if (ImGui::BeginTableEx(
"##FileDialog_fileTable", listViewID, 5, flags, vSize, 0.0f)) {
4050 ImGui::TableSetupScrollFreeze(0, 1);
4051 ImGui::TableSetupColumn(fdi.headerFileName.c_str(), ImGuiTableColumnFlags_WidthStretch | (defaultSortOrderFilename ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 0);
4052 ImGui::TableSetupColumn(fdi.headerFileType.c_str(),
4053 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderType ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
4054 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnType) ? ImGuiTableColumnFlags_DefaultHide : 0),
4056 ImGui::TableSetupColumn(fdi.headerFileSize.c_str(),
4057 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderSize ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
4058 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnSize) ? ImGuiTableColumnFlags_DefaultHide : 0),
4060 ImGui::TableSetupColumn(fdi.headerFileDate.c_str(),
4061 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderDate ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
4062 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnDate) ? ImGuiTableColumnFlags_DefaultHide : 0),
4065 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_THUMBNAILS].c_str(), ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderThumbnails ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 4);
4067#ifndef USE_CUSTOM_SORTING_ICON
4069 if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) {
4070 if (sorts_specs->SpecsDirty && !fdi.IsFileListEmpty()) {
4071 bool direction = sorts_specs->Specs->SortDirection == ImGuiSortDirection_Ascending;
4073 if (sorts_specs->Specs->ColumnUserID == 0) {
4074 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
4075 fdi.sortingDirection[0] = direction;
4076 fdi.SortFields(m_FileDialogInternal);
4077 }
else if (sorts_specs->Specs->ColumnUserID == 1) {
4078 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
4079 fdi.sortingDirection[1] = direction;
4080 fdi.SortFields(m_FileDialogInternal);
4081 }
else if (sorts_specs->Specs->ColumnUserID == 2) {
4082 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
4083 fdi.sortingDirection[2] = direction;
4084 fdi.SortFields(m_FileDialogInternal);
4085 }
else if (sorts_specs->Specs->ColumnUserID == 3) {
4086 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
4087 fdi.sortingDirection[3] = direction;
4088 fdi.SortFields(m_FileDialogInternal);
4092 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_THUMBNAILS;
4093 fdi.sortingDirection[4] = direction;
4094 fdi.SortFields(m_FileDialogInternal);
4097 sorts_specs->SpecsDirty =
false;
4101 ImGui::TableHeadersRow();
4103 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
4104 for (
int column = 0; column < 5; column++) {
4105 ImGui::TableSetColumnIndex(column);
4106 const char* column_name = ImGui::TableGetColumnName(column);
4107 ImGui::PushID(column);
4108 ImGui::TableHeader(column_name);
4110 if (ImGui::IsItemClicked()) {
4112 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME)
4113 fdi.sortingDirection[0] = !fdi.sortingDirection[0];
4115 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
4117 fdi.SortFields(m_FileDialogInternal);
4118 }
else if (column == 1) {
4119 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_TYPE)
4120 fdi.sortingDirection[1] = !fdi.sortingDirection[1];
4122 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
4124 fdi.SortFields(m_FileDialogInternal);
4125 }
else if (column == 2) {
4126 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_SIZE)
4127 fdi.sortingDirection[2] = !fdi.sortingDirection[2];
4129 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
4131 fdi.SortFields(m_FileDialogInternal);
4132 }
else if (column == 3) {
4133 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_DATE)
4134 fdi.sortingDirection[3] = !fdi.sortingDirection[3];
4136 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
4138 fdi.SortFields(m_FileDialogInternal);
4142 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_THUMBNAILS)
4143 fdi.sortingDirection[4] = !fdi.sortingDirection[4];
4145 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_THUMBNAILS;
4147 fdi.SortFields(m_FileDialogInternal);
4152 if (!fdi.IsFilteredListEmpty()) {
4154 ImFont* _font =
nullptr;
4155 bool _showColor =
false;
4158 const float itemHeight = ImMax(
g.FontSize, DisplayMode_ThumbailsList_ImageHeight) +
g.Style.ItemSpacing.y;
4161 m_FileListClipper.Begin((
int)fdi.GetFilteredListSize(), itemHeight);
4162 while (m_FileListClipper.Step()) {
4163 for (
int i = m_FileListClipper.DisplayStart; i < m_FileListClipper.DisplayEnd; i++) {
4164 if (i < 0)
continue;
4166 auto infos = fdi.GetFilteredFileAt((
size_t)i);
4167 if (!infos.use_count())
continue;
4169 m_BeginFileColorIconStyle(infos, _showColor, _str, &_font);
4171 bool selected = fdi.IsFileNameSelected(infos->fileNameExt);
4173 ImGui::TableNextRow();
4176 if (ImGui::TableNextColumn())
4178 m_SelectableItem(i, infos, selected, _str.c_str());
4179 m_DisplayFileInfosTooltip(i, column_id++, infos);
4181 if (ImGui::TableNextColumn())
4183 ImGui::Text(
"%s", infos->fileExtLevels[0].c_str());
4184 m_DisplayFileInfosTooltip(i, column_id++, infos);
4186 if (ImGui::TableNextColumn())
4188 if (!infos->fileType.isDir()) {
4189 ImGui::Text(
"%s ", infos->formatedFileSize.c_str());
4193 m_DisplayFileInfosTooltip(i, column_id++, infos);
4195 if (ImGui::TableNextColumn())
4197 ImGui::Text(
"%s", infos->fileModifDate.c_str());
4198 m_DisplayFileInfosTooltip(i, column_id++, infos);
4200 if (ImGui::TableNextColumn())
4202 auto th = &infos->thumbnailInfo;
4204 if (!th->isLoadingOrLoaded) {
4205 m_AddThumbnailToLoad(infos);
4207 if (th->isReadyToDisplay && th->textureID) {
4208 ImGui::Image((ImTextureID)th->textureID, ImVec2((
float)th->textureWidth, (
float)th->textureHeight));
4210 m_DisplayFileInfosTooltip(i, column_id++, infos);
4213 m_EndFileColorIconStyle(_showColor, _font);
4216 m_FileListClipper.End();
4219#ifdef USE_EXPLORATION_BY_KEYS
4220 if (!fdi.inputPathActivated) {
4221 m_LocateByInputKey(m_FileDialogInternal);
4222 m_ExploreWithkeys(m_FileDialogInternal, listViewID);
4227 if (
g.LastActiveId - 1 == listViewID ||
g.LastActiveId == listViewID) {
4228 m_FileDialogInternal.fileListViewIsActive =
true;
4237void IGFD::FileDialog::m_DrawThumbnailsGridView(ImVec2 vSize) {
4238 if (ImGui::BeginChild(
"##thumbnailsGridsFiles", vSize)) {
4247void IGFD::FileDialog::m_DrawSidePane(
float vHeight) {
4250 ImGui::BeginChild(
"##FileTypes", ImVec2(0, vHeight));
4252 m_FileDialogInternal.getDialogConfig().sidePane(
4253 m_FileDialogInternal.filterManager.GetSelectedFilter().getFirstFilter().c_str(),
4254 m_FileDialogInternal.getDialogConfigRef().userDatas,
4255 &m_FileDialogInternal.canWeContinue);
4259void IGFD::FileDialog::Close() {
4260 m_FileDialogInternal.dLGkey.clear();
4261 m_FileDialogInternal.showDialog =
false;
4264bool IGFD::FileDialog::WasOpenedThisFrame(
const std::string& vKey)
const {
4265 bool res = m_FileDialogInternal.showDialog && m_FileDialogInternal.dLGkey == vKey;
4267 res &= m_FileDialogInternal.lastImGuiFrameCount ==
GImGui->FrameCount;
4272bool IGFD::FileDialog::WasOpenedThisFrame()
const {
4273 bool res = m_FileDialogInternal.showDialog;
4275 res &= m_FileDialogInternal.lastImGuiFrameCount ==
GImGui->FrameCount;
4280bool IGFD::FileDialog::IsOpened(
const std::string& vKey)
const {
4281 return (m_FileDialogInternal.showDialog && m_FileDialogInternal.dLGkey == vKey);
4284bool IGFD::FileDialog::IsOpened()
const {
4285 return m_FileDialogInternal.showDialog;
4288std::string IGFD::FileDialog::GetOpenedKey()
const {
4289 if (m_FileDialogInternal.showDialog) {
4290 return m_FileDialogInternal.dLGkey;
4295std::string IGFD::FileDialog::GetFilePathName(IGFD_ResultMode vFlag) {
4296 return m_FileDialogInternal.fileManager.GetResultingFilePathName(m_FileDialogInternal, vFlag);
4299std::string IGFD::FileDialog::GetCurrentPath() {
4300 return m_FileDialogInternal.fileManager.GetResultingPath();
4303std::string IGFD::FileDialog::GetCurrentFileName(IGFD_ResultMode vFlag) {
4304 return m_FileDialogInternal.fileManager.GetResultingFileName(m_FileDialogInternal, vFlag);
4307std::string IGFD::FileDialog::GetCurrentFilter() {
4308 return m_FileDialogInternal.filterManager.GetSelectedFilter().title;
4311std::map<std::string, std::string> IGFD::FileDialog::GetSelection(IGFD_ResultMode vFlag) {
4312 return m_FileDialogInternal.fileManager.GetResultingSelection(m_FileDialogInternal, vFlag);
4315IGFD::UserDatas IGFD::FileDialog::GetUserDatas()
const {
4316 return m_FileDialogInternal.getDialogConfig().userDatas;
4319bool IGFD::FileDialog::IsOk()
const {
4320 return m_FileDialogInternal.isOk;
4323void IGFD::FileDialog::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const FileStyle& vInfos) {
4324 m_FileDialogInternal.filterManager.SetFileStyle(vFlags, vCriteria, vInfos);
4327void IGFD::FileDialog::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const ImVec4& vColor,
const std::string& vIcon, ImFont* vFont) {
4328 m_FileDialogInternal.filterManager.SetFileStyle(vFlags, vCriteria, vColor, vIcon, vFont);
4331void IGFD::FileDialog::SetFileStyle(FileStyle::FileStyleFunctor vFunctor) {
4332 m_FileDialogInternal.filterManager.SetFileStyle(vFunctor);
4335bool IGFD::FileDialog::GetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const std::string& vCriteria, ImVec4* vOutColor, std::string* vOutIcon, ImFont** vOutFont) {
4336 return m_FileDialogInternal.filterManager.GetFileStyle(vFlags, vCriteria, vOutColor, vOutIcon, vOutFont);
4339void IGFD::FileDialog::ClearFilesStyle() {
4340 m_FileDialogInternal.filterManager.ClearFilesStyle();
4343void IGFD::FileDialog::SetLocales(
const int& ,
const std::string& vLocaleBegin,
const std::string& vLocaleEnd) {
4344 m_FileDialogInternal.puUseCustomLocale =
true;
4345 m_FileDialogInternal.localeBegin = vLocaleBegin;
4346 m_FileDialogInternal.localeEnd = vLocaleEnd;
4353bool IGFD::FileDialog::m_Confirm_Or_OpenOverWriteFileDialog_IfNeeded(
bool vLastAction, ImGuiWindowFlags vFlags) {
4358 if (!m_FileDialogInternal.isOk && vLastAction) {
4364 if (m_FileDialogInternal.isOk && vLastAction && !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_ConfirmOverwrite)) {
4370 if ((m_FileDialogInternal.okResultToConfirm || (m_FileDialogInternal.isOk && vLastAction)) && (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_ConfirmOverwrite)) {
4371 if (m_FileDialogInternal.isOk)
4373 if (!m_FileDialogInternal.fileManager.GetFileSystemInstance()->IsFileExist(GetFilePathName()))
4379 m_FileDialogInternal.isOk =
false;
4380 m_FileDialogInternal.okResultToConfirm =
true;
4384 std::string name = OverWriteDialogTitleString
"##" + m_FileDialogInternal.dLGtitle + m_FileDialogInternal.dLGkey +
"OverWriteDialog";
4388 ImGui::OpenPopup(name.c_str());
4389 if (ImGui::BeginPopupModal(name.c_str(), (
bool*)0, vFlags | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
4390 ImGui::SetWindowPos(m_FileDialogInternal.dialogCenterPos - ImGui::GetWindowSize() * 0.5f);
4392 ImGui::Text(
"%s", OverWriteDialogMessageString);
4394 if (IMGUI_BUTTON(OverWriteDialogConfirmButtonString)) {
4395 m_FileDialogInternal.okResultToConfirm =
false;
4396 m_FileDialogInternal.isOk =
true;
4398 ImGui::CloseCurrentPopup();
4403 if (IMGUI_BUTTON(OverWriteDialogCancelButtonString)) {
4404 m_FileDialogInternal.okResultToConfirm =
false;
4405 m_FileDialogInternal.isOk =
false;
4407 ImGui::CloseCurrentPopup();
4432 IGFD_FileDialog_Config res = {};
4435 res.filePathName =
"";
4436 res.countSelectionMax = 1;
4437 res.userDatas =
nullptr;
4438 res.sidePane =
nullptr;
4439 res.sidePaneWidth = 250.0f;
4440 res.flags = ImGuiFileDialogFlags_Default;
4446 IGFD_Selection_Pair res = {};
4447 res.fileName =
nullptr;
4448 res.filePathName =
nullptr;
4454 if (vSelection_Pair) {
4455 delete[] vSelection_Pair->fileName;
4456 delete[] vSelection_Pair->filePathName;
4462 return {
nullptr, 0U};
4468 if (vSelection->table) {
4469 for (
size_t i = 0U; i < vSelection->count; i++) {
4472 delete[] vSelection->table;
4474 vSelection->count = 0U;
4480 return new ImGuiFileDialog();
4485 if (vContextPtr !=
nullptr) {
4487 vContextPtr =
nullptr;
4492 ImGuiFileDialog* vContextPtr,
4495 const char* vFilters,
4496 const IGFD_FileDialog_Config vConfig) {
4497 if (vContextPtr !=
nullptr) {
4498 IGFD::FileDialogConfig config;
4499 config.path = vConfig.path;
4500 config.fileName = vConfig.fileName;
4501 config.filePathName = vConfig.filePathName;
4502 config.countSelectionMax = vConfig.countSelectionMax;
4503 config.userDatas = vConfig.userDatas;
4504 config.flags = vConfig.flags;
4505 config.sidePane = vConfig.sidePane;
4506 config.sidePaneWidth = vConfig.sidePaneWidth;
4507 vContextPtr->OpenDialog(vKey, vTitle, vFilters, config);
4511IGFD_C_API
bool IGFD_DisplayDialog(ImGuiFileDialog* vContextPtr,
const char* vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize) {
4512 if (vContextPtr !=
nullptr) {
4513 return vContextPtr->Display(vKey, vFlags, vMinSize, vMaxSize);
4519 if (vContextPtr !=
nullptr) {
4520 vContextPtr->Close();
4525 if (vContextPtr !=
nullptr) {
4526 return vContextPtr->IsOk();
4532 if (vContextPtr !=
nullptr) {
4533 return vContextPtr->WasOpenedThisFrame(vKey);
4539 if (vContextPtr !=
nullptr) {
4540 return vContextPtr->WasOpenedThisFrame();
4547 if (vContextPtr !=
nullptr) {
4548 return vContextPtr->IsOpened(vCurrentOpenedKey);
4555 if (vContextPtr !=
nullptr) {
4556 return vContextPtr->IsOpened();
4564 if (vContextPtr !=
nullptr) {
4565 auto sel = vContextPtr->GetSelection(vMode);
4567 res.count = sel.size();
4568 res.table =
new IGFD_Selection_Pair[res.count];
4571 for (
const auto& s : sel) {
4572 IGFD_Selection_Pair* pair = res.table + idx++;
4575 if (!s.first.empty()) {
4576 size_t siz = s.first.size() + 1U;
4577 pair->fileName =
new char[siz];
4579 strncpy(pair->fileName, s.first.c_str(), siz);
4581 strncpy_s(pair->fileName, siz, s.first.c_str(), siz);
4583 pair->fileName[siz - 1U] =
'\0';
4587 if (!s.second.empty()) {
4588 size_t siz = s.second.size() + 1U;
4589 pair->filePathName =
new char[siz];
4591 strncpy(pair->filePathName, s.second.c_str(), siz);
4593 strncpy_s(pair->filePathName, siz, s.second.c_str(), siz);
4595 pair->filePathName[siz - 1U] =
'\0';
4607 char* res =
nullptr;
4609 if (vContextPtr !=
nullptr) {
4610 auto s = vContextPtr->GetFilePathName(vMode);
4612 size_t siz = s.size() + 1U;
4613 res = (
char*)malloc(siz);
4616 strncpy(res, s.c_str(), siz);
4618 strncpy_s(res, siz, s.c_str(), siz);
4620 res[siz - 1U] =
'\0';
4629 char* res =
nullptr;
4631 if (vContextPtr !=
nullptr) {
4632 auto s = vContextPtr->GetCurrentFileName(vMode);
4634 size_t siz = s.size() + 1U;
4635 res = (
char*)malloc(siz);
4638 strncpy(res, s.c_str(), siz);
4640 strncpy_s(res, siz, s.c_str(), siz);
4642 res[siz - 1U] =
'\0';
4651 char* res =
nullptr;
4653 if (vContextPtr !=
nullptr) {
4654 auto s = vContextPtr->GetCurrentPath();
4656 size_t siz = s.size() + 1U;
4657 res = (
char*)malloc(siz);
4660 strncpy(res, s.c_str(), siz);
4662 strncpy_s(res, siz, s.c_str(), siz);
4664 res[siz - 1U] =
'\0';
4673 char* res =
nullptr;
4675 if (vContextPtr !=
nullptr) {
4676 auto s = vContextPtr->GetCurrentFilter();
4678 size_t siz = s.size() + 1U;
4679 res = (
char*)malloc(siz);
4682 strncpy(res, s.c_str(), siz);
4684 strncpy_s(res, siz, s.c_str(), siz);
4686 res[siz - 1U] =
'\0';
4695 if (vContextPtr !=
nullptr) {
4696 return vContextPtr->GetUserDatas();
4702IGFD_C_API
void IGFD_SetFileStyle(ImGuiFileDialog* vContextPtr, IGFD_FileStyleFlags vFlags,
const char* vCriteria, ImVec4 vColor,
const char* vIcon,
4705 if (vContextPtr !=
nullptr) {
4706 vContextPtr->SetFileStyle(vFlags, vCriteria, vColor, vIcon, vFont);
4710IGFD_C_API
void IGFD_SetFileStyle2(ImGuiFileDialog* vContextPtr, IGFD_FileStyleFlags vFlags,
const char* vCriteria,
float vR,
float vG,
float vB,
float vA,
const char* vIcon, ImFont* vFont) {
4711 if (vContextPtr !=
nullptr) {
4712 vContextPtr->SetFileStyle(vFlags, vCriteria, ImVec4(vR, vG, vB, vA), vIcon, vFont);
4716IGFD_C_API
bool IGFD_GetFileStyle(ImGuiFileDialog* vContextPtr, IGFD_FileStyleFlags vFlags,
const char* vCriteria, ImVec4* vOutColor,
char** vOutIconText, ImFont** vOutFont) {
4717 if (vContextPtr !=
nullptr) {
4719 bool res = vContextPtr->GetFileStyle(vFlags, vCriteria, vOutColor, &icon, vOutFont);
4720 if (!icon.empty() && vOutIconText) {
4721 size_t siz = icon.size() + 1U;
4722 *vOutIconText = (
char*)malloc(siz);
4723 if (*vOutIconText) {
4725 strncpy(*vOutIconText, icon.c_str(), siz);
4727 strncpy_s(*vOutIconText, siz, icon.c_str(), siz);
4729 (*vOutIconText)[siz - 1U] =
'\0';
4739 if (vContextPtr !=
nullptr) {
4740 vContextPtr->ClearFilesStyle();
4744IGFD_C_API
void SetLocales(ImGuiFileDialog* vContextPtr,
const int vCategory,
const char* vBeginLocale,
const char* vEndLocale) {
4745 if (vContextPtr !=
nullptr) {
4746 vContextPtr->SetLocales(vCategory, (vBeginLocale ? vBeginLocale :
""), (vEndLocale ? vEndLocale :
""));
4750#ifdef USE_EXPLORATION_BY_KEYS
4752 if (vContextPtr !=
nullptr) {
4753 vContextPtr->SetFlashingAttenuationInSeconds(vAttenValue);
4760 char* res =
nullptr;
4762 if (vContextPtr !=
nullptr) {
4763 auto s = vContextPtr->SerializeBookmarks(vDontSerializeCodeBasedBookmarks);
4765 size_t siz = s.size() + 1U;
4766 res = (
char*)malloc(siz);
4769 strncpy(res, s.c_str(), siz);
4771 strncpy_s(res, siz, s.c_str(), siz);
4773 res[siz - 1U] =
'\0';
4782 if (vContextPtr !=
nullptr) {
4783 vContextPtr->DeserializeBookmarks(vBookmarks);
4787IGFD_C_API
void IGFD_AddBookmark(ImGuiFileDialog* vContextPtr,
const char* vBookMarkName,
const char* vBookMarkPath) {
4788 if (vContextPtr !=
nullptr) {
4789 vContextPtr->AddBookmark(vBookMarkName, vBookMarkPath);
4794 if (vContextPtr !=
nullptr) {
4795 vContextPtr->RemoveBookmark(vBookMarkName);
4801#ifdef USE_THUMBNAILS
4802IGFD_C_API
void SetCreateThumbnailCallback(ImGuiFileDialog* vContextPtr,
const IGFD_CreateThumbnailFun vCreateThumbnailFun) {
4803 if (vContextPtr !=
nullptr) {
4804 vContextPtr->SetCreateThumbnailCallback(vCreateThumbnailFun);
4808IGFD_C_API
void SetDestroyThumbnailCallback(ImGuiFileDialog* vContextPtr,
const IGFD_DestroyThumbnailFun vDestroyThumbnailFun) {
4809 if (vContextPtr !=
nullptr) {
4810 vContextPtr->SetDestroyThumbnailCallback(vDestroyThumbnailFun);
4814IGFD_C_API
void ManageGPUThumbnails(ImGuiFileDialog* vContextPtr) {
4815 if (vContextPtr !=
nullptr) {
4816 vContextPtr->ManageGPUThumbnails();
IGFD_C_API IGFD_Selection_Pair IGFD_Selection_Pair_Get(void)
IGFD_C_API void IGFD_Selection_Pair_DestroyContent(IGFD_Selection_Pair *vSelection_Pair)
IGFD_C_API void IGFD_RemoveBookmark(ImGuiFileDialog *vContextPtr, const char *vBookMarkName)
IGFD_C_API IGFD_Selection IGFD_GetSelection(ImGuiFileDialog *vContextPtr, IGFD_ResultMode vMode)
IGFD_C_API void * IGFD_GetUserDatas(ImGuiFileDialog *vContextPtr)
IGFD_C_API char * IGFD_GetFilePathName(ImGuiFileDialog *vContextPtr, IGFD_ResultMode vMode)
IGFD_C_API char * IGFD_SerializeBookmarks(ImGuiFileDialog *vContextPtr, bool vDontSerializeCodeBasedBookmarks)
IGFD_C_API void IGFD_DeserializeBookmarks(ImGuiFileDialog *vContextPtr, const char *vBookmarks)
IGFD_C_API bool IGFD_IsOk(ImGuiFileDialog *vContextPtr)
IGFD_C_API ImGuiFileDialog * IGFD_Create(void)
IGFD_C_API void IGFD_SetFileStyle2(ImGuiFileDialog *vContextPtr, IGFD_FileStyleFlags vFlags, const char *vCriteria, float vR, float vG, float vB, float vA, const char *vIcon, ImFont *vFont)
IGFD_C_API IGFD_FileDialog_Config IGFD_FileDialog_Config_Get()
IGFD_C_API void IGFD_ClearFilesStyle(ImGuiFileDialog *vContextPtr)
IGFD_C_API bool IGFD_IsKeyOpened(ImGuiFileDialog *vContextPtr, const char *vCurrentOpenedKey)
IGFD_C_API void IGFD_Destroy(ImGuiFileDialog *vContextPtr)
IGFD_C_API char * IGFD_GetCurrentPath(ImGuiFileDialog *vContextPtr)
IGFD_C_API void SetLocales(ImGuiFileDialog *vContextPtr, const int vCategory, const char *vBeginLocale, const char *vEndLocale)
IGFD_C_API IGFD_Selection IGFD_Selection_Get(void)
IGFD_C_API void IGFD_AddBookmark(ImGuiFileDialog *vContextPtr, const char *vBookMarkName, const char *vBookMarkPath)
IGFD_C_API char * IGFD_GetCurrentFileName(ImGuiFileDialog *vContextPtr, IGFD_ResultMode vMode)
IGFD_C_API void IGFD_CloseDialog(ImGuiFileDialog *vContextPtr)
IGFD_C_API void IGFD_SetFileStyle(ImGuiFileDialog *vContextPtr, IGFD_FileStyleFlags vFlags, const char *vCriteria, ImVec4 vColor, const char *vIcon, ImFont *vFont)
IGFD_C_API bool IGFD_IsOpened(ImGuiFileDialog *vContextPtr)
IGFD_C_API char * IGFD_GetCurrentFilter(ImGuiFileDialog *vContextPtr)
IGFD_C_API void IGFD_SetFlashingAttenuationInSeconds(ImGuiFileDialog *vContextPtr, float vAttenValue)
IGFD_C_API void IGFD_OpenDialog(ImGuiFileDialog *vContextPtr, const char *vKey, const char *vTitle, const char *vFilters, const IGFD_FileDialog_Config vConfig)
IGFD_C_API bool IGFD_WasOpenedThisFrame(ImGuiFileDialog *vContextPtr)
IGFD_C_API bool IGFD_DisplayDialog(ImGuiFileDialog *vContextPtr, const char *vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize)
IGFD_C_API void IGFD_Selection_DestroyContent(IGFD_Selection *vSelection)
IGFD_C_API bool IGFD_WasKeyOpenedThisFrame(ImGuiFileDialog *vContextPtr, const char *vKey)
IGFD_C_API bool IGFD_GetFileStyle(ImGuiFileDialog *vContextPtr, IGFD_FileStyleFlags vFlags, const char *vCriteria, ImVec4 *vOutColor, char **vOutIconText, ImFont **vOutFont)
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
uint16_t word
16 bit unsigned integer
size_t size(std::string_view utf8)
auto filter(ForwardRange &&range, Predicate pred)
constexpr auto end(const zstring_view &x)