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: }