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

View file

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

View file

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

View file

@ -390,6 +390,22 @@ bool ViewController::input(InputConfig* config, Input input)
if (!(UIModeController::getInstance()->isUIModeKid() && if (!(UIModeController::getInstance()->isUIModeKid() &&
Settings::getInstance()->getBool("DisableKidStartMenu")) && Settings::getInstance()->getBool("DisableKidStartMenu")) &&
config->isMappedTo("start", input) && input.value != 0) { 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)); mWindow->pushGui(new GuiMenu(mWindow));
return true; 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() void BasicGameListView::addPlaceholder()
{ {
// Empty list - add a placeholder. // Empty list - add a placeholder.

View file

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

View file

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

View file

@ -27,6 +27,8 @@ public:
virtual FileData* getCursor() override; virtual FileData* getCursor() override;
virtual void setCursor(FileData*) override; virtual void setCursor(FileData*) override;
virtual FileData* getFirstEntry() override;
virtual FileData* getLastEntry() override;
virtual bool input(InputConfig* config, Input input) 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())); mWindow->pushGui(new GuiGamelistOptions(mWindow, this->mRoot->getSystem()));
return true; return true;
} }
// Ctrl-R reloads the view when debugging. // Ctrl-R reloads the view when debugging.
else if (Settings::getInstance()->getBool("Debug") && else if (Settings::getInstance()->getBool("Debug") &&
config->getDeviceId() == DEVICE_KEYBOARD && config->getDeviceId() == DEVICE_KEYBOARD &&

View file

@ -43,6 +43,8 @@ public:
virtual FileData* getCursor() = 0; virtual FileData* getCursor() = 0;
virtual void setCursor(FileData*) = 0; virtual void setCursor(FileData*) = 0;
virtual FileData* getFirstEntry() = 0;
virtual FileData* getLastEntry() = 0;
virtual bool input(InputConfig* config, Input input) override; virtual bool input(InputConfig* config, Input input) override;
virtual void remove(FileData* game, bool deleteFile) = 0; 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) bool ISimpleGameListView::input(InputConfig* config, Input input)
{ {
std::shared_ptr<Sound> soundfile;
if (input.value != 0) { if (input.value != 0) {
if (config->isMappedTo("a", input)) { if (config->isMappedTo("a", input)) {
FileData* cursor = getCursor(); 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); return isMappedTo("leftshoulder", input) || isMappedTo("pageup", input);
}else if(name == "rightshoulder"){ }else if(name == "rightshoulder"){
return isMappedTo("rightshoulder", input) || isMappedTo("pagedown", input); 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); 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("right", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RIGHT, 1, true));
cfg->mapInput("a", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RETURN, 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("start", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F1, 1, true));
cfg->mapInput("select", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_F2, 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("leftshoulder", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_PAGEUP, 1, true));
cfg->mapInput("rightshoulder", Input(DEVICE_KEYBOARD, TYPE_KEY, SDLK_RIGHTBRACKET, 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) 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. // 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); 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); 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); 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); 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; return false;
} }

View file

@ -129,6 +129,18 @@ public:
return mEntries.at(mCursor).object; 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) void setCursor(typename std::vector<Entry>::const_iterator& it)
{ {
assert(it != mEntries.cend()); assert(it != mEntries.cend());
@ -186,6 +198,19 @@ protected:
mEntries.erase(it); 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 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); listInput(-10);
return true; return true;
} }
if (config->isMappedLike("righttrigger", input)) {
return this->listLastRow();
}
if (config->isMappedLike("lefttrigger", input)) {
return this->listFirstRow();
}
} }
else { else {
if (config->isMappedLike("down", input) || if (config->isMappedLike("down", input) ||
config->isMappedLike("up", input) || config->isMappedLike("up", input) ||
config->isMappedLike("rightshoulder", input) || config->isMappedLike("rightshoulder", input) ||
config->isMappedLike("leftshoulder", input)) config->isMappedLike("leftshoulder", input) ||
config->isMappedLike("lefttrigger", input) ||
config->isMappedLike("righttrigger", input))
stopScrolling(); 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); return GuiComponent::input(config, input);
} }

View file

@ -15,7 +15,7 @@ struct InputConfigStructure
const char* icon; const char* icon;
}; };
static const int inputCount = 25; static const int inputCount = 22;
static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] = static const InputConfigStructure GUI_INPUT_CONFIG_LIST[inputCount] =
{ {
{ "Up", false, "D-PAD UP", ":/help/dpad_up.svg" }, { "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" }, { "RightShoulder", true, "RIGHT SHOULDER", ":/help/button_r.svg" },
{ "LeftTrigger", true, "LEFT TRIGGER", ":/help/button_lt.svg" }, { "LeftTrigger", true, "LEFT TRIGGER", ":/help/button_lt.svg" },
{ "RightTrigger", true, "RIGHT TRIGGER", ":/help/button_rt.svg" }, { "RightTrigger", true, "RIGHT TRIGGER", ":/help/button_rt.svg" },
{ "LeftThumb", true, "LEFT THUMB", ":/help/analog_thumb.svg" }, // { "LeftThumb", true, "LEFT THUMB", ":/help/analog_thumb.svg" },
{ "RightThumb", true, "RIGHT THUMB", ":/help/analog_thumb.svg" }, // { "RightThumb", true, "RIGHT THUMB", ":/help/analog_thumb.svg" },
{ "LeftAnalogUp", true, "LEFT ANALOG UP", ":/help/analog_up.svg" }, { "LeftAnalogUp", true, "LEFT ANALOG UP", ":/help/analog_up.svg" },
{ "LeftAnalogDown", true, "LEFT ANALOG DOWN", ":/help/analog_down.svg" }, { "LeftAnalogDown", true, "LEFT ANALOG DOWN", ":/help/analog_down.svg" },
{ "LeftAnalogLeft", true, "LEFT ANALOG LEFT", ":/help/analog_left.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" }, { "RightAnalogDown", true, "RIGHT ANALOG DOWN", ":/help/analog_down.svg" },
{ "RightAnalogLeft", true, "RIGHT ANALOG LEFT", ":/help/analog_left.svg" }, { "RightAnalogLeft", true, "RIGHT ANALOG LEFT", ":/help/analog_left.svg" },
{ "RightAnalogRight", true, "RIGHT ANALOG RIGHT", ":/help/analog_right.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. //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] { 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. // check if the hotkey enable button is set. if not prompt the user to use select or nothing.
Input input; Input input;
if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) { okFunction();
mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(), // Temporary comments, needs to be properly cleaned up later.
"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.", // if (!mTargetConfig->getInputByName("HotKeyEnable", &input)) {
"YES", [this, okFunction] { // mWindow->pushGui(new GuiMsgBox(mWindow, getHelpStyle(),
Input input; // "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.",
mTargetConfig->getInputByName("Select", &input); // "YES", [this, okFunction] {
mTargetConfig->mapInput("HotKeyEnable", input); // Input input;
okFunction(); // mTargetConfig->getInputByName("Select", &input);
}, // mTargetConfig->mapInput("HotKeyEnable", input);
"NO", [this, okFunction] { // okFunction();
// for a disabled hotkey enable button, set to a key with id 0, // },
// so the input configuration script can be backwards compatible. // "NO", [this, okFunction] {
mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, TYPE_KEY, 0, 1, true)); // // for a disabled hotkey enable button, set to a key with id 0,
okFunction(); // // so the input configuration script can be backwards compatible.
} // mTargetConfig->mapInput("HotKeyEnable", Input(DEVICE_KEYBOARD, TYPE_KEY, 0, 1, true));
)); // okFunction();
} else { // }
okFunction(); // ));
} // } else {
// okFunction();
// }
})); }));
mButtonGrid = makeButtonGrid(mWindow, buttons); mButtonGrid = makeButtonGrid(mWindow, buttons);
mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false); mGrid.setEntry(mButtonGrid, Vector2i(0, 6), true, false);