Merge pull request #295 from zigurana/UIModeController

[Ready to Merge] UIModeController Class
This commit is contained in:
Jools Wills 2017-11-25 13:38:16 +00:00 committed by GitHub
commit ca046f75f1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 263 additions and 118 deletions

View file

@ -50,6 +50,7 @@ set(ES_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/VideoGameListView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemView.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/ViewController.h
${CMAKE_CURRENT_SOURCE_DIR}/src/views/UIModeController.h
# Animations
${CMAKE_CURRENT_SOURCE_DIR}/src/animations/LaunchAnimation.h
@ -106,6 +107,7 @@ set(ES_SOURCES
${CMAKE_CURRENT_SOURCE_DIR}/src/views/gamelist/VideoGameListView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/SystemView.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/ViewController.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/views/UIModeController.cpp
)
#-------------------------------------------------------------------------------

View file

@ -1,9 +1,9 @@
#include "FileFilterIndex.h"
#include "Settings.h"
#include "views/ViewController.h"
#include "views/UIModeController.h"
#include "FileData.h"
#include "Log.h"
#include "Settings.h"
#include "Util.h"
#include <boost/algorithm/string/trim.hpp>
@ -248,13 +248,13 @@ void FileFilterIndex::resetFilters()
void FileFilterIndex::setUIModeFilters()
{
if (!ViewController::get()->isUIModeFull())
if (!UIModeController::getInstance()->isUIModeFull())
{
filterByHidden = true;
std::vector<std::string> val = { "FALSE" };
setFilter(HIDDEN_FILTER, &val);
}
if (ViewController::get()->isUIModeKid())
if (UIModeController::getInstance()->isUIModeKid())
{
filterByKidGame = true;
std::vector<std::string> val = { "TRUE" };

View file

@ -1,7 +1,7 @@
#include "guis/GuiGamelistFilter.h"
#include "components/OptionListComponent.h"
#include "views/ViewController.h"
#include "views/UIModeController.h"
#include "SystemData.h"
GuiGamelistFilter::GuiGamelistFilter(Window* window, SystemData* system) : GuiComponent(window), mMenu(window, "FILTER GAMELIST BY"), mSystem(system)
@ -52,9 +52,9 @@ void GuiGamelistFilter::addFiltersToMenu()
std::vector<FilterDataDecl> decls = mFilterIndex->getFilterDataDecls();
int skip = 0;
if (!ViewController::get()->isUIModeFull())
if (!UIModeController::getInstance()->isUIModeFull())
skip = 1;
if (ViewController::get()->isUIModeKid())
if (UIModeController::getInstance()->isUIModeKid())
skip = 2;
for (std::vector<FilterDataDecl>::const_iterator it = decls.cbegin(); it != decls.cend()-skip; ++it ) {

View file

@ -3,6 +3,7 @@
#include "guis/GuiGamelistFilter.h"
#include "scrapers/Scraper.h"
#include "views/gamelist/IGameListView.h"
#include "views/UIModeController.h"
#include "views/ViewController.h"
#include "CollectionSystemManager.h"
#include "FileFilterIndex.h"
@ -84,7 +85,7 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
std::map<std::string, CollectionSystemData> customCollections = CollectionSystemManager::get()->getCustomCollectionSystems();
if(ViewController::get()->isUIModeFull() &&
if(UIModeController::getInstance()->isUIModeFull() &&
((customCollections.find(system->getName()) != customCollections.cend() && CollectionSystemManager::get()->getEditingCollection() != system->getName()) ||
CollectionSystemManager::get()->getCustomCollectionsBundle()->getName() == system->getName()))
{
@ -94,7 +95,7 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
mMenu.addRow(row);
}
if(ViewController::get()->isUIModeFull() && CollectionSystemManager::get()->isEditing())
if(UIModeController::getInstance()->isUIModeFull() && CollectionSystemManager::get()->isEditing())
{
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "FINISH EDITING '" + strToUpper(CollectionSystemManager::get()->getEditingCollection()) + "' COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
@ -102,7 +103,7 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
mMenu.addRow(row);
}
if (ViewController::get()->isUIModeFull() && !fromPlaceholder && !(mSystem->isCollection() && file->getType() == FOLDER))
if (UIModeController::getInstance()->isUIModeFull() && !fromPlaceholder && !(mSystem->isCollection() && file->getType() == FOLDER))
{
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "EDIT THIS GAME'S METADATA", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);

View file

@ -9,6 +9,7 @@
#include "guis/GuiMsgBox.h"
#include "guis/GuiScraperStart.h"
#include "guis/GuiSettings.h"
#include "views/UIModeController.h"
#include "views/ViewController.h"
#include "CollectionSystemManager.h"
#include "EmulationStation.h"
@ -18,7 +19,7 @@
GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MENU"), mVersion(window)
{
bool isFullUI = ViewController::get()->isUIModeFull();
bool isFullUI = UIModeController::getInstance()->isUIModeFull();
if (isFullUI)
addEntry("SCRAPER", 0x777777FF, true, [this] { openScraperSettings(); });
@ -38,7 +39,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
if (isFullUI)
addEntry("CONFIGURE INPUT", 0x777777FF, true, [this] { openConfigInput(); });
if (!(ViewController::get()->isUIModeKid() && Settings::getInstance()->getBool("hideQuitMenuOnKidUI")))
if (!(UIModeController::getInstance()->isUIModeKid() && Settings::getInstance()->getBool("hideQuitMenuOnKidUI")))
addEntry("QUIT", 0x777777FF, true, [this] {openQuitMenu(); });
addChild(&mMenu);
@ -92,7 +93,7 @@ void GuiMenu::openSoundSettings()
s->addWithLabel("SYSTEM VOLUME", volume);
s->addSaveFunc([volume] { VolumeControl::getInstance()->setVolume((int)Math::round(volume->getValue())); });
if (ViewController::get()->isUIModeFull())
if (UIModeController::getInstance()->isUIModeFull())
{
#ifdef _RPI_
// volume control device
@ -161,7 +162,7 @@ void GuiMenu::openUISettings()
//UI mode
auto UImodeSelection = std::make_shared< OptionListComponent<std::string> >(mWindow, "UI MODE", false);
std::vector<std::string> UImodes = ViewController::get()->getUIModes();
std::vector<std::string> UImodes = UIModeController::getInstance()->getUIModes();
for (auto it = UImodes.cbegin(); it != UImodes.cend(); it++)
UImodeSelection->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it);
s->addWithLabel("UI MODE", UImodeSelection);
@ -174,14 +175,14 @@ void GuiMenu::openUISettings()
std::string msg = "You are changing the UI to a restricted mode:\n" + selectedMode + "\n";
msg += "This will hide most menu-options to prevent changes to the system.\n";
msg += "To unlock and return to the full UI, enter this code: \n";
msg += "Up, up, down, down, left, right, left, right, B, A. \n\n";
msg += "\"" + UIModeController::getInstance()->getFormattedPassKeyStr() + "\"\n\n";
msg += "Do you want to proceed?";
window->pushGui(new GuiMsgBox(window, msg, "YES",
[selectedMode] {
LOG(LogDebug) << "Setting UI mode to" << selectedMode;
window->pushGui(new GuiMsgBox(window, msg,
"YES", [selectedMode] {
LOG(LogDebug) << "Setting UI mode to " << selectedMode;
Settings::getInstance()->setString("UIMode", selectedMode);
}, "NO", nullptr));
Settings::getInstance()->saveFile();
}, "NO",nullptr));
}
});
@ -407,7 +408,7 @@ void GuiMenu::openQuitMenu()
Window* window = mWindow;
ComponentListRow row;
if (ViewController::get()->isUIModeFull())
if (UIModeController::getInstance()->isUIModeFull())
{
row.makeAcceptInputHandler([window] {
window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES",

View file

@ -2,6 +2,7 @@
#include "animations/LambdaAnimation.h"
#include "guis/GuiMsgBox.h"
#include "views/UIModeController.h"
#include "views/ViewController.h"
#include "Log.h"
#include "Renderer.h"
@ -113,7 +114,7 @@ void SystemView::populate()
if (mEntries.size() == 0)
{
// Something is wrong, there is not a single system to show, check if UI mode is not full
if (!ViewController::get()->isUIModeFull())
if (!UIModeController::getInstance()->isUIModeFull())
{
Settings::getInstance()->setString("UIMode", "Full");
mWindow->pushGui(new GuiMsgBox(mWindow, "The selected UI mode has nothing to show,\n returning to UI mode: FULL", "OK", nullptr));

View file

@ -0,0 +1,162 @@
#include "UIModeController.h"
#include "utils/StringUtil.h"
#include "views/ViewController.h"
#include "Log.h"
#include "Window.h"
UIModeController * UIModeController::sInstance = NULL;
UIModeController * UIModeController::getInstance()
{
if (sInstance == NULL)
sInstance = new UIModeController();
return sInstance;
}
UIModeController::UIModeController()
:mPassKeyCounter(0)
{
mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey");
mCurrentUIMode = Settings::getInstance()->getString("UIMode");
}
void UIModeController::monitorUIMode()
{
std::string uimode = Settings::getInstance()->getString("UIMode");
if (uimode != mCurrentUIMode) // UIMODE HAS CHANGED
{
mCurrentUIMode = uimode;
ViewController::get()->ReloadAndGoToStart();
}
}
bool UIModeController::listen(InputConfig * config, Input input)
{
// Reads the current input to listen for the passkey
// sequence to unlock the UI mode. The progress is saved in mPassKeyCounter
if (Settings::getInstance()->getBool("Debug"))
{
logInput(config, input);
}
if ((Settings::getInstance()->getString("UIMode") == "Full") || !isValidInput(config, input))
{
return false; // Already unlocked, or invalid input, nothing to do here.
}
if (!inputIsMatch(config, input))
{
mPassKeyCounter = 0; // current input is incorrect, reset counter
}
if (mPassKeyCounter == (mPassKeySequence.length()))
{
unlockUIMode();
return true;
}
return false;
}
bool UIModeController::inputIsMatch(InputConfig * config, Input input)
{
for (auto valstring : mInputVals)
{
if (config->isMappedTo(valstring, input) &&
(mPassKeySequence[mPassKeyCounter] == valstring[0]))
{
mPassKeyCounter++;
return true;
}
}
return false;
}
// When we have reached the end of the list, trigger UI_mode unlock
void UIModeController::unlockUIMode()
{
LOG(LogDebug) << " UIModeController::listen(): Passkey sequence completed, switching UIMode to full";
Settings::getInstance()->setString("UIMode", "Full");
Settings::getInstance()->saveFile();
mPassKeyCounter = 0;
}
bool UIModeController::isUIModeFull()
{
return ((mCurrentUIMode == "Full") && !Settings::getInstance()->getBool("ForceKiosk"));
}
bool UIModeController::isUIModeKid()
{
return (Settings::getInstance()->getBool("ForceKid") ||
((mCurrentUIMode == "Kid") && !Settings::getInstance()->getBool("ForceKiosk")));
}
std::string UIModeController::getFormattedPassKeyStr()
{
// supported sequence-inputs: u (up), d (down), l (left), r (right), a, b, x, y
std::string out = "";
for (auto c : mPassKeySequence)
{
out += (out == "") ? "" : ", "; // add a comma after the first entry
switch (c)
{
case 'u':
out += Utils::String::unicode2Chars(0x2191); // arrow pointing up
break;
case 'd':
out += Utils::String::unicode2Chars(0x2193); // arrow pointing down
break;
case 'l':
out += Utils::String::unicode2Chars(0x2190); // arrow pointing left
break;
case 'r':
out += Utils::String::unicode2Chars(0x2192); // arrow pointing right
break;
case 'a':
out += "A";
break;
case 'b':
out += "B";
break;
case 'x':
out += "X";
break;
case 'y':
out += "Y";
break;
}
}
return out;
}
void UIModeController::logInput(InputConfig * config, Input input)
{
std::string mapname = "";
std::vector<std::string> maps = config->getMappedTo(input);
for( auto mn : maps)
{
mapname += mn;
mapname += ", ";
}
LOG(LogDebug) << "UIModeController::logInput( " << config->getDeviceName() <<" ):" << input.string() << ", isMappedTo= " << mapname << ", value=" << input.value;
}
bool UIModeController::isValidInput(InputConfig * config, Input input)
{
if((config->getMappedTo(input).size() == 0) || // not a mapped input, so ignore.
(input.type == TYPE_HAT) || // ignore all HAT inputs
(!input.value)) // not a key-down event
{
return false;
}
else
{
return true;
}
}

View file

@ -0,0 +1,50 @@
#pragma once
#ifndef ES_APP_VIEWS_UI_MODE_CONTROLLER_H
#define ES_APP_VIEWS_UI_MODE_CONTROLLER_H
//#include "InputConfig.h"
#include <vector>
#include <string>
class FileData;
class InputConfig;
class ViewController;
struct Input;
class UIModeController {
public:
static UIModeController* getInstance();
// Monitor input for UI mode change, returns true (consumes input) when UI mode change is triggered.
bool listen(InputConfig* config, Input input);
// Get the current Passphrase as a (unicode) formatted, comma-separated, string.
std::string getFormattedPassKeyStr();
// Check for change in UI mode.
void monitorUIMode();
bool isUIModeFull();
bool isUIModeKid();
inline std::vector<std::string> getUIModes() { return mUIModes; };
private:
UIModeController();
bool inputIsMatch(InputConfig * config, Input input);
bool isValidInput(InputConfig * config, Input input);
void logInput(InputConfig * config, Input input);
// Return UI mode to 'FULL'
void unlockUIMode();
static UIModeController * sInstance;
const std::vector<std::string> mUIModes = { "Full", "Kiosk", "Kid" };
// default passkeyseq = "uuddlrlrba", as defined in the setting 'UIMode_passkey'.
std::string mPassKeySequence;
int mPassKeyCounter;
const std::vector<std::string> mInputVals = { "up", "down", "left", "right", "a", "b", "x", "y" };
std::string mCurrentUIMode;
};
#endif // ES_APP_VIEWS_UI_MODE_CONTROLLER_H

View file

@ -9,6 +9,7 @@
#include "views/gamelist/IGameListView.h"
#include "views/gamelist/VideoGameListView.h"
#include "views/SystemView.h"
#include "views/UIModeController.h"
#include "FileFilterIndex.h"
#include "Log.h"
#include "Settings.h"
@ -33,7 +34,6 @@ ViewController::ViewController(Window* window)
: GuiComponent(window), mCurrentView(nullptr), mCamera(Transform4x4f::Identity()), mFadeOpacity(0), mLockInput(false)
{
mState.viewing = NOTHING;
mCurUIMode = Settings::getInstance()->getString("UIMode");
}
ViewController::~ViewController()
@ -59,6 +59,13 @@ void ViewController::goToStart()
goToSystemView(SystemData::sSystemVector.at(0));
}
void ViewController::ReloadAndGoToStart()
{
mWindow->renderLoadingScreen();
ViewController::get()->reloadAll();
ViewController::get()->goToStart();
}
int ViewController::getSystemId(SystemData* system)
{
std::vector<SystemData*>& sysVec = SystemData::sSystemVector;
@ -353,6 +360,11 @@ bool ViewController::input(InputConfig* config, Input input)
return true;
}
if(UIModeController::getInstance()->listen(config, input)) // check if UI mode has changed due to passphrase completion
{
return true;
}
if(mCurrentView)
return mCurrentView->input(config, input);
@ -380,7 +392,7 @@ void ViewController::render(const Transform4x4f& parentTrans)
Vector3f viewEnd = transInverse * Vector3f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), 0);
// Keep track of UI mode changes.
monitorUIMode();
UIModeController::getInstance()->monitorUIMode();
// draw systemview
getSystemListView()->render(trans);
@ -488,29 +500,6 @@ void ViewController::reloadAll()
updateHelpPrompts();
}
void ViewController::monitorUIMode()
{
std::string uimode = Settings::getInstance()->getString("UIMode");
if (uimode != mCurUIMode) // UIMODE HAS CHANGED
{
mWindow->renderLoadingScreen();
mCurUIMode = uimode;
reloadAll();
goToStart();
}
}
bool ViewController::isUIModeFull()
{
return ((mCurUIMode == "Full") && ! Settings::getInstance()->getBool("ForceKiosk"));
}
bool ViewController::isUIModeKid()
{
return (Settings::getInstance()->getBool("ForceKid") ||
((mCurUIMode == "Kid") && !Settings::getInstance()->getBool("ForceKiosk")));
}
std::vector<HelpPrompt> ViewController::getHelpPrompts()
{
std::vector<HelpPrompt> prompts;

View file

@ -11,8 +11,6 @@ class IGameListView;
class SystemData;
class SystemView;
const std::vector<std::string> UIModes = { "Full", "Kiosk", "Kid" };
// Used to smoothly transition the camera between multiple views (e.g. from system to system, from gamelist to gamelist).
class ViewController : public GuiComponent
{
@ -32,17 +30,13 @@ public:
inline void reloadGameListView(SystemData* system, bool reloadTheme = false) { reloadGameListView(getGameListView(system).get(), reloadTheme); }
void reloadAll(); // Reload everything with a theme. Used when the "ThemeSet" setting changes.
void monitorUIMode();
inline std::vector<std::string> getUIModes() { return UIModes; };
bool isUIModeFull();
bool isUIModeKid();
// Navigation.
void goToNextGameList();
void goToPrevGameList();
void goToGameList(SystemData* system);
void goToSystemView(SystemData* system);
void goToStart();
void ReloadAndGoToStart();
void onFileChanged(FileData* file, FileChangeType change);
@ -107,7 +101,6 @@ private:
bool mLockInput;
State mState;
std::string mCurUIMode;
};
#endif // ES_APP_VIEWS_VIEW_CONTROLLER_H

View file

@ -1,5 +1,6 @@
#include "views/gamelist/BasicGameListView.h"
#include "views/UIModeController.h"
#include "views/ViewController.h"
#include "CollectionSystemManager.h"
#include "Settings.h"
@ -141,7 +142,7 @@ std::vector<HelpPrompt> BasicGameListView::getHelpPrompts()
prompts.push_back(HelpPrompt("b", "back"));
prompts.push_back(HelpPrompt("select", "options"));
prompts.push_back(HelpPrompt("x", "random"));
if(mRoot->getSystem()->isGameSystem() && !ViewController::get()->isUIModeKid())
if(mRoot->getSystem()->isGameSystem() && !UIModeController::getInstance()->isUIModeKid())
{
std::string prompt = CollectionSystemManager::get()->getEditingCollection();
prompts.push_back(HelpPrompt("y", prompt));

View file

@ -1,5 +1,6 @@
#include "views/gamelist/ISimpleGameListView.h"
#include "views/UIModeController.h"
#include "views/ViewController.h"
#include "CollectionSystemManager.h"
#include "Settings.h"
@ -142,7 +143,7 @@ bool ISimpleGameListView::input(InputConfig* config, Input input)
setCursor(randomGame);
}
return true;
}else if (config->isMappedTo("y", input) && !(ViewController::get()->isUIModeKid()))
}else if (config->isMappedTo("y", input) && !(UIModeController::getInstance()->isUIModeKid()))
{
if(mRoot->getSystem()->isGameSystem())
{

View file

@ -146,6 +146,7 @@ void saveMap(pugi::xml_document& doc, std::map<K, V>& map, const char* type)
void Settings::saveFile()
{
LOG(LogDebug) << "Settings::saveFile() : Saving Settings to file.";
const std::string path = getHomePath() + "/.emulationstation/es_settings.cfg";
pugi::xml_document doc;

View file

@ -14,7 +14,6 @@ Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCoun
{
mHelp = new HelpComponent(this);
mBackgroundOverlay = new ImageComponent(this);
mPassKeyListener = new PassKeyListener;
}
Window::~Window()
@ -171,8 +170,7 @@ void Window::input(InputConfig* config, Input input)
}
else
{
if (!mPassKeyListener->isUIModeChanged(config, input, this) && // check if UI mode has changed due to passphrase completion
peekGui())
if (peekGui())
{
this->peekGui()->input(config, input); // this is where the majority of inputs will be consumed: the GuiComponent Stack
}
@ -438,44 +436,3 @@ void Window::startScreenSaver()
if (mScreenSaver)
mScreenSaver->renderScreenSaver();
}
bool Window::PassKeyListener::isUIModeChanged(InputConfig * config, Input input, Window* /*window*/)
{
// This function reads the current input to listen for the passkey
// sequence to unlock the UI mode. The progress is saved in mPassKeyCounter
// supported sequence-inputs: u (up), d (down), l (left), r (right), a, b, x, y
// default passkeyseq = "uuddlrlrba", as defined in the setting 'UIMode_passkey'.
if ((Settings::getInstance()->getString("UIMode") == "Full") || (!input.value))
{
return false; // Already unlocked, or no keydown, nothing to do here.
}
bool foundMatch = false;
for (auto valstring : mInputVals)
{
if (config->isMappedTo(valstring, input) &&
(this->mPassKeySequence[this->mPassKeyCounter] == valstring[0]))
{
this->mPassKeyCounter ++;
foundMatch = true;
}
}
if (!foundMatch)
{
this->mPassKeyCounter = 0; // current input is incorrect, reset counter
}
if (this->mPassKeyCounter == (int)(this->mPassKeySequence.length()))
{
// When we have reached the end of the list, trigger UI_mode unlock
LOG(LogDebug) << " Window::PassKeyListener::isUIModeChanged(): Passkey sequence completed, switching UIMode to full";
Settings::getInstance()->setString("UIMode", "Full");
Settings::getInstance()->saveFile();
this->mPassKeyCounter = 0;
return true;
}
return false;
}

View file

@ -41,20 +41,6 @@ public:
virtual ~InfoPopup() {};
};
class PassKeyListener {
public:
bool isUIModeChanged(InputConfig* config, Input input, Window* window);
PassKeyListener()
{
mPassKeySequence = Settings::getInstance()->getString("UIMode_passkey");
mPassKeyCounter = 0;
}
private:
std::string mPassKeySequence;
int mPassKeyCounter;
const std::vector<std::string> mInputVals = { "up", "down", "left", "right", "a", "b", "x", "y" };
};
Window();
~Window();
@ -102,7 +88,6 @@ private:
ScreenSaver* mScreenSaver;
InfoPopup* mInfoPopup;
bool mRenderScreenSaver;
PassKeyListener* mPassKeyListener;
std::vector<GuiComponent*> mGuiStack;

View file

@ -257,8 +257,9 @@ std::vector<std::string> getFallbackFontPaths()
#else
// Linux
// TODO
const char* paths[] = {
const char* paths[] = {
"/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
"/usr/share/fonts/truetype/freefont/FreeMono.ttf",
"/usr/share/fonts/truetype/droid/DroidSansFallbackFull.ttf" // japanese, chinese, present on Debian
};