This commit is contained in:
georgemoralis 2026-04-08 14:50:51 +00:00 committed by GitHub
commit e4d291005a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 609 additions and 117 deletions

View File

@ -623,8 +623,10 @@ set(NP_LIBS src/core/libraries/np/np_error.h
src/core/libraries/np/np_party.h
src/core/libraries/np/np_auth.cpp
src/core/libraries/np/np_auth.h
src/core/libraries/np/np_profile_dialog.cpp
src/core/libraries/np/np_profile_dialog.h
src/core/libraries/np/np_profile_dialog/np_profile_dialog.cpp
src/core/libraries/np/np_profile_dialog/np_profile_dialog.h
src/core/libraries/np/np_profile_dialog/np_profile_dialog_ui.cpp
src/core/libraries/np/np_profile_dialog/np_profile_dialog_ui.h
src/core/libraries/np/np_sns_facebook_dialog.cpp
src/core/libraries/np/np_sns_facebook_dialog.h
src/core/libraries/np/np_partner.cpp

View File

@ -38,7 +38,7 @@
#include "core/libraries/np/np_matching2.h"
#include "core/libraries/np/np_partner.h"
#include "core/libraries/np/np_party.h"
#include "core/libraries/np/np_profile_dialog.h"
#include "core/libraries/np/np_profile_dialog/np_profile_dialog.h"
#include "core/libraries/np/np_score.h"
#include "core/libraries/np/np_sns_facebook_dialog.h"
#include "core/libraries/np/np_trophy.h"

View File

@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "core/libraries/np/np_profile_dialog.h"
namespace Libraries::Np::NpProfileDialog {
s32 PS4_SYSV_ABI sceNpProfileDialogOpen() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogClose() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogGetResult() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogGetStatus() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogInitialize() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogOpenA() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogTerminate() {
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceNpProfileDialogUpdateStatus() {
LOG_DEBUG(Lib_NpProfileDialog, "(STUBBED) called");
return ORBIS_OK;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("uj9Cz7Tk0cc", "libSceNpProfileDialogCompat", 1, "libSceNpProfileDialog",
sceNpProfileDialogOpen);
LIB_FUNCTION("wkwjz0Xdo2A", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogClose);
LIB_FUNCTION("8rhLl1-0W-o", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogGetResult);
LIB_FUNCTION("3BqoiFOjSsk", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogGetStatus);
LIB_FUNCTION("Lg+NCE6pTwQ", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogInitialize);
LIB_FUNCTION("uj9Cz7Tk0cc", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogOpen);
LIB_FUNCTION("nrQRlLKzdwE", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogOpenA);
LIB_FUNCTION("0Sp9vJcB1-w", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogTerminate);
LIB_FUNCTION("haVZE9FgKqE", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogUpdateStatus);
};
} // namespace Libraries::Np::NpProfileDialog

View File

@ -1,24 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Np::NpProfileDialog {
s32 PS4_SYSV_ABI sceNpProfileDialogOpen();
s32 PS4_SYSV_ABI sceNpProfileDialogClose();
s32 PS4_SYSV_ABI sceNpProfileDialogGetResult();
s32 PS4_SYSV_ABI sceNpProfileDialogGetStatus();
s32 PS4_SYSV_ABI sceNpProfileDialogInitialize();
s32 PS4_SYSV_ABI sceNpProfileDialogOpenA();
s32 PS4_SYSV_ABI sceNpProfileDialogTerminate();
s32 PS4_SYSV_ABI sceNpProfileDialogUpdateStatus();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Np::NpProfileDialog

View File

@ -0,0 +1,155 @@
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cstring>
#include <core/libraries/system/commondialog.h>
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/libs.h"
#include "magic_enum/magic_enum.hpp"
#include "np_profile_dialog.h"
#include "np_profile_dialog_ui.h"
namespace Libraries::Np::NpProfileDialog {
static auto g_status = Libraries::CommonDialog::Status::NONE;
static NpProfileDialogState g_state{};
static OrbisNpProfileDialogResult g_result{};
static NpProfileDialogUi g_profile_dialog_ui;
Libraries::CommonDialog::Error PS4_SYSV_ABI
sceNpProfileDialogOpen(OrbisNpProfileDialogParam* param) {
if (g_status != Libraries::CommonDialog::Status::INITIALIZED &&
g_status != Libraries::CommonDialog::Status::FINISHED) {
LOG_INFO(Lib_NpProfileDialog, "called without initialize");
return Libraries::CommonDialog::Error::INVALID_STATE;
}
if (param == nullptr) {
return Libraries::CommonDialog::Error::ARG_NULL;
}
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
NpProfileDialogState state{};
state.onlineId = std::string(param->targetOnlineId.data);
state.hasAccountId = false;
state.mode = param->mode;
state.userId = param->userId;
g_state = state;
g_result = {};
g_result.userData = param->userData;
g_status = Libraries::CommonDialog::Status::RUNNING;
g_profile_dialog_ui = NpProfileDialogUi(&g_state, &g_status, &g_result);
return Libraries::CommonDialog::Error::OK;
}
Libraries::CommonDialog::Error PS4_SYSV_ABI sceNpProfileDialogClose() {
LOG_DEBUG(Lib_NpProfileDialog, "called");
if (g_status == Libraries::CommonDialog::Status::NONE) {
return Libraries::CommonDialog::Error::NOT_INITIALIZED;
}
if (g_status != Libraries::CommonDialog::Status::RUNNING) {
return Libraries::CommonDialog::Error::NOT_RUNNING;
}
g_profile_dialog_ui.Finish(Libraries::CommonDialog::Result::OK);
return Libraries::CommonDialog::Error::OK;
}
Libraries::CommonDialog::Error PS4_SYSV_ABI
sceNpProfileDialogGetResult(OrbisNpProfileDialogResult* result) {
LOG_DEBUG(Lib_NpProfileDialog, "called");
if (g_status == Libraries::CommonDialog::Status::NONE) {
return Libraries::CommonDialog::Error::NOT_INITIALIZED;
}
if (result == nullptr) {
return Libraries::CommonDialog::Error::ARG_NULL;
}
if (g_status != Libraries::CommonDialog::Status::FINISHED) {
return Libraries::CommonDialog::Error::NOT_FINISHED;
}
*result = g_result;
return Libraries::CommonDialog::Error::OK;
}
Libraries::CommonDialog::Status PS4_SYSV_ABI sceNpProfileDialogGetStatus() {
LOG_TRACE(Lib_NpProfileDialog, "called status={}", magic_enum::enum_name(g_status));
return g_status;
}
Libraries::CommonDialog::Error PS4_SYSV_ABI sceNpProfileDialogInitialize() {
if (!CommonDialog::g_isInitialized) {
return Libraries::CommonDialog::Error::NOT_SYSTEM_INITIALIZED;
}
if (g_status != Libraries::CommonDialog::Status::NONE) {
LOG_INFO(Lib_NpProfileDialog, "already initialized");
return Libraries::CommonDialog::Error::ALREADY_INITIALIZED;
}
if (CommonDialog::g_isUsed) {
return Libraries::CommonDialog::Error::BUSY;
}
g_status = Libraries::CommonDialog::Status::INITIALIZED;
CommonDialog::g_isUsed = true;
return Libraries::CommonDialog::Error::OK;
}
Libraries::CommonDialog::Error PS4_SYSV_ABI
sceNpProfileDialogOpenA(OrbisNpProfileDialogParamA* param) {
if (g_status != Libraries::CommonDialog::Status::INITIALIZED &&
g_status != Libraries::CommonDialog::Status::FINISHED) {
LOG_INFO(Lib_NpProfileDialog, "called without initialize");
return Libraries::CommonDialog::Error::INVALID_STATE;
}
if (param == nullptr) {
return Libraries::CommonDialog::Error::ARG_NULL;
}
LOG_ERROR(Lib_NpProfileDialog, "(STUBBED) called");
NpProfileDialogState state{};
state.accountId = param->targetAccountId;
state.hasAccountId = true;
state.mode = param->mode;
state.userId = param->userId;
g_state = state;
g_result = {};
g_result.userData = param->userData;
g_status = Libraries::CommonDialog::Status::RUNNING;
g_profile_dialog_ui = NpProfileDialogUi(&g_state, &g_status, &g_result);
return Libraries::CommonDialog::Error::OK;
}
Libraries::CommonDialog::Error PS4_SYSV_ABI sceNpProfileDialogTerminate() {
if (g_status == Libraries::CommonDialog::Status::RUNNING) {
sceNpProfileDialogClose();
}
if (g_status == Libraries::CommonDialog::Status::NONE) {
return Libraries::CommonDialog::Error::NOT_INITIALIZED;
}
g_status = Libraries::CommonDialog::Status::NONE;
CommonDialog::g_isUsed = false;
return Libraries::CommonDialog::Error::OK;
}
Libraries::CommonDialog::Status PS4_SYSV_ABI sceNpProfileDialogUpdateStatus() {
LOG_TRACE(Lib_NpProfileDialog, "called status={}", magic_enum::enum_name(g_status));
return g_status;
}
void RegisterLib(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("uj9Cz7Tk0cc", "libSceNpProfileDialogCompat", 1, "libSceNpProfileDialog",
sceNpProfileDialogOpen);
LIB_FUNCTION("wkwjz0Xdo2A", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogClose);
LIB_FUNCTION("8rhLl1-0W-o", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogGetResult);
LIB_FUNCTION("3BqoiFOjSsk", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogGetStatus);
LIB_FUNCTION("Lg+NCE6pTwQ", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogInitialize);
LIB_FUNCTION("uj9Cz7Tk0cc", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogOpen);
LIB_FUNCTION("nrQRlLKzdwE", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogOpenA);
LIB_FUNCTION("0Sp9vJcB1-w", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogTerminate);
LIB_FUNCTION("haVZE9FgKqE", "libSceNpProfileDialog", 1, "libSceNpProfileDialog",
sceNpProfileDialogUpdateStatus);
};
} // namespace Libraries::Np::NpProfileDialog

View File

@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <core/libraries/system/commondialog.h>
#include <core/libraries/system/userservice.h>
#include "common/types.h"
#include "core/libraries/np/np_types.h"
namespace Core::Loader {
class SymbolsResolver;
}
namespace Libraries::Np::NpProfileDialog {
enum class OrbisNpProfileDialogMode : u32 {
ORBIS_NP_PROFILE_DIALOG_MODE_INVALID = 0,
ORBIS_NP_PROFILE_DIALOG_MODE_NORMAL = 1,
ORBIS_NP_PROFILE_DIALOG_MODE_FRIEND_REQUEST = 2,
ORBIS_NP_PROFILE_DIALOG_MODE_ADD_TO_BLOCK_LIST = 3,
ORBIS_NP_PROFILE_DIALOG_MODE_GRIEF_REPORT = 4,
};
using OrbisNpProfileGriefReportItem = s32;
static constexpr OrbisNpProfileGriefReportItem
ORBIS_NP_PROFILE_DIALOG_MENU_GRIEF_REPORT_ITEM_INVALID = 0x00000000;
static constexpr OrbisNpProfileGriefReportItem
ORBIS_NP_PROFILE_DIALOG_MENU_GRIEF_REPORT_ITEM_ONLINE_ID = 0x00000001;
static constexpr OrbisNpProfileGriefReportItem ORBIS_NP_PROFILE_DIALOG_MENU_GRIEF_REPORT_ITEM_NAME =
0x00000002;
static constexpr OrbisNpProfileGriefReportItem
ORBIS_NP_PROFILE_DIALOG_MENU_GRIEF_REPORT_ITEM_PICTURE = 0x00000004;
static constexpr OrbisNpProfileGriefReportItem
ORBIS_NP_PROFILE_DIALOG_MENU_GRIEF_REPORT_ITEM_ABOUT_ME = 0x00000008;
struct OrbisNpProfileDialogParam {
CommonDialog::BaseParam baseParam;
u64 size;
OrbisNpProfileDialogMode mode;
Libraries::UserService::OrbisUserServiceUserId userId;
Libraries::Np::OrbisNpOnlineId targetOnlineId;
void* userData;
u8 reserved[32];
};
struct OrbisNpProfileGriefReportParam {
s32 reportItem;
u8 reserved[28];
};
struct OrbisNpProfileDialogParamA {
CommonDialog::BaseParam baseParam;
u64 size;
OrbisNpProfileDialogMode mode;
Libraries::UserService::OrbisUserServiceUserId userId;
Libraries::Np::OrbisNpAccountId targetAccountId;
int : 32;
void* userData;
union {
uint8_t reserved[32];
OrbisNpProfileGriefReportParam griefReportParam;
};
};
struct OrbisNpProfileDialogResult {
s32 result;
CommonDialog::Result userAction;
void* userData;
u8 reserved[32];
};
Libraries::CommonDialog::Error PS4_SYSV_ABI
sceNpProfileDialogOpen(OrbisNpProfileDialogParam* param);
Libraries::CommonDialog::Error PS4_SYSV_ABI sceNpProfileDialogClose();
Libraries::CommonDialog::Error PS4_SYSV_ABI
sceNpProfileDialogGetResult(OrbisNpProfileDialogResult* result);
Libraries::CommonDialog::Status PS4_SYSV_ABI sceNpProfileDialogGetStatus();
Libraries::CommonDialog::Error PS4_SYSV_ABI sceNpProfileDialogInitialize();
Libraries::CommonDialog::Error PS4_SYSV_ABI
sceNpProfileDialogOpenA(OrbisNpProfileDialogParamA* param);
Libraries::CommonDialog::Error PS4_SYSV_ABI sceNpProfileDialogTerminate();
Libraries::CommonDialog::Status PS4_SYSV_ABI sceNpProfileDialogUpdateStatus();
void RegisterLib(Core::Loader::SymbolsResolver* sym);
} // namespace Libraries::Np::NpProfileDialog

View File

@ -0,0 +1,279 @@
// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <cinttypes>
#include <cmath>
#include <thread>
#include <utility>
#include <imgui.h>
#include <imgui/imgui_std.h>
#include "np_profile_dialog_ui.h"
using namespace ImGui;
using namespace Libraries::CommonDialog;
namespace Libraries::Np::NpProfileDialog {
// PS4 color palette
static constexpr ImVec4 COL_OVERLAY = {0.00f, 0.00f, 0.00f, 0.65f};
static constexpr ImVec4 COL_HEADER_TOP = {0.00f, 0.34f, 0.62f, 1.00f};
static constexpr ImVec4 COL_HEADER_BOT = {0.00f, 0.22f, 0.42f, 1.00f};
static constexpr ImVec4 COL_CARD_BG = {0.11f, 0.11f, 0.12f, 1.00f};
static constexpr ImVec4 COL_SEPARATOR = {0.22f, 0.22f, 0.24f, 1.00f};
static constexpr ImVec4 COL_AVATAR_BG = {0.18f, 0.18f, 0.20f, 1.00f};
static constexpr ImVec4 COL_AVATAR_OUTLINE = {0.00f, 0.44f, 0.75f, 1.00f};
static constexpr ImVec4 COL_TEXT_PRIMARY = {1.00f, 1.00f, 1.00f, 1.00f};
static constexpr ImVec4 COL_TEXT_SECONDARY = {0.65f, 0.65f, 0.68f, 1.00f};
static constexpr ImVec4 COL_BUTTON_NORMAL = {0.18f, 0.18f, 0.20f, 1.00f};
static constexpr ImVec4 COL_BUTTON_HOVERED = {0.00f, 0.44f, 0.75f, 1.00f};
static constexpr ImVec4 COL_BUTTON_ACTIVE = {0.00f, 0.33f, 0.60f, 1.00f};
static constexpr ImVec4 COL_BUTTON_BORDER = {0.32f, 0.32f, 0.35f, 1.00f};
static constexpr float CARD_WIDTH = 480.0f;
static constexpr float CARD_HEIGHT = 330.0f;
static constexpr float HEADER_HEIGHT = 44.0f;
static constexpr float FOOTER_HEIGHT = 56.0f;
static constexpr float AVATAR_RADIUS = 44.0f;
static constexpr float AVATAR_REL_X = CARD_WIDTH * 0.5f;
static constexpr float AVATAR_REL_Y = HEADER_HEIGHT + AVATAR_RADIUS + 16.0f;
static constexpr float FADE_SPEED = 8.0f;
static constexpr ImVec2 CLOSE_BUTTON_SIZE = {110.0f, 34.0f};
static ImU32 AlphaScale(ImVec4 col, float alpha) {
col.w *= alpha;
return GetColorU32(col);
}
static void DrawCardShadow(ImDrawList* dl, ImVec2 min, ImVec2 max, float alpha) {
for (int i = 0; i < 6; ++i) {
const float spread = (float)(i + 1) * 3.5f;
const float a = alpha * (0.28f - (float)i * 0.04f);
if (a <= 0.0f)
break;
dl->AddRectFilled({min.x - spread, min.y + spread}, {max.x + spread, max.y + spread * 1.5f},
IM_COL32(0, 0, 0, (int)(a * 255.0f)), 8.0f + spread);
}
}
static void DrawAvatarPlaceholder(ImDrawList* dl, ImVec2 center, float radius, float alpha) {
const ImU32 bg_col = AlphaScale(COL_AVATAR_BG, alpha);
const ImU32 outline_col = AlphaScale(COL_AVATAR_OUTLINE, alpha);
const ImU32 silhouette = IM_COL32(90, 90, 96, (int)(alpha * 255.0f));
dl->AddCircleFilled(center, radius, bg_col, 64);
dl->AddCircleFilled({center.x, center.y - radius * 0.18f}, radius * 0.32f, silhouette, 32);
dl->AddCircleFilled({center.x, center.y + radius * 0.45f}, radius * 0.55f, silhouette, 48);
// Outline drawn last — sits on top of silhouette
dl->AddCircle(center, radius, outline_col, 64, 2.5f);
}
static const char* GetModeTitle(OrbisNpProfileDialogMode mode) {
switch (mode) {
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_NORMAL:
return "Profile";
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_FRIEND_REQUEST:
return "Friend Request";
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_ADD_TO_BLOCK_LIST:
return "Block List";
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_GRIEF_REPORT:
return "Report";
default:
return "Profile";
}
}
static const char* GetModeSubtitle(OrbisNpProfileDialogMode mode) {
switch (mode) {
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_NORMAL:
return "Player Profile";
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_FRIEND_REQUEST:
return "Send Friend Request";
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_ADD_TO_BLOCK_LIST:
return "Add to Block List";
case OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_GRIEF_REPORT:
return "Report Player";
default:
return "Player Profile";
}
}
NpProfileDialogUi::NpProfileDialogUi(NpProfileDialogState* state, Status* status,
OrbisNpProfileDialogResult* result)
: state(state), status(status), result(result) {
if (status && *status == Status::RUNNING) {
first_render = true;
open_alpha = 0.0f;
AddLayer(this);
}
}
NpProfileDialogUi::~NpProfileDialogUi() {
Finish(Result::USER_CANCELED);
}
NpProfileDialogUi::NpProfileDialogUi(NpProfileDialogUi&& other) noexcept
: Layer(other), state(other.state), status(other.status), result(other.result),
open_alpha(other.open_alpha) {
other.state = nullptr;
other.status = nullptr;
other.result = nullptr;
other.open_alpha = 0.0f;
}
NpProfileDialogUi& NpProfileDialogUi::operator=(NpProfileDialogUi other) {
using std::swap;
swap(state, other.state);
swap(status, other.status);
swap(result, other.result);
swap(open_alpha, other.open_alpha);
if (status && *status == Status::RUNNING) {
first_render = true;
open_alpha = 0.0f;
AddLayer(this);
}
return *this;
}
void NpProfileDialogUi::Finish(Result user_action) {
if (result) {
result->result = 0; // ORBIS_OK
result->userAction = user_action;
}
if (status) {
*status = Status::FINISHED;
}
state = nullptr;
status = nullptr;
result = nullptr;
RemoveLayer(this);
}
void NpProfileDialogUi::Draw() {
if (status == nullptr || *status != Status::RUNNING) {
return;
}
const auto& io = GetIO();
open_alpha = std::fmin(open_alpha + io.DeltaTime * FADE_SPEED, 1.0f);
const float card_x = (io.DisplaySize.x - CARD_WIDTH) * 0.5f;
const float card_y = (io.DisplaySize.y - CARD_HEIGHT) * 0.5f;
const ImVec2 card_min = {card_x, card_y};
const ImVec2 card_max = {card_x + CARD_WIDTH, card_y + CARD_HEIGHT};
SetNextWindowPos({0, 0});
SetNextWindowSize(io.DisplaySize);
PushStyleColor(ImGuiCol_WindowBg, AlphaScale(COL_OVERLAY, open_alpha));
PushStyleVar(ImGuiStyleVar_WindowPadding, {0.0f, 0.0f});
Begin("##NpProfileDialogOverlay", nullptr,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoNav |
ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoFocusOnAppearing);
End();
PopStyleVar();
PopStyleColor();
SetNextWindowPos(card_min);
SetNextWindowSize({CARD_WIDTH, CARD_HEIGHT});
SetNextWindowCollapsed(false);
if (first_render || !io.NavActive) {
SetNextWindowFocus();
}
KeepNavHighlight();
PushStyleColor(ImGuiCol_WindowBg, AlphaScale(COL_CARD_BG, open_alpha));
PushStyleColor(ImGuiCol_Border, AlphaScale(COL_SEPARATOR, open_alpha));
PushStyleColor(ImGuiCol_Text, AlphaScale(COL_TEXT_PRIMARY, open_alpha));
PushStyleColor(ImGuiCol_Button, AlphaScale(COL_BUTTON_NORMAL, open_alpha));
PushStyleColor(ImGuiCol_ButtonHovered, AlphaScale(COL_BUTTON_HOVERED, open_alpha));
PushStyleColor(ImGuiCol_ButtonActive, AlphaScale(COL_BUTTON_ACTIVE, open_alpha));
PushStyleVar(ImGuiStyleVar_WindowPadding, {0.0f, 0.0f});
PushStyleVar(ImGuiStyleVar_WindowRounding, 6.0f);
PushStyleVar(ImGuiStyleVar_FrameRounding, 4.0f);
PushStyleVar(ImGuiStyleVar_WindowBorderSize, 1.0f);
if (Begin("##NpProfileDialog", nullptr,
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings |
ImGuiWindowFlags_NoMove)) {
ImDrawList* dl = GetWindowDrawList();
const ImVec2 win_pos = GetWindowPos();
DrawCardShadow(dl, card_min, card_max, open_alpha);
const ImVec2 hdr_min = win_pos;
const ImVec2 hdr_max = {win_pos.x + CARD_WIDTH, win_pos.y + HEADER_HEIGHT};
dl->AddRectFilledMultiColor(hdr_min, hdr_max, AlphaScale(COL_HEADER_TOP, open_alpha),
AlphaScale(COL_HEADER_TOP, open_alpha),
AlphaScale(COL_HEADER_BOT, open_alpha),
AlphaScale(COL_HEADER_BOT, open_alpha));
dl->AddRectFilled({hdr_min.x, hdr_max.y - 6.0f}, hdr_max,
AlphaScale(COL_HEADER_BOT, open_alpha));
dl->AddLine({hdr_min.x + 6.0f, hdr_min.y + 1.0f}, {hdr_max.x - 6.0f, hdr_min.y + 1.0f},
IM_COL32(255, 255, 255, (int)(open_alpha * 40.0f)), 1.0f);
// Footer separator
const float footer_top_screen = win_pos.y + CARD_HEIGHT - FOOTER_HEIGHT;
dl->AddLine({win_pos.x, footer_top_screen}, {win_pos.x + CARD_WIDTH, footer_top_screen},
AlphaScale(COL_SEPARATOR, open_alpha), 1.0f);
// Avatar
const ImVec2 avatar_screen = {win_pos.x + AVATAR_REL_X, win_pos.y + AVATAR_REL_Y};
DrawAvatarPlaceholder(dl, avatar_screen, AVATAR_RADIUS, open_alpha);
// Header title
const char* title = GetModeTitle(state->mode);
const ImVec2 title_sz = CalcTextSize(title);
SetCursorPos({(CARD_WIDTH - title_sz.x) * 0.5f, (HEADER_HEIGHT - title_sz.y) * 0.5f});
TextUnformatted(title);
// Online ID / Account ID
char id_buf[32]{};
const char* id_str = state->onlineId.c_str();
if (state->hasAccountId) {
snprintf(id_buf, sizeof(id_buf), "%" PRIu64, state->accountId);
id_str = id_buf;
}
const float id_y = AVATAR_REL_Y + AVATAR_RADIUS + 14.0f;
const ImVec2 id_sz = CalcTextSize(id_str);
SetCursorPos({(CARD_WIDTH - id_sz.x) * 0.5f, id_y});
TextUnformatted(id_str);
// Mode subtitle
PushStyleColor(ImGuiCol_Text, AlphaScale(COL_TEXT_SECONDARY, open_alpha));
const char* subtitle = GetModeSubtitle(state->mode);
const ImVec2 sub_sz = CalcTextSize(subtitle);
SetCursorPos({(CARD_WIDTH - sub_sz.x) * 0.5f, id_y + id_sz.y + 5.0f});
TextUnformatted(subtitle);
PopStyleColor();
const float footer_y_local = CARD_HEIGHT - FOOTER_HEIGHT;
PushStyleColor(ImGuiCol_Border, AlphaScale(COL_BUTTON_BORDER, open_alpha));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.0f);
SetCursorPos({CARD_WIDTH - CLOSE_BUTTON_SIZE.x - 16.0f,
footer_y_local + (FOOTER_HEIGHT - CLOSE_BUTTON_SIZE.y) * 0.5f});
if (Button("Close##btn", CLOSE_BUTTON_SIZE)) {
Finish(Result::USER_CANCELED);
}
PopStyleVar();
PopStyleColor();
if (first_render) {
SetItemCurrentNavFocus();
}
}
End();
PopStyleVar(4);
PopStyleColor(6);
first_render = false;
}
} // namespace Libraries::Np::NpProfileDialog

View File

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <string>
#include <variant>
#include "common/fixed_value.h"
#include "common/types.h"
#include "core/libraries/system/commondialog.h"
#include "imgui/imgui_layer.h"
#include "np_profile_dialog.h"
namespace Libraries::Np::NpProfileDialog {
struct NpProfileDialogState {
std::string onlineId;
OrbisNpAccountId accountId{};
bool hasAccountId{false};
OrbisNpProfileDialogMode mode{OrbisNpProfileDialogMode::ORBIS_NP_PROFILE_DIALOG_MODE_INVALID};
int userId{};
};
class NpProfileDialogUi : public ImGui::Layer {
public:
explicit NpProfileDialogUi(NpProfileDialogState* state = nullptr,
CommonDialog::Status* status = nullptr,
OrbisNpProfileDialogResult* result = nullptr);
~NpProfileDialogUi() override;
NpProfileDialogUi(const NpProfileDialogUi& other) = delete;
NpProfileDialogUi(NpProfileDialogUi&& other) noexcept;
NpProfileDialogUi& operator=(NpProfileDialogUi other);
void Finish(CommonDialog::Result user_action);
void Draw() override;
private:
NpProfileDialogState* state{};
CommonDialog::Status* status{};
OrbisNpProfileDialogResult* result{};
bool first_render{false};
float open_alpha{0.0f};
};
} // namespace Libraries::Np::NpProfileDialog

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
@ -11,9 +11,13 @@ namespace Libraries::WebBrowserDialog {
static auto g_status = Libraries::CommonDialog::Status::NONE;
s32 PS4_SYSV_ABI sceWebBrowserDialogClose() {
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogClose() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
if (g_status != Libraries::CommonDialog::Status::RUNNING) {
return Libraries::CommonDialog::Error::NOT_RUNNING;
}
LOG_INFO(Lib_NpProfileDialog, "TODO: close npprofile ui dialog"); // TODO close Ui dialog
return Libraries::CommonDialog::Error::OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent() {
@ -27,17 +31,23 @@ s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult() {
}
Libraries::CommonDialog::Status PS4_SYSV_ABI sceWebBrowserDialogGetStatus() {
LOG_TRACE(Lib_MsgDlg, "called status={}", magic_enum::enum_name(g_status));
LOG_TRACE(Lib_WebBrowserDialog, "called status={}", magic_enum::enum_name(g_status));
return g_status;
}
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogInitialize() {
if (CommonDialog::g_isInitialized) {
LOG_INFO(Lib_WebBrowserDialog, "already initialized");
return Libraries::CommonDialog::Error::ALREADY_SYSTEM_INITIALIZED;
if (!CommonDialog::g_isInitialized) {
return Libraries::CommonDialog::Error::NOT_SYSTEM_INITIALIZED;
}
LOG_DEBUG(Lib_WebBrowserDialog, "initialized");
CommonDialog::g_isInitialized = true;
if (g_status != Libraries::CommonDialog::Status::NONE) {
LOG_ERROR(Lib_WebBrowserDialog, "already initialized");
return Libraries::CommonDialog::Error::ALREADY_INITIALIZED;
}
if (CommonDialog::g_isUsed) {
return Libraries::CommonDialog::Error::BUSY;
}
g_status = Libraries::CommonDialog::Status::INITIALIZED;
CommonDialog::g_isUsed = true;
return Libraries::CommonDialog::Error::OK;
}
@ -46,9 +56,15 @@ s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate() {
return ORBIS_OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen() {
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called");
return ORBIS_OK;
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogOpen() {
if (g_status != Libraries::CommonDialog::Status::INITIALIZED &&
g_status != Libraries::CommonDialog::Status::FINISHED) {
LOG_INFO(Lib_WebBrowserDialog, "called without initialize");
return Libraries::CommonDialog::Error::INVALID_STATE;
}
LOG_ERROR(Lib_WebBrowserDialog, "(STUBBED) called"); // TODO open ui dialog
g_status = Libraries::CommonDialog::Status::RUNNING;
return Libraries::CommonDialog::Error::OK;
}
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent() {
@ -73,8 +89,7 @@ s32 PS4_SYSV_ABI sceWebBrowserDialogSetZoom() {
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogTerminate() {
if (g_status == Libraries::CommonDialog::Status::RUNNING) {
LOG_ERROR(Lib_WebBrowserDialog,
"CloseWebBrowser Dialog unimplemented"); // sceWebBrowserDialogClose();
sceWebBrowserDialogClose();
}
if (g_status == Libraries::CommonDialog::Status::NONE) {
return Libraries::CommonDialog::Error::NOT_INITIALIZED;
@ -85,7 +100,11 @@ Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogTerminate() {
}
Libraries::CommonDialog::Status PS4_SYSV_ABI sceWebBrowserDialogUpdateStatus() {
LOG_TRACE(Lib_MsgDlg, "called status={}", magic_enum::enum_name(g_status));
LOG_TRACE(Lib_WebBrowserDialog, "called status={}", magic_enum::enum_name(g_status));
if (g_status == Libraries::CommonDialog::Status::RUNNING) {
g_status = Libraries::CommonDialog::Status::FINISHED; // TODO removed it when implementing
// real dialog
}
return g_status;
}

View File

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
@ -12,13 +12,13 @@ class SymbolsResolver;
namespace Libraries::WebBrowserDialog {
s32 PS4_SYSV_ABI sceWebBrowserDialogClose();
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogClose();
s32 PS4_SYSV_ABI sceWebBrowserDialogGetEvent();
s32 PS4_SYSV_ABI sceWebBrowserDialogGetResult();
Libraries::CommonDialog::Status PS4_SYSV_ABI sceWebBrowserDialogGetStatus();
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogInitialize();
s32 PS4_SYSV_ABI sceWebBrowserDialogNavigate();
s32 PS4_SYSV_ABI sceWebBrowserDialogOpen();
Libraries::CommonDialog::Error PS4_SYSV_ABI sceWebBrowserDialogOpen();
s32 PS4_SYSV_ABI sceWebBrowserDialogOpenForPredeterminedContent();
s32 PS4_SYSV_ABI sceWebBrowserDialogResetCookie();
s32 PS4_SYSV_ABI sceWebBrowserDialogSetCookie();