mirror of
				https://github.com/hedge-dev/UnleashedRecomp.git
				synced 2025-10-30 07:11:05 +00:00 
			
		
		
		
	Add ruby annotation support for text displayed in various spaces. (#232)
* allow preliminary annotation on DrawCenteredParagraph * improve annotated text line spacing * fix functionality of non-annotated paragraphs * a lot of very bad code that but line wrapping works * support ruby annotations for options menu descriptions * make installer wizard more accurate * remove wrapper function * add furigana support to config names * add furigana support for marquee text for options * fully support annotated text in options menu * fix option names being split to multiple lines * fix and cleanup installer wizard text placements * implement furigana support for message window * remove regex usage * remove excessive const ref usage
This commit is contained in:
		
							parent
							
								
									091b4ef089
								
							
						
					
					
						commit
						4816d4aa9d
					
				
					 5 changed files with 465 additions and 74 deletions
				
			
		|  | @ -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<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations(const char* input) { | ||||
|     std::string output; | ||||
|     std::map<std::string, std::string> 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<std::string, std::string>& 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<std::string> Split(const char* strStart, const ImFont *font, float fontSize, float maxWidth) | ||||
| { | ||||
|     if (!strStart) | ||||
|  | @ -359,17 +498,111 @@ std::vector<std::string> Split(const char* strStart, const ImFont *font, float f | |||
|     return result; | ||||
| } | ||||
| 
 | ||||
| ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, std::vector<std::string> lines) | ||||
| Paragraph CalculateAnnotatedParagraph(const std::vector<std::string>& lines) | ||||
| { | ||||
|     Paragraph result; | ||||
| 
 | ||||
|     for (const auto& line : lines) | ||||
|     { | ||||
|         std::vector<TextSegment> 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<std::string> RemoveAnnotationFromParagraph(const std::vector<std::string>& lines) | ||||
| { | ||||
|     std::vector<std::string> 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<TextSegment>& 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<std::string>& lines) | ||||
| { | ||||
|     auto x = 0.0f; | ||||
|     auto y = 0.0f; | ||||
| 
 | ||||
|     for (auto& str : lines) | ||||
|     const auto paragraph = CalculateAnnotatedParagraph(lines); | ||||
|      | ||||
|     std::vector<std::string> 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<void(const char*, ImVec2)> drawMethod) | ||||
| void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, const ImVec2& pos, float lineMargin, const char* text, std::function<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> 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; | ||||
|  |  | |||
|  | @ -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<GuestTexture> g_texGeneralWindow; | ||||
| extern std::unique_ptr<GuestTexture> g_texLight; | ||||
| extern std::unique_ptr<GuestTexture> g_texSelectFade; | ||||
| extern std::unique_ptr<GuestTexture> g_texSelectFill; | ||||
| 
 | ||||
| struct TextSegment { | ||||
|     bool annotated; | ||||
|     std::string text; | ||||
|     std::string annotation; | ||||
| }; | ||||
| 
 | ||||
| struct Paragraph { | ||||
|     bool annotated = false; | ||||
|     std::vector<std::vector<TextSegment>> 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<std::string> strs); | ||||
| std::string Truncate(const std::string& input, size_t maxLength, bool useEllipsis = true, bool usePrefixEllipsis = false); | ||||
| std::pair<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations(const char* input); | ||||
| std::string ReAddRubyAnnotations(const std::string_view& wrappedText, const std::map<std::string, std::string>& rubyMap); | ||||
| std::vector<std::string> Split(const char* strStart, const ImFont* font, float fontSize, float maxWidth); | ||||
| ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, std::vector<std::string> lines); | ||||
| Paragraph CalculateAnnotatedParagraph(const std::vector<std::string>& lines); | ||||
| std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::string>& lines); | ||||
| std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& annotatedLine); | ||||
| ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMargin, const std::vector<std::string>& 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<void(const char*, ImVec2)> 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<void(const char*, ImVec2)> drawMethod, std::function<void(const char*, float, ImVec2)> 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); | ||||
|  |  | |||
|  | @ -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"; | ||||
|  |  | |||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -724,6 +724,11 @@ static void DrawConfigOption(int32_t rowIndex, float yOffset, ConfigDef<T>* 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<T>* 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(); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 DeaTh-G
						DeaTh-G