FullscreenUI: Add notifications API

This commit is contained in:
Connor McLaughlin
2021-02-21 16:55:28 +10:00
parent 229ed5a852
commit 7e1fe166ee
4 changed files with 220 additions and 41 deletions

View File

@ -6,6 +6,7 @@
#include "common/file_system.h"
#include "common/string.h"
#include "common/string_util.h"
#include "common/timer.h"
#include "core/host_display.h"
#include "core/host_interface.h"
#include "imgui_internal.h"
@ -16,7 +17,8 @@
namespace ImGuiFullscreen {
static void DrawFileSelector();
static void DrawChoiceDialog();
static void DrawBackgroundProgressDialogs();
static void DrawBackgroundProgressDialogs(ImVec2& position, float spacing);
static void DrawNotifications(ImVec2& position, float spacing);
ImFont* g_standard_font = nullptr;
ImFont* g_medium_font = nullptr;
@ -33,6 +35,7 @@ static std::string s_icon_font_filename;
static std::vector<u8> s_icon_font_data;
static float s_font_size = 15.0f;
static const ImWchar* s_font_glyph_range = nullptr;
static ResolveTextureHandleCallback s_resolve_texture_handle = nullptr;
static u32 s_menu_button_index = 0;
@ -75,6 +78,11 @@ void SetMenuBarSize(float size)
s_menu_bar_size = size;
}
void SetResolveTextureFunction(ResolveTextureHandleCallback callback)
{
s_resolve_texture_handle = callback;
}
static void AddIconFonts(float size)
{
static const ImWchar range_fa[] = {ICON_MIN_FA, ICON_MAX_FA, 0};
@ -182,7 +190,12 @@ void EndLayout()
{
DrawFileSelector();
DrawChoiceDialog();
DrawBackgroundProgressDialogs();
const float notification_margin = LayoutScale(10.0f);
const float spacing = LayoutScale(10.0f);
ImVec2 position(notification_margin, g_layout_padding_top + LayoutScale(LAYOUT_SCREEN_HEIGHT) - notification_margin);
DrawBackgroundProgressDialogs(position, spacing);
DrawNotifications(position, spacing);
ImGui::PopStyleColor(5);
ImGui::PopStyleVar(2);
@ -321,7 +334,7 @@ static void GetMenuButtonFrameBounds(float height, ImVec2* pos, ImVec2* size)
}
static bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool* visible, bool* hovered, ImRect* bb,
ImGuiButtonFlags flags = 0)
ImGuiButtonFlags flags = 0, float hover_alpha = 1.0f)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
@ -365,7 +378,7 @@ static bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool
pressed = ImGui::ButtonBehavior(*bb, id, hovered, &held, flags);
if (*hovered)
{
const ImU32 col = ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
const ImU32 col = ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, hover_alpha);
ImGui::RenderFrame(bb->Min, bb->Max, col, true, 0.0f);
}
}
@ -383,10 +396,10 @@ static bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool
}
bool MenuButtonFrame(const char* str_id, bool enabled, float height, bool* visible, bool* hovered, ImVec2* min,
ImVec2* max, ImGuiButtonFlags flags /*= 0*/)
ImVec2* max, ImGuiButtonFlags flags /*= 0*/, float hover_alpha /*= 0*/)
{
ImRect bb;
const bool result = MenuButtonFrame(str_id, enabled, height, visible, hovered, &bb, flags);
const bool result = MenuButtonFrame(str_id, enabled, height, visible, hovered, &bb, flags, hover_alpha);
*min = bb.Min;
*max = bb.Max;
return result;
@ -1214,7 +1227,7 @@ void CloseBackgroundProgressDialog(const char* str_id)
Panic("Closing unknown progress entry.");
}
void DrawBackgroundProgressDialogs()
void DrawBackgroundProgressDialogs(ImVec2& position, float spacing)
{
std::unique_lock<std::mutex> lock(s_background_progress_lock);
if (s_background_progress_dialogs.empty())
@ -1222,10 +1235,6 @@ void DrawBackgroundProgressDialogs()
const float window_width = LayoutScale(500.0f);
const float window_height = LayoutScale(75.0f);
const float window_spacing = LayoutScale(20.0f);
float current_pos_x = LayoutScale(10.0f);
float current_pos_y = (LayoutScale(LAYOUT_SCREEN_HEIGHT) + g_layout_padding_top) - window_height - LayoutScale(10.0f);
ImGui::PushStyleColor(ImGuiCol_WindowBg, UIPrimaryDarkColor());
ImGui::PushStyleColor(ImGuiCol_PlotHistogram, UISecondaryLightColor());
@ -1239,11 +1248,14 @@ void DrawBackgroundProgressDialogs()
for (const BackgroundProgressDialogData& data : s_background_progress_dialogs)
{
dl->AddRectFilled(ImVec2(current_pos_x, current_pos_y),
ImVec2(current_pos_x + window_width, current_pos_y + window_height),
const float window_pos_x = position.x;
const float window_pos_y = position.y - window_height;
dl->AddRectFilled(ImVec2(window_pos_x, window_pos_y),
ImVec2(window_pos_x + window_width, window_pos_y + window_height),
IM_COL32(0x11, 0x11, 0x11, 200), LayoutScale(10.0f));
ImVec2 pos(current_pos_x + LayoutScale(10.0f), current_pos_y + LayoutScale(10.0f));
ImVec2 pos(window_pos_x + LayoutScale(10.0f), window_pos_y + LayoutScale(10.0f));
dl->AddText(g_medium_font, g_medium_font->FontSize, pos, IM_COL32(255, 255, 255, 255), data.message.c_str(),
nullptr, 0.0f);
pos.y += g_medium_font->FontSize + LayoutScale(10.0f);
@ -1261,7 +1273,7 @@ void DrawBackgroundProgressDialogs()
pos.y + ((bar_end.y - pos.y) / 2.0f) - (text_size.y / 2.0f));
dl->AddText(g_medium_font, g_medium_font->FontSize, text_pos, ImGui::GetColorU32(UIPrimaryTextColor()), text);
current_pos_y -= window_height - window_spacing;
position.y -= window_height + spacing;
}
ImGui::PopFont();
@ -1269,4 +1281,118 @@ void DrawBackgroundProgressDialogs()
ImGui::PopStyleColor(2);
}
//////////////////////////////////////////////////////////////////////////
// Notifications
//////////////////////////////////////////////////////////////////////////
struct Notification
{
std::string title;
std::string text;
std::string badge_path;
Common::Timer::Value start_time;
float duration;
};
static std::vector<Notification> s_notifications;
void AddNotification(float duration, std::string title, std::string text, std::string image_path)
{
Notification notif;
notif.duration = duration;
notif.title = std::move(title);
notif.text = std::move(text);
notif.badge_path = std::move(image_path);
notif.start_time = Common::Timer::GetValue();
s_notifications.push_back(std::move(notif));
}
void DrawNotifications(ImVec2& position, float spacing)
{
if (s_notifications.empty())
return;
const Common::Timer::Value current_time = Common::Timer::GetValue();
const float horizontal_padding = ImGuiFullscreen::LayoutScale(20.0f);
const float vertical_padding = ImGuiFullscreen::LayoutScale(10.0f);
const float horizontal_spacing = ImGuiFullscreen::LayoutScale(10.0f);
const float vertical_spacing = ImGuiFullscreen::LayoutScale(4.0f);
const float badge_size = ImGuiFullscreen::LayoutScale(48.0f);
const float min_width = ImGuiFullscreen::LayoutScale(200.0f);
const float max_width = ImGuiFullscreen::LayoutScale(800.0f);
const float max_text_width = max_width - badge_size - (horizontal_padding * 2.0f) - horizontal_spacing;
const float min_height = (vertical_padding * 2.0f) + badge_size;
const float shadow_size = ImGuiFullscreen::LayoutScale(4.0f);
const float rounding = ImGuiFullscreen::LayoutScale(4.0f);
ImFont* const title_font = ImGuiFullscreen::g_large_font;
ImFont* const text_font = ImGuiFullscreen::g_medium_font;
#if 0
static constexpr u32 toast_background_color = IM_COL32(241, 241, 241, 255);
static constexpr u32 toast_border_color = IM_COL32(0x88, 0x88, 0x88, 255);
static constexpr u32 toast_title_color = IM_COL32(1, 1, 1, 255);
static constexpr u32 toast_text_color = IM_COL32(0, 0, 0, 255);
#else
static constexpr u32 toast_background_color = IM_COL32(0x21, 0x21, 0x21, 255);
static constexpr u32 toast_border_color = IM_COL32(0x48, 0x48, 0x48, 255);
static constexpr u32 toast_title_color = IM_COL32(0xff, 0xff, 0xff, 255);
static constexpr u32 toast_text_color = IM_COL32(0xff, 0xff, 0xff, 255);
#endif
for (u32 index = 0; index < static_cast<u32>(s_notifications.size());)
{
Notification& notif = s_notifications[index];
if (Common::Timer::ConvertValueToSeconds(current_time - notif.start_time) >= notif.duration)
{
s_notifications.erase(s_notifications.begin() + index);
continue;
}
const ImVec2 title_size(text_font->CalcTextSizeA(title_font->FontSize, max_text_width, max_text_width,
notif.title.c_str(), notif.title.c_str() + notif.title.size()));
const ImVec2 text_size(text_font->CalcTextSizeA(text_font->FontSize, max_text_width, max_text_width,
notif.text.c_str(), notif.text.c_str() + notif.text.size()));
const float box_width = std::max(
(horizontal_padding * 2.0f) + badge_size + horizontal_spacing + std::max(title_size.x, text_size.x), min_width);
const float box_height =
std::max((vertical_padding * 2.0f) + title_size.y + vertical_spacing + text_size.y, min_height);
const ImVec2 box_min(position.x, position.y - box_height);
const ImVec2 box_max(box_min.x + box_width, box_min.y + box_height);
ImDrawList* dl = ImGui::GetForegroundDrawList();
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,
ImDrawCornerFlags_All);
dl->AddRectFilled(box_min, box_max, toast_background_color, rounding, ImDrawCornerFlags_All);
dl->AddRect(box_min, box_max, toast_border_color, rounding, ImDrawCornerFlags_All,
ImGuiFullscreen::LayoutScale(1.0f));
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);
if (!notif.badge_path.empty() && s_resolve_texture_handle)
{
ImTextureID tex = s_resolve_texture_handle(notif.badge_path);
if (tex)
dl->AddImage(tex, badge_min, badge_max);
}
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);
dl->AddText(title_font, title_font->FontSize, title_min, toast_title_color, notif.title.c_str(),
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_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(),
notif.text.c_str() + notif.text.size(), max_text_width);
position.y -= box_height + shadow_size + spacing;
index++;
}
}
} // namespace ImGuiFullscreen