1
0
mirror of https://gitlab.com/OpenMW/openmw.git synced 2025-02-19 03:39:58 +00:00
OpenMW/apps/openmw/mwgui/windowmanagerimp.cpp
AnyOldName3 28131fd62b Fixes for a whole bunch of warnings
These warnings were always enabled, but we didn't see them due to https://gitlab.com/OpenMW/openmw/-/issues/7882.
I do not fully understand the cause of 7822 as I can't repro it in a minimal CMake project.

Some of these fixes are thought through.
Some are sensible best guesses.
Some are kind of a stab in the dark as I don't know whether there was a
possible bug the warning was telling me about that I've done nothing to
help by introducing a static_cast.

Nearly all of these warnings were about some kind of narrowing
conversion, so I'm not sure why they weren't firing with GCC and Clang,
which have -Wall -Wextra -pedantic set, which should imply -Wnarrowing,
and they can't have been affected by 7882.

There were also some warnings being triggered from Boost code.
The vast majority of library headers that do questionable things weren't
firing warnings off, but for some reason, /external:I wasn't putting
these Boost headers into external mode.

We need these warnings dealt with one way or another so we can switch
the default Windows CI from MSBuild (which doesn't do ccache) to Ninja
(which does).
I have the necessary magic for that on a branch, but the branch won't
build because of these warnings.
2024-03-14 23:39:33 +00:00

2401 lines
81 KiB
C++

#include "windowmanagerimp.hpp"
#include <algorithm>
#include <cassert>
#include <chrono>
#include <filesystem>
#include <thread>
#include <osgViewer/Viewer>
#include <MyGUI_ClipboardManager.h>
#include <MyGUI_FactoryManager.h>
#include <MyGUI_InputManager.h>
#include <MyGUI_LanguageManager.h>
#include <MyGUI_PointerManager.h>
#include <MyGUI_UString.h>
// For BT_NO_PROFILE
#include <LinearMath/btQuickprof.h>
#include <SDL_clipboard.h>
#include <SDL_keyboard.h>
#include <components/debug/debuglog.hpp>
#include <components/esm3/esmreader.hpp>
#include <components/esm3/esmwriter.hpp>
#include <components/fontloader/fontloader.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/resourcesystem.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/sceneutil/workqueue.hpp>
#include <components/translation/translation.hpp>
#include <components/myguiplatform/additivelayer.hpp>
#include <components/myguiplatform/myguiplatform.hpp>
#include <components/myguiplatform/myguirendermanager.hpp>
#include <components/myguiplatform/scalinglayer.hpp>
#include <components/vfs/manager.hpp>
#include <components/widgets/tags.hpp>
#include <components/widgets/widgets.hpp>
#include <components/misc/frameratelimiter.hpp>
#include <components/l10n/manager.hpp>
#include <components/lua_ui/util.hpp>
#include <components/lua_ui/widget.hpp>
#include <components/settings/values.hpp>
#include "../mwbase/environment.hpp"
#include "../mwbase/inputmanager.hpp"
#include "../mwbase/luamanager.hpp"
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/statemanager.hpp"
#include "../mwbase/world.hpp"
#include "../mwrender/vismask.hpp"
#include "../mwworld/cellstore.hpp"
#include "../mwworld/class.hpp"
#include "../mwworld/esmstore.hpp"
#include "../mwworld/globals.hpp"
#include "../mwworld/player.hpp"
#include "../mwmechanics/actorutil.hpp"
#include "../mwmechanics/npcstats.hpp"
#include "../mwrender/postprocessor.hpp"
#include "alchemywindow.hpp"
#include "backgroundimage.hpp"
#include "bookpage.hpp"
#include "bookwindow.hpp"
#include "companionwindow.hpp"
#include "confirmationdialog.hpp"
#include "console.hpp"
#include "container.hpp"
#include "controllers.hpp"
#include "countdialog.hpp"
#include "cursor.hpp"
#include "debugwindow.hpp"
#include "dialogue.hpp"
#include "enchantingdialog.hpp"
#include "exposedwindow.hpp"
#include "hud.hpp"
#include "inventorywindow.hpp"
#include "itemchargeview.hpp"
#include "itemview.hpp"
#include "itemwidget.hpp"
#include "jailscreen.hpp"
#include "journalviewmodel.hpp"
#include "journalwindow.hpp"
#include "keyboardnavigation.hpp"
#include "levelupdialog.hpp"
#include "loadingscreen.hpp"
#include "mainmenu.hpp"
#include "merchantrepair.hpp"
#include "postprocessorhud.hpp"
#include "quickkeysmenu.hpp"
#include "recharge.hpp"
#include "repair.hpp"
#include "resourceskin.hpp"
#include "screenfader.hpp"
#include "scrollwindow.hpp"
#include "settingswindow.hpp"
#include "spellbuyingwindow.hpp"
#include "spellview.hpp"
#include "spellwindow.hpp"
#include "statswindow.hpp"
#include "tradewindow.hpp"
#include "trainingwindow.hpp"
#include "travelwindow.hpp"
#include "videowidget.hpp"
#include "waitdialog.hpp"
namespace MWGui
{
namespace
{
Settings::SettingValue<bool>* findHiddenSetting(GuiWindow window)
{
switch (window)
{
case GW_Inventory:
return &Settings::windows().mInventoryHidden;
case GW_Map:
return &Settings::windows().mMapHidden;
case GW_Magic:
return &Settings::windows().mSpellsHidden;
case GW_Stats:
return &Settings::windows().mStatsHidden;
default:
return nullptr;
}
}
}
WindowManager::WindowManager(SDL_Window* window, osgViewer::Viewer* viewer, osg::Group* guiRoot,
Resource::ResourceSystem* resourceSystem, SceneUtil::WorkQueue* workQueue, const std::filesystem::path& logpath,
bool consoleOnlyScripts, Translation::Storage& translationDataStorage, ToUTF8::FromType encoding,
const std::string& versionDescription, bool useShaders, Files::ConfigurationManager& cfgMgr)
: mOldUpdateMask(0)
, mOldCullMask(0)
, mStore(nullptr)
, mResourceSystem(resourceSystem)
, mWorkQueue(workQueue)
, mViewer(viewer)
, mConsoleOnlyScripts(consoleOnlyScripts)
, mCurrentModals()
, mHud(nullptr)
, mMap(nullptr)
, mStatsWindow(nullptr)
, mConsole(nullptr)
, mDialogueWindow(nullptr)
, mInventoryWindow(nullptr)
, mScrollWindow(nullptr)
, mBookWindow(nullptr)
, mCountDialog(nullptr)
, mTradeWindow(nullptr)
, mSettingsWindow(nullptr)
, mConfirmationDialog(nullptr)
, mSpellWindow(nullptr)
, mQuickKeysMenu(nullptr)
, mLoadingScreen(nullptr)
, mWaitDialog(nullptr)
, mVideoBackground(nullptr)
, mVideoWidget(nullptr)
, mWerewolfFader(nullptr)
, mBlindnessFader(nullptr)
, mHitFader(nullptr)
, mScreenFader(nullptr)
, mDebugWindow(nullptr)
, mPostProcessorHud(nullptr)
, mJailScreen(nullptr)
, mContainerWindow(nullptr)
, mTranslationDataStorage(translationDataStorage)
, mInputBlocker(nullptr)
, mHudEnabled(true)
, mCursorVisible(true)
, mCursorActive(true)
, mPlayerBounty(-1)
, mGuiModes()
, mGarbageDialogs()
, mShown(GW_ALL)
, mForceHidden(GW_None)
, mAllowed(GW_ALL)
, mRestAllowed(true)
, mEncoding(encoding)
, mVersionDescription(versionDescription)
, mWindowVisible(true)
, mCfgMgr(cfgMgr)
{
int w, h;
SDL_GetWindowSize(window, &w, &h);
int dw, dh;
SDL_GL_GetDrawableSize(window, &dw, &dh);
mScalingFactor = Settings::gui().mScalingFactor * (dw / w);
mGuiPlatform = std::make_unique<osgMyGUI::Platform>(viewer, guiRoot, resourceSystem->getImageManager(),
resourceSystem->getVFS(), mScalingFactor, "mygui", logpath / "MyGUI.log");
mGui = std::make_unique<MyGUI::Gui>();
mGui->initialise({});
createTextures();
MyGUI::LanguageManager::getInstance().eventRequestTag = MyGUI::newDelegate(this, &WindowManager::onRetrieveTag);
// Load fonts
mFontLoader = std::make_unique<Gui::FontLoader>(encoding, resourceSystem->getVFS(), mScalingFactor);
// Register own widgets with MyGUI
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSkill>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWAttribute>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSpell>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWEffectList>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWSpellEffect>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Widgets::MWDynamicStat>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Window>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<VideoWidget>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<BackgroundImage>("Widget");
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::AdditiveLayer>("Layer");
MyGUI::FactoryManager::getInstance().registerFactory<osgMyGUI::ScalingLayer>("Layer");
BookPage::registerMyGUIComponents();
PostProcessorHud::registerMyGUIComponents();
ItemView::registerComponents();
ItemChargeView::registerComponents();
ItemWidget::registerComponents();
SpellView::registerComponents();
Gui::registerAllWidgets();
LuaUi::registerAllWidgets();
MyGUI::FactoryManager::getInstance().registerFactory<MWGui::Controllers::ControllerFollowMouse>("Controller");
MyGUI::FactoryManager::getInstance().registerFactory<ResourceImageSetPointerFix>(
"Resource", "ResourceImageSetPointer");
MyGUI::FactoryManager::getInstance().registerFactory<AutoSizedResourceSkin>(
"Resource", "AutoSizedResourceSkin");
MyGUI::ResourceManager::getInstance().load("core.xml");
const bool keyboardNav = Settings::gui().mKeyboardNavigation;
mKeyboardNavigation = std::make_unique<KeyboardNavigation>();
mKeyboardNavigation->setEnabled(keyboardNav);
Gui::ImageButton::setDefaultNeedKeyFocus(keyboardNav);
auto loadingScreen = std::make_unique<LoadingScreen>(mResourceSystem, mViewer);
mLoadingScreen = loadingScreen.get();
mWindows.push_back(std::move(loadingScreen));
// set up the hardware cursor manager
mCursorManager = std::make_unique<SDLUtil::SDLCursorManager>();
MyGUI::PointerManager::getInstance().eventChangeMousePointer
+= MyGUI::newDelegate(this, &WindowManager::onCursorChange);
MyGUI::InputManager::getInstance().eventChangeKeyFocus
+= MyGUI::newDelegate(this, &WindowManager::onKeyFocusChanged);
// Create all cursors in advance
createCursors();
onCursorChange(MyGUI::PointerManager::getInstance().getDefaultPointer());
mCursorManager->setEnabled(true);
// hide mygui's pointer
MyGUI::PointerManager::getInstance().setVisible(false);
mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal<MyGUI::ImageBox>(
"ImageBox", 0, 0, 1, 1, MyGUI::Align::Default, "Video");
mVideoBackground->setImageTexture("black");
mVideoBackground->setVisible(false);
mVideoBackground->setNeedMouseFocus(true);
mVideoBackground->setNeedKeyFocus(true);
mVideoWidget = mVideoBackground->createWidgetReal<VideoWidget>("ImageBox", 0, 0, 1, 1, MyGUI::Align::Default);
mVideoWidget->setNeedMouseFocus(true);
mVideoWidget->setNeedKeyFocus(true);
mVideoWidget->setVFS(resourceSystem->getVFS());
// Removes default MyGUI system clipboard implementation, which supports windows only
MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear();
MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear();
MyGUI::ClipboardManager::getInstance().eventClipboardChanged
+= MyGUI::newDelegate(this, &WindowManager::onClipboardChanged);
MyGUI::ClipboardManager::getInstance().eventClipboardRequested
+= MyGUI::newDelegate(this, &WindowManager::onClipboardRequested);
mVideoWrapper = std::make_unique<SDLUtil::VideoWrapper>(window, viewer);
mVideoWrapper->setGammaContrast(Settings::video().mGamma, Settings::video().mContrast);
if (useShaders)
mGuiPlatform->getRenderManagerPtr()->enableShaders(mResourceSystem->getSceneManager()->getShaderManager());
mStatsWatcher = std::make_unique<StatsWatcher>();
}
void WindowManager::initUI()
{
// Get size info from the Gui object
int w = MyGUI::RenderManager::getInstance().getViewSize().width;
int h = MyGUI::RenderManager::getInstance().getViewSize().height;
mTextColours.loadColours();
mDragAndDrop = std::make_unique<DragAndDrop>();
auto recharge = std::make_unique<Recharge>();
mGuiModeStates[GM_Recharge] = GuiModeState(recharge.get());
mWindows.push_back(std::move(recharge));
auto menu = std::make_unique<MainMenu>(w, h, mResourceSystem->getVFS(), mVersionDescription);
mGuiModeStates[GM_MainMenu] = GuiModeState(menu.get());
mWindows.push_back(std::move(menu));
mLocalMapRender = std::make_unique<MWRender::LocalMap>(mViewer->getSceneData()->asGroup());
auto map = std::make_unique<MapWindow>(mCustomMarkers, mDragAndDrop.get(), mLocalMapRender.get(), mWorkQueue);
mMap = map.get();
mWindows.push_back(std::move(map));
mMap->renderGlobalMap();
trackWindow(mMap, makeMapWindowSettingValues());
auto statsWindow = std::make_unique<StatsWindow>(mDragAndDrop.get());
mStatsWindow = statsWindow.get();
mWindows.push_back(std::move(statsWindow));
trackWindow(mStatsWindow, makeStatsWindowSettingValues());
auto inventoryWindow = std::make_unique<InventoryWindow>(
mDragAndDrop.get(), mViewer->getSceneData()->asGroup(), mResourceSystem);
mInventoryWindow = inventoryWindow.get();
mWindows.push_back(std::move(inventoryWindow));
auto spellWindow = std::make_unique<SpellWindow>(mDragAndDrop.get());
mSpellWindow = spellWindow.get();
mWindows.push_back(std::move(spellWindow));
trackWindow(mSpellWindow, makeSpellsWindowSettingValues());
mGuiModeStates[GM_Inventory] = GuiModeState({ mMap, mInventoryWindow, mSpellWindow, mStatsWindow });
mGuiModeStates[GM_None] = GuiModeState({ mMap, mInventoryWindow, mSpellWindow, mStatsWindow });
auto tradeWindow = std::make_unique<TradeWindow>();
mTradeWindow = tradeWindow.get();
mWindows.push_back(std::move(tradeWindow));
trackWindow(mTradeWindow, makeBarterWindowSettingValues());
mGuiModeStates[GM_Barter] = GuiModeState({ mInventoryWindow, mTradeWindow });
auto console = std::make_unique<Console>(w, h, mConsoleOnlyScripts, mCfgMgr);
mConsole = console.get();
mWindows.push_back(std::move(console));
trackWindow(mConsole, makeConsoleWindowSettingValues());
bool questList = mResourceSystem->getVFS()->exists("textures/tx_menubook_options_over.dds");
auto journal = JournalWindow::create(JournalViewModel::create(), questList, mEncoding);
mGuiModeStates[GM_Journal] = GuiModeState(journal.get());
mWindows.push_back(std::move(journal));
mMessageBoxManager = std::make_unique<MessageBoxManager>(
mStore->get<ESM::GameSetting>().find("fMessageTimePerChar")->mValue.getFloat());
auto spellBuyingWindow = std::make_unique<SpellBuyingWindow>();
mGuiModeStates[GM_SpellBuying] = GuiModeState(spellBuyingWindow.get());
mWindows.push_back(std::move(spellBuyingWindow));
auto travelWindow = std::make_unique<TravelWindow>();
mGuiModeStates[GM_Travel] = GuiModeState(travelWindow.get());
mWindows.push_back(std::move(travelWindow));
auto dialogueWindow = std::make_unique<DialogueWindow>();
mDialogueWindow = dialogueWindow.get();
mWindows.push_back(std::move(dialogueWindow));
trackWindow(mDialogueWindow, makeDialogueWindowSettingValues());
mGuiModeStates[GM_Dialogue] = GuiModeState(mDialogueWindow);
mTradeWindow->eventTradeDone += MyGUI::newDelegate(mDialogueWindow, &DialogueWindow::onTradeComplete);
auto containerWindow = std::make_unique<ContainerWindow>(mDragAndDrop.get());
mContainerWindow = containerWindow.get();
mWindows.push_back(std::move(containerWindow));
trackWindow(mContainerWindow, makeContainerWindowSettingValues());
mGuiModeStates[GM_Container] = GuiModeState({ mContainerWindow, mInventoryWindow });
auto hud = std::make_unique<HUD>(mCustomMarkers, mDragAndDrop.get(), mLocalMapRender.get());
mHud = hud.get();
mWindows.push_back(std::move(hud));
mToolTips = std::make_unique<ToolTips>();
auto scrollWindow = std::make_unique<ScrollWindow>();
mScrollWindow = scrollWindow.get();
mWindows.push_back(std::move(scrollWindow));
mGuiModeStates[GM_Scroll] = GuiModeState(mScrollWindow);
auto bookWindow = std::make_unique<BookWindow>();
mBookWindow = bookWindow.get();
mWindows.push_back(std::move(bookWindow));
mGuiModeStates[GM_Book] = GuiModeState(mBookWindow);
auto countDialog = std::make_unique<CountDialog>();
mCountDialog = countDialog.get();
mWindows.push_back(std::move(countDialog));
auto settingsWindow = std::make_unique<SettingsWindow>();
mSettingsWindow = settingsWindow.get();
mWindows.push_back(std::move(settingsWindow));
trackWindow(mSettingsWindow, makeSettingsWindowSettingValues());
auto confirmationDialog = std::make_unique<ConfirmationDialog>();
mConfirmationDialog = confirmationDialog.get();
mWindows.push_back(std::move(confirmationDialog));
auto alchemyWindow = std::make_unique<AlchemyWindow>();
trackWindow(alchemyWindow.get(), makeAlchemyWindowSettingValues());
mGuiModeStates[GM_Alchemy] = GuiModeState(alchemyWindow.get());
mWindows.push_back(std::move(alchemyWindow));
auto quickKeysMenu = std::make_unique<QuickKeysMenu>();
mQuickKeysMenu = quickKeysMenu.get();
mWindows.push_back(std::move(quickKeysMenu));
mGuiModeStates[GM_QuickKeysMenu] = GuiModeState(mQuickKeysMenu);
auto levelupDialog = std::make_unique<LevelupDialog>();
mGuiModeStates[GM_Levelup] = GuiModeState(levelupDialog.get());
mWindows.push_back(std::move(levelupDialog));
auto waitDialog = std::make_unique<WaitDialog>();
mWaitDialog = waitDialog.get();
mWindows.push_back(std::move(waitDialog));
mGuiModeStates[GM_Rest] = GuiModeState({ mWaitDialog->getProgressBar(), mWaitDialog });
auto spellCreationDialog = std::make_unique<SpellCreationDialog>();
mGuiModeStates[GM_SpellCreation] = GuiModeState(spellCreationDialog.get());
mWindows.push_back(std::move(spellCreationDialog));
auto enchantingDialog = std::make_unique<EnchantingDialog>();
mGuiModeStates[GM_Enchanting] = GuiModeState(enchantingDialog.get());
mWindows.push_back(std::move(enchantingDialog));
auto trainingWindow = std::make_unique<TrainingWindow>();
mGuiModeStates[GM_Training] = GuiModeState({ trainingWindow->getProgressBar(), trainingWindow.get() });
mWindows.push_back(std::move(trainingWindow));
auto merchantRepair = std::make_unique<MerchantRepair>();
mGuiModeStates[GM_MerchantRepair] = GuiModeState(merchantRepair.get());
mWindows.push_back(std::move(merchantRepair));
auto repair = std::make_unique<Repair>();
mGuiModeStates[GM_Repair] = GuiModeState(repair.get());
mWindows.push_back(std::move(repair));
mSoulgemDialog = std::make_unique<SoulgemDialog>(mMessageBoxManager.get());
auto companionWindow = std::make_unique<CompanionWindow>(mDragAndDrop.get(), mMessageBoxManager.get());
trackWindow(companionWindow.get(), makeCompanionWindowSettingValues());
mGuiModeStates[GM_Companion] = GuiModeState({ mInventoryWindow, companionWindow.get() });
mWindows.push_back(std::move(companionWindow));
auto jailScreen = std::make_unique<JailScreen>();
mJailScreen = jailScreen.get();
mWindows.push_back(std::move(jailScreen));
mGuiModeStates[GM_Jail] = GuiModeState(mJailScreen);
std::string werewolfFaderTex = "textures\\werewolfoverlay.dds";
if (mResourceSystem->getVFS()->exists(werewolfFaderTex))
{
auto werewolfFader = std::make_unique<ScreenFader>(werewolfFaderTex);
mWerewolfFader = werewolfFader.get();
mWindows.push_back(std::move(werewolfFader));
}
auto blindnessFader = std::make_unique<ScreenFader>("black");
mBlindnessFader = blindnessFader.get();
mWindows.push_back(std::move(blindnessFader));
// fall back to player_hit_01.dds if bm_player_hit_01.dds is not available
std::string hitFaderTexture = "textures\\bm_player_hit_01.dds";
const std::string hitFaderLayout = "openmw_screen_fader_hit.layout";
MyGUI::FloatCoord hitFaderCoord(0, 0, 1, 1);
if (!mResourceSystem->getVFS()->exists(hitFaderTexture))
{
hitFaderTexture = "textures\\player_hit_01.dds";
hitFaderCoord = MyGUI::FloatCoord(0.2, 0.25, 0.6, 0.5);
}
auto hitFader = std::make_unique<ScreenFader>(hitFaderTexture, hitFaderLayout, hitFaderCoord);
mHitFader = hitFader.get();
mWindows.push_back(std::move(hitFader));
auto screenFader = std::make_unique<ScreenFader>("black");
mScreenFader = screenFader.get();
mWindows.push_back(std::move(screenFader));
auto debugWindow = std::make_unique<DebugWindow>();
mDebugWindow = debugWindow.get();
mWindows.push_back(std::move(debugWindow));
trackWindow(mDebugWindow, makeDebugWindowSettingValues());
auto postProcessorHud = std::make_unique<PostProcessorHud>();
mPostProcessorHud = postProcessorHud.get();
mWindows.push_back(std::move(postProcessorHud));
trackWindow(mPostProcessorHud, makePostprocessorWindowSettingValues());
mInputBlocker = MyGUI::Gui::getInstance().createWidget<MyGUI::Widget>(
{}, 0, 0, w, h, MyGUI::Align::Stretch, "InputBlocker");
mHud->setVisible(true);
mCharGen = std::make_unique<CharacterCreation>(mViewer->getSceneData()->asGroup(), mResourceSystem);
updatePinnedWindows();
// Set up visibility
updateVisible();
mStatsWatcher->addListener(mHud);
mStatsWatcher->addListener(mStatsWindow);
mStatsWatcher->addListener(mCharGen.get());
for (auto& window : mWindows)
{
std::string_view id = window->getWindowIdForLua();
if (!id.empty())
mLuaIdToWindow.emplace(id, window.get());
}
}
void WindowManager::setNewGame(bool newgame)
{
if (newgame)
{
disallowAll();
mStatsWatcher->removeListener(mCharGen.get());
mCharGen = std::make_unique<CharacterCreation>(mViewer->getSceneData()->asGroup(), mResourceSystem);
mStatsWatcher->addListener(mCharGen.get());
}
else
allow(GW_ALL);
mStatsWatcher->forceUpdate();
}
WindowManager::~WindowManager()
{
try
{
LuaUi::clearGameInterface();
LuaUi::clearMenuInterface();
mStatsWatcher.reset();
MyGUI::LanguageManager::getInstance().eventRequestTag.clear();
MyGUI::PointerManager::getInstance().eventChangeMousePointer.clear();
MyGUI::InputManager::getInstance().eventChangeKeyFocus.clear();
MyGUI::ClipboardManager::getInstance().eventClipboardChanged.clear();
MyGUI::ClipboardManager::getInstance().eventClipboardRequested.clear();
mWindows.clear();
mMessageBoxManager.reset();
mToolTips.reset();
mCharGen.reset();
mKeyboardNavigation.reset();
cleanupGarbage();
mFontLoader.reset();
mGui->shutdown();
mGuiPlatform->shutdown();
}
catch (const MyGUI::Exception& e)
{
Log(Debug::Error) << "Error in the destructor: " << e.what();
}
}
void WindowManager::setStore(const MWWorld::ESMStore& store)
{
mStore = &store;
}
void WindowManager::cleanupGarbage()
{
// Delete any dialogs which are no longer in use
mGarbageDialogs.clear();
}
void WindowManager::enableScene(bool enable)
{
unsigned int disablemask = MWRender::Mask_GUI | MWRender::Mask_PreCompile;
if (!enable && getCullMask() != disablemask)
{
mOldUpdateMask = mViewer->getUpdateVisitor()->getTraversalMask();
mOldCullMask = getCullMask();
mViewer->getUpdateVisitor()->setTraversalMask(disablemask);
setCullMask(disablemask);
}
else if (enable && getCullMask() == disablemask)
{
mViewer->getUpdateVisitor()->setTraversalMask(mOldUpdateMask);
setCullMask(mOldCullMask);
}
}
void WindowManager::updateConsoleObjectPtr(const MWWorld::Ptr& currentPtr, const MWWorld::Ptr& newPtr)
{
mConsole->updateSelectedObjectPtr(currentPtr, newPtr);
}
void WindowManager::updateVisible()
{
bool loading = (getMode() == GM_Loading || getMode() == GM_LoadingWallpaper);
bool mainmenucover = containsMode(GM_MainMenu)
&& MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame;
enableScene(!loading && !mainmenucover);
if (!mMap)
return; // UI not created yet
mHud->setVisible(mHudEnabled && !loading);
mToolTips->setVisible(mHudEnabled && !loading);
bool gameMode = !isGuiMode();
MWBase::Environment::get().getInputManager()->changeInputMode(!gameMode);
mInputBlocker->setVisible(gameMode);
if (loading)
setCursorVisible(mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox());
else
setCursorVisible(!gameMode);
if (gameMode)
setKeyFocusWidget(nullptr);
// Icons of forced hidden windows are displayed
setMinimapVisibility((mAllowed & GW_Map) && (!mMap->pinned() || (mForceHidden & GW_Map)));
setWeaponVisibility(
(mAllowed & GW_Inventory) && (!mInventoryWindow->pinned() || (mForceHidden & GW_Inventory)));
setSpellVisibility((mAllowed & GW_Magic) && (!mSpellWindow->pinned() || (mForceHidden & GW_Magic)));
setHMSVisibility((mAllowed & GW_Stats) && (!mStatsWindow->pinned() || (mForceHidden & GW_Stats)));
mInventoryWindow->setGuiMode(getMode());
// If in game mode (or interactive messagebox), show the pinned windows
if (mGuiModes.empty())
{
mMap->setVisible(mMap->pinned() && !isConsoleMode() && !(mForceHidden & GW_Map) && (mAllowed & GW_Map));
mStatsWindow->setVisible(
mStatsWindow->pinned() && !isConsoleMode() && !(mForceHidden & GW_Stats) && (mAllowed & GW_Stats));
mInventoryWindow->setVisible(mInventoryWindow->pinned() && !isConsoleMode()
&& !(mForceHidden & GW_Inventory) && (mAllowed & GW_Inventory));
mSpellWindow->setVisible(
mSpellWindow->pinned() && !isConsoleMode() && !(mForceHidden & GW_Magic) && (mAllowed & GW_Magic));
return;
}
else if (getMode() != GM_Inventory)
{
mMap->setVisible(false);
mStatsWindow->setVisible(false);
mSpellWindow->setVisible(false);
mHud->setDrowningBarVisible(false);
mInventoryWindow->setVisible(
getMode() == GM_Container || getMode() == GM_Barter || getMode() == GM_Companion);
}
GuiMode mode = mGuiModes.back();
mInventoryWindow->setTrading(mode == GM_Barter);
if (getMode() == GM_Inventory)
{
// For the inventory mode, compute the effective set of windows to show.
// This is controlled both by what windows the
// user has opened/closed (the 'shown' variable) and by what
// windows we are allowed to show (the 'allowed' var.)
int eff = mShown & mAllowed & ~mForceHidden;
mMap->setVisible(eff & GW_Map);
mInventoryWindow->setVisible(eff & GW_Inventory);
mSpellWindow->setVisible(eff & GW_Magic);
mStatsWindow->setVisible(eff & GW_Stats);
}
switch (mode)
{
// FIXME: refactor chargen windows to use modes properly (or not use them at all)
case GM_Name:
case GM_Race:
case GM_Class:
case GM_ClassPick:
case GM_ClassCreate:
case GM_Birth:
case GM_ClassGenerate:
case GM_Review:
mCharGen->spawnDialog(mode);
break;
default:
break;
}
}
void WindowManager::setDrowningTimeLeft(float time, float maxTime)
{
mHud->setDrowningTimeLeft(time, maxTime);
}
void WindowManager::removeDialog(std::unique_ptr<Layout>&& dialog)
{
if (!dialog)
return;
dialog->setVisible(false);
mGarbageDialogs.push_back(std::move(dialog));
}
void WindowManager::exitCurrentGuiMode()
{
if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop)
{
mDragAndDrop->finish();
return;
}
GuiModeState& state = mGuiModeStates[mGuiModes.back()];
for (const auto& window : state.mWindows)
{
if (!window->exit())
{
// unable to exit window, but give access to main menu
if (!MyGUI::InputManager::getInstance().isModalAny() && getMode() != GM_MainMenu)
pushGuiMode(GM_MainMenu);
return;
}
}
popGuiMode();
}
void WindowManager::interactiveMessageBox(
std::string_view message, const std::vector<std::string>& buttons, bool block, int defaultFocus)
{
mMessageBoxManager->createInteractiveMessageBox(message, buttons, block, defaultFocus);
updateVisible();
if (block)
{
Misc::FrameRateLimiter frameRateLimiter
= Misc::makeFrameRateLimiter(MWBase::Environment::get().getFrameRateLimit());
while (mMessageBoxManager->readPressedButton(false) == -1
&& !MWBase::Environment::get().getStateManager()->hasQuitRequest())
{
const double dt
= std::chrono::duration_cast<std::chrono::duration<double>>(frameRateLimiter.getLastFrameDuration())
.count();
mKeyboardNavigation->onFrame();
mMessageBoxManager->onFrame(dt);
MWBase::Environment::get().getInputManager()->update(dt, true, false);
if (!mWindowVisible)
std::this_thread::sleep_for(std::chrono::milliseconds(5));
else
{
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
}
// at the time this function is called we are in the middle of a frame,
// so out of order calls are necessary to get a correct frameNumber for the next frame.
// refer to the advance() and frame() order in Engine::go()
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
frameRateLimiter.limit();
}
mMessageBoxManager->resetInteractiveMessageBox();
}
}
void WindowManager::messageBox(std::string_view message, enum MWGui::ShowInDialogueMode showInDialogueMode)
{
if (getMode() == GM_Dialogue && showInDialogueMode != MWGui::ShowInDialogueMode_Never)
{
MyGUI::UString text = MyGUI::LanguageManager::getInstance().replaceTags(MyGUI::UString(message));
mDialogueWindow->addMessageBox(text);
}
else if (showInDialogueMode != MWGui::ShowInDialogueMode_Only)
{
mMessageBoxManager->createMessageBox(message);
}
}
void WindowManager::scheduleMessageBox(std::string message, enum MWGui::ShowInDialogueMode showInDialogueMode)
{
mScheduledMessageBoxes.lock()->emplace_back(std::move(message), showInDialogueMode);
}
void WindowManager::staticMessageBox(std::string_view message)
{
mMessageBoxManager->createMessageBox(message, true);
}
void WindowManager::removeStaticMessageBox()
{
mMessageBoxManager->removeStaticMessageBox();
}
int WindowManager::readPressedButton()
{
return mMessageBoxManager->readPressedButton();
}
std::string_view WindowManager::getGameSettingString(std::string_view id, std::string_view default_)
{
const ESM::GameSetting* setting = mStore->get<ESM::GameSetting>().search(id);
if (setting && setting->mValue.getType() == ESM::VT_String)
return setting->mValue.getString();
return default_;
}
void WindowManager::updateMap()
{
if (!mLocalMapRender)
return;
MWWorld::ConstPtr player = MWMechanics::getPlayer();
osg::Vec3f playerPosition = player.getRefData().getPosition().asVec3();
osg::Quat playerOrientation(-player.getRefData().getPosition().rot[2], osg::Vec3(0, 0, 1));
osg::Vec3f playerdirection;
int x, y;
float u, v;
mLocalMapRender->updatePlayer(playerPosition, playerOrientation, u, v, x, y, playerdirection);
if (!player.getCell()->isExterior())
{
setActiveMap(*player.getCell()->getCell());
}
// else: need to know the current grid center, call setActiveMap from changeCell
mMap->setPlayerDir(playerdirection.x(), playerdirection.y());
mMap->setPlayerPos(x, y, u, v);
mHud->setPlayerDir(playerdirection.x(), playerdirection.y());
mHud->setPlayerPos(x, y, u, v);
}
void WindowManager::update(float frameDuration)
{
handleScheduledMessageBoxes();
bool gameRunning
= MWBase::Environment::get().getStateManager()->getState() != MWBase::StateManager::State_NoGame;
if (gameRunning)
updateMap();
if (!mGuiModes.empty())
{
GuiModeState& state = mGuiModeStates[mGuiModes.back()];
for (WindowBase* window : state.mWindows)
window->onFrame(frameDuration);
}
else
{
// update pinned windows if visible
for (WindowBase* window : mGuiModeStates[GM_Inventory].mWindows)
if (window->isVisible())
window->onFrame(frameDuration);
}
// Make sure message boxes are always in front
// This is an awful workaround for a series of awfully interwoven issues that couldn't be worked around
// in a better way because of an impressive number of even more awfully interwoven issues.
if (mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox()
&& mCurrentModals.back() != mMessageBoxManager->getInteractiveMessageBox())
{
std::vector<WindowModal*>::iterator found = std::find(
mCurrentModals.begin(), mCurrentModals.end(), mMessageBoxManager->getInteractiveMessageBox());
if (found != mCurrentModals.end())
{
WindowModal* msgbox = *found;
std::swap(*found, mCurrentModals.back());
MyGUI::InputManager::getInstance().addWidgetModal(msgbox->mMainWidget);
mKeyboardNavigation->setModalWindow(msgbox->mMainWidget);
mKeyboardNavigation->setDefaultFocus(msgbox->mMainWidget, msgbox->getDefaultKeyFocus());
}
}
if (!mCurrentModals.empty())
mCurrentModals.back()->onFrame(frameDuration);
mKeyboardNavigation->onFrame();
if (mMessageBoxManager)
mMessageBoxManager->onFrame(frameDuration);
mToolTips->onFrame(frameDuration);
if (mLocalMapRender)
mLocalMapRender->cleanupCameras();
mDebugWindow->onFrame(frameDuration);
if (isConsoleMode())
mConsole->onFrame(frameDuration);
if (!gameRunning)
return;
// We should display message about crime only once per frame, even if there are several crimes.
// Otherwise we will get message spam when stealing several items via Take All button.
const MWWorld::Ptr player = MWMechanics::getPlayer();
const MWWorld::Class& playerCls = player.getClass();
int currentBounty = playerCls.getNpcStats(player).getBounty();
if (currentBounty != mPlayerBounty)
{
if (mPlayerBounty >= 0 && currentBounty > mPlayerBounty)
messageBox("#{sCrimeMessage}");
mPlayerBounty = currentBounty;
}
MWBase::LuaManager::ActorControls* playerControls
= MWBase::Environment::get().getLuaManager()->getActorControls(player);
bool triedToMove = playerControls
&& (playerControls->mMovement != 0 || playerControls->mSideMovement != 0 || playerControls->mJump);
if (mMessageBoxManager && triedToMove && playerCls.getEncumbrance(player) > playerCls.getCapacity(player))
{
const auto& msgboxs = mMessageBoxManager->getActiveMessageBoxes();
auto it
= std::find_if(msgboxs.begin(), msgboxs.end(), [](const std::unique_ptr<MWGui::MessageBox>& msgbox) {
return (msgbox->getMessage() == "#{sNotifyMessage59}");
});
// if an overencumbered messagebox is already present, reset its expiry timer,
// otherwise create a new one.
if (it != msgboxs.end())
(*it)->mCurrentTime = 0;
else
messageBox("#{sNotifyMessage59}");
}
mDragAndDrop->onFrame();
mHud->onFrame(frameDuration);
mPostProcessorHud->onFrame(frameDuration);
if (mCharGen)
mCharGen->onFrame(frameDuration);
updateActivatedQuickKey();
mStatsWatcher->update();
cleanupGarbage();
}
void WindowManager::changeCell(const MWWorld::CellStore* cell)
{
mMap->requestMapRender(cell);
std::string name{ MWBase::Environment::get().getWorld()->getCellName(cell) };
mMap->setCellName(name);
mHud->setCellName(name);
auto cellCommon = cell->getCell();
if (cellCommon->isExterior())
{
if (!cellCommon->getNameId().empty())
mMap->addVisitedLocation(name, cellCommon->getGridX(), cellCommon->getGridY());
mMap->cellExplored(cellCommon->getGridX(), cellCommon->getGridY());
}
else
{
osg::Vec3f worldPos;
if (!MWBase::Environment::get().getWorld()->findInteriorPositionInWorldSpace(cell, worldPos))
worldPos = MWBase::Environment::get().getWorld()->getPlayer().getLastKnownExteriorPosition();
else
MWBase::Environment::get().getWorld()->getPlayer().setLastKnownExteriorPosition(worldPos);
mMap->setGlobalMapPlayerPosition(worldPos.x(), worldPos.y());
}
setActiveMap(*cellCommon);
}
void WindowManager::setActiveMap(const MWWorld::Cell& cell)
{
mMap->setActiveCell(cell);
mHud->setActiveCell(cell);
}
void WindowManager::setDrowningBarVisibility(bool visible)
{
mHud->setDrowningBarVisible(visible);
}
void WindowManager::setHMSVisibility(bool visible)
{
mHud->setHmsVisible(visible);
}
void WindowManager::setMinimapVisibility(bool visible)
{
mHud->setMinimapVisible(visible);
}
bool WindowManager::toggleFogOfWar()
{
mMap->toggleFogOfWar();
return mHud->toggleFogOfWar();
}
void WindowManager::setFocusObject(const MWWorld::Ptr& focus)
{
mToolTips->setFocusObject(focus);
const int showOwned = Settings::game().mShowOwned;
if (mHud && (showOwned == 2 || showOwned == 3))
{
bool owned = mToolTips->checkOwned();
mHud->setCrosshairOwned(owned);
}
}
void WindowManager::setFocusObjectScreenCoords(float min_x, float min_y, float max_x, float max_y)
{
mToolTips->setFocusObjectScreenCoords(min_x, min_y, max_x, max_y);
}
bool WindowManager::toggleFullHelp()
{
return mToolTips->toggleFullHelp();
}
bool WindowManager::getFullHelp() const
{
return mToolTips->getFullHelp();
}
void WindowManager::setWeaponVisibility(bool visible)
{
mHud->setWeapVisible(visible);
}
void WindowManager::setSpellVisibility(bool visible)
{
mHud->setSpellVisible(visible);
mHud->setEffectVisible(visible);
}
void WindowManager::setSneakVisibility(bool visible)
{
mHud->setSneakVisible(visible);
}
void WindowManager::setDragDrop(bool dragDrop)
{
mToolTips->setEnabled(!dragDrop);
MWBase::Environment::get().getInputManager()->setDragDrop(dragDrop);
}
void WindowManager::setCursorVisible(bool visible)
{
mCursorVisible = visible;
}
void WindowManager::setCursorActive(bool active)
{
mCursorActive = active;
}
void WindowManager::onRetrieveTag(const MyGUI::UString& _tag, MyGUI::UString& _result)
{
std::string_view tag = _tag;
std::string_view MyGuiPrefix = "setting=";
std::string_view tokenToFind = "sCell=";
if (tag.starts_with(MyGuiPrefix))
{
tag = tag.substr(MyGuiPrefix.length());
size_t comma_pos = tag.find(',');
std::string_view settingSection = tag.substr(0, comma_pos);
std::string_view settingTag = tag.substr(comma_pos + 1, tag.length());
_result = Settings::get<MyGUI::Colour>(settingSection, settingTag).get().print();
}
else if (tag.starts_with(tokenToFind))
{
std::string_view cellName = mTranslationDataStorage.translateCellName(tag.substr(tokenToFind.length()));
_result.assign(cellName.data(), cellName.size());
_result = MyGUI::TextIterator::toTagsString(_result);
}
else if (Gui::replaceTag(tag, _result))
{
return;
}
else
{
std::vector<std::string> split;
Misc::StringUtils::split(tag, split, ":");
l10n::Manager& l10nManager = *MWBase::Environment::get().getL10nManager();
// If a key has a "Context:KeyName" format, use YAML to translate data
if (split.size() == 2)
{
_result = l10nManager.getContext(split[0])->formatMessage(split[1], {}, {});
return;
}
// If not, treat is as GMST name from legacy localization
if (!mStore)
{
Log(Debug::Error) << "Error: WindowManager::onRetrieveTag: no Store set up yet, can not replace '"
<< tag << "'";
_result.assign(tag.data(), tag.size());
return;
}
const ESM::GameSetting* setting = mStore->get<ESM::GameSetting>().search(tag);
if (setting && setting->mValue.getType() == ESM::VT_String)
_result = setting->mValue.getString();
else
_result.assign(tag.data(), tag.size());
}
}
void WindowManager::processChangedSettings(const Settings::CategorySettingVector& changed)
{
bool changeRes = false;
for (const auto& setting : changed)
{
if (setting.first == "GUI" && setting.second == "menu transparency")
setMenuTransparency(Settings::gui().mMenuTransparency);
else if (setting.first == "Video"
&& (setting.second == "resolution x" || setting.second == "resolution y"
|| setting.second == "window mode" || setting.second == "window border"))
changeRes = true;
else if (setting.first == "Video" && setting.second == "vsync mode")
mVideoWrapper->setSyncToVBlank(Settings::video().mVsyncMode);
else if (setting.first == "Video" && (setting.second == "gamma" || setting.second == "contrast"))
mVideoWrapper->setGammaContrast(Settings::video().mGamma, Settings::video().mContrast);
}
if (changeRes)
{
mVideoWrapper->setVideoMode(Settings::video().mResolutionX, Settings::video().mResolutionY,
Settings::video().mWindowMode, Settings::video().mWindowBorder);
}
}
void WindowManager::windowResized(int x, int y)
{
Settings::video().mResolutionX.set(x);
Settings::video().mResolutionY.set(y);
// We only want to process changes to window-size related settings.
Settings::CategorySettingVector filter = { { "Video", "resolution x" }, { "Video", "resolution y" } };
// If the HUD has not been initialised, the World singleton will not be available.
if (mHud)
{
MWBase::Environment::get().getWorld()->processChangedSettings(Settings::Manager::getPendingChanges(filter));
}
Settings::Manager::resetPendingChanges(filter);
mGuiPlatform->getRenderManagerPtr()->setViewSize(x, y);
// scaled size
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
x = viewSize.width;
y = viewSize.height;
sizeVideo(x, y);
if (!mHud)
return; // UI not initialized yet
for (const auto& [window, settings] : mTrackedWindows)
{
const WindowRectSettingValues& rect = settings.mIsMaximized ? settings.mMaximized : settings.mRegular;
window->setPosition(MyGUI::IntPoint(static_cast<int>(rect.mX * x), static_cast<int>(rect.mY * y)));
window->setSize(MyGUI::IntSize(static_cast<int>(rect.mW * x), static_cast<int>(rect.mH * y)));
}
for (const auto& window : mWindows)
window->onResChange(x, y);
// TODO: check if any windows are now off-screen and move them back if so
}
bool WindowManager::isWindowVisible()
{
return mWindowVisible;
}
void WindowManager::windowVisibilityChange(bool visible)
{
mWindowVisible = visible;
}
void WindowManager::windowClosed()
{
MWBase::Environment::get().getStateManager()->requestQuit();
}
void WindowManager::onCursorChange(std::string_view name)
{
mCursorManager->cursorChanged(name);
}
void WindowManager::pushGuiMode(GuiMode mode)
{
pushGuiMode(mode, MWWorld::Ptr());
}
void WindowManager::pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg)
{
pushGuiMode(mode, arg, false);
}
void WindowManager::forceLootMode(const MWWorld::Ptr& ptr)
{
pushGuiMode(MWGui::GM_Container, ptr, true);
}
void WindowManager::pushGuiMode(GuiMode mode, const MWWorld::Ptr& arg, bool force)
{
if (mode == GM_Inventory && mAllowed == GW_None)
return;
if (mGuiModes.empty() || mGuiModes.back() != mode)
{
// If this mode already exists somewhere in the stack, just bring it to the front.
if (std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end())
{
mGuiModes.erase(std::find(mGuiModes.begin(), mGuiModes.end(), mode));
}
if (!mGuiModes.empty())
{
mKeyboardNavigation->saveFocus(mGuiModes.back());
mGuiModeStates[mGuiModes.back()].update(false);
}
mGuiModes.push_back(mode);
mGuiModeStates[mode].update(true);
}
if (force)
mContainerWindow->treatNextOpenAsLoot();
try
{
for (WindowBase* window : mGuiModeStates[mode].mWindows)
window->setPtr(arg);
}
catch (...)
{
popGuiMode();
throw;
}
mKeyboardNavigation->restoreFocus(mode);
updateVisible();
MWBase::Environment::get().getLuaManager()->uiModeChanged(arg);
}
void WindowManager::setCullMask(uint32_t mask)
{
mViewer->getCamera()->setCullMask(mask);
// We could check whether stereo is enabled here, but these methods are
// trivial and have no effect in mono or multiview so just call them regardless.
mViewer->getCamera()->setCullMaskLeft(mask);
mViewer->getCamera()->setCullMaskRight(mask);
}
uint32_t WindowManager::getCullMask()
{
return mViewer->getCamera()->getCullMask();
}
void WindowManager::popGuiMode()
{
if (mDragAndDrop && mDragAndDrop->mIsOnDragAndDrop)
{
mDragAndDrop->finish();
}
if (!mGuiModes.empty())
{
const GuiMode mode = mGuiModes.back();
mKeyboardNavigation->saveFocus(mode);
mGuiModes.pop_back();
mGuiModeStates[mode].update(false);
MWBase::Environment::get().getLuaManager()->uiModeChanged(MWWorld::Ptr());
}
if (!mGuiModes.empty())
{
const GuiMode mode = mGuiModes.back();
mGuiModeStates[mode].update(true);
mKeyboardNavigation->restoreFocus(mode);
}
updateVisible();
// To make sure that console window get focus again
if (mConsole && mConsole->isVisible())
mConsole->onOpen();
}
void WindowManager::removeGuiMode(GuiMode mode)
{
if (!mGuiModes.empty() && mGuiModes.back() == mode)
{
popGuiMode();
return;
}
std::vector<GuiMode>::iterator it = mGuiModes.begin();
while (it != mGuiModes.end())
{
if (*it == mode)
it = mGuiModes.erase(it);
else
++it;
}
updateVisible();
MWBase::Environment::get().getLuaManager()->uiModeChanged(MWWorld::Ptr());
}
void WindowManager::goToJail(int days)
{
pushGuiMode(MWGui::GM_Jail);
mJailScreen->goToJail(days);
}
void WindowManager::setSelectedSpell(const ESM::RefId& spellId, int successChancePercent)
{
mSelectedSpell = spellId;
mSelectedEnchantItem = MWWorld::Ptr();
mHud->setSelectedSpell(spellId, successChancePercent);
const ESM::Spell* spell = mStore->get<ESM::Spell>().find(spellId);
mSpellWindow->setTitle(spell->mName);
}
void WindowManager::setSelectedEnchantItem(const MWWorld::Ptr& item)
{
mSelectedEnchantItem = item;
mSelectedSpell = ESM::RefId();
const ESM::Enchantment* ench = mStore->get<ESM::Enchantment>().find(item.getClass().getEnchantment(item));
int chargePercent = static_cast<int>(item.getCellRef().getNormalizedEnchantmentCharge(*ench) * 100);
mHud->setSelectedEnchantItem(item, chargePercent);
mSpellWindow->setTitle(item.getClass().getName(item));
}
const MWWorld::Ptr& WindowManager::getSelectedEnchantItem() const
{
return mSelectedEnchantItem;
}
void WindowManager::setSelectedWeapon(const MWWorld::Ptr& item)
{
mSelectedWeapon = item;
int durabilityPercent = 100;
if (item.getClass().hasItemHealth(item))
{
durabilityPercent = static_cast<int>(item.getClass().getItemNormalizedHealth(item) * 100);
}
mHud->setSelectedWeapon(item, durabilityPercent);
mInventoryWindow->setTitle(item.getClass().getName(item));
}
const MWWorld::Ptr& WindowManager::getSelectedWeapon() const
{
return mSelectedWeapon;
}
void WindowManager::unsetSelectedSpell()
{
mSelectedSpell = ESM::RefId();
mSelectedEnchantItem = MWWorld::Ptr();
mHud->unsetSelectedSpell();
MWWorld::Player* player = &MWBase::Environment::get().getWorld()->getPlayer();
if (player->getDrawState() == MWMechanics::DrawState::Spell)
player->setDrawState(MWMechanics::DrawState::Nothing);
mSpellWindow->setTitle("#{Interface:None}");
}
void WindowManager::unsetSelectedWeapon()
{
mSelectedWeapon = MWWorld::Ptr();
mHud->unsetSelectedWeapon();
mInventoryWindow->setTitle("#{sSkillHandtohand}");
}
void WindowManager::getMousePosition(int& x, int& y)
{
const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition();
x = pos.left;
y = pos.top;
}
void WindowManager::getMousePosition(float& x, float& y)
{
const MyGUI::IntPoint& pos = MyGUI::InputManager::getInstance().getMousePosition();
x = static_cast<float>(pos.left);
y = static_cast<float>(pos.top);
const MyGUI::IntSize& viewSize = MyGUI::RenderManager::getInstance().getViewSize();
x /= viewSize.width;
y /= viewSize.height;
}
bool WindowManager::getWorldMouseOver()
{
return mHud->getWorldMouseOver();
}
float WindowManager::getScalingFactor() const
{
return mScalingFactor;
}
void WindowManager::executeInConsole(const std::filesystem::path& path)
{
mConsole->executeFile(path);
}
MWGui::InventoryWindow* WindowManager::getInventoryWindow()
{
return mInventoryWindow;
}
MWGui::CountDialog* WindowManager::getCountDialog()
{
return mCountDialog;
}
MWGui::ConfirmationDialog* WindowManager::getConfirmationDialog()
{
return mConfirmationDialog;
}
MWGui::TradeWindow* WindowManager::getTradeWindow()
{
return mTradeWindow;
}
MWGui::PostProcessorHud* WindowManager::getPostProcessorHud()
{
return mPostProcessorHud;
}
MWGui::SettingsWindow* WindowManager::getSettingsWindow()
{
return mSettingsWindow;
}
void WindowManager::useItem(const MWWorld::Ptr& item, bool bypassBeastRestrictions)
{
if (mInventoryWindow)
mInventoryWindow->useItem(item, bypassBeastRestrictions);
}
bool WindowManager::isAllowed(GuiWindow wnd) const
{
return (mAllowed & wnd) != 0;
}
void WindowManager::allow(GuiWindow wnd)
{
mAllowed = (GuiWindow)(mAllowed | wnd);
if (wnd & GW_Inventory)
{
mBookWindow->setInventoryAllowed(true);
mScrollWindow->setInventoryAllowed(true);
}
updateVisible();
}
void WindowManager::disallowAll()
{
mAllowed = GW_None;
mRestAllowed = false;
mBookWindow->setInventoryAllowed(false);
mScrollWindow->setInventoryAllowed(false);
updateVisible();
}
void WindowManager::toggleVisible(GuiWindow wnd)
{
if (getMode() != GM_Inventory)
return;
if (Settings::SettingValue<bool>* const hidden = findHiddenSetting(wnd))
hidden->set(!hidden->get());
mShown = (GuiWindow)(mShown ^ wnd);
updateVisible();
}
void WindowManager::forceHide(GuiWindow wnd)
{
mForceHidden = (GuiWindow)(mForceHidden | wnd);
updateVisible();
}
void WindowManager::unsetForceHide(GuiWindow wnd)
{
mForceHidden = (GuiWindow)(mForceHidden & ~wnd);
updateVisible();
}
bool WindowManager::isGuiMode() const
{
return !mGuiModes.empty() || isConsoleMode() || isPostProcessorHudVisible() || isInteractiveMessageBoxActive();
}
bool WindowManager::isConsoleMode() const
{
return mConsole && mConsole->isVisible();
}
bool WindowManager::isPostProcessorHudVisible() const
{
return mPostProcessorHud && mPostProcessorHud->isVisible();
}
bool WindowManager::isInteractiveMessageBoxActive() const
{
return mMessageBoxManager && mMessageBoxManager->isInteractiveMessageBox();
}
MWGui::GuiMode WindowManager::getMode() const
{
if (mGuiModes.empty())
return GM_None;
return mGuiModes.back();
}
void WindowManager::disallowMouse()
{
mInputBlocker->setVisible(true);
}
void WindowManager::allowMouse()
{
mInputBlocker->setVisible(!isGuiMode());
}
void WindowManager::notifyInputActionBound()
{
mSettingsWindow->updateControlsBox();
allowMouse();
}
bool WindowManager::containsMode(GuiMode mode) const
{
if (mGuiModes.empty())
return false;
return std::find(mGuiModes.begin(), mGuiModes.end(), mode) != mGuiModes.end();
}
void WindowManager::showCrosshair(bool show)
{
if (mHud)
mHud->setCrosshairVisible(show && Settings::hud().mCrosshair);
}
void WindowManager::updateActivatedQuickKey()
{
mQuickKeysMenu->updateActivatedQuickKey();
}
void WindowManager::activateQuickKey(int index)
{
mQuickKeysMenu->activateQuickKey(index);
}
bool WindowManager::setHudVisibility(bool show)
{
mHudEnabled = show;
updateVisible();
mMessageBoxManager->setVisible(mHudEnabled);
return mHudEnabled;
}
bool WindowManager::getRestEnabled()
{
// Enable rest dialogue if character creation finished
if (mRestAllowed == false
&& MWBase::Environment::get().getWorld()->getGlobalFloat(MWWorld::Globals::sCharGenState) == -1)
mRestAllowed = true;
return mRestAllowed;
}
bool WindowManager::getPlayerSleeping()
{
return mWaitDialog->getSleeping();
}
void WindowManager::wakeUpPlayer()
{
mWaitDialog->wakeUp();
}
void WindowManager::addVisitedLocation(const std::string& name, int x, int y)
{
mMap->addVisitedLocation(name, x, y);
}
const Translation::Storage& WindowManager::getTranslationDataStorage() const
{
return mTranslationDataStorage;
}
void WindowManager::changePointer(const std::string& name)
{
MyGUI::PointerManager::getInstance().setPointer(name);
onCursorChange(name);
}
void WindowManager::showSoulgemDialog(MWWorld::Ptr item)
{
mSoulgemDialog->show(item);
updateVisible();
}
void WindowManager::updatePlayer()
{
mInventoryWindow->updatePlayer();
const MWWorld::Ptr player = MWMechanics::getPlayer();
if (player.getClass().getNpcStats(player).isWerewolf())
{
setWerewolfOverlay(true);
forceHide((GuiWindow)(MWGui::GW_Inventory | MWGui::GW_Magic));
}
}
// Remove this wrapper once onKeyFocusChanged call is rendered unnecessary
void WindowManager::setKeyFocusWidget(MyGUI::Widget* widget)
{
MyGUI::InputManager::getInstance().setKeyFocusWidget(widget);
onKeyFocusChanged(widget);
}
void WindowManager::onKeyFocusChanged(MyGUI::Widget* widget)
{
bool isEditBox = widget && widget->castType<MyGUI::EditBox>(false);
LuaUi::WidgetExtension* luaWidget = dynamic_cast<LuaUi::WidgetExtension*>(widget);
bool capturesInput = luaWidget ? luaWidget->isTextInput() : isEditBox;
if (widget && capturesInput)
SDL_StartTextInput();
else
SDL_StopTextInput();
}
void WindowManager::setEnemy(const MWWorld::Ptr& enemy)
{
mHud->setEnemy(enemy);
}
std::size_t WindowManager::getMessagesCount() const
{
std::size_t count = 0;
if (mMessageBoxManager)
count = mMessageBoxManager->getMessagesCount();
return count;
}
Loading::Listener* WindowManager::getLoadingScreen()
{
return mLoadingScreen;
}
bool WindowManager::getCursorVisible()
{
return mCursorVisible && mCursorActive;
}
void WindowManager::trackWindow(Layout* layout, const WindowSettingValues& settings)
{
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
const WindowRectSettingValues& rect = settings.mIsMaximized ? settings.mMaximized : settings.mRegular;
layout->mMainWidget->setPosition(
MyGUI::IntPoint(static_cast<int>(rect.mX * viewSize.width), static_cast<int>(rect.mY * viewSize.height)));
layout->mMainWidget->setSize(
MyGUI::IntSize(static_cast<int>(rect.mW * viewSize.width), static_cast<int>(rect.mH * viewSize.height)));
MyGUI::Window* window = layout->mMainWidget->castType<MyGUI::Window>();
window->eventWindowChangeCoord += MyGUI::newDelegate(this, &WindowManager::onWindowChangeCoord);
mTrackedWindows.emplace(window, settings);
}
void WindowManager::toggleMaximized(Layout* layout)
{
MyGUI::Window* window = layout->mMainWidget->castType<MyGUI::Window>();
const auto it = mTrackedWindows.find(window);
if (it == mTrackedWindows.end())
return;
const WindowSettingValues& settings = it->second;
const WindowRectSettingValues& rect = settings.mIsMaximized ? settings.mRegular : settings.mMaximized;
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
const float x = rect.mX * viewSize.width;
const float y = rect.mY * viewSize.height;
const float w = rect.mW * viewSize.width;
const float h = rect.mH * viewSize.height;
window->setCoord(x, y, w, h);
settings.mIsMaximized.set(!settings.mIsMaximized.get());
}
void WindowManager::onWindowChangeCoord(MyGUI::Window* window)
{
const auto it = mTrackedWindows.find(window);
if (it == mTrackedWindows.end())
return;
const WindowSettingValues& settings = it->second;
MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize();
settings.mRegular.mX.set(window->getPosition().left / static_cast<float>(viewSize.width));
settings.mRegular.mY.set(window->getPosition().top / static_cast<float>(viewSize.height));
settings.mRegular.mW.set(window->getSize().width / static_cast<float>(viewSize.width));
settings.mRegular.mH.set(window->getSize().height / static_cast<float>(viewSize.height));
settings.mIsMaximized.set(false);
}
void WindowManager::clear()
{
mPlayerBounty = -1;
for (const auto& window : mWindows)
{
window->clear();
window->setDisabledByLua(false);
}
if (mLocalMapRender)
mLocalMapRender->clear();
mMessageBoxManager->clear();
mToolTips->clear();
mSelectedSpell = ESM::RefId();
mCustomMarkers.clear();
mForceHidden = GW_None;
mRestAllowed = true;
while (!mGuiModes.empty())
popGuiMode();
updateVisible();
}
void WindowManager::write(ESM::ESMWriter& writer, Loading::Listener& progress)
{
mMap->write(writer, progress);
mQuickKeysMenu->write(writer);
if (!mSelectedSpell.empty())
{
writer.startRecord(ESM::REC_ASPL);
writer.writeHNRefId("ID__", mSelectedSpell);
writer.endRecord(ESM::REC_ASPL);
}
for (CustomMarkerCollection::ContainerType::const_iterator it = mCustomMarkers.begin();
it != mCustomMarkers.end(); ++it)
{
writer.startRecord(ESM::REC_MARK);
it->second.save(writer);
writer.endRecord(ESM::REC_MARK);
}
}
void WindowManager::readRecord(ESM::ESMReader& reader, uint32_t type)
{
if (type == ESM::REC_GMAP)
mMap->readRecord(reader, type);
else if (type == ESM::REC_KEYS)
mQuickKeysMenu->readRecord(reader, type);
else if (type == ESM::REC_ASPL)
{
reader.getSubNameIs("ID__");
ESM::RefId spell = reader.getRefId();
if (mStore->get<ESM::Spell>().search(spell))
mSelectedSpell = spell;
}
else if (type == ESM::REC_MARK)
{
ESM::CustomMarker marker;
marker.load(reader);
mCustomMarkers.addMarker(marker, false);
}
}
int WindowManager::countSavedGameRecords() const
{
return 1 // Global map
+ 1 // QuickKeysMenu
+ mCustomMarkers.size() + (!mSelectedSpell.empty() ? 1 : 0);
}
bool WindowManager::isSavingAllowed() const
{
return !MyGUI::InputManager::getInstance().isModalAny()
&& !isConsoleMode()
// TODO: remove this, once we have properly serialized the state of open windows
&& (!isGuiMode() || (mGuiModes.size() == 1 && (getMode() == GM_MainMenu || getMode() == GM_Rest)));
}
void WindowManager::playVideo(std::string_view name, bool allowSkipping, bool overrideSounds)
{
mVideoWidget->playVideo("video\\" + std::string{ name });
mVideoWidget->eventKeyButtonPressed.clear();
mVideoBackground->eventKeyButtonPressed.clear();
if (allowSkipping)
{
mVideoWidget->eventKeyButtonPressed += MyGUI::newDelegate(this, &WindowManager::onVideoKeyPressed);
mVideoBackground->eventKeyButtonPressed += MyGUI::newDelegate(this, &WindowManager::onVideoKeyPressed);
}
enableScene(false);
MyGUI::IntSize screenSize = MyGUI::RenderManager::getInstance().getViewSize();
sizeVideo(screenSize.width, screenSize.height);
MyGUI::Widget* oldKeyFocus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
setKeyFocusWidget(mVideoWidget);
mVideoBackground->setVisible(true);
bool cursorWasVisible = mCursorVisible;
setCursorVisible(false);
if (overrideSounds && mVideoWidget->hasAudioStream())
MWBase::Environment::get().getSoundManager()->pauseSounds(
MWSound::VideoPlayback, ~MWSound::Type::Movie & MWSound::Type::Mask);
Misc::FrameRateLimiter frameRateLimiter
= Misc::makeFrameRateLimiter(MWBase::Environment::get().getFrameRateLimit());
while (mVideoWidget->update() && !MWBase::Environment::get().getStateManager()->hasQuitRequest())
{
const double dt
= std::chrono::duration_cast<std::chrono::duration<double>>(frameRateLimiter.getLastFrameDuration())
.count();
MWBase::Environment::get().getInputManager()->update(dt, true, false);
if (!mWindowVisible)
{
mVideoWidget->pause();
std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
else
{
if (mVideoWidget->isPaused())
mVideoWidget->resume();
mViewer->eventTraversal();
mViewer->updateTraversal();
mViewer->renderingTraversals();
}
// at the time this function is called we are in the middle of a frame,
// so out of order calls are necessary to get a correct frameNumber for the next frame.
// refer to the advance() and frame() order in Engine::go()
mViewer->advance(mViewer->getFrameStamp()->getSimulationTime());
frameRateLimiter.limit();
}
mVideoWidget->stop();
MWBase::Environment::get().getSoundManager()->resumeSounds(MWSound::VideoPlayback);
setKeyFocusWidget(oldKeyFocus);
setCursorVisible(cursorWasVisible);
// Restore normal rendering
updateVisible();
mVideoBackground->setVisible(false);
}
void WindowManager::sizeVideo(int screenWidth, int screenHeight)
{
// Use black bars to correct aspect ratio
mVideoBackground->setSize(screenWidth, screenHeight);
mVideoWidget->autoResize(Settings::gui().mStretchMenuBackground);
}
void WindowManager::exitCurrentModal()
{
if (!mCurrentModals.empty())
{
WindowModal* window = mCurrentModals.back();
if (!window->exit())
return;
window->setVisible(false);
}
}
void WindowManager::addCurrentModal(WindowModal* input)
{
if (mCurrentModals.empty())
mKeyboardNavigation->saveFocus(getMode());
mCurrentModals.push_back(input);
mKeyboardNavigation->restoreFocus(-1);
mKeyboardNavigation->setModalWindow(input->mMainWidget);
mKeyboardNavigation->setDefaultFocus(input->mMainWidget, input->getDefaultKeyFocus());
}
void WindowManager::removeCurrentModal(WindowModal* input)
{
if (!mCurrentModals.empty())
{
if (input == mCurrentModals.back())
{
mCurrentModals.pop_back();
mKeyboardNavigation->saveFocus(-1);
}
else
{
auto found = std::find(mCurrentModals.begin(), mCurrentModals.end(), input);
if (found != mCurrentModals.end())
mCurrentModals.erase(found);
else
Log(Debug::Warning) << "Warning: can't find modal window " << input;
}
}
if (mCurrentModals.empty())
{
mKeyboardNavigation->setModalWindow(nullptr);
mKeyboardNavigation->restoreFocus(getMode());
}
else
mKeyboardNavigation->setModalWindow(mCurrentModals.back()->mMainWidget);
}
void WindowManager::onVideoKeyPressed(MyGUI::Widget* _sender, MyGUI::KeyCode _key, MyGUI::Char _char)
{
if (_key == MyGUI::KeyCode::Escape)
mVideoWidget->stop();
}
void WindowManager::updatePinnedWindows()
{
mInventoryWindow->setPinned(Settings::windows().mInventoryPin);
if (Settings::windows().mInventoryHidden)
mShown = (GuiWindow)(mShown ^ GW_Inventory);
mMap->setPinned(Settings::windows().mMapPin);
if (Settings::windows().mMapHidden)
mShown = (GuiWindow)(mShown ^ GW_Map);
mSpellWindow->setPinned(Settings::windows().mSpellsPin);
if (Settings::windows().mSpellsHidden)
mShown = (GuiWindow)(mShown ^ GW_Magic);
mStatsWindow->setPinned(Settings::windows().mStatsPin);
if (Settings::windows().mStatsHidden)
mShown = (GuiWindow)(mShown ^ GW_Stats);
}
void WindowManager::pinWindow(GuiWindow window)
{
switch (window)
{
case GW_Inventory:
mInventoryWindow->setPinned(true);
break;
case GW_Map:
mMap->setPinned(true);
break;
case GW_Magic:
mSpellWindow->setPinned(true);
break;
case GW_Stats:
mStatsWindow->setPinned(true);
break;
default:
break;
}
updateVisible();
}
void WindowManager::fadeScreenIn(const float time, bool clearQueue, float delay)
{
if (clearQueue)
mScreenFader->clearQueue();
mScreenFader->fadeOut(time, delay);
}
void WindowManager::fadeScreenOut(const float time, bool clearQueue, float delay)
{
if (clearQueue)
mScreenFader->clearQueue();
mScreenFader->fadeIn(time, delay);
}
void WindowManager::fadeScreenTo(const int percent, const float time, bool clearQueue, float delay)
{
if (clearQueue)
mScreenFader->clearQueue();
mScreenFader->fadeTo(percent, time, delay);
}
void WindowManager::setBlindness(const int percent)
{
mBlindnessFader->notifyAlphaChanged(percent / 100.f);
}
void WindowManager::activateHitOverlay(bool interrupt)
{
if (!Settings::gui().mHitFader)
return;
if (!interrupt && !mHitFader->isEmpty())
return;
mHitFader->clearQueue();
mHitFader->fadeTo(100, 0.0f);
mHitFader->fadeTo(0, 0.5f);
}
void WindowManager::setWerewolfOverlay(bool set)
{
if (!Settings::gui().mWerewolfOverlay)
return;
if (mWerewolfFader)
mWerewolfFader->notifyAlphaChanged(set ? 1.0f : 0.0f);
}
void WindowManager::onClipboardChanged(std::string_view _type, std::string_view _data)
{
if (_type == "Text")
SDL_SetClipboardText(MyGUI::TextIterator::getOnlyText(MyGUI::UString(_data)).asUTF8().c_str());
}
void WindowManager::onClipboardRequested(std::string_view _type, std::string& _data)
{
if (_type != "Text")
return;
char* text = nullptr;
text = SDL_GetClipboardText();
if (text)
_data = MyGUI::TextIterator::toTagsString(text);
SDL_free(text);
}
void WindowManager::toggleConsole()
{
bool visible = mConsole->isVisible();
if (!visible && !mGuiModes.empty())
mKeyboardNavigation->saveFocus(mGuiModes.back());
mConsole->setVisible(!visible);
if (visible && !mGuiModes.empty())
mKeyboardNavigation->restoreFocus(mGuiModes.back());
updateVisible();
}
void WindowManager::toggleDebugWindow()
{
mDebugWindow->setVisible(!mDebugWindow->isVisible());
}
void WindowManager::togglePostProcessorHud()
{
if (!MWBase::Environment::get().getWorld()->getPostProcessor()->isEnabled())
{
messageBox("#{OMWEngine:PostProcessingIsNotEnabled}");
return;
}
bool visible = mPostProcessorHud->isVisible();
if (!visible && !mGuiModes.empty())
mKeyboardNavigation->saveFocus(mGuiModes.back());
mPostProcessorHud->setVisible(!visible);
if (visible && !mGuiModes.empty())
mKeyboardNavigation->restoreFocus(mGuiModes.back());
updateVisible();
}
void WindowManager::cycleSpell(bool next)
{
if (!isGuiMode())
mSpellWindow->cycle(next);
}
void WindowManager::cycleWeapon(bool next)
{
if (!isGuiMode())
mInventoryWindow->cycle(next);
}
void WindowManager::playSound(const ESM::RefId& soundId, float volume, float pitch)
{
if (soundId.empty())
return;
MWBase::Environment::get().getSoundManager()->playSound(
soundId, volume, pitch, MWSound::Type::Sfx, MWSound::PlayMode::NoEnvNoScaling);
}
void WindowManager::updateSpellWindow()
{
if (mSpellWindow)
mSpellWindow->updateSpells();
}
void WindowManager::setConsoleSelectedObject(const MWWorld::Ptr& object)
{
mConsole->setSelectedObject(object);
}
MWWorld::Ptr WindowManager::getConsoleSelectedObject() const
{
return mConsole->getSelectedObject();
}
void WindowManager::printToConsole(const std::string& msg, std::string_view color)
{
mConsole->print(msg, color);
}
void WindowManager::setConsoleMode(std::string_view mode)
{
mConsole->setConsoleMode(mode);
}
const std::string& WindowManager::getConsoleMode()
{
return mConsole->getConsoleMode();
}
void WindowManager::createCursors()
{
MyGUI::ResourceManager::EnumeratorPtr enumerator = MyGUI::ResourceManager::getInstance().getEnumerator();
while (enumerator.next())
{
MyGUI::IResource* resource = enumerator.current().second;
ResourceImageSetPointerFix* imgSetPointer = resource->castType<ResourceImageSetPointerFix>(false);
if (!imgSetPointer)
continue;
auto tex_name = imgSetPointer->getImageSet()->getIndexInfo(0, 0).texture;
osg::ref_ptr<osg::Image> image = mResourceSystem->getImageManager()->getImage(tex_name);
if (image.valid())
{
// everything looks good, send it to the cursor manager
Uint8 hotspot_x = imgSetPointer->getHotSpot().left;
Uint8 hotspot_y = imgSetPointer->getHotSpot().top;
int rotation = imgSetPointer->getRotation();
MyGUI::IntSize pointerSize = imgSetPointer->getSize();
mCursorManager->createCursor(imgSetPointer->getResourceName(), rotation, image, hotspot_x, hotspot_y,
pointerSize.width, pointerSize.height);
}
}
}
void WindowManager::createTextures()
{
{
MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("white");
tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8);
unsigned char* data = reinterpret_cast<unsigned char*>(tex->lock(MyGUI::TextureUsage::Write));
for (int x = 0; x < 8; ++x)
for (int y = 0; y < 8; ++y)
{
*(data++) = 255;
*(data++) = 255;
*(data++) = 255;
}
tex->unlock();
}
{
MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("black");
tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8);
unsigned char* data = reinterpret_cast<unsigned char*>(tex->lock(MyGUI::TextureUsage::Write));
for (int x = 0; x < 8; ++x)
for (int y = 0; y < 8; ++y)
{
*(data++) = 0;
*(data++) = 0;
*(data++) = 0;
}
tex->unlock();
}
{
MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().createTexture("transparent");
tex->createManual(8, 8, MyGUI::TextureUsage::Write, MyGUI::PixelFormat::R8G8B8A8);
setMenuTransparency(Settings::gui().mMenuTransparency);
}
}
void WindowManager::setMenuTransparency(float value)
{
MyGUI::ITexture* tex = MyGUI::RenderManager::getInstance().getTexture("transparent");
unsigned char* data = reinterpret_cast<unsigned char*>(tex->lock(MyGUI::TextureUsage::Write));
for (int x = 0; x < 8; ++x)
for (int y = 0; y < 8; ++y)
{
*(data++) = 255;
*(data++) = 255;
*(data++) = 255;
*(data++) = static_cast<unsigned char>(value * 255);
}
tex->unlock();
}
void WindowManager::addCell(MWWorld::CellStore* cell)
{
mLocalMapRender->addCell(cell);
}
void WindowManager::removeCell(MWWorld::CellStore* cell)
{
mLocalMapRender->removeCell(cell);
}
void WindowManager::writeFog(MWWorld::CellStore* cell)
{
mLocalMapRender->saveFogOfWar(cell);
}
const MWGui::TextColours& WindowManager::getTextColours()
{
return mTextColours;
}
bool WindowManager::injectKeyPress(MyGUI::KeyCode key, unsigned int text, bool repeat)
{
if (!mKeyboardNavigation->injectKeyPress(key, text, repeat))
{
MyGUI::Widget* focus = MyGUI::InputManager::getInstance().getKeyFocusWidget();
bool widgetActive = MyGUI::InputManager::getInstance().injectKeyPress(key, text);
if (!widgetActive || !focus)
return false;
// FIXME: MyGUI doesn't allow widgets to state if a given key was actually used, so make a guess
if (focus->getTypeName().find("Button") != std::string::npos)
{
switch (key.getValue())
{
case MyGUI::KeyCode::ArrowDown:
case MyGUI::KeyCode::ArrowUp:
case MyGUI::KeyCode::ArrowLeft:
case MyGUI::KeyCode::ArrowRight:
case MyGUI::KeyCode::Return:
case MyGUI::KeyCode::NumpadEnter:
case MyGUI::KeyCode::Space:
return true;
default:
return false;
}
}
return false;
}
else
return true;
}
bool WindowManager::injectKeyRelease(MyGUI::KeyCode key)
{
return MyGUI::InputManager::getInstance().injectKeyRelease(key);
}
void WindowManager::GuiModeState::update(bool visible)
{
for (const auto& window : mWindows)
window->setVisible(visible);
}
void WindowManager::watchActor(const MWWorld::Ptr& ptr)
{
mStatsWatcher->watchActor(ptr);
}
MWWorld::Ptr WindowManager::getWatchedActor() const
{
return mStatsWatcher->getWatchedActor();
}
const std::string& WindowManager::getVersionDescription() const
{
return mVersionDescription;
}
void WindowManager::handleScheduledMessageBoxes()
{
const auto scheduledMessageBoxes = mScheduledMessageBoxes.lock();
for (const ScheduledMessageBox& v : *scheduledMessageBoxes)
messageBox(v.mMessage, v.mShowInDialogueMode);
scheduledMessageBoxes->clear();
}
void WindowManager::onDeleteCustomData(const MWWorld::Ptr& ptr)
{
for (const auto& window : mWindows)
window->onDeleteCustomData(ptr);
}
void WindowManager::asyncPrepareSaveMap()
{
mMap->asyncPrepareSaveMap();
}
void WindowManager::setDisabledByLua(std::string_view windowId, bool disabled)
{
mLuaIdToWindow.at(windowId)->setDisabledByLua(disabled);
updateVisible();
}
std::vector<std::string_view> WindowManager::getAllWindowIds() const
{
std::vector<std::string_view> res;
for (const auto& [id, _] : mLuaIdToWindow)
res.push_back(id);
return res;
}
std::vector<std::string_view> WindowManager::getAllowedWindowIds(GuiMode mode) const
{
std::vector<std::string_view> res;
if (mode == GM_Inventory)
{
if (mAllowed & GW_Map)
res.push_back(mMap->getWindowIdForLua());
if (mAllowed & GW_Inventory)
res.push_back(mInventoryWindow->getWindowIdForLua());
if (mAllowed & GW_Magic)
res.push_back(mSpellWindow->getWindowIdForLua());
if (mAllowed & GW_Stats)
res.push_back(mStatsWindow->getWindowIdForLua());
}
else
{
auto it = mGuiModeStates.find(mode);
if (it != mGuiModeStates.end())
{
for (const auto* w : it->second.mWindows)
if (!w->getWindowIdForLua().empty())
res.push_back(w->getWindowIdForLua());
}
}
return res;
}
}