all repos — mgba @ ea12461c5ba577c7056ffb9348098d3f0f592822

mGBA Game Boy Advance Emulator

src/util/gui/file-select.c (view raw)

  1/* Copyright (c) 2013-2015 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include "file-select.h"
  7
  8#include "util/gui/font.h"
  9#include "util/vector.h"
 10#include "util/vfs.h"
 11
 12DECLARE_VECTOR(FileList, char*);
 13DEFINE_VECTOR(FileList, char*);
 14
 15void _cleanFiles(struct FileList* currentFiles) {
 16	size_t size = FileListSize(currentFiles);
 17	size_t i;
 18	for (i = 0; i < size; ++i) {
 19		free(*FileListGetPointer(currentFiles, i));
 20	}
 21	FileListClear(currentFiles);
 22}
 23
 24void _upDirectory(char* currentPath) {
 25	char* end = strrchr(currentPath, '/');
 26	if (!end) {
 27		return;
 28	}
 29	if (end == currentPath) {
 30		end[1] = '\0';
 31		return;
 32	}
 33	end[0] = '\0';
 34	if (end[1]) {
 35		return;
 36	}
 37	// TODO: What if there was a trailing slash?
 38}
 39
 40bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) {
 41	_cleanFiles(currentFiles);
 42
 43	struct VDir* dir = VDirOpen(currentPath);
 44	if (!dir) {
 45		return false;
 46	}
 47	struct VDirEntry* de;
 48	while ((de = dir->listNext(dir))) {
 49		if (de->name(de)[0] == '.') {
 50			continue;
 51		}
 52		*FileListAppend(currentFiles) = strdup(de->name(de));
 53	}
 54	dir->close(dir);
 55	return true;
 56}
 57
 58bool selectFile(const struct GUIParams* params, const char* basePath, char* outPath, size_t outLen, const char* suffix) {
 59	char currentPath[256];
 60	strncpy(currentPath, basePath, sizeof(currentPath));
 61	int oldInput = -1;
 62	size_t fileIndex = 0;
 63	size_t start = 0;
 64
 65	struct FileList currentFiles;
 66	FileListInit(&currentFiles, 0);
 67	_refreshDirectory(currentPath, &currentFiles);
 68
 69	while (true) {
 70		int input = params->pollInput();
 71		int newInput = input & (oldInput ^ input);
 72		oldInput = input;
 73
 74		if (newInput & (1 << GUI_INPUT_UP) && fileIndex > 0) {
 75			--fileIndex;
 76		}
 77		if (newInput & (1 << GUI_INPUT_DOWN) && fileIndex < FileListSize(&currentFiles) - 1) {
 78			++fileIndex;
 79		}
 80		if (fileIndex < start) {
 81			start = fileIndex;
 82		}
 83		while ((fileIndex - start + 4) * GUIFontHeight(params->font) > params->height) {
 84			++start;
 85		}
 86		if (newInput & (1 << GUI_INPUT_CANCEL)) {
 87			_cleanFiles(&currentFiles);
 88			FileListDeinit(&currentFiles);
 89			return false;
 90		}
 91		if (newInput & (1 << GUI_INPUT_SELECT)) {
 92			size_t len = strlen(currentPath);
 93			const char* sep = PATH_SEP;
 94			if (currentPath[len - 1] == *sep) {
 95				sep = "";
 96			}
 97			snprintf(currentPath, sizeof(currentPath), "%s%s%s", currentPath, sep, *FileListGetPointer(&currentFiles, fileIndex));
 98			if (!_refreshDirectory(currentPath, &currentFiles)) {
 99				strncpy(outPath, currentPath, outLen);
100				return true;
101			}
102			fileIndex = 0;
103		}
104		if (newInput & (1 << GUI_INPUT_BACK)) {
105			if (strncmp(currentPath, basePath, sizeof(currentPath)) == 0) {
106				_cleanFiles(&currentFiles);
107				FileListDeinit(&currentFiles);
108				return false;
109			}
110			_upDirectory(currentPath);
111			_refreshDirectory(currentPath, &currentFiles);
112			fileIndex = 0;
113		}
114
115		params->drawStart();
116		int y = GUIFontHeight(params->font);
117		GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, "Current directory: %s", currentPath);
118		y += 2 * GUIFontHeight(params->font);
119		size_t i;
120		for (i = start; i < FileListSize(&currentFiles); ++i) {
121			int color = 0xE0A0A0A0;
122			char bullet = ' ';
123			if (i == fileIndex) {
124				color = 0xFFFFFFFF;
125				bullet = '>';
126			}
127			GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, *FileListGetPointer(&currentFiles, i));
128			y += GUIFontHeight(params->font);
129			if (y + GUIFontHeight(params->font) > params->height) {
130				break;
131			}
132		}
133		y += GUIFontHeight(params->font) * 2;
134
135		params->drawEnd();
136	}
137}