Triggering build against new mac libprotobuf.
3 * =============================================================================
5 * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
6 * =============================================================================
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.
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
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/>.
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>.
33 #include "sm_stringutil.h"
34 #include "MenuStyle_Base.h"
35 #include "PlayerManager.h"
36 #include "MenuManager.h"
37 #include "HandleSys.h"
38 #include "CellRecipientFilter.h"
39 #if defined MENU_DEBUG
43 BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
47 Handle_t BaseMenuStyle::GetHandle()
49 /* Don't create the handle until we need it */
50 if (m_hHandle == BAD_HANDLE)
52 m_hHandle = g_Menus.CreateStyleHandle(this);
58 void BaseMenuStyle::AddClientToWatch(int client)
60 #if defined MENU_DEBUG
61 g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
63 m_WatchList.push_back(client);
66 void BaseMenuStyle::RemoveClientFromWatch(int client)
68 #if defined MENU_DEBUG
69 g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
71 m_WatchList.remove(client);
74 void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
76 #if defined MENU_DEBUG
77 g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
79 CBaseMenuPlayer *player = GetMenuPlayer(client);
80 menu_states_t &states = player->states;
82 bool bOldIgnore = player->bAutoIgnore;
85 player->bAutoIgnore = true;
89 IMenuHandler *mh = states.mh;
90 IBaseMenu *menu = states.menu;
93 player->bInMenu = false;
94 if (player->menuHoldTime)
96 RemoveClientFromWatch(client);
100 mh->OnMenuCancel(menu, client, reason);
102 /* Only fire end if there's a valid menu */
105 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
110 player->bAutoIgnore = bOldIgnore;
114 void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
116 #if defined MENU_DEBUG
117 g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
119 int maxClients = g_Players.GetMaxClients();
120 for (int i=1; i<=maxClients; i++)
122 CBaseMenuPlayer *player = GetMenuPlayer(i);
125 menu_states_t &states = player->states;
126 if (states.menu == menu)
128 _CancelClientMenu(i, MenuCancel_Interrupted);
134 bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
136 #if defined MENU_DEBUG
137 g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
139 if (client < 1 || client > g_Players.MaxClients())
144 CBaseMenuPlayer *player = GetMenuPlayer(client);
145 if (!player->bInMenu)
150 _CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
155 MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
157 if (client < 1 || client > g_Players.GetMaxClients())
159 return MenuSource_None;
162 CBaseMenuPlayer *player = GetMenuPlayer(client);
167 if ((menu=player->states.menu) != NULL)
173 return MenuSource_BaseMenu;
176 return MenuSource_Display;
177 } else if (player->bInExternMenu) {
178 if (player->menuHoldTime != 0
179 && (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
181 player->bInExternMenu = false;
182 return MenuSource_None;
184 return MenuSource_External;
187 return MenuSource_None;
190 void BaseMenuStyle::OnClientDisconnected(int client)
192 #if defined MENU_DEBUG
193 g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
195 CBaseMenuPlayer *player = GetMenuPlayer(client);
196 if (!player->bInMenu)
201 _CancelClientMenu(client, MenuCancel_Disconnected, true);
203 player->bInMenu = false;
204 player->bInExternMenu = false;
207 static int do_lookup[256];
208 void BaseMenuStyle::ProcessWatchList()
210 if (!m_WatchList.size())
215 #if defined MENU_DEBUG
216 g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
218 m_WatchList.m_FirstLink,
219 m_WatchList.m_FreeNodes,
220 m_WatchList.m_LastLink,
221 m_WatchList.m_MaxSize,
222 m_WatchList.m_Nodes);
225 unsigned int total = 0;
226 for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
228 do_lookup[total++] = (*iter);
231 #if defined MENU_DEBUG
234 g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
239 CBaseMenuPlayer *player;
240 float curTime = gpGlobals->curtime;
241 for (unsigned int i=0; i<total; i++)
243 client = do_lookup[i];
244 player = GetMenuPlayer(client);
245 #if defined MENU_DEBUG
246 g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
249 player->menuHoldTime,
251 player->menuStartTime);
253 if (!player->bInMenu || !player->menuHoldTime)
255 #if defined MENU_DEBUG
256 g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
258 m_WatchList.remove(client);
261 if (curTime > player->menuStartTime + player->menuHoldTime)
263 _CancelClientMenu(client, MenuCancel_Timeout, false);
268 void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
270 #if defined MENU_DEBUG
271 g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
273 CBaseMenuPlayer *player = GetMenuPlayer(client);
275 /* First question: Are we in a menu? */
276 if (!player->bInMenu)
282 unsigned int item = 0;
283 MenuCancelReason reason = MenuCancel_Exit;
284 MenuEndReason end_reason = MenuEnd_Selected;
285 menu_states_t &states = player->states;
288 IMenuHandler *mh = states.mh;
289 IBaseMenu *menu = states.menu;
291 unsigned int item_on_page = states.item_on_page;
298 } else if (key_press < 1 || key_press > GetMaxPageItems()) {
301 ItemSelection type = states.slots[key_press].type;
303 /* Check if we should play a sound about the type */
304 if (g_Menus.MenuSoundsEnabled() &&
305 (!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
307 CellRecipientFilter filter;
311 filter.Initialize(clients, 1);
313 const char *sound = g_Menus.GetMenuSound(type);
317 edict_t *pEdict = PEntityOfEntIndex(client);
320 ICollideable *pCollideable = pEdict->GetCollideable();
324 const Vector & pos = pCollideable->GetCollisionOrigin();
325 enginesound->EmitSound(filter,
328 #if SOURCE_ENGINE >= SE_PORTAL2
335 #if SOURCE_ENGINE >= SE_PORTAL2
340 #if SOURCE_ENGINE == SE_CSS || SOURCE_ENGINE == SE_ORANGEBOXVALVE
349 /* For navigational items, we're going to redisplay */
350 if (type == ItemSel_Back)
352 if (!RedoClientMenu(client, ItemOrder_Descending))
355 reason = MenuCancel_NoDisplay;
356 end_reason = MenuEnd_Cancelled;
360 } else if (type == ItemSel_Next) {
361 if (!RedoClientMenu(client, ItemOrder_Ascending))
363 cancel = true; /* I like Saltines. */
364 reason = MenuCancel_NoDisplay;
365 end_reason = MenuEnd_Cancelled;
369 } else if (type == ItemSel_Exit || type == ItemSel_None) {
371 reason = MenuCancel_Exit;
372 end_reason = MenuEnd_Exit;
373 } else if (type == ItemSel_ExitBack) {
375 reason = MenuCancel_ExitBack;
376 end_reason = MenuEnd_ExitBack;
378 item = states.slots[key_press].item;
383 player->bInMenu = false;
384 if (player->menuHoldTime)
386 RemoveClientFromWatch(client);
389 Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE;
390 AutoHandleRooter ahr(hndl);
394 mh->OnMenuCancel(menu, client, reason);
396 mh->OnMenuSelect(menu, client, item);
397 if (mh->GetMenuAPIVersion2() >= 13)
399 mh->OnMenuSelect2(menu, client, item, item_on_page);
403 /* Only fire end for valid menus */
406 mh->OnMenuEnd(menu, end_reason);
410 bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
412 #if defined MENU_DEBUG
413 g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
419 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
420 if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
425 CBaseMenuPlayer *player = GetMenuPlayer(client);
426 if (player->bAutoIgnore)
431 /* For the duration of this, we are going to totally ignore whether
432 * the player is already in a menu or not (except to cancel the old one).
433 * Instead, we are simply going to ignore any further menu displays, so
434 * this display can't be interrupted.
436 player->bAutoIgnore = true;
438 /* Cancel any old menus */
439 menu_states_t &states = player->states;
442 _CancelClientMenu(client, MenuCancel_Interrupted, true);
445 states.firstItem = 0;
449 states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
450 player->bInMenu = true;
451 player->bInExternMenu = false;
452 player->menuStartTime = gpGlobals->curtime;
453 player->menuHoldTime = time;
457 AddClientToWatch(client);
460 /* Draw the display */
461 SendDisplay(client, menu);
463 /* We can be interrupted again! */
464 player->bAutoIgnore = false;
469 bool BaseMenuStyle::DoClientMenu(int client,
471 unsigned int first_item,
475 #if defined MENU_DEBUG
476 g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
482 mh->OnMenuStart(menu);
484 CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
485 if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
487 #if defined MENU_DEBUG
488 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
490 mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
491 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
495 CBaseMenuPlayer *player = GetMenuPlayer(client);
496 if (player->bAutoIgnore)
498 #if defined MENU_DEBUG
499 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
501 mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
502 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
506 /* For the duration of this, we are going to totally ignore whether
507 * the player is already in a menu or not (except to cancel the old one).
508 * Instead, we are simply going to ignore any further menu displays, so
509 * this display can't be interrupted.
511 player->bAutoIgnore = true;
513 /* Cancel any old menus */
514 menu_states_t &states = player->states;
517 #if defined MENU_DEBUG
518 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
520 _CancelClientMenu(client, MenuCancel_Interrupted, true);
523 states.firstItem = 0;
524 states.lastItem = first_item;
527 states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
529 IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
532 #if defined MENU_DEBUG
533 g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
535 player->bAutoIgnore = false;
536 player->bInMenu = false;
537 mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
538 mh->OnMenuEnd(menu, MenuEnd_Cancelled);
542 /* Finally, set our states */
543 player->bInMenu = true;
544 player->bInExternMenu = false;
545 player->menuStartTime = gpGlobals->curtime;
546 player->menuHoldTime = time;
550 AddClientToWatch(client);
553 /* Draw the display */
554 SendDisplay(client, display);
556 /* Free the display pointer */
557 display->DeleteThis();
559 /* We can be interrupted again! */
560 player->bAutoIgnore = false;
562 #if defined MENU_DEBUG
563 g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
569 bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
571 #if defined MENU_DEBUG
572 g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
574 CBaseMenuPlayer *player = GetMenuPlayer(client);
575 menu_states_t &states = player->states;
577 player->bAutoIgnore = true;
578 IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
581 #if defined MENU_DEBUG
582 g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
584 if (player->menuHoldTime)
586 RemoveClientFromWatch(client);
588 player->bAutoIgnore = false;
592 SendDisplay(client, display);
594 display->DeleteThis();
596 player->bAutoIgnore = false;
598 #if defined MENU_DEBUG
599 g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
605 CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
606 m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
607 m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
608 m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
612 CBaseMenu::~CBaseMenu()
616 Handle_t CBaseMenu::GetHandle()
620 m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
626 bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
628 if (m_Pagination == (unsigned)MENU_NO_PAGINATION
629 && m_items.size() >= m_pStyle->GetMaxPageItems())
636 item.infoString = m_Strings.AddString(info);
639 item.displayString = m_Strings.AddString(draw.display);
641 item.style = draw.style;
643 m_items.push_back(item);
648 bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
650 if (m_Pagination == (unsigned)MENU_NO_PAGINATION
651 && m_items.size() >= m_pStyle->GetMaxPageItems())
656 if (position >= m_items.size())
662 item.infoString = m_Strings.AddString(info);
665 item.displayString = m_Strings.AddString(draw.display);
667 item.style = draw.style;
669 CVector<CItem>::iterator iter = m_items.iterAt(position);
670 m_items.insert(iter, item);
675 bool CBaseMenu::RemoveItem(unsigned int position)
677 if (position >= m_items.size())
682 m_items.erase(m_items.iterAt(position));
684 if (m_items.size() == 0)
692 void CBaseMenu::RemoveAllItems()
698 const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
700 if (position >= m_items.size())
707 draw->display = m_Strings.GetString(m_items[position].displayString);
708 draw->style = m_items[position].style;
711 return m_Strings.GetString(m_items[position].infoString);
714 unsigned int CBaseMenu::GetItemCount()
716 return m_items.size();
719 bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
721 if (itemsPerPage > 7 || itemsPerPage == 1)
726 if (itemsPerPage == MENU_NO_PAGINATION
727 && m_Pagination != MENU_NO_PAGINATION)
729 m_nFlags &= ~MENUFLAG_BUTTON_EXIT;
732 m_Pagination = itemsPerPage;
737 unsigned int CBaseMenu::GetPagination()
742 IMenuStyle *CBaseMenu::GetDrawStyle()
747 void CBaseMenu::SetDefaultTitle(const char *message)
749 m_Title.assign(message);
752 const char *CBaseMenu::GetDefaultTitle()
754 return m_Title.c_str();
757 void CBaseMenu::Cancel()
764 #if defined MENU_DEBUG
765 g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
770 m_bCancelling = true;
772 m_bCancelling = false;
780 void CBaseMenu::Destroy(bool releaseHandle)
782 /* Check if we shouldn't be here */
788 #if defined MENU_DEBUG
789 g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
796 /* Save the destruction hint about our handle */
797 m_bWillFreeHandle = releaseHandle;
799 /* Now actually do stuff */
800 if (!m_bCancelling || m_bShouldDelete)
805 m_bShouldDelete = true;
809 void CBaseMenu::InternalDelete()
811 if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
813 Handle_t hndl = m_hHandle;
816 sec.pOwner = m_pOwner;
817 sec.pIdentity = g_pCoreIdent;
819 m_hHandle = BAD_HANDLE;
821 g_HandleSys.FreeHandle(hndl, &sec);
824 m_pHandler->OnMenuDestroy(this);
829 unsigned int CBaseMenu::GetMenuOptionFlags()
834 void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
839 IMenuHandler *CBaseMenu::GetHandler()
844 unsigned int CBaseMenu::GetBaseMemUsage()
846 return m_Title.size()
847 + m_Strings.GetMemTable()->GetMemUsage()
848 + (m_items.size() * sizeof(CItem));