diff --git a/Source/Core/DolphinQt/CMakeLists.txt b/Source/Core/DolphinQt/CMakeLists.txt
index 8ff38fe645..ebd6aa738f 100644
--- a/Source/Core/DolphinQt/CMakeLists.txt
+++ b/Source/Core/DolphinQt/CMakeLists.txt
@@ -63,7 +63,7 @@ add_executable(dolphin-emu
Config/Mapping/MappingCommon.cpp
Config/Mapping/MappingIndicator.cpp
Config/Mapping/MappingNumeric.cpp
- Config/Mapping/MappingRadio.cpp
+ Config/Mapping/MappingRadio.cpp
Config/Mapping/MappingWidget.cpp
Config/Mapping/MappingWindow.cpp
Config/Mapping/WiimoteEmuExtension.cpp
@@ -113,7 +113,7 @@ add_executable(dolphin-emu
Settings/USBDeviceAddToWhitelistDialog.cpp
TAS/GCTASInputWindow.cpp
TAS/WiiTASInputWindow.cpp
- TAS/Shared.cpp
+ TAS/TASInputWindow.cpp
TAS/StickWidget.cpp
TAS/IRWidget.cpp
Updater.cpp
diff --git a/Source/Core/DolphinQt/DolphinQt.vcxproj b/Source/Core/DolphinQt/DolphinQt.vcxproj
index b87180eb2d..a1ddc418e9 100644
--- a/Source/Core/DolphinQt/DolphinQt.vcxproj
+++ b/Source/Core/DolphinQt/DolphinQt.vcxproj
@@ -110,6 +110,7 @@
+
@@ -246,6 +247,7 @@
+
@@ -318,9 +320,9 @@
+
-
@@ -377,7 +379,6 @@
-
diff --git a/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp b/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp
index b2a3d20fbf..eb23072faf 100644
--- a/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp
+++ b/Source/Core/DolphinQt/TAS/GCTASInputWindow.cpp
@@ -12,35 +12,32 @@
#include "Common/CommonTypes.h"
-#include "DolphinQt/TAS/Shared.h"
-
#include "InputCommon/GCPadStatus.h"
-GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : QDialog(parent)
+GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : TASInputWindow(parent)
{
setWindowTitle(tr("GameCube TAS Input %1").arg(num + 1));
- setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
- auto* main_stick_box = CreateStickInputs(this, tr("Main Stick"), m_x_main_stick_value,
- m_y_main_stick_value, 255, 255, Qt::Key_F, Qt::Key_G);
- auto* c_stick_box = CreateStickInputs(this, tr("C Stick"), m_x_c_stick_value, m_y_c_stick_value,
- 255, 255, Qt::Key_H, Qt::Key_J);
+ m_main_stick_box = CreateStickInputs(tr("Main Stick"), m_x_main_stick_value, m_y_main_stick_value,
+ 255, 255, Qt::Key_F, Qt::Key_G);
+ m_c_stick_box = CreateStickInputs(tr("C Stick"), m_x_c_stick_value, m_y_c_stick_value, 255, 255,
+ Qt::Key_H, Qt::Key_J);
auto* top_layout = new QHBoxLayout;
- top_layout->addWidget(main_stick_box);
- top_layout->addWidget(c_stick_box);
+ top_layout->addWidget(m_main_stick_box);
+ top_layout->addWidget(m_c_stick_box);
- auto* triggers_box = new QGroupBox(tr("Triggers"));
+ m_triggers_box = new QGroupBox(tr("Triggers"));
- auto* l_trigger_layout = CreateSliderValuePairLayout(this, tr("Left"), m_l_trigger_value, 255,
- Qt::Key_N, triggers_box);
- auto* r_trigger_layout = CreateSliderValuePairLayout(this, tr("Right"), m_r_trigger_value, 255,
- Qt::Key_M, triggers_box);
+ auto* l_trigger_layout =
+ CreateSliderValuePairLayout(tr("Left"), m_l_trigger_value, 255, Qt::Key_N, m_triggers_box);
+ auto* r_trigger_layout =
+ CreateSliderValuePairLayout(tr("Right"), m_r_trigger_value, 255, Qt::Key_M, m_triggers_box);
auto* triggers_layout = new QVBoxLayout;
triggers_layout->addLayout(l_trigger_layout);
triggers_layout->addLayout(r_trigger_layout);
- triggers_box->setLayout(triggers_layout);
+ m_triggers_box->setLayout(triggers_layout);
m_a_button = new QCheckBox(QStringLiteral("&A"));
m_b_button = new QCheckBox(QStringLiteral("&B"));
@@ -76,42 +73,35 @@ GCTASInputWindow::GCTASInputWindow(QWidget* parent, int num) : QDialog(parent)
buttons_layout->addLayout(buttons_layout1);
buttons_layout->addLayout(buttons_layout2);
- auto* buttons_box = new QGroupBox(tr("Buttons"));
- buttons_box->setLayout(buttons_layout);
+ m_buttons_box = new QGroupBox(tr("Buttons"));
+ m_buttons_box->setLayout(buttons_layout);
auto* layout = new QVBoxLayout;
layout->addLayout(top_layout);
- layout->addWidget(triggers_box);
- layout->addWidget(buttons_box);
+ layout->addWidget(m_triggers_box);
+ layout->addWidget(m_buttons_box);
+ layout->addWidget(m_use_controller);
setLayout(layout);
}
-static void SetButton(QCheckBox* button, GCPadStatus* pad, u16 mask)
-{
- if (button->isChecked())
- pad->button |= mask;
- else
- pad->button &= ~mask;
-}
-
void GCTASInputWindow::GetValues(GCPadStatus* pad)
{
if (!isVisible())
return;
- SetButton(m_a_button, pad, PAD_BUTTON_A);
- SetButton(m_b_button, pad, PAD_BUTTON_B);
- SetButton(m_x_button, pad, PAD_BUTTON_X);
- SetButton(m_y_button, pad, PAD_BUTTON_Y);
- SetButton(m_z_button, pad, PAD_TRIGGER_Z);
- SetButton(m_l_button, pad, PAD_TRIGGER_L);
- SetButton(m_r_button, pad, PAD_TRIGGER_R);
- SetButton(m_left_button, pad, PAD_BUTTON_LEFT);
- SetButton(m_up_button, pad, PAD_BUTTON_UP);
- SetButton(m_down_button, pad, PAD_BUTTON_DOWN);
- SetButton(m_right_button, pad, PAD_BUTTON_RIGHT);
- SetButton(m_start_button, pad, PAD_BUTTON_START);
+ GetButton(m_a_button, pad->button, PAD_BUTTON_A);
+ GetButton(m_b_button, pad->button, PAD_BUTTON_B);
+ GetButton(m_x_button, pad->button, PAD_BUTTON_X);
+ GetButton(m_y_button, pad->button, PAD_BUTTON_Y);
+ GetButton(m_z_button, pad->button, PAD_TRIGGER_Z);
+ GetButton(m_l_button, pad->button, PAD_TRIGGER_L);
+ GetButton(m_r_button, pad->button, PAD_TRIGGER_R);
+ GetButton(m_left_button, pad->button, PAD_BUTTON_LEFT);
+ GetButton(m_up_button, pad->button, PAD_BUTTON_UP);
+ GetButton(m_down_button, pad->button, PAD_BUTTON_DOWN);
+ GetButton(m_right_button, pad->button, PAD_BUTTON_RIGHT);
+ GetButton(m_start_button, pad->button, PAD_BUTTON_START);
if (m_a_button->isChecked())
pad->analogA = 0xFF;
@@ -123,11 +113,12 @@ void GCTASInputWindow::GetValues(GCPadStatus* pad)
else
pad->analogB = 0x00;
- pad->triggerLeft = m_l_trigger_value->value();
- pad->triggerRight = m_r_trigger_value->value();
+ GetSpinBoxU8(m_l_trigger_value, pad->triggerLeft);
+ GetSpinBoxU8(m_r_trigger_value, pad->triggerRight);
- pad->stickX = m_x_main_stick_value->value();
- pad->stickY = m_y_main_stick_value->value();
- pad->substickX = m_x_c_stick_value->value();
- pad->substickY = m_y_c_stick_value->value();
+ GetSpinBoxU8(m_x_main_stick_value, pad->stickX);
+ GetSpinBoxU8(m_y_main_stick_value, pad->stickY);
+
+ GetSpinBoxU8(m_x_c_stick_value, pad->substickX);
+ GetSpinBoxU8(m_y_c_stick_value, pad->substickY);
}
diff --git a/Source/Core/DolphinQt/TAS/GCTASInputWindow.h b/Source/Core/DolphinQt/TAS/GCTASInputWindow.h
index 1269145352..a75a4a76d9 100644
--- a/Source/Core/DolphinQt/TAS/GCTASInputWindow.h
+++ b/Source/Core/DolphinQt/TAS/GCTASInputWindow.h
@@ -4,15 +4,14 @@
#pragma once
-#include
-
-#include "Common/CommonTypes.h"
+#include "DolphinQt/TAS/TASInputWindow.h"
class QCheckBox;
+class QGroupBox;
class QSpinBox;
struct GCPadStatus;
-class GCTASInputWindow : public QDialog
+class GCTASInputWindow : public TASInputWindow
{
Q_OBJECT
public:
@@ -38,4 +37,8 @@ private:
QSpinBox* m_y_main_stick_value;
QSpinBox* m_x_c_stick_value;
QSpinBox* m_y_c_stick_value;
+ QGroupBox* m_main_stick_box;
+ QGroupBox* m_c_stick_box;
+ QGroupBox* m_triggers_box;
+ QGroupBox* m_buttons_box;
};
diff --git a/Source/Core/DolphinQt/TAS/Shared.cpp b/Source/Core/DolphinQt/TAS/Shared.cpp
deleted file mode 100644
index 91679f121f..0000000000
--- a/Source/Core/DolphinQt/TAS/Shared.cpp
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2018 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#include "DolphinQt/TAS/Shared.h"
-
-#include
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "Common/CommonTypes.h"
-
-#include "DolphinQt/QtUtils/AspectRatioWidget.h"
-#include "DolphinQt/TAS/StickWidget.h"
-
-#include "InputCommon/GCPadStatus.h"
-
-QGroupBox* CreateStickInputs(QDialog* window, QString name, QSpinBox*& x_value, QSpinBox*& y_value,
- u16 max_x, u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key)
-{
- const QKeySequence x_shortcut_key_sequence = QKeySequence(Qt::ALT + x_shortcut_key);
- const QKeySequence y_shortcut_key_sequence = QKeySequence(Qt::ALT + y_shortcut_key);
-
- auto* box =
- new QGroupBox(QStringLiteral("%1 (%2/%3)")
- .arg(name, x_shortcut_key_sequence.toString(QKeySequence::NativeText),
- y_shortcut_key_sequence.toString(QKeySequence::NativeText)));
-
- auto* x_layout = new QHBoxLayout;
- x_value =
- CreateSliderValuePair(window, x_layout, max_x, x_shortcut_key_sequence, Qt::Horizontal, box);
-
- auto* y_layout = new QVBoxLayout;
- y_value =
- CreateSliderValuePair(window, y_layout, max_y, y_shortcut_key_sequence, Qt::Vertical, box);
- y_value->setMaximumWidth(60);
-
- auto* visual = new StickWidget(window, max_x, max_y);
- window->connect(x_value, static_cast(&QSpinBox::valueChanged), visual,
- &StickWidget::SetX);
- window->connect(y_value, static_cast(&QSpinBox::valueChanged), visual,
- &StickWidget::SetY);
- window->connect(visual, &StickWidget::ChangedX, x_value, &QSpinBox::setValue);
- window->connect(visual, &StickWidget::ChangedY, y_value, &QSpinBox::setValue);
-
- x_value->setValue(static_cast(std::round(max_x / 2.)));
- y_value->setValue(static_cast(std::round(max_y / 2.)));
-
- auto* visual_ar = new AspectRatioWidget(visual, max_x, max_y);
-
- auto* visual_layout = new QHBoxLayout;
- visual_layout->addWidget(visual_ar);
- visual_layout->addLayout(y_layout);
-
- auto* layout = new QVBoxLayout;
- layout->addLayout(x_layout);
- layout->addLayout(visual_layout);
- box->setLayout(layout);
-
- return box;
-}
-
-QBoxLayout* CreateSliderValuePairLayout(QDialog* window, QString name, QSpinBox*& value, u16 max,
- Qt::Key shortcut_key, QWidget* shortcut_widget, bool invert)
-{
- const QKeySequence shortcut_key_sequence = QKeySequence(Qt::ALT + shortcut_key);
-
- auto* label = new QLabel(QStringLiteral("%1 (%2)").arg(
- name, shortcut_key_sequence.toString(QKeySequence::NativeText)));
-
- QBoxLayout* layout = new QHBoxLayout;
- layout->addWidget(label);
-
- value = CreateSliderValuePair(window, layout, max, shortcut_key_sequence, Qt::Horizontal,
- shortcut_widget, invert);
-
- return layout;
-}
-
-// The shortcut_widget argument needs to specify the container widget that will be hidden/shown.
-// This is done to avoid ambigous shortcuts
-QSpinBox* CreateSliderValuePair(QDialog* window, QBoxLayout* layout, u16 max,
- QKeySequence shortcut_key_sequence, Qt::Orientation orientation,
- QWidget* shortcut_widget, bool invert)
-{
- auto* value = new QSpinBox();
- value->setRange(0, 99999);
- window->connect(value, static_cast(&QSpinBox::valueChanged),
- [value, max](int i) {
- if (i > max)
- value->setValue(max);
- });
- auto* slider = new QSlider(orientation);
- slider->setRange(0, max);
- slider->setFocusPolicy(Qt::ClickFocus);
- slider->setInvertedAppearance(invert);
-
- window->connect(slider, &QSlider::valueChanged, value, &QSpinBox::setValue);
- window->connect(value, static_cast(&QSpinBox::valueChanged), slider,
- &QSlider::setValue);
-
- auto* shortcut = new QShortcut(shortcut_key_sequence, shortcut_widget);
- window->connect(shortcut, &QShortcut::activated, [value] {
- value->setFocus();
- value->selectAll();
- });
-
- layout->addWidget(slider);
- layout->addWidget(value);
- if (orientation == Qt::Vertical)
- layout->setAlignment(slider, Qt::AlignRight);
-
- return value;
-}
diff --git a/Source/Core/DolphinQt/TAS/Shared.h b/Source/Core/DolphinQt/TAS/Shared.h
deleted file mode 100644
index ae0f3abad4..0000000000
--- a/Source/Core/DolphinQt/TAS/Shared.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018 Dolphin Emulator Project
-// Licensed under GPLv2+
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include
-
-#include "Common/CommonTypes.h"
-
-struct GCPadStatus;
-class QDialog;
-class QString;
-class QSpinBox;
-class QCheckBox;
-class QBoxLayout;
-class QGroupBox;
-
-QGroupBox* CreateStickInputs(QDialog* window, QString name, QSpinBox*& x_value, QSpinBox*& y_value,
- u16 max_x, u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key);
-QBoxLayout* CreateSliderValuePairLayout(QDialog* window, QString name, QSpinBox*& value, u16 max,
- Qt::Key shortcut_key, QWidget* shortcut_widget,
- bool invert = false);
-QSpinBox* CreateSliderValuePair(QDialog* window, QBoxLayout* layout, u16 max,
- QKeySequence shortcut_key_sequence, Qt::Orientation orientation,
- QWidget* shortcut_widget, bool invert = false);
diff --git a/Source/Core/DolphinQt/TAS/TASInputWindow.cpp b/Source/Core/DolphinQt/TAS/TASInputWindow.cpp
new file mode 100644
index 0000000000..e87f358889
--- /dev/null
+++ b/Source/Core/DolphinQt/TAS/TASInputWindow.cpp
@@ -0,0 +1,192 @@
+// Copyright 2018 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "Common/CommonTypes.h"
+
+#include "DolphinQt/QtUtils/AspectRatioWidget.h"
+#include "DolphinQt/QtUtils/QueueOnObject.h"
+#include "DolphinQt/TAS/StickWidget.h"
+#include "DolphinQt/TAS/TASInputWindow.h"
+
+#include "InputCommon/GCPadStatus.h"
+
+TASInputWindow::TASInputWindow(QWidget* parent) : QDialog(parent)
+{
+ setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
+ m_use_controller = new QCheckBox(QStringLiteral("Enable Controller Inpu&t"));
+ m_use_controller->setToolTip(tr("Warning: Analog inputs may reset to controller values at "
+ "random. In some cases this can be fixed by adding a deadzone."));
+}
+
+QGroupBox* TASInputWindow::CreateStickInputs(QString name, QSpinBox*& x_value, QSpinBox*& y_value,
+ u16 max_x, u16 max_y, Qt::Key x_shortcut_key,
+ Qt::Key y_shortcut_key)
+{
+ const QKeySequence x_shortcut_key_sequence = QKeySequence(Qt::ALT + x_shortcut_key);
+ const QKeySequence y_shortcut_key_sequence = QKeySequence(Qt::ALT + y_shortcut_key);
+
+ auto* box =
+ new QGroupBox(QStringLiteral("%1 (%2/%3)")
+ .arg(name, x_shortcut_key_sequence.toString(QKeySequence::NativeText),
+ y_shortcut_key_sequence.toString(QKeySequence::NativeText)));
+
+ auto* x_layout = new QHBoxLayout;
+ x_value = CreateSliderValuePair(x_layout, max_x, x_shortcut_key_sequence, Qt::Horizontal, box);
+
+ auto* y_layout = new QVBoxLayout;
+ y_value = CreateSliderValuePair(y_layout, max_y, y_shortcut_key_sequence, Qt::Vertical, box);
+ y_value->setMaximumWidth(60);
+
+ auto* visual = new StickWidget(this, max_x, max_y);
+ connect(x_value, static_cast(&QSpinBox::valueChanged), visual,
+ &StickWidget::SetX);
+ connect(y_value, static_cast(&QSpinBox::valueChanged), visual,
+ &StickWidget::SetY);
+ connect(visual, &StickWidget::ChangedX, x_value, &QSpinBox::setValue);
+ connect(visual, &StickWidget::ChangedY, y_value, &QSpinBox::setValue);
+
+ x_value->setValue(static_cast(std::round(max_x / 2.)));
+ y_value->setValue(static_cast(std::round(max_y / 2.)));
+
+ auto* visual_ar = new AspectRatioWidget(visual, max_x, max_y);
+
+ auto* visual_layout = new QHBoxLayout;
+ visual_layout->addWidget(visual_ar);
+ visual_layout->addLayout(y_layout);
+
+ auto* layout = new QVBoxLayout;
+ layout->addLayout(x_layout);
+ layout->addLayout(visual_layout);
+ box->setLayout(layout);
+
+ return box;
+}
+
+QBoxLayout* TASInputWindow::CreateSliderValuePairLayout(QString name, QSpinBox*& value, u16 max,
+ Qt::Key shortcut_key,
+ QWidget* shortcut_widget, bool invert)
+{
+ const QKeySequence shortcut_key_sequence = QKeySequence(Qt::ALT + shortcut_key);
+
+ auto* label = new QLabel(QStringLiteral("%1 (%2)").arg(
+ name, shortcut_key_sequence.toString(QKeySequence::NativeText)));
+
+ QBoxLayout* layout = new QHBoxLayout;
+ layout->addWidget(label);
+
+ value = CreateSliderValuePair(layout, max, shortcut_key_sequence, Qt::Horizontal, shortcut_widget,
+ invert);
+
+ return layout;
+}
+
+// The shortcut_widget argument needs to specify the container widget that will be hidden/shown.
+// This is done to avoid ambigous shortcuts
+QSpinBox* TASInputWindow::CreateSliderValuePair(QBoxLayout* layout, u16 max,
+ QKeySequence shortcut_key_sequence,
+ Qt::Orientation orientation,
+ QWidget* shortcut_widget, bool invert)
+{
+ auto* value = new QSpinBox();
+ value->setRange(0, 99999);
+ connect(value, static_cast(&QSpinBox::valueChanged),
+ [value, max](int i) {
+ if (i > max)
+ value->setValue(max);
+ });
+ auto* slider = new QSlider(orientation);
+ slider->setRange(0, max);
+ slider->setFocusPolicy(Qt::ClickFocus);
+ slider->setInvertedAppearance(invert);
+
+ connect(slider, &QSlider::valueChanged, value, &QSpinBox::setValue);
+ connect(value, static_cast(&QSpinBox::valueChanged), slider,
+ &QSlider::setValue);
+
+ auto* shortcut = new QShortcut(shortcut_key_sequence, shortcut_widget);
+ connect(shortcut, &QShortcut::activated, [value] {
+ value->setFocus();
+ value->selectAll();
+ });
+
+ layout->addWidget(slider);
+ layout->addWidget(value);
+ if (orientation == Qt::Vertical)
+ layout->setAlignment(slider, Qt::AlignRight);
+
+ return value;
+}
+
+template
+void TASInputWindow::GetButton(QCheckBox* checkbox, UX& buttons, UX mask)
+{
+ const bool pressed = (buttons & mask) != 0;
+ if (m_use_controller->isChecked())
+ {
+ if (pressed)
+ {
+ m_checkbox_set_by_controller[checkbox] = true;
+ QueueOnObject(checkbox, [checkbox] { checkbox->setChecked(true); });
+ }
+ else if (m_checkbox_set_by_controller.count(checkbox) && m_checkbox_set_by_controller[checkbox])
+ {
+ m_checkbox_set_by_controller[checkbox] = false;
+ QueueOnObject(checkbox, [checkbox] { checkbox->setChecked(false); });
+ }
+ }
+
+ if (checkbox->isChecked())
+ buttons |= mask;
+ else
+ buttons &= ~mask;
+}
+template void TASInputWindow::GetButton(QCheckBox* button, u8& pad, u8 mask);
+template void TASInputWindow::GetButton(QCheckBox* button, u16& pad, u16 mask);
+
+void TASInputWindow::GetSpinBoxU8(QSpinBox* spin, u8& controller_value)
+{
+ if (m_use_controller->isChecked())
+ {
+ if (!m_spinbox_most_recent_values_u8.count(spin) ||
+ m_spinbox_most_recent_values_u8[spin] != controller_value)
+ QueueOnObject(spin, [spin, controller_value] { spin->setValue(controller_value); });
+
+ m_spinbox_most_recent_values_u8[spin] = controller_value;
+ }
+ else
+ {
+ m_spinbox_most_recent_values_u8.clear();
+ }
+
+ controller_value = spin->value();
+}
+
+void TASInputWindow::GetSpinBoxU16(QSpinBox* spin, u16& controller_value)
+{
+ if (m_use_controller->isChecked())
+ {
+ if (!m_spinbox_most_recent_values_u16.count(spin) ||
+ m_spinbox_most_recent_values_u16[spin] != controller_value)
+ QueueOnObject(spin, [spin, controller_value] { spin->setValue(controller_value); });
+
+ m_spinbox_most_recent_values_u16[spin] = controller_value;
+ }
+ else
+ {
+ m_spinbox_most_recent_values_u16.clear();
+ }
+
+ controller_value = spin->value();
+}
diff --git a/Source/Core/DolphinQt/TAS/TASInputWindow.h b/Source/Core/DolphinQt/TAS/TASInputWindow.h
new file mode 100644
index 0000000000..66d6239abf
--- /dev/null
+++ b/Source/Core/DolphinQt/TAS/TASInputWindow.h
@@ -0,0 +1,44 @@
+// Copyright 2018 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+#include "Common/CommonTypes.h"
+
+struct GCPadStatus;
+class QBoxLayout;
+class QCheckBox;
+class QDialog;
+class QGroupBox;
+class QSpinBox;
+class QString;
+
+class TASInputWindow : public QDialog
+{
+ Q_OBJECT
+public:
+ explicit TASInputWindow(QWidget* parent);
+
+protected:
+ QGroupBox* CreateStickInputs(QString name, QSpinBox*& x_value, QSpinBox*& y_value, u16 max_x,
+ u16 max_y, Qt::Key x_shortcut_key, Qt::Key y_shortcut_key);
+ QBoxLayout* CreateSliderValuePairLayout(QString name, QSpinBox*& value, u16 max,
+ Qt::Key shortcut_key, QWidget* shortcut_widget,
+ bool invert = false);
+ QSpinBox* CreateSliderValuePair(QBoxLayout* layout, u16 max, QKeySequence shortcut_key_sequence,
+ Qt::Orientation orientation, QWidget* shortcut_widget,
+ bool invert = false);
+ template
+ void GetButton(QCheckBox* button, UX& pad, UX mask);
+ void GetSpinBoxU8(QSpinBox* spin, u8& controller_value);
+ void GetSpinBoxU16(QSpinBox* spin, u16& controller_value);
+ QCheckBox* m_use_controller;
+
+private:
+ std::map m_checkbox_set_by_controller;
+ std::map m_spinbox_most_recent_values_u8;
+ std::map m_spinbox_most_recent_values_u16;
+};
diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp
index df9ad7b270..03a09f83a9 100644
--- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp
+++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.cpp
@@ -2,8 +2,6 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.
-#include "DolphinQt/TAS/WiiTASInputWindow.h"
-
#include
#include
@@ -23,15 +21,14 @@
#include "Core/HW/WiimoteReal/WiimoteReal.h"
#include "DolphinQt/QtUtils/AspectRatioWidget.h"
+#include "DolphinQt/QtUtils/QueueOnObject.h"
#include "DolphinQt/TAS/IRWidget.h"
-#include "DolphinQt/TAS/Shared.h"
+#include "DolphinQt/TAS/WiiTASInputWindow.h"
#include "InputCommon/InputConfig.h"
-WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent), m_num(num)
+WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : TASInputWindow(parent), m_num(num)
{
- setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
-
const QKeySequence ir_x_shortcut_key_sequence = QKeySequence(Qt::ALT + Qt::Key_F);
const QKeySequence ir_y_shortcut_key_sequence = QKeySequence(Qt::ALT + Qt::Key_G);
@@ -41,12 +38,12 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent)
ir_y_shortcut_key_sequence.toString(QKeySequence::NativeText)));
auto* x_layout = new QHBoxLayout;
- m_ir_x_value = CreateSliderValuePair(this, x_layout, ir_max_x, ir_x_shortcut_key_sequence,
+ m_ir_x_value = CreateSliderValuePair(x_layout, ir_max_x, ir_x_shortcut_key_sequence,
Qt::Horizontal, m_ir_box, true);
auto* y_layout = new QVBoxLayout;
- m_ir_y_value = CreateSliderValuePair(this, y_layout, ir_max_y, ir_y_shortcut_key_sequence,
- Qt::Vertical, m_ir_box, true);
+ m_ir_y_value = CreateSliderValuePair(y_layout, ir_max_y, ir_y_shortcut_key_sequence, Qt::Vertical,
+ m_ir_box, true);
m_ir_y_value->setMaximumWidth(60);
auto* visual = new IRWidget(this);
@@ -71,15 +68,15 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent)
ir_layout->addLayout(visual_layout);
m_ir_box->setLayout(ir_layout);
- m_nunchuk_stick_box = CreateStickInputs(this, tr("Nunchuk Stick"), m_nunchuk_stick_x_value,
+ m_nunchuk_stick_box = CreateStickInputs(tr("Nunchuk Stick"), m_nunchuk_stick_x_value,
m_nunchuk_stick_y_value, 255, 255, Qt::Key_X, Qt::Key_Y);
m_classic_left_stick_box =
- CreateStickInputs(this, tr("Left Stick"), m_classic_left_stick_x_value,
+ CreateStickInputs(tr("Left Stick"), m_classic_left_stick_x_value,
m_classic_left_stick_y_value, 63, 63, Qt::Key_F, Qt::Key_G);
m_classic_right_stick_box =
- CreateStickInputs(this, tr("Right Stick"), m_classic_right_stick_x_value,
+ CreateStickInputs(tr("Right Stick"), m_classic_right_stick_x_value,
m_classic_right_stick_y_value, 31, 31, Qt::Key_Q, Qt::Key_W);
// Need to enforce the same minimum width because otherwise the different lengths in the labels
@@ -97,17 +94,21 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent)
auto* remote_orientation_x_layout =
// i18n: Refers to a 3D axis (used when mapping motion controls)
- CreateSliderValuePairLayout(this, tr("X"), m_remote_orientation_x_value, 1023, Qt::Key_Q,
+ CreateSliderValuePairLayout(tr("X"), m_remote_orientation_x_value, 1023, Qt::Key_Q,
m_remote_orientation_box);
auto* remote_orientation_y_layout =
// i18n: Refers to a 3D axis (used when mapping motion controls)
- CreateSliderValuePairLayout(this, tr("Y"), m_remote_orientation_y_value, 1023, Qt::Key_W,
+ CreateSliderValuePairLayout(tr("Y"), m_remote_orientation_y_value, 1023, Qt::Key_W,
m_remote_orientation_box);
auto* remote_orientation_z_layout =
// i18n: Refers to a 3D axis (used when mapping motion controls)
- CreateSliderValuePairLayout(this, tr("Z"), m_remote_orientation_z_value, 1023, Qt::Key_E,
+ CreateSliderValuePairLayout(tr("Z"), m_remote_orientation_z_value, 1023, Qt::Key_E,
m_remote_orientation_box);
+ m_remote_orientation_x_value->setValue(512);
+ m_remote_orientation_y_value->setValue(512);
+ m_remote_orientation_z_value->setValue(616);
+
auto* remote_orientation_layout = new QVBoxLayout;
remote_orientation_layout->addLayout(remote_orientation_x_layout);
remote_orientation_layout->addLayout(remote_orientation_y_layout);
@@ -118,17 +119,21 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent)
auto* nunchuk_orientation_x_layout =
// i18n: Refers to a 3D axis (used when mapping motion controls)
- CreateSliderValuePairLayout(this, tr("X"), m_nunchuk_orientation_x_value, 1023, Qt::Key_I,
+ CreateSliderValuePairLayout(tr("X"), m_nunchuk_orientation_x_value, 1023, Qt::Key_I,
m_nunchuk_orientation_box);
auto* nunchuk_orientation_y_layout =
// i18n: Refers to a 3D axis (used when mapping motion controls)
- CreateSliderValuePairLayout(this, tr("Y"), m_nunchuk_orientation_y_value, 1023, Qt::Key_O,
+ CreateSliderValuePairLayout(tr("Y"), m_nunchuk_orientation_y_value, 1023, Qt::Key_O,
m_nunchuk_orientation_box);
auto* nunchuk_orientation_z_layout =
// i18n: Refers to a 3D axis (used when mapping motion controls)
- CreateSliderValuePairLayout(this, tr("Z"), m_nunchuk_orientation_z_value, 1023, Qt::Key_P,
+ CreateSliderValuePairLayout(tr("Z"), m_nunchuk_orientation_z_value, 1023, Qt::Key_P,
m_nunchuk_orientation_box);
+ m_nunchuk_orientation_x_value->setValue(512);
+ m_nunchuk_orientation_y_value->setValue(512);
+ m_nunchuk_orientation_z_value->setValue(512);
+
auto* nunchuk_orientation_layout = new QVBoxLayout;
nunchuk_orientation_layout->addLayout(nunchuk_orientation_x_layout);
nunchuk_orientation_layout->addLayout(nunchuk_orientation_y_layout);
@@ -136,9 +141,9 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent)
m_nunchuk_orientation_box->setLayout(nunchuk_orientation_layout);
m_triggers_box = new QGroupBox(tr("Triggers"));
- auto* l_trigger_layout = CreateSliderValuePairLayout(this, tr("Left"), m_left_trigger_value, 31,
- Qt::Key_N, m_triggers_box);
- auto* r_trigger_layout = CreateSliderValuePairLayout(this, tr("Right"), m_right_trigger_value, 31,
+ auto* l_trigger_layout =
+ CreateSliderValuePairLayout(tr("Left"), m_left_trigger_value, 31, Qt::Key_N, m_triggers_box);
+ auto* r_trigger_layout = CreateSliderValuePairLayout(tr("Right"), m_right_trigger_value, 31,
Qt::Key_M, m_triggers_box);
auto* triggers_layout = new QVBoxLayout;
@@ -241,6 +246,7 @@ WiiTASInputWindow::WiiTASInputWindow(QWidget* parent, int num) : QDialog(parent)
layout->addWidget(m_remote_buttons_box);
layout->addWidget(m_nunchuk_buttons_box);
layout->addWidget(m_classic_buttons_box);
+ layout->addWidget(m_use_controller);
layout->setAlignment(m_nunchuk_buttons_box, Qt::AlignLeft);
setLayout(layout);
@@ -312,15 +318,6 @@ void WiiTASInputWindow::UpdateExt(u8 ext)
}
}
-template
-static void SetButton(QCheckBox* check_box, UX* buttons, UX mask)
-{
- if (check_box->isChecked())
- *buttons |= mask;
- else
- *buttons &= ~mask;
-}
-
void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rptf, int ext,
wiimote_key key)
{
@@ -336,18 +333,18 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp
if (m_remote_buttons_box->isVisible() && buttons_data)
{
- u16* buttons = &(reinterpret_cast(buttons_data))->hex;
- SetButton(m_a_button, buttons, WiimoteEmu::Wiimote::BUTTON_A);
- SetButton(m_b_button, buttons, WiimoteEmu::Wiimote::BUTTON_B);
- SetButton(m_1_button, buttons, WiimoteEmu::Wiimote::BUTTON_ONE);
- SetButton(m_2_button, buttons, WiimoteEmu::Wiimote::BUTTON_TWO);
- SetButton(m_plus_button, buttons, WiimoteEmu::Wiimote::BUTTON_PLUS);
- SetButton(m_minus_button, buttons, WiimoteEmu::Wiimote::BUTTON_MINUS);
- SetButton(m_home_button, buttons, WiimoteEmu::Wiimote::BUTTON_HOME);
- SetButton(m_left_button, buttons, WiimoteEmu::Wiimote::PAD_LEFT);
- SetButton(m_up_button, buttons, WiimoteEmu::Wiimote::PAD_UP);
- SetButton(m_down_button, buttons, WiimoteEmu::Wiimote::PAD_DOWN);
- SetButton(m_right_button, buttons, WiimoteEmu::Wiimote::PAD_RIGHT);
+ u16& buttons = (reinterpret_cast(buttons_data))->hex;
+ GetButton(m_a_button, buttons, WiimoteEmu::Wiimote::BUTTON_A);
+ GetButton(m_b_button, buttons, WiimoteEmu::Wiimote::BUTTON_B);
+ GetButton(m_1_button, buttons, WiimoteEmu::Wiimote::BUTTON_ONE);
+ GetButton(m_2_button, buttons, WiimoteEmu::Wiimote::BUTTON_TWO);
+ GetButton(m_plus_button, buttons, WiimoteEmu::Wiimote::BUTTON_PLUS);
+ GetButton(m_minus_button, buttons, WiimoteEmu::Wiimote::BUTTON_MINUS);
+ GetButton(m_home_button, buttons, WiimoteEmu::Wiimote::BUTTON_HOME);
+ GetButton(m_left_button, buttons, WiimoteEmu::Wiimote::PAD_LEFT);
+ GetButton(m_up_button, buttons, WiimoteEmu::Wiimote::PAD_UP);
+ GetButton(m_down_button, buttons, WiimoteEmu::Wiimote::PAD_DOWN);
+ GetButton(m_right_button, buttons, WiimoteEmu::Wiimote::PAD_RIGHT);
}
if (m_remote_orientation_box->isVisible() && accel_data && buttons_data)
@@ -355,16 +352,24 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp
wm_accel& accel = *reinterpret_cast(accel_data);
wm_buttons& buttons = *reinterpret_cast(buttons_data);
- accel.x = m_remote_orientation_x_value->value() >> 2;
- accel.y = m_remote_orientation_y_value->value() >> 2;
- accel.z = m_remote_orientation_z_value->value() >> 2;
+ u16 accel_x = (accel.x << 2) & (buttons.acc_x_lsb & 0b11);
+ u16 accel_y = (accel.y << 2) & ((buttons.acc_y_lsb & 0b1) << 1);
+ u16 accel_z = (accel.z << 2) & ((buttons.acc_z_lsb & 0b1) << 1);
- buttons.acc_x_lsb = m_remote_orientation_x_value->value() & 0x3;
- buttons.acc_y_lsb = m_remote_orientation_y_value->value() >> 1 & 0x1;
- buttons.acc_z_lsb = m_remote_orientation_z_value->value() >> 1 & 0x1;
+ GetSpinBoxU16(m_remote_orientation_x_value, accel_x);
+ GetSpinBoxU16(m_remote_orientation_y_value, accel_y);
+ GetSpinBoxU16(m_remote_orientation_z_value, accel_z);
+
+ accel.x = accel_x >> 2;
+ accel.y = accel_y >> 2;
+ accel.z = accel_z >> 2;
+
+ buttons.acc_x_lsb = accel_x & 0b11;
+ buttons.acc_y_lsb = (accel_y >> 1) & 0b1;
+ buttons.acc_z_lsb = (accel_z >> 1) & 0b1;
}
- if (m_ir_box->isVisible() && ir_data)
+ if (m_ir_box->isVisible() && ir_data && !m_use_controller->isChecked())
{
u16 y = m_ir_y_value->value();
std::array x;
@@ -429,19 +434,30 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp
if (ext_data && m_nunchuk_stick_box->isVisible())
{
wm_nc& nunchuk = *reinterpret_cast(ext_data);
- nunchuk.jx = m_nunchuk_stick_x_value->value();
- nunchuk.jy = m_nunchuk_stick_y_value->value();
- nunchuk.ax = m_nunchuk_orientation_x_value->value() >> 2;
- nunchuk.bt.acc_x_lsb = m_nunchuk_orientation_x_value->value() & 0x3;
- nunchuk.ay = m_nunchuk_orientation_y_value->value() >> 2;
- nunchuk.bt.acc_y_lsb = m_nunchuk_orientation_y_value->value() & 0x3;
- nunchuk.az = m_nunchuk_orientation_z_value->value() >> 2;
- nunchuk.bt.acc_z_lsb = m_nunchuk_orientation_z_value->value() & 0x3;
+ GetSpinBoxU8(m_nunchuk_stick_x_value, nunchuk.jx);
+ GetSpinBoxU8(m_nunchuk_stick_y_value, nunchuk.jy);
- SetButton(m_c_button, &nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_C);
- SetButton(m_z_button, &nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_Z);
- nunchuk.bt.hex ^= 0x3;
+ u16 accel_x = nunchuk.ax << 2 & (nunchuk.bt.acc_x_lsb & 0b11);
+ u16 accel_y = nunchuk.ay << 2 & (nunchuk.bt.acc_y_lsb & 0b11);
+ u16 accel_z = nunchuk.az << 2 & (nunchuk.bt.acc_z_lsb & 0b11);
+
+ GetSpinBoxU16(m_nunchuk_orientation_x_value, accel_x);
+ GetSpinBoxU16(m_nunchuk_orientation_y_value, accel_y);
+ GetSpinBoxU16(m_nunchuk_orientation_z_value, accel_z);
+
+ nunchuk.ax = accel_x >> 2;
+ nunchuk.ay = accel_y >> 2;
+ nunchuk.az = accel_z >> 2;
+
+ nunchuk.bt.acc_x_lsb = accel_x & 0b11;
+ nunchuk.bt.acc_y_lsb = accel_y & 0b11;
+ nunchuk.bt.acc_z_lsb = accel_z & 0b11;
+
+ nunchuk.bt.hex ^= 0b11;
+ GetButton(m_c_button, nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_C);
+ GetButton(m_z_button, nunchuk.bt.hex, WiimoteEmu::Nunchuk::BUTTON_Z);
+ nunchuk.bt.hex ^= 0b11;
WiimoteEncrypt(&key, reinterpret_cast(&nunchuk), 0, sizeof(wm_nc));
}
@@ -450,36 +466,51 @@ void WiiTASInputWindow::GetValues(u8* report_data, WiimoteEmu::ReportFeatures rp
{
wm_classic_extension& cc = *reinterpret_cast(ext_data);
WiimoteDecrypt(&key, reinterpret_cast(&cc), 0, sizeof(wm_classic_extension));
- cc.bt.hex = 0;
- SetButton(m_classic_a_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_A);
- SetButton(m_classic_b_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_B);
- SetButton(m_classic_x_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_X);
- SetButton(m_classic_y_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_Y);
- SetButton(m_classic_plus_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_PLUS);
- SetButton(m_classic_minus_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_MINUS);
- SetButton(m_classic_l_button, &cc.bt.hex, WiimoteEmu::Classic::TRIGGER_L);
- SetButton(m_classic_r_button, &cc.bt.hex, WiimoteEmu::Classic::TRIGGER_R);
- SetButton(m_classic_zl_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZL);
- SetButton(m_classic_zr_button, &cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZR);
- SetButton(m_classic_left_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_LEFT);
- SetButton(m_classic_up_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_UP);
- SetButton(m_classic_down_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_DOWN);
- SetButton(m_classic_right_button, &cc.bt.hex, WiimoteEmu::Classic::PAD_RIGHT);
+ cc.bt.hex ^= 0xFFFF;
+ GetButton(m_classic_a_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_A);
+ GetButton(m_classic_b_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_B);
+ GetButton(m_classic_x_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_X);
+ GetButton(m_classic_y_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_Y);
+ GetButton(m_classic_plus_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_PLUS);
+ GetButton(m_classic_minus_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_MINUS);
+ GetButton(m_classic_l_button, cc.bt.hex, WiimoteEmu::Classic::TRIGGER_L);
+ GetButton(m_classic_r_button, cc.bt.hex, WiimoteEmu::Classic::TRIGGER_R);
+ GetButton(m_classic_zl_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZL);
+ GetButton(m_classic_zr_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_ZR);
+ GetButton(m_classic_home_button, cc.bt.hex, WiimoteEmu::Classic::BUTTON_HOME);
+ GetButton(m_classic_left_button, cc.bt.hex, WiimoteEmu::Classic::PAD_LEFT);
+ GetButton(m_classic_up_button, cc.bt.hex, WiimoteEmu::Classic::PAD_UP);
+ GetButton(m_classic_down_button, cc.bt.hex, WiimoteEmu::Classic::PAD_DOWN);
+ GetButton(m_classic_right_button, cc.bt.hex, WiimoteEmu::Classic::PAD_RIGHT);
cc.bt.hex ^= 0xFFFF;
- u16 rx = m_classic_right_stick_x_value->value();
- cc.rx1 = rx & 0x1;
- cc.rx2 = (rx >> 1) & 0x3;
- cc.rx3 = (rx >> 3) & 0x3;
- cc.ry = m_classic_right_stick_y_value->value();
+ u8 rx = (cc.rx1 & 0b1) & ((cc.rx2 & 0b11) << 1) & ((cc.rx3 & 0b11) << 3);
+ GetSpinBoxU8(m_classic_right_stick_x_value, rx);
+ cc.rx1 = rx & 0b1;
+ cc.rx2 = (rx >> 1) & 0b11;
+ cc.rx3 = (rx >> 3) & 0b11;
- cc.regular_data.lx = m_classic_left_stick_x_value->value();
- cc.regular_data.ly = m_classic_left_stick_y_value->value();
+ u8 ry = cc.ry;
+ GetSpinBoxU8(m_classic_right_stick_y_value, ry);
+ cc.ry = ry;
- cc.rt = m_right_trigger_value->value();
- cc.lt1 = m_left_trigger_value->value() & 0x7;
- cc.lt2 = (m_left_trigger_value->value() >> 3) & 0x3;
+ u8 lx = cc.regular_data.lx;
+ GetSpinBoxU8(m_classic_left_stick_x_value, lx);
+ cc.regular_data.lx = lx;
+
+ u8 ly = cc.regular_data.ly;
+ GetSpinBoxU8(m_classic_left_stick_y_value, ly);
+ cc.regular_data.ly = ly;
+
+ u8 rt = cc.rt;
+ GetSpinBoxU8(m_right_trigger_value, rt);
+ cc.rt = rt;
+
+ u8 lt = (cc.lt1 & 0b111) & (cc.lt2 >> 3);
+ GetSpinBoxU8(m_left_trigger_value, lt);
+ cc.lt1 = lt & 0b111;
+ cc.lt2 = (lt >> 3) & 0b11;
WiimoteEncrypt(&key, reinterpret_cast(&cc), 0, sizeof(wm_classic_extension));
}
diff --git a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h
index 2c1a206266..a8decedbf6 100644
--- a/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h
+++ b/Source/Core/DolphinQt/TAS/WiiTASInputWindow.h
@@ -4,9 +4,7 @@
#pragma once
-#include
-
-#include "Common/CommonTypes.h"
+#include "DolphinQt/TAS/TASInputWindow.h"
namespace WiimoteEmu
{
@@ -17,7 +15,7 @@ class QGroupBox;
class QSpinBox;
struct wiimote_key;
-class WiiTASInputWindow : public QDialog
+class WiiTASInputWindow : public TASInputWindow
{
Q_OBJECT
public: