1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069 |
- #pragma once
- #include <algorithm>
- #include <array>
- #include <cctype>
- #include <cstring>
- #include <filesystem>
- #include <memory>
- #include <set>
- #include <string>
- #include <string_view>
- #include <vector>
- #ifndef IMGUI_VERSION
- # error "include imgui.h before this header"
- #endif
- using ImGuiFileBrowserFlags = int;
- enum ImGuiFileBrowserFlags_
- {
- ImGuiFileBrowserFlags_SelectDirectory = 1 << 0, // select directory instead of regular file
- ImGuiFileBrowserFlags_EnterNewFilename = 1 << 1, // allow user to enter new filename when selecting regular file
- ImGuiFileBrowserFlags_NoModal = 1 << 2, // file browsing window is modal by default. specify this to use a popup window
- ImGuiFileBrowserFlags_NoTitleBar = 1 << 3, // hide window title bar
- ImGuiFileBrowserFlags_NoStatusBar = 1 << 4, // hide status bar at the bottom of browsing window
- ImGuiFileBrowserFlags_CloseOnEsc = 1 << 5, // close file browser when pressing 'ESC'
- ImGuiFileBrowserFlags_CreateNewDir = 1 << 6, // allow user to create new directory
- ImGuiFileBrowserFlags_MultipleSelection = 1 << 7, // allow user to select multiple files. this will hide ImGuiFileBrowserFlags_EnterNewFilename
- ImGuiFileBrowserFlags_HideRegularFiles = 1 << 8, // hide regular files when ImGuiFileBrowserFlags_SelectDirectory is enabled
- ImGuiFileBrowserFlags_ConfirmOnEnter = 1 << 9, // confirm selection when pressnig 'ENTER'
- };
- namespace ImGui
- {
- class FileBrowser
- {
- public:
- // pwd is set to current working directory by default
- explicit FileBrowser(ImGuiFileBrowserFlags flags = 0);
- FileBrowser(const FileBrowser ©From);
- FileBrowser &operator=(const FileBrowser ©From);
- // set the window position (in pixels)
- // default is centered
- void SetWindowPos(int posx, int posy) noexcept;
- // set the window size (in pixels)
- // default is (700, 450)
- void SetWindowSize(int width, int height) noexcept;
- // set the window title text
- void SetTitle(std::string title);
- // open the browsing window
- void Open();
- // close the browsing window
- void Close();
- // the browsing window is opened or not
- bool IsOpened() const noexcept;
- // display the browsing window if opened
- void Display();
- // returns true when there is a selected filename and the "ok" button was clicked
- bool HasSelected() const noexcept;
- // set current browsing directory
- bool SetPwd(const std::filesystem::path &pwd =
- std::filesystem::current_path());
- // get current browsing directory
- const std::filesystem::path &GetPwd() const noexcept;
- // returns selected filename. make sense only when HasSelected returns true
- // when ImGuiFileBrowserFlags_MultipleSelection is enabled, only one of
- // selected filename will be returned
- std::filesystem::path GetSelected() const;
- // returns all selected filenames.
- // when ImGuiFileBrowserFlags_MultipleSelection is enabled, use this
- // instead of GetSelected
- std::vector<std::filesystem::path> GetMultiSelected() const;
- // set selected filename to empty
- void ClearSelected();
- // (optional) set file type filters. eg. { ".h", ".cpp", ".hpp" }
- // ".*" matches any file types
- void SetTypeFilters(const std::vector<std::string> &typeFilters);
- // set currently applied type filter
- // default value is 0 (the first type filter)
- void SetCurrentTypeFilterIndex(int index);
- // when ImGuiFileBrowserFlags_EnterNewFilename is set
- // this function will pre-fill the input dialog with a filename.
- void SetInputName(std::string_view input);
- private:
- template <class Functor>
- struct ScopeGuard
- {
- ScopeGuard(Functor&& t) : func(std::move(t)) { }
- ~ScopeGuard() { func(); }
- private:
- Functor func;
- };
- struct FileRecord
- {
- bool isDir = false;
- std::filesystem::path name;
- std::string showName;
- std::filesystem::path extension;
- };
- static std::string ToLower(const std::string &s);
- void UpdateFileRecords();
- void SetPwdUncatched(const std::filesystem::path &pwd);
- bool IsExtensionMatched(const std::filesystem::path &extension) const;
- void ClearRangeSelectionState();
- #ifdef _WIN32
- static std::uint32_t GetDrivesBitMask();
- #endif
- // for c++17 compatibility
- #if defined(__cpp_lib_char8_t)
- static std::string u8StrToStr(std::u8string s);
- #endif
- static std::string u8StrToStr(std::string s);
- int width_;
- int height_;
- int posX_;
- int posY_;
- ImGuiFileBrowserFlags flags_;
- std::string title_;
- std::string openLabel_;
- bool openFlag_;
- bool closeFlag_;
- bool isOpened_;
- bool ok_;
- bool posIsSet_;
- std::string statusStr_;
- std::vector<std::string> typeFilters_;
- unsigned int typeFilterIndex_;
- bool hasAllFilter_;
- std::filesystem::path pwd_;
- std::set<std::filesystem::path> selectedFilenames_;
- unsigned int rangeSelectionStart_; // enable range selection when shift is pressed
- std::vector<FileRecord> fileRecords_;
- // IMPROVE: truncate when selectedFilename_.length() > inputNameBuf_.size() - 1
- static constexpr size_t INPUT_NAME_BUF_SIZE = 512;
- std::unique_ptr<std::array<char, INPUT_NAME_BUF_SIZE>> inputNameBuf_;
- std::string openNewDirLabel_;
- std::unique_ptr<std::array<char, INPUT_NAME_BUF_SIZE>> newDirNameBuf_;
- #ifdef _WIN32
- uint32_t drives_;
- #endif
- };
- } // namespace ImGui
- inline ImGui::FileBrowser::FileBrowser(ImGuiFileBrowserFlags flags)
- : width_(700), height_(450), posX_(0), posY_(0), flags_(flags),
- openFlag_(false), closeFlag_(false), isOpened_(false), ok_(false), posIsSet_(false),
- rangeSelectionStart_(0), inputNameBuf_(std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>())
- {
- if(flags_ & ImGuiFileBrowserFlags_CreateNewDir)
- {
- newDirNameBuf_ =
- std::make_unique<std::array<char, INPUT_NAME_BUF_SIZE>>();
- }
- inputNameBuf_->front() = '\0';
- inputNameBuf_->back() = '\0';
- SetTitle("file browser");
- SetPwd(std::filesystem::current_path());
- typeFilters_.clear();
- typeFilterIndex_ = 0;
- hasAllFilter_ = false;
- #ifdef _WIN32
- drives_ = GetDrivesBitMask();
- #endif
- }
- inline ImGui::FileBrowser::FileBrowser(const FileBrowser ©From)
- : FileBrowser()
- {
- *this = copyFrom;
- }
- inline ImGui::FileBrowser &ImGui::FileBrowser::operator=(
- const FileBrowser ©From)
- {
- width_ = copyFrom.width_;
- height_ = copyFrom.height_;
- posX_ = copyFrom.posX_;
- posY_ = copyFrom.posY_;
- flags_ = copyFrom.flags_;
- SetTitle(copyFrom.title_);
- openFlag_ = copyFrom.openFlag_;
- closeFlag_ = copyFrom.closeFlag_;
- isOpened_ = copyFrom.isOpened_;
- ok_ = copyFrom.ok_;
- posIsSet_ = copyFrom.posIsSet_;
- statusStr_ = "";
- typeFilters_ = copyFrom.typeFilters_;
- typeFilterIndex_ = copyFrom.typeFilterIndex_;
- hasAllFilter_ = copyFrom.hasAllFilter_;
- pwd_ = copyFrom.pwd_;
- selectedFilenames_ = copyFrom.selectedFilenames_;
- rangeSelectionStart_ = copyFrom.rangeSelectionStart_;
- fileRecords_ = copyFrom.fileRecords_;
- *inputNameBuf_ = *copyFrom.inputNameBuf_;
- openNewDirLabel_ = copyFrom.openNewDirLabel_;
- if(flags_ & ImGuiFileBrowserFlags_CreateNewDir)
- {
- newDirNameBuf_ = std::make_unique<
- std::array<char, INPUT_NAME_BUF_SIZE>>();
- *newDirNameBuf_ = *copyFrom.newDirNameBuf_;
- }
- #ifdef _WIN32
- drives_ = copyFrom.drives_;
- #endif
- return *this;
- }
- inline void ImGui::FileBrowser::SetWindowPos(int posx, int posy) noexcept
- {
- posX_ = posx;
- posY_ = posy;
- posIsSet_ = true;
- }
- inline void ImGui::FileBrowser::SetWindowSize(int width, int height) noexcept
- {
- assert(width > 0 && height > 0);
- width_ = width;
- height_ = height;
- }
- inline void ImGui::FileBrowser::SetTitle(std::string title)
- {
- title_ = std::move(title);
- openLabel_ = title_ + "##filebrowser_" +
- std::to_string(reinterpret_cast<size_t>(this));
- openNewDirLabel_ = "new dir##new_dir_" +
- std::to_string(reinterpret_cast<size_t>(this));
- }
- inline void ImGui::FileBrowser::Open()
- {
- UpdateFileRecords();
- ClearSelected();
- statusStr_ = std::string();
- openFlag_ = true;
- closeFlag_ = false;
- }
- inline void ImGui::FileBrowser::Close()
- {
- ClearSelected();
- statusStr_ = std::string();
- closeFlag_ = true;
- openFlag_ = false;
- }
- inline bool ImGui::FileBrowser::IsOpened() const noexcept
- {
- return isOpened_;
- }
- inline void ImGui::FileBrowser::Display()
- {
- PushID(this);
- ScopeGuard exitThis([this]
- {
- openFlag_ = false;
- closeFlag_ = false;
- PopID();
- });
- if(openFlag_)
- {
- OpenPopup(openLabel_.c_str());
- }
- isOpened_ = false;
- // open the popup window
- if(openFlag_ && (flags_ & ImGuiFileBrowserFlags_NoModal))
- {
- if(posIsSet_)
- {
- SetNextWindowPos(
- ImVec2(static_cast<float>(posX_), static_cast<float>(posY_)));
- }
- SetNextWindowSize(
- ImVec2(static_cast<float>(width_), static_cast<float>(height_)));
- }
- else
- {
- if(posIsSet_)
- {
- SetNextWindowPos(
- ImVec2(static_cast<float>(posX_), static_cast<float>(posY_)),
- ImGuiCond_FirstUseEver);
- }
- SetNextWindowSize(
- ImVec2(static_cast<float>(width_), static_cast<float>(height_)),
- ImGuiCond_FirstUseEver);
- }
- if(flags_ & ImGuiFileBrowserFlags_NoModal)
- {
- if(!BeginPopup(openLabel_.c_str()))
- {
- return;
- }
- }
- else if(!BeginPopupModal(openLabel_.c_str(), nullptr,
- flags_ & ImGuiFileBrowserFlags_NoTitleBar ?
- ImGuiWindowFlags_NoTitleBar : 0))
- {
- return;
- }
- isOpened_ = true;
- ScopeGuard endPopup([] { EndPopup(); });
- // display elements in pwd
- #ifdef _WIN32
- char currentDrive = static_cast<char>(pwd_.c_str()[0]);
- char driveStr[] = { currentDrive, ':', '\0' };
- PushItemWidth(4 * GetFontSize());
- if(BeginCombo("##select_drive", driveStr))
- {
- ScopeGuard guard([&] { EndCombo(); });
- for(int i = 0; i < 26; ++i)
- {
- if(!(drives_ & (1 << i)))
- {
- continue;
- }
- char driveCh = static_cast<char>('A' + i);
- char selectableStr[] = { driveCh, ':', '\0' };
- bool selected = currentDrive == driveCh;
- if(Selectable(selectableStr, selected) && !selected)
- {
- char newPwd[] = { driveCh, ':', '\\', '\0' };
- SetPwd(newPwd);
- }
- }
- }
- PopItemWidth();
- SameLine();
- #endif
- int secIdx = 0, newPwdLastSecIdx = -1;
- for(const auto &sec : pwd_)
- {
- #ifdef _WIN32
- if(secIdx == 1)
- {
- ++secIdx;
- continue;
- }
- #endif
- PushID(secIdx);
- if(secIdx > 0)
- {
- SameLine();
- }
- if(SmallButton(u8StrToStr(sec.u8string()).c_str()))
- {
- newPwdLastSecIdx = secIdx;
- }
- PopID();
- ++secIdx;
- }
- if(newPwdLastSecIdx >= 0)
- {
- int i = 0;
- std::filesystem::path newPwd;
- for(const auto &sec : pwd_)
- {
- if(i++ > newPwdLastSecIdx)
- {
- break;
- }
- newPwd /= sec;
- }
- #ifdef _WIN32
- if(newPwdLastSecIdx == 0)
- {
- newPwd /= "\\";
- }
- #endif
- SetPwd(newPwd);
- }
- SameLine();
- if(SmallButton("*"))
- {
- UpdateFileRecords();
- std::set<std::filesystem::path> newSelectedFilenames;
- for(auto &name : selectedFilenames_)
- {
- auto it = std::find_if(
- fileRecords_.begin(), fileRecords_.end(),
- [&](const FileRecord &record)
- {
- return name == record.name;
- });
- if(it != fileRecords_.end())
- {
- newSelectedFilenames.insert(name);
- }
- }
- if(inputNameBuf_ && (*inputNameBuf_)[0])
- {
- newSelectedFilenames.insert(inputNameBuf_->data());
- }
- }
- bool focusOnInputText = false;
- if(newDirNameBuf_)
- {
- SameLine();
- if(SmallButton("+"))
- {
- OpenPopup(openNewDirLabel_.c_str());
- (*newDirNameBuf_)[0] = '\0';
- }
- if(BeginPopup(openNewDirLabel_.c_str()))
- {
- ScopeGuard endNewDirPopup([] { EndPopup(); });
- InputText("name", newDirNameBuf_->data(), newDirNameBuf_->size());
- focusOnInputText |= IsItemFocused();
- SameLine();
- if(Button("ok") && (*newDirNameBuf_)[0] != '\0')
- {
- ScopeGuard closeNewDirPopup([] { CloseCurrentPopup(); });
- if(create_directory(pwd_ / newDirNameBuf_->data()))
- {
- UpdateFileRecords();
- }
- else
- {
- statusStr_ = "failed to create " +
- std::string(newDirNameBuf_->data());
- }
- }
- }
- }
- // browse files in a child window
- float reserveHeight = GetFrameHeightWithSpacing();
- std::filesystem::path newPwd; bool setNewPwd = false;
- if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) &&
- (flags_ & ImGuiFileBrowserFlags_EnterNewFilename))
- reserveHeight += GetFrameHeightWithSpacing();
- {
- BeginChild("ch", ImVec2(0, -reserveHeight), true,
- (flags_ & ImGuiFileBrowserFlags_NoModal) ?
- ImGuiWindowFlags_AlwaysHorizontalScrollbar : 0);
- ScopeGuard endChild([] { EndChild(); });
- const bool shouldHideRegularFiles =
- (flags_ & ImGuiFileBrowserFlags_HideRegularFiles) &&
- (flags_ & ImGuiFileBrowserFlags_SelectDirectory);
- for(unsigned int rscIndex = 0; rscIndex < fileRecords_.size(); ++rscIndex)
- {
- auto &rsc = fileRecords_[rscIndex];
- if(!rsc.isDir && shouldHideRegularFiles)
- {
- continue;
- }
- if(!rsc.isDir && !IsExtensionMatched(rsc.extension))
- {
- continue;
- }
- if(!rsc.name.empty() && rsc.name.c_str()[0] == '$')
- {
- continue;
- }
- const bool selected = selectedFilenames_.find(rsc.name)
- != selectedFilenames_.end();
- if(Selectable(rsc.showName.c_str(), selected,
- ImGuiSelectableFlags_DontClosePopups))
- {
- const bool wantDir = flags_ & ImGuiFileBrowserFlags_SelectDirectory;
- const bool canSelect = rsc.name != ".." && rsc.isDir == wantDir;
- const bool rangeSelect =
- canSelect && GetIO().KeyShift &&
- rangeSelectionStart_ < fileRecords_.size() &&
- (flags_ & ImGuiFileBrowserFlags_MultipleSelection) &&
- IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
- const bool multiSelect =
- !rangeSelect && GetIO().KeyCtrl &&
- (flags_ & ImGuiFileBrowserFlags_MultipleSelection) &&
- IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows);
- if(rangeSelect)
- {
- const unsigned int first = (std::min)(rangeSelectionStart_, rscIndex);
- const unsigned int last = (std::max)(rangeSelectionStart_, rscIndex);
- selectedFilenames_.clear();
- for(unsigned int i = first; i <= last; ++i)
- {
- if(fileRecords_[i].isDir != wantDir)
- {
- continue;
- }
- if(!wantDir && !IsExtensionMatched(fileRecords_[i].extension))
- {
- continue;
- }
- selectedFilenames_.insert(fileRecords_[i].name);
- }
- }
- else if(selected)
- {
- if(!multiSelect)
- {
- selectedFilenames_ = { rsc.name };
- rangeSelectionStart_ = rscIndex;
- }
- else
- {
- selectedFilenames_.erase(rsc.name);
- }
- (*inputNameBuf_)[0] = '\0';
- }
- else if(canSelect)
- {
- if(multiSelect)
- {
- selectedFilenames_.insert(rsc.name);
- }
- else
- {
- selectedFilenames_ = { rsc.name };
- }
- if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
- {
- #ifdef _MSC_VER
- strcpy_s(
- inputNameBuf_->data(), inputNameBuf_->size(),
- u8StrToStr(rsc.name.u8string()).c_str());
- #else
- std::strncpy(inputNameBuf_->data(),
- u8StrToStr(rsc.name.u8string()).c_str(),
- inputNameBuf_->size() - 1);
- #endif
- }
- rangeSelectionStart_ = rscIndex;
- }
- else
- {
- if(!multiSelect)
- {
- selectedFilenames_.clear();
- }
- }
- }
- if(IsItemClicked(0) && IsMouseDoubleClicked(0))
- {
- if(rsc.isDir)
- {
- setNewPwd = true;
- newPwd = (rsc.name != "..") ? (pwd_ / rsc.name) :
- pwd_.parent_path();
- }
- else if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
- {
- selectedFilenames_ = { rsc.name };
- ok_ = true;
- CloseCurrentPopup();
- }
- }
- }
- }
- if(setNewPwd)
- {
- SetPwd(newPwd);
- }
- if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory) &&
- (flags_ & ImGuiFileBrowserFlags_EnterNewFilename))
- {
- PushID(this);
- ScopeGuard popTextID([] { PopID(); });
- PushItemWidth(-1);
- if(InputText("", inputNameBuf_->data(), inputNameBuf_->size()) &&
- inputNameBuf_->at(0) != '\0')
- {
- selectedFilenames_ = { inputNameBuf_->data() };
- }
- focusOnInputText |= IsItemFocused();
- PopItemWidth();
- }
- if(!focusOnInputText)
- {
- const bool selectAll = (flags_ & ImGuiFileBrowserFlags_MultipleSelection) &&
- IsKeyPressed(ImGuiKey_A) && (IsKeyDown(ImGuiKey_LeftCtrl) ||
- IsKeyDown(ImGuiKey_RightCtrl));
- if(selectAll)
- {
- const bool needDir = flags_ & ImGuiFileBrowserFlags_SelectDirectory;
- selectedFilenames_.clear();
- for(size_t i = 1; i < fileRecords_.size(); ++i)
- {
- auto &record = fileRecords_[i];
- if(record.isDir == needDir &&
- (needDir || IsExtensionMatched(record.extension)))
- {
- selectedFilenames_.insert(record.name);
- }
- }
- }
- }
- const bool enter =
- (flags_ & ImGuiFileBrowserFlags_ConfirmOnEnter) &&
- IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
- IsKeyPressed(ImGuiKey_Enter);
- if(!(flags_ & ImGuiFileBrowserFlags_SelectDirectory))
- {
- if((Button(" ok ") || enter) && !selectedFilenames_.empty())
- {
- ok_ = true;
- CloseCurrentPopup();
- }
- }
- else
- {
- if(Button(" ok ") || enter)
- {
- ok_ = true;
- CloseCurrentPopup();
- }
- }
- SameLine();
- bool shouldExit =
- Button("cancel") || closeFlag_ ||
- ((flags_ & ImGuiFileBrowserFlags_CloseOnEsc) &&
- IsWindowFocused(ImGuiFocusedFlags_RootAndChildWindows) &&
- IsKeyPressed(ImGuiKey_Escape));
- if(shouldExit)
- {
- CloseCurrentPopup();
- }
- if(!statusStr_.empty() && !(flags_ & ImGuiFileBrowserFlags_NoStatusBar))
- {
- SameLine();
- Text("%s", statusStr_.c_str());
- }
- if(!typeFilters_.empty())
- {
- SameLine();
- PushItemWidth(8 * GetFontSize());
- if(BeginCombo(
- "##type_filters", typeFilters_[typeFilterIndex_].c_str()))
- {
- ScopeGuard guard([&] { EndCombo(); });
- for(size_t i = 0; i < typeFilters_.size(); ++i)
- {
- bool selected = i == typeFilterIndex_;
- if(Selectable(typeFilters_[i].c_str(), selected) && !selected)
- {
- typeFilterIndex_ = static_cast<unsigned int>(i);
- }
- }
- }
- PopItemWidth();
- }
- }
- inline bool ImGui::FileBrowser::HasSelected() const noexcept
- {
- return ok_;
- }
- inline bool ImGui::FileBrowser::SetPwd(const std::filesystem::path &pwd)
- {
- try
- {
- SetPwdUncatched(pwd);
- return true;
- }
- catch(const std::exception &err)
- {
- statusStr_ = std::string("last error: ") + err.what();
- }
- catch(...)
- {
- statusStr_ = "last error: unknown";
- }
- SetPwdUncatched(std::filesystem::current_path());
- return false;
- }
- inline const class std::filesystem::path &ImGui::FileBrowser::GetPwd() const noexcept
- {
- return pwd_;
- }
- inline std::filesystem::path ImGui::FileBrowser::GetSelected() const
- {
- // when ok_ is true, selectedFilenames_ may be empty if SelectDirectory
- // is enabled. return pwd in that case.
- if(selectedFilenames_.empty())
- {
- return pwd_;
- }
- return pwd_ / *selectedFilenames_.begin();
- }
- inline std::vector<std::filesystem::path>
- ImGui::FileBrowser::GetMultiSelected() const
- {
- if(selectedFilenames_.empty())
- {
- return { pwd_ };
- }
- std::vector<std::filesystem::path> ret;
- ret.reserve(selectedFilenames_.size());
- for(auto &s : selectedFilenames_)
- {
- ret.push_back(pwd_ / s);
- }
- return ret;
- }
- inline void ImGui::FileBrowser::ClearSelected()
- {
- selectedFilenames_.clear();
- (*inputNameBuf_)[0] = '\0';
- ok_ = false;
- }
- inline void ImGui::FileBrowser::SetTypeFilters(
- const std::vector<std::string> &_typeFilters)
- {
- typeFilters_.clear();
- // remove duplicate filter names due to case unsensitivity on windows
- #ifdef _WIN32
- std::vector<std::string> typeFilters;
- for(auto &rawFilter : _typeFilters)
- {
- std::string lowerFilter = ToLower(rawFilter);
- auto it = std::find(typeFilters.begin(), typeFilters.end(), lowerFilter);
- if(it == typeFilters.end())
- {
- typeFilters.push_back(std::move(lowerFilter));
- }
- }
- #else
- auto &typeFilters = _typeFilters;
- #endif
- // insert auto-generated filter
- hasAllFilter_ = false;
- if(typeFilters.size() > 1)
- {
- hasAllFilter_ = true;
- std::string allFiltersName = std::string();
- for(size_t i = 0; i < typeFilters.size(); ++i)
- {
- if(typeFilters[i] == std::string_view(".*"))
- {
- hasAllFilter_ = false;
- break;
- }
- if(i > 0)
- {
- allFiltersName += ",";
- }
- allFiltersName += typeFilters[i];
- }
- if(hasAllFilter_)
- {
- typeFilters_.push_back(std::move(allFiltersName));
- }
- }
- std::copy(
- typeFilters.begin(), typeFilters.end(),
- std::back_inserter(typeFilters_));
- typeFilterIndex_ = 0;
- }
- inline void ImGui::FileBrowser::SetCurrentTypeFilterIndex(int index)
- {
- typeFilterIndex_ = static_cast<unsigned int>(index);
- }
- inline void ImGui::FileBrowser::SetInputName(std::string_view input)
- {
- if(flags_ & ImGuiFileBrowserFlags_EnterNewFilename)
- {
- if(input.size() >= static_cast<size_t>(INPUT_NAME_BUF_SIZE))
- {
- // If input doesn't fit trim off characters
- input = input.substr(0, INPUT_NAME_BUF_SIZE - 1);
- }
- std::copy(input.begin(), input.end(), inputNameBuf_->begin());
- inputNameBuf_->at(input.size()) = '\0';
- selectedFilenames_ = { inputNameBuf_->data() };
- }
- }
- inline std::string ImGui::FileBrowser::ToLower(const std::string &s)
- {
- std::string ret = s;
- for(char &c : ret)
- {
- c = static_cast<char>(std::tolower(c));
- }
- return ret;
- }
- inline void ImGui::FileBrowser::UpdateFileRecords()
- {
- fileRecords_ = { FileRecord{ true, "..", "[D] ..", "" } };
- for(auto &p : std::filesystem::directory_iterator(pwd_))
- {
- FileRecord rcd;
- if(p.is_regular_file())
- {
- rcd.isDir = false;
- }
- else if(p.is_directory())
- {
- rcd.isDir = true;
- }
- else
- {
- continue;
- }
- rcd.name = p.path().filename();
- if(rcd.name.empty())
- {
- continue;
- }
- rcd.extension = p.path().filename().extension();
- rcd.showName = (rcd.isDir ? "[D] " : "[F] ") +
- u8StrToStr(p.path().filename().u8string());
- fileRecords_.push_back(rcd);
- }
- std::sort(fileRecords_.begin(), fileRecords_.end(),
- [](const FileRecord &L, const FileRecord &R)
- {
- return (L.isDir ^ R.isDir) ? L.isDir : (L.name < R.name);
- });
- ClearRangeSelectionState();
- }
- inline void ImGui::FileBrowser::SetPwdUncatched(const std::filesystem::path &pwd)
- {
- pwd_ = absolute(pwd);
- UpdateFileRecords();
- selectedFilenames_.clear();
- (*inputNameBuf_)[0] = '\0';
- }
- inline bool ImGui::FileBrowser::IsExtensionMatched(
- const std::filesystem::path &_extension) const
- {
- #ifdef _WIN32
- std::filesystem::path extension = ToLower(u8StrToStr(_extension.u8string()));
- #else
- auto &extension = _extension;
- #endif
- // no type filters
- if(typeFilters_.empty())
- {
- return true;
- }
- // invalid type filter index
- if(static_cast<size_t>(typeFilterIndex_) >= typeFilters_.size())
- {
- return true;
- }
- // all type filters
- if(hasAllFilter_ && typeFilterIndex_ == 0)
- {
- for(size_t i = 1; i < typeFilters_.size(); ++i)
- {
- if(extension == typeFilters_[i])
- {
- return true;
- }
- }
- return false;
- }
- // universal filter
- if(typeFilters_[typeFilterIndex_] == std::string_view(".*"))
- {
- return true;
- }
- // regular filter
- return extension == typeFilters_[typeFilterIndex_];
- }
- inline void ImGui::FileBrowser::ClearRangeSelectionState()
- {
- rangeSelectionStart_ = 9999999;
- const bool dir = flags_ & ImGuiFileBrowserFlags_SelectDirectory;
- for(unsigned int i = 1; i < fileRecords_.size(); ++i)
- {
- if(fileRecords_[i].isDir == dir)
- {
- if(!dir && !IsExtensionMatched(fileRecords_[i].extension))
- {
- continue;
- }
- rangeSelectionStart_ = i;
- break;
- }
- }
- }
- #if defined(__cpp_lib_char8_t)
- inline std::string ImGui::FileBrowser::u8StrToStr(std::u8string s)
- {
- return std::string(s.begin(), s.end());
- }
- #endif
- inline std::string ImGui::FileBrowser::u8StrToStr(std::string s)
- {
- return s;
- }
- #ifdef _WIN32
- #ifndef _INC_WINDOWS
- #ifndef WIN32_LEAN_AND_MEAN
- #define IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
- #define WIN32_LEAN_AND_MEAN
- #endif // #ifndef WIN32_LEAN_AND_MEAN
- #include <windows.h>
- #ifdef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
- #undef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
- #undef WIN32_LEAN_AND_MEAN
- #endif // #ifdef IMGUI_FILEBROWSER_UNDEF_WIN32_LEAN_AND_MEAN
- #endif // #ifdef _INC_WINDOWS
- inline std::uint32_t ImGui::FileBrowser::GetDrivesBitMask()
- {
- DWORD mask = GetLogicalDrives();
- uint32_t ret = 0;
- for(int i = 0; i < 26; ++i)
- {
- if(!(mask & (1 << i)))
- {
- continue;
- }
- char rootName[4] = { static_cast<char>('A' + i), ':', '\\', '\0' };
- UINT type = GetDriveTypeA(rootName);
- if(type == DRIVE_REMOVABLE || type == DRIVE_FIXED || type == DRIVE_REMOTE)
- {
- ret |= (1 << i);
- }
- }
- return ret;
- }
- #endif
|