#include "mainmenu.hpp" #include #include #include #include #include #include #include "../mwbase/environment.hpp" #include "../mwbase/statemanager.hpp" #include "../mwbase/windowmanager.hpp" #include "../mwbase/world.hpp" #include "../mwworld/globals.hpp" #include "backgroundimage.hpp" #include "confirmationdialog.hpp" #include "savegamedialog.hpp" #include "videowidget.hpp" namespace MWGui { MainMenu::MainMenu(int w, int h, const VFS::Manager* vfs, const std::string& versionDescription) : WindowBase("openmw_mainmenu.layout") , mWidth(w) , mHeight(h) , mVFS(vfs) , mButtonBox(nullptr) , mBackground(nullptr) , mVideoBackground(nullptr) , mVideo(nullptr) { getWidget(mVersionText, "VersionText"); mVersionText->setCaption(versionDescription); mHasAnimatedMenu = mVFS->exists("video/menu_background.bik"); updateMenu(); } void MainMenu::onResChange(int w, int h) { mWidth = w; mHeight = h; updateMenu(); } void MainMenu::setVisible(bool visible) { if (visible) updateMenu(); bool isMainMenu = MWBase::Environment::get().getWindowManager()->containsMode(MWGui::GM_MainMenu) && MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame; showBackground(isMainMenu); if (visible) { if (isMainMenu) { if (mButtons["loadgame"]->getVisible()) MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["loadgame"]); else MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["newgame"]); } else MWBase::Environment::get().getWindowManager()->setKeyFocusWidget(mButtons["return"]); } Layout::setVisible(visible); } void MainMenu::onNewGameConfirmed() { MWBase::Environment::get().getWindowManager()->removeGuiMode(MWGui::GM_MainMenu); MWBase::Environment::get().getStateManager()->newGame(); } void MainMenu::onExitConfirmed() { MWBase::Environment::get().getStateManager()->requestQuit(); } void MainMenu::onButtonClicked(MyGUI::Widget* sender) { MWBase::WindowManager* winMgr = MWBase::Environment::get().getWindowManager(); const std::string& name = *sender->getUserData(); winMgr->playSound(ESM::RefId::stringRefId("Menu Click")); if (name == "return") { winMgr->removeGuiMode(GM_MainMenu); } else if (name == "options") winMgr->pushGuiMode(GM_Settings); else if (name == "credits") winMgr->playVideo("mw_credits.bik", true); else if (name == "exitgame") { if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame) onExitConfirmed(); else { ConfirmationDialog* dialog = winMgr->getConfirmationDialog(); dialog->askForConfirmation("#{OMWEngine:QuitGameConfirmation}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onExitConfirmed); dialog->eventCancelClicked.clear(); } } else if (name == "newgame") { if (MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_NoGame) onNewGameConfirmed(); else { ConfirmationDialog* dialog = winMgr->getConfirmationDialog(); dialog->askForConfirmation("#{OMWEngine:NewGameConfirmation}"); dialog->eventOkClicked.clear(); dialog->eventOkClicked += MyGUI::newDelegate(this, &MainMenu::onNewGameConfirmed); dialog->eventCancelClicked.clear(); } } else { if (!mSaveGameDialog) mSaveGameDialog = std::make_unique(); if (name == "loadgame") mSaveGameDialog->setLoadOrSave(true); else if (name == "savegame") mSaveGameDialog->setLoadOrSave(false); mSaveGameDialog->setVisible(true); } } void MainMenu::showBackground(bool show) { if (mVideo && !show) { MyGUI::Gui::getInstance().destroyWidget(mVideoBackground); mVideoBackground = nullptr; mVideo = nullptr; } if (mBackground && !show) { MyGUI::Gui::getInstance().destroyWidget(mBackground); mBackground = nullptr; } if (!show) return; bool stretch = Settings::Manager::getBool("stretch menu background", "GUI"); if (mHasAnimatedMenu) { if (!mVideo) { // Use black background to correct aspect ratio mVideoBackground = MyGUI::Gui::getInstance().createWidgetReal( "ImageBox", 0, 0, 1, 1, MyGUI::Align::Default, "MainMenuBackground"); mVideoBackground->setImageTexture("black"); mVideo = mVideoBackground->createWidget( "ImageBox", 0, 0, 1, 1, MyGUI::Align::Stretch, "MainMenuBackground"); mVideo->setVFS(mVFS); mVideo->playVideo("video\\menu_background.bik"); } MyGUI::IntSize viewSize = MyGUI::RenderManager::getInstance().getViewSize(); int screenWidth = viewSize.width; int screenHeight = viewSize.height; mVideoBackground->setSize(screenWidth, screenHeight); mVideo->autoResize(stretch); mVideo->setVisible(true); } else { if (!mBackground) { mBackground = MyGUI::Gui::getInstance().createWidgetReal( "ImageBox", 0, 0, 1, 1, MyGUI::Align::Stretch, "MainMenuBackground"); mBackground->setBackgroundImage("textures\\menu_morrowind.dds", true, stretch); } mBackground->setVisible(true); } } void MainMenu::onFrame(float dt) { if (mVideo) { if (!mVideo->update()) { // If finished playing, start again mVideo->playVideo("video\\menu_background.bik"); } } } bool MainMenu::exit() { return MWBase::Environment::get().getStateManager()->getState() == MWBase::StateManager::State_Running; } void MainMenu::updateMenu() { setCoord(0, 0, mWidth, mHeight); if (!mButtonBox) mButtonBox = mMainWidget->createWidget("", MyGUI::IntCoord(0, 0, 0, 0), MyGUI::Align::Default); int curH = 0; MWBase::StateManager::State state = MWBase::Environment::get().getStateManager()->getState(); mVersionText->setVisible(state == MWBase::StateManager::State_NoGame); std::vector buttons; if (state == MWBase::StateManager::State_Running) buttons.emplace_back("return"); buttons.emplace_back("newgame"); if (state == MWBase::StateManager::State_Running && MWBase::Environment::get().getWorld()->getGlobalInt(MWWorld::Globals::sCharGenState) == -1 && MWBase::Environment::get().getWindowManager()->isSavingAllowed()) buttons.emplace_back("savegame"); if (MWBase::Environment::get().getStateManager()->characterBegin() != MWBase::Environment::get().getStateManager()->characterEnd()) buttons.emplace_back("loadgame"); buttons.emplace_back("options"); if (state == MWBase::StateManager::State_NoGame) buttons.emplace_back("credits"); buttons.emplace_back("exitgame"); // Create new buttons if needed std::vector allButtons{ "return", "newgame", "savegame", "loadgame", "options", "credits", "exitgame" }; for (std::string& buttonId : allButtons) { if (mButtons.find(buttonId) == mButtons.end()) { Gui::ImageButton* button = mButtonBox->createWidget( "ImageBox", MyGUI::IntCoord(0, curH, 0, 0), MyGUI::Align::Default); button->setProperty("ImageHighlighted", "textures\\menu_" + buttonId + "_over.dds"); button->setProperty("ImageNormal", "textures\\menu_" + buttonId + ".dds"); button->setProperty("ImagePushed", "textures\\menu_" + buttonId + "_pressed.dds"); button->eventMouseButtonClick += MyGUI::newDelegate(this, &MainMenu::onButtonClicked); button->setUserData(std::string(buttonId)); mButtons[buttonId] = button; } } // Start by hiding all buttons int maxwidth = 0; for (auto& buttonPair : mButtons) { buttonPair.second->setVisible(false); MyGUI::IntSize requested = buttonPair.second->getRequestedSize(); if (requested.width > maxwidth) maxwidth = requested.width; } // Now show and position the ones we want for (std::string& buttonId : buttons) { assert(mButtons.find(buttonId) != mButtons.end()); Gui::ImageButton* button = mButtons[buttonId]; button->setVisible(true); // By default, assume that all menu buttons textures should have 64 height. // If they have a different resolution, scale them. MyGUI::IntSize requested = button->getRequestedSize(); float scale = requested.height / 64.f; button->setImageCoord(MyGUI::IntCoord(0, 0, requested.width, requested.height)); // Trim off some of the excessive padding // TODO: perhaps do this within ImageButton? int height = requested.height; button->setImageTile(MyGUI::IntSize(requested.width, requested.height - 16 * scale)); button->setCoord( (maxwidth - requested.width / scale) / 2, curH, requested.width / scale, height / scale - 16); curH += height / scale - 16; } if (state == MWBase::StateManager::State_NoGame) { // Align with the background image int bottomPadding = 24; mButtonBox->setCoord(mWidth / 2 - maxwidth / 2, mHeight - curH - bottomPadding, maxwidth, curH); } else mButtonBox->setCoord(mWidth / 2 - maxwidth / 2, mHeight / 2 - curH / 2, maxwidth, curH); } }