Merge pull request #235 from zigurana/KioskMode

Introducing Kiosk Mode, hiding certain menu items from the UI.
This commit is contained in:
Jools Wills 2017-09-28 18:55:14 +01:00 committed by GitHub
commit 99c1ddb260
10 changed files with 489 additions and 345 deletions

View file

@ -103,6 +103,9 @@ You can use `--help` or `-h` to view a list of command-line options. Briefly out
--windowed - run ES in a window, works best in conjunction with --resolution [w] [h].
--vsync [1/on or 0/off] - turn vsync on or off (default is on).
--scrape - run the interactive command-line metadata scraper.
--no-splash - don't show the splash screen.
--max-vram [size] - Max VRAM to use in Mb before swapping. 0 for unlimited.
--force-kiosk - Force the UI mode to be Kiosk.
```
As long as ES hasn't frozen, you can always press F4 to close the application.

View file

@ -1,6 +1,7 @@
#include "GuiGamelistOptions.h"
#include "GuiMetaDataEd.h"
#include "Util.h"
#include "Settings.h"
#include "views/gamelist/IGameListView.h"
#include "views/ViewController.h"
#include "CollectionSystemManager.h"
@ -64,8 +65,10 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
mMenu.addRow(row);
std::map<std::string, CollectionSystemData> customCollections = CollectionSystemManager::get()->getCustomCollectionSystems();
if((customCollections.find(system->getName()) != customCollections.end() && CollectionSystemManager::get()->getEditingCollection() != system->getName()) ||
CollectionSystemManager::get()->getCustomCollectionsBundle()->getName() == system->getName())
if(ViewController::get()->isUIModeFull() &&
((customCollections.find(system->getName()) != customCollections.end() && CollectionSystemManager::get()->getEditingCollection() != system->getName()) ||
CollectionSystemManager::get()->getCustomCollectionsBundle()->getName() == system->getName()))
{
row.elements.clear();
row.addElement(std::make_shared<TextComponent>(mWindow, "ADD/REMOVE GAMES TO THIS GAME COLLECTION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
@ -73,7 +76,7 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
mMenu.addRow(row);
}
if(CollectionSystemManager::get()->isEditing())
if(ViewController::get()->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);
@ -81,8 +84,8 @@ GuiGamelistOptions::GuiGamelistOptions(Window* window, SystemData* system) : Gui
mMenu.addRow(row);
}
if (!fromPlaceholder && !(mSystem->isCollection() && file->getType() == FOLDER)) {
if (ViewController::get()->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);
row.addElement(makeArrow(mWindow), false);

View file

@ -23,19 +23,36 @@
GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MENU"), mVersion(window)
{
// MAIN MENU
bool isFullUI = ViewController::get()->isUIModeFull();
// SCRAPER >
// SOUND SETTINGS >
// UI SETTINGS >
// CONFIGURE INPUT >
// QUIT >
if (isFullUI)
addEntry("SCRAPER", 0x777777FF, true, [this] { openScraperSettings(); });
// [version]
addEntry("SOUND SETTINGS", 0x777777FF, true, [this] { openSoundSettings(); });
auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); };
addEntry("SCRAPER", 0x777777FF, true,
[this, openScrapeNow] {
if (isFullUI)
addEntry("UI SETTINGS", 0x777777FF, true, [this] { openUISettings(); });
if (isFullUI)
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true, [this] { openCollectionSystemSettings(); });
if (isFullUI)
addEntry("OTHER SETTINGS", 0x777777FF, true, [this] { openOtherSettings(); });
if (isFullUI)
addEntry("CONFIGURE INPUT", 0x777777FF, true, [this] { openConfigInput(); });
addEntry("QUIT", 0x777777FF, true, [this] {openQuitMenu(); });
addChild(&mMenu);
addVersionInfo();
setSize(mMenu.getSize());
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, Renderer::getScreenHeight() * 0.15f);
}
void GuiMenu::openScraperSettings()
{
auto s = new GuiSettings(mWindow, "SCRAPER");
// scrape from
@ -55,6 +72,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
// scrape now
ComponentListRow row;
auto openScrapeNow = [this] { mWindow->pushGui(new GuiScraperStart(mWindow)); };
std::function<void()> openAndSave = openScrapeNow;
openAndSave = [s, openAndSave] { s->save(); openAndSave(); };
row.makeAcceptInputHandler(openAndSave);
@ -66,10 +84,10 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
s->addRow(row);
mWindow->pushGui(s);
});
}
addEntry("SOUND SETTINGS", 0x777777FF, true,
[this] {
void GuiMenu::openSoundSettings()
{
auto s = new GuiSettings(mWindow, "SOUND SETTINGS");
// volume
@ -78,7 +96,9 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
s->addWithLabel("SYSTEM VOLUME", volume);
s->addSaveFunc([volume] { VolumeControl::getInstance()->setVolume((int)round(volume->getValue())); });
#ifdef _RPI_
if (ViewController::get()->isUIModeFull())
{
#ifdef _RPI_
// volume control device
auto vol_dev = std::make_shared< OptionListComponent<std::string> >(mWindow, "AUDIO DEVICE", false);
std::vector<std::string> transitions;
@ -93,7 +113,7 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
VolumeControl::getInstance()->deinit();
VolumeControl::getInstance()->init();
});
#endif
#endif
// disable sounds
auto sounds_enabled = std::make_shared<SwitchComponent>(mWindow);
@ -124,14 +144,30 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
Settings::getInstance()->setString("OMXAudioDev", omx_audio_dev->getSelected());
});
#endif
}
mWindow->pushGui(s);
});
addEntry("UI SETTINGS", 0x777777FF, true,
[this] {
}
void GuiMenu::openUISettings()
{
auto s = new GuiSettings(mWindow, "UI SETTINGS");
//UI mode
auto UImodeSelection = std::make_shared< OptionListComponent<std::string> >(mWindow, "UI MODE", false);
std::vector<std::string> UImodes = ViewController::get()->getUIModes();
for (auto it = UImodes.begin(); it != UImodes.end(); it++)
UImodeSelection->add(*it, *it, Settings::getInstance()->getString("UIMode") == *it);
s->addWithLabel("UI MODE", UImodeSelection);
Window* window = mWindow;
s->addSaveFunc([UImodeSelection, window]
{
LOG(LogDebug) << "Setting UI mode to" << UImodeSelection->getSelected();
Settings::getInstance()->setString("UIMode", UImodeSelection->getSelected());
});
// screensaver
ComponentListRow screensaver_row;
screensaver_row.elements.clear();
screensaver_row.addElement(std::make_shared<TextComponent>(mWindow, "SCREENSAVER SETTINGS", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
@ -237,14 +273,11 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
s->addSaveFunc([show_help] { Settings::getInstance()->setBool("ShowHelpPrompts", show_help->getState()); });
mWindow->pushGui(s);
});
addEntry("GAME COLLECTION SETTINGS", 0x777777FF, true,
[this] { openCollectionSystemSettings();
});
}
addEntry("OTHER SETTINGS", 0x777777FF, true,
[this] {
void GuiMenu::openOtherSettings()
{
auto s = new GuiSettings(mWindow, "OTHER SETTINGS");
// maximum vram
@ -319,25 +352,29 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
mWindow->pushGui(s);
});
addEntry("CONFIGURE INPUT", 0x777777FF, true,
[this] {
}
void GuiMenu::openConfigInput()
{
Window* window = mWindow;
window->pushGui(new GuiMsgBox(window, "ARE YOU SURE YOU WANT TO CONFIGURE INPUT?", "YES",
[window] {
window->pushGui(new GuiDetectDevice(window, false, nullptr));
}, "NO", nullptr)
);
});
addEntry("QUIT", 0x777777FF, true,
[this] {
}
void GuiMenu::openQuitMenu()
{
auto s = new GuiSettings(mWindow, "QUIT");
Window* window = mWindow;
ComponentListRow row;
if (ViewController::get()->isUIModeFull())
{
row.makeAcceptInputHandler([window] {
window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES",
[] {
@ -348,6 +385,24 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
row.addElement(std::make_shared<TextComponent>(window, "RESTART EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
s->addRow(row);
if(Settings::getInstance()->getBool("ShowExit"))
{
row.elements.clear();
row.makeAcceptInputHandler([window] {
window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES",
[] {
SDL_Event ev;
ev.type = SDL_QUIT;
SDL_PushEvent(&ev);
}, "NO", nullptr));
});
row.addElement(std::make_shared<TextComponent>(window, "QUIT EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
s->addRow(row);
}
}
row.elements.clear();
row.makeAcceptInputHandler([window] {
window->pushGui(new GuiMsgBox(window, "REALLY RESTART?", "YES",
@ -363,41 +418,24 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN
row.makeAcceptInputHandler([window] {
window->pushGui(new GuiMsgBox(window, "REALLY SHUTDOWN?", "YES",
[] {
if(quitES("/tmp/es-shutdown") != 0)
if (quitES("/tmp/es-shutdown") != 0)
LOG(LogWarning) << "Shutdown terminated with non-zero result!";
}, "NO", nullptr));
});
row.addElement(std::make_shared<TextComponent>(window, "SHUTDOWN SYSTEM", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
s->addRow(row);
if(Settings::getInstance()->getBool("ShowExit"))
{
row.elements.clear();
row.makeAcceptInputHandler([window] {
window->pushGui(new GuiMsgBox(window, "REALLY QUIT?", "YES",
[] {
SDL_Event ev;
ev.type = SDL_QUIT;
SDL_PushEvent(&ev);
}, "NO", nullptr));
});
row.addElement(std::make_shared<TextComponent>(window, "QUIT EMULATIONSTATION", Font::get(FONT_SIZE_MEDIUM), 0x777777FF), true);
s->addRow(row);
}
mWindow->pushGui(s);
});
}
void GuiMenu::addVersionInfo()
{
mVersion.setFont(Font::get(FONT_SIZE_SMALL));
mVersion.setColor(0x5E5E5EFF);
mVersion.setText("EMULATIONSTATION V" + strToUpper(PROGRAM_VERSION_STRING));
mVersion.setHorizontalAlignment(ALIGN_CENTER);
addChild(&mMenu);
addChild(&mVersion);
setSize(mMenu.getSize());
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, Renderer::getScreenHeight() * 0.15f);
}
void GuiMenu::openScreensaverOptions() {

View file

@ -16,8 +16,16 @@ public:
private:
void addEntry(const char* name, unsigned int color, bool add_arrow, const std::function<void()>& func);
void openScreensaverOptions();
void addVersionInfo();
void openCollectionSystemSettings();
void openConfigInput();
void openOtherSettings();
void openQuitMenu();
void openScraperSettings();
void openScreensaverOptions();
void openSoundSettings();
void openUISettings();
MenuComponent mMenu;
TextComponent mVersion;
};

View file

@ -85,6 +85,10 @@ bool parseArgs(int argc, char* argv[], unsigned int* width, unsigned int* height
{
int maxVRAM = atoi(argv[i + 1]);
Settings::getInstance()->setInt("MaxVRAM", maxVRAM);
}
else if (strcmp(argv[i], "--force-kiosk") == 0)
{
Settings::getInstance()->setBool("ForceKiosk", true);
}else if(strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0)
{
#ifdef WIN32
@ -111,6 +115,7 @@ bool parseArgs(int argc, char* argv[], unsigned int* width, unsigned int* height
"--windowed not fullscreen, should be used with --resolution\n"
"--vsync [1/on or 0/off] turn vsync on or off (default is on)\n"
"--max-vram [size] Max VRAM to use in Mb before swapping. 0 for unlimited\n"
"--force-kiosk Force the UI mode to be Kiosk\n"
"--help, -h summon a sentient, angry tuba\n\n"
"More information available in README.md.\n";
return false; //exit after printing help

View file

@ -33,6 +33,7 @@ ViewController::ViewController(Window* window)
: GuiComponent(window), mCurrentView(nullptr), mCamera(Eigen::Affine3f::Identity()), mFadeOpacity(0), mLockInput(false)
{
mState.viewing = NOTHING;
mCurUIMode = Settings::getInstance()->getString("UIMode");
}
ViewController::~ViewController()
@ -43,10 +44,6 @@ ViewController::~ViewController()
void ViewController::goToStart()
{
// TODO
/* mState.viewing = START_SCREEN;
mCurrentView.reset();
playViewTransition(); */
goToSystemView(SystemData::sSystemVector.at(0));
}
@ -399,6 +396,9 @@ void ViewController::render(const Eigen::Affine3f& parentTrans)
Eigen::Vector3f viewStart = trans.inverse().translation();
Eigen::Vector3f viewEnd = trans.inverse() * Eigen::Vector3f((float)Renderer::getScreenWidth(), (float)Renderer::getScreenHeight(), 0);
// Keep track of UI mode changes.
monitorUIMode();
// draw systemview
getSystemListView()->render(trans);
@ -499,6 +499,22 @@ void ViewController::reloadAll()
updateHelpPrompts();
}
void ViewController::monitorUIMode()
{
std::string uimode = Settings::getInstance()->getString("UIMode");
if (uimode != mCurUIMode) // UIMODE HAS CHANGED
{
mCurUIMode = uimode;
reloadAll();
goToStart();
}
}
bool ViewController::isUIModeFull()
{
return ((mCurUIMode == "Full") && ! Settings::getInstance()->getBool("ForceKiosk"));
}
std::vector<HelpPrompt> ViewController::getHelpPrompts()
{
std::vector<HelpPrompt> prompts;

View file

@ -5,6 +5,8 @@
class SystemData;
const std::vector<std::string> UIModes = { "Full", "Kiosk" };
// Used to smoothly transition the camera between multiple views (e.g. from system to system, from gamelist to gamelist).
class ViewController : public GuiComponent
{
@ -24,6 +26,10 @@ 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();
bool isUIModeFull();
inline std::vector<std::string> getUIModes() { return UIModes; };
// Navigation.
void goToNextGameList();
void goToPrevGameList();
@ -95,4 +101,5 @@ private:
bool mLockInput;
State mState;
std::string mCurUIMode;
};

View file

@ -13,12 +13,13 @@ std::vector<const char*> settings_dont_save = boost::assign::list_of
("Debug")
("DebugGrid")
("DebugText")
("ShowExit")
("Windowed")
("VSync")
("HideConsole")
("ForceKiosk")
("IgnoreGamelist")
("SplashScreen");
("HideConsole")
("ShowExit")
("SplashScreen")
("VSync")
("Windowed");
Settings::Settings()
{
@ -124,6 +125,9 @@ void Settings::setDefaults()
mStringMap["AudioDevice"] = "Master";
#endif
mStringMap["UIMode"] = "Full";
mStringMap["UIMode_passkey"] = "uuddlrlrba";
mBoolMap["ForceKiosk"] = false;
}
template <typename K, typename V>

View file

@ -14,6 +14,7 @@ Window::Window() : mNormalizeNextUpdate(false), mFrameTimeElapsed(0), mFrameCoun
{
mHelp = new HelpComponent(this);
mBackgroundOverlay = new ImageComponent(this);
mPassKeyListener = new PassKeyListener;
}
Window::~Window()
@ -170,8 +171,11 @@ void Window::input(InputConfig* config, Input input)
}
else
{
if(peekGui())
this->peekGui()->input(config, input);
if (!mPassKeyListener->isUIModeChanged(config, input, this) && // check if UI mode has changed due to passphrase completion
peekGui())
{
this->peekGui()->input(config, input); // this is where the majority of inputs will be consumed: the GuiComponent Stack
}
}
}
@ -435,3 +439,43 @@ void Window::startScreenSaver()
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 == (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

@ -1,9 +1,10 @@
#pragma once
#include "GuiComponent.h"
#include "InputManager.h"
#include "Settings.h"
#include <vector>
#include "resources/Font.h"
#include "InputManager.h"
class FileData;
class HelpComponent;
@ -32,6 +33,20 @@ 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();
@ -79,6 +94,7 @@ private:
ScreenSaver* mScreenSaver;
InfoPopup* mInfoPopup;
bool mRenderScreenSaver;
PassKeyListener* mPassKeyListener;
std::vector<GuiComponent*> mGuiStack;