Skip to content

Instantly share code, notes, and snippets.

@LiquidFenrir
Last active June 4, 2017 15:55
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save LiquidFenrir/25ec409f34e224c14686acf3b91785b6 to your computer and use it in GitHub Desktop.
Save LiquidFenrir/25ec409f34e224c14686acf3b91785b6 to your computer and use it in GitHub Desktop.
simple filebrowser for 3ds
#pragma once
#include <3ds.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdbool.h>
// according to wikipedia, the max FAT32 path length is 255 UTF-16 characters, so 0xFF * 2 (because the 16 in UTF-16 means 16 bits = 2 bytes) (shifting left of 1 is the same as multiplying by 2)
#define MAX_PATH_LEN (0xFF << 1)
typedef struct {
char name[MAX_PATH_LEN+1];
bool isFile;
} dirInfo;
#include <dirent.h>
#include "dir.h"
int listdir(char * path, dirInfo * dirInfoArray)
{
DIR *dir;
struct dirent *ent;
int count = 0;
if ((dir = opendir(path)) != NULL) {
while ((ent = readdir(dir)) != NULL) {
strcpy(dirInfoArray[count].name, ent->d_name);
dirInfoArray[count].isFile = (ent->d_type == 8);
count++;
}
closedir (dir);
}
return count;
}
#include "common.h"
int listdir(char * path, dirInfo * dirInfoArray);
#include "draw.h"
//width in characters of the screen you're drawing on. 50 for the top screen, 40 for bottom
#define SCREEN_WIDTH 50
#define OFFSET 1 //offset in characters of the file list from the location bar
#define MAX_ENTRIES_PER_SCREEN (SCREEN_WIDTH-1-OFFSET*2)
static int scroll = 0;
static char uparrow[] = {30, 0};
static char downarrow[] = {31, 0};
void drawDirList(dirInfo * dirInfoArray, char * currentPath, int currentDir, int dirCount)
{
consoleClear();
if (strlen(currentPath) <= SCREEN_WIDTH) printf("\x1b[0;0H\x1b[47;30m%s\x1b[0m", currentPath);
else printf("\x1b[0;0H\x1b[47;30m...%s\x1b[0m", &currentPath[strlen(currentPath)-SCREEN_WIDTH+3]);
if (currentDir == 0) {
scroll = 0;
}
else if ((dirCount > MAX_ENTRIES_PER_SCREEN) && (currentDir == dirCount-1)) {
scroll = dirCount - MAX_ENTRIES_PER_SCREEN;
}
else if (currentDir >= (MAX_ENTRIES_PER_SCREEN + scroll)) {
scroll++;
}
else if ((currentDir - scroll) < 0) {
scroll--;
}
if (scroll != 0) printf("\x1b[%i;0H%s", OFFSET+1, uparrow);
if ((dirCount > MAX_ENTRIES_PER_SCREEN) && scroll != (dirCount - MAX_ENTRIES_PER_SCREEN)) printf("\x1b[%i;0H%s", MAX_ENTRIES_PER_SCREEN+OFFSET, downarrow);
for (int i = scroll; (i-scroll) < MAX_ENTRIES_PER_SCREEN; i++) {
//selected dir has white background, others have black
int bgcolor = (i == currentDir) ? 47 : 40;
//if it's a file, it has a blue name. otherwise, reverse of background
int txtcolor = (dirInfoArray[i].isFile) ? 36 : ((i == currentDir) ? 30 : 37);
if (dirInfoArray[i].name != NULL) printf("\x1b[%i;2H\x1b[%i;%im%s\x1b[0m", i+OFFSET+1-scroll, bgcolor, txtcolor, dirInfoArray[i].name);
}
}
#include "common.h"
void drawDirList(dirInfo * dirInfoArray, char * currentPath, int currentDir, int dirCount);
#include "common.h"
#include "dir.h"
#include "draw.h"
#include "sort.h"
static char currentPath[MAX_PATH_LEN+1]; //for the ending nullbyte
static dirInfo dirInfoArray[256];
static int dirCount = 0;
static int currentDir = 0;
int main() {
gfxInitDefault();
consoleInit(GFX_TOP, NULL);
chdir("/");
goto change;
while (aptMainLoop()) {
if (false) { //things in there will only run if you do a goto, otherwise the screen would flicker because of constantly clearing
change:
currentDir = 0;
getcwd(currentPath, MAX_PATH_LEN+1);
dirCount = listdir(currentPath, dirInfoArray);
for (int i = dirCount; i < 256; i++) {
dirInfoArray[i].name[0] = 0;
dirInfoArray[i].isFile = false;
}
sortDirList(dirInfoArray, dirCount);
draw:
if (currentDir > dirCount-1) currentDir = dirCount-1;
if (currentDir < 0) currentDir = 0;
drawDirList(dirInfoArray, currentPath, currentDir, dirCount);
gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();
}
hidScanInput();
if (hidKeysDown() & KEY_START) {
break;
}
else if (hidKeysDown() & KEY_A) {
if (dirCount != 0) {
if (dirInfoArray[currentDir].isFile) {
//do stuff with file
}
else {
chdir(dirInfoArray[currentDir].name);
goto change;
}
}
}
else if (hidKeysDown() & KEY_B) {
chdir("..");
goto change;
}
else if (hidKeysDown() & KEY_LEFT) {
currentDir = 0;
goto draw;
}
else if (hidKeysDown() & KEY_RIGHT) {
currentDir = dirCount-1;
goto draw;
}
else if (hidKeysDown() & KEY_UP) {
currentDir--;
goto draw;
}
else if (hidKeysDown() & KEY_DOWN) {
currentDir++;
goto draw;
}
gfxFlushBuffers();
gfxSwapBuffers();
gspWaitForVBlank();
}
gfxExit();
return 0;
}
#include "sort.h"
int checkSorted(const void * a, const void * b)
{
dirInfo * entryA = (dirInfo *)a;
dirInfo * entryB = (dirInfo *)b;
if ((entryA->isFile && entryB->isFile) || (!entryA->isFile && !entryB->isFile)) {
return strcmp(entryA->name, entryB->name);
}
else if (entryA->isFile) {
return 1;
}
else if (entryB->isFile) {
return -1;
}
return 0;
}
void sortDirList(dirInfo * dirInfoArrayArray, int dirCount)
{
qsort(dirInfoArrayArray, dirCount, sizeof(dirInfo), &checkSorted);
}
#include "common.h"
void sortDirList(dirInfo * dirInfoArrayArray, int dirCount);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment