diff --git a/UI/DeveloperToolsScreen.cpp b/UI/DeveloperToolsScreen.cpp index b969531dce..cd2c641df1 100644 --- a/UI/DeveloperToolsScreen.cpp +++ b/UI/DeveloperToolsScreen.cpp @@ -384,10 +384,10 @@ void DeveloperToolsScreen::CreateUITab(UI::LinearLayout *list) { g_OSD.Show(OSDType::MESSAGE_ERROR, str); }); list->Add(new Choice(si->T("Warning")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.Show(OSDType::MESSAGE_WARNING, "Warning", "Some\nAdditional\nDetail"); + g_OSD.Show(OSDType::MESSAGE_WARNING, "Warning, a pretty long warning heading", "Some\nAdditional\nDetail, some of which is very, very long and wide and will need line wrapping on most screens."); }); list->Add(new Choice(si->T("Info")))->OnClick.Add([&](UI::EventParams &) { - g_OSD.Show(OSDType::MESSAGE_INFO, "Info"); + g_OSD.Show(OSDType::MESSAGE_INFO, "Info, info info info info info info info info info info"); }); // This one is clickable list->Add(new Choice(si->T("Success")))->OnClick.Add([&](UI::EventParams &) { diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index b95fd55a91..7a66a91176 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -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; diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 90c2963478..80aeea98aa 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -422,6 +422,7 @@ void RetroAchievementsSettingsScreen::CreateDeveloperToolsTab(UI::ViewGroup *vie viewGroup->Add(new CheckBox(&g_Config.bAchievementsSaveStateInHardcoreMode, ac->T("Allow Save State in Hardcore Mode (but not Load State)")))->SetEnabledPtr(&g_Config.bAchievementsEnable); } +// TODO : Use a spec horizontally. void MeasureAchievement(const UIContext &dc, const rc_client_achievement_t *achievement, AchievementRenderStyle style, float *w, float *h) { *w = 0.0f; switch (style) {