#include <3ds.h> #include #include #include #include #include #include #include #include #include #include #include #include "browse_entry.h" #include "vshader_v_shbin.h" #include "textengine.h" #include "utility.h" #include "viewer.h" #include "textviewer.h" #include "settingsviewer.h" enum FileMode { SELECT, DELETE, COPY, PASTE }mode; Viewer* currentViewer; int currentSelection = 0; int viewOffset = 0; std::vector entries; std::map selectedEntries; std::string currentPath = "/"; PrintConsole bottomScreen; u32 kDown; TextEngine* te; TextEngine* tb; void cleanViewer() { currentViewer->Cleanup(); delete currentViewer; currentViewer = NULL; } void initDirectory() { currentSelection = 0; viewOffset = 0; entries.clear(); DIR *dpdf; struct dirent *epdf; dpdf = opendir(currentPath.c_str()); if (dpdf != NULL){ while (epdf = readdir(dpdf)){ BrowseEntry *ent = new BrowseEntry; ent->name = std::string(epdf->d_name); if(epdf->d_type == DT_REG) { ent->isDirectory = false; } else { ent->isDirectory = true; } entries.push_back(ent); } } //Sort directories first (TODO: sort alphabetically) std::sort(entries.begin(), entries.end(), [] (BrowseEntry* const& a, BrowseEntry* const& b) { if(a->isDirectory && !b->isDirectory) { return true; } else { return false; } }); } void OpenDirectory(std::string path, bool isrel) { if(isrel) { currentPath += path + "/"; } initDirectory(); } //Sometimes going up a directory will permentantly make the directory contents blank, never happened on printf so it's probably a GPU-related issue void UpDirectory() { size_t found; currentPath = currentPath.substr(0, currentPath.length() - 1); found=currentPath.find_last_of("/\\"); currentPath = currentPath.substr(0, found + 1); initDirectory(); } void ViewFile(std::string filename) { //Re-implement extension checking when we can support something more than plain-text text files std::string ext = filename.substr(filename.find_last_of(".") + 1); currentViewer = new TextViewer(); currentViewer->path = currentPath + filename; currentViewer->Init(); } std::string GetModeString() { switch(mode) { case SELECT: return "SELECT"; break; case DELETE: return "DELETE"; break; case COPY: return "COPY"; break; case PASTE: return "PASTE"; break; } } void drawFileBrowser() { te->renderText(8.0f, 8.0f, 0.5f, 0.5f, false, std::string("Current Path:" + currentPath + " View Offset: " + SSTR(viewOffset) + " Cur: " + SSTR(currentSelection) + " Mode: " + GetModeString()).c_str()); for(int i = viewOffset; i < entries.size(); i++) { if(selectedEntries[(currentPath + entries[i]->name)]) { te->setTextColor(0x68B0D8FF); } else { te->setTextColor(0xFFFFFFFF); } if(i == currentSelection) { if(entries[i]->isDirectory) { te->renderText(8.0f, (16.0f * i) - (viewOffset * 16.0f) + 16.0f, 0.5f, 0.5f, false, std::string(">[" + Utility::truncate(entries[i]->name, 65, true) + "]").c_str()); } else { te->renderText(8.0f, (16.0f * i) - (viewOffset * 16.0f) + 16.0f, 0.5f, 0.5f, false, std::string(">" + Utility::truncate(entries[i]->name, 65, true)).c_str()); } } else { if(entries[i]->isDirectory) { te->renderText(8.0f, (16.0f * i) - (viewOffset * 16.0f) + 16.0f, 0.5f, 0.5f, false, std::string("[" + Utility::truncate(entries[i]->name, 65, true) + "]").c_str()); } else { te->renderText(8.0f, (16.0f * i) - (viewOffset * 16.0f) + 16.0f, 0.5f, 0.5f, false, std::string(Utility::truncate(entries[i]->name, 65, true)).c_str()); } } } if(entries.size() <= 0) { te->renderText(8.0f, 32.0f, 0.5f, 0.5f, false, "Directory is empty!"); } } void updateFilebrowser() { if(kDown & KEY_SELECT) { currentViewer = new SettingsViewer(); currentViewer->Init(); } //Find a better way to cycle through these if(kDown & KEY_L) { switch(mode) { case SELECT: mode = DELETE; break; case DELETE: mode = COPY; break; case COPY: mode = PASTE; break; case PASTE: mode = SELECT; break; } } //Mode action if(kDown & KEY_X) { switch(mode) { case SELECT: { selectedEntries[(currentPath + entries[currentSelection]->name)] = !selectedEntries[(currentPath + entries[currentSelection]->name)]; printf("Toggled selection for: %s\n", (currentPath + entries[currentSelection]->name).c_str()); } break; } } if(kDown & KEY_UP) { //Easy fix until i'm bothered to fix the issue if(currentSelection < 0 | viewOffset < 0) { currentSelection = 0; viewOffset = 0; } if(viewOffset != 0) { viewOffset -= 1; currentSelection -= 1; } if(currentSelection != 0) { currentSelection -= 1; } } if(kDown & KEY_DOWN) { //Failsafe to prevent crashing if(currentSelection > entries.size()) { currentSelection = 0; viewOffset = 0; } if(currentSelection == 13 + viewOffset) { viewOffset += 1; } if(currentSelection != entries.size() - 1) { currentSelection += 1; } } if(kDown & KEY_A) { if(!entries[currentSelection]->isDirectory) { ViewFile(entries[currentSelection]->name); } else { OpenDirectory(entries[currentSelection]->name, true); } } if(kDown & KEY_B) { if(currentPath != "./") UpDirectory(); } } void update() { if(currentViewer == NULL) { updateFilebrowser(); } else { if(!currentViewer->Update(kDown)) { cleanViewer(); return; } } } void drawTopScreen() { if(currentViewer == NULL) { drawFileBrowser(); } else { currentViewer->Draw(te); } } void drawBottomScreen() { if(currentViewer == NULL) { tb->renderText(8.0f, 8.0f, 0.5f, 0.5f, false, std::string("A - View file").c_str()); tb->renderText(8.0f, 16.0f, 0.5f, 0.5f, false, std::string("X - Mode action").c_str()); tb->renderText(8.0f, 32.0f, 0.5f, 0.5f, false, std::string("L - Switch mode").c_str()); tb->renderText(8.0f, 50.0f, 0.5f, 0.5f, false, std::string("Start - Exit").c_str()); } } void Cleanup() { te->Cleanup(); entries.clear(); if(currentViewer != NULL) { cleanViewer(); } C3D_Fini(); gfxExit(); } int main(int argc, char **argv) { gfxInitDefault(); C3D_Init(C3D_DEFAULT_CMDBUF_SIZE); te = new TextEngine(); te->Initialize(GFX_TOP); tb = new TextEngine(); tb->Initialize(GFX_BOTTOM); //TODO: Thanks to TheCruel (xerpi) for the solution to the GPU freezing issue on cia builds //aptHook(&apt_hook_cookie, apt_hook_func, NULL); initDirectory(); while (aptMainLoop()) { hidScanInput(); kDown = hidKeysDown(); update(); if (kDown & KEY_START) break; C3D_FrameBegin(C3D_FRAME_SYNCDRAW); te->Update(); C3D_FrameDrawOn(te->target); drawTopScreen(); tb->Update(); C3D_FrameDrawOn(tb->target); drawBottomScreen(); C3D_FrameEnd(0); } Cleanup(); return 0; }