core/MenuManager.cpp
author Nicholas Hastings <skamonkey@gmail.com>
Tue Jan 22 23:18:27 2013 -0500 (2013-01-22)
changeset 3749 4dc3d723c490
parent 3004 e3ac0dc6d9a4
child 3872 4c93f74cae51
permissions -rw-r--r--
Triggering build against new mac libprotobuf.
     1 /**
     2  * vim: set ts=4 :
     3  * =============================================================================
     4  * SourceMod
     5  * Copyright (C) 2004-2008 AlliedModders LLC.  All rights reserved.
     6  * =============================================================================
     7  *
     8  * This program is free software; you can redistribute it and/or modify it under
     9  * the terms of the GNU General Public License, version 3.0, as published by the
    10  * Free Software Foundation.
    11  * 
    12  * This program is distributed in the hope that it will be useful, but WITHOUT
    13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    15  * details.
    16  *
    17  * You should have received a copy of the GNU General Public License along with
    18  * this program.  If not, see <http://www.gnu.org/licenses/>.
    19  *
    20  * As a special exception, AlliedModders LLC gives you permission to link the
    21  * code of this program (as well as its derivative works) to "Half-Life 2," the
    22  * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
    23  * by the Valve Corporation.  You must obey the GNU General Public License in
    24  * all respects for all other code used.  Additionally, AlliedModders LLC grants
    25  * this exception to all derivative works.  AlliedModders LLC defines further
    26  * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
    27  * or <http://www.sourcemod.net/license.php>.
    28  *
    29  * Version: $Id$
    30  */
    31 
    32 #include <time.h>
    33 #include <stdarg.h>
    34 #include <stdlib.h>
    35 #include "MenuManager.h"
    36 #include "MenuVoting.h"
    37 #include "sm_stringutil.h"
    38 #include "sourcemm_api.h"
    39 #include "PlayerManager.h"
    40 #include "MenuStyle_Valve.h"
    41 #include "ShareSys.h"
    42 #include "HandleSys.h"
    43 #include "sourcemm_api.h"
    44 #include "logic_bridge.h"
    45 
    46 MenuManager g_Menus;
    47 VoteMenuHandler s_VoteHandler;
    48 
    49 ConVar sm_menu_sounds("sm_menu_sounds", "1", 0, "Sets whether SourceMod menus play trigger sounds");
    50 
    51 MenuManager::MenuManager()
    52 {
    53 	m_Styles.push_back(&g_ValveMenuStyle);
    54 	SetDefaultStyle(&g_ValveMenuStyle);
    55 }
    56 
    57 void MenuManager::OnSourceModAllInitialized()
    58 {
    59 	g_ShareSys.AddInterface(NULL, this);
    60 
    61 	HandleAccess access;
    62 	g_HandleSys.InitAccessDefaults(NULL, &access);
    63 
    64 	/* Deny cloning to menus */
    65 	access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
    66 	m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL);
    67 
    68 	/* Also deny deletion to styles */
    69 	access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY;
    70 	m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL);
    71 }
    72 
    73 void MenuManager::OnSourceModAllShutdown()
    74 {
    75 	g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent);
    76 	g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent);
    77 }
    78 
    79 void MenuManager::OnHandleDestroy(HandleType_t type, void *object)
    80 {
    81 	if (type == m_MenuType)
    82 	{
    83 		IBaseMenu *menu = (IBaseMenu *)object;
    84 		menu->Destroy(false);
    85 	}
    86 	else if (type == m_StyleType)
    87 	{
    88 		/* Do nothing */
    89 	}
    90 }
    91 
    92 bool MenuManager::GetHandleApproxSize(HandleType_t type, void *object, unsigned int *pSize)
    93 {
    94 	if (type == m_MenuType)
    95 	{
    96 		*pSize = ((IBaseMenu *)object)->GetApproxMemUsage();
    97 		return true;
    98 	}
    99 	else
   100 	{
   101 		*pSize = ((IMenuStyle *)object)->GetApproxMemUsage();
   102 		return true;
   103 	}
   104 
   105 	return false;
   106 }
   107 
   108 Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner)
   109 {
   110 	if (m_MenuType == NO_HANDLE_TYPE)
   111 	{
   112 		return BAD_HANDLE;
   113 	}
   114 
   115 	return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL);
   116 }
   117 
   118 Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style)
   119 {
   120 	if (m_StyleType == NO_HANDLE_TYPE)
   121 	{
   122 		return BAD_HANDLE;
   123 	}
   124 
   125 	return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL);
   126 }
   127 
   128 HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu)
   129 {
   130 	HandleSecurity sec;
   131 
   132 	sec.pIdentity = g_pCoreIdent;
   133 	sec.pOwner = NULL;
   134 
   135 	return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu);
   136 }
   137 
   138 HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style)
   139 {
   140 	HandleSecurity sec;
   141 
   142 	sec.pIdentity = g_pCoreIdent;
   143 	sec.pOwner = g_pCoreIdent;
   144 
   145 	return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style);
   146 }
   147 
   148 bool MenuManager::SetDefaultStyle(IMenuStyle *style)
   149 {
   150 	if (!style)
   151 	{
   152 		return false;
   153 	}
   154 
   155 	m_pDefaultStyle = style;
   156 
   157 	return true;
   158 }
   159 
   160 IMenuStyle *MenuManager::GetStyle(unsigned int index)
   161 {
   162 	if (index >= GetStyleCount())
   163 	{
   164 		return NULL;
   165 	}
   166 
   167 	return m_Styles[index];
   168 }
   169 
   170 void MenuManager::AddStyle(IMenuStyle *style)
   171 {
   172 	m_Styles.push_back(style);
   173 }
   174 
   175 unsigned int MenuManager::GetStyleCount()
   176 {
   177 	return (unsigned int)m_Styles.size();
   178 }
   179 
   180 IMenuStyle *MenuManager::FindStyleByName(const char *name)
   181 {
   182 	unsigned int count = GetStyleCount();
   183 	for (unsigned int i=0; i<count; i++)
   184 	{
   185 		IMenuStyle *ptr = GetStyle(i);
   186 		if (strcasecmp(ptr->GetStyleName(), name) == 0)
   187 		{
   188 			return ptr;
   189 		}
   190 	}
   191 
   192 	return NULL;
   193 }
   194 
   195 inline bool IsSlotItem(IMenuPanel *display,
   196 					   unsigned int style)
   197 {
   198 	if (!display->CanDrawItem(style))
   199 	{
   200 	return false;
   201 	}
   202 	if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE)
   203 	{
   204 		return false;
   205 	}
   206 	if (style & ITEMDRAW_RAWLINE)
   207 	{
   208 		return false;
   209 	}
   210 
   211 	return true;
   212 }
   213 
   214 IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order)
   215 {
   216 	IBaseMenu *menu = md.menu;
   217 
   218 	if (!menu)
   219 	{
   220 		return NULL;
   221 	}
   222 
   223 	struct
   224 	{
   225 		unsigned int position;
   226 		ItemDrawInfo draw;
   227 	} drawItems[10];
   228 
   229 	/* Figure out how many items to draw */
   230 	IMenuStyle *style = menu->GetDrawStyle();
   231 	unsigned int pgn = menu->GetPagination();
   232 	unsigned int maxItems = style->GetMaxPageItems();
   233 	bool exitButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXIT) == MENUFLAG_BUTTON_EXIT;
   234 	bool novoteButton = (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_NOVOTE) == MENUFLAG_BUTTON_NOVOTE;
   235 
   236 	if (pgn != MENU_NO_PAGINATION)
   237 	{
   238 		maxItems = pgn;
   239 	}
   240 	else if (exitButton)
   241 	{
   242 		maxItems--;
   243 	}
   244 
   245 	if (novoteButton)
   246 	{
   247 		maxItems--;
   248 	}
   249 
   250 	/* This is very not allowed! */
   251 	if (maxItems < 2)
   252 	{
   253 		return NULL;
   254 	}
   255 
   256 	unsigned int totalItems = menu->GetItemCount();
   257 	unsigned int startItem = 0;
   258 
   259 	/* For pagination, find the starting point. */
   260 	if (pgn != MENU_NO_PAGINATION)
   261 	{
   262 		if (order == ItemOrder_Ascending)
   263 		{
   264 			startItem = md.lastItem;
   265 			/* This shouldn't happen with well-coded menus.
   266 			 * If the item is out of bounds, switch the order to
   267 			 * Items_Descending and make us start from the top.
   268 			 */
   269 			if (startItem >= totalItems)
   270 			{
   271 				startItem = totalItems - 1;
   272 				order = ItemOrder_Descending;
   273 			}
   274 		}
   275 		else if (order == ItemOrder_Descending)
   276 		{
   277 			startItem = md.firstItem;
   278 			/* This shouldn't happen with well-coded menus.
   279 			 * If searching backwards doesn't give us enough room,
   280 			 * start from the beginning and change to ascending.
   281 			 */
   282 			if (startItem <= maxItems)
   283 			{
   284 				startItem = 0;
   285 				order = ItemOrder_Ascending;
   286 			}
   287 		}
   288 	}
   289 
   290 	/* Get our Display pointer and initialize some crap */
   291 	IMenuPanel *panel = menu->CreatePanel();
   292 	IMenuHandler *mh = md.mh;
   293 	bool foundExtra = false;
   294 	unsigned int extraItem = 0;
   295 
   296 	if (panel == NULL)
   297 	{
   298 		return NULL;
   299 	}
   300 
   301 	/**
   302 	 * We keep searching until:
   303 	 * 1) There are no more items
   304 	 * 2) We reach one OVER the maximum number of slot items
   305 	 * 3) We have reached maxItems and pagination is MENU_NO_PAGINATION
   306 	 */
   307 	unsigned int i = startItem;
   308 	unsigned int foundItems = 0;
   309 	while (totalItems)
   310 	{
   311 		ItemDrawInfo &dr = drawItems[foundItems].draw;
   312 		/* Is the item valid? */
   313 		if (menu->GetItemInfo(i, &dr) != NULL)
   314 		{
   315 			/* Ask the user to change the style, if necessary */
   316 			mh->OnMenuDrawItem(menu, client, i, dr.style);
   317 			/* Check if it's renderable */
   318 			if (IsSlotItem(panel, dr.style))
   319 			{
   320 				/* If we've already found the max number of items,
   321 				 * This means we should just cancel out and log our
   322 				 * "last item."
   323 				 */
   324 				if (foundItems >= maxItems)
   325 				{
   326 					foundExtra = true;
   327 					extraItem = i;
   328 					break;
   329 				}
   330 				drawItems[foundItems++].position = i;
   331 			}
   332 		}
   333 		/* If there's no pagination, stop once the menu is full. */
   334 		if (pgn == MENU_NO_PAGINATION)
   335 		{
   336 			/* If we've filled up, then stop */
   337 			if (foundItems >= maxItems)
   338 			{
   339 				break;
   340 			}
   341 		}
   342 		/* If we're descending and this is the first item, stop */
   343 		if (order == ItemOrder_Descending)
   344 		{
   345 			if (i == 0)
   346 			{
   347 				break;
   348 			}
   349 			i--;
   350 		} 
   351 		/* If we're ascending and this is the last item, stop */
   352 		else if (order == ItemOrder_Ascending)
   353 		{
   354 			if (i >= totalItems - 1)
   355 			{
   356 				break;
   357 			}
   358 			i++;
   359 		}
   360 	}
   361 
   362 	/* There were no items to draw! */
   363 	if (!foundItems)
   364 	{
   365 		panel->DeleteThis();
   366 		return NULL;
   367 	}
   368 
   369 	bool displayPrev = false;
   370 	bool displayNext = false;
   371 
   372 	/* This is an annoying process.
   373 	 * Skip it for non-paginated menus, which get special treatment.
   374 	 */
   375 	if (pgn != MENU_NO_PAGINATION)
   376 	{
   377 		if (foundExtra)
   378 		{
   379 			if (order == ItemOrder_Descending)
   380 			{
   381 				displayPrev = true;
   382 				md.firstItem = extraItem;
   383 			}
   384 			else if (order == ItemOrder_Ascending)
   385 			{
   386 				displayNext = true;
   387 				md.lastItem = extraItem;
   388 			}
   389 		}
   390 
   391 		unsigned int lastItem = 0;
   392 		ItemDrawInfo dr;
   393 		/* Find the last feasible item to search from. */
   394 		if (order == ItemOrder_Descending)
   395 		{
   396 			lastItem = drawItems[0].position;
   397 			if (lastItem >= totalItems - 1)
   398 			{
   399 				goto skip_search;
   400 			}
   401 			while (++lastItem < totalItems)
   402 			{
   403 				if (menu->GetItemInfo(lastItem, &dr) != NULL)
   404 				{
   405 					mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
   406 					if (IsSlotItem(panel, dr.style))
   407 					{
   408 						displayNext = true;
   409 						md.lastItem = lastItem;
   410 						break;
   411 					}
   412 				}
   413 			}
   414 		}
   415 		else if (order == ItemOrder_Ascending)
   416 		{
   417 			lastItem = drawItems[0].position;
   418 			if (lastItem == 0)
   419 			{
   420 				goto skip_search;
   421 			}
   422 			lastItem--;
   423 			while (lastItem != 0)
   424 			{
   425 				if (menu->GetItemInfo(lastItem, &dr) != NULL)
   426 				{
   427 					mh->OnMenuDrawItem(menu, client, lastItem, dr.style);
   428 					if (IsSlotItem(panel, dr.style))
   429 					{
   430 						displayPrev = true;
   431 						md.firstItem = lastItem;
   432 						break;
   433 					}
   434 				}
   435 				lastItem--;
   436 			}
   437 		}
   438 	}
   439 
   440 skip_search:
   441 
   442 	/* Draw the item according to the order */
   443 	menu_slots_t *slots = md.slots;
   444 	unsigned int position = 0;			/* Keep track of the last position */
   445 
   446 	if (novoteButton)
   447 	{
   448 		char text[50];
   449 		if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "No Vote", &client))
   450 		{
   451 			UTIL_Format(text, sizeof(text), "No Vote");
   452 		}
   453 		ItemDrawInfo dr(text, 0);
   454 		position = panel->DrawItem(dr);
   455 		slots[position].type = ItemSel_Exit;
   456 		position++;
   457 	}
   458 
   459 	if (order == ItemOrder_Ascending)
   460 	{
   461 		md.item_on_page = drawItems[0].position;
   462 		for (unsigned int i = 0; i < foundItems; i++)
   463 		{
   464 			ItemDrawInfo &dr = drawItems[i].draw;
   465 			if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
   466 			{
   467 				position = panel->DrawItem(dr);
   468 			}
   469 			if (position != 0)
   470 			{
   471 				slots[position].item = drawItems[i].position;
   472 				if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED)
   473 				{
   474 					slots[position].type = ItemSel_None;
   475 				}
   476 				else
   477 				{
   478 					slots[position].type = ItemSel_Item;
   479 				}
   480 			}
   481 		}
   482 	}
   483 	else if (order == ItemOrder_Descending)
   484 	{
   485 		unsigned int i = foundItems;
   486 		/* NOTE: There will always be at least one item because
   487 		 * of the check earlier.
   488 		 */
   489 		md.item_on_page = drawItems[foundItems - 1].position;
   490 		while (i--)
   491 		{
   492 			ItemDrawInfo &dr = drawItems[i].draw;
   493 			if ((position = mh->OnMenuDisplayItem(menu, client, panel, drawItems[i].position, dr)) == 0)
   494 			{
   495 				position = panel->DrawItem(dr);
   496 			}
   497 			if (position != 0)
   498 			{
   499 				slots[position].item = drawItems[i].position;
   500 				if ((dr.style & ITEMDRAW_DISABLED) == ITEMDRAW_DISABLED)
   501 				{
   502 					slots[position].type = ItemSel_None;
   503 				}
   504 				else
   505 				{
   506 					slots[position].type = ItemSel_Item;
   507 				}
   508 			}
   509 		}
   510 	}
   511 
   512 	/* Now, we need to check if we need to add anything extra */
   513 	if (pgn != MENU_NO_PAGINATION || exitButton)
   514 	{
   515 		bool canDrawDisabled = panel->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL);
   516 		bool exitBackButton = false;
   517 		char text[50];
   518 
   519 		if (pgn != MENU_NO_PAGINATION
   520 			&& (menu->GetMenuOptionFlags() & MENUFLAG_BUTTON_EXITBACK) == MENUFLAG_BUTTON_EXITBACK)
   521 		{
   522 			exitBackButton = true;
   523 		}
   524 
   525 		/* Calculate how many items we are allowed for control stuff */
   526 		unsigned int padding = style->GetMaxPageItems() - maxItems;
   527 		
   528 		/* Add the number of available slots */
   529 		padding += (maxItems - foundItems);
   530 
   531 		/* Someday, if we are able to re-enable this, we will be very lucky men. */
   532 #if 0
   533 		if (!style->FeatureExists(MenuStyleFeature_ImplicitExit))
   534 		{
   535 #endif
   536 		/* Even if we don't draw an exit button, we invalidate the slot. */
   537 		padding--;
   538 #if 0
   539 		} else {
   540 			/* Otherwise, we don't draw anything and leave the slot available */
   541 			exitButton = false;
   542 		}
   543 #endif
   544 
   545 		if (pgn != MENU_NO_PAGINATION)
   546 		{
   547 			/* Subtract two slots for the displayNext/displayPrev padding */
   548 			padding -= 2;
   549 		}
   550 
   551 		/* If we have an "Exit Back" button and the space to draw it, do so. */
   552 		if (exitBackButton)
   553 		{
   554 			if (!displayPrev)
   555 			{
   556 				displayPrev = true;
   557 			}
   558 			else
   559 			{
   560 				exitBackButton = false;
   561 			}
   562 		}
   563 
   564 		/**
   565 		 * We allow next/prev to be undrawn if neither exists.
   566 		 * Thus, we only need padding if one of them will be drawn,
   567 		 * or the exit button will be drawn.
   568 		 */
   569 		ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER);
   570 		if (exitButton || (displayNext || displayPrev))
   571 		{
   572 			/* If there are no control options,
   573 			 * Instead just pad with invisible slots.
   574 			 */
   575 			if (!displayPrev && !displayPrev)
   576 			{
   577 				padItem.style = ITEMDRAW_NOTEXT;
   578 			}
   579 			/* Add spacers so we can pad to the end */
   580 			for (unsigned int i=0; i<padding; i++)
   581 			{
   582 				position = panel->DrawItem(padItem);
   583 				slots[position].type = ItemSel_None;
   584 			}
   585 		}
   586 
   587 		/* Put a fake spacer before control stuff, if possible */
   588 		if ((displayPrev || displayNext) || exitButton)
   589 		{
   590 			ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER);
   591 			panel->DrawItem(draw);
   592 		}
   593 
   594 		ItemDrawInfo dr(text, 0);
   595 
   596 		/**
   597 		 * If we have one or the other, we need to have spacers for both.
   598 		 */
   599 		if (pgn != MENU_NO_PAGINATION)
   600 		{
   601 			if (displayPrev || displayNext)
   602 			{
   603 				/* PREVIOUS */
   604 				ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL);
   605 				if (displayPrev || canDrawDisabled)
   606 				{
   607 					if (exitBackButton)
   608 					{
   609 						if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Back", &client))
   610 						{
   611 							UTIL_Format(text, sizeof(text), "Back");
   612 						}
   613 						dr.style = ITEMDRAW_CONTROL;
   614 						position = panel->DrawItem(dr);
   615 						slots[position].type = ItemSel_ExitBack;
   616 					}
   617 					else
   618 					{
   619 						if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Previous", &client))
   620 						{
   621 							UTIL_Format(text, sizeof(text), "Previous");
   622 						}
   623 						dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
   624 						position = panel->DrawItem(dr);
   625 						slots[position].type = ItemSel_Back;
   626 					}
   627 				}
   628 				else if (displayNext || exitButton)
   629 				{
   630 					/* If we can't display this, and there is an exit button,
   631 					 * we need to pad!
   632 					 */
   633 					position = panel->DrawItem(padCtrlItem);
   634 					slots[position].type = ItemSel_None;
   635 				}
   636 
   637 				/* NEXT */
   638 				if (displayNext || canDrawDisabled)
   639 				{
   640 					if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Next", &client))
   641 					{
   642 						UTIL_Format(text, sizeof(text), "Next");
   643 					}
   644 					dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL;
   645 					position = panel->DrawItem(dr);
   646 					slots[position].type = ItemSel_Next;
   647 				}
   648 				else if (exitButton)
   649 				{
   650 					/* If we can't display this,
   651 					 * but there is an "exit" button, we need to pad!
   652 					 */
   653 					position = panel->DrawItem(padCtrlItem);
   654 					slots[position].type = ItemSel_None;
   655 				}
   656 			}
   657 			else
   658 			{
   659 				/* Otherwise, bump to two slots! */
   660 				ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT);
   661 				position = panel->DrawItem(numBump);
   662 				slots[position].type = ItemSel_None;
   663 				position = panel->DrawItem(numBump);
   664 				slots[position].type = ItemSel_None;
   665 			}
   666 		}
   667 
   668 		/* EXIT */
   669 		if (exitButton)
   670 		{
   671 			if (!logicore.CoreTranslate(text, sizeof(text), "%T", 2, NULL, "Exit", &client))
   672 			{
   673 				UTIL_Format(text, sizeof(text), "Exit");
   674 			}
   675 			dr.style = ITEMDRAW_CONTROL;
   676 			position = panel->DrawItem(dr);
   677 			slots[position].type = ItemSel_Exit;
   678 		}
   679 	}
   680 
   681 	/* Lastly, fill in any slots we could have missed */
   682 	for (unsigned int i = position + 1; i < 10; i++)
   683 	{
   684 		slots[i].type = ItemSel_None;
   685 	}
   686 
   687 	/* Do title stuff */
   688 	mh->OnMenuDisplay(menu, client, panel);
   689 	panel->DrawTitle(menu->GetDefaultTitle(), true);
   690 
   691 	return panel;
   692 }
   693 
   694 IMenuStyle *MenuManager::GetDefaultStyle()
   695 {
   696 	return m_pDefaultStyle;
   697 }
   698 
   699 bool MenuManager::MenuSoundsEnabled()
   700 {
   701 	return (sm_menu_sounds.GetInt() != 0);
   702 }
   703 
   704 ConfigResult MenuManager::OnSourceModConfigChanged(const char *key,
   705 												   const char *value,
   706 												   ConfigSource source,
   707 												   char *error,
   708 												   size_t maxlength)
   709 {
   710 	if (strcmp(key, "MenuItemSound") == 0)
   711 	{
   712 		m_SelectSound.assign(value);
   713 		return ConfigResult_Accept;
   714 	} else if (strcmp(key, "MenuExitBackSound") == 0) {
   715 		m_ExitBackSound.assign(value);
   716 		return ConfigResult_Accept;
   717 	} else if (strcmp(key, "MenuExitSound") == 0) {
   718 		m_ExitSound.assign(value);
   719 		return ConfigResult_Accept;
   720 	}
   721 
   722 	return ConfigResult_Ignore;
   723 }
   724 
   725 const char *MenuManager::GetMenuSound(ItemSelection sel)
   726 {
   727 	const char *sound = NULL;
   728 
   729 	switch (sel)
   730 	{
   731 	case ItemSel_Back:
   732 	case ItemSel_Next:
   733 	case ItemSel_Item:
   734 		{
   735 			if (m_SelectSound.size() > 0)
   736 			{
   737 				sound = m_SelectSound.c_str();
   738 			}
   739 			break;
   740 		}
   741 	case ItemSel_ExitBack:
   742 		{
   743 			if (m_ExitBackSound.size() > 0)
   744 			{
   745 				sound = m_ExitBackSound.c_str();
   746 			}
   747 			break;
   748 		}
   749 	case ItemSel_Exit:
   750 		{
   751 			if (m_ExitSound.size() > 0)
   752 			{
   753 				sound = m_ExitSound.c_str();
   754 			}
   755 			break;
   756 		}
   757 	default:
   758 		{
   759 			break;
   760 		}
   761 	}
   762 
   763 	return sound;
   764 }
   765 
   766 void MenuManager::OnSourceModLevelChange(const char *mapName)
   767 {
   768 	if (m_SelectSound.size() > 0)
   769 	{
   770 		enginesound->PrecacheSound(m_SelectSound.c_str(), true);
   771 	}
   772 	if (m_ExitBackSound.size() > 0)
   773 	{
   774 		enginesound->PrecacheSound(m_ExitBackSound.c_str(), true);
   775 	}
   776 	if (m_ExitSound.size() > 0)
   777 	{
   778 		enginesound->PrecacheSound(m_ExitSound.c_str(), true);
   779 	}
   780 }
   781 
   782 void MenuManager::CancelMenu(IBaseMenu *menu)
   783 {
   784 	if (s_VoteHandler.GetCurrentMenu() == menu
   785 		&& !s_VoteHandler.IsCancelling())
   786 	{
   787 		s_VoteHandler.CancelVoting();
   788 		return;
   789 	}
   790 
   791 	menu->Cancel();
   792 }
   793 
   794 bool MenuManager::StartVote(IBaseMenu *menu, unsigned int num_clients, int clients[], unsigned int max_time, unsigned int flags)
   795 {
   796 	return s_VoteHandler.StartVote(menu, num_clients, clients, max_time, flags);
   797 }
   798 
   799 bool MenuManager::IsVoteInProgress()
   800 {
   801 	return s_VoteHandler.IsVoteInProgress();
   802 }
   803 
   804 void MenuManager::CancelVoting()
   805 {
   806 	s_VoteHandler.CancelVoting();
   807 }
   808 
   809 unsigned int MenuManager::GetRemainingVoteDelay()
   810 {
   811 	return s_VoteHandler.GetRemainingVoteDelay();
   812 }
   813 
   814 bool MenuManager::IsClientInVotePool(int client)
   815 {
   816 	return s_VoteHandler.IsClientInVotePool(client);
   817 }
   818 
   819 bool MenuManager::RedrawClientVoteMenu(int client)
   820 {
   821 	return RedrawClientVoteMenu2(client, true);
   822 }
   823 
   824 bool MenuManager::RedrawClientVoteMenu2(int client, bool revote)
   825 {
   826 	return s_VoteHandler.RedrawToClient(client, revote);
   827 }
   828