add fonticon modifier autocomplete and dvars to control autocomplete and hint text
This commit is contained in:
parent
68acf467b1
commit
d640c4488c
@ -43,6 +43,8 @@ namespace Components
|
|||||||
TextRenderer::FontIconAutocompleteContext TextRenderer::autocompleteContextArray[FONT_ICON_ACI_COUNT]{};
|
TextRenderer::FontIconAutocompleteContext TextRenderer::autocompleteContextArray[FONT_ICON_ACI_COUNT]{};
|
||||||
|
|
||||||
Dvar::Var TextRenderer::cg_newColors;
|
Dvar::Var TextRenderer::cg_newColors;
|
||||||
|
Dvar::Var TextRenderer::cg_fontIconAutocomplete;
|
||||||
|
Dvar::Var TextRenderer::cg_fontIconAutocompleteHint;
|
||||||
Game::dvar_t* TextRenderer::sv_customTextColor;
|
Game::dvar_t* TextRenderer::sv_customTextColor;
|
||||||
Dvar::Var TextRenderer::r_colorBlind;
|
Dvar::Var TextRenderer::r_colorBlind;
|
||||||
Game::dvar_t* TextRenderer::g_ColorBlind_MyTeam;
|
Game::dvar_t* TextRenderer::g_ColorBlind_MyTeam;
|
||||||
@ -190,20 +192,41 @@ namespace Components
|
|||||||
void TextRenderer::UpdateAutocompleteContext(FontIconAutocompleteContext& context, Game::field_t* edit, Game::Font_s* font)
|
void TextRenderer::UpdateAutocompleteContext(FontIconAutocompleteContext& context, Game::field_t* edit, Game::Font_s* font)
|
||||||
{
|
{
|
||||||
int fontIconStart = -1;
|
int fontIconStart = -1;
|
||||||
for(auto i = edit->cursor - 1; i >= 0; i--)
|
auto inModifiers = false;
|
||||||
|
|
||||||
|
for(auto i = 0; i < edit->cursor; i++)
|
||||||
{
|
{
|
||||||
const auto c = static_cast<unsigned char>(edit->buffer[i]);
|
const auto c = static_cast<unsigned char>(edit->buffer[i]);
|
||||||
if (c == ':')
|
if (c == ':')
|
||||||
|
{
|
||||||
|
if(fontIconStart < 0)
|
||||||
{
|
{
|
||||||
fontIconStart = i + 1;
|
fontIconStart = i + 1;
|
||||||
break;
|
inModifiers = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fontIconStart = -1;
|
||||||
|
inModifiers = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if(isspace(c))
|
||||||
|
{
|
||||||
|
fontIconStart = -1;
|
||||||
|
inModifiers = false;
|
||||||
|
}
|
||||||
|
else if(c == '+')
|
||||||
|
{
|
||||||
|
if (fontIconStart >= 0 && !inModifiers)
|
||||||
|
{
|
||||||
|
inModifiers = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fontIconStart = -1;
|
||||||
|
inModifiers = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isspace(c))
|
|
||||||
break;
|
|
||||||
|
|
||||||
if (c == '+')
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(fontIconStart < 0 || fontIconStart == edit->cursor)
|
if(fontIconStart < 0 || fontIconStart == edit->cursor)
|
||||||
@ -214,6 +237,8 @@ namespace Components
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
context.inModifiers = inModifiers;
|
||||||
|
|
||||||
// Update scroll
|
// Update scroll
|
||||||
if(context.selectedOffset < context.resultOffset)
|
if(context.selectedOffset < context.resultOffset)
|
||||||
context.resultOffset = context.selectedOffset;
|
context.resultOffset = context.selectedOffset;
|
||||||
@ -222,6 +247,10 @@ namespace Components
|
|||||||
|
|
||||||
context.autocompleteActive = true;
|
context.autocompleteActive = true;
|
||||||
|
|
||||||
|
// No need to update results when in modifiers
|
||||||
|
if (context.inModifiers)
|
||||||
|
return;
|
||||||
|
|
||||||
// Check if results need updates
|
// Check if results need updates
|
||||||
const auto currentFontIconHash = Game::R_HashString(&edit->buffer[fontIconStart], edit->cursor - fontIconStart);
|
const auto currentFontIconHash = Game::R_HashString(&edit->buffer[fontIconStart], edit->cursor - fontIconStart);
|
||||||
if (currentFontIconHash == context.lastHash && context.lastResultOffset == context.resultOffset)
|
if (currentFontIconHash == context.lastHash && context.lastResultOffset == context.resultOffset)
|
||||||
@ -240,13 +269,32 @@ namespace Components
|
|||||||
UpdateAutocompleteContextResults(context, font);
|
UpdateAutocompleteContextResults(context, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextRenderer::DrawAutocomplete(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font)
|
void TextRenderer::DrawAutocompleteModifiers(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font)
|
||||||
|
{
|
||||||
|
const auto* text = "The following modifiers are available:\n"
|
||||||
|
"^2h ^7Flip icon horizontally\n"
|
||||||
|
"^2v ^7Flip icon vertically\n"
|
||||||
|
"^2b ^7Bigger icon";
|
||||||
|
const auto boxWidth = static_cast<float>(Game::R_TextWidth(text, INT_MAX, font));
|
||||||
|
constexpr auto totalLines = 4u;
|
||||||
|
DrawAutocompleteBox(context,
|
||||||
|
x - FONT_ICON_AUTOCOMPLETE_BOX_PADDING,
|
||||||
|
y - FONT_ICON_AUTOCOMPLETE_BOX_PADDING,
|
||||||
|
boxWidth + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
|
||||||
|
static_cast<float>(font->pixelHeight * totalLines) + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
|
||||||
|
(*con_inputBoxColor)->current.vector);
|
||||||
|
const auto currentY = y + static_cast<float>(font->pixelHeight);
|
||||||
|
Game::R_AddCmdDrawText(text, INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, TEXT_COLOR, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextRenderer::DrawAutocompleteResults(const FontIconAutocompleteContext& context, const float x, const float y, Game::Font_s* font)
|
||||||
{
|
{
|
||||||
const auto* text = Utils::String::VA("Font icons starting with ^2%s^7:", context.lastQuery.c_str());
|
const auto* text = Utils::String::VA("Font icons starting with ^2%s^7:", context.lastQuery.c_str());
|
||||||
const auto boxWidth = std::max(context.maxFontIconWidth + context.maxMaterialNameWidth + FONT_ICON_AUTOCOMPLETE_COL_SPACING,
|
const auto boxWidth = std::max(context.maxFontIconWidth + context.maxMaterialNameWidth + FONT_ICON_AUTOCOMPLETE_COL_SPACING,
|
||||||
static_cast<float>(Game::R_TextWidth(text, INT_MAX, font)));
|
static_cast<float>(Game::R_TextWidth(text, INT_MAX, font)));
|
||||||
|
|
||||||
const auto totalLines = 1u + context.resultCount;
|
const auto hintEnabled = cg_fontIconAutocompleteHint.get<bool>();
|
||||||
|
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,
|
||||||
x - FONT_ICON_AUTOCOMPLETE_BOX_PADDING,
|
x - FONT_ICON_AUTOCOMPLETE_BOX_PADDING,
|
||||||
@ -255,30 +303,37 @@ namespace Components
|
|||||||
static_cast<float>(font->pixelHeight * totalLines) + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
|
static_cast<float>(font->pixelHeight * totalLines) + FONT_ICON_AUTOCOMPLETE_BOX_PADDING * 2,
|
||||||
(*con_inputBoxColor)->current.vector);
|
(*con_inputBoxColor)->current.vector);
|
||||||
|
|
||||||
const float textColor[4]
|
|
||||||
{
|
|
||||||
1.0f,
|
|
||||||
1.0f,
|
|
||||||
0.8f,
|
|
||||||
1.0f
|
|
||||||
};
|
|
||||||
|
|
||||||
auto currentY = y + static_cast<float>(font->pixelHeight);
|
auto currentY = y + static_cast<float>(font->pixelHeight);
|
||||||
Game::R_AddCmdDrawText(text, INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, textColor, 0);
|
Game::R_AddCmdDrawText(text, INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, TEXT_COLOR, 0);
|
||||||
currentY += static_cast<float>(font->pixelHeight);
|
currentY += static_cast<float>(font->pixelHeight);
|
||||||
|
|
||||||
const auto selectedIndex = context.selectedOffset - context.resultOffset;
|
const auto selectedIndex = context.selectedOffset - context.resultOffset;
|
||||||
for(auto resultIndex = 0u; resultIndex < context.resultCount; resultIndex++)
|
for(auto resultIndex = 0u; resultIndex < context.resultCount; resultIndex++)
|
||||||
{
|
{
|
||||||
const auto& result = context.results[resultIndex];
|
const auto& result = context.results[resultIndex];
|
||||||
Game::R_AddCmdDrawText(result.fontIconName.c_str(), INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, textColor, 0);
|
Game::R_AddCmdDrawText(result.fontIconName.c_str(), INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, TEXT_COLOR, 0);
|
||||||
|
|
||||||
if(selectedIndex == resultIndex)
|
if(selectedIndex == resultIndex)
|
||||||
Game::R_AddCmdDrawText(Utils::String::VA("^2%s", result.materialName.c_str()), INT_MAX, font, x + context.maxFontIconWidth + FONT_ICON_AUTOCOMPLETE_COL_SPACING, currentY, 1.0f, 1.0f, 0.0, textColor, 0);
|
Game::R_AddCmdDrawText(Utils::String::VA("^2%s", result.materialName.c_str()), INT_MAX, font, x + context.maxFontIconWidth + FONT_ICON_AUTOCOMPLETE_COL_SPACING, currentY, 1.0f, 1.0f, 0.0, TEXT_COLOR, 0);
|
||||||
else
|
else
|
||||||
Game::R_AddCmdDrawText(result.materialName.c_str(), INT_MAX, font, x + context.maxFontIconWidth + FONT_ICON_AUTOCOMPLETE_COL_SPACING, currentY, 1.0f, 1.0f, 0.0, textColor, 0);
|
Game::R_AddCmdDrawText(result.materialName.c_str(), INT_MAX, font, x + context.maxFontIconWidth + FONT_ICON_AUTOCOMPLETE_COL_SPACING, currentY, 1.0f, 1.0f, 0.0, TEXT_COLOR, 0);
|
||||||
currentY += static_cast<float>(font->pixelHeight);
|
currentY += static_cast<float>(font->pixelHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(hintEnabled)
|
||||||
|
{
|
||||||
|
Game::R_AddCmdDrawText("Press ^3TAB ^7for autocomplete", INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, HINT_COLOR, 0);
|
||||||
|
currentY += static_cast<float>(font->pixelHeight);
|
||||||
|
Game::R_AddCmdDrawText("Use ^3+ ^7for modifiers", INT_MAX, font, x, currentY, 1.0f, 1.0f, 0.0, HINT_COLOR, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextRenderer::DrawAutocomplete(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font)
|
||||||
|
{
|
||||||
|
if (context.inModifiers)
|
||||||
|
DrawAutocompleteModifiers(context, x, y, font);
|
||||||
|
else
|
||||||
|
DrawAutocompleteResults(context, x, y, font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextRenderer::Con_DrawInput_Hk(const int localClientNum)
|
void TextRenderer::Con_DrawInput_Hk(const int localClientNum)
|
||||||
@ -287,6 +342,12 @@ namespace Components
|
|||||||
Utils::Hook::Call<void(int)>(0x5A4480)(localClientNum);
|
Utils::Hook::Call<void(int)>(0x5A4480)(localClientNum);
|
||||||
|
|
||||||
auto& autocompleteContext = autocompleteContextArray[FONT_ICON_ACI_CONSOLE];
|
auto& autocompleteContext = autocompleteContextArray[FONT_ICON_ACI_CONSOLE];
|
||||||
|
if (cg_fontIconAutocomplete.get<bool>() == false)
|
||||||
|
{
|
||||||
|
autocompleteContext.autocompleteActive = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateAutocompleteContext(autocompleteContext, Game::g_consoleField, Game::cls->consoleFont);
|
UpdateAutocompleteContext(autocompleteContext, Game::g_consoleField, Game::cls->consoleFont);
|
||||||
if (autocompleteContext.autocompleteActive)
|
if (autocompleteContext.autocompleteActive)
|
||||||
{
|
{
|
||||||
@ -301,6 +362,12 @@ namespace Components
|
|||||||
Game::Field_Draw(localClientNum, edit, x, y, horzAlign, vertAlign);
|
Game::Field_Draw(localClientNum, edit, x, y, horzAlign, vertAlign);
|
||||||
|
|
||||||
auto& autocompleteContext = autocompleteContextArray[FONT_ICON_ACI_CHAT];
|
auto& autocompleteContext = autocompleteContextArray[FONT_ICON_ACI_CHAT];
|
||||||
|
if (cg_fontIconAutocomplete.get<bool>() == false)
|
||||||
|
{
|
||||||
|
autocompleteContext.autocompleteActive = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
UpdateAutocompleteContext(autocompleteContext, edit, Game::cls->consoleFont);
|
UpdateAutocompleteContext(autocompleteContext, edit, Game::cls->consoleFont);
|
||||||
if (autocompleteContext.autocompleteActive)
|
if (autocompleteContext.autocompleteActive)
|
||||||
{
|
{
|
||||||
@ -1257,6 +1324,8 @@ namespace Components
|
|||||||
currentColorTable = &colorTableDefault;
|
currentColorTable = &colorTableDefault;
|
||||||
|
|
||||||
cg_newColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare 2 color code style.");
|
cg_newColors = Dvar::Register<bool>("cg_newColors", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Use Warfare 2 color code style.");
|
||||||
|
cg_fontIconAutocomplete = Dvar::Register<bool>("cg_fontIconAutocomplete", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Show autocomplete for fonticons when typing.");
|
||||||
|
cg_fontIconAutocompleteHint = Dvar::Register<bool>("cg_fontIconAutocompleteHint", true, Game::dvar_flag::DVAR_FLAG_SAVED, "Show hint text in autocomplete for fonticons.");
|
||||||
sv_customTextColor = Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
|
sv_customTextColor = Game::Dvar_RegisterColor("sv_customTextColor", 1, 0.7f, 0, 1, Game::dvar_flag::DVAR_FLAG_REPLICATED, "Color for the extended color code.");
|
||||||
|
|
||||||
// Replace vanilla text drawing function with a reimplementation with extensions
|
// Replace vanilla text drawing function with a reimplementation with extensions
|
||||||
|
@ -78,6 +78,7 @@ namespace Components
|
|||||||
static constexpr auto MAX_RESULTS = 10;
|
static constexpr auto MAX_RESULTS = 10;
|
||||||
|
|
||||||
bool autocompleteActive;
|
bool autocompleteActive;
|
||||||
|
bool inModifiers;
|
||||||
unsigned int lastHash;
|
unsigned int lastHash;
|
||||||
std::string lastQuery;
|
std::string lastQuery;
|
||||||
FontIconAutocompleteResult results[MAX_RESULTS];
|
FontIconAutocompleteResult results[MAX_RESULTS];
|
||||||
@ -105,6 +106,20 @@ namespace Components
|
|||||||
{1.0f, -1.0f},
|
{1.0f, -1.0f},
|
||||||
{1.0f, 1.0f},
|
{1.0f, 1.0f},
|
||||||
};
|
};
|
||||||
|
static constexpr float TEXT_COLOR[4]
|
||||||
|
{
|
||||||
|
1.0f,
|
||||||
|
1.0f,
|
||||||
|
0.8f,
|
||||||
|
1.0f
|
||||||
|
};
|
||||||
|
static constexpr float HINT_COLOR[4]
|
||||||
|
{
|
||||||
|
0.6f,
|
||||||
|
0.6f,
|
||||||
|
0.6f,
|
||||||
|
1.0f
|
||||||
|
};
|
||||||
|
|
||||||
static unsigned colorTableDefault[TEXT_COLOR_COUNT];
|
static unsigned colorTableDefault[TEXT_COLOR_COUNT];
|
||||||
static unsigned colorTableNew[TEXT_COLOR_COUNT];
|
static unsigned colorTableNew[TEXT_COLOR_COUNT];
|
||||||
@ -112,6 +127,8 @@ namespace Components
|
|||||||
static FontIconAutocompleteContext autocompleteContextArray[FONT_ICON_ACI_COUNT];
|
static FontIconAutocompleteContext autocompleteContextArray[FONT_ICON_ACI_COUNT];
|
||||||
|
|
||||||
static Dvar::Var cg_newColors;
|
static Dvar::Var cg_newColors;
|
||||||
|
static Dvar::Var cg_fontIconAutocomplete;
|
||||||
|
static Dvar::Var cg_fontIconAutocompleteHint;
|
||||||
static Game::dvar_t* sv_customTextColor;
|
static Game::dvar_t* sv_customTextColor;
|
||||||
static Dvar::Var r_colorBlind;
|
static Dvar::Var r_colorBlind;
|
||||||
static Game::dvar_t* g_ColorBlind_MyTeam;
|
static Game::dvar_t* g_ColorBlind_MyTeam;
|
||||||
@ -135,6 +152,8 @@ namespace Components
|
|||||||
static unsigned HsvToRgb(HsvColor hsv);
|
static unsigned HsvToRgb(HsvColor hsv);
|
||||||
|
|
||||||
static void DrawAutocompleteBox(const FontIconAutocompleteContext& context, float x, float y, float w, float h, const float* color);
|
static void DrawAutocompleteBox(const FontIconAutocompleteContext& context, float x, float y, float w, float h, const float* color);
|
||||||
|
static void DrawAutocompleteModifiers(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font);
|
||||||
|
static void DrawAutocompleteResults(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font);
|
||||||
static void DrawAutocomplete(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font);
|
static void DrawAutocomplete(const FontIconAutocompleteContext& context, float x, float y, Game::Font_s* font);
|
||||||
static void UpdateAutocompleteContextResults(FontIconAutocompleteContext& context, Game::Font_s* font);
|
static void UpdateAutocompleteContextResults(FontIconAutocompleteContext& context, Game::Font_s* font);
|
||||||
static void UpdateAutocompleteContext(FontIconAutocompleteContext& context, Game::field_t* edit, Game::Font_s* font);
|
static void UpdateAutocompleteContext(FontIconAutocompleteContext& context, Game::field_t* edit, Game::Font_s* font);
|
||||||
|
Loading…
Reference in New Issue
Block a user