From 0f7e1a50c9c5e6034287144787f8514d364c281d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Sun, 28 Sep 2025 18:26:10 -0500 Subject: [PATCH] does this work? also add a crude diagnosis tool for #1825 --- src/fileutils.cpp | 21 ++ src/fileutils.h | 1 + src/gui/newFilePicker.cpp | 527 +++++++++++++++++++------------------- src/gui/newFilePicker.h | 2 + src/gui/tutorial.cpp | 37 +++ 5 files changed, 330 insertions(+), 258 deletions(-) diff --git a/src/fileutils.cpp b/src/fileutils.cpp index 975eaad31..75c02016b 100644 --- a/src/fileutils.cpp +++ b/src/fileutils.cpp @@ -50,6 +50,27 @@ bool moveFiles(const char* src, const char* dest) { #endif } +bool copyFiles(const char* src, const char* dest) { + FILE* f=ps_fopen(src,"rb"); + if (f==NULL) return false; + + FILE* of=ps_fopen(dest,"wb"); + if (of==NULL) { + fclose(f); + return false; + } + + char block[2048]; + while (!feof(f)) { + size_t readTotal=fread(block,1,2048,f); + if (readTotal) fwrite(block,1,readTotal,of); + } + + fclose(of); + fclose(f); + return true; +} + bool deleteFile(const char* path) { #ifdef _WIN32 return DeleteFileW(utf8To16(path).c_str()); diff --git a/src/fileutils.h b/src/fileutils.h index c3bef8697..8f7a2a433 100644 --- a/src/fileutils.h +++ b/src/fileutils.h @@ -23,6 +23,7 @@ FILE* ps_fopen(const char* path, const char* mode); bool moveFiles(const char* src, const char* dest); +bool copyFiles(const char* src, const char* dest); bool deleteFile(const char* path); // returns 1 if file exists, 0 if it doesn't and -1 on error. int fileExists(const char* path); diff --git a/src/gui/newFilePicker.cpp b/src/gui/newFilePicker.cpp index e9e8111c8..e2899d1ab 100644 --- a/src/gui/newFilePicker.cpp +++ b/src/gui/newFilePicker.cpp @@ -592,6 +592,263 @@ void FurnaceFilePicker::setSizeConstraints(const ImVec2& min, const ImVec2& max) hasSizeConstraints=true; } +void FurnaceFilePicker::drawFileList(ImVec2& tableSize, bool& acknowledged) { + // display a message on empty dir, no matches or error + if (!haveFiles) { + if (ImGui::BeginTable("LoadingFiles",1,ImGuiTableFlags_BordersOuter,tableSize)) { + ImGui::EndTable(); + } + } else if (filteredEntries.empty()) { + if (ImGui::BeginTable("NoFiles",3,ImGuiTableFlags_BordersOuter,tableSize)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.5f); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + + ImGui::TableNextColumn(); + ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(tableSize.y-ImGui::GetTextLineHeight())*0.5); + if (sortedEntries.empty()) { + if (failMessage.empty()) { + ImGui::Text("This directory is empty!"); + } else { +#ifdef _WIN32 + ImGui::Text("%s",failMessage.c_str()); +#else + ImGui::Text("%s!",failMessage.c_str()); +#endif + } + } else { + if (failMessage.empty()) { + ImGui::Text("No results"); + } else { +#ifdef _WIN32 + ImGui::Text("%s",failMessage.c_str()); +#else + ImGui::Text("%s!",failMessage.c_str()); +#endif + } + } + + ImGui::TableNextColumn(); + ImGui::EndTable(); + } + } else { + // this is the list view. I might add other view modes in the future... + int columns=1; + if (displayType) columns++; + if (displaySize) columns++; + if (displayDate) columns++; + if (ImGui::BeginTable("FileList",columns,ImGuiTableFlags_BordersOuter|ImGuiTableFlags_ScrollY|ImGuiTableFlags_RowBg,tableSize)) { + float rowHeight=ImGui::GetTextLineHeight()+ImGui::GetStyle().CellPadding.y*2.0f; + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); + if (displayType) ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize(" .eeee").x); + if (displaySize) ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize(" 999.99G").x); + if (displayDate) ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize(" 6969/69/69 04:20").x); + ImGui::TableSetupScrollFreeze(0,1); + + // header (sort options) + const char* nameHeader="Name##SortName"; + const char* typeHeader="Type##SortType"; + const char* sizeHeader="Size##SortSize"; + const char* dateHeader="Date##SortDate"; + + switch (sortMode) { + case FP_SORT_NAME: + if (sortInvert[FP_SORT_NAME]) { + nameHeader=ICON_FA_CHEVRON_UP "Name##SortName"; + } else { + nameHeader=ICON_FA_CHEVRON_DOWN "Name##SortName"; + } + break; + case FP_SORT_EXT: + if (sortInvert[FP_SORT_EXT]) { + typeHeader=ICON_FA_CHEVRON_UP "Type##SortType"; + } else { + typeHeader=ICON_FA_CHEVRON_DOWN "Type##SortType"; + } + break; + case FP_SORT_SIZE: + if (sortInvert[FP_SORT_SIZE]) { + sizeHeader=ICON_FA_CHEVRON_UP "Size##SortSize"; + } else { + sizeHeader=ICON_FA_CHEVRON_DOWN "Size##SortSize"; + } + break; + case FP_SORT_DATE: + if (sortInvert[FP_SORT_DATE]) { + dateHeader=ICON_FA_CHEVRON_UP "Date##SortDate"; + } else { + dateHeader=ICON_FA_CHEVRON_DOWN "Date##SortDate"; + } + break; + case FP_SORT_MAX: + // impossible + break; + } + + ImGui::TableNextRow(ImGuiTableRowFlags_Headers,rowHeight); + ImGui::TableNextColumn(); + if (ImGui::Selectable(nameHeader)) { + if (sortMode==FP_SORT_NAME) { + sortInvert[sortMode]=!sortInvert[sortMode]; + } else { + sortMode=FP_SORT_NAME; + scheduledSort=1; + } + } + if (displayType) { + ImGui::TableNextColumn(); + if (ImGui::Selectable(typeHeader)) { + if (sortMode==FP_SORT_EXT) { + sortInvert[sortMode]=!sortInvert[sortMode]; + } else { + sortMode=FP_SORT_EXT; + scheduledSort=1; + } + } + } + if (displaySize) { + ImGui::TableNextColumn(); + if (ImGui::Selectable(sizeHeader)) { + if (sortMode==FP_SORT_SIZE) { + sortInvert[sortMode]=!sortInvert[sortMode]; + } else { + sortMode=FP_SORT_SIZE; + scheduledSort=1; + } + } + } + if (displayDate) { + ImGui::TableNextColumn(); + if (ImGui::Selectable(dateHeader)) { + if (sortMode==FP_SORT_DATE) { + sortInvert[sortMode]=!sortInvert[sortMode]; + } else { + sortMode=FP_SORT_DATE; + scheduledSort=1; + } + } + } + + // file list + entryLock.lock(); + int index=0; + listClipper.Begin(filteredEntries.size(),rowHeight); + while (listClipper.Step()) { + for (int _i=listClipper.DisplayStart; _itype]; + + // get style for this entry + if (i->isDir) { + style=&defaultTypeStyle[FP_TYPE_DIR]; + } else { + if (!i->ext.empty()) { + for (FileTypeStyle& j: fileTypeRegistry) { + if (i->ext==j.ext) { + style=&j; + break; + } + } + } + } + + // draw + ImGui::TableNextRow(0,rowHeight); + // name + ImGui::TableNextColumn(); + ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(style->color)); + ImGui::PushID(index++); + if (ImGui::Selectable(style->icon.c_str(),i->isSelected,ImGuiSelectableFlags_AllowDoubleClick|ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_SpanAvailWidth)) { + bool doNotAcknowledge=false; + if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && multiSelect) { + // multiple selection + doNotAcknowledge=true; + } else { + // clear selected entries + for (FileEntry* j: chosenEntries) { + j->isSelected=false; + } + chosenEntries.clear(); + } + + bool alreadySelected=false; + for (FileEntry* j: chosenEntries) { + if (j==i) alreadySelected=true; + } + + if (!alreadySelected) { + // select this entry + chosenEntries.push_back(i); + i->isSelected=true; + updateEntryName(); + if (!doNotAcknowledge) { + if (isMobile || singleClickSelect) { + acknowledged=true; + } else if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { + acknowledged=true; + } + } + } + } + ImGui::PopID(); + ImGui::SameLine(); + + ImGui::TextUnformatted(i->name.c_str()); + + // type + if (displayType) { + ImGui::TableNextColumn(); + ImGui::TextUnformatted(i->ext.c_str()); + } + + // size + if (displaySize) { + ImGui::TableNextColumn(); + if (i->hasSize && (i->type==FP_TYPE_NORMAL || path.empty())) { + int sizeShift=0; + uint64_t sizeShifted=i->size; + + while (sizeShifted && sizeShift<7) { + sizeShifted>>=10; + sizeShift++; + } + + sizeShift--; + + uint64_t intPart=i->size>>(sizeShift*10); + uint64_t fracPart=i->size&((1U<<(sizeShift*10))-1); + // shift so we have sufficient digits for 100 + // (precision loss is negligible) + if (sizeShift>0) { + fracPart=(100*(fracPart>>3))>>((sizeShift*10)-3); + if (fracPart>99) fracPart=99; + ImGui::Text("%" PRIu64 ".%02" PRIu64 "%c",intPart,fracPart,sizeSuffixes[sizeShift&7]); + } else { + ImGui::Text("%" PRIu64,i->size); + } + } + } + + // date + if (displayDate) { + ImGui::TableNextColumn(); + if (i->hasTime) { + ImGui::Text("%d/%02d/%02d %02d:%02d",i->time.tm_year+1900,i->time.tm_mon+1,i->time.tm_mday,i->time.tm_hour,i->time.tm_min); + } + } + + ImGui::PopStyleColor(); + } + } + ImGui::EndTable(); + entryLock.unlock(); + } + } +} + bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) { if (!isOpen) { hasSizeConstraints=false; @@ -849,270 +1106,24 @@ bool FurnaceFilePicker::draw(ImGuiWindowFlags winFlags) { // bookmarks view, if open if (showBookmarks) { - ImVec2 bookmarksSize=tableSize; - bookmarksSize.x*=0.2f; - if (ImGui::BeginChild("Bookmarks",bookmarksSize)) { - ImGui::Text("Here we go..."); - } - ImGui::EndChild(); - ImGui::SameLine(); - - tableSize.x=ImGui::GetContentRegionAvail().x; - } - - // display a message on empty dir, no matches or error - if (!haveFiles) { - if (ImGui::BeginTable("LoadingFiles",1,ImGuiTableFlags_BordersOuter,tableSize)) { - ImGui::EndTable(); - } - } else if (filteredEntries.empty()) { - if (ImGui::BeginTable("NoFiles",3,ImGuiTableFlags_BordersOuter,tableSize)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.5f); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.5f); - + ImVec2 oldCellPadding=ImGui::GetStyle().CellPadding; + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,ImVec2(oldCellPadding.x,0)); + if (ImGui::BeginTable("BMPanel",2,ImGuiTableFlags_BordersInnerV|ImGuiTableFlags_Resizable)) { ImGui::TableNextRow(); ImGui::TableNextColumn(); - - ImGui::TableNextColumn(); - ImGui::SetCursorPosY(ImGui::GetCursorPosY()+(tableSize.y-ImGui::GetTextLineHeight())*0.5); - if (sortedEntries.empty()) { - if (failMessage.empty()) { - ImGui::Text("This directory is empty!"); - } else { -#ifdef _WIN32 - ImGui::Text("%s",failMessage.c_str()); -#else - ImGui::Text("%s!",failMessage.c_str()); -#endif - } - } else { - if (failMessage.empty()) { - ImGui::Text("No results"); - } else { -#ifdef _WIN32 - ImGui::Text("%s",failMessage.c_str()); -#else - ImGui::Text("%s!",failMessage.c_str()); -#endif - } - } - + ImGui::Text("Here we go..."); ImGui::TableNextColumn(); + tableSize.x=ImGui::GetContentRegionAvail().x; + ImGui::PushStyleVar(ImGuiStyleVar_CellPadding,oldCellPadding); + drawFileList(tableSize,acknowledged); + ImGui::PopStyleVar(); ImGui::EndTable(); } + ImGui::PopStyleVar(); + } else { - // this is the list view. I might add other view modes in the future... - int columns=1; - if (displayType) columns++; - if (displaySize) columns++; - if (displayDate) columns++; - if (ImGui::BeginTable("FileList",columns,ImGuiTableFlags_BordersOuter|ImGuiTableFlags_ScrollY|ImGuiTableFlags_RowBg,tableSize)) { - float rowHeight=ImGui::GetTextLineHeight()+ImGui::GetStyle().CellPadding.y*2.0f; - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch); - if (displayType) ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize(" .eeee").x); - if (displaySize) ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize(" 999.99G").x); - if (displayDate) ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,ImGui::CalcTextSize(" 6969/69/69 04:20").x); - ImGui::TableSetupScrollFreeze(0,1); - - // header (sort options) - const char* nameHeader="Name##SortName"; - const char* typeHeader="Type##SortType"; - const char* sizeHeader="Size##SortSize"; - const char* dateHeader="Date##SortDate"; - - switch (sortMode) { - case FP_SORT_NAME: - if (sortInvert[FP_SORT_NAME]) { - nameHeader=ICON_FA_CHEVRON_UP "Name##SortName"; - } else { - nameHeader=ICON_FA_CHEVRON_DOWN "Name##SortName"; - } - break; - case FP_SORT_EXT: - if (sortInvert[FP_SORT_EXT]) { - typeHeader=ICON_FA_CHEVRON_UP "Type##SortType"; - } else { - typeHeader=ICON_FA_CHEVRON_DOWN "Type##SortType"; - } - break; - case FP_SORT_SIZE: - if (sortInvert[FP_SORT_SIZE]) { - sizeHeader=ICON_FA_CHEVRON_UP "Size##SortSize"; - } else { - sizeHeader=ICON_FA_CHEVRON_DOWN "Size##SortSize"; - } - break; - case FP_SORT_DATE: - if (sortInvert[FP_SORT_DATE]) { - dateHeader=ICON_FA_CHEVRON_UP "Date##SortDate"; - } else { - dateHeader=ICON_FA_CHEVRON_DOWN "Date##SortDate"; - } - break; - case FP_SORT_MAX: - // impossible - break; - } - - ImGui::TableNextRow(ImGuiTableRowFlags_Headers,rowHeight); - ImGui::TableNextColumn(); - if (ImGui::Selectable(nameHeader)) { - if (sortMode==FP_SORT_NAME) { - sortInvert[sortMode]=!sortInvert[sortMode]; - } else { - sortMode=FP_SORT_NAME; - scheduledSort=1; - } - } - if (displayType) { - ImGui::TableNextColumn(); - if (ImGui::Selectable(typeHeader)) { - if (sortMode==FP_SORT_EXT) { - sortInvert[sortMode]=!sortInvert[sortMode]; - } else { - sortMode=FP_SORT_EXT; - scheduledSort=1; - } - } - } - if (displaySize) { - ImGui::TableNextColumn(); - if (ImGui::Selectable(sizeHeader)) { - if (sortMode==FP_SORT_SIZE) { - sortInvert[sortMode]=!sortInvert[sortMode]; - } else { - sortMode=FP_SORT_SIZE; - scheduledSort=1; - } - } - } - if (displayDate) { - ImGui::TableNextColumn(); - if (ImGui::Selectable(dateHeader)) { - if (sortMode==FP_SORT_DATE) { - sortInvert[sortMode]=!sortInvert[sortMode]; - } else { - sortMode=FP_SORT_DATE; - scheduledSort=1; - } - } - } - - // file list - entryLock.lock(); - int index=0; - listClipper.Begin(filteredEntries.size(),rowHeight); - while (listClipper.Step()) { - for (int _i=listClipper.DisplayStart; _itype]; - - // get style for this entry - if (i->isDir) { - style=&defaultTypeStyle[FP_TYPE_DIR]; - } else { - if (!i->ext.empty()) { - for (FileTypeStyle& j: fileTypeRegistry) { - if (i->ext==j.ext) { - style=&j; - break; - } - } - } - } - - // draw - ImGui::TableNextRow(0,rowHeight); - // name - ImGui::TableNextColumn(); - ImGui::PushStyleColor(ImGuiCol_Text,ImGui::GetColorU32(style->color)); - ImGui::PushID(index++); - if (ImGui::Selectable(style->icon.c_str(),i->isSelected,ImGuiSelectableFlags_AllowDoubleClick|ImGuiSelectableFlags_SpanAllColumns|ImGuiSelectableFlags_SpanAvailWidth)) { - bool doNotAcknowledge=false; - if ((ImGui::IsKeyDown(ImGuiKey_LeftShift) || ImGui::IsKeyDown(ImGuiKey_RightShift)) && multiSelect) { - // multiple selection - doNotAcknowledge=true; - } else { - // clear selected entries - for (FileEntry* j: chosenEntries) { - j->isSelected=false; - } - chosenEntries.clear(); - } - - bool alreadySelected=false; - for (FileEntry* j: chosenEntries) { - if (j==i) alreadySelected=true; - } - - if (!alreadySelected) { - // select this entry - chosenEntries.push_back(i); - i->isSelected=true; - updateEntryName(); - if (!doNotAcknowledge) { - if (isMobile || singleClickSelect) { - acknowledged=true; - } else if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) { - acknowledged=true; - } - } - } - } - ImGui::PopID(); - ImGui::SameLine(); - - ImGui::TextUnformatted(i->name.c_str()); - - // type - if (displayType) { - ImGui::TableNextColumn(); - ImGui::TextUnformatted(i->ext.c_str()); - } - - // size - if (displaySize) { - ImGui::TableNextColumn(); - if (i->hasSize && (i->type==FP_TYPE_NORMAL || path.empty())) { - int sizeShift=0; - uint64_t sizeShifted=i->size; - - while (sizeShifted && sizeShift<7) { - sizeShifted>>=10; - sizeShift++; - } - - sizeShift--; - - uint64_t intPart=i->size>>(sizeShift*10); - uint64_t fracPart=i->size&((1U<<(sizeShift*10))-1); - // shift so we have sufficient digits for 100 - // (precision loss is negligible) - if (sizeShift>0) { - fracPart=(100*(fracPart>>3))>>((sizeShift*10)-3); - if (fracPart>99) fracPart=99; - ImGui::Text("%" PRIu64 ".%02" PRIu64 "%c",intPart,fracPart,sizeSuffixes[sizeShift&7]); - } else { - ImGui::Text("%" PRIu64,i->size); - } - } - } - - // date - if (displayDate) { - ImGui::TableNextColumn(); - if (i->hasTime) { - ImGui::Text("%d/%02d/%02d %02d:%02d",i->time.tm_year+1900,i->time.tm_mon+1,i->time.tm_mday,i->time.tm_hour,i->time.tm_min); - } - } - - ImGui::PopStyleColor(); - } - } - ImGui::EndTable(); - entryLock.unlock(); - } + // file list + drawFileList(tableSize,acknowledged); } // file name input diff --git a/src/gui/newFilePicker.h b/src/gui/newFilePicker.h index be6ae3a0d..7e6d73c80 100644 --- a/src/gui/newFilePicker.h +++ b/src/gui/newFilePicker.h @@ -142,6 +142,8 @@ class FurnaceFilePicker { String normalizePath(const String& which); bool isPathAbsolute(const String& p); + void drawFileList(ImVec2& tableSize, bool& acknowledged); + public: void readDirectorySub(); void setHomeDir(String where); diff --git a/src/gui/tutorial.cpp b/src/gui/tutorial.cpp index e06c52f6d..2b6d0eb2c 100644 --- a/src/gui/tutorial.cpp +++ b/src/gui/tutorial.cpp @@ -48,6 +48,10 @@ tutorial.popupTimer=0; \ } #else +#ifndef _WIN32 +#include "../fileutils.h" +#include +#endif #define CLICK_TO_OPEN(t) ImGui::TextColored(uiColors[GUI_COLOR_ACCENT_PRIMARY],t); if (ImGui::IsItemClicked()) SDL_OpenURL(t); #endif @@ -880,6 +884,39 @@ void FurnaceGUI::drawTutorial() { ImGui::CloseCurrentPopup(); } +#ifdef IS_MOBILE + ImGui::SameLine(); + if (ImGui::Button(_("My config was reset!"))) { +#ifndef _WIN32 + String configPath1=e->getConfigPath(); + makeDir("/storage/emulated/0/failedConfig"); + DIR* dir=opendir(configPath1.c_str()); + if (dir==NULL) { + showError(fmt::sprintf("Current config path is %s\nERROR - ERROR - ERROR\n%s",configPath1,strerror(errno))); + } else { + struct dirent* de; + String inPath, outPath; + while ((de=readdir(dir))!=NULL) { + if (de->d_type==DT_REG) { + inPath=configPath1+"/"+de->d_name; + outPath=String("/storage/emulated/0/failedConfig/")+String(de->d_name); + + logV("copying %s",de->d_name); + if (!copyFiles(inPath.c_str(),outPath.c_str())) { + logV("ERROR!!! %s",strerror(errno)); + } + } + } + closedir(dir); + + showError(fmt::sprintf("Current config path is %s\nNow exporting last config to storage. Check it out for bug diagnosis.",configPath1)); + } + tutorial.protoWelcome=true; + ImGui::CloseCurrentPopup(); +#endif + } +#endif + ImGui::SetWindowPos(ImVec2( (canvasW-ImGui::GetWindowSize().x)*0.5, (canvasH-ImGui::GetWindowSize().y)*0.5