all repos — mgba @ e37a3253da794d75cd8fa21e6b5e0a1a919098ed

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
 15static void _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
 24static void _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
 40static bool _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	size_t fileIndex = 0;
 62	size_t start = 0;
 63
 64	struct FileList currentFiles;
 65	FileListInit(&currentFiles, 0);
 66	_refreshDirectory(currentPath, &currentFiles);
 67
 68	int inputHistory[GUI_INPUT_MAX] = { 0 };
 69
 70	while (true) {
 71		int input = params->pollInput();
 72		int newInput = 0;
 73		for (int i = 0; i < GUI_INPUT_MAX; ++i) {
 74			if (input & (1 << i)) {
 75				++inputHistory[i];
 76			} else {
 77				inputHistory[i] = -1;
 78			}
 79			if (!inputHistory[i] || (inputHistory[i] >= 30 && !(inputHistory[i] % 6))) {
 80				newInput |= (1 << i);
 81			}
 82		}
 83
 84		if (newInput & (1 << GUI_INPUT_UP) && fileIndex > 0) {
 85			--fileIndex;
 86		}
 87		if (newInput & (1 << GUI_INPUT_DOWN) && fileIndex < FileListSize(&currentFiles) - 1) {
 88			++fileIndex;
 89		}
 90		if (fileIndex < start) {
 91			start = fileIndex;
 92		}
 93		while ((fileIndex - start + 4) * GUIFontHeight(params->font) > params->height) {
 94			++start;
 95		}
 96		if (newInput & (1 << GUI_INPUT_CANCEL)) {
 97			_cleanFiles(&currentFiles);
 98			FileListDeinit(&currentFiles);
 99			return false;
100		}
101		if (newInput & (1 << GUI_INPUT_SELECT)) {
102			size_t len = strlen(currentPath);
103			const char* sep = PATH_SEP;
104			if (currentPath[len - 1] == *sep) {
105				sep = "";
106			}
107			snprintf(currentPath, sizeof(currentPath), "%s%s%s", currentPath, sep, *FileListGetPointer(&currentFiles, fileIndex));
108			if (!_refreshDirectory(currentPath, &currentFiles)) {
109				strncpy(outPath, currentPath, outLen);
110				return true;
111			}
112			fileIndex = 0;
113		}
114		if (newInput & (1 << GUI_INPUT_BACK)) {
115			if (strncmp(currentPath, basePath, sizeof(currentPath)) == 0) {
116				_cleanFiles(&currentFiles);
117				FileListDeinit(&currentFiles);
118				return false;
119			}
120			_upDirectory(currentPath);
121			_refreshDirectory(currentPath, &currentFiles);
122			fileIndex = 0;
123		}
124
125		params->drawStart();
126		int y = GUIFontHeight(params->font);
127		GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, "Current directory: %s", currentPath);
128		y += 2 * GUIFontHeight(params->font);
129		size_t i;
130		for (i = start; i < FileListSize(&currentFiles); ++i) {
131			int color = 0xE0A0A0A0;
132			char bullet = ' ';
133			if (i == fileIndex) {
134				color = 0xFFFFFFFF;
135				bullet = '>';
136			}
137			GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, *FileListGetPointer(&currentFiles, i));
138			y += GUIFontHeight(params->font);
139			if (y + GUIFontHeight(params->font) > params->height) {
140				break;
141			}
142		}
143		y += GUIFontHeight(params->font) * 2;
144
145		params->drawEnd();
146	}
147}