mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-25 15:15:40 +00:00
ImGuiFullscreen: Less jarring notifications
This commit is contained in:
parent
a4911946ec
commit
631d1e7433
|
@ -132,7 +132,7 @@ ALWAYS_INLINE_RELEASE static T InExpo(T t)
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ALWAYS_INLINE_RELEASE static T OutExpo(T t)
|
ALWAYS_INLINE_RELEASE static T OutExpo(T t)
|
||||||
{
|
{
|
||||||
return 1 - std::pow(2, -8 * t);
|
return 1.0f - std::pow(2.0f, -8.0f * t);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|
|
@ -146,7 +146,10 @@ struct Notification
|
||||||
std::string text;
|
std::string text;
|
||||||
std::string badge_path;
|
std::string badge_path;
|
||||||
Common::Timer::Value start_time;
|
Common::Timer::Value start_time;
|
||||||
|
Common::Timer::Value move_time;
|
||||||
float duration;
|
float duration;
|
||||||
|
float target_y;
|
||||||
|
float last_y;
|
||||||
};
|
};
|
||||||
|
|
||||||
static std::vector<Notification> s_notifications;
|
static std::vector<Notification> s_notifications;
|
||||||
|
@ -2340,6 +2343,9 @@ void ImGuiFullscreen::AddNotification(float duration, std::string title, std::st
|
||||||
notif.text = std::move(text);
|
notif.text = std::move(text);
|
||||||
notif.badge_path = std::move(image_path);
|
notif.badge_path = std::move(image_path);
|
||||||
notif.start_time = Common::Timer::GetCurrentValue();
|
notif.start_time = Common::Timer::GetCurrentValue();
|
||||||
|
notif.move_time = notif.start_time;
|
||||||
|
notif.target_y = -1.0f;
|
||||||
|
notif.last_y = -1.0f;
|
||||||
s_notifications.push_back(std::move(notif));
|
s_notifications.push_back(std::move(notif));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2353,8 +2359,9 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
|
||||||
if (s_notifications.empty())
|
if (s_notifications.empty())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
static constexpr float EASE_IN_TIME = 0.6f;
|
static constexpr float FADE_IN_TIME = 0.2f;
|
||||||
static constexpr float EASE_OUT_TIME = 0.6f;
|
static constexpr float FADE_OUT_TIME = 0.8f;
|
||||||
|
static constexpr float MOVE_DURATION = 0.5f;
|
||||||
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
const Common::Timer::Value current_time = Common::Timer::GetCurrentValue();
|
||||||
|
|
||||||
const float horizontal_padding = ImGuiFullscreen::LayoutScale(20.0f);
|
const float horizontal_padding = ImGuiFullscreen::LayoutScale(20.0f);
|
||||||
|
@ -2386,7 +2393,7 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
|
||||||
|
|
||||||
for (u32 index = 0; index < static_cast<u32>(s_notifications.size());)
|
for (u32 index = 0; index < static_cast<u32>(s_notifications.size());)
|
||||||
{
|
{
|
||||||
const Notification& notif = s_notifications[index];
|
Notification& notif = s_notifications[index];
|
||||||
const float time_passed = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - notif.start_time));
|
const float time_passed = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - notif.start_time));
|
||||||
if (time_passed >= notif.duration)
|
if (time_passed >= notif.duration)
|
||||||
{
|
{
|
||||||
|
@ -2405,29 +2412,50 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
|
||||||
const float box_height =
|
const float box_height =
|
||||||
std::max((vertical_padding * 2.0f) + title_size.y + vertical_spacing + text_size.y, min_height);
|
std::max((vertical_padding * 2.0f) + title_size.y + vertical_spacing + text_size.y, min_height);
|
||||||
|
|
||||||
float x_offset = 0.0f;
|
u8 opacity;
|
||||||
if (time_passed < EASE_IN_TIME)
|
if (time_passed < FADE_IN_TIME)
|
||||||
|
opacity = static_cast<u8>((time_passed / FADE_IN_TIME) * 255.0f);
|
||||||
|
else if (time_passed > (notif.duration - FADE_OUT_TIME))
|
||||||
|
opacity = static_cast<u8>(std::min((notif.duration - time_passed) / FADE_OUT_TIME, 1.0f) * 255.0f);
|
||||||
|
else
|
||||||
|
opacity = 255;
|
||||||
|
|
||||||
|
const float expected_y = position.y - ((s_notification_vertical_direction < 0.0f) ? box_height : 0.0f);
|
||||||
|
float actual_y = notif.last_y;
|
||||||
|
if (notif.target_y != expected_y)
|
||||||
{
|
{
|
||||||
const float disp = (box_width + position.x);
|
notif.move_time = current_time;
|
||||||
x_offset = -(disp - (disp * Easing::InBack(time_passed / EASE_IN_TIME)));
|
notif.target_y = expected_y;
|
||||||
|
notif.last_y = (notif.last_y < 0.0f) ? expected_y : notif.last_y;
|
||||||
|
actual_y = notif.last_y;
|
||||||
}
|
}
|
||||||
else if (time_passed > (notif.duration - EASE_OUT_TIME))
|
else if (actual_y != expected_y)
|
||||||
{
|
{
|
||||||
const float disp = (box_width + position.x);
|
const float time_since_move = static_cast<float>(Common::Timer::ConvertValueToSeconds(current_time - notif.move_time));
|
||||||
x_offset = -(disp - (disp * Easing::OutBack((notif.duration - time_passed) / EASE_OUT_TIME)));
|
if (time_since_move >= MOVE_DURATION)
|
||||||
|
{
|
||||||
|
notif.move_time = current_time;
|
||||||
|
notif.last_y = notif.target_y;
|
||||||
|
actual_y = notif.last_y;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
const float frac = Easing::OutExpo(time_since_move / MOVE_DURATION);
|
||||||
|
actual_y = notif.last_y - ((notif.last_y - notif.target_y) * frac);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImVec2 box_min(position.x + x_offset,
|
const ImVec2 box_min(position.x, actual_y);
|
||||||
position.y - ((s_notification_vertical_direction < 0.0f) ? box_height : 0.0f));
|
|
||||||
const ImVec2 box_max(box_min.x + box_width, box_min.y + box_height);
|
const ImVec2 box_max(box_min.x + box_width, box_min.y + box_height);
|
||||||
|
const u32 background_color = (toast_background_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
|
||||||
|
const u32 border_color = (toast_border_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
|
||||||
|
|
||||||
ImDrawList* dl = ImGui::GetForegroundDrawList();
|
ImDrawList* dl = ImGui::GetForegroundDrawList();
|
||||||
dl->AddRectFilled(ImVec2(box_min.x + shadow_size, box_min.y + shadow_size),
|
dl->AddRectFilled(ImVec2(box_min.x + shadow_size, box_min.y + shadow_size),
|
||||||
ImVec2(box_max.x + shadow_size, box_max.y + shadow_size), IM_COL32(20, 20, 20, 180), rounding,
|
ImVec2(box_max.x + shadow_size, box_max.y + shadow_size),
|
||||||
ImDrawCornerFlags_All);
|
IM_COL32(20, 20, 20, (180 * opacity) / 255u), rounding, ImDrawCornerFlags_All);
|
||||||
dl->AddRectFilled(box_min, box_max, toast_background_color, rounding, ImDrawCornerFlags_All);
|
dl->AddRectFilled(box_min, box_max, background_color, rounding, ImDrawCornerFlags_All);
|
||||||
dl->AddRect(box_min, box_max, toast_border_color, rounding, ImDrawCornerFlags_All,
|
dl->AddRect(box_min, box_max, border_color, rounding, ImDrawCornerFlags_All, ImGuiFullscreen::LayoutScale(1.0f));
|
||||||
ImGuiFullscreen::LayoutScale(1.0f));
|
|
||||||
|
|
||||||
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + vertical_padding);
|
const ImVec2 badge_min(box_min.x + horizontal_padding, box_min.y + vertical_padding);
|
||||||
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
|
const ImVec2 badge_max(badge_min.x + badge_size, badge_min.y + badge_size);
|
||||||
|
@ -2435,17 +2463,22 @@ void ImGuiFullscreen::DrawNotifications(ImVec2& position, float spacing)
|
||||||
{
|
{
|
||||||
GPUTexture* tex = GetCachedTexture(notif.badge_path.c_str());
|
GPUTexture* tex = GetCachedTexture(notif.badge_path.c_str());
|
||||||
if (tex)
|
if (tex)
|
||||||
dl->AddImage(tex, badge_min, badge_max);
|
{
|
||||||
|
dl->AddImage(tex, badge_min, badge_max, ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f),
|
||||||
|
IM_COL32(255, 255, 255, opacity));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);
|
const ImVec2 title_min(badge_max.x + horizontal_spacing, box_min.y + vertical_padding);
|
||||||
const ImVec2 title_max(title_min.x + title_size.x, title_min.y + title_size.y);
|
const ImVec2 title_max(title_min.x + title_size.x, title_min.y + title_size.y);
|
||||||
dl->AddText(title_font, title_font->FontSize, title_min, toast_title_color, notif.title.c_str(),
|
const u32 title_col = (toast_title_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
|
||||||
|
dl->AddText(title_font, title_font->FontSize, title_min, title_col, notif.title.c_str(),
|
||||||
notif.title.c_str() + notif.title.size(), max_text_width);
|
notif.title.c_str() + notif.title.size(), max_text_width);
|
||||||
|
|
||||||
const ImVec2 text_min(badge_max.x + horizontal_spacing, title_max.y + vertical_spacing);
|
const ImVec2 text_min(badge_max.x + horizontal_spacing, title_max.y + vertical_spacing);
|
||||||
const ImVec2 text_max(text_min.x + text_size.x, text_min.y + text_size.y);
|
const ImVec2 text_max(text_min.x + text_size.x, text_min.y + text_size.y);
|
||||||
dl->AddText(text_font, text_font->FontSize, text_min, toast_text_color, notif.text.c_str(),
|
const u32 text_col = (toast_text_color & ~IM_COL32_A_MASK) | (opacity << IM_COL32_A_SHIFT);
|
||||||
|
dl->AddText(text_font, text_font->FontSize, text_min, text_col, notif.text.c_str(),
|
||||||
notif.text.c_str() + notif.text.size(), max_text_width);
|
notif.text.c_str() + notif.text.size(), max_text_width);
|
||||||
|
|
||||||
position.y += s_notification_vertical_direction * (box_height + shadow_size + spacing);
|
position.y += s_notification_vertical_direction * (box_height + shadow_size + spacing);
|
||||||
|
|
Loading…
Reference in a new issue