mirror of
https://github.com/FunKey-Project/RetroFE.git
synced 2025-12-13 18:28:52 +01:00
891 lines
26 KiB
C++
891 lines
26 KiB
C++
/* This file is part of RetroFE.
|
|
*
|
|
* RetroFE is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* RetroFE is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with RetroFE. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "RetroFE.h"
|
|
#include "Collection/CollectionInfoBuilder.h"
|
|
#include "Collection/CollectionInfo.h"
|
|
#include "Database/Configuration.h"
|
|
#include "Collection/Item.h"
|
|
#include "Execute/Launcher.h"
|
|
#include "Utility/Log.h"
|
|
#include "Utility/Utils.h"
|
|
#include "Collection/MenuParser.h"
|
|
#include "SDL.h"
|
|
#include "Control/UserInput.h"
|
|
#include "Graphics/PageBuilder.h"
|
|
#include "Graphics/Page.h"
|
|
#include "Graphics/Component/ScrollingList.h"
|
|
#include "Graphics/Component/Video.h"
|
|
#include "Video/VideoFactory.h"
|
|
#include <vector>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <dirent.h>
|
|
|
|
#if defined(__linux) || defined(__APPLE__)
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#include <cstring>
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
#include <Windows.h>
|
|
#include <SDL2/SDL_syswm.h>
|
|
#include <SDL2/SDL_thread.h>
|
|
#endif
|
|
|
|
RetroFE::RetroFE(Configuration &c)
|
|
: initialized(false)
|
|
, initializeError(false)
|
|
, initializeThread(NULL)
|
|
, config_(c)
|
|
, db_(NULL)
|
|
, metadb_(NULL)
|
|
, input_(config_)
|
|
, currentPage_(NULL)
|
|
, keyInputDisable_(0)
|
|
, currentTime_(0)
|
|
, lastLaunchReturnTime_(0)
|
|
, keyLastTime_(0)
|
|
, keyDelayTime_(.3f)
|
|
{
|
|
}
|
|
|
|
RetroFE::~RetroFE()
|
|
{
|
|
deInitialize();
|
|
}
|
|
|
|
void RetroFE::render()
|
|
{
|
|
SDL_LockMutex(SDL::getMutex());
|
|
SDL_SetRenderDrawColor(SDL::getRenderer(), 0x0, 0x0, 0x00, 0xFF);
|
|
SDL_RenderClear(SDL::getRenderer());
|
|
|
|
if(currentPage_)
|
|
{
|
|
currentPage_->draw();
|
|
}
|
|
|
|
SDL_RenderPresent(SDL::getRenderer());
|
|
SDL_UnlockMutex(SDL::getMutex());
|
|
}
|
|
|
|
int RetroFE::initialize(void *context)
|
|
{
|
|
RetroFE *instance = static_cast<RetroFE *>(context);
|
|
|
|
Logger::write(Logger::ZONE_INFO, "RetroFE", "Initializing");
|
|
|
|
if(!instance->input_.initialize())
|
|
{
|
|
Logger::write(Logger::ZONE_ERROR, "RetroFE", "Could not initialize user controls");
|
|
instance->initializeError = true;
|
|
return -1;
|
|
}
|
|
|
|
instance->db_ = new DB(Utils::combinePath(Configuration::absolutePath, "meta.db"));
|
|
|
|
if(!instance->db_->initialize())
|
|
{
|
|
Logger::write(Logger::ZONE_ERROR, "RetroFE", "Could not initialize database");
|
|
instance->initializeError = true;
|
|
return -1;
|
|
}
|
|
|
|
instance->metadb_ = new MetadataDatabase(*(instance->db_), instance->config_);
|
|
|
|
if(!instance->metadb_->initialize())
|
|
{
|
|
Logger::write(Logger::ZONE_ERROR, "RetroFE", "Could not initialize meta database");
|
|
instance->initializeError = true;
|
|
return -1;
|
|
}
|
|
|
|
instance->initialized = true;
|
|
return 0;
|
|
}
|
|
|
|
void RetroFE::launchEnter()
|
|
{
|
|
if(currentPage_)
|
|
{
|
|
currentPage_->launchEnter();
|
|
}
|
|
|
|
SDL_SetWindowGrab(SDL::getWindow(), SDL_FALSE);
|
|
}
|
|
|
|
void RetroFE::launchExit()
|
|
{
|
|
SDL_RestoreWindow(SDL::getWindow());
|
|
SDL_RaiseWindow(SDL::getWindow());
|
|
SDL_SetWindowGrab(SDL::getWindow(), SDL_TRUE);
|
|
input_.resetStates();
|
|
attract_.reset();
|
|
|
|
currentTime_ = static_cast<float>(SDL_GetTicks()) / 1000;
|
|
if(currentPage_)
|
|
{
|
|
currentPage_->launchExit();
|
|
}
|
|
lastLaunchReturnTime_ = currentTime_;
|
|
|
|
}
|
|
|
|
void RetroFE::freeGraphicsMemory()
|
|
{
|
|
if(currentPage_)
|
|
{
|
|
currentPage_->freeGraphicsMemory();
|
|
}
|
|
fontcache_.deInitialize();
|
|
|
|
SDL::deInitialize();
|
|
}
|
|
|
|
void RetroFE::allocateGraphicsMemory()
|
|
{
|
|
SDL::initialize(config_);
|
|
|
|
fontcache_.initialize();
|
|
|
|
if(currentPage_)
|
|
{
|
|
currentPage_->allocateGraphicsMemory();
|
|
}
|
|
}
|
|
|
|
bool RetroFE::deInitialize()
|
|
{
|
|
bool retVal = true;
|
|
freeGraphicsMemory();
|
|
|
|
if(currentPage_)
|
|
{
|
|
currentPage_->DeInitialize();
|
|
delete currentPage_;
|
|
currentPage_ = NULL;
|
|
}
|
|
if(metadb_)
|
|
{
|
|
delete metadb_;
|
|
metadb_ = NULL;
|
|
}
|
|
|
|
if(db_)
|
|
{
|
|
delete db_;
|
|
db_ = NULL;
|
|
}
|
|
|
|
initialized = false;
|
|
//todo: handle video deallocation
|
|
|
|
Logger::write(Logger::ZONE_INFO, "RetroFE", "Exiting");
|
|
|
|
return retVal;
|
|
}
|
|
|
|
void RetroFE::run()
|
|
{
|
|
if(!SDL::initialize(config_)) return;
|
|
|
|
fontcache_.initialize();
|
|
float preloadTime = 0;
|
|
bool videoEnable = true;
|
|
int videoLoop = 0;
|
|
config_.getProperty("videoEnable", videoEnable);
|
|
config_.getProperty("videoLoop", videoLoop);
|
|
|
|
VideoFactory::setEnabled(videoEnable);
|
|
VideoFactory::setNumLoops(videoLoop);
|
|
VideoFactory::createVideo(); // pre-initialize the gstreamer engine
|
|
Video::setEnabled(videoEnable);
|
|
|
|
|
|
initializeThread = SDL_CreateThread(initialize, "RetroFEInit", (void *)this);
|
|
|
|
if(!initializeThread)
|
|
{
|
|
Logger::write(Logger::ZONE_INFO, "RetroFE", "Could not initialize RetroFE");
|
|
return;
|
|
}
|
|
|
|
int attractModeTime = 0;
|
|
std::string firstCollection = "Main";
|
|
bool running = true;
|
|
RETROFE_STATE state = RETROFE_NEW;
|
|
|
|
config_.getProperty("attractModeTime", attractModeTime);
|
|
config_.getProperty("firstCollection", firstCollection);
|
|
|
|
attract_.idleTime = static_cast<float>(attractModeTime);
|
|
|
|
int initializeStatus = 0;
|
|
|
|
// load the initial splash screen, unload it once it is complete
|
|
currentPage_ = loadSplashPage();
|
|
state = RETROFE_ENTER;
|
|
bool splashMode = true;
|
|
bool exitSplashMode = false;
|
|
|
|
Launcher l(*this, config_);
|
|
preloadTime = static_cast<float>(SDL_GetTicks()) / 1000;
|
|
|
|
while (running)
|
|
{
|
|
float lastTime = 0;
|
|
float deltaTime = 0;
|
|
SDL_Event e;
|
|
if (SDL_PollEvent(&e))
|
|
{
|
|
if(input_.update(e))
|
|
{
|
|
exitSplashMode = true;
|
|
attract_.reset();
|
|
}
|
|
}
|
|
|
|
if(!currentPage_)
|
|
{
|
|
Logger::write(Logger::ZONE_WARNING, "RetroFE", "Could not load page");
|
|
running = false;
|
|
break;
|
|
}
|
|
switch(state)
|
|
{
|
|
case RETROFE_IDLE:
|
|
if(currentPage_ && !splashMode)
|
|
{
|
|
|
|
// account for when returning from a menu and the previous key was still "stuck"
|
|
if(lastLaunchReturnTime_ == 0 || (currentTime_ - lastLaunchReturnTime_ > .3))
|
|
{
|
|
state = processUserInput(currentPage_);
|
|
lastLaunchReturnTime_ = 0;
|
|
}
|
|
}
|
|
|
|
if((initialized || initializeError) && splashMode && (exitSplashMode || (currentPage_->getMinShowTime() <= (currentTime_ - preloadTime) && !(currentPage_->isPlaying()))))
|
|
{
|
|
SDL_WaitThread(initializeThread, &initializeStatus);
|
|
|
|
if(initializeError)
|
|
{
|
|
state = RETROFE_QUIT_REQUEST;
|
|
break;
|
|
}
|
|
|
|
currentPage_->stop();
|
|
state = RETROFE_SPLASH_EXIT;
|
|
|
|
}
|
|
break;
|
|
|
|
case RETROFE_LOAD_ART:
|
|
currentPage_->start();
|
|
state = RETROFE_ENTER;
|
|
break;
|
|
|
|
case RETROFE_ENTER:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
state = RETROFE_IDLE;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_SPLASH_EXIT:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
// delete the splash screen and use the standard menu
|
|
currentPage_->DeInitialize();
|
|
delete currentPage_;
|
|
|
|
currentPage_ = loadPage();
|
|
splashMode = false;
|
|
if(currentPage_)
|
|
{
|
|
std::string firstCollection = "Main";
|
|
|
|
config_.getProperty("firstCollection", firstCollection);
|
|
config_.setProperty("currentCollection", firstCollection);
|
|
CollectionInfo *info = getCollection(firstCollection);
|
|
|
|
currentPage_->pushCollection(info);
|
|
|
|
bool autoFavorites = true;
|
|
config_.getProperty("autoFavorites", autoFavorites);
|
|
|
|
if (autoFavorites)
|
|
{
|
|
currentPage_->selectPlaylist("favorites"); // Switch to favorites playlist
|
|
}
|
|
|
|
currentPage_->onNewItemSelected();
|
|
currentPage_->reallocateMenuSpritePoints();
|
|
|
|
state = RETROFE_LOAD_ART;
|
|
}
|
|
else
|
|
{
|
|
state = RETROFE_QUIT_REQUEST;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case RETROFE_PLAYLIST_REQUEST:
|
|
currentPage_->highlightExit();
|
|
currentPage_->setScrolling(Page::ScrollDirectionIdle);
|
|
state = RETROFE_PLAYLIST_EXIT;
|
|
break;
|
|
|
|
case RETROFE_PLAYLIST_EXIT:
|
|
if (currentPage_->isIdle())
|
|
{
|
|
currentPage_->onNewItemSelected();
|
|
state = RETROFE_PLAYLIST_LOAD_ART;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_PLAYLIST_LOAD_ART:
|
|
if (currentPage_->isIdle())
|
|
{
|
|
currentPage_->reallocateMenuSpritePoints();
|
|
currentPage_->highlightEnter();
|
|
state = RETROFE_PLAYLIST_ENTER;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_PLAYLIST_ENTER:
|
|
if (currentPage_->isIdle())
|
|
{
|
|
state = RETROFE_IDLE;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_HIGHLIGHT_MENU_IDLE:
|
|
currentPage_->setScrolling(Page::ScrollDirectionIdle);
|
|
if (currentPage_->isIdle())
|
|
{
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_HIGHLIGHT_REQUEST:
|
|
currentPage_->setScrolling(Page::ScrollDirectionIdle);
|
|
currentPage_->highlightExit();
|
|
state = RETROFE_HIGHLIGHT_EXIT;
|
|
break;
|
|
|
|
case RETROFE_HIGHLIGHT_EXIT:
|
|
if (processUserInput(currentPage_) == RETROFE_HIGHLIGHT_REQUEST)
|
|
{
|
|
state = RETROFE_HIGHLIGHT_MENU_IDLE;
|
|
}
|
|
else if (currentPage_->isIdle())
|
|
{
|
|
currentPage_->highlightLoadArt();
|
|
state = RETROFE_HIGHLIGHT_LOAD_ART;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_HIGHLIGHT_LOAD_ART:
|
|
currentPage_->highlightEnter();
|
|
state = RETROFE_HIGHLIGHT_ENTER;
|
|
break;
|
|
|
|
case RETROFE_HIGHLIGHT_ENTER:
|
|
if (processUserInput(currentPage_) == RETROFE_HIGHLIGHT_REQUEST)
|
|
{
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
else if (currentPage_->isIdle())
|
|
{
|
|
state = RETROFE_IDLE;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_NEXT_PAGE_REQUEST:
|
|
currentPage_->exitMenu();
|
|
state = RETROFE_NEXT_PAGE_MENU_EXIT;
|
|
break;
|
|
|
|
case RETROFE_NEXT_PAGE_MENU_EXIT:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
lastMenuOffsets_[currentPage_->getCollectionName()] = currentPage_->getScrollOffsetIndex();
|
|
lastMenuPlaylists_[currentPage_->getCollectionName()] = currentPage_->getPlaylistName();
|
|
// Load new layout if available
|
|
std::string layoutName;
|
|
config_.getProperty("layout", layoutName);
|
|
PageBuilder pb(layoutName, "layout", config_, &fontcache_);
|
|
Page *page = pb.buildPage( nextPageItem_->name);
|
|
std::string nextPageName = nextPageItem_->name;
|
|
if(page)
|
|
{
|
|
currentPage_->freeGraphicsMemory();
|
|
pages_.push( currentPage_ );
|
|
currentPage_ = page;
|
|
}
|
|
|
|
config_.setProperty("currentCollection", nextPageName);
|
|
|
|
CollectionInfo *info = getCollection(nextPageName);
|
|
|
|
currentPage_->pushCollection(info);
|
|
|
|
bool rememberMenu = false;
|
|
config_.getProperty("rememberMenu", rememberMenu);
|
|
bool autoFavorites = true;
|
|
config_.getProperty("autoFavorites", autoFavorites);
|
|
|
|
if (rememberMenu && lastMenuPlaylists_.find(nextPageName) != lastMenuPlaylists_.end())
|
|
{
|
|
currentPage_->selectPlaylist(lastMenuPlaylists_[nextPageName]); // Switch to last playlist
|
|
}
|
|
else if (autoFavorites)
|
|
{
|
|
currentPage_->selectPlaylist("favorites"); // Switch to favorites playlist
|
|
}
|
|
|
|
if(rememberMenu && lastMenuOffsets_.find(nextPageName) != lastMenuOffsets_.end())
|
|
{
|
|
currentPage_->setScrollOffsetIndex(lastMenuOffsets_[nextPageName]);
|
|
}
|
|
|
|
currentPage_->onNewItemSelected();
|
|
currentPage_->reallocateMenuSpritePoints();
|
|
|
|
state = RETROFE_NEXT_PAGE_MENU_LOAD_ART;
|
|
|
|
}
|
|
break;
|
|
|
|
case RETROFE_NEXT_PAGE_MENU_LOAD_ART:
|
|
if (currentPage_->getMenuDepth() != 1 )
|
|
{
|
|
currentPage_->enterMenu();
|
|
}
|
|
else
|
|
{
|
|
currentPage_->start();
|
|
}
|
|
state = RETROFE_NEXT_PAGE_MENU_ENTER;
|
|
break;
|
|
|
|
case RETROFE_NEXT_PAGE_MENU_ENTER:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
state = RETROFE_IDLE;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_LAUNCH_REQUEST:
|
|
nextPageItem_ = currentPage_->getSelectedItem();
|
|
launchEnter();
|
|
l.run(nextPageItem_->collectionInfo->name, nextPageItem_);
|
|
launchExit();
|
|
state = RETROFE_IDLE;
|
|
break;
|
|
|
|
case RETROFE_BACK_REQUEST:
|
|
if (currentPage_->getMenuDepth() == 1 )
|
|
{
|
|
currentPage_->stop();
|
|
}
|
|
else
|
|
{
|
|
currentPage_->exitMenu();
|
|
}
|
|
state = RETROFE_BACK_MENU_EXIT;
|
|
break;
|
|
|
|
case RETROFE_BACK_MENU_EXIT:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
lastMenuOffsets_[currentPage_->getCollectionName()] = currentPage_->getScrollOffsetIndex();
|
|
lastMenuPlaylists_[currentPage_->getCollectionName()] = currentPage_->getPlaylistName();
|
|
if (currentPage_->getMenuDepth() == 1)
|
|
{
|
|
currentPage_->DeInitialize();
|
|
delete currentPage_;
|
|
currentPage_ = pages_.top();
|
|
pages_.pop();
|
|
currentPage_->allocateGraphicsMemory();
|
|
}
|
|
else
|
|
{
|
|
currentPage_->popCollection();
|
|
}
|
|
config_.setProperty("currentCollection", currentPage_->getCollectionName());
|
|
|
|
bool rememberMenu = false;
|
|
config_.getProperty("rememberMenu", rememberMenu);
|
|
bool autoFavorites = true;
|
|
config_.getProperty("autoFavorites", autoFavorites);
|
|
|
|
if (rememberMenu && lastMenuPlaylists_.find(currentPage_->getCollectionName()) != lastMenuPlaylists_.end())
|
|
{
|
|
currentPage_->selectPlaylist(lastMenuPlaylists_[currentPage_->getCollectionName()]); // Switch to last playlist
|
|
}
|
|
else if (autoFavorites)
|
|
{
|
|
currentPage_->selectPlaylist("favorites"); // Switch to favorites playlist
|
|
}
|
|
|
|
if(rememberMenu && lastMenuOffsets_.find(currentPage_->getCollectionName()) != lastMenuOffsets_.end())
|
|
{
|
|
currentPage_->setScrollOffsetIndex(lastMenuOffsets_[currentPage_->getCollectionName()]);
|
|
}
|
|
|
|
currentPage_->onNewItemSelected();
|
|
currentPage_->reallocateMenuSpritePoints();
|
|
state = RETROFE_BACK_MENU_LOAD_ART;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_BACK_MENU_LOAD_ART:
|
|
currentPage_->enterMenu();
|
|
state = RETROFE_BACK_MENU_ENTER;
|
|
break;
|
|
|
|
case RETROFE_BACK_MENU_ENTER:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
currentPage_->cleanup();
|
|
state = RETROFE_IDLE;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_NEW:
|
|
if(currentPage_->isIdle())
|
|
{
|
|
state = RETROFE_IDLE;
|
|
}
|
|
break;
|
|
|
|
case RETROFE_QUIT_REQUEST:
|
|
currentPage_->stop();
|
|
state = RETROFE_QUIT;
|
|
break;
|
|
|
|
case RETROFE_QUIT:
|
|
if(currentPage_->isGraphicsIdle())
|
|
{
|
|
running = false;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// the logic below could be done in a helper method
|
|
if(running)
|
|
{
|
|
lastTime = currentTime_;
|
|
currentTime_ = static_cast<float>(SDL_GetTicks()) / 1000;
|
|
|
|
if (currentTime_ < lastTime)
|
|
{
|
|
currentTime_ = lastTime;
|
|
}
|
|
|
|
deltaTime = currentTime_ - lastTime;
|
|
double sleepTime = 1000.0/60.0 - deltaTime*1000;
|
|
if(sleepTime > 0)
|
|
{
|
|
SDL_Delay(static_cast<unsigned int>(sleepTime));
|
|
}
|
|
|
|
if(currentPage_)
|
|
{
|
|
if (!splashMode)
|
|
{
|
|
attract_.update(deltaTime, *currentPage_);
|
|
}
|
|
currentPage_->update(deltaTime);
|
|
}
|
|
|
|
render();
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
bool RetroFE::back(bool &exit)
|
|
{
|
|
bool canGoBack = false;
|
|
bool exitOnBack = false;
|
|
config_.getProperty("exitOnFirstPageBack", exitOnBack);
|
|
exit = false;
|
|
|
|
if(currentPage_->getMenuDepth() <= 1 && pages_.empty())
|
|
{
|
|
exit = exitOnBack;
|
|
}
|
|
else
|
|
{
|
|
canGoBack = true;
|
|
}
|
|
|
|
return canGoBack;
|
|
}
|
|
|
|
|
|
RetroFE::RETROFE_STATE RetroFE::processUserInput(Page *page)
|
|
{
|
|
bool exit = false;
|
|
RETROFE_STATE state = RETROFE_IDLE;
|
|
|
|
if(page->isHorizontalScroll())
|
|
{
|
|
if (input_.keystate(UserInput::KeyCodeLeft))
|
|
{
|
|
page->setScrolling(Page::ScrollDirectionBack);
|
|
}
|
|
if (input_.keystate(UserInput::KeyCodeRight))
|
|
{
|
|
page->setScrolling(Page::ScrollDirectionForward);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (input_.keystate(UserInput::KeyCodeUp))
|
|
{
|
|
page->setScrolling(Page::ScrollDirectionBack);
|
|
}
|
|
if (input_.keystate(UserInput::KeyCodeDown))
|
|
{
|
|
page->setScrolling(Page::ScrollDirectionForward);
|
|
}
|
|
}
|
|
|
|
if(page->isMenuIdle())
|
|
{
|
|
|
|
if (!input_.keystate(UserInput::KeyCodePageUp) &&
|
|
!input_.keystate(UserInput::KeyCodePageDown) &&
|
|
!input_.keystate(UserInput::KeyCodeLetterUp) &&
|
|
!input_.keystate(UserInput::KeyCodeLetterDown) &&
|
|
!input_.keystate(UserInput::KeyCodeNextPlaylist) &&
|
|
!input_.keystate(UserInput::KeyCodeAddPlaylist) &&
|
|
!input_.keystate(UserInput::KeyCodeRemovePlaylist) &&
|
|
!input_.keystate(UserInput::KeyCodeRandom))
|
|
{
|
|
keyLastTime_ = 0;
|
|
keyDelayTime_= 0.3f;
|
|
}
|
|
|
|
else if((currentTime_ - keyLastTime_) > keyDelayTime_ || keyLastTime_ == 0)
|
|
{
|
|
keyLastTime_ = currentTime_;
|
|
keyDelayTime_-= .05f;
|
|
if(keyDelayTime_< 0.1f) keyDelayTime_= 0.1f;
|
|
|
|
if (input_.keystate(UserInput::KeyCodePageUp))
|
|
{
|
|
page->pageScroll(Page::ScrollDirectionBack);
|
|
page->reallocateMenuSpritePoints();
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
if (input_.keystate(UserInput::KeyCodePageDown))
|
|
{
|
|
page->pageScroll(Page::ScrollDirectionForward);
|
|
page->reallocateMenuSpritePoints();
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
if (input_.keystate(UserInput::KeyCodeLetterUp))
|
|
{
|
|
page->letterScroll(Page::ScrollDirectionBack);
|
|
page->reallocateMenuSpritePoints();
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
if (input_.keystate(UserInput::KeyCodeLetterDown))
|
|
{
|
|
page->letterScroll(Page::ScrollDirectionForward);
|
|
page->reallocateMenuSpritePoints();
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
if(input_.newKeyPressed(UserInput::KeyCodeNextPlaylist))
|
|
{
|
|
page->nextPlaylist();
|
|
state = RETROFE_PLAYLIST_REQUEST;
|
|
}
|
|
if(input_.newKeyPressed(UserInput::KeyCodeRemovePlaylist))
|
|
{
|
|
page->removePlaylist();
|
|
state = RETROFE_PLAYLIST_REQUEST;
|
|
}
|
|
if(input_.newKeyPressed(UserInput::KeyCodeAddPlaylist))
|
|
{
|
|
page->addPlaylist();
|
|
state = RETROFE_PLAYLIST_REQUEST;
|
|
}
|
|
if(input_.keystate(UserInput::KeyCodeRandom))
|
|
{
|
|
page->selectRandom();
|
|
page->reallocateMenuSpritePoints();
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
}
|
|
|
|
if (input_.keystate(UserInput::KeyCodeAdminMode))
|
|
{
|
|
//todo: add admin mode support
|
|
}
|
|
if (input_.keystate(UserInput::KeyCodeSelect))
|
|
{
|
|
nextPageItem_ = page->getSelectedItem();
|
|
|
|
if(nextPageItem_)
|
|
{
|
|
if(nextPageItem_->leaf)
|
|
{
|
|
state = RETROFE_LAUNCH_REQUEST;
|
|
}
|
|
else
|
|
{
|
|
state = RETROFE_NEXT_PAGE_REQUEST;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (input_.keystate(UserInput::KeyCodeBack))
|
|
{
|
|
if(back(exit) || exit)
|
|
{
|
|
state = (exit) ? RETROFE_QUIT_REQUEST : RETROFE_BACK_REQUEST;
|
|
}
|
|
}
|
|
|
|
if (input_.keystate(UserInput::KeyCodeQuit))
|
|
{
|
|
state = RETROFE_QUIT_REQUEST;
|
|
}
|
|
}
|
|
|
|
if(!input_.keystate(UserInput::KeyCodeUp) &&
|
|
!input_.keystate(UserInput::KeyCodeLeft) &&
|
|
!input_.keystate(UserInput::KeyCodeDown) &&
|
|
!input_.keystate(UserInput::KeyCodeRight) &&
|
|
!input_.keystate(UserInput::KeyCodePageUp) &&
|
|
!input_.keystate(UserInput::KeyCodePageDown) &&
|
|
!attract_.isActive())
|
|
{
|
|
if (page->isMenuScrolling())
|
|
state = RETROFE_HIGHLIGHT_REQUEST;
|
|
}
|
|
|
|
return state;
|
|
}
|
|
|
|
Page *RetroFE::loadPage()
|
|
{
|
|
std::string layoutName;
|
|
|
|
config_.getProperty("layout", layoutName);
|
|
|
|
PageBuilder pb(layoutName, "layout", config_, &fontcache_);
|
|
Page *page = pb.buildPage();
|
|
|
|
if(!page)
|
|
{
|
|
Logger::write(Logger::ZONE_ERROR, "RetroFE", "Could not create page");
|
|
}
|
|
|
|
return page;
|
|
}
|
|
|
|
Page *RetroFE::loadSplashPage()
|
|
{
|
|
std::string layoutName;
|
|
config_.getProperty("layout", layoutName);
|
|
|
|
PageBuilder pb(layoutName, "splash", config_, &fontcache_);
|
|
Page * page = pb.buildPage();
|
|
page->start();
|
|
|
|
return page;
|
|
}
|
|
|
|
|
|
CollectionInfo *RetroFE::getCollection(std::string collectionName)
|
|
{
|
|
// the page will deallocate this once its done
|
|
|
|
CollectionInfoBuilder cib(config_, *metadb_);
|
|
CollectionInfo *collection = cib.buildCollection(collectionName);
|
|
cib.injectMetadata(collection);
|
|
|
|
DIR *dp;
|
|
struct dirent *dirp;
|
|
|
|
std::string path = Utils::combinePath(Configuration::absolutePath, "collections", collectionName);
|
|
dp = opendir(path.c_str());
|
|
|
|
while((dirp = readdir(dp)) != NULL)
|
|
{
|
|
std::string file = dirp->d_name;
|
|
|
|
size_t position = file.find_last_of(".");
|
|
std::string basename = (std::string::npos == position)? file : file.substr(0, position);
|
|
|
|
std::string comparator = ".sub";
|
|
int start = file.length() - comparator.length();
|
|
|
|
if(start >= 0)
|
|
{
|
|
if(file.compare(start, comparator.length(), comparator) == 0)
|
|
{
|
|
Logger::write(Logger::ZONE_INFO, "RetroFE", "Loading subcollection into menu: " + basename);
|
|
|
|
CollectionInfo *subcollection = cib.buildCollection(basename, collectionName);
|
|
collection->addSubcollection(subcollection);
|
|
cib.injectMetadata(subcollection);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool menuSort = true;
|
|
config_.getProperty("collections." + collectionName + ".list.menuSort", menuSort);
|
|
|
|
if (menuSort)
|
|
{
|
|
collection->sortItems();
|
|
}
|
|
|
|
MenuParser mp;
|
|
mp.buildMenuItems(collection, menuSort);
|
|
|
|
cib.addFavorites(collection);
|
|
collection->sortFavoriteItems();
|
|
|
|
return collection;
|
|
}
|
|
|
|
std::string RetroFE::getLayout(std::string collectionName)
|
|
{
|
|
std::string layoutKeyName = "collections." + collectionName + ".layout";
|
|
std::string layoutName = "Default 16x9";
|
|
|
|
if(!config_.getProperty(layoutKeyName, layoutName))
|
|
{
|
|
config_.getProperty("layout", layoutName);
|
|
}
|
|
|
|
return layoutName;
|
|
}
|