Improve scrolling in list windows and fix a crash in a few menus when no items are selectable

This commit is contained in:
Andrew Lanzone 2025-05-26 23:07:20 -07:00
parent 274434e0d6
commit f67aae086a
8 changed files with 45 additions and 24 deletions

View File

@ -473,7 +473,8 @@ namespace MWGui
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)
{
onButtonClicked(mButtons[mControllerFocus]);
if (mControllerFocus >= 0 && mControllerFocus < mButtons.size())
onButtonClicked(mButtons[mControllerFocus]);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_B)
{

View File

@ -446,6 +446,7 @@ namespace MWGui
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)
{
mControllerFocus = std::clamp(mControllerFocus, 0, (int)mButtons.size() - 1);
buttonActivated(mButtons[mControllerFocus]);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_B)

View File

@ -78,7 +78,7 @@ namespace MWGui
toAdd->eventMouseButtonClick += MyGUI::newDelegate(this, &SpellBuyingWindow::onSpellButtonClick);
mSpellsWidgetMap.insert(std::make_pair(toAdd, spell.mId));
if (price <= playerGold)
mSpellButtons.emplace_back(toAdd);
mSpellButtons.emplace_back(std::make_pair(toAdd, mSpellsWidgetMap.size()));
}
void SpellBuyingWindow::clearSpells()
@ -143,7 +143,7 @@ namespace MWGui
{
mControllerFocus = 0;
if (mSpellButtons.size() > 0)
mSpellButtons[0]->setStateSelected(true);
mSpellButtons[0].first->setStateSelected(true);
}
// Canvas size must be expressed with VScroll disabled, otherwise MyGUI would expand the scroll area when the
@ -221,7 +221,8 @@ namespace MWGui
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)
{
onSpellButtonClick(mSpellButtons[mControllerFocus]);
if (mControllerFocus >= 0 && mControllerFocus < mSpellButtons.size())
onSpellButtonClick(mSpellButtons[mControllerFocus].first);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_B)
{
@ -232,25 +233,29 @@ namespace MWGui
if (mSpellButtons.size() <= 1)
return true;
mSpellButtons[mControllerFocus]->setStateSelected(false);
mSpellButtons[mControllerFocus].first->setStateSelected(false);
mControllerFocus = wrap(mControllerFocus - 1, mSpellButtons.size());
mSpellButtons[mControllerFocus]->setStateSelected(true);
mSpellButtons[mControllerFocus].first->setStateSelected(true);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
{
if (mSpellButtons.size() <= 1)
return true;
mSpellButtons[mControllerFocus]->setStateSelected(false);
mSpellButtons[mControllerFocus].first->setStateSelected(false);
mControllerFocus = wrap(mControllerFocus + 1, mSpellButtons.size());
mSpellButtons[mControllerFocus]->setStateSelected(true);
mSpellButtons[mControllerFocus].first->setStateSelected(true);
}
// Scroll the list to keep the active item in view
if (mControllerFocus <= 5)
int line = mSpellButtons[mControllerFocus].second;
if (line <= 5)
mSpellsView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mSpellsView->setViewOffset(MyGUI::IntPoint(0, -10 * (mControllerFocus - 5)));
{
const int lineHeight = Settings::gui().mFontSize + 2;
mSpellsView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5)));
}
return true;
}

View File

@ -39,7 +39,8 @@ namespace MWGui
MyGUI::ScrollView* mSpellsView;
std::map<MyGUI::Widget*, ESM::RefId> mSpellsWidgetMap;
std::vector<MyGUI::Button*> mSpellButtons;
/// List of enabled/purchasable spells and their index in the full list.
std::vector<std::pair<MyGUI::Button*, int>> mSpellButtons;
void onCancelButtonClicked(MyGUI::Widget* _sender);
void onSpellButtonClick(MyGUI::Widget* _sender);

View File

@ -122,7 +122,7 @@ namespace MWGui
t->setCaption(spell.mName + captionSuffix);
t->setTextAlign(MyGUI::Align::Left);
adjustSpellWidget(spell, i, t);
mButtons.emplace_back(t);
mButtons.emplace_back(std::make_pair(t, i));
if (!spell.mCostColumn.empty() && mShowCostColumn)
{
@ -339,7 +339,7 @@ namespace MWGui
// Select the focused item, if any.
if (mControllerFocus >= 0 && mControllerFocus < mButtons.size())
{
onSpellSelected(mButtons.at(mControllerFocus));
onSpellSelected(mButtons[mControllerFocus].first);
MWBase::Environment::get().getWindowManager()->playSound(ESM::RefId::stringRefId("Menu Click"));
}
}
@ -348,12 +348,16 @@ namespace MWGui
// Toggle info tooltip
mControllerTooltip = !mControllerTooltip;
if (mControllerTooltip && mControllerFocus >= 0 && mControllerFocus < mButtons.size())
MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons.at(mControllerFocus));
MWBase::Environment::get().getInputManager()->warpMouseToWidget(mButtons[mControllerFocus].first);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP)
mControllerFocus--;
else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
mControllerFocus++;
else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT)
mControllerFocus = std::max(0, mControllerFocus - 10);
else if (arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
mControllerFocus = std::min(mControllerFocus + 10, (int)mButtons.size() - 1);
else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
{
// Jump to first item in previous group
@ -380,10 +384,7 @@ namespace MWGui
}
}
if (mControllerFocus < 0)
mControllerFocus = mButtons.size() - 1;
else if (mControllerFocus >= mButtons.size())
mControllerFocus = 0;
mControllerFocus = wrap(mControllerFocus, mButtons.size());
if (prevFocus != mControllerFocus)
updateControllerFocus(prevFocus, mControllerFocus);
@ -396,19 +397,29 @@ namespace MWGui
if (prevFocus >= 0 && prevFocus < mButtons.size())
{
Gui::SharedStateButton* prev = mButtons.at(prevFocus);
Gui::SharedStateButton* prev = mButtons[prevFocus].first;
if (prev)
prev->onMouseLostFocus(nullptr);
}
if (newFocus >= 0 && newFocus < mButtons.size())
{
Gui::SharedStateButton* focused = mButtons.at(newFocus);
Gui::SharedStateButton* focused = mButtons[newFocus].first;
if (focused)
{
focused->onMouseSetFocus(nullptr);
if (mControllerTooltip)
MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused);
// Scroll the list to keep the active item in view
int line = mButtons[newFocus].second;
if (line <= 5)
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
else
{
const int lineHeight = focused->getHeight();
mScrollView->setViewOffset(MyGUI::IntPoint(0, -lineHeight * (line - 5)));
}
}
}
}

View File

@ -94,8 +94,8 @@ namespace MWGui
void addGroup(const std::string& label1, const std::string& label2);
void adjustSpellWidget(const Spell& spell, SpellModel::ModelIndex index, MyGUI::Widget* widget);
/// Keep a list of buttons for controller navigation
std::vector<Gui::SharedStateButton *> mButtons;
/// Keep a list of buttons for controller navigation and their index in the full list.
std::vector<std::pair<Gui::SharedStateButton *, int>> mButtons;
/// Keep a list of group offsets for controller navigation
std::vector<int> mGroupIndices;

View File

@ -251,7 +251,8 @@ namespace MWGui
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)
{
onTrainingSelected(mTrainingButtons[mControllerFocus]);
if (mControllerFocus >= 0 && mControllerFocus < mTrainingButtons.size())
onTrainingSelected(mTrainingButtons[mControllerFocus]);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_B)
{

View File

@ -258,7 +258,8 @@ namespace MWGui
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)
{
onTravelButtonClick(mDestinationButtons[mControllerFocus]);
if (mControllerFocus >= 0 && mControllerFocus < mDestinationButtons.size())
onTravelButtonClick(mDestinationButtons[mControllerFocus]);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_B)
{