326 lines
6.9 KiB
C++
326 lines
6.9 KiB
C++
#include <3ds.h>
|
|
#include <stdio.h>
|
|
#include <dirent.h>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <fstream>
|
|
#include <algorithm>
|
|
#include <citro3d.h>
|
|
#include <sstream>
|
|
#include <map>
|
|
#include <iostream>
|
|
|
|
#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<BrowseEntry*> entries;
|
|
std::map<std::string,bool> 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;
|
|
}
|