mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-21 20:14:45 +00:00
system/MsgDialog: User message dialog
This commit is contained in:
parent
2e4eac3d19
commit
8c1a6fbb5e
2 changed files with 138 additions and 39 deletions
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include <imgui.h>
|
||||
#include <magic_enum.hpp>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
|
@ -10,11 +11,10 @@
|
|||
#include "core/libraries/system/msgdialog.h"
|
||||
#include "imgui/imgui_layer.h"
|
||||
#include "imgui/imgui_std.h"
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace Libraries::MsgDialog {
|
||||
|
||||
class MsgDialogGui;
|
||||
|
||||
using CommonDialog::Error;
|
||||
using CommonDialog::Result;
|
||||
using CommonDialog::Status;
|
||||
|
@ -102,26 +102,88 @@ struct Param {
|
|||
|
||||
struct MsgDialogResult {
|
||||
FixedValue<u32, 0> mode{};
|
||||
Result result{};
|
||||
ButtonId buttonId{};
|
||||
Result result{Result::OK};
|
||||
ButtonId buttonId{ButtonId::INVALID};
|
||||
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{};
|
||||
s32 dialog_unique_id{};
|
||||
|
||||
void DrawUser(const UserMessageParam& user_message_param) {
|
||||
const auto ws = ImGui::GetWindowSize();
|
||||
ImGui::SetCursorPosY(ws.y / 2.0f - 30.0f);
|
||||
ImGui::BeginGroup();
|
||||
ImGui::PushTextWrapPos(ws.x - 30.0f);
|
||||
ImGui::SetCursorPosX(
|
||||
(ws.x - ImGui::CalcTextSize(user_message_param.msg, nullptr, false, ws.x - 40.0f).x) /
|
||||
2.0f);
|
||||
ImGui::Text("%s", user_message_param.msg);
|
||||
ImGui::PopTextWrapPos();
|
||||
ImGui::EndGroup();
|
||||
switch (user_message_param.buttonType) {}
|
||||
constexpr ImVec2 BUTTON_SIZE{100.0f, 30.0f};
|
||||
|
||||
const auto ws = GetWindowSize();
|
||||
SetCursorPosY(ws.y / 2.0f - 50.0f);
|
||||
PushTextWrapPos(ws.x - 30.0f);
|
||||
SetCursorPosX(
|
||||
(ws.x - CalcTextSize(user_message_param.msg, nullptr, false, ws.x - 40.0f).x) / 2.0f);
|
||||
Text("%s", user_message_param.msg);
|
||||
PopTextWrapPos();
|
||||
const auto button_type = 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) {}
|
||||
|
@ -130,46 +192,67 @@ class MsgDialogGui final : public ImGui::Layer {
|
|||
|
||||
public:
|
||||
void Draw() override {
|
||||
const auto& io = ImGui::GetIO();
|
||||
if (g_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),
|
||||
};
|
||||
|
||||
ImGui::CentralizeWindow();
|
||||
ImGui::SetNextWindowSize(window_size);
|
||||
ImGui::Begin("##Message Dialog", nullptr, ImGuiWindowFlags_NoDecoration);
|
||||
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;
|
||||
CentralizeWindow();
|
||||
SetNextWindowSize(window_size);
|
||||
SetNextWindowFocus();
|
||||
SetNextWindowCollapsed(false);
|
||||
KeepNavHighlight();
|
||||
// Hack to allow every dialog to have a unique window
|
||||
#define TITLE "Message Dialog##MD"
|
||||
char id[sizeof(TITLE) + sizeof(int)] = TITLE "\0\0\0\0";
|
||||
*reinterpret_cast<int*>(&id[sizeof(TITLE) - 1]) =
|
||||
dialog_unique_id |
|
||||
0x80808080; // keep the MSB set to extend the string length (null terminated)
|
||||
#undef TITLE
|
||||
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 {
|
||||
return true;
|
||||
}
|
||||
|
||||
explicit MsgDialogGui(const Param* param = nullptr) : param(param) {}
|
||||
} static g_msg_dialog_gui;
|
||||
explicit MsgDialogGui(const Param* param = nullptr)
|
||||
: 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 MsgDialogResult g_result{};
|
||||
static void Finish(ButtonId buttonId) {
|
||||
g_result.buttonId = buttonId;
|
||||
g_status = Status::FINISHED;
|
||||
Layer::RemoveLayer(&g_msg_dialog_gui);
|
||||
}
|
||||
|
||||
Error PS4_SYSV_ABI sceMsgDialogClose() {
|
||||
if (g_status != Status::RUNNING) {
|
||||
return Error::NOT_RUNNING;
|
||||
}
|
||||
g_status = Status::FINISHED;
|
||||
ImGui::Layer::RemoveLayer(&g_msg_dialog_gui);
|
||||
Finish(ButtonId::INVALID);
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
|
@ -189,7 +272,7 @@ Error PS4_SYSV_ABI sceMsgDialogGetResult(MsgDialogResult* result) {
|
|||
return Error::OK;
|
||||
}
|
||||
|
||||
CommonDialog::Status PS4_SYSV_ABI sceMsgDialogGetStatus() {
|
||||
Status PS4_SYSV_ABI sceMsgDialogGetStatus() {
|
||||
return g_status;
|
||||
}
|
||||
|
||||
|
@ -216,8 +299,9 @@ Error PS4_SYSV_ABI sceMsgDialogOpen(const Param* param) {
|
|||
ASSERT(param->size == sizeof(Param));
|
||||
ASSERT(param->baseParam.size == sizeof(CommonDialog::BaseParam));
|
||||
g_status = Status::RUNNING;
|
||||
g_result = {};
|
||||
g_msg_dialog_gui = MsgDialogGui(param);
|
||||
ImGui::Layer::AddLayer(&g_msg_dialog_gui);
|
||||
Layer::AddLayer(&g_msg_dialog_gui);
|
||||
return Error::OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,10 +5,25 @@
|
|||
|
||||
#include <imgui.h>
|
||||
|
||||
#include "imgui_internal.h"
|
||||
|
||||
namespace ImGui {
|
||||
|
||||
inline void CentralizeWindow() {
|
||||
const auto display_size = GetIO().DisplaySize;
|
||||
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
|
||||
|
|
Loading…
Add table
Reference in a new issue