diff -r c7b4237fff50 -r 03a67e41afbc core/MenuManager.cpp
--- a/core/MenuManager.cpp Fri Mar 28 06:21:34 2008 +0000
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,747 +0,0 @@
-/**
- * vim: set ts=4 :
- * =============================================================================
- * SourceMod
- * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
- * =============================================================================
- *
- * This program is free software; you can redistribute it and/or modify it under
- * the terms of the GNU General Public License, version 3.0, as published by the
- * Free Software Foundation.
- *
- * This program 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
- * this program. If not, see .
- *
- * As a special exception, AlliedModders LLC gives you permission to link the
- * code of this program (as well as its derivative works) to "Half-Life 2," the
- * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
- * by the Valve Corporation. You must obey the GNU General Public License in
- * all respects for all other code used. Additionally, AlliedModders LLC grants
- * this exception to all derivative works. AlliedModders LLC defines further
- * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
- * or .
- *
- * Version: $Id$
- */
-
-#include
-#include
-#include
-#include "MenuManager.h"
-#include "MenuVoting.h"
-#include "sm_stringutil.h"
-#include "sourcemm_api.h"
-#include "PlayerManager.h"
-#include "MenuStyle_Valve.h"
-#include "ShareSys.h"
-#include "HandleSys.h"
-#include "sourcemm_api.h"
-
-MenuManager g_Menus;
-VoteMenuHandler s_VoteHandler;
-
-ConVar sm_menu_sounds("sm_menu_sounds", "1", 0, "Sets whether SourceMod menus play trigger sounds");
-
-MenuManager::MenuManager()
-{
- m_Styles.push_back(&g_ValveMenuStyle);
- SetDefaultStyle(&g_ValveMenuStyle);
-}
-
-void MenuManager::OnSourceModAllInitialized()
-{
- g_ShareSys.AddInterface(NULL, this);
-
- HandleAccess access;
- g_HandleSys.InitAccessDefaults(NULL, &access);
-
- /* Deny cloning to menus */
- access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
- m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
-
- /* Also deny deletion to styles */
- access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
- m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
-}
-
-void MenuManager::OnSourceModAllShutdown()
-{
- g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
- g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
-}
-
-void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
-{
- if (type == m_MenuType)
- {
- IBaseMenu *menu = (IBaseMenu *)object;
- menu->Destroy(false);
- } else if (type == m_StyleType) {
- /* Do nothing */
- }
-}
-
-Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
-{
- if (m_MenuType == NO_HANDLE_TYPE)
- {
- return BAD_HANDLE;
- }
-
- return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
-}
-
-Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
-{
- if (m_StyleType == NO_HANDLE_TYPE)
- {
- return BAD_HANDLE;
- }
-
- return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
-}
-
-HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
-{
- HandleSecurity sec;
-
- sec.pIdentity = g_pCoreIdent;
- sec.pOwner = NULL;
-
- return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
-}
-
-HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
-{
- HandleSecurity sec;
-
- sec.pIdentity = g_pCoreIdent;
- sec.pOwner = g_pCoreIdent;
-
- return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
-}
-
-bool MenuManager::SetDefaultStyle(IMenuStyle *style)
-{
- if (!style)
- {
- return false;
- }
-
- m_pDefaultStyle = style;
-
- return true;
-}
-
-IMenuStyle *MenuManager::GetStyle(unsigned int index)
-{
- if (index >= GetStyleCount())
- {
- return NULL;
- }
-
- return m_Styles[index];
-}
-
-void MenuManager::AddStyle(IMenuStyle *style)
-{
- m_Styles.push_back(style);
-}
-
-unsigned int MenuManager::GetStyleCount()
-{
- return (unsigned int)m_Styles.size();
-}
-
-IMenuStyle *MenuManager::FindStyleByName(const char *name)
-{
- unsigned int count = GetStyleCount();
- for (unsigned int i=0; iGetStyleName(), name) == 0)
- {
- return ptr;
- }
- }
-
- return NULL;
-}
-
-inline bool IsSlotItem(IMenuPanel *display,
- unsigned int style)
-{
- if (!display->CanDrawItem(style))
- {
- return false;
- }
- if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
- {
- return false;
- }
- if (style & ITEMDRAW_RAWLINE)
- {
- return false;
- }
-
- return true;
-}
-
-IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order)
-{
- IBaseMenu *menu = md.menu;
-
- if (!menu)
- {
- return NULL;
- }
-
- struct
- {
- unsigned int position;
- ItemDrawInfo draw;
- } drawItems[10];
-
- /* Figure out how many items to draw */
- IMenuStyle *style = menu->GetDrawStyle();
- unsigned int pgn = menu->GetPagination();
- unsigned int maxItems = style->GetMaxPageItems();
- bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
-
- if (pgn != MENU_NO_PAGINATION)
- {
- maxItems = pgn;
- }
- else if (exitButton)
- {
- maxItems--;
- }
-
- /* This is very not allowed! */
- if (maxItems < 2)
- {
- return NULL;
- }
-
- unsigned int totalItems = menu->GetItemCount();
- unsigned int startItem = 0;
-
- /* For pagination, find the starting point. */
- if (pgn != MENU_NO_PAGINATION)
- {
- if (order == ItemOrder_Ascending)
- {
- startItem = md.lastItem;
- /* This shouldn't happen with well-coded menus.
- * If the item is out of bounds, switch the order to
- * Items_Descending and make us start from the top.
- */
- if (startItem >= totalItems)
- {
- startItem = totalItems - 1;
- order = ItemOrder_Descending;
- }
- }
- else if (order == ItemOrder_Descending)
- {
- startItem = md.firstItem;
- /* This shouldn't happen with well-coded menus.
- * If searching backwards doesn't give us enough room,
- * start from the beginning and change to ascending.
- */
- if (startItem <= maxItems)
- {
- startItem = 0;
- order = ItemOrder_Ascending;
- }
- }
- }
-
- /* Get our Display pointer and initialize some crap */
- IMenuPanel *panel = menu->CreatePanel();
- IMenuHandler *mh = md.mh;
- bool foundExtra = false;
- unsigned int extraItem = 0;
-
- if (panel == NULL)
- {
- return NULL;
- }
-
- /**
- * We keep searching until:
- * 1) There are no more items
- * 2) We reach one OVER the maximum number of slot items
- * 3) We have reached maxItems and pagination is MENU_NO_PAGINATION
- */
- unsigned int i = startItem;
- unsigned int foundItems = 0;
- while (totalItems)
- {
- ItemDrawInfo &dr = drawItems[foundItems].draw;
- /* Is the item valid? */
- if (menu->GetItemInfo(i, &dr) != NULL)
- {
- /* Ask the user to change the style, if necessary */
- mh->OnMenuDrawItem(menu, client, i, dr.style);
- /* Check if it's renderable */
- if (IsSlotItem(panel, dr.style))
- {
- /* If we've already found the max number of items,
- * This means we should just cancel out and log our
- * "last item."
- */
- if (foundItems >= maxItems)
- {
- foundExtra = true;
- extraItem = i;
- break;
- }
- drawItems[foundItems++].position = i;
- }
- }
- /* If there's no pagination, stop once the menu is full. */
- if (pgn == MENU_NO_PAGINATION)
- {
- /* If we've filled up, then stop */
- if (foundItems >= maxItems)
- {
- break;
- }
- }
- /* If we're descending and this is the first item, stop */
- if (order == ItemOrder_Descending)
- {
- if (i == 0)
- {
- break;
- }
- i--;
- }
- /* If we're ascending and this is the last item, stop */
- else if (order == ItemOrder_Ascending)
- {
- if (i >= totalItems - 1)
- {
- break;
- }
- i++;
- }
- }
-
- /* There were no items to draw! */
- if (!foundItems)
- {
- panel->DeleteThis();
- return NULL;
- }
-
- bool displayPrev = false;
- bool displayNext = false;
-
- /* This is an annoying process.
- * Skip it for non-paginated menus, which get special treatment.
- */
- if (pgn != MENU_NO_PAGINATION)
- {
- if (foundExtra)
- {
- if (order == ItemOrder_Descending)
- {
- displayPrev = true;
- md.firstItem = extraItem;
- }
- else if (order == ItemOrder_Ascending)
- {
- displayNext = true;
- md.lastItem = extraItem;
- }
- }
-
- unsigned int lastItem = 0;
- ItemDrawInfo dr;
- /* Find the last feasible item to search from. */
- if (order == ItemOrder_Descending)
- {
- lastItem = drawItems[0].position;
- if (lastItem >= totalItems - 1)
- {
- goto skip_search;
- }
- while (++lastItem < totalItems)
- {
- if (menu->GetItemInfo(lastItem, &dr) != NULL)
- {
- mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
- if (IsSlotItem(panel, dr.style))
- {
- displayNext = true;
- md.lastItem = lastItem;
- break;
- }
- }
- }
- }
- else if (order == ItemOrder_Ascending)
- {
- lastItem = drawItems[0].position;
- if (lastItem == 0)
- {
- goto skip_search;
- }
- lastItem--;
- while (lastItem != 0)
- {
- if (menu->GetItemInfo(lastItem, &dr) != NULL)
- {
- mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
- if (IsSlotItem(panel, dr.style))
- {
- displayPrev = true;
- md.firstItem = lastItem;
- break;
- }
- }
- lastItem--;
- }
- }
- }
-
-skip_search:
-
- /* Draw the item according to the order */
- menu_slots_t *slots = md.slots;
- unsigned int position = 0; /* Keep track of the last position */
- if (order == ItemOrder_Ascending)
- {
- md.item_on_page = drawItems[0].position;
- for (unsigned int i = 0; i < foundItems; i++)
- {
- ItemDrawInfo &dr = drawItems[i].draw;
- if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
- {
- position = panel->DrawItem(dr);
- }
- if (position != 0)
- {
- slots[position].item = drawItems[i].position;
- slots[position].type = ItemSel_Item;
- }
- }
- }
- else if (order == ItemOrder_Descending)
- {
- unsigned int i = foundItems;
- /* NOTE: There will always be at least one item because
- * of the check earlier.
- */
- md.item_on_page = drawItems[foundItems - 1].position;
- while (i--)
- {
- ItemDrawInfo &dr = drawItems[i].draw;
- if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
- {
- position = panel->DrawItem(dr);
- }
- if (position != 0)
- {
- slots[position].item = drawItems[i].position;
- slots[position].type = ItemSel_Item;
- }
- }
- }
-
- /* Now, we need to check if we need to add anything extra */
- if (pgn != MENU_NO_PAGINATION || exitButton)
- {
- bool canDrawDisabled = panel->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
- bool exitBackButton = false;
- char text[50];
-
- if (pgn != MENU_NO_PAGINATION
- && (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK)
- {
- exitBackButton = true;
- }
-
- /* Calculate how many items we are allowed for control stuff */
- unsigned int padding = style->GetMaxPageItems() - maxItems;
-
- /* Add the number of available slots */
- padding += (maxItems - foundItems);
-
- /* Someday, if we are able to re-enable this, we will be very lucky men. */
-#if 0
- if (!style->FeatureExists(MenuStyleFeature_ImplicitExit))
- {
-#endif
- /* Even if we don't draw an exit button, we invalidate the slot. */
- padding--;
-#if 0
- } else {
- /* Otherwise, we don't draw anything and leave the slot available */
- exitButton = false;
- }
-#endif
-
- if (pgn != MENU_NO_PAGINATION)
- {
- /* Subtract two slots for the displayNext/displayPrev padding */
- padding -= 2;
- }
-
- /* If we have an "Exit Back" button and the space to draw it, do so. */
- if (exitBackButton)
- {
- if (!displayPrev)
- {
- displayPrev = true;
- }
- else
- {
- exitBackButton = false;
- }
- }
-
- /**
- * We allow next/prev to be undrawn if neither exists.
- * Thus, we only need padding if one of them will be drawn,
- * or the exit button will be drawn.
- */
- ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER);
- if (exitButton || (displayNext || displayPrev))
- {
- /* If there are no control options,
- * Instead just pad with invisible slots.
- */
- if (!displayPrev && !displayPrev)
- {
- padItem.style = ITEMDRAW_NOTEXT;
- }
- /* Add spacers so we can pad to the end */
- for (unsigned int i=0; iDrawItem(padItem);
- slots[position].type = ItemSel_None;
- }
- }
-
- /* Put a fake spacer before control stuff, if possible */
- if ((displayPrev || displayNext) || exitButton)
- {
- ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER);
- panel->DrawItem(draw);
- }
-
- ItemDrawInfo dr(text, 0);
-
- /**
- * If we have one or the other, we need to have spacers for both.
- */
- if (pgn != MENU_NO_PAGINATION)
- {
- if (displayPrev || displayNext)
- {
- /* PREVIOUS */
- ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL);
- if (displayPrev || canDrawDisabled)
- {
- if (exitBackButton)
- {
- CorePlayerTranslate(client, text, sizeof(text), "Back", NULL);
- dr.style = ITEMDRAW_CONTROL;
- position = panel->DrawItem(dr);
- slots[position].type = ItemSel_ExitBack;
- }
- else
- {
- CorePlayerTranslate(client, text, sizeof(text), "Previous", NULL);
- dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
- position = panel->DrawItem(dr);
- slots[position].type = ItemSel_Back;
- }
- }
- else if (displayNext || exitButton)
- {
- /* If we can't display this, and there is an exit button,
- * we need to pad!
- */
- position = panel->DrawItem(padCtrlItem);
- slots[position].type = ItemSel_None;
- }
-
- /* NEXT */
- if (displayNext || canDrawDisabled)
- {
- CorePlayerTranslate(client, text, sizeof(text), "Next", NULL);
- dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
- position = panel->DrawItem(dr);
- slots[position].type = ItemSel_Next;
- }
- else if (exitButton)
- {
- /* If we can't display this,
- * but there is an "exit" button, we need to pad!
- */
- position = panel->DrawItem(padCtrlItem);
- slots[position].type = ItemSel_None;
- }
- }
- else
- {
- /* Otherwise, bump to two slots! */
- ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT);
- position = panel->DrawItem(numBump);
- slots[position].type = ItemSel_None;
- position = panel->DrawItem(numBump);
- slots[position].type = ItemSel_None;
- }
- }
-
- /* EXIT */
- if (exitButton)
- {
- CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL);
- dr.style = ITEMDRAW_CONTROL;
- position = panel->DrawItem(dr);
- slots[position].type = ItemSel_Exit;
- }
- }
-
- /* Lastly, fill in any slots we could have missed */
- for (unsigned int i = position + 1; i < 10; i++)
- {
- slots[i].type = ItemSel_None;
- }
-
- /* Do title stuff */
- mh->OnMenuDisplay(menu, client, panel);
- panel->DrawTitle(menu->GetDefaultTitle(), true);
-
- return panel;
-}
-
-IMenuStyle *MenuManager::GetDefaultStyle()
-{
- return m_pDefaultStyle;
-}
-
-bool MenuManager::MenuSoundsEnabled()
-{
- return (sm_menu_sounds.GetInt() != 0);
-}
-
-ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
- const char *value,
- ConfigSource source,
- char *error,
- size_t maxlength)
-{
- if (strcmp(key, "MenuItemSound") == 0)
- {
- m_SelectSound.assign(value);
- return ConfigResult_Accept;
- } else if (strcmp(key, "MenuExitBackSound") == 0) {
- m_ExitBackSound.assign(value);
- return ConfigResult_Accept;
- } else if (strcmp(key, "MenuExitSound") == 0) {
- m_ExitSound.assign(value);
- return ConfigResult_Accept;
- }
-
- return ConfigResult_Ignore;
-}
-
-const char *MenuManager::GetMenuSound(ItemSelection sel)
-{
- const char *sound = NULL;
-
- switch (sel)
- {
- case ItemSel_Back:
- case ItemSel_Next:
- case ItemSel_Item:
- {
- if (m_SelectSound.size() > 0)
- {
- sound = m_SelectSound.c_str();
- }
- break;
- }
- case ItemSel_ExitBack:
- {
- if (m_ExitBackSound.size() > 0)
- {
- sound = m_ExitBackSound.c_str();
- }
- break;
- }
- case ItemSel_Exit:
- {
- if (m_ExitSound.size() > 0)
- {
- sound = m_ExitSound.c_str();
- }
- break;
- }
- default:
- {
- break;
- }
- }
-
- return sound;
-}
-
-void MenuManager::OnSourceModLevelChange(const char *mapName)
-{
- if (m_SelectSound.size() > 0)
- {
- enginesound->PrecacheSound(m_SelectSound.c_str(), true);
- }
- if (m_ExitBackSound.size() > 0)
- {
- enginesound->PrecacheSound(m_ExitBackSound.c_str(), true);
- }
- if (m_ExitSound.size() > 0)
- {
- enginesound->PrecacheSound(m_ExitSound.c_str(), true);
- }
-}
-
-void MenuManager::CancelMenu(IBaseMenu *menu)
-{
- if (s_VoteHandler.GetCurrentMenu() == menu
- && !s_VoteHandler.IsCancelling())
- {
- s_VoteHandler.CancelVoting();
- return;
- }
-
- menu->Cancel();
-}
-
-bool MenuManager::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags)
-{
- return s_VoteHandler.StartVote(menu, num_clients, clients, max_time, flags);
-}
-
-bool MenuManager::IsVoteInProgress()
-{
- return s_VoteHandler.IsVoteInProgress();
-}
-
-void MenuManager::CancelVoting()
-{
- s_VoteHandler.CancelVoting();
-}
-
-unsigned int MenuManager::GetRemainingVoteDelay()
-{
- return s_VoteHandler.GetRemainingVoteDelay();
-}