Implement menu_create "ml" param to allow menu title/item to be looked up as multilingual key (#593)

* Clean up menu_create() internal code

No code changes. Just modernizing code a little and tidying up things.

* Implement menu_create() "ml" param

* Include newmenu.inc to VS project files

* Adjust documentation

* Put back the quote in the log error message.
This commit is contained in:
Vincent Herbet 2018-09-28 16:46:52 +02:00 committed by GitHub
parent b4768a3d1d
commit 8717ffe07c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 75 additions and 33 deletions

View File

@ -457,6 +457,7 @@ md -p JIT 2>NUL
<None Include="..\..\plugins\include\cvars.inc" />
<None Include="..\..\plugins\include\datapack.inc" />
<None Include="..\..\plugins\include\gameconfig.inc" />
<None Include="..\..\plugins\include\newmenus.inc" />
<None Include="..\..\plugins\include\string_const.inc" />
<None Include="..\..\plugins\include\string_stocks.inc" />
<None Include="..\..\plugins\include\textparse_ini.inc" />

View File

@ -54,7 +54,7 @@
</Filter>
<Filter Include="ReSDK\engine">
<UniqueIdentifier>{04fab577-6f56-40d0-8f69-7ce1b8bf3bb9}</UniqueIdentifier>
</Filter>
</Filter>
<Filter Include="Third Party\UTF8Rewind">
<UniqueIdentifier>{270f3524-564f-4154-bb35-242a6faac09e}</UniqueIdentifier>
</Filter>
@ -693,6 +693,9 @@
<None Include="..\..\plugins\include\string_stocks.inc">
<Filter>Pawn Includes</Filter>
</None>
<None Include="..\..\plugins\include\newmenus.inc">
<Filter>Pawn Includes</Filter>
</None>
</ItemGroup>
<ItemGroup>
<Object Include="..\Jit\helpers-x86.obj">

View File

@ -10,6 +10,7 @@
#include "amxmodx.h"
#include "CMenu.h"
#include "newmenus.h"
#include "format.h"
ke::Vector<Menu *> g_NewMenus;
CStack<int> g_MenuFreeStack;
@ -90,9 +91,9 @@ bool CloseNewMenus(CPlayer *pPlayer)
return true;
}
Menu::Menu(const char *title, AMX *amx, int fid) : m_Title(title), m_ItemColor("\\r"),
Menu::Menu(const char *title, AMX *amx, int fid, bool use_ml) : m_Title(title), m_ItemColor("\\r"),
m_NeverExit(false), m_AutoColors(g_coloredmenus), thisId(0), func(fid),
isDestroying(false), pageCallback(-1), showPageNumber(true), items_per_page(7)
isDestroying(false), pageCallback(-1), showPageNumber(true), useMultilingual(use_ml), amx(amx), items_per_page(7)
{
CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx);
menuId = g_menucmds.registerMenuId(title, amx);
@ -356,18 +357,32 @@ const char *Menu::GetTextString(int player, page_t page, int &keys)
m_Text = nullptr;
auto title = m_Title.chars();
if (this->useMultilingual)
{
const auto language = playerlang(player);
const auto definition = translate(this->amx, language, title);
if (definition)
{
title = definition;
}
}
char buffer[255];
if (showPageNumber && items_per_page && (pages != 1))
{
if (m_AutoColors)
ke::SafeSprintf(buffer, sizeof(buffer), "\\y%s %d/%d\n\\w\n", m_Title.chars(), page + 1, pages);
ke::SafeSprintf(buffer, sizeof(buffer), "\\y%s %d/%d\n\\w\n", title, page + 1, pages);
else
ke::SafeSprintf(buffer, sizeof(buffer), "%s %d/%d\n\n", m_Title.chars(), page + 1, pages);
ke::SafeSprintf(buffer, sizeof(buffer), "%s %d/%d\n\n", title, page + 1, pages);
} else {
if (m_AutoColors)
ke::SafeSprintf(buffer, sizeof(buffer), "\\y%s\n\\w\n", m_Title.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "\\y%s\n\\w\n", title);
else
ke::SafeSprintf(buffer, sizeof(buffer), "%s\n\n", m_Title.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "%s\n\n", title);
}
m_Text = m_Text + buffer;
@ -462,24 +477,37 @@ const char *Menu::GetTextString(int player, page_t page, int &keys)
option_display = 0;
}
auto itemName = pItem->name.chars();
if (this->useMultilingual)
{
const auto language = playerlang(player);
const auto definition = translate(this->amx, language, itemName);
if (definition)
{
itemName = definition;
}
}
if (pItem->isBlank)
{
ke::SafeSprintf(buffer, sizeof(buffer), "%s\n", pItem->name.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "%s\n", itemName);
}
else if (enabled)
{
if (m_AutoColors)
{
ke::SafeSprintf(buffer, sizeof(buffer), "%s%d.\\w %s\n", m_ItemColor.chars(),option_display, pItem->name.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "%s%d.\\w %s\n", m_ItemColor.chars(),option_display, itemName);
} else {
ke::SafeSprintf(buffer, sizeof(buffer), "%d. %s\n", option_display, pItem->name.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "%d. %s\n", option_display, itemName);
}
} else {
if (m_AutoColors)
{
ke::SafeSprintf(buffer, sizeof(buffer), "\\d%d. %s\n\\w", option_display, pItem->name.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "\\d%d. %s\n\\w", option_display, itemName);
} else {
ke::SafeSprintf(buffer, sizeof(buffer), "#. %s\n", pItem->name.chars());
ke::SafeSprintf(buffer, sizeof(buffer), "#. %s\n", itemName);
}
}
slots++;
@ -620,38 +648,45 @@ const char *Menu::GetTextString(int player, page_t page, int &keys)
LogError(amx, AMX_ERR_NATIVE, "Invalid menu id %d(%d)", p, g_NewMenus.length()); \
return 0; }
//Makes a new menu handle (-1 for failure)
//native csdm_makemenu(title[]);
// native menu_create(const title[], const handler[], bool:ml = false);
static cell AMX_NATIVE_CALL menu_create(AMX *amx, cell *params)
{
int len;
char *title = get_amxstring(amx, params[1], 0, len);
validate_menu_text(title);
char *handler = get_amxstring(amx, params[2], 1, len);
enum args { arg_count, arg_title, arg_handler, arg_ml };
int func = registerSPForwardByName(amx, handler, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
int length;
const auto title = get_amxstring(amx, params[arg_title], 0, length);
const auto handler = get_amxstring(amx, params[arg_handler], 1, length);
const auto callback = registerSPForwardByName(amx, handler, FP_CELL, FP_CELL, FP_CELL, FP_DONE);
if (func == -1)
if (callback == -1)
{
LogError(amx, AMX_ERR_NOTFOUND, "Invalid function \"%s\"", handler);
LogError(amx, AMX_ERR_NOTFOUND, R"(Invalid function "%s")", handler);
return 0;
}
Menu *pMenu = new Menu(title, amx, func);
validate_menu_text(title);
auto pMenu = new Menu(title, amx, callback, params[arg_ml] != 0);
if (g_MenuFreeStack.empty())
{
g_NewMenus.append(pMenu);
pMenu->thisId = (int)g_NewMenus.length() - 1;
} else {
int pos = g_MenuFreeStack.front();
pMenu->thisId = static_cast<int>(g_NewMenus.length()) - 1;
}
else
{
const auto position = g_MenuFreeStack.front();
g_MenuFreeStack.pop();
g_NewMenus[pos] = pMenu;
pMenu->thisId = pos;
g_NewMenus[position] = pMenu;
pMenu->thisId = position;
}
return pMenu->thisId;
}
static cell AMX_NATIVE_CALL menu_addblank(AMX *amx, cell *params)
{
GETMENU(params[1]);

View File

@ -95,7 +95,7 @@ typedef unsigned int page_t;
class Menu
{
public:
Menu(const char *title, AMX *amx, int fid);
Menu(const char *title, AMX *amx, int fid, bool use_ml);
~Menu();
menuitem *GetMenuItem(item_t item);
@ -127,6 +127,8 @@ public:
bool isDestroying;
int pageCallback;
bool showPageNumber;
bool useMultilingual;
AMX *amx;
public:
unsigned int items_per_page;
};

View File

@ -117,13 +117,14 @@
* @param title Title the menu should use.
* @param handler Name of the handler function. The function will be invoked
* once and only once to every menu_display() call.
* @param ml Unused (should be 0).
* @param ml If true, the menu title and items will be looked up as multilingual keys
* when the menu displays.
* @return Menu resource identifier which must be destroyed via
* menu_destroy(). All menus are destroyed when the plugin
* unloads.
* @error Function name not found.
*/
native menu_create(const title[], const handler[], ml=0);
native menu_create(const title[], const handler[], bool:ml = false);
/**
* Creates a menu item callback handler.