mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 20:15:27 +00:00
Implement most of cellUserInfo
This commit is contained in:
parent
61450335a5
commit
087dccd194
10 changed files with 562 additions and 28 deletions
|
@ -422,6 +422,7 @@ target_sources(rpcs3_emu PRIVATE
|
|||
RSX/Overlays/overlay_perf_metrics.cpp
|
||||
RSX/Overlays/overlay_progress_bar.cpp
|
||||
RSX/Overlays/overlay_save_dialog.cpp
|
||||
RSX/Overlays/overlay_user_list_dialog.cpp
|
||||
RSX/Overlays/overlay_utils.cpp
|
||||
RSX/Overlays/overlays.cpp
|
||||
RSX/Overlays/overlay_shader_compile_notification.cpp
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/VFS.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/localized_string.h"
|
||||
#include "Emu/Cell/lv2/sys_fs.h"
|
||||
#include "Emu/Cell/lv2/sys_sync.h"
|
||||
|
@ -97,7 +98,7 @@ vm::gvar<savedata_context> g_savedata_context;
|
|||
struct savedata_manager
|
||||
{
|
||||
semaphore<> mutex;
|
||||
atomic_t<bool> enable_overlay;
|
||||
atomic_t<bool> enable_overlay{false};
|
||||
};
|
||||
|
||||
static std::vector<SaveDataEntry> get_save_entries(const std::string& base_dir, const std::string& prefix)
|
||||
|
@ -931,7 +932,7 @@ static NEVER_INLINE error_code savedata_op(ppu_thread& ppu, u32 operation, u32 v
|
|||
return {CELL_SAVEDATA_ERROR_PARAM, "34"};
|
||||
}
|
||||
|
||||
//TODO: If adding the new data to the save_entries vector
|
||||
// TODO: If adding the new data to the save_entries vector
|
||||
// to be displayed in the save mangaer UI, it should be focused here
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,9 @@
|
|||
#include "stdafx.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/VFS.h"
|
||||
#include "Emu/IdManager.h"
|
||||
#include "Emu/Cell/PPUModule.h"
|
||||
#include "Emu/RSX/Overlays/overlay_user_list_dialog.h"
|
||||
|
||||
#include "cellUserInfo.h"
|
||||
|
||||
|
@ -10,6 +12,25 @@
|
|||
|
||||
LOG_CHANNEL(cellUserInfo);
|
||||
|
||||
struct user_info_manager
|
||||
{
|
||||
atomic_t<bool> enable_overlay{false};
|
||||
atomic_t<bool> dialog_opened{false};
|
||||
};
|
||||
|
||||
std::string get_username(const u32 user_id)
|
||||
{
|
||||
std::string username;
|
||||
|
||||
if (const fs::file file{Emulator::GetHddDir() + fmt::format("home/%08d/localusername", user_id)})
|
||||
{
|
||||
username = file.to_string();
|
||||
username.resize(CELL_USERINFO_USERNAME_SIZE); // TODO: investigate
|
||||
}
|
||||
|
||||
return username;
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<CellUserInfoError>::format(std::string& out, u64 arg)
|
||||
{
|
||||
|
@ -27,6 +48,21 @@ void fmt_class_string<CellUserInfoError>::format(std::string& out, u64 arg)
|
|||
});
|
||||
}
|
||||
|
||||
template<>
|
||||
void fmt_class_string<cell_user_callback_result>::format(std::string& out, u64 arg)
|
||||
{
|
||||
format_enum(out, arg, [](auto error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
STR_CASE(CELL_USERINFO_RET_OK);
|
||||
STR_CASE(CELL_USERINFO_RET_CANCEL);
|
||||
}
|
||||
|
||||
return unknown;
|
||||
});
|
||||
}
|
||||
|
||||
error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
||||
{
|
||||
cellUserInfo.warning("cellUserInfoGetStat(id=%d, stat=*0x%x)", id, stat);
|
||||
|
@ -43,7 +79,7 @@ error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
|||
id = Emu.GetUsrId();
|
||||
}
|
||||
|
||||
const std::string& path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id));
|
||||
const std::string path = vfs::get(fmt::format("/dev_hdd0/home/%08d/", id));
|
||||
|
||||
if (!fs::is_dir(path))
|
||||
{
|
||||
|
@ -70,12 +106,103 @@ error_code cellUserInfoGetStat(u32 id, vm::ptr<CellUserInfoUserStat> stat)
|
|||
|
||||
error_code cellUserInfoSelectUser_ListType(vm::ptr<CellUserInfoTypeSet> listType, vm::ptr<CellUserInfoFinishCallback> funcSelect, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoSelectUser_ListType(listType=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", listType, funcSelect, container, userdata);
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_ListType(listType=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", listType, funcSelect, container, userdata);
|
||||
|
||||
if (!listType || !funcSelect) // TODO: confirm
|
||||
{
|
||||
return CELL_USERINFO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened)
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
std::vector<u32> user_ids;
|
||||
const std::string home_dir = Emulator::GetHddDir() + "home";
|
||||
|
||||
for (const auto& user_folder : fs::dir(home_dir))
|
||||
{
|
||||
if (!user_folder.is_directory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the folder name exactly 8 all-numerical characters long?
|
||||
const u32 user_id = Emulator::CheckUsr(user_folder.name);
|
||||
|
||||
if (user_id == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the localusername file exist?
|
||||
if (!fs::is_file(home_dir + "/" + user_folder.name + "/localusername"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// TODO: maybe also restrict this to CELL_USERINFO_USER_MAX
|
||||
if (listType->type != CELL_USERINFO_LISTTYPE_NOCURRENT || user_id != Emu.GetUsrId())
|
||||
{
|
||||
user_ids.push_back(user_id);
|
||||
}
|
||||
}
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened.exchange(true))
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
const std::string title = listType->title.get_ptr();
|
||||
const u32 focused = listType->focus;
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_ListType: opening user_list_dialog with: title='%s', focused=%d", title, focused);
|
||||
|
||||
const bool enable_overlay = g_fxo->get<user_info_manager>().enable_overlay;
|
||||
const error_code result = manager->create<rsx::overlays::user_list_dialog>()->show(title, focused, user_ids, enable_overlay, [funcSelect, userdata](s32 status)
|
||||
{
|
||||
s32 callback_result = CELL_USERINFO_RET_CANCEL;
|
||||
u32 selected_user_id = 0;
|
||||
std::string selected_username;
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
callback_result = CELL_USERINFO_RET_OK;
|
||||
selected_user_id = static_cast<u32>(status);
|
||||
selected_username = get_username(selected_user_id);
|
||||
}
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_ListType: callback_result=%s, selected_user_id=%d, selected_username='%s'", callback_result, selected_user_id, selected_username);
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
if (status >= 0)
|
||||
{
|
||||
selectUser->id = selected_user_id;
|
||||
strcpy_trunc(selectUser->name, selected_username);
|
||||
}
|
||||
funcSelect(ppu, callback_result, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
g_fxo->get<user_info_manager>().dialog_opened = false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cellUserInfo.error("User selection is only possible when the native user interface is enabled in the settings. The currently active user will be selected as a fallback.");
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
funcSelect(ppu, CELL_OK, selectUser, userdata);
|
||||
selectUser->id = Emu.GetUsrId();
|
||||
strcpy_trunc(selectUser->name, get_username(Emu.GetUsrId()));
|
||||
funcSelect(ppu, CELL_USERINFO_RET_OK, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
|
@ -84,12 +211,99 @@ error_code cellUserInfoSelectUser_ListType(vm::ptr<CellUserInfoTypeSet> listType
|
|||
|
||||
error_code cellUserInfoSelectUser_SetList(vm::ptr<CellUserInfoListSet> setList, vm::ptr<CellUserInfoFinishCallback> funcSelect, u32 container, vm::ptr<void> userdata)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoSelectUser_SetList(setList=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", setList, funcSelect, container, userdata);
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_SetList(setList=*0x%x, funcSelect=*0x%x, container=0x%x, userdata=*0x%x)", setList, funcSelect, container, userdata);
|
||||
|
||||
if (!setList || !funcSelect) // TODO: confirm
|
||||
{
|
||||
return CELL_USERINFO_ERROR_PARAM;
|
||||
}
|
||||
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened)
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
std::vector<u32> user_ids;
|
||||
|
||||
for (usz i = 0; i < CELL_USERINFO_USER_MAX && i < setList->fixedListNum; i++)
|
||||
{
|
||||
if (const u32 id = setList->fixedList->userId[i])
|
||||
{
|
||||
user_ids.push_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
if (user_ids.empty())
|
||||
{
|
||||
// TODO: Confirm. Also check if this is possible in cellUserInfoSelectUser_ListType.
|
||||
cellUserInfo.error("cellUserInfoSelectUser_SetList: callback_result=%s", CELL_USERINFO_ERROR_NOUSER);
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
funcSelect(ppu, CELL_USERINFO_ERROR_NOUSER, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
// TODO: does this function return an error if any (user_id > 0 && not_found) ?
|
||||
|
||||
if (auto manager = g_fxo->try_get<rsx::overlays::display_manager>())
|
||||
{
|
||||
if (g_fxo->get<user_info_manager>().dialog_opened.exchange(true))
|
||||
{
|
||||
return CELL_USERINFO_ERROR_BUSY;
|
||||
}
|
||||
|
||||
const std::string title = setList->title.get_ptr();
|
||||
const u32 focused = setList->focus;
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_SetList: opening user_list_dialog with: title='%s', focused=%d", title, focused);
|
||||
|
||||
const bool enable_overlay = g_fxo->get<user_info_manager>().enable_overlay;
|
||||
const error_code result = manager->create<rsx::overlays::user_list_dialog>()->show(title, focused, user_ids, enable_overlay, [funcSelect, userdata](s32 status)
|
||||
{
|
||||
s32 callback_result = CELL_USERINFO_RET_CANCEL;
|
||||
u32 selected_user_id = 0;
|
||||
std::string selected_username;
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
callback_result = CELL_USERINFO_RET_OK;
|
||||
selected_user_id = static_cast<u32>(status);
|
||||
selected_username = get_username(selected_user_id);
|
||||
}
|
||||
|
||||
cellUserInfo.warning("cellUserInfoSelectUser_SetList: callback_result=%s, selected_user_id=%d, selected_username='%s'", callback_result, selected_user_id, selected_username);
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
if (status >= 0)
|
||||
{
|
||||
selectUser->id = selected_user_id;
|
||||
strcpy_trunc(selectUser->name, selected_username);
|
||||
}
|
||||
funcSelect(ppu, callback_result, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
g_fxo->get<user_info_manager>().dialog_opened = false;
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
cellUserInfo.error("User selection is only possible when the native user interface is enabled in the settings. The currently active user will be selected as a fallback.");
|
||||
|
||||
sysutil_register_cb([=](ppu_thread& ppu) -> s32
|
||||
{
|
||||
vm::var<CellUserInfoUserStat> selectUser;
|
||||
funcSelect(ppu, CELL_OK, selectUser, userdata);
|
||||
selectUser->id = Emu.GetUsrId();
|
||||
strcpy_trunc(selectUser->name, get_username(Emu.GetUsrId()));
|
||||
funcSelect(ppu, CELL_USERINFO_RET_OK, selectUser, userdata);
|
||||
return CELL_OK;
|
||||
});
|
||||
|
||||
|
@ -98,12 +312,14 @@ error_code cellUserInfoSelectUser_SetList(vm::ptr<CellUserInfoListSet> setList,
|
|||
|
||||
void cellUserInfoEnableOverlay(s32 enable)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoEnableOverlay(enable=%d)", enable);
|
||||
cellUserInfo.notice("cellUserInfoEnableOverlay(enable=%d)", enable);
|
||||
auto& manager = g_fxo->get<user_info_manager>();
|
||||
manager.enable_overlay = enable != 0;
|
||||
}
|
||||
|
||||
error_code cellUserInfoGetList(vm::ptr<u32> listNum, vm::ptr<CellUserInfoUserList> listBuf, vm::ptr<u32> currentUserId)
|
||||
{
|
||||
cellUserInfo.todo("cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)", listNum, listBuf, currentUserId);
|
||||
cellUserInfo.warning("cellUserInfoGetList(listNum=*0x%x, listBuf=*0x%x, currentUserId=*0x%x)", listNum, listBuf, currentUserId);
|
||||
|
||||
// If only listNum is NULL, an error will be returned
|
||||
if (!listNum)
|
||||
|
@ -114,17 +330,58 @@ error_code cellUserInfoGetList(vm::ptr<u32> listNum, vm::ptr<CellUserInfoUserLis
|
|||
}
|
||||
}
|
||||
|
||||
const std::string home_dir = Emulator::GetHddDir() + "home";
|
||||
std::vector<u32> user_ids;
|
||||
|
||||
for (const auto& user_folder : fs::dir(home_dir))
|
||||
{
|
||||
if (!user_folder.is_directory)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Is the folder name exactly 8 all-numerical characters long?
|
||||
const u32 user_id = Emulator::CheckUsr(user_folder.name);
|
||||
|
||||
if (user_id == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Does the localusername file exist?
|
||||
if (!fs::is_file(home_dir + "/" + user_folder.name + "/localusername"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (user_ids.size() < CELL_USERINFO_USER_MAX)
|
||||
{
|
||||
user_ids.push_back(user_id);
|
||||
}
|
||||
else
|
||||
{
|
||||
cellUserInfo.warning("cellUserInfoGetList: Cannot add user %s. Too many users.", user_folder.name);
|
||||
}
|
||||
}
|
||||
|
||||
if (listNum)
|
||||
{
|
||||
*listNum = 1;
|
||||
*listNum = static_cast<u32>(user_ids.size());
|
||||
}
|
||||
|
||||
if (listBuf)
|
||||
{
|
||||
std::memset(listBuf.get_ptr(), 0, listBuf.size());
|
||||
|
||||
// We report only one user, so it must be the current user
|
||||
listBuf->userId[0] = Emu.GetUsrId();
|
||||
for (usz i = 0; i < CELL_USERINFO_USER_MAX; i++)
|
||||
{
|
||||
if (i < user_ids.size())
|
||||
{
|
||||
listBuf->userId[i] = user_ids[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
listBuf->userId[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (currentUserId)
|
||||
|
|
|
@ -25,12 +25,23 @@ enum CellUserInfoListType
|
|||
CELL_USERINFO_LISTTYPE_NOCURRENT = 1,
|
||||
};
|
||||
|
||||
enum
|
||||
enum cell_user_callback_result : u32
|
||||
{
|
||||
CELL_USERINFO_RET_OK = 0,
|
||||
CELL_USERINFO_RET_CANCEL = 1,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_SYSUTIL_USERID_CURRENT = 0,
|
||||
CELL_SYSUTIL_USERID_MAX = 99999999,
|
||||
};
|
||||
|
||||
enum : u32
|
||||
{
|
||||
CELL_USERINFO_FOCUS_LISTHEAD = 0xffffffff
|
||||
};
|
||||
|
||||
// Structs
|
||||
struct CellUserInfoUserStat
|
||||
{
|
||||
|
|
|
@ -133,7 +133,8 @@ namespace rsx
|
|||
// Ignore cancel operation for Ok-only
|
||||
return;
|
||||
}
|
||||
else if (cancel_only)
|
||||
|
||||
if (cancel_only)
|
||||
{
|
||||
return_code = CELL_MSGDIALOG_BUTTON_ESCAPE;
|
||||
}
|
||||
|
@ -220,7 +221,7 @@ namespace rsx
|
|||
{
|
||||
if (interactive)
|
||||
{
|
||||
if (auto error = run_input_loop())
|
||||
if (const auto error = run_input_loop())
|
||||
{
|
||||
rsx_log.error("Dialog input loop exited with error code=%d", error);
|
||||
return error;
|
||||
|
@ -249,7 +250,7 @@ namespace rsx
|
|||
{
|
||||
auto ref = g_fxo->get<display_manager>().get(uid);
|
||||
|
||||
if (auto error = run_input_loop())
|
||||
if (const auto error = run_input_loop())
|
||||
{
|
||||
rsx_log.error("Dialog input loop exited with error code=%d", error);
|
||||
}
|
||||
|
|
|
@ -96,8 +96,8 @@ namespace rsx
|
|||
m_time_thingy->set_pos(1000, 30);
|
||||
m_time_thingy->set_text(date_time::current_time());
|
||||
|
||||
static_cast<label*>(m_description.get())->auto_resize();
|
||||
static_cast<label*>(m_time_thingy.get())->auto_resize();
|
||||
m_description->auto_resize();
|
||||
m_time_thingy->auto_resize();
|
||||
|
||||
m_dim_background->back_color.a = 0.5f;
|
||||
m_description->back_color.a = 0.f;
|
||||
|
@ -109,7 +109,7 @@ namespace rsx
|
|||
void save_dialog::update()
|
||||
{
|
||||
m_time_thingy->set_text(date_time::current_time());
|
||||
static_cast<label*>(m_time_thingy.get())->auto_resize();
|
||||
m_time_thingy->auto_resize();
|
||||
}
|
||||
|
||||
void save_dialog::on_button_pressed(pad_button button_press)
|
||||
|
@ -138,6 +138,7 @@ namespace rsx
|
|||
break;
|
||||
default:
|
||||
rsx_log.trace("[ui] Button %d pressed", static_cast<u8>(button_press));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -166,7 +167,7 @@ namespace rsx
|
|||
|
||||
if (enable_overlay)
|
||||
{
|
||||
m_dim_background->back_color.a = 1.0f;
|
||||
m_dim_background->back_color.a = 0.9f;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -261,10 +262,10 @@ namespace rsx
|
|||
m_list->select_entry(focused);
|
||||
}
|
||||
|
||||
static_cast<label*>(m_description.get())->auto_resize();
|
||||
m_description->auto_resize();
|
||||
visible = true;
|
||||
|
||||
if (auto err = run_input_loop())
|
||||
if (const auto err = run_input_loop())
|
||||
return err;
|
||||
|
||||
if (return_code >= 0)
|
||||
|
@ -273,7 +274,7 @@ namespace rsx
|
|||
{
|
||||
return return_code - 1;
|
||||
}
|
||||
else if (static_cast<usz>(return_code) == entries.size())
|
||||
if (static_cast<usz>(return_code) == entries.size())
|
||||
{
|
||||
return selection_code::new_save;
|
||||
}
|
||||
|
|
217
rpcs3/Emu/RSX/Overlays/overlay_user_list_dialog.cpp
Normal file
217
rpcs3/Emu/RSX/Overlays/overlay_user_list_dialog.cpp
Normal file
|
@ -0,0 +1,217 @@
|
|||
#include "stdafx.h"
|
||||
#include "overlay_user_list_dialog.h"
|
||||
#include "Emu/System.h"
|
||||
#include "Emu/system_config.h"
|
||||
#include "Utilities/StrUtil.h"
|
||||
#include "Utilities/Thread.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
user_list_dialog::user_list_entry::user_list_entry(const std::string& username, const std::string& user_id, const std::string& avatar_path)
|
||||
{
|
||||
std::unique_ptr<overlay_element> image = std::make_unique<image_view>();
|
||||
image->set_size(160, 110);
|
||||
image->set_padding(36, 36, 11, 11); // Square image, 88x88
|
||||
|
||||
if (fs::exists(avatar_path))
|
||||
{
|
||||
icon_data = std::make_unique<image_info>(avatar_path.c_str());
|
||||
static_cast<image_view*>(image.get())->set_raw_image(icon_data.get());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Fallback
|
||||
static_cast<image_view*>(image.get())->set_image_resource(resource_config::standard_image_resource::square);
|
||||
}
|
||||
|
||||
std::unique_ptr<overlay_element> text_stack = std::make_unique<vertical_layout>();
|
||||
std::unique_ptr<overlay_element> padding = std::make_unique<spacer>();
|
||||
std::unique_ptr<overlay_element> header_text = std::make_unique<label>(username);
|
||||
std::unique_ptr<overlay_element> subtext = std::make_unique<label>(user_id);
|
||||
|
||||
padding->set_size(1, 1);
|
||||
header_text->set_size(800, 40);
|
||||
header_text->set_font("Arial", 16);
|
||||
header_text->set_wrap_text(true);
|
||||
|
||||
subtext->set_size(800, 0);
|
||||
subtext->set_font("Arial", 14);
|
||||
subtext->set_wrap_text(true);
|
||||
static_cast<label*>(subtext.get())->auto_resize(true);
|
||||
|
||||
// Make back color transparent for text
|
||||
header_text->back_color.a = 0.f;
|
||||
subtext->back_color.a = 0.f;
|
||||
|
||||
static_cast<vertical_layout*>(text_stack.get())->pack_padding = 5;
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(padding);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(header_text);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(subtext);
|
||||
|
||||
if (text_stack->h > image->h)
|
||||
{
|
||||
std::unique_ptr<overlay_element> padding2 = std::make_unique<spacer>();
|
||||
padding2->set_size(1, 5);
|
||||
static_cast<vertical_layout*>(text_stack.get())->add_element(padding2);
|
||||
}
|
||||
|
||||
// Pack
|
||||
this->pack_padding = 15;
|
||||
add_element(image);
|
||||
add_element(text_stack);
|
||||
}
|
||||
|
||||
user_list_dialog::user_list_dialog()
|
||||
{
|
||||
m_dim_background = std::make_unique<overlay_element>();
|
||||
m_dim_background->set_size(1280, 720);
|
||||
m_dim_background->back_color.a = 0.5f;
|
||||
|
||||
m_list = std::make_unique<list_view>(1240, 540);
|
||||
m_list->set_pos(20, 85);
|
||||
|
||||
m_description = std::make_unique<label>();
|
||||
m_description->set_font("Arial", 20);
|
||||
m_description->set_pos(20, 37);
|
||||
m_description->set_text("Select user");
|
||||
m_description->auto_resize();
|
||||
m_description->back_color.a = 0.f;
|
||||
|
||||
return_code = selection_code::canceled;
|
||||
}
|
||||
|
||||
void user_list_dialog::on_button_pressed(pad_button button_press)
|
||||
{
|
||||
switch (button_press)
|
||||
{
|
||||
case pad_button::cross:
|
||||
if (const usz index = static_cast<usz>(m_list->get_selected_index()); index < m_entry_ids.size())
|
||||
{
|
||||
return_code = static_cast<s32>(m_entry_ids[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
return_code = selection_code::error;
|
||||
}
|
||||
[[fallthrough]];
|
||||
case pad_button::circle:
|
||||
close(true, true);
|
||||
break;
|
||||
case pad_button::dpad_up:
|
||||
m_list->select_previous();
|
||||
break;
|
||||
case pad_button::dpad_down:
|
||||
m_list->select_next();
|
||||
break;
|
||||
case pad_button::L1:
|
||||
m_list->select_previous(10);
|
||||
break;
|
||||
case pad_button::R1:
|
||||
m_list->select_next(10);
|
||||
break;
|
||||
default:
|
||||
rsx_log.trace("[ui] Button %d pressed", static_cast<u8>(button_press));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
compiled_resource user_list_dialog::get_compiled()
|
||||
{
|
||||
if (!visible)
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
compiled_resource result;
|
||||
result.add(m_dim_background->get_compiled());
|
||||
result.add(m_list->get_compiled());
|
||||
result.add(m_description->get_compiled());
|
||||
return result;
|
||||
}
|
||||
|
||||
struct user_list_dialog_thread
|
||||
{
|
||||
static constexpr auto thread_name = "UserList Thread"sv;
|
||||
};
|
||||
|
||||
error_code user_list_dialog::show(const std::string& title, u32 focused, const std::vector<u32>& user_ids, bool enable_overlay, std::function<void(s32 status)> on_close)
|
||||
{
|
||||
visible = false;
|
||||
|
||||
if (enable_overlay)
|
||||
{
|
||||
m_dim_background->back_color.a = 0.9f;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dim_background->back_color.a = 0.5f;
|
||||
}
|
||||
|
||||
std::vector<u8> icon;
|
||||
std::vector<std::unique_ptr<overlay_element>> entries;
|
||||
|
||||
const std::string home_dir = Emulator::GetHddDir() + "home/";
|
||||
s32 selected_index = 0;
|
||||
|
||||
for (const auto& id : user_ids)
|
||||
{
|
||||
const std::string user_id = fmt::format("%08d", id);
|
||||
|
||||
if (const fs::file file{home_dir + user_id + "/localusername"})
|
||||
{
|
||||
if (id == focused)
|
||||
{
|
||||
selected_index = static_cast<s32>(entries.size());
|
||||
}
|
||||
|
||||
// Let's assume there are 26 avatar pngs (like in my installation)
|
||||
const std::string avatar_path = g_cfg.vfs.get_dev_flash() + fmt::format("vsh/resource/explore/user/%03d.png", id % 26);
|
||||
const std::string username = file.to_string();
|
||||
std::unique_ptr<overlay_element> entry = std::make_unique<user_list_entry>(username, user_id, avatar_path);
|
||||
entries.emplace_back(std::move(entry));
|
||||
m_entry_ids.emplace_back(id);
|
||||
}
|
||||
}
|
||||
|
||||
for (auto& entry : entries)
|
||||
{
|
||||
m_list->add_entry(entry);
|
||||
}
|
||||
|
||||
if (m_list->m_items.empty())
|
||||
{
|
||||
m_list->set_cancel_only(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only select an entry if there are entries available
|
||||
m_list->select_entry(selected_index);
|
||||
}
|
||||
|
||||
m_description->set_text(title);
|
||||
m_description->auto_resize();
|
||||
|
||||
this->on_close = std::move(on_close);
|
||||
visible = true;
|
||||
|
||||
g_fxo->get<named_thread<user_list_dialog_thread>>()([&, tbit = alloc_thread_bit()]()
|
||||
{
|
||||
g_thread_bit = tbit;
|
||||
|
||||
auto ref = g_fxo->get<display_manager>().get(uid);
|
||||
|
||||
if (const auto error = run_input_loop())
|
||||
{
|
||||
rsx_log.error("Dialog input loop exited with error code=%d", error);
|
||||
}
|
||||
|
||||
thread_bits &= ~tbit;
|
||||
thread_bits.notify_all();
|
||||
});
|
||||
|
||||
return CELL_OK;
|
||||
}
|
||||
} // namespace overlays
|
||||
} // namespace RSX
|
37
rpcs3/Emu/RSX/Overlays/overlay_user_list_dialog.h
Normal file
37
rpcs3/Emu/RSX/Overlays/overlay_user_list_dialog.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
|
||||
#include "overlays.h"
|
||||
#include "Emu/Cell/ErrorCodes.h"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
namespace overlays
|
||||
{
|
||||
struct user_list_dialog : public user_interface
|
||||
{
|
||||
private:
|
||||
struct user_list_entry : horizontal_layout
|
||||
{
|
||||
private:
|
||||
std::unique_ptr<image_info> icon_data;
|
||||
|
||||
public:
|
||||
user_list_entry(const std::string& username, const std::string& user_id, const std::string& avatar_path);
|
||||
};
|
||||
|
||||
std::vector<u32> m_entry_ids;
|
||||
std::unique_ptr<overlay_element> m_dim_background;
|
||||
std::unique_ptr<list_view> m_list;
|
||||
std::unique_ptr<label> m_description;
|
||||
|
||||
public:
|
||||
user_list_dialog();
|
||||
|
||||
void on_button_pressed(pad_button button_press) override;
|
||||
|
||||
compiled_resource get_compiled() override;
|
||||
|
||||
error_code show(const std::string& title, u32 focused, const std::vector<u32>& user_ids, bool enable_overlay, std::function<void(s32 status)> on_close);
|
||||
};
|
||||
}
|
||||
}
|
|
@ -72,6 +72,7 @@
|
|||
<ClCompile Include="Emu\NP\rpcn_config.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Common\texture_cache.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_osk_panel.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_user_list_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_utils.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.cpp" />
|
||||
<ClCompile Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.cpp" />
|
||||
|
@ -465,6 +466,7 @@
|
|||
<ClInclude Include="Emu\RSX\Overlays\overlay_save_dialog.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_shader_compile_notification.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_trophy_notification.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_user_list_dialog.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_utils.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog.h" />
|
||||
<ClInclude Include="Emu\RSX\Overlays\Shaders\shader_loading_dialog_native.h" />
|
||||
|
|
|
@ -722,9 +722,6 @@
|
|||
<ClCompile Include="Emu\Cell\PPUTranslator.cpp">
|
||||
<Filter>Emu\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\Cell\timers.hpp">
|
||||
<Filter>Emu\Cell</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\CPU\CPUTranslator.cpp">
|
||||
<Filter>Emu\CPU</Filter>
|
||||
</ClCompile>
|
||||
|
@ -992,6 +989,9 @@
|
|||
<ClCompile Include="Emu\Io\Turntable.cpp">
|
||||
<Filter>Emu\Io</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Emu\RSX\Overlays\overlay_user_list_dialog.cpp">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Crypto\aes.h">
|
||||
|
@ -1933,6 +1933,12 @@
|
|||
<ClInclude Include="Loader\mself.hpp">
|
||||
<Filter>Loader</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\Cell\timers.hpp">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Emu\RSX\Overlays\overlay_user_list_dialog.h">
|
||||
<Filter>Emu\GPU\RSX\Overlays</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Emu\RSX\Common\Interpreter\FragmentInterpreter.glsl">
|
||||
|
|
Loading…
Add table
Reference in a new issue