dvander@769: /**
dvander@769: * vim: set ts=4 :
ds@1330: * =============================================================================
dvander@1231: * SourceMod
dvander@1231: * Copyright (C) 2004-2007 AlliedModders LLC. All rights reserved.
ds@1330: * =============================================================================
dvander@769: *
ds@1330: * This program is free software; you can redistribute it and/or modify it under
ds@1330: * the terms of the GNU General Public License, version 3.0, as published by the
ds@1330: * Free Software Foundation.
dvander@1231: *
ds@1330: * This program is distributed in the hope that it will be useful, but WITHOUT
ds@1330: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
ds@1330: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
ds@1330: * details.
dvander@1231: *
ds@1330: * You should have received a copy of the GNU General Public License along with
ds@1330: * this program. If not, see .
dvander@1231: *
ds@1330: * As a special exception, AlliedModders LLC gives you permission to link the
ds@1330: * code of this program (as well as its derivative works) to "Half-Life 2," the
ds@1330: * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
ds@1330: * by the Valve Corporation. You must obey the GNU General Public License in
ds@1330: * all respects for all other code used. Additionally, AlliedModders LLC grants
ds@1330: * this exception to all derivative works. AlliedModders LLC defines further
ds@1330: * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
ds@1330: * or .
dvander@769: *
dvander@769: * Version: $Id$
dvander@769: */
dvander@771:
dvander@769: #include
dvander@769: #include "sm_stringutil.h"
dvander@769: #include "MenuStyle_Base.h"
dvander@775: #include "PlayerManager.h"
dvander@775: #include "MenuManager.h"
dvander@790: #include "HandleSys.h"
dvander@1220: #include "CellRecipientFilter.h"
dvander@970: #if defined MENU_DEBUG
dvander@970: #include "Logger.h"
dvander@970: #endif
dvander@775:
dvander@790: BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
dvander@790: {
dvander@790: }
dvander@790:
dvander@790: Handle_t BaseMenuStyle::GetHandle()
dvander@775: {
dvander@790: /* Don't create the handle until we need it */
dvander@790: if (m_hHandle == BAD_HANDLE)
dvander@790: {
dvander@790: m_hHandle = g_Menus.CreateStyleHandle(this);
dvander@790: }
dvander@790:
dvander@790: return m_hHandle;
dvander@775: }
dvander@775:
dvander@775: void BaseMenuStyle::AddClientToWatch(int client)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
dvander@970: #endif
dvander@775: m_WatchList.push_back(client);
dvander@775: }
dvander@775:
dvander@775: void BaseMenuStyle::RemoveClientFromWatch(int client)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
dvander@970: #endif
dvander@775: m_WatchList.remove(client);
dvander@775: }
dvander@775:
dvander@1005: void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
dvander@970: #endif
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775: menu_states_t &states = player->states;
dvander@775:
dvander@775: bool bOldIgnore = player->bAutoIgnore;
dvander@775: if (bAutoIgnore)
dvander@775: {
dvander@775: player->bAutoIgnore = true;
dvander@775: }
dvander@775:
dvander@775: /* Save states */
dvander@775: IMenuHandler *mh = states.mh;
dvander@775: IBaseMenu *menu = states.menu;
dvander@775:
dvander@775: /* Clear menu */
dvander@775: player->bInMenu = false;
dvander@775: if (player->menuHoldTime)
dvander@775: {
dvander@775: RemoveClientFromWatch(client);
dvander@775: }
dvander@775:
dvander@775: /* Fire callbacks */
dvander@775: mh->OnMenuCancel(menu, client, reason);
dvander@790:
dvander@790: /* Only fire end if there's a valid menu */
dvander@790: if (menu)
dvander@790: {
dvander@997: mh->OnMenuEnd(menu, MenuEnd_Cancelled);
dvander@790: }
dvander@775:
dvander@775: if (bAutoIgnore)
dvander@775: {
dvander@775: player->bAutoIgnore = bOldIgnore;
dvander@775: }
dvander@775: }
dvander@775:
dvander@775: void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
dvander@970: #endif
dvander@775: int maxClients = g_Players.GetMaxClients();
dvander@775: for (int i=1; i<=maxClients; i++)
dvander@775: {
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(i);
dvander@775: if (player->bInMenu)
dvander@775: {
dvander@775: menu_states_t &states = player->states;
dvander@775: if (states.menu == menu)
dvander@775: {
dvander@1005: _CancelClientMenu(i, MenuCancel_Interrupted);
dvander@775: }
dvander@775: }
dvander@775: }
dvander@775: }
dvander@775:
dvander@775: bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
dvander@970: #endif
dvander@775: if (client < 1 || client > g_Players.MaxClients())
dvander@775: {
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775: if (!player->bInMenu)
dvander@775: {
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@1005: _CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
dvander@775:
dvander@775: return true;
dvander@775: }
dvander@775:
dvander@775: MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
dvander@775: {
dvander@775: if (client < 1 || client > g_Players.GetMaxClients())
dvander@775: {
dvander@775: return MenuSource_None;
dvander@775: }
dvander@775:
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775:
dvander@775: if (player->bInMenu)
dvander@775: {
dvander@775: IBaseMenu *menu;
dvander@775: if ((menu=player->states.menu) != NULL)
dvander@775: {
dvander@775: if (object)
dvander@775: {
dvander@775: *object = menu;
dvander@775: }
dvander@775: return MenuSource_BaseMenu;
dvander@775: }
dvander@775:
dvander@775: return MenuSource_Display;
dvander@780: } else if (player->bInExternMenu) {
dvander@782: if (player->menuHoldTime != 0
dvander@782: && (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
dvander@782: {
dvander@782: player->bInExternMenu = false;
dvander@782: return MenuSource_None;
dvander@782: }
dvander@780: return MenuSource_External;
dvander@775: }
dvander@775:
dvander@775: return MenuSource_None;
dvander@775: }
dvander@775:
dvander@775: void BaseMenuStyle::OnClientDisconnected(int client)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
dvander@970: #endif
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775: if (!player->bInMenu)
dvander@775: {
dvander@775: return;
dvander@775: }
dvander@775:
dvander@1005: _CancelClientMenu(client, MenuCancel_Disconnected, true);
dvander@775:
dvander@775: player->bInMenu = false;
dvander@790: player->bInExternMenu = false;
dvander@775: }
dvander@775:
dvander@775: static int do_lookup[256];
dvander@775: void BaseMenuStyle::ProcessWatchList()
dvander@775: {
dvander@775: if (!m_WatchList.size())
dvander@775: {
dvander@775: return;
dvander@775: }
dvander@775:
dvander@1131: #if defined MENU_DEBUG
dvander@1131: g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
dvander@1131: m_WatchList.m_Size,
dvander@1131: m_WatchList.m_FirstLink,
dvander@1131: m_WatchList.m_FreeNodes,
dvander@1131: m_WatchList.m_LastLink,
dvander@1131: m_WatchList.m_MaxSize,
dvander@1131: m_WatchList.m_Nodes);
dvander@1131: #endif
dvander@1131:
dvander@775: unsigned int total = 0;
dvander@775: for (FastLink::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
dvander@775: {
dvander@775: do_lookup[total++] = (*iter);
dvander@775: }
dvander@775:
dvander@970: #if defined MENU_DEBUG
dvander@970: if (total)
dvander@970: {
dvander@970: g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
dvander@970: }
dvander@970: #endif
dvander@970:
dvander@775: int client;
dvander@775: CBaseMenuPlayer *player;
dvander@775: float curTime = gpGlobals->curtime;
dvander@775: for (unsigned int i=0; ibInMenu,
dvander@970: player->menuHoldTime,
dvander@970: curTime,
dvander@970: player->menuStartTime);
dvander@970: #endif
dvander@775: if (!player->bInMenu || !player->menuHoldTime)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
dvander@970: #endif
dvander@825: m_WatchList.remove(client);
dvander@775: continue;
dvander@775: }
dvander@775: if (curTime > player->menuStartTime + player->menuHoldTime)
dvander@775: {
dvander@1005: _CancelClientMenu(client, MenuCancel_Timeout, false);
dvander@775: }
dvander@775: }
dvander@775: }
dvander@775:
dvander@775: void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
dvander@970: #endif
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775:
dvander@775: /* First question: Are we in a menu? */
dvander@775: if (!player->bInMenu)
dvander@775: {
dvander@775: return;
dvander@775: }
dvander@775:
dvander@775: bool cancel = false;
dvander@775: unsigned int item = 0;
dvander@775: MenuCancelReason reason = MenuCancel_Exit;
dvander@1005: MenuEndReason end_reason = MenuEnd_Selected;
dvander@775: menu_states_t &states = player->states;
dvander@775:
dvander@1259: /* Save variables */
dvander@1259: IMenuHandler *mh = states.mh;
dvander@1259: IBaseMenu *menu = states.menu;
dvander@775:
dvander@1476: unsigned int item_on_page = states.item_on_page;
dvander@1474:
dvander@1259: assert(mh != NULL);
dvander@1259:
dvander@1259: if (menu == NULL)
dvander@775: {
dvander@775: item = key_press;
dvander@785: } else if (key_press < 1 || key_press > GetMaxPageItems()) {
dvander@775: cancel = true;
dvander@775: } else {
dvander@775: ItemSelection type = states.slots[key_press].type;
dvander@775:
dvander@1220: /* Check if we should play a sound about the type */
dvander@1259: if (g_Menus.MenuSoundsEnabled() &&
dvander@1259: (!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
dvander@1220: {
dvander@1220: CellRecipientFilter filter;
dvander@1220: cell_t clients[1];
dvander@1220:
dvander@1220: clients[0] = client;
dvander@1220: filter.Initialize(clients, 1);
dvander@1220:
dvander@1220: const char *sound = g_Menus.GetMenuSound(type);
dvander@1220:
dvander@1220: if (sound != NULL)
dvander@1220: {
dvander@1220: edict_t *pEdict = engine->PEntityOfEntIndex(client);
dvander@1220: if (pEdict)
dvander@1220: {
dvander@1220: ICollideable *pCollideable = pEdict->GetCollideable();
dvander@1220:
dvander@1220: if (pCollideable)
dvander@1220: {
dvander@1220: const Vector & pos = pCollideable->GetCollisionOrigin();
dvander@1220:
dvander@1220: enginesound->EmitSound(filter,
dvander@1220: client,
dvander@1220: CHAN_AUTO,
dvander@1220: sound,
dvander@1220: VOL_NORM,
dvander@1220: ATTN_NORM,
dvander@1220: 0,
dvander@1220: PITCH_NORM,
dvander@1220: &pos);
dvander@1220: }
dvander@1220: }
dvander@1220: }
dvander@1220: }
dvander@1220:
dvander@775: /* For navigational items, we're going to redisplay */
dvander@775: if (type == ItemSel_Back)
dvander@775: {
dvander@775: if (!RedoClientMenu(client, ItemOrder_Descending))
dvander@775: {
dvander@775: cancel = true;
dvander@775: reason = MenuCancel_NoDisplay;
dvander@1005: end_reason = MenuEnd_Cancelled;
dvander@775: } else {
dvander@775: return;
dvander@775: }
dvander@775: } else if (type == ItemSel_Next) {
dvander@775: if (!RedoClientMenu(client, ItemOrder_Ascending))
dvander@775: {
dvander@775: cancel = true; /* I like Saltines. */
dvander@775: reason = MenuCancel_NoDisplay;
dvander@1005: end_reason = MenuEnd_Cancelled;
dvander@775: } else {
dvander@775: return;
dvander@775: }
dvander@775: } else if (type == ItemSel_Exit || type == ItemSel_None) {
dvander@775: cancel = true;
dvander@1005: reason = MenuCancel_Exit;
dvander@1005: end_reason = MenuEnd_Exit;
dvander@1005: } else if (type == ItemSel_ExitBack) {
dvander@1005: cancel = true;
dvander@1005: reason = MenuCancel_ExitBack;
dvander@1005: end_reason = MenuEnd_ExitBack;
dvander@775: } else {
dvander@775: item = states.slots[key_press].item;
dvander@775: }
dvander@775: }
dvander@775:
dvander@775: /* Clear states */
dvander@775: player->bInMenu = false;
dvander@775: if (player->menuHoldTime)
dvander@775: {
dvander@883: RemoveClientFromWatch(client);
dvander@775: }
dvander@775:
dvander@775: if (cancel)
dvander@775: {
dvander@775: mh->OnMenuCancel(menu, client, reason);
dvander@775: } else {
dvander@775: mh->OnMenuSelect(menu, client, item);
dvander@1474: if (mh->GetMenuAPIVersion2() >= 13)
dvander@1474: {
dvander@1474: mh->OnMenuSelect2(menu, client, item, item_on_page);
dvander@1474: }
dvander@775: }
dvander@775:
dvander@790: /* Only fire end for valid menus */
dvander@790: if (menu)
dvander@790: {
dvander@997: mh->OnMenuEnd(menu, end_reason);
dvander@790: }
dvander@775: }
dvander@775:
dvander@787: bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
dvander@970: client,
dvander@970: menu,
dvander@970: mh,
dvander@970: time);
dvander@970: #endif
dvander@775: CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
dvander@775: if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
dvander@775: {
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775: if (player->bAutoIgnore)
dvander@775: {
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: /* For the duration of this, we are going to totally ignore whether
dvander@775: * the player is already in a menu or not (except to cancel the old one).
dvander@775: * Instead, we are simply going to ignore any further menu displays, so
dvander@775: * this display can't be interrupted.
dvander@775: */
dvander@775: player->bAutoIgnore = true;
dvander@775:
dvander@775: /* Cancel any old menus */
dvander@775: menu_states_t &states = player->states;
dvander@775: if (player->bInMenu)
dvander@775: {
dvander@1005: _CancelClientMenu(client, MenuCancel_Interrupted, true);
dvander@775: }
dvander@775:
dvander@775: states.firstItem = 0;
dvander@775: states.lastItem = 0;
dvander@775: states.menu = NULL;
dvander@775: states.mh = mh;
dvander@775: states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
dvander@775: player->bInMenu = true;
dvander@790: player->bInExternMenu = false;
dvander@775: player->menuStartTime = gpGlobals->curtime;
dvander@775: player->menuHoldTime = time;
dvander@775:
dvander@775: if (time)
dvander@775: {
dvander@775: AddClientToWatch(client);
dvander@775: }
dvander@775:
dvander@775: /* Draw the display */
dvander@775: SendDisplay(client, menu);
dvander@775:
dvander@775: /* We can be interrupted again! */
dvander@775: player->bAutoIgnore = false;
dvander@775:
dvander@775: return true;
dvander@775: }
dvander@775:
dvander@1474: bool BaseMenuStyle::DoClientMenu(int client,
dvander@1474: CBaseMenu *menu,
dvander@1474: unsigned int first_item,
dvander@1474: IMenuHandler *mh,
dvander@1474: unsigned int time)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
dvander@970: client,
dvander@970: menu,
dvander@970: mh,
dvander@970: time);
dvander@970: #endif
dvander@775: mh->OnMenuStart(menu);
dvander@775:
dvander@775: CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
dvander@775: if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
dvander@970: #endif
dvander@775: mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
dvander@997: mh->OnMenuEnd(menu, MenuEnd_Cancelled);
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775: if (player->bAutoIgnore)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
dvander@970: #endif
dvander@775: mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
dvander@997: mh->OnMenuEnd(menu, MenuEnd_Cancelled);
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: /* For the duration of this, we are going to totally ignore whether
dvander@1163: * the player is already in a menu or not (except to cancel the old one).
dvander@1163: * Instead, we are simply going to ignore any further menu displays, so
dvander@1163: * this display can't be interrupted.
dvander@1163: */
dvander@775: player->bAutoIgnore = true;
dvander@775:
dvander@775: /* Cancel any old menus */
dvander@775: menu_states_t &states = player->states;
dvander@775: if (player->bInMenu)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
dvander@970: #endif
dvander@1005: _CancelClientMenu(client, MenuCancel_Interrupted, true);
dvander@775: }
dvander@775:
dvander@1476: states.firstItem = 0;
dvander@1476: states.lastItem = first_item;
dvander@775: states.menu = menu;
dvander@775: states.mh = mh;
dvander@775: states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
dvander@775:
dvander@787: IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
dvander@775: if (!display)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
dvander@970: #endif
dvander@775: player->bAutoIgnore = false;
dvander@775: player->bInMenu = false;
dvander@775: mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
dvander@997: mh->OnMenuEnd(menu, MenuEnd_Cancelled);
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: /* Finally, set our states */
dvander@775: player->bInMenu = true;
dvander@790: player->bInExternMenu = false;
dvander@775: player->menuStartTime = gpGlobals->curtime;
dvander@775: player->menuHoldTime = time;
dvander@775:
dvander@775: if (time)
dvander@775: {
dvander@775: AddClientToWatch(client);
dvander@775: }
dvander@775:
dvander@775: /* Draw the display */
dvander@775: SendDisplay(client, display);
dvander@775:
dvander@775: /* Free the display pointer */
dvander@776: display->DeleteThis();
dvander@775:
dvander@775: /* We can be interrupted again! */
dvander@775: player->bAutoIgnore = false;
dvander@775:
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
dvander@970: #endif
dvander@970:
dvander@775: return true;
dvander@775: }
dvander@775:
dvander@775: bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
dvander@970: #endif
dvander@775: CBaseMenuPlayer *player = GetMenuPlayer(client);
dvander@775: menu_states_t &states = player->states;
dvander@775:
dvander@775: player->bAutoIgnore = true;
dvander@787: IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
dvander@775: if (!display)
dvander@775: {
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
dvander@970: #endif
dvander@775: if (player->menuHoldTime)
dvander@775: {
dvander@883: RemoveClientFromWatch(client);
dvander@775: }
dvander@775: player->bAutoIgnore = false;
dvander@775: return false;
dvander@775: }
dvander@775:
dvander@775: SendDisplay(client, display);
dvander@775:
dvander@776: display->DeleteThis();
dvander@775:
dvander@775: player->bAutoIgnore = false;
dvander@775:
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
dvander@970: #endif
dvander@970:
dvander@775: return true;
dvander@775: }
dvander@769:
dvander@790: CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
dvander@1259: m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
dvander@1259: m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
dvander@1269: m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
dvander@769: {
dvander@769: }
dvander@769:
dvander@769: CBaseMenu::~CBaseMenu()
dvander@769: {
dvander@769: }
dvander@769:
dvander@790: Handle_t CBaseMenu::GetHandle()
dvander@790: {
dvander@790: if (!m_hHandle)
dvander@790: {
dvander@790: m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
dvander@790: }
dvander@790:
dvander@790: return m_hHandle;
dvander@790: }
dvander@790:
dvander@769: bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
dvander@769: {
dvander@778: if (m_Pagination == (unsigned)MENU_NO_PAGINATION
dvander@769: && m_items.size() >= m_pStyle->GetMaxPageItems())
dvander@769: {
dvander@769: return false;
dvander@769: }
dvander@769:
dvander@769: CItem item;
dvander@769:
dvander@769: item.infoString = m_Strings.AddString(info);
dvander@769: if (draw.display)
dvander@769: {
dvander@769: item.displayString = m_Strings.AddString(draw.display);
dvander@769: }
dvander@769: item.style = draw.style;
dvander@769:
dvander@769: m_items.push_back(item);
dvander@769:
dvander@769: return true;
dvander@769: }
dvander@769:
dvander@769: bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
dvander@769: {
dvander@778: if (m_Pagination == (unsigned)MENU_NO_PAGINATION
dvander@769: && m_items.size() >= m_pStyle->GetMaxPageItems())
dvander@769: {
dvander@769: return false;
dvander@769: }
dvander@769:
dvander@769: if (position >= m_items.size())
dvander@769: {
dvander@769: return false;
dvander@769: }
dvander@769:
dvander@769: CItem item;
dvander@769: item.infoString = m_Strings.AddString(info);
dvander@769: if (draw.display)
dvander@769: {
dvander@769: item.displayString = m_Strings.AddString(draw.display);
dvander@769: }
dvander@769: item.style = draw.style;
dvander@769:
dvander@769: CVector::iterator iter = m_items.iterAt(position);
dvander@769: m_items.insert(iter, item);
dvander@769:
dvander@769: return true;
dvander@769: }
dvander@769:
dvander@769: bool CBaseMenu::RemoveItem(unsigned int position)
dvander@769: {
dvander@769: if (position >= m_items.size())
dvander@769: {
dvander@769: return false;
dvander@769: }
dvander@769:
dvander@769: m_items.erase(m_items.iterAt(position));
dvander@769:
dvander@769: if (m_items.size() == 0)
dvander@769: {
dvander@769: m_Strings.Reset();
dvander@769: }
dvander@769:
dvander@769: return true;
dvander@769: }
dvander@769:
dvander@769: void CBaseMenu::RemoveAllItems()
dvander@769: {
dvander@769: m_items.clear();
dvander@769: m_Strings.Reset();
dvander@769: }
dvander@769:
dvander@769: const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
dvander@769: {
dvander@769: if (position >= m_items.size())
dvander@769: {
dvander@769: return NULL;
dvander@769: }
dvander@769:
dvander@769: if (draw)
dvander@769: {
dvander@769: draw->display = m_Strings.GetString(m_items[position].displayString);
dvander@769: draw->style = m_items[position].style;
dvander@769: }
dvander@769:
dvander@769: return m_Strings.GetString(m_items[position].infoString);
dvander@769: }
dvander@769:
dvander@769: unsigned int CBaseMenu::GetItemCount()
dvander@769: {
dvander@769: return m_items.size();
dvander@769: }
dvander@769:
dvander@769: bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
dvander@769: {
dvander@820: if (itemsPerPage > 7 || itemsPerPage == 1)
dvander@769: {
dvander@769: return false;
dvander@769: }
dvander@769:
dvander@1653: if (itemsPerPage == MENU_NO_PAGINATION
dvander@1653: && m_Pagination != MENU_NO_PAGINATION)
dvander@1653: {
dvander@1653: m_nFlags &= ~MENUFLAG_BUTTON_EXIT;
dvander@1653: }
dvander@1653:
dvander@769: m_Pagination = itemsPerPage;
dvander@769:
dvander@769: return true;
dvander@769: }
dvander@769:
dvander@769: unsigned int CBaseMenu::GetPagination()
dvander@769: {
dvander@769: return m_Pagination;
dvander@769: }
dvander@769:
dvander@769: IMenuStyle *CBaseMenu::GetDrawStyle()
dvander@769: {
dvander@769: return m_pStyle;
dvander@769: }
dvander@769:
dvander@769: void CBaseMenu::SetDefaultTitle(const char *message)
dvander@769: {
dvander@769: m_Title.assign(message);
dvander@769: }
dvander@769:
dvander@769: const char *CBaseMenu::GetDefaultTitle()
dvander@769: {
dvander@769: return m_Title.c_str();
dvander@769: }
dvander@769:
dvander@775: void CBaseMenu::Cancel()
dvander@775: {
dvander@775: if (m_bCancelling)
dvander@775: {
dvander@775: return;
dvander@775: }
dvander@775:
dvander@970: #if defined MENU_DEBUG
dvander@1269: g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
dvander@970: this,
dvander@970: m_bShouldDelete);
dvander@970: #endif
dvander@970:
dvander@775: m_bCancelling = true;
dvander@775: Cancel_Finally();
dvander@775: m_bCancelling = false;
dvander@775:
dvander@775: if (m_bShouldDelete)
dvander@775: {
dvander@790: InternalDelete();
dvander@775: }
dvander@775: }
dvander@775:
dvander@790: void CBaseMenu::Destroy(bool releaseHandle)
dvander@775: {
dvander@790: /* Check if we shouldn't be here */
dvander@790: if (m_bDeleting)
dvander@790: {
dvander@790: return;
dvander@790: }
dvander@790:
dvander@970: #if defined MENU_DEBUG
dvander@970: g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
dvander@970: this,
dvander@970: releaseHandle,
dvander@970: m_bCancelling,
dvander@970: m_bShouldDelete);
dvander@970: #endif
dvander@970:
dvander@790: /* Save the destruction hint about our handle */
dvander@790: m_bWillFreeHandle = releaseHandle;
dvander@790:
dvander@790: /* Now actually do stuff */
dvander@775: if (!m_bCancelling || m_bShouldDelete)
dvander@775: {
dvander@775: Cancel();
dvander@790: InternalDelete();
dvander@775: } else {
dvander@775: m_bShouldDelete = true;
dvander@775: }
dvander@775: }
dvander@775:
dvander@790: void CBaseMenu::InternalDelete()
dvander@790: {
dvander@790: if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
dvander@790: {
dvander@790: Handle_t hndl = m_hHandle;
dvander@790: HandleSecurity sec;
dvander@790:
dvander@790: sec.pOwner = m_pOwner;
dvander@790: sec.pIdentity = g_pCoreIdent;
dvander@790:
dvander@790: m_hHandle = BAD_HANDLE;
dvander@790: m_bDeleting = true;
dvander@790: g_HandleSys.FreeHandle(hndl, &sec);
dvander@790: }
dvander@790:
dvander@790: m_pHandler->OnMenuDestroy(this);
dvander@790:
dvander@790: delete this;
dvander@790: }
dvander@790:
dvander@1259: unsigned int CBaseMenu::GetMenuOptionFlags()
dvander@1259: {
dvander@1259: return m_nFlags;
dvander@1259: }
dvander@1259:
dvander@1259: void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
dvander@1259: {
dvander@1259: m_nFlags = flags;
dvander@1259: }
dvander@1269:
dvander@1269: IMenuHandler *CBaseMenu::GetHandler()
dvander@1269: {
dvander@1269: return m_pHandler;
dvander@1269: }
dvander@1766:
dvander@1766: unsigned int CBaseMenu::GetBaseMemUsage()
dvander@1766: {
dvander@1766: return m_Title.size()
dvander@1766: + m_Strings.GetMemTable()->GetMemUsage()
dvander@1766: + (m_items.size() * sizeof(CItem));
dvander@1766: }