/* =========================================================================== Copyright (C) 2015 the OpenMoHAA team This file is part of OpenMoHAA source code. OpenMoHAA source code is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenMoHAA source code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenMoHAA source code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA =========================================================================== */ #include "ui_local.h" MenuManager menuManager; Event EV_PushMenu ( "pushmenu", EV_DEFAULT, "s", "menuname", "Pushes the menu on the stack" ); Event EV_LockMenus ( "lock", EV_DEFAULT, NULL, NULL, "Lock out the menu from receiving input" ); Event EV_UnlockMenus ( "unlock", EV_DEFAULT, NULL, NULL, "Unlock the menu from receiving input" ); Event EV_ShowMenu ( "showmenu", EV_DEFAULT, "B", "activate", "Shows the menu." ); Event EV_HideMenu ( "hidemenu", EV_DEFAULT, NULL, NULL, "Hides the menu." ); CLASS_DECLARATION(Listener, Menu, NULL) { {&EV_HideMenu, &Menu::HideMenu}, {&EV_ShowMenu, &Menu::ShowMenu}, {NULL, NULL } }; Menu::Menu() { menuManager.AddMenu(this); m_fullscreen = qfalse; } Menu::Menu(str name) { setName(name); m_fullscreen = qfalse; menuManager.AddMenu(this); } void Menu::AddMenuItem(UIWidget *item) { m_itemlist.AddObject(item); // add all item's children for (int i = 1; i <= item->m_children.NumObjects(); i++) { m_itemlist.AddObject(item->m_children.ObjectAt(i)); } } void Menu::DeleteMenuItem(UIWidget *item) { // remove all item's children for (int i = item->m_children.NumObjects(); i > 0; i--) { m_itemlist.RemoveObject(item->m_children.ObjectAt(i)); } m_itemlist.RemoveObject(item); } void Menu::setName(str name) { m_name = name; } void Menu::ShowMenu(Event *ev) { qboolean activate; int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); UIWidgetContainer *widcon = (UIWidgetContainer *)wid; if (wid->isSubclassOf(UIWidgetContainer) && widcon->m_layout) { widcon->m_layout->ForceLoad(); } if (wid->isEnabled()) { wid->setShow(true); wid->ResetMotion(MOTION_IN); wid->UpdateUIElement(); wid->UpdateData(); wid->ExecuteShowCommands(); } } if (ev && ev->NumArgs() > 0) { activate = ev->GetBoolean(1); } else { activate = qtrue; } if (n && activate) { UIWidgetContainer *widcon = (UIWidgetContainer *)m_itemlist.ObjectAt(1); uWinMan.ActivateControl(widcon); widcon->SetLastActiveWidgetOrderNum(); } uWinMan.setFirstResponder(NULL); } void Menu::HideMenu(Event *ev) { int i, n; bool force = false; float maxtime; maxtime = GetMaxMotionTime(); if (ev->NumArgs() > 0) { force = ev->GetBoolean(1); } n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->getMotionType() != MOTION_OUT) { wid->ResetMotion(MOTION_OUT); if (!force) { Event *event = new Event("hide"); wid->PostEvent(event, maxtime); } else { wid->setShow(false); } } } } void Menu::ForceShow(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); UIWidgetContainer *widcon = (UIWidgetContainer *)wid; if (wid->isSubclassOf(UIWidgetContainer) && widcon->m_layout) { widcon->m_layout->ForceLoad(); } if (wid->isEnabled()) { wid->setShow(true); } } } void Menu::ForceHide(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); wid->ExecuteHideCommands(); wid->setShow(false); } } UIWidget *Menu::GetContainerWidget(void) { if (m_itemlist.NumObjects() > 0) { return m_itemlist.ObjectAt(1); } else { return NULL; } } UIWidget *Menu::GetNamedWidget(const char *pszName) { int i; UIWidget *pWidget; for (i = 1; i <= m_itemlist.NumObjects(); i++) { pWidget = m_itemlist.ObjectAt(i); if (!stricmp(pszName, pWidget->getName())) { return pWidget; } } return NULL; } void Menu::Update(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); wid->UpdateUIElement(); wid->UpdateData(); } } void Menu::RealignWidgets(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); wid->Realign(); } } float Menu::GetMaxMotionTime(void) { int i; int n; float maxtime = 0.0; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (maxtime < wid->getMotionTime()) { maxtime = wid->getMotionTime(); } } return maxtime; } void Menu::ActivateMenu(void) { if (m_itemlist.NumObjects()) { UIWidgetContainer *widcon = (UIWidgetContainer *)m_itemlist.ObjectAt(1); uWinMan.ActivateControl(widcon); widcon->SetLastActiveWidgetOrderNum(); uWinMan.setFirstResponder(NULL); widcon->BringToFrontPropogated(); } } qboolean Menu::isFullscreen(void) { return m_fullscreen; } void Menu::setFullscreen(qboolean bFullScreen) { m_fullscreen = bFullScreen; } int Menu::getVidMode(void) { return m_vidmode; } void Menu::setVidMode(int iMode) { m_vidmode = iMode; } qboolean Menu::isVisible(void) { UIWidget *wid = GetContainerWidget(); if (wid) { return wid->IsVisible(); } return false; } void Menu::SaveCVars(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->m_cvarname.length()) { const char *ret = UI_GetCvarString(wid->m_cvarname, NULL); if (ret) { wid->m_cvarvalue = ret; } else { wid->m_cvarvalue = ""; } } } } void Menu::RestoreCVars(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->m_cvarname.length()) { uii.Cvar_Set(wid->m_cvarname, wid->m_cvarvalue); } } } void Menu::ResetCVars(void) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->m_cvarname.length()) { uii.Cvar_Reset(wid->m_cvarname); } } } void Menu::PassEventToWidget(str name, Event *ev) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->getName() == name && wid->ValidEvent(ev->getName())) { wid->ProcessEvent(ev); return; } } } void Menu::PassEventToAllWidgets(Event& ev) { int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->ValidEvent(ev.getName())) { wid->ProcessEvent(ev); } } } void Menu::CheckRestart(void) { cvar_t *cvar; qboolean do_restart = false; qboolean do_snd_restart = false; qboolean do_ter_restart = false; int i; int n; n = m_itemlist.NumObjects(); for (i = 1; i <= n; i++) { UIWidget *wid = m_itemlist.ObjectAt(i); if (wid->m_cvarname.length()) { cvar = uii.Cvar_Find(wid->m_cvarname); if (cvar && cvar->latchedString) { if (str::icmp(wid->m_cvarvalue, cvar->latchedString)) { if (cvar->flags & CVAR_LATCH) { do_restart = true; } else if (cvar->flags & CVAR_SOUND_LATCH) { do_snd_restart = true; } else if (cvar->flags & CVAR_TERRAIN_LATCH) { do_ter_restart = true; } } } } } if (do_restart) { uii.Cmd_Stuff("vid_restart\n"); } else { if (do_snd_restart) { uii.Cmd_Stuff("snd_restart\n"); } if (do_ter_restart) { uii.Cmd_Stuff("ter_restart\n"); } } } CLASS_DECLARATION(Listener, MenuManager, NULL) { {&EV_PushMenu, &MenuManager::PushMenu}, {&EV_LockMenus, &MenuManager::Lock }, {&EV_UnlockMenus, &MenuManager::Unlock }, {NULL, NULL } }; MenuManager::MenuManager() { m_lock = false; } void MenuManager::RealignMenus(void) { int i; int num; num = m_menulist.NumObjects(); for (i = 1; i <= num; i++) { m_menulist.ObjectAt(i)->RealignWidgets(); } } void MenuManager::AddMenu(Menu *m) { m_menulist.AddObject(m); } void MenuManager::DeleteMenu(Menu *m) { m_menulist.RemoveObject(m); } void MenuManager::DeleteAllMenus(void) { for (int i = m_menulist.NumObjects(); i > 0; i--) { Menu *menu = m_menulist.ObjectAt(i); delete menu; } // // Added in OPM // Make sure to clear the menu list and stack m_menulist.FreeObjectList(); m_menustack.Clear(); m_showmenustack.Clear(); } Menu *MenuManager::FindMenu(str name) { int i; int count; count = m_menulist.NumObjects(); for (i = 1; i <= count; i++) { Menu *m = m_menulist.ObjectAt(i); if (!str::icmp(m->m_name, name)) { return m; } } return NULL; } bool MenuManager::PushMenu(str name) { Menu *m; float maxouttime = 0.0; float maxintime; Menu *head; if (m_lock) { return false; } m = FindMenu(name); if (!m) { uii.Sys_Printf("Couldn't find menu %s\n", name.c_str()); return false; } // don't push the same menu head = m_menustack.Head(); if (head == m) { return false; } m->SaveCVars(); if (head) { maxouttime = head->GetMaxMotionTime(); head->ProcessEvent(Event("hidemenu")); } if (maxouttime == 0.0) { m->ProcessEvent(Event("showmenu")); } else { m->PostEvent(Event("showmenu"), maxouttime); } maxintime = m->GetMaxMotionTime(); Lock(NULL); PostEvent(EV_UnlockMenus, maxintime + maxouttime); m_menustack.Push(m); return true; } bool MenuManager::ShowMenu(str name) { Menu *m; float maxintime; if (m_lock) { return false; } m = FindMenu(name); if (!m) { uii.Sys_Printf("Couldn't find menu %s\n", name.c_str()); return false; } m->SaveCVars(); m->ProcessEvent(new Event("showmenu")); maxintime = m->GetMaxMotionTime(); Lock(NULL); PostEvent(EV_UnlockMenus, maxintime); m_showmenustack.Push(m); return true; } void MenuManager::PushMenu(Event *ev) { if (!ui_pLoadingMenu || CurrentMenu() != ui_pLoadingMenu) { PushMenu(ev->GetString(1)); } } void MenuManager::PopMenu(qboolean restore_cvars) { Menu *top; Menu *head; float maxtime = 0.0; if (m_lock) { return; } top = m_showmenustack.Pop(); if (top) { if (restore_cvars) { top->RestoreCVars(); } //maxtime = top->GetMaxMotionTime(); top->ProcessEvent(Event("hidemenu")); } else { top = m_menustack.Pop(); if (top) { if (restore_cvars) { top->RestoreCVars(); } maxtime = top->GetMaxMotionTime(); top->ProcessEvent(Event("hidemenu")); head = m_menustack.Head(); if (head) { head->PostEvent(Event("showmenu"), maxtime); } } Lock(NULL); PostEvent(EV_UnlockMenus, maxtime); } } Menu *MenuManager::CurrentMenu(void) { Menu *head; head = m_showmenustack.Head(); if (head) { return head; } head = m_menustack.Head(); if (head) { return head; } return NULL; } bool MenuManager::ClearMenus(bool force) { int i, num; Menu *top; Menu *menu; float maxtime; float newmaxtime; maxtime = 0.0; if (m_lock) { return false; } if (!m_showmenustack.Head() && !m_menustack.Head()) { return true; } top = m_showmenustack.Head(); while (!m_showmenustack.Empty()) { menu = m_showmenustack.Pop(); newmaxtime = top->GetMaxMotionTime(); if (maxtime < newmaxtime) { maxtime = newmaxtime; } if (force) { // force the menu to hide menu->ForceHide(); continue; } // otherwise send the "hidemenu" event // the menu will process it or not menu->ProcessEvent(new Event("hidemenu")); } top = m_menustack.Head(); while (!m_menustack.Empty()) { menu = m_menustack.Pop(); newmaxtime = top->GetMaxMotionTime(); if (maxtime < newmaxtime) { maxtime = newmaxtime; } if (force) { // force the menu to hide menu->ForceHide(); continue; } // otherwise send the "hidemenu" event // the menu will process it or not menu->ProcessEvent(new Event("hidemenu")); } num = m_menulist.NumObjects(); for (i = 1; i <= num; i++) { menu = m_menulist.ObjectAt(i); if (!menu->isVisible()) { continue; } newmaxtime = top->GetMaxMotionTime(); if (maxtime < newmaxtime) { maxtime = newmaxtime; } if (force) { menu->ForceHide(); continue; } menu->ProcessEvent(new Event("hidemenu")); } if (!force) { Lock(NULL); PostEvent(EV_UnlockMenus, maxtime); } return true; } void MenuManager::ListMenus(void) { int i; int num; num = m_menulist.NumObjects(); for (i = 1; i <= num; i++) { Menu *menu = m_menulist.ObjectAt(i); uii.Sys_Printf("%s\n", menu->m_name.c_str()); } } void MenuManager::UpdateAllMenus(void) { int i; int num; num = m_menulist.NumObjects(); for (i = 1; i <= num; i++) { Menu *menu = m_menulist.ObjectAt(i); menu->Update(); } } void MenuManager::Lock(Event *ev) { m_lock = true; } void MenuManager::Unlock(Event *ev) { m_lock = false; } void MenuManager::PassEventToWidget(str name, Event *ev) { Menu *head = CurrentMenu(); if (head) { head->PassEventToWidget(name, ev); } } void MenuManager::PassEventToAllWidgets(Event& ev) { int i; int iMenuCount; iMenuCount = m_menulist.NumObjects(); for (i = 1; i <= iMenuCount; i++) { Menu *pMenu = m_menulist.ObjectAt(i); pMenu->PassEventToAllWidgets(ev); } } void MenuManager::ResetCVars(void) { Menu *head = CurrentMenu(); if (head) { head->ResetCVars(); } } void MenuManager::CheckRestart(void) { Menu *head = CurrentMenu(); if (head) { head->CheckRestart(); } } bool MenuManager::ForceMenu(str name) { Menu *m; Menu *head; m = FindMenu(name); if (!m) { uii.Sys_Printf("Couldn't find menu %s\n", name.c_str()); return false; } // don't push the same menu head = m_menustack.Head(); if (head == m) { return false; } m->SaveCVars(); if (head) { head->ForceHide(); } m->ProcessEvent(Event("showmenu")); // add the new menu to the stack m_menustack.Push(m); return true; }