FullscreenUI: Redo landing page and add help bar

Backport of bf4e8feb25
This commit is contained in:
Stenzek 2024-04-13 00:53:58 +10:00 committed by Connor McLaughlin
parent 888f3d8499
commit 2157a7ed0b
18 changed files with 935 additions and 210 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include <atomic>
@ -356,7 +356,11 @@ void Host::OnCaptureStopped()
{
}
void Host::RequestExit(bool allow_confirm)
void Host::RequestExitApplication(bool allow_confirm)
{
}
void Host::RequestExitBigPicture()
{
}

View File

@ -215,6 +215,8 @@ void EmuThread::stopFullscreenUI()
return;
}
setFullscreen(false, true);
if (MTGS::IsOpen() && !VMManager::HasValidVM())
MTGS::WaitForClose();
@ -1145,11 +1147,16 @@ void Host::CancelGameListRefresh()
QMetaObject::invokeMethod(g_main_window, "cancelGameListRefresh", Qt::BlockingQueuedConnection);
}
void Host::RequestExit(bool allow_confirm)
void Host::RequestExitApplication(bool allow_confirm)
{
QMetaObject::invokeMethod(g_main_window, "requestExit", Qt::QueuedConnection, Q_ARG(bool, allow_confirm));
}
void Host::RequestExitBigPicture()
{
g_emu_thread->stopFullscreenUI();
}
void Host::RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state)
{
if (!VMManager::HasValidVM())

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#define IMGUI_DEFINE_MATH_OPERATORS
@ -1729,16 +1729,7 @@ void Achievements::ShowLoginSuccess(const rc_client_t* client)
if (EmuConfig.Achievements.Notifications && MTGS::IsOpen())
{
std::string badge_path = GetUserBadgePath(user->username);
if (!FileSystem::FileExists(badge_path.c_str()))
{
char url[512];
const int res = rc_client_user_get_image_url(user, url, std::size(url));
if (res == RC_OK)
DownloadImage(url, badge_path);
else
ReportRCError(res, "rc_client_user_get_image_url() failed: ");
}
std::string badge_path = GetLoggedInUserBadgePath();
//: Summary for login notification.
std::string title = user->display_name;
@ -1755,6 +1746,37 @@ void Achievements::ShowLoginSuccess(const rc_client_t* client)
}
}
const char* Achievements::GetLoggedInUserName()
{
const rc_client_user_t* user = rc_client_get_user_info(s_client);
if (!user) [[unlikely]]
return nullptr;
return user->username;
}
std::string Achievements::GetLoggedInUserBadgePath()
{
std::string badge_path;
const rc_client_user_t* user = rc_client_get_user_info(s_client);
if (!user) [[unlikely]]
return badge_path;
badge_path = GetUserBadgePath(user->username);
if (!FileSystem::FileExists(badge_path.c_str())) [[unlikely]]
{
char url[512];
const int res = rc_client_user_get_image_url(user, url, std::size(url));
if (res == RC_OK)
DownloadImage(url, badge_path);
else
ReportRCError(res, "rc_client_user_get_image_url() failed: ");
}
return badge_path;
}
void Achievements::Logout()
{
if (IsActive())
@ -2279,6 +2301,7 @@ void Achievements::DrawAchievementsWindow()
ImGuiFullscreen::EndMenuButtons();
}
ImGuiFullscreen::EndFullscreenWindow();
FullscreenUI::SetStandardSelectionFooterText(true);
}
void Achievements::DrawAchievement(const rc_client_achievement_t* cheevo)
@ -2657,6 +2680,7 @@ void Achievements::DrawLeaderboardsWindow()
}
}
ImGuiFullscreen::EndFullscreenWindow();
FullscreenUI::SetStandardSelectionFooterText(true);
if (!is_leaderboard_open)
{

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
@ -109,6 +109,13 @@ namespace Achievements
/// Should be called with the lock held.
const std::string& GetGameTitle();
/// Returns the logged-in user name.
const char* GetLoggedInUserName();
/// Returns the path to the user's profile avatar.
/// Should be called with the lock held.
std::string GetLoggedInUserBadgePath();
/// Clears all cached state used to render the UI.
void ClearUIState();

View File

@ -81,10 +81,6 @@ namespace Host
/// Cancels game list refresh, if there is one in progress.
void CancelGameListRefresh();
/// Requests shut down and exit of the hosting application. This may not actually exit,
/// if the user cancels the shutdown confirmation.
void RequestExit(bool allow_confirm);
/// Requests shut down of the current virtual machine.
void RequestVMShutdown(bool allow_confirm, bool allow_save_state, bool default_save_state);

File diff suppressed because it is too large Load Diff

View File

@ -31,6 +31,7 @@ namespace FullscreenUI
bool IsLeaderboardsWindowOpen();
void ReturnToPreviousWindow();
void ReturnToMainWindow();
void SetStandardSelectionFooterText(bool back_instead_of_cancel);
void Shutdown(bool clear_state);
void Render();
@ -41,6 +42,13 @@ namespace FullscreenUI
// Host UI triggers from Big Picture mode.
namespace Host
{
void OnCoverDownloaderOpenRequested();
void OnCreateMemoryCardOpenRequested();
}
/// Requests shut down and exit of the hosting application. This may not actually exit,
/// if the user cancels the shutdown confirmation.
void RequestExitApplication(bool allow_confirm);
/// Requests Big Picture mode to be shut down, returning to the desktop interface.
void RequestExitBigPicture();
void OnCoverDownloaderOpenRequested();
void OnCreateMemoryCardOpenRequested();
} // namespace Host

View File

@ -95,6 +95,10 @@ namespace ImGuiFullscreen
static std::deque<std::pair<std::string, RGBA8Image>> s_texture_upload_queue;
static Threading::Thread s_texture_load_thread;
static SmallString s_fullscreen_footer_text;
static SmallString s_last_fullscreen_footer_text;
static float s_fullscreen_text_change_time;
static bool s_choice_dialog_open = false;
static bool s_choice_dialog_checkable = false;
static std::string s_choice_dialog_title;
@ -238,6 +242,9 @@ void ImGuiFullscreen::Shutdown(bool clear_state)
{
s_notifications.clear();
s_background_progress_dialogs.clear();
s_fullscreen_footer_text.clear();
s_last_fullscreen_footer_text.clear();
s_fullscreen_text_change_time = 0.0f;
CloseInputDialog();
CloseMessageDialog();
s_choice_dialog_open = false;
@ -255,6 +262,11 @@ void ImGuiFullscreen::Shutdown(bool clear_state)
s_file_selector_current_directory = {};
s_file_selector_filters.clear();
s_file_selector_items.clear();
s_message_dialog_open = false;
s_message_dialog_title = {};
s_message_dialog_message = {};
s_message_dialog_buttons = {};
s_message_dialog_callback = {};
}
}
@ -309,12 +321,13 @@ std::shared_ptr<GSTexture> ImGuiFullscreen::UploadTexture(const char* path, cons
return std::shared_ptr<GSTexture>(texture, [](GSTexture* tex) { g_gs_device->Recycle(tex); });
}
std::shared_ptr<GSTexture> ImGuiFullscreen::LoadTexture(const char* path)
std::shared_ptr<GSTexture> ImGuiFullscreen::LoadTexture(std::string_view path)
{
std::optional<RGBA8Image> image(LoadTextureImage(path));
std::string path_str(path);
std::optional<RGBA8Image> image(LoadTextureImage(path_str.c_str()));
if (image.has_value())
{
std::shared_ptr<GSTexture> ret(UploadTexture(path, image.value()));
std::shared_ptr<GSTexture> ret(UploadTexture(path_str.c_str(), image.value()));
if (ret)
return ret;
}
@ -322,25 +335,25 @@ std::shared_ptr<GSTexture> ImGuiFullscreen::LoadTexture(const char* path)
return s_placeholder_texture;
}
GSTexture* ImGuiFullscreen::GetCachedTexture(const char* name)
GSTexture* ImGuiFullscreen::GetCachedTexture(std::string_view name)
{
std::shared_ptr<GSTexture>* tex_ptr = s_texture_cache.Lookup(name);
if (!tex_ptr)
{
std::shared_ptr<GSTexture> tex(LoadTexture(name));
tex_ptr = s_texture_cache.Insert(name, std::move(tex));
tex_ptr = s_texture_cache.Insert(std::string(name), std::move(tex));
}
return tex_ptr->get();
}
GSTexture* ImGuiFullscreen::GetCachedTextureAsync(const char* name)
GSTexture* ImGuiFullscreen::GetCachedTextureAsync(std::string_view name)
{
std::shared_ptr<GSTexture>* tex_ptr = s_texture_cache.Lookup(name);
if (!tex_ptr)
{
// insert the placeholder
tex_ptr = s_texture_cache.Insert(name, s_placeholder_texture);
tex_ptr = s_texture_cache.Insert(std::string(name), s_placeholder_texture);
// queue the actual load
std::unique_lock lock(s_texture_load_mutex);
@ -484,6 +497,8 @@ void ImGuiFullscreen::EndLayout()
DrawInputDialog();
DrawMessageDialog();
DrawFullscreenFooter();
const float notification_margin = LayoutScale(10.0f);
const float spacing = LayoutScale(10.0f);
const float notification_vertical_pos = GetNotificationVerticalPosition();
@ -495,6 +510,8 @@ void ImGuiFullscreen::EndLayout()
PopResetLayout();
s_fullscreen_footer_text.clear();
s_rendered_menu_item_border = false;
s_had_hovered_menu_item = std::exchange(s_has_hovered_menu_item, false);
}
@ -544,6 +561,10 @@ bool ImGuiFullscreen::ResetFocusHere()
if (!s_focus_reset_queued)
return false;
// don't take focus from dialogs
if (ImGui::FindBlockingModal(ImGui::GetCurrentWindow()))
return false;
s_focus_reset_queued = false;
ImGui::SetWindowFocus();
@ -551,6 +572,20 @@ bool ImGuiFullscreen::ResetFocusHere()
return (GImGui->NavInputSource == ImGuiInputSource_Keyboard || GImGui->NavInputSource == ImGuiInputSource_Gamepad);
}
bool ImGuiFullscreen::IsFocusResetQueued()
{
return s_focus_reset_queued;
}
void ImGuiFullscreen::ForceKeyNavEnabled()
{
ImGuiContext& g = *ImGui::GetCurrentContext();
g.ActiveIdSource = (g.ActiveIdSource == ImGuiInputSource_Mouse) ? ImGuiInputSource_Keyboard : g.ActiveIdSource;
g.NavInputSource = (g.NavInputSource == ImGuiInputSource_Mouse) ? ImGuiInputSource_Keyboard : g.ActiveIdSource;
g.NavDisableHighlight = false;
g.NavDisableMouseHover = true;
}
bool ImGuiFullscreen::WantsToCloseMenu()
{
// Wait for the Close button to be released, THEN pressed
@ -592,11 +627,12 @@ void ImGuiFullscreen::PopPrimaryColor()
ImGui::PopStyleColor(5);
}
bool ImGuiFullscreen::BeginFullscreenColumns(const char* title, float pos_y, bool expand_to_screen_width)
bool ImGuiFullscreen::BeginFullscreenColumns(const char* title, float pos_y, bool expand_to_screen_width, bool footer)
{
ImGui::SetNextWindowPos(ImVec2(expand_to_screen_width ? 0.0f : g_layout_padding_left, pos_y));
ImGui::SetNextWindowSize(ImVec2(
expand_to_screen_width ? ImGui::GetIO().DisplaySize.x : LayoutScale(LAYOUT_SCREEN_WIDTH), ImGui::GetIO().DisplaySize.y - pos_y));
expand_to_screen_width ? ImGui::GetIO().DisplaySize.x : LayoutScale(LAYOUT_SCREEN_WIDTH),
ImGui::GetIO().DisplaySize.y - pos_y - (footer ? LayoutScale(LAYOUT_FOOTER_HEIGHT) : 0.0f)));
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
@ -688,14 +724,103 @@ void ImGuiFullscreen::EndFullscreenWindow()
ImGui::PopStyleColor();
}
bool ImGuiFullscreen::IsGamepadInputSource()
{
return (ImGui::GetCurrentContext()->NavInputSource == ImGuiInputSource_Gamepad);
}
void ImGuiFullscreen::CreateFooterTextString(SmallStringBase& dest,
std::span<const std::pair<const char*, std::string_view>> items)
{
dest.clear();
for (const auto& [icon, text] : items)
{
if (!dest.empty())
dest.append(" ");
dest.append(icon);
dest.append(' ');
dest.append(text);
}
}
void ImGuiFullscreen::SetFullscreenFooterText(std::string_view text)
{
s_fullscreen_footer_text.assign(text);
}
void ImGuiFullscreen::SetFullscreenFooterText(std::span<const std::pair<const char*, std::string_view>> items)
{
CreateFooterTextString(s_fullscreen_footer_text, items);
}
void ImGuiFullscreen::DrawFullscreenFooter()
{
const ImGuiIO& io = ImGui::GetIO();
if (s_fullscreen_footer_text.empty())
{
s_last_fullscreen_footer_text.clear();
return;
}
const float padding = LayoutScale(LAYOUT_FOOTER_PADDING);
const float height = LayoutScale(LAYOUT_FOOTER_HEIGHT);
ImDrawList* dl = ImGui::GetForegroundDrawList();
dl->AddRectFilled(ImVec2(0.0f, io.DisplaySize.y - height), io.DisplaySize, ImGui::GetColorU32(UIPrimaryColor), 0.0f);
ImFont* const font = g_medium_font;
const float max_width = io.DisplaySize.x - padding * 2.0f;
float prev_opacity = 0.0f;
if (!s_last_fullscreen_footer_text.empty() && s_fullscreen_footer_text != s_last_fullscreen_footer_text)
{
if (s_fullscreen_text_change_time == 0.0f)
s_fullscreen_text_change_time = 0.15f;
else
s_fullscreen_text_change_time = std::max(s_fullscreen_text_change_time - io.DeltaTime, 0.0f);
if (s_fullscreen_text_change_time == 0.0f)
s_last_fullscreen_footer_text = s_fullscreen_footer_text;
prev_opacity = s_fullscreen_text_change_time * (1.0f / 0.15f);
if (prev_opacity > 0.0f)
{
const ImVec2 text_size =
font->CalcTextSizeA(font->FontSize, max_width, 0.0f, s_last_fullscreen_footer_text.c_str(),
s_last_fullscreen_footer_text.end_ptr());
dl->AddText(
font, font->FontSize,
ImVec2(io.DisplaySize.x - padding * 2.0f - text_size.x, io.DisplaySize.y - font->FontSize - padding),
ImGui::GetColorU32(ImVec4(UIPrimaryTextColor.x, UIPrimaryTextColor.y, UIPrimaryTextColor.z, prev_opacity)),
s_last_fullscreen_footer_text.c_str(), s_last_fullscreen_footer_text.end_ptr());
}
}
else if (s_last_fullscreen_footer_text.empty())
{
s_last_fullscreen_footer_text = s_fullscreen_footer_text;
}
if (prev_opacity < 1.0f)
{
const ImVec2 text_size = font->CalcTextSizeA(font->FontSize, max_width, 0.0f, s_fullscreen_footer_text.c_str(),
s_fullscreen_footer_text.end_ptr());
dl->AddText(
font, font->FontSize,
ImVec2(io.DisplaySize.x - padding * 2.0f - text_size.x, io.DisplaySize.y - font->FontSize - padding),
ImGui::GetColorU32(ImVec4(UIPrimaryTextColor.x, UIPrimaryTextColor.y, UIPrimaryTextColor.z, 1.0f - prev_opacity)),
s_fullscreen_footer_text.c_str(), s_fullscreen_footer_text.end_ptr());
}
}
void ImGuiFullscreen::PrerenderMenuButtonBorder()
{
if (!s_had_hovered_menu_item)
return;
// updating might finish the animation
const ImVec2 min = s_menu_button_frame_min_animated.UpdateAndGetValue();
const ImVec2 max = s_menu_button_frame_max_animated.UpdateAndGetValue();
const ImVec2& min = s_menu_button_frame_min_animated.UpdateAndGetValue();
const ImVec2& max = s_menu_button_frame_max_animated.UpdateAndGetValue();
const ImU32 col = ImGui::GetColorU32(ImGuiCol_ButtonHovered);
const float t = std::min<float>(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0f);
@ -787,7 +912,7 @@ void ImGuiFullscreen::DrawMenuButtonFrame(const ImVec2& p_min, const ImVec2& p_m
MENU_BACKGROUND_ANIMATION_TIME);
}
if (frame_max.x != s_menu_button_frame_max_animated.GetEndValue().x ||
frame_max.y != s_menu_button_frame_max_animated.GetEndValue().x)
frame_max.y != s_menu_button_frame_max_animated.GetEndValue().y)
{
s_menu_button_frame_max_animated.Start(s_menu_button_frame_max_animated.GetCurrentValue(), frame_max,
MENU_BACKGROUND_ANIMATION_TIME);
@ -1739,6 +1864,100 @@ bool ImGuiFullscreen::NavTab(const char* title, bool is_active, bool enabled /*
return pressed;
}
bool ImGuiFullscreen::BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, u32 num_items)
{
s_menu_button_index = 0;
const float item_padding = LayoutScale(LAYOUT_HORIZONTAL_MENU_PADDING);
const float item_width = LayoutScale(LAYOUT_HORIZONTAL_MENU_ITEM_WIDTH);
const float item_spacing = LayoutScale(30.0f);
const float menu_width = static_cast<float>(num_items) * (item_width + item_spacing) - item_spacing;
const float menu_height = LayoutScale(LAYOUT_HORIZONTAL_MENU_HEIGHT);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(item_padding, item_padding));
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 0.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, LayoutScale(1.0f));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(item_spacing, 0.0f));
if (!BeginFullscreenWindow(position, size, name, UIBackgroundColor, 0.0f, 0.0f))
return false;
ImGui::SetCursorPos(ImVec2((size.x - menu_width) * 0.5f, (size.y - menu_height) * 0.5f));
PrerenderMenuButtonBorder();
return true;
}
void ImGuiFullscreen::EndHorizontalMenu()
{
ImGui::PopStyleVar(4);
EndFullscreenWindow();
}
bool ImGuiFullscreen::HorizontalMenuItem(GSTexture* icon, const char* title, const char* description)
{
ImGuiWindow* window = ImGui::GetCurrentWindow();
if (window->SkipItems)
return false;
const ImVec2 pos = window->DC.CursorPos;
const ImVec2 size = LayoutScale(LAYOUT_HORIZONTAL_MENU_ITEM_WIDTH, LAYOUT_HORIZONTAL_MENU_HEIGHT);
ImRect bb = ImRect(pos, pos + size);
const ImGuiID id = window->GetID(title);
ImGui::ItemSize(size);
if (!ImGui::ItemAdd(bb, id))
return false;
bool held;
bool hovered;
const bool pressed = ImGui::ButtonBehavior(bb, id, &hovered, &held, 0);
if (hovered)
{
const ImU32 col = ImGui::GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered, 1.0f);
const float t = static_cast<float>(std::min(std::abs(std::sin(ImGui::GetTime() * 0.75) * 1.1), 1.0));
ImGui::PushStyleColor(ImGuiCol_Border, ImGui::GetColorU32(ImGuiCol_Border, t));
DrawMenuButtonFrame(bb.Min, bb.Max, col, true, 0.0f);
ImGui::PopStyleColor();
}
const ImGuiStyle& style = ImGui::GetStyle();
bb.Min += style.FramePadding;
bb.Max -= style.FramePadding;
const float avail_width = bb.Max.x - bb.Min.x;
const float icon_size = LayoutScale(150.0f);
const ImVec2 icon_pos = bb.Min + ImVec2((avail_width - icon_size) * 0.5f, 0.0f);
ImDrawList* dl = ImGui::GetWindowDrawList();
dl->AddImage(reinterpret_cast<ImTextureID>(icon), icon_pos, icon_pos + ImVec2(icon_size, icon_size));
ImFont* title_font = g_large_font;
const ImVec2 title_size = title_font->CalcTextSizeA(title_font->FontSize, avail_width, 0.0f, title);
const ImVec2 title_pos =
ImVec2(bb.Min.x + (avail_width - title_size.x) * 0.5f, icon_pos.y + icon_size + LayoutScale(10.0f));
const ImVec4 title_bb = ImVec4(title_pos.x, title_pos.y, title_pos.x + title_size.x, title_pos.y + title_size.y);
dl->AddText(title_font, title_font->FontSize, title_pos, ImGui::GetColorU32(ImGuiCol_Text), title, nullptr, 0.0f,
&title_bb);
ImFont* desc_font = g_medium_font;
const ImVec2 desc_size = desc_font->CalcTextSizeA(desc_font->FontSize, avail_width, avail_width, description);
const ImVec2 desc_pos = ImVec2(bb.Min.x + (avail_width - desc_size.x) * 0.5f, title_bb.w + LayoutScale(10.0f));
const ImVec4 desc_bb = ImVec4(desc_pos.x, desc_pos.y, desc_pos.x + desc_size.x, desc_pos.y + desc_size.y);
dl->AddText(desc_font, desc_font->FontSize, desc_pos, ImGui::GetColorU32(ImGuiCol_Text), description, nullptr,
avail_width, &desc_bb);
ImGui::SameLine();
s_menu_button_index++;
return pressed;
}
void ImGuiFullscreen::PopulateFileSelectorItems()
{
s_file_selector_items.clear();
@ -1817,21 +2036,22 @@ bool ImGuiFullscreen::IsFileSelectorOpen()
return s_file_selector_open;
}
void ImGuiFullscreen::OpenFileSelector(
const char* title, bool select_directory, FileSelectorCallback callback, FileSelectorFilters filters, std::string initial_directory)
void ImGuiFullscreen::OpenFileSelector(std::string_view title, bool select_directory, FileSelectorCallback callback,
FileSelectorFilters filters, std::string initial_directory)
{
if (s_file_selector_open)
CloseFileSelector();
s_file_selector_open = true;
s_file_selector_directory = select_directory;
s_file_selector_title = StringUtil::StdStringFromFormat("%s##file_selector", title);
s_file_selector_title = fmt::format("{}##file_selector", title);
s_file_selector_callback = std::move(callback);
s_file_selector_filters = std::move(filters);
if (initial_directory.empty() || !FileSystem::DirectoryExists(initial_directory.c_str()))
initial_directory = FileSystem::GetWorkingDirectory();
SetFileSelectorDirectory(std::move(initial_directory));
QueueResetFocus();
}
void ImGuiFullscreen::CloseFileSelector()
@ -1856,7 +2076,8 @@ void ImGuiFullscreen::DrawFileSelector()
return;
ImGui::SetNextWindowSize(LayoutScale(1000.0f, 680.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowPos((ImGui::GetIO().DisplaySize - LayoutScale(0.0f, LAYOUT_FOOTER_HEIGHT)) * 0.5f,
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(s_file_selector_title.c_str());
FileSelectorItem* selected = nullptr;
@ -1878,6 +2099,7 @@ void ImGuiFullscreen::DrawFileSelector()
ImGui::PushStyleColor(ImGuiCol_Text, UIBackgroundTextColor);
BeginMenuButtons();
ResetFocusHere();
if (!s_file_selector_current_directory.empty())
{
@ -1912,11 +2134,15 @@ void ImGuiFullscreen::DrawFileSelector()
ImGui::PopStyleVar(3);
ImGui::PopFont();
if (is_open)
GetFileSelectorHelpText(s_fullscreen_footer_text);
if (selected)
{
if (selected->is_file)
{
s_file_selector_callback(selected->full_path);
QueueResetFocus();
}
else
{
@ -1933,6 +2159,18 @@ void ImGuiFullscreen::DrawFileSelector()
s_file_selector_callback(no_path);
CloseFileSelector();
}
else
{
if (ImGui::IsKeyPressed(ImGuiKey_Backspace, false) || ImGui::IsKeyPressed(ImGuiKey_NavGamepadMenu, false))
{
if (!s_file_selector_items.empty() && s_file_selector_items.front().display_name == ICON_FA_FOLDER_OPEN
" <Parent Directory>")
{
SetFileSelectorDirectory(std::move(s_file_selector_items.front().full_path));
QueueResetFocus();
}
}
}
}
bool ImGuiFullscreen::IsChoiceDialogOpen()
@ -1940,16 +2178,17 @@ bool ImGuiFullscreen::IsChoiceDialogOpen()
return s_choice_dialog_open;
}
void ImGuiFullscreen::OpenChoiceDialog(const char* title, bool checkable, ChoiceDialogOptions options, ChoiceDialogCallback callback)
void ImGuiFullscreen::OpenChoiceDialog(std::string_view title, bool checkable, ChoiceDialogOptions options, ChoiceDialogCallback callback)
{
if (s_choice_dialog_open)
CloseChoiceDialog();
s_choice_dialog_open = true;
s_choice_dialog_checkable = checkable;
s_choice_dialog_title = StringUtil::StdStringFromFormat("%s##choice_dialog", title);
s_choice_dialog_title = fmt::format("{}##choice_dialog", title);
s_choice_dialog_options = std::move(options);
s_choice_dialog_callback = std::move(callback);
QueueResetFocus();
}
void ImGuiFullscreen::CloseChoiceDialog()
@ -1985,7 +2224,8 @@ void ImGuiFullscreen::DrawChoiceDialog()
LayoutScale(450.0f), title_height + LayoutScale(LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY + (LAYOUT_MENU_BUTTON_Y_PADDING * 2.0f)) *
static_cast<float>(s_choice_dialog_options.size()));
ImGui::SetNextWindowSize(ImVec2(width, height));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowPos((ImGui::GetIO().DisplaySize - LayoutScale(0.0f, LAYOUT_FOOTER_HEIGHT)) * 0.5f,
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(s_choice_dialog_title.c_str());
bool is_open = !WantsToCloseMenu();
@ -1997,6 +2237,7 @@ void ImGuiFullscreen::DrawChoiceDialog()
ImGui::PushStyleColor(ImGuiCol_Text, UIBackgroundTextColor);
BeginMenuButtons();
ResetFocusHere();
if (s_choice_dialog_checkable)
{
@ -2057,6 +2298,10 @@ void ImGuiFullscreen::DrawChoiceDialog()
s_choice_dialog_callback(-1, no_string, false);
CloseChoiceDialog();
}
else
{
GetChoiceDialogHelpText(s_fullscreen_footer_text);
}
}
@ -2074,6 +2319,7 @@ void ImGuiFullscreen::OpenInputStringDialog(
s_input_dialog_caption = std::move(caption);
s_input_dialog_ok_text = std::move(ok_button_text);
s_input_dialog_callback = std::move(callback);
QueueResetFocus();
}
void ImGuiFullscreen::DrawInputDialog()
@ -2082,7 +2328,8 @@ void ImGuiFullscreen::DrawInputDialog()
return;
ImGui::SetNextWindowSize(LayoutScale(700.0f, 0.0f));
ImGui::SetNextWindowPos(ImGui::GetIO().DisplaySize * 0.5f, ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::SetNextWindowPos((ImGui::GetIO().DisplaySize - LayoutScale(0.0f, LAYOUT_FOOTER_HEIGHT)) * 0.5f,
ImGuiCond_Always, ImVec2(0.5f, 0.5f));
ImGui::OpenPopup(s_input_dialog_title.c_str());
ImGui::PushFont(g_large_font);
@ -2098,6 +2345,7 @@ void ImGuiFullscreen::DrawInputDialog()
if (ImGui::BeginPopupModal(s_input_dialog_title.c_str(), &is_open,
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove))
{
ResetFocusHere();
ImGui::TextWrapped("%s", s_input_dialog_message.c_str());
BeginMenuButtons();
@ -2143,6 +2391,8 @@ void ImGuiFullscreen::DrawInputDialog()
}
if (!is_open)
CloseInputDialog();
else
GetInputDialogHelpText(s_fullscreen_footer_text);
ImGui::PopStyleColor(4);
ImGui::PopStyleVar(3);
@ -2179,6 +2429,7 @@ void ImGuiFullscreen::OpenConfirmMessageDialog(
s_message_dialog_callback = std::move(callback);
s_message_dialog_buttons[0] = std::move(yes_button_text);
s_message_dialog_buttons[1] = std::move(no_button_text);
QueueResetFocus();
}
void ImGuiFullscreen::OpenInfoMessageDialog(
@ -2191,6 +2442,7 @@ void ImGuiFullscreen::OpenInfoMessageDialog(
s_message_dialog_message = std::move(message);
s_message_dialog_callback = std::move(callback);
s_message_dialog_buttons[0] = std::move(button_text);
QueueResetFocus();
}
void ImGuiFullscreen::OpenMessageDialog(std::string title, std::string message, MessageDialogCallback callback,
@ -2205,6 +2457,7 @@ void ImGuiFullscreen::OpenMessageDialog(std::string title, std::string message,
s_message_dialog_buttons[0] = std::move(first_button_text);
s_message_dialog_buttons[1] = std::move(second_button_text);
s_message_dialog_buttons[2] = std::move(third_button_text);
QueueResetFocus();
}
void ImGuiFullscreen::CloseMessageDialog()
@ -2217,6 +2470,7 @@ void ImGuiFullscreen::CloseMessageDialog()
s_message_dialog_message = {};
s_message_dialog_buttons = {};
s_message_dialog_callback = {};
QueueResetFocus();
}
void ImGuiFullscreen::DrawMessageDialog()
@ -2248,6 +2502,7 @@ void ImGuiFullscreen::DrawMessageDialog()
if (ImGui::BeginPopupModal(win_id, &is_open, flags))
{
BeginMenuButtons();
ResetFocusHere();
ImGui::TextWrapped("%s", s_message_dialog_message.c_str());
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + LayoutScale(20.0f));
@ -2289,6 +2544,10 @@ void ImGuiFullscreen::DrawMessageDialog()
func(result.value_or(1) == 0);
}
}
else
{
GetChoiceDialogHelpText(s_fullscreen_footer_text);
}
}
static float s_notification_vertical_position = 0.15f;
@ -2648,7 +2907,7 @@ void ImGuiFullscreen::DrawToast()
ImFont* message_font = g_medium_font;
const float padding = LayoutScale(20.0f);
const float total_padding = padding * 2.0f;
const float margin = LayoutScale(20.0f);
const float margin = LayoutScale(20.0f + (s_fullscreen_footer_text.empty() ? 0.0f : LAYOUT_FOOTER_HEIGHT));
const float spacing = s_toast_title.empty() ? 0.0f : LayoutScale(10.0f);
const ImVec2 display_size(ImGui::GetIO().DisplaySize);
const ImVec2 title_size(s_toast_title.empty() ? ImVec2(0.0f, 0.0f) :

View File

@ -1,14 +1,18 @@
// SPDX-FileCopyrightText: 2002-2023 PCSX2 Dev Team
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
#include "common/Pcsx2Defs.h"
#include "IconsFontAwesome5.h"
#include "imgui.h"
#include "imgui_internal.h"
#include <functional>
#include <memory>
#include <optional>
#include <span>
#include <string>
#include <string_view>
#include <vector>
@ -30,6 +34,11 @@ namespace ImGuiFullscreen
static constexpr float LAYOUT_MENU_BUTTON_HEIGHT_NO_SUMMARY = 26.0f;
static constexpr float LAYOUT_MENU_BUTTON_X_PADDING = 15.0f;
static constexpr float LAYOUT_MENU_BUTTON_Y_PADDING = 10.0f;
static constexpr float LAYOUT_FOOTER_PADDING = 10.0f;
static constexpr float LAYOUT_FOOTER_HEIGHT = LAYOUT_MEDIUM_FONT_SIZE + LAYOUT_FOOTER_PADDING * 2.0f;
static constexpr float LAYOUT_HORIZONTAL_MENU_HEIGHT = 320.0f;
static constexpr float LAYOUT_HORIZONTAL_MENU_PADDING = 30.0f;
static constexpr float LAYOUT_HORIZONTAL_MENU_ITEM_WIDTH = 250.0f;
extern ImFont* g_standard_font;
extern ImFont* g_medium_font;
@ -106,9 +115,9 @@ namespace ImGuiFullscreen
/// Texture cache.
const std::shared_ptr<GSTexture>& GetPlaceholderTexture();
std::shared_ptr<GSTexture> LoadTexture(const char* path);
GSTexture* GetCachedTexture(const char* name);
GSTexture* GetCachedTextureAsync(const char* name);
std::shared_ptr<GSTexture> LoadTexture(std::string_view path);
GSTexture* GetCachedTexture(std::string_view name);
GSTexture* GetCachedTextureAsync(std::string_view name);
bool InvalidateCachedTexture(const std::string& path);
void UploadAsyncTextures();
@ -120,6 +129,9 @@ namespace ImGuiFullscreen
void QueueResetFocus();
bool ResetFocusHere();
bool IsFocusResetQueued();
void ForceKeyNavEnabled();
bool WantsToCloseMenu();
void ResetCloseMenuIfNeeded();
@ -128,7 +140,7 @@ namespace ImGuiFullscreen
void DrawWindowTitle(const char* title);
bool BeginFullscreenColumns(const char* title = nullptr, float pos_y = 0.0f, bool expand_to_screen_width = false);
bool BeginFullscreenColumns(const char* title = nullptr, float pos_y = 0.0f, bool expand_to_screen_width = false, bool footer = false);
void EndFullscreenColumns();
bool BeginFullscreenColumnWindow(float start, float end, const char* name, const ImVec4& background = UIBackgroundColor);
@ -140,6 +152,12 @@ namespace ImGuiFullscreen
const ImVec4& background = HEX_TO_IMVEC4(0x212121, 0xFF), float rounding = 0.0f, float padding = 0.0f, ImGuiWindowFlags flags = 0);
void EndFullscreenWindow();
bool IsGamepadInputSource();
void CreateFooterTextString(SmallStringBase& dest, std::span<const std::pair<const char*, std::string_view>> items);
void SetFullscreenFooterText(std::string_view text);
void SetFullscreenFooterText(std::span<const std::pair<const char*, std::string_view>> items);
void DrawFullscreenFooter();
void PrerenderMenuButtonBorder();
void BeginMenuButtons(u32 num_items = 0, float y_align = 0.0f, float x_padding = LAYOUT_MENU_BUTTON_X_PADDING,
float y_padding = LAYOUT_MENU_BUTTON_Y_PADDING, float item_height = LAYOUT_MENU_BUTTON_HEIGHT);
@ -209,17 +227,21 @@ namespace ImGuiFullscreen
bool NavTab(const char* title, bool is_active, bool enabled, float width, float height, const ImVec4& background,
ImFont* font = g_large_font);
bool BeginHorizontalMenu(const char* name, const ImVec2& position, const ImVec2& size, u32 num_items);
void EndHorizontalMenu();
bool HorizontalMenuItem(GSTexture* icon, const char* title, const char* description);
using FileSelectorCallback = std::function<void(const std::string& path)>;
using FileSelectorFilters = std::vector<std::string>;
bool IsFileSelectorOpen();
void OpenFileSelector(const char* title, bool select_directory, FileSelectorCallback callback,
void OpenFileSelector(std::string_view title, bool select_directory, FileSelectorCallback callback,
FileSelectorFilters filters = FileSelectorFilters(), std::string initial_directory = std::string());
void CloseFileSelector();
using ChoiceDialogCallback = std::function<void(s32 index, const std::string& title, bool checked)>;
using ChoiceDialogOptions = std::vector<std::pair<std::string, bool>>;
bool IsChoiceDialogOpen();
void OpenChoiceDialog(const char* title, bool checkable, ChoiceDialogOptions options, ChoiceDialogCallback callback);
void OpenChoiceDialog(std::string_view title, bool checkable, ChoiceDialogOptions options, ChoiceDialogCallback callback);
void CloseChoiceDialog();
using InputStringDialogCallback = std::function<void(std::string text)>;
@ -253,4 +275,9 @@ namespace ImGuiFullscreen
void ShowToast(std::string title, std::string message, float duration = 10.0f);
void ClearToast();
// Message callbacks.
void GetChoiceDialogHelpText(SmallStringBase& dest);
void GetFileSelectorHelpText(SmallStringBase& dest);
void GetInputDialogHelpText(SmallStringBase& dest);
} // namespace ImGuiFullscreen

View File

@ -489,8 +489,8 @@ ImFont* ImGuiManager::AddFixedFont(float size)
bool ImGuiManager::AddIconFonts(float size)
{
// clang-format off
static constexpr ImWchar range_fa[] = { 0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02b,0xf02b,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03e,0xf04b,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf059,0xf059,0xf05e,0xf05e,0xf063,0xf063,0xf065,0xf065,0xf067,0xf067,0xf06a,0xf06a,0xf06e,0xf06e,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf084,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf11b,0xf11c,0xf121,0xf121,0xf129,0xf12a,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1b3,0xf1b3,0xf1de,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf21e,0xf21e,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2bd,0xf2bd,0xf2d0,0xf2d0,0xf2f1,0xf2f2,0xf2f5,0xf2f5,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf462,0xf462,0xf466,0xf466,0xf51f,0xf51f,0xf543,0xf543,0xf547,0xf547,0xf54c,0xf54c,0xf552,0xf553,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf794,0xf794,0xf815,0xf815,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 };
static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a1,0x21b0,0x21b3,0x21ba,0x21c3,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x221a,0x221a,0x227a,0x227d,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x2380,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe001,0xe001,0xff21,0xff3a,0x0,0x0 };
static constexpr ImWchar range_fa[] = { 0xf002,0xf002,0xf005,0xf005,0xf007,0xf007,0xf00c,0xf00e,0xf011,0xf011,0xf013,0xf013,0xf017,0xf017,0xf019,0xf019,0xf021,0xf023,0xf025,0xf025,0xf027,0xf028,0xf02b,0xf02b,0xf02e,0xf02e,0xf030,0xf030,0xf03a,0xf03a,0xf03d,0xf03e,0xf04a,0xf04c,0xf04e,0xf04e,0xf050,0xf050,0xf052,0xf052,0xf05e,0xf05e,0xf063,0xf063,0xf067,0xf067,0xf06a,0xf06a,0xf06e,0xf06e,0xf071,0xf071,0xf077,0xf078,0xf07b,0xf07c,0xf084,0xf084,0xf091,0xf091,0xf0ac,0xf0ad,0xf0b0,0xf0b0,0xf0c5,0xf0c5,0xf0c7,0xf0c8,0xf0cb,0xf0cb,0xf0d0,0xf0d0,0xf0dc,0xf0dc,0xf0e2,0xf0e2,0xf0eb,0xf0eb,0xf0f3,0xf0f3,0xf0fe,0xf0fe,0xf11b,0xf11c,0xf121,0xf121,0xf129,0xf12a,0xf140,0xf140,0xf144,0xf144,0xf14a,0xf14a,0xf15b,0xf15b,0xf15d,0xf15d,0xf188,0xf188,0xf191,0xf192,0xf1b3,0xf1b3,0xf1de,0xf1de,0xf1e6,0xf1e6,0xf1ea,0xf1eb,0xf1f8,0xf1f8,0xf1fc,0xf1fc,0xf21e,0xf21e,0xf245,0xf245,0xf26c,0xf26c,0xf279,0xf279,0xf2bd,0xf2bd,0xf2d0,0xf2d0,0xf2f1,0xf2f2,0xf302,0xf302,0xf3c1,0xf3c1,0xf3fd,0xf3fd,0xf410,0xf410,0xf462,0xf462,0xf466,0xf466,0xf51f,0xf51f,0xf543,0xf543,0xf547,0xf547,0xf54c,0xf54c,0xf553,0xf553,0xf56d,0xf56d,0xf5a2,0xf5a2,0xf65d,0xf65e,0xf6a9,0xf6a9,0xf756,0xf756,0xf794,0xf794,0xf815,0xf815,0xf84c,0xf84c,0xf8cc,0xf8cc,0x0,0x0 };
static constexpr ImWchar range_pf[] = { 0x2198,0x2199,0x219e,0x21a1,0x21b0,0x21b3,0x21ba,0x21c3,0x21d0,0x21d4,0x21dc,0x21dd,0x21e0,0x21e3,0x21f3,0x21f3,0x21f7,0x21f8,0x21fa,0x21fb,0x221a,0x221a,0x227a,0x227f,0x2284,0x2284,0x22bf,0x22c8,0x2349,0x2349,0x235a,0x235e,0x2360,0x2361,0x2364,0x2367,0x237a,0x237b,0x237d,0x237d,0x237f,0x2380,0x23b2,0x23b5,0x23cc,0x23cc,0x23f4,0x23f7,0x2427,0x243a,0x243d,0x243d,0x2443,0x2443,0x2460,0x246b,0x248f,0x248f,0x24f5,0x24fd,0x24ff,0x24ff,0x2605,0x2605,0x2699,0x2699,0x278a,0x278e,0xe001,0xe001,0xff21,0xff3a,0x0,0x0 };
// clang-format on
{

View File

@ -161,7 +161,11 @@ void Host::OnCaptureStopped()
{
}
void Host::RequestExit(bool save_state_if_running)
void Host::RequestExitApplication(bool allow_confirm)
{
}
void Host::RequestExitBigPicture()
{
}