diff --git a/builtin/common/settings/dlg_settings.lua b/builtin/common/settings/dlg_settings.lua index 7f519f9c3..e19ed7351 100644 --- a/builtin/common/settings/dlg_settings.lua +++ b/builtin/common/settings/dlg_settings.lua @@ -518,7 +518,7 @@ local function get_formspec(dialogdata) ("button[0,%f;%f,0.8;back;%s]"):format( tabsize.height + 0.2, back_w, - INIT == "pause_menu" and fgettext("Exit") or fgettext("Back")), + fgettext("Back")), ("box[%f,%f;%f,0.8;#0000008C]"):format( back_w + 0.2, tabsize.height + 0.2, checkbox_w), diff --git a/src/client/game_formspec.cpp b/src/client/game_formspec.cpp index 3b86ae7e3..3d46ddab5 100644 --- a/src/client/game_formspec.cpp +++ b/src/client/game_formspec.cpp @@ -215,7 +215,6 @@ void GameFormSpec::deleteFormspec() m_formspec->drop(); m_formspec = nullptr; } - m_formname.clear(); } GameFormSpec::~GameFormSpec() { @@ -227,8 +226,10 @@ GameFormSpec::~GameFormSpec() { bool GameFormSpec::handleEmptyFormspec(const std::string &formspec, const std::string &formname) { if (formspec.empty()) { - if (m_formspec && (formname.empty() || formname == m_formname)) { - m_formspec->quitMenu(); + GUIModalMenu *menu = g_menumgr.tryGetTopMenu(); + if (menu && (formname.empty() || formname == menu->getName())) { + // `m_formspec` will be fixed up in `GameFormSpec::update()` + menu->quitMenu(); } return true; } @@ -245,10 +246,11 @@ void GameFormSpec::showFormSpec(const std::string &formspec, const std::string & TextDestPlayerInventory *txt_dst = new TextDestPlayerInventory(m_client, formname); - m_formname = formname; + // Replace the currently open formspec GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), m_client->getSoundManager()); + m_formspec->setName(formname); } void GameFormSpec::showCSMFormSpec(const std::string &formspec, const std::string &formname) @@ -260,10 +262,10 @@ void GameFormSpec::showCSMFormSpec(const std::string &formspec, const std::strin LocalScriptingFormspecHandler *txt_dst = new LocalScriptingFormspecHandler(formname, m_client->getScript()); - m_formname = formname; GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), m_client->getSoundManager()); + m_formspec->setName(formname); } void GameFormSpec::showPauseMenuFormSpec(const std::string &formspec, const std::string &formname) @@ -272,20 +274,25 @@ void GameFormSpec::showPauseMenuFormSpec(const std::string &formspec, const std: // the in-game settings formspec. // Neither CSM nor the server must be allowed to mess with it. - if (handleEmptyFormspec(formspec, formname)) + // If we send updated formspec contents, we can either (1) recycle the old + // GUIFormSpecMenu or (2) close the old and open a new one. This is option 2. + (void)handleEmptyFormspec("", formname); + if (formspec.empty()) return; FormspecFormSource *fs_src = new FormspecFormSource(formspec); LocalScriptingFormspecHandler *txt_dst = new LocalScriptingFormspecHandler(formname, m_pause_script.get()); - m_formname = formname; - GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), + GUIFormSpecMenu *fs = nullptr; + GUIFormSpecMenu::create(fs, m_client, m_rendering_engine->get_gui_env(), // Ignore formspec prepend. &m_input->joystick, fs_src, txt_dst, "", m_client->getSoundManager()); - m_formspec->doPause = true; + fs->setName(formname); + fs->doPause = true; + fs->drop(); // 1 reference held by `g_menumgr` } void GameFormSpec::showNodeFormspec(const std::string &formspec, const v3s16 &nodepos) @@ -299,7 +306,6 @@ void GameFormSpec::showNodeFormspec(const std::string &formspec, const v3s16 &no &m_client->getEnv().getClientMap(), nodepos); TextDest *txt_dst = new TextDestNodeMetadata(nodepos, m_client); - m_formname = ""; GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), m_client->getSoundManager()); @@ -336,7 +342,7 @@ void GameFormSpec::showPlayerInventory() } TextDest *txt_dst = new TextDestPlayerInventory(m_client); - m_formname = ""; + GUIFormSpecMenu::create(m_formspec, m_client, m_rendering_engine->get_gui_env(), &m_input->joystick, fs_src, txt_dst, m_client->getFormspecPrepend(), m_client->getSoundManager()); diff --git a/src/client/game_formspec.h b/src/client/game_formspec.h index b38056463..6dff32e50 100644 --- a/src/client/game_formspec.h +++ b/src/client/game_formspec.h @@ -55,9 +55,9 @@ private: InputHandler *m_input; std::unique_ptr m_pause_script; - // Default: "". If other than "": Empty show_formspec packets will only - // close the formspec when the formname matches - std::string m_formname; + /// The currently open formspec that is not a submenu of the pause menu + /// FIXME: Layering is already managed by `GUIModalMenu` (`g_menumgr`), hence this + /// variable should be removed in long-term. GUIFormSpecMenu *m_formspec = nullptr; bool handleEmptyFormspec(const std::string &formspec, const std::string &formname); diff --git a/src/gui/guiVolumeChange.cpp b/src/gui/guiVolumeChange.cpp index 4d1139dce..7546e8ccc 100644 --- a/src/gui/guiVolumeChange.cpp +++ b/src/gui/guiVolumeChange.cpp @@ -77,7 +77,7 @@ void GUIVolumeChange::regenerateGui(v2u32 screensize) core::rect rect(0, 0, 100 * s, 30 * s); rect = rect + v2s32(size.X / 2 - 100 * s / 2, size.Y / 2 + 55 * s); GUIButton::addButton(Environment, rect, m_tsrc, this, ID_soundExitButton, - wstrgettext("Exit").c_str()); + wstrgettext("Back").c_str()); } { core::rect rect(0, 0, 300 * s, 20 * s); diff --git a/src/gui/mainmenumanager.h b/src/gui/mainmenumanager.h index 9b5bea5f7..3bc8f7daa 100644 --- a/src/gui/mainmenumanager.h +++ b/src/gui/mainmenumanager.h @@ -76,6 +76,13 @@ public: return m_stack.size(); } + GUIModalMenu *tryGetTopMenu() const + { + if (m_stack.empty()) + return nullptr; + return dynamic_cast(m_stack.back()); + } + void deleteFront() { m_stack.front()->setVisible(false);