Added support for jumping to the beginning and end of gamelists and menus using the left and right trigger buttons. Also fixed some navigation bugs.

This commit is contained in:
Leon Styhre 2020-06-13 10:25:09 +02:00
parent 7cefe6a2bd
commit f1f82ac29f
17 changed files with 142 additions and 48 deletions

View file

@ -348,9 +348,7 @@ void CollectionSystemManager::updateCollectionSystem(FileData* file, CollectionS
// Select the first row of the gamelist (the game just played).
IGameListView* gameList =
ViewController::get()->getGameListView(getSystemToView(sysData.system)).get();
FileData* firstRow =
gameList->getCursor()->getParent()->getChildrenListToDisplay()[0];
gameList->setCursor(firstRow);
gameList->setCursor(gameList->getFirstEntry());
}
else {
ViewController::get()->onFileChanged(rootFolder, FILE_SORTED);
@ -924,9 +922,7 @@ void CollectionSystemManager::addEnabledCollectionsToDisplayedSystems(
IGameListView* gameList = ViewController::get()->
getGameListView((it->second.system)).get();
if (!gameList->getCursor()->isPlaceHolder()) {
FileData* firstRow = gameList->getCursor()->
getParent()->getChildrenListToDisplay().front();
gameList->setCursor(firstRow);
gameList->setCursor(gameList->getFirstEntry());
}
}
}

View file

@ -50,7 +50,7 @@ GuiGamelistOptions::GuiGamelistOptions(
// Jump to letter quick selector.
row.elements.clear();
// The letter index is generated in FileData during game system sorting.
// The letter index is generated in FileData during gamelist sorting.
mFirstLetterIndex = file->getParent()->getFirstLetterIndex();
// Set the quick selector to the first character of the selected game.
@ -240,7 +240,7 @@ void GuiGamelistOptions::jumpToLetter()
{
char letter = mJumpToLetterList->getSelected().front();
// Get first row of the gamelist.
// Get the gamelist.
const std::vector<FileData*>& files = getGamelist()->getCursor()->
getParent()->getChildrenListToDisplay();
@ -264,9 +264,7 @@ void GuiGamelistOptions::jumpToLetter()
void GuiGamelistOptions::jumpToFirstRow()
{
// Get first row of the gamelist.
const std::vector<FileData*>& files = getGamelist()->getCursor()->
getParent()->getChildrenListToDisplay();
getGamelist()->setCursor(files.at(0));
getGamelist()->setCursor(getGamelist()->getFirstEntry());
}
bool GuiGamelistOptions::input(InputConfig* config, Input input)

View file

@ -338,8 +338,7 @@ void GuiMenu::openUISettings()
// Jump to the first row of the gamelist.
IGameListView* gameList = ViewController::get()->getGameListView((*it)).get();
FileData* firstRow = gameList->getCursor()->getParent()->getChildrenListToDisplay()[0];
gameList->setCursor(firstRow);
gameList->setCursor(gameList->getFirstEntry());
}
});

View file

@ -390,6 +390,22 @@ bool ViewController::input(InputConfig* config, Input input)
if (!(UIModeController::getInstance()->isUIModeKid() &&
Settings::getInstance()->getBool("DisableKidStartMenu")) &&
config->isMappedTo("start", input) && input.value != 0) {
// 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);
// for (unsigned int i = 0; i > mGameListViews.size(); i++)
// mGameListViews[i].get()->finishAnimation(0);
for (auto it = mGameListViews.begin(); it != mGameListViews.end(); it++) {
std::string teststring = it->second->getCursor()->getName();
std::string teststring2;
}
mWindow->pushGui(new GuiMenu(mWindow));
return true;
}

View file

@ -107,6 +107,16 @@ void BasicGameListView::setCursor(FileData* cursor)
}
}
FileData* BasicGameListView::getFirstEntry()
{
return mList.getFirst();
}
FileData* BasicGameListView::getLastEntry()
{
return mList.getLast();
}
void BasicGameListView::addPlaceholder()
{
// Empty list - add a placeholder.

View file

@ -23,6 +23,8 @@ public:
virtual FileData* getCursor() override;
virtual void setCursor(FileData* file) override;
virtual FileData* getFirstEntry() override;
virtual FileData* getLastEntry() override;
virtual const char* getName() const override { return "basic"; }

View file

@ -153,13 +153,22 @@ FileData* GridGameListView::getCursor()
void GridGameListView::setCursor(FileData* file)
{
if (!mGrid.setCursor(file))
{
if (!mGrid.setCursor(file)) {
populateList(file->getParent()->getChildrenListToDisplay());
mGrid.setCursor(file);
}
}
FileData* GridGameListView::getFirstEntry()
{
return mGrid.getFirst();;
}
FileData* GridGameListView::getLastEntry()
{
return mGrid.getLast();
}
std::string GridGameListView::getQuickSystemSelectRightButton()
{
return "rightshoulder";

View file

@ -27,6 +27,8 @@ public:
virtual FileData* getCursor() override;
virtual void setCursor(FileData*) override;
virtual FileData* getFirstEntry() override;
virtual FileData* getLastEntry() override;
virtual bool input(InputConfig* config, Input input) override;

View file

@ -20,6 +20,7 @@ bool IGameListView::input(InputConfig* config, Input input)
mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem()));
return true;
}
// Ctrl-R reloads the view when debugging.
else if (Settings::getInstance()->getBool("Debug") &&
config->getDeviceId() == DEVICE_KEYBOARD &&

View file

@ -43,6 +43,8 @@ public:
virtual FileData* getCursor() = 0;
virtual void setCursor(FileData*) = 0;
virtual FileData* getFirstEntry() = 0;
virtual FileData* getLastEntry() = 0;
virtual bool input(InputConfig* config, Input input) override;
virtual void remove(FileData* game, bool deleteFile) = 0;

View file

@ -87,8 +87,6 @@ void ISimpleGameListView::onFileChanged(FileData* /*file*/, FileChangeType /*cha
bool ISimpleGameListView::input(InputConfig* config, Input input)
{
std::shared_ptr<Sound> soundfile;
if (input.value != 0) {
if (config->isMappedTo("a", input)) {
FileData* cursor = getCursor();

View file

@ -126,6 +126,10 @@ bool InputConfig::isMappedLike(const std::string& name, Input input)
return isMappedTo("leftshoulder", input) || isMappedTo("pageup", input);
}else if(name == "rightshoulder"){
return isMappedTo("rightshoulder", input) || isMappedTo("pagedown", input);
}else if(name == "lefttrigger"){
return isMappedTo("lefttrigger", input) || isMappedTo("home", input);
}else if(name == "righttrigger"){
return isMappedTo("righttrigger", input) || isMappedTo("end", input);
}
return isMappedTo(name, input);
}

View file

@ -324,12 +324,16 @@ void InputManager::loadDefaultKBConfig()
cfg->mapInput("right", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RIGHT, 1, true));
cfg->mapInput("a", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RETURN, 1, true));
cfg->mapInput("b", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_ESCAPE, 1, true));
cfg->mapInput("b", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_BACKSPACE, 1, true));
cfg->mapInput("x", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_DELETE, 1, true));
cfg->mapInput("y", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_INSERT, 1, true));
cfg->mapInput("start", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F1, 1, true));
cfg->mapInput("select", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F2, 1, true));
cfg->mapInput("leftshoulder", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_LEFTBRACKET, 1, true));
cfg->mapInput("rightshoulder", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RIGHTBRACKET, 1, true));
cfg->mapInput("leftshoulder", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_PAGEUP, 1, true));
cfg->mapInput("rightshoulder", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_PAGEDOWN, 1, true));
cfg->mapInput("lefttrigger", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_HOME, 1, true));
cfg->mapInput("righttrigger", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_END, 1, true));
}
void InputManager::writeDeviceConfig(InputConfig* config)

View file

@ -79,14 +79,26 @@ bool ComponentList::input(InputConfig* config, Input input)
}
// Input handler didn't consume the input - try to scroll.
if (config->isMappedLike("up", input))
if (config->isMappedLike("up", input)) {
return listInput(input.value != 0 ? -1 : 0);
else if (config->isMappedLike("down", input))
}
else if (config->isMappedLike("down", input)) {
return listInput(input.value != 0 ? 1 : 0);
else if (config->isMappedLike("leftshoulder", input))
}
else if (config->isMappedLike("leftshoulder", input)) {
return listInput(input.value != 0 ? -6 : 0);
else if (config->isMappedLike("rightshoulder", input))
}
else if (config->isMappedLike("rightshoulder", input)) {
return listInput(input.value != 0 ? 6 : 0);
}
else if (config->isMappedLike("lefttrigger", input)) {
mSelectorBarOffset = 0;
return listFirstRow();
}
else if (config->isMappedLike("righttrigger", input)) {
mSelectorBarOffset = mEntries.size() - 1;
return listLastRow();
}
return false;
}

View file

@ -129,6 +129,18 @@ public:
return mEntries.at(mCursor).object;
}
inline const UserData& getFirst() const
{
assert(size() > 0);
return mEntries.front().object;
}
inline const UserData& getLast() const
{
assert(size() > 0);
return mEntries.back().object;
}
void setCursor(typename std::vector<Entry>::const_iterator& it)
{
assert(it != mEntries.cend());
@ -186,6 +198,19 @@ protected:
mEntries.erase(it);
}
bool listFirstRow()
{
mCursor = 0;
onCursorChanged(CURSOR_STOPPED);
return true;
}
bool listLastRow()
{
mCursor = mEntries.size() - 1;
onCursorChanged(CURSOR_STOPPED);
return true;
}
bool listInput(int velocity) // a velocity of 0 = stop scrolling
{

View file

@ -288,15 +288,29 @@ bool TextListComponent<T>::input(InputConfig* config, Input input)
listInput(-10);
return true;
}
if (config->isMappedLike("righttrigger", input)) {
return this->listLastRow();
}
if (config->isMappedLike("lefttrigger", input)) {
return this->listFirstRow();
}
}
else {
if (config->isMappedLike("down", input) ||
config->isMappedLike("up", input) ||
config->isMappedLike("rightshoulder", input) ||
config->isMappedLike("leftshoulder", input))
config->isMappedLike("leftshoulder", input) ||
config->isMappedLike("lefttrigger", input) ||
config->isMappedLike("righttrigger", input))
stopScrolling();
}
}
// Explicitly stop the scrolling, otherwise it will go forever in case
// the menu was openened or another gamelist was selected using the
// quick system selector etc.
stopScrolling();
return GuiComponent::input(config, input);
}

View file

@ -15,7 +15,7 @@ struct InputConfigStructure
const char* icon;
};
static const int inputCount = 25;
static const int inputCount = 22;
static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] =
{
{ "Up", false, "D-PAD UP", ":/help/dpad_up.svg" },
@ -32,8 +32,8 @@ static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] =
{ "RightShoulder", true, "RIGHT SHOULDER", ":/help/button_r.svg" },
{ "LeftTrigger", true, "LEFT TRIGGER", ":/help/button_lt.svg" },
{ "RightTrigger", true, "RIGHT TRIGGER", ":/help/button_rt.svg" },
{ "LeftThumb", true, "LEFT THUMB", ":/help/analog_thumb.svg" },
{ "RightThumb", true, "RIGHT THUMB", ":/help/analog_thumb.svg" },
// { "LeftThumb", true, "LEFT THUMB", ":/help/analog_thumb.svg" },
// { "RightThumb", true, "RIGHT THUMB", ":/help/analog_thumb.svg" },
{ "LeftAnalogUp", true, "LEFT ANALOG UP", ":/help/analog_up.svg" },
{ "LeftAnalogDown", true, "LEFT ANALOG DOWN", ":/help/analog_down.svg" },
{ "LeftAnalogLeft", true, "LEFT ANALOG LEFT", ":/help/analog_left.svg" },
@ -42,7 +42,7 @@ static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] =
{ "RightAnalogDown", true, "RIGHT ANALOG DOWN", ":/help/analog_down.svg" },
{ "RightAnalogLeft", true, "RIGHT ANALOG LEFT", ":/help/analog_left.svg" },
{ "RightAnalogRight", true, "RIGHT ANALOG RIGHT", ":/help/analog_right.svg" },
{ "HotKeyEnable", true, "HOTKEY ENABLE", ":/help/button_hotkey.svg" }
// { "HotKeyEnable", true, "HOTKEY ENABLE", ":/help/button_hotkey.svg" }
};
//MasterVolUp and MasterVolDown are also hooked up, but do not appear on this screen.
@ -190,25 +190,27 @@ GuiInputConfig::GuiInputConfig(Window* window, InputConfig* target, bool reconfi
buttons.push_back(std::make_shared<ButtonComponent>(mWindow, "OK", "ok", [this, okFunction] {
// check if the hotkey enable button is set. if not prompt the user to use select or nothing.
Input input;
if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) {
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
"YOU DIDN'T CHOOSE A HOTKEY ENABLE BUTTON. THIS IS REQUIRED FOR EXITING GAMES WITH A CONTROLLER. DO YOU WANT TO USE THE SELECT BUTTON DEFAULT ? PLEASE ANSWER YES TO USE SELECT OR NO TO NOT SET A HOTKEY ENABLE BUTTON.",
"YES", [this, okFunction] {
Input input;
mTargetConfig->getInputByName("Select", &input);
mTargetConfig->mapInput("HotKeyEnable", input);
okFunction();
},
"NO", [this, okFunction] {
// for a disabled hotkey enable button, set to a key with id 0,
// so the input configuration script can be backwards compatible.
mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, TYPE_KEY, 0, 1, true));
okFunction();
}
));
} else {
okFunction();
}
// Temporary comments, needs to be properly cleaned up later.
// if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) {
// mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
// "YOU DIDN'T CHOOSE A HOTKEY ENABLE BUTTON. THIS IS REQUIRED FOR EXITING GAMES WITH A CONTROLLER. DO YOU WANT TO USE THE SELECT BUTTON DEFAULT ? PLEASE ANSWER YES TO USE SELECT OR NO TO NOT SET A HOTKEY ENABLE BUTTON.",
// "YES", [this, okFunction] {
// Input input;
// mTargetConfig->getInputByName("Select", &input);
// mTargetConfig->mapInput("HotKeyEnable", input);
// okFunction();
// },
// "NO", [this, okFunction] {
// // for a disabled hotkey enable button, set to a key with id 0,
// // so the input configuration script can be backwards compatible.
// mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, TYPE_KEY, 0, 1, true));
// okFunction();
// }
// ));
// } else {
// okFunction();
// }
}));
mButtonGrid = makeButtonGrid(mWindow, buttons);
mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false);