1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/core/MenuStyle_Base.cpp Sun Jul 06 04:49:55 2008 +0000
1.3 @@ -0,0 +1,837 @@
1.4 +/**
1.5 + * vim: set ts=4 :
1.6 + * =============================================================================
1.7 + * SourceMod
1.8 + * Copyright (C) 2004-2008 AlliedModders LLC. All rights reserved.
1.9 + * =============================================================================
1.10 + *
1.11 + * This program is free software; you can redistribute it and/or modify it under
1.12 + * the terms of the GNU General Public License, version 3.0, as published by the
1.13 + * Free Software Foundation.
1.14 + *
1.15 + * This program is distributed in the hope that it will be useful, but WITHOUT
1.16 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
1.17 + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
1.18 + * details.
1.19 + *
1.20 + * You should have received a copy of the GNU General Public License along with
1.21 + * this program. If not, see <http://www.gnu.org/licenses/>.
1.22 + *
1.23 + * As a special exception, AlliedModders LLC gives you permission to link the
1.24 + * code of this program (as well as its derivative works) to "Half-Life 2," the
1.25 + * "Source Engine," the "SourcePawn JIT," and any Game MODs that run on software
1.26 + * by the Valve Corporation. You must obey the GNU General Public License in
1.27 + * all respects for all other code used. Additionally, AlliedModders LLC grants
1.28 + * this exception to all derivative works. AlliedModders LLC defines further
1.29 + * exceptions, found in LICENSE.txt (as of this writing, version JULY-31-2007),
1.30 + * or <http://www.sourcemod.net/license.php>.
1.31 + *
1.32 + * Version: $Id$
1.33 + */
1.34 +
1.35 +#include <stdarg.h>
1.36 +#include "sm_stringutil.h"
1.37 +#include "MenuStyle_Base.h"
1.38 +#include "PlayerManager.h"
1.39 +#include "MenuManager.h"
1.40 +#include "HandleSys.h"
1.41 +#include "CellRecipientFilter.h"
1.42 +#if defined MENU_DEBUG
1.43 +#include "Logger.h"
1.44 +#endif
1.45 +
1.46 +BaseMenuStyle::BaseMenuStyle() : m_WatchList(256), m_hHandle(BAD_HANDLE)
1.47 +{
1.48 +}
1.49 +
1.50 +Handle_t BaseMenuStyle::GetHandle()
1.51 +{
1.52 + /* Don't create the handle until we need it */
1.53 + if (m_hHandle == BAD_HANDLE)
1.54 + {
1.55 + m_hHandle = g_Menus.CreateStyleHandle(this);
1.56 + }
1.57 +
1.58 + return m_hHandle;
1.59 +}
1.60 +
1.61 +void BaseMenuStyle::AddClientToWatch(int client)
1.62 +{
1.63 +#if defined MENU_DEBUG
1.64 + g_Logger.LogMessage("[SM_MENU] AddClientToWatch(%d)", client);
1.65 +#endif
1.66 + m_WatchList.push_back(client);
1.67 +}
1.68 +
1.69 +void BaseMenuStyle::RemoveClientFromWatch(int client)
1.70 +{
1.71 +#if defined MENU_DEBUG
1.72 + g_Logger.LogMessage("[SM_MENU] RemoveClientFromWatch(%d)", client);
1.73 +#endif
1.74 + m_WatchList.remove(client);
1.75 +}
1.76 +
1.77 +void BaseMenuStyle::_CancelClientMenu(int client, MenuCancelReason reason, bool bAutoIgnore/* =false */)
1.78 +{
1.79 +#if defined MENU_DEBUG
1.80 + g_Logger.LogMessage("[SM_MENU] _CancelClientMenu() (client %d) (bAutoIgnore %d) (reason %d)", client, bAutoIgnore, reason);
1.81 +#endif
1.82 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.83 + menu_states_t &states = player->states;
1.84 +
1.85 + bool bOldIgnore = player->bAutoIgnore;
1.86 + if (bAutoIgnore)
1.87 + {
1.88 + player->bAutoIgnore = true;
1.89 + }
1.90 +
1.91 + /* Save states */
1.92 + IMenuHandler *mh = states.mh;
1.93 + IBaseMenu *menu = states.menu;
1.94 +
1.95 + /* Clear menu */
1.96 + player->bInMenu = false;
1.97 + if (player->menuHoldTime)
1.98 + {
1.99 + RemoveClientFromWatch(client);
1.100 + }
1.101 +
1.102 + /* Fire callbacks */
1.103 + mh->OnMenuCancel(menu, client, reason);
1.104 +
1.105 + /* Only fire end if there's a valid menu */
1.106 + if (menu)
1.107 + {
1.108 + mh->OnMenuEnd(menu, MenuEnd_Cancelled);
1.109 + }
1.110 +
1.111 + if (bAutoIgnore)
1.112 + {
1.113 + player->bAutoIgnore = bOldIgnore;
1.114 + }
1.115 +}
1.116 +
1.117 +void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
1.118 +{
1.119 +#if defined MENU_DEBUG
1.120 + g_Logger.LogMessage("[SM_MENU] CancelMenu() (menu %p)", menu);
1.121 +#endif
1.122 + int maxClients = g_Players.GetMaxClients();
1.123 + for (int i=1; i<=maxClients; i++)
1.124 + {
1.125 + CBaseMenuPlayer *player = GetMenuPlayer(i);
1.126 + if (player->bInMenu)
1.127 + {
1.128 + menu_states_t &states = player->states;
1.129 + if (states.menu == menu)
1.130 + {
1.131 + _CancelClientMenu(i, MenuCancel_Interrupted);
1.132 + }
1.133 + }
1.134 + }
1.135 +}
1.136 +
1.137 +bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
1.138 +{
1.139 +#if defined MENU_DEBUG
1.140 + g_Logger.LogMessage("[SM_MENU] CancelClientMenu() (client %d) (bAutoIgnore %d)", client, autoIgnore);
1.141 +#endif
1.142 + if (client < 1 || client > g_Players.MaxClients())
1.143 + {
1.144 + return false;
1.145 + }
1.146 +
1.147 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.148 + if (!player->bInMenu)
1.149 + {
1.150 + return false;
1.151 + }
1.152 +
1.153 + _CancelClientMenu(client, MenuCancel_Interrupted, autoIgnore);
1.154 +
1.155 + return true;
1.156 +}
1.157 +
1.158 +MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
1.159 +{
1.160 + if (client < 1 || client > g_Players.GetMaxClients())
1.161 + {
1.162 + return MenuSource_None;
1.163 + }
1.164 +
1.165 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.166 +
1.167 + if (player->bInMenu)
1.168 + {
1.169 + IBaseMenu *menu;
1.170 + if ((menu=player->states.menu) != NULL)
1.171 + {
1.172 + if (object)
1.173 + {
1.174 + *object = menu;
1.175 + }
1.176 + return MenuSource_BaseMenu;
1.177 + }
1.178 +
1.179 + return MenuSource_Display;
1.180 + } else if (player->bInExternMenu) {
1.181 + if (player->menuHoldTime != 0
1.182 + && (gpGlobals->curtime > player->menuStartTime + player->menuHoldTime))
1.183 + {
1.184 + player->bInExternMenu = false;
1.185 + return MenuSource_None;
1.186 + }
1.187 + return MenuSource_External;
1.188 + }
1.189 +
1.190 + return MenuSource_None;
1.191 +}
1.192 +
1.193 +void BaseMenuStyle::OnClientDisconnected(int client)
1.194 +{
1.195 +#if defined MENU_DEBUG
1.196 + g_Logger.LogMessage("[SM_MENU] OnClientDisconnected(%d)", client);
1.197 +#endif
1.198 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.199 + if (!player->bInMenu)
1.200 + {
1.201 + return;
1.202 + }
1.203 +
1.204 + _CancelClientMenu(client, MenuCancel_Disconnected, true);
1.205 +
1.206 + player->bInMenu = false;
1.207 + player->bInExternMenu = false;
1.208 +}
1.209 +
1.210 +static int do_lookup[256];
1.211 +void BaseMenuStyle::ProcessWatchList()
1.212 +{
1.213 + if (!m_WatchList.size())
1.214 + {
1.215 + return;
1.216 + }
1.217 +
1.218 +#if defined MENU_DEBUG
1.219 + g_Logger.LogMessage("BaseMenuStyle::ProcessWatchList(%d,%d,%d,%d,%d,%p)",
1.220 + m_WatchList.m_Size,
1.221 + m_WatchList.m_FirstLink,
1.222 + m_WatchList.m_FreeNodes,
1.223 + m_WatchList.m_LastLink,
1.224 + m_WatchList.m_MaxSize,
1.225 + m_WatchList.m_Nodes);
1.226 +#endif
1.227 +
1.228 + unsigned int total = 0;
1.229 + for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
1.230 + {
1.231 + do_lookup[total++] = (*iter);
1.232 + }
1.233 +
1.234 +#if defined MENU_DEBUG
1.235 + if (total)
1.236 + {
1.237 + g_Logger.LogMessage("[SM_MENU] ProcessWatchList() found %d clients", total);
1.238 + }
1.239 +#endif
1.240 +
1.241 + int client;
1.242 + CBaseMenuPlayer *player;
1.243 + float curTime = gpGlobals->curtime;
1.244 + for (unsigned int i=0; i<total; i++)
1.245 + {
1.246 + client = do_lookup[i];
1.247 + player = GetMenuPlayer(client);
1.248 +#if defined MENU_DEBUG
1.249 + g_Logger.LogMessage("[SM_MENU] ProcessWatchList() (client %d) (bInMenu %d) (menuHoldTime %d) (curTime %f) (menuStartTime %f)",
1.250 + client,
1.251 + player->bInMenu,
1.252 + player->menuHoldTime,
1.253 + curTime,
1.254 + player->menuStartTime);
1.255 +#endif
1.256 + if (!player->bInMenu || !player->menuHoldTime)
1.257 + {
1.258 +#if defined MENU_DEBUG
1.259 + g_Logger.LogMessage("[SM_MENU] ProcessWatchList() removing client %d", client);
1.260 +#endif
1.261 + m_WatchList.remove(client);
1.262 + continue;
1.263 + }
1.264 + if (curTime > player->menuStartTime + player->menuHoldTime)
1.265 + {
1.266 + _CancelClientMenu(client, MenuCancel_Timeout, false);
1.267 + }
1.268 + }
1.269 +}
1.270 +
1.271 +void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
1.272 +{
1.273 +#if defined MENU_DEBUG
1.274 + g_Logger.LogMessage("[SM_MENU] ClientPressedKey() (client %d) (key_press %d)", client, key_press);
1.275 +#endif
1.276 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.277 +
1.278 + /* First question: Are we in a menu? */
1.279 + if (!player->bInMenu)
1.280 + {
1.281 + return;
1.282 + }
1.283 +
1.284 + bool cancel = false;
1.285 + unsigned int item = 0;
1.286 + MenuCancelReason reason = MenuCancel_Exit;
1.287 + MenuEndReason end_reason = MenuEnd_Selected;
1.288 + menu_states_t &states = player->states;
1.289 +
1.290 + /* Save variables */
1.291 + IMenuHandler *mh = states.mh;
1.292 + IBaseMenu *menu = states.menu;
1.293 +
1.294 + unsigned int item_on_page = states.item_on_page;
1.295 +
1.296 + assert(mh != NULL);
1.297 +
1.298 + if (menu == NULL)
1.299 + {
1.300 + item = key_press;
1.301 + } else if (key_press < 1 || key_press > GetMaxPageItems()) {
1.302 + cancel = true;
1.303 + } else {
1.304 + ItemSelection type = states.slots[key_press].type;
1.305 +
1.306 + /* Check if we should play a sound about the type */
1.307 + if (g_Menus.MenuSoundsEnabled() &&
1.308 + (!menu || (menu->GetMenuOptionFlags() & MENUFLAG_NO_SOUND) != MENUFLAG_NO_SOUND))
1.309 + {
1.310 + CellRecipientFilter filter;
1.311 + cell_t clients[1];
1.312 +
1.313 + clients[0] = client;
1.314 + filter.Initialize(clients, 1);
1.315 +
1.316 + const char *sound = g_Menus.GetMenuSound(type);
1.317 +
1.318 + if (sound != NULL)
1.319 + {
1.320 + edict_t *pEdict = engine->PEntityOfEntIndex(client);
1.321 + if (pEdict)
1.322 + {
1.323 + ICollideable *pCollideable = pEdict->GetCollideable();
1.324 +
1.325 + if (pCollideable)
1.326 + {
1.327 + const Vector & pos = pCollideable->GetCollisionOrigin();
1.328 +
1.329 + enginesound->EmitSound(filter,
1.330 + client,
1.331 + CHAN_AUTO,
1.332 + sound,
1.333 + VOL_NORM,
1.334 + ATTN_NORM,
1.335 + 0,
1.336 + PITCH_NORM,
1.337 + &pos);
1.338 + }
1.339 + }
1.340 + }
1.341 + }
1.342 +
1.343 + /* For navigational items, we're going to redisplay */
1.344 + if (type == ItemSel_Back)
1.345 + {
1.346 + if (!RedoClientMenu(client, ItemOrder_Descending))
1.347 + {
1.348 + cancel = true;
1.349 + reason = MenuCancel_NoDisplay;
1.350 + end_reason = MenuEnd_Cancelled;
1.351 + } else {
1.352 + return;
1.353 + }
1.354 + } else if (type == ItemSel_Next) {
1.355 + if (!RedoClientMenu(client, ItemOrder_Ascending))
1.356 + {
1.357 + cancel = true; /* I like Saltines. */
1.358 + reason = MenuCancel_NoDisplay;
1.359 + end_reason = MenuEnd_Cancelled;
1.360 + } else {
1.361 + return;
1.362 + }
1.363 + } else if (type == ItemSel_Exit || type == ItemSel_None) {
1.364 + cancel = true;
1.365 + reason = MenuCancel_Exit;
1.366 + end_reason = MenuEnd_Exit;
1.367 + } else if (type == ItemSel_ExitBack) {
1.368 + cancel = true;
1.369 + reason = MenuCancel_ExitBack;
1.370 + end_reason = MenuEnd_ExitBack;
1.371 + } else {
1.372 + item = states.slots[key_press].item;
1.373 + }
1.374 + }
1.375 +
1.376 + /* Clear states */
1.377 + player->bInMenu = false;
1.378 + if (player->menuHoldTime)
1.379 + {
1.380 + RemoveClientFromWatch(client);
1.381 + }
1.382 +
1.383 + if (cancel)
1.384 + {
1.385 + mh->OnMenuCancel(menu, client, reason);
1.386 + } else {
1.387 + mh->OnMenuSelect(menu, client, item);
1.388 + if (mh->GetMenuAPIVersion2() >= 13)
1.389 + {
1.390 + mh->OnMenuSelect2(menu, client, item, item_on_page);
1.391 + }
1.392 + }
1.393 +
1.394 + /* Only fire end for valid menus */
1.395 + if (menu)
1.396 + {
1.397 + mh->OnMenuEnd(menu, end_reason);
1.398 + }
1.399 +}
1.400 +
1.401 +bool BaseMenuStyle::DoClientMenu(int client, IMenuPanel *menu, IMenuHandler *mh, unsigned int time)
1.402 +{
1.403 +#if defined MENU_DEBUG
1.404 + g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (panel %p) (mh %p) (time %d)",
1.405 + client,
1.406 + menu,
1.407 + mh,
1.408 + time);
1.409 +#endif
1.410 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
1.411 + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
1.412 + {
1.413 + return false;
1.414 + }
1.415 +
1.416 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.417 + if (player->bAutoIgnore)
1.418 + {
1.419 + return false;
1.420 + }
1.421 +
1.422 + /* For the duration of this, we are going to totally ignore whether
1.423 + * the player is already in a menu or not (except to cancel the old one).
1.424 + * Instead, we are simply going to ignore any further menu displays, so
1.425 + * this display can't be interrupted.
1.426 + */
1.427 + player->bAutoIgnore = true;
1.428 +
1.429 + /* Cancel any old menus */
1.430 + menu_states_t &states = player->states;
1.431 + if (player->bInMenu)
1.432 + {
1.433 + _CancelClientMenu(client, MenuCancel_Interrupted, true);
1.434 + }
1.435 +
1.436 + states.firstItem = 0;
1.437 + states.lastItem = 0;
1.438 + states.menu = NULL;
1.439 + states.mh = mh;
1.440 + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
1.441 + player->bInMenu = true;
1.442 + player->bInExternMenu = false;
1.443 + player->menuStartTime = gpGlobals->curtime;
1.444 + player->menuHoldTime = time;
1.445 +
1.446 + if (time)
1.447 + {
1.448 + AddClientToWatch(client);
1.449 + }
1.450 +
1.451 + /* Draw the display */
1.452 + SendDisplay(client, menu);
1.453 +
1.454 + /* We can be interrupted again! */
1.455 + player->bAutoIgnore = false;
1.456 +
1.457 + return true;
1.458 +}
1.459 +
1.460 +bool BaseMenuStyle::DoClientMenu(int client,
1.461 + CBaseMenu *menu,
1.462 + unsigned int first_item,
1.463 + IMenuHandler *mh,
1.464 + unsigned int time)
1.465 +{
1.466 +#if defined MENU_DEBUG
1.467 + g_Logger.LogMessage("[SM_MENU] DoClientMenu() (client %d) (menu %p) (mh %p) (time %d)",
1.468 + client,
1.469 + menu,
1.470 + mh,
1.471 + time);
1.472 +#endif
1.473 + mh->OnMenuStart(menu);
1.474 +
1.475 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
1.476 + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
1.477 + {
1.478 +#if defined MENU_DEBUG
1.479 + g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to display to client %d", client);
1.480 +#endif
1.481 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.482 + mh->OnMenuEnd(menu, MenuEnd_Cancelled);
1.483 + return false;
1.484 + }
1.485 +
1.486 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.487 + if (player->bAutoIgnore)
1.488 + {
1.489 +#if defined MENU_DEBUG
1.490 + g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Client %d is autoIgnoring", client);
1.491 +#endif
1.492 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.493 + mh->OnMenuEnd(menu, MenuEnd_Cancelled);
1.494 + return false;
1.495 + }
1.496 +
1.497 + /* For the duration of this, we are going to totally ignore whether
1.498 + * the player is already in a menu or not (except to cancel the old one).
1.499 + * Instead, we are simply going to ignore any further menu displays, so
1.500 + * this display can't be interrupted.
1.501 + */
1.502 + player->bAutoIgnore = true;
1.503 +
1.504 + /* Cancel any old menus */
1.505 + menu_states_t &states = player->states;
1.506 + if (player->bInMenu)
1.507 + {
1.508 +#if defined MENU_DEBUG
1.509 + g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Cancelling old menu to client %d", client);
1.510 +#endif
1.511 + _CancelClientMenu(client, MenuCancel_Interrupted, true);
1.512 + }
1.513 +
1.514 + states.firstItem = 0;
1.515 + states.lastItem = first_item;
1.516 + states.menu = menu;
1.517 + states.mh = mh;
1.518 + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
1.519 +
1.520 + IMenuPanel *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
1.521 + if (!display)
1.522 + {
1.523 +#if defined MENU_DEBUG
1.524 + g_Logger.LogMessage("[SM_MENU] DoClientMenu(): Failed to render to client %d", client);
1.525 +#endif
1.526 + player->bAutoIgnore = false;
1.527 + player->bInMenu = false;
1.528 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.529 + mh->OnMenuEnd(menu, MenuEnd_Cancelled);
1.530 + return false;
1.531 + }
1.532 +
1.533 + /* Finally, set our states */
1.534 + player->bInMenu = true;
1.535 + player->bInExternMenu = false;
1.536 + player->menuStartTime = gpGlobals->curtime;
1.537 + player->menuHoldTime = time;
1.538 +
1.539 + if (time)
1.540 + {
1.541 + AddClientToWatch(client);
1.542 + }
1.543 +
1.544 + /* Draw the display */
1.545 + SendDisplay(client, display);
1.546 +
1.547 + /* Free the display pointer */
1.548 + display->DeleteThis();
1.549 +
1.550 + /* We can be interrupted again! */
1.551 + player->bAutoIgnore = false;
1.552 +
1.553 +#if defined MENU_DEBUG
1.554 + g_Logger.LogMessage("[SM_MENU] DoClientMenu() finished successfully (client %d)", client);
1.555 +#endif
1.556 +
1.557 + return true;
1.558 +}
1.559 +
1.560 +bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
1.561 +{
1.562 +#if defined MENU_DEBUG
1.563 + g_Logger.LogMessage("[SM_MENU] RedoClientMenu() (client %d) (order %d)", client, order);
1.564 +#endif
1.565 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.566 + menu_states_t &states = player->states;
1.567 +
1.568 + player->bAutoIgnore = true;
1.569 + IMenuPanel *display = g_Menus.RenderMenu(client, states, order);
1.570 + if (!display)
1.571 + {
1.572 +#if defined MENU_DEBUG
1.573 + g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Failed to render menu");
1.574 +#endif
1.575 + if (player->menuHoldTime)
1.576 + {
1.577 + RemoveClientFromWatch(client);
1.578 + }
1.579 + player->bAutoIgnore = false;
1.580 + return false;
1.581 + }
1.582 +
1.583 + SendDisplay(client, display);
1.584 +
1.585 + display->DeleteThis();
1.586 +
1.587 + player->bAutoIgnore = false;
1.588 +
1.589 +#if defined MENU_DEBUG
1.590 + g_Logger.LogMessage("[SM_MENU] RedoClientMenu(): Succeeded to client %d", client);
1.591 +#endif
1.592 +
1.593 + return true;
1.594 +}
1.595 +
1.596 +CBaseMenu::CBaseMenu(IMenuHandler *pHandler, IMenuStyle *pStyle, IdentityToken_t *pOwner) :
1.597 +m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_bShouldDelete(false), m_bCancelling(false),
1.598 +m_pOwner(pOwner ? pOwner : g_pCoreIdent), m_bDeleting(false), m_bWillFreeHandle(false),
1.599 +m_hHandle(BAD_HANDLE), m_pHandler(pHandler), m_nFlags(MENUFLAG_BUTTON_EXIT)
1.600 +{
1.601 +}
1.602 +
1.603 +CBaseMenu::~CBaseMenu()
1.604 +{
1.605 +}
1.606 +
1.607 +Handle_t CBaseMenu::GetHandle()
1.608 +{
1.609 + if (!m_hHandle)
1.610 + {
1.611 + m_hHandle = g_Menus.CreateMenuHandle(this, m_pOwner);
1.612 + }
1.613 +
1.614 + return m_hHandle;
1.615 +}
1.616 +
1.617 +bool CBaseMenu::AppendItem(const char *info, const ItemDrawInfo &draw)
1.618 +{
1.619 + if (m_Pagination == (unsigned)MENU_NO_PAGINATION
1.620 + && m_items.size() >= m_pStyle->GetMaxPageItems())
1.621 + {
1.622 + return false;
1.623 + }
1.624 +
1.625 + CItem item;
1.626 +
1.627 + item.infoString = m_Strings.AddString(info);
1.628 + if (draw.display)
1.629 + {
1.630 + item.displayString = m_Strings.AddString(draw.display);
1.631 + }
1.632 + item.style = draw.style;
1.633 +
1.634 + m_items.push_back(item);
1.635 +
1.636 + return true;
1.637 +}
1.638 +
1.639 +bool CBaseMenu::InsertItem(unsigned int position, const char *info, const ItemDrawInfo &draw)
1.640 +{
1.641 + if (m_Pagination == (unsigned)MENU_NO_PAGINATION
1.642 + && m_items.size() >= m_pStyle->GetMaxPageItems())
1.643 + {
1.644 + return false;
1.645 + }
1.646 +
1.647 + if (position >= m_items.size())
1.648 + {
1.649 + return false;
1.650 + }
1.651 +
1.652 + CItem item;
1.653 + item.infoString = m_Strings.AddString(info);
1.654 + if (draw.display)
1.655 + {
1.656 + item.displayString = m_Strings.AddString(draw.display);
1.657 + }
1.658 + item.style = draw.style;
1.659 +
1.660 + CVector<CItem>::iterator iter = m_items.iterAt(position);
1.661 + m_items.insert(iter, item);
1.662 +
1.663 + return true;
1.664 +}
1.665 +
1.666 +bool CBaseMenu::RemoveItem(unsigned int position)
1.667 +{
1.668 + if (position >= m_items.size())
1.669 + {
1.670 + return false;
1.671 + }
1.672 +
1.673 + m_items.erase(m_items.iterAt(position));
1.674 +
1.675 + if (m_items.size() == 0)
1.676 + {
1.677 + m_Strings.Reset();
1.678 + }
1.679 +
1.680 + return true;
1.681 +}
1.682 +
1.683 +void CBaseMenu::RemoveAllItems()
1.684 +{
1.685 + m_items.clear();
1.686 + m_Strings.Reset();
1.687 +}
1.688 +
1.689 +const char *CBaseMenu::GetItemInfo(unsigned int position, ItemDrawInfo *draw/* =NULL */)
1.690 +{
1.691 + if (position >= m_items.size())
1.692 + {
1.693 + return NULL;
1.694 + }
1.695 +
1.696 + if (draw)
1.697 + {
1.698 + draw->display = m_Strings.GetString(m_items[position].displayString);
1.699 + draw->style = m_items[position].style;
1.700 + }
1.701 +
1.702 + return m_Strings.GetString(m_items[position].infoString);
1.703 +}
1.704 +
1.705 +unsigned int CBaseMenu::GetItemCount()
1.706 +{
1.707 + return m_items.size();
1.708 +}
1.709 +
1.710 +bool CBaseMenu::SetPagination(unsigned int itemsPerPage)
1.711 +{
1.712 + if (itemsPerPage > 7 || itemsPerPage == 1)
1.713 + {
1.714 + return false;
1.715 + }
1.716 +
1.717 + if (itemsPerPage == MENU_NO_PAGINATION
1.718 + && m_Pagination != MENU_NO_PAGINATION)
1.719 + {
1.720 + m_nFlags &= ~MENUFLAG_BUTTON_EXIT;
1.721 + }
1.722 +
1.723 + m_Pagination = itemsPerPage;
1.724 +
1.725 + return true;
1.726 +}
1.727 +
1.728 +unsigned int CBaseMenu::GetPagination()
1.729 +{
1.730 + return m_Pagination;
1.731 +}
1.732 +
1.733 +IMenuStyle *CBaseMenu::GetDrawStyle()
1.734 +{
1.735 + return m_pStyle;
1.736 +}
1.737 +
1.738 +void CBaseMenu::SetDefaultTitle(const char *message)
1.739 +{
1.740 + m_Title.assign(message);
1.741 +}
1.742 +
1.743 +const char *CBaseMenu::GetDefaultTitle()
1.744 +{
1.745 + return m_Title.c_str();
1.746 +}
1.747 +
1.748 +void CBaseMenu::Cancel()
1.749 +{
1.750 + if (m_bCancelling)
1.751 + {
1.752 + return;
1.753 + }
1.754 +
1.755 +#if defined MENU_DEBUG
1.756 + g_Logger.LogMessage("[SM_MENU] CBaseMenu::Cancel(%p) (m_bShouldDelete %d)",
1.757 + this,
1.758 + m_bShouldDelete);
1.759 +#endif
1.760 +
1.761 + m_bCancelling = true;
1.762 + Cancel_Finally();
1.763 + m_bCancelling = false;
1.764 +
1.765 + if (m_bShouldDelete)
1.766 + {
1.767 + InternalDelete();
1.768 + }
1.769 +}
1.770 +
1.771 +void CBaseMenu::Destroy(bool releaseHandle)
1.772 +{
1.773 + /* Check if we shouldn't be here */
1.774 + if (m_bDeleting)
1.775 + {
1.776 + return;
1.777 + }
1.778 +
1.779 +#if defined MENU_DEBUG
1.780 + g_Logger.LogMessage("[SM_MENU] CBaseMenu::Destroy(%p) (release %d) (m_bCancelling %d) (m_bShouldDelete %d)",
1.781 + this,
1.782 + releaseHandle,
1.783 + m_bCancelling,
1.784 + m_bShouldDelete);
1.785 +#endif
1.786 +
1.787 + /* Save the destruction hint about our handle */
1.788 + m_bWillFreeHandle = releaseHandle;
1.789 +
1.790 + /* Now actually do stuff */
1.791 + if (!m_bCancelling || m_bShouldDelete)
1.792 + {
1.793 + Cancel();
1.794 + InternalDelete();
1.795 + } else {
1.796 + m_bShouldDelete = true;
1.797 + }
1.798 +}
1.799 +
1.800 +void CBaseMenu::InternalDelete()
1.801 +{
1.802 + if (m_bWillFreeHandle && m_hHandle != BAD_HANDLE)
1.803 + {
1.804 + Handle_t hndl = m_hHandle;
1.805 + HandleSecurity sec;
1.806 +
1.807 + sec.pOwner = m_pOwner;
1.808 + sec.pIdentity = g_pCoreIdent;
1.809 +
1.810 + m_hHandle = BAD_HANDLE;
1.811 + m_bDeleting = true;
1.812 + g_HandleSys.FreeHandle(hndl, &sec);
1.813 + }
1.814 +
1.815 + m_pHandler->OnMenuDestroy(this);
1.816 +
1.817 + delete this;
1.818 +}
1.819 +
1.820 +unsigned int CBaseMenu::GetMenuOptionFlags()
1.821 +{
1.822 + return m_nFlags;
1.823 +}
1.824 +
1.825 +void CBaseMenu::SetMenuOptionFlags(unsigned int flags)
1.826 +{
1.827 + m_nFlags = flags;
1.828 +}
1.829 +
1.830 +IMenuHandler *CBaseMenu::GetHandler()
1.831 +{
1.832 + return m_pHandler;
1.833 +}
1.834 +
1.835 +unsigned int CBaseMenu::GetBaseMemUsage()
1.836 +{
1.837 + return m_Title.size()
1.838 + + m_Strings.GetMemTable()->GetMemUsage()
1.839 + + (m_items.size() * sizeof(CItem));
1.840 +}