summaryrefslogtreecommitdiffstats
path: root/src/yuzu/util/overlay_dialog.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/yuzu/util/overlay_dialog.cpp')
-rw-r--r--src/yuzu/util/overlay_dialog.cpp249
1 files changed, 249 insertions, 0 deletions
diff --git a/src/yuzu/util/overlay_dialog.cpp b/src/yuzu/util/overlay_dialog.cpp
new file mode 100644
index 000000000..95b148545
--- /dev/null
+++ b/src/yuzu/util/overlay_dialog.cpp
@@ -0,0 +1,249 @@
+// Copyright 2021 yuzu Emulator Project
+// Licensed under GPLv2 or any later version
+// Refer to the license.txt file included.
+
+#include <QKeyEvent>
+#include <QScreen>
+
+#include "core/core.h"
+#include "core/frontend/input_interpreter.h"
+#include "ui_overlay_dialog.h"
+#include "yuzu/util/overlay_dialog.h"
+
+namespace {
+
+constexpr float BASE_TITLE_FONT_SIZE = 14.0f;
+constexpr float BASE_FONT_SIZE = 18.0f;
+constexpr float BASE_WIDTH = 1280.0f;
+constexpr float BASE_HEIGHT = 720.0f;
+
+} // Anonymous namespace
+
+OverlayDialog::OverlayDialog(QWidget* parent, Core::System& system, const QString& title_text,
+ const QString& body_text, const QString& left_button_text,
+ const QString& right_button_text, Qt::Alignment alignment,
+ bool use_rich_text_)
+ : QDialog(parent), ui{std::make_unique<Ui::OverlayDialog>()}, use_rich_text{use_rich_text_} {
+ ui->setupUi(this);
+
+ setWindowFlags(Qt::Dialog | Qt::FramelessWindowHint | Qt::WindowTitleHint |
+ Qt::WindowSystemMenuHint | Qt::CustomizeWindowHint);
+ setWindowModality(Qt::WindowModal);
+ setAttribute(Qt::WA_TranslucentBackground);
+
+ if (use_rich_text) {
+ InitializeRichTextDialog(title_text, body_text, left_button_text, right_button_text,
+ alignment);
+ } else {
+ InitializeRegularTextDialog(title_text, body_text, left_button_text, right_button_text,
+ alignment);
+ }
+
+ MoveAndResizeWindow();
+
+ // TODO (Morph): Remove this when InputInterpreter no longer relies on the HID backend
+ if (system.IsPoweredOn()) {
+ input_interpreter = std::make_unique<InputInterpreter>(system);
+
+ StartInputThread();
+ }
+}
+
+OverlayDialog::~OverlayDialog() {
+ StopInputThread();
+}
+
+void OverlayDialog::InitializeRegularTextDialog(const QString& title_text, const QString& body_text,
+ const QString& left_button_text,
+ const QString& right_button_text,
+ Qt::Alignment alignment) {
+ ui->stackedDialog->setCurrentIndex(0);
+
+ ui->label_title->setText(title_text);
+ ui->label_dialog->setText(body_text);
+ ui->button_cancel->setText(left_button_text);
+ ui->button_ok_label->setText(right_button_text);
+
+ ui->label_dialog->setAlignment(alignment);
+
+ if (title_text.isEmpty()) {
+ ui->label_title->hide();
+ ui->verticalLayout_2->setStretch(0, 0);
+ ui->verticalLayout_2->setStretch(1, 219);
+ ui->verticalLayout_2->setStretch(2, 82);
+ }
+
+ if (left_button_text.isEmpty()) {
+ ui->button_cancel->hide();
+ ui->button_cancel->setEnabled(false);
+ }
+
+ if (right_button_text.isEmpty()) {
+ ui->button_ok_label->hide();
+ ui->button_ok_label->setEnabled(false);
+ }
+
+ connect(
+ ui->button_cancel, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::reject();
+ },
+ Qt::QueuedConnection);
+ connect(
+ ui->button_ok_label, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::accept();
+ },
+ Qt::QueuedConnection);
+}
+
+void OverlayDialog::InitializeRichTextDialog(const QString& title_text, const QString& body_text,
+ const QString& left_button_text,
+ const QString& right_button_text,
+ Qt::Alignment alignment) {
+ ui->stackedDialog->setCurrentIndex(1);
+
+ ui->label_title_rich->setText(title_text);
+ ui->text_browser_dialog->setText(body_text);
+ ui->button_cancel_rich->setText(left_button_text);
+ ui->button_ok_rich->setText(right_button_text);
+
+ // TODO (Morph/Rei): Replace this with something that works better
+ ui->text_browser_dialog->setAlignment(alignment);
+
+ if (title_text.isEmpty()) {
+ ui->label_title_rich->hide();
+ ui->verticalLayout_3->setStretch(0, 0);
+ ui->verticalLayout_3->setStretch(1, 438);
+ ui->verticalLayout_3->setStretch(2, 82);
+ }
+
+ if (left_button_text.isEmpty()) {
+ ui->button_cancel_rich->hide();
+ ui->button_cancel_rich->setEnabled(false);
+ }
+
+ if (right_button_text.isEmpty()) {
+ ui->button_ok_rich->hide();
+ ui->button_ok_rich->setEnabled(false);
+ }
+
+ connect(
+ ui->button_cancel_rich, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::reject();
+ },
+ Qt::QueuedConnection);
+ connect(
+ ui->button_ok_rich, &QPushButton::clicked, this,
+ [this](bool) {
+ StopInputThread();
+ QDialog::accept();
+ },
+ Qt::QueuedConnection);
+}
+
+void OverlayDialog::MoveAndResizeWindow() {
+ const auto pos = parentWidget()->mapToGlobal(parentWidget()->rect().topLeft());
+ const auto width = static_cast<float>(parentWidget()->width());
+ const auto height = static_cast<float>(parentWidget()->height());
+
+ // High DPI
+ const float dpi_scale = qApp->screenAt(pos)->logicalDotsPerInch() / 96.0f;
+
+ const auto title_text_font_size = BASE_TITLE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+ const auto body_text_font_size =
+ BASE_FONT_SIZE * (((width / BASE_WIDTH) + (height / BASE_HEIGHT)) / 2.0f) / dpi_scale;
+ const auto button_text_font_size = BASE_FONT_SIZE * (height / BASE_HEIGHT) / dpi_scale;
+
+ QFont title_text_font(QStringLiteral("MS Shell Dlg 2"), title_text_font_size, QFont::Normal);
+ QFont body_text_font(QStringLiteral("MS Shell Dlg 2"), body_text_font_size, QFont::Normal);
+ QFont button_text_font(QStringLiteral("MS Shell Dlg 2"), button_text_font_size, QFont::Normal);
+
+ if (use_rich_text) {
+ ui->label_title_rich->setFont(title_text_font);
+ ui->text_browser_dialog->setFont(body_text_font);
+ ui->button_cancel_rich->setFont(button_text_font);
+ ui->button_ok_rich->setFont(button_text_font);
+ } else {
+ ui->label_title->setFont(title_text_font);
+ ui->label_dialog->setFont(body_text_font);
+ ui->button_cancel->setFont(button_text_font);
+ ui->button_ok_label->setFont(button_text_font);
+ }
+
+ QDialog::move(pos);
+ QDialog::resize(width, height);
+}
+
+template <HIDButton... T>
+void OverlayDialog::HandleButtonPressedOnce() {
+ const auto f = [this](HIDButton button) {
+ if (input_interpreter->IsButtonPressedOnce(button)) {
+ TranslateButtonPress(button);
+ }
+ };
+
+ (f(T), ...);
+}
+
+void OverlayDialog::TranslateButtonPress(HIDButton button) {
+ QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
+ QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
+
+ // TODO (Morph): Handle QTextBrowser text scrolling
+ // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
+
+ switch (button) {
+ case HIDButton::A:
+ case HIDButton::B:
+ if (left_button->hasFocus()) {
+ left_button->click();
+ } else if (right_button->hasFocus()) {
+ right_button->click();
+ }
+ break;
+ case HIDButton::DLeft:
+ case HIDButton::LStickLeft:
+ focusPreviousChild();
+ break;
+ case HIDButton::DRight:
+ case HIDButton::LStickRight:
+ focusNextChild();
+ break;
+ default:
+ break;
+ }
+}
+
+void OverlayDialog::StartInputThread() {
+ if (input_thread_running) {
+ return;
+ }
+
+ input_thread_running = true;
+
+ input_thread = std::thread(&OverlayDialog::InputThread, this);
+}
+
+void OverlayDialog::StopInputThread() {
+ input_thread_running = false;
+
+ if (input_thread.joinable()) {
+ input_thread.join();
+ }
+}
+
+void OverlayDialog::InputThread() {
+ while (input_thread_running) {
+ input_interpreter->PollInput();
+
+ HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight,
+ HIDButton::LStickLeft, HIDButton::LStickRight>();
+
+ std::this_thread::sleep_for(std::chrono::milliseconds(50));
+ }
+}