mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-08-02 23:42:43 +00:00
system/MsgDialog: User message dialog
This commit is contained in:
parent
2e4eac3d19
commit
8c1a6fbb5e
@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <magic_enum.hpp>
|
#include <magic_enum.hpp>
|
||||||
|
|
||||||
#include "common/assert.h"
|
#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"
|
||||||
@ -10,11 +11,10 @@
|
|||||||
#include "core/libraries/system/msgdialog.h"
|
#include "core/libraries/system/msgdialog.h"
|
||||||
#include "imgui/imgui_layer.h"
|
#include "imgui/imgui_layer.h"
|
||||||
#include "imgui/imgui_std.h"
|
#include "imgui/imgui_std.h"
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
namespace Libraries::MsgDialog {
|
namespace Libraries::MsgDialog {
|
||||||
|
|
||||||
class MsgDialogGui;
|
|
||||||
|
|
||||||
using CommonDialog::Error;
|
using CommonDialog::Error;
|
||||||
using CommonDialog::Result;
|
using CommonDialog::Result;
|
||||||
using CommonDialog::Status;
|
using CommonDialog::Status;
|
||||||
@ -102,26 +102,88 @@ struct Param {
|
|||||||
|
|
||||||
struct MsgDialogResult {
|
struct MsgDialogResult {
|
||||||
FixedValue<u32, 0> mode{};
|
FixedValue<u32, 0> mode{};
|
||||||
Result result{};
|
Result result{Result::OK};
|
||||||
ButtonId buttonId{};
|
ButtonId buttonId{ButtonId::INVALID};
|
||||||
std::array<char, 32> reserved{};
|
std::array<char, 32> reserved{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class MsgDialogGui final : public ImGui::Layer {
|
static auto g_status = Status::NONE;
|
||||||
|
static MsgDialogResult g_result{};
|
||||||
|
|
||||||
|
struct {
|
||||||
|
int count = 0;
|
||||||
|
const char* text1;
|
||||||
|
const char* text2;
|
||||||
|
} static constexpr button_texts[] = {
|
||||||
|
{1, "OK"}, // 0 OK
|
||||||
|
{2, "Yes", "No"}, // 1 YESNO
|
||||||
|
{0}, // 2 NONE
|
||||||
|
{2, "OK", "Cancel"}, // 3 OK_CANCEL
|
||||||
|
{}, // 4 !!NOP
|
||||||
|
{1, "Wait"}, // 5 WAIT
|
||||||
|
{2, "Wait", "Cancel"}, // 6 WAIT_CANCEL
|
||||||
|
{2, "Yes", "No"}, // 7 YESNO_FOCUS_NO
|
||||||
|
{2, "OK", "Cancel"}, // 8 OK_CANCEL_FOCUS_CANCEL
|
||||||
|
{0xFF}, // 9 TWO_BUTTONS
|
||||||
|
};
|
||||||
|
static_assert(std::size(button_texts) == static_cast<int>(ButtonType::TWO_BUTTONS) + 1);
|
||||||
|
|
||||||
|
static void Finish(ButtonId buttonId);
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
using namespace ImGui;
|
||||||
|
class MsgDialogGui final : public Layer {
|
||||||
const Param* param{};
|
const Param* param{};
|
||||||
|
s32 dialog_unique_id{};
|
||||||
|
|
||||||
void DrawUser(const UserMessageParam& user_message_param) {
|
void DrawUser(const UserMessageParam& user_message_param) {
|
||||||
const auto ws = ImGui::GetWindowSize();
|
constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||||
ImGui::SetCursorPosY(ws.y / 2.0f - 30.0f);
|
|
||||||
ImGui::BeginGroup();
|
const auto ws = GetWindowSize();
|
||||||
ImGui::PushTextWrapPos(ws.x - 30.0f);
|
SetCursorPosY(ws.y / 2.0f - 50.0f);
|
||||||
ImGui::SetCursorPosX(
|
PushTextWrapPos(ws.x - 30.0f);
|
||||||
(ws.x - ImGui::CalcTextSize(user_message_param.msg, nullptr, false, ws.x - 40.0f).x) /
|
SetCursorPosX(
|
||||||
2.0f);
|
(ws.x - CalcTextSize(user_message_param.msg, nullptr, false, ws.x - 40.0f).x) / 2.0f);
|
||||||
ImGui::Text("%s", user_message_param.msg);
|
Text("%s", user_message_param.msg);
|
||||||
ImGui::PopTextWrapPos();
|
PopTextWrapPos();
|
||||||
ImGui::EndGroup();
|
const auto button_type = user_message_param.buttonType;
|
||||||
switch (user_message_param.buttonType) {}
|
ASSERT(user_message_param.buttonType <= ButtonType::TWO_BUTTONS);
|
||||||
|
auto [count, text1, text2] = button_texts[static_cast<u32>(button_type)];
|
||||||
|
if (count == 0xFF) { // TWO_BUTTONS -> User defined message
|
||||||
|
count = 2;
|
||||||
|
text1 = user_message_param.buttonsParam->msg1;
|
||||||
|
text2 = user_message_param.buttonsParam->msg2;
|
||||||
|
}
|
||||||
|
const bool focus_first = button_type < ButtonType::YESNO_FOCUS_NO;
|
||||||
|
SetCursorPos({
|
||||||
|
ws.x / 2.0f - BUTTON_SIZE.x / 2.0f * static_cast<float>(count),
|
||||||
|
ws.y - 10.0f - BUTTON_SIZE.y,
|
||||||
|
});
|
||||||
|
BeginGroup();
|
||||||
|
if (count > 0) {
|
||||||
|
// First button at the right, so we render the second button first
|
||||||
|
if (count == 2) {
|
||||||
|
PushID(2);
|
||||||
|
if (Button(text2, BUTTON_SIZE)) {
|
||||||
|
Finish(ButtonId::BUTTON2);
|
||||||
|
}
|
||||||
|
if (!focus_first) {
|
||||||
|
SetItemDefaultNav();
|
||||||
|
}
|
||||||
|
PopID();
|
||||||
|
SameLine();
|
||||||
|
}
|
||||||
|
PushID(1);
|
||||||
|
if (Button(text1, BUTTON_SIZE)) {
|
||||||
|
Finish(ButtonId::BUTTON1);
|
||||||
|
}
|
||||||
|
if (focus_first) {
|
||||||
|
SetItemDefaultNav();
|
||||||
|
}
|
||||||
|
PopID();
|
||||||
|
SameLine();
|
||||||
|
}
|
||||||
|
EndGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawProgressBar(const ProgressBarParam& progress_bar_param) {}
|
void DrawProgressBar(const ProgressBarParam& progress_bar_param) {}
|
||||||
@ -130,46 +192,67 @@ class MsgDialogGui final : public ImGui::Layer {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
void Draw() override {
|
void Draw() override {
|
||||||
const auto& io = ImGui::GetIO();
|
if (g_status != Status::RUNNING) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const auto& io = GetIO();
|
||||||
|
|
||||||
const ImVec2 window_size{
|
const ImVec2 window_size{
|
||||||
std::min(io.DisplaySize.x, 500.0f),
|
std::min(io.DisplaySize.x, 500.0f),
|
||||||
std::min(io.DisplaySize.y, 300.0f),
|
std::min(io.DisplaySize.y, 300.0f),
|
||||||
};
|
};
|
||||||
|
|
||||||
ImGui::CentralizeWindow();
|
CentralizeWindow();
|
||||||
ImGui::SetNextWindowSize(window_size);
|
SetNextWindowSize(window_size);
|
||||||
ImGui::Begin("##Message Dialog", nullptr, ImGuiWindowFlags_NoDecoration);
|
SetNextWindowFocus();
|
||||||
switch (param->mode) {
|
SetNextWindowCollapsed(false);
|
||||||
case MsgDialogMode::USER_MSG:
|
KeepNavHighlight();
|
||||||
DrawUser(*param->userMsgParam);
|
// Hack to allow every dialog to have a unique window
|
||||||
break;
|
#define TITLE "Message Dialog##MD"
|
||||||
case MsgDialogMode::PROGRESS_BAR:
|
char id[sizeof(TITLE) + sizeof(int)] = TITLE "\0\0\0\0";
|
||||||
DrawProgressBar(*param->progBarParam);
|
*reinterpret_cast<int*>(&id[sizeof(TITLE) - 1]) =
|
||||||
break;
|
dialog_unique_id |
|
||||||
case MsgDialogMode::SYSTEM_MSG:
|
0x80808080; // keep the MSB set to extend the string length (null terminated)
|
||||||
DrawSystemMessage(*param->sysMsgParam);
|
#undef TITLE
|
||||||
break;
|
if (Begin(id, nullptr, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings)) {
|
||||||
|
switch (param->mode) {
|
||||||
|
case MsgDialogMode::USER_MSG:
|
||||||
|
DrawUser(*param->userMsgParam);
|
||||||
|
break;
|
||||||
|
case MsgDialogMode::PROGRESS_BAR:
|
||||||
|
DrawProgressBar(*param->progBarParam);
|
||||||
|
break;
|
||||||
|
case MsgDialogMode::SYSTEM_MSG:
|
||||||
|
DrawSystemMessage(*param->sysMsgParam);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
End();
|
||||||
}
|
}
|
||||||
ImGui::End();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShouldGrabGamepad() override {
|
bool ShouldGrabGamepad() override {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit MsgDialogGui(const Param* param = nullptr) : param(param) {}
|
explicit MsgDialogGui(const Param* param = nullptr)
|
||||||
} static g_msg_dialog_gui;
|
: param(param), dialog_unique_id([] {
|
||||||
|
static s32 last_id = 0;
|
||||||
|
return last_id++;
|
||||||
|
}()) {}
|
||||||
|
} g_msg_dialog_gui;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
static auto g_status = Status::NONE;
|
static void Finish(ButtonId buttonId) {
|
||||||
static MsgDialogResult g_result{};
|
g_result.buttonId = buttonId;
|
||||||
|
g_status = Status::FINISHED;
|
||||||
|
Layer::RemoveLayer(&g_msg_dialog_gui);
|
||||||
|
}
|
||||||
|
|
||||||
Error PS4_SYSV_ABI sceMsgDialogClose() {
|
Error PS4_SYSV_ABI sceMsgDialogClose() {
|
||||||
if (g_status != Status::RUNNING) {
|
if (g_status != Status::RUNNING) {
|
||||||
return Error::NOT_RUNNING;
|
return Error::NOT_RUNNING;
|
||||||
}
|
}
|
||||||
g_status = Status::FINISHED;
|
Finish(ButtonId::INVALID);
|
||||||
ImGui::Layer::RemoveLayer(&g_msg_dialog_gui);
|
|
||||||
return Error::OK;
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +272,7 @@ Error PS4_SYSV_ABI sceMsgDialogGetResult(MsgDialogResult* result) {
|
|||||||
return Error::OK;
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
CommonDialog::Status PS4_SYSV_ABI sceMsgDialogGetStatus() {
|
Status PS4_SYSV_ABI sceMsgDialogGetStatus() {
|
||||||
return g_status;
|
return g_status;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,8 +299,9 @@ Error PS4_SYSV_ABI sceMsgDialogOpen(const Param* param) {
|
|||||||
ASSERT(param->size == sizeof(Param));
|
ASSERT(param->size == sizeof(Param));
|
||||||
ASSERT(param->baseParam.size == sizeof(CommonDialog::BaseParam));
|
ASSERT(param->baseParam.size == sizeof(CommonDialog::BaseParam));
|
||||||
g_status = Status::RUNNING;
|
g_status = Status::RUNNING;
|
||||||
|
g_result = {};
|
||||||
g_msg_dialog_gui = MsgDialogGui(param);
|
g_msg_dialog_gui = MsgDialogGui(param);
|
||||||
ImGui::Layer::AddLayer(&g_msg_dialog_gui);
|
Layer::AddLayer(&g_msg_dialog_gui);
|
||||||
return Error::OK;
|
return Error::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,10 +5,25 @@
|
|||||||
|
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include "imgui_internal.h"
|
||||||
|
|
||||||
namespace ImGui {
|
namespace ImGui {
|
||||||
|
|
||||||
inline void CentralizeWindow() {
|
inline void CentralizeWindow() {
|
||||||
const auto display_size = GetIO().DisplaySize;
|
const auto display_size = GetIO().DisplaySize;
|
||||||
SetNextWindowPos(display_size / 2.0f, ImGuiCond_Always, {0.5f});
|
SetNextWindowPos(display_size / 2.0f, ImGuiCond_Always, {0.5f});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void KeepNavHighlight() {
|
||||||
|
GetCurrentContext()->NavDisableHighlight = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void SetItemDefaultNav() {
|
||||||
|
if (IsWindowAppearing()) {
|
||||||
|
const auto ctx = GetCurrentContext();
|
||||||
|
SetFocusID(ctx->LastItemData.ID, ctx->CurrentWindow);
|
||||||
|
ctx->NavInitResult.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ImGui
|
} // namespace ImGui
|
||||||
|
Loading…
Reference in New Issue
Block a user