mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 23:55:38 +00:00
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:
parent
77f82134bb
commit
d736aba22c
2
Makefile
2
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
|
||||
|
|
14
src/FileData.h
Normal file
14
src/FileData.h
Normal 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
31
src/FolderData.cpp
Normal 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
30
src/FolderData.h
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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";
|
||||
std::cerr << "Error - folder with path \"" << folderPath << "\" is not a directory!\n";
|
||||
return;
|
||||
}
|
||||
|
||||
for(fs::directory_iterator end, dir(folderPath); dir != end; ++dir)
|
||||
{
|
||||
fs::path filePath = (*dir).path();
|
||||
|
||||
if(fs::is_directory(filePath))
|
||||
{
|
||||
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;
|
||||
GameData* newGame = new GameData(this, filePath.string(), filePath.stem().string());
|
||||
folder->pushFileData(newGame);
|
||||
}
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
Loading…
Reference in a new issue