Commit 980a2c4e authored by Aloshi's avatar Aloshi

InputManager mostly redone to handle rolling joystick changes instead of...

InputManager mostly redone to handle rolling joystick changes instead of completely deinitializing/reinitializing itself every time a change is detected.
Some other slight changes to better fit with SDL2's joystick improvements.
Completely redid GuiDetectDevice and GuiInputConfig.
Inching closer and closer to beta.
parent 9a3b0af3
......@@ -49,9 +49,8 @@ std::string toLower(std::string str)
}
//end util functions
InputConfig::InputConfig(int deviceId, const std::string& deviceName) : mDeviceId(deviceId), mDeviceName(deviceName)
InputConfig::InputConfig(int deviceId, const std::string& deviceName, const std::string& deviceGUID) : mDeviceId(deviceId), mDeviceName(deviceName), mDeviceGUID(deviceGUID)
{
mPlayerNum = -1;
}
void InputConfig::clear()
......@@ -59,6 +58,11 @@ void InputConfig::clear()
mNameMap.clear();
}
bool InputConfig::isConfigured()
{
return mNameMap.size() > 0;
}
void InputConfig::mapInput(const std::string& name, Input input)
{
mNameMap[toLower(name)] = input;
......@@ -126,11 +130,9 @@ std::vector<std::string> InputConfig::getMappedTo(Input input)
return maps;
}
void InputConfig::loadFromXML(pugi::xml_node node, int playerNum)
void InputConfig::loadFromXML(pugi::xml_node node)
{
this->clear();
setPlayerNum(playerNum);
clear();
for(pugi::xml_node input = node.child("input"); input; input = input.next_sibling("input"))
{
......@@ -161,11 +163,14 @@ void InputConfig::writeToXML(pugi::xml_node parent)
if(mDeviceId == DEVICE_KEYBOARD)
{
cfg.append_attribute("type") = "keyboard";
cfg.append_attribute("deviceName") = "Keyboard";
}else{
cfg.append_attribute("type") = "joystick";
cfg.append_attribute("deviceName") = mDeviceName.c_str();
}
cfg.append_attribute("deviceGUID") = mDeviceGUID.c_str();
typedef std::map<std::string, Input>::iterator it_type;
for(it_type iterator = mNameMap.begin(); iterator != mNameMap.end(); iterator++)
{
......@@ -179,7 +184,3 @@ void InputConfig::writeToXML(pugi::xml_node parent)
input.append_attribute("value").set_value(iterator->second.value);
}
}
void InputConfig::setPlayerNum(int num) { mPlayerNum = num; }
int InputConfig::getPlayerNum() { return mPlayerNum; }
int InputConfig::getDeviceId() { return mDeviceId; }
......@@ -56,9 +56,6 @@ public:
std::string string()
{
if(!configured)
return "";
std::stringstream stream;
switch(type)
{
......@@ -86,14 +83,14 @@ public:
class InputConfig
{
public:
InputConfig(int deviceId, const std::string& deviceName);
InputConfig(int deviceId, const std::string& deviceName, const std::string& deviceGUID);
void clear();
void mapInput(const std::string& name, Input input);
void setPlayerNum(int num);
int getPlayerNum();
int getDeviceId();
inline int getDeviceId() const { return mDeviceId; };
inline const std::string& getDeviceName() { return mDeviceName; }
inline const std::string& getDeviceGUIDString() { return mDeviceGUID; }
//Returns the input mapped to this name.
Input getInputByName(const std::string& name);
......@@ -104,13 +101,16 @@ public:
//Returns a list of names this input is mapped to.
std::vector<std::string> getMappedTo(Input input);
void loadFromXML(pugi::xml_node root, int playerNum);
void loadFromXML(pugi::xml_node root);
void writeToXML(pugi::xml_node parent);
bool isConfigured();
private:
std::map<std::string, Input> mNameMap;
const int mDeviceId;
const std::string mDeviceName;
int mPlayerNum;
const std::string mDeviceGUID;
};
#endif
This diff is collapsed.
......@@ -12,19 +12,14 @@ class Window;
//you should only ever instantiate one of these, by the way
class InputManager
{
private:
static const int DEADZONE = 23000;
Window* mWindow;
//non-InputManager classes shouldn't use this, as you can easily miss the keyboard and don't have SDL_JoystickIDs
InputConfig* getInputConfigByDevice(SDL_JoystickID device);
void loadDefaultKBConfig();
void loadDefaultConfig();
int mNumJoysticks;
int mNumPlayers;
std::vector<SDL_Joystick*> mJoysticks;
std::map<SDL_JoystickID, SDL_Joystick*> mJoysticks;
std::map<SDL_JoystickID, InputConfig*> mInputConfigs;
InputConfig* mKeyboardInputConfig;
......@@ -32,26 +27,29 @@ class InputManager
bool initialized() const;
void addJoystickByDeviceIndex(int id);
void removeJoystickByJoystickID(SDL_JoystickID id);
bool loadInputConfig(InputConfig* config); // returns true if successfully loaded, false if not (or didn't exist)
public:
InputManager(Window* window);
~InputManager();
void loadConfig();
void writeConfig();
void writeDeviceConfig(InputConfig* config);
static std::string getConfigPath();
void init();
void deinit();
void setNumPlayers(int num);
int getNumPlayers();
int getNumJoysticks();
int getButtonCountByDevice(int id);
int getButtonCountByDevice(int deviceId);
int getNumConfiguredDevices();
bool parseEvent(const SDL_Event& ev);
std::string getDeviceGUIDString(int deviceId);
InputConfig* getInputConfigByDevice(int deviceId);
InputConfig* getInputConfigByPlayer(int player);
bool parseEvent(const SDL_Event& ev);
};
#endif
......@@ -290,3 +290,10 @@ std::vector<HelpPrompt> ComponentList::getHelpPrompts()
return mEntries.at(mCursor).data.elements.back().component->getHelpPrompts();
}
bool ComponentList::moveCursor(int amt)
{
bool ret = listInput(amt);
listInput(0);
return ret;
}
......@@ -59,6 +59,7 @@ public:
void onFocusGained() override;
void onFocusLost() override;
bool moveCursor(int amt);
inline int getCursorId() const { return mCursor; }
float getTotalRowHeight() const;
......
......@@ -12,7 +12,7 @@ static const std::map<std::string, const char*> ICON_PATH_MAP = boost::assign::m
("up/down/left/right", ":/help/dpad_all.png")
("a", ":/help/a.png")
("b", ":/help/b.png")
("menu", ":/help/start.png")
("start", ":/help/start.png")
("select", ":/help/select.png");
HelpComponent::HelpComponent(Window* window) : GuiComponent(window)
......
......@@ -3,104 +3,101 @@
#include "../Renderer.h"
#include "../resources/Font.h"
#include "GuiInputConfig.h"
#include "../components/TextComponent.h"
#include <iostream>
#include <string>
#include <sstream>
#include "../views/ViewController.h"
GuiDetectDevice::GuiDetectDevice(Window* window) : GuiComponent(window)
{
//clear any player information from the InputManager
for(int i = 0; i < mWindow->getInputManager()->getNumPlayers(); i++)
{
InputConfig* cfg = mWindow->getInputManager()->getInputConfigByPlayer(i);
cfg->setPlayerNum(-1);
cfg->clear();
}
mWindow->getInputManager()->setNumPlayers(0);
#define HOLD_TIME 1000
mCurrentPlayer = 0;
mHoldingFinish = false;
}
using namespace Eigen;
bool GuiDetectDevice::input(InputConfig* config, Input input)
GuiDetectDevice::GuiDetectDevice(Window* window, bool firstRun) : GuiComponent(window),
mBackground(window, ":/frame.png"), mGrid(window, Vector2i(1, 4))
{
if((input.type == TYPE_BUTTON || input.type == TYPE_KEY))
{
if(config->getPlayerNum() != -1)
{
if(config->getPlayerNum() == 0)
{
if(input.value)
{
mFinishTimer = 0;
mHoldingFinish = true;
}else{
mHoldingFinish = false;
}
}
return true;
}
mHoldingConfig = NULL;
mHoldTime = 0;
if(!input.value)
return false;
addChild(&mBackground);
addChild(&mGrid);
config->setPlayerNum(mCurrentPlayer);
mWindow->getInputManager()->setNumPlayers(mWindow->getInputManager()->getNumPlayers() + 1); //inc total number of players
mCurrentPlayer++;
//mapped everything we possibly can?
if(mCurrentPlayer >= mWindow->getInputManager()->getNumJoysticks() + 1) //+1 for keyboard
{
done();
}
return true;
if(firstRun)
{
mDoneCallback = [window] {
window->getViewController()->goToStart();
};
}
return false;
mTitle = std::make_shared<TextComponent>(mWindow, firstRun ? "WELCOME TO EMULATIONSTATION" : "SELECT A DEVICE",
Font::get(FONT_SIZE_MEDIUM), 0x666666FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
std::string msg = (firstRun ? "First, we need to configure your input device!\n" : "");
msg += "Hold a button on your input device to configure it.\n"
"Press F4 to quit at any time.";
mMsg = std::make_shared<TextComponent>(mWindow, msg, Font::get(FONT_SIZE_SMALL), 0x777777FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mMsg, Vector2i(0, 1), false, true);
std::stringstream deviceInfo;
int numDevices = mWindow->getInputManager()->getNumJoysticks();
if(numDevices > 0)
deviceInfo << numDevices << " joystick" << (numDevices > 1 ? "s" : "") << " detected.";
else
deviceInfo << "No joysticks detected!";
mDeviceInfo = std::make_shared<TextComponent>(mWindow, deviceInfo.str(), Font::get(FONT_SIZE_SMALL), 0x888888FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mDeviceInfo, Vector2i(0, 2), false, true);
mDeviceHeld = std::make_shared<TextComponent>(mWindow, "", Font::get(FONT_SIZE_MEDIUM), 0x777777FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mDeviceHeld, Vector2i(0, 3), false, true);
setSize(Renderer::getScreenWidth() * 0.6f, Renderer::getScreenHeight() * 0.5f);
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2);
}
void GuiDetectDevice::done()
void GuiDetectDevice::onSizeChanged()
{
mWindow->pushGui(new GuiInputConfig(mWindow, mWindow->getInputManager()->getInputConfigByPlayer(0)));
delete this;
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
// grid
mGrid.setSize(mSize);
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y());
mGrid.setRowHeightPerc(2, mDeviceInfo->getFont()->getHeight() / mSize.y());
mGrid.setRowHeightPerc(3, mDeviceHeld->getFont()->getHeight() / mSize.y());
}
void GuiDetectDevice::update(int deltaTime)
bool GuiDetectDevice::input(InputConfig* config, Input input)
{
if(mHoldingFinish)
if(input.type == TYPE_BUTTON || input.type == TYPE_KEY)
{
mFinishTimer += deltaTime;
if(mFinishTimer > 1000)
done();
if(input.value && mHoldingConfig == NULL)
{
// started holding
mHoldingConfig = config;
mHoldTime = HOLD_TIME;
mDeviceHeld->setText(config->getDeviceName());
}else if(!input.value && mHoldingConfig == config)
{
// cancel
mHoldingConfig = NULL;
mDeviceHeld->setText("");
}
}
return true;
}
void GuiDetectDevice::render(const Eigen::Affine3f& parentTrans)
void GuiDetectDevice::update(int deltaTime)
{
Eigen::Affine3f trans = parentTrans * getTransform();
Renderer::setMatrix(trans);
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
std::string playerString;
std::stringstream stream;
stream << (mCurrentPlayer + 1);
stream >> playerString;
font->drawCenteredText("Press a button on the device for", 0, Renderer::getScreenHeight() / 3.0f, 0x000000FF);
font->drawCenteredText("PLAYER " + playerString, 0, (Renderer::getScreenHeight()*1.5f) / 3.0f, 0x333333FF);
if(mWindow->getInputManager()->getNumPlayers() > 0)
{
font->drawCenteredText("(P1 - hold a button to finish)", 0, (Renderer::getScreenHeight()*2) / 3.0f, (mHoldingFinish ? 0x0000FFFF : 0x000066FF));
}
if(mWindow->getInputManager()->getNumJoysticks() == 0)
if(mHoldingConfig)
{
font->drawCenteredText("No joysticks detected!", 0, Renderer::getScreenHeight() - (font->getHeight()*2.0f)-10, 0xFF0000FF);
mHoldTime -= deltaTime;
if(mHoldTime <= 0)
{
// picked one!
mWindow->pushGui(new GuiInputConfig(mWindow, mHoldingConfig, true, mDoneCallback));
delete this;
}
}
font->drawCenteredText("Press F4 to quit.", 0, Renderer::getScreenHeight() - font->getHeight() - 2.0f , 0x000000FF);
}
#pragma once
#include "../GuiComponent.h"
#include "../components/NinePatchComponent.h"
#include "../components/ComponentGrid.h"
class TextComponent;
class GuiDetectDevice : public GuiComponent
{
public:
GuiDetectDevice(Window* window);
GuiDetectDevice(Window* window, bool firstRun);
bool input(InputConfig* config, Input input);
void update(int deltaTime);
void render(const Eigen::Affine3f& parentTrans) override;
bool input(InputConfig* config, Input input) override;
void update(int deltaTime) override;
void onSizeChanged() override;
private:
void done();
InputConfig* mHoldingConfig;
int mHoldTime;
NinePatchComponent mBackground;
ComponentGrid mGrid;
std::shared_ptr<TextComponent> mTitle;
std::shared_ptr<TextComponent> mMsg;
std::shared_ptr<TextComponent> mDeviceInfo;
std::shared_ptr<TextComponent> mDeviceHeld;
bool mHoldingFinish;
int mFinishTimer;
int mCurrentPlayer;
std::function<void()> mDoneCallback;
};
#include "GuiInputConfig.h"
#include "../Window.h"
#include "../Renderer.h"
#include "../resources/Font.h"
#include "../Log.h"
#include "../views/ViewController.h"
#include "../components/TextComponent.h"
#include "../components/ImageComponent.h"
#include "../components/MenuComponent.h"
#include "../components/ButtonComponent.h"
#include "../Util.h"
static const int inputCount = 10;
static std::string inputName[inputCount] = { "Up", "Down", "Left", "Right", "A", "B", "Menu", "Select", "PageUp", "PageDown"};
static std::string inputDispName[inputCount] = { "Up", "Down", "Left", "Right", "Accept", "Back", "Menu", "Jump to Letter", "Page Up", "Page Down"};
static const char* inputName[inputCount] = { "Up", "Down", "Left", "Right", "A", "B", "Start", "Select", "PageUp", "PageDown"};
static const char* inputDispName[inputCount] = { "Up", "Down", "Left", "Right", "A", "B", "Start", "Select", "Page Up", "Page Down"};
static const char* inputIcon[inputCount] = { ":/help/dpad_up.png", ":/help/dpad_down.png", ":/help/dpad_left.png", ":/help/dpad_right.png",
":/help/a.png", ":/help/b.png", ":/help/start.png", ":/help/select.png", ":/help/l.png", ":/help/r.png" };
//MasterVolUp and MasterVolDown are also hooked up, but do not appear on this screen.
//If you want, you can manually add them to es_input.cfg.
GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target) : GuiComponent(window), mTargetConfig(target), mCanSkip(false)
using namespace Eigen;
GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfigureAll, const std::function<void()>& okCallback) : GuiComponent(window),
mBackground(window, ":/frame.png"), mGrid(window, Vector2i(1, 5)),
mTargetConfig(target)
{
mCurInputId = 0;
LOG(LogInfo) << "Configuring device " << target->getDeviceId();
}
void GuiInputConfig::update(int deltaTime)
{
if(reconfigureAll)
target->clear();
}
mConfiguringAll = reconfigureAll;
mConfiguringRow = mConfiguringAll;
bool GuiInputConfig::input(InputConfig* config, Input input)
{
if(config != mTargetConfig || input.value == 0)
return false;
addChild(&mBackground);
addChild(&mGrid);
mTitle = std::make_shared<TextComponent>(mWindow, "PLEASE CONFIGURE INPUT FOR", Font::get(FONT_SIZE_SMALL), 0x555555FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mTitle, Vector2i(0, 0), false, true);
mSubtitle1 = std::make_shared<TextComponent>(mWindow, target->getDeviceName(), Font::get(FONT_SIZE_MEDIUM), 0x555555FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mSubtitle1, Vector2i(0, 1), false, true);
if(mCurInputId >= inputCount)
mSubtitle2 = std::make_shared<TextComponent>(mWindow, "(HOLD ANY BUTTON TO SKIP BUT NOT YET)", Font::get(FONT_SIZE_SMALL), 0x999999FF, TextComponent::ALIGN_CENTER);
mGrid.setEntry(mSubtitle2, Vector2i(0, 2), false, true);
mList = std::make_shared<ComponentList>(mWindow);
mGrid.setEntry(mList, Vector2i(0, 3), true, true);
for(int i = 0; i < inputCount; i++)
{
//done
if(input.type == TYPE_BUTTON || input.type == TYPE_KEY)
ComponentListRow row;
// icon
auto icon = std::make_shared<ImageComponent>(mWindow);
icon->setImage(inputIcon[i]);
icon->setResize(0, Font::get(FONT_SIZE_MEDIUM)->getHeight() * 0.8f);
row.addElement(icon, false);
auto text = std::make_shared<TextComponent>(mWindow, inputDispName[i], Font::get(FONT_SIZE_MEDIUM), 0x777777FF);
row.addElement(text, true);
auto mapping = std::make_shared<TextComponent>(mWindow, "-NOT DEFINED-", Font::get(FONT_SIZE_MEDIUM, FONT_PATH_LIGHT), 0x999999FF);
row.addElement(mapping, true);
row.input_handler = [this, i, mapping](InputConfig* config, Input input) -> bool
{
if(mTargetConfig->getPlayerNum() < mWindow->getInputManager()->getNumPlayers() - 1)
if(!input.value)
return false;
if(mConfiguringRow)
{
mWindow->pushGui(new GuiInputConfig(mWindow, mWindow->getInputManager()->getInputConfigByPlayer(mTargetConfig->getPlayerNum() + 1)));
if(!process(config, input, i, mapping)) // button press invalid; try again
return true;
if(mConfiguringAll)
{
if(!mList->moveCursor(1)) // try to move to the next one
{
// at bottom of list
mConfiguringAll = false;
mConfiguringRow = false;
mGrid.moveCursor(Vector2i(0, 1));
}
}else{
mConfiguringRow = false; // we only wanted to configure one row
}
return true;
}else{
mWindow->getInputManager()->writeConfig();
mWindow->getViewController()->goToStart();
// not configuring, start configuring when A is pressed
if(config->isMappedTo("a", input) && input.value)
{
mConfiguringRow = true;
return true;
}
return false;
}
delete this;
return true;
}
}else{
if(mCanSkip && config->isMappedTo("a", input))
{
mCurInputId++;
return true;
}
if(config->getMappedTo(input).size() > 0)
{
mErrorMsg = "Already mapped!";
return true;
}
return false;
};
mList->addRow(row);
}
input.configured = true;
LOG(LogInfo) << " [" << input.string() << "] -> " << inputName[mCurInputId];
// buttons
std::vector< std::shared_ptr<ButtonComponent> > buttons;
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "OK", "ok", [this, okCallback] {
mWindow->getInputManager()->writeDeviceConfig(mTargetConfig); // save
if(okCallback)
okCallback();
delete this;
}));
mButtonGrid = makeButtonGrid(mWindow, buttons);
mGrid.setEntry(mButtonGrid, Vector2i(0, 4), true, false);
setSize(Renderer::getScreenWidth() * 0.6f, Renderer::getScreenHeight() * 0.7f);
setPosition((Renderer::getScreenWidth() - mSize.x()) / 2, (Renderer::getScreenHeight() - mSize.y()) / 2);
}
config->mapInput(inputName[mCurInputId], input);
mCurInputId++;
mErrorMsg = "";
void GuiInputConfig::onSizeChanged()
{
mBackground.fitTo(mSize, Vector3f::Zero(), Vector2f(-32, -32));
//for buttons with not enough buttons, press A to skip
if(mCurInputId >= 7)
{
mCanSkip = true;
}
return true;
}
// update grid
mGrid.setSize(mSize);
return false;
mGrid.setRowHeightPerc(0, mTitle->getFont()->getHeight() / mSize.y());
mGrid.setRowHeightPerc(1, mSubtitle1->getFont()->getHeight() / mSize.y());
mGrid.setRowHeightPerc(2, mSubtitle2->getFont()->getHeight() / mSize.y());
mGrid.setRowHeightPerc(4, mButtonGrid->getSize().y() / mSize.y());
}
void GuiInputConfig::render(const Eigen::Affine3f& parentTrans)
void GuiInputConfig::error(const std::string& msg)
{
Eigen::Affine3f trans = parentTrans * getTransform();
Renderer::setMatrix(trans);
std::shared_ptr<Font> font = Font::get(FONT_SIZE_MEDIUM);
// TODO
LOG(LogWarning) << msg;
}
std::stringstream stream;
stream << "PLAYER " << mTargetConfig->getPlayerNum() + 1 << ", press...";
font->drawText(stream.str(), Eigen::Vector2f(10, 10), 0x000000FF);
bool GuiInputConfig::process(InputConfig* config, Input input, int inputId, const std::shared_ptr<TextComponent>& text)
{
// from some other input source
if(config != mTargetConfig)
return false;
int y = 14 + (int)font->getHeight();
for(int i = 0; i < mCurInputId; i++)
// if this input is mapped to something other than "nothing" or the current row, error
// (if it's the same as what it was before, allow it)
if(config->getMappedTo(input).size() > 0 && !config->isMappedTo(inputName[inputId], input))
{
font->drawText(inputDispName[i], Eigen::Vector2f(10, y), 0x00CC00FF);
y += (int)font->getHeight() + 5;
error("Already mapped!");
return false;
}
if(mCurInputId >= inputCount)
{
font->drawCenteredText("Basic config done!", 0, Renderer::getScreenHeight() * 0.4f, 0x00CC00FF);
font->drawCenteredText("Press any button to continue.", 0, Renderer::getScreenHeight() * 0.4f + font->getHeight() + 4, 0x000000FF);
}else{
font->drawText(inputDispName[mCurInputId], Eigen::Vector2f(10, y), 0x000000FF);
if(mCanSkip)
{
Eigen::Vector2f textSize = font->sizeText(inputDispName[mCurInputId]);
textSize[0] += 14;
text->setText(strToUpper(input.string()));
text->setColor(0x777777FF);
if(Renderer::getScreenWidth() / 2.5f > textSize.x())
textSize[0] = Renderer::getScreenWidth() / 2.5f;
input.configured = true;
config->mapInput(inputName[inputId], input);
font->drawText("press Accept to skip", Eigen::Vector2f(textSize.x(), y), 0x0000AAFF);
}
}
LOG(LogInfo) << " Mapping [" << input.string() << "] -> " << inputName[inputId];
if(!mErrorMsg.empty())
font->drawCenteredText(mErrorMsg, 0, (float)Renderer::getScreenHeight() - font->getHeight() - 10, 0xFF0000FF);
return true;
}
#pragma once
#include "../GuiComponent.h"
#include <string>
#include "../components/NinePatchComponent.h"
#include "../components/ComponentGrid.h"
#include "../components/ComponentList.h"
class TextComponent;
class GuiInputConfig : public GuiComponent
{
public:
GuiInputConfig(Window* window, InputConfig* target);
GuiInputConfig(Window* window, InputConfig* target, bool reconfigureAll, const std::function<void()>& okCallback);
bool input(InputConfig* config, Input input);
void update(int deltaTime);
void render(const Eigen::Affine3f& parentTrans) override;
void onSizeChanged() override;
private:
std::string mErrorMsg;
void error(const std::string& msg);
bool process(InputConfig* config, Input input, int inputId, const std::shared_ptr<TextComponent>& text);
NinePatchComponent mBackground;
ComponentGrid mGrid;
std::shared_ptr<TextComponent> mTitle;
std::shared_ptr<TextComponent> mSubtitle1;
std::shared_ptr<TextComponent> mSubtitle2;
std::shared_ptr<ComponentList> mList;
std::shared_ptr<ComponentGrid> mButtonGrid;
InputConfig* mTargetConfig;
int mCurInputId;
bool mCanSkip;
bool mConfiguringRow; // next input captured by mList will be interpretted as a remap
bool mConfiguringAll; // move the cursor down after configuring a row and start configuring the next row until we reach the bottom
};
......@@ -6,6 +6,7 @@
#include "GuiMsgBox.h"
#include "GuiSettings.h"
#include "GuiScraperStart.h"
#include "GuiDetectDevice.h"
#include "../components/ButtonComponent.h"
#include "../components/SwitchComponent.h"
......@@ -120,6 +121,11 @@ GuiMenu::GuiMenu(Window* window) : GuiComponent(window), mMenu(window, "MAIN MEN