From 3f19be9b8d49135302200f2f55aa231e61b1d7d4 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sat, 27 Sep 2025 16:33:43 -0500 Subject: [PATCH] improve file name typing behavior --- src/gui/gui.cpp | 17 ++++++ src/gui/newFilePicker.cpp | 118 ++++++++++++++++++++++++++++++-------- src/gui/newFilePicker.h | 4 +- 3 files changed, 113 insertions(+), 26 deletions(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index dd01ac0c8..ba41d5f91 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -5115,6 +5115,23 @@ bool FurnaceGUI::loop() { #endif #endif + switch (newFilePicker->getStatus()) { + case FP_STATUS_ACCEPTED: { + String combined="The file picker says: "; + for (const String& i: newFilePicker->getSelected()) { + combined+="\n- "; + combined+=i; + } + showError(combined); + break; + } + case FP_STATUS_CLOSED: + showError("The file picker was closed."); + break; + default: + break; + } + if (fileDialog->render(mobileUI?ImVec2(canvasW-(portrait?0:(60.0*dpiScale)),canvasH-60.0*dpiScale):ImVec2(600.0f*dpiScale,400.0f*dpiScale),ImVec2(canvasW-((mobileUI && !portrait)?(60.0*dpiScale):0),canvasH-(mobileUI?(60.0*dpiScale):0)))) { bool openOpen=false; //ImGui::GetIO().ConfigFlags&=~ImGuiConfigFlags_NavEnableKeyboard; diff --git a/src/gui/newFilePicker.cpp b/src/gui/newFilePicker.cpp index 79364ee6a..3d8ee9f08 100644 --- a/src/gui/newFilePicker.cpp +++ b/src/gui/newFilePicker.cpp @@ -196,10 +196,8 @@ void FurnaceFilePicker::readDirectorySub() { readLinkPath=path+'/'+newEntry->name; } // silly, but works. - logV("Read a symlink..."); readLinkDir=opendir(readLinkPath.c_str()); if (readLinkDir!=NULL) { - logV("Is file"); newEntry->isDir=true; closedir(readLinkDir); } @@ -524,6 +522,32 @@ void FurnaceFilePicker::filterFiles() { } } +bool FurnaceFilePicker::isPathAbsolute(const String& p) { +#ifdef _WIN32 + // TODO: test for UNC path? + + // convert to absolute path if necessary + bool willConvert=(p.size()<3); + if (!willConvert) { + // test for drive letter + if (!(((p[0]>='A' && p[0]<='Z') || (p[0]>='a' && p[0]<='z')) && p[1]==':' && p[2]=='\\')) { + if (p.size()<4) { + willConvert=true; + } else { + if (!(((p[0]>='A' && p[0]<='Z') || (p[0]>='a' && p[0]<='z')) && ((p[1]>='A' && p[1]<='Z') || (p[1]>='a' && p[1]<='z')) && p[2]==':' && p[3]=='\\')) { + willConvert=true; + } + } + } + } + + return !willConvert; +#else + if (p.size()<1) return false; + return (p[0]=='/'); +#endif +} + bool FurnaceFilePicker::draw() { if (!isOpen) return false; @@ -550,22 +574,7 @@ bool FurnaceFilePicker::draw() { mkdirError="Maybe try that again under better circumstances..."; } else { #ifdef _WIN32 - // convert to absolute path if necessary - bool willConvert=(mkdirPath.size()<3); - if (!willConvert) { - // test for drive letter - if (!(((mkdirPath[0]>='A' && mkdirPath[0]<='Z') || (mkdirPath[0]>='a' && mkdirPath[0]<='z')) && mkdirPath[1]==':' && mkdirPath[2]=='\\')) { - if (mkdirPath.size()<4) { - willConvert=true; - } else { - if (!(((mkdirPath[0]>='A' && mkdirPath[0]<='Z') || (mkdirPath[0]>='a' && mkdirPath[0]<='z')) && ((mkdirPath[1]>='A' && mkdirPath[1]<='Z') || (mkdirPath[1]>='a' && mkdirPath[1]<='z')) && mkdirPath[2]==':' && mkdirPath[3]=='\\')) { - willConvert=true; - } - } - } - } - - if (willConvert) { + if (!isPathAbsolute(mkdirPath)) { if (path.empty()) { // error out in the drives view mkdirError="Trying to create a directory in the drives list"; @@ -595,7 +604,7 @@ bool FurnaceFilePicker::draw() { } #else // convert to absolute path if necessary - if (mkdirPath[0]!='/') { + if (!isPathAbsolute(mkdirPath)) { if (!path.empty()) { if (*path.rbegin()=='/') { mkdirPath=path+mkdirPath; @@ -947,7 +956,10 @@ bool FurnaceFilePicker::draw() { ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x*0.68f); if (ImGui::InputText("##EntryName",&entryName)) { - // find an entry with this name + for (FileEntry* j: chosenEntries) { + j->isSelected=false; + } + chosenEntries.clear(); } ImGui::SameLine(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); @@ -962,7 +974,7 @@ bool FurnaceFilePicker::draw() { } // OK/Cancel buttons - ImGui::BeginDisabled(chosenEntries.empty()); + ImGui::BeginDisabled(entryName.empty() && chosenEntries.empty()); if (ImGui::Button("OK")) { // accept entry acknowledged=true; @@ -995,9 +1007,61 @@ bool FurnaceFilePicker::draw() { } } else { // select this entry + finalSelection.clear(); + for (FileEntry* i: chosenEntries) { + if (path.empty()) { + finalSelection.push_back(i->name); + } else if (*path.rbegin()==DIR_SEPARATOR) { + finalSelection.push_back(path+i->name); + } else { + finalSelection.push_back(path+DIR_SEPARATOR_STR+i->name); + } + } + curStatus=FP_STATUS_ACCEPTED; isOpen=false; } + } else { + // return the user-provided entry + finalSelection.clear(); + if (!entryName.empty()) { + String dirCheckPath; + if (isPathAbsolute(entryName)) { + dirCheckPath=entryName; + } else { + if (path.empty()) { + dirCheckPath=entryName; + } else if (*path.rbegin()==DIR_SEPARATOR) { + dirCheckPath=path+entryName; + } else { + dirCheckPath=path+DIR_SEPARATOR_STR+entryName; + } + } + + // check whether this is a directory + bool isDir=false; +#ifdef _WIN32 + WString dirCheckPathW=utf8To16(dirCheckPath); + isDir=PathIsDirectoryW(dirCheckPathW.c_str()); +#else + // again, silly but works. + DIR* checkDir=opendir(dirCheckPath.c_str()); + if (checkDir!=NULL) { + isDir=true; + closedir(checkDir); + } +#endif + + if (isDir) { + // go to directory + newDir=dirCheckPath; + } else { + // return now + finalSelection.push_back(dirCheckPath); + curStatus=FP_STATUS_ACCEPTED; + isOpen=false; + } + } } } } @@ -1031,10 +1095,6 @@ bool FurnaceFilePicker::open(String name, String pa, bool modal, const std::vect return true; } -const String& FurnaceFilePicker::getEntryName() { - return entryName; -} - void FurnaceFilePicker::setMobile(bool val) { isMobile=val; } @@ -1053,6 +1113,14 @@ void FurnaceFilePicker::saveSettings(DivConfig& conf) { } +const String& FurnaceFilePicker::getEntryName() { + return entryName; +} + +const std::vector& FurnaceFilePicker::getSelected() { + return finalSelection; +} + void FurnaceFilePicker::setTypeStyle(FileType type, ImVec4 color, String icon) { // "##File" is appended here for performance. defaultTypeStyle[type].icon=icon+"##File"; diff --git a/src/gui/newFilePicker.h b/src/gui/newFilePicker.h index ac6940197..8aa44c1c7 100644 --- a/src/gui/newFilePicker.h +++ b/src/gui/newFilePicker.h @@ -73,6 +73,7 @@ class FurnaceFilePicker { std::vector sortedEntries; std::vector filteredEntries; std::vector chosenEntries; + std::vector finalSelection; std::vector filterOptions; std::thread* fileThread; std::mutex entryLock; @@ -104,13 +105,14 @@ class FurnaceFilePicker { void updateEntryName(); void readDirectory(String path); String normalizePath(const String& which); + bool isPathAbsolute(const String& p); public: void readDirectorySub(); void setHomeDir(String where); FilePickerStatus getStatus(); const String& getEntryName(); - const std::vector& getSelected(); + const std::vector& getSelected(); void setMobile(bool val); bool draw(); bool open(String name, String path, bool modal, const std::vector& filter);