diff --git a/overlay_experimental/overlay/steam_overlay.h b/overlay_experimental/overlay/steam_overlay.h index a001a2d3..79bbdac8 100644 --- a/overlay_experimental/overlay/steam_overlay.h +++ b/overlay_experimental/overlay/steam_overlay.h @@ -54,7 +54,7 @@ struct Friend_Less enum class notification_type { - message = 0, + message, invite, achievement, achievement_progress, @@ -86,10 +86,11 @@ struct Overlay_Achievement struct Notification { static constexpr float width_percent = 0.25f; // percentage from total width - static constexpr std::chrono::milliseconds show_time = std::chrono::milliseconds(6000); + static constexpr std::chrono::milliseconds default_show_time = std::chrono::milliseconds(6000); int id{}; uint8 type{}; + bool expired = false; std::chrono::milliseconds start_time{}; std::string message{}; std::pair* frd{}; @@ -214,10 +215,11 @@ class Steam_Overlay void build_friend_context_menu(Friend const& frd, friend_window_state &state); // Double click on friend void build_friend_window(Friend const& frd, friend_window_state &state); + std::chrono::milliseconds get_notification_duration(notification_type type); // Notifications like achievements, chat and invitations - void set_next_notification_pos(std::pair scrn_size, std::chrono::milliseconds elapsed, const Notification ¬i, struct NotificationsCoords &coords); + void set_next_notification_pos(std::pair scrn_size, std::chrono::milliseconds elapsed, std::chrono::milliseconds duration, const Notification ¬i, struct NotificationsCoords &coords); // factor controlling the amount of sliding during the animation, 0 means disabled - float animate_factor(std::chrono::milliseconds elapsed); + float animate_factor(std::chrono::milliseconds elapsed, std::chrono::milliseconds duration); void add_ach_progressbar(const Overlay_Achievement &ach); ImVec4 get_notification_bg_rgba_safe(); void build_notifications(float width, float height); diff --git a/overlay_experimental/steam_overlay.cpp b/overlay_experimental/steam_overlay.cpp index e6b41747..a07a73b1 100644 --- a/overlay_experimental/steam_overlay.cpp +++ b/overlay_experimental/steam_overlay.cpp @@ -869,8 +869,33 @@ void Steam_Overlay::build_friend_window(Friend const& frd, friend_window_state& ImGui::End(); } + +std::chrono::milliseconds Steam_Overlay::get_notification_duration(notification_type type) +{ + switch (type) + { + case notification_type::message: + return std::chrono::milliseconds(settings->overlay_appearance.notification_duration_chat); + + case notification_type::invite: + return std::chrono::milliseconds(settings->overlay_appearance.notification_duration_invitation); + + case notification_type::achievement: + return std::chrono::milliseconds(settings->overlay_appearance.notification_duration_achievement); + + case notification_type::achievement_progress: + return std::chrono::milliseconds(settings->overlay_appearance.notification_duration_progress); + + case notification_type::auto_accept_invite: + return Notification::default_show_time; + } + + PRINT_DEBUG("ERROR unhandled type %i", (int)type); + return Notification::default_show_time; +} + // set the position of the next notification -void Steam_Overlay::set_next_notification_pos(std::pair scrn_size, std::chrono::milliseconds elapsed, const Notification ¬i, struct NotificationsCoords &coords) +void Steam_Overlay::set_next_notification_pos(std::pair scrn_size, std::chrono::milliseconds elapsed, std::chrono::milliseconds duration, const Notification ¬i, struct NotificationsCoords &coords) { const float scrn_width = scrn_size.first; const float scrn_height = scrn_size.second; @@ -932,19 +957,19 @@ void Steam_Overlay::set_next_notification_pos(std::pair scrn_size, switch (pos) { // top case Overlay_Appearance::NotificationPosition::top_left: - animate_size = animate_factor(elapsed) * noti_width; + animate_size = animate_factor(elapsed, duration) * noti_width; x = margin_x - animate_size; y = coords.top_left.second + margin_y; coords.top_left.second = y + noti_height; break; case Overlay_Appearance::NotificationPosition::top_center: - animate_size = animate_factor(elapsed) * noti_height; + animate_size = animate_factor(elapsed, duration) * noti_height; x = (scrn_width / 2) - (noti_width / 2); y = coords.top_center.second + margin_y - animate_size; coords.top_center.second = y + noti_height; break; case Overlay_Appearance::NotificationPosition::top_right: - animate_size = animate_factor(elapsed) * noti_width; + animate_size = animate_factor(elapsed, duration) * noti_width; x = (scrn_width - noti_width - margin_x) + animate_size; y = coords.top_right.second + margin_y; coords.top_right.second = y + noti_height; @@ -952,19 +977,19 @@ void Steam_Overlay::set_next_notification_pos(std::pair scrn_size, // bot case Overlay_Appearance::NotificationPosition::bot_left: - animate_size = animate_factor(elapsed) * noti_width; + animate_size = animate_factor(elapsed, duration) * noti_width; x = margin_x - animate_size; y = scrn_height - coords.bot_left.second - margin_y - noti_height; coords.bot_left.second = scrn_height - y; break; case Overlay_Appearance::NotificationPosition::bot_center: - animate_size = animate_factor(elapsed) * noti_height; + animate_size = animate_factor(elapsed, duration) * noti_height; x = (scrn_width / 2) - (noti_width / 2); y = scrn_height - coords.bot_center.second - margin_y - noti_height + animate_size; coords.bot_center.second = scrn_height - y; break; case Overlay_Appearance::NotificationPosition::bot_right: - animate_size = animate_factor(elapsed) * noti_width; + animate_size = animate_factor(elapsed, duration) * noti_width; x = (scrn_width - noti_width - margin_x) + animate_size; y = scrn_height - coords.bot_right.second - margin_y - noti_height; coords.bot_right.second = scrn_height - y; @@ -977,12 +1002,12 @@ void Steam_Overlay::set_next_notification_pos(std::pair scrn_size, ImGui::SetNextWindowSize(ImVec2(noti_width, noti_height)); } -float Steam_Overlay::animate_factor(std::chrono::milliseconds elapsed) +float Steam_Overlay::animate_factor(std::chrono::milliseconds elapsed, std::chrono::milliseconds duration) { if (settings->overlay_appearance.notification_animation <= 0) return 0.0f; // no animation std::chrono::milliseconds animation_duration(settings->overlay_appearance.notification_animation); - // PRINT_DEBUG("ELAPSED %u/%u", (uint32)elapsed.count(), (uint32)animation_duration.count()); + // PRINT_DEBUG("ELAPSED %u/%u/%u", (uint32)elapsed.count(), (uint32)duration.count(), (uint32)animation_duration.count()); float factor = 0.0f; if (elapsed < animation_duration) { // sliding in @@ -990,9 +1015,14 @@ float Steam_Overlay::animate_factor(std::chrono::milliseconds elapsed) // PRINT_DEBUG("SHOW FACTOR %f", factor); } else { // time between sliding in/out animation - auto steady_time = Notification::show_time - animation_duration; + // here we add the animation duration because we want to count after the animation + // if we have 1 sec animation & 2 sec show time: + // the duration will start at < 1 sec during the initial animation + // after the animation (1 sec), the duration will be >= 1 sec + // but since we want 2 sec show time, the duration must last 3 sec + auto steady_time = animation_duration + duration; if (elapsed > steady_time) { - factor = 1.0f - static_cast((Notification::show_time - elapsed).count()) / animation_duration.count(); + factor = static_cast((elapsed - steady_time).count()) / animation_duration.count(); // PRINT_DEBUG("HIDE FACTOR %f", factor); } } @@ -1044,9 +1074,19 @@ void Steam_Overlay::build_notifications(float width, float height) NotificationsCoords coords{}; for (auto it = notifications.begin(); it != notifications.end(); ++it) { - auto elapsed_notif = now - it->start_time; + auto noti_duration = get_notification_duration((notification_type)it->type); + if (noti_duration.count() <= 0) { + it->expired = true; + continue; + } - set_next_notification_pos({width, height}, elapsed_notif, *it, coords); + // *2 for sliding in & out animation + auto total_allowed_duration = noti_duration + std::chrono::milliseconds(settings->overlay_appearance.notification_animation * 2); + auto elapsed_notif = now - it->start_time; + if (elapsed_notif > total_allowed_duration) { + it->expired = true; + continue; + } float settings_noti_alpha = settings->overlay_appearance.notification_a >= 0.0f && settings->overlay_appearance.notification_a <= 1.0f ? settings->overlay_appearance.notification_a @@ -1078,6 +1118,8 @@ void Steam_Overlay::build_notifications(float width, float height) } std::string wnd_name = "NotiPopupShow" + std::to_string(it->id); + + set_next_notification_pos({width, height}, elapsed_notif, noti_duration, *it, coords); if (ImGui::Begin(wnd_name.c_str(), nullptr, ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoResize | extra_flags)) { switch ((notification_type)it->type) { @@ -1142,8 +1184,8 @@ void Steam_Overlay::build_notifications(float width, float height) ImGui::PopFont(); // erase all notifications whose visible time exceeded the max - notifications.erase(std::remove_if(notifications.begin(), notifications.end(), [this, &now](Notification &item) { - if ((now - item.start_time) > Notification::show_time) { + notifications.erase(std::remove_if(notifications.begin(), notifications.end(), [this](const Notification &item) { + if (item.expired) { PRINT_DEBUG("removing a notification"); allow_renderer_frame_processing(false); // uncomment this block to restore app input focus