Now with folders! Folders will appear as a green entry in the games list. BUTTON2 can be used to 'go back.' If you're updating, you'll need to delete ~/.es_input.cfg to map BUTTON2.

This commit is contained in:
Aloshi 2012-07-27 11:58:27 -05:00
parent 77f82134bb
commit d736aba22c
14 changed files with 203 additions and 107 deletions

View file

@ -1,7 +1,7 @@
CC=g++
CFLAGS=-c -Wall
LDFLAGS=-lSDL -lSDL_ttf -lboost_system -lboost_filesystem
SRCSOURCES=main.cpp Renderer.cpp Renderer_draw.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp components/GuiTitleScreen.cpp components/GuiList.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp
SRCSOURCES=main.cpp Renderer.cpp Renderer_draw.cpp GuiComponent.cpp InputManager.cpp SystemData.cpp GameData.cpp FolderData.cpp components/GuiTitleScreen.cpp components/GuiList.cpp components/GuiGameList.cpp components/GuiInputConfig.cpp
SOURCES=$(addprefix src/,$(SRCSOURCES))
OBJECTS=$(SOURCES:.cpp=.o)
EXECUTABLE=emulationstation

14
src/FileData.h Normal file
View file

@ -0,0 +1,14 @@
#ifndef _FILEDATA_H_
#define _FILEDATA_H_
#include <string>
class FileData
{
public:
virtual bool isFolder() = 0;
virtual std::string getName() = 0;
virtual std::string getPath() = 0;
};
#endif

31
src/FolderData.cpp Normal file
View file

@ -0,0 +1,31 @@
#include "FolderData.h"
#include "SystemData.h"
bool FolderData::isFolder() { return true; }
std::string FolderData::getName() { return mName; }
std::string FolderData::getPath() { return mPath; }
unsigned int FolderData::getFileCount() { return mFileVector.size(); }
FileData* FolderData::getFile(unsigned int i) { return mFileVector.at(i); }
FolderData::FolderData(SystemData* system, std::string path, std::string name)
{
mSystem = system;
mPath = path;
mName = name;
}
FolderData::~FolderData()
{
for(unsigned int i = 0; i < mFileVector.size(); i++)
{
delete mFileVector.at(i);
}
mFileVector.clear();
}
void FolderData::pushFileData(FileData* file)
{
mFileVector.push_back(file);
}

30
src/FolderData.h Normal file
View file

@ -0,0 +1,30 @@
#ifndef _FOLDER_H_
#define _FOLDER_H_
#include "FileData.h"
#include <vector>
class SystemData;
class FolderData : public FileData
{
public:
FolderData(SystemData* system, std::string path, std::string name);
~FolderData();
bool isFolder();
std::string getName();
std::string getPath();
unsigned int getFileCount();
FileData* getFile(unsigned int i);
void pushFileData(FileData* file);
private:
SystemData* mSystem;
std::string mPath;
std::string mName;
std::vector<FileData*> mFileVector;
};
#endif

View file

@ -1,6 +1,9 @@
#include "GameData.h"
#include <iostream>
bool GameData::isFolder() { return false; }
std::string GameData::getName() { return mName; }
GameData::GameData(SystemData* system, std::string path, std::string name)
{
mSystem = system;
@ -8,14 +11,7 @@ GameData::GameData(SystemData* system, std::string path, std::string name)
mName = name;
}
std::string GameData::getName()
{
return mName;
}
std::string GameData::getValidPath()
std::string GameData::getPath()
{
//a quick and dirty way to insert a backslash before most characters that would mess up a bash path
std::string path = mPath;

View file

@ -2,16 +2,17 @@
#define _GAMEDATA_H_
#include <string>
#include "FileData.h"
#include "SystemData.h"
class GameData
class GameData : public FileData
{
public:
GameData(SystemData* system, std::string path, std::string name);
std::string getName();
std::string getValidPath();
std::string getPath();
bool isFolder();
private:
SystemData* mSystem;
std::string mPath;

View file

@ -61,6 +61,9 @@ void InputManager::processEvent(SDL_Event* event)
case SDLK_RETURN:
button = BUTTON1;
break;
case SDLK_ESCAPE:
button = BUTTON2;
break;
default:
button = UNKNOWN;

View file

@ -12,15 +12,34 @@ namespace fs = boost::filesystem;
SystemData::SystemData(std::string name, std::string startPath, std::string extension, std::string command)
{
mName = name;
//expand home symbol if the startpath contains it
if(startPath[0] == '~')
{
startPath.erase(0, 1);
std::string home = getenv("HOME");
if(home.empty())
{
std::cerr << "ERROR - System start path contains ~ but $HOME is not set!\n";
return;
}else{
startPath.insert(0, home);
}
}
mStartPath = startPath;
mSearchExtension = extension;
mLaunchCommand = command;
buildGameList();
mRootFolder = new FolderData(this, mStartPath, "Search Root");
populateFolder(mRootFolder);
}
SystemData::~SystemData()
{
deleteGames();
delete mRootFolder;
}
std::string strreplace(std::string& str, std::string replace, std::string with)
@ -30,7 +49,7 @@ std::string strreplace(std::string& str, std::string replace, std::string with)
return str.replace(pos, replace.length(), with.c_str(), with.length());
}
void SystemData::launchGame(unsigned int i)
void SystemData::launchGame(GameData* game)
{
std::cout << "Attempting to launch game...\n";
@ -38,9 +57,8 @@ void SystemData::launchGame(unsigned int i)
SDL_JoystickEventState(0);
std::string command = mLaunchCommand;
GameData* game = mGameVector.at(i);
command = strreplace(command, "%ROM%", game->getValidPath());
command = strreplace(command, "%ROM%", game->getPath());
std::cout << " " << command << "\n";
std::cout << "=====================================================\n";
@ -53,74 +71,34 @@ void SystemData::launchGame(unsigned int i)
SDL_JoystickEventState(1);
}
void SystemData::deleteGames()
void SystemData::populateFolder(FolderData* folder)
{
for(unsigned int i = 0; i < mGameVector.size(); i++)
std::string folderPath = folder->getPath();
if(!fs::is_directory(folderPath))
{
delete mGameVector.at(i);
std::cerr << "Error - folder with path \"" << folderPath << "\" is not a directory!\n";
return;
}
mGameVector.clear();
}
void SystemData::buildGameList()
{
std::cout << "System " << mName << " building game list...\n";
deleteGames();
//expand home symbol if necessary
if(mStartPath[0] == '~')
for(fs::directory_iterator end, dir(folderPath); dir != end; ++dir)
{
mStartPath.erase(0, 1);
fs::path filePath = (*dir).path();
std::string home = getenv("HOME");
if(home.empty())
if(fs::is_directory(filePath))
{
std::cerr << "ERROR - System start path contains ~ but $HOME is not set!\n";
return;
FolderData* newFolder = new FolderData(this, filePath.string(), filePath.stem().string());
populateFolder(newFolder);
folder->pushFileData(newFolder);
}else{
mStartPath.insert(0, home);
}
}
if(!fs::is_directory(mStartPath))
if(filePath.extension().string() == mSearchExtension)
{
std::cout << "Error - system \"" << mName << "\"'s start path does not exist!\n";
return;
}
for(fs::recursive_directory_iterator end, dir(mStartPath); dir != end; ++dir)
{
//std::cout << "File found: " << *dir << "\n";
fs::path path = (*dir).path();
if(fs::is_directory(path))
continue;
std::string name = path.stem().string();
std::string extension = path.extension().string();
if(extension == mSearchExtension)
{
mGameVector.push_back(new GameData(this, path.string(), name));
std::cout << " Added game \"" << name << "\"\n";
GameData* newGame = new GameData(this, filePath.string(), filePath.stem().string());
folder->pushFileData(newGame);
}
}
}
std::cout << "...done! Found " << mGameVector.size() << " games.\n";
}
unsigned int SystemData::getGameCount()
{
return mGameVector.size();
}
GameData* SystemData::getGame(unsigned int i)
{
return mGameVector.at(i);
}
std::string SystemData::getName()
{
@ -252,3 +230,8 @@ std::string SystemData::getConfigPath()
return(home + "/.es_systems.cfg");
}
FolderData* SystemData::getRootFolder()
{
return mRootFolder;
}

View file

@ -3,6 +3,7 @@
#include <vector>
#include <string>
#include "FolderData.h"
class GameData;
@ -12,12 +13,10 @@ public:
SystemData(std::string name, std::string startPath, std::string extension, std::string command);
~SystemData();
unsigned int getGameCount();
GameData* getGame(unsigned int i);
FolderData* getRootFolder();
std::string getName();
void buildGameList();
void launchGame(unsigned int i);
void launchGame(GameData* game);
static void deleteSystems();
static void loadConfig();
static void writeExampleConfig();
@ -30,9 +29,9 @@ private:
std::string mSearchExtension;
std::string mLaunchCommand;
std::vector<GameData*> mGameVector;
void populateFolder(FolderData* folder);
void deleteGames();
FolderData* mRootFolder;
};
#endif

View file

@ -40,6 +40,11 @@ void GuiGameList::setSystemId(int id)
mSystemId = id;
mSystem = SystemData::sSystemVector.at(mSystemId);
//clear the folder stack (I can't look up the proper method right now)
while(mFolderStack.size()){ mFolderStack.pop(); }
mFolder = mSystem->getRootFolder();
updateList();
}
@ -52,10 +57,29 @@ void GuiGameList::onRender()
void GuiGameList::onInput(InputManager::InputButton button, bool keyDown)
{
if(button == InputManager::BUTTON1 && mSystem->getGameCount() > 0)
if(button == InputManager::BUTTON1 && mFolder->getFileCount() > 0)
{
if(!keyDown)
mSystem->launchGame(mList->getSelection());
{
FileData* file = (FileData*)mList->getSelectedObject();
if(file->isFolder())
{
//set current directory to this or something
mFolderStack.push(mFolder);
mFolder = (FolderData*)file;
updateList();
}else{
mSystem->launchGame((GameData*)file);
}
}
}
//std::cout << "mFolderStack.size(): " << mFolderStack.size() << "\n";
if(button == InputManager::BUTTON2 && keyDown && mFolderStack.size())
{
mFolder = mFolderStack.top();
mFolderStack.pop();
updateList();
}
if(button == InputManager::RIGHT && keyDown)
@ -72,10 +96,13 @@ void GuiGameList::updateList()
{
mList->clear();
for(unsigned int i = 0; i < mSystem->getGameCount(); i++)
for(unsigned int i = 0; i < mFolder->getFileCount(); i++)
{
GameData* game = mSystem->getGame(i);
FileData* file = mFolder->getFile(i);
mList->addObject(game->getName(), game);
if(file->isFolder())
mList->addObject(file->getName(), file, 0x00C000);
else
mList->addObject(file->getName(), file);
}
}

View file

@ -4,8 +4,10 @@
#include "../GuiComponent.h"
#include "GuiList.h"
#include <string>
#include <stack>
#include "../SystemData.h"
#include "../GameData.h"
#include "../FolderData.h"
class GuiGameList : GuiComponent
{
@ -18,8 +20,11 @@ public:
void onRender();
void onInput(InputManager::InputButton button, bool keyDown);
private:
SystemData* mSystem;
FolderData* mFolder;
std::stack<FolderData*> mFolderStack;
int mSystemId;
GuiList* mList;
};

View file

@ -4,8 +4,8 @@
#include <fstream>
std::string GuiInputConfig::sConfigPath = "./input.cfg";
std::string GuiInputConfig::sInputs[] = { "UNKNOWN", "UP", "DOWN", "LEFT", "RIGHT", "BUTTON1", "BUTTON2" }; //must be same order as InputManager::InputButton enum
int GuiInputConfig::sInputCount = 6;
std::string GuiInputConfig::sInputs[] = { "UNKNOWN", "UP", "DOWN", "LEFT", "RIGHT", "BUTTON1 (Accept)", "BUTTON2 (Back)" }; //must be same order as InputManager::InputButton enum
int GuiInputConfig::sInputCount = 7;
GuiInputConfig::GuiInputConfig()
{

View file

@ -23,27 +23,27 @@ void GuiList::onRender()
int screenCount = (Renderer::getScreenHeight() - cutoff) / entrySize;
screenCount -= 1;
if((int)mNameVector.size() >= screenCount)
if((int)mRowVector.size() >= screenCount)
{
startEntry = mSelection - (screenCount * 0.5);
if(startEntry < 0)
startEntry = 0;
if(startEntry >= (int)mNameVector.size() - screenCount)
startEntry = mNameVector.size() - screenCount;
if(startEntry >= (int)mRowVector.size() - screenCount)
startEntry = mRowVector.size() - screenCount;
}
int y = cutoff;
int color = 0xFF0000;
if(mNameVector.size() == 0)
if(mRowVector.size() == 0)
{
Renderer::drawCenteredText("The list is empty.", y, color);
return;
}
int listCutoff = startEntry + screenCount;
if(listCutoff > (int)mNameVector.size())
listCutoff = mNameVector.size();
if(listCutoff > (int)mRowVector.size())
listCutoff = mRowVector.size();
for(int i = startEntry; i < listCutoff; i++)
{
@ -52,14 +52,15 @@ void GuiList::onRender()
Renderer::drawRect(0, y, Renderer::getScreenWidth(), 52, 0x000000);
}
Renderer::drawCenteredText(mNameVector.at((unsigned int)i), y, color);
ListRow row = mRowVector.at((unsigned int)i);
Renderer::drawCenteredText(row.name, y, row.color);
y += 40;
}
}
void GuiList::onInput(InputManager::InputButton button, bool keyDown)
{
if(mNameVector.size() > 0 && keyDown)
if(mRowVector.size() > 0 && keyDown)
{
if(button == InputManager::DOWN)
mSelection++;
@ -68,34 +69,33 @@ void GuiList::onInput(InputManager::InputButton button, bool keyDown)
mSelection--;
if(mSelection < 0)
mSelection += mNameVector.size();
mSelection += mRowVector.size();
if(mSelection >= (int)mNameVector.size())
mSelection -= mNameVector.size();
if(mSelection >= (int)mRowVector.size())
mSelection -= mRowVector.size();
}
}
void GuiList::addObject(std::string name, void* obj)
void GuiList::addObject(std::string name, void* obj, int color)
{
mNameVector.push_back(name);
mPointerVector.push_back(obj);
ListRow row = {name, obj, color};
mRowVector.push_back(row);
}
void GuiList::clear()
{
mNameVector.clear();
mPointerVector.clear();
mRowVector.clear();
mSelection = 0;
}
std::string GuiList::getSelectedName()
{
return mNameVector.at(mSelection);
return mRowVector.at(mSelection).name;
}
void* GuiList::getSelectedObject()
{
return mPointerVector.at(mSelection);
return mRowVector.at(mSelection).object;
}
int GuiList::getSelection()

View file

@ -7,6 +7,14 @@
#include <vector>
#include <string>
struct ListRow
{
std::string name;
void* object;
int color;
};
//this should really be a template
class GuiList : public GuiComponent
{
public:
@ -16,15 +24,14 @@ public:
void onRender();
void onInput(InputManager::InputButton button, bool keyDown);
void addObject(std::string name, void* obj);
void addObject(std::string name, void* obj, int color = 0xFF0000);
void clear();
std::string getSelectedName();
void* getSelectedObject();
int getSelection();
private:
std::vector<std::string> mNameVector;
std::vector<void*> mPointerVector;
std::vector<ListRow> mRowVector;
int mSelection;
};