dvander@773: /** dvander@773: * vim: set ts=4 : dvander@773: * =============================================================== dvander@773: * SourceMod (C)2004-2007 AlliedModders LLC. All rights reserved. dvander@773: * =============================================================== dvander@773: * dvander@773: * This file is not open source and may not be copied without explicit dvander@773: * written permission of AlliedModders LLC. This file may not be redistributed dvander@773: * in whole or significant part. dvander@773: * For information, see LICENSE.txt or http://www.sourcemod.net/license.php dvander@773: * dvander@773: * Version: $Id$ dvander@773: */ dvander@773: dvander@877: #include dvander@769: #include dvander@877: #include dvander@769: #include "MenuManager.h" dvander@769: #include "sm_stringutil.h" dvander@769: #include "sourcemm_api.h" dvander@769: #include "PlayerManager.h" dvander@769: #include "MenuStyle_Valve.h" dvander@781: #include "ShareSys.h" dvander@790: #include "HandleSys.h" dvander@769: dvander@769: MenuManager g_Menus; dvander@769: dvander@877: /******************************* dvander@877: ******************************* dvander@877: ******** VOTE HANDLER ********* dvander@877: ******************************* dvander@877: *******************************/ dvander@769: dvander@877: unsigned int VoteMenuHandler::GetMenuAPIVersion2() dvander@769: { dvander@769: return m_pHandler->GetMenuAPIVersion2(); dvander@769: } dvander@769: dvander@877: bool VoteMenuHandler::IsVoteInProgress() dvander@877: { dvander@877: return (m_pCurMenu != NULL); dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::InitializeVoting(IBaseMenu *menu) dvander@877: { dvander@877: m_Items = menu->GetItemCount(); dvander@877: dvander@877: if (m_Votes.size() < (size_t)m_Items) dvander@877: { dvander@877: /* Only clear the items we need to... */ dvander@877: size_t size = m_Votes.size(); dvander@877: for (size_t i=0; iOnMenuStart(m_pCurMenu); dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::StartVoting() dvander@877: { dvander@877: m_bStarted = true; dvander@877: dvander@877: m_pHandler->OnMenuVoteStart(m_pCurMenu); dvander@877: dvander@877: /* By now we know how many clients were set. dvander@877: * If there are none, we should end IMMEDIATELY. dvander@877: */ dvander@877: if (m_Clients == 0) dvander@877: { dvander@877: EndVoting(); dvander@877: } dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::DecrementPlayerCount() dvander@877: { dvander@877: assert(m_Clients > 0); dvander@877: dvander@877: m_Clients--; dvander@877: dvander@877: if (m_bStarted && m_Clients == 0) dvander@877: { dvander@877: EndVoting(); dvander@877: } dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::EndVoting() dvander@877: { dvander@884: if (m_bCancelled) dvander@884: { dvander@884: /* If we were cancelled, don't bother tabulating anything. dvander@884: * Reset just in case someone tries to redraw, which means dvander@884: * we need to save our states. dvander@884: */ dvander@884: IBaseMenu *menu = m_pCurMenu; dvander@884: InternalReset(); dvander@884: m_pHandler->OnMenuVoteCancel(menu); dvander@997: m_pHandler->OnMenuEnd(menu, MenuEnd_VotingCancelled); dvander@884: return; dvander@884: } dvander@884: dvander@877: unsigned int chosen = 0; dvander@882: unsigned int highest = 0; dvander@879: unsigned int dup_count = 0; dvander@962: unsigned int total = m_Votes.size() ? m_Votes[0] : 0; dvander@877: dvander@877: /* If we got zero votes, take a shortcut. */ dvander@877: if (m_NumVotes == 0) dvander@877: { dvander@877: /* Pick a random item and then jump far, far away. */ dvander@877: srand((unsigned int)(time(NULL))); dvander@884: chosen = (unsigned int)rand() % m_Items; dvander@877: goto picked_item; dvander@877: } dvander@877: dvander@877: /* We can't have more dups than this! dvander@877: * This is the max number of players. dvander@877: */ dvander@877: unsigned int dup_array[256]; dvander@877: dvander@882: for (size_t i=1; i m_Votes[highest]) dvander@877: { dvander@877: /* If we have a new highest count, mark it and trash the duplicate dvander@877: * list by setting the total to 0. dvander@877: */ dvander@877: highest = i; dvander@877: dup_count = 0; dvander@877: } else if (m_Votes[i] == m_Votes[highest]) { dvander@877: /* If they're equal, mark it in the duplicate list. dvander@877: * We'll add in the original later. dvander@877: */ dvander@877: dup_array[dup_count++] = i; dvander@877: } dvander@960: total += m_Votes[i]; dvander@877: } dvander@877: dvander@877: /* Check if we need to pick from the duplicate list */ dvander@877: if (dup_count) dvander@877: { dvander@877: /* Re-add the original to the list because it's not in there. */ dvander@882: dup_array[dup_count++] = highest; dvander@877: dvander@877: /* Pick a random slot. */ dvander@877: srand((unsigned int)(time(NULL))); dvander@877: unsigned int r = (unsigned int)rand() % dup_count; dvander@877: dvander@877: /* Pick the item. */ dvander@877: chosen = dup_array[r]; dvander@877: } else { dvander@882: chosen = highest; dvander@877: } dvander@877: dvander@877: picked_item: dvander@960: m_pHandler->OnMenuVoteEnd(m_pCurMenu, chosen, m_Votes[highest], total); dvander@997: m_pHandler->OnMenuEnd(m_pCurMenu, MenuEnd_VotingDone); dvander@877: InternalReset(); dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::OnMenuStart(IBaseMenu *menu) dvander@877: { dvander@877: m_Clients++; dvander@877: } dvander@877: dvander@997: void VoteMenuHandler::OnMenuEnd(IBaseMenu *menu, MenuEndReason reason) dvander@877: { dvander@877: DecrementPlayerCount(); dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason) dvander@769: { dvander@769: m_pHandler->OnMenuCancel(menu, client, reason); dvander@769: } dvander@769: dvander@877: void VoteMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display) dvander@769: { dvander@769: m_pHandler->OnMenuDisplay(menu, client, display); dvander@769: } dvander@769: dvander@877: void VoteMenuHandler::OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display) dvander@769: { dvander@877: m_pHandler->OnMenuDisplayItem(menu, client, item, display); dvander@877: } dvander@877: dvander@877: void VoteMenuHandler::OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style) dvander@877: { dvander@877: m_pHandler->OnMenuDrawItem(menu, client, item, style); dvander@769: } dvander@769: dvander@877: void VoteMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item) dvander@769: { dvander@877: /* Check by our item count, NOT the vote array size */ dvander@877: if (item < m_Items) dvander@877: { dvander@877: m_Votes[item]++; dvander@877: m_NumVotes++; dvander@877: } dvander@877: dvander@769: m_pHandler->OnMenuSelect(menu, client, item); dvander@769: } dvander@769: dvander@877: void VoteMenuHandler::Reset(IMenuHandler *mh) dvander@769: { dvander@877: m_pHandler = mh; dvander@877: InternalReset(); dvander@769: } dvander@769: dvander@877: void VoteMenuHandler::InternalReset() dvander@769: { dvander@877: m_Clients = 0; dvander@877: m_Items = 0; dvander@877: m_bStarted = false; dvander@877: m_pCurMenu = NULL; dvander@877: m_NumVotes = 0; dvander@884: m_bCancelled = false; dvander@884: } dvander@884: dvander@884: void VoteMenuHandler::CancelVoting() dvander@884: { dvander@884: m_bCancelled = true; dvander@769: } dvander@769: dvander@769: /******************************* dvander@769: ******************************* dvander@769: ******** MENU MANAGER ********* dvander@769: ******************************* dvander@769: *******************************/ dvander@769: dvander@769: MenuManager::MenuManager() dvander@769: { dvander@780: m_Styles.push_back(&g_ValveMenuStyle); dvander@780: SetDefaultStyle(&g_ValveMenuStyle); dvander@769: } dvander@769: dvander@769: void MenuManager::OnSourceModAllInitialized() dvander@769: { dvander@781: g_ShareSys.AddInterface(NULL, this); dvander@790: dvander@790: HandleAccess access; dvander@790: g_HandleSys.InitAccessDefaults(NULL, &access); dvander@790: dvander@790: /* Deny cloning to menus */ dvander@790: access.access[HandleAccess_Clone] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; dvander@790: m_MenuType = g_HandleSys.CreateType("IBaseMenu", this, 0, NULL, &access, g_pCoreIdent, NULL); dvander@790: dvander@790: /* Also deny deletion to styles */ dvander@790: access.access[HandleAccess_Delete] = HANDLE_RESTRICT_OWNER|HANDLE_RESTRICT_IDENTITY; dvander@790: m_StyleType = g_HandleSys.CreateType("IMenuStyle", this, 0, NULL, &access, g_pCoreIdent, NULL); dvander@769: } dvander@769: dvander@769: void MenuManager::OnSourceModAllShutdown() dvander@769: { dvander@790: g_HandleSys.RemoveType(m_MenuType, g_pCoreIdent); dvander@790: g_HandleSys.RemoveType(m_StyleType, g_pCoreIdent); dvander@790: dvander@769: while (!m_VoteHandlers.empty()) dvander@769: { dvander@769: delete m_VoteHandlers.front(); dvander@769: m_VoteHandlers.pop(); dvander@769: } dvander@769: } dvander@769: dvander@790: void MenuManager::OnHandleDestroy(HandleType_t type, void *object) dvander@790: { dvander@790: if (type == m_MenuType) dvander@790: { dvander@790: IBaseMenu *menu = (IBaseMenu *)object; dvander@790: menu->Destroy(false); dvander@790: } else if (type == m_StyleType) { dvander@790: /* Do nothing */ dvander@790: } dvander@790: } dvander@790: dvander@790: Handle_t MenuManager::CreateMenuHandle(IBaseMenu *menu, IdentityToken_t *pOwner) dvander@790: { dvander@790: if (m_MenuType == NO_HANDLE_TYPE) dvander@790: { dvander@790: return BAD_HANDLE; dvander@790: } dvander@790: dvander@790: return g_HandleSys.CreateHandle(m_MenuType, menu, pOwner, g_pCoreIdent, NULL); dvander@790: } dvander@790: dvander@790: Handle_t MenuManager::CreateStyleHandle(IMenuStyle *style) dvander@790: { dvander@790: if (m_StyleType == NO_HANDLE_TYPE) dvander@790: { dvander@790: return BAD_HANDLE; dvander@790: } dvander@790: dvander@790: return g_HandleSys.CreateHandle(m_StyleType, style, g_pCoreIdent, g_pCoreIdent, NULL); dvander@790: } dvander@790: dvander@790: HandleError MenuManager::ReadMenuHandle(Handle_t handle, IBaseMenu **menu) dvander@790: { dvander@790: HandleSecurity sec; dvander@790: dvander@790: sec.pIdentity = g_pCoreIdent; dvander@790: sec.pOwner = NULL; dvander@790: dvander@790: return g_HandleSys.ReadHandle(handle, m_MenuType, &sec, (void **)menu); dvander@790: } dvander@790: dvander@790: HandleError MenuManager::ReadStyleHandle(Handle_t handle, IMenuStyle **style) dvander@790: { dvander@790: HandleSecurity sec; dvander@790: dvander@790: sec.pIdentity = g_pCoreIdent; dvander@790: sec.pOwner = g_pCoreIdent; dvander@790: dvander@790: return g_HandleSys.ReadHandle(handle, m_StyleType, &sec, (void **)style); dvander@790: } dvander@790: dvander@769: bool MenuManager::SetDefaultStyle(IMenuStyle *style) dvander@769: { dvander@769: if (!style) dvander@769: { dvander@769: return false; dvander@769: } dvander@769: dvander@769: m_pDefaultStyle = style; dvander@769: dvander@769: return true; dvander@769: } dvander@769: dvander@769: IMenuStyle *MenuManager::GetStyle(unsigned int index) dvander@769: { dvander@769: if (index >= GetStyleCount()) dvander@769: { dvander@769: return NULL; dvander@769: } dvander@769: dvander@769: return m_Styles[index]; dvander@769: } dvander@769: dvander@780: void MenuManager::AddStyle(IMenuStyle *style) dvander@780: { dvander@780: m_Styles.push_back(style); dvander@780: } dvander@780: dvander@769: unsigned int MenuManager::GetStyleCount() dvander@769: { dvander@769: return (unsigned int)m_Styles.size(); dvander@769: } dvander@769: dvander@769: IMenuStyle *MenuManager::FindStyleByName(const char *name) dvander@769: { dvander@769: unsigned int count = GetStyleCount(); dvander@769: for (unsigned int i=0; iGetStyleName(), name) == 0) dvander@769: { dvander@769: return ptr; dvander@769: } dvander@769: } dvander@769: dvander@769: return NULL; dvander@769: } dvander@769: dvander@787: inline bool IsSlotItem(IMenuPanel *display, dvander@769: unsigned int style) dvander@769: { dvander@769: if (!display->CanDrawItem(style)) dvander@769: { dvander@769: return false; dvander@769: } dvander@769: if ((style & ITEMDRAW_IGNORE) == ITEMDRAW_IGNORE) dvander@769: { dvander@769: return false; dvander@769: } dvander@769: if (style & ITEMDRAW_RAWLINE) dvander@769: { dvander@769: return false; dvander@769: } dvander@769: dvander@769: return true; dvander@769: } dvander@769: dvander@787: IMenuPanel *MenuManager::RenderMenu(int client, menu_states_t &md, ItemOrder order) dvander@769: { dvander@769: IBaseMenu *menu = md.menu; dvander@769: dvander@769: if (!menu) dvander@769: { dvander@769: return NULL; dvander@769: } dvander@769: dvander@769: struct dvander@769: { dvander@769: unsigned int position; dvander@769: ItemDrawInfo draw; dvander@769: } drawItems[10]; dvander@769: dvander@769: /* Figure out how many items to draw */ dvander@769: IMenuStyle *style = menu->GetDrawStyle(); dvander@769: unsigned int pgn = menu->GetPagination(); dvander@769: unsigned int maxItems = style->GetMaxPageItems(); dvander@769: if (pgn != MENU_NO_PAGINATION) dvander@769: { dvander@769: maxItems = pgn; dvander@769: } dvander@769: dvander@769: unsigned int totalItems = menu->GetItemCount(); dvander@769: unsigned int startItem = 0; dvander@769: dvander@769: /* For pagination, find the starting point. */ dvander@769: if (pgn != MENU_NO_PAGINATION) dvander@769: { dvander@769: if (order == ItemOrder_Ascending) dvander@769: { dvander@769: startItem = md.lastItem; dvander@769: /* This shouldn't happen with well-coded menus. dvander@769: * If the item is out of bounds, switch the order to dvander@769: * Items_Descending and make us start from the top. dvander@769: */ dvander@769: if (startItem >= totalItems) dvander@769: { dvander@769: startItem = totalItems - 1; dvander@769: order = ItemOrder_Descending; dvander@769: } dvander@769: } else if (order == ItemOrder_Descending) { dvander@769: startItem = md.firstItem; dvander@769: /* This shouldn't happen with well-coded menus. dvander@769: * If searching backwards doesn't give us enough room, dvander@769: * start from the beginning and change to ascending. dvander@769: */ dvander@769: if (startItem <= maxItems) dvander@769: { dvander@769: startItem = 0; dvander@769: order = ItemOrder_Ascending; dvander@769: } dvander@769: } dvander@769: } dvander@769: dvander@769: /* Get our Display pointer and initialize some crap */ dvander@787: IMenuPanel *display = menu->CreatePanel(); dvander@769: IMenuHandler *mh = md.mh; dvander@769: bool foundExtra = false; dvander@769: unsigned int extraItem = 0; dvander@769: dvander@769: /** dvander@769: * We keep searching until: dvander@769: * 1) There are no more items dvander@769: * 2) We reach one OVER the maximum number of slot items dvander@769: * 3) We have reached maxItems and pagination is MENU_NO_PAGINATION dvander@769: */ dvander@769: unsigned int i = startItem; dvander@769: unsigned int foundItems = 0; dvander@769: while (true) dvander@769: { dvander@769: ItemDrawInfo &dr = drawItems[foundItems].draw; dvander@769: /* Is the item valid? */ dvander@769: if (menu->GetItemInfo(i, &dr) != NULL) dvander@769: { dvander@769: /* Ask the user to change the style, if necessary */ dvander@769: mh->OnMenuDrawItem(menu, client, i, dr.style); dvander@769: /* Check if it's renderable */ dvander@769: if (IsSlotItem(display, dr.style)) dvander@769: { dvander@769: /* If we've already found the max number of items, dvander@769: * This means we should just cancel out and log our dvander@769: * "last item." dvander@769: */ dvander@769: if (foundItems >= maxItems) dvander@769: { dvander@769: foundExtra = true; dvander@769: extraItem = i; dvander@769: break; dvander@769: } dvander@769: drawItems[foundItems++].position = i; dvander@769: } dvander@769: } dvander@769: /* If there's no pagination, stop once the menu is full. */ dvander@769: if (pgn == MENU_NO_PAGINATION) dvander@769: { dvander@769: /* If we've filled up, then stop */ dvander@769: if (foundItems >= maxItems) dvander@769: { dvander@769: break; dvander@769: } dvander@769: } dvander@769: /* If we're descending and this is the first item, stop */ dvander@769: if (order == ItemOrder_Descending) dvander@769: { dvander@769: if (i == 0) dvander@769: { dvander@769: break; dvander@769: } dvander@769: i--; dvander@769: } dvander@769: /* If we're ascending and this is the last item, stop */ dvander@769: else if (order == ItemOrder_Ascending) dvander@769: { dvander@769: if (i >= totalItems - 1) dvander@769: { dvander@769: break; dvander@769: } dvander@769: i++; dvander@769: } dvander@769: } dvander@769: dvander@769: /* There were no items to draw! */ dvander@769: if (!foundItems) dvander@769: { dvander@776: display->DeleteThis(); dvander@769: return NULL; dvander@769: } dvander@769: dvander@769: /* Check initial buttons */ dvander@769: bool displayPrev = false; dvander@769: bool displayNext = false; dvander@769: if (foundExtra) dvander@769: { dvander@769: if (order == ItemOrder_Descending) dvander@769: { dvander@769: displayPrev = true; dvander@769: md.firstItem = extraItem; dvander@769: } else if (order == ItemOrder_Ascending) { dvander@769: displayNext = true; dvander@769: md.lastItem = extraItem; dvander@769: } dvander@769: } dvander@769: dvander@769: /** dvander@769: * If we're paginated, we have to find if there is another page. dvander@769: * Sadly, the only way to do this is to try drawing more items! dvander@769: */ dvander@769: if (pgn != MENU_NO_PAGINATION) dvander@769: { dvander@769: unsigned int lastItem = 0; dvander@769: ItemDrawInfo dr; dvander@769: /* Find the last feasible item to search from. */ dvander@769: if (order == ItemOrder_Descending) dvander@769: { dvander@769: lastItem = drawItems[0].position; dvander@769: if (lastItem >= totalItems - 1) dvander@769: { dvander@769: goto skip_search; dvander@769: } dvander@769: while (++lastItem < totalItems) dvander@769: { dvander@769: if (menu->GetItemInfo(lastItem, &dr) != NULL) dvander@769: { dvander@769: mh->OnMenuDrawItem(menu, client, lastItem, dr.style); dvander@769: if (IsSlotItem(display, dr.style)) dvander@769: { dvander@769: displayNext = true; dvander@769: md.lastItem = lastItem; dvander@769: break; dvander@769: } dvander@769: } dvander@769: } dvander@769: } else if (order == ItemOrder_Ascending) { dvander@769: lastItem = drawItems[0].position; dvander@769: if (lastItem == 0) dvander@769: { dvander@769: goto skip_search; dvander@769: } dvander@769: lastItem--; dvander@1004: while (lastItem != 0) dvander@769: { dvander@769: if (menu->GetItemInfo(lastItem, &dr) != NULL) dvander@769: { dvander@769: mh->OnMenuDrawItem(menu, client, lastItem, dr.style); dvander@769: if (IsSlotItem(display, dr.style)) dvander@769: { dvander@769: displayPrev = true; dvander@769: md.firstItem = lastItem; dvander@769: break; dvander@769: } dvander@769: } dvander@1004: lastItem--; dvander@769: } dvander@769: } dvander@769: } dvander@769: skip_search: dvander@769: dvander@769: /* Draw the item according to the order */ dvander@769: menu_slots_t *slots = md.slots; dvander@769: unsigned int position = 0; /* Keep track of the last position */ dvander@769: if (order == ItemOrder_Ascending) dvander@769: { dvander@769: for (unsigned int i=0; iOnMenuDisplayItem(menu, client, drawItems[i].position, &(dr.display)); dvander@769: if ((position = display->DrawItem(dr)) != 0) dvander@769: { dvander@769: slots[position].item = drawItems[i].position; dvander@769: slots[position].type = ItemSel_Item; dvander@769: } dvander@769: } dvander@769: } else if (order == ItemOrder_Descending) { dvander@769: unsigned int i = foundItems; dvander@769: /* NOTE: There will always be at least one item because dvander@769: * of the check earlier. dvander@769: */ dvander@769: while (i--) dvander@769: { dvander@769: ItemDrawInfo &dr = drawItems[i].draw; dvander@769: mh->OnMenuDisplayItem(menu, client, drawItems[i].position, &(dr.display)); dvander@769: if ((position = display->DrawItem(dr)) != 0) dvander@769: { dvander@769: slots[position].item = drawItems[i].position; dvander@769: slots[position].type = ItemSel_Item; dvander@769: } dvander@769: } dvander@769: } dvander@769: dvander@769: /* Now, we need to check if we need to add anything extra */ dvander@769: if (pgn != MENU_NO_PAGINATION) dvander@769: { dvander@785: bool canDrawDisabled = display->CanDrawItem(ITEMDRAW_DISABLED|ITEMDRAW_CONTROL); dvander@769: bool exitButton = menu->GetExitButton(); dvander@1005: bool exitBackButton = menu->GetExitBackButton(); dvander@769: char text[50]; dvander@769: dvander@769: /* Calculate how many items we are allowed for control stuff */ dvander@769: unsigned int padding = style->GetMaxPageItems() - maxItems; dvander@769: dvander@769: /* Add the number of available slots */ dvander@769: padding += (maxItems - foundItems); dvander@769: dvander@769: /* Someday, if we are able to re-enable this, we will be very lucky men. */ dvander@769: #if 0 dvander@769: if (!style->FeatureExists(MenuStyleFeature_ImplicitExit)) dvander@769: { dvander@769: #endif dvander@769: /* Even if we don't draw an exit button, we invalidate the slot. */ dvander@769: padding--; dvander@769: #if 0 dvander@769: } else { dvander@769: /* Otherwise, we don't draw anything and leave the slot available */ dvander@769: exitButton = false; dvander@769: } dvander@769: #endif dvander@769: dvander@769: /* Subtract two slots for the displayNext/displayPrev padding */ dvander@769: padding -= 2; dvander@769: dvander@1005: /* If we have an "Exit Back" button and the space to draw it, do so. */ dvander@1005: if (exitBackButton) dvander@1005: { dvander@1005: if (!displayPrev) dvander@1005: { dvander@1005: displayPrev = true; dvander@1005: } else { dvander@1005: exitBackButton = false; dvander@1005: } dvander@1005: } dvander@1005: dvander@769: /** dvander@769: * We allow next/prev to be undrawn if neither exists. dvander@769: * Thus, we only need padding if one of them will be drawn, dvander@769: * or the exit button will be drawn. dvander@769: */ dvander@769: ItemDrawInfo padItem(NULL, ITEMDRAW_SPACER); dvander@769: if (exitButton || (displayNext || displayPrev)) dvander@769: { dvander@790: /* If there are no control options, dvander@790: * Instead just pad with invisible slots. dvander@790: */ dvander@790: if (!displayPrev && !displayPrev) dvander@790: { dvander@790: padItem.style = ITEMDRAW_NOTEXT; dvander@790: } dvander@769: /* Add spacers so we can pad to the end */ dvander@769: for (unsigned int i=0; iDrawItem(padItem); dvander@769: slots[position].type = ItemSel_None; dvander@769: } dvander@769: } dvander@776: dvander@776: /* Put a fake spacer before control stuff, if possible */ dvander@797: if ((displayPrev || displayNext) || exitButton) dvander@776: { dvander@776: ItemDrawInfo draw("", ITEMDRAW_RAWLINE|ITEMDRAW_SPACER); dvander@776: display->DrawItem(draw); dvander@776: } dvander@769: dvander@776: ItemDrawInfo dr(text, 0); dvander@785: /** dvander@785: * If we have one or the other, we need to have spacers for both. dvander@785: */ dvander@785: if (displayPrev || displayNext) dvander@769: { dvander@785: /* PREVIOUS */ dvander@785: ItemDrawInfo padCtrlItem(NULL, ITEMDRAW_SPACER|ITEMDRAW_CONTROL); dvander@785: if (displayPrev || canDrawDisabled) dvander@785: { dvander@1005: if (exitBackButton) dvander@1005: { dvander@1005: CorePlayerTranslate(client, text, sizeof(text), "Back", NULL); dvander@1005: dr.style = ITEMDRAW_CONTROL; dvander@1005: position = display->DrawItem(dr); dvander@1005: slots[position].type = ItemSel_ExitBack; dvander@1005: } else { dvander@1005: CorePlayerTranslate(client, text, sizeof(text), "Previous", NULL); dvander@1005: dr.style = (displayPrev ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; dvander@1005: position = display->DrawItem(dr); dvander@1005: slots[position].type = ItemSel_Back; dvander@1005: } dvander@785: } else if (displayNext || exitButton) { dvander@785: /* If we can't display this, and there is an exit button, dvander@785: * we need to pad! dvander@785: */ dvander@785: position = display->DrawItem(padCtrlItem); dvander@785: slots[position].type = ItemSel_None; dvander@785: } dvander@785: dvander@785: /* NEXT */ dvander@785: if (displayNext || canDrawDisabled) dvander@785: { dvander@785: CorePlayerTranslate(client, text, sizeof(text), "Next", NULL); dvander@785: dr.style = (displayNext ? 0 : ITEMDRAW_DISABLED)|ITEMDRAW_CONTROL; dvander@785: position = display->DrawItem(dr); dvander@785: slots[position].type = ItemSel_Next; dvander@785: } else if (exitButton) { dvander@785: /* If we can't display this, dvander@785: * but there is an "exit" button, we need to pad! dvander@785: */ dvander@785: position = display->DrawItem(padCtrlItem); dvander@785: slots[position].type = ItemSel_None; dvander@785: } dvander@785: } else { dvander@785: /* Otherwise, bump to two slots! */ dvander@785: ItemDrawInfo numBump(NULL, ITEMDRAW_NOTEXT); dvander@785: position = display->DrawItem(numBump); dvander@769: slots[position].type = ItemSel_None; dvander@785: position = display->DrawItem(numBump); dvander@769: slots[position].type = ItemSel_None; dvander@769: } dvander@769: dvander@769: /* EXIT */ dvander@769: if (exitButton) dvander@769: { dvander@769: CorePlayerTranslate(client, text, sizeof(text), "Exit", NULL); dvander@785: dr.style = ITEMDRAW_CONTROL; dvander@769: position = display->DrawItem(dr); dvander@769: slots[position].type = ItemSel_Exit; dvander@769: } dvander@769: } dvander@769: dvander@769: /* Lastly, fill in any slots we could have missed */ dvander@769: for (unsigned int i = position + 1; i < 10; i++) dvander@769: { dvander@769: slots[i].type = ItemSel_None; dvander@769: } dvander@769: dvander@769: /* Do title stuff */ dvander@769: mh->OnMenuDisplay(menu, client, display); dvander@769: display->DrawTitle(menu->GetDefaultTitle(), true); dvander@769: dvander@769: return display; dvander@769: } dvander@769: dvander@769: IMenuStyle *MenuManager::GetDefaultStyle() dvander@769: { dvander@769: return m_pDefaultStyle; dvander@769: } dvander@769: dvander@877: IVoteMenuHandler *MenuManager::CreateVoteWrapper(IMenuHandler *mh) dvander@877: { dvander@877: VoteMenuHandler *vh = NULL; dvander@877: dvander@877: if (m_VoteHandlers.empty()) dvander@877: { dvander@877: vh = new VoteMenuHandler; dvander@877: } else { dvander@877: vh = m_VoteHandlers.front(); dvander@877: m_VoteHandlers.pop(); dvander@877: } dvander@877: dvander@877: vh->Reset(mh); dvander@877: dvander@877: return vh; dvander@877: } dvander@877: dvander@877: void MenuManager::ReleaseVoteWrapper(IVoteMenuHandler *mh) dvander@877: { dvander@877: if (mh == NULL) dvander@877: { dvander@877: return; dvander@877: } dvander@877: dvander@877: m_VoteHandlers.push((VoteMenuHandler *)mh); dvander@877: }