From 4bad7a30741efed63a19da9fa93098736b67924c Mon Sep 17 00:00:00 2001 From: Andrew Lanzone Date: Mon, 12 May 2025 02:20:28 -0700 Subject: [PATCH] Update character creation controller support to work better with gamepad mouse mode --- apps/openmw/mwgui/birth.cpp | 48 ++++++++++++----- apps/openmw/mwgui/birth.hpp | 5 ++ apps/openmw/mwgui/class.cpp | 102 +++++++++++++++++++++++++++++------- apps/openmw/mwgui/class.hpp | 12 ++++- apps/openmw/mwgui/race.cpp | 49 ++++++++++------- apps/openmw/mwgui/race.hpp | 4 ++ 6 files changed, 168 insertions(+), 52 deletions(-) diff --git a/apps/openmw/mwgui/birth.cpp b/apps/openmw/mwgui/birth.cpp index bf495273be..b121c1978b 100644 --- a/apps/openmw/mwgui/birth.cpp +++ b/apps/openmw/mwgui/birth.cpp @@ -50,15 +50,16 @@ namespace MWGui mBirthList->eventListSelectAccept += MyGUI::newDelegate(this, &BirthDialog::onAccept); mBirthList->eventListChangePosition += MyGUI::newDelegate(this, &BirthDialog::onSelectBirth); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption( + getWidget(mOkButton, "OKButton"); + mOkButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &BirthDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + mOkButton->setStateSelected(true); updateBirths(); updateSpells(); @@ -277,29 +278,50 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mBirthList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + mUsingGamepadGuiCursor = false; + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } return true; } + + bool BirthDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } } diff --git a/apps/openmw/mwgui/birth.hpp b/apps/openmw/mwgui/birth.hpp index 20db2b70de..8a7190b934 100644 --- a/apps/openmw/mwgui/birth.hpp +++ b/apps/openmw/mwgui/birth.hpp @@ -53,10 +53,15 @@ namespace MWGui MyGUI::ScrollView* mSpellArea; MyGUI::ImageBox* mBirthImage; std::vector mSpellItems; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; ESM::RefId mCurrentBirthId; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/class.cpp b/apps/openmw/mwgui/class.cpp index 25218c9e25..a7b5b36aa5 100644 --- a/apps/openmw/mwgui/class.cpp +++ b/apps/openmw/mwgui/class.cpp @@ -143,13 +143,14 @@ namespace MWGui getWidget(mClassImage, "ClassImage"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + getWidget(mOkButton, "OKButton"); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &PickClassDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + mOkButton->setStateSelected(true); updateClasses(); updateStats(); @@ -316,32 +317,53 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mClassList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + mUsingGamepadGuiCursor = false; + } + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) + { + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } return true; } + bool PickClassDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } + /* InfoBoxDialog */ void InfoBoxDialog::fitToText(MyGUI::TextBox* widget) @@ -569,14 +591,20 @@ namespace MWGui MyGUI::Button* descriptionButton; getWidget(descriptionButton, "DescriptionButton"); descriptionButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onDescriptionClicked); + mButtons.push_back(descriptionButton); MyGUI::Button* backButton; getWidget(backButton, "BackButton"); backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onBackClicked); + mButtons.push_back(backButton); MyGUI::Button* okButton; getWidget(okButton, "OKButton"); okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &CreateClassDialog::onOkClicked); + mButtons.push_back(okButton); + + if (Settings::gui().mControllerMenus) + okButton->setStateSelected(true); // Set default skills, attributes @@ -676,19 +704,57 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mControllerFocus == 0) + onDescriptionClicked(mButtons[0]); + else if (mControllerFocus == 1) + onBackClicked(mButtons[1]); + else + onOkClicked(mButtons[2]); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mButtons[1]); + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP || + arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) + { + mUsingGamepadGuiCursor = false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == 0) + mControllerFocus = mButtons.size() - 1; + else + mControllerFocus--; + mButtons[mControllerFocus]->setStateSelected(true); + mUsingGamepadGuiCursor = false; + } + else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) + { + mButtons[mControllerFocus]->setStateSelected(false); + if (mControllerFocus == mButtons.size() - 1) + mControllerFocus = 0; + else + mControllerFocus++; + mButtons[mControllerFocus]->setStateSelected(true); + mUsingGamepadGuiCursor = false; } return true; } + bool CreateClassDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) + { + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + return false; + } + // widget controls void CreateClassDialog::onDialogCancel() diff --git a/apps/openmw/mwgui/class.hpp b/apps/openmw/mwgui/class.hpp index 4567776beb..e2566ce6c0 100644 --- a/apps/openmw/mwgui/class.hpp +++ b/apps/openmw/mwgui/class.hpp @@ -138,7 +138,6 @@ namespace MWGui void onOkClicked(MyGUI::Widget* _sender); void onBackClicked(MyGUI::Widget* _sender); - bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; private: void updateClasses(); @@ -147,11 +146,18 @@ namespace MWGui MyGUI::ImageBox* mClassImage; MyGUI::ListBox* mClassList; MyGUI::TextBox* mSpecializationName; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; Widgets::MWAttributePtr mFavoriteAttribute[2]; Widgets::MWSkillPtr mMajorSkill[5]; Widgets::MWSkillPtr mMinorSkill[5]; ESM::RefId mCurrentClassId; + + bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; class SelectSpecializationDialog : public WindowModal @@ -325,6 +331,7 @@ namespace MWGui private: MyGUI::EditBox* mEditName; MyGUI::TextBox* mSpecializationName; + std::vector mButtons; Widgets::MWAttributePtr mFavoriteAttribute0, mFavoriteAttribute1; std::array mMajorSkill; std::array mMinorSkill; @@ -342,6 +349,9 @@ namespace MWGui Widgets::MWSkillPtr mAffectedSkill; bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; + bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + int mControllerFocus = 2; + bool mUsingGamepadGuiCursor = false; }; } #endif diff --git a/apps/openmw/mwgui/race.cpp b/apps/openmw/mwgui/race.cpp index 6a62fb3b47..1ff5cc4784 100644 --- a/apps/openmw/mwgui/race.cpp +++ b/apps/openmw/mwgui/race.cpp @@ -108,15 +108,16 @@ namespace MWGui MWBase::Environment::get().getWindowManager()->getGameSettingString("sRaceMenu7", "Specials")); getWidget(mSpellPowerList, "SpellPowerList"); - MyGUI::Button* backButton; - getWidget(backButton, "BackButton"); - backButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); + getWidget(mBackButton, "BackButton"); + mBackButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onBackClicked); - MyGUI::Button* okButton; - getWidget(okButton, "OKButton"); - okButton->setCaption( + getWidget(mOkButton, "OKButton"); + mOkButton->setCaption( MyGUI::UString(MWBase::Environment::get().getWindowManager()->getGameSettingString("sOK", {}))); - okButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + mOkButton->eventMouseButtonClick += MyGUI::newDelegate(this, &RaceDialog::onOkClicked); + + if (Settings::gui().mControllerMenus) + mOkButton->setStateSelected(true); updateRaces(); updateSkills(); @@ -467,15 +468,17 @@ namespace MWGui if (arg.button == SDL_CONTROLLER_BUTTON_A) { // Have A button do nothing so mouse controller still works. - return false; - } - else if (arg.button == SDL_CONTROLLER_BUTTON_START) - { - onOkClicked(nullptr); + if (mUsingGamepadGuiCursor) + return false; + + if (mOkButtonFocus) + onOkClicked(mOkButton); + else + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_B) { - onBackClicked(nullptr); + onBackClicked(mBackButton); } else if (arg.button == SDL_CONTROLLER_BUTTON_X) { @@ -494,20 +497,22 @@ namespace MWGui MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowUp, 0, false); + mUsingGamepadGuiCursor = false; } else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); winMgr->setKeyFocusWidget(mRaceList); winMgr->injectKeyPress(MyGUI::KeyCode::ArrowDown, 0, false); + mUsingGamepadGuiCursor = false; } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT) + else if ((arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT && mOkButtonFocus) || + (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT && !mOkButtonFocus)) { - onPreviewScroll(nullptr, 5); - } - else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT) - { - onPreviewScroll(nullptr, -5); + mOkButtonFocus = !mOkButtonFocus; + mOkButton->setStateSelected(mOkButtonFocus); + mBackButton->setStateSelected(!mOkButtonFocus); + mUsingGamepadGuiCursor = false; } return true; @@ -515,7 +520,11 @@ namespace MWGui bool RaceDialog::onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) { - if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) + if (arg.axis == SDL_CONTROLLER_AXIS_LEFTX || arg.axis == SDL_CONTROLLER_AXIS_LEFTY) + { + mUsingGamepadGuiCursor = true; + } + else if (arg.axis == SDL_CONTROLLER_AXIS_RIGHTX) { if (arg.value < -1000 || arg.value > 1000) onPreviewScroll(nullptr, arg.value < 0 ? 1 : -1); diff --git a/apps/openmw/mwgui/race.hpp b/apps/openmw/mwgui/race.hpp index 8589743b9e..c3b322ba8b 100644 --- a/apps/openmw/mwgui/race.hpp +++ b/apps/openmw/mwgui/race.hpp @@ -102,6 +102,8 @@ namespace MWGui MyGUI::ImageBox* mPreviewImage; MyGUI::ListBox* mRaceList; Gui::ScrollBar* mHeadRotate; + MyGUI::Button* mBackButton; + MyGUI::Button* mOkButton; MyGUI::Widget* mSkillList; std::vector mSkillItems; @@ -122,6 +124,8 @@ namespace MWGui bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override; bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) override; + bool mOkButtonFocus = true; + bool mUsingGamepadGuiCursor = false; }; } #endif