Add controller support to barter window

This commit is contained in:
Andrew Lanzone 2025-05-26 21:08:05 -07:00
parent 71fd8b8840
commit 14b0c9afbe
6 changed files with 127 additions and 5 deletions

View File

@ -41,7 +41,7 @@ namespace MWGui
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
mSlider->setScrollRange(maxCount); mSlider->setScrollRange(maxCount);
mItemText->setCaption(item); mItemText->setCaptionWithReplacing(item);
int width = std::max(mItemText->getTextSize().width + 160, 320); int width = std::max(mItemText->getTextSize().width + 160, 320);
setCoord(viewSize.width / 2 - width / 2, viewSize.height / 2 - mMainWidget->getHeight() / 2, width, setCoord(viewSize.width / 2 - width / 2, viewSize.height / 2 - mMainWidget->getHeight() / 2, width,
@ -57,6 +57,13 @@ namespace MWGui
mItemEdit->setValue(maxCount); mItemEdit->setValue(maxCount);
} }
void CountDialog::setCount(int count)
{
count = std::clamp(count, 1, (int)mSlider->getScrollRange());
mSlider->setScrollPosition(count - 1);
mItemEdit->setValue(count);
}
void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender) void CountDialog::onCancelButtonClicked(MyGUI::Widget* _sender)
{ {
setVisible(false); setVisible(false);

View File

@ -17,6 +17,7 @@ namespace MWGui
public: public:
CountDialog(); CountDialog();
void openCountDialog(const std::string& item, const std::string& message, const int maxCount); void openCountDialog(const std::string& item, const std::string& message, const int maxCount);
void setCount(int count);
typedef MyGUI::delegates::MultiDelegate<MyGUI::Widget*, int> EventHandle_WidgetInt; typedef MyGUI::delegates::MultiDelegate<MyGUI::Widget*, int> EventHandle_WidgetInt;

View File

@ -133,7 +133,6 @@ namespace MWGui
if (Settings::gui().mControllerMenus) if (Settings::gui().mControllerMenus)
{ {
mControllerButtons.b = "#{sBack}"; mControllerButtons.b = "#{sBack}";
mControllerButtons.r1 = "Filter";
mControllerButtons.r3 = "#{sInfo}"; mControllerButtons.r3 = "#{sInfo}";
} }
@ -892,7 +891,7 @@ namespace MWGui
break; break;
case MWGui::GM_Barter: case MWGui::GM_Barter:
mControllerButtons.a = "#{sSell}"; mControllerButtons.a = "#{sSell}";
mControllerButtons.x = ""; mControllerButtons.x = "#{sOffer}";
mControllerButtons.y = ""; mControllerButtons.y = "";
mControllerButtons.r2 = "#{sBarter}"; mControllerButtons.r2 = "#{sBarter}";
break; break;
@ -959,6 +958,14 @@ namespace MWGui
(MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0); (MWGui::ContainerWindow *)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(0);
containerWindow->onControllerButtonEvent(arg); containerWindow->onControllerButtonEvent(arg);
} }
else if (mGuiMode == MWGui::GM_Barter)
{
// Offer. Pass the button press to the barter window and let it do the logic
// of making an offer.
MWGui::TradeWindow* tradeWindow =
(MWGui::TradeWindow*)MWBase::Environment::get().getWindowManager()->getGuiModeWindows(mGuiMode).at(1);
tradeWindow->onControllerButtonEvent(arg);
}
} }
else if (arg.button == SDL_CONTROLLER_BUTTON_Y) else if (arg.button == SDL_CONTROLLER_BUTTON_Y)
{ {

View File

@ -52,12 +52,14 @@ namespace MWGui
MyGUI::Widget* dragArea = mScrollView->getChildAt(0); MyGUI::Widget* dragArea = mScrollView->getChildAt(0);
int maxHeight = mScrollView->getHeight(); int maxHeight = mScrollView->getHeight();
mRows = maxHeight / 42; mRows = std::max(maxHeight / 42, 1);
mRows = std::max(mRows, 1);
mItemCount = dragArea->getChildCount(); mItemCount = dragArea->getChildCount();
bool showScrollbar = int(std::ceil(mItemCount / float(mRows))) > mScrollView->getWidth() / 42; bool showScrollbar = int(std::ceil(mItemCount / float(mRows))) > mScrollView->getWidth() / 42;
if (showScrollbar) if (showScrollbar)
{
maxHeight -= 18; maxHeight -= 18;
mRows = std::max(maxHeight / 42, 1);
}
for (unsigned int i = 0; i < mItemCount; ++i) for (unsigned int i = 0; i < mItemCount; ++i)
{ {
@ -262,6 +264,13 @@ namespace MWGui
focused->setControllerFocus(true); focused->setControllerFocus(true);
if (mControllerTooltip) if (mControllerTooltip)
MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused); MWBase::Environment::get().getInputManager()->warpMouseToWidget(focused);
// Scroll the list to keep the active item in view
int column = newFocus / mRows;
if (column <= 3)
mScrollView->setViewOffset(MyGUI::IntPoint(0, 0));
else
mScrollView->setViewOffset(MyGUI::IntPoint(-42 * (column - 3), 0));
} }
} }
} }

View File

@ -168,6 +168,12 @@ namespace MWGui
std::numeric_limits<int>::min() + 1); // disallow INT_MIN since abs(INT_MIN) is undefined std::numeric_limits<int>::min() + 1); // disallow INT_MIN since abs(INT_MIN) is undefined
setCoord(400, 0, 400, 300); setCoord(400, 0, 400, 300);
mControllerButtons.a = "#{sBuy}";
mControllerButtons.b = "#{sBack}";
mControllerButtons.x = "#{sOffer}";
mControllerButtons.r3 = "#{sInfo}";
mControllerButtons.l2 = "#{sInventory}";
} }
void TradeWindow::setPtr(const MWWorld::Ptr& actor) void TradeWindow::setPtr(const MWWorld::Ptr& actor)
@ -201,6 +207,10 @@ namespace MWGui
onFilterChanged(mFilterAll); onFilterChanged(mFilterAll);
mFilterEdit->setCaption({}); mFilterEdit->setCaption({});
// Cycle to the buy window if it's not active.
if (Settings::gui().mControllerMenus && !mActiveControllerWindow)
MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(true);
} }
void TradeWindow::onFrame(float dt) void TradeWindow::onFrame(float dt)
@ -339,6 +349,13 @@ namespace MWGui
} }
} }
void TradeWindow::onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount)
{
mCurrentBalance = mCurrentBalance < 0 ? -offerAmount : offerAmount;
updateLabels();
onOfferButtonClicked(mOfferButton);
}
void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender) void TradeWindow::onOfferButtonClicked(MyGUI::Widget* _sender)
{ {
TradeItemModel* playerItemModel TradeItemModel* playerItemModel
@ -643,4 +660,81 @@ namespace MWGui
if (mTradeModel && mTradeModel->usesContainer(ptr)) if (mTradeModel && mTradeModel->usesContainer(ptr))
MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter); MWBase::Environment::get().getWindowManager()->removeGuiMode(GM_Barter);
} }
bool TradeWindow::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg)
{
if (arg.button == SDL_CONTROLLER_BUTTON_A)
{
int index = mItemView->getControllerFocus();
if (index >= 0 && index < mItemView->getItemCount())
onItemSelected(index);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_B)
{
onCancelButtonClicked(mCancelButton);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_X)
{
if (mCurrentBalance == 0)
return true;
// Show a count dialog to allow for bartering.
CountDialog* dialog = MWBase::Environment::get().getWindowManager()->getCountDialog();
if (mCurrentBalance < 0)
{
// Buying from the merchant
dialog->openCountDialog("#{sTotalcost}:", "#{sOffer}", -mCurrentMerchantOffer);
dialog->setCount(-mCurrentBalance);
}
else
{
// Selling to the merchant
dialog->openCountDialog("#{sTotalsold}:", "#{sOffer}", getMerchantGold());
dialog->setCount(mCurrentBalance);
}
dialog->eventOkClicked.clear();
dialog->eventOkClicked += MyGUI::newDelegate(this, &TradeWindow::onOfferSubmitted);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER)
{
if (mFilterAll->getStateSelected())
onFilterChanged(mFilterMisc);
else if (mFilterWeapon->getStateSelected())
onFilterChanged(mFilterAll);
else if (mFilterApparel->getStateSelected())
onFilterChanged(mFilterWeapon);
else if (mFilterMagic->getStateSelected())
onFilterChanged(mFilterApparel);
else if (mFilterMisc->getStateSelected())
onFilterChanged(mFilterMagic);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER)
{
if (mFilterAll->getStateSelected())
onFilterChanged(mFilterWeapon);
else if (mFilterWeapon->getStateSelected())
onFilterChanged(mFilterApparel);
else if (mFilterApparel->getStateSelected())
onFilterChanged(mFilterMagic);
else if (mFilterMagic->getStateSelected())
onFilterChanged(mFilterMisc);
else if (mFilterMisc->getStateSelected())
onFilterChanged(mFilterAll);
}
else if (arg.button == SDL_CONTROLLER_BUTTON_RIGHTSTICK ||
arg.button == SDL_CONTROLLER_BUTTON_DPAD_UP ||
arg.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN ||
arg.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT ||
arg.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
{
mItemView->onControllerButtonEvent(arg.button);
}
return true;
}
void TradeWindow::setActiveControllerWindow(bool active)
{
mItemView->setActiveControllerWindow(active);
WindowBase::setActiveControllerWindow(active);
}
} }

View File

@ -47,6 +47,9 @@ namespace MWGui
std::string_view getWindowIdForLua() const override { return "Trade"; } std::string_view getWindowIdForLua() const override { return "Trade"; }
bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) override;
void setActiveControllerWindow(bool active) override;
private: private:
ItemView* mItemView; ItemView* mItemView;
SortFilterItemModel* mSortModel; SortFilterItemModel* mSortModel;
@ -102,6 +105,7 @@ namespace MWGui
void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id); void onBalanceButtonReleased(MyGUI::Widget* _sender, int _left, int _top, MyGUI::MouseButton _id);
void onBalanceValueChanged(int value); void onBalanceValueChanged(int value);
void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller); void onRepeatClick(MyGUI::Widget* widget, MyGUI::ControllerItem* controller);
void onOfferSubmitted(MyGUI::Widget* _sender, int offerAmount);
void addRepeatController(MyGUI::Widget* widget); void addRepeatController(MyGUI::Widget* widget);