[App] Add notifications for hotkeys & XNotifyQueueUI
This commit is contained in:
parent
9c8a575b76
commit
1a9ff8fe67
|
@ -1606,6 +1606,9 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string notificationTitle = "";
|
||||||
|
std::string notificationDesc = "";
|
||||||
|
|
||||||
EmulatorWindow::ControllerHotKey button_combination = it->second;
|
EmulatorWindow::ControllerHotKey button_combination = it->second;
|
||||||
|
|
||||||
switch (button_combination.function) {
|
switch (button_combination.function) {
|
||||||
|
@ -1630,45 +1633,81 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
||||||
GpuClearCaches();
|
GpuClearCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
notificationTitle = "Toggle Clear Memory Page State";
|
||||||
|
notificationDesc =
|
||||||
|
cvars::clear_memory_page_state ? "Enabled" : "Disabled";
|
||||||
|
|
||||||
// Extra Sleep
|
// Extra Sleep
|
||||||
xe::threading::Sleep(delay);
|
xe::threading::Sleep(delay);
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::ReadbackResolve:
|
case ButtonFunctions::ReadbackResolve:
|
||||||
ToggleGPUSetting(gpu_cvar::ReadbackResolve);
|
ToggleGPUSetting(gpu_cvar::ReadbackResolve);
|
||||||
|
|
||||||
|
notificationTitle = "Toggle Readback Resolve";
|
||||||
|
notificationDesc = cvars::d3d12_readback_resolve ? "Enabled" : "Disabled";
|
||||||
|
|
||||||
// Extra Sleep
|
// Extra Sleep
|
||||||
xe::threading::Sleep(delay);
|
xe::threading::Sleep(delay);
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::CpuTimeScalarSetHalf:
|
case ButtonFunctions::CpuTimeScalarSetHalf:
|
||||||
CpuTimeScalarSetHalf();
|
CpuTimeScalarSetHalf();
|
||||||
|
|
||||||
|
notificationTitle = "Time Scalar";
|
||||||
|
notificationDesc =
|
||||||
|
fmt::format("Decreased to {}", Clock::guest_time_scalar());
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::CpuTimeScalarSetDouble:
|
case ButtonFunctions::CpuTimeScalarSetDouble:
|
||||||
CpuTimeScalarSetDouble();
|
CpuTimeScalarSetDouble();
|
||||||
|
|
||||||
|
notificationTitle = "Time Scalar";
|
||||||
|
notificationDesc =
|
||||||
|
fmt::format("Increased to {}", Clock::guest_time_scalar());
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::CpuTimeScalarReset:
|
case ButtonFunctions::CpuTimeScalarReset:
|
||||||
CpuTimeScalarReset();
|
CpuTimeScalarReset();
|
||||||
|
|
||||||
|
notificationTitle = "Time Scalar";
|
||||||
|
notificationDesc = fmt::format("Reset to {}", Clock::guest_time_scalar());
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::ClearGPUCache:
|
case ButtonFunctions::ClearGPUCache:
|
||||||
GpuClearCaches();
|
GpuClearCaches();
|
||||||
|
|
||||||
// Extra Sleep
|
notificationTitle = "Clear GPU Cache";
|
||||||
xe::threading::Sleep(delay);
|
notificationDesc = "Complete";
|
||||||
break;
|
|
||||||
case ButtonFunctions::ToggleControllerVibration:
|
|
||||||
ToggleControllerVibration();
|
|
||||||
|
|
||||||
// Extra Sleep
|
// Extra Sleep
|
||||||
xe::threading::Sleep(delay);
|
xe::threading::Sleep(delay);
|
||||||
break;
|
break;
|
||||||
|
case ButtonFunctions::ToggleControllerVibration: {
|
||||||
|
ToggleControllerVibration();
|
||||||
|
|
||||||
|
bool vibration = false;
|
||||||
|
|
||||||
|
auto input_sys = emulator()->input_system();
|
||||||
|
if (input_sys) {
|
||||||
|
vibration = input_sys->GetVibrationCvar();
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationTitle = "Toggle Controller Vibration";
|
||||||
|
notificationDesc = vibration ? "Enabled" : "Disabled";
|
||||||
|
|
||||||
|
// Extra Sleep
|
||||||
|
xe::threading::Sleep(delay);
|
||||||
|
} break;
|
||||||
case ButtonFunctions::IncTitleSelect:
|
case ButtonFunctions::IncTitleSelect:
|
||||||
selected_title_index++;
|
selected_title_index++;
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::DecTitleSelect:
|
case ButtonFunctions::DecTitleSelect:
|
||||||
selected_title_index--;
|
selected_title_index--;
|
||||||
break;
|
break;
|
||||||
case ButtonFunctions::ToggleLogging:
|
case ButtonFunctions::ToggleLogging: {
|
||||||
logging::internal::ToggleLogLevel();
|
logging::internal::ToggleLogLevel();
|
||||||
break;
|
|
||||||
|
notificationTitle = "Toggle Logging";
|
||||||
|
|
||||||
|
LogLevel level = static_cast<LogLevel>(logging::internal::GetLogLevel());
|
||||||
|
notificationDesc = level == LogLevel::Disabled ? "Disabled" : "Enabled";
|
||||||
|
} break;
|
||||||
case ButtonFunctions::Unknown:
|
case ButtonFunctions::Unknown:
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -1704,6 +1743,13 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey(
|
||||||
title);
|
title);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!notificationTitle.empty()) {
|
||||||
|
app_context_.CallInUIThread([&]() {
|
||||||
|
new xe::ui::HostNotificationWindow(imgui_drawer(), notificationTitle,
|
||||||
|
notificationDesc, 0);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
xe::threading::Sleep(delay);
|
xe::threading::Sleep(delay);
|
||||||
|
|
||||||
return it->second;
|
return it->second;
|
||||||
|
|
|
@ -482,6 +482,7 @@ bool logging::internal::ShouldLog(LogLevel log_level, uint32_t log_mask) {
|
||||||
return static_cast<int32_t>(log_level) <= cvars::log_level &&
|
return static_cast<int32_t>(log_level) <= cvars::log_level &&
|
||||||
(log_mask & cvars::log_mask) == 0;
|
(log_mask & cvars::log_mask) == 0;
|
||||||
}
|
}
|
||||||
|
uint32_t logging::internal::GetLogLevel() { return cvars::log_level; }
|
||||||
|
|
||||||
std::pair<char*, size_t> logging::internal::GetThreadBuffer() {
|
std::pair<char*, size_t> logging::internal::GetThreadBuffer() {
|
||||||
return {thread_log_buffer_, sizeof(thread_log_buffer_)};
|
return {thread_log_buffer_, sizeof(thread_log_buffer_)};
|
||||||
|
|
|
@ -86,6 +86,7 @@ void ToggleLogLevel();
|
||||||
|
|
||||||
bool ShouldLog(LogLevel log_level,
|
bool ShouldLog(LogLevel log_level,
|
||||||
uint32_t log_mask = xe::LogSrc::Uncategorized);
|
uint32_t log_mask = xe::LogSrc::Uncategorized);
|
||||||
|
uint32_t GetLogLevel();
|
||||||
std::pair<char*, size_t> GetThreadBuffer();
|
std::pair<char*, size_t> GetThreadBuffer();
|
||||||
XE_NOALIAS
|
XE_NOALIAS
|
||||||
void AppendLogLine(LogLevel log_level, const char prefix_char, size_t written);
|
void AppendLogLine(LogLevel log_level, const char prefix_char, size_t written);
|
||||||
|
|
|
@ -140,6 +140,8 @@ X_RESULT InputSystem::GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||||
return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED;
|
return any_connected ? X_ERROR_EMPTY : X_ERROR_DEVICE_NOT_CONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool InputSystem::GetVibrationCvar() { return cvars::vibration; }
|
||||||
|
|
||||||
void InputSystem::ToggleVibration() {
|
void InputSystem::ToggleVibration() {
|
||||||
OVERRIDE_bool(vibration, !cvars::vibration);
|
OVERRIDE_bool(vibration, !cvars::vibration);
|
||||||
// Send instant update to vibration state to prevent awaiting for next tick.
|
// Send instant update to vibration state to prevent awaiting for next tick.
|
||||||
|
|
|
@ -47,6 +47,8 @@ class InputSystem {
|
||||||
X_RESULT GetKeystroke(uint32_t user_index, uint32_t flags,
|
X_RESULT GetKeystroke(uint32_t user_index, uint32_t flags,
|
||||||
X_INPUT_KEYSTROKE* out_keystroke);
|
X_INPUT_KEYSTROKE* out_keystroke);
|
||||||
|
|
||||||
|
bool GetVibrationCvar();
|
||||||
|
|
||||||
void ToggleVibration();
|
void ToggleVibration();
|
||||||
|
|
||||||
const std::bitset<max_allowed_controllers> GetConnectedSlots() const {
|
const std::bitset<max_allowed_controllers> GetConnectedSlots() const {
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "xenia/kernel/xam/xam_private.h"
|
#include "xenia/kernel/xam/xam_private.h"
|
||||||
#include "xenia/ui/imgui_dialog.h"
|
#include "xenia/ui/imgui_dialog.h"
|
||||||
#include "xenia/ui/imgui_drawer.h"
|
#include "xenia/ui/imgui_drawer.h"
|
||||||
|
#include "xenia/ui/imgui_guest_notification.h"
|
||||||
#include "xenia/ui/window.h"
|
#include "xenia/ui/window.h"
|
||||||
#include "xenia/ui/windowed_app_context.h"
|
#include "xenia/ui/windowed_app_context.h"
|
||||||
#include "xenia/xbox.h"
|
#include "xenia/xbox.h"
|
||||||
|
@ -398,8 +399,8 @@ dword_result_t XNotifyQueueUI_entry(dword_t exnq, dword_t dwUserIndex,
|
||||||
qword_t qwAreas,
|
qword_t qwAreas,
|
||||||
lpu16string_t displayText_ptr,
|
lpu16string_t displayText_ptr,
|
||||||
lpvoid_t contextData) {
|
lpvoid_t contextData) {
|
||||||
std::string title_text = "XNotifyQueueUI";
|
|
||||||
std::string displayText = "";
|
std::string displayText = "";
|
||||||
|
const uint8_t position_id = static_cast<uint8_t>(qwAreas);
|
||||||
|
|
||||||
if (displayText_ptr) {
|
if (displayText_ptr) {
|
||||||
displayText = xe::to_utf8(displayText_ptr.value());
|
displayText = xe::to_utf8(displayText_ptr.value());
|
||||||
|
@ -407,23 +408,11 @@ dword_result_t XNotifyQueueUI_entry(dword_t exnq, dword_t dwUserIndex,
|
||||||
|
|
||||||
XELOGI("XNotifyQueueUI: {}", displayText);
|
XELOGI("XNotifyQueueUI: {}", displayText);
|
||||||
|
|
||||||
if (cvars::headless) {
|
|
||||||
return X_ERROR_SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto close = [](MessageBoxDialog* dialog) -> X_RESULT {
|
|
||||||
dialog->chosen_button();
|
|
||||||
return X_ERROR_SUCCESS;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<std::string> buttons(1, "OK");
|
|
||||||
|
|
||||||
const Emulator* emulator = kernel_state()->emulator();
|
const Emulator* emulator = kernel_state()->emulator();
|
||||||
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
|
ui::ImGuiDrawer* imgui_drawer = emulator->imgui_drawer();
|
||||||
|
|
||||||
xeXamDispatchDialog<MessageBoxDialog>(
|
new xe::ui::XNotifyWindow(imgui_drawer, "", displayText, dwUserIndex,
|
||||||
new MessageBoxDialog(imgui_drawer, title_text, displayText, buttons, 0),
|
position_id);
|
||||||
close, false);
|
|
||||||
|
|
||||||
// XNotifyQueueUI -> XNotifyQueueUIEx -> XMsgProcessRequest ->
|
// XNotifyQueueUI -> XNotifyQueueUIEx -> XMsgProcessRequest ->
|
||||||
// XMsgStartIORequestEx & XMsgInProcessCall
|
// XMsgStartIORequestEx & XMsgInProcessCall
|
||||||
|
|
|
@ -180,5 +180,82 @@ void AchievementNotificationWindow::OnDraw(ImGuiIO& io) {
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XNotifyWindow::OnDraw(ImGuiIO& io) {
|
||||||
|
UpdateNotificationState();
|
||||||
|
|
||||||
|
if (IsNotificationExpired()) {
|
||||||
|
delete this;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string longest_notification_text_line =
|
||||||
|
GetTitle().size() > GetDescription().size() ? GetTitle().c_str()
|
||||||
|
: GetDescription().c_str();
|
||||||
|
|
||||||
|
const ImVec2 screen_size = io.DisplaySize;
|
||||||
|
const float window_scale =
|
||||||
|
std::fminf(screen_size.x / default_drawing_resolution.x,
|
||||||
|
screen_size.y / default_drawing_resolution.y);
|
||||||
|
const float font_scale = default_font_size / io.Fonts->Fonts[0]->FontSize;
|
||||||
|
const ImVec2 text_size = io.Fonts->Fonts[0]->CalcTextSizeA(
|
||||||
|
default_font_size * default_notification_text_scale * window_scale,
|
||||||
|
FLT_MAX, -1.0f, longest_notification_text_line.c_str());
|
||||||
|
|
||||||
|
const ImVec2 final_notification_size =
|
||||||
|
CalculateNotificationSize(text_size, window_scale);
|
||||||
|
|
||||||
|
const ImVec2 notification_position = CalculateNotificationScreenPosition(
|
||||||
|
screen_size, final_notification_size, GetPositionId());
|
||||||
|
|
||||||
|
if (isnan(notification_position.x) || isnan(notification_position.y)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ImVec2 current_notification_size = final_notification_size;
|
||||||
|
current_notification_size.x *= notification_draw_progress_;
|
||||||
|
current_notification_size.x = std::floorf(current_notification_size.x);
|
||||||
|
|
||||||
|
// Initialize position and window size
|
||||||
|
ImGui::SetNextWindowSize(current_notification_size);
|
||||||
|
ImGui::SetNextWindowPos(notification_position);
|
||||||
|
|
||||||
|
// Set new window style before drawing window
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding,
|
||||||
|
default_notification_rounding * window_scale);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_WindowBg,
|
||||||
|
default_notification_background_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Separator,
|
||||||
|
default_notification_background_color);
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, default_notification_border_color);
|
||||||
|
|
||||||
|
ImGui::Begin("Notification Window", NULL, NOTIFY_TOAST_FLAGS);
|
||||||
|
{
|
||||||
|
ImGui::SetWindowFontScale(default_notification_text_scale * font_scale *
|
||||||
|
window_scale);
|
||||||
|
// Set offset to image to prevent it from being right on border.
|
||||||
|
ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.005f,
|
||||||
|
final_notification_size.y * 0.05f));
|
||||||
|
// Elements of window
|
||||||
|
ImGui::Image(reinterpret_cast<ImTextureID>(
|
||||||
|
GetDrawer()->GetNotificationIcon(GetUserIndex())),
|
||||||
|
ImVec2(default_notification_icon_size.x * window_scale,
|
||||||
|
default_notification_icon_size.y * window_scale));
|
||||||
|
|
||||||
|
// Set offset to image to prevent it from being right on border.
|
||||||
|
// ImGui::SetCursorPos(ImVec2(final_notification_size.x * 0.1f,
|
||||||
|
// final_notification_size.y * 0.2f));
|
||||||
|
|
||||||
|
ImGui::SameLine();
|
||||||
|
if (notification_draw_progress_ > 0.5f) {
|
||||||
|
ImGui::TextColored(white_color, GetDescription().c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Restore previous style
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
ImGui::PopStyleColor(3);
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
|
@ -76,6 +76,17 @@ class AchievementNotificationWindow final : ImGuiGuestNotification {
|
||||||
void OnDraw(ImGuiIO& io) override;
|
void OnDraw(ImGuiIO& io) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class XNotifyWindow final : ImGuiGuestNotification {
|
||||||
|
public:
|
||||||
|
XNotifyWindow(ui::ImGuiDrawer* imgui_drawer, std::string title,
|
||||||
|
std::string description, uint8_t user_index,
|
||||||
|
uint8_t position_id = 0)
|
||||||
|
: ImGuiGuestNotification(imgui_drawer, title, description, user_index,
|
||||||
|
position_id) {};
|
||||||
|
|
||||||
|
void OnDraw(ImGuiIO& io) override;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace ui
|
} // namespace ui
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue