all repos — mgba @ 0affe7c8d70db3631b5a567926caa459a1e30192

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	end[0] = '\0';
 30	if (end[1]) {
 31		return;
 32	}
 33	// TODO: What if there was a trailing slash?
 34}
 35
 36bool _refreshDirectory(const char* currentPath, struct FileList* currentFiles) {
 37	_cleanFiles(currentFiles);
 38
 39	struct VDir* dir = VDirOpen(currentPath);
 40	if (!dir) {
 41		return false;
 42	}
 43	struct VDirEntry* de;
 44	while ((de = dir->listNext(dir))) {
 45		if (de->name(de)[0] == '.') {
 46			continue;
 47		}
 48		*FileListAppend(currentFiles) = strdup(de->name(de));
 49	}
 50	dir->close(dir);
 51	return true;
 52}
 53
 54bool selectFile(const struct GUIParams* params, const char* basePath, char* outPath, size_t outLen, const char* suffix) {
 55	char currentPath[256];
 56	strncpy(currentPath, basePath, sizeof(currentPath));
 57	int oldInput = -1;
 58	size_t fileIndex = 0;
 59	size_t start = 0;
 60
 61	struct FileList currentFiles;
 62	FileListInit(&currentFiles, 0);
 63	_refreshDirectory(currentPath, &currentFiles);
 64
 65	while (true) {
 66		int input = params->pollInput();
 67		int newInput = input & (oldInput ^ input);
 68		oldInput = input;
 69
 70		if (newInput & (1 << GUI_INPUT_UP) && fileIndex > 0) {
 71			--fileIndex;
 72		}
 73		if (newInput & (1 << GUI_INPUT_DOWN) && fileIndex < FileListSize(&currentFiles) - 1) {
 74			++fileIndex;
 75		}
 76		if (fileIndex < start) {
 77			start = fileIndex;
 78		}
 79		while ((fileIndex - start + 4) * GUIFontHeight(params->font) > params->height) {
 80			++start;
 81		}
 82		if (newInput & (1 << GUI_INPUT_CANCEL)) {
 83			_cleanFiles(&currentFiles);
 84			FileListDeinit(&currentFiles);
 85			return false;
 86		}
 87		if (newInput & (1 << GUI_INPUT_SELECT)) {
 88			snprintf(currentPath, sizeof(currentPath), "%s%c%s", currentPath, '/', *FileListGetPointer(&currentFiles, fileIndex));
 89			if (!_refreshDirectory(currentPath, &currentFiles)) {
 90				strncpy(outPath, currentPath, outLen);
 91				return true;
 92			}
 93			fileIndex = 0;
 94		}
 95		if (newInput & (1 << GUI_INPUT_BACK)) {
 96			if (strncmp(currentPath, basePath, sizeof(currentPath)) == 0) {
 97				_cleanFiles(&currentFiles);
 98				FileListDeinit(&currentFiles);
 99				return false;
100			}
101			_upDirectory(currentPath);
102			_refreshDirectory(currentPath, &currentFiles);
103			fileIndex = 0;
104		}
105
106		params->drawStart();
107		int y = GUIFontHeight(params->font);
108		GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, 0xFFFFFFFF, "Current directory: %s", currentPath);
109		y += 2 * GUIFontHeight(params->font);
110		size_t i;
111		for (i = start; i < FileListSize(&currentFiles); ++i) {
112			int color = 0xE0A0A0A0;
113			char bullet = ' ';
114			if (i == fileIndex) {
115				color = 0xFFFFFFFF;
116				bullet = '>';
117			}
118			GUIFontPrintf(params->font, 0, y, GUI_TEXT_LEFT, color, "%c %s", bullet, *FileListGetPointer(&currentFiles, i));
119			y += GUIFontHeight(params->font);
120			if (y + GUIFontHeight(params->font) > params->height) {
121				break;
122			}
123		}
124		y += GUIFontHeight(params->font) * 2;
125
126		params->drawEnd();
127	}
128}