You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
openmw/apps/openmw/mwgui/windowmanagerimp.cpp

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;
}
}