2020-09-15 20:57:54 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
2020-05-24 08:29:29 +00:00
|
|
|
//
|
2020-09-15 20:57:54 +00:00
|
|
|
// EmulationStation Desktop Edition
|
2020-06-21 12:25:28 +00:00
|
|
|
// ViewController.cpp
|
2020-05-24 08:29:29 +00:00
|
|
|
//
|
2020-06-21 12:25:28 +00:00
|
|
|
// Handles overall system navigation including animations and transitions.
|
2021-03-10 17:21:49 +00:00
|
|
|
// Creates the gamelist views and handles refresh and reloads of these when needed
|
2020-06-21 12:25:28 +00:00
|
|
|
// (for example when metadata has been changed or when a list sorting has taken place).
|
|
|
|
// Initiates the launching of games, calling FileData to do the actual launch.
|
2021-03-10 17:21:49 +00:00
|
|
|
// Displays a dialog when there are no games found on startup.
|
2020-05-24 08:29:29 +00:00
|
|
|
//
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
#include "views/ViewController.h"
|
|
|
|
|
2021-05-09 20:47:46 +00:00
|
|
|
#include "AudioManager.h"
|
2017-09-08 13:20:07 +00:00
|
|
|
#include "FileFilterIndex.h"
|
2020-07-14 17:16:21 +00:00
|
|
|
#include "InputManager.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "Log.h"
|
|
|
|
#include "Settings.h"
|
2020-07-14 17:16:21 +00:00
|
|
|
#include "Sound.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "SystemData.h"
|
2020-11-17 16:30:23 +00:00
|
|
|
#include "SystemView.h"
|
2017-11-01 22:21:10 +00:00
|
|
|
#include "Window.h"
|
2021-07-07 18:03:42 +00:00
|
|
|
#include "animations/Animation.h"
|
|
|
|
#include "animations/LambdaAnimation.h"
|
|
|
|
#include "animations/MoveCameraAnimation.h"
|
|
|
|
#include "guis/GuiInfoPopup.h"
|
|
|
|
#include "guis/GuiMenu.h"
|
|
|
|
#include "views/SystemView.h"
|
|
|
|
#include "views/UIModeController.h"
|
|
|
|
#include "views/gamelist/DetailedGameListView.h"
|
|
|
|
#include "views/gamelist/GridGameListView.h"
|
|
|
|
#include "views/gamelist/IGameListView.h"
|
|
|
|
#include "views/gamelist/VideoGameListView.h"
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-05-24 08:29:29 +00:00
|
|
|
ViewController* ViewController::sInstance = nullptr;
|
2021-07-07 18:03:42 +00:00
|
|
|
|
2020-12-29 13:51:29 +00:00
|
|
|
#if defined(_MSC_VER) // MSVC compiler.
|
|
|
|
const std::string ViewController::FAVORITE_CHAR = Utils::String::wideStringToString(L"\uF005");
|
|
|
|
const std::string ViewController::FOLDER_CHAR = Utils::String::wideStringToString(L"\uF07C");
|
|
|
|
const std::string ViewController::TICKMARK_CHAR = Utils::String::wideStringToString(L"\uF14A");
|
|
|
|
const std::string ViewController::CONTROLLER_CHAR = Utils::String::wideStringToString(L"\uF11b");
|
|
|
|
const std::string ViewController::FILTER_CHAR = Utils::String::wideStringToString(L"\uF0b0");
|
|
|
|
#else
|
2020-12-16 20:19:48 +00:00
|
|
|
const std::string ViewController::FAVORITE_CHAR = "\uF005";
|
|
|
|
const std::string ViewController::FOLDER_CHAR = "\uF07C";
|
2020-12-29 13:51:29 +00:00
|
|
|
const std::string ViewController::TICKMARK_CHAR = "\uF14A";
|
|
|
|
const std::string ViewController::CONTROLLER_CHAR = "\uF11b";
|
|
|
|
const std::string ViewController::FILTER_CHAR = "\uF0b0";
|
|
|
|
#endif
|
2014-06-25 16:29:58 +00:00
|
|
|
|
|
|
|
ViewController* ViewController::get()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
assert(sInstance);
|
|
|
|
return sInstance;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::init(Window* window)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
assert(!sInstance);
|
|
|
|
sInstance = new ViewController(window);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
ViewController::ViewController(Window* window)
|
|
|
|
: GuiComponent(window)
|
|
|
|
, mCurrentView(nullptr)
|
|
|
|
, mPreviousView(nullptr)
|
|
|
|
, mSkipView(nullptr)
|
2021-08-15 17:30:31 +00:00
|
|
|
, mCamera(Renderer::getIdentity())
|
2021-07-07 18:03:42 +00:00
|
|
|
, mSystemViewTransition(false)
|
|
|
|
, mWrappedViews(false)
|
|
|
|
, mFadeOpacity(0)
|
|
|
|
, mCancelledTransition(false)
|
|
|
|
, mLockInput(false)
|
|
|
|
, mNextSystem(false)
|
|
|
|
, mGameToLaunch(nullptr)
|
|
|
|
, mNoGamesMessageBox(nullptr)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mState.viewing = NOTHING;
|
2021-01-12 17:40:25 +00:00
|
|
|
mState.viewstyle = AUTOMATIC;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ViewController::~ViewController()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
assert(sInstance == this);
|
|
|
|
sInstance = nullptr;
|
2021-03-19 17:34:10 +00:00
|
|
|
UIModeController::deinit();
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2021-06-16 16:54:04 +00:00
|
|
|
void ViewController::invalidSystemsFileDialog()
|
2021-03-10 17:21:49 +00:00
|
|
|
{
|
2021-07-07 18:03:42 +00:00
|
|
|
std::string errorMessage = "COULDN'T PARSE THE SYSTEMS CONFIGURATION FILE.\n"
|
|
|
|
"IF YOU HAVE A CUSTOMIZED es_systems.xml FILE, THEN\n"
|
|
|
|
"SOMETHING IS LIKELY WRONG WITH YOUR XML SYNTAX.\n"
|
|
|
|
"IF YOU DON'T HAVE A CUSTOM SYSTEMS FILE, THEN THE\n"
|
|
|
|
"EMULATIONSTATION INSTALLATION IS BROKEN. SEE THE\n"
|
|
|
|
"APPLICATION LOG FILE es_log.txt FOR ADDITIONAL INFO.";
|
|
|
|
|
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
|
|
|
mWindow, HelpStyle(), errorMessage.c_str(), "QUIT",
|
|
|
|
[] {
|
|
|
|
SDL_Event quit;
|
|
|
|
quit.type = SDL_QUIT;
|
|
|
|
SDL_PushEvent(&quit);
|
|
|
|
},
|
|
|
|
"", nullptr, "", nullptr, true));
|
2021-03-10 17:21:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::noGamesDialog()
|
|
|
|
{
|
2021-07-07 18:03:42 +00:00
|
|
|
mNoGamesErrorMessage = "NO GAME FILES WERE FOUND. EITHER PLACE YOUR GAMES IN\n"
|
|
|
|
"THE CURRENTLY CONFIGURED ROM DIRECTORY OR CHANGE\n"
|
|
|
|
"ITS PATH USING THE BUTTON BELOW. OPTIONALLY THE ROM\n"
|
|
|
|
"DIRECTORY STRUCTURE CAN BE GENERATED WHICH WILL\n"
|
|
|
|
"CREATE A TEXT FILE FOR EACH SYSTEM PROVIDING SOME\n"
|
|
|
|
"INFORMATION SUCH AS THE SUPPORTED FILE EXTENSIONS.\n"
|
|
|
|
"THIS IS THE CURRENTLY CONFIGURED ROM DIRECTORY:\n";
|
|
|
|
|
|
|
|
#if defined(_WIN64)
|
2021-03-10 17:21:49 +00:00
|
|
|
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
2021-07-07 18:03:42 +00:00
|
|
|
#else
|
2021-03-10 17:21:49 +00:00
|
|
|
mRomDirectory = FileData::getROMDirectory();
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
mNoGamesMessageBox = new GuiMsgBox(
|
|
|
|
mWindow, HelpStyle(), mNoGamesErrorMessage + mRomDirectory, "CHANGE ROM DIRECTORY",
|
|
|
|
[this] {
|
|
|
|
std::string currentROMDirectory;
|
|
|
|
#if defined(_WIN64)
|
|
|
|
currentROMDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
|
|
|
#else
|
|
|
|
currentROMDirectory = FileData::getROMDirectory();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
mWindow->pushGui(new GuiComplexTextEditPopup(
|
|
|
|
mWindow, HelpStyle(), "ENTER ROM DIRECTORY PATH",
|
|
|
|
"Currently configured path:", currentROMDirectory, currentROMDirectory,
|
2021-03-10 17:21:49 +00:00
|
|
|
[this](const std::string& newROMDirectory) {
|
|
|
|
Settings::getInstance()->setString("ROMDirectory", newROMDirectory);
|
|
|
|
Settings::getInstance()->saveFile();
|
2021-07-07 18:03:42 +00:00
|
|
|
#if defined(_WIN64)
|
2021-03-10 17:21:49 +00:00
|
|
|
mRomDirectory = Utils::String::replace(FileData::getROMDirectory(), "/", "\\");
|
2021-07-07 18:03:42 +00:00
|
|
|
#else
|
2021-03-10 17:21:49 +00:00
|
|
|
mRomDirectory = FileData::getROMDirectory();
|
2021-07-07 18:03:42 +00:00
|
|
|
#endif
|
2021-03-10 17:21:49 +00:00
|
|
|
mNoGamesMessageBox->changeText(mNoGamesErrorMessage + mRomDirectory);
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
2021-07-07 18:03:42 +00:00
|
|
|
"ROM DIRECTORY SETTING SAVED, RESTART\n"
|
|
|
|
"THE APPLICATION TO RESCAN THE SYSTEMS",
|
|
|
|
"OK", nullptr, "", nullptr, "", nullptr, true));
|
2021-03-10 17:21:49 +00:00
|
|
|
},
|
2021-07-07 18:03:42 +00:00
|
|
|
false, "SAVE", "SAVE CHANGES?", "LOAD CURRENT", "LOAD CURRENTLY CONFIGURED VALUE",
|
|
|
|
"CLEAR", "CLEAR (LEAVE BLANK TO RESET TO DEFAULT DIRECTORY)", false));
|
|
|
|
},
|
|
|
|
"CREATE DIRECTORIES",
|
|
|
|
[this] {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(
|
|
|
|
mWindow, HelpStyle(),
|
2021-03-10 17:21:49 +00:00
|
|
|
"THIS WILL CREATE DIRECTORIES FOR ALL THE\n"
|
2021-06-16 16:54:04 +00:00
|
|
|
"GAME SYSTEMS DEFINED IN es_systems.xml\n\n"
|
2021-03-10 17:21:49 +00:00
|
|
|
"THIS MAY CREATE A LOT OF FOLDERS SO IT'S\n"
|
2021-03-20 08:01:34 +00:00
|
|
|
"ADVICED TO REMOVE THE ONES YOU DON'T NEED\n\n"
|
2021-03-10 17:21:49 +00:00
|
|
|
"PROCEED?",
|
2021-07-07 18:03:42 +00:00
|
|
|
"YES",
|
|
|
|
[this] {
|
|
|
|
if (!SystemData::createSystemDirectories()) {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
|
|
|
"THE SYSTEM DIRECTORIES WERE SUCCESSFULLY\n"
|
|
|
|
"GENERATED, EXIT THE APPLICATION AND PLACE\n"
|
|
|
|
"YOUR GAMES IN THE NEWLY CREATED FOLDERS",
|
|
|
|
"OK", nullptr, "", nullptr, "", nullptr,
|
|
|
|
true));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mWindow->pushGui(new GuiMsgBox(mWindow, HelpStyle(),
|
|
|
|
"ERROR CREATING THE SYSTEM DIRECTORIES,\n"
|
|
|
|
"PERMISSION PROBLEMS OR DISK FULL?\n\n"
|
|
|
|
"SEE THE LOG FILE FOR MORE DETAILS",
|
|
|
|
"OK", nullptr, "", nullptr, "", nullptr,
|
|
|
|
true));
|
|
|
|
}
|
|
|
|
},
|
|
|
|
"NO", nullptr, "", nullptr, true));
|
|
|
|
},
|
|
|
|
"QUIT",
|
|
|
|
[] {
|
|
|
|
SDL_Event quit;
|
|
|
|
quit.type = SDL_QUIT;
|
|
|
|
SDL_PushEvent(&quit);
|
|
|
|
},
|
|
|
|
true, false);
|
2021-03-10 17:21:49 +00:00
|
|
|
|
|
|
|
mWindow->pushGui(mNoGamesMessageBox);
|
|
|
|
}
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
void ViewController::goToStart()
|
|
|
|
{
|
2020-12-15 17:44:56 +00:00
|
|
|
// If the system view does not exist, then create it. We do this here as it would
|
|
|
|
// otherwise not be done if jumping directly into a specific game system on startup.
|
|
|
|
if (!mSystemListView)
|
|
|
|
getSystemListView();
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// If a specific system is requested, go directly to its game list.
|
|
|
|
auto requestedSystem = Settings::getInstance()->getString("StartupSystem");
|
|
|
|
if ("" != requestedSystem && "retropie" != requestedSystem) {
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto it = SystemData::sSystemVector.cbegin(); // Line break.
|
|
|
|
it != SystemData::sSystemVector.cend(); it++) {
|
2020-06-21 12:25:28 +00:00
|
|
|
if ((*it)->getName() == requestedSystem) {
|
|
|
|
goToGameList(*it);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Requested system doesn't exist.
|
|
|
|
Settings::getInstance()->setString("StartupSystem", "");
|
|
|
|
}
|
2020-09-27 10:49:14 +00:00
|
|
|
// Get the first system entry.
|
2020-11-15 21:54:39 +00:00
|
|
|
goToSystemView(getSystemListView()->getFirst(), false);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2017-11-18 22:23:56 +00:00
|
|
|
void ViewController::ReloadAndGoToStart()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
mWindow->renderLoadingScreen("Loading...");
|
2021-01-05 09:45:32 +00:00
|
|
|
reloadAll();
|
|
|
|
if (mState.viewing == GAME_LIST) {
|
|
|
|
goToSystemView(SystemData::sSystemVector.front(), false);
|
|
|
|
goToSystem(SystemData::sSystemVector.front(), false);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
goToSystem(SystemData::sSystemVector.front(), false);
|
|
|
|
}
|
2017-11-18 22:23:56 +00:00
|
|
|
}
|
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
bool ViewController::isCameraMoving()
|
|
|
|
{
|
|
|
|
if (mCurrentView) {
|
2021-08-15 17:30:31 +00:00
|
|
|
if (mCamera[3].x - -mCurrentView->getPosition().x != 0.0f ||
|
|
|
|
mCamera[3].y - -mCurrentView->getPosition().y != 0.0f)
|
2020-09-15 20:57:54 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-16 16:44:33 +00:00
|
|
|
void ViewController::cancelViewTransitions()
|
2020-09-15 20:57:54 +00:00
|
|
|
{
|
2020-11-18 21:26:58 +00:00
|
|
|
if (Settings::getInstance()->getString("TransitionStyle") == "slide") {
|
|
|
|
if (isCameraMoving()) {
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].x = -mCurrentView->getPosition().x;
|
|
|
|
mCamera[3].y = -mCurrentView->getPosition().y;
|
2020-11-18 21:26:58 +00:00
|
|
|
stopAllAnimations();
|
|
|
|
}
|
|
|
|
// mSkipView is used when skipping through the gamelists in quick succession.
|
|
|
|
// Without this, the game video (or static image) would not get rendered during
|
|
|
|
// the slide transition animation.
|
|
|
|
else if (mSkipView) {
|
|
|
|
mSkipView.reset();
|
|
|
|
mSkipView = nullptr;
|
|
|
|
}
|
2020-09-15 20:57:54 +00:00
|
|
|
}
|
2020-11-16 16:44:33 +00:00
|
|
|
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") {
|
|
|
|
if (isAnimationPlaying(0)) {
|
|
|
|
finishAnimation(0);
|
2020-11-18 21:26:58 +00:00
|
|
|
mCancelledTransition = true;
|
2020-11-16 16:44:33 +00:00
|
|
|
mFadeOpacity = 0;
|
|
|
|
mWindow->invalidateCachedBackground();
|
|
|
|
}
|
|
|
|
}
|
2020-09-15 20:57:54 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::stopScrolling()
|
|
|
|
{
|
|
|
|
mSystemListView->stopScrolling();
|
|
|
|
mCurrentView->stopListScrolling();
|
|
|
|
|
|
|
|
if (mSystemListView->isAnimationPlaying(0))
|
|
|
|
mSystemListView->finishAnimation(0);
|
|
|
|
}
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
int ViewController::getSystemId(SystemData* system)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
2020-09-15 20:57:54 +00:00
|
|
|
return static_cast<int>(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 21:54:39 +00:00
|
|
|
void ViewController::restoreViewPosition()
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-11-15 21:54:39 +00:00
|
|
|
if (mPreviousView) {
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec3 restorePosition{mPreviousView->getPosition()};
|
2021-08-15 17:30:31 +00:00
|
|
|
restorePosition.x = mWrapPreviousPositionX;
|
2020-11-15 21:54:39 +00:00
|
|
|
mPreviousView->setPosition(restorePosition);
|
|
|
|
mWrapPreviousPositionX = 0;
|
|
|
|
mWrappedViews = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::goToSystemView(SystemData* system, bool playTransition)
|
|
|
|
{
|
2020-11-17 16:30:23 +00:00
|
|
|
bool applicationStartup = false;
|
|
|
|
|
|
|
|
if (mState.viewing == NOTHING)
|
|
|
|
applicationStartup = true;
|
|
|
|
|
2020-11-15 21:54:39 +00:00
|
|
|
// Restore the X position for the view, if it was previously moved.
|
|
|
|
if (mWrappedViews)
|
|
|
|
restoreViewPosition();
|
|
|
|
|
2020-11-18 21:26:58 +00:00
|
|
|
if (mPreviousView) {
|
|
|
|
mPreviousView.reset();
|
|
|
|
mPreviousView = nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
mPreviousView = mCurrentView;
|
|
|
|
|
2020-11-06 19:27:41 +00:00
|
|
|
if (system->isGroupedCustomCollection())
|
|
|
|
system = system->getRootFolder()->getParent()->getSystem();
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mState.viewing = SYSTEM_SELECT;
|
|
|
|
mState.system = system;
|
2020-11-18 22:47:32 +00:00
|
|
|
mSystemViewTransition = true;
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
auto systemList = getSystemListView();
|
2020-09-15 20:57:54 +00:00
|
|
|
systemList->setPosition(getSystemId(system) * static_cast<float>(Renderer::getScreenWidth()),
|
2021-08-15 17:30:31 +00:00
|
|
|
systemList->getPosition().y);
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
systemList->goToSystem(system, false);
|
|
|
|
mCurrentView = systemList;
|
|
|
|
mCurrentView->onShow();
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-11-17 16:30:23 +00:00
|
|
|
// Application startup animation.
|
|
|
|
if (applicationStartup) {
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera = glm::translate(mCamera, -mCurrentView->getPosition());
|
2020-11-17 16:30:23 +00:00
|
|
|
if (Settings::getInstance()->getString("TransitionStyle") == "slide") {
|
|
|
|
if (getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL ||
|
2021-07-07 18:03:42 +00:00
|
|
|
getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL_WHEEL)
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].y += static_cast<float>(Renderer::getScreenHeight());
|
2020-11-17 16:30:23 +00:00
|
|
|
else
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].x -= static_cast<float>(Renderer::getScreenWidth());
|
2020-11-17 16:30:23 +00:00
|
|
|
updateHelpPrompts();
|
|
|
|
}
|
|
|
|
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") {
|
|
|
|
if (getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL ||
|
2021-07-07 18:03:42 +00:00
|
|
|
getSystemListView()->getCarouselType() == CarouselType::HORIZONTAL_WHEEL)
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].y += static_cast<float>(Renderer::getScreenHeight());
|
2020-11-17 16:30:23 +00:00
|
|
|
else
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].x += static_cast<float>(Renderer::getScreenWidth());
|
2020-11-17 16:30:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
updateHelpPrompts();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (playTransition || applicationStartup)
|
2020-11-15 21:54:39 +00:00
|
|
|
playViewTransition();
|
|
|
|
else
|
|
|
|
playViewTransition(true);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2021-01-01 21:37:21 +00:00
|
|
|
void ViewController::goToSystem(SystemData* system, bool animate)
|
|
|
|
{
|
|
|
|
mSystemListView->goToSystem(system, animate);
|
|
|
|
}
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
void ViewController::goToNextGameList()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
assert(mState.viewing == GAME_LIST);
|
|
|
|
SystemData* system = getState().getSystem();
|
|
|
|
assert(system);
|
|
|
|
NavigationSounds::getInstance()->playThemeNavigationSound(QUICKSYSSELECTSOUND);
|
2021-01-01 20:45:51 +00:00
|
|
|
mNextSystem = true;
|
2020-06-21 12:25:28 +00:00
|
|
|
goToGameList(system->getNext());
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::goToPrevGameList()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
assert(mState.viewing == GAME_LIST);
|
|
|
|
SystemData* system = getState().getSystem();
|
|
|
|
assert(system);
|
|
|
|
NavigationSounds::getInstance()->playThemeNavigationSound(QUICKSYSSELECTSOUND);
|
2021-01-01 20:45:51 +00:00
|
|
|
mNextSystem = false;
|
2020-06-21 12:25:28 +00:00
|
|
|
goToGameList(system->getPrev());
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::goToGameList(SystemData* system)
|
|
|
|
{
|
2020-11-15 21:54:39 +00:00
|
|
|
bool wrapFirstToLast = false;
|
|
|
|
bool wrapLastToFirst = false;
|
2020-11-16 16:44:33 +00:00
|
|
|
bool slideTransitions = false;
|
|
|
|
|
|
|
|
if (Settings::getInstance()->getString("TransitionStyle") == "slide")
|
|
|
|
slideTransitions = true;
|
2020-11-15 21:54:39 +00:00
|
|
|
|
|
|
|
// Restore the X position for the view, if it was previously moved.
|
|
|
|
if (mWrappedViews)
|
|
|
|
restoreViewPosition();
|
|
|
|
|
2020-11-18 21:26:58 +00:00
|
|
|
if (mPreviousView && Settings::getInstance()->getString("TransitionStyle") == "fade" &&
|
2021-07-07 18:03:42 +00:00
|
|
|
isAnimationPlaying(0)) {
|
2020-11-18 21:26:58 +00:00
|
|
|
mPreviousView->onHide();
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
2020-11-18 21:26:58 +00:00
|
|
|
|
|
|
|
if (mPreviousView) {
|
|
|
|
mSkipView = mPreviousView;
|
|
|
|
mPreviousView.reset();
|
|
|
|
mPreviousView = nullptr;
|
|
|
|
}
|
2021-07-03 11:52:47 +00:00
|
|
|
else if (!mPreviousView && mState.viewing == GAME_LIST) {
|
|
|
|
// This is needed as otherwise the static image would not get rendered during the
|
|
|
|
// first Slide transition when coming from the System view.
|
|
|
|
mSkipView = getGameListView(system);
|
|
|
|
}
|
2020-11-18 21:26:58 +00:00
|
|
|
|
2020-11-18 22:47:32 +00:00
|
|
|
if (mState.viewing != SYSTEM_SELECT) {
|
2020-11-18 21:26:58 +00:00
|
|
|
mPreviousView = mCurrentView;
|
2020-11-18 22:47:32 +00:00
|
|
|
mSystemViewTransition = false;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
mSystemViewTransition = true;
|
|
|
|
}
|
2020-11-18 21:26:58 +00:00
|
|
|
|
2020-11-15 21:54:39 +00:00
|
|
|
// Find if we're wrapping around the first and last systems, which requires the gamelist
|
|
|
|
// to be moved in order to avoid weird camera movements. This is only needed for the
|
2021-06-22 16:06:20 +00:00
|
|
|
// slide transition style.
|
|
|
|
if (mState.viewing == GAME_LIST && SystemData::sSystemVector.size() > 1 && slideTransitions) {
|
2020-11-15 21:54:39 +00:00
|
|
|
if (SystemData::sSystemVector.front() == mState.getSystem()) {
|
|
|
|
if (SystemData::sSystemVector.back() == system)
|
|
|
|
wrapFirstToLast = true;
|
|
|
|
}
|
|
|
|
else if (SystemData::sSystemVector.back() == mState.getSystem()) {
|
|
|
|
if (SystemData::sSystemVector.front() == system)
|
|
|
|
wrapLastToFirst = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
// Stop any scrolling, animations and camera movements.
|
2020-09-18 16:40:22 +00:00
|
|
|
if (mState.viewing == SYSTEM_SELECT) {
|
2020-09-15 20:57:54 +00:00
|
|
|
mSystemListView->stopScrolling();
|
|
|
|
if (mSystemListView->isAnimationPlaying(0))
|
|
|
|
mSystemListView->finishAnimation(0);
|
|
|
|
}
|
2020-11-16 16:44:33 +00:00
|
|
|
|
|
|
|
if (slideTransitions)
|
|
|
|
cancelViewTransitions();
|
2020-09-15 20:57:54 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mState.viewing == SYSTEM_SELECT) {
|
2020-11-18 21:26:58 +00:00
|
|
|
// Move the system list.
|
2020-06-21 12:25:28 +00:00
|
|
|
auto sysList = getSystemListView();
|
2021-08-15 17:30:31 +00:00
|
|
|
float offsetX = sysList->getPosition().x;
|
2020-06-21 12:25:28 +00:00
|
|
|
int sysId = getSystemId(system);
|
2020-05-24 08:29:29 +00:00
|
|
|
|
2020-11-16 16:44:33 +00:00
|
|
|
sysList->setPosition(sysId * static_cast<float>(Renderer::getScreenWidth()),
|
2021-08-15 17:30:31 +00:00
|
|
|
sysList->getPosition().y);
|
|
|
|
offsetX = sysList->getPosition().x - offsetX;
|
|
|
|
mCamera[3].x -= offsetX;
|
2020-11-15 21:54:39 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// If we are wrapping around, either from the first to last system, or the other way
|
|
|
|
// around, we need to temporarily move the gamelist view location so that the camera
|
|
|
|
// movements will be correct. This is accomplished by simply offsetting the X position
|
|
|
|
// with the position of the first or last system plus the screen width.
|
|
|
|
if (wrapFirstToLast) {
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec3 currentPosition{mCurrentView->getPosition()};
|
2021-08-15 17:30:31 +00:00
|
|
|
mWrapPreviousPositionX = currentPosition.x;
|
2021-08-17 16:41:45 +00:00
|
|
|
float offsetX{getGameListView(system)->getPosition().x};
|
2021-01-01 20:45:51 +00:00
|
|
|
// This is needed to move the camera in the correct direction if there are only two systems.
|
|
|
|
if (SystemData::sSystemVector.size() == 2 && mNextSystem)
|
2021-07-07 18:03:42 +00:00
|
|
|
offsetX -= Renderer::getScreenWidth();
|
2021-01-01 20:45:51 +00:00
|
|
|
else
|
|
|
|
offsetX += Renderer::getScreenWidth();
|
2021-08-15 17:30:31 +00:00
|
|
|
currentPosition.x = offsetX;
|
2020-11-15 21:54:39 +00:00
|
|
|
mCurrentView->setPosition(currentPosition);
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].x -= offsetX;
|
2020-11-15 21:54:39 +00:00
|
|
|
mWrappedViews = true;
|
|
|
|
}
|
|
|
|
else if (wrapLastToFirst) {
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec3 currentPosition{mCurrentView->getPosition()};
|
2021-08-15 17:30:31 +00:00
|
|
|
mWrapPreviousPositionX = currentPosition.x;
|
2021-08-17 16:41:45 +00:00
|
|
|
float offsetX{getGameListView(system)->getPosition().x};
|
2021-01-01 20:45:51 +00:00
|
|
|
if (SystemData::sSystemVector.size() == 2 && !mNextSystem)
|
|
|
|
offsetX += Renderer::getScreenWidth();
|
|
|
|
else
|
|
|
|
offsetX -= Renderer::getScreenWidth();
|
2021-08-15 17:30:31 +00:00
|
|
|
currentPosition.x = offsetX;
|
2020-11-15 21:54:39 +00:00
|
|
|
mCurrentView->setPosition(currentPosition);
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].x = -offsetX;
|
2020-11-15 21:54:39 +00:00
|
|
|
mWrappedViews = true;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-11-17 16:30:23 +00:00
|
|
|
mCurrentView = getGameListView(system);
|
|
|
|
|
|
|
|
// Application startup animation, if starting in a gamelist rather than in the system view.
|
|
|
|
if (mState.viewing == NOTHING) {
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera = glm::translate(mCamera, -mCurrentView->getPosition());
|
2020-11-17 16:30:23 +00:00
|
|
|
if (Settings::getInstance()->getString("TransitionStyle") == "slide") {
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].y -= static_cast<float>(Renderer::getScreenHeight());
|
2020-11-17 16:30:23 +00:00
|
|
|
updateHelpPrompts();
|
|
|
|
}
|
|
|
|
else if (Settings::getInstance()->getString("TransitionStyle") == "fade") {
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].y += static_cast<float>(Renderer::getScreenHeight() * 2);
|
2020-11-17 16:30:23 +00:00
|
|
|
}
|
|
|
|
else {
|
|
|
|
updateHelpPrompts();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mState.viewing = GAME_LIST;
|
|
|
|
mState.system = system;
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2021-04-05 10:37:52 +00:00
|
|
|
auto it = mGameListViews.find(system);
|
|
|
|
if (it != mGameListViews.cend()) {
|
|
|
|
std::string viewStyle = it->second->getName();
|
|
|
|
if (viewStyle == "basic")
|
|
|
|
mState.viewstyle = BASIC;
|
|
|
|
else if (viewStyle == "detailed")
|
|
|
|
mState.viewstyle = DETAILED;
|
|
|
|
else if (viewStyle == "video")
|
|
|
|
mState.viewstyle = VIDEO;
|
|
|
|
else if (viewStyle == "grid")
|
|
|
|
mState.viewstyle = GRID;
|
|
|
|
}
|
|
|
|
|
2020-11-18 22:47:32 +00:00
|
|
|
if (mCurrentView)
|
2020-06-21 12:25:28 +00:00
|
|
|
mCurrentView->onShow();
|
2020-11-18 22:47:32 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
playViewTransition();
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2020-11-15 21:54:39 +00:00
|
|
|
void ViewController::playViewTransition(bool instant)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-11-18 21:26:58 +00:00
|
|
|
mCancelledTransition = false;
|
2020-11-16 16:44:33 +00:00
|
|
|
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec3 target{};
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mCurrentView)
|
|
|
|
target = mCurrentView->getPosition();
|
|
|
|
|
|
|
|
// No need to animate, we're not going anywhere (probably due to goToNextGamelist()
|
|
|
|
// or goToPrevGamelist() being called when there's only 1 system).
|
2021-08-15 17:30:31 +00:00
|
|
|
if (target == static_cast<glm::vec3>(-mCamera[3]) && !isAnimationPlaying(0))
|
2020-06-21 12:25:28 +00:00
|
|
|
return;
|
|
|
|
|
2021-08-17 16:41:45 +00:00
|
|
|
std::string transition_style{Settings::getInstance()->getString("TransitionStyle")};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-11-15 21:54:39 +00:00
|
|
|
if (instant || transition_style == "instant") {
|
2021-07-07 18:03:42 +00:00
|
|
|
setAnimation(new LambdaAnimation(
|
|
|
|
[this, target](float /*t*/) {
|
2021-08-15 17:30:31 +00:00
|
|
|
this->mCamera[3].x = -target.x;
|
|
|
|
this->mCamera[3].y = -target.y;
|
|
|
|
this->mCamera[3].z = -target.z;
|
2021-07-07 18:03:42 +00:00
|
|
|
if (mPreviousView)
|
|
|
|
mPreviousView->onHide();
|
|
|
|
},
|
|
|
|
1));
|
2020-11-15 21:54:39 +00:00
|
|
|
updateHelpPrompts();
|
|
|
|
}
|
|
|
|
else if (transition_style == "fade") {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Stop whatever's currently playing, leaving mFadeOpacity wherever it is.
|
|
|
|
cancelAnimation(0);
|
|
|
|
|
|
|
|
auto fadeFunc = [this](float t) {
|
2020-11-18 21:26:58 +00:00
|
|
|
// The flag mCancelledTransition is required only when cancelViewTransitions()
|
2020-11-16 16:44:33 +00:00
|
|
|
// cancels the animation, and it's only needed for the Fade transitions.
|
|
|
|
// Without this, a (much shorter) fade transition would still play as
|
|
|
|
// finishedCallback is calling this function.
|
2020-11-18 21:26:58 +00:00
|
|
|
if (!mCancelledTransition)
|
2021-07-07 18:03:42 +00:00
|
|
|
mFadeOpacity = Math::lerp(0.0f, 1.0f, t);
|
2020-06-21 12:25:28 +00:00
|
|
|
};
|
|
|
|
|
2020-11-18 21:26:58 +00:00
|
|
|
auto fadeCallback = [this]() {
|
|
|
|
if (mPreviousView)
|
|
|
|
mPreviousView->onHide();
|
|
|
|
};
|
|
|
|
|
2020-07-19 10:23:30 +00:00
|
|
|
const static int FADE_DURATION = 120; // Fade in/out time.
|
|
|
|
const static int FADE_WAIT = 200; // Time to wait between in/out.
|
2020-11-18 21:26:58 +00:00
|
|
|
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), 0,
|
2021-07-07 18:03:42 +00:00
|
|
|
[this, fadeFunc, fadeCallback, target] {
|
2021-08-15 17:30:31 +00:00
|
|
|
this->mCamera[3].x = -target.x;
|
|
|
|
this->mCamera[3].y = -target.y;
|
|
|
|
this->mCamera[3].z = -target.z;
|
2021-07-07 18:03:42 +00:00
|
|
|
updateHelpPrompts();
|
|
|
|
setAnimation(new LambdaAnimation(fadeFunc, FADE_DURATION), FADE_WAIT,
|
|
|
|
fadeCallback, true);
|
|
|
|
});
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Fast-forward animation if we're partway faded.
|
2021-08-15 17:30:31 +00:00
|
|
|
if (target == static_cast<glm::vec3>(-mCamera[3])) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// Not changing screens, so cancel the first half entirely.
|
|
|
|
advanceAnimation(0, FADE_DURATION);
|
|
|
|
advanceAnimation(0, FADE_WAIT);
|
2020-09-15 20:57:54 +00:00
|
|
|
advanceAnimation(0, FADE_DURATION - static_cast<int>(mFadeOpacity * FADE_DURATION));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-09-15 20:57:54 +00:00
|
|
|
advanceAnimation(0, static_cast<int>(mFadeOpacity * FADE_DURATION));
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (transition_style == "slide") {
|
2020-11-18 21:26:58 +00:00
|
|
|
auto slideCallback = [this]() {
|
|
|
|
if (mSkipView) {
|
|
|
|
mSkipView->onHide();
|
|
|
|
mSkipView.reset();
|
|
|
|
mSkipView = nullptr;
|
|
|
|
}
|
|
|
|
else if (mPreviousView) {
|
|
|
|
mPreviousView->onHide();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
setAnimation(new MoveCameraAnimation(mCamera, target), 0, slideCallback);
|
2020-06-21 12:25:28 +00:00
|
|
|
updateHelpPrompts(); // Update help prompts immediately.
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2020-10-27 18:07:35 +00:00
|
|
|
void ViewController::onFileChanged(FileData* file, bool reloadGameList)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
auto it = mGameListViews.find(file->getSystem());
|
|
|
|
if (it != mGameListViews.cend())
|
2020-10-27 18:07:35 +00:00
|
|
|
it->second->onFileChanged(file, reloadGameList);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2021-03-27 12:49:09 +00:00
|
|
|
bool ViewController::runInBackground(SystemData* system)
|
|
|
|
{
|
2021-06-30 15:19:57 +00:00
|
|
|
// Running in the background is required for Steam games as Steam itself may start together
|
|
|
|
// with the game. In that situation ES-DE would wait until the whole Steam application was
|
|
|
|
// shut down before it would resume. I.e. it would not be enough to just stop the game.
|
2021-03-27 12:49:09 +00:00
|
|
|
if (system->hasPlatformId(PlatformIds::VALVE_STEAM) ||
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("RunInBackground"))
|
2021-03-27 12:49:09 +00:00
|
|
|
return true;
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2020-11-17 16:30:23 +00:00
|
|
|
void ViewController::launch(FileData* game)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (game->getType() != GAME) {
|
2021-02-01 17:51:00 +00:00
|
|
|
LOG(LogError) << "Tried to launch something that isn't a game";
|
2020-06-21 12:25:28 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
// If the video view style is used, pause the video currently playing or block the
|
|
|
|
// video from starting to play if the static image is still shown.
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mCurrentView)
|
2020-09-15 20:57:54 +00:00
|
|
|
mCurrentView->onPauseVideo();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-09-17 20:00:07 +00:00
|
|
|
// Disable text scrolling. It will be enabled again in FileData upon returning from the game.
|
|
|
|
mWindow->setAllowTextScrolling(false);
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
stopAnimation(1); // Make sure the fade in isn't still playing.
|
|
|
|
mWindow->stopInfoPopup(); // Make sure we disable any existing info popup.
|
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
int duration = 0;
|
|
|
|
std::string durationString = Settings::getInstance()->getString("LaunchScreenDuration");
|
|
|
|
|
|
|
|
if (durationString == "disabled") {
|
|
|
|
// If the game launch screen has been set as disabled, show a simple info popup
|
|
|
|
// notification instead.
|
2021-07-07 18:03:42 +00:00
|
|
|
GuiInfoPopup* s = new GuiInfoPopup(
|
|
|
|
mWindow, "LAUNCHING GAME '" + Utils::String::toUpper(game->metadata.get("name") + "'"),
|
|
|
|
10000);
|
2021-06-14 17:15:22 +00:00
|
|
|
mWindow->setInfoPopup(s);
|
|
|
|
duration = 1700;
|
|
|
|
}
|
|
|
|
else if (durationString == "brief") {
|
|
|
|
duration = 1700;
|
|
|
|
}
|
|
|
|
else if (durationString == "long") {
|
|
|
|
duration = 4500;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
// Normal duration.
|
|
|
|
duration = 3000;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (durationString != "disabled")
|
|
|
|
mWindow->displayLaunchScreen(game->getSourceFileData());
|
2020-08-15 13:41:11 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
NavigationSounds::getInstance()->playThemeNavigationSound(LAUNCHSOUND);
|
2020-09-15 20:57:54 +00:00
|
|
|
|
2021-06-14 17:15:22 +00:00
|
|
|
// This is just a dummy animation in order for the launch screen or notification popup
|
|
|
|
// to be displayed briefly, and for the navigation sound playing to be able to complete.
|
2020-09-15 20:57:54 +00:00
|
|
|
// During this time period, all user input is blocked.
|
2021-07-07 18:03:42 +00:00
|
|
|
setAnimation(new LambdaAnimation([](float t) {}, duration), 0, [this, game] {
|
2020-07-19 20:08:14 +00:00
|
|
|
game->launchGame(mWindow);
|
2021-06-14 17:15:22 +00:00
|
|
|
// If the launch screen is disabled then this will do nothing.
|
|
|
|
mWindow->closeLaunchScreen();
|
2020-10-27 18:07:35 +00:00
|
|
|
onFileChanged(game, true);
|
2021-06-14 17:15:22 +00:00
|
|
|
// This is a workaround so that any keys or button presses used for exiting the emulator
|
|
|
|
// are not captured upon returning.
|
2021-07-07 18:03:42 +00:00
|
|
|
setAnimation(new LambdaAnimation([](float t) {}, 1), 0, [this] { mLockInput = false; });
|
2020-07-19 20:08:14 +00:00
|
|
|
});
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2017-07-18 09:45:50 +00:00
|
|
|
void ViewController::removeGameListView(SystemData* system)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
auto exists = mGameListViews.find(system);
|
|
|
|
if (exists != mGameListViews.cend()) {
|
|
|
|
exists->second.reset();
|
|
|
|
mGameListViews.erase(system);
|
|
|
|
}
|
2017-07-18 09:45:50 +00:00
|
|
|
}
|
|
|
|
|
2014-06-25 16:29:58 +00:00
|
|
|
std::shared_ptr<IGameListView> ViewController::getGameListView(SystemData* system)
|
|
|
|
{
|
2020-09-15 20:57:54 +00:00
|
|
|
// If we have already created an entry for this system, then return that one.
|
2020-06-21 12:25:28 +00:00
|
|
|
auto exists = mGameListViews.find(system);
|
|
|
|
if (exists != mGameListViews.cend())
|
|
|
|
return exists->second;
|
|
|
|
|
2021-01-05 09:45:32 +00:00
|
|
|
system->getIndex()->setKidModeFilters();
|
2020-09-15 20:57:54 +00:00
|
|
|
// If there's no entry, then create it and return it.
|
2020-06-21 12:25:28 +00:00
|
|
|
std::shared_ptr<IGameListView> view;
|
|
|
|
|
|
|
|
bool themeHasVideoView = system->getTheme()->hasView("video");
|
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
// Decide which view style to use.
|
2021-01-12 17:40:25 +00:00
|
|
|
GameListViewStyle selectedViewStyle = AUTOMATIC;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
std::string viewPreference = Settings::getInstance()->getString("GamelistViewStyle");
|
|
|
|
if (viewPreference.compare("basic") == 0)
|
2020-09-15 20:57:54 +00:00
|
|
|
selectedViewStyle = BASIC;
|
2020-06-21 12:25:28 +00:00
|
|
|
if (viewPreference.compare("detailed") == 0)
|
2020-09-15 20:57:54 +00:00
|
|
|
selectedViewStyle = DETAILED;
|
2020-06-21 12:25:28 +00:00
|
|
|
if (viewPreference.compare("grid") == 0)
|
2020-09-15 20:57:54 +00:00
|
|
|
selectedViewStyle = GRID;
|
2020-06-21 12:25:28 +00:00
|
|
|
if (viewPreference.compare("video") == 0)
|
2020-09-15 20:57:54 +00:00
|
|
|
selectedViewStyle = VIDEO;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
if (selectedViewStyle == AUTOMATIC) {
|
2020-06-21 12:25:28 +00:00
|
|
|
std::vector<FileData*> files = system->getRootFolder()->getFilesRecursive(GAME | FOLDER);
|
|
|
|
for (auto it = files.cbegin(); it != files.cend(); it++) {
|
|
|
|
if (themeHasVideoView && !(*it)->getVideoPath().empty()) {
|
2020-09-15 20:57:54 +00:00
|
|
|
selectedViewStyle = VIDEO;
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
|
|
|
}
|
2020-07-13 18:10:09 +00:00
|
|
|
else if (!(*it)->getImagePath().empty()) {
|
2020-09-15 20:57:54 +00:00
|
|
|
selectedViewStyle = DETAILED;
|
2020-06-21 12:25:28 +00:00
|
|
|
// Don't break out in case any subsequent files have videos.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create the view.
|
2021-07-07 18:03:42 +00:00
|
|
|
switch (selectedViewStyle) {
|
|
|
|
case VIDEO: {
|
2020-06-21 12:25:28 +00:00
|
|
|
view = std::shared_ptr<IGameListView>(
|
2021-07-07 18:03:42 +00:00
|
|
|
new VideoGameListView(mWindow, system->getRootFolder()));
|
2021-01-12 17:40:25 +00:00
|
|
|
mState.viewstyle = VIDEO;
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
|
|
|
case DETAILED: {
|
2020-06-21 12:25:28 +00:00
|
|
|
view = std::shared_ptr<IGameListView>(
|
2021-07-07 18:03:42 +00:00
|
|
|
new DetailedGameListView(mWindow, system->getRootFolder()));
|
2021-01-12 17:40:25 +00:00
|
|
|
mState.viewstyle = DETAILED;
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
|
|
|
case GRID: {
|
2020-06-21 12:25:28 +00:00
|
|
|
view = std::shared_ptr<IGameListView>(
|
2021-07-07 18:03:42 +00:00
|
|
|
new GridGameListView(mWindow, system->getRootFolder()));
|
2021-01-12 17:40:25 +00:00
|
|
|
mState.viewstyle = GRID;
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
|
|
|
case BASIC: {
|
|
|
|
}
|
|
|
|
default: {
|
2020-06-21 12:25:28 +00:00
|
|
|
view = std::shared_ptr<IGameListView>(
|
2021-07-07 18:03:42 +00:00
|
|
|
new BasicGameListView(mWindow, system->getRootFolder()));
|
2021-01-12 17:40:25 +00:00
|
|
|
mState.viewstyle = BASIC;
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
2021-07-07 18:03:42 +00:00
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
view->setTheme(system->getTheme());
|
|
|
|
|
|
|
|
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
|
2021-07-07 18:03:42 +00:00
|
|
|
int id = static_cast<int>(std::find(sysVec.cbegin(), sysVec.cend(), system) - sysVec.cbegin());
|
2020-09-15 20:57:54 +00:00
|
|
|
view->setPosition(id * static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight() * 2));
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
addChild(view.get());
|
|
|
|
|
|
|
|
mGameListViews[system] = view;
|
|
|
|
return view;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::shared_ptr<SystemView> ViewController::getSystemListView()
|
|
|
|
{
|
2020-09-15 20:57:54 +00:00
|
|
|
// If we have already created a system view entry, then return it.
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mSystemListView)
|
|
|
|
return mSystemListView;
|
|
|
|
|
|
|
|
mSystemListView = std::shared_ptr<SystemView>(new SystemView(mWindow));
|
|
|
|
addChild(mSystemListView.get());
|
2020-09-15 20:57:54 +00:00
|
|
|
mSystemListView->setPosition(0, static_cast<float>(Renderer::getScreenHeight()));
|
2020-06-21 12:25:28 +00:00
|
|
|
return mSystemListView;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ViewController::input(InputConfig* config, Input input)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mLockInput)
|
|
|
|
return true;
|
|
|
|
|
2021-06-30 15:19:57 +00:00
|
|
|
// For Steam games or if enabling the "RunInBackground" setting, ES-DE will run in the
|
|
|
|
// background while a game is launched. If we're in this state and then register some
|
|
|
|
// input, it means that the user is back in ES-DE. Therefore unset the game launch flag
|
|
|
|
// and update all the GUI components. This will re-enable the video player and let the
|
|
|
|
// screensaver start on schedule again.
|
2021-03-24 19:13:33 +00:00
|
|
|
if (mWindow->getGameLaunchedState())
|
|
|
|
mWindow->unsetLaunchedGame();
|
2020-07-18 11:21:44 +00:00
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
// Open the main menu.
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
2021-07-07 18:03:42 +00:00
|
|
|
!Settings::getInstance()->getBool("EnableMenuKidMode")) &&
|
|
|
|
config->isMappedTo("start", input) && input.value != 0) {
|
2020-06-21 12:25:28 +00:00
|
|
|
// If we don't stop the scrolling here, it will continue to
|
|
|
|
// run after closing the menu.
|
|
|
|
if (mSystemListView->isScrolling())
|
|
|
|
mSystemListView->stopScrolling();
|
|
|
|
// Finish the animation too, so that it doesn't continue
|
|
|
|
// to play when we've closed the menu.
|
|
|
|
if (mSystemListView->isAnimationPlaying(0))
|
|
|
|
mSystemListView->finishAnimation(0);
|
2020-09-13 17:08:17 +00:00
|
|
|
// Stop the gamelist scrolling as well as it would otherwise
|
|
|
|
// also continue to run after closing the menu.
|
2020-09-15 20:57:54 +00:00
|
|
|
mCurrentView->stopListScrolling();
|
|
|
|
// Finally, if the camera is currently moving, reset its position.
|
2020-11-16 16:44:33 +00:00
|
|
|
cancelViewTransitions();
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
mWindow->pushGui(new GuiMenu(mWindow));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if UI mode has changed due to passphrase completion.
|
|
|
|
if (UIModeController::getInstance()->listen(config, input))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (mCurrentView)
|
|
|
|
return mCurrentView->input(config, input);
|
|
|
|
|
|
|
|
return false;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::update(int deltaTime)
|
|
|
|
{
|
2021-06-22 16:08:20 +00:00
|
|
|
if (mWindow->getChangedThemeSet())
|
|
|
|
cancelViewTransitions();
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (mCurrentView)
|
|
|
|
mCurrentView->update(deltaTime);
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
updateSelf(deltaTime);
|
2020-11-17 16:30:23 +00:00
|
|
|
|
|
|
|
if (mGameToLaunch) {
|
|
|
|
launch(mGameToLaunch);
|
|
|
|
mGameToLaunch = nullptr;
|
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
2021-08-15 17:30:31 +00:00
|
|
|
void ViewController::render(const glm::mat4& parentTrans)
|
2014-06-25 16:29:58 +00:00
|
|
|
{
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::mat4 trans{mCamera * parentTrans};
|
|
|
|
glm::mat4 transInverse{glm::inverse(trans)};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Camera position, position + size.
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec3 viewStart{transInverse[3]};
|
|
|
|
glm::vec3 viewEnd{std::fabs(trans[3].x) + static_cast<float>(Renderer::getScreenWidth()),
|
|
|
|
std::fabs(trans[3].y) + static_cast<float>(Renderer::getScreenHeight()),
|
|
|
|
0.0f};
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Keep track of UI mode changes.
|
|
|
|
UIModeController::getInstance()->monitorUIMode();
|
|
|
|
|
2020-11-18 22:47:32 +00:00
|
|
|
// Render the system view if it's the currently displayed view, or if we're in the progress
|
|
|
|
// of transitioning to or from this view.
|
|
|
|
if (mSystemListView == mCurrentView || (mSystemViewTransition && isCameraMoving()))
|
2020-09-15 20:57:54 +00:00
|
|
|
getSystemListView()->render(trans);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
// Draw the gamelists.
|
2020-06-21 12:25:28 +00:00
|
|
|
for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++) {
|
2020-09-15 20:57:54 +00:00
|
|
|
// Same thing as for the system view, limit the rendering only to what needs to be drawn.
|
2020-11-18 22:47:32 +00:00
|
|
|
if (it->second == mCurrentView || (it->second == mPreviousView && isCameraMoving())) {
|
2020-09-15 20:57:54 +00:00
|
|
|
// Clipping.
|
2021-08-17 16:41:45 +00:00
|
|
|
glm::vec3 guiStart{it->second->getPosition()};
|
|
|
|
glm::vec3 guiEnd{it->second->getPosition() +
|
|
|
|
glm::vec3{it->second->getSize().x, it->second->getSize().y, 0.0f}};
|
2020-09-15 20:57:54 +00:00
|
|
|
|
2021-08-15 17:30:31 +00:00
|
|
|
if (guiEnd.x >= viewStart.x && guiEnd.y >= viewStart.y && guiStart.x <= viewEnd.x &&
|
|
|
|
guiStart.y <= viewEnd.y)
|
2020-09-15 20:57:54 +00:00
|
|
|
it->second->render(trans);
|
|
|
|
}
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (mWindow->peekGui() == this)
|
|
|
|
mWindow->renderHelpPromptsEarly();
|
|
|
|
|
|
|
|
// Fade out.
|
|
|
|
if (mFadeOpacity) {
|
2020-09-15 20:57:54 +00:00
|
|
|
unsigned int fadeColor = 0x00000000 | static_cast<unsigned char>(mFadeOpacity * 255);
|
2020-06-21 12:25:28 +00:00
|
|
|
Renderer::setMatrix(parentTrans);
|
2020-12-29 11:54:24 +00:00
|
|
|
Renderer::drawRect(0.0f, 0.0f, static_cast<float>(Renderer::getScreenWidth()),
|
2021-07-07 18:03:42 +00:00
|
|
|
static_cast<float>(Renderer::getScreenHeight()), fadeColor, fadeColor);
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::preload()
|
|
|
|
{
|
2020-12-29 11:54:24 +00:00
|
|
|
unsigned int systemCount = static_cast<int>(SystemData::sSystemVector.size());
|
2020-09-15 20:57:54 +00:00
|
|
|
|
2021-07-07 18:03:42 +00:00
|
|
|
for (auto it = SystemData::sSystemVector.cbegin(); it != SystemData::sSystemVector.cend();
|
|
|
|
it++) {
|
2020-06-21 12:25:28 +00:00
|
|
|
if (Settings::getInstance()->getBool("SplashScreen") &&
|
2021-07-07 18:03:42 +00:00
|
|
|
Settings::getInstance()->getBool("SplashScreenProgress")) {
|
|
|
|
mWindow->renderLoadingScreen(
|
|
|
|
"Loading '" + (*it)->getFullName() + "' (" +
|
|
|
|
std::to_string(std::distance(SystemData::sSystemVector.cbegin(), it) + 1) + "/" +
|
|
|
|
std::to_string(systemCount) + ")");
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
(*it)->getIndex()->resetFilters();
|
|
|
|
getGameListView(*it);
|
|
|
|
}
|
2021-03-21 14:42:13 +00:00
|
|
|
|
|
|
|
// Load navigation sounds, either from the theme if it supports it, or otherwise from
|
|
|
|
// the bundled fallback sound files.
|
|
|
|
bool themeSoundSupport = false;
|
|
|
|
for (SystemData* system : SystemData::sSystemVector) {
|
|
|
|
if (system->getTheme()->hasView("all")) {
|
|
|
|
NavigationSounds::getInstance()->loadThemeNavigationSounds(system->getTheme());
|
|
|
|
themeSoundSupport = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!SystemData::sSystemVector.empty() && !themeSoundSupport)
|
|
|
|
NavigationSounds::getInstance()->loadThemeNavigationSounds(nullptr);
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::reloadGameListView(IGameListView* view, bool reloadTheme)
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++) {
|
|
|
|
if (it->second.get() == view) {
|
|
|
|
bool isCurrent = (mCurrentView == it->second);
|
|
|
|
SystemData* system = it->first;
|
|
|
|
FileData* cursor = view->getCursor();
|
2020-12-20 11:07:02 +00:00
|
|
|
|
|
|
|
// Retain the cursor history for the view.
|
|
|
|
std::vector<FileData*> cursorHistoryTemp;
|
|
|
|
it->second->copyCursorHistory(cursorHistoryTemp);
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
mGameListViews.erase(it);
|
|
|
|
|
2021-03-01 17:50:12 +00:00
|
|
|
if (isCurrent)
|
|
|
|
mCurrentView = nullptr;
|
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
if (reloadTheme)
|
|
|
|
system->loadTheme();
|
2021-01-05 09:45:32 +00:00
|
|
|
system->getIndex()->setKidModeFilters();
|
2020-06-21 12:25:28 +00:00
|
|
|
std::shared_ptr<IGameListView> newView = getGameListView(system);
|
|
|
|
|
|
|
|
// To counter having come from a placeholder.
|
|
|
|
if (!cursor->isPlaceHolder()) {
|
|
|
|
newView->setCursor(cursor);
|
|
|
|
}
|
|
|
|
if (isCurrent)
|
|
|
|
mCurrentView = newView;
|
|
|
|
|
2020-12-20 11:07:02 +00:00
|
|
|
newView->populateCursorHistory(cursorHistoryTemp);
|
2020-06-21 12:25:28 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-07-18 11:21:44 +00:00
|
|
|
|
2021-06-30 15:19:57 +00:00
|
|
|
// For Steam games or if enabling the "RunInBackground" setting, ES-DE will run in the
|
|
|
|
// background while a game is launched. If this flag has been set, then update all the
|
|
|
|
// GUI components. This will disable the video player and prevent the screensaver from
|
|
|
|
// starting on schedule.
|
2021-03-24 19:13:33 +00:00
|
|
|
if (mWindow->getGameLaunchedState())
|
|
|
|
mWindow->setLaunchedGame();
|
2020-07-18 11:21:44 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
// Redisplay the current view.
|
2020-11-18 22:47:32 +00:00
|
|
|
if (mCurrentView)
|
2020-06-21 12:25:28 +00:00
|
|
|
mCurrentView->onShow();
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void ViewController::reloadAll()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
// Clear all GameListViews.
|
|
|
|
std::map<SystemData*, FileData*> cursorMap;
|
|
|
|
for (auto it = mGameListViews.cbegin(); it != mGameListViews.cend(); it++)
|
|
|
|
cursorMap[it->first] = it->second->getCursor();
|
|
|
|
|
|
|
|
mGameListViews.clear();
|
2021-03-01 17:50:12 +00:00
|
|
|
mCurrentView = nullptr;
|
2020-06-21 12:25:28 +00:00
|
|
|
|
|
|
|
// Load themes, create GameListViews and reset filters.
|
|
|
|
for (auto it = cursorMap.cbegin(); it != cursorMap.cend(); it++) {
|
|
|
|
it->first->loadTheme();
|
|
|
|
it->first->getIndex()->resetFilters();
|
|
|
|
getGameListView(it->first)->setCursor(it->second);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Rebuild SystemListView.
|
|
|
|
mSystemListView.reset();
|
|
|
|
getSystemListView();
|
|
|
|
|
|
|
|
// Update mCurrentView since the pointers changed.
|
|
|
|
if (mState.viewing == GAME_LIST) {
|
|
|
|
mCurrentView = getGameListView(mState.getSystem());
|
|
|
|
}
|
|
|
|
else if (mState.viewing == SYSTEM_SELECT) {
|
|
|
|
SystemData* system = mState.getSystem();
|
|
|
|
mSystemListView->goToSystem(system, false);
|
|
|
|
mCurrentView = mSystemListView;
|
2021-08-15 17:30:31 +00:00
|
|
|
mCamera[3].x = 0.0f;
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-11-15 21:54:39 +00:00
|
|
|
goToSystemView(SystemData::sSystemVector.front(), false);
|
2020-06-21 12:25:28 +00:00
|
|
|
}
|
|
|
|
|
2021-03-21 14:42:13 +00:00
|
|
|
// Load navigation sounds, either from the theme if it supports it, or otherwise from
|
|
|
|
// the bundled fallback sound files.
|
2020-06-21 12:25:28 +00:00
|
|
|
NavigationSounds::getInstance()->deinit();
|
2021-03-21 14:42:13 +00:00
|
|
|
bool themeSoundSupport = false;
|
|
|
|
for (SystemData* system : SystemData::sSystemVector) {
|
|
|
|
if (system->getTheme()->hasView("all")) {
|
|
|
|
NavigationSounds::getInstance()->loadThemeNavigationSounds(system->getTheme());
|
|
|
|
themeSoundSupport = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!SystemData::sSystemVector.empty() && !themeSoundSupport)
|
|
|
|
NavigationSounds::getInstance()->loadThemeNavigationSounds(nullptr);
|
2020-06-21 12:25:28 +00:00
|
|
|
|
2020-09-15 20:57:54 +00:00
|
|
|
mCurrentView->onShow();
|
2020-06-21 12:25:28 +00:00
|
|
|
updateHelpPrompts();
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<HelpPrompt> ViewController::getHelpPrompts()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
std::vector<HelpPrompt> prompts;
|
|
|
|
if (!mCurrentView)
|
|
|
|
return prompts;
|
|
|
|
|
|
|
|
prompts = mCurrentView->getHelpPrompts();
|
|
|
|
if (!(UIModeController::getInstance()->isUIModeKid() &&
|
2021-07-07 18:03:42 +00:00
|
|
|
!Settings::getInstance()->getBool("EnableMenuKidMode")))
|
2020-06-21 12:25:28 +00:00
|
|
|
prompts.push_back(HelpPrompt("start", "menu"));
|
|
|
|
return prompts;
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
HelpStyle ViewController::getHelpStyle()
|
|
|
|
{
|
2020-06-21 12:25:28 +00:00
|
|
|
if (!mCurrentView)
|
|
|
|
return GuiComponent::getHelpStyle();
|
2014-06-25 16:29:58 +00:00
|
|
|
|
2020-06-21 12:25:28 +00:00
|
|
|
return mCurrentView->getHelpStyle();
|
2014-06-25 16:29:58 +00:00
|
|
|
}
|