36#include "ImGuiFileDialog.h"
54static void RightAlignText(
const char* text,
const char* maxWidthText)
58 if (
auto spacing = maxWidth - actualWidth; spacing > 0.0f) {
59 auto pos = ImGui::GetCursorPosX();
60 ImGui::SetCursorPosX(pos + spacing);
70#ifdef USE_STD_FILESYSTEM
76#include <emscripten.h>
81#define IGFD_DEBUG_BREAK \
82 if (IsDebuggerPresent()) __debugbreak()
84#define IGFD_DEBUG_BREAK
87#if defined(__WIN32__) || defined(WIN32) || defined(_WIN32) || defined(__WIN64__) || defined(WIN64) || defined(_WIN64) || defined(_MSC_VER)
90#define stricmp _stricmp
93#ifdef USE_STD_FILESYSTEM
96#include "dirent/dirent.h"
102#elif defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__NetBSD__) || defined(__APPLE__) || defined(__EMSCRIPTEN__)
104#define stricmp strcasecmp
105#include <sys/types.h>
107#ifndef USE_STD_FILESYSTEM
114#include "imgui_internal.h"
118#define IM_TRUNC IM_FLOOR
130#ifndef DONT_DEFINE_AGAIN__STB_IMAGE_IMPLEMENTATION
131#ifndef STB_IMAGE_IMPLEMENTATION
132#define STB_IMAGE_IMPLEMENTATION
135#include "stb/stb_image.h"
136#ifndef DONT_DEFINE_AGAIN__STB_IMAGE_RESIZE_IMPLEMENTATION
137#ifndef STB_IMAGE_RESIZE_IMPLEMENTATION
138#define STB_IMAGE_RESIZE_IMPLEMENTATION
141#include "stb/stb_image_resize.h"
145#ifndef IS_FLOAT_DIFFERENT
146#define IS_FLOAT_DIFFERENT(a, b) (fabs((a) - (b)) > FLT_EPSILON)
148#ifndef IS_FLOAT_EQUAL
149#define IS_FLOAT_EQUAL(a, b) (fabs((a) - (b)) < FLT_EPSILON)
161#ifndef FILTER_COMBO_AUTO_SIZE
162#define FILTER_COMBO_AUTO_SIZE 1
164#ifndef FILTER_COMBO_MIN_WIDTH
165#define FILTER_COMBO_MIN_WIDTH 150.0f
167#ifndef IMGUI_BEGIN_COMBO
168#define IMGUI_BEGIN_COMBO ImGui::BeginCombo
175#ifndef IMGUI_PATH_BUTTON
176#define IMGUI_PATH_BUTTON ImGui::Button
179#define IMGUI_BUTTON ImGui::Button
184#ifndef createDirButtonString
185#define createDirButtonString "+"
187#ifndef okButtonString
188#define okButtonString "OK"
191#define okButtonWidth 0.0f
193#ifndef cancelButtonString
194#define cancelButtonString "Cancel"
196#ifndef cancelButtonWidth
197#define cancelButtonWidth 0.0f
199#ifndef okCancelButtonAlignement
200#define okCancelButtonAlignement 0.0f
202#ifndef invertOkAndCancelButtons
204#define invertOkAndCancelButtons 0
206#ifndef resetButtonString
207#define resetButtonString "R"
209#ifndef drivesButtonString
210#define drivesButtonString "Drives"
212#ifndef editPathButtonString
213#define editPathButtonString "E"
216#define searchString "Filter:"
218#ifndef dirEntryString
219#define dirEntryString "[Dir]"
221#ifndef linkEntryString
222#define linkEntryString "[Link]"
224#ifndef fileEntryString
225#define fileEntryString "[File]"
227#ifndef fileNameString
228#define fileNameString "File Name:"
231#define dirNameString "Directory Path:"
233#ifndef buttonResetSearchString
234#define buttonResetSearchString "Reset filter"
236#ifndef buttonDriveString
237#define buttonDriveString "Drives"
239#ifndef buttonEditPathString
240#define buttonEditPathString "Edit path\nYou can also right click on path buttons"
242#ifndef buttonResetPathString
243#define buttonResetPathString "Reset to current directory"
245#ifndef buttonCreateDirString
246#define buttonCreateDirString "Create Directory"
248#ifndef tableHeaderAscendingIcon
249#define tableHeaderAscendingIcon "A|"
251#ifndef tableHeaderDescendingIcon
252#define tableHeaderDescendingIcon "D|"
254#ifndef tableHeaderFileNameString
255#define tableHeaderFileNameString "File name"
257#ifndef tableHeaderFileTypeString
258#define tableHeaderFileTypeString "Type"
260#ifndef tableHeaderFileSizeString
261#define tableHeaderFileSizeString "Size"
263#ifndef tableHeaderFileDateString
264#define tableHeaderFileDateString "Date"
267#define fileSizeBytes "o"
269#ifndef fileSizeKiloBytes
270#define fileSizeKiloBytes "Ko"
272#ifndef fileSizeMegaBytes
273#define fileSizeMegaBytes "Mo"
275#ifndef fileSizeGigaBytes
276#define fileSizeGigaBytes "Go"
278#ifndef OverWriteDialogTitleString
279#define OverWriteDialogTitleString "The selected file already exists!"
281#ifndef OverWriteDialogMessageString
282#define OverWriteDialogMessageString "Are you sure you want to overwrite it?"
284#ifndef OverWriteDialogConfirmButtonString
285#define OverWriteDialogConfirmButtonString "Confirm"
287#ifndef OverWriteDialogCancelButtonString
288#define OverWriteDialogCancelButtonString "Cancel"
290#ifndef DateTimeFormat
292#define DateTimeFormat "%Y/%m/%d %H:%M"
298#ifndef tableHeaderFileThumbnailsString
299#define tableHeaderFileThumbnailsString "Thumbnails"
301#ifndef DisplayMode_FilesList_ButtonString
302#define DisplayMode_FilesList_ButtonString "FL"
304#ifndef DisplayMode_FilesList_ButtonHelp
305#define DisplayMode_FilesList_ButtonHelp "File List"
307#ifndef DisplayMode_ThumbailsList_ButtonString
308#define DisplayMode_ThumbailsList_ButtonString "TL"
310#ifndef DisplayMode_ThumbailsList_ButtonHelp
311#define DisplayMode_ThumbailsList_ButtonHelp "Thumbnails List"
313#ifndef DisplayMode_ThumbailsGrid_ButtonString
314#define DisplayMode_ThumbailsGrid_ButtonString "TG"
316#ifndef DisplayMode_ThumbailsGrid_ButtonHelp
317#define DisplayMode_ThumbailsGrid_ButtonHelp "Thumbnails Grid"
319#ifndef DisplayMode_ThumbailsList_ImageHeight
320#define DisplayMode_ThumbailsList_ImageHeight 32.0f
322#ifndef IMGUI_RADIO_BUTTON
323inline bool inRadioButton(
const char* vLabel,
bool vToggled) {
324 bool pressed =
false;
326 ImVec4 bua = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
327 ImVec4 te = ImGui::GetStyleColorVec4(ImGuiCol_Text);
328 ImGui::PushStyleColor(ImGuiCol_Button, te);
329 ImGui::PushStyleColor(ImGuiCol_ButtonActive, te);
330 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, te);
331 ImGui::PushStyleColor(ImGuiCol_Text, bua);
333 pressed = IMGUI_BUTTON(vLabel);
335 ImGui::PopStyleColor(4);
339#define IMGUI_RADIO_BUTTON inRadioButton
346#ifndef defaultBookmarkPaneWith
347#define defaultBookmarkPaneWith 150.0f
349#ifndef bookmarksButtonString
350#define bookmarksButtonString "Bookmark"
352#ifndef bookmarksButtonHelpString
353#define bookmarksButtonHelpString "Bookmark"
355#ifndef addBookmarkButtonString
356#define addBookmarkButtonString "+"
358#ifndef removeBookmarkButtonString
359#define removeBookmarkButtonString "-"
361#ifndef IMGUI_TOGGLE_BUTTON
362inline bool inToggleButton(
const char* vLabel,
bool* vToggled) {
363 bool pressed =
false;
365 if (vToggled && *vToggled) {
366 ImVec4 bua = ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive);
369 ImVec4 te = ImGui::GetStyleColorVec4(ImGuiCol_Text);
370 ImGui::PushStyleColor(ImGuiCol_Button, te);
371 ImGui::PushStyleColor(ImGuiCol_ButtonActive, te);
372 ImGui::PushStyleColor(ImGuiCol_ButtonHovered, te);
373 ImGui::PushStyleColor(ImGuiCol_Text, bua);
376 pressed = IMGUI_BUTTON(vLabel);
378 if (vToggled && *vToggled) {
379 ImGui::PopStyleColor(4);
382 if (vToggled && pressed) *vToggled = !*vToggled;
386#define IMGUI_TOGGLE_BUTTON inToggleButton
396class IGFDException :
public std::exception {
398 std::string m_Message;
401 IGFDException(
const std::string& vMessage) : m_Message(vMessage) {
404 return m_Message.c_str();
412#ifndef CUSTOM_FILESYSTEM_INCLUDE
413#ifdef USE_STD_FILESYSTEM
415static std::filesystem::path stringToPath(
const std::string& str)
418 return std::filesystem::path(IGFD::Utils::UTF8Decode(str));
420 return std::filesystem::path(str);
424static std::string pathToString(
const std::filesystem::path& path)
427 return IGFD::Utils::UTF8Encode(path.wstring());
429 return path.string();
433class FileSystemStd :
public IGFD::IFileSystem {
435 bool IsDirectoryCanBeOpened(
const std::string& vName)
override {
436 bool bExists =
false;
437 if (!vName.empty()) {
438 namespace fs = std::filesystem;
439 auto pathName = stringToPath(vName);
443 bExists = fs::is_directory(pathName);
446 const auto dir_iter = fs::directory_iterator(pathName);
448 }
catch (
const std::exception& ) {
455 bool IsDirectoryExist(
const std::string& vName)
override {
456 if (!vName.empty()) {
457 namespace fs = std::filesystem;
458 return fs::is_directory(stringToPath(vName));
462 bool IsFileExist(
const std::string& vName)
override {
463 namespace fs = std::filesystem;
464 return fs::is_regular_file(stringToPath(vName));
466 bool CreateDirectoryIfNotExist(
const std::string& vName)
override {
467 if (vName.empty())
return false;
468 if (IsDirectoryExist(vName))
return false;
470#if defined(__EMSCRIPTEN__)
471 std::string str = std::string(
"FS.mkdir('") + vName +
"');";
472 emscripten_run_script(str.c_str());
475 namespace fs = std::filesystem;
476 bool res = fs::create_directories(stringToPath(vName));
479 std::cout <<
"Error creating directory " << vName << std::endl;
483 std::vector<std::string> GetDrivesList()
override {
484 std::vector<std::string> res;
486 const DWORD mydrives = 2048;
488#define mini(a, b) (((a) < (b)) ? (a) : (b))
489 const DWORD countChars = mini(GetLogicalDriveStringsA(mydrives, lpBuffer), 2047);
491 if (countChars > 0U && countChars < 2049U) {
492 std::string var = std::string(lpBuffer, (
size_t)countChars);
493 IGFD::Utils::ReplaceString(var,
"\\",
"");
494 res = IGFD::Utils::SplitStringToVector(var,
'\0',
false);
500 IGFD::Utils::PathStruct ParsePathFileName(
const std::string& vPathFileName)
override {
502 namespace fs = std::filesystem;
503 IGFD::Utils::PathStruct res;
504 if (vPathFileName.empty())
return res;
505 auto fsPath = stringToPath(vPathFileName);
506 if (fs::is_directory(fsPath)) {
508 res.path = pathToString(fsPath);
510 }
else if (fs::is_regular_file(fsPath)) {
511 res.name = pathToString(fsPath.filename());
512 res.path = pathToString(fsPath.parent_path());
518 std::vector<IGFD::FileInfos> ScanDirectory(
const std::string& vPath)
override {
519 std::vector<IGFD::FileInfos> res;
521 namespace fs = std::filesystem;
522 auto fspath = stringToPath(vPath);
523 const auto dir_iter = fs::directory_iterator(fspath);
524 IGFD::FileType fstype = IGFD::FileType(IGFD::FileType::ContentType::Directory, fs::is_symlink(fs::status(fspath)));
526 IGFD::FileInfos file_two_dot;
527 file_two_dot.filePath = vPath;
528 file_two_dot.fileNameExt =
"..";
529 file_two_dot.fileType = fstype;
530 res.push_back(file_two_dot);
532 for (
const auto& file : dir_iter) {
533 IGFD::FileType fileType;
534 if (file.is_symlink()) {
535 fileType.SetSymLink(file.is_symlink());
536 fileType.SetContent(IGFD::FileType::ContentType::LinkToUnknown);
538 if (file.is_directory()) {
539 fileType.SetContent(IGFD::FileType::ContentType::Directory);
541 else if (file.is_regular_file()) {
542 fileType.SetContent(IGFD::FileType::ContentType::File);
544 if (fileType.isValid()) {
545 auto fileNameExt = pathToString(file.path().filename());
547 IGFD::FileInfos _file;
548 _file.filePath = vPath;
549 _file.fileNameExt = fileNameExt;
550 _file.fileType = fileType;
551 res.push_back(_file);
555 }
catch (
const std::exception& ex) {
556 printf(
"%s", ex.what());
560 bool IsDirectory(
const std::string& vFilePathName)
override {
561 namespace fs = std::filesystem;
562 return fs::is_directory(stringToPath(vFilePathName));
565#define FILE_SYSTEM_OVERRIDE FileSystemStd
567class FileSystemDirent :
public IGFD::IFileSystem {
569 bool IsDirectoryCanBeOpened(
const std::string& vName)
override {
570 if (!vName.empty()) {
574 pDir = opendir(vName.c_str());
575 if (pDir !=
nullptr) {
576 (void)closedir(pDir);
582 bool IsDirectoryExist(
const std::string& vName)
override {
583 bool bExists =
false;
584 if (!vName.empty()) {
586 pDir = opendir(vName.c_str());
590 }
else if (ENOENT == errno) {
602 bool IsFileExist(
const std::string& vName)
override {
603 std::ifstream docFile(vName, std::ios::in);
604 if (docFile.is_open()) {
610 bool CreateDirectoryIfNotExist(
const std::string& vName)
override {
612 if (!vName.empty()) {
613 if (!IsDirectoryExist(vName)) {
615 std::wstring wname = IGFD::Utils::UTF8Decode(vName);
616 if (CreateDirectoryW(wname.c_str(),
nullptr)) {
619#elif defined(__EMSCRIPTEN__)
620 std::string str = std::string(
"FS.mkdir('") + vName +
"');";
621 emscripten_run_script(str.c_str());
623#elif defined(_IGFD_UNIX_)
624 char buffer[PATH_MAX] = {};
625 snprintf(buffer, PATH_MAX,
"mkdir -p \"%s\"", vName.c_str());
626 const int dir_err = std::system(buffer);
632 std::cout <<
"Error creating directory " << vName << std::endl;
640 std::vector<std::string> GetDrivesList()
override {
641 std::vector<std::string> res;
643 const DWORD mydrives = 2048;
645#define mini(a, b) (((a) < (b)) ? (a) : (b))
646 const DWORD countChars = mini(GetLogicalDriveStringsA(mydrives, lpBuffer), 2047);
648 if (countChars > 0U && countChars < 2049U) {
649 std::string var = std::string(lpBuffer, (
size_t)countChars);
650 IGFD::Utils::ReplaceString(var,
"\\",
"");
651 res = IGFD::Utils::SplitStringToVector(var,
'\0',
false);
657 IGFD::Utils::PathStruct ParsePathFileName(
const std::string& vPathFileName)
override {
658 IGFD::Utils::PathStruct res;
659 if (!vPathFileName.empty()) {
660 std::string pfn = vPathFileName;
661 std::string separator(1u, PATH_SEP);
662 IGFD::Utils::ReplaceString(pfn,
"\\", separator);
663 IGFD::Utils::ReplaceString(pfn,
"/", separator);
664 size_t lastSlash = pfn.find_last_of(separator);
665 if (lastSlash != std::string::npos) {
666 res.name = pfn.substr(lastSlash + 1);
667 res.path = pfn.substr(0, lastSlash);
670 size_t lastPoint = pfn.find_last_of(
'.');
671 if (lastPoint != std::string::npos) {
676 res.ext = pfn.substr(lastPoint + 1);
677 IGFD::Utils::ReplaceString(res.name,
"." + res.ext,
"");
680 res.name = std::move(pfn);
687 std::vector<IGFD::FileInfos> ScanDirectory(
const std::string& vPath)
override {
688 std::vector<IGFD::FileInfos> res;
689 struct dirent** files =
nullptr;
690 size_t n = scandir(vPath.c_str(), &files,
nullptr,
691 [](
const struct dirent** a,
const struct dirent** b) {
692 return strcoll((*a)->d_name, (*b)->d_name);
695 for (
size_t i = 0; i < n; ++i) {
696 struct dirent* ent = files[i];
697 IGFD::FileType fileType;
698 switch (ent->d_type) {
699 case DT_DIR: fileType.SetContent(IGFD::FileType::ContentType::Directory);
break;
700 case DT_REG: fileType.SetContent(IGFD::FileType::ContentType::File);
break;
701#if defined(_IGFD_UNIX_) || (DT_LNK != DT_UNKNOWN)
707 auto filePath = vPath + ent->d_name;
709 auto filePath = vPath + IGFD::Utils::GetPathSeparator() + ent->d_name;
711 if (!stat(filePath.c_str(), &sb)) {
712 if (sb.st_mode & S_IFLNK) {
713 fileType.SetSymLink(
true);
715 fileType.SetContent(IGFD::FileType::ContentType::LinkToUnknown);
717 if (sb.st_mode & S_IFREG) {
718 fileType.SetContent(IGFD::FileType::ContentType::File);
720 }
else if (sb.st_mode & S_IFDIR) {
721 fileType.SetContent(IGFD::FileType::ContentType::Directory);
729 if (fileType.isValid()) {
730 IGFD::FileInfos _file;
731 _file.filePath = vPath;
732 _file.fileNameExt = ent->d_name;
733 _file.fileType = fileType;
734 res.push_back(_file);
737 for (
size_t i = 0; i < n; ++i) {
744 bool IsDirectory(
const std::string& vFilePathName)
override {
745 DIR *pDir = opendir(vFilePathName.c_str());
747 (void)closedir(pDir);
753#define FILE_SYSTEM_OVERRIDE FileSystemDirent
756#include CUSTOM_FILESYSTEM_INCLUDE
764bool IGFD::Utils::ImSplitter(
bool split_vertically,
float thickness,
float* size1,
float* size2,
float min_size1,
float min_size2,
float splitter_long_axis_size) {
765 using namespace ImGui;
767 ImGuiWindow* window =
g.CurrentWindow;
768 ImGuiID
id = window->GetID(
"##Splitter");
770 bb.Min = window->DC.CursorPos + (split_vertically ? ImVec2(*size1, 0.0f) : ImVec2(0.0f, *size1));
771 bb.Max = bb.Min + CalcItemSize(split_vertically ? ImVec2(thickness, splitter_long_axis_size) : ImVec2(splitter_long_axis_size, thickness), 0.0f, 0.0f);
772 return SplitterBehavior(bb,
id, split_vertically ? ImGuiAxis_X : ImGuiAxis_Y, size1, size2, min_size1, min_size2, 1.0f);
776std::string IGFD::Utils::UTF8Encode(
const std::wstring& wstr) {
780 int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (
int)wstr.size(), NULL, 0, NULL, NULL);
782 res = std::string(size_needed, 0);
783 WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (
int)wstr.size(), &res[0], size_needed, NULL, NULL);
794std::wstring IGFD::Utils::UTF8Decode(
const std::string& str) {
798 int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (
int)str.size(), NULL, 0);
800 res = std::wstring(size_needed, 0);
801 MultiByteToWideChar(CP_UTF8, 0, &str[0], (
int)str.size(), &res[0], size_needed);
811bool IGFD::Utils::ReplaceString(std::string& str, const ::std::string& oldStr, const ::std::string& newStr,
const size_t& vMaxRecursion) {
812 if (!str.empty() && oldStr != newStr) {
816 size_t max_recursion = vMaxRecursion;
818 pos = str.find(oldStr, pos);
819 if (pos != std::string::npos) {
821 str.replace(pos, oldStr.length(), newStr);
822 pos += newStr.length();
823 }
else if (found && max_recursion > 0) {
828 }
while (pos != std::string::npos);
834std::vector<std::string> IGFD::Utils::SplitStringToVector(
const std::string& vText,
const char& vDelimiter,
const bool& vPushEmpty) {
835 std::vector<std::string> arr;
836 if (!vText.empty()) {
838 size_t end = vText.find(vDelimiter, start);
839 while (
end != std::string::npos) {
840 auto token = vText.substr(start,
end - start);
841 if (!token.empty() || (token.empty() && vPushEmpty)) {
842 arr.push_back(token);
845 end = vText.find(vDelimiter, start);
847 auto token = vText.substr(start);
848 if (!token.empty() || (token.empty() && vPushEmpty)) {
849 arr.push_back(token);
855void IGFD::Utils::AppendToBuffer(
char* vBuffer,
size_t vBufferLen,
const std::string& vStr) {
856 std::string st = vStr;
857 size_t len = vBufferLen - 1u;
858 size_t slen = strlen(vBuffer);
860 if (!st.empty() && st !=
"\n") {
861 IGFD::Utils::ReplaceString(st,
"\n",
"");
862 IGFD::Utils::ReplaceString(st,
"\r",
"");
864 vBuffer[slen] =
'\0';
865 std::string str = std::string(vBuffer);
868 if (len > str.size()) {
872 strncpy_s(vBuffer, vBufferLen, str.c_str(), len);
874 strncpy(vBuffer, str.c_str(), len);
879void IGFD::Utils::ResetBuffer(
char* vBuffer) {
883void IGFD::Utils::SetBuffer(
char* vBuffer,
size_t vBufferLen,
const std::string& vStr) {
884 ResetBuffer(vBuffer);
885 AppendToBuffer(vBuffer, vBufferLen, vStr);
888std::string IGFD::Utils::LowerCaseString(
const std::string& vString) {
892 for (
char& c : str) {
893 c = (char)std::tolower(c);
899size_t IGFD::Utils::GetCharCountInString(
const std::string& vString,
const char& vChar) {
901 for (
const auto& c : vString) {
909size_t IGFD::Utils::GetLastCharPosWithMinCharCount(
const std::string& vString,
const char& vChar,
const size_t& vMinCharCount) {
911 size_t last_dot_pos = vString.size() + 1U;
912 size_t count_dots = vMinCharCount;
913 while (count_dots > 0U && last_dot_pos > 0U && last_dot_pos != std::string::npos) {
914 auto new_dot = vString.rfind(vChar, last_dot_pos - 1U);
915 if (new_dot != std::string::npos) {
916 last_dot_pos = new_dot;
924 return std::string::npos;
927std::string IGFD::Utils::GetPathSeparator() {
928 return std::string(1U, PATH_SEP);
931std::string IGFD::Utils::RoundNumber(
double vvalue,
int n) {
932 std::stringstream tmp;
933 tmp << std::setprecision(n) << std::fixed << vvalue;
937std::pair<std::string, std::string> IGFD::Utils::FormatFileSize(
size_t vByteSize) {
938 if (vByteSize != 0) {
939 static double lo = 1024.0;
940 static double ko = 1024.0 * 1024.0;
941 static double mo = 1024.0 * 1024.0 * 1024.0;
943 auto v = (double)vByteSize;
946 return {RoundNumber(v, 0), fileSizeBytes};
948 return {RoundNumber(v / lo, 2), fileSizeKiloBytes};
950 return {RoundNumber(v / ko, 2), fileSizeMegaBytes};
952 return {RoundNumber(v / mo, 2), fileSizeGigaBytes};
955 return {
"0", fileSizeBytes};
962IGFD::FileStyle::FileStyle() : color(0, 0, 0, 0) {
965IGFD::FileStyle::FileStyle(
const FileStyle& vStyle) {
966 color = vStyle.color;
969 flags = vStyle.flags;
972IGFD::FileStyle::FileStyle(
const ImVec4& vColor,
const std::string& vIcon, ImFont* vFont) : color(vColor), icon(vIcon), font(vFont) {
979void IGFD::SearchManager::Clear() {
981 IGFD::Utils::ResetBuffer(searchBuffer);
984void IGFD::SearchManager::DrawSearchBar(FileDialogInternal& vFileDialogInternal) {
986 if (IMGUI_BUTTON(resetButtonString
"##BtnImGuiFileDialogSearchField")) {
988 vFileDialogInternal.fileManager.ApplyFilteringOnFileList(vFileDialogInternal);
990 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonResetSearchString);
992 ImGui::Text(searchString);
994 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
995 bool edited = ImGui::InputText(
"##InputImGuiFileDialogSearchField", searchBuffer, MAX_FILE_DIALOG_NAME_BUFFER);
996 if (ImGui::GetItemID() == ImGui::GetActiveID()) searchInputIsActive =
true;
997 ImGui::PopItemWidth();
999 searchTag = searchBuffer;
1000 vFileDialogInternal.fileManager.ApplyFilteringOnFileList(vFileDialogInternal);
1008void IGFD::FilterInfos::setCollectionTitle(
const std::string& vTitle) {
1012void IGFD::FilterInfos::addFilter(
const std::string& vFilter,
const bool& vIsRegex) {
1013 setCollectionTitle(vFilter);
1014 addCollectionFilter(vFilter, vIsRegex);
1017void IGFD::FilterInfos::addCollectionFilter(
const std::string& vFilter,
const bool& vIsRegex) {
1019 if (vFilter.find(
'*') != std::string::npos) {
1020 const auto& regex_string = transformAsteriskBasedFilterToRegex(vFilter);
1021 addCollectionFilter(regex_string,
true);
1024 filters.try_add(vFilter);
1025 filters_optimized.try_add(Utils::LowerCaseString(vFilter));
1026 auto _count_dots = Utils::GetCharCountInString(vFilter,
'.');
1027 if (_count_dots > count_dots) {
1028 count_dots = _count_dots;
1032 auto rx = std::regex(vFilter);
1033 filters.try_add(vFilter);
1034 filters_regex.emplace_back(rx);
1035 }
catch (std::exception&) {
1041void IGFD::FilterInfos::clear() {
1044 filters_optimized.clear();
1045 filters_regex.clear();
1048bool IGFD::FilterInfos::empty()
const {
1049 return filters.empty() || filters.begin()->empty();
1052const std::string& IGFD::FilterInfos::getFirstFilter()
const {
1053 if (!filters.empty()) {
1054 return *filters.begin();
1056 return empty_string;
1059bool IGFD::FilterInfos::exist(
const FileInfos& vFileInfos,
bool vIsCaseInsensitive)
const {
1060 for (
const auto& filter : filters) {
1061 if (vFileInfos.SearchForExt(filter, vIsCaseInsensitive, count_dots)) {
1068bool IGFD::FilterInfos::regexExist(
const std::string& vFilter)
const {
1069 for (
auto regex : filters_regex) {
1070 if (std::regex_search(vFilter, regex)) {
1077std::string IGFD::FilterInfos::transformAsteriskBasedFilterToRegex(
const std::string& vFilter) {
1079 if (!vFilter.empty() && vFilter.find(
'*') != std::string::npos) {
1081 for (
const auto& c : vFilter) {
1084 }
else if (c ==
'*') {
1099const IGFD::FilterInfos& IGFD::FilterManager::GetSelectedFilter()
const {
1100 return m_SelectedFilter;
1103void IGFD::FilterManager::ParseFilters(
const char* vFilters) {
1104 m_ParsedFilters.clear();
1107 dLGFilters = vFilters;
1112 if (!dLGFilters.empty()) {
1124 bool current_filter_found =
false;
1125 bool started =
false;
1126 bool regex_started =
false;
1127 bool parenthesis_started =
false;
1130 std::string filter_name;
1132 char last_split_char = 0;
1133 for (
char c : dLGFilters) {
1135 if (regex_started) {
1139 m_ParsedFilters.emplace_back();
1140 m_ParsedFilters.back().setCollectionTitle(filter_name);
1141 filter_name.clear();
1144 last_split_char = c;
1145 }
else if (c ==
'}') {
1146 if (regex_started) {
1150 if (
word.size() > 1U && word[0] ==
'.') {
1151 if (m_ParsedFilters.empty()) {
1152 m_ParsedFilters.emplace_back();
1154 m_ParsedFilters.back().addCollectionFilter(word,
false);
1157 filter_name.clear();
1161 last_split_char = c;
1162 }
else if (c ==
'(') {
1164 if (last_split_char ==
'(') {
1165 regex_started =
true;
1167 parenthesis_started =
true;
1171 last_split_char = c;
1172 }
else if (c ==
')') {
1174 if (last_split_char ==
')') {
1175 if (regex_started) {
1177 m_ParsedFilters.back().addCollectionFilter(word,
true);
1179 m_ParsedFilters.emplace_back();
1180 m_ParsedFilters.back().addFilter(word,
true);
1183 filter_name.clear();
1184 regex_started =
false;
1187 if (!m_ParsedFilters.empty()) {
1188 m_ParsedFilters.erase(m_ParsedFilters.begin() + m_ParsedFilters.size() - 1U);
1190 m_ParsedFilters.clear();
1194 filter_name.clear();
1197 parenthesis_started =
false;
1201 last_split_char = c;
1202 }
else if (c ==
'.') {
1207 last_split_char = c;
1208 }
else if (c ==
',') {
1209 if (regex_started) {
1210 regex_started =
false;
1212 filter_name.clear();
1215 if (
word.size() > 1U && word[0] ==
'.') {
1216 m_ParsedFilters.back().addCollectionFilter(word,
false);
1218 filter_name.clear();
1221 if (
word.size() > 1U && word[0] ==
'.') {
1222 m_ParsedFilters.emplace_back();
1223 m_ParsedFilters.back().addFilter(word,
false);
1225 filter_name.clear();
1227 if (parenthesis_started) {
1243 if (!m_ParsedFilters.empty()) {
1244 m_ParsedFilters.erase(m_ParsedFilters.begin() + m_ParsedFilters.size() - 1U);
1246 m_ParsedFilters.clear();
1248 }
else if (
word.size() > 1U && word[0] ==
'.') {
1249 m_ParsedFilters.emplace_back();
1250 m_ParsedFilters.back().addFilter(word,
false);
1254 for (
const auto& it : m_ParsedFilters) {
1255 if (it.title == m_SelectedFilter.title) {
1256 m_SelectedFilter = it;
1257 current_filter_found =
true;
1262 if (!current_filter_found) {
1263 if (!m_ParsedFilters.empty()) {
1264 m_SelectedFilter = *m_ParsedFilters.begin();
1270void IGFD::FilterManager::SetSelectedFilterWithExt(
const std::string& vFilter) {
1271 if (!m_ParsedFilters.empty()) {
1272 if (!vFilter.empty()) {
1273 for (
const auto& infos : m_ParsedFilters) {
1274 for (
const auto& filter : infos.filters) {
1275 if (vFilter == filter) {
1276 m_SelectedFilter = infos;
1282 if (m_SelectedFilter.empty()) {
1283 m_SelectedFilter = *m_ParsedFilters.begin();
1288void IGFD::FilterManager::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const FileStyle& vInfos) {
1289 std::string _criteria = (vCriteria !=
nullptr) ? std::string(vCriteria) :
"";
1290 m_FilesStyle[vFlags][_criteria] = std::make_shared<FileStyle>(vInfos);
1291 m_FilesStyle[vFlags][_criteria]->flags = vFlags;
1296bool IGFD::FilterManager::m_FillFileStyle(std::shared_ptr<FileInfos> vFileInfos)
const {
1300 if (vFileInfos.use_count() && !m_FilesStyle.empty()) {
1301 for (
const auto& _flag : m_FilesStyle) {
1302 for (
const auto& _file : _flag.second) {
1303 if ((_flag.first & IGFD_FileStyleByTypeDir && _flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType.isDir() && vFileInfos->fileType.isSymLink()) ||
1304 (_flag.first & IGFD_FileStyleByTypeFile && _flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType.isFile() && vFileInfos->fileType.isSymLink()) ||
1305 (_flag.first & IGFD_FileStyleByTypeLink && vFileInfos->fileType.isSymLink()) || (_flag.first & IGFD_FileStyleByTypeDir && vFileInfos->fileType.isDir()) ||
1306 (_flag.first & IGFD_FileStyleByTypeFile && vFileInfos->fileType.isFile())) {
1307 if (_file.first.empty()) {
1308 vFileInfos->fileStyle = _file.second;
1309 }
else if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileNameExt,
1310 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_FileStyleByExtention) {
1318 if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileExtLevels[0], std::regex(_file.first))) {
1319 vFileInfos->fileStyle = _file.second;
1320 }
else if (vFileInfos->SearchForExt(_file.first,
false)) {
1321 vFileInfos->fileStyle = _file.second;
1325 if (_flag.first & IGFD_FileStyleByFullName) {
1326 if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileNameExt, std::regex(_file.first))) {
1327 vFileInfos->fileStyle = _file.second;
1328 }
else if (_file.first == vFileInfos->fileNameExt) {
1329 vFileInfos->fileStyle = _file.second;
1333 if (_flag.first & IGFD_FileStyleByContainedInFullName) {
1334 if (_file.first.find(
"((") != std::string::npos && std::regex_search(vFileInfos->fileNameExt, std::regex(_file.first))) {
1335 vFileInfos->fileStyle = _file.second;
1336 }
else if (vFileInfos->fileNameExt.find(_file.first) != std::string::npos) {
1337 vFileInfos->fileStyle = _file.second;
1341 for (
auto& functor : m_FilesStyleFunctors) {
1344 if (functor(*(vFileInfos.get()), result)) {
1345 vFileInfos->fileStyle = std::make_shared<FileStyle>(std::move(result));
1350 if (vFileInfos->fileStyle.use_count()) {
1360void IGFD::FilterManager::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const ImVec4& vColor,
const std::string& vIcon, ImFont* vFont) {
1361 std::string _criteria;
1362 if (vCriteria) _criteria = std::string(vCriteria);
1363 m_FilesStyle[vFlags][_criteria] = std::make_shared<FileStyle>(vColor, vIcon, vFont);
1364 m_FilesStyle[vFlags][_criteria]->flags = vFlags;
1367void IGFD::FilterManager::SetFileStyle(FileStyle::FileStyleFunctor vFunctor) {
1369 m_FilesStyleFunctors.push_back(vFunctor);
1374bool IGFD::FilterManager::GetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const std::string& vCriteria, ImVec4* vOutColor, std::string* vOutIcon, ImFont** vOutFont) {
1376 if (!m_FilesStyle.empty()) {
1377 if (m_FilesStyle.find(vFlags) != m_FilesStyle.end()) {
1378 if (vFlags & IGFD_FileStyleByContainedInFullName) {
1380 for (
const auto& _file : m_FilesStyle.at(vFlags)) {
1381 if (vCriteria.find(_file.first) != std::string::npos) {
1382 if (_file.second.use_count()) {
1383 *vOutColor = _file.second->color;
1384 if (vOutIcon) *vOutIcon = _file.second->icon;
1385 if (vOutFont) *vOutFont = _file.second->font;
1391 if (m_FilesStyle.at(vFlags).find(vCriteria) != m_FilesStyle.at(vFlags).end()) {
1392 *vOutColor = m_FilesStyle[vFlags][vCriteria]->color;
1393 if (vOutIcon) *vOutIcon = m_FilesStyle[vFlags][vCriteria]->icon;
1394 if (vOutFont) *vOutFont = m_FilesStyle[vFlags][vCriteria]->font;
1400 for (
const auto& _flag : m_FilesStyle) {
1401 if (_flag.first & vFlags) {
1402 if (_flag.first & IGFD_FileStyleByContainedInFullName) {
1404 for (
const auto& _file : m_FilesStyle.at(_flag.first)) {
1405 if (vCriteria.find(_file.first) != std::string::npos) {
1406 if (_file.second.use_count()) {
1407 *vOutColor = _file.second->color;
1408 if (vOutIcon) *vOutIcon = _file.second->icon;
1409 if (vOutFont) *vOutFont = _file.second->font;
1415 if (m_FilesStyle.at(_flag.first).find(vCriteria) != m_FilesStyle.at(_flag.first).end()) {
1416 *vOutColor = m_FilesStyle[_flag.first][vCriteria]->color;
1417 if (vOutIcon) *vOutIcon = m_FilesStyle[_flag.first][vCriteria]->icon;
1418 if (vOutFont) *vOutFont = m_FilesStyle[_flag.first][vCriteria]->font;
1430void IGFD::FilterManager::ClearFilesStyle() {
1431 m_FilesStyle.clear();
1434bool IGFD::FilterManager::IsCoveredByFilters(
const FileInfos& vFileInfos,
bool vIsCaseInsensitive)
const {
1435 if (!dLGFilters.empty() && !m_SelectedFilter.empty()) {
1436 return (m_SelectedFilter.exist(vFileInfos, vIsCaseInsensitive) || m_SelectedFilter.regexExist(vFileInfos.fileNameExt));
1442float IGFD::FilterManager::GetFilterComboBoxWidth()
const {
1443#if FILTER_COMBO_AUTO_SIZE
1444 const auto& combo_width =
ImGui::CalcTextSize(m_SelectedFilter.title.c_str()).x + ImGui::GetFrameHeight() + ImGui::GetStyle().ItemInnerSpacing.x;
1445 return ImMax(combo_width, FILTER_COMBO_MIN_WIDTH);
1447 return FILTER_COMBO_MIN_WIDTH;
1451bool IGFD::FilterManager::DrawFilterComboBox(FileDialogInternal& vFileDialogInternal) {
1452 if (!dLGFilters.empty()) {
1454 bool needToApllyNewFilter =
false;
1455 ImGui::PushItemWidth(GetFilterComboBoxWidth());
1456 if (IMGUI_BEGIN_COMBO(
"##Filters", m_SelectedFilter.title.c_str(), ImGuiComboFlags_None)) {
1458 for (
const auto& filter : m_ParsedFilters) {
1459 const bool item_selected = (
filter.title == m_SelectedFilter.title);
1460 ImGui::PushID((
void*)(intptr_t)i++);
1461 if (ImGui::Selectable(
filter.title.c_str(), item_selected)) {
1462 m_SelectedFilter =
filter;
1463 needToApllyNewFilter =
true;
1469 ImGui::PopItemWidth();
1470 if (needToApllyNewFilter) {
1471 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
1473 return needToApllyNewFilter;
1478std::string IGFD::FilterManager::ReplaceExtentionWithCurrentFilterIfNeeded(
const std::string& vFileName, IGFD_ResultMode vFlag)
const {
1479 auto result = vFileName;
1480 if (!result.empty()) {
1481 const auto& current_filter = m_SelectedFilter.getFirstFilter();
1482 if (!current_filter.empty()) {
1483 Utils::ReplaceString(result,
"..",
".");
1486 if (current_filter.find(
"((") != std::string::npos) {
1491 if (current_filter.find(
".*") != std::string::npos) {
1496 case IGFD_ResultMode_KeepInputFile: {
1499 case IGFD_ResultMode_OverwriteFileExt: {
1500 const auto& count_dots = Utils::GetCharCountInString(vFileName,
'.');
1501 const auto& min_dots = ImMin<size_t>(count_dots, m_SelectedFilter.count_dots);
1502 const auto& lp = Utils::GetLastCharPosWithMinCharCount(vFileName,
'.', min_dots);
1503 if (lp != std::string::npos) {
1504 const auto& file_name_without_user_ext = vFileName.substr(0, lp);
1505 result = file_name_without_user_ext + current_filter;
1507 result = vFileName + current_filter;
1511 case IGFD_ResultMode_AddIfNoFileExt: {
1512 const auto& count_dots = Utils::GetCharCountInString(vFileName,
'.');
1513 const auto& min_dots = ImMin<size_t>(count_dots, m_SelectedFilter.count_dots);
1514 const auto& lp = Utils::GetLastCharPosWithMinCharCount(vFileName,
'.', min_dots);
1515 if (lp == std::string::npos ||
1516 lp == (vFileName.size() - 1U)) {
1517 const auto& file_name_without_user_ext = vFileName.substr(0, lp);
1518 result = file_name_without_user_ext + current_filter;
1524 Utils::ReplaceString(result,
"..",
".");
1530void IGFD::FilterManager::SetDefaultFilterIfNotDefined() {
1531 if (m_SelectedFilter.empty() &&
1532 !m_ParsedFilters.empty()) {
1533 m_SelectedFilter = *m_ParsedFilters.begin();
1541IGFD::FileType::FileType() =
default;
1542IGFD::FileType::FileType(
const ContentType& vContentType,
const bool& vIsSymlink) : m_Content(vContentType), m_Symlink(vIsSymlink) {
1544void IGFD::FileType::SetContent(
const ContentType& vContentType) {
1545 m_Content = vContentType;
1547void IGFD::FileType::SetSymLink(
const bool& vIsSymlink) {
1548 m_Symlink = vIsSymlink;
1550bool IGFD::FileType::isValid()
const {
1551 return m_Content != ContentType::Invalid;
1553bool IGFD::FileType::isDir()
const {
1554 return m_Content == ContentType::Directory;
1556bool IGFD::FileType::isFile()
const {
1557 return m_Content == ContentType::File;
1559bool IGFD::FileType::isLinkToUnknown()
const {
1560 return m_Content == ContentType::LinkToUnknown;
1562bool IGFD::FileType::isSymLink()
const {
1566bool IGFD::FileType::operator==(
const FileType& rhs)
const {
1567 return m_Content == rhs.m_Content;
1569bool IGFD::FileType::operator!=(
const FileType& rhs)
const {
1570 return m_Content != rhs.m_Content;
1572bool IGFD::FileType::operator<(
const FileType& rhs)
const {
1573 return m_Content < rhs.m_Content;
1575bool IGFD::FileType::operator>(
const FileType& rhs)
const {
1576 return m_Content > rhs.m_Content;
1583bool IGFD::FileInfos::SearchForTag(
const std::string& vTag)
const {
1584 if (!vTag.empty()) {
1585 if (fileNameExt_optimized ==
"..")
return true;
1586 return fileNameExt_optimized.find(vTag) != std::string::npos ||
1587 fileNameExt.find(vTag) != std::string::npos;
1594bool IGFD::FileInfos::SearchForExt(
const std::string& vExt,
const bool& vIsCaseInsensitive,
const size_t& vMaxLevel)
const {
1595 if (!vExt.empty()) {
1596 const auto& ext_to_check = vIsCaseInsensitive ? Utils::LowerCaseString(vExt) : vExt;
1597 const auto& ext_levels = vIsCaseInsensitive ? fileExtLevels_optimized : fileExtLevels;
1598 if (vMaxLevel >= 1 && countExtDot >= vMaxLevel) {
1599 for (
const auto& ext : ext_levels) {
1600 if (!ext.empty() && ext == ext_to_check) {
1605 return (fileExtLevels[0] == vExt);
1611bool IGFD::FileInfos::SearchForExts(
const std::string& vComaSepExts,
const bool& vIsCaseInsensitive,
const size_t& vMaxLevel)
const {
1612 if (!vComaSepExts.empty()) {
1613 const auto& arr = Utils::SplitStringToVector(vComaSepExts,
',',
false);
1614 for (
const auto& a : arr) {
1615 if (SearchForExt(a, vIsCaseInsensitive, vMaxLevel)) {
1623bool IGFD::FileInfos::FinalizeFileTypeParsing(
const size_t& vMaxDotToExtract) {
1624 if (fileType.isFile() || fileType.isLinkToUnknown()) {
1625 countExtDot = Utils::GetCharCountInString(fileNameExt,
'.');
1627 if (countExtDot > 1U) {
1628 size_t max_dot_to_extract = vMaxDotToExtract;
1629 if (max_dot_to_extract > countExtDot) {
1630 max_dot_to_extract = countExtDot;
1632 lpt = Utils::GetLastCharPosWithMinCharCount(fileNameExt,
'.', max_dot_to_extract);
1634 lpt = fileNameExt.find_first_of(
'.');
1636 if (lpt != std::string::npos) {
1638 fileNameLevels[lvl] = fileNameExt.substr(0, lpt);
1639 fileNameLevels[lvl] = Utils::LowerCaseString(fileNameLevels[lvl]);
1640 fileExtLevels[lvl] = fileNameExt.substr(lpt);
1641 fileExtLevels_optimized[lvl] = Utils::LowerCaseString(fileExtLevels[lvl]);
1642 if (countExtDot > 1U) {
1643 auto count = countExtDot;
1644 while (count > 0 && lpt != std::string::npos && lvl < fileExtLevels.size()) {
1646 if (fileNameExt.size() > lpt) {
1647 lpt = fileNameExt.find_first_of(
'.', lpt);
1648 if (lpt != std::string::npos) {
1649 fileNameLevels[lvl] = fileNameExt.substr(0, lpt);
1650 fileNameLevels[lvl] = Utils::LowerCaseString(fileNameLevels[lvl]);
1651 fileExtLevels[lvl] = fileNameExt.substr(lpt);
1652 fileExtLevels_optimized[lvl] = Utils::LowerCaseString(fileExtLevels[lvl]);
1667IGFD::FileManager::FileManager() {
1668 fsRoot = IGFD::Utils::GetPathSeparator();
1669 m_FileSystemName =
typeid(FILE_SYSTEM_OVERRIDE).name();
1671 m_FileSystemPtr = std::unique_ptr<FILE_SYSTEM_OVERRIDE>(
new FILE_SYSTEM_OVERRIDE());
1675void IGFD::FileManager::OpenCurrentPath(
const FileDialogInternal& vFileDialogInternal) {
1679 if (dLGDirectoryMode) {
1680 SetDefaultFileName(
".");
1682 SetDefaultFileName(dLGDefaultFileName);
1684 ScanDir(vFileDialogInternal, GetCurrentPath());
1687void IGFD::FileManager::SortFields(
const FileDialogInternal& vFileDialogInternal) {
1688 m_SortFields(vFileDialogInternal, m_FileList, m_FilteredFileList);
1691void IGFD::FileManager::m_SortFields(
const FileDialogInternal& vFileDialogInternal, std::vector<std::shared_ptr<FileInfos> >& vFileInfosList, std::vector<std::shared_ptr<FileInfos> >& vFileInfosFilteredList) {
1692 static constexpr const char* defaultHeaderString[] = {
1693 tableHeaderFileNameString,
1694 tableHeaderFileTypeString,
1695 tableHeaderFileSizeString,
1696 tableHeaderFileDateString,
1697#ifdef USE_THUMBNAILS
1698 tableHeaderFileThumbnailsString,
1701 for (
int i = 0; i < SortingFieldEnum::NUM_FIELDS; ++i) {
1702 header[i] = defaultHeaderString[i];
1704 bool ascending = sortingDirection[sortingField];
1705#ifdef USE_CUSTOM_SORTING_ICON
1706 header[sortingField] = (ascending ? tableHeaderAscendingIcon : tableHeaderDescendingIcon)
1707 + header[sortingField];
1710 std::stable_sort(vFileInfosList.begin(), vFileInfosList.end(), [&](
const std::shared_ptr<FileInfos>& a,
const std::shared_ptr<FileInfos>& b) ->
bool {
1711 bool a_used = a.use_count() != 0;
1712 bool b_used = b.use_count() != 0;
1713 if (a_used != b_used) return a_used < b_used;
1714 if (!a_used) return true;
1717 bool a_not_dotdot = a->fileNameExt !=
"..";
1718 bool b_not_dotdot = b->fileNameExt !=
"..";
1719 if (a_not_dotdot != b_not_dotdot) return a_not_dotdot < b_not_dotdot;
1721 auto compare = [&](auto extractor) {
1723 auto a_type = a->fileType;
1724 auto b_type = b->fileType;
1725 if (a_type != b_type) return ascending ? a_type < b_type : b_type < a_type;
1728 auto a_properties = extractor(a);
1729 auto b_properties = extractor(b);
1730 return ascending ? a_properties < b_properties : b_properties < a_properties;
1732 switch (sortingField) {
1733 case SortingFieldEnum::FIELD_FILENAME:
1734 return compare([](
const auto& x) {
return x->fileNameExt_optimized; });
1735 case SortingFieldEnum::FIELD_TYPE:
1736 return compare([](
const auto& x) {
return x->fileExtLevels_optimized[0]; });
1737 case SortingFieldEnum::FIELD_SIZE:
1738 return compare([](
const auto& x) {
return x->fileSize; });
1739 case SortingFieldEnum::FIELD_DATE:
1740 return compare([](
const auto& x) {
return x->fileModifDate; });
1741#ifdef USE_THUMBNAILS
1742 case SortingFieldEnum::FIELD_THUMBNAILS:
1743 return compare([](
const auto& x) {
return std::make_tuple(x->thumbnailInfo.textureWidth, x->thumbnailInfo.textureHeight); });
1750 m_ApplyFilteringOnFileList(vFileDialogInternal, vFileInfosList, vFileInfosFilteredList);
1753bool IGFD::FileManager::m_CompleteFileInfosWithUserFileAttirbutes(
const FileDialogInternal& vFileDialogInternal,
const std::shared_ptr<FileInfos>& vInfos) {
1754 if (vFileDialogInternal.getDialogConfig().userFileAttributes !=
nullptr) {
1755 if (!vFileDialogInternal.getDialogConfig().userFileAttributes(vInfos.get(), vFileDialogInternal.getDialogConfig().userDatas)) {
1758 if (!vInfos->fileType.isDir()) {
1759 vInfos->formatedFileSize = IGFD::Utils::FormatFileSize(vInfos->fileSize);
1766void IGFD::FileManager::ClearFileLists() {
1767 m_FilteredFileList.clear();
1771void IGFD::FileManager::ClearPathLists() {
1772 m_FilteredPathList.clear();
1776void IGFD::FileManager::m_AddFile(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath,
const std::string& vFileName,
const FileType& vFileType) {
1777 auto infos = std::make_shared<FileInfos>();
1779 infos->filePath = vPath;
1780 infos->fileNameExt = vFileName;
1781 infos->fileNameExt_optimized = Utils::LowerCaseString(infos->fileNameExt);
1782 infos->fileType = vFileType;
1784 if (infos->fileNameExt.empty() || (infos->fileNameExt ==
"." && !vFileDialogInternal.filterManager.dLGFilters.empty())) {
1788 if (infos->fileNameExt !=
".." && (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DontShowHiddenFiles) && infos->fileNameExt[0] ==
'.') {
1789 if (!vFileDialogInternal.filterManager.dLGFilters.empty() || (vFileDialogInternal.filterManager.dLGFilters.empty() && infos->fileNameExt !=
".")) {
1794 if (infos->FinalizeFileTypeParsing(vFileDialogInternal.filterManager.GetSelectedFilter().count_dots)) {
1795 if (!vFileDialogInternal.filterManager.IsCoveredByFilters(*infos.get(), (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_CaseInsensitiveExtention) != 0)) {
1800 vFileDialogInternal.filterManager.m_FillFileStyle(infos);
1802 m_CompleteFileInfos(infos);
1804 if (m_CompleteFileInfosWithUserFileAttirbutes(vFileDialogInternal, infos)) {
1805 m_FileList.push_back(infos);
1809void IGFD::FileManager::m_AddPath(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath,
const std::string& vFileName,
const FileType& vFileType) {
1810 if (!vFileType.isDir())
return;
1812 auto infos = std::make_shared<FileInfos>();
1814 infos->filePath = vPath;
1815 infos->fileNameExt = vFileName;
1816 infos->fileNameExt_optimized = Utils::LowerCaseString(infos->fileNameExt);
1817 infos->fileType = vFileType;
1819 if (infos->fileNameExt.empty() || (infos->fileNameExt ==
"." && !vFileDialogInternal.filterManager.dLGFilters.empty())) {
1823 if (infos->fileNameExt !=
".." && (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DontShowHiddenFiles) && infos->fileNameExt[0] ==
'.') {
1824 if (!vFileDialogInternal.filterManager.dLGFilters.empty() || (vFileDialogInternal.filterManager.dLGFilters.empty() && infos->fileNameExt !=
".")) {
1829 vFileDialogInternal.filterManager.m_FillFileStyle(infos);
1831 m_CompleteFileInfos(infos);
1833 if (m_CompleteFileInfosWithUserFileAttirbutes(vFileDialogInternal, infos)) {
1834 m_PathList.push_back(infos);
1838void IGFD::FileManager::ScanDir(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath) {
1839 std::string path = vPath;
1841 if (m_CurrentPathDecomposition.empty()) {
1842 SetCurrentDir(path);
1845 if (!m_CurrentPathDecomposition.empty()) {
1847 if (path == fsRoot) path += IGFD::Utils::GetPathSeparator();
1852 const auto& files = m_FileSystemPtr->ScanDirectory(vPath);
1853 for (
const auto& file : files) {
1854 m_AddFile(vFileDialogInternal, path, file.fileNameExt, file.fileType);
1857 m_SortFields(vFileDialogInternal, m_FileList, m_FilteredFileList);
1861void IGFD::FileManager::m_ScanDirForPathSelection(
const FileDialogInternal& vFileDialogInternal,
const std::string& vPath) {
1862 std::string path = vPath;
1864 if (!path.empty()) {
1866 if (path == fsRoot) path += IGFD::Utils::GetPathSeparator();
1871 const auto& files = m_FileSystemPtr->ScanDirectory(path);
1872 for (
const auto& file : files) {
1873 if (file.fileType.isDir()) {
1874 m_AddPath(vFileDialogInternal, path, file.fileNameExt, file.fileType);
1878 m_SortFields(vFileDialogInternal, m_PathList, m_FilteredPathList);
1882void IGFD::FileManager::m_OpenPathPopup(
const FileDialogInternal& vFileDialogInternal, std::vector<std::string>::iterator vPathIter) {
1883 const auto path = ComposeNewPath(vPathIter);
1884 m_ScanDirForPathSelection(vFileDialogInternal, path);
1885 m_PopupComposedPath = vPathIter;
1886 ImGui::OpenPopup(
"IGFD_Path_Popup");
1889bool IGFD::FileManager::GetDrives() {
1890 auto drives = m_FileSystemPtr->GetDrivesList();
1891 if (!drives.empty()) {
1892 m_CurrentPath.clear();
1893 m_CurrentPathDecomposition.clear();
1895 for (
auto& drive : drives) {
1896 auto info = std::make_shared<FileInfos>();
1897 info->fileNameExt = drive;
1898 info->fileNameExt_optimized = Utils::LowerCaseString(drive);
1899 info->fileType.SetContent(FileType::ContentType::Directory);
1901 if (!info->fileNameExt.empty()) {
1902 m_FileList.push_back(info);
1911bool IGFD::FileManager::IsComposerEmpty() {
1912 return m_CurrentPathDecomposition.empty();
1915size_t IGFD::FileManager::GetComposerSize() {
1916 return m_CurrentPathDecomposition.size();
1919bool IGFD::FileManager::IsFileListEmpty() {
1920 return m_FileList.empty();
1923bool IGFD::FileManager::IsPathListEmpty() {
1924 return m_PathList.empty();
1927size_t IGFD::FileManager::GetFullFileListSize() {
1928 return m_FileList.size();
1931std::shared_ptr<IGFD::FileInfos> IGFD::FileManager::GetFullFileAt(
size_t vIdx) {
1932 if (vIdx < m_FileList.size())
return m_FileList[vIdx];
1936bool IGFD::FileManager::IsFilteredListEmpty() {
1937 return m_FilteredFileList.empty();
1940bool IGFD::FileManager::IsPathFilteredListEmpty() {
1941 return m_FilteredPathList.empty();
1944size_t IGFD::FileManager::GetFilteredListSize() {
1945 return m_FilteredFileList.size();
1948size_t IGFD::FileManager::GetPathFilteredListSize() {
1949 return m_FilteredPathList.size();
1952std::shared_ptr<IGFD::FileInfos> IGFD::FileManager::GetFilteredFileAt(
size_t vIdx) {
1953 if (vIdx < m_FilteredFileList.size())
return m_FilteredFileList[vIdx];
1957std::shared_ptr<IGFD::FileInfos> IGFD::FileManager::GetFilteredPathAt(
size_t vIdx) {
1958 if (vIdx < m_FilteredPathList.size())
return m_FilteredPathList[vIdx];
1962std::vector<std::string>::iterator IGFD::FileManager::GetCurrentPopupComposedPath() {
1963 return m_PopupComposedPath;
1966bool IGFD::FileManager::IsFileNameSelected(
const std::string& vFileName) {
1967 return m_SelectedFileNames.find(vFileName) != m_SelectedFileNames.end();
1970std::string IGFD::FileManager::GetBack() {
1971 return m_CurrentPathDecomposition.back();
1974void IGFD::FileManager::ClearComposer() {
1975 m_CurrentPathDecomposition.clear();
1978void IGFD::FileManager::ClearAll() {
1983void IGFD::FileManager::ApplyFilteringOnFileList(
const FileDialogInternal& vFileDialogInternal) {
1984 m_ApplyFilteringOnFileList(vFileDialogInternal, m_FileList, m_FilteredFileList);
1987void IGFD::FileManager::m_ApplyFilteringOnFileList(
const FileDialogInternal& vFileDialogInternal, std::vector<std::shared_ptr<FileInfos> >& vFileInfosList, std::vector<std::shared_ptr<FileInfos> >& vFileInfosFilteredList) {
1988 vFileInfosFilteredList.clear();
1989 for (
const auto& file : vFileInfosList) {
1990 if (!file.use_count())
continue;
1992 if (!file->SearchForTag(vFileDialogInternal.searchManager.searchTag))
1994 if (dLGDirectoryMode && !file->fileType.isDir()) show =
false;
1995 if (show) vFileInfosFilteredList.push_back(file);
1999void IGFD::FileManager::m_CompleteFileInfos(
const std::shared_ptr<FileInfos>& vInfos) {
2000 if (!vInfos.use_count())
return;
2002 if (vInfos->fileNameExt !=
"." && vInfos->fileNameExt !=
"..") {
2021 if (vInfos->fileType.isFile() || vInfos->fileType.isLinkToUnknown() || vInfos->fileType.isDir()) {
2022 fpn = vInfos->filePath + IGFD::Utils::GetPathSeparator() + vInfos->fileNameExt;
2025 struct stat statInfos = {};
2027 int result = stat(fpn.c_str(), &statInfos);
2029 if (!vInfos->fileType.isDir()) {
2030 vInfos->fileSize = (size_t)statInfos.st_size;
2031 vInfos->formatedFileSize = IGFD::Utils::FormatFileSize(vInfos->fileSize);
2037 errno_t err = localtime_s(&_tm, &statInfos.st_mtime);
2038 if (!err) len = strftime(timebuf, 99, DateTimeFormat, &_tm);
2040 struct tm* _tm = localtime(&statInfos.st_mtime);
2041 if (_tm) len = strftime(timebuf, 99, DateTimeFormat, _tm);
2044 vInfos->fileModifDate = std::string(timebuf, len);
2050void IGFD::FileManager::m_RemoveFileNameInSelection(
const std::string& vFileName) {
2051 m_SelectedFileNames.erase(vFileName);
2053 if (m_SelectedFileNames.size() == 1) {
2054 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%s", vFileName.c_str());
2056 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%zu files Selected", m_SelectedFileNames.size());
2060void IGFD::FileManager::m_m_AddFileNameInSelection(
const std::string& vFileName,
bool vSetLastSelectionFileName) {
2061 m_SelectedFileNames.emplace(vFileName);
2063 if (m_SelectedFileNames.size() == 1) {
2064 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%s", vFileName.c_str());
2066 snprintf(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER,
"%zu files Selected", m_SelectedFileNames.size());
2069 if (vSetLastSelectionFileName) m_LastSelectedFileName = vFileName;
2072void IGFD::FileManager::SetCurrentDir(
const std::string& vPath) {
2073 std::string path = vPath;
2075 if (fsRoot == path) path += IGFD::Utils::GetPathSeparator();
2078 bool dir_opened = m_FileSystemPtr->IsDirectory(path);
2081 dir_opened = m_FileSystemPtr->IsDirectory(path);
2086 std::wstring wpath = IGFD::Utils::UTF8Decode(path);
2087 numchar = GetFullPathNameW(wpath.c_str(), 0,
nullptr,
nullptr);
2088 std::wstring fpath(numchar, 0);
2089 GetFullPathNameW(wpath.c_str(), numchar, (
wchar_t*)fpath.data(),
nullptr);
2090 std::string real_path = IGFD::Utils::UTF8Encode(fpath);
2091 while (real_path.back() ==
'\0')
2092 real_path = real_path.substr(0, real_path.size() - 1U);
2093 if (!real_path.empty())
2094#elif defined(_IGFD_UNIX_)
2095 char real_path[PATH_MAX];
2096 char* numchar = realpath(path.c_str(), real_path);
2097 if (numchar !=
nullptr)
2100 m_CurrentPath = std::move(real_path);
2101 if (m_CurrentPath[m_CurrentPath.size() - 1] == PATH_SEP) {
2102 m_CurrentPath = m_CurrentPath.substr(0, m_CurrentPath.size() - 1);
2104 IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
2105 m_CurrentPathDecomposition = IGFD::Utils::SplitStringToVector(m_CurrentPath, PATH_SEP,
false);
2107 m_CurrentPathDecomposition.insert(m_CurrentPathDecomposition.begin(), IGFD::Utils::GetPathSeparator());
2109 if (!m_CurrentPathDecomposition.empty()) {
2111 fsRoot = m_CurrentPathDecomposition[0];
2118bool IGFD::FileManager::CreateDir(
const std::string& vPath) {
2119 if (!vPath.empty()) {
2120 std::string path = m_CurrentPath + IGFD::Utils::GetPathSeparator() + vPath;
2121 return m_FileSystemPtr->CreateDirectoryIfNotExist(path);
2126std::string IGFD::FileManager::ComposeNewPath(std::vector<std::string>::iterator vIter) {
2132 res = *vIter + IGFD::Utils::GetPathSeparator() + res;
2133#elif defined(_IGFD_UNIX_)
2134 if (*vIter == fsRoot)
2137 res = *vIter + PATH_SEP + res;
2142 if (vIter == m_CurrentPathDecomposition.begin()) {
2144 if (res[0] != PATH_SEP) res = PATH_SEP + res;
2146 if (res.back() != PATH_SEP) res.push_back(PATH_SEP);
2157bool IGFD::FileManager::SetPathOnParentDirectoryIfAny() {
2158 if (m_CurrentPathDecomposition.size() > 1) {
2159 m_CurrentPath = ComposeNewPath(m_CurrentPathDecomposition.end() - 2);
2165std::string IGFD::FileManager::GetCurrentPath() {
2166 if (m_CurrentPath.empty()) m_CurrentPath =
".";
2167 return m_CurrentPath;
2170void IGFD::FileManager::SetCurrentPath(
const std::string& vCurrentPath) {
2171 if (vCurrentPath.empty())
2172 m_CurrentPath =
".";
2174 m_CurrentPath = vCurrentPath;
2177void IGFD::FileManager::SetDefaultFileName(
const std::string& vFileName) {
2178 dLGDefaultFileName = vFileName;
2179 IGFD::Utils::SetBuffer(fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER, vFileName);
2182bool IGFD::FileManager::SelectDirectory(
const std::shared_ptr<FileInfos>& vInfos) {
2183 if (!vInfos.use_count())
return false;
2185 bool pathClick =
false;
2187 if (vInfos->fileNameExt ==
"..") {
2188 pathClick = SetPathOnParentDirectoryIfAny();
2190 std::string newPath;
2193 newPath = vInfos->fileNameExt + IGFD::Utils::GetPathSeparator();
2196 if (fsRoot == m_CurrentPath)
2197 newPath = m_CurrentPath + vInfos->fileNameExt;
2200 newPath = m_CurrentPath + IGFD::Utils::GetPathSeparator() + vInfos->fileNameExt;
2203 if (m_FileSystemPtr->IsDirectoryCanBeOpened(newPath)) {
2205 m_CurrentPath = vInfos->fileNameExt;
2206 fsRoot = m_CurrentPath;
2208 m_CurrentPath = newPath;
2217void IGFD::FileManager::SelectFileName(
const FileDialogInternal& vFileDialogInternal,
const std::shared_ptr<FileInfos>& vInfos) {
2218 if (!vInfos.use_count())
return;
2220 if (ImGui::IsKeyDown(ImGuiMod_Ctrl)) {
2221 if (dLGcountSelectionMax == 0)
2223 if (m_SelectedFileNames.find(vInfos->fileNameExt) == m_SelectedFileNames.end())
2225 m_m_AddFileNameInSelection(vInfos->fileNameExt,
true);
2227 m_RemoveFileNameInSelection(vInfos->fileNameExt);
2231 if (m_SelectedFileNames.size() < dLGcountSelectionMax) {
2232 if (m_SelectedFileNames.find(vInfos->fileNameExt) == m_SelectedFileNames.end())
2234 m_m_AddFileNameInSelection(vInfos->fileNameExt,
true);
2236 m_RemoveFileNameInSelection(vInfos->fileNameExt);
2240 }
else if (ImGui::IsKeyDown(ImGuiMod_Shift)) {
2241 if (dLGcountSelectionMax != 1) {
2242 m_SelectedFileNames.clear();
2244 bool startMultiSelection =
false;
2245 std::string fileNameToSelect = vInfos->fileNameExt;
2246 std::string savedLastSelectedFileName;
2247 for (
const auto& file : m_FileList) {
2248 if (!file.use_count())
continue;
2250 bool canTake =
true;
2251 if (!file->SearchForTag(vFileDialogInternal.searchManager.searchTag)) canTake =
false;
2254 if (file->fileNameExt == m_LastSelectedFileName) {
2255 startMultiSelection =
true;
2256 m_m_AddFileNameInSelection(m_LastSelectedFileName,
false);
2257 }
else if (startMultiSelection) {
2258 if (dLGcountSelectionMax == 0)
2260 m_m_AddFileNameInSelection(file->fileNameExt,
false);
2262 if (m_SelectedFileNames.size() < dLGcountSelectionMax) {
2263 m_m_AddFileNameInSelection(file->fileNameExt,
false);
2265 startMultiSelection =
false;
2266 if (!savedLastSelectedFileName.empty()) m_LastSelectedFileName = savedLastSelectedFileName;
2272 if (file->fileNameExt == fileNameToSelect) {
2273 if (!startMultiSelection)
2275 savedLastSelectedFileName = m_LastSelectedFileName;
2276 m_LastSelectedFileName = fileNameToSelect;
2277 fileNameToSelect = savedLastSelectedFileName;
2278 startMultiSelection =
true;
2279 m_m_AddFileNameInSelection(m_LastSelectedFileName,
false);
2281 startMultiSelection =
false;
2282 if (!savedLastSelectedFileName.empty()) m_LastSelectedFileName = savedLastSelectedFileName;
2290 m_SelectedFileNames.clear();
2291 IGFD::Utils::ResetBuffer(fileNameBuffer);
2292 m_m_AddFileNameInSelection(vInfos->fileNameExt,
true);
2296void IGFD::FileManager::DrawDirectoryCreation(
const FileDialogInternal& vFileDialogInternal) {
2297 if (vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableCreateDirectoryButton)
return;
2299 if (IMGUI_BUTTON(createDirButtonString)) {
2300 if (!m_CreateDirectoryMode) {
2301 m_CreateDirectoryMode =
true;
2302 IGFD::Utils::ResetBuffer(directoryNameBuffer);
2305 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonCreateDirString);
2307 if (m_CreateDirectoryMode) {
2310 ImGui::PushItemWidth(100.0f);
2311 ImGui::InputText(
"##DirectoryFileName", directoryNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER);
2312 ImGui::PopItemWidth();
2316 if (IMGUI_BUTTON(okButtonString)) {
2317 std::string newDir = std::string(directoryNameBuffer);
2318 if (CreateDir(newDir)) {
2319 SetCurrentPath(m_CurrentPath + IGFD::Utils::GetPathSeparator() + newDir);
2320 OpenCurrentPath(vFileDialogInternal);
2323 m_CreateDirectoryMode =
false;
2328 if (IMGUI_BUTTON(cancelButtonString)) {
2329 m_CreateDirectoryMode =
false;
2336void IGFD::FileManager::DrawPathComposer(
const FileDialogInternal& vFileDialogInternal) {
2337 if (IMGUI_BUTTON(resetButtonString)) {
2338 SetCurrentPath(
".");
2339 OpenCurrentPath(vFileDialogInternal);
2341 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonResetPathString);
2346 if (IMGUI_BUTTON(drivesButtonString)) {
2347 drivesClicked =
true;
2349 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonDriveString);
2354 if (IMGUI_BUTTON(editPathButtonString)) {
2355 inputPathActivated = !inputPathActivated;
2356 if (inputPathActivated) {
2357 if (!m_CurrentPathDecomposition.empty()) {
2358 auto endIt = m_CurrentPathDecomposition.end();
2359 m_CurrentPath = ComposeNewPath(--endIt);
2360 IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
2364 if (ImGui::IsItemHovered()) ImGui::SetTooltip(buttonEditPathString);
2368 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
2371 if (!m_CurrentPathDecomposition.empty()) {
2374 if (inputPathActivated) {
2375 ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x);
2376 ImGui::InputText(
"##pathedition", inputPathBuffer, MAX_PATH_BUFFER_SIZE);
2377 ImGui::PopItemWidth();
2380 for (
auto itPathDecomp = m_CurrentPathDecomposition.begin(); itPathDecomp != m_CurrentPathDecomposition.end(); ++itPathDecomp) {
2381 if (itPathDecomp != m_CurrentPathDecomposition.begin()) {
2382#if defined(CUSTOM_PATH_SPACING)
2383 ImGui::SameLine(0, CUSTOM_PATH_SPACING);
2387 if (!(vFileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableQuickPathSelection)) {
2388#if defined(_IGFD_WIN_)
2389 const char* sep =
"\\";
2390#elif defined(_IGFD_UNIX_)
2391 const char* sep =
"/";
2392 if (itPathDecomp != m_CurrentPathDecomposition.begin() + 1)
2395 ImGui::PushID(_id++);
2396 bool click = IMGUI_PATH_BUTTON(sep);
2399#if defined(CUSTOM_PATH_SPACING)
2400 ImGui::SameLine(0, CUSTOM_PATH_SPACING);
2406 m_OpenPathPopup(vFileDialogInternal, itPathDecomp - 1);
2407 }
else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
2408 m_SetCurrentPath(itPathDecomp - 1);
2415 ImGui::PushID(_id++);
2416 bool click = IMGUI_PATH_BUTTON((*itPathDecomp).c_str());
2419 m_CurrentPath = ComposeNewPath(itPathDecomp);
2420 puPathClicked =
true;
2422 }
else if (ImGui::IsItemClicked(ImGuiMouseButton_Right)) {
2423 m_SetCurrentPath(itPathDecomp);
2431void IGFD::FileManager::m_SetCurrentPath(std::vector<std::string>::iterator vPathIter) {
2432 m_CurrentPath = ComposeNewPath(vPathIter);
2433 IGFD::Utils::SetBuffer(inputPathBuffer, MAX_PATH_BUFFER_SIZE, m_CurrentPath);
2434 inputPathActivated =
true;
2437std::string IGFD::FileManager::GetResultingPath() {
2438 if (dLGDirectoryMode && m_SelectedFileNames.size() == 1) {
2439 std::string selectedDirectory = fileNameBuffer;
2440 std::string path = m_CurrentPath;
2441 if (!selectedDirectory.empty() && selectedDirectory !=
".") {
2442 path += IGFD::Utils::GetPathSeparator() + selectedDirectory;
2446 return m_CurrentPath;
2449std::string IGFD::FileManager::GetResultingFileName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag) {
2450 if (!dLGDirectoryMode) {
2451 const auto& filename = std::string(fileNameBuffer);
2452 return vFileDialogInternal.filterManager.ReplaceExtentionWithCurrentFilterIfNeeded(filename, vFlag);
2457std::string IGFD::FileManager::GetResultingFilePathName(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag) {
2458 if (!dLGDirectoryMode) {
2459 auto result = GetResultingPath();
2460 const auto& filename = GetResultingFileName(vFileDialogInternal, vFlag);
2461 if (!filename.empty()) {
2462 if (m_FileSystemPtr !=
nullptr && m_FileSystemPtr->IsFileExist(filename)) {
2466 if (fsRoot != result)
2469 result += IGFD::Utils::GetPathSeparator();
2480std::map<std::string, std::string> IGFD::FileManager::GetResultingSelection(FileDialogInternal& vFileDialogInternal, IGFD_ResultMode vFlag) {
2481 std::map<std::string, std::string> res;
2482 for (
const auto& selectedFileName : m_SelectedFileNames) {
2483 auto result = GetResultingPath();
2485 if (fsRoot != result)
2488 result += IGFD::Utils::GetPathSeparator();
2490 result += vFileDialogInternal.filterManager.ReplaceExtentionWithCurrentFilterIfNeeded(selectedFileName, vFlag);
2491 res[selectedFileName] = result;
2500void IGFD::FileDialogInternal::NewFrame() {
2501 canWeContinue =
true;
2503 fileManager.drivesClicked =
false;
2504 fileManager.puPathClicked =
false;
2506 needToExitDialog =
false;
2508#ifdef USE_DIALOG_EXIT_WITH_KEY
2509 if (ImGui::IsKeyPressed(IGFD_EXIT_KEY)) {
2513 if (!(fileManager.inputPathActivated || searchManager.searchInputIsActive || fileInputIsActive || fileListViewIsActive)) {
2514 needToExitDialog =
true;
2519 searchManager.searchInputIsActive =
false;
2520 fileInputIsActive =
false;
2521 fileListViewIsActive =
false;
2525void IGFD::FileDialogInternal::EndFrame() {
2527 if (fileManager.puPathClicked) {
2528 fileManager.OpenCurrentPath(*
this);
2531 if (fileManager.drivesClicked) {
2532 if (fileManager.GetDrives()) {
2533 fileManager.ApplyFilteringOnFileList(*
this);
2537 if (fileManager.inputPathActivated) {
2538 auto gio = ImGui::GetIO();
2539 if (ImGui::IsKeyReleased(ImGuiKey_Enter)) {
2540 fileManager.SetCurrentPath(std::string(fileManager.inputPathBuffer));
2541 fileManager.OpenCurrentPath(*
this);
2542 fileManager.inputPathActivated =
false;
2544 if (ImGui::IsKeyReleased(ImGuiKey_Escape)) {
2545 fileManager.inputPathActivated =
false;
2550void IGFD::FileDialogInternal::ResetForNewDialog() {
2553void IGFD::FileDialogInternal::configureDialog(
const std::string& vKey,
const std::string& vTitle,
const char* vFilters,
const FileDialogConfig& vConfig) {
2554 m_DialogConfig = vConfig;
2555 ResetForNewDialog();
2560 if (m_DialogConfig.sidePane ==
nullptr) {
2561 m_DialogConfig.sidePaneWidth = 0.0f;
2564 if (m_DialogConfig.filePathName.empty()) {
2565 if (m_DialogConfig.path.empty()) {
2566 fileManager.dLGpath = fileManager.GetCurrentPath();
2568 fileManager.dLGpath = m_DialogConfig.path;
2570 fileManager.SetCurrentPath(m_DialogConfig.path);
2571 fileManager.dLGcountSelectionMax = (size_t)m_DialogConfig.countSelectionMax;
2572 fileManager.SetDefaultFileName(m_DialogConfig.fileName);
2574 auto ps = fileManager.GetFileSystemInstance()->ParsePathFileName(m_DialogConfig.filePathName);
2576 fileManager.dLGpath = ps.path;
2577 fileManager.SetDefaultFileName(ps.name);
2578 filterManager.dLGdefaultExt =
"." + ps.ext;
2580 fileManager.dLGpath = fileManager.GetCurrentPath();
2581 fileManager.SetDefaultFileName(
"");
2582 filterManager.dLGdefaultExt.clear();
2586 filterManager.dLGdefaultExt.clear();
2587 filterManager.ParseFilters(vFilters);
2588 filterManager.SetSelectedFilterWithExt(filterManager.dLGdefaultExt);
2589 fileManager.SetCurrentPath(fileManager.dLGpath);
2590 fileManager.dLGDirectoryMode = (vFilters ==
nullptr);
2591 fileManager.dLGcountSelectionMax = m_DialogConfig.countSelectionMax;
2592 fileManager.ClearAll();
2596const IGFD::FileDialogConfig& IGFD::FileDialogInternal::getDialogConfig()
const {
2597 return m_DialogConfig;
2600IGFD::FileDialogConfig& IGFD::FileDialogInternal::getDialogConfigRef() {
2601 return m_DialogConfig;
2612IGFD::ThumbnailFeature::ThumbnailFeature() {
2613#ifdef USE_THUMBNAILS
2614 m_DisplayMode = DisplayModeEnum::FILE_LIST;
2618IGFD::ThumbnailFeature::~ThumbnailFeature() =
default;
2620void IGFD::ThumbnailFeature::m_NewThumbnailFrame(FileDialogInternal& ) {
2621#ifdef USE_THUMBNAILS
2622 m_StartThumbnailFileDatasExtraction();
2626void IGFD::ThumbnailFeature::m_EndThumbnailFrame(FileDialogInternal& vFileDialogInternal) {
2627#ifdef USE_THUMBNAILS
2628 m_ClearThumbnails(vFileDialogInternal);
2630 (void)vFileDialogInternal;
2634void IGFD::ThumbnailFeature::m_QuitThumbnailFrame(FileDialogInternal& vFileDialogInternal) {
2635#ifdef USE_THUMBNAILS
2636 m_StopThumbnailFileDatasExtraction();
2637 m_ClearThumbnails(vFileDialogInternal);
2639 (void)vFileDialogInternal;
2643#ifdef USE_THUMBNAILS
2644void IGFD::ThumbnailFeature::m_StartThumbnailFileDatasExtraction() {
2645 const bool res = m_ThumbnailGenerationThread.use_count() && m_ThumbnailGenerationThread->joinable();
2649 m_ThumbnailGenerationThread = std::shared_ptr<std::thread>(
new std::thread(&IGFD::ThumbnailFeature::m_ThreadThumbnailFileDatasExtractionFunc,
this), [
this](std::thread* obj) {
2650 m_IsWorking =
false;
2652 m_ThumbnailFileDatasToGetCv.notify_all();
2659bool IGFD::ThumbnailFeature::m_StopThumbnailFileDatasExtraction() {
2660 const bool res = m_ThumbnailGenerationThread.use_count() && m_ThumbnailGenerationThread->joinable();
2662 m_ThumbnailGenerationThread.reset();
2668void IGFD::ThumbnailFeature::m_ThreadThumbnailFileDatasExtractionFunc() {
2673 while (m_IsWorking) {
2674 std::unique_lock<std::mutex> thumbnailFileDatasToGetLock(m_ThumbnailFileDatasToGetMutex);
2675 m_ThumbnailFileDatasToGetCv.wait(thumbnailFileDatasToGetLock);
2676 if (!m_ThumbnailFileDatasToGet.empty()) {
2677 std::shared_ptr<FileInfos> file =
nullptr;
2679 file = (*m_ThumbnailFileDatasToGet.begin());
2680 m_ThumbnailFileDatasToGet.pop_front();
2681 thumbnailFileDatasToGetLock.unlock();
2684 if (file.use_count()) {
2685 if (file->fileType.isFile())
2688 if (file->SearchForExts(
".png,.bmp,.tga,.jpg,.jpeg,.gif,.psd,.pic,.ppm,.pgm",
true)) {
2689 auto fpn = file->filePath + IGFD::Utils::GetPathSeparator() + file->fileNameExt;
2694 uint8_t* datas = stbi_load(fpn.c_str(), &w, &h, &chans, STBI_rgb_alpha);
2698 const float ratioX = (float)w / (
float)h;
2699 const float newX = DisplayMode_ThumbailsList_ImageHeight * ratioX;
2700 float newY = w / ratioX;
2701 if (newX < w) newY = DisplayMode_ThumbailsList_ImageHeight;
2703 const auto newWidth = (int)newX;
2704 const auto newHeight = (int)newY;
2705 const auto newBufSize = (size_t)(newWidth * newHeight * 4U);
2706 auto resizedData =
new uint8_t[newBufSize];
2708 const int resizeSucceeded = stbir_resize_uint8(datas, w, h, 0, resizedData, newWidth, newHeight, 0,
2711 if (resizeSucceeded) {
2712 auto th = &file->thumbnailInfo;
2714 th->textureFileDatas = resizedData;
2715 th->textureWidth = newWidth;
2716 th->textureHeight = newHeight;
2717 th->textureChannels = 4;
2721 th->isReadyToUpload =
true;
2724 m_AddThumbnailToCreate(file);
2727 printf(
"image loading fail : w:%i h:%i c:%i\n", w, h, 4);
2730 stbi_image_free(datas);
2736 thumbnailFileDatasToGetLock.unlock();
2741void IGFD::ThumbnailFeature::m_VariadicProgressBar(
float fraction,
const ImVec2& size_arg,
const char* fmt, ...) {
2743 va_start(args, fmt);
2744 char TempBuffer[512];
2745 const int w = vsnprintf(TempBuffer, 511, fmt, args);
2748 ImGui::ProgressBar(fraction, size_arg, TempBuffer);
2752void IGFD::ThumbnailFeature::m_DrawThumbnailGenerationProgress() {
2753 if (m_ThumbnailGenerationThread.use_count() && m_ThumbnailGenerationThread->joinable()) {
2754 if (!m_ThumbnailFileDatasToGet.empty()) {
2755 const auto p = (float)((
double)m_CountFiles / (double)m_ThumbnailFileDatasToGet.size());
2756 m_VariadicProgressBar(p, ImVec2(50, 0),
"%u/%u", m_CountFiles,
2757 (uint32_t)m_ThumbnailFileDatasToGet.size());
2763void IGFD::ThumbnailFeature::m_AddThumbnailToLoad(
const std::shared_ptr<FileInfos>& vFileInfos) {
2764 if (vFileInfos.use_count()) {
2765 if (vFileInfos->fileType.isFile()) {
2767 if (vFileInfos->SearchForExts(
".png,.bmp,.tga,.jpg,.jpeg,.gif,.psd,.pic,.ppm,.pgm",
true)) {
2769 m_ThumbnailFileDatasToGetMutex.lock();
2770 m_ThumbnailFileDatasToGet.push_back(vFileInfos);
2771 vFileInfos->thumbnailInfo.isLoadingOrLoaded =
true;
2772 m_ThumbnailFileDatasToGetMutex.unlock();
2773 m_ThumbnailFileDatasToGetCv.notify_all();
2779void IGFD::ThumbnailFeature::m_AddThumbnailToCreate(
const std::shared_ptr<FileInfos>& vFileInfos) {
2780 if (vFileInfos.use_count()) {
2782 m_ThumbnailToCreateMutex.lock();
2783 m_ThumbnailToCreate.push_back(vFileInfos);
2784 m_ThumbnailToCreateMutex.unlock();
2788void IGFD::ThumbnailFeature::m_AddThumbnailToDestroy(
const IGFD_Thumbnail_Info& vIGFD_Thumbnail_Info) {
2790 m_ThumbnailToDestroyMutex.lock();
2791 m_ThumbnailToDestroy.push_back(vIGFD_Thumbnail_Info);
2792 m_ThumbnailToDestroyMutex.unlock();
2795void IGFD::ThumbnailFeature::m_DrawDisplayModeToolBar() {
2796 if (IMGUI_RADIO_BUTTON(DisplayMode_FilesList_ButtonString, m_DisplayMode == DisplayModeEnum::FILE_LIST)) m_DisplayMode = DisplayModeEnum::FILE_LIST;
2797 if (ImGui::IsItemHovered()) ImGui::SetTooltip(DisplayMode_FilesList_ButtonHelp);
2799 if (IMGUI_RADIO_BUTTON(DisplayMode_ThumbailsList_ButtonString, m_DisplayMode == DisplayModeEnum::THUMBNAILS_LIST)) m_DisplayMode = DisplayModeEnum::THUMBNAILS_LIST;
2800 if (ImGui::IsItemHovered()) ImGui::SetTooltip(DisplayMode_ThumbailsList_ButtonHelp);
2809 m_DrawThumbnailGenerationProgress();
2812void IGFD::ThumbnailFeature::m_ClearThumbnails(FileDialogInternal& vFileDialogInternal) {
2814 if (vFileDialogInternal.fileManager.puPathClicked) {
2815 size_t count = vFileDialogInternal.fileManager.GetFullFileListSize();
2816 for (
size_t idx = 0U; idx <
count; idx++) {
2817 auto file = vFileDialogInternal.fileManager.GetFullFileAt(idx);
2818 if (file.use_count()) {
2819 if (file->thumbnailInfo.isReadyToDisplay)
2821 m_AddThumbnailToDestroy(file->thumbnailInfo);
2828void IGFD::ThumbnailFeature::SetCreateThumbnailCallback(
const CreateThumbnailFun& vCreateThumbnailFun) {
2829 m_CreateThumbnailFun = vCreateThumbnailFun;
2832void IGFD::ThumbnailFeature::SetDestroyThumbnailCallback(
const DestroyThumbnailFun& vCreateThumbnailFun) {
2833 m_DestroyThumbnailFun = vCreateThumbnailFun;
2836void IGFD::ThumbnailFeature::ManageGPUThumbnails() {
2837 if (m_CreateThumbnailFun) {
2838 m_ThumbnailToCreateMutex.lock();
2839 if (!m_ThumbnailToCreate.empty()) {
2840 for (
const auto& file : m_ThumbnailToCreate) {
2841 if (file.use_count()) {
2842 m_CreateThumbnailFun(&file->thumbnailInfo);
2845 m_ThumbnailToCreate.clear();
2847 m_ThumbnailToCreateMutex.unlock();
2850 "No Callback found for create texture\nYou need to define the callback with a call to "
2851 "SetCreateThumbnailCallback\n");
2854 if (m_DestroyThumbnailFun) {
2855 m_ThumbnailToDestroyMutex.lock();
2856 if (!m_ThumbnailToDestroy.empty()) {
2857 for (
auto thumbnail : m_ThumbnailToDestroy) {
2858 m_DestroyThumbnailFun(&thumbnail);
2860 m_ThumbnailToDestroy.clear();
2862 m_ThumbnailToDestroyMutex.unlock();
2865 "No Callback found for destroy texture\nYou need to define the callback with a call to "
2866 "SetCreateThumbnailCallback\n");
2876IGFD::BookMarkFeature::BookMarkFeature() {
2878 m_BookmarkWidth = defaultBookmarkPaneWith;
2883void IGFD::BookMarkFeature::m_DrawBookmarkButton() {
2884 IMGUI_TOGGLE_BUTTON(bookmarksButtonString, &m_BookmarkPaneShown);
2886 if (ImGui::IsItemHovered()) ImGui::SetTooltip(bookmarksButtonHelpString);
2889bool IGFD::BookMarkFeature::m_DrawBookmarkPane(FileDialogInternal& vFileDialogInternal,
const ImVec2& vSize) {
2892 ImGui::BeginChild(
"##bookmarkpane", vSize);
2894 static int selectedBookmarkForEdition = -1;
2896 if (IMGUI_BUTTON(addBookmarkButtonString
"##ImGuiFileDialogAddBookmark")) {
2897 if (!vFileDialogInternal.fileManager.IsComposerEmpty()) {
2898 BookmarkStruct bookmark;
2899 bookmark.name = vFileDialogInternal.fileManager.GetBack();
2900 bookmark.path = vFileDialogInternal.fileManager.GetCurrentPath();
2901 m_Bookmarks.push_back(bookmark);
2904 if (selectedBookmarkForEdition >= 0 && selectedBookmarkForEdition < (
int)m_Bookmarks.size()) {
2906 if (IMGUI_BUTTON(removeBookmarkButtonString
"##ImGuiFileDialogAddBookmark")) {
2907 m_Bookmarks.erase(m_Bookmarks.begin() + selectedBookmarkForEdition);
2908 if (selectedBookmarkForEdition == (
int)m_Bookmarks.size()) selectedBookmarkForEdition--;
2911 if (selectedBookmarkForEdition >= 0 && selectedBookmarkForEdition < (
int)m_Bookmarks.size()) {
2914 ImGui::PushItemWidth(vSize.x - ImGui::GetCursorPosX());
2915 if (ImGui::InputText(
"##ImGuiFileDialogBookmarkEdit", m_BookmarkEditBuffer, MAX_FILE_DIALOG_NAME_BUFFER)) {
2916 m_Bookmarks[(size_t)selectedBookmarkForEdition].name = std::string(m_BookmarkEditBuffer);
2918 ImGui::PopItemWidth();
2924 if (!m_Bookmarks.empty()) {
2925 m_BookmarkClipper.Begin((
int)m_Bookmarks.size(), ImGui::GetTextLineHeightWithSpacing());
2926 while (m_BookmarkClipper.Step()) {
2927 for (
int i = m_BookmarkClipper.DisplayStart; i < m_BookmarkClipper.DisplayEnd; i++) {
2928 if (i < 0)
continue;
2929 const BookmarkStruct& bookmark = m_Bookmarks[(size_t)i];
2931 if (ImGui::Selectable(bookmark.name.c_str(), selectedBookmarkForEdition == i,
2932 ImGuiSelectableFlags_AllowDoubleClick) ||
2933 (selectedBookmarkForEdition == -1 && bookmark.path == vFileDialogInternal.fileManager.GetCurrentPath()))
2935 selectedBookmarkForEdition = i;
2936 IGFD::Utils::ResetBuffer(m_BookmarkEditBuffer);
2937 IGFD::Utils::AppendToBuffer(m_BookmarkEditBuffer, MAX_FILE_DIALOG_NAME_BUFFER, bookmark.name);
2939 if (ImGui::IsMouseDoubleClicked(0))
2941 vFileDialogInternal.fileManager.SetCurrentPath(bookmark.path);
2942 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
2947 if (ImGui::IsItemHovered()) ImGui::SetTooltip(
"%s", bookmark.path.c_str());
2950 m_BookmarkClipper.End();
2958std::string IGFD::BookMarkFeature::SerializeBookmarks(
const bool& vDontSerializeCodeBasedBookmarks) {
2962 for (
auto& it : m_Bookmarks) {
2963 if (vDontSerializeCodeBasedBookmarks && it.defined_by_code)
continue;
2965 if (idx++ != 0) res +=
"##";
2967 res += it.name +
"##" + it.path;
2973void IGFD::BookMarkFeature::DeserializeBookmarks(
const std::string& vBookmarks) {
2974 if (!vBookmarks.empty()) {
2975 m_Bookmarks.clear();
2976 auto arr = IGFD::Utils::SplitStringToVector(vBookmarks,
'#',
false);
2977 for (
size_t i = 0; i < arr.size(); i += 2) {
2978 if (i + 1 < arr.size())
2980 BookmarkStruct bookmark;
2981 bookmark.name = arr[i];
2983 bookmark.path = arr[i + 1];
2984 m_Bookmarks.push_back(bookmark);
2990void IGFD::BookMarkFeature::AddBookmark(
const std::string& vBookMarkName,
const std::string& vBookMarkPath) {
2991 if (vBookMarkName.empty() || vBookMarkPath.empty())
return;
2993 BookmarkStruct bookmark;
2994 bookmark.name = vBookMarkName;
2995 bookmark.path = vBookMarkPath;
2996 bookmark.defined_by_code =
true;
2997 m_Bookmarks.push_back(bookmark);
3000bool IGFD::BookMarkFeature::RemoveBookmark(
const std::string& vBookMarkName) {
3001 if (vBookMarkName.empty())
return false;
3003 for (
auto bookmark_it = m_Bookmarks.begin(); bookmark_it != m_Bookmarks.end(); ++bookmark_it) {
3004 if ((*bookmark_it).name == vBookMarkName) {
3005 m_Bookmarks.erase(bookmark_it);
3018IGFD::KeyExplorerFeature::KeyExplorerFeature() =
default;
3020#ifdef USE_EXPLORATION_BY_KEYS
3021bool IGFD::KeyExplorerFeature::m_LocateItem_Loop(FileDialogInternal& vFileDialogInternal, ImWchar vC) {
3024 auto& fdi = vFileDialogInternal.fileManager;
3025 if (!fdi.IsFilteredListEmpty()) {
3026 auto countFiles = fdi.GetFilteredListSize();
3027 for (
size_t i = m_LocateFileByInputChar_lastFileIdx; i < countFiles; i++) {
3028 auto nfo = fdi.GetFilteredFileAt(i);
3029 if (nfo.use_count()) {
3030 if (nfo->fileNameExt_optimized[0] == vC ||
3031 nfo->fileNameExt[0] == vC)
3034 float p = (float)((
double)i / (double)countFiles) * ImGui::GetScrollMaxY();
3035 ImGui::SetScrollY(p);
3036 m_LocateFileByInputChar_lastFound =
true;
3037 m_LocateFileByInputChar_lastFileIdx = i;
3038 m_StartFlashItem(m_LocateFileByInputChar_lastFileIdx);
3040 auto infos = fdi.GetFilteredFileAt(m_LocateFileByInputChar_lastFileIdx);
3041 if (infos.use_count()) {
3042 if (infos->fileType.isDir())
3044 if (fdi.dLGDirectoryMode)
3046 fdi.SelectFileName(vFileDialogInternal, infos);
3049 fdi.SelectFileName(vFileDialogInternal, infos);
3063void IGFD::KeyExplorerFeature::m_LocateByInputKey(FileDialogInternal& vFileDialogInternal) {
3065 auto& fdi = vFileDialogInternal.fileManager;
3066 if (!
g.ActiveId && !fdi.IsFilteredListEmpty()) {
3067 auto& queueChar = ImGui::GetIO().InputQueueCharacters;
3068 auto countFiles = fdi.GetFilteredListSize();
3071 if (!queueChar.empty()) {
3072 ImWchar c = queueChar.back();
3073 if (m_LocateFileByInputChar_InputQueueCharactersSize != queueChar.size()) {
3074 if (c == m_LocateFileByInputChar_lastChar)
3076 if (m_LocateFileByInputChar_lastFileIdx < countFiles - 1U)
3077 m_LocateFileByInputChar_lastFileIdx++;
3079 m_LocateFileByInputChar_lastFileIdx = 0;
3082 if (!m_LocateItem_Loop(vFileDialogInternal, c)) {
3084 m_LocateFileByInputChar_lastFileIdx = 0;
3085 m_LocateItem_Loop(vFileDialogInternal, c);
3088 m_LocateFileByInputChar_lastChar = c;
3092 m_LocateFileByInputChar_InputQueueCharactersSize = queueChar.size();
3096void IGFD::KeyExplorerFeature::m_ExploreWithkeys(FileDialogInternal& vFileDialogInternal, ImGuiID vListViewID) {
3097 auto& fdi = vFileDialogInternal.fileManager;
3098 if (!fdi.IsFilteredListEmpty()) {
3099 bool canWeExplore =
false;
3100 bool hasNav = (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard);
3103 if (!hasNav && !
g.ActiveId)
3104 canWeExplore =
true;
3106 if (
g.NavId &&
g.NavId == vListViewID) {
3107 if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter) || ImGui::IsKeyPressed(ImGuiKey_Space)) {
3108 ImGui::ActivateItemByID(vListViewID);
3109 ImGui::SetActiveID(vListViewID,
g.CurrentWindow);
3113 if (vListViewID ==
g.LastActiveId - 1)
3114 canWeExplore =
true;
3116 if (canWeExplore && ImGui::IsWindowFocused()) {
3117 if (ImGui::IsKeyPressed(ImGuiKey_Escape)) {
3118 ImGui::ClearActiveID();
3122 auto countFiles = fdi.GetFilteredListSize();
3125 bool exploreByKey =
false;
3126 bool enterInDirectory =
false;
3127 bool exitDirectory =
false;
3129 if ((hasNav && ImGui::IsKeyPressed(ImGuiKey_UpArrow)) || (!hasNav && ImGui::IsKeyPressed(ImGuiKey_UpArrow))) {
3130 exploreByKey =
true;
3131 if (m_LocateFileByInputChar_lastFileIdx > 0)
3132 m_LocateFileByInputChar_lastFileIdx--;
3134 m_LocateFileByInputChar_lastFileIdx = countFiles - 1U;
3135 }
else if ((hasNav && ImGui::IsKeyPressed(ImGuiKey_DownArrow)) || (!hasNav && ImGui::IsKeyPressed(ImGuiKey_DownArrow))) {
3136 exploreByKey =
true;
3137 if (m_LocateFileByInputChar_lastFileIdx < countFiles - 1U)
3138 m_LocateFileByInputChar_lastFileIdx++;
3140 m_LocateFileByInputChar_lastFileIdx = 0U;
3141 }
else if (ImGui::IsKeyReleased(ImGuiKey_Enter)) {
3142 exploreByKey =
true;
3143 enterInDirectory =
true;
3144 }
else if (ImGui::IsKeyReleased(ImGuiKey_Backspace)) {
3145 exploreByKey =
true;
3146 exitDirectory =
true;
3151 float p = (float)((
double)m_LocateFileByInputChar_lastFileIdx / (double)(countFiles - 1U)) * ImGui::GetScrollMaxY();
3153 ImGui::SetScrollY(p);
3154 m_StartFlashItem(m_LocateFileByInputChar_lastFileIdx);
3156 auto infos = fdi.GetFilteredFileAt(m_LocateFileByInputChar_lastFileIdx);
3157 if (infos.use_count()) {
3158 if (infos->fileType.isDir())
3160 if (!fdi.dLGDirectoryMode || enterInDirectory) {
3161 if (enterInDirectory) {
3162 if (fdi.SelectDirectory(infos)) {
3164 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
3165 if (m_LocateFileByInputChar_lastFileIdx > countFiles - 1U) {
3166 m_LocateFileByInputChar_lastFileIdx = 0;
3172 fdi.SelectFileName(vFileDialogInternal, infos);
3175 fdi.SelectFileName(vFileDialogInternal, infos);
3177 if (enterInDirectory) {
3178 vFileDialogInternal.isOk =
true;
3182 if (exitDirectory) {
3183 auto nfo = std::make_shared<FileInfos>();
3184 nfo->fileNameExt =
"..";
3186 if (fdi.SelectDirectory(nfo)) {
3188 vFileDialogInternal.fileManager.OpenCurrentPath(vFileDialogInternal);
3189 if (m_LocateFileByInputChar_lastFileIdx > countFiles - 1U) {
3190 m_LocateFileByInputChar_lastFileIdx = 0;
3195 if (fdi.GetComposerSize() == 1U) {
3196 if (fdi.GetDrives()) {
3197 fdi.ApplyFilteringOnFileList(vFileDialogInternal);
3209bool IGFD::KeyExplorerFeature::m_FlashableSelectable(
const char* label,
bool selected, ImGuiSelectableFlags flags,
bool vFlashing,
const ImVec2& size_arg) {
3210 using namespace ImGui;
3212 ImGuiWindow* window = GetCurrentWindow();
3213 if (window->SkipItems)
return false;
3216 const ImGuiStyle& style =
g.Style;
3219 ImGuiID
id = window->GetID(label);
3221 ImVec2
size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
3222 ImVec2 pos = window->DC.CursorPos;
3223 pos.y += window->DC.CurrLineTextBaseOffset;
3224 ItemSize(size, 0.0f);
3229 const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0;
3230 const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x;
3231 const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
3232 if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth))
size.x = ImMax(label_size.x, max_x - min_x);
3235 const ImVec2 text_min = pos;
3236 const ImVec2 text_max(min_x +
size.x, pos.y +
size.y);
3239 ImRect bb(min_x, pos.y, text_max.x, text_max.y);
3240 if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0) {
3241 const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x;
3242 const float spacing_y = style.ItemSpacing.y;
3243 const float spacing_L = IM_TRUNC(spacing_x * 0.50f);
3244 const float spacing_U = IM_TRUNC(spacing_y * 0.50f);
3245 bb.Min.x -= spacing_L;
3246 bb.Min.y -= spacing_U;
3247 bb.Max.x += (spacing_x - spacing_L);
3248 bb.Max.y += (spacing_y - spacing_U);
3253 const float backup_clip_rect_min_x = window->ClipRect.Min.x;
3254 const float backup_clip_rect_max_x = window->ClipRect.Max.x;
3255 if (span_all_columns) {
3256 window->ClipRect.Min.x = window->ParentWorkRect.Min.x;
3257 window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
3260 const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
3261 const bool item_add = ItemAdd(bb,
id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None);
3262 if (span_all_columns) {
3263 window->ClipRect.Min.x = backup_clip_rect_min_x;
3264 window->ClipRect.Max.x = backup_clip_rect_max_x;
3267 if (!item_add)
return false;
3269 const bool disabled_global = (
g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
3270 if (disabled_item && !disabled_global)
3275 if (span_all_columns && window->DC.CurrentColumns)
3276 PushColumnsBackground();
3277 else if (span_all_columns &&
g.CurrentTable)
3278 TablePushBackgroundChannel();
3281 ImGuiButtonFlags button_flags = 0;
3282 if (flags & ImGuiSelectableFlags_NoHoldingActiveID) {
3283 button_flags |= ImGuiButtonFlags_NoHoldingActiveId;
3285 if (flags & ImGuiSelectableFlags_NoSetKeyOwner) {
3286 button_flags |= ImGuiButtonFlags_NoSetKeyOwner;
3288 if (flags & ImGuiSelectableFlags_SelectOnClick) {
3289 button_flags |= ImGuiButtonFlags_PressedOnClick;
3291 if (flags & ImGuiSelectableFlags_SelectOnRelease) {
3292 button_flags |= ImGuiButtonFlags_PressedOnRelease;
3294 if (flags & ImGuiSelectableFlags_AllowDoubleClick) {
3295 button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
3297 if ((flags & ImGuiSelectableFlags_AllowOverlap) || (
g.LastItemData.ItemFlags & ImGuiItemFlags_AllowOverlap)) {
3298 button_flags |= ImGuiButtonFlags_AllowOverlap;
3301 const bool was_selected = selected;
3303 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, button_flags);
3312 if ((flags & ImGuiSelectableFlags_SelectOnNav) &&
g.NavJustMovedToId != 0 &&
g.NavJustMovedToFocusScopeId ==
g.CurrentFocusScopeId)
3313 if (
g.NavJustMovedToId ==
id) selected = pressed =
true;
3316 if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover))) {
3317 if (!
g.NavHighlightItemUnderNav &&
g.NavWindow == window &&
g.NavLayer == window->DC.NavLayerCurrent) {
3318 SetNavID(
id, window->DC.NavLayerCurrent,
g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb));
3319 g.NavCursorVisible =
true;
3322 if (pressed) MarkItemEdited(
id);
3325 if (selected != was_selected)
3326 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
3330 hovered |= vFlashing;
3334 if (hovered || selected) {
3335 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
3336 RenderFrame(bb.Min, bb.Max, col,
false, 0.0f);
3338 if (
g.NavId ==
id) RenderNavCursor(bb,
id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding);
3340 if (span_all_columns && window->DC.CurrentColumns)
3341 PopColumnsBackground();
3342 else if (span_all_columns &&
g.CurrentTable)
3343 TablePopBackgroundChannel();
3345 RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
3348 if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_NoAutoClosePopups) && (
g.LastItemData.ItemFlags & ImGuiItemFlags_AutoClosePopups)) CloseCurrentPopup();
3350 if (disabled_item && !disabled_global) EndDisabled();
3352 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags);
3356void IGFD::KeyExplorerFeature::m_StartFlashItem(
size_t vIdx) {
3357 m_FlashAlpha = 1.0f;
3358 m_FlashedItem = vIdx;
3361bool IGFD::KeyExplorerFeature::m_BeginFlashItem(
size_t vIdx) {
3364 if (m_FlashedItem == vIdx && std::abs(m_FlashAlpha - 0.0f) > 0.00001f) {
3365 m_FlashAlpha -= m_FlashAlphaAttenInSecs * ImGui::GetIO().DeltaTime;
3366 if (m_FlashAlpha < 0.0f) m_FlashAlpha = 0.0f;
3368 ImVec4 hov = ImGui::GetStyleColorVec4(ImGuiCol_HeaderHovered);
3369 hov.w = m_FlashAlpha;
3370 ImGui::PushStyleColor(ImGuiCol_HeaderHovered, hov);
3377void IGFD::KeyExplorerFeature::m_EndFlashItem() {
3378 ImGui::PopStyleColor();
3381void IGFD::KeyExplorerFeature::SetFlashingAttenuationInSeconds(
float vAttenValue) {
3382 m_FlashAlphaAttenInSecs = 1.0f / ImMax(vAttenValue, 0.01f);
3392IGFD::FileDialog::FileDialog() : BookMarkFeature(), KeyExplorerFeature(), ThumbnailFeature() {
3394IGFD::FileDialog::~FileDialog() =
default;
3401void IGFD::FileDialog::OpenDialog(
const std::string& vKey,
const std::string& vTitle,
const char* vFilters,
const FileDialogConfig& vConfig) {
3402 if (m_FileDialogInternal.showDialog)
3404 m_FileDialogInternal.configureDialog(vKey, vTitle, vFilters, vConfig);
3411bool IGFD::FileDialog::Display(
const std::string& vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize) {
3414 if (m_FileDialogInternal.showDialog && m_FileDialogInternal.dLGkey == vKey) {
3415 if (m_FileDialogInternal.puUseCustomLocale) setlocale(m_FileDialogInternal.localeCategory, m_FileDialogInternal.localeBegin.c_str());
3417 auto& fdFile = m_FileDialogInternal.fileManager;
3418 auto& fdFilter = m_FileDialogInternal.filterManager;
3420 static ImGuiWindowFlags flags;
3424 if (
g.FrameCount == m_FileDialogInternal.lastImGuiFrameCount)
3427 m_FileDialogInternal.lastImGuiFrameCount =
g.FrameCount;
3429 std::string name = m_FileDialogInternal.dLGtitle +
"##" + m_FileDialogInternal.dLGkey;
3430 if (m_FileDialogInternal.name != name) {
3431 fdFile.ClearComposer();
3432 fdFile.ClearFileLists();
3438#ifdef IMGUI_HAS_VIEWPORT
3439 if (!ImGui::GetIO().ConfigViewportsNoDecoration) {
3441 ImGuiWindowClass window_class;
3442 window_class.ViewportFlagsOverrideClear = ImGuiViewportFlags_NoDecoration;
3443 ImGui::SetNextWindowClass(&window_class);
3448 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_NoDialog)
3452 ImGui::SetNextWindowSizeConstraints(vMinSize, vMaxSize);
3454 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_Modal && !m_FileDialogInternal.okResultToConfirm)
3457 ImGui::OpenPopup(name.c_str());
3458 beg = ImGui::BeginPopupModal(name.c_str(), (
bool*)
nullptr, flags | ImGuiWindowFlags_NoScrollbar);
3460 beg = ImGui::Begin(name.c_str(), (
bool*)
nullptr, flags | ImGuiWindowFlags_NoScrollbar);
3464#ifdef IMGUI_HAS_VIEWPORT
3466 if (ImGui::GetIO().ConfigViewportsNoDecoration) {
3469 auto win = ImGui::GetCurrentWindowRead();
3470 if (win->Viewport->Idx != 0)
3471 flags |= ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoTitleBar;
3477 ImGuiID _frameId = ImGui::GetID(name.c_str());
3478 ImVec2 frameSize = ImVec2(0, 0);
3479 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_NoDialog) frameSize = vMaxSize;
3480 if (ImGui::BeginChild(_frameId, frameSize,
false, flags | ImGuiWindowFlags_NoScrollbar)) {
3481 m_FileDialogInternal.name = name;
3483 if (fdFile.dLGpath.empty()) fdFile.dLGpath =
".";
3485 fdFilter.SetDefaultFilterIfNotDefined();
3488 if (fdFile.IsFileListEmpty() && !fdFile.showDrives) {
3489 if (fdFile.dLGpath !=
".")
3490 IGFD::Utils::ReplaceString(fdFile.dLGDefaultFileName, fdFile.dLGpath,
"");
3492 if (!fdFile.dLGDefaultFileName.empty()) {
3493 fdFile.SetDefaultFileName(fdFile.dLGDefaultFileName);
3494 fdFilter.SetSelectedFilterWithExt(fdFilter.dLGdefaultExt);
3495 }
else if (fdFile.dLGDirectoryMode)
3496 fdFile.SetDefaultFileName(
".");
3497 fdFile.ScanDir(m_FileDialogInternal, fdFile.dLGpath);
3503 res = m_DrawFooter();
3510 m_FileDialogInternal.dialogCenterPos = ImGui::GetCurrentWindowRead()->ContentRegionRect.GetCenter();
3515 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_Modal && !m_FileDialogInternal.okResultToConfirm) {
3520 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_NoDialog) {
3523 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_Modal) || m_FileDialogInternal.okResultToConfirm) {
3528 res = m_Confirm_Or_OpenOverWriteFileDialog_IfNeeded(res, vFlags);
3530 if (m_FileDialogInternal.puUseCustomLocale) setlocale(m_FileDialogInternal.localeCategory, m_FileDialogInternal.localeEnd.c_str());
3536void IGFD::FileDialog::m_NewFrame() {
3537 m_FileDialogInternal.NewFrame();
3538 m_NewThumbnailFrame(m_FileDialogInternal);
3541void IGFD::FileDialog::m_EndFrame() {
3542 m_EndThumbnailFrame(m_FileDialogInternal);
3543 m_FileDialogInternal.EndFrame();
3545void IGFD::FileDialog::m_QuitFrame() {
3546 m_QuitThumbnailFrame(m_FileDialogInternal);
3549void IGFD::FileDialog::m_DrawHeader() {
3551 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableBookmarkMode)) {
3552 m_DrawBookmarkButton();
3558 m_FileDialogInternal.fileManager.DrawDirectoryCreation(m_FileDialogInternal);
3562 !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableBookmarkMode) ||
3564 !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableCreateDirectoryButton)) {
3565 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
3568 m_FileDialogInternal.fileManager.DrawPathComposer(m_FileDialogInternal);
3570#ifdef USE_THUMBNAILS
3571 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableThumbnailMode)) {
3572 m_DrawDisplayModeToolBar();
3574 ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
3579 m_FileDialogInternal.searchManager.DrawSearchBar(m_FileDialogInternal);
3582void IGFD::FileDialog::m_DrawContent() {
3583 ImVec2
size = ImGui::GetContentRegionAvail() - ImVec2(0.0f, m_FileDialogInternal.footerHeight);
3586 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableBookmarkMode)) {
3587 if (m_BookmarkPaneShown) {
3589 float otherWidth =
size.x - m_BookmarkWidth;
3590 ImGui::PushID(
"##splitterbookmark");
3591 IGFD::Utils::ImSplitter(
true, 4.0f, &m_BookmarkWidth, &otherWidth, 10.0f, 10.0f + m_FileDialogInternal.getDialogConfig().sidePaneWidth,
size.y);
3593 size.x -= otherWidth;
3594 m_DrawBookmarkPane(m_FileDialogInternal, size);
3600 size.x = ImGui::GetContentRegionAvail().x - m_FileDialogInternal.getDialogConfig().sidePaneWidth;
3602 if (m_FileDialogInternal.getDialogConfig().sidePane) {
3603 ImGui::PushID(
"##splittersidepane");
3604 IGFD::Utils::ImSplitter(
true, 4.0f, &
size.x, &m_FileDialogInternal.getDialogConfigRef().sidePaneWidth, 10.0f, 10.0f,
size.y);
3608#ifdef USE_THUMBNAILS
3609 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableThumbnailMode) {
3610 m_DrawFileListView(size);
3612 switch (m_DisplayMode) {
3613 case DisplayModeEnum::FILE_LIST: m_DrawFileListView(size);
break;
3614 case DisplayModeEnum::THUMBNAILS_LIST: m_DrawThumbnailsListView(size);
break;
3615 case DisplayModeEnum::THUMBNAILS_GRID: m_DrawThumbnailsGridView(size);
3619 m_DrawFileListView(size);
3622 if (m_FileDialogInternal.getDialogConfig().sidePane) {
3623 m_DrawSidePane(
size.y);
3626 if (!(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableQuickPathSelection)) {
3627 m_DisplayPathPopup(size);
3631void IGFD::FileDialog::m_DisplayPathPopup(ImVec2 vSize) {
3632 ImVec2
size = ImVec2(vSize.x * 0.5f, vSize.y * 0.5f);
3633 if (ImGui::BeginPopup(
"IGFD_Path_Popup")) {
3634 auto& fdi = m_FileDialogInternal.fileManager;
3636 ImGui::PushID(
this);
3638 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY;
3639 auto listViewID = ImGui::GetID(
"##FileDialog_pathTable");
3640 if (ImGui::BeginTableEx(
"##FileDialog_pathTable", listViewID, 1, flags, size, 0.0f))
3642 ImGui::TableSetupScrollFreeze(0, 1);
3643 ImGui::TableSetupColumn(tableHeaderFileNameString, ImGuiTableColumnFlags_WidthStretch | (defaultSortOrderFilename ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 0);
3645 ImGui::TableHeadersRow();
3647 if (!fdi.IsPathFilteredListEmpty()) {
3649 ImFont* _font =
nullptr;
3650 bool _showColor =
false;
3652 m_PathListClipper.Begin((
int)fdi.GetPathFilteredListSize(), ImGui::GetTextLineHeightWithSpacing());
3653 while (m_PathListClipper.Step()) {
3654 for (
int i = m_PathListClipper.DisplayStart; i < m_PathListClipper.DisplayEnd; i++) {
3655 if (i < 0)
continue;
3657 auto infos = fdi.GetFilteredPathAt((
size_t)i);
3658 if (!infos.use_count())
continue;
3660 m_BeginFileColorIconStyle(infos, _showColor, _str, &_font);
3662 bool selected = fdi.IsFileNameSelected(infos->fileNameExt);
3664 ImGui::TableNextRow();
3666 if (ImGui::TableNextColumn())
3668 if (ImGui::Selectable(infos->fileNameExt.c_str(), &selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth)) {
3669 fdi.SetCurrentPath(fdi.ComposeNewPath(fdi.GetCurrentPopupComposedPath()));
3670 fdi.puPathClicked = fdi.SelectDirectory(infos);
3671 ImGui::CloseCurrentPopup();
3675 m_EndFileColorIconStyle(_showColor, _font);
3678 m_PathListClipper.End();
3690bool IGFD::FileDialog::m_DrawOkButton() {
3691 auto& fdFile = m_FileDialogInternal.fileManager;
3692 if (m_FileDialogInternal.canWeContinue && strlen(fdFile.fileNameBuffer)) {
3693 if (IMGUI_BUTTON(okButtonString
"##validationdialog", ImVec2(okButtonWidth, 0.0f)) || m_FileDialogInternal.isOk) {
3694 m_FileDialogInternal.isOk =
true;
3698#if !invertOkAndCancelButtons
3706bool IGFD::FileDialog::m_DrawCancelButton() {
3707 if (IMGUI_BUTTON(cancelButtonString
"##validationdialog", ImVec2(cancelButtonWidth, 0.0f)) || m_FileDialogInternal.needToExitDialog)
3709 m_FileDialogInternal.isOk =
false;
3713#if invertOkAndCancelButtons
3720bool IGFD::FileDialog::m_DrawValidationButtons() {
3723 ImGui::SetCursorPosX(ImGui::GetCursorPosX() + (ImGui::GetContentRegionAvail().x - prOkCancelButtonWidth) * okCancelButtonAlignement);
3725 ImGui::BeginGroup();
3727 if (invertOkAndCancelButtons) {
3728 res |= m_DrawCancelButton();
3729 res |= m_DrawOkButton();
3731 res |= m_DrawOkButton();
3732 res |= m_DrawCancelButton();
3737 prOkCancelButtonWidth = ImGui::GetItemRectSize().x;
3742bool IGFD::FileDialog::m_DrawFooter() {
3743 auto& fdFile = m_FileDialogInternal.fileManager;
3745 float posY = ImGui::GetCursorPos().y;
3746 ImGui::AlignTextToFramePadding();
3747 if (!fdFile.dLGDirectoryMode)
3748 ImGui::Text(fileNameString);
3750 ImGui::Text(dirNameString);
3754 float width = ImGui::GetContentRegionAvail().x;
3755 if (!fdFile.dLGDirectoryMode) {
3757 width -= m_FileDialogInternal.filterManager.GetFilterComboBoxWidth() +
g.Style.ItemSpacing.x;
3760 ImGui::PushItemWidth(width);
3761 ImGuiInputTextFlags flags = ImGuiInputTextFlags_EnterReturnsTrue;
3762 if (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_ReadOnlyFileNameField) {
3763 flags |= ImGuiInputTextFlags_ReadOnly;
3765 if (ImGui::InputText(
"##FileName", fdFile.fileNameBuffer, MAX_FILE_DIALOG_NAME_BUFFER, flags)) {
3766 m_FileDialogInternal.isOk =
true;
3768 if (ImGui::GetItemID() == ImGui::GetActiveID()) m_FileDialogInternal.fileInputIsActive =
true;
3769 ImGui::PopItemWidth();
3772 m_FileDialogInternal.filterManager.DrawFilterComboBox(m_FileDialogInternal);
3774 bool res = m_DrawValidationButtons();
3775 m_FileDialogInternal.footerHeight = ImGui::GetCursorPosY() - posY;
3779void IGFD::FileDialog::m_SelectableItem(
int vidx, std::shared_ptr<FileInfos> vInfos,
bool vSelected,
const char* vFmt, ...) {
3780 if (!vInfos.use_count())
return;
3782 auto& fdi = m_FileDialogInternal.fileManager;
3784 static ImGuiSelectableFlags selectableFlags = ImGuiSelectableFlags_AllowDoubleClick | ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_SpanAvailWidth;
3787 va_start(args, vFmt);
3788 vsnprintf(fdi.variadicBuffer, MAX_FILE_DIALOG_NAME_BUFFER, vFmt, args);
3792#ifdef USE_THUMBNAILS
3793 if (m_DisplayMode == DisplayModeEnum::THUMBNAILS_LIST && !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_DisableThumbnailMode)) {
3794 h = DisplayMode_ThumbailsList_ImageHeight;
3797#ifdef USE_EXPLORATION_BY_KEYS
3798 bool flashed = m_BeginFlashItem((
size_t)vidx);
3799 bool res = m_FlashableSelectable(fdi.variadicBuffer, vSelected, selectableFlags, flashed, ImVec2(-1.0f, h));
3800 if (flashed) m_EndFlashItem();
3804 bool res = ImGui::Selectable(fdi.variadicBuffer, vSelected, selectableFlags, ImVec2(-1.0f, h));
3807 if (vInfos->fileType.isDir()) {
3809 if (ImGui::GetIO().ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) {
3811 if (ImGui::IsMouseDoubleClicked(0))
3813 fdi.puPathClicked = fdi.SelectDirectory(vInfos);
3814 }
else if (fdi.dLGDirectoryMode)
3816 fdi.SelectFileName(m_FileDialogInternal, vInfos);
3822 if (ImGui::IsMouseDoubleClicked(0))
3824 fdi.puPathClicked = fdi.SelectDirectory(vInfos);
3825 }
else if (fdi.dLGDirectoryMode)
3827 fdi.SelectFileName(m_FileDialogInternal, vInfos);
3831 fdi.SelectFileName(m_FileDialogInternal, vInfos);
3833 if (ImGui::IsMouseDoubleClicked(0)) {
3834 m_FileDialogInternal.isOk =
true;
3840void IGFD::FileDialog::m_DisplayFileInfosTooltip(
const int32_t& vRowIdx,
const int32_t& vColumnIdx, std::shared_ptr<FileInfos> vFileInfos) {
3841 if (ImGui::IsItemHovered()) {
3842 if (vFileInfos !=
nullptr && vFileInfos->tooltipColumn == vColumnIdx) {
3843 if (!vFileInfos->tooltipMessage.empty()) {
3844 ImGui::SetTooltip(
"%s", vFileInfos->tooltipMessage.c_str());
3850void IGFD::FileDialog::m_BeginFileColorIconStyle(std::shared_ptr<FileInfos> vFileInfos,
bool& vOutShowColor, std::string& vOutStr, ImFont** vOutFont) {
3852 vOutShowColor =
false;
3854 if (vFileInfos->fileStyle.use_count())
3856 vOutShowColor =
true;
3858 *vOutFont = vFileInfos->fileStyle->font;
3861 if (vOutShowColor && !vFileInfos->fileStyle->icon.empty())
3862 vOutStr = vFileInfos->fileStyle->icon;
3863 else if (vFileInfos->fileType.isDir())
3864 vOutStr = dirEntryString;
3865 else if (vFileInfos->fileType.isLinkToUnknown())
3866 vOutStr = linkEntryString;
3867 else if (vFileInfos->fileType.isFile())
3868 vOutStr = fileEntryString;
3870 vOutStr +=
" " + vFileInfos->fileNameExt;
3872 if (vOutShowColor) ImGui::PushStyleColor(ImGuiCol_Text, vFileInfos->fileStyle->color);
3873 if (*vOutFont) ImGui::PushFont(*vOutFont);
3876void IGFD::FileDialog::m_EndFileColorIconStyle(
const bool& vShowColor, ImFont* vFont) {
3877 if (vFont) ImGui::PopFont();
3878 if (vShowColor) ImGui::PopStyleColor();
3881void IGFD::FileDialog::m_DrawFileListView(ImVec2 vSize) {
3882 auto& fdi = m_FileDialogInternal.fileManager;
3884 ImGui::PushID(
this);
3886 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY
3887#ifndef USE_CUSTOM_SORTING_ICON
3888 | ImGuiTableFlags_Sortable
3891 auto listViewID = ImGui::GetID(
"##FileDialog_fileTable");
3892 if (ImGui::BeginTableEx(
"##FileDialog_fileTable", listViewID, 4, flags, vSize, 0.0f))
3894 ImGui::TableSetupScrollFreeze(0, 1);
3895 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_FILENAME].c_str(), ImGuiTableColumnFlags_WidthStretch | (defaultSortOrderFilename ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 0);
3896 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_TYPE].c_str(),
3897 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderType ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
3898 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnType) ? ImGuiTableColumnFlags_DefaultHide : 0),
3900 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_SIZE].c_str(),
3901 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderSize ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
3902 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnSize) ? ImGuiTableColumnFlags_DefaultHide : 0),
3904 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_DATE].c_str(),
3905 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderDate ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
3906 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnDate) ? ImGuiTableColumnFlags_DefaultHide : 0),
3909#ifndef USE_CUSTOM_SORTING_ICON
3911 if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) {
3912 if (sorts_specs->SpecsDirty && !fdi.IsFileListEmpty()) {
3913 bool direction = sorts_specs->Specs->SortDirection == ImGuiSortDirection_Ascending;
3915 if (sorts_specs->Specs->ColumnUserID == 0) {
3916 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
3917 fdi.sortingDirection[0] = direction;
3918 fdi.SortFields(m_FileDialogInternal);
3919 }
else if (sorts_specs->Specs->ColumnUserID == 1) {
3920 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
3921 fdi.sortingDirection[1] = direction;
3922 fdi.SortFields(m_FileDialogInternal);
3923 }
else if (sorts_specs->Specs->ColumnUserID == 2) {
3924 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
3925 fdi.sortingDirection[2] = direction;
3926 fdi.SortFields(m_FileDialogInternal);
3930 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
3931 fdi.sortingDirection[3] = direction;
3932 fdi.SortFields(m_FileDialogInternal);
3935 sorts_specs->SpecsDirty =
false;
3939 ImGui::TableHeadersRow();
3941 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
3942 for (
int column = 0; column < 4; column++)
3944 ImGui::TableSetColumnIndex(column);
3945 const char* column_name = ImGui::TableGetColumnName(column);
3946 ImGui::PushID(column);
3947 ImGui::TableHeader(column_name);
3949 if (ImGui::IsItemClicked()) {
3951 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME)
3952 fdi.sortingDirection[0] = !fdi.sortingDirection[0];
3954 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
3956 fdi.SortFields(m_FileDialogInternal);
3957 }
else if (column == 1) {
3958 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_TYPE)
3959 fdi.sortingDirection[1] = !fdi.sortingDirection[1];
3961 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
3963 fdi.SortFields(m_FileDialogInternal);
3964 }
else if (column == 2) {
3965 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_SIZE)
3966 fdi.sortingDirection[2] = !fdi.sortingDirection[2];
3968 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
3970 fdi.SortFields(m_FileDialogInternal);
3973 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_DATE)
3974 fdi.sortingDirection[3] = !fdi.sortingDirection[3];
3976 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
3978 fdi.SortFields(m_FileDialogInternal);
3983 if (!fdi.IsFilteredListEmpty()) {
3985 ImFont* _font =
nullptr;
3986 bool _showColor =
false;
3989 m_FileListClipper.Begin((
int)fdi.GetFilteredListSize(), ImGui::GetTextLineHeightWithSpacing());
3990 while (m_FileListClipper.Step()) {
3991 for (
int i = m_FileListClipper.DisplayStart; i < m_FileListClipper.DisplayEnd; i++) {
3992 if (i < 0)
continue;
3994 auto infos = fdi.GetFilteredFileAt((
size_t)i);
3995 if (!infos.use_count())
continue;
3997 m_BeginFileColorIconStyle(infos, _showColor, _str, &_font);
3999 bool selected = fdi.IsFileNameSelected(infos->fileNameExt);
4001 ImGui::TableNextRow();
4004 if (ImGui::TableNextColumn())
4006 m_SelectableItem(i, infos, selected, _str.c_str());
4007 m_DisplayFileInfosTooltip(i, column_id++, infos);
4009 if (ImGui::TableNextColumn())
4011 ImGui::Text(
"%s", infos->fileExtLevels[0].c_str());
4012 m_DisplayFileInfosTooltip(i, column_id++, infos);
4014 if (ImGui::TableNextColumn())
4016 if (!infos->fileType.isDir()) {
4017 RightAlignText(infos->formatedFileSize.first.c_str(),
"1888.88");
4018 ImGui::SameLine(0.0f, 0.0f);
4019 ImGui::Text(
" %s ", infos->formatedFileSize.second.c_str());
4023 m_DisplayFileInfosTooltip(i, column_id++, infos);
4025 if (ImGui::TableNextColumn())
4027 ImGui::Text(
"%s", infos->fileModifDate.c_str());
4028 m_DisplayFileInfosTooltip(i, column_id++, infos);
4031 m_EndFileColorIconStyle(_showColor, _font);
4034 m_FileListClipper.End();
4037#ifdef USE_EXPLORATION_BY_KEYS
4038 if (!fdi.inputPathActivated) {
4039 m_LocateByInputKey(m_FileDialogInternal);
4040 m_ExploreWithkeys(m_FileDialogInternal, listViewID);
4045 if (
g.LastActiveId - 1 == listViewID ||
g.LastActiveId == listViewID) {
4046 m_FileDialogInternal.fileListViewIsActive =
true;
4055#ifdef USE_THUMBNAILS
4056void IGFD::FileDialog::m_DrawThumbnailsListView(ImVec2 vSize) {
4057 auto& fdi = m_FileDialogInternal.fileManager;
4059 ImGui::PushID(
this);
4061 static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Hideable | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY
4062#ifndef USE_CUSTOM_SORTING_ICON
4063 | ImGuiTableFlags_Sortable
4066 auto listViewID = ImGui::GetID(
"##FileDialog_fileTable");
4067 if (ImGui::BeginTableEx(
"##FileDialog_fileTable", listViewID, 5, flags, vSize, 0.0f)) {
4068 ImGui::TableSetupScrollFreeze(0, 1);
4069 ImGui::TableSetupColumn(fdi.headerFileName.c_str(), ImGuiTableColumnFlags_WidthStretch | (defaultSortOrderFilename ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 0);
4070 ImGui::TableSetupColumn(fdi.headerFileType.c_str(),
4071 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderType ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
4072 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnType) ? ImGuiTableColumnFlags_DefaultHide : 0),
4074 ImGui::TableSetupColumn(fdi.headerFileSize.c_str(),
4075 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderSize ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
4076 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnSize) ? ImGuiTableColumnFlags_DefaultHide : 0),
4078 ImGui::TableSetupColumn(fdi.headerFileDate.c_str(),
4079 ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderDate ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending) |
4080 ((m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_HideColumnDate) ? ImGuiTableColumnFlags_DefaultHide : 0),
4083 ImGui::TableSetupColumn(fdi.header[FileManager::SortingFieldEnum::FIELD_THUMBNAILS].c_str(), ImGuiTableColumnFlags_WidthFixed | (defaultSortOrderThumbnails ? ImGuiTableColumnFlags_PreferSortAscending : ImGuiTableColumnFlags_PreferSortDescending), -1, 4);
4085#ifndef USE_CUSTOM_SORTING_ICON
4087 if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) {
4088 if (sorts_specs->SpecsDirty && !fdi.IsFileListEmpty()) {
4089 bool direction = sorts_specs->Specs->SortDirection == ImGuiSortDirection_Ascending;
4091 if (sorts_specs->Specs->ColumnUserID == 0) {
4092 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
4093 fdi.sortingDirection[0] = direction;
4094 fdi.SortFields(m_FileDialogInternal);
4095 }
else if (sorts_specs->Specs->ColumnUserID == 1) {
4096 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
4097 fdi.sortingDirection[1] = direction;
4098 fdi.SortFields(m_FileDialogInternal);
4099 }
else if (sorts_specs->Specs->ColumnUserID == 2) {
4100 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
4101 fdi.sortingDirection[2] = direction;
4102 fdi.SortFields(m_FileDialogInternal);
4103 }
else if (sorts_specs->Specs->ColumnUserID == 3) {
4104 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
4105 fdi.sortingDirection[3] = direction;
4106 fdi.SortFields(m_FileDialogInternal);
4110 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_THUMBNAILS;
4111 fdi.sortingDirection[4] = direction;
4112 fdi.SortFields(m_FileDialogInternal);
4115 sorts_specs->SpecsDirty =
false;
4119 ImGui::TableHeadersRow();
4121 ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
4122 for (
int column = 0; column < 5; column++) {
4123 ImGui::TableSetColumnIndex(column);
4124 const char* column_name = ImGui::TableGetColumnName(column);
4125 ImGui::PushID(column);
4126 ImGui::TableHeader(column_name);
4128 if (ImGui::IsItemClicked()) {
4130 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME)
4131 fdi.sortingDirection[0] = !fdi.sortingDirection[0];
4133 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_FILENAME;
4135 fdi.SortFields(m_FileDialogInternal);
4136 }
else if (column == 1) {
4137 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_TYPE)
4138 fdi.sortingDirection[1] = !fdi.sortingDirection[1];
4140 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_TYPE;
4142 fdi.SortFields(m_FileDialogInternal);
4143 }
else if (column == 2) {
4144 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_SIZE)
4145 fdi.sortingDirection[2] = !fdi.sortingDirection[2];
4147 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_SIZE;
4149 fdi.SortFields(m_FileDialogInternal);
4150 }
else if (column == 3) {
4151 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_DATE)
4152 fdi.sortingDirection[3] = !fdi.sortingDirection[3];
4154 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_DATE;
4156 fdi.SortFields(m_FileDialogInternal);
4160 if (fdi.sortingField == IGFD::FileManager::SortingFieldEnum::FIELD_THUMBNAILS)
4161 fdi.sortingDirection[4] = !fdi.sortingDirection[4];
4163 fdi.sortingField = IGFD::FileManager::SortingFieldEnum::FIELD_THUMBNAILS;
4165 fdi.SortFields(m_FileDialogInternal);
4170 if (!fdi.IsFilteredListEmpty()) {
4172 ImFont* _font =
nullptr;
4173 bool _showColor =
false;
4176 const float itemHeight = ImMax(
g.FontSize, DisplayMode_ThumbailsList_ImageHeight) +
g.Style.ItemSpacing.y;
4179 m_FileListClipper.Begin((
int)fdi.GetFilteredListSize(), itemHeight);
4180 while (m_FileListClipper.Step()) {
4181 for (
int i = m_FileListClipper.DisplayStart; i < m_FileListClipper.DisplayEnd; i++) {
4182 if (i < 0)
continue;
4184 auto infos = fdi.GetFilteredFileAt((
size_t)i);
4185 if (!infos.use_count())
continue;
4187 m_BeginFileColorIconStyle(infos, _showColor, _str, &_font);
4189 bool selected = fdi.IsFileNameSelected(infos->fileNameExt);
4191 ImGui::TableNextRow();
4194 if (ImGui::TableNextColumn())
4196 m_SelectableItem(i, infos, selected, _str.c_str());
4197 m_DisplayFileInfosTooltip(i, column_id++, infos);
4199 if (ImGui::TableNextColumn())
4201 ImGui::Text(
"%s", infos->fileExtLevels[0].c_str());
4202 m_DisplayFileInfosTooltip(i, column_id++, infos);
4204 if (ImGui::TableNextColumn())
4206 if (!infos->fileType.isDir()) {
4207 RightAlignText(infos->formatedFileSize.first.c_str(),
"1888.88");
4208 ImGui::SameLine(0.0f, 0.0f);
4209 ImGui::Text(
" %s ", infos->formatedFileSize.second.c_str());
4213 m_DisplayFileInfosTooltip(i, column_id++, infos);
4215 if (ImGui::TableNextColumn())
4217 ImGui::Text(
"%s", infos->fileModifDate.c_str());
4218 m_DisplayFileInfosTooltip(i, column_id++, infos);
4220 if (ImGui::TableNextColumn())
4222 auto th = &infos->thumbnailInfo;
4224 if (!th->isLoadingOrLoaded) {
4225 m_AddThumbnailToLoad(infos);
4227 if (th->isReadyToDisplay && th->textureID) {
4228 ImGui::Image((ImTextureID)th->textureID, ImVec2((
float)th->textureWidth, (
float)th->textureHeight));
4230 m_DisplayFileInfosTooltip(i, column_id++, infos);
4233 m_EndFileColorIconStyle(_showColor, _font);
4236 m_FileListClipper.End();
4239#ifdef USE_EXPLORATION_BY_KEYS
4240 if (!fdi.inputPathActivated) {
4241 m_LocateByInputKey(m_FileDialogInternal);
4242 m_ExploreWithkeys(m_FileDialogInternal, listViewID);
4247 if (
g.LastActiveId - 1 == listViewID ||
g.LastActiveId == listViewID) {
4248 m_FileDialogInternal.fileListViewIsActive =
true;
4257void IGFD::FileDialog::m_DrawThumbnailsGridView(ImVec2 vSize) {
4258 if (ImGui::BeginChild(
"##thumbnailsGridsFiles", vSize)) {
4267void IGFD::FileDialog::m_DrawSidePane(
float vHeight) {
4270 ImGui::BeginChild(
"##FileTypes", ImVec2(0, vHeight));
4272 m_FileDialogInternal.getDialogConfig().sidePane(
4273 m_FileDialogInternal.filterManager.GetSelectedFilter().getFirstFilter().c_str(),
4274 m_FileDialogInternal.getDialogConfigRef().userDatas,
4275 &m_FileDialogInternal.canWeContinue);
4279void IGFD::FileDialog::Close() {
4280 m_FileDialogInternal.dLGkey.clear();
4281 m_FileDialogInternal.showDialog =
false;
4284bool IGFD::FileDialog::WasOpenedThisFrame(
const std::string& vKey)
const {
4285 bool res = m_FileDialogInternal.showDialog && m_FileDialogInternal.dLGkey == vKey;
4287 res &= m_FileDialogInternal.lastImGuiFrameCount ==
GImGui->FrameCount;
4292bool IGFD::FileDialog::WasOpenedThisFrame()
const {
4293 bool res = m_FileDialogInternal.showDialog;
4295 res &= m_FileDialogInternal.lastImGuiFrameCount ==
GImGui->FrameCount;
4300bool IGFD::FileDialog::IsOpened(
const std::string& vKey)
const {
4301 return (m_FileDialogInternal.showDialog && m_FileDialogInternal.dLGkey == vKey);
4304bool IGFD::FileDialog::IsOpened()
const {
4305 return m_FileDialogInternal.showDialog;
4308std::string IGFD::FileDialog::GetOpenedKey()
const {
4309 if (m_FileDialogInternal.showDialog) {
4310 return m_FileDialogInternal.dLGkey;
4315std::string IGFD::FileDialog::GetFilePathName(IGFD_ResultMode vFlag) {
4316 return m_FileDialogInternal.fileManager.GetResultingFilePathName(m_FileDialogInternal, vFlag);
4319std::string IGFD::FileDialog::GetCurrentPath() {
4320 return m_FileDialogInternal.fileManager.GetResultingPath();
4323std::string IGFD::FileDialog::GetCurrentFileName(IGFD_ResultMode vFlag) {
4324 return m_FileDialogInternal.fileManager.GetResultingFileName(m_FileDialogInternal, vFlag);
4327std::string IGFD::FileDialog::GetCurrentFilter() {
4328 return m_FileDialogInternal.filterManager.GetSelectedFilter().title;
4331std::map<std::string, std::string> IGFD::FileDialog::GetSelection(IGFD_ResultMode vFlag) {
4332 return m_FileDialogInternal.fileManager.GetResultingSelection(m_FileDialogInternal, vFlag);
4335IGFD::UserDatas IGFD::FileDialog::GetUserDatas()
const {
4336 return m_FileDialogInternal.getDialogConfig().userDatas;
4339bool IGFD::FileDialog::IsOk()
const {
4340 return m_FileDialogInternal.isOk;
4343void IGFD::FileDialog::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const FileStyle& vInfos) {
4344 m_FileDialogInternal.filterManager.SetFileStyle(vFlags, vCriteria, vInfos);
4347void IGFD::FileDialog::SetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const char* vCriteria,
const ImVec4& vColor,
const std::string& vIcon, ImFont* vFont) {
4348 m_FileDialogInternal.filterManager.SetFileStyle(vFlags, vCriteria, vColor, vIcon, vFont);
4351void IGFD::FileDialog::SetFileStyle(FileStyle::FileStyleFunctor vFunctor) {
4352 m_FileDialogInternal.filterManager.SetFileStyle(vFunctor);
4355bool IGFD::FileDialog::GetFileStyle(
const IGFD_FileStyleFlags& vFlags,
const std::string& vCriteria, ImVec4* vOutColor, std::string* vOutIcon, ImFont** vOutFont) {
4356 return m_FileDialogInternal.filterManager.GetFileStyle(vFlags, vCriteria, vOutColor, vOutIcon, vOutFont);
4359void IGFD::FileDialog::ClearFilesStyle() {
4360 m_FileDialogInternal.filterManager.ClearFilesStyle();
4363void IGFD::FileDialog::SetLocales(
const int& ,
const std::string& vLocaleBegin,
const std::string& vLocaleEnd) {
4364 m_FileDialogInternal.puUseCustomLocale =
true;
4365 m_FileDialogInternal.localeBegin = vLocaleBegin;
4366 m_FileDialogInternal.localeEnd = vLocaleEnd;
4373bool IGFD::FileDialog::m_Confirm_Or_OpenOverWriteFileDialog_IfNeeded(
bool vLastAction, ImGuiWindowFlags vFlags) {
4378 if (!m_FileDialogInternal.isOk && vLastAction) {
4384 if (m_FileDialogInternal.isOk && vLastAction && !(m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_ConfirmOverwrite)) {
4390 if ((m_FileDialogInternal.okResultToConfirm || (m_FileDialogInternal.isOk && vLastAction)) && (m_FileDialogInternal.getDialogConfig().flags & ImGuiFileDialogFlags_ConfirmOverwrite)) {
4391 if (m_FileDialogInternal.isOk)
4393 if (!m_FileDialogInternal.fileManager.GetFileSystemInstance()->IsFileExist(GetFilePathName()))
4399 m_FileDialogInternal.isOk =
false;
4400 m_FileDialogInternal.okResultToConfirm =
true;
4404 std::string name = OverWriteDialogTitleString
"##" + m_FileDialogInternal.dLGtitle + m_FileDialogInternal.dLGkey +
"OverWriteDialog";
4408 ImGui::OpenPopup(name.c_str());
4409 if (ImGui::BeginPopupModal(name.c_str(), (
bool*)0, vFlags | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove)) {
4410 ImGui::SetWindowPos(m_FileDialogInternal.dialogCenterPos - ImGui::GetWindowSize() * 0.5f);
4412 ImGui::Text(
"%s", OverWriteDialogMessageString);
4414 if (IMGUI_BUTTON(OverWriteDialogConfirmButtonString)) {
4415 m_FileDialogInternal.okResultToConfirm =
false;
4416 m_FileDialogInternal.isOk =
true;
4418 ImGui::CloseCurrentPopup();
4423 if (IMGUI_BUTTON(OverWriteDialogCancelButtonString)) {
4424 m_FileDialogInternal.okResultToConfirm =
false;
4425 m_FileDialogInternal.isOk =
false;
4427 ImGui::CloseCurrentPopup();
4452 IGFD_FileDialog_Config res = {};
4455 res.filePathName =
"";
4456 res.countSelectionMax = 1;
4457 res.userDatas =
nullptr;
4458 res.sidePane =
nullptr;
4459 res.sidePaneWidth = 250.0f;
4460 res.flags = ImGuiFileDialogFlags_Default;
4466 IGFD_Selection_Pair res = {};
4467 res.fileName =
nullptr;
4468 res.filePathName =
nullptr;
4474 if (vSelection_Pair) {
4475 delete[] vSelection_Pair->fileName;
4476 delete[] vSelection_Pair->filePathName;
4482 return {
nullptr, 0U};
4488 if (vSelection->table) {
4489 for (
size_t i = 0U; i < vSelection->count; i++) {
4492 delete[] vSelection->table;
4494 vSelection->count = 0U;
4500 return new ImGuiFileDialog();
4505 if (vContextPtr !=
nullptr) {
4507 vContextPtr =
nullptr;
4512 ImGuiFileDialog* vContextPtr,
4515 const char* vFilters,
4516 const IGFD_FileDialog_Config vConfig) {
4517 if (vContextPtr !=
nullptr) {
4518 IGFD::FileDialogConfig config;
4519 config.path = vConfig.path;
4520 config.fileName = vConfig.fileName;
4521 config.filePathName = vConfig.filePathName;
4522 config.countSelectionMax = vConfig.countSelectionMax;
4523 config.userDatas = vConfig.userDatas;
4524 config.flags = vConfig.flags;
4525 config.sidePane = vConfig.sidePane;
4526 config.sidePaneWidth = vConfig.sidePaneWidth;
4527 vContextPtr->OpenDialog(vKey, vTitle, vFilters, config);
4531IGFD_C_API
bool IGFD_DisplayDialog(ImGuiFileDialog* vContextPtr,
const char* vKey, ImGuiWindowFlags vFlags, ImVec2 vMinSize, ImVec2 vMaxSize) {
4532 if (vContextPtr !=
nullptr) {
4533 return vContextPtr->Display(vKey, vFlags, vMinSize, vMaxSize);
4539 if (vContextPtr !=
nullptr) {
4540 vContextPtr->Close();
4545 if (vContextPtr !=
nullptr) {
4546 return vContextPtr->IsOk();
4552 if (vContextPtr !=
nullptr) {
4553 return vContextPtr->WasOpenedThisFrame(vKey);
4559 if (vContextPtr !=
nullptr) {
4560 return vContextPtr->WasOpenedThisFrame();
4567 if (vContextPtr !=
nullptr) {
4568 return vContextPtr->IsOpened(vCurrentOpenedKey);
4575 if (vContextPtr !=
nullptr) {
4576 return vContextPtr->IsOpened();
4584 if (vContextPtr !=
nullptr) {
4585 auto sel = vContextPtr->GetSelection(vMode);
4587 res.count = sel.size();
4588 res.table =
new IGFD_Selection_Pair[res.count];
4591 for (
const auto& s : sel) {
4592 IGFD_Selection_Pair* pair = res.table + idx++;
4595 if (!s.first.empty()) {
4596 size_t siz = s.first.size() + 1U;
4597 pair->fileName =
new char[siz];
4599 strncpy(pair->fileName, s.first.c_str(), siz);
4601 strncpy_s(pair->fileName, siz, s.first.c_str(), siz);
4603 pair->fileName[siz - 1U] =
'\0';
4607 if (!s.second.empty()) {
4608 size_t siz = s.second.size() + 1U;
4609 pair->filePathName =
new char[siz];
4611 strncpy(pair->filePathName, s.second.c_str(), siz);
4613 strncpy_s(pair->filePathName, siz, s.second.c_str(), siz);
4615 pair->filePathName[siz - 1U] =
'\0';
4627 char* res =
nullptr;
4629 if (vContextPtr !=
nullptr) {
4630 auto s = vContextPtr->GetFilePathName(vMode);
4632 size_t siz = s.size() + 1U;
4633 res = (
char*)malloc(siz);
4636 strncpy(res, s.c_str(), siz);
4638 strncpy_s(res, siz, s.c_str(), siz);
4640 res[siz - 1U] =
'\0';
4649 char* res =
nullptr;
4651 if (vContextPtr !=
nullptr) {
4652 auto s = vContextPtr->GetCurrentFileName(vMode);
4654 size_t siz = s.size() + 1U;
4655 res = (
char*)malloc(siz);
4658 strncpy(res, s.c_str(), siz);
4660 strncpy_s(res, siz, s.c_str(), siz);
4662 res[siz - 1U] =
'\0';
4671 char* res =
nullptr;
4673 if (vContextPtr !=
nullptr) {
4674 auto s = vContextPtr->GetCurrentPath();
4676 size_t siz = s.size() + 1U;
4677 res = (
char*)malloc(siz);
4680 strncpy(res, s.c_str(), siz);
4682 strncpy_s(res, siz, s.c_str(), siz);
4684 res[siz - 1U] =
'\0';
4693 char* res =
nullptr;
4695 if (vContextPtr !=
nullptr) {
4696 auto s = vContextPtr->GetCurrentFilter();
4698 size_t siz = s.size() + 1U;
4699 res = (
char*)malloc(siz);
4702 strncpy(res, s.c_str(), siz);
4704 strncpy_s(res, siz, s.c_str(), siz);
4706 res[siz - 1U] =
'\0';
4715 if (vContextPtr !=
nullptr) {
4716 return vContextPtr->GetUserDatas();
4722IGFD_C_API
void IGFD_SetFileStyle(ImGuiFileDialog* vContextPtr, IGFD_FileStyleFlags vFlags,
const char* vCriteria, ImVec4 vColor,
const char* vIcon,
4725 if (vContextPtr !=
nullptr) {
4726 vContextPtr->SetFileStyle(vFlags, vCriteria, vColor, vIcon, vFont);
4730IGFD_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) {
4731 if (vContextPtr !=
nullptr) {
4732 vContextPtr->SetFileStyle(vFlags, vCriteria, ImVec4(vR, vG, vB, vA), vIcon, vFont);
4736IGFD_C_API
bool IGFD_GetFileStyle(ImGuiFileDialog* vContextPtr, IGFD_FileStyleFlags vFlags,
const char* vCriteria, ImVec4* vOutColor,
char** vOutIconText, ImFont** vOutFont) {
4737 if (vContextPtr !=
nullptr) {
4739 bool res = vContextPtr->GetFileStyle(vFlags, vCriteria, vOutColor, &icon, vOutFont);
4740 if (!icon.empty() && vOutIconText) {
4741 size_t siz = icon.size() + 1U;
4742 *vOutIconText = (
char*)malloc(siz);
4743 if (*vOutIconText) {
4745 strncpy(*vOutIconText, icon.c_str(), siz);
4747 strncpy_s(*vOutIconText, siz, icon.c_str(), siz);
4749 (*vOutIconText)[siz - 1U] =
'\0';
4759 if (vContextPtr !=
nullptr) {
4760 vContextPtr->ClearFilesStyle();
4764IGFD_C_API
void SetLocales(ImGuiFileDialog* vContextPtr,
const int vCategory,
const char* vBeginLocale,
const char* vEndLocale) {
4765 if (vContextPtr !=
nullptr) {
4766 vContextPtr->SetLocales(vCategory, (vBeginLocale ? vBeginLocale :
""), (vEndLocale ? vEndLocale :
""));
4770#ifdef USE_EXPLORATION_BY_KEYS
4772 if (vContextPtr !=
nullptr) {
4773 vContextPtr->SetFlashingAttenuationInSeconds(vAttenValue);
4780 char* res =
nullptr;
4782 if (vContextPtr !=
nullptr) {
4783 auto s = vContextPtr->SerializeBookmarks(vDontSerializeCodeBasedBookmarks);
4785 size_t siz = s.size() + 1U;
4786 res = (
char*)malloc(siz);
4789 strncpy(res, s.c_str(), siz);
4791 strncpy_s(res, siz, s.c_str(), siz);
4793 res[siz - 1U] =
'\0';
4802 if (vContextPtr !=
nullptr) {
4803 vContextPtr->DeserializeBookmarks(vBookmarks);
4807IGFD_C_API
void IGFD_AddBookmark(ImGuiFileDialog* vContextPtr,
const char* vBookMarkName,
const char* vBookMarkPath) {
4808 if (vContextPtr !=
nullptr) {
4809 vContextPtr->AddBookmark(vBookMarkName, vBookMarkPath);
4814 if (vContextPtr !=
nullptr) {
4815 vContextPtr->RemoveBookmark(vBookMarkName);
4821#ifdef USE_THUMBNAILS
4822IGFD_C_API
void SetCreateThumbnailCallback(ImGuiFileDialog* vContextPtr,
const IGFD_CreateThumbnailFun vCreateThumbnailFun) {
4823 if (vContextPtr !=
nullptr) {
4824 vContextPtr->SetCreateThumbnailCallback(vCreateThumbnailFun);
4828IGFD_C_API
void SetDestroyThumbnailCallback(ImGuiFileDialog* vContextPtr,
const IGFD_DestroyThumbnailFun vDestroyThumbnailFun) {
4829 if (vContextPtr !=
nullptr) {
4830 vContextPtr->SetDestroyThumbnailCallback(vDestroyThumbnailFun);
4834IGFD_C_API
void ManageGPUThumbnails(ImGuiFileDialog* vContextPtr) {
4835 if (vContextPtr !=
nullptr) {
4836 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)
void RightAlignText(std::string_view text, std::string_view maxWidthText)
uint16_t word
16 bit unsigned integer
auto count(InputRange &&range, const T &value)
size_t size(std::string_view utf8)
auto filter(ForwardRange &&range, Predicate pred)
constexpr auto end(const zstring_view &x)