diff --git a/UnleashedRecomp/ui/imgui_utils.cpp b/UnleashedRecomp/ui/imgui_utils.cpp index 683eba7..2bed3ed 100644 --- a/UnleashedRecomp/ui/imgui_utils.cpp +++ b/UnleashedRecomp/ui/imgui_utils.cpp @@ -189,7 +189,68 @@ 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 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 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& position, const ImVec2& min, const ImVec2& max, ImU32 color, const char* text, double time, double delay, double speed) +{ + auto drawList = ImGui::GetForegroundDrawList(); + auto rectWidth = max.x - min.x; + auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, text); + auto textX = position.x - fmodf(std::max(0.0, ImGui::GetTime() - (time + delay)) * speed, textSize.x + rectWidth); + + drawList->PushClipRect(min, max, true); + + if (textX <= position.x) + { + DrawRubyAnnotatedText + ( + font, + fontSize, + FLT_MAX, + { textX, position.y }, + 0.0f, + text, + [=](const char* str, ImVec2 pos) + { + DrawTextBasic(font, fontSize, pos, color, str); + }, + [=](const char* str, float size, ImVec2 pos) + { + DrawTextBasic(font, size, pos, color, str); + } + ); + } + + if (textX + textSize.x < position.x) + { + DrawRubyAnnotatedText + ( + font, + fontSize, + FLT_MAX, + { textX + textSize.x + rectWidth, position.y }, + 0.0f, + text, + [=](const char* str, ImVec2 pos) + { + DrawTextBasic(font, fontSize, pos, color, str); + }, + [=](const char* str, float size, ImVec2 pos) + { + DrawTextBasic(font, size, pos, color, str); + } + ); + } + + 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; @@ -199,10 +260,10 @@ void DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& pos, drawList->PushClipRect(min, max, true); if (textX <= pos.x) - drawList->AddText(font, fontSize, { textX, pos.y }, color, text); + DrawTextWithShadow(font, fontSize, { textX, pos.y }, colour, text, offset, radius, shadowColour); if (textX + textSize.x < pos.x) - drawList->AddText(font, fontSize, { textX + textSize.x + rectWidth, pos.y }, color, text); + DrawTextWithShadow(font, fontSize, { textX + textSize.x + rectWidth, pos.y }, colour, text, offset, radius, shadowColour); drawList->PopClipRect(); } @@ -273,6 +334,84 @@ 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_view& 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 += "["; + annotatedText += mainText; + annotatedText += ":"; + annotatedText += rubyText; + annotatedText += "]"; + + 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) @@ -359,17 +498,111 @@ std::vector Split(const char* strStart, const ImFont *font, float f return result; } -ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, std::vector lines) +Paragraph CalculateAnnotatedParagraph(const std::vector& lines) +{ + Paragraph result; + + for (const auto& line : lines) + { + std::vector segments; + + size_t pos = 0; + size_t start = 0; + + while ((start = line.find('[', pos)) != std::string::npos) + { + size_t end = line.find(']', start); + if (end == std::string::npos) + break; + + size_t colon = line.find(':', start); + if (colon != std::string::npos && colon < end) + { + if (start != pos) + { + segments.push_back({ false, line.substr(pos, start - pos), "" }); + } + + segments.push_back({ true, line.substr(start + 1, colon - start - 1), line.substr(colon + 1, end - colon - 1) }); + + result.annotated = true; + pos = end + 1; + } + else + { + pos = start + 1; + } + } + + if (pos < line.size()) + { + segments.push_back({ false, line.substr(pos), "" }); + } + + result.lines.push_back(segments); + } + + return result; +} + +std::vector RemoveAnnotationFromParagraph(const std::vector& lines) +{ + std::vector result; + const auto paragraph = CalculateAnnotatedParagraph(lines); + + for (auto& annotatedLine : paragraph.lines) + { + std::string annotationRemovedLine = ""; + for (const auto& segment : annotatedLine) + { + annotationRemovedLine += segment.text; + } + + result.push_back(annotationRemovedLine); + } + + return result; +} + +std::string RemoveAnnotationFromParagraphLine(const std::vector& annotatedLine) +{ + std::string result = ""; + + for (auto& segment : annotatedLine) + { + result += segment.text; + } + + return result; +} + +ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector& lines) { auto x = 0.0f; auto y = 0.0f; - for (auto& str : lines) + const auto paragraph = CalculateAnnotatedParagraph(lines); + + std::vector annotationRemovedLines; + for (const auto& line : paragraph.lines) { - auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str()); + annotationRemovedLines.emplace_back(RemoveAnnotationFromParagraphLine(line)); + } + + for (size_t i = 0; i < annotationRemovedLines.size(); i++) + { + auto& line = annotationRemovedLines[i]; + + auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, line.c_str()); + auto annotationSize = font->CalcTextSizeA(fontSize * ANNOTATION_FONT_SIZE_MODIFIER, FLT_MAX, 0, ""); x = std::max(x, textSize.x); y += textSize.y + Scale(lineMargin); + + if (paragraph.annotated) + { + y += annotationSize.y; + } } return { x, y }; @@ -380,47 +613,66 @@ 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) { - auto lines = Split(text, font, fontSize, maxWidth); - auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines); - auto offsetY = 0.0f; + float annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER; - for (int i = 0; i < lines.size(); i++) + const auto input = RemoveRubyAnnotations(text); + auto lines = Split(input.first.c_str(), font, fontSize, maxWidth); + + for (auto& line : lines) { - auto& str = lines[i]; - auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, str.c_str()); + line = ReAddRubyAnnotations(line, input.second); + } + + auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines); + float offsetY = 0.0f; - auto textX = str.starts_with("- ") - ? centre.x - paragraphSize.x / 2 - : centre.x - textSize.x / 2; + const auto paragraph = CalculateAnnotatedParagraph(lines); - auto textY = centre.y - paragraphSize.y / 2 + offsetY; + for (const auto& annotatedLine : paragraph.lines) + { + const auto annotationRemovedLine = RemoveAnnotationFromParagraphLine(annotatedLine); - drawMethod(str.c_str(), { textX, textY }); + auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLine.c_str()); + auto annotationSize = font->CalcTextSizeA(annotationFontSize, FLT_MAX, 0, ""); + + float textX = pos.x; + float textY = pos.y + offsetY; + + if (isCentred) + { + textX = annotationRemovedLine.starts_with("- ") + ? pos.x - paragraphSize.x / 2 + : pos.x - textSize.x / 2; + + textY = pos.y - paragraphSize.y / 2 + offsetY; + } + + for (const auto& segment : annotatedLine) + { + textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, segment.text.c_str()); + + if (segment.annotated) + { + annotationSize = font->CalcTextSizeA(annotationFontSize, FLT_MAX, 0, segment.annotation.c_str()); + float annotationX = textX + (textSize.x - annotationSize.x) / 2.0f; + + annotationDrawMethod(segment.annotation.c_str(), annotationFontSize, { annotationX, textY - annotationFontSize }); + } + + drawMethod(segment.text.c_str(), { textX, textY }); + textX += textSize.x; + } offsetY += textSize.y + Scale(lineMargin); + if (paragraph.annotated) + { + offsetY += annotationSize.y; + } } } -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(); -} - float Lerp(float a, float b, float t) { return a + (b - a) * t; diff --git a/UnleashedRecomp/ui/imgui_utils.h b/UnleashedRecomp/ui/imgui_utils.h index 244487c..f664700 100644 --- a/UnleashedRecomp/ui/imgui_utils.h +++ b/UnleashedRecomp/ui/imgui_utils.h @@ -14,11 +14,24 @@ #define BREATHE_MOTION(start, end, time, rate) Lerp(start, end, (sin((ImGui::GetTime() - time) * (2.0f * M_PI / rate)) + 1.0f) / 2.0f) +constexpr float ANNOTATION_FONT_SIZE_MODIFIER = 0.6f; + extern std::unique_ptr g_texGeneralWindow; extern std::unique_ptr g_texLight; extern std::unique_ptr g_texSelectFade; extern std::unique_ptr g_texSelectFill; +struct TextSegment { + bool annotated; + std::string text; + std::string annotation; +}; + +struct Paragraph { + bool annotated = false; + std::vector> lines; +}; + void InitImGuiUtils(); void SetGradient(const ImVec2& min, const ImVec2& max, ImU32 top, ImU32 bottom); @@ -40,17 +53,23 @@ 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 DrawTextWithMarquee(const ImFont* font, float fontSize, const ImVec2& position, 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); 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_view& wrappedText, const std::map& rubyMap); std::vector Split(const char* strStart, const ImFont* font, float fontSize, float maxWidth); -ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, std::vector lines); +Paragraph CalculateAnnotatedParagraph(const std::vector& lines); +std::vector RemoveAnnotationFromParagraph(const std::vector& lines); +std::string RemoveAnnotationFromParagraphLine(const std::vector& annotatedLine); +ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector& lines); ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text); -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)); +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); 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/installer_wizard.cpp b/UnleashedRecomp/ui/installer_wizard.cpp index 9da1bdc..1027f60 100644 --- a/UnleashedRecomp/ui/installer_wizard.cpp +++ b/UnleashedRecomp/ui/installer_wizard.cpp @@ -65,19 +65,19 @@ static constexpr double PULSE_ANIMATION_LOOP_SPEED = 1.5; static constexpr double PULSE_ANIMATION_LOOP_DELAY = 0.5; static constexpr double PULSE_ANIMATION_LOOP_FADE_HIGH_POINT = 0.5; -constexpr float IMAGE_X = 165.0f; -constexpr float IMAGE_Y = 106.0f; +constexpr float IMAGE_X = 161.5f; +constexpr float IMAGE_Y = 103.5f; constexpr float IMAGE_WIDTH = 512.0f; constexpr float IMAGE_HEIGHT = 512.0f; -constexpr float CONTAINER_X = 510.0f; -constexpr float CONTAINER_Y = 225.0f; -constexpr float CONTAINER_WIDTH = 528.0f; -constexpr float CONTAINER_HEIGHT = 245.0f; +constexpr float CONTAINER_X = 513.0f; +constexpr float CONTAINER_Y = 226.0f; +constexpr float CONTAINER_WIDTH = 526.5f; +constexpr float CONTAINER_HEIGHT = 246.0f; constexpr float SIDE_CONTAINER_WIDTH = CONTAINER_WIDTH / 2.0f; constexpr float BOTTOM_X_GAP = 4.0f; -constexpr float BOTTOM_Y_GAP = 4.0f; +constexpr float BOTTOM_Y_GAP = 6.0f; constexpr float CONTAINER_BUTTON_WIDTH = 250.0f; constexpr float CONTAINER_BUTTON_GAP = 9.0f; constexpr float BUTTON_HEIGHT = 22.0f; @@ -512,9 +512,9 @@ static void DrawHeaderIcons() { auto drawList = ImGui::GetForegroundDrawList(); - float iconsPosX = 253.0f; - float iconsPosY = 79.0f; - float iconsScale = 58; + float iconsPosX = 256.0f; + float iconsPosY = 80.0f; + float iconsScale = 62.0f; // Miles Electric Icon float milesIconMotion = ComputeMotionInstaller(g_appearTime, g_disappearTime, MILES_ICON_ANIMATION_TIME, MILES_ICON_ANIMATION_DURATION); @@ -594,8 +594,8 @@ static void DrawScanlineBars() DrawTextWithOutline ( g_dfsogeistdFont, - Scale(42), - { g_aspectRatioOffsetX + Scale(285), Scale(57) }, + Scale(48.0f), + { g_aspectRatioOffsetX + Scale(288.0f), Scale(54.5f) }, IM_COL32(255, 195, 0, 255 * alphaMotion * breatheMotion), headerText.c_str(), 4, IM_COL32(0, 0, 0, 255 * alphaMotion * breatheMotion), @@ -669,17 +669,18 @@ static void DrawContainer(ImVec2 min, ImVec2 max, bool isTextArea) } // The draw area - drawList->PushClipRect({ min.x + gridSize * 2.0f, min.y + gridSize * 2.0f }, { max.x - gridSize * 2.0f + 1.0f, max.y - gridSize * 2.0f + 1.0f }); + drawList->PushClipRect({ min.x - gridSize * 2.0f, min.y + gridSize * 2.0f }, { max.x - gridSize * 2.0f + 1.0f, max.y - gridSize * 2.0f + 1.0f }); } static void DrawDescriptionContainer() { auto &res = ImGui::GetIO().DisplaySize; auto drawList = ImGui::GetForegroundDrawList(); - auto fontSize = Scale(26.0f); + auto fontSize = Scale(28.0f); + auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER; - ImVec2 descriptionMin = { round(g_aspectRatioOffsetX + Scale(CONTAINER_X)), round(g_aspectRatioOffsetY + Scale(CONTAINER_Y)) }; - ImVec2 descriptionMax = { round(g_aspectRatioOffsetX + Scale(CONTAINER_X + CONTAINER_WIDTH)), round(g_aspectRatioOffsetY + Scale(CONTAINER_Y + CONTAINER_HEIGHT)) }; + ImVec2 descriptionMin = { round(g_aspectRatioOffsetX + Scale(CONTAINER_X + 0.5f)), round(g_aspectRatioOffsetY + Scale(CONTAINER_Y + 0.5f)) }; + ImVec2 descriptionMax = { round(g_aspectRatioOffsetX + Scale(CONTAINER_X + 0.5f + CONTAINER_WIDTH)), round(g_aspectRatioOffsetY + Scale(CONTAINER_Y + 0.5f + CONTAINER_HEIGHT)) }; SetProceduralOrigin(descriptionMin); DrawContainer(descriptionMin, descriptionMax, true); @@ -706,19 +707,53 @@ static void DrawDescriptionContainer() auto clipRectMin = drawList->GetClipRectMin(); auto clipRectMax = drawList->GetClipRectMax(); - drawList->AddText + float textX = clipRectMin.x + fontSize; + float textY = clipRectMin.y - Scale(1.0f); + + float lineMargin = 5.0f; + + if (Config::Language == ELanguage::Japanese) + { + lineMargin = 5.5f; + + // Removing some padding of the applied due to the inclusion of annotation for Japanese + textX -= (fontSize + Scale(1.5f)); + textY -= Scale(7.0f); + + // The annotation (and thus the Japanese) can be drawn above the edges of the info panel thus the clip needs to be extended a bit + clipRectMin.x -= annotationFontSize; + clipRectMin.y -= annotationFontSize; + clipRectMax.x += annotationFontSize; + clipRectMax.y += annotationFontSize; + + textX += annotationFontSize; + textY += annotationFontSize; + } + + drawList->PushClipRect(clipRectMin, clipRectMax, false); + + DrawRubyAnnotatedText ( g_seuratFont, fontSize, - { clipRectMin.x, clipRectMin.y }, - IM_COL32(255, 255, 255, 255 * textAlpha), + clipRectMax.x - clipRectMin.x, + { textX, textY }, + lineMargin, descriptionText, - 0, - clipRectMax.x - clipRectMin.x + [=](const char* str, ImVec2 pos) + { + DrawTextBasic(g_seuratFont, fontSize, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str); + }, + [=](const char* str, float size, ImVec2 pos) + { + DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255 * textAlpha), str); + } ); drawList->PopClipRect(); + drawList->PopClipRect(); + if (g_currentPage == WizardPage::InstallSucceeded) { auto hedgeDevStr = "hedge-dev"; diff --git a/UnleashedRecomp/ui/message_window.cpp b/UnleashedRecomp/ui/message_window.cpp index fb48688..8e562c7 100644 --- a/UnleashedRecomp/ui/message_window.cpp +++ b/UnleashedRecomp/ui/message_window.cpp @@ -272,10 +272,31 @@ void MessageWindow::Draw() auto maxWidth = Scale(820); auto fontSize = Scale(28); - auto textSize = MeasureCentredParagraph(g_fntSeurat, fontSize, maxWidth, 5, g_text.c_str()); + + const auto input = RemoveRubyAnnotations(g_text.c_str()); + auto lines = Split(input.first.c_str(), g_fntSeurat, fontSize, maxWidth); + + for (auto& line : lines) + { + line = ReAddRubyAnnotations(line, input.second); + } + + auto lineMargin = Config::Language != ELanguage::Japanese ? 5.0f : 5.5f; + auto textSize = MeasureCentredParagraph(g_fntSeurat, fontSize, lineMargin, lines); auto textMarginX = Scale(37); auto textMarginY = Scale(45); + auto textX = centre.x; + auto textY = centre.y + Scale(3); + + if (Config::Language == ELanguage::Japanese) + { + textMarginX -= Scale(2.5f); + textMarginY -= Scale(7.5f); + + textY += Scale(lines.size() % 2 == 0 ? 8.5f : 15.5f); + } + bool isController = hid::IsInputDeviceController(); bool isKeyboard = hid::g_inputDevice == hid::EInputDevice::Keyboard; @@ -307,19 +328,25 @@ void MessageWindow::Draw() if (DrawContainer(g_appearTime, centre, { textSize.x / 2 + textMarginX, textSize.y / 2 + textMarginY }, !g_isControlsVisible)) { - DrawCentredParagraph + DrawRubyAnnotatedText ( g_fntSeurat, fontSize, maxWidth, - { centre.x, centre.y + Scale(3) }, - 5, + { textX, textY }, + lineMargin, g_text.c_str(), [=](const char* str, ImVec2 pos) { DrawTextWithShadow(g_fntSeurat, fontSize, pos, IM_COL32(255, 255, 255, 255), str); - } + }, + [=](const char* str, float size, ImVec2 pos) + { + DrawTextWithShadow(g_fntSeurat, size, pos, IM_COL32(255, 255, 255, 255), str, 1.0f); + }, + + true ); drawList->PopClipRect(); diff --git a/UnleashedRecomp/ui/options_menu.cpp b/UnleashedRecomp/ui/options_menu.cpp index 3fd5fbc..1f701e3 100644 --- a/UnleashedRecomp/ui/options_menu.cpp +++ b/UnleashedRecomp/ui/options_menu.cpp @@ -724,6 +724,11 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef* conf auto alpha = fadedOut ? 0.5f : 1.0f; auto textColour = IM_COL32(255, 255, 255, 255 * alpha); + if (Config::Language == ELanguage::Japanese) + { + textPos.y += Scale(10.0f); + } + if (g_selectedItem == config) { float prevItemOffset = (g_prevSelectedRowIndex - g_selectedRowIndex) * (optionHeight + optionPadding); @@ -746,7 +751,27 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef* conf } else { - drawList->AddText(g_seuratFont, size, textPos, textColour, configName.c_str(), 0, 0.0f, &textClipRect); + drawList->PushClipRect(min, max, true); + + DrawRubyAnnotatedText + ( + g_seuratFont, + size, + FLT_MAX, + textPos, + 0.0f, + configName.c_str(), + [=](const char* str, ImVec2 pos) + { + DrawTextBasic(g_seuratFont, size, pos, textColour, str); + }, + [=](const char* str, float annotationSize, ImVec2 pos) + { + DrawTextBasic(g_seuratFont, annotationSize, pos, textColour, str); + } + ); + + drawList->PopClipRect(); } // Right side @@ -1231,18 +1256,51 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax) desc += "\n\n" + g_selectedItem->GetValueDescription(Config::Language); } - auto size = Scale(26.0f); + auto fontSize = Scale(28.0f); + auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER; - drawList->AddText + // Extra padding between the start of the description text and the bottom of the thumbnail + float offsetY = Scale(24.0f); + + float textX = clipRectMin.x - Scale(0.5f); + float textY = thumbnailMax.y + offsetY; + + if (Config::Language == ELanguage::Japanese) + { + // Removing some padding of the applied due to the inclusion of annotation for Japanese + textY -= Scale(8.0f); + + // The annotation (and thus the Japanese) can be drawn above the edges of the info panel thus the clip needs to be extended a bit + clipRectMin.x -= annotationFontSize; + clipRectMin.y -= annotationFontSize; + clipRectMax.x += annotationFontSize; + clipRectMax.y += annotationFontSize; + + textY += annotationFontSize; + } + + drawList->PushClipRect(clipRectMin, clipRectMax, false); + + DrawRubyAnnotatedText ( g_seuratFont, - size, - { clipRectMin.x, thumbnailMax.y + size - 5.0f }, - IM_COL32_WHITE, + fontSize, + clipRectMax.x - clipRectMin.x, + { textX, textY }, + 5.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); + } ); + + drawList->PopClipRect(); } ResetProceduralOrigin();