mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-22 04:24:44 +00:00
Error dialog implementation
This commit is contained in:
parent
f79da986e3
commit
6bb67b71e2
2 changed files with 168 additions and 50 deletions
|
@ -1,40 +1,166 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// 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 "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "error_codes.h"
|
||||
#include "core/libraries/system/commondialog.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 {
|
||||
|
||||
static OrbisErrorDialogStatus g_error_dlg_status =
|
||||
OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_NONE;
|
||||
using CommonDialog::Error;
|
||||
using CommonDialog::Result;
|
||||
using CommonDialog::Status;
|
||||
|
||||
int PS4_SYSV_ABI sceErrorDialogClose() {
|
||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_FINISHED;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
class ErrorDialogUi final : public ImGui::Layer {
|
||||
bool first_render{false};
|
||||
|
||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogGetStatus() {
|
||||
return g_error_dlg_status;
|
||||
}
|
||||
Status* status{nullptr};
|
||||
std::string err_message{};
|
||||
|
||||
int PS4_SYSV_ABI sceErrorDialogInitialize(OrbisErrorDialogParam* param) {
|
||||
if (g_error_dlg_status == OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_INITIALIZED) {
|
||||
LOG_ERROR(Lib_ErrorDialog, "Error dialog is already at init mode");
|
||||
return ORBIS_ERROR_DIALOG_ERROR_ALREADY_INITIALIZED;
|
||||
public:
|
||||
explicit ErrorDialogUi(Status* status = nullptr, std::string err_message = "")
|
||||
: status(status), err_message(std::move(err_message)) {
|
||||
if (status && *status == Status::RUNNING) {
|
||||
first_render = true;
|
||||
AddLayer(this);
|
||||
}
|
||||
}
|
||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_INITIALIZED;
|
||||
return ORBIS_OK;
|
||||
~ErrorDialogUi() override {
|
||||
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) {
|
||||
LOG_ERROR(Lib_ErrorDialog, "size = {} errorcode = {:#x} userid = {}", param->size,
|
||||
param->errorCode, param->userId);
|
||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_RUNNING;
|
||||
return ORBIS_OK;
|
||||
Status PS4_SYSV_ABI sceErrorDialogGetStatus() {
|
||||
LOG_TRACE(Lib_ErrorDialog, "called status={}", magic_enum::enum_name(g_status));
|
||||
return g_status;
|
||||
}
|
||||
|
||||
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() {
|
||||
|
@ -47,20 +173,21 @@ int PS4_SYSV_ABI sceErrorDialogOpenWithReport() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceErrorDialogTerminate() {
|
||||
if (g_error_dlg_status == OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_NONE) {
|
||||
LOG_ERROR(Lib_ErrorDialog, "Error dialog hasn't initialized");
|
||||
return ORBIS_ERROR_DIALOG_ERROR_NOT_INITIALIZED;
|
||||
Error PS4_SYSV_ABI sceErrorDialogTerminate() {
|
||||
LOG_DEBUG(Lib_ErrorDialog, "called");
|
||||
if (g_status == Status::RUNNING) {
|
||||
sceErrorDialogClose();
|
||||
}
|
||||
g_error_dlg_status = OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_NONE;
|
||||
return ORBIS_OK;
|
||||
if (g_status == Status::NONE) {
|
||||
return Error::NOT_INITIALIZED;
|
||||
}
|
||||
g_status = Status::NONE;
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogUpdateStatus() {
|
||||
// TODO when imgui dialog is done this will loop until ORBIS_ERROR_DIALOG_STATUS_FINISHED
|
||||
// This should be done calling sceErrorDialogClose but since we don't have a dialog we finish it
|
||||
// here
|
||||
return OrbisErrorDialogStatus::ORBIS_ERROR_DIALOG_STATUS_FINISHED;
|
||||
Status PS4_SYSV_ABI sceErrorDialogUpdateStatus() {
|
||||
LOG_TRACE(Lib_ErrorDialog, "called status={}", magic_enum::enum_name(g_status));
|
||||
return g_status;
|
||||
}
|
||||
|
||||
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym) {
|
||||
|
|
|
@ -4,34 +4,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "common/types.h"
|
||||
#include "core/libraries/system/commondialog.h"
|
||||
|
||||
namespace Core::Loader {
|
||||
class SymbolsResolver;
|
||||
}
|
||||
namespace Libraries::ErrorDialog {
|
||||
|
||||
enum OrbisErrorDialogStatus {
|
||||
ORBIS_ERROR_DIALOG_STATUS_NONE = 0,
|
||||
ORBIS_ERROR_DIALOG_STATUS_INITIALIZED = 1,
|
||||
ORBIS_ERROR_DIALOG_STATUS_RUNNING = 2,
|
||||
ORBIS_ERROR_DIALOG_STATUS_FINISHED = 3
|
||||
};
|
||||
using OrbisUserServiceUserId = s32;
|
||||
|
||||
struct OrbisErrorDialogParam {
|
||||
s32 size;
|
||||
u32 errorCode;
|
||||
s32 userId;
|
||||
s32 reserved;
|
||||
};
|
||||
struct Param;
|
||||
|
||||
int PS4_SYSV_ABI sceErrorDialogClose();
|
||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogGetStatus();
|
||||
int PS4_SYSV_ABI sceErrorDialogInitialize(OrbisErrorDialogParam* param);
|
||||
int PS4_SYSV_ABI sceErrorDialogOpen(OrbisErrorDialogParam* param);
|
||||
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogClose();
|
||||
CommonDialog::Status PS4_SYSV_ABI sceErrorDialogGetStatus();
|
||||
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogInitialize();
|
||||
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogOpen(const Param* param);
|
||||
int PS4_SYSV_ABI sceErrorDialogOpenDetail();
|
||||
int PS4_SYSV_ABI sceErrorDialogOpenWithReport();
|
||||
int PS4_SYSV_ABI sceErrorDialogTerminate();
|
||||
OrbisErrorDialogStatus PS4_SYSV_ABI sceErrorDialogUpdateStatus();
|
||||
CommonDialog::Error PS4_SYSV_ABI sceErrorDialogTerminate();
|
||||
CommonDialog::Status PS4_SYSV_ABI sceErrorDialogUpdateStatus();
|
||||
|
||||
void RegisterlibSceErrorDialog(Core::Loader::SymbolsResolver* sym);
|
||||
} // namespace Libraries::ErrorDialog
|
Loading…
Add table
Reference in a new issue