diff --git a/UnleashedRecomp/ui/imgui_utils.cpp b/UnleashedRecomp/ui/imgui_utils.cpp index eb458456..3b2bb4d1 100644 --- a/UnleashedRecomp/ui/imgui_utils.cpp +++ b/UnleashedRecomp/ui/imgui_utils.cpp @@ -273,6 +273,79 @@ std::string Truncate(const std::string& input, size_t maxLength, bool useEllipsi return input; } +std::pair> RemoveRubyAnnotations(const char* input) { + std::string output; + std::map rubyMap; + std::string currentMain, currentRuby; + size_t idx = 0; + + while (input[idx] != '\0') + { + if (input[idx] == '[') + { + idx++; + currentMain.clear(); + currentRuby.clear(); + + while (input[idx] != ':' && input[idx] != ']' && input[idx] != '\0') + { + currentMain += input[idx++]; + } + if (input[idx] == ':') + { + idx++; + while (input[idx] != ']' && input[idx] != '\0') + { + currentRuby += input[idx++]; + } + } + if (input[idx] == ']') + { + idx++; + } + + if (!currentMain.empty() && !currentRuby.empty()) + { + rubyMap[currentMain] = currentRuby; + } + + output += currentMain; + } + else + { + output += input[idx++]; + } + } + + return { output, rubyMap }; +} + +std::string ReAddRubyAnnotations(const std::string& wrappedText, const std::map& rubyMap) { + std::string annotatedText; + size_t idx = 0; + size_t length = wrappedText.length(); + + while (idx < length) { + bool matched = false; + for (const auto& [mainText, rubyText] : rubyMap) + { + if (wrappedText.substr(idx, mainText.length()) == mainText) + { + annotatedText += "[" + mainText + ":" + rubyText + "]"; + idx += mainText.length(); + matched = true; + break; + } + } + if (!matched) + { + annotatedText += wrappedText[idx++]; + } + } + + return annotatedText; +} + std::vector Split(const char* strStart, const ImFont *font, float fontSize, float maxWidth) { if (!strStart) @@ -463,10 +536,16 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidt void DrawCentredParagraph(const ImFont* font, float fontSize, float maxWidth, const ImVec2& centre, float lineMargin, const char* text, std::function drawMethod) { - auto lines = Split(text, font, fontSize, maxWidth); + 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; + for (auto& line : lines) + { + line = ReAddRubyAnnotations(line, input.second); + } + const auto& annotatedLines = CalculateAnnotatedParagraph(lines); for (const auto& annotatedLine : annotatedLines.lines) diff --git a/UnleashedRecomp/ui/imgui_utils.h b/UnleashedRecomp/ui/imgui_utils.h index b7cecec5..84954c38 100644 --- a/UnleashedRecomp/ui/imgui_utils.h +++ b/UnleashedRecomp/ui/imgui_utils.h @@ -57,6 +57,8 @@ void DrawTextWithOutline(const ImFont* font, float fontSize, const ImVec2& pos, 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); std::string Truncate(const std::string& input, size_t maxLength, bool useEllipsis = true, bool usePrefixEllipsis = false); +std::pair> RemoveRubyAnnotations(const char* input); +std::string ReAddRubyAnnotations(const std::string& wrappedText, const std::map& rubyMap); std::vector Split(const char* strStart, const ImFont* font, float fontSize, float maxWidth); Paragraph CalculateAnnotatedParagraph(const std::vector& lines); std::vector RemoveAnnotationFromParagraph(const std::vector& lines);