From 82c760135ffa51955f97bad0cb7b46bbef777134 Mon Sep 17 00:00:00 2001 From: rainmakerv2 <30595646+rainmakerv3@users.noreply.github.com> Date: Sat, 9 May 2026 16:14:11 +0800 Subject: [PATCH] ImGui:: Notifications (#4379) * notifications * cleanup * clang --- CMakeLists.txt | 3 + src/imgui/notifications_layer.cpp | 124 ++++++++++++++++++ src/imgui/notifications_layer.h | 36 +++++ .../renderer_vulkan/vk_presenter.cpp | 3 + 4 files changed, 166 insertions(+) create mode 100644 src/imgui/notifications_layer.cpp create mode 100644 src/imgui/notifications_layer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index a913c34f1..952af9148 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1092,6 +1092,8 @@ set(IMGUI src/imgui/imgui_config.h src/imgui/imgui_texture.h src/imgui/imgui_translations.cpp src/imgui/imgui_translations.h + src/imgui/notifications_layer.cpp + src/imgui/notifications_layer.h src/imgui/renderer/imgui_core.cpp src/imgui/renderer/imgui_core.h src/imgui/renderer/imgui_impl_sdl3.cpp @@ -1275,6 +1277,7 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeRC.cmake") cmrc_add_resource_library(embedded-resources ALIAS res::embedded NAMESPACE res + src/images/shadps4.png src/images/big_picture/folder.png src/images/big_picture/settings.png src/images/big_picture/experimental.png diff --git a/src/imgui/notifications_layer.cpp b/src/imgui/notifications_layer.cpp new file mode 100644 index 000000000..76ce2fe34 --- /dev/null +++ b/src/imgui/notifications_layer.cpp @@ -0,0 +1,124 @@ +// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include + +#include "imgui/imgui_std.h" +#include "notifications_layer.h" + +CMRC_DECLARE(res); +namespace shadNotifications { + +std::optional current_notif; +std::queue notif_queue; +std::mutex queueMtx; + +NotificationsUI::NotificationsUI(NotificationInfo info) { + AddLayer(this); + + if (shadIcon.GetTexture().im_id == nullptr) { + auto resource = cmrc::res::get_filesystem(); + auto file = resource.open("src/images/shadps4.png"); + std::vector imgdata = std::vector(file.begin(), file.end()); + shadIcon = ImGui::RefCountedTexture::DecodePngTexture(imgdata); + } + + currentNotification = info; + + // Resetting the animation + elapsed_time = 0.0f; // Resetting animation time + fade_opacity = 0.0f; // Starts invisible +} + +NotificationsUI::~NotificationsUI() { + RemoveLayer(this); +} + +void NotificationsUI::Draw() { + auto& io = ImGui::GetIO(); + currentNotification.timer -= io.DeltaTime; + + float AdjustWidth = io.DisplaySize.x / 1920; + float AdjustHeight = io.DisplaySize.y / 1080; + + ImVec2 padding = ImGui::GetStyle().WindowPadding; + float wrapWidth = 300 * AdjustWidth - padding.x * 2; // 350 window size - 50 image size + float textHeight = + ImGui::CalcTextSize(currentNotification.message.c_str(), nullptr, false, wrapWidth).y; + + ImVec2 window_size{(350 * AdjustWidth), + std::max({70 * AdjustHeight, (textHeight + padding.y * 2.0f)})}; + + elapsed_time += io.DeltaTime; + float progress = std::min(elapsed_time / animation_duration, 1.0f); + float final_pos_x, start_x; + + start_x = io.DisplaySize.x; + final_pos_x = io.DisplaySize.x - window_size.x - 20 * AdjustWidth; + ImVec2 current_pos = ImVec2(start_x + (final_pos_x - start_x) * progress, + io.DisplaySize.y - window_size.y - 50 * AdjustHeight); + ImGui::SetNextWindowPos(current_pos); + + // If the remaining time of the notif is less than or equal to 1 second, the fade-out begins. + if (currentNotification.timer <= 1.0f) { + float fade_out_time = 1.0f - (currentNotification.timer / 1.0f); + fade_opacity = 1.0f - fade_out_time; + } else { + // Fade in , 0 to 1 + fade_opacity = 1.0f; + } + + fade_opacity = std::max(0.0f, std::min(fade_opacity, 1.0f)); + + ImGui::SetNextWindowSize(window_size); + ImGui::SetNextWindowPos(current_pos); + ImGui::SetNextWindowCollapsed(false); + ImGui::KeepNavHighlight(); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, fade_opacity); + + if (ImGui::Begin("Notification Window", nullptr, + ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings | + ImGuiWindowFlags_NoInputs)) { + ImGui::GetColorU32(ImVec4{0.7f}); + + if (shadIcon.GetTexture().im_id) { + ImGui::Image(shadIcon.GetTexture().im_id, + ImVec2((50 * AdjustWidth), (50 * AdjustHeight))); + } + ImGui::SameLine(); + + ImGui::TextWrapped("%s", currentNotification.message.c_str()); + } + + ImGui::PopStyleVar(); + ImGui::End(); + + if (currentNotification.timer <= 0) { + std::lock_guard lock(queueMtx); + if (!notif_queue.empty()) { + NotificationInfo next = notif_queue.front(); + notif_queue.pop(); + current_notif.emplace(next); + } else { + current_notif.reset(); + } + } +} + +void QueueNotification(std::string message, float timer) { + std::lock_guard lock(queueMtx); + + NotificationInfo info; + info.message = message; + info.timer = timer; + + if (!current_notif.has_value()) { + current_notif.emplace(info); + } else { + notif_queue.push(info); + } +} + +} // namespace shadNotifications diff --git a/src/imgui/notifications_layer.h b/src/imgui/notifications_layer.h new file mode 100644 index 000000000..6affb9a8d --- /dev/null +++ b/src/imgui/notifications_layer.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "imgui/imgui_layer.h" +#include "imgui/imgui_texture.h" + +namespace shadNotifications { + +struct NotificationInfo { + std::string message; + float timer; +}; + +class NotificationsUI final : public ImGui::Layer { +public: + NotificationsUI(NotificationInfo info); + ~NotificationsUI() override; + + void Draw() override; + +private: + ImGui::RefCountedTexture shadIcon; + NotificationInfo currentNotification; + + // notification animation + const float animation_duration = 0.5f; // Animation duration + const float fade_out_duration = 0.5f; // Final fade duration + float fade_opacity = 0.0f; // Initial opacity (invisible) + float elapsed_time = 0.0f; // Animation time +}; + +void QueueNotification(std::string message, float timer); + +}; // namespace shadNotifications diff --git a/src/video_core/renderer_vulkan/vk_presenter.cpp b/src/video_core/renderer_vulkan/vk_presenter.cpp index edb736dcd..d04a70cea 100644 --- a/src/video_core/renderer_vulkan/vk_presenter.cpp +++ b/src/video_core/renderer_vulkan/vk_presenter.cpp @@ -10,6 +10,7 @@ #include "core/devtools/layer.h" #include "core/emulator_settings.h" #include "core/libraries/system/systemservice.h" +#include "imgui/notifications_layer.h" #include "imgui/renderer/imgui_core.h" #include "imgui/renderer/imgui_impl_vulkan.h" #include "sdl_window.h" @@ -452,6 +453,7 @@ static void SavePendingScreenshots(const std::vector& readba } LOG_INFO(Render_Vulkan, "Saved screenshot: {}", primary_path.string()); + shadNotifications::QueueNotification("Saved screenshot:\n" + primary_path.string(), 3.0f); for (size_t i = 1; i < readback.paths.size(); ++i) { const auto& path = readback.paths[i]; @@ -467,6 +469,7 @@ static void SavePendingScreenshots(const std::vector& readba } LOG_INFO(Render_Vulkan, "Saved screenshot: {}", path.string()); + shadNotifications::QueueNotification("Saved screenshot:\n" + path.string(), 3.0f); } } }