Files
2025-07-19 23:30:20 +02:00

834 lines
16 KiB
C++

/*
===========================================================================
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;
}