262 lines
9.8 KiB
C++
262 lines
9.8 KiB
C++
/**
|
|
******************************************************************************
|
|
* Xenia : Xbox 360 Emulator Research Project *
|
|
******************************************************************************
|
|
* Copyright 2023 Ben Vanik. All rights reserved. *
|
|
* Released under the BSD license - see LICENSE in the root for more details. *
|
|
******************************************************************************
|
|
*/
|
|
|
|
#include <cmath>
|
|
|
|
#include "xenia/base/logging.h"
|
|
#include "xenia/base/platform.h"
|
|
#include "xenia/ui/imgui_guest_notification.h"
|
|
#include "xenia/ui/imgui_notification.h"
|
|
|
|
#if XE_PLATFORM_WIN32
|
|
#include <playsoundapi.h>
|
|
#endif
|
|
|
|
DEFINE_string(notification_sound_path, "",
|
|
"Path (including filename) to selected notification sound. Sound "
|
|
"MUST be in wav format!",
|
|
"General");
|
|
|
|
namespace xe {
|
|
namespace ui {
|
|
|
|
ImGuiGuestNotification::ImGuiGuestNotification(ui::ImGuiDrawer* imgui_drawer,
|
|
std::string& title,
|
|
std::string& description,
|
|
uint8_t user_index,
|
|
uint8_t position_id)
|
|
: ImGuiNotification(imgui_drawer, NotificationType::Guest, title,
|
|
description, user_index, position_id),
|
|
current_stage_(NotificationStage::Awaiting),
|
|
notification_draw_progress_(0.0f) {
|
|
imgui_drawer->AddNotification(this);
|
|
}
|
|
|
|
ImGuiGuestNotification::~ImGuiGuestNotification() {}
|
|
|
|
void ImGuiGuestNotification::UpdateNotificationState() {
|
|
switch (current_stage_) {
|
|
case NotificationStage::Awaiting:
|
|
// TODO(Gliniak): Implement delayed notifications.
|
|
current_stage_ = NotificationStage::FazeIn;
|
|
notification_draw_progress_ = 0.2f;
|
|
#if XE_PLATFORM_WIN32
|
|
if (!cvars::notification_sound_path.empty()) {
|
|
auto notification_sound_path = cvars::notification_sound_path;
|
|
if (std::filesystem::exists(notification_sound_path)) {
|
|
PlaySound(std::wstring(notification_sound_path.begin(),
|
|
notification_sound_path.end())
|
|
.c_str(),
|
|
NULL,
|
|
SND_FILENAME | SND_NODEFAULT | SND_NOSTOP | SND_ASYNC);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
break;
|
|
case NotificationStage::FazeIn: {
|
|
SetCreationTime(Clock::QueryHostUptimeMillis());
|
|
if (notification_draw_progress_ < 1.1f) {
|
|
notification_draw_progress_ += 0.02f;
|
|
}
|
|
|
|
// Mimics a bit original console behaviour when it makes window a bit
|
|
// longer for few frames then decreases size
|
|
if (notification_draw_progress_ >= 1.1f) {
|
|
current_stage_ = NotificationStage::Present;
|
|
notification_draw_progress_ = 1.0f;
|
|
}
|
|
break;
|
|
}
|
|
case NotificationStage::Present:
|
|
if (IsNotificationClosingTime()) {
|
|
current_stage_ = NotificationStage::FazeOut;
|
|
}
|
|
break;
|
|
case NotificationStage::FazeOut: {
|
|
if (notification_draw_progress_ > 0.2f) {
|
|
notification_draw_progress_ -= 0.02f;
|
|
} else {
|
|
current_stage_ = NotificationStage::Finished;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
const ImVec2 ImGuiGuestNotification::CalculateNotificationSize(ImVec2 text_size,
|
|
float scale) {
|
|
const ImVec2 result = ImVec2(floorf((default_notification_icon_size.x +
|
|
default_notification_margin_size.x) *
|
|
scale) +
|
|
text_size.x,
|
|
floorf((default_notification_icon_size.y +
|
|
default_notification_margin_size.y) *
|
|
scale));
|
|
|
|
return result;
|
|
}
|
|
|
|
void AchievementNotificationWindow::OnDraw(ImGuiIO& io) {
|
|
UpdateNotificationState();
|
|
|
|
if (IsNotificationExpired()) {
|
|
delete this;
|
|
return;
|
|
}
|
|
|
|
const std::string_view longest_notification_text_line =
|
|
GetTitle().size() > GetDescription().size() ? GetTitle()
|
|
: GetDescription();
|
|
|
|
const ImVec2 screen_size = io.DisplaySize;
|
|
const float window_scale =
|
|
std::fminf(screen_size.x / default_drawing_resolution.x,
|
|
screen_size.y / default_drawing_resolution.y);
|
|
const float font_scale = default_font_size / io.Fonts->Fonts[0]->FontSize;
|
|
const ImVec2 text_size = io.Fonts->Fonts[0]->CalcTextSizeA(
|
|
default_font_size * default_notification_text_scale * window_scale,
|
|
FLT_MAX, -1.0f, longest_notification_text_line.data());
|
|
|
|
const ImVec2 final_notification_size =
|
|
CalculateNotificationSize(text_size, window_scale);
|
|
|
|
const ImVec2 notification_position = CalculateNotificationScreenPosition(
|
|
screen_size, final_notification_size, GetPositionId());
|
|
|
|
if (std::isnan(notification_position.x) ||
|
|
std::isnan(notification_position.y)) {
|
|
return;
|
|
}
|
|
|
|
ImVec2 current_notification_size = final_notification_size;
|
|
current_notification_size.x *= notification_draw_progress_;
|
|
current_notification_size.x = floorf(current_notification_size.x);
|
|
|
|
// Initialize position and window size
|
|
ImGui::SetNextWindowSize(current_notification_size);
|
|
ImGui::SetNextWindowPos(notification_position);
|
|
|
|
// Set new window style before drawing window
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding,
|
|
default_notification_rounding * window_scale);
|
|
ImGui::PushStyleColor(ImGuiCol_WindowBg,
|
|
default_notification_background_color);
|
|
ImGui::PushStyleColor(ImGuiCol_Separator,
|
|
default_notification_background_color);
|
|
ImGui::PushStyleColor(ImGuiCol_Border, default_notification_border_color);
|
|
|
|
ImGui::Begin("Notification Window", NULL, NOTIFY_TOAST_FLAGS);
|
|
{
|
|
ImGui::SetWindowFontScale(default_notification_text_scale * font_scale *
|
|
window_scale);
|
|
// Set offset to image to prevent it from being right on border.
|
|
ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.005f,
|
|
final_notification_size.y * 0.05f));
|
|
// Elements of window
|
|
ImGui::Image(reinterpret_cast<ImTextureID>(
|
|
GetDrawer()->GetNotificationIcon(GetUserIndex())),
|
|
ImVec2(default_notification_icon_size.x * window_scale,
|
|
default_notification_icon_size.y * window_scale));
|
|
|
|
ImGui::SameLine();
|
|
if (notification_draw_progress_ > 0.5f) {
|
|
ImGui::TextColored(white_color, "%s", GetNotificationText().data());
|
|
}
|
|
}
|
|
// Restore previous style
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor(3);
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
void XNotifyWindow::OnDraw(ImGuiIO& io) {
|
|
UpdateNotificationState();
|
|
|
|
if (IsNotificationExpired()) {
|
|
delete this;
|
|
return;
|
|
}
|
|
|
|
const std::string_view longest_notification_text_line =
|
|
GetTitle().size() > GetDescription().size() ? GetTitle()
|
|
: GetDescription();
|
|
|
|
const ImVec2 screen_size = io.DisplaySize;
|
|
const float window_scale =
|
|
std::fminf(screen_size.x / default_drawing_resolution.x,
|
|
screen_size.y / default_drawing_resolution.y);
|
|
const float font_scale = default_font_size / io.Fonts->Fonts[0]->FontSize;
|
|
const ImVec2 text_size = io.Fonts->Fonts[0]->CalcTextSizeA(
|
|
default_font_size * default_notification_text_scale * window_scale,
|
|
FLT_MAX, -1.0f, longest_notification_text_line.data());
|
|
|
|
const ImVec2 final_notification_size =
|
|
CalculateNotificationSize(text_size, window_scale);
|
|
|
|
const ImVec2 notification_position = CalculateNotificationScreenPosition(
|
|
screen_size, final_notification_size, GetPositionId());
|
|
|
|
if (std::isnan(notification_position.x) ||
|
|
std::isnan(notification_position.y)) {
|
|
return;
|
|
}
|
|
|
|
ImVec2 current_notification_size = final_notification_size;
|
|
current_notification_size.x *= notification_draw_progress_;
|
|
current_notification_size.x = floorf(current_notification_size.x);
|
|
|
|
// Initialize position and window size
|
|
ImGui::SetNextWindowSize(current_notification_size);
|
|
ImGui::SetNextWindowPos(notification_position);
|
|
|
|
// Set new window style before drawing window
|
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding,
|
|
default_notification_rounding * window_scale);
|
|
ImGui::PushStyleColor(ImGuiCol_WindowBg,
|
|
default_notification_background_color);
|
|
ImGui::PushStyleColor(ImGuiCol_Separator,
|
|
default_notification_background_color);
|
|
ImGui::PushStyleColor(ImGuiCol_Border, default_notification_border_color);
|
|
|
|
ImGui::Begin("Notification Window", NULL, NOTIFY_TOAST_FLAGS);
|
|
{
|
|
ImGui::SetWindowFontScale(default_notification_text_scale * font_scale *
|
|
window_scale);
|
|
// Set offset to image to prevent it from being right on border.
|
|
ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.005f,
|
|
final_notification_size.y * 0.05f));
|
|
// Elements of window
|
|
ImGui::Image(reinterpret_cast<ImTextureID>(
|
|
GetDrawer()->GetNotificationIcon(GetUserIndex())),
|
|
ImVec2(default_notification_icon_size.x * window_scale,
|
|
default_notification_icon_size.y * window_scale));
|
|
|
|
// Set offset to image to prevent it from being right on border.
|
|
// ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.1f,
|
|
// final_notification_size.y * 0.2f));
|
|
|
|
ImGui::SameLine();
|
|
if (notification_draw_progress_ > 0.5f) {
|
|
ImGui::TextColored(white_color, "%s", GetDescription().data());
|
|
}
|
|
}
|
|
// Restore previous style
|
|
ImGui::PopStyleVar();
|
|
ImGui::PopStyleColor(3);
|
|
|
|
ImGui::End();
|
|
}
|
|
|
|
} // namespace ui
|
|
} // namespace xe
|