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.
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
virtual const std::vector<MWGui::GuiMode>& getGuiModeStack() const = 0;

View File

@ -398,4 +398,10 @@ namespace MWGui
}
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"; }
void setActiveControllerWindow(bool active) override;
private:
DragAndDrop* mDragAndDrop;

View File

@ -180,6 +180,14 @@ namespace MWGui
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)
{
if (!mItemCount)

View File

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

View File

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

View File

@ -859,7 +859,7 @@ namespace MWGui
mHud->setPlayerPos(x, y, u, v);
}
WindowBase* WindowManager::getTopWindow()
WindowBase* WindowManager::getActiveControllerWindow()
{
if (!mCurrentModals.empty())
return mCurrentModals.back();
@ -869,15 +869,18 @@ namespace MWGui
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
Log(Debug::Error) << "getTopWindow: " << state.mWindows.size() << " windows in state " << mGuiModes.back();
// find the topmost window
for (WindowBase* window : state.mWindows)
if (window->isVisible())
return window;
else
Log(Debug::Error) << "-- Skipping hidden window " << window;
Log(Debug::Error) << "getActiveControllerWindow: " << state.mWindows.size() << " windows in state, mActiveControllerWindows[mode] = " << mActiveControllerWindows[mode];
// If the active window is no longer visible, find the next visible window.
if (!state.mWindows[activeIndex]->isVisible())
cycleActiveControllerWindow(true);
return state.mWindows[activeIndex];
}
else
{
@ -893,6 +896,48 @@ namespace MWGui
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)
{
handleScheduledMessageBoxes();
@ -1316,6 +1361,13 @@ namespace MWGui
{
for (WindowBase* window : mGuiModeStates[mode].mWindows)
window->setPtr(arg);
// Activate first visible window
mActiveControllerWindows[mode] = -1;
cycleActiveControllerWindow(true);
// REMOVEME
Log(Debug::Error) << "pushGuiMode: mode=" << mode << ", activeIndex=" << mActiveControllerWindows[mode];
}
catch (...)
{

View File

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

View File

@ -243,7 +243,7 @@ namespace MWInput
{
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))
return true;
}
@ -311,7 +311,20 @@ namespace MWInput
{
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))
return true;
}