mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-05-21 19:05:00 +00:00
Error dialog implementation (#1062)
This commit is contained in:
parent
f79da986e3
commit
cc99f52606
2 changed files with 168 additions and 50 deletions
|
@ -1,40 +1,166 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <imgui.h>
|
||||||
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/libraries/error_codes.h"
|
#include "core/libraries/error_codes.h"
|
||||||
#include "core/libraries/libs.h"
|
#include "core/libraries/libs.h"
|
||||||
#include "error_codes.h"
|
#include "core/libraries/system/commondialog.h"
|
||||||
#include "error_dialog.h"
|
#include "error_dialog.h"
|
||||||
|
#include "imgui/imgui_layer.h"
|
||||||
|
#include "imgui/imgui_std.h"
|
||||||
|
|
||||||
|
static constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||||
|
|
||||||
namespace Libraries::ErrorDialog {
|
namespace Libraries::ErrorDialog {
|
||||||
|
|
||||||
static OrbisErrorDialogStatus g_error_dlg_status =
|
using CommonDialog::Error;
|
||||||
OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_NONE;
|
using CommonDialog::Result;
|
||||||
|
using CommonDialog::Status;
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceErrorDialogClose() {
|
class ErrorDialogUi final : public ImGui::Layer {
|
||||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_FINISHED;
|
bool first_render{false};
|
||||||
return ORBIS_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogGetStatus() {
|
Status* status{nullptr};
|
||||||
return g_error_dlg_status;
|
std::string err_message{};
|
||||||
}
|
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceErrorDialogInitialize(OrbisErrorDialogParam* param) {
|
public:
|
||||||
if (g_error_dlg_status == OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_INITIALIZED) {
|
explicit ErrorDialogUi(Status* status = nullptr, std::string err_message = "")
|
||||||
LOG_ERROR(Lib_ErrorDialog, "Error dialog is already at init mode");
|
: status(status), err_message(std::move(err_message)) {
|
||||||
return ORBIS_ERROR_DIALOG_ERROR_ALREADY_INITIALIZED;
|
if (status && *status == Status::RUNNING) {
|
||||||
|
first_render = true;
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_INITIALIZED;
|
~ErrorDialogUi() override {
|
||||||
return ORBIS_OK;
|
Finish();
|
||||||
|
}
|
||||||
|
ErrorDialogUi(const ErrorDialogUi& other) = delete;
|
||||||
|
ErrorDialogUi(ErrorDialogUi&& other) noexcept
|
||||||
|
: Layer(other), status(other.status), err_message(std::move(other.err_message)) {
|
||||||
|
other.status = nullptr;
|
||||||
|
}
|
||||||
|
ErrorDialogUi& operator=(ErrorDialogUi other) {
|
||||||
|
using std::swap;
|
||||||
|
swap(status, other.status);
|
||||||
|
swap(err_message, other.err_message);
|
||||||
|
if (status && *status == Status::RUNNING) {
|
||||||
|
first_render = true;
|
||||||
|
AddLayer(this);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Finish() {
|
||||||
|
if (status) {
|
||||||
|
*status = Status::FINISHED;
|
||||||
|
}
|
||||||
|
status = nullptr;
|
||||||
|
RemoveLayer(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Draw() override {
|
||||||
|
using namespace ImGui;
|
||||||
|
if (status == nullptr || *status != Status::RUNNING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& io = GetIO();
|
||||||
|
|
||||||
|
const ImVec2 window_size{
|
||||||
|
std::min(io.DisplaySize.x, 500.0f),
|
||||||
|
std::min(io.DisplaySize.y, 300.0f),
|
||||||
|
};
|
||||||
|
|
||||||
|
CentralizeWindow();
|
||||||
|
SetNextWindowSize(window_size);
|
||||||
|
SetNextWindowCollapsed(false);
|
||||||
|
if (first_render || !io.NavActive) {
|
||||||
|
SetNextWindowFocus();
|
||||||
|
}
|
||||||
|
KeepNavHighlight();
|
||||||
|
if (Begin("Error Dialog##ErrorDialog", nullptr,
|
||||||
|
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
const auto ws = GetWindowSize();
|
||||||
|
|
||||||
|
DrawPrettyBackground();
|
||||||
|
const char* begin = &err_message.front();
|
||||||
|
const char* end = &err_message.back() + 1;
|
||||||
|
SetWindowFontScale(1.3f);
|
||||||
|
DrawCenteredText(begin, end,
|
||||||
|
GetContentRegionAvail() - ImVec2{0.0f, 15.0f + BUTTON_SIZE.y});
|
||||||
|
SetWindowFontScale(1.0f);
|
||||||
|
|
||||||
|
SetCursorPos({
|
||||||
|
ws.x / 2.0f - BUTTON_SIZE.x / 2.0f,
|
||||||
|
ws.y - 10.0f - BUTTON_SIZE.y,
|
||||||
|
});
|
||||||
|
if (Button("OK", BUTTON_SIZE)) {
|
||||||
|
Finish();
|
||||||
|
}
|
||||||
|
if (first_render) {
|
||||||
|
SetItemCurrentNavFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
End();
|
||||||
|
|
||||||
|
first_render = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static auto g_status = Status::NONE;
|
||||||
|
static ErrorDialogUi g_dialog_ui;
|
||||||
|
|
||||||
|
struct Param {
|
||||||
|
s32 size;
|
||||||
|
s32 errorCode;
|
||||||
|
OrbisUserServiceUserId userId;
|
||||||
|
s32 _reserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
Error PS4_SYSV_ABI sceErrorDialogClose() {
|
||||||
|
LOG_DEBUG(Lib_ErrorDialog, "called");
|
||||||
|
if (g_status != Status::RUNNING) {
|
||||||
|
return Error::NOT_RUNNING;
|
||||||
|
}
|
||||||
|
g_dialog_ui.Finish();
|
||||||
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceErrorDialogOpen(OrbisErrorDialogParam* param) {
|
Status PS4_SYSV_ABI sceErrorDialogGetStatus() {
|
||||||
LOG_ERROR(Lib_ErrorDialog, "size = {} errorcode = {:#x} userid = {}", param->size,
|
LOG_TRACE(Lib_ErrorDialog, "called status={}", magic_enum::enum_name(g_status));
|
||||||
param->errorCode, param->userId);
|
return g_status;
|
||||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_RUNNING;
|
}
|
||||||
return ORBIS_OK;
|
|
||||||
|
Error PS4_SYSV_ABI sceErrorDialogInitialize() {
|
||||||
|
LOG_DEBUG(Lib_ErrorDialog, "called");
|
||||||
|
if (g_status != Status::NONE) {
|
||||||
|
return Error::ALREADY_INITIALIZED;
|
||||||
|
}
|
||||||
|
g_status = Status::INITIALIZED;
|
||||||
|
return Error::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error PS4_SYSV_ABI sceErrorDialogOpen(const Param* param) {
|
||||||
|
if (g_status != Status::INITIALIZED && g_status != Status::FINISHED) {
|
||||||
|
LOG_INFO(Lib_ErrorDialog, "called without initialize");
|
||||||
|
return Error::INVALID_STATE;
|
||||||
|
}
|
||||||
|
if (param == nullptr) {
|
||||||
|
LOG_DEBUG(Lib_ErrorDialog, "called param:(NULL)");
|
||||||
|
return Error::ARG_NULL;
|
||||||
|
}
|
||||||
|
const auto err = static_cast<u32>(param->errorCode);
|
||||||
|
LOG_DEBUG(Lib_ErrorDialog, "called param->errorCode = {:#x}", err);
|
||||||
|
ASSERT(param->size == sizeof(Param));
|
||||||
|
|
||||||
|
const std::string err_message = fmt::format("An error has occurred. \nCode: {:#X}", err);
|
||||||
|
g_status = Status::RUNNING;
|
||||||
|
g_dialog_ui = ErrorDialogUi{&g_status, err_message};
|
||||||
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceErrorDialogOpenDetail() {
|
int PS4_SYSV_ABI sceErrorDialogOpenDetail() {
|
||||||
|
@ -47,20 +173,21 @@ int PS4_SYSV_ABI sceErrorDialogOpenWithReport() {
|
||||||
return ORBIS_OK;
|
return ORBIS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceErrorDialogTerminate() {
|
Error PS4_SYSV_ABI sceErrorDialogTerminate() {
|
||||||
if (g_error_dlg_status == OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_NONE) {
|
LOG_DEBUG(Lib_ErrorDialog, "called");
|
||||||
LOG_ERROR(Lib_ErrorDialog, "Error dialog hasn't initialized");
|
if (g_status == Status::RUNNING) {
|
||||||
return ORBIS_ERROR_DIALOG_ERROR_NOT_INITIALIZED;
|
sceErrorDialogClose();
|
||||||
}
|
}
|
||||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_NONE;
|
if (g_status == Status::NONE) {
|
||||||
return ORBIS_OK;
|
return Error::NOT_INITIALIZED;
|
||||||
|
}
|
||||||
|
g_status = Status::NONE;
|
||||||
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogUpdateStatus() {
|
Status PS4_SYSV_ABI sceErrorDialogUpdateStatus() {
|
||||||
// TODO when imgui dialog is done this will loop until ORBIS_ERROR_DIALOG_STATUS_FINISHED
|
LOG_TRACE(Lib_ErrorDialog, "called status={}", magic_enum::enum_name(g_status));
|
||||||
// This should be done calling sceErrorDialogClose but since we don't have a dialog we finish it
|
return g_status;
|
||||||
// here
|
|
||||||
return OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_FINISHED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym) {
|
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym) {
|
||||||
|
|
|
@ -4,34 +4,25 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/types.h"
|
#include "common/types.h"
|
||||||
|
#include "core/libraries/system/commondialog.h"
|
||||||
|
|
||||||
namespace Core::Loader {
|
namespace Core::Loader {
|
||||||
class SymbolsResolver;
|
class SymbolsResolver;
|
||||||
}
|
}
|
||||||
namespace Libraries::ErrorDialog {
|
namespace Libraries::ErrorDialog {
|
||||||
|
|
||||||
enum OrbisErrorDialogStatus {
|
using OrbisUserServiceUserId = s32;
|
||||||
ORBIS_ERROR_DIALOG_STATUS_NONE = 0,
|
|
||||||
ORBIS_ERROR_DIALOG_STATUS_INITIALIZED = 1,
|
|
||||||
ORBIS_ERROR_DIALOG_STATUS_RUNNING = 2,
|
|
||||||
ORBIS_ERROR_DIALOG_STATUS_FINISHED = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
struct OrbisErrorDialogParam {
|
struct Param;
|
||||||
s32 size;
|
|
||||||
u32 errorCode;
|
|
||||||
s32 userId;
|
|
||||||
s32 reserved;
|
|
||||||
};
|
|
||||||
|
|
||||||
int PS4_SYSV_ABI sceErrorDialogClose();
|
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogClose();
|
||||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogGetStatus();
|
CommonDialog::Status PS4_SYSV_ABI sceErrorDialogGetStatus();
|
||||||
int PS4_SYSV_ABI sceErrorDialogInitialize(OrbisErrorDialogParam* param);
|
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogInitialize();
|
||||||
int PS4_SYSV_ABI sceErrorDialogOpen(OrbisErrorDialogParam* param);
|
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogOpen(const Param* param);
|
||||||
int PS4_SYSV_ABI sceErrorDialogOpenDetail();
|
int PS4_SYSV_ABI sceErrorDialogOpenDetail();
|
||||||
int PS4_SYSV_ABI sceErrorDialogOpenWithReport();
|
int PS4_SYSV_ABI sceErrorDialogOpenWithReport();
|
||||||
int PS4_SYSV_ABI sceErrorDialogTerminate();
|
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogTerminate();
|
||||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogUpdateStatus();
|
CommonDialog::Status PS4_SYSV_ABI sceErrorDialogUpdateStatus();
|
||||||
|
|
||||||
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym);
|
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym);
|
||||||
} // namespace Libraries::ErrorDialog
|
} // namespace Libraries::ErrorDialog
|
Loading…
Add table
Add a link
Reference in a new issue