diff --git a/Makefile b/Makefile index fbc771a2d..c4c7aa88b 100644 --- a/Makefile +++ b/Makefile @@ -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 diff --git a/src/FileData.h b/src/FileData.h new file mode 100644 index 000000000..8a662b358 --- /dev/null +++ b/src/FileData.h @@ -0,0 +1,14 @@ +#ifndef _FILEDATA_H_ +#define _FILEDATA_H_ + +#include + +class FileData +{ +public: + virtual bool isFolder() = 0; + virtual std::string getName() = 0; + virtual std::string getPath() = 0; +}; + +#endif diff --git a/src/FolderData.cpp b/src/FolderData.cpp new file mode 100644 index 000000000..fa7932654 --- /dev/null +++ b/src/FolderData.cpp @@ -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); +} + diff --git a/src/FolderData.h b/src/FolderData.h new file mode 100644 index 000000000..781046c38 --- /dev/null +++ b/src/FolderData.h @@ -0,0 +1,30 @@ +#ifndef _FOLDER_H_ +#define _FOLDER_H_ + +#include "FileData.h" +#include + +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 mFileVector; +}; + +#endif diff --git a/src/GameData.cpp b/src/GameData.cpp index 0de2fef29..6a7e6c4e9 100644 --- a/src/GameData.cpp +++ b/src/GameData.cpp @@ -1,6 +1,9 @@ #include "GameData.h" #include +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; diff --git a/src/GameData.h b/src/GameData.h index 51987f250..f4d9c67b8 100644 --- a/src/GameData.h +++ b/src/GameData.h @@ -2,16 +2,17 @@ #define _GAMEDATA_H_ #include +#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; diff --git a/src/InputManager.cpp b/src/InputManager.cpp index 6c55f5f65..8350c7333 100644 --- a/src/InputManager.cpp +++ b/src/InputManager.cpp @@ -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; diff --git a/src/SystemData.cpp b/src/SystemData.cpp index 8ca2814bf..9bdfd5e68 100644 --- a/src/SystemData.cpp +++ b/src/SystemData.cpp @@ -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); - } - - mGameVector.clear(); -} - -void SystemData::buildGameList() -{ - std::cout << "System " << mName << " building game list...\n"; - - deleteGames(); - - //expand home symbol if necessary - if(mStartPath[0] == '~') - { - mStartPath.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{ - mStartPath.insert(0, home); - } - } - - if(!fs::is_directory(mStartPath)) - { - std::cout << "Error - system \"" << mName << "\"'s start path does not exist!\n"; + std::cerr << "Error - folder with path \"" << folderPath << "\" is not a directory!\n"; return; } - for(fs::recursive_directory_iterator end, dir(mStartPath); dir != end; ++dir) + for(fs::directory_iterator end, dir(folderPath); dir != end; ++dir) { - //std::cout << "File found: " << *dir << "\n"; + fs::path filePath = (*dir).path(); - 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) + if(fs::is_directory(filePath)) { - mGameVector.push_back(new GameData(this, path.string(), name)); - std::cout << " Added game \"" << name << "\"\n"; + FolderData* newFolder = new FolderData(this, filePath.string(), filePath.stem().string()); + populateFolder(newFolder); + folder->pushFileData(newFolder); + }else{ + if(filePath.extension().string() == mSearchExtension) + { + 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; +} diff --git a/src/SystemData.h b/src/SystemData.h index c52463e89..c8926339b 100644 --- a/src/SystemData.h +++ b/src/SystemData.h @@ -3,6 +3,7 @@ #include #include +#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 mGameVector; + void populateFolder(FolderData* folder); - void deleteGames(); + FolderData* mRootFolder; }; #endif diff --git a/src/components/GuiGameList.cpp b/src/components/GuiGameList.cpp index 0d1ae5434..0f74d0f51 100644 --- a/src/components/GuiGameList.cpp +++ b/src/components/GuiGameList.cpp @@ -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); } } diff --git a/src/components/GuiGameList.h b/src/components/GuiGameList.h index ddc78d1eb..c15d6cbd9 100644 --- a/src/components/GuiGameList.h +++ b/src/components/GuiGameList.h @@ -4,8 +4,10 @@ #include "../GuiComponent.h" #include "GuiList.h" #include +#include #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 mFolderStack; int mSystemId; GuiList* mList; }; diff --git a/src/components/GuiInputConfig.cpp b/src/components/GuiInputConfig.cpp index 65191be20..a1889a1d4 100644 --- a/src/components/GuiInputConfig.cpp +++ b/src/components/GuiInputConfig.cpp @@ -4,8 +4,8 @@ #include 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() { diff --git a/src/components/GuiList.cpp b/src/components/GuiList.cpp index 2a9597539..485170060 100644 --- a/src/components/GuiList.cpp +++ b/src/components/GuiList.cpp @@ -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() diff --git a/src/components/GuiList.h b/src/components/GuiList.h index ef313d52b..e52e09788 100644 --- a/src/components/GuiList.h +++ b/src/components/GuiList.h @@ -7,6 +7,14 @@ #include #include +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 mNameVector; - std::vector mPointerVector; + std::vector mRowVector; int mSelection; };