dvander@769: /** dvander@769: * vim: set ts=4 : ds@1330: * ============================================================================= dvander@1231: * SourceMod ds@1947: * Copyright (C) 2004-2008 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: { ds@2400: edict_t *pEdict = 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: enginesound->EmitSound(filter, dvander@1220: client, dvander@1220: CHAN_AUTO, skamonkey@3515: #if SOURCE_ENGINE >= SE_PORTAL2 skamonkey@3515: sound, skamonkey@3515: -1, skamonkey@3515: #endif dvander@1220: sound, dvander@1220: VOL_NORM, dvander@1220: ATTN_NORM, skamonkey@3515: #if SOURCE_ENGINE >= SE_PORTAL2 skamonkey@3515: 0, skamonkey@3515: #endif 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@2964: Handle_t hndl = menu ? menu->GetHandle() : BAD_HANDLE; dvander@2959: AutoHandleRooter ahr(hndl); dvander@2959: 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: }