Allow LT and RT to toggle between open gui windows

This commit is contained in:
Andrew Lanzone 2025-05-15 00:46:02 -07:00
parent f055ccf5ba
commit 8c2ecc2a88
9 changed files with 103 additions and 13 deletions

View File

@ -382,7 +382,10 @@ namespace MWBase
/// Same as viewer->getCamera()->getCullMask(), provided for consistency. /// Same as viewer->getCamera()->getCullMask(), provided for consistency.
virtual uint32_t getCullMask() = 0; virtual uint32_t getCullMask() = 0;
virtual MWGui::WindowBase* getTopWindow() = 0; /// Return the window that should receive controller events
virtual MWGui::WindowBase* getActiveControllerWindow() = 0;
/// Cycle to the next window to receive controller events
virtual void cycleActiveControllerWindow(bool next) = 0;
// Used in Lua bindings // Used in Lua bindings
virtual const std::vector<MWGui::GuiMode>& getGuiModeStack() const = 0; virtual const std::vector<MWGui::GuiMode>& getGuiModeStack() const = 0;

View File

@ -398,4 +398,10 @@ namespace MWGui
} }
return false; return false;
} }
void ContainerWindow::setActiveControllerWindow(bool active)
{
mItemView->setActiveControllerWindow(active);
WindowBase::setActiveControllerWindow(active);
}
} }

View File

@ -40,6 +40,8 @@ namespace MWGui
std::string_view getWindowIdForLua() const override { return "Container"; } std::string_view getWindowIdForLua() const override { return "Container"; }
void setActiveControllerWindow(bool active) override;
private: private:
DragAndDrop* mDragAndDrop; DragAndDrop* mDragAndDrop;

View File

@ -180,6 +180,14 @@ namespace MWGui
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ItemView>("Widget"); MyGUI::FactoryManager::getInstance().registerFactory<MWGui::ItemView>("Widget");
} }
void ItemView::setActiveControllerWindow(bool active)
{
if (active)
updateControllerFocus(-1, mControllerFocus);
else
updateControllerFocus(mControllerFocus, -1);
}
void ItemView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) void ItemView::onControllerButtonEvent(const SDL_ControllerButtonEvent& arg)
{ {
if (!mItemCount) if (!mItemCount)

View File

@ -32,6 +32,7 @@ namespace MWGui
void resetScrollBars(); void resetScrollBars();
void setActiveControllerWindow(bool active);
int getControllerFocus() { return mControllerFocus; } int getControllerFocus() { return mControllerFocus; }
int getItemCount() { return mItemCount; } int getItemCount() { return mItemCount; }
void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg); void onControllerButtonEvent(const SDL_ControllerButtonEvent& arg);

View File

@ -62,11 +62,13 @@ namespace MWGui
// REMOVEME // REMOVEME
// virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0; // virtual bool onControllerButtonEvent(const SDL_ControllerButtonEvent& arg) = 0;
// virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0; // virtual bool onControllerThumbstickEvent(const SDL_ControllerAxisEvent& arg) = 0;
virtual void setActiveControllerWindow(bool active) { mActiveControllerWindow = active; }
protected: protected:
virtual void onTitleDoubleClicked(); virtual void onTitleDoubleClicked();
MyGUI::Widget* mMouseFocus = nullptr; MyGUI::Widget* mMouseFocus = nullptr;
bool mActiveControllerWindow = false;
void trackFocusEvents(MyGUI::Widget* widget); void trackFocusEvents(MyGUI::Widget* widget);
private: private:

View File

@ -859,7 +859,7 @@ namespace MWGui
mHud->setPlayerPos(x, y, u, v); mHud->setPlayerPos(x, y, u, v);
} }
WindowBase* WindowManager::getTopWindow() WindowBase* WindowManager::getActiveControllerWindow()
{ {
if (!mCurrentModals.empty()) if (!mCurrentModals.empty())
return mCurrentModals.back(); return mCurrentModals.back();
@ -869,15 +869,18 @@ namespace MWGui
if (!mGuiModes.empty()) if (!mGuiModes.empty())
{ {
GuiModeState& state = mGuiModeStates[mGuiModes.back()]; GuiMode mode = mGuiModes.back();
GuiModeState& state = mGuiModeStates[mode];
int activeIndex = std::clamp(mActiveControllerWindows[mode], 0, (int)state.mWindows.size() - 1);
// REMOVEME // REMOVEME
Log(Debug::Error) << "getTopWindow: " << state.mWindows.size() << " windows in state " << mGuiModes.back(); Log(Debug::Error) << "getActiveControllerWindow: " << state.mWindows.size() << " windows in state, mActiveControllerWindows[mode] = " << mActiveControllerWindows[mode];
// find the topmost window
for (WindowBase* window : state.mWindows) // If the active window is no longer visible, find the next visible window.
if (window->isVisible()) if (!state.mWindows[activeIndex]->isVisible())
return window; cycleActiveControllerWindow(true);
else
Log(Debug::Error) << "-- Skipping hidden window " << window; return state.mWindows[activeIndex];
} }
else else
{ {
@ -893,6 +896,48 @@ namespace MWGui
return nullptr; return nullptr;
} }
void WindowManager::cycleActiveControllerWindow(bool next)
{
if (mGuiModes.empty())
return;
GuiMode mode = mGuiModes.back();
int winCount = mGuiModeStates[mode].mWindows.size();
int activeIndex = 0;
if (winCount > 1)
{
// Find next/previous visible window
activeIndex = mActiveControllerWindows[mode];
int delta = next ? 1 : -1;
for (int i = 0; i < winCount; i++)
{
activeIndex += delta;
if (activeIndex < 0)
activeIndex = winCount - 1;
else if (activeIndex >= winCount)
activeIndex = 0;
if (mGuiModeStates[mode].mWindows[activeIndex]->isVisible())
break;
}
}
// REMOVEME
Log(Debug::Error) << "focusNextWindow: mode=" << mode << ", activeIndex=" << activeIndex;
if (mActiveControllerWindows[mode] != activeIndex)
{
mActiveControllerWindows[mode] = activeIndex;
for (int i = 0; i < winCount; i++)
{
mGuiModeStates[mode].mWindows[i]->setActiveControllerWindow(i == activeIndex);
}
playSound(ESM::RefId::stringRefId("Menu Click"));
}
}
void WindowManager::update(float frameDuration) void WindowManager::update(float frameDuration)
{ {
handleScheduledMessageBoxes(); handleScheduledMessageBoxes();
@ -1316,6 +1361,13 @@ namespace MWGui
{ {
for (WindowBase* window : mGuiModeStates[mode].mWindows) for (WindowBase* window : mGuiModeStates[mode].mWindows)
window->setPtr(arg); window->setPtr(arg);
// Activate first visible window
mActiveControllerWindows[mode] = -1;
cycleActiveControllerWindow(true);
// REMOVEME
Log(Debug::Error) << "pushGuiMode: mode=" << mode << ", activeIndex=" << mActiveControllerWindows[mode];
} }
catch (...) catch (...)
{ {

View File

@ -387,7 +387,8 @@ namespace MWGui
void asyncPrepareSaveMap() override; void asyncPrepareSaveMap() override;
WindowBase* getTopWindow() override; WindowBase* getActiveControllerWindow() override;
void cycleActiveControllerWindow(bool next) override;
// Used in Lua bindings // Used in Lua bindings
const std::vector<GuiMode>& getGuiModeStack() const override { return mGuiModes; } const std::vector<GuiMode>& getGuiModeStack() const override { return mGuiModes; }
@ -495,6 +496,8 @@ namespace MWGui
std::map<GuiMode, GuiModeState> mGuiModeStates; std::map<GuiMode, GuiModeState> mGuiModeStates;
// The currently active stack of GUI modes (top mode is the one we are in). // The currently active stack of GUI modes (top mode is the one we are in).
std::vector<GuiMode> mGuiModes; std::vector<GuiMode> mGuiModes;
// The active window for controller mode for each GUI mode.
std::map<GuiMode, int> mActiveControllerWindows;
std::unique_ptr<SDLUtil::SDLCursorManager> mCursorManager; std::unique_ptr<SDLUtil::SDLCursorManager> mCursorManager;

View File

@ -243,7 +243,7 @@ namespace MWInput
{ {
if (Settings::gui().mControllerMenus) if (Settings::gui().mControllerMenus)
{ {
MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getActiveControllerWindow();
if (topWin && topWin->onControllerButtonEvent(arg)) if (topWin && topWin->onControllerButtonEvent(arg))
return true; return true;
} }
@ -311,7 +311,20 @@ namespace MWInput
{ {
if (Settings::gui().mControllerMenus) if (Settings::gui().mControllerMenus)
{ {
MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getTopWindow(); // Left and right triggers toggle through open GUI windows.
if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT)
{
if (arg.value == 32767) // Treat like a button.
MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(true);
return true;
}
else if (arg.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT)
{
if (arg.value == 32767) // Treat like a button.
MWBase::Environment::get().getWindowManager()->cycleActiveControllerWindow(false);
return true;
}
MWGui::WindowBase* topWin = MWBase::Environment::get().getWindowManager()->getActiveControllerWindow();
if (topWin && topWin->onControllerThumbstickEvent(arg)) if (topWin && topWin->onControllerThumbstickEvent(arg))
return true; return true;
} }