From e182837f8634012fc83b8b6f1c526e44655b9a94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 7 Jul 2023 15:16:47 +0200 Subject: [PATCH 1/2] Remove left-over debug logging --- Common/UI/Root.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/Common/UI/Root.cpp b/Common/UI/Root.cpp index 280a534ae5c0..123cd3376f95 100644 --- a/Common/UI/Root.cpp +++ b/Common/UI/Root.cpp @@ -418,7 +418,6 @@ void UpdateViewHierarchy(ViewGroup *root) { } root->SubviewFocused(GetFocusedView()); } else { - INFO_LOG(SCECTRL, "Processing focus moves."); for (size_t i = 0; i < focusMoves.size(); i++) { switch (focusMoves[i]) { case NKCODE_DPAD_LEFT: MoveFocus(root, FOCUS_LEFT); break; @@ -432,7 +431,6 @@ void UpdateViewHierarchy(ViewGroup *root) { } } } - INFO_LOG(SCECTRL, "Clearing focus moves."); focusMoves.clear(); } From 952e125c7e5eea441719f77ed7232db45cbebd6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 7 Jul 2023 15:23:19 +0200 Subject: [PATCH 2/2] Break out rendering of "notices" from OnScreenDisplay. They can now also be used as views. Use it for the new message in ControlMappingScreen, when you try to map a combo when that's disabled. It'll have more uses. --- Common/UI/View.h | 1 + GPU/D3D11/DrawEngineD3D11.cpp | 4 +- UI/ControlMappingScreen.cpp | 3 +- UI/OnScreenDisplay.cpp | 119 ++++++++++++++++++++++------------ UI/OnScreenDisplay.h | 31 +++++++++ 5 files changed, 113 insertions(+), 45 deletions(-) diff --git a/Common/UI/View.h b/Common/UI/View.h index a683cb94740d..f520d9aab11a 100644 --- a/Common/UI/View.h +++ b/Common/UI/View.h @@ -1050,6 +1050,7 @@ class Spinner : public InertView { }; void MeasureBySpec(Size sz, float contentWidth, MeasureSpec spec, float *measured); +void ApplyBoundsBySpec(Bounds &bounds, MeasureSpec horiz, MeasureSpec vert); bool IsDPadKey(const KeyInput &key); bool IsAcceptKey(const KeyInput &key); diff --git a/GPU/D3D11/DrawEngineD3D11.cpp b/GPU/D3D11/DrawEngineD3D11.cpp index 119607d76d29..2068d57118ea 100644 --- a/GPU/D3D11/DrawEngineD3D11.cpp +++ b/GPU/D3D11/DrawEngineD3D11.cpp @@ -132,7 +132,9 @@ void DrawEngineD3D11::NotifyConfigChanged() { } void DrawEngineD3D11::DestroyDeviceObjects() { - draw_->SetInvalidationCallback(InvalidationCallback()); + if (draw_) { + draw_->SetInvalidationCallback(InvalidationCallback()); + } ClearTrackedVertexArrays(); ClearInputLayoutMap(); diff --git a/UI/ControlMappingScreen.cpp b/UI/ControlMappingScreen.cpp index 927cbcf9c657..3b0bd26cdd00 100644 --- a/UI/ControlMappingScreen.cpp +++ b/UI/ControlMappingScreen.cpp @@ -46,6 +46,7 @@ #include "UI/ControlMappingScreen.h" #include "UI/GameSettingsScreen.h" #include "UI/JoystickHistoryView.h" +#include "UI/OnScreenDisplay.h" #if PPSSPP_PLATFORM(ANDROID) #include "android/jni/app-android.h" @@ -334,7 +335,7 @@ void KeyMappingNewKeyDialog::CreatePopupContents(UI::ViewGroup *parent) { parent->Add(new TextView(std::string(km->T("Map a new key for")) + " " + mc->T(pspButtonName), new LinearLayoutParams(Margins(10, 0)))); parent->Add(new TextView(std::string(mapping_.ToVisualString()), new LinearLayoutParams(Margins(10, 0)))); - comboMappingsNotEnabled_ = parent->Add(new TextView(km->T("Combo mappings are not enabled"), new LinearLayoutParams(Margins(10, 0)))); + comboMappingsNotEnabled_ = parent->Add(new NoticeView(NoticeLevel::WARN, km->T("Combo mappings are not enabled"), "", new LinearLayoutParams(Margins(10, 0)))); comboMappingsNotEnabled_->SetVisibility(UI::V_GONE); SetVRAppMode(VRAppMode::VR_CONTROLLER_MAPPING_MODE); diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 0a508faac0c4..9d921b666fd6 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -18,63 +18,62 @@ #include "Common/Net/HTTPClient.h" #include "Core/Config.h" -static uint32_t GetOSDBackgroundColor(OSDType type) { +static const float g_atlasIconSize = 36.0f; +static const float extraTextScale = 0.7f; + +static uint32_t GetNoticeBackgroundColor(NoticeLevel type) { // Colors from Infima switch (type) { - case OSDType::MESSAGE_ERROR: - case OSDType::MESSAGE_ERROR_DUMP: return 0x3530d5; // danger-darker - case OSDType::MESSAGE_WARNING: return 0x009ed9; // warning-darker - case OSDType::MESSAGE_INFO: return 0x706760; // gray-700 - case OSDType::MESSAGE_SUCCESS: return 0x008b00; + case NoticeLevel::ERROR: return 0x3530d5; // danger-darker + case NoticeLevel::WARN: return 0x009ed9; // warning-darker + case NoticeLevel::INFO: return 0x706760; // gray-700 + case NoticeLevel::SUCCESS: return 0x008b00; // nice green default: return 0x606770; } } -ImageID GetOSDIcon(OSDType type) { - switch (type) { - case OSDType::MESSAGE_INFO: return ImageID::invalid(); // return ImageID("I_INFO"); - case OSDType::MESSAGE_ERROR: return ImageID("I_CROSS"); - case OSDType::MESSAGE_WARNING: return ImageID("I_WARNING"); - case OSDType::MESSAGE_SUCCESS: return ImageID("I_CHECKEDBOX"); +static ImageID GetOSDIcon(NoticeLevel level) { + switch (level) { + case NoticeLevel::INFO: return ImageID::invalid(); // return ImageID("I_INFO"); + case NoticeLevel::ERROR: return ImageID("I_CROSS"); + case NoticeLevel::WARN: return ImageID("I_WARNING"); + case NoticeLevel::SUCCESS: return ImageID("I_CHECKEDBOX"); default: return ImageID::invalid(); } } -static const float g_atlasIconSize = 36.0f; - -static const float extraTextScale = 0.7f; - -// Align only matters here for the ASCII-only flag. -static void MeasureOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, int align, float *width, float *height, float *height1) { - if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) { - const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID); - MeasureAchievement(dc, *achievement, width, height); - *width = 550.0f; - *height1 = *height; - return; +static NoticeLevel GetNoticeLevel(OSDType type) { + switch (type) { + case OSDType::MESSAGE_INFO: return NoticeLevel::INFO; + case OSDType::MESSAGE_ERROR: + case OSDType::MESSAGE_ERROR_DUMP: return NoticeLevel::ERROR; + case OSDType::MESSAGE_WARNING: return NoticeLevel::WARN; + case OSDType::MESSAGE_SUCCESS: return NoticeLevel::SUCCESS; + default: return NoticeLevel::SUCCESS; } +} - dc.SetFontStyle(dc.theme->uiFont); - dc.MeasureText(dc.theme->uiFont, 1.0f, 1.0f, entry.text.c_str(), width, height, align); +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.theme->uiFont, 1.0f, 1.0f, text.c_str(), width, height, align); *height1 = *height; float width2 = 0.0f, height2 = 0.0f; - if (!entry.text2.empty()) { - dc.MeasureText(dc.theme->uiFont, extraTextScale, extraTextScale, entry.text2.c_str(), &width2, &height2, align); + if (!details.empty()) { + dc.MeasureText(dc.theme->uiFont, extraTextScale, extraTextScale, details.c_str(), &width2, &height2, align); *width = std::max(*width, width2); *height += 5.0f + height2; } float iconSize = 0.0f; - if (!entry.iconName.empty()) { + if (!iconName.empty()) { // Normal entry but with a cached icon. int iconWidth, iconHeight; - if (g_iconCache.GetDimensions(entry.iconName, &iconWidth, &iconHeight)) { + if (g_iconCache.GetDimensions(iconName, &iconWidth, &iconHeight)) { *width += 5.0f + iconWidth; iconSize = iconWidth + 5.0f; } - } else if (!GetOSDIcon(entry.type).isInvalid()) { + } else if (!GetOSDIcon(level).isInvalid()) { // Atlas icon. iconSize = g_atlasIconSize + 5.0f; } @@ -83,14 +82,20 @@ static void MeasureOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, *height = std::max(*height, iconSize + 5.0f); } -static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, float height1, int align, float alpha) { +// 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) { if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) { const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID); - RenderAchievement(dc, *achievement, AchievementRenderStyle::UNLOCKED, bounds, alpha, entry.startTime, time_now_d()); - return; + MeasureAchievement(dc, *achievement, width, height); + *width = 550.0f; + *height1 = *height; + } else { + MeasureNotice(dc, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, width, height, height1); } +} - UI::Drawable background = UI::Drawable(colorAlpha(GetOSDBackgroundColor(entry.type), alpha)); +static void RenderNotice(UIContext &dc, Bounds bounds, float height1, NoticeLevel level, const std::string &text, const std::string &details, const std::string &iconName, int align, float alpha) { + UI::Drawable background = UI::Drawable(colorAlpha(GetNoticeBackgroundColor(level), alpha)); uint32_t foreGround = whiteAlpha(alpha); @@ -100,13 +105,13 @@ static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, B dc.FillRect(background, bounds); - ImageID iconID = GetOSDIcon(entry.type); + ImageID iconID = GetOSDIcon(level); float iconSize = 0.0f; - if (!entry.iconName.empty()) { + if (!iconName.empty()) { dc.Flush(); // Normal entry but with a cached icon. - Draw::Texture *texture = g_iconCache.BindIconTexture(&dc, entry.iconName); + Draw::Texture *texture = g_iconCache.BindIconTexture(&dc, iconName); if (texture) { iconSize = texture->Width(); dc.Draw()->DrawTexRect(Bounds(bounds.x + 2.5f, bounds.y + 2.5f, iconSize, iconSize), 0.0f, 0.0f, 1.0f, 1.0f, foreGround); @@ -124,19 +129,29 @@ static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, B bounds.x += iconSize + 5.0f; bounds.w -= iconSize + 5.0f; - dc.DrawTextShadowRect(entry.text.c_str(), bounds.Inset(0.0f, 1.0f, 0.0f, 0.0f), foreGround, (align & FLAG_DYNAMIC_ASCII)); + dc.DrawTextShadowRect(text.c_str(), bounds.Inset(0.0f, 1.0f, 0.0f, 0.0f), foreGround, (align & FLAG_DYNAMIC_ASCII)); - if (!entry.text2.empty()) { + if (!details.empty()) { Bounds bottomTextBounds = bounds.Inset(3.0f, height1 + 5.0f, 3.0f, 3.0f); - UI::Drawable backgroundDark = UI::Drawable(colorAlpha(darkenColor(GetOSDBackgroundColor(entry.type)), alpha)); + UI::Drawable backgroundDark = UI::Drawable(colorAlpha(darkenColor(GetNoticeBackgroundColor(level)), alpha)); dc.FillRect(backgroundDark, bottomTextBounds); dc.SetFontScale(extraTextScale, extraTextScale); - dc.DrawTextRect(entry.text2.c_str(), bottomTextBounds, foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_LEFT); + dc.DrawTextRect(details.c_str(), bottomTextBounds, foreGround, (align & FLAG_DYNAMIC_ASCII) | ALIGN_LEFT); } dc.SetFontScale(1.0f, 1.0f); } -static void MeasureOSDProgressBar(UIContext &dc, const OnScreenDisplay::ProgressBar &bar, float *width, float *height) { +static void RenderOSDEntry(UIContext &dc, const OnScreenDisplay::Entry &entry, Bounds bounds, float height1, int align, float alpha) { + if (entry.type == OSDType::ACHIEVEMENT_UNLOCKED) { + const Achievements::Achievement *achievement = Achievements::GetAchievementByID(entry.numericID); + RenderAchievement(dc, *achievement, AchievementRenderStyle::UNLOCKED, bounds, alpha, entry.startTime, time_now_d()); + return; + } + + RenderNotice(dc, bounds, height1, GetNoticeLevel(entry.type), entry.text, entry.text2, entry.iconName, align, alpha); +} + +static void MeasureOSDProgressBar(const UIContext &dc, const OnScreenDisplay::ProgressBar &bar, float *width, float *height) { *height = 36; *width = 450.0f; } @@ -289,3 +304,21 @@ void OSDOverlayScreen::CreateViews() { root_->SetTag("OSDOverlayScreen"); root_->Add(new OnScreenMessagesView(new UI::AnchorLayoutParams(0.0f, 0.0f, 0.0f, 0.0f))); } + +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) { + // If there's no size, let's grow as big as we want. + bounds.w = horiz.size; + } + if (bounds.h < 0) { + bounds.h = vert.size; + } + + ApplyBoundsBySpec(bounds, horiz, vert); + MeasureNotice(dc, level_, text_, detailsText_, iconName_, 0, &w, &h, &height1_); +} + +void NoticeView::Draw(UIContext &dc) { + RenderNotice(dc, bounds_, height1_, level_, text_, detailsText_, iconName_, 0, 1.0f); +} diff --git a/UI/OnScreenDisplay.h b/UI/OnScreenDisplay.h index 3c8ec988b293..24c819da0194 100644 --- a/UI/OnScreenDisplay.h +++ b/UI/OnScreenDisplay.h @@ -9,6 +9,10 @@ #include "Common/UI/UIScreen.h" #include "Common/System/System.h" +#ifdef ERROR +#undef ERROR +#endif + class DrawBuffer; // Infrastructure for rendering overlays. @@ -25,3 +29,30 @@ class OSDOverlayScreen : public UIScreen { const char *tag() const override { return "OSDOverlayScreen"; } void CreateViews() override; }; + +enum class NoticeLevel { + SUCCESS, + INFO, + WARN, + ERROR, +}; + +class NoticeView : public UI::InertView { +public: + NoticeView(NoticeLevel level, const std::string &text, const std::string &detailsText, UI::LayoutParams *layoutParams = 0) + : InertView(layoutParams), level_(level), text_(text), detailsText_(detailsText), iconName_("") {} + + void SetIconName(const std::string &name) { + iconName_ = name; + } + + void GetContentDimensionsBySpec(const UIContext &dc, UI::MeasureSpec horiz, UI::MeasureSpec vert, float &w, float &h) const override; + void Draw(UIContext &dc) override; + +private: + std::string text_; + std::string detailsText_; + std::string iconName_; + NoticeLevel level_; + mutable float height1_ = 0.0f; +};