core/smn_menus.cpp
author David Anderson <dvander@alliedmods.net>
Wed Jun 06 06:04:16 2007 +0000 (2007-06-06)
changeset 883 f4eff9faf362
parent 879 f1e33b35f3b6
child 885 7767bebc6262
permissions -rw-r--r--
fixed inheritance not being used in the base menu style when removing clients from the watch list
     1 /**
     2  * vim: set ts=4 :
     3  * ===============================================================
     4  * SourceMod (C)2004-2007 AlliedModders LLC.  All rights reserved.
     5  * ===============================================================
     6  *
     7  * This file is not open source and may not be copied without explicit
     8  * written permission of AlliedModders LLC.  This file may not be redistributed 
     9  * in whole or significant part.
    10  * For information, see LICENSE.txt or http://www.sourcemod.net/license.php
    11  *
    12  * Version: $Id$
    13  */
    14 
    15 #include "sm_globals.h"
    16 #include <sh_stack.h>
    17 #include "MenuManager.h"
    18 #include "MenuStyle_Valve.h"
    19 #include "MenuStyle_Radio.h"
    20 #include "HandleSys.h"
    21 #include "PluginSys.h"
    22 
    23 #if defined CreateMenu
    24 #undef CreateMenu
    25 #endif
    26 
    27 /**
    28  * And God said, "let there be menus," and behold, there were menus.  
    29  * God saw the menus and they were good.  And the evening and the morning
    30  * were the third day.
    31  */
    32 
    33 enum MenuAction
    34 {
    35 	MenuAction_Start = (1<<0),		/**< A menu has been started (nothing passed) */
    36 	MenuAction_Display = (1<<1),	/**< A menu is about to be displayed (param1=client, param2=MenuPanel Handle) */
    37 	MenuAction_Select = (1<<2),		/**< An item was selected (param1=client, param2=item) */
    38 	MenuAction_Cancel = (1<<3),		/**< The menu was cancelled (param1=client, param2=item) */
    39 	MenuAction_End = (1<<4),		/**< A menu's display/selection cycle is complete (nothing passed). */
    40 	MenuAction_VoteEnd = (1<<5),	/**< (VOTE ONLY): A vote sequence has ended (param1=chosen item) */
    41 	MenuAction_VoteStart = (1<<6), 	/**< (VOTE ONLY): A vote sequence has started */
    42 };
    43 
    44 class CPanelHandler : public IMenuHandler
    45 {
    46 	friend class MenuNativeHelpers;
    47 public:
    48 	CPanelHandler()
    49 	{
    50 	}
    51 	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
    52 	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
    53 private:
    54 	IPluginFunction *m_pFunc;
    55 	IPlugin *m_pPlugin;
    56 };
    57 
    58 class CMenuHandler : public IMenuHandler
    59 {
    60 	friend class MenuNativeHelpers;
    61 public:
    62 	CMenuHandler(IPluginFunction *pBasic, int flags);
    63 public:
    64 	void OnMenuStart(IBaseMenu *menu);
    65 	void OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *display);
    66 	void OnMenuSelect(IBaseMenu *menu, int client, unsigned int item);
    67 	void OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason);
    68 	void OnMenuEnd(IBaseMenu *menu);
    69 	void OnMenuDestroy(IBaseMenu *menu);
    70 	void OnMenuVoteStart(IBaseMenu *menu);
    71 	void OnMenuVoteEnd(IBaseMenu *menu, unsigned int item);
    72 #if 0
    73 	void OnMenuDrawItem(IBaseMenu *menu, int client, unsigned int item, unsigned int &style);
    74 	void OnMenuDisplayItem(IBaseMenu *menu, int client, unsigned int item, const char **display);
    75 #endif
    76 private:
    77 	void DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2);
    78 private:
    79 	IPluginFunction *m_pBasic;
    80 	int m_Flags;
    81 };
    82 
    83 /**
    84  * GLOBAL CLASS FOR HELPERS
    85  */
    86 
    87 class MenuNativeHelpers : 
    88 	public SMGlobalClass,
    89 	public IHandleTypeDispatch,
    90 	public IPluginsListener
    91 {
    92 public:
    93 	virtual void OnSourceModAllInitialized()
    94 	{
    95 		m_PanelType = g_HandleSys.CreateType("IMenuPanel", this, 0, NULL, NULL, g_pCoreIdent, NULL);
    96 		g_PluginSys.AddPluginsListener(this);
    97 	}
    98 
    99 	virtual void OnSourceModShutdown()
   100 	{
   101 		g_HandleSys.RemoveType(m_PanelType, g_pCoreIdent);
   102 
   103 		while (!m_FreePanelHandlers.empty())
   104 		{
   105 			delete m_FreePanelHandlers.front();
   106 			m_FreePanelHandlers.pop();
   107 		}
   108 
   109 		while (!m_FreeMenuHandlers.empty())
   110 		{
   111 			delete m_FreeMenuHandlers.front();
   112 			m_FreeMenuHandlers.pop();
   113 		}
   114 	}
   115 
   116 	virtual void OnHandleDestroy(HandleType_t type, void *object)
   117 	{
   118 		IMenuPanel *panel = (IMenuPanel *)object;
   119 		panel->DeleteThis();
   120 	}
   121 
   122 	/**
   123 	 *   It is extremely important that unloaded plugins don't crash.
   124 	 * Thus, if a plugin unloads, we run through every handler we have.
   125 	 * This means we do almost no runtime work for keeping track of
   126 	 * our panel handlers (we don't have to store a list of the running 
   127 	 * ones), but when push comes to shove, we have to scan them all
   128 	 * in case any of them are active.
   129 	 */
   130 	virtual void OnPluginUnloaded(IPlugin *plugin)
   131 	{
   132 		for (size_t i = 0; i < m_PanelHandlers.size(); i++)
   133 		{
   134 			if (m_PanelHandlers[i]->m_pPlugin == plugin)
   135 			{
   136 				m_PanelHandlers[i]->m_pPlugin = NULL;
   137 				m_PanelHandlers[i]->m_pFunc = NULL;
   138 			}
   139 		}
   140 	}
   141 
   142 	inline HandleType_t GetPanelType()
   143 	{
   144 		return m_PanelType;
   145 	}
   146 
   147 	CPanelHandler *GetPanelHandler(IPluginFunction *pFunction)
   148 	{
   149 		CPanelHandler *handler;
   150 		if (m_FreePanelHandlers.empty())
   151 		{
   152 			handler = new CPanelHandler;
   153 			m_PanelHandlers.push_back(handler);
   154 		} else {
   155 			handler = m_FreePanelHandlers.front();
   156 			m_FreePanelHandlers.pop();
   157 		}
   158 		handler->m_pFunc = pFunction;
   159 		handler->m_pPlugin = g_PluginSys.GetPluginByCtx(pFunction->GetParentContext()->GetContext());
   160 		return handler;
   161 	}
   162 
   163 	void FreePanelHandler(CPanelHandler *handler)
   164 	{
   165 		handler->m_pFunc = NULL;
   166 		handler->m_pPlugin = NULL;
   167 		m_FreePanelHandlers.push(handler);
   168 	}
   169 
   170 	CMenuHandler *GetMenuHandler(IPluginFunction *pFunction, int flags)
   171 	{
   172 		CMenuHandler *handler;
   173 		if (m_FreeMenuHandlers.empty())
   174 		{
   175 			handler = new CMenuHandler(pFunction, flags);
   176 		} else {
   177 			handler = m_FreeMenuHandlers.front();
   178 			m_FreeMenuHandlers.pop();
   179 			handler->m_pBasic = pFunction;
   180 			handler->m_Flags = flags;
   181 		}
   182 		return handler;
   183 	}
   184 
   185 	void FreeMenuHandler(CMenuHandler *handler)
   186 	{
   187 		m_FreeMenuHandlers.push(handler);
   188 	}
   189 
   190 private:
   191 	HandleType_t m_PanelType;
   192 	CStack<CPanelHandler *> m_FreePanelHandlers;
   193 	CStack<CMenuHandler *> m_FreeMenuHandlers;
   194 	CVector<CPanelHandler *> m_PanelHandlers;
   195 } g_MenuHelpers;
   196 
   197 /**
   198  * BASIC PANEL HANDLER WRAPPER
   199  */
   200 
   201 void CPanelHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
   202 {
   203 	if (m_pFunc)
   204 	{
   205 		m_pFunc->PushCell(BAD_HANDLE);
   206 		m_pFunc->PushCell(MenuAction_Cancel);
   207 		m_pFunc->PushCell(client);
   208 		m_pFunc->PushCell(reason);
   209 		m_pFunc->Execute(NULL);
   210 	}
   211 	g_MenuHelpers.FreePanelHandler(this);
   212 }
   213 
   214 void CPanelHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   215 {
   216 	if (m_pFunc)
   217 	{
   218 		m_pFunc->PushCell(BAD_HANDLE);
   219 		m_pFunc->PushCell(MenuAction_Select);
   220 		m_pFunc->PushCell(client);
   221 		m_pFunc->PushCell(item);
   222 		m_pFunc->Execute(NULL);
   223 	}
   224 	g_MenuHelpers.FreePanelHandler(this);
   225 }
   226 
   227 /**
   228  * MENU HANDLER WRAPPER
   229  */
   230 CMenuHandler::CMenuHandler(IPluginFunction *pBasic, int flags) : 
   231 	m_pBasic(pBasic), m_Flags(flags)
   232 {
   233 	/* :TODO: We can probably cache the handle ahead of time */
   234 }
   235 
   236 void CMenuHandler::OnMenuStart(IBaseMenu *menu)
   237 {
   238 	if ((m_Flags & (int)MenuAction_Start) == (int)MenuAction_Start)
   239 	{
   240 		DoAction(menu, MenuAction_Start, 0, 0);
   241 	}
   242 }
   243 
   244 void CMenuHandler::OnMenuDisplay(IBaseMenu *menu, int client, IMenuPanel *panel)
   245 {
   246 	if ((m_Flags & (int)MenuAction_Display) == (int)MenuAction_Display)
   247 	{
   248 		HandleSecurity sec;
   249 		sec.pIdentity = m_pBasic->GetParentContext()->GetIdentity();
   250 		sec.pOwner = g_pCoreIdent;
   251 	
   252 		HandleAccess access;
   253 		g_HandleSys.InitAccessDefaults(NULL, &access);
   254 		access.access[HandleAccess_Delete] = HANDLE_RESTRICT_IDENTITY|HANDLE_RESTRICT_OWNER;
   255 
   256 		Handle_t hndl =  g_HandleSys.CreateHandleEx(g_MenuHelpers.GetPanelType(), panel, &sec, &access, NULL);
   257 
   258 		DoAction(menu, MenuAction_Display, client, hndl);
   259 
   260 		g_HandleSys.FreeHandle(hndl, &sec);
   261 	}
   262 }
   263 
   264 void CMenuHandler::OnMenuSelect(IBaseMenu *menu, int client, unsigned int item)
   265 {
   266 	DoAction(menu, MenuAction_Select, client, item);
   267 }
   268 
   269 void CMenuHandler::OnMenuCancel(IBaseMenu *menu, int client, MenuCancelReason reason)
   270 {
   271 	DoAction(menu, MenuAction_Cancel, client, (cell_t)reason);
   272 }
   273 
   274 void CMenuHandler::OnMenuEnd(IBaseMenu *menu)
   275 {
   276 	DoAction(menu, MenuAction_End, 0, 0);
   277 }
   278 
   279 void CMenuHandler::OnMenuDestroy(IBaseMenu *menu)
   280 {
   281 	g_MenuHelpers.FreeMenuHandler(this);
   282 }
   283 
   284 void CMenuHandler::OnMenuVoteStart(IBaseMenu *menu)
   285 {
   286 	DoAction(menu, MenuAction_VoteStart, 0, 0);
   287 }
   288 
   289 void CMenuHandler::OnMenuVoteEnd(IBaseMenu *menu, unsigned int item)
   290 {
   291 	DoAction(menu, MenuAction_VoteEnd, item, 0);
   292 }
   293 
   294 void CMenuHandler::DoAction(IBaseMenu *menu, MenuAction action, cell_t param1, cell_t param2)
   295 {
   296 	m_pBasic->PushCell(menu->GetHandle());
   297 	m_pBasic->PushCell((cell_t)action);
   298 	m_pBasic->PushCell(param1);
   299 	m_pBasic->PushCell(param2);
   300 	m_pBasic->Execute(NULL);
   301 }
   302 
   303 /**
   304  * INLINE FUNCTIONS FOR NATIVES
   305  */
   306 
   307 inline Handle_t MakePanelHandle(IMenuPanel *panel, IPluginContext *pContext)
   308 {
   309 	return g_HandleSys.CreateHandle(g_MenuHelpers.GetPanelType(), panel, pContext->GetIdentity(), g_pCoreIdent, NULL);
   310 }
   311 
   312 inline HandleError ReadPanelHandle(Handle_t hndl, IMenuPanel **panel)
   313 {
   314 	HandleSecurity sec;
   315 	sec.pIdentity = g_pCoreIdent;
   316 	sec.pOwner = NULL;
   317 	return g_HandleSys.ReadHandle(hndl, g_MenuHelpers.GetPanelType(), &sec, (void **)panel);
   318 }
   319 
   320 inline IMenuStyle *GetStyleFromCell(cell_t cell)
   321 {
   322 	enum MenuStyle
   323 	{
   324 		MenuStyle_Default = 0,		/**< The "default" menu style for the mod */
   325 		MenuStyle_Valve = 1,		/**< The Valve provided menu style (Used on HL2DM) */
   326 		MenuStyle_Radio = 2,		/**< The simpler menu style commonly used on CS:S */
   327 	};
   328 
   329 	if (cell == MenuStyle_Valve)
   330 	{
   331 		return &g_ValveMenuStyle;
   332 	} else if (cell == MenuStyle_Radio
   333 			   && g_RadioMenuStyle.IsSupported())
   334 	{
   335 		return &g_RadioMenuStyle;
   336 	}
   337 
   338 	return g_Menus.GetDefaultStyle();
   339 }
   340 
   341 /***********************************
   342  **** NATIVE DEFINITIONS ***********
   343  ***********************************/
   344 
   345 static cell_t CreateMenu(IPluginContext *pContext, const cell_t *params)
   346 {
   347 	IMenuStyle *style = g_Menus.GetDefaultStyle();
   348 	IPluginFunction *pFunction;
   349 
   350 	if ((pFunction=pContext->GetFunctionById(params[1])) == NULL)
   351 	{
   352 		return pContext->ThrowNativeError("Function id %x is invalid", params[1]);
   353 	}
   354 
   355 	CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[2]);
   356 	IBaseMenu *menu = style->CreateMenu(handler, pContext->GetIdentity());
   357 
   358 	Handle_t hndl = menu->GetHandle();
   359 	if (!hndl)
   360 	{
   361 		menu->Destroy();
   362 		return BAD_HANDLE;
   363 	}
   364 
   365 	return hndl;
   366 }
   367 
   368 static cell_t DisplayMenu(IPluginContext *pContext, const cell_t *params)
   369 {
   370 	Handle_t hndl = (Handle_t)params[1];
   371 	HandleError err;
   372 	IBaseMenu *menu;
   373 
   374 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   375 	{
   376 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   377 	}
   378 
   379 	return menu->Display(params[2], params[3]) ? 1 : 0;
   380 }
   381 
   382 static cell_t VoteMenu(IPluginContext *pContext, const cell_t *params)
   383 {
   384 	Handle_t hndl = (Handle_t)params[1];
   385 	HandleError err;
   386 	IBaseMenu *menu;
   387 
   388 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   389 	{
   390 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   391 	}
   392 
   393 	cell_t *addr;
   394 	pContext->LocalToPhysAddr(params[2], &addr);
   395 
   396 	return menu->BroadcastVote(addr, params[3], params[4]) ? 1 : 0;
   397 }
   398 
   399 static cell_t AddMenuItem(IPluginContext *pContext, const cell_t *params)
   400 {
   401 	Handle_t hndl = (Handle_t)params[1];
   402 	HandleError err;
   403 	IBaseMenu *menu;
   404 
   405 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   406 	{
   407 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   408 	}
   409 
   410 	char *info;
   411 	ItemDrawInfo dr;
   412 
   413 	pContext->LocalToString(params[2], &info);
   414 	pContext->LocalToString(params[3], (char **)&dr.display);
   415 	dr.style = params[4];
   416 
   417 	return menu->AppendItem(info, dr) ? 1 : 0;
   418 }
   419 
   420 static cell_t InsertMenuItem(IPluginContext *pContext, const cell_t *params)
   421 {
   422 	Handle_t hndl = (Handle_t)params[1];
   423 	HandleError err;
   424 	IBaseMenu *menu;
   425 
   426 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   427 	{
   428 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   429 	}
   430 
   431 	char *info;
   432 	ItemDrawInfo dr;
   433 
   434 	pContext->LocalToString(params[3], &info);
   435 	pContext->LocalToString(params[4], (char **)&dr.display);
   436 	dr.style = params[5];
   437 
   438 	return menu->InsertItem(params[2], info, dr) ? 1 : 0;
   439 }
   440 
   441 static cell_t RemoveMenuItem(IPluginContext *pContext, const cell_t *params)
   442 {
   443 	Handle_t hndl = (Handle_t)params[1];
   444 	HandleError err;
   445 	IBaseMenu *menu;
   446 
   447 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   448 	{
   449 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   450 	}
   451 
   452 	return menu->RemoveItem(params[2]) ? 1 : 0;
   453 }
   454 
   455 static cell_t RemoveAllMenuItems(IPluginContext *pContext, const cell_t *params)
   456 {
   457 	Handle_t hndl = (Handle_t)params[1];
   458 	HandleError err;
   459 	IBaseMenu *menu;
   460 
   461 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   462 	{
   463 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   464 	}
   465 
   466 	menu->RemoveAllItems();
   467 
   468 	return 1;
   469 }
   470 
   471 static cell_t GetMenuItem(IPluginContext *pContext, const cell_t *params)
   472 {
   473 	Handle_t hndl = (Handle_t)params[1];
   474 	HandleError err;
   475 	IBaseMenu *menu;
   476 
   477 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   478 	{
   479 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   480 	}
   481 
   482 	ItemDrawInfo dr;
   483 	const char *info;
   484 
   485 	if ((info=menu->GetItemInfo(params[2], &dr)) == NULL)
   486 	{
   487 		return 0;
   488 	}
   489 
   490 	pContext->StringToLocalUTF8(params[3], params[4], info, NULL);
   491 	pContext->StringToLocalUTF8(params[6], params[7], dr.display ? dr.display : "", NULL);
   492 
   493 	cell_t *addr;
   494 	pContext->LocalToPhysAddr(params[5], &addr);
   495 	*addr = dr.style;
   496 
   497 	return 1;
   498 }
   499 
   500 static cell_t SetMenuPagination(IPluginContext *pContext, const cell_t *params)
   501 {
   502 	Handle_t hndl = (Handle_t)params[1];
   503 	HandleError err;
   504 	IBaseMenu *menu;
   505 
   506 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   507 	{
   508 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   509 	}
   510 
   511 	return menu->SetPagination(params[2]) ? 1 : 0;
   512 }
   513 
   514 static cell_t GetMenuPagination(IPluginContext *pContext, const cell_t *params)
   515 {
   516 	Handle_t hndl = (Handle_t)params[1];
   517 	HandleError err;
   518 	IBaseMenu *menu;
   519 
   520 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   521 	{
   522 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   523 	}
   524 
   525 	return menu->GetPagination();
   526 }
   527 
   528 static cell_t GetMenuItemCount(IPluginContext *pContext, const cell_t *params)
   529 {
   530 	Handle_t hndl = (Handle_t)params[1];
   531 	HandleError err;
   532 	IBaseMenu *menu;
   533 
   534 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   535 	{
   536 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   537 	}
   538 
   539 	return menu->GetItemCount();
   540 }
   541 
   542 static cell_t SetMenuTitle(IPluginContext *pContext, const cell_t *params)
   543 {
   544 	Handle_t hndl = (Handle_t)params[1];
   545 	HandleError err;
   546 	IBaseMenu *menu;
   547 
   548 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   549 	{
   550 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   551 	}
   552 
   553 	char buffer[1024];
   554 	g_SourceMod.FormatString(buffer, sizeof(buffer), pContext, params, 2);
   555 
   556 	menu->SetDefaultTitle(buffer);
   557 
   558 	return 1;
   559 }
   560 
   561 static cell_t CreatePanelFromMenu(IPluginContext *pContext, const cell_t *params)
   562 {
   563 	Handle_t hndl = (Handle_t)params[1];
   564 	HandleError err;
   565 	IBaseMenu *menu;
   566 
   567 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   568 	{
   569 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   570 	}
   571 
   572 	IMenuPanel *panel = menu->CreatePanel();
   573 	hndl = MakePanelHandle(panel, pContext);
   574 	if (!hndl)
   575 	{
   576 		panel->DeleteThis();
   577 	}
   578 
   579 	return hndl;
   580 }
   581 
   582 static cell_t GetMenuExitButton(IPluginContext *pContext, const cell_t *params)
   583 {
   584 	Handle_t hndl = (Handle_t)params[1];
   585 	HandleError err;
   586 	IBaseMenu *menu;
   587 
   588 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   589 	{
   590 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   591 	}
   592 
   593 	return menu->GetExitButton() ? 1 : 0;
   594 }
   595 
   596 static cell_t SetMenuExitButton(IPluginContext *pContext, const cell_t *params)
   597 {
   598 	Handle_t hndl = (Handle_t)params[1];
   599 	HandleError err;
   600 	IBaseMenu *menu;
   601 
   602 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   603 	{
   604 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   605 	}
   606 
   607 	return menu->SetExitButton(params[2] ? true : false) ? 1 : 0;
   608 }
   609 
   610 static cell_t CancelMenu(IPluginContext *pContext, const cell_t *params)
   611 {
   612 	Handle_t hndl = (Handle_t)params[1];
   613 	HandleError err;
   614 	IBaseMenu *menu;
   615 
   616 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   617 	{
   618 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   619 	}
   620 
   621 	menu->Cancel();
   622 
   623 	return 1;
   624 }
   625 
   626 static cell_t GetMenuStyle(IPluginContext *pContext, const cell_t *params)
   627 {
   628 	Handle_t hndl = (Handle_t)params[1];
   629 	HandleError err;
   630 	IBaseMenu *menu;
   631 
   632 	if ((err=g_Menus.ReadMenuHandle(params[1], &menu)) != HandleError_None)
   633 	{
   634 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   635 	}
   636 
   637 	return menu->GetDrawStyle()->GetHandle();
   638 }
   639 
   640 static cell_t GetMenuStyleHandle(IPluginContext *pContext, const cell_t *params)
   641 {
   642 	IMenuStyle *style = GetStyleFromCell(params[1]);
   643 	if (!style)
   644 	{
   645 		return BAD_HANDLE;
   646 	}
   647 
   648 	return style->GetHandle();
   649 }
   650 
   651 static cell_t CreatePanel(IPluginContext *pContext, const cell_t *params)
   652 {
   653 	Handle_t hndl = (Handle_t)params[1];
   654 	HandleError err;
   655 	IMenuStyle *style;
   656 
   657 	if (hndl != 0)
   658 	{
   659 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   660 		{
   661 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   662 		}
   663 	} else {
   664 		style = g_Menus.GetDefaultStyle();
   665 	}
   666 
   667 	IMenuPanel *panel = style->CreatePanel();
   668 
   669 	hndl = MakePanelHandle(panel, pContext);
   670 	if (!hndl)
   671 	{
   672 		panel->DeleteThis();
   673 		return BAD_HANDLE;
   674 	}
   675 
   676 	return hndl;
   677 }
   678 
   679 static cell_t CreateMenuEx(IPluginContext *pContext, const cell_t *params)
   680 {
   681 	Handle_t hndl = (Handle_t)params[1];
   682 	HandleError err;
   683 	IMenuStyle *style;
   684 
   685 	if (hndl != 0)
   686 	{
   687 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   688 		{
   689 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   690 		}
   691 	} else {
   692 		style = g_Menus.GetDefaultStyle();
   693 	}
   694 
   695 	IPluginFunction *pFunction;
   696 	if ((pFunction=pContext->GetFunctionById(params[2])) == NULL)
   697 	{
   698 		return pContext->ThrowNativeError("Function id %x is invalid", params[2]);
   699 	}
   700 
   701 	CMenuHandler *handler = g_MenuHelpers.GetMenuHandler(pFunction, params[3]);
   702 
   703 	IBaseMenu *pMenu = style->CreateMenu(handler, pContext->GetIdentity());
   704 	hndl = pMenu->GetHandle();
   705 	if (!hndl)
   706 	{
   707 		pMenu->Destroy();
   708 		return BAD_HANDLE;
   709 	}
   710 
   711 	return hndl;
   712 }
   713 
   714 static cell_t GetClientMenu(IPluginContext *pContext, const cell_t *params)
   715 {
   716 	Handle_t hndl = (Handle_t)params[2];
   717 	HandleError err;
   718 	IMenuStyle *style;
   719 
   720 	if (hndl != 0)
   721 	{
   722 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   723 		{
   724 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   725 		}
   726 	} else {
   727 		style = g_Menus.GetDefaultStyle();
   728 	}
   729 
   730 	return style->GetClientMenu(params[1], NULL);
   731 }
   732 
   733 static cell_t CancelClientMenu(IPluginContext *pContext, const cell_t *params)
   734 {
   735 	Handle_t hndl = (Handle_t)params[3];
   736 	HandleError err;
   737 	IMenuStyle *style;
   738 
   739 	if (hndl != 0)
   740 	{
   741 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   742 		{
   743 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   744 		}
   745 	} else {
   746 		style = g_Menus.GetDefaultStyle();
   747 	}
   748 
   749 	return style->CancelClientMenu(params[1], params[2] ? true : false) ? 1 : 0;
   750 }
   751 
   752 static cell_t GetMaxPageItems(IPluginContext *pContext, const cell_t *params)
   753 {
   754 	Handle_t hndl = (Handle_t)params[1];
   755 	HandleError err;
   756 	IMenuStyle *style;
   757 
   758 	if (hndl != 0)
   759 	{
   760 		if ((err=g_Menus.ReadStyleHandle(params[1], &style)) != HandleError_None)
   761 		{
   762 			return pContext->ThrowNativeError("MenuStyle handle %x is invalid (error %d)", hndl, err);
   763 		}
   764 	} else {
   765 		style = g_Menus.GetDefaultStyle();
   766 	}
   767 
   768 	return style->GetMaxPageItems();
   769 }
   770 
   771 static cell_t GetPanelStyle(IPluginContext *pContext, const cell_t *params)
   772 {
   773 	Handle_t hndl = (Handle_t)params[1];
   774 	HandleError err;
   775 	IMenuPanel *panel;
   776 
   777 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   778 	{
   779 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   780 	}
   781 
   782 	return panel->GetParentStyle()->GetHandle();
   783 }
   784 
   785 static cell_t SetPanelTitle(IPluginContext *pContext, const cell_t *params)
   786 {
   787 	Handle_t hndl = (Handle_t)params[1];
   788 	HandleError err;
   789 	IMenuPanel *panel;
   790 
   791 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   792 	{
   793 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   794 	}
   795 
   796 	char *text;
   797 	pContext->LocalToString(params[2], &text);
   798 
   799 	panel->DrawTitle(text, params[3] ? true : false);
   800 
   801 	return 1;
   802 }
   803 
   804 static cell_t DrawPanelItem(IPluginContext *pContext, const cell_t *params)
   805 {
   806 	Handle_t hndl = (Handle_t)params[1];
   807 	HandleError err;
   808 	IMenuPanel *panel;
   809 
   810 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   811 	{
   812 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   813 	}
   814 
   815 	ItemDrawInfo dr;
   816 	pContext->LocalToString(params[2], (char **)&dr.display);
   817 	dr.style = params[3];
   818 
   819 	return panel->DrawItem(dr);
   820 }
   821 
   822 static cell_t DrawPanelText(IPluginContext *pContext, const cell_t *params)
   823 {
   824 	Handle_t hndl = (Handle_t)params[1];
   825 	HandleError err;
   826 	IMenuPanel *panel;
   827 
   828 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   829 	{
   830 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   831 	}
   832 
   833 	char *text;
   834 	pContext->LocalToString(params[2], &text);
   835 
   836 	return panel->DrawRawLine(text) ? 1 : 0;
   837 }
   838 
   839 static cell_t CanPanelDrawFlags(IPluginContext *pContext, const cell_t *params)
   840 {
   841 	Handle_t hndl = (Handle_t)params[1];
   842 	HandleError err;
   843 	IMenuPanel *panel;
   844 
   845 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   846 	{
   847 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   848 	}
   849 
   850 	return panel->CanDrawItem(params[2]);
   851 }
   852 
   853 static cell_t SendPanelToClient(IPluginContext *pContext, const cell_t *params)
   854 {
   855 	Handle_t hndl = (Handle_t)params[1];
   856 	HandleError err;
   857 	IMenuPanel *panel;
   858 
   859 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   860 	{
   861 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   862 	}
   863 
   864 	IPluginFunction *pFunction;
   865 	if ((pFunction=pContext->GetFunctionById(params[3])) == NULL)
   866 	{
   867 		return pContext->ThrowNativeError("Function id %x is invalid", params[3]);
   868 	}
   869 
   870 	CPanelHandler *handler = g_MenuHelpers.GetPanelHandler(pFunction);
   871 	if (!panel->SendDisplay(params[2], handler, params[4]))
   872 	{
   873 		g_MenuHelpers.FreePanelHandler(handler);
   874 	}
   875 
   876 	return 1;
   877 }
   878 
   879 static cell_t SetPanelKeys(IPluginContext *pContext, const cell_t *params)
   880 {
   881 	Handle_t hndl = (Handle_t)params[1];
   882 	HandleError err;
   883 	IMenuPanel *panel;
   884 
   885 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   886 	{
   887 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   888 	}
   889 
   890 	return panel->SetSelectableKeys(params[2]);
   891 }
   892 
   893 static cell_t GetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
   894 {
   895 	Handle_t hndl = (Handle_t)params[1];
   896 	HandleError err;
   897 	IMenuPanel *panel;
   898 
   899 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   900 	{
   901 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   902 	}
   903 
   904 	return panel->GetCurrentKey();
   905 }
   906 
   907 static cell_t SetPanelCurrentKey(IPluginContext *pContext, const cell_t *params)
   908 {
   909 	Handle_t hndl = (Handle_t)params[1];
   910 	HandleError err;
   911 	IMenuPanel *panel;
   912 
   913 	if ((err=ReadPanelHandle(hndl, &panel)) != HandleError_None)
   914 	{
   915 		return pContext->ThrowNativeError("Menu handle %x is invalid (error %d)", hndl, err);
   916 	}
   917 
   918 	return panel->SetCurrentKey(params[2]) ? 1 : 0;
   919 }
   920 
   921 REGISTER_NATIVES(menuNatives)
   922 {
   923 	{"AddMenuItem",				AddMenuItem},
   924 	{"CanPanelDrawFlags",		CanPanelDrawFlags},
   925 	{"CancelClientMenu",		CancelClientMenu},
   926 	{"CancelMenu",				CancelMenu},
   927 	{"CreateMenu",				CreateMenu},
   928 	{"CreateMenuEx",			CreateMenuEx},
   929 	{"CreatePanel",				CreatePanel},
   930 	{"CreatePanelFromMenu",		CreatePanelFromMenu},
   931 	{"DisplayMenu",				DisplayMenu},
   932 	{"DrawPanelItem",			DrawPanelItem},
   933 	{"DrawPanelText",			DrawPanelText},
   934 	{"GetClientMenu",			GetClientMenu},
   935 	{"GetMaxPageItems",			GetMaxPageItems},
   936 	{"GetMenuExitButton",		GetMenuExitButton},
   937 	{"GetMenuItem",				GetMenuItem},
   938 	{"GetMenuItemCount",		GetMenuItemCount},
   939 	{"GetMenuPagination",		GetMenuPagination},
   940 	{"GetMenuStyle",			GetMenuStyle},
   941 	{"GetMenuStyleHandle",		GetMenuStyleHandle},
   942 	{"GetPanelCurrentKey",		GetPanelCurrentKey},
   943 	{"GetPanelStyle",			GetPanelStyle},
   944 	{"InsertMenuItem",			InsertMenuItem},
   945 	{"RemoveAllMenuItems",		RemoveAllMenuItems},
   946 	{"RemoveMenuItem",			RemoveMenuItem},
   947 	{"SendPanelToClient",		SendPanelToClient},
   948 	{"SetMenuExitButton",		SetMenuExitButton},
   949 	{"SetMenuPagination",		SetMenuPagination},
   950 	{"SetMenuTitle",			SetMenuTitle},
   951 	{"SetPanelCurrentKey",		SetPanelCurrentKey},
   952 	{"SetPanelTitle",			SetPanelTitle},
   953 	{"SetPanelKeys",			SetPanelKeys},
   954 	{"VoteMenu",				VoteMenu},
   955 	{NULL,						NULL},
   956 };