core/MenuStyle_Base.cpp
author David Anderson <dvander@alliedmods.net>
Fri Jun 22 21:04:13 2007 +0000 (2007-06-22)
changeset 1005 b15b5682d181
parent 997 2fc3152c3118
child 1131 d109d9e33ee5
permissions -rw-r--r--
- added request amb426
- "Back" is now "Previous" and "Back" is used for ExitBack
- menu api got bumped again, but will be compat
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include <stdarg.h>
    16 #include "sm_stringutil.h"
    17 #include "MenuStyle_Base.h"
    18 #include "PlayerManager.h"
    19 #include "MenuManager.h"
    20 #include "HandleSys.h"
    21 #if defined MENU_DEBUG
    22 #include "Logger.h"
    23 #endif
    24 
    25 BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
    26 {
    27 }
    28 
    29 Handle_t BaseMenuStyle::GetHandle()
    30 {
    31 	/* Don't create the handle until we need it */
    32 	if (m_hHandle == BAD_HANDLE)
    33 	{
    34 		m_hHandle = g_Menus.CreateStyleHandle(this);
    35 	}
    36 
    37 	return m_hHandle;
    38 }
    39 
    40 void BaseMenuStyle::AddClientToWatch(int client)
    41 {
    42 #if defined MENU_DEBUG
    43 	g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
    44 #endif
    45 	m_WatchList.push_back(client);
    46 }
    47 
    48 void BaseMenuStyle::RemoveClientFromWatch(int client)
    49 {
    50 #if defined MENU_DEBUG
    51 	g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
    52 #endif
    53 	m_WatchList.remove(client);
    54 }
    55 
    56 void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
    57 {
    58 #if defined MENU_DEBUG
    59 	g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
    60 #endif
    61 	CBaseMenuPlayer *player = GetMenuPlayer(client);
    62 	menu_states_t &states = player->states;
    63 
    64 	bool bOldIgnore = player->bAutoIgnore;
    65 	if (bAutoIgnore)
    66 	{
    67 		player->bAutoIgnore = true;
    68 	}
    69 
    70 	/* Save states */
    71 	IMenuHandler *mh = states.mh;
    72 	IBaseMenu *menu = states.menu;
    73 
    74 	/* Clear menu */
    75 	player->bInMenu = false;
    76 	if (player->menuHoldTime)
    77 	{
    78 		RemoveClientFromWatch(client);
    79 	}
    80 
    81 	/* Fire callbacks */
    82 	mh->OnMenuCancel(menu, client, reason);
    83 	
    84 	/* Only fire end if there's a valid menu */
    85 	if (menu)
    86 	{
    87 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
    88 	}
    89 
    90 	if (bAutoIgnore)
    91 	{
    92 		player->bAutoIgnore = bOldIgnore;
    93 	}
    94 }
    95 
    96 void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
    97 {
    98 #if defined MENU_DEBUG
    99 	g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
   100 #endif
   101 	int maxClients = g_Players.GetMaxClients();
   102 	for (int i=1; i<=maxClients; i++)
   103 	{
   104 		CBaseMenuPlayer *player = GetMenuPlayer(i);
   105 		if (player->bInMenu)
   106 		{
   107 			menu_states_t &states = player->states;
   108 			if (states.menu == menu)
   109 			{
   110 				_CancelClientMenu(i, MenuCancel_Interrupted);
   111 			}
   112 		}
   113 	}
   114 }
   115 
   116 bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
   117 {
   118 #if defined MENU_DEBUG
   119 	g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
   120 #endif
   121 	if (client < 1 || client > g_Players.MaxClients())
   122 	{
   123 		return false;
   124 	}
   125 
   126 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   127 	if (!player->bInMenu)
   128 	{
   129 		return false;
   130 	}
   131 
   132 	_CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
   133 
   134 	return true;
   135 }
   136 
   137 MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
   138 {
   139 	if (client < 1 || client > g_Players.GetMaxClients())
   140 	{
   141 		return MenuSource_None;
   142 	}
   143 
   144 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   145 
   146 	if (player->bInMenu)
   147 	{
   148 		IBaseMenu *menu;
   149 		if ((menu=player->states.menu) != NULL)
   150 		{
   151 			if (object)
   152 			{
   153 				*object = menu;
   154 			}
   155 			return MenuSource_BaseMenu;
   156 		}
   157 
   158 		return MenuSource_Display;
   159 	} else if (player->bInExternMenu) {
   160 		if (player->menuHoldTime != 0
   161 			&& (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
   162 		{
   163 			player->bInExternMenu = false;
   164 			return MenuSource_None;
   165 		}
   166 		return MenuSource_External;
   167 	}
   168 
   169 	return MenuSource_None;
   170 }
   171 
   172 void BaseMenuStyle::OnClientDisconnected(int client)
   173 {
   174 #if defined MENU_DEBUG
   175 	g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
   176 #endif
   177 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   178 	if (!player->bInMenu)
   179 	{
   180 		return;
   181 	}
   182 
   183 	_CancelClientMenu(client, MenuCancel_Disconnected, true);
   184 
   185 	player->bInMenu = false;
   186 	player->bInExternMenu = false;
   187 }
   188 
   189 static int do_lookup[256];
   190 void BaseMenuStyle::ProcessWatchList()
   191 {
   192 	if (!m_WatchList.size())
   193 	{
   194 		return;
   195 	}
   196 
   197 	unsigned int total = 0;
   198 	for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
   199 	{
   200 		do_lookup[total++] = (*iter);
   201 	}
   202 
   203 #if defined MENU_DEBUG
   204 	if (total)
   205 	{
   206 		g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
   207 	}
   208 #endif
   209 
   210 	int client;
   211 	CBaseMenuPlayer *player;
   212 	float curTime = gpGlobals->curtime;
   213 	for (unsigned int i=0; i<total; i++)
   214 	{
   215 		client = do_lookup[i];
   216 		player = GetMenuPlayer(client);
   217 #if defined MENU_DEBUG
   218 		g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
   219 			client,
   220 			player->bInMenu,
   221 			player->menuHoldTime,
   222 			curTime,
   223 			player->menuStartTime);
   224 #endif
   225 		if (!player->bInMenu || !player->menuHoldTime)
   226 		{
   227 #if defined MENU_DEBUG
   228 			g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
   229 #endif
   230 			m_WatchList.remove(client);
   231 			continue;
   232 		}
   233 		if (curTime > player->menuStartTime + player->menuHoldTime)
   234 		{
   235 			_CancelClientMenu(client, MenuCancel_Timeout, false);
   236 		}
   237 	}
   238 }
   239 
   240 void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
   241 {
   242 #if defined MENU_DEBUG
   243 	g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
   244 #endif
   245 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   246 
   247 	/* First question: Are we in a menu? */
   248 	if (!player->bInMenu)
   249 	{
   250 		return;
   251 	}
   252 
   253 	bool cancel = false;
   254 	unsigned int item = 0;
   255 	MenuCancelReason reason = MenuCancel_Exit;
   256 	MenuEndReason end_reason = MenuEnd_Selected;
   257 	menu_states_t &states = player->states;
   258 
   259 	assert(states.mh != NULL);
   260 
   261 	if (states.menu == NULL)
   262 	{
   263 		item = key_press;
   264 	} else if (key_press < 1 || key_press > GetMaxPageItems()) {
   265 		cancel = true;
   266 	} else {
   267 		ItemSelection type = states.slots[key_press].type;
   268 
   269 		/* For navigational items, we're going to redisplay */
   270 		if (type == ItemSel_Back)
   271 		{
   272 			if (!RedoClientMenu(client, ItemOrder_Descending))
   273 			{
   274 				cancel = true;
   275 				reason = MenuCancel_NoDisplay;
   276 				end_reason = MenuEnd_Cancelled;
   277 			} else {
   278 				return;
   279 			}
   280 		} else if (type == ItemSel_Next) {
   281 			if (!RedoClientMenu(client, ItemOrder_Ascending))
   282 			{
   283 				cancel = true;						/* I like Saltines. */
   284 				reason = MenuCancel_NoDisplay;
   285 				end_reason = MenuEnd_Cancelled;
   286 			} else {
   287 				return;
   288 			}
   289 		} else if (type == ItemSel_Exit || type == ItemSel_None) {
   290 			cancel = true;
   291 			reason = MenuCancel_Exit;
   292 			end_reason = MenuEnd_Exit;
   293 		} else if (type == ItemSel_ExitBack) {
   294 			cancel = true;
   295 			reason = MenuCancel_ExitBack;
   296 			end_reason = MenuEnd_ExitBack;
   297 		} else {
   298 			item = states.slots[key_press].item;
   299 		}
   300 	}
   301 
   302 	/* Save variables */
   303 	IMenuHandler *mh = states.mh;
   304 	IBaseMenu *menu = states.menu;
   305 
   306 	/* Clear states */
   307 	player->bInMenu = false;
   308 	if (player->menuHoldTime)
   309 	{
   310 		RemoveClientFromWatch(client);
   311 	}
   312 
   313 	if (cancel)
   314 	{
   315 		mh->OnMenuCancel(menu, client, reason);
   316 	} else {
   317 		mh->OnMenuSelect(menu, client, item);
   318 	}
   319 
   320 	/* Only fire end for valid menus */
   321 	if (menu)
   322 	{
   323 		mh->OnMenuEnd(menu, end_reason);
   324 	}
   325 }
   326 
   327 bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
   328 {
   329 #if defined MENU_DEBUG
   330 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
   331 		client,
   332 		menu,
   333 		mh,
   334 		time);
   335 #endif
   336 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   337 	if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
   338 	{
   339 		return false;
   340 	}
   341 
   342 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   343 	if (player->bAutoIgnore)
   344 	{
   345 		return false;
   346 	}
   347 
   348 	/* For the duration of this, we are going to totally ignore whether
   349 	* the player is already in a menu or not (except to cancel the old one).
   350 	* Instead, we are simply going to ignore any further menu displays, so
   351 	* this display can't be interrupted.
   352 	*/
   353 	player->bAutoIgnore = true;
   354 
   355 	/* Cancel any old menus */
   356 	menu_states_t &states = player->states;
   357 	if (player->bInMenu)
   358 	{
   359 		_CancelClientMenu(client, MenuCancel_Interrupted, true);
   360 	}
   361 
   362 	states.firstItem = 0;
   363 	states.lastItem = 0;
   364 	states.menu = NULL;
   365 	states.mh = mh;
   366 	states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
   367 	player->bInMenu = true;
   368 	player->bInExternMenu = false;
   369 	player->menuStartTime = gpGlobals->curtime;
   370 	player->menuHoldTime = time;
   371 
   372 	if (time)
   373 	{
   374 		AddClientToWatch(client);
   375 	}
   376 
   377 	/* Draw the display */
   378 	SendDisplay(client, menu);
   379 
   380 	/* We can be interrupted again! */
   381 	player->bAutoIgnore = false;
   382 
   383 	return true;
   384 }
   385 
   386 bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time)
   387 {
   388 #if defined MENU_DEBUG
   389 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
   390 		client,
   391 		menu,
   392 		mh,
   393 		time);
   394 #endif
   395 	mh->OnMenuStart(menu);
   396 
   397 	CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
   398 	if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
   399 	{
   400 #if defined MENU_DEBUG
   401 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
   402 #endif
   403 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   404 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   405 		return false;
   406 	}
   407 
   408 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   409 	if (player->bAutoIgnore)
   410 	{
   411 #if defined MENU_DEBUG
   412 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
   413 #endif
   414 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   415 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   416 		return false;
   417 	}
   418 
   419 	/* For the duration of this, we are going to totally ignore whether
   420 	* the player is already in a menu or not (except to cancel the old one).
   421 	* Instead, we are simply going to ignore any further menu displays, so
   422 	* this display can't be interrupted.
   423 	*/
   424 	player->bAutoIgnore = true;
   425 
   426 	/* Cancel any old menus */
   427 	menu_states_t &states = player->states;
   428 	if (player->bInMenu)
   429 	{
   430 #if defined MENU_DEBUG
   431 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
   432 #endif
   433 		_CancelClientMenu(client, MenuCancel_Interrupted, true);
   434 	}
   435 
   436 	states.firstItem = 0;
   437 	states.lastItem = 0;
   438 	states.menu = menu;
   439 	states.mh = mh;
   440 	states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
   441 
   442 	IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
   443 	if (!display)
   444 	{
   445 #if defined MENU_DEBUG
   446 		g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
   447 #endif
   448 		player->bAutoIgnore = false;
   449 		player->bInMenu = false;
   450 		mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
   451 		mh->OnMenuEnd(menu, MenuEnd_Cancelled);
   452 		return false;
   453 	}
   454 
   455 	/* Finally, set our states */
   456 	player->bInMenu = true;
   457 	player->bInExternMenu = false;
   458 	player->menuStartTime = gpGlobals->curtime;
   459 	player->menuHoldTime = time;
   460 
   461 	if (time)
   462 	{
   463 		AddClientToWatch(client);
   464 	}
   465 
   466 	/* Draw the display */
   467 	SendDisplay(client, display);
   468 
   469 	/* Free the display pointer */
   470 	display->DeleteThis();
   471 
   472 	/* We can be interrupted again! */
   473 	player->bAutoIgnore = false;
   474 
   475 #if defined MENU_DEBUG
   476 	g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
   477 #endif
   478 
   479 	return true;
   480 }
   481 
   482 bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
   483 {
   484 #if defined MENU_DEBUG
   485 	g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
   486 #endif
   487 	CBaseMenuPlayer *player = GetMenuPlayer(client);
   488 	menu_states_t &states = player->states;
   489 
   490 	player->bAutoIgnore = true;
   491 	IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
   492 	if (!display)
   493 	{
   494 #if defined MENU_DEBUG
   495 		g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
   496 #endif
   497 		if (player->menuHoldTime)
   498 		{
   499 			RemoveClientFromWatch(client);
   500 		}
   501 		player->bAutoIgnore = false;
   502 		return false;
   503 	}
   504 
   505 	SendDisplay(client, display);
   506 
   507 	display->DeleteThis();
   508 
   509 	player->bAutoIgnore = false;
   510 
   511 #if defined MENU_DEBUG
   512 	g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
   513 #endif
   514 
   515 	return true;
   516 }
   517 
   518 CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) : 
   519 m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), 
   520 m_bShouldDelete(false), m_bCancelling(false), m_pOwner(pOwner ? pOwner : g_pCoreIdent), 
   521 m_bDeleting(false), m_bWillFreeHandle(false), m_hHandle(BAD_HANDLE), m_pHandler(pHandler),
   522 m_pVoteHandler(NULL), m_ExitBackButton(false)
   523 {
   524 }
   525 
   526 CBaseMenu::~CBaseMenu()
   527 {
   528 	g_Menus.ReleaseVoteWrapper(m_pVoteHandler);
   529 }
   530 
   531 Handle_t CBaseMenu::GetHandle()
   532 {
   533 	if (!m_hHandle)
   534 	{
   535 		m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
   536 	}
   537 
   538 	return m_hHandle;
   539 }
   540 
   541 bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
   542 {
   543 	if (m_Pagination == (unsigned)MENU_NO_PAGINATION
   544 		&& m_items.size() >= m_pStyle->GetMaxPageItems())
   545 	{
   546 		return false;
   547 	}
   548 
   549 	CItem item;
   550 
   551 	item.infoString = m_Strings.AddString(info);
   552 	if (draw.display)
   553 	{
   554 		item.displayString = m_Strings.AddString(draw.display);
   555 	}
   556 	item.style = draw.style;
   557 
   558 
   559 	m_items.push_back(item);
   560 
   561 	return true;
   562 }
   563 
   564 bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
   565 {
   566 	if (m_Pagination == (unsigned)MENU_NO_PAGINATION
   567 		&& m_items.size() >= m_pStyle->GetMaxPageItems())
   568 	{
   569 		return false;
   570 	}
   571 
   572 	if (position >= m_items.size())
   573 	{
   574 		return false;
   575 	}
   576 
   577 	CItem item;
   578 	item.infoString = m_Strings.AddString(info);
   579 	if (draw.display)
   580 	{
   581 		item.displayString = m_Strings.AddString(draw.display);
   582 	}
   583 	item.style = draw.style;
   584 
   585 	CVector<CItem>::iterator iter = m_items.iterAt(position);
   586 	m_items.insert(iter, item);
   587 
   588 	return true;
   589 }
   590 
   591 bool CBaseMenu::RemoveItem(unsigned int position)
   592 {
   593 	if (position >= m_items.size())
   594 	{
   595 		return false;
   596 	}
   597 
   598 	m_items.erase(m_items.iterAt(position));
   599 
   600 	if (m_items.size() == 0)
   601 	{
   602 		m_Strings.Reset();
   603 	}
   604 
   605 	return true;
   606 }
   607 
   608 void CBaseMenu::RemoveAllItems()
   609 {
   610 	m_items.clear();
   611 	m_Strings.Reset();
   612 }
   613 
   614 const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
   615 {
   616 	if (position >= m_items.size())
   617 	{
   618 		return NULL;
   619 	}
   620 
   621 	if (draw)
   622 	{
   623 		draw->display = m_Strings.GetString(m_items[position].displayString);
   624 		draw->style = m_items[position].style;
   625 	}
   626 
   627 	return m_Strings.GetString(m_items[position].infoString);
   628 }
   629 
   630 unsigned int CBaseMenu::GetItemCount()
   631 {
   632 	return m_items.size();
   633 }
   634 
   635 bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
   636 {
   637 	if (itemsPerPage > 7 || itemsPerPage == 1)
   638 	{
   639 		return false;
   640 	}
   641 
   642 	m_Pagination = itemsPerPage;
   643 
   644 	return true;
   645 }
   646 
   647 unsigned int CBaseMenu::GetPagination()
   648 {
   649 	return m_Pagination;
   650 }
   651 
   652 IMenuStyle *CBaseMenu::GetDrawStyle()
   653 {
   654 	return m_pStyle;
   655 }
   656 
   657 void CBaseMenu::SetDefaultTitle(const char *message)
   658 {
   659 	m_Title.assign(message);
   660 }
   661 
   662 const char *CBaseMenu::GetDefaultTitle()
   663 {
   664 	return m_Title.c_str();
   665 }
   666 
   667 bool CBaseMenu::GetExitButton()
   668 {
   669 	return m_ExitButton;
   670 }
   671 
   672 bool CBaseMenu::SetExitButton(bool set)
   673 {
   674 	m_ExitButton = set;
   675 	return true;
   676 }
   677 
   678 void CBaseMenu::Cancel()
   679 {
   680 	if (m_bCancelling)
   681 	{
   682 		return;
   683 	}
   684 
   685 #if defined MENU_DEBUG
   686 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_pVote %p) (inVote %d) (m_bShouldDelete %d)",
   687 		this,
   688 		m_pVoteHandler,
   689 		m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false,
   690 		m_bShouldDelete);
   691 #endif
   692 
   693 	if (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress())
   694 	{
   695 		m_pVoteHandler->CancelVoting();
   696 	}
   697 
   698 	m_bCancelling = true;
   699 	Cancel_Finally();
   700 	m_bCancelling = false;
   701 
   702 	if (m_bShouldDelete)
   703 	{
   704 		InternalDelete();
   705 	}
   706 }
   707 
   708 void CBaseMenu::Destroy(bool releaseHandle)
   709 {
   710 	/* Check if we shouldn't be here */
   711 	if (m_bDeleting)
   712 	{
   713 		return;
   714 	}
   715 
   716 #if defined MENU_DEBUG
   717 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
   718 		this,
   719 		releaseHandle,
   720 		m_bCancelling,
   721 		m_bShouldDelete);
   722 #endif
   723 
   724 	/* Save the destruction hint about our handle */
   725 	m_bWillFreeHandle = releaseHandle;
   726 
   727 	/* Now actually do stuff */
   728 	if (!m_bCancelling || m_bShouldDelete)
   729 	{
   730 		Cancel();
   731 		InternalDelete();
   732 	} else {
   733 		m_bShouldDelete = true;
   734 	}
   735 }
   736 
   737 void CBaseMenu::InternalDelete()
   738 {
   739 	if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
   740 	{
   741 		Handle_t hndl = m_hHandle;
   742 		HandleSecurity sec;
   743 
   744 		sec.pOwner = m_pOwner;
   745 		sec.pIdentity = g_pCoreIdent;
   746 
   747 		m_hHandle = BAD_HANDLE;
   748 		m_bDeleting = true;
   749 		g_HandleSys.FreeHandle(hndl, &sec);
   750 	}
   751 
   752 	m_pHandler->OnMenuDestroy(this);
   753 
   754 	delete this;
   755 }
   756 
   757 bool CBaseMenu::BroadcastVote(int clients[], 
   758 							  unsigned int numClients, 
   759 							  unsigned int maxTime,
   760 							  unsigned int flags)
   761 {
   762 #if defined MENU_DEBUG
   763 	g_Logger.LogMessage("[SM_MENU] CBaseMenu::BroadcastVote(%p) (maxTime %d) (numClients %d) (m_pVote %p) (inVote %d)",
   764 		this,
   765 		maxTime,
   766 		numClients,
   767 		m_pVoteHandler,
   768 		m_pVoteHandler ? m_pVoteHandler->IsVoteInProgress() : false);
   769 #endif
   770 	if (!m_pVoteHandler)
   771 	{
   772 		m_pVoteHandler = g_Menus.CreateVoteWrapper(m_pHandler);
   773 	} else if (m_pVoteHandler->IsVoteInProgress()) {
   774 		return false;
   775 	}
   776 
   777 	m_pVoteHandler->InitializeVoting(this);
   778 
   779 	for (unsigned int i=0; i<numClients; i++)
   780 	{
   781 		VoteDisplay(clients[i], maxTime);
   782 	}
   783 
   784 	m_pVoteHandler->StartVoting();
   785 
   786 	return true;
   787 }
   788 
   789 bool CBaseMenu::IsVoteInProgress()
   790 {
   791 	return (m_pVoteHandler && m_pVoteHandler->IsVoteInProgress());
   792 }
   793 
   794 bool CBaseMenu::GetExitBackButton()
   795 {
   796 	return m_ExitBackButton;
   797 }
   798 
   799 void CBaseMenu::SetExitBackButton(bool set)
   800 {
   801 	m_ExitBackButton = set;
   802 }