1.1 --- a/core/MenuStyle_Base.cpp Sun May 13 00:42:39 2007 +0000
1.2 +++ b/core/MenuStyle_Base.cpp Sun May 13 03:38:36 2007 +0000
1.3 @@ -15,9 +15,403 @@
1.4 #include <stdarg.h>
1.5 #include "sm_stringutil.h"
1.6 #include "MenuStyle_Base.h"
1.7 +#include "PlayerManager.h"
1.8 +#include "MenuManager.h"
1.9 +
1.10 +BaseMenuStyle::BaseMenuStyle() : m_WatchList(256)
1.11 +{
1.12 +}
1.13 +
1.14 +void BaseMenuStyle::AddClientToWatch(int client)
1.15 +{
1.16 + m_WatchList.push_back(client);
1.17 +}
1.18 +
1.19 +void BaseMenuStyle::RemoveClientFromWatch(int client)
1.20 +{
1.21 + m_WatchList.remove(client);
1.22 +}
1.23 +
1.24 +void BaseMenuStyle::_CancelClientMenu(int client, bool bAutoIgnore/* =false */, MenuCancelReason reason/* =MenuCancel_Interrupt */)
1.25 +{
1.26 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.27 + menu_states_t &states = player->states;
1.28 +
1.29 + bool bOldIgnore = player->bAutoIgnore;
1.30 + if (bAutoIgnore)
1.31 + {
1.32 + player->bAutoIgnore = true;
1.33 + }
1.34 +
1.35 + /* Save states */
1.36 + IMenuHandler *mh = states.mh;
1.37 + IBaseMenu *menu = states.menu;
1.38 +
1.39 + /* Clear menu */
1.40 + player->bInMenu = false;
1.41 + if (player->menuHoldTime)
1.42 + {
1.43 + RemoveClientFromWatch(client);
1.44 + }
1.45 +
1.46 + /* Fire callbacks */
1.47 + mh->OnMenuCancel(menu, client, reason);
1.48 + mh->OnMenuEnd(menu);
1.49 +
1.50 + if (bAutoIgnore)
1.51 + {
1.52 + player->bAutoIgnore = bOldIgnore;
1.53 + }
1.54 +}
1.55 +
1.56 +void BaseMenuStyle::CancelMenu(CBaseMenu *menu)
1.57 +{
1.58 + int maxClients = g_Players.GetMaxClients();
1.59 + for (int i=1; i<=maxClients; i++)
1.60 + {
1.61 + CBaseMenuPlayer *player = GetMenuPlayer(i);
1.62 + if (player->bInMenu)
1.63 + {
1.64 + menu_states_t &states = player->states;
1.65 + if (states.menu == menu)
1.66 + {
1.67 + _CancelClientMenu(i);
1.68 + }
1.69 + }
1.70 + }
1.71 +}
1.72 +
1.73 +bool BaseMenuStyle::CancelClientMenu(int client, bool autoIgnore)
1.74 +{
1.75 + if (client < 1 || client > g_Players.MaxClients())
1.76 + {
1.77 + return false;
1.78 + }
1.79 +
1.80 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.81 + if (!player->bInMenu)
1.82 + {
1.83 + return false;
1.84 + }
1.85 +
1.86 + _CancelClientMenu(client, autoIgnore);
1.87 +
1.88 + return true;
1.89 +}
1.90 +
1.91 +MenuSource BaseMenuStyle::GetClientMenu(int client, void **object)
1.92 +{
1.93 + if (client < 1 || client > g_Players.GetMaxClients())
1.94 + {
1.95 + return MenuSource_None;
1.96 + }
1.97 +
1.98 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.99 +
1.100 + if (player->bInMenu)
1.101 + {
1.102 + IBaseMenu *menu;
1.103 + if ((menu=player->states.menu) != NULL)
1.104 + {
1.105 + if (object)
1.106 + {
1.107 + *object = menu;
1.108 + }
1.109 + return MenuSource_BaseMenu;
1.110 + }
1.111 +
1.112 + return MenuSource_Display;
1.113 + } else {
1.114 + return GetClientExternMenu(client, object);
1.115 + }
1.116 +}
1.117 +
1.118 +MenuSource BaseMenuStyle::GetClientExternMenu(int client, void **object)
1.119 +{
1.120 + return MenuSource_None;
1.121 +}
1.122 +
1.123 +void BaseMenuStyle::OnClientDisconnected(int client)
1.124 +{
1.125 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.126 + if (!player->bInMenu)
1.127 + {
1.128 + return;
1.129 + }
1.130 +
1.131 + _CancelClientMenu(client, true, MenuCancel_Disconnect);
1.132 +
1.133 + player->bInMenu = false;
1.134 +}
1.135 +
1.136 +static int do_lookup[256];
1.137 +void BaseMenuStyle::ProcessWatchList()
1.138 +{
1.139 + if (!m_WatchList.size())
1.140 + {
1.141 + return;
1.142 + }
1.143 +
1.144 + unsigned int total = 0;
1.145 + for (FastLink<int>::iterator iter=m_WatchList.begin(); iter!=m_WatchList.end(); ++iter)
1.146 + {
1.147 + do_lookup[total++] = (*iter);
1.148 + }
1.149 +
1.150 + int client;
1.151 + CBaseMenuPlayer *player;
1.152 + float curTime = gpGlobals->curtime;
1.153 + for (unsigned int i=0; i<total; i++)
1.154 + {
1.155 + client = do_lookup[i];
1.156 + player = GetMenuPlayer(client);
1.157 + if (!player->bInMenu || !player->menuHoldTime)
1.158 + {
1.159 + m_WatchList.remove(i);
1.160 + continue;
1.161 + }
1.162 + if (curTime > player->menuStartTime + player->menuHoldTime)
1.163 + {
1.164 + _CancelClientMenu(client, false);
1.165 + }
1.166 + }
1.167 +}
1.168 +
1.169 +void BaseMenuStyle::ClientPressedKey(int client, unsigned int key_press)
1.170 +{
1.171 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.172 +
1.173 + /* First question: Are we in a menu? */
1.174 + if (!player->bInMenu)
1.175 + {
1.176 + return;
1.177 + }
1.178 +
1.179 + bool cancel = false;
1.180 + unsigned int item = 0;
1.181 + MenuCancelReason reason = MenuCancel_Exit;
1.182 + menu_states_t &states = player->states;
1.183 +
1.184 + assert(states.mh != NULL);
1.185 +
1.186 + if (states.menu == NULL)
1.187 + {
1.188 + item = key_press;
1.189 + } else if (key_press < 1 || key_press > 8) {
1.190 + cancel = true;
1.191 + } else {
1.192 + ItemSelection type = states.slots[key_press].type;
1.193 +
1.194 + /* For navigational items, we're going to redisplay */
1.195 + if (type == ItemSel_Back)
1.196 + {
1.197 + if (!RedoClientMenu(client, ItemOrder_Descending))
1.198 + {
1.199 + cancel = true;
1.200 + reason = MenuCancel_NoDisplay;
1.201 + } else {
1.202 + return;
1.203 + }
1.204 + } else if (type == ItemSel_Next) {
1.205 + if (!RedoClientMenu(client, ItemOrder_Ascending))
1.206 + {
1.207 + cancel = true; /* I like Saltines. */
1.208 + reason = MenuCancel_NoDisplay;
1.209 + } else {
1.210 + return;
1.211 + }
1.212 + } else if (type == ItemSel_Exit || type == ItemSel_None) {
1.213 + cancel = true;
1.214 + } else {
1.215 + item = states.slots[key_press].item;
1.216 + }
1.217 + }
1.218 +
1.219 + /* Save variables */
1.220 + IMenuHandler *mh = states.mh;
1.221 + IBaseMenu *menu = states.menu;
1.222 +
1.223 + /* Clear states */
1.224 + player->bInMenu = false;
1.225 + if (player->menuHoldTime)
1.226 + {
1.227 + m_WatchList.remove(client);
1.228 + }
1.229 +
1.230 + if (cancel)
1.231 + {
1.232 + mh->OnMenuCancel(menu, client, reason);
1.233 + } else {
1.234 + mh->OnMenuSelect(menu, client, item);
1.235 + }
1.236 +
1.237 + mh->OnMenuEnd(menu);
1.238 +}
1.239 +
1.240 +bool BaseMenuStyle::DoClientMenu(int client, IMenuDisplay *menu, IMenuHandler *mh, unsigned int time)
1.241 +{
1.242 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
1.243 + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
1.244 + {
1.245 + return false;
1.246 + }
1.247 +
1.248 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.249 + if (player->bAutoIgnore)
1.250 + {
1.251 + return false;
1.252 + }
1.253 +
1.254 + /* For the duration of this, we are going to totally ignore whether
1.255 + * the player is already in a menu or not (except to cancel the old one).
1.256 + * Instead, we are simply going to ignore any further menu displays, so
1.257 + * this display can't be interrupted.
1.258 + */
1.259 + player->bAutoIgnore = true;
1.260 +
1.261 + /* Cancel any old menus */
1.262 + menu_states_t &states = player->states;
1.263 + if (player->bInMenu)
1.264 + {
1.265 + /* We need to cancel the old menu */
1.266 + if (player->menuHoldTime)
1.267 + {
1.268 + RemoveClientFromWatch(client);
1.269 + }
1.270 + states.mh->OnMenuCancel(states.menu, client, MenuCancel_Interrupt);
1.271 + states.mh->OnMenuEnd(states.menu);
1.272 + }
1.273 +
1.274 + states.firstItem = 0;
1.275 + states.lastItem = 0;
1.276 + states.menu = NULL;
1.277 + states.mh = mh;
1.278 + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
1.279 + player->bInMenu = true;
1.280 + player->menuStartTime = gpGlobals->curtime;
1.281 + player->menuHoldTime = time;
1.282 +
1.283 + if (time)
1.284 + {
1.285 + AddClientToWatch(client);
1.286 + }
1.287 +
1.288 + /* Draw the display */
1.289 + SendDisplay(client, menu);
1.290 +
1.291 + /* We can be interrupted again! */
1.292 + player->bAutoIgnore = false;
1.293 +
1.294 + return true;
1.295 +}
1.296 +
1.297 +bool BaseMenuStyle::DoClientMenu(int client, CBaseMenu *menu, IMenuHandler *mh, unsigned int time)
1.298 +{
1.299 + mh->OnMenuStart(menu);
1.300 +
1.301 + if (!mh)
1.302 + {
1.303 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.304 + mh->OnMenuEnd(menu);
1.305 + return false;
1.306 + }
1.307 +
1.308 + CPlayer *pPlayer = g_Players.GetPlayerByIndex(client);
1.309 + if (!pPlayer || pPlayer->IsFakeClient() || !pPlayer->IsInGame())
1.310 + {
1.311 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.312 + mh->OnMenuEnd(menu);
1.313 + return false;
1.314 + }
1.315 +
1.316 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.317 + if (player->bAutoIgnore)
1.318 + {
1.319 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.320 + mh->OnMenuEnd(menu);
1.321 + return false;
1.322 + }
1.323 +
1.324 + /* For the duration of this, we are going to totally ignore whether
1.325 + * the player is already in a menu or not (except to cancel the old one).
1.326 + * Instead, we are simply going to ignore any further menu displays, so
1.327 + * this display can't be interrupted.
1.328 + */
1.329 + player->bAutoIgnore = true;
1.330 +
1.331 + /* Cancel any old menus */
1.332 + menu_states_t &states = player->states;
1.333 + if (player->bInMenu)
1.334 + {
1.335 + _CancelClientMenu(client, true);
1.336 + }
1.337 +
1.338 + states.firstItem = 0;
1.339 + states.lastItem = 0;
1.340 + states.menu = menu;
1.341 + states.mh = mh;
1.342 + states.apiVers = SMINTERFACE_MENUMANAGER_VERSION;
1.343 +
1.344 + IMenuDisplay *display = g_Menus.RenderMenu(client, states, ItemOrder_Ascending);
1.345 + if (!display)
1.346 + {
1.347 + player->bAutoIgnore = false;
1.348 + player->bInMenu = false;
1.349 + mh->OnMenuCancel(menu, client, MenuCancel_NoDisplay);
1.350 + mh->OnMenuEnd(menu);
1.351 + return false;
1.352 + }
1.353 +
1.354 + /* Finally, set our states */
1.355 + player->bInMenu = true;
1.356 + player->menuStartTime = gpGlobals->curtime;
1.357 + player->menuHoldTime = time;
1.358 +
1.359 + if (time)
1.360 + {
1.361 + AddClientToWatch(client);
1.362 + }
1.363 +
1.364 + /* Draw the display */
1.365 + SendDisplay(client, display);
1.366 +
1.367 + /* Free the display pointer */
1.368 + delete display;
1.369 +
1.370 + /* We can be interrupted again! */
1.371 + player->bAutoIgnore = false;
1.372 +
1.373 + return true;
1.374 +}
1.375 +
1.376 +bool BaseMenuStyle::RedoClientMenu(int client, ItemOrder order)
1.377 +{
1.378 + CBaseMenuPlayer *player = GetMenuPlayer(client);
1.379 + menu_states_t &states = player->states;
1.380 +
1.381 + player->bAutoIgnore = true;
1.382 + IMenuDisplay *display = g_Menus.RenderMenu(client, states, order);
1.383 + if (!display)
1.384 + {
1.385 + if (player->menuHoldTime)
1.386 + {
1.387 + m_WatchList.remove(client);
1.388 + }
1.389 + player->bAutoIgnore = false;
1.390 + return false;
1.391 + }
1.392 +
1.393 + SendDisplay(client, display);
1.394 +
1.395 + delete display;
1.396 +
1.397 + player->bAutoIgnore = false;
1.398 +
1.399 + return true;
1.400 +}
1.401
1.402 CBaseMenu::CBaseMenu(IMenuStyle *pStyle) :
1.403 -m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true)
1.404 +m_pStyle(pStyle), m_Strings(512), m_Pagination(7), m_ExitButton(true), m_bShouldDelete(false), m_bCancelling(false)
1.405 {
1.406 }
1.407
1.408 @@ -161,3 +555,32 @@
1.409 m_ExitButton = set;
1.410 return true;
1.411 }
1.412 +
1.413 +void CBaseMenu::Cancel()
1.414 +{
1.415 + if (m_bCancelling)
1.416 + {
1.417 + return;
1.418 + }
1.419 +
1.420 + m_bCancelling = true;
1.421 + Cancel_Finally();
1.422 + m_bCancelling = false;
1.423 +
1.424 + if (m_bShouldDelete)
1.425 + {
1.426 + delete this;
1.427 + }
1.428 +}
1.429 +
1.430 +void CBaseMenu::Destroy()
1.431 +{
1.432 + if (!m_bCancelling || m_bShouldDelete)
1.433 + {
1.434 + Cancel();
1.435 + delete this;
1.436 + } else {
1.437 + m_bShouldDelete = true;
1.438 + }
1.439 +}
1.440 +