mirror of
				https://github.com/hedge-dev/UnleashedRecomp.git
				synced 2025-10-30 07:11:05 +00:00 
			
		
		
		
	Implemented vertical scrolling for descriptions (#271)
* options_menu: implemented vertical scrolling for descriptions * use correct size calculation * remove empty lines from descriptions without value desc, move fix * remove calculating the space for the next annotation after the last line --------- Co-authored-by: DeaTh-G <hatvongeorge@gmail.com> Co-authored-by: DeaTh-G <55578911+DeaTh-G@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									c40ffbc70d
								
							
						
					
					
						commit
						66648d550a
					
				
					 5 changed files with 143 additions and 50 deletions
				
			
		|  | @ -138,14 +138,14 @@ float4 main(in Interpolators interpolators) : SV_Target | |||
|     if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE) | ||||
|     { | ||||
|         float minAlpha = saturate((interpolators.Position.x - g_PushConstants.BoundsMin.x) / g_PushConstants.Scale.x); | ||||
|         float maxAlpha = saturate((g_PushConstants.BoundsMax.x - interpolators.Position.x) / g_PushConstants.Scale.x); | ||||
|         float maxAlpha = saturate((g_PushConstants.BoundsMax.x - interpolators.Position.x) / g_PushConstants.Scale.y); | ||||
|          | ||||
|         color.a *= minAlpha; | ||||
|         color.a *= maxAlpha; | ||||
|     } | ||||
|     else if (g_PushConstants.ShaderModifier == IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE) | ||||
|     { | ||||
|         float minAlpha = saturate((interpolators.Position.y - g_PushConstants.BoundsMin.y) / g_PushConstants.Scale.y); | ||||
|         float minAlpha = saturate((interpolators.Position.y - g_PushConstants.BoundsMin.y) / g_PushConstants.Scale.x); | ||||
|         float maxAlpha = saturate((g_PushConstants.BoundsMax.y - interpolators.Position.y) / g_PushConstants.Scale.y); | ||||
|          | ||||
|         color.a *= minAlpha; | ||||
|  |  | |||
|  | @ -80,7 +80,7 @@ void ResetTextSkew() | |||
|     SetScale({ 1.0f, 1.0f }); | ||||
| } | ||||
| 
 | ||||
| void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) | ||||
| void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleLeft, float fadeScaleRight) | ||||
| { | ||||
|     auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade); | ||||
|     callbackData->setMarqueeFade.boundsMin[0] = min.x; | ||||
|  | @ -89,10 +89,15 @@ void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) | |||
|     callbackData->setMarqueeFade.boundsMax[1] = max.y; | ||||
| 
 | ||||
|     SetShaderModifier(IMGUI_SHADER_MODIFIER_HORIZONTAL_MARQUEE_FADE); | ||||
|     SetScale({ fadeScale, 1.0f }); | ||||
|     SetScale({ fadeScaleLeft, fadeScaleRight }); | ||||
| } | ||||
| 
 | ||||
| void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) | ||||
| void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) | ||||
| { | ||||
|     SetHorizontalMarqueeFade(min, max, fadeScale, fadeScale); | ||||
| } | ||||
| 
 | ||||
| void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleTop, float fadeScaleBottom) | ||||
| { | ||||
|     auto callbackData = AddImGuiCallback(ImGuiCallback::SetMarqueeFade); | ||||
|     callbackData->setMarqueeFade.boundsMin[0] = min.x; | ||||
|  | @ -101,7 +106,12 @@ void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) | |||
|     callbackData->setMarqueeFade.boundsMax[1] = max.y; | ||||
| 
 | ||||
|     SetShaderModifier(IMGUI_SHADER_MODIFIER_VERTICAL_MARQUEE_FADE); | ||||
|     SetScale({ 1.0f, fadeScale }); | ||||
|     SetScale({ fadeScaleTop, fadeScaleBottom }); | ||||
| } | ||||
| 
 | ||||
| void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale) | ||||
| { | ||||
|     SetVerticalMarqueeFade(min, max, fadeScale, fadeScale); | ||||
| } | ||||
| 
 | ||||
| void ResetMarqueeFade() | ||||
|  | @ -353,7 +363,8 @@ 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::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; | ||||
|  | @ -400,7 +411,8 @@ std::pair<std::string, std::map<std::string, std::string>> RemoveRubyAnnotations | |||
|     return { output, rubyMap }; | ||||
| } | ||||
| 
 | ||||
| std::string ReAddRubyAnnotations(const std::string_view& wrappedText, const std::map<std::string, std::string>& 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(); | ||||
|  | @ -431,7 +443,7 @@ std::string ReAddRubyAnnotations(const std::string_view& wrappedText, const std: | |||
|     return annotatedText; | ||||
| } | ||||
| 
 | ||||
| std::vector<std::string> Split(const char* strStart, const ImFont *font, float fontSize, float maxWidth) | ||||
| std::vector<std::string> Split(const char* strStart, const ImFont* font, float fontSize, float maxWidth) | ||||
| { | ||||
|     if (!strStart) | ||||
|         return {}; | ||||
|  | @ -445,6 +457,7 @@ std::vector<std::string> Split(const char* strStart, const ImFont *font, float f | |||
|     const char *lineStart = strStart; | ||||
|     const bool wordWrapEnabled = (maxWidth > 0.0f); | ||||
|     const char *wordWrapEOL = nullptr; | ||||
| 
 | ||||
|     while (*str != 0)  | ||||
|     { | ||||
|         if (wordWrapEnabled) | ||||
|  | @ -572,10 +585,9 @@ std::vector<std::string> RemoveAnnotationFromParagraph(const std::vector<std::st | |||
|     for (auto& annotatedLine : paragraph.lines) | ||||
|     { | ||||
|         std::string annotationRemovedLine = ""; | ||||
| 
 | ||||
|         for (const auto& segment : annotatedLine) | ||||
|         { | ||||
|             annotationRemovedLine += segment.text; | ||||
|         } | ||||
| 
 | ||||
|         result.push_back(annotationRemovedLine); | ||||
|     } | ||||
|  | @ -588,9 +600,7 @@ std::string RemoveAnnotationFromParagraphLine(const std::vector<TextSegment>& an | |||
|     std::string result = ""; | ||||
| 
 | ||||
|     for (auto& segment : annotatedLine) | ||||
|     { | ||||
|         result += segment.text; | ||||
|     } | ||||
| 
 | ||||
|     return result; | ||||
| } | ||||
|  | @ -603,25 +613,19 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMar | |||
|     const auto paragraph = CalculateAnnotatedParagraph(lines); | ||||
|      | ||||
|     std::vector<std::string> annotationRemovedLines; | ||||
| 
 | ||||
|     for (const auto& line : paragraph.lines) | ||||
|     { | ||||
|         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, ""); | ||||
|         auto textSize = font->CalcTextSizeA(fontSize, FLT_MAX, 0, annotationRemovedLines[i].c_str()); | ||||
| 
 | ||||
|         x = std::max(x, textSize.x); | ||||
|         y += textSize.y + Scale(lineMargin); | ||||
| 
 | ||||
|         if (paragraph.annotated) | ||||
|         { | ||||
|             y += annotationSize.y; | ||||
|         } | ||||
|         if (paragraph.annotated && i != (annotationRemovedLines.size() - 1)) | ||||
|             y += fontSize * ANNOTATION_FONT_SIZE_MODIFIER; | ||||
|     } | ||||
| 
 | ||||
|     return { x, y }; | ||||
|  | @ -629,23 +633,27 @@ ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float lineMar | |||
| 
 | ||||
| ImVec2 MeasureCentredParagraph(const ImFont* font, float fontSize, float maxWidth, float lineMargin, const char* text) | ||||
| { | ||||
|     return MeasureCentredParagraph(font, fontSize, lineMargin, Split(text, font, fontSize, maxWidth)); | ||||
|     const auto input = RemoveRubyAnnotations(text); | ||||
|     auto lines = Split(input.first.c_str(), font, fontSize, maxWidth); | ||||
| 
 | ||||
|     for (auto& line : lines) | ||||
|         line = ReAddRubyAnnotations(line, input.second); | ||||
| 
 | ||||
|     return MeasureCentredParagraph(font, fontSize, lineMargin, lines); | ||||
| } | ||||
| 
 | ||||
| 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) | ||||
| { | ||||
|     float annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER; | ||||
|     auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER; | ||||
| 
 | ||||
|     const auto input = RemoveRubyAnnotations(text); | ||||
|     auto lines = Split(input.first.c_str(), font, fontSize, maxWidth); | ||||
| 
 | ||||
|     for (auto& line : lines) | ||||
|     { | ||||
|         line = ReAddRubyAnnotations(line, input.second); | ||||
|     } | ||||
|      | ||||
|     auto paragraphSize = MeasureCentredParagraph(font, fontSize, lineMargin, lines); | ||||
|     float offsetY = 0.0f; | ||||
|     auto offsetY = 0.0f; | ||||
| 
 | ||||
|     const auto paragraph = CalculateAnnotatedParagraph(lines); | ||||
| 
 | ||||
|  | @ -655,9 +663,8 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c | |||
| 
 | ||||
|         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; | ||||
|         auto textX = pos.x; | ||||
|         auto textY = pos.y + offsetY; | ||||
| 
 | ||||
|         if (isCentred) | ||||
|         { | ||||
|  | @ -681,14 +688,14 @@ void DrawRubyAnnotatedText(const ImFont* font, float fontSize, float maxWidth, c | |||
|             } | ||||
| 
 | ||||
|             drawMethod(segment.text.c_str(), { textX, textY }); | ||||
|              | ||||
|             textX += textSize.x; | ||||
|         } | ||||
| 
 | ||||
|         offsetY += textSize.y + Scale(lineMargin); | ||||
| 
 | ||||
|         if (paragraph.annotated) | ||||
|         { | ||||
|             offsetY += annotationSize.y; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -42,7 +42,9 @@ void SetOrigin(ImVec2 origin); | |||
| void SetScale(ImVec2 scale); | ||||
| void SetTextSkew(float yCenter, float skewScale); | ||||
| void ResetTextSkew(); | ||||
| void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleLeft, float fadeScaleRight); | ||||
| void SetHorizontalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale); | ||||
| void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScaleTop, float fadeScaleBottom); | ||||
| void SetVerticalMarqueeFade(ImVec2 min, ImVec2 max, float fadeScale); | ||||
| void ResetMarqueeFade(); | ||||
| void SetOutline(float outline); | ||||
|  |  | |||
|  | @ -292,9 +292,9 @@ void MessageWindow::Draw() | |||
|     if (Config::Language == ELanguage::Japanese) | ||||
|     { | ||||
|         textMarginX -= Scale(2.5f); | ||||
|         textMarginY -= Scale(7.5f); | ||||
|         textMarginY -= Scale(2.0f); | ||||
| 
 | ||||
|         textY += Scale(lines.size() % 2 == 0 ? 8.5f : 15.5f); | ||||
|         textY += Scale(lines.size() % 2 == 0 ? 1.5f : 8.0f); | ||||
|     } | ||||
| 
 | ||||
|     bool isController = hid::IsInputDeviceController(); | ||||
|  |  | |||
|  | @ -55,6 +55,8 @@ static constexpr float SETTINGS_NARROW_GRID_COUNT = 70.0f; | |||
| static constexpr float INFO_NARROW_GRID_COUNT = 34.0f; | ||||
| static constexpr float PADDING_NARROW_GRID_COUNT = 1.0f; | ||||
| 
 | ||||
| static constexpr float INFO_TEXT_MARQUEE_DELAY = 1.2f; | ||||
| 
 | ||||
| static constexpr int32_t g_categoryCount = 4; | ||||
| static int32_t g_categoryIndex; | ||||
| static ImVec2 g_categoryAnimMin; | ||||
|  | @ -1404,7 +1406,7 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax) | |||
|         } | ||||
|         else | ||||
|         { | ||||
|             // Specialised description for resolution scale
 | ||||
|             // Specialised description for resolution scale.
 | ||||
|             if (g_selectedItem == &Config::ResolutionScale) | ||||
|             { | ||||
|                 char buf[100]; | ||||
|  | @ -1417,54 +1419,136 @@ static void DrawInfoPanel(ImVec2 infoMin, ImVec2 infoMax) | |||
|                 desc = buf; | ||||
|             } | ||||
| 
 | ||||
|             desc += "\n\n" + g_selectedItem->GetValueDescription(Config::Language); | ||||
|             const auto& valueDescription = g_selectedItem->GetValueDescription(Config::Language); | ||||
|             if (!valueDescription.empty()) | ||||
|             { | ||||
|                 desc += "\n\n" + valueDescription; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         clipRectMin = { clipRectMin.x, thumbnailMax.y }; | ||||
| 
 | ||||
|         auto fontSize = Scale(28.0f); | ||||
|         auto annotationFontSize = fontSize * ANNOTATION_FONT_SIZE_MODIFIER; | ||||
| 
 | ||||
|         // 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; | ||||
|         /* Extra padding between the start
 | ||||
|            of the description text and the | ||||
|            bottom of the thumbnail. */ | ||||
|         auto offsetY = Scale(24.0f); | ||||
| 
 | ||||
|         auto textX = clipRectMin.x - Scale(0.5f); | ||||
|         auto textY = thumbnailMax.y + offsetY; | ||||
| 
 | ||||
|         if (Config::Language == ELanguage::Japanese) | ||||
|         { | ||||
|             // Removing some padding of the applied due to the inclusion of annotation for 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
 | ||||
|             /* 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; | ||||
|         } | ||||
| 
 | ||||
|         auto textSize = MeasureCentredParagraph(g_seuratFont, fontSize, clipRectMax.x - clipRectMin.x, 5.0f, desc.c_str()); | ||||
| 
 | ||||
|         drawList->PushClipRect(clipRectMin, clipRectMax, false); | ||||
| 
 | ||||
|         static auto isScrolling = false; | ||||
|         static auto isManualScrolling = false; | ||||
|         static auto scrollOffset = 0.0f; | ||||
|         static auto scrollTimer = 0.0f; | ||||
|         static auto scrollDirection = 1.0f; | ||||
|         auto scrollMax = textSize.y - (clipRectMax.y - textY); | ||||
|         auto scrollSpeed = Scale(50); | ||||
| 
 | ||||
|         if (scrollMax > 0.0f) | ||||
|         { | ||||
|             if (auto pInputState = SWA::CInputState::GetInstance()) | ||||
|             { | ||||
|                 auto& rPadState = pInputState->GetPadState(); | ||||
|                 auto& vert = rPadState.RightStickVertical; | ||||
|          | ||||
|                 if (fabs(vert) > 0.25f) | ||||
|                 { | ||||
|                     isManualScrolling = true; | ||||
|                     scrollOffset += vert * scrollSpeed * App::s_deltaTime; | ||||
|                 } | ||||
|                 else if (isManualScrolling && fabs(vert) <= 0.25f) | ||||
|                 { | ||||
|                     isManualScrolling = false; | ||||
|                 } | ||||
|             } | ||||
|          | ||||
|             if (!isManualScrolling) | ||||
|             { | ||||
|                 if (!isScrolling) | ||||
|                 { | ||||
|                     scrollTimer += App::s_deltaTime; | ||||
|              | ||||
|                     if (scrollTimer >= INFO_TEXT_MARQUEE_DELAY) | ||||
|                         isScrolling = true; | ||||
|                 } | ||||
|              | ||||
|                 if (isScrolling) | ||||
|                 { | ||||
|                     scrollOffset += scrollSpeed * scrollDirection * App::s_deltaTime; | ||||
|              | ||||
|                     if (scrollOffset >= scrollMax) | ||||
|                     { | ||||
|                         isScrolling = false; | ||||
|                         scrollOffset = scrollMax; | ||||
|                         scrollTimer = 0.0f; | ||||
|                         scrollDirection = -1.0f; | ||||
|                     } | ||||
|                     else if (scrollOffset <= 0.0f) | ||||
|                     { | ||||
|                         isScrolling = false; | ||||
|                         scrollOffset = 0; | ||||
|                         scrollTimer = 0.0f; | ||||
|                         scrollDirection = 1.0f; | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|          | ||||
|             scrollOffset = std::clamp(scrollOffset, 0.0f, scrollMax); | ||||
|         } | ||||
| 
 | ||||
|         SetVerticalMarqueeFade(clipRectMin, clipRectMax, Scale(24), Lerp(Scale(24), 0.0f, scrollOffset / scrollMax)); | ||||
| 
 | ||||
|         DrawRubyAnnotatedText | ||||
|         ( | ||||
|             g_seuratFont, | ||||
|             fontSize, | ||||
|             clipRectMax.x - clipRectMin.x, | ||||
|             { textX, textY }, | ||||
|             { textX, textY - scrollOffset }, | ||||
|             5.0f, | ||||
|             desc.c_str(), | ||||
| 
 | ||||
|             [=](const char* str, ImVec2 pos) | ||||
|             { | ||||
|                 DrawTextBasic(g_seuratFont, fontSize, pos, IM_COL32(255, 255, 255, 255), str); | ||||
|                 DrawTextBasic(g_seuratFont, fontSize, pos, IM_COL32_WHITE, str); | ||||
|             }, | ||||
|             [=](const char* str, float size, ImVec2 pos) | ||||
|             { | ||||
|                 DrawTextBasic(g_seuratFont, size, pos, IM_COL32(255, 255, 255, 255), str); | ||||
|                 DrawTextBasic(g_seuratFont, size, pos, IM_COL32_WHITE, str); | ||||
|             } | ||||
|         ); | ||||
| 
 | ||||
|         ResetMarqueeFade(); | ||||
| 
 | ||||
|         drawList->PopClipRect(); | ||||
| 
 | ||||
|         // Reset parameters on new selected row.
 | ||||
|         if (ImGui::GetTime() - g_rowSelectionTime <= 0.0f) | ||||
|         { | ||||
|             isScrolling = false; | ||||
|             scrollOffset = 0.0f; | ||||
|             scrollTimer = 0.0f; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     ResetProceduralOrigin(); | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Hyper
						Hyper