2012-07-20 01:08:29 +00:00
|
|
|
#include "GuiGameList.h"
|
2012-07-21 19:06:24 +00:00
|
|
|
#include "../InputManager.h"
|
2012-07-20 16:14:09 +00:00
|
|
|
#include <iostream>
|
2012-08-02 04:03:15 +00:00
|
|
|
#include "GuiMenu.h"
|
2012-10-01 03:29:55 +00:00
|
|
|
#include "GuiFastSelect.h"
|
2012-08-10 19:28:34 +00:00
|
|
|
#include <boost/filesystem.hpp>
|
2013-01-04 23:31:51 +00:00
|
|
|
#include "../Log.h"
|
2013-06-17 19:01:03 +00:00
|
|
|
#include "../Settings.h"
|
2013-10-10 21:49:59 +00:00
|
|
|
|
2013-08-23 22:15:00 +00:00
|
|
|
#include "GuiMetaDataEd.h"
|
2013-10-10 21:49:59 +00:00
|
|
|
#include "GuiScraperStart.h"
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
|
|
|
|
std::vector<FolderData::SortState> GuiGameList::sortStates;
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
Eigen::Vector3f GuiGameList::getImagePos()
|
2013-06-14 15:48:13 +00:00
|
|
|
{
|
2013-07-10 11:29:43 +00:00
|
|
|
return Eigen::Vector3f(Renderer::getScreenWidth() * mTheme->getFloat("gameImageOffsetX"), Renderer::getScreenHeight() * mTheme->getFloat("gameImageOffsetY"), 0.0f);
|
2013-06-14 15:48:13 +00:00
|
|
|
}
|
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
bool GuiGameList::isDetailed() const
|
2012-07-20 01:08:29 +00:00
|
|
|
{
|
2013-07-02 07:04:52 +00:00
|
|
|
if(mSystem == NULL)
|
|
|
|
return false;
|
2012-08-02 01:43:55 +00:00
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
return mSystem->hasGamelist();
|
|
|
|
}
|
2012-07-20 01:08:29 +00:00
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
GuiGameList::GuiGameList(Window* window) : GuiComponent(window),
|
|
|
|
mTheme(new ThemeComponent(mWindow)),
|
2013-10-04 23:09:54 +00:00
|
|
|
mList(window, 0.0f, 0.0f, Font::get(FONT_SIZE_MEDIUM)),
|
2013-07-02 07:04:52 +00:00
|
|
|
mScreenshot(window),
|
|
|
|
mDescription(window),
|
2013-09-23 19:58:28 +00:00
|
|
|
mRating(window),
|
2013-07-03 01:01:58 +00:00
|
|
|
mDescContainer(window),
|
2013-07-10 11:29:43 +00:00
|
|
|
mTransitionImage(window, 0.0f, 0.0f, "", (float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), true),
|
2013-07-23 06:27:28 +00:00
|
|
|
mHeaderText(mWindow),
|
2013-08-06 13:15:20 +00:00
|
|
|
sortStateIndex(Settings::getInstance()->getInt("GameListSortIndex")),
|
|
|
|
mLockInput(false),
|
|
|
|
mEffectFunc(NULL), mEffectTime(0), mGameLaunchEffectLength(700)
|
2013-07-02 07:04:52 +00:00
|
|
|
{
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
//first object initializes the vector
|
|
|
|
if (sortStates.empty()) {
|
2013-06-30 17:24:09 +00:00
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareFileName, true, "file name, ascending"));
|
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareFileName, false, "file name, descending"));
|
2013-09-24 02:02:41 +00:00
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareRating, true, "rating, ascending"));
|
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareRating, false, "rating, descending"));
|
2013-06-30 17:24:09 +00:00
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, true, "played least often"));
|
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareTimesPlayed, false, "played most often"));
|
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, true, "played least recently"));
|
|
|
|
sortStates.push_back(FolderData::SortState(FolderData::compareLastPlayed, false, "played most recently"));
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
}
|
2012-08-02 01:43:55 +00:00
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
mImageAnimation.addChild(&mScreenshot);
|
2013-09-23 19:58:28 +00:00
|
|
|
mDescContainer.addChild(&mRating);
|
2013-09-24 02:02:41 +00:00
|
|
|
mDescContainer.addChild(&mDescription);
|
2013-06-21 21:54:41 +00:00
|
|
|
|
2013-07-02 05:57:31 +00:00
|
|
|
//scale delay with screen width (higher width = more text per line)
|
2013-07-02 07:53:23 +00:00
|
|
|
//the scroll speed is automatically scaled by component size
|
2013-07-03 01:01:58 +00:00
|
|
|
mDescContainer.setAutoScroll((int)(1500 + (Renderer::getScreenWidth() * 0.5)), 0.025f);
|
2013-07-02 05:57:31 +00:00
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
mTransitionImage.setPosition((float)Renderer::getScreenWidth(), 0);
|
2013-06-16 21:23:04 +00:00
|
|
|
mTransitionImage.setOrigin(0, 0);
|
|
|
|
|
2013-07-23 06:27:28 +00:00
|
|
|
mHeaderText.setColor(0xFF0000FF);
|
2013-10-04 23:09:54 +00:00
|
|
|
mHeaderText.setFont(Font::get(FONT_SIZE_LARGE));
|
2013-07-23 06:27:28 +00:00
|
|
|
mHeaderText.setPosition(0, 1);
|
|
|
|
mHeaderText.setSize((float)Renderer::getScreenWidth(), 0);
|
|
|
|
mHeaderText.setCentered(true);
|
|
|
|
|
|
|
|
addChild(mTheme);
|
|
|
|
addChild(&mHeaderText);
|
|
|
|
addChild(&mScreenshot);
|
|
|
|
addChild(&mDescContainer);
|
|
|
|
addChild(&mList);
|
|
|
|
addChild(&mTransitionImage);
|
|
|
|
|
|
|
|
mTransitionAnimation.addChild(this);
|
2013-06-16 21:23:04 +00:00
|
|
|
|
2012-07-21 20:57:53 +00:00
|
|
|
setSystemId(0);
|
2012-07-21 19:06:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GuiGameList::~GuiGameList()
|
|
|
|
{
|
2013-06-14 15:48:13 +00:00
|
|
|
delete mTheme;
|
2012-07-20 01:08:29 +00:00
|
|
|
}
|
|
|
|
|
2012-07-21 20:57:53 +00:00
|
|
|
void GuiGameList::setSystemId(int id)
|
|
|
|
{
|
2012-07-23 23:53:33 +00:00
|
|
|
if(SystemData::sSystemVector.size() == 0)
|
|
|
|
{
|
2013-01-04 23:31:51 +00:00
|
|
|
LOG(LogError) << "Error - no systems found!";
|
2012-07-23 23:53:33 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2012-07-21 20:57:53 +00:00
|
|
|
//make sure the id is within range
|
|
|
|
if(id >= (int)SystemData::sSystemVector.size())
|
|
|
|
id -= SystemData::sSystemVector.size();
|
|
|
|
if(id < 0)
|
|
|
|
id += SystemData::sSystemVector.size();
|
|
|
|
|
|
|
|
mSystemId = id;
|
|
|
|
mSystem = SystemData::sSystemVector.at(mSystemId);
|
|
|
|
|
2012-10-13 23:37:51 +00:00
|
|
|
//clear the folder stack
|
2012-07-27 16:58:27 +00:00
|
|
|
while(mFolderStack.size()){ mFolderStack.pop(); }
|
|
|
|
|
|
|
|
mFolder = mSystem->getRootFolder();
|
|
|
|
|
2012-08-11 04:17:52 +00:00
|
|
|
updateTheme();
|
2012-07-21 20:57:53 +00:00
|
|
|
updateList();
|
2012-08-12 14:43:09 +00:00
|
|
|
updateDetailData();
|
2013-07-17 06:47:02 +00:00
|
|
|
mWindow->normalizeNextUpdate(); //image loading can be slow
|
2012-07-21 20:57:53 +00:00
|
|
|
}
|
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
void GuiGameList::render(const Eigen::Affine3f& parentTrans)
|
2012-07-20 01:08:29 +00:00
|
|
|
{
|
2013-07-10 11:29:43 +00:00
|
|
|
Eigen::Affine3f trans = parentTrans * getTransform();
|
2013-07-23 06:27:28 +00:00
|
|
|
renderChildren(trans);
|
2012-07-20 16:14:09 +00:00
|
|
|
}
|
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
bool GuiGameList::input(InputConfig* config, Input input)
|
2013-08-06 13:15:20 +00:00
|
|
|
{
|
|
|
|
if(mLockInput)
|
|
|
|
return false;
|
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.input(config, input);
|
2013-04-09 18:13:47 +00:00
|
|
|
|
2013-08-18 14:16:11 +00:00
|
|
|
if(input.id == SDLK_F3)
|
|
|
|
{
|
2013-08-23 17:21:22 +00:00
|
|
|
GameData* game = dynamic_cast<GameData*>(mList.getSelectedObject());
|
|
|
|
if(game)
|
2013-08-23 22:15:00 +00:00
|
|
|
{
|
|
|
|
FolderData* root = mSystem->getRootFolder();
|
2013-09-17 21:50:49 +00:00
|
|
|
ScraperSearchParams searchParams;
|
|
|
|
searchParams.game = game;
|
|
|
|
searchParams.system = mSystem;
|
2013-09-19 23:41:14 +00:00
|
|
|
mWindow->pushGui(new GuiMetaDataEd(mWindow, game->metadata(), mSystem->getGameMDD(), searchParams, game->getBaseName(),
|
2013-08-23 22:15:00 +00:00
|
|
|
[&] { updateDetailData(); },
|
|
|
|
[game, root, this] { root->removeFileRecursive(game); updateList(); }
|
|
|
|
));
|
|
|
|
}
|
2013-08-18 14:16:11 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-10-10 21:49:59 +00:00
|
|
|
if(input.id == SDLK_F5)
|
|
|
|
{
|
|
|
|
mWindow->pushGui(new GuiScraperStart(mWindow));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("a", input) && mFolder->getFileCount() > 0 && input.value != 0)
|
2012-07-21 20:57:53 +00:00
|
|
|
{
|
2013-04-08 16:52:40 +00:00
|
|
|
//play select sound
|
|
|
|
mTheme->getSound("menuSelect")->play();
|
2012-10-13 20:05:43 +00:00
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
FileData* file = mList.getSelectedObject();
|
2013-04-08 16:52:40 +00:00
|
|
|
if(file->isFolder()) //if you selected a folder, add this directory to the stack, and use the selected one
|
|
|
|
{
|
|
|
|
mFolderStack.push(mFolder);
|
|
|
|
mFolder = (FolderData*)file;
|
|
|
|
updateList();
|
2013-06-14 15:48:13 +00:00
|
|
|
updateDetailData();
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2013-04-08 16:52:40 +00:00
|
|
|
}else{
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.stopScrolling();
|
2012-10-14 17:49:57 +00:00
|
|
|
|
2013-08-06 13:15:20 +00:00
|
|
|
mEffectFunc = &GuiGameList::updateGameLaunchEffect;
|
|
|
|
mEffectTime = 0;
|
|
|
|
mGameLaunchEffectLength = (int)mTheme->getSound("menuSelect")->getLengthMS();
|
|
|
|
if(mGameLaunchEffectLength < 800)
|
|
|
|
mGameLaunchEffectLength = 800;
|
|
|
|
|
|
|
|
mLockInput = true;
|
2012-10-13 20:05:43 +00:00
|
|
|
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2012-07-27 16:58:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 01:27:39 +00:00
|
|
|
//if there's something on the directory stack, return to it
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("b", input) && input.value != 0 && mFolderStack.size())
|
2012-07-27 16:58:27 +00:00
|
|
|
{
|
|
|
|
mFolder = mFolderStack.top();
|
|
|
|
mFolderStack.pop();
|
|
|
|
updateList();
|
2012-08-12 14:43:09 +00:00
|
|
|
updateDetailData();
|
2012-10-13 20:05:43 +00:00
|
|
|
|
|
|
|
//play the back sound
|
2012-11-17 18:39:49 +00:00
|
|
|
mTheme->getSound("menuBack")->play();
|
2013-06-02 15:08:32 +00:00
|
|
|
|
|
|
|
return true;
|
2012-07-21 20:57:53 +00:00
|
|
|
}
|
|
|
|
|
2012-09-07 21:44:07 +00:00
|
|
|
//only allow switching systems if more than one exists (otherwise it'll reset your position when you switch and it's annoying)
|
2013-04-08 16:52:40 +00:00
|
|
|
if(SystemData::sSystemVector.size() > 1 && input.value != 0)
|
2012-07-21 19:06:24 +00:00
|
|
|
{
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("right", input))
|
2012-09-07 21:44:07 +00:00
|
|
|
{
|
|
|
|
setSystemId(mSystemId + 1);
|
2013-06-16 21:23:04 +00:00
|
|
|
doTransition(-1);
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2012-09-07 21:44:07 +00:00
|
|
|
}
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("left", input))
|
2012-09-07 21:44:07 +00:00
|
|
|
{
|
|
|
|
setSystemId(mSystemId - 1);
|
2013-06-16 21:23:04 +00:00
|
|
|
doTransition(1);
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2012-09-07 21:44:07 +00:00
|
|
|
}
|
2012-07-21 19:06:24 +00:00
|
|
|
}
|
2012-08-02 01:43:55 +00:00
|
|
|
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
//change sort order
|
|
|
|
if(config->isMappedTo("sortordernext", input) && input.value != 0) {
|
|
|
|
setNextSortIndex();
|
|
|
|
//std::cout << "Sort order is " << FolderData::getSortStateName(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending) << std::endl;
|
|
|
|
}
|
|
|
|
else if(config->isMappedTo("sortorderprevious", input) && input.value != 0) {
|
|
|
|
setPreviousSortIndex();
|
|
|
|
//std::cout << "Sort order is " << FolderData::getSortStateName(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending) << std::endl;
|
|
|
|
}
|
|
|
|
|
2012-10-13 20:05:43 +00:00
|
|
|
//open the "start menu"
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("menu", input) && input.value != 0)
|
2012-08-02 04:03:15 +00:00
|
|
|
{
|
2013-04-09 18:13:47 +00:00
|
|
|
mWindow->pushGui(new GuiMenu(mWindow, this));
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2012-08-02 04:03:15 +00:00
|
|
|
}
|
|
|
|
|
2012-10-13 20:05:43 +00:00
|
|
|
//open the fast select menu
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("select", input) && input.value != 0)
|
2012-10-01 03:29:55 +00:00
|
|
|
{
|
2013-07-02 20:49:53 +00:00
|
|
|
mWindow->pushGui(new GuiFastSelect(mWindow, this, &mList, mList.getSelectedObject()->getName()[0], mTheme));
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2012-10-01 03:29:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
if(isDetailed())
|
2012-08-02 01:43:55 +00:00
|
|
|
{
|
2013-04-08 16:52:40 +00:00
|
|
|
if(config->isMappedTo("up", input) || config->isMappedTo("down", input) || config->isMappedTo("pageup", input) || config->isMappedTo("pagedown", input))
|
2012-08-02 01:43:55 +00:00
|
|
|
{
|
2013-04-08 16:52:40 +00:00
|
|
|
if(input.value == 0)
|
2012-08-16 15:23:23 +00:00
|
|
|
updateDetailData();
|
|
|
|
else
|
2013-09-24 02:02:41 +00:00
|
|
|
hideDetailData();
|
2012-08-02 01:43:55 +00:00
|
|
|
}
|
2013-06-02 15:08:32 +00:00
|
|
|
return true;
|
2012-08-02 01:43:55 +00:00
|
|
|
}
|
2013-06-02 15:08:32 +00:00
|
|
|
|
|
|
|
return false;
|
2012-07-21 19:06:24 +00:00
|
|
|
}
|
|
|
|
|
2013-06-30 17:24:09 +00:00
|
|
|
const FolderData::SortState & GuiGameList::getSortState() const
|
|
|
|
{
|
|
|
|
return sortStates.at(sortStateIndex);
|
|
|
|
}
|
|
|
|
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
void GuiGameList::setSortIndex(size_t index)
|
|
|
|
{
|
|
|
|
//make the index valid
|
|
|
|
if (index >= sortStates.size()) {
|
|
|
|
index = 0;
|
|
|
|
}
|
|
|
|
if (index != sortStateIndex) {
|
|
|
|
//get sort state from vector and sort list
|
|
|
|
sortStateIndex = index;
|
|
|
|
sort(sortStates.at(sortStateIndex).comparisonFunction, sortStates.at(sortStateIndex).ascending);
|
|
|
|
}
|
2013-07-02 21:14:33 +00:00
|
|
|
//save new index to settings
|
|
|
|
Settings::getInstance()->setInt("GameListSortIndex", sortStateIndex);
|
Support sorting of game list via input
You can now map the functions "sortordernext" and "sortorderprevious" to
inputs (in es_input.cfg) and toggle the game list sort order with them.
The order is: "file name, ascending" (default), "file name, descending",
"rating ascending", "rating descending", "user rating ascending", "user
rating descending", "time played ascending", "times played descending",
"last played time ascending", "last played time descending".
2013-06-28 17:44:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void GuiGameList::setNextSortIndex()
|
|
|
|
{
|
|
|
|
//make the index wrap around
|
|
|
|
if ((sortStateIndex - 1) >= sortStates.size()) {
|
|
|
|
setSortIndex(0);
|
|
|
|
}
|
|
|
|
setSortIndex(sortStateIndex + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GuiGameList::setPreviousSortIndex()
|
|
|
|
{
|
|
|
|
//make the index wrap around
|
|
|
|
if (((int)sortStateIndex - 1) < 0) {
|
|
|
|
setSortIndex(sortStates.size() - 1);
|
|
|
|
}
|
|
|
|
setSortIndex(sortStateIndex - 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
void GuiGameList::sort(FolderData::ComparisonFunction & comparisonFunction, bool ascending)
|
|
|
|
{
|
|
|
|
//resort list and update it
|
|
|
|
mFolder->sort(comparisonFunction, ascending);
|
|
|
|
updateList();
|
|
|
|
updateDetailData();
|
|
|
|
}
|
|
|
|
|
2012-07-20 16:14:09 +00:00
|
|
|
void GuiGameList::updateList()
|
|
|
|
{
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.clear();
|
2012-07-20 16:14:09 +00:00
|
|
|
|
2012-07-27 16:58:27 +00:00
|
|
|
for(unsigned int i = 0; i < mFolder->getFileCount(); i++)
|
2012-07-20 16:14:09 +00:00
|
|
|
{
|
2012-07-27 16:58:27 +00:00
|
|
|
FileData* file = mFolder->getFile(i);
|
2012-07-21 20:57:53 +00:00
|
|
|
|
2012-07-27 16:58:27 +00:00
|
|
|
if(file->isFolder())
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.addObject(file->getName(), file, mTheme->getColor("secondary"));
|
2012-07-27 16:58:27 +00:00
|
|
|
else
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.addObject(file->getName(), file, mTheme->getColor("primary"));
|
2012-07-20 16:14:09 +00:00
|
|
|
}
|
2012-07-20 01:08:29 +00:00
|
|
|
}
|
2012-08-02 04:03:15 +00:00
|
|
|
|
2013-04-08 16:52:40 +00:00
|
|
|
std::string GuiGameList::getThemeFile()
|
|
|
|
{
|
2012-12-17 19:29:43 +00:00
|
|
|
std::string themePath;
|
|
|
|
|
2013-05-13 19:53:28 +00:00
|
|
|
themePath = getHomePath();
|
2012-12-17 19:29:43 +00:00
|
|
|
themePath += "/.emulationstation/" + mSystem->getName() + "/theme.xml";
|
|
|
|
if(boost::filesystem::exists(themePath))
|
|
|
|
return themePath;
|
|
|
|
|
|
|
|
themePath = mSystem->getStartPath() + "/theme.xml";
|
|
|
|
if(boost::filesystem::exists(themePath))
|
|
|
|
return themePath;
|
|
|
|
|
2013-05-13 19:53:28 +00:00
|
|
|
themePath = getHomePath();
|
2012-12-17 19:29:43 +00:00
|
|
|
themePath += "/.emulationstation/es_theme.xml";
|
|
|
|
if(boost::filesystem::exists(themePath))
|
|
|
|
return themePath;
|
|
|
|
|
|
|
|
return "";
|
|
|
|
}
|
|
|
|
|
2012-08-10 19:28:34 +00:00
|
|
|
void GuiGameList::updateTheme()
|
|
|
|
{
|
2013-07-02 07:04:52 +00:00
|
|
|
mTheme->readXML(getThemeFile(), isDetailed());
|
2012-08-13 18:32:53 +00:00
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.setSelectorColor(mTheme->getColor("selector"));
|
|
|
|
mList.setSelectedTextColor(mTheme->getColor("selected"));
|
|
|
|
mList.setScrollSound(mTheme->getSound("menuScroll"));
|
2012-09-15 21:24:33 +00:00
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.setFont(mTheme->getListFont());
|
2013-10-04 23:09:54 +00:00
|
|
|
mList.setPosition(0.0f, Font::get(FONT_SIZE_LARGE)->getHeight() + 2.0f);
|
2012-10-31 14:46:06 +00:00
|
|
|
|
2013-07-23 06:27:28 +00:00
|
|
|
if(!mTheme->getBool("hideHeader"))
|
|
|
|
{
|
2013-08-13 06:56:10 +00:00
|
|
|
mHeaderText.setText(mSystem->getFullName());
|
2013-07-23 06:27:28 +00:00
|
|
|
}else{
|
|
|
|
mHeaderText.setText("");
|
|
|
|
}
|
|
|
|
|
2013-07-02 07:04:52 +00:00
|
|
|
if(isDetailed())
|
2012-09-15 21:24:33 +00:00
|
|
|
{
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.setCentered(mTheme->getBool("listCentered"));
|
2012-10-13 23:40:44 +00:00
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
mList.setPosition(mTheme->getFloat("listOffsetX") * Renderer::getScreenWidth(), mList.getPosition().y());
|
2013-07-02 07:04:52 +00:00
|
|
|
mList.setTextOffsetX((int)(mTheme->getFloat("listTextOffsetX") * Renderer::getScreenWidth()));
|
2012-10-13 23:37:51 +00:00
|
|
|
|
2013-07-10 11:29:43 +00:00
|
|
|
mScreenshot.setPosition(mTheme->getFloat("gameImageOffsetX") * Renderer::getScreenWidth(), mTheme->getFloat("gameImageOffsetY") * Renderer::getScreenHeight());
|
2013-07-02 07:04:52 +00:00
|
|
|
mScreenshot.setOrigin(mTheme->getFloat("gameImageOriginX"), mTheme->getFloat("gameImageOriginY"));
|
2013-07-10 11:29:43 +00:00
|
|
|
mScreenshot.setResize(mTheme->getFloat("gameImageWidth") * Renderer::getScreenWidth(), mTheme->getFloat("gameImageHeight") * Renderer::getScreenHeight(), false);
|
2013-06-14 15:48:13 +00:00
|
|
|
|
|
|
|
mDescription.setColor(mTheme->getColor("description"));
|
|
|
|
mDescription.setFont(mTheme->getDescriptionFont());
|
2013-07-02 07:04:52 +00:00
|
|
|
}else{
|
|
|
|
mList.setCentered(true);
|
2013-07-10 11:29:43 +00:00
|
|
|
mList.setPosition(0, mList.getPosition().y());
|
2013-07-10 00:02:59 +00:00
|
|
|
mList.setTextOffsetX(0);
|
2013-08-07 04:35:06 +00:00
|
|
|
|
|
|
|
//mDescription.setFont(nullptr);
|
2012-09-15 21:24:33 +00:00
|
|
|
}
|
2012-08-10 19:28:34 +00:00
|
|
|
}
|
|
|
|
|
2012-08-12 14:43:09 +00:00
|
|
|
void GuiGameList::updateDetailData()
|
|
|
|
{
|
2013-09-24 02:02:41 +00:00
|
|
|
if(!isDetailed() || !mList.getSelectedObject() || mList.getSelectedObject()->isFolder())
|
2012-08-12 14:43:09 +00:00
|
|
|
{
|
2013-09-24 02:02:41 +00:00
|
|
|
hideDetailData();
|
2013-07-02 07:04:52 +00:00
|
|
|
}else{
|
2013-09-24 02:02:41 +00:00
|
|
|
if(mDescContainer.getParent() != this)
|
|
|
|
addChild(&mDescContainer);
|
|
|
|
|
|
|
|
GameData* game = (GameData*)mList.getSelectedObject();
|
|
|
|
//set image to either "not found" image or metadata image
|
|
|
|
if(game->metadata()->get("image").empty())
|
|
|
|
mScreenshot.setImage(mTheme->getString("imageNotFoundPath"));
|
|
|
|
else
|
|
|
|
mScreenshot.setImage(game->metadata()->get("image"));
|
2012-10-25 17:36:30 +00:00
|
|
|
|
2013-09-24 02:02:41 +00:00
|
|
|
Eigen::Vector3f imgOffset = Eigen::Vector3f(Renderer::getScreenWidth() * 0.10f, 0, 0);
|
|
|
|
mScreenshot.setPosition(getImagePos() - imgOffset);
|
2013-06-14 15:48:13 +00:00
|
|
|
|
2013-09-24 02:02:41 +00:00
|
|
|
mImageAnimation.fadeIn(35);
|
2013-10-11 00:55:57 +00:00
|
|
|
mImageAnimation.move((int)imgOffset.x(), (int)imgOffset.y(), 20);
|
2013-06-14 15:48:13 +00:00
|
|
|
|
2013-09-24 02:02:41 +00:00
|
|
|
mDescContainer.setPosition(Eigen::Vector3f(Renderer::getScreenWidth() * 0.03f, getImagePos().y() + mScreenshot.getSize().y() + 12, 0));
|
|
|
|
mDescContainer.setSize(Eigen::Vector2f(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03f), Renderer::getScreenHeight() - mDescContainer.getPosition().y()));
|
|
|
|
mDescContainer.setScrollPos(Eigen::Vector2d(0, 0));
|
|
|
|
mDescContainer.resetAutoScrollTimer();
|
2013-07-03 01:01:58 +00:00
|
|
|
|
2013-09-24 02:02:41 +00:00
|
|
|
const float colwidth = mDescContainer.getSize().x();
|
|
|
|
float ratingHeight = colwidth * 0.3f / 5.0f;
|
|
|
|
mRating.setSize(ratingHeight * 5.0f, ratingHeight);
|
|
|
|
|
|
|
|
mRating.setPosition(colwidth - mRating.getSize().x() - 12, 0);
|
|
|
|
mRating.setValue(game->metadata()->get("rating"));
|
|
|
|
|
|
|
|
mDescription.setPosition(0, mRating.getSize().y());
|
|
|
|
mDescription.setSize(Eigen::Vector2f(Renderer::getScreenWidth() * (mTheme->getFloat("listOffsetX") - 0.03f), 0));
|
|
|
|
mDescription.setText(game->metadata()->get("desc"));
|
2012-08-12 14:43:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-24 02:02:41 +00:00
|
|
|
void GuiGameList::hideDetailData()
|
2012-10-17 17:15:58 +00:00
|
|
|
{
|
2013-09-24 02:02:41 +00:00
|
|
|
if(mDescContainer.getParent() == this)
|
|
|
|
removeChild(&mDescContainer);
|
|
|
|
|
|
|
|
mImageAnimation.fadeOut(35);
|
2012-10-17 17:15:58 +00:00
|
|
|
}
|
|
|
|
|
2013-04-08 16:52:40 +00:00
|
|
|
GuiGameList* GuiGameList::create(Window* window)
|
2012-10-05 20:18:36 +00:00
|
|
|
{
|
2013-07-02 07:04:52 +00:00
|
|
|
GuiGameList* list = new GuiGameList(window);
|
2013-04-08 17:40:15 +00:00
|
|
|
window->pushGui(list);
|
|
|
|
return list;
|
2012-10-05 20:18:36 +00:00
|
|
|
}
|
2013-04-09 18:13:47 +00:00
|
|
|
|
|
|
|
void GuiGameList::update(int deltaTime)
|
|
|
|
{
|
2013-06-16 21:23:04 +00:00
|
|
|
mTransitionAnimation.update(deltaTime);
|
2013-07-23 06:27:28 +00:00
|
|
|
mImageAnimation.update(deltaTime);
|
2013-08-06 13:15:20 +00:00
|
|
|
|
|
|
|
if(mEffectFunc != NULL)
|
|
|
|
{
|
|
|
|
mEffectTime += deltaTime;
|
|
|
|
(this->*mEffectFunc)(mEffectTime);
|
|
|
|
}
|
|
|
|
|
2013-07-23 06:27:28 +00:00
|
|
|
GuiComponent::update(deltaTime);
|
2013-04-09 18:13:47 +00:00
|
|
|
}
|
2013-06-16 21:23:04 +00:00
|
|
|
|
|
|
|
void GuiGameList::doTransition(int dir)
|
|
|
|
{
|
|
|
|
mTransitionImage.copyScreen();
|
|
|
|
mTransitionImage.setOpacity(255);
|
2013-07-23 06:27:28 +00:00
|
|
|
|
|
|
|
//put the image of what's currently onscreen at what will be (in screen coords) 0, 0
|
|
|
|
mTransitionImage.setPosition((float)Renderer::getScreenWidth() * dir, 0);
|
|
|
|
|
|
|
|
//move the entire thing offscreen so we'll move into place
|
|
|
|
setPosition((float)Renderer::getScreenWidth() * -dir, mPosition[1]);
|
|
|
|
|
2013-06-16 21:23:04 +00:00
|
|
|
mTransitionAnimation.move(Renderer::getScreenWidth() * dir, 0, 50);
|
|
|
|
}
|
2013-08-06 13:15:20 +00:00
|
|
|
|
|
|
|
float lerpFloat(const float& start, const float& end, float t)
|
|
|
|
{
|
|
|
|
if(t <= 0)
|
|
|
|
return start;
|
|
|
|
if(t >= 1)
|
|
|
|
return end;
|
|
|
|
|
|
|
|
return (start * (1 - t) + end * t);
|
|
|
|
}
|
|
|
|
|
|
|
|
Eigen::Vector2f lerpVector2f(const Eigen::Vector2f& start, const Eigen::Vector2f& end, float t)
|
|
|
|
{
|
|
|
|
if(t <= 0)
|
|
|
|
return start;
|
|
|
|
if(t >= 1)
|
|
|
|
return end;
|
|
|
|
|
|
|
|
return (start * (1 - t) + end * t);
|
|
|
|
}
|
|
|
|
|
2013-08-07 03:46:25 +00:00
|
|
|
float clamp(float min, float max, float val)
|
|
|
|
{
|
|
|
|
if(val < min)
|
|
|
|
val = min;
|
|
|
|
else if(val > max)
|
|
|
|
val = max;
|
|
|
|
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
//http://en.wikipedia.org/wiki/Smoothstep
|
|
|
|
float smoothStep(float edge0, float edge1, float x)
|
|
|
|
{
|
|
|
|
// Scale, and clamp x to 0..1 range
|
|
|
|
x = clamp(0, 1, (x - edge0)/(edge1 - edge0));
|
|
|
|
|
|
|
|
// Evaluate polynomial
|
|
|
|
return x*x*x*(x*(x*6 - 15) + 10);
|
|
|
|
}
|
|
|
|
|
2013-08-06 13:15:20 +00:00
|
|
|
void GuiGameList::updateGameLaunchEffect(int t)
|
|
|
|
{
|
|
|
|
const int endTime = mGameLaunchEffectLength;
|
|
|
|
|
|
|
|
const int zoomTime = endTime;
|
2013-08-07 03:46:25 +00:00
|
|
|
const int centerTime = endTime - 50;
|
2013-08-06 13:15:20 +00:00
|
|
|
|
2013-08-07 03:46:25 +00:00
|
|
|
const int fadeDelay = endTime - 600;
|
|
|
|
const int fadeTime = endTime - fadeDelay - 100;
|
2013-08-06 13:15:20 +00:00
|
|
|
|
|
|
|
Eigen::Vector2f imageCenter(mScreenshot.getCenter());
|
|
|
|
if(!isDetailed())
|
|
|
|
{
|
|
|
|
imageCenter << mList.getPosition().x() + mList.getSize().x() / 2, mList.getPosition().y() + mList.getSize().y() / 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
const Eigen::Vector2f centerStart(Renderer::getScreenWidth() / 2, Renderer::getScreenHeight() / 2);
|
|
|
|
|
2013-08-07 03:46:25 +00:00
|
|
|
//remember to clamp or zoom factor will be incorrect with a negative t because squared
|
|
|
|
const float tNormalized = clamp(0, 1, (float)t / endTime);
|
|
|
|
|
|
|
|
mWindow->setCenterPoint(lerpVector2f(centerStart, imageCenter, smoothStep(0.0, 1.0, tNormalized)));
|
|
|
|
mWindow->setZoomFactor(lerpFloat(1.0f, 3.0f, tNormalized*tNormalized));
|
2013-08-06 13:15:20 +00:00
|
|
|
mWindow->setFadePercent(lerpFloat(0.0f, 1.0f, (float)(t - fadeDelay) / fadeTime));
|
|
|
|
|
|
|
|
if(t > endTime)
|
|
|
|
{
|
|
|
|
//effect done
|
2013-08-07 04:35:06 +00:00
|
|
|
mTransitionImage.setImage(""); //fixes "tried to bind uninitialized texture!" since copyScreen()'d textures don't reinit
|
2013-08-06 13:15:20 +00:00
|
|
|
mSystem->launchGame(mWindow, (GameData*)mList.getSelectedObject());
|
|
|
|
mEffectFunc = &GuiGameList::updateGameReturnEffect;
|
|
|
|
mEffectTime = 0;
|
|
|
|
mGameLaunchEffectLength = 700;
|
|
|
|
mLockInput = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GuiGameList::updateGameReturnEffect(int t)
|
|
|
|
{
|
|
|
|
updateGameLaunchEffect(mGameLaunchEffectLength - t);
|
|
|
|
|
|
|
|
if(t >= mGameLaunchEffectLength)
|
|
|
|
mEffectFunc = NULL;
|
|
|
|
}
|