Use localized strings for fonticon autocompletion

This commit is contained in:
Jan 2021-09-21 20:05:30 +02:00
parent de107be4e0
commit afc097b432
5 changed files with 135 additions and 13 deletions

View File

@ -44,6 +44,14 @@ namespace Components
std::map<std::string, TextRenderer::FontIconTableEntry> TextRenderer::fontIconLookup; std::map<std::string, TextRenderer::FontIconTableEntry> TextRenderer::fontIconLookup;
std::vector<TextRenderer::FontIconTableEntry> TextRenderer::fontIconList; std::vector<TextRenderer::FontIconTableEntry> TextRenderer::fontIconList;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_BIG> TextRenderer::stringSearchStartWith;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringHintAutoComplete;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringHintModifier;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_NONE> TextRenderer::stringListHeader;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringListFlipHorizontal;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringListFlipVertical;
TextRenderer::FormattedStringBuffer<TextRenderer::STRING_BUFFER_SIZE_SMALL> TextRenderer::stringListBig;
Dvar::Var TextRenderer::cg_newColors; Dvar::Var TextRenderer::cg_newColors;
Dvar::Var TextRenderer::cg_fontIconAutocomplete; Dvar::Var TextRenderer::cg_fontIconAutocomplete;
Dvar::Var TextRenderer::cg_fontIconAutocompleteHint; Dvar::Var TextRenderer::cg_fontIconAutocompleteHint;
@ -277,16 +285,16 @@ namespace Components
// Update results for query and scroll // Update results for query and scroll
context.lastQuery = std::string(&edit->buffer[fontIconStart], edit->cursor - fontIconStart); context.lastQuery = std::string(&edit->buffer[fontIconStart], edit->cursor - fontIconStart);
stringSearchStartWith.Format(context.lastQuery.c_str());
UpdateAutocompleteContextResults(context, font, textXScale); UpdateAutocompleteContextResults(context, font, textXScale);
} }
void TextRenderer::DrawAutocompleteModifiers(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, float textXScale, float textYScale) void TextRenderer::DrawAutocompleteModifiers(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, float textXScale, float textYScale)
{ {
const auto* text = "The following modifiers are available:\n" const auto textWidth = std::max(std::max(std::max(stringListHeader.GetWidth(font), stringListFlipHorizontal.GetWidth(font)),
"^2h ^7Flip icon horizontally\n" stringListFlipVertical.GetWidth(font)),
"^2v ^7Flip icon vertically\n" stringListBig.GetWidth(font));
"^2b ^7Bigger icon"; const auto boxWidth = static_cast<float>(textWidth) * textXScale;
const auto boxWidth = static_cast<float>(Game::R_TextWidth(text, std::numeric_limits<int>::max(), font)) * textXScale;
constexpr auto totalLines = 4u; constexpr auto totalLines = 4u;
const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale; const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale;
DrawAutocompleteBox(context, DrawAutocompleteBox(context,
@ -295,18 +303,30 @@ namespace Components
boxWidth + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2, boxWidth + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
static_cast<float>(totalLines) * lineHeight + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2, static_cast<float>(totalLines) * lineHeight + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
(*con_inputBoxColor)->current.vector); (*con_inputBoxColor)->current.vector);
Game::R_AddCmdDrawText(text, std::numeric_limits<int>::max(), font, x, y + lineHeight, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
auto currentY = y + lineHeight;
Game::R_AddCmdDrawText(stringListHeader.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight;
Game::R_AddCmdDrawText(stringListFlipHorizontal.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight;
Game::R_AddCmdDrawText(stringListFlipVertical.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight;
Game::R_AddCmdDrawText(stringListBig.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
} }
void TextRenderer::DrawAutocompleteResults(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale) void TextRenderer::DrawAutocompleteResults(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font, const float textXScale, const float textYScale)
{ {
const auto* text = Utils::String::VA("Font icons starting with ^2%s^7:", context.lastQuery.c_str()); const auto hintEnabled = cg_fontIconAutocompleteHint.get<bool>();
auto longestStringLength = stringSearchStartWith.GetWidth(font);
if(hintEnabled)
longestStringLength = std::max(std::max(longestStringLength, stringHintAutoComplete.GetWidth(font)), stringHintModifier.GetWidth(font));
const auto colSpacing = FONT_ICON_AUTOCOMPLETE_COL_SPACING * textXScale; const auto colSpacing = FONT_ICON_AUTOCOMPLETE_COL_SPACING * textXScale;
const auto boxWidth = std::max(context.maxFontIconWidth + context.maxMaterialNameWidth + colSpacing, const auto boxWidth = std::max(context.maxFontIconWidth + context.maxMaterialNameWidth + colSpacing, static_cast<float>(longestStringLength) * textXScale);
static_cast<float>(Game::R_TextWidth(text, std::numeric_limits<int>::max(), font)) * textXScale);
const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale; const auto lineHeight = static_cast<float>(font->pixelHeight) * textYScale;
const auto hintEnabled = cg_fontIconAutocompleteHint.get<bool>();
const auto totalLines = 1u + context.resultCount + (hintEnabled ? 2u : 0u); const auto totalLines = 1u + context.resultCount + (hintEnabled ? 2u : 0u);
const auto arrowPadding = context.resultOffset > 0 || context.hasMoreResults ? FONT_ICON_AUTOCOMPLETE_ARROW_SIZE : 0.0f; const auto arrowPadding = context.resultOffset > 0 || context.hasMoreResults ? FONT_ICON_AUTOCOMPLETE_ARROW_SIZE : 0.0f;
DrawAutocompleteBox(context, DrawAutocompleteBox(context,
@ -317,7 +337,7 @@ namespace Components
(*con_inputBoxColor)->current.vector); (*con_inputBoxColor)->current.vector);
auto currentY = y + lineHeight; auto currentY = y + lineHeight;
Game::R_AddCmdDrawText(text, std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0); Game::R_AddCmdDrawText(stringSearchStartWith.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, TEXT_COLOR, 0);
currentY += lineHeight; currentY += lineHeight;
const auto selectedIndex = context.selectedOffset - context.resultOffset; const auto selectedIndex = context.selectedOffset - context.resultOffset;
@ -335,9 +355,9 @@ namespace Components
if(hintEnabled) if(hintEnabled)
{ {
Game::R_AddCmdDrawText("Press ^3TAB ^7for autocomplete", std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, HINT_COLOR, 0); Game::R_AddCmdDrawText(stringHintAutoComplete.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, HINT_COLOR, 0);
currentY += lineHeight; currentY += lineHeight;
Game::R_AddCmdDrawText("Use ^3+ ^7for modifiers", std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, HINT_COLOR, 0); Game::R_AddCmdDrawText(stringHintModifier.GetString(), std::numeric_limits<int>::max(), font, x, currentY, textXScale, textYScale, 0.0, HINT_COLOR, 0);
} }
} }
@ -1392,8 +1412,32 @@ namespace Components
(*currentColorTable)[TEXT_COLOR_SERVER] = sv_customTextColor->current.unsignedInt; (*currentColorTable)[TEXT_COLOR_SERVER] = sv_customTextColor->current.unsignedInt;
} }
void TextRenderer::InitFontIconStrings()
{
stringSearchStartWith.Load("FONT_ICON_SEARCH_START_WITH");
stringHintAutoComplete.Load("FONT_ICON_HINT_AUTO_COMPLETE");
stringHintAutoComplete.Format("TAB");
stringHintModifier.Load("FONT_ICON_HINT_MODIFIER");
stringHintModifier.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_SEPARATOR_CHARACTER));
stringListHeader.Load("FONT_ICON_MODIFIER_LIST_HEADER");
stringListFlipHorizontal.Load("FONT_ICON_MODIFIER_LIST_FLIP_HORIZONTAL");
stringListFlipHorizontal.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_FLIP_HORIZONTALLY));
stringListFlipVertical.Load("FONT_ICON_MODIFIER_LIST_FLIP_VERTICAL");
stringListFlipVertical.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_FLIP_VERTICALLY));
stringListBig.Load("FONT_ICON_MODIFIER_LIST_BIG");
stringListBig.Format(Utils::String::VA("%c", FONT_ICON_MODIFIER_BIG));
}
void TextRenderer::InitFontIcons() void TextRenderer::InitFontIcons()
{ {
InitFontIconStrings();
fontIconList.clear(); fontIconList.clear();
fontIconLookup.clear(); fontIconLookup.clear();

View File

@ -91,6 +91,58 @@ namespace Components
float maxMaterialNameWidth; float maxMaterialNameWidth;
}; };
template<size_t S>
class FormattedStringBuffer
{
public:
FormattedStringBuffer()
: formattingString(nullptr),
stringBuffer{0},
stringWidth(-1)
{
}
void Load(const char* reference)
{
formattingString = Game::UI_SafeTranslateString(reference);
}
const char* Format(const char* value)
{
if (formattingString == nullptr)
return stringBuffer;
Game::ConversionArguments conversionArguments{};
conversionArguments.args[conversionArguments.argCount++] = value;
Game::UI_ReplaceConversions(formattingString, &conversionArguments, stringBuffer, sizeof(stringBuffer));
stringWidth = -1;
return stringBuffer;
}
const char* GetString() const
{
if(stringBuffer[0] != '\0')
return stringBuffer;
if(formattingString)
return formattingString;
return stringBuffer;
}
int GetWidth(Game::Font_s* font)
{
if (stringWidth < 0)
stringWidth = Game::R_TextWidth(GetString(), std::numeric_limits<int>::max(), font);
return stringWidth;
}
private:
const char* formattingString;
char stringBuffer[S];
int stringWidth;
};
static constexpr unsigned MY_ALTCOLOR_TWO = 0x0DCE6FFE6; static constexpr unsigned MY_ALTCOLOR_TWO = 0x0DCE6FFE6;
static constexpr unsigned COLOR_MAP_HASH = 0xA0AB1041; static constexpr unsigned COLOR_MAP_HASH = 0xA0AB1041;
static constexpr auto FONT_ICON_AUTOCOMPLETE_BOX_PADDING = 6.0f; static constexpr auto FONT_ICON_AUTOCOMPLETE_BOX_PADDING = 6.0f;
@ -133,6 +185,17 @@ namespace Components
static std::map<std::string, FontIconTableEntry> fontIconLookup; static std::map<std::string, FontIconTableEntry> fontIconLookup;
static std::vector<FontIconTableEntry> fontIconList; static std::vector<FontIconTableEntry> fontIconList;
static constexpr auto STRING_BUFFER_SIZE_BIG = 1024;
static constexpr auto STRING_BUFFER_SIZE_SMALL = 128;
static constexpr auto STRING_BUFFER_SIZE_NONE = 1;
static FormattedStringBuffer<STRING_BUFFER_SIZE_BIG> stringSearchStartWith;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringHintAutoComplete;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringHintModifier;
static FormattedStringBuffer<STRING_BUFFER_SIZE_NONE> stringListHeader;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringListFlipHorizontal;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringListFlipVertical;
static FormattedStringBuffer<STRING_BUFFER_SIZE_SMALL> stringListBig;
static Dvar::Var cg_newColors; static Dvar::Var cg_newColors;
static Dvar::Var cg_fontIconAutocomplete; static Dvar::Var cg_fontIconAutocomplete;
static Dvar::Var cg_fontIconAutocompleteHint; static Dvar::Var cg_fontIconAutocompleteHint;
@ -214,6 +277,7 @@ namespace Components
static void RotateXY(float cosAngle, float sinAngle, float pivotX, float pivotY, float x, float y, float* outX, float* outY); static void RotateXY(float cosAngle, float sinAngle, float pivotX, float pivotY, float x, float y, float* outX, float* outY);
static void UpdateColorTable(); static void UpdateColorTable();
static void InitFontIconStrings();
static void InitFontIcons(); static void InitFontIcons();
static void UI_Init_Hk(int localClientNum); static void UI_Init_Hk(int localClientNum);
}; };

View File

@ -346,6 +346,8 @@ namespace Game
UI_GetFontHandle_t UI_GetFontHandle = UI_GetFontHandle_t(0x4AEA60); UI_GetFontHandle_t UI_GetFontHandle = UI_GetFontHandle_t(0x4AEA60);
ScrPlace_ApplyRect_t ScrPlace_ApplyRect = ScrPlace_ApplyRect_t(0x454E20); ScrPlace_ApplyRect_t ScrPlace_ApplyRect = ScrPlace_ApplyRect_t(0x454E20);
UI_KeyEvent_t UI_KeyEvent = UI_KeyEvent_t(0x4970F0); UI_KeyEvent_t UI_KeyEvent = UI_KeyEvent_t(0x4970F0);
UI_SafeTranslateString_t UI_SafeTranslateString = UI_SafeTranslateString_t(0x4F1700);
UI_ReplaceConversions_t UI_ReplaceConversions = UI_ReplaceConversions_t(0x4E9740);
Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0); Win_GetLanguage_t Win_GetLanguage = Win_GetLanguage_t(0x45CBA0);

View File

@ -459,6 +459,12 @@ namespace Game
typedef bool(__cdecl * UI_KeyEvent_t)(int clientNum, int key, int down); typedef bool(__cdecl * UI_KeyEvent_t)(int clientNum, int key, int down);
extern UI_KeyEvent_t UI_KeyEvent; extern UI_KeyEvent_t UI_KeyEvent;
typedef const char* (__cdecl * UI_SafeTranslateString_t)(const char* reference);
extern UI_SafeTranslateString_t UI_SafeTranslateString;
typedef void(__cdecl * UI_ReplaceConversions_t)(const char* sourceString, ConversionArguments* arguments, char* outputString, size_t outputStringSize);
extern UI_ReplaceConversions_t UI_ReplaceConversions;
typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length); typedef void(__cdecl * MSG_Init_t)(msg_t *buf, char *data, int length);
extern MSG_Init_t MSG_Init; extern MSG_Init_t MSG_Init;

View File

@ -6858,6 +6858,12 @@ namespace Game
static_assert(sizeof(cgs_t) == 0x3BA4); static_assert(sizeof(cgs_t) == 0x3BA4);
struct ConversionArguments
{
int argCount;
const char* args[9];
};
#pragma endregion #pragma endregion
#ifndef IDA #ifndef IDA