diff --git a/Common/UI/Context.cpp b/Common/UI/Context.cpp index b4deb5af30..118d1ac1bc 100644 --- a/Common/UI/Context.cpp +++ b/Common/UI/Context.cpp @@ -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; } } diff --git a/Common/UI/Notice.cpp b/Common/UI/Notice.cpp index e0b117220f..106d5d1d1a 100644 --- a/Common/UI/Notice.cpp +++ b/Common/UI/Notice.cpp @@ -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); diff --git a/Common/UI/Notice.h b/Common/UI/Notice.h index fee57922de..c786d137be 100644 --- a/Common/UI/Notice.h +++ b/Common/UI/Notice.h @@ -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); diff --git a/Common/UI/PopupScreens.cpp b/Common/UI/PopupScreens.cpp index 86d5d8acbc..1125f71f5b 100644 --- a/Common/UI/PopupScreens.cpp +++ b/Common/UI/PopupScreens.cpp @@ -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(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()) diff --git a/Common/UI/ScrollView.cpp b/Common/UI/ScrollView.cpp index af8ceedb76..e5606de287 100644 --- a/Common/UI/ScrollView.cpp +++ b/Common/UI/ScrollView.cpp @@ -663,6 +663,7 @@ void ListView::CreateAllItems() { OnItemCallback(i, e); }); } + linLayout_->ApplyRoundCorners(); } void ListView::Measure(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert) { diff --git a/Common/UI/View.cpp b/Common/UI/View.cpp index fff44f9a19..ebecf62d7c 100644 --- a/Common/UI/View.cpp +++ b/Common/UI/View.cpp @@ -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; diff --git a/Common/UI/ViewGroup.cpp b/Common/UI/ViewGroup.cpp index 9133e8db28..2440c417d2 100644 --- a/Common/UI/ViewGroup.cpp +++ b/Common/UI/ViewGroup.cpp @@ -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. diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 314cb1dfda..195d85c540 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -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(); } diff --git a/UI/RetroAchievementScreens.cpp b/UI/RetroAchievementScreens.cpp index 9d66e9e849..07a7ab57b7 100644 --- a/UI/RetroAchievementScreens.cpp +++ b/UI/RetroAchievementScreens.cpp @@ -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();