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,15 +688,15 @@ 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
float Lerp(float a, float b, float t)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
/* Extra padding between the start
|
||||
of the description text and the
|
||||
bottom of the thumbnail. */
|
||||
auto offsetY = Scale(24.0f);
|
||||
|
||||
float textX = clipRectMin.x - Scale(0.5f);
|
||||
float textY = thumbnailMax.y + offsetY;
|
||||
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