From a1540cd6c37c99c9e2ef7755b0ebc98da1721afa Mon Sep 17 00:00:00 2001 From: DeaTh-G Date: Sat, 25 Jan 2025 12:18:14 +0100 Subject: [PATCH] support ruby annotations for options menu descriptions --- UnleashedRecomp/ui/imgui_utils.cpp | 66 ++++++++++++++++++----------- UnleashedRecomp/ui/imgui_utils.h | 4 +- UnleashedRecomp/ui/options_menu.cpp | 25 +++++++---- 3 files changed, 61 insertions(+), 34 deletions(-) diff --git a/UnleashedRecomp/ui/imgui_utils.cpp b/UnleashedRecomp/ui/imgui_utils.cpp index 3b2bb4d1..7a8aae66 100644 --- a/UnleashedRecomp/ui/imgui_utils.cpp +++ b/UnleashedRecomp/ui/imgui_utils.cpp @@ -189,6 +189,13 @@ void DrawPauseHeaderContainer(ImVec2 min, ImVec2 max, float alpha) drawList->AddImage(g_texGeneralWindow.get(), { max.x - commonWidth, min.y }, max, GET_UV_COORDS(right), colour); } +void DrawTextBasic(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 colour, const char* text) +{ + auto drawList = ImGui::GetForegroundDrawList(); + + drawList->AddText(font, fontSize, pos, colour, text, nullptr); +} + void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 color, const char* text, double time, double delay, double speed) { auto drawList = ImGui::GetForegroundDrawList(); @@ -207,6 +214,24 @@ void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& pos, drawList->PopClipRect(); } +void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 colour, const char* text, double time, double delay, double speed, float offset, float radius, ImU32 shadowColour) +{ + auto drawList = ImGui::GetForegroundDrawList(); + auto rectWidth = max.x - min.x; + auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text); + auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth); + + drawList->PushClipRect(min, max, true); + + if (textX <= pos.x) + DrawTextWithShadow(font, fontSize, { textX, pos.y }, colour, text, offset, radius, shadowColour); + + if (textX + textSize.x < pos.x) + DrawTextWithShadow(font, fontSize, { textX + textSize.x + rectWidth, pos.y }, colour, text, offset, radius, shadowColour); + + drawList->PopClipRect(); +} + void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 color, const char* text, float outlineSize, ImU32 outlineColor, uint32_t shaderModifier) { auto drawList = ImGui::GetForegroundDrawList(); @@ -534,12 +559,12 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidt return MeasureCentredParagraph(font, fontSize, lineMargin, Split(text, font, fontSize, maxWidth)); } -void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, const ImVec2& centre, float lineMargin, const char* text, std::function drawMethod) +void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function drawMethod, std::function annotationDrawMethod, bool isCentred) { const auto& input = RemoveRubyAnnotations(text); auto lines = Split(input.first.c_str(), font, fontSize, maxWidth); auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines); - auto offsetY = 0.0f; + float offsetY = 0.0f; for (auto& line : lines) { @@ -555,20 +580,26 @@ void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, co auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLine.c_str()); auto annotationSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, ""); - auto textX = annotationRemovedLine.starts_with("- ") - ? centre.x - paragraphSize.x / 2 - : centre.x - textSize.x / 2; + float textX = pos.x; + if (isCentred) + { + textX = annotationRemovedLine.starts_with("- ") + ? pos.x - paragraphSize.x / 2 + : pos.x - textSize.x / 2; + } for (const auto& segment : annotatedLine) { textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, segment.text.c_str()); - - auto textY = centre.y - paragraphSize.y / 2 + offsetY; + float textY = pos.y + offsetY; + if (isCentred) + { + textY = pos.y - paragraphSize.y / 2 + offsetY; + } if (segment.annotated) { annotationSize = font->CalcTextSizeA(fontSize * 0.55f, FLT_MAX, 0, segment.annotation.c_str()); - float annotationX = textX + (textSize.x - annotationSize.x) / 2.0f; annotationDrawMethod(segment.annotation.c_str(), fontSize * 0.55f, { annotationX, textY - (fontSize * 0.55f) }); @@ -577,7 +608,7 @@ void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, co drawMethod(segment.text.c_str(), { textX, textY }); textX += textSize.x; } - + offsetY += textSize.y + Scale(lineMargin); if (annotatedLines.annotated) { @@ -586,22 +617,9 @@ void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, co } } -void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 colour, const char* text, double time, double delay, double speed, float offset, float radius, ImU32 shadowColour) +void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, const ImVec2& centre, float lineMargin, const char* text, std::function drawMethod) { - auto drawList = ImGui::GetForegroundDrawList(); - auto rectWidth = max.x - min.x; - auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text); - auto textX = pos.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth); - - drawList->PushClipRect(min, max, true); - - if (textX <= pos.x) - DrawTextWithShadow(font, fontSize, { textX, pos.y }, colour, text, offset, radius, shadowColour); - - if (textX + textSize.x < pos.x) - DrawTextWithShadow(font, fontSize, { textX + textSize.x + rectWidth, pos.y }, colour, text, offset, radius, shadowColour); - - drawList->PopClipRect(); + DrawRubyAnnotatedText(font, fontSize, maxWidth, centre, lineMargin, text, drawMethod, annotationDrawMethod, true); } float Lerp(float a, float b, float t) diff --git a/UnleashedRecomp/ui/imgui_utils.h b/UnleashedRecomp/ui/imgui_utils.h index 84954c38..1c99b173 100644 --- a/UnleashedRecomp/ui/imgui_utils.h +++ b/UnleashedRecomp/ui/imgui_utils.h @@ -51,8 +51,10 @@ float Scale(float size); double ComputeLinearMotion(double duration, double offset, double total); double ComputeMotion(double duration, double offset, double total); void DrawPauseContainer(ImVec2 min, ImVec2 max, float alpha = 1); +void DrawTextBasic(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 colour, const char* text); void DrawPauseHeaderContainer(ImVec2 min, ImVec2 max, float alpha = 1); void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 color, const char* text, double time, double delay, double speed); +void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 colour, const char* text, double time, double delay, double speed, float offset = 2.0f, float radius = 1.0f, ImU32 shadowColour = IM_COL32(0, 0, 0, 255)); void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 color, const char* text, float outlineSize, ImU32 outlineColor, uint32_t shaderModifier = IMGUI_SHADER_MODIFIER_NONE); void DrawTextWithShadow(const ImFont* font, float fontSize, const ImVec2& pos, ImU32 colour, const char* text, float offset = 2.0f, float radius = 1.0f, ImU32 shadowColour = IM_COL32(0, 0, 0, 255)); float CalcWidestTextSize(const ImFont* font, float fontSize, std::span strs); @@ -65,8 +67,8 @@ std::vector RemoveAnnotationFromParagraph(const std::vector& annotatedLine); ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, std::vector lines); ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text); +void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function drawMethod, std::function annotationDrawMethod, bool isCentred = false); void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, const ImVec2& centre, float lineMargin, const char* text, std::function drawMethod); -void DrawTextWithMarqueeShadow(const ImFont* font, float fontSize, const ImVec2& pos, const ImVec2& min, const ImVec2& max, ImU32 colour, const char* text, double time, double delay, double speed, float offset = 2.0f, float radius = 1.0f, ImU32 shadowColour = IM_COL32(0, 0, 0, 255)); float Lerp(float a, float b, float t); float Cubic(float a, float b, float t); float Hermite(float a, float b, float t); diff --git a/UnleashedRecomp/ui/options_menu.cpp b/UnleashedRecomp/ui/options_menu.cpp index 3fd5fbc6..1be46926 100644 --- a/UnleashedRecomp/ui/options_menu.cpp +++ b/UnleashedRecomp/ui/options_menu.cpp @@ -1231,17 +1231,24 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax) desc += "\n\n" + g_selectedItem->GetValueDescription(Config::Language); } - auto size = Scale(26.0f); - - drawList->AddText - ( + auto fontSize = Scale(26.0f); + + DrawRubyAnnotatedText( g_seuratFont, - size, - { clipRectMin.x, thumbnailMax.y + size - 5.0f }, - IM_COL32_WHITE, + fontSize, + clipRectMax.x - clipRectMin.y, + { clipRectMin.x, thumbnailMax.y + fontSize - 5.0f }, + 0.0f, desc.c_str(), - 0, - clipRectMax.x - clipRectMin.x + + [=](const char* str, ImVec2 pos) + { + DrawTextBasic(g_seuratFont, fontSize, pos, IM_COL32(255, 255, 255, 255), str); + }, + [=](const char* str, float size, ImVec2 pos) + { + DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255), str); + } ); }