Merge pull request #22816 from hrydgard/popup-round-corners

UI: Round corners and a little padding on popups and notifications
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2026-10-27 22:36:18 +01:00
commit 8d96fdb6cd
9 files changed
+53 -32

No files matched your search

+2 -1
View File
@@ -393,7 +393,8 @@ void UIContext::FillRoundRect(const UI::Drawable &drawable, const Bounds &bounds
uidrawbuffer_->DrawRoundRect(bounds, radius, drawable.color, RoundRectStyle::Filled, corners);
break;
default:
// Not supported
// Not supported, draw it square.
FillRect(drawable, bounds);
break;
}
}
+2 -2
View File
@@ -92,7 +92,7 @@ void MeasureNotice(const UIContext &dc, NoticeLevel level, std::string_view text
*height = std::max(heightSum, iconH + m) + padding * 2.0f;
}
void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLevel level, std::string_view text, std::string_view details, std::string_view iconName, int align, float alpha, OSDMessageFlags flags, float timeVal, float padding, RoundCorners corners) {
void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLevel level, std::string_view text, std::string_view details, std::string_view iconName, int align, float alpha, OSDMessageFlags flags, float timeVal, float padding, float radius, RoundCorners corners) {
UI::Drawable background = UI::Drawable(colorAlpha(GetNoticeBackgroundColor(level), alpha));
dc.SetFontStyle(dc.GetTheme().uiFont);
@@ -100,7 +100,7 @@ void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLevel level
uint32_t foreGround = whiteAlpha(alpha);
if (!(flags & OSDMessageFlags::Transparent)) {
dc.FillRoundRect(background, bounds, dc.GetTheme().choiceRoundRadius, corners);
dc.FillRoundRect(background, bounds, radius, corners);
}
bounds = bounds.Expand(-padding);
+1 -1
View File
@@ -59,4 +59,4 @@ uint32_t GetNoticeBackgroundColor(NoticeLevel type);
// padding is added around the contents, inside the background. Pass the same to both.
void MeasureNotice(const UIContext &dc, NoticeLevel level, std::string_view text, std::string_view details, std::string_view iconName, int align, float maxWidth, float *width, float *height, float *height1, float padding = 0.0f);
// Doesn't draw a drop shadow, floating notices draw their own.
void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLevel level, std::string_view text, std::string_view details, std::string_view iconName, int align, float alpha, OSDMessageFlags flags, float timeVal, float padding = 0.0f, RoundCorners corners = RoundCorners::None);
void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLevel level, std::string_view text, std::string_view details, std::string_view iconName, int align, float alpha, OSDMessageFlags flags, float timeVal, float padding = 0.0f, float radius = 0.0f, RoundCorners corners = RoundCorners::All);
+17 -5
View File
@@ -192,6 +192,7 @@ void PopupScreen::CreateViews() {
// Since we scale a bit, make the dropshadow bleed past the edges.
box_->SetDropShadowExpand(std::max(g_display.dp_xres, g_display.dp_yres));
box_->SetSpacing(0.0f);
box_->SetPadding(Margins(8));
if (!title_.empty()) {
View *title = new PopupHeader(title_);
@@ -230,11 +231,16 @@ void PopupScreen::CreateViews() {
defaultButton_->OnClick.Handle<UIScreen>(this, &UIScreen::OnOK);
}
// The buttons have margins between them, so round them all.
for (int i = 0; i < buttonRow->GetNumSubviews(); i++) {
buttonRow->GetViewByIndex(i)->SetRoundCorners(RoundCorners::All);
}
box_->Add(buttonRow);
}
// The popup layout isn't compatible with round corners.
box_->ApplyRoundCorners(RoundCorners::None);
box_->SetRoundCorners(RoundCorners::All);
// Rounds the top of the header and the bottom of the last view, to match the box.
box_->ApplyRoundCorners(RoundCorners::All);
}
void MessagePopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
@@ -654,8 +660,12 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
vert->Add(slider_);
LinearLayout *lin = vert->Add(new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(UI::Margins(10, 10))));
lin->Add(new Button("", ImageID("I_MINUS"), new LayoutParams(60.0f, 60.0f)))->OnClick.Handle(this, &SliderPopupScreen::OnDecrease);
lin->Add(new Button("", ImageID("I_PLUS"), new LayoutParams(60.0f, 60.0f)))->OnClick.Handle(this, &SliderPopupScreen::OnIncrease);
Button *decrease = lin->Add(new Button("", ImageID("I_MINUS"), new LayoutParams(60.0f, 60.0f)));
decrease->OnClick.Handle(this, &SliderPopupScreen::OnDecrease);
decrease->SetRoundCorners();
Button *increase = lin->Add(new Button("", ImageID("I_PLUS"), new LayoutParams(60.0f, 60.0f)));
increase->OnClick.Handle(this, &SliderPopupScreen::OnIncrease);
increase->SetRoundCorners();
edit_ = new TextEdit("", Title(), "", new LinearLayoutParams(1.0f));
edit_->SetMaxLen(16);
@@ -670,12 +680,14 @@ void SliderPopupScreen::CreatePopupContents(UI::ViewGroup *parent) {
if (defaultValue_ != NO_DEFAULT_FLOAT) {
auto di = GetI18NCategory(I18NCat::DIALOG);
lin->Add(new Button(di->T("Reset"), new LayoutParams(WRAP_CONTENT, 60.0f)))->OnClick.Add([=](UI::EventParams &) {
Button *reset = lin->Add(new Button(di->T("Reset"), new LayoutParams(WRAP_CONTENT, 60.0f)));
reset->OnClick.Add([=](UI::EventParams &) {
sliderValue_ = defaultValue_;
changing_ = true;
UpdateTextBox();
changing_ = false;
});
reset->SetRoundCorners();
}
if (!negativeLabel_.empty())
+1
View File
@@ -663,6 +663,7 @@ void ListView::CreateAllItems() {
OnItemCallback(i, e);
});
}
linLayout_->ApplyRoundCorners();
}
void ListView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) {
+5 -4
View File
@@ -734,11 +734,12 @@ void PopupHeader::Draw(UIContext &dc) {
}
// Header background
dc.FillRect(dc.GetTheme().popupTitleStyle.background, bounds_);
dc.FillRoundRect(dc.GetTheme().popupTitleStyle.background, bounds_, dc.GetTheme().choiceRoundRadius, roundCorners_);
// Header title text
dc.DrawText(text_, bounds_.x + tx, bounds_.centerY(), dc.GetTheme().popupTitleStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER);
// Underline
dc.Draw()->DrawImageCenterTexel(dc.GetTheme().whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.GetTheme().popupTitleStyle.fgColor);
// Underline. Skipping it with the new style.
// dc.Draw()->DrawImageCenterTexel(dc.GetTheme().whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.GetTheme().popupTitleStyle.fgColor);
if (availableWidth < tw) {
dc.PopScissor();
@@ -1282,7 +1283,7 @@ void TextEdit::Draw(UIContext &dc) {
dc.SetFontStyle(dc.GetTheme().uiFont);
// TODO: make background themeable?
dc.FillRect(HasFocus() ? UI::Drawable(0x80000000) : UI::Drawable(0x30000000), bounds_);
dc.FillRoundRect(HasFocus() ? UI::Drawable(0x80000000) : UI::Drawable(0x30000000), bounds_, dc.GetTheme().choiceRoundRadius * 0.5f);
dc.PushScissor(textBounds);
Bounds origTextBounds = textBounds;
uint32_t textColor = popupStyle_ ? dc.GetTheme().popupStyle.fgColor : dc.GetTheme().infoStyle.fgColor;
+5 -1
View File
@@ -187,7 +187,11 @@ void ViewGroup::Draw(UIContext &dc) {
dc.PushScissor(bounds_);
}
dc.FillRect(bg_, bounds_);
if (roundCorners_ != RoundCorners::None) {
dc.FillRoundRect(bg_, bounds_, dc.GetTheme().choiceRoundRadius, roundCorners_);
} else {
dc.FillRect(bg_, bounds_);
}
for (View *view : views_) {
if (view->GetVisibility() == V_VISIBLE) {
// Check if bounds are in current scissor rectangle.
+16 -16
View File
@@ -26,6 +26,11 @@ static inline const char *DeNull(const char *ptr) {
static const float g_atlasIconSize = 36.0f;
// Inside the background, enough to keep the contents clear of the rounded corners.
static float NoticeViewPadding(const UIContext &dc) {
return dc.GetTheme().choiceRoundRadius * 0.5f;
}
// Align only matters here for the ASCII-only flag.
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) {
@@ -34,7 +39,7 @@ static void MeasureOSDEntry(const UIContext &dc, const OnScreenDisplay::Entry &e
*width = std::min(maxWidth, 550.0f);
*height1 = *height;
} else {
MeasureNotice(dc, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, maxWidth, width, height, height1);
MeasureNotice(dc, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, maxWidth, width, height, height1, NoticeViewPadding(dc));
}
}
@@ -49,13 +54,14 @@ static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, B
if (!(entry.flags & OSDMessageFlags::Transparent)) {
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
}
RenderNotice(dc, bounds, height1, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, alpha, entry.flags, now - entry.startTime);
RenderNotice(dc, bounds, height1, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, alpha, entry.flags, now - entry.startTime, NoticeViewPadding(dc), dc.GetTheme().choiceRoundRadius * 0.75f);
}
}
static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, int align, float alpha) {
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
const float radius = dc.GetTheme().choiceRoundRadius * 0.75f;
uint32_t backgroundColor = colorAlpha(0x806050, alpha);
uint32_t progressBackgroundColor = colorAlpha(0xa08070, alpha);
@@ -68,20 +74,19 @@ static void RenderOSDProgressBar(UIContext &dc, const OnScreenDisplay::Entry &en
float ratio = (float)(entry.progress - entry.minValue) / (float)entry.maxValue;
Bounds boundLeft = bounds;
Bounds boundRight = bounds;
boundLeft.w *= ratio;
boundRight.x += ratio * boundRight.w;
boundRight.w *= (1.0f - ratio);
dc.FillRect(progressBackground, boundLeft);
dc.FillRect(background, boundRight);
// Clip the progress part, so its rounded corners match the background's at any width.
dc.FillRoundRect(background, bounds, radius);
dc.PushScissor(boundLeft);
dc.FillRoundRect(progressBackground, bounds, radius);
dc.PopScissor();
} else {
// Indeterminate spinner
float alpha = cos(time_now_d() * 5.0) * 0.5f + 0.5f;
uint32_t pulse = colorBlend(backgroundColor, progressBackgroundColor, alpha);
UI::Drawable background = UI::Drawable(pulse);
dc.FillRect(background, bounds);
dc.FillRoundRect(background, bounds, radius);
}
dc.SetFontStyle(dc.GetTheme().uiFont);
@@ -101,7 +106,7 @@ static void RenderLeaderboardTracker(UIContext &dc, const Bounds &bounds, const
uint32_t backgroundColor = colorAlpha(0x806050, alpha);
UI::Drawable background = UI::Drawable(backgroundColor);
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
dc.FillRect(background, bounds);
dc.FillRoundRect(background, bounds, dc.GetTheme().choiceRoundRadius * 0.75f);
dc.SetFontStyle(dc.GetTheme().uiFont);
dc.SetFontScale(1.0f, 1.0f);
dc.DrawTextShadowRect(text, bounds.Inset(5.0f, 5.0f), colorAlpha(0xFFFFFFFF, alpha), ALIGN_VCENTER | ALIGN_HCENTER);
@@ -427,11 +432,6 @@ ViewLayoutMode OSDOverlayScreen::LayoutMode() const {
return ViewLayoutMode::ApplyInsets;
}
// Inside the background, enough to keep the contents clear of the rounded corners.
static float NoticeViewPadding(const UIContext &dc) {
return dc.GetTheme().choiceRoundRadius * 0.5f;
}
NoticeView::NoticeView(NoticeLevel level, std::string_view text, std::string_view detailsText, UI::LayoutParams *layoutParams)
: InertView(layoutParams), level_(level), text_(text), detailsText_(detailsText) {
if (!layoutParams) {
@@ -454,6 +454,6 @@ void NoticeView::GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec
void NoticeView::Draw(UIContext &dc) {
dc.PushScissor(bounds_);
const int align = wrapText_ ? FLAG_WRAP_TEXT : 0;
RenderNotice(dc, bounds_, height1_, level_, text_, detailsText_, iconName_, align, 1.0f, OSDMessageFlags::None, 0.0f, NoticeViewPadding(dc), roundCorners_);
RenderNotice(dc, bounds_, height1_, level_, text_, detailsText_, iconName_, align, 1.0f, OSDMessageFlags::None, 0.0f, NoticeViewPadding(dc), dc.GetTheme().choiceRoundRadius, roundCorners_);
dc.PopScissor();
}
+4 -2
View File
@@ -596,11 +596,13 @@ void RenderAchievement(UIContext &dc, const rc_client_achievement_t *achievement
dc.Begin();
if (style != AchievementRenderStyle::LISTED) {
// On-screen notification.
dc.DrawRectDropShadow(bounds, 12.0f, 0.7f * alpha);
dc.FillRoundRect(background, bounds, dc.GetTheme().choiceRoundRadius * 0.75f);
} else {
dc.FillRect(background, bounds);
}
dc.FillRect(background, bounds);
dc.Flush();
dc.Begin();