Implement correct word wrapping for popup notices that don't fit on the screen

This commit is contained in:
Henrik Rydgård committed 2025-11-27 19:34:46 +01:00
1 parent e5bafa4264
commit 56feb8692f
3 files changed
+34 -30

No files matched your search

+31 -28
View File
@@ -68,17 +68,7 @@ static NoticeLevel GetNoticeLevel(OSDType type) {
}
// Align only matters here for the ASCII-only flag.
static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::string &text, const std::string &details, const std::string &iconName, int align, float *width, float *height, float *height1) {
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, text, width, height, align);
*height1 = *height;
float width2 = 0.0f, height2 = 0.0f;
if (!details.empty()) {
dc.MeasureText(dc.GetTheme().uiFont, extraTextScale, extraTextScale, details, &width2, &height2, align);
*width = std::max(*width, width2);
}
static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::string &text, const std::string &details, const std::string &iconName, int align, float maxWidth, float *width, float *height, float *height1) {
float iconW = 0.0f;
float iconH = 0.0f;
if (!iconName.empty() && !startsWith(iconName, "I_")) { // Check for atlas image. Bit hacky, but we choose prefixes for icon IDs anyway in a way that this is safe.
@@ -96,9 +86,25 @@ static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::str
}
}
iconW += 5.0f;
float chromeWidth = iconW + 5.0f + 12.0f;
float availableWidth = maxWidth - chromeWidth;
*width += iconW + 12.0f;
// OK, now that we have figured out how much space we have for the text, we can measure it (with wrapping if needed).
// We currently don't wrap the title.
float titleWidth, titleHeight;
dc.MeasureText(dc.GetTheme().uiFont, 1.0f, 1.0f, text, &titleWidth, &titleHeight, align);
*width = std::min(titleWidth, availableWidth);
*height1 = titleHeight;
float width2 = 0.0f, height2 = 0.0f;
if (!details.empty()) {
dc.MeasureTextRect(dc.GetTheme().uiFont, extraTextScale, extraTextScale, details, availableWidth, &width2, &height2, align | FLAG_WRAP_TEXT);
*width = std::max(*width, width2);
}
*width += chromeWidth;
if (height2 == 0.0f && iconH < 2.0f * *height1) {
// Center vertically using the icon.
*height1 = std::max(*height1, iconH + 2.0f);
@@ -107,14 +113,14 @@ static void MeasureNotice(const UIContext &dc, NoticeLevel level, const std::str
}
// Align only matters here for the ASCII-only flag.
static void MeasureOSDEntry(const UIContext &dc, const OnScreenDisplay::Entry &entry, int align, float *width, float *height, float *height1) {
static void MeasureOSDEntry(const UIContext &dc, const OnScreenDisplay::Entry &entry, int align, float maxWidth, float *width, float *height, float *height1) {
if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) {
const rc_client_achievement_t *achievement = rc_client_get_achievement_info(Achievements::GetClient(), entry.numericID);
MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, width, height);
*width = 550.0f;
*width = std::min(maxWidth, 550.0f);
*height1 = *height;
} else {
MeasureNotice(dc, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, width, height, height1);
MeasureNotice(dc, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, maxWidth, width, height, height1);
}
}
@@ -172,7 +178,7 @@ static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLeve
Bounds primaryBounds = bounds;
primaryBounds.h = height1;
dc.DrawTextShadowRect(text, primaryBounds.Inset(2.0f, 0.0f, 1.0f, 0.0f), foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_VCENTER);
dc.DrawTextShadowRect(text, primaryBounds.Inset(2.0f, 0.0f, 1.0f, 0.0f), foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_VCENTER | FLAG_ELLIPSIZE_TEXT);
if (!details.empty()) {
Bounds bottomTextBounds = bounds.Inset(3.0f, height1 + 5.0f, 3.0f, 3.0f);
@@ -181,7 +187,7 @@ static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLeve
dc.FillRect(backgroundDark, bottomTextBounds);
}
dc.SetFontScale(extraTextScale, extraTextScale);
dc.DrawTextRect(details, bottomTextBounds.Inset(1.0f, 1.0f), foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_LEFT);
dc.DrawTextRect(details, bottomTextBounds.Inset(1.0f, 1.0f), foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_LEFT | FLAG_WRAP_TEXT);
}
dc.SetFontScale(1.0f, 1.0f);
}
@@ -380,14 +386,14 @@ void OnScreenMessagesView::Draw(UIContext &dc) {
measuredEntry.style = AchievementRenderStyle::UNLOCKED;
MeasureAchievement(dc, achievement, AchievementRenderStyle::UNLOCKED, &measuredEntry.w, &measuredEntry.h);
measuredEntry.h1 = measuredEntry.h;
measuredEntry.w = 550.0f;
measuredEntry.w = std::min(bounds_.w, 550.0f);
break;
}
case OSDType::PROGRESS_BAR:
MeasureOSDProgressBar(dc, entry, &measuredEntry.w, &measuredEntry.h);
break;
default:
MeasureOSDEntry(dc, entry, measuredEntry.align, &measuredEntry.w, &measuredEntry.h, &measuredEntry.h1);
MeasureOSDEntry(dc, entry, measuredEntry.align, bounds_.w, &measuredEntry.w, &measuredEntry.h, &measuredEntry.h1);
break;
}
@@ -575,16 +581,13 @@ void OSDOverlayScreen::update() {
}
void NoticeView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const {
Bounds bounds(0, 0, layoutParams_->width, layoutParams_->height);
if (bounds.w < 0) {
float layoutWidth = layoutParams_->width;
if (layoutWidth < 0) {
// If there's no size, let's grow as big as we want.
bounds.w = horiz.size;
layoutWidth = horiz.size;
}
if (bounds.h < 0) {
bounds.h = vert.size;
}
ApplyBoundsBySpec(bounds, horiz, vert);
MeasureNotice(dc, level_, text_, detailsText_, iconName_, 0, &w, &h, &height1_);
ApplyBoundBySpec(layoutWidth, horiz);
MeasureNotice(dc, level_, text_, detailsText_, iconName_, 0, layoutWidth, &w, &h, &height1_);
// Layout hack! Some weird problems with the layout that I can't figure out right now..
if (squishy_) {
w = 50.0;