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