diff options
23 files changed, 426 insertions, 208 deletions
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 4cab599b4..732a1bf89 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -31,6 +31,8 @@ add_executable(yuzu | |||
| 31 | configuration/configure_general.h | 31 | configuration/configure_general.h |
| 32 | configuration/configure_graphics.cpp | 32 | configuration/configure_graphics.cpp |
| 33 | configuration/configure_graphics.h | 33 | configuration/configure_graphics.h |
| 34 | configuration/configure_hotkeys.cpp | ||
| 35 | configuration/configure_hotkeys.h | ||
| 34 | configuration/configure_input.cpp | 36 | configuration/configure_input.cpp |
| 35 | configuration/configure_input.h | 37 | configuration/configure_input.h |
| 36 | configuration/configure_input_player.cpp | 38 | configuration/configure_input_player.cpp |
| @@ -78,6 +80,8 @@ add_executable(yuzu | |||
| 78 | ui_settings.h | 80 | ui_settings.h |
| 79 | util/limitable_input_dialog.cpp | 81 | util/limitable_input_dialog.cpp |
| 80 | util/limitable_input_dialog.h | 82 | util/limitable_input_dialog.h |
| 83 | util/sequence_dialog/sequence_dialog.cpp | ||
| 84 | util/sequence_dialog/sequence_dialog.h | ||
| 81 | util/spinbox.cpp | 85 | util/spinbox.cpp |
| 82 | util/spinbox.h | 86 | util/spinbox.h |
| 83 | util/util.cpp | 87 | util/util.cpp |
| @@ -95,6 +99,7 @@ set(UIS | |||
| 95 | configuration/configure_gamelist.ui | 99 | configuration/configure_gamelist.ui |
| 96 | configuration/configure_general.ui | 100 | configuration/configure_general.ui |
| 97 | configuration/configure_graphics.ui | 101 | configuration/configure_graphics.ui |
| 102 | configuration/configure_hotkeys.ui | ||
| 98 | configuration/configure_input.ui | 103 | configuration/configure_input.ui |
| 99 | configuration/configure_input_player.ui | 104 | configuration/configure_input_player.ui |
| 100 | configuration/configure_input_simple.ui | 105 | configuration/configure_input_simple.ui |
| @@ -105,7 +110,6 @@ set(UIS | |||
| 105 | configuration/configure_touchscreen_advanced.ui | 110 | configuration/configure_touchscreen_advanced.ui |
| 106 | configuration/configure_web.ui | 111 | configuration/configure_web.ui |
| 107 | compatdb.ui | 112 | compatdb.ui |
| 108 | hotkeys.ui | ||
| 109 | loading_screen.ui | 113 | loading_screen.ui |
| 110 | main.ui | 114 | main.ui |
| 111 | ) | 115 | ) |
diff --git a/src/yuzu/applets/profile_select.cpp b/src/yuzu/applets/profile_select.cpp index f95f7fe3c..743b24d76 100644 --- a/src/yuzu/applets/profile_select.cpp +++ b/src/yuzu/applets/profile_select.cpp | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #include <mutex> | 5 | #include <mutex> |
| 6 | #include <QDialogButtonBox> | 6 | #include <QDialogButtonBox> |
| 7 | #include <QHeaderView> | ||
| 7 | #include <QLabel> | 8 | #include <QLabel> |
| 8 | #include <QLineEdit> | 9 | #include <QLineEdit> |
| 9 | #include <QScrollArea> | 10 | #include <QScrollArea> |
diff --git a/src/yuzu/applets/profile_select.h b/src/yuzu/applets/profile_select.h index 868573324..1c2922e54 100644 --- a/src/yuzu/applets/profile_select.h +++ b/src/yuzu/applets/profile_select.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <vector> | 7 | #include <vector> |
| 8 | #include <QDialog> | 8 | #include <QDialog> |
| 9 | #include <QList> | 9 | #include <QList> |
| 10 | #include <QTreeView> | ||
| 10 | #include "core/frontend/applets/profile_select.h" | 11 | #include "core/frontend/applets/profile_select.h" |
| 11 | 12 | ||
| 12 | class GMainWindow; | 13 | class GMainWindow; |
| @@ -16,7 +17,6 @@ class QLabel; | |||
| 16 | class QScrollArea; | 17 | class QScrollArea; |
| 17 | class QStandardItem; | 18 | class QStandardItem; |
| 18 | class QStandardItemModel; | 19 | class QStandardItemModel; |
| 19 | class QTreeView; | ||
| 20 | class QVBoxLayout; | 20 | class QVBoxLayout; |
| 21 | 21 | ||
| 22 | class QtProfileSelectionDialog final : public QDialog { | 22 | class QtProfileSelectionDialog final : public QDialog { |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index dead9f807..802db3945 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -2,6 +2,8 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <array> | ||
| 6 | #include <QKeySequence> | ||
| 5 | #include <QSettings> | 7 | #include <QSettings> |
| 6 | #include "common/file_util.h" | 8 | #include "common/file_util.h" |
| 7 | #include "configure_input_simple.h" | 9 | #include "configure_input_simple.h" |
| @@ -9,7 +11,6 @@ | |||
| 9 | #include "core/hle/service/hid/controllers/npad.h" | 11 | #include "core/hle/service/hid/controllers/npad.h" |
| 10 | #include "input_common/main.h" | 12 | #include "input_common/main.h" |
| 11 | #include "yuzu/configuration/config.h" | 13 | #include "yuzu/configuration/config.h" |
| 12 | #include "yuzu/ui_settings.h" | ||
| 13 | 14 | ||
| 14 | Config::Config() { | 15 | Config::Config() { |
| 15 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. | 16 | // TODO: Don't hardcode the path; let the frontend decide where to put the config files. |
| @@ -17,7 +18,6 @@ Config::Config() { | |||
| 17 | FileUtil::CreateFullPath(qt_config_loc); | 18 | FileUtil::CreateFullPath(qt_config_loc); |
| 18 | qt_config = | 19 | qt_config = |
| 19 | std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat); | 20 | std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat); |
| 20 | |||
| 21 | Reload(); | 21 | Reload(); |
| 22 | } | 22 | } |
| 23 | 23 | ||
| @@ -205,6 +205,27 @@ const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default | |||
| 205 | Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight, | 205 | Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight, |
| 206 | }; | 206 | }; |
| 207 | 207 | ||
| 208 | // This shouldn't have anything except static initializers (no functions). So | ||
| 209 | // QKeySequnce(...).toString() is NOT ALLOWED HERE. | ||
| 210 | // This must be in alphabetical order according to action name as it must have the same order as | ||
| 211 | // UISetting::values.shortcuts, which is alphabetically ordered. | ||
| 212 | const std::array<UISettings::Shortcut, 15> Config::default_hotkeys{ | ||
| 213 | {{"Capture Screenshot", "Main Window", {"Ctrl+P", Qt::ApplicationShortcut}}, | ||
| 214 | {"Continue/Pause Emulation", "Main Window", {"F4", Qt::WindowShortcut}}, | ||
| 215 | {"Decrease Speed Limit", "Main Window", {"-", Qt::ApplicationShortcut}}, | ||
| 216 | {"Exit yuzu", "Main Window", {"Ctrl+Q", Qt::WindowShortcut}}, | ||
| 217 | {"Exit Fullscreen", "Main Window", {"Esc", Qt::WindowShortcut}}, | ||
| 218 | {"Fullscreen", "Main Window", {"F11", Qt::WindowShortcut}}, | ||
| 219 | {"Increase Speed Limit", "Main Window", {"+", Qt::ApplicationShortcut}}, | ||
| 220 | {"Load Amiibo", "Main Window", {"F2", Qt::ApplicationShortcut}}, | ||
| 221 | {"Load File", "Main Window", {"Ctrl+O", Qt::WindowShortcut}}, | ||
| 222 | {"Restart Emulation", "Main Window", {"F6", Qt::WindowShortcut}}, | ||
| 223 | {"Stop Emulation", "Main Window", {"F5", Qt::WindowShortcut}}, | ||
| 224 | {"Toggle Filter Bar", "Main Window", {"Ctrl+F", Qt::WindowShortcut}}, | ||
| 225 | {"Toggle Speed Limit", "Main Window", {"Ctrl+Z", Qt::ApplicationShortcut}}, | ||
| 226 | {"Toggle Status Bar", "Main Window", {"Ctrl+S", Qt::WindowShortcut}}, | ||
| 227 | {"Change Docked Mode", "Main Window", {"F10", Qt::ApplicationShortcut}}}}; | ||
| 228 | |||
| 208 | void Config::ReadPlayerValues() { | 229 | void Config::ReadPlayerValues() { |
| 209 | for (std::size_t p = 0; p < Settings::values.players.size(); ++p) { | 230 | for (std::size_t p = 0; p < Settings::values.players.size(); ++p) { |
| 210 | auto& player = Settings::values.players[p]; | 231 | auto& player = Settings::values.players[p]; |
| @@ -508,20 +529,15 @@ void Config::ReadValues() { | |||
| 508 | qt_config->endGroup(); | 529 | qt_config->endGroup(); |
| 509 | 530 | ||
| 510 | qt_config->beginGroup("Shortcuts"); | 531 | qt_config->beginGroup("Shortcuts"); |
| 511 | QStringList groups = qt_config->childGroups(); | 532 | for (auto [name, group, shortcut] : default_hotkeys) { |
| 512 | for (auto group : groups) { | 533 | auto [keyseq, context] = shortcut; |
| 513 | qt_config->beginGroup(group); | 534 | qt_config->beginGroup(group); |
| 514 | 535 | qt_config->beginGroup(name); | |
| 515 | QStringList hotkeys = qt_config->childGroups(); | 536 | UISettings::values.shortcuts.push_back( |
| 516 | for (auto hotkey : hotkeys) { | 537 | {name, |
| 517 | qt_config->beginGroup(hotkey); | 538 | group, |
| 518 | UISettings::values.shortcuts.emplace_back(UISettings::Shortcut( | 539 | {ReadSetting("KeySeq", keyseq).toString(), ReadSetting("Context", context).toInt()}}); |
| 519 | group + "/" + hotkey, | 540 | qt_config->endGroup(); |
| 520 | UISettings::ContextualShortcut(ReadSetting("KeySeq").toString(), | ||
| 521 | ReadSetting("Context").toInt()))); | ||
| 522 | qt_config->endGroup(); | ||
| 523 | } | ||
| 524 | |||
| 525 | qt_config->endGroup(); | 541 | qt_config->endGroup(); |
| 526 | } | 542 | } |
| 527 | qt_config->endGroup(); | 543 | qt_config->endGroup(); |
| @@ -758,9 +774,16 @@ void Config::SaveValues() { | |||
| 758 | qt_config->endGroup(); | 774 | qt_config->endGroup(); |
| 759 | 775 | ||
| 760 | qt_config->beginGroup("Shortcuts"); | 776 | qt_config->beginGroup("Shortcuts"); |
| 761 | for (auto shortcut : UISettings::values.shortcuts) { | 777 | // Lengths of UISettings::values.shortcuts & default_hotkeys are same. |
| 762 | WriteSetting(shortcut.first + "/KeySeq", shortcut.second.first); | 778 | // However, their ordering must also be the same. |
| 763 | WriteSetting(shortcut.first + "/Context", shortcut.second.second); | 779 | for (std::size_t i = 0; i < default_hotkeys.size(); i++) { |
| 780 | auto [name, group, shortcut] = UISettings::values.shortcuts[i]; | ||
| 781 | qt_config->beginGroup(group); | ||
| 782 | qt_config->beginGroup(name); | ||
| 783 | WriteSetting("KeySeq", shortcut.first, default_hotkeys[i].shortcut.first); | ||
| 784 | WriteSetting("Context", shortcut.second, default_hotkeys[i].shortcut.second); | ||
| 785 | qt_config->endGroup(); | ||
| 786 | qt_config->endGroup(); | ||
| 764 | } | 787 | } |
| 765 | qt_config->endGroup(); | 788 | qt_config->endGroup(); |
| 766 | 789 | ||
diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index f4185db18..221d2364c 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <string> | 9 | #include <string> |
| 10 | #include <QVariant> | 10 | #include <QVariant> |
| 11 | #include "core/settings.h" | 11 | #include "core/settings.h" |
| 12 | #include "yuzu/ui_settings.h" | ||
| 12 | 13 | ||
| 13 | class QSettings; | 14 | class QSettings; |
| 14 | 15 | ||
| @@ -47,6 +48,8 @@ private: | |||
| 47 | void WriteSetting(const QString& name, const QVariant& value); | 48 | void WriteSetting(const QString& name, const QVariant& value); |
| 48 | void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); | 49 | void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value); |
| 49 | 50 | ||
| 51 | static const std::array<UISettings::Shortcut, 15> default_hotkeys; | ||
| 52 | |||
| 50 | std::unique_ptr<QSettings> qt_config; | 53 | std::unique_ptr<QSettings> qt_config; |
| 51 | std::string qt_config_loc; | 54 | std::string qt_config_loc; |
| 52 | }; | 55 | }; |
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index 3f03f0b77..267717bc9 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui | |||
| @@ -7,9 +7,15 @@ | |||
| 7 | <x>0</x> | 7 | <x>0</x> |
| 8 | <y>0</y> | 8 | <y>0</y> |
| 9 | <width>382</width> | 9 | <width>382</width> |
| 10 | <height>241</height> | 10 | <height>650</height> |
| 11 | </rect> | 11 | </rect> |
| 12 | </property> | 12 | </property> |
| 13 | <property name="minimumSize"> | ||
| 14 | <size> | ||
| 15 | <width>0</width> | ||
| 16 | <height>650</height> | ||
| 17 | </size> | ||
| 18 | </property> | ||
| 13 | <property name="windowTitle"> | 19 | <property name="windowTitle"> |
| 14 | <string>yuzu Configuration</string> | 20 | <string>yuzu Configuration</string> |
| 15 | </property> | 21 | </property> |
| @@ -62,6 +68,11 @@ | |||
| 62 | <string>Input</string> | 68 | <string>Input</string> |
| 63 | </attribute> | 69 | </attribute> |
| 64 | </widget> | 70 | </widget> |
| 71 | <widget class="ConfigureHotkeys" name="hotkeysTab"> | ||
| 72 | <attribute name="title"> | ||
| 73 | <string>Hotkeys</string> | ||
| 74 | </attribute> | ||
| 75 | </widget> | ||
| 65 | <widget class="ConfigureGraphics" name="graphicsTab"> | 76 | <widget class="ConfigureGraphics" name="graphicsTab"> |
| 66 | <attribute name="title"> | 77 | <attribute name="title"> |
| 67 | <string>Graphics</string> | 78 | <string>Graphics</string> |
| @@ -150,6 +161,12 @@ | |||
| 150 | <header>configuration/configure_input_simple.h</header> | 161 | <header>configuration/configure_input_simple.h</header> |
| 151 | <container>1</container> | 162 | <container>1</container> |
| 152 | </customwidget> | 163 | </customwidget> |
| 164 | <customwidget> | ||
| 165 | <class>ConfigureHotkeys</class> | ||
| 166 | <extends>QWidget</extends> | ||
| 167 | <header>configuration/configure_hotkeys.h</header> | ||
| 168 | <container>1</container> | ||
| 169 | </customwidget> | ||
| 153 | </customwidgets> | 170 | </customwidgets> |
| 154 | <resources/> | 171 | <resources/> |
| 155 | <connections> | 172 | <connections> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 777050405..51bd1f121 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -8,20 +8,22 @@ | |||
| 8 | #include "ui_configure.h" | 8 | #include "ui_configure.h" |
| 9 | #include "yuzu/configuration/config.h" | 9 | #include "yuzu/configuration/config.h" |
| 10 | #include "yuzu/configuration/configure_dialog.h" | 10 | #include "yuzu/configuration/configure_dialog.h" |
| 11 | #include "yuzu/configuration/configure_input_player.h" | ||
| 11 | #include "yuzu/hotkeys.h" | 12 | #include "yuzu/hotkeys.h" |
| 12 | 13 | ||
| 13 | ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry) | 14 | ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry) |
| 14 | : QDialog(parent), ui(new Ui::ConfigureDialog) { | 15 | : QDialog(parent), registry(registry), ui(new Ui::ConfigureDialog) { |
| 15 | ui->setupUi(this); | 16 | ui->setupUi(this); |
| 16 | ui->generalTab->PopulateHotkeyList(registry); | 17 | ui->hotkeysTab->Populate(registry); |
| 17 | this->setConfiguration(); | 18 | this->setConfiguration(); |
| 18 | this->PopulateSelectionList(); | 19 | this->PopulateSelectionList(); |
| 19 | connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, | 20 | connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, |
| 20 | &ConfigureDialog::UpdateVisibleTabs); | 21 | &ConfigureDialog::UpdateVisibleTabs); |
| 21 | |||
| 22 | adjustSize(); | 22 | adjustSize(); |
| 23 | |||
| 24 | ui->selectorList->setCurrentRow(0); | 23 | ui->selectorList->setCurrentRow(0); |
| 24 | |||
| 25 | // Synchronise lists upon initialisation | ||
| 26 | ui->hotkeysTab->EmitHotkeysChanged(); | ||
| 25 | } | 27 | } |
| 26 | 28 | ||
| 27 | ConfigureDialog::~ConfigureDialog() = default; | 29 | ConfigureDialog::~ConfigureDialog() = default; |
| @@ -34,6 +36,7 @@ void ConfigureDialog::applyConfiguration() { | |||
| 34 | ui->systemTab->applyConfiguration(); | 36 | ui->systemTab->applyConfiguration(); |
| 35 | ui->profileManagerTab->applyConfiguration(); | 37 | ui->profileManagerTab->applyConfiguration(); |
| 36 | ui->inputTab->applyConfiguration(); | 38 | ui->inputTab->applyConfiguration(); |
| 39 | ui->hotkeysTab->applyConfiguration(registry); | ||
| 37 | ui->graphicsTab->applyConfiguration(); | 40 | ui->graphicsTab->applyConfiguration(); |
| 38 | ui->audioTab->applyConfiguration(); | 41 | ui->audioTab->applyConfiguration(); |
| 39 | ui->debugTab->applyConfiguration(); | 42 | ui->debugTab->applyConfiguration(); |
| @@ -47,7 +50,7 @@ void ConfigureDialog::PopulateSelectionList() { | |||
| 47 | {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}}, | 50 | {{tr("General"), {tr("General"), tr("Web"), tr("Debug"), tr("Game List")}}, |
| 48 | {tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}}, | 51 | {tr("System"), {tr("System"), tr("Profiles"), tr("Audio")}}, |
| 49 | {tr("Graphics"), {tr("Graphics")}}, | 52 | {tr("Graphics"), {tr("Graphics")}}, |
| 50 | {tr("Controls"), {tr("Input")}}}}; | 53 | {tr("Controls"), {tr("Input"), tr("Hotkeys")}}}}; |
| 51 | 54 | ||
| 52 | for (const auto& entry : items) { | 55 | for (const auto& entry : items) { |
| 53 | auto* const item = new QListWidgetItem(entry.first); | 56 | auto* const item = new QListWidgetItem(entry.first); |
| @@ -66,6 +69,7 @@ void ConfigureDialog::UpdateVisibleTabs() { | |||
| 66 | {tr("System"), ui->systemTab}, | 69 | {tr("System"), ui->systemTab}, |
| 67 | {tr("Profiles"), ui->profileManagerTab}, | 70 | {tr("Profiles"), ui->profileManagerTab}, |
| 68 | {tr("Input"), ui->inputTab}, | 71 | {tr("Input"), ui->inputTab}, |
| 72 | {tr("Hotkeys"), ui->hotkeysTab}, | ||
| 69 | {tr("Graphics"), ui->graphicsTab}, | 73 | {tr("Graphics"), ui->graphicsTab}, |
| 70 | {tr("Audio"), ui->audioTab}, | 74 | {tr("Audio"), ui->audioTab}, |
| 71 | {tr("Debug"), ui->debugTab}, | 75 | {tr("Debug"), ui->debugTab}, |
diff --git a/src/yuzu/configuration/configure_dialog.h b/src/yuzu/configuration/configure_dialog.h index 243d9fa09..2363ba584 100644 --- a/src/yuzu/configuration/configure_dialog.h +++ b/src/yuzu/configuration/configure_dialog.h | |||
| @@ -17,7 +17,7 @@ class ConfigureDialog : public QDialog { | |||
| 17 | Q_OBJECT | 17 | Q_OBJECT |
| 18 | 18 | ||
| 19 | public: | 19 | public: |
| 20 | explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry); | 20 | explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry); |
| 21 | ~ConfigureDialog() override; | 21 | ~ConfigureDialog() override; |
| 22 | 22 | ||
| 23 | void applyConfiguration(); | 23 | void applyConfiguration(); |
| @@ -28,4 +28,5 @@ private: | |||
| 28 | void PopulateSelectionList(); | 28 | void PopulateSelectionList(); |
| 29 | 29 | ||
| 30 | std::unique_ptr<Ui::ConfigureDialog> ui; | 30 | std::unique_ptr<Ui::ConfigureDialog> ui; |
| 31 | HotkeyRegistry& registry; | ||
| 31 | }; | 32 | }; |
diff --git a/src/yuzu/configuration/configure_general.cpp b/src/yuzu/configuration/configure_general.cpp index 389fcf667..eeb038afb 100644 --- a/src/yuzu/configuration/configure_general.cpp +++ b/src/yuzu/configuration/configure_general.cpp | |||
| @@ -35,10 +35,6 @@ void ConfigureGeneral::setConfiguration() { | |||
| 35 | ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); | 35 | ui->use_cpu_jit->setChecked(Settings::values.use_cpu_jit); |
| 36 | } | 36 | } |
| 37 | 37 | ||
| 38 | void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) { | ||
| 39 | ui->widget->Populate(registry); | ||
| 40 | } | ||
| 41 | |||
| 42 | void ConfigureGeneral::applyConfiguration() { | 38 | void ConfigureGeneral::applyConfiguration() { |
| 43 | UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); | 39 | UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked(); |
| 44 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); | 40 | UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked(); |
diff --git a/src/yuzu/configuration/configure_general.h b/src/yuzu/configuration/configure_general.h index 59738af40..df41d995b 100644 --- a/src/yuzu/configuration/configure_general.h +++ b/src/yuzu/configuration/configure_general.h | |||
| @@ -20,7 +20,6 @@ public: | |||
| 20 | explicit ConfigureGeneral(QWidget* parent = nullptr); | 20 | explicit ConfigureGeneral(QWidget* parent = nullptr); |
| 21 | ~ConfigureGeneral() override; | 21 | ~ConfigureGeneral() override; |
| 22 | 22 | ||
| 23 | void PopulateHotkeyList(const HotkeyRegistry& registry); | ||
| 24 | void applyConfiguration(); | 23 | void applyConfiguration(); |
| 25 | 24 | ||
| 26 | private: | 25 | private: |
diff --git a/src/yuzu/configuration/configure_general.ui b/src/yuzu/configuration/configure_general.ui index 01d1c0b8e..1a5721fe7 100644 --- a/src/yuzu/configuration/configure_general.ui +++ b/src/yuzu/configuration/configure_general.ui | |||
| @@ -98,22 +98,6 @@ | |||
| 98 | </widget> | 98 | </widget> |
| 99 | </item> | 99 | </item> |
| 100 | <item> | 100 | <item> |
| 101 | <widget class="QGroupBox" name="HotKeysGroupBox"> | ||
| 102 | <property name="title"> | ||
| 103 | <string>Hotkeys</string> | ||
| 104 | </property> | ||
| 105 | <layout class="QHBoxLayout" name="HotKeysHorizontalLayout"> | ||
| 106 | <item> | ||
| 107 | <layout class="QVBoxLayout" name="HotKeysVerticalLayout"> | ||
| 108 | <item> | ||
| 109 | <widget class="GHotkeysDialog" name="widget" native="true"/> | ||
| 110 | </item> | ||
| 111 | </layout> | ||
| 112 | </item> | ||
| 113 | </layout> | ||
| 114 | </widget> | ||
| 115 | </item> | ||
| 116 | <item> | ||
| 117 | <spacer name="verticalSpacer"> | 101 | <spacer name="verticalSpacer"> |
| 118 | <property name="orientation"> | 102 | <property name="orientation"> |
| 119 | <enum>Qt::Vertical</enum> | 103 | <enum>Qt::Vertical</enum> |
| @@ -130,14 +114,6 @@ | |||
| 130 | </item> | 114 | </item> |
| 131 | </layout> | 115 | </layout> |
| 132 | </widget> | 116 | </widget> |
| 133 | <customwidgets> | ||
| 134 | <customwidget> | ||
| 135 | <class>GHotkeysDialog</class> | ||
| 136 | <extends>QWidget</extends> | ||
| 137 | <header>hotkeys.h</header> | ||
| 138 | <container>1</container> | ||
| 139 | </customwidget> | ||
| 140 | </customwidgets> | ||
| 141 | <resources/> | 117 | <resources/> |
| 142 | <connections/> | 118 | <connections/> |
| 143 | </ui> | 119 | </ui> |
diff --git a/src/yuzu/configuration/configure_hotkeys.cpp b/src/yuzu/configuration/configure_hotkeys.cpp new file mode 100644 index 000000000..bfb562535 --- /dev/null +++ b/src/yuzu/configuration/configure_hotkeys.cpp | |||
| @@ -0,0 +1,121 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QMessageBox> | ||
| 6 | #include <QStandardItemModel> | ||
| 7 | #include "core/settings.h" | ||
| 8 | #include "ui_configure_hotkeys.h" | ||
| 9 | #include "yuzu/configuration/configure_hotkeys.h" | ||
| 10 | #include "yuzu/hotkeys.h" | ||
| 11 | #include "yuzu/util/sequence_dialog/sequence_dialog.h" | ||
| 12 | |||
| 13 | ConfigureHotkeys::ConfigureHotkeys(QWidget* parent) | ||
| 14 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureHotkeys>()) { | ||
| 15 | ui->setupUi(this); | ||
| 16 | setFocusPolicy(Qt::ClickFocus); | ||
| 17 | |||
| 18 | model = new QStandardItemModel(this); | ||
| 19 | model->setColumnCount(3); | ||
| 20 | model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Context")}); | ||
| 21 | |||
| 22 | connect(ui->hotkey_list, &QTreeView::doubleClicked, this, &ConfigureHotkeys::Configure); | ||
| 23 | ui->hotkey_list->setModel(model); | ||
| 24 | |||
| 25 | // TODO(Kloen): Make context configurable as well (hiding the column for now) | ||
| 26 | ui->hotkey_list->hideColumn(2); | ||
| 27 | |||
| 28 | ui->hotkey_list->setColumnWidth(0, 200); | ||
| 29 | ui->hotkey_list->resizeColumnToContents(1); | ||
| 30 | } | ||
| 31 | |||
| 32 | ConfigureHotkeys::~ConfigureHotkeys() = default; | ||
| 33 | |||
| 34 | void ConfigureHotkeys::EmitHotkeysChanged() { | ||
| 35 | emit HotkeysChanged(GetUsedKeyList()); | ||
| 36 | } | ||
| 37 | |||
| 38 | QList<QKeySequence> ConfigureHotkeys::GetUsedKeyList() const { | ||
| 39 | QList<QKeySequence> list; | ||
| 40 | for (int r = 0; r < model->rowCount(); r++) { | ||
| 41 | const QStandardItem* parent = model->item(r, 0); | ||
| 42 | for (int r2 = 0; r2 < parent->rowCount(); r2++) { | ||
| 43 | const QStandardItem* keyseq = parent->child(r2, 1); | ||
| 44 | list << QKeySequence::fromString(keyseq->text(), QKeySequence::NativeText); | ||
| 45 | } | ||
| 46 | } | ||
| 47 | return list; | ||
| 48 | } | ||
| 49 | |||
| 50 | void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) { | ||
| 51 | for (const auto& group : registry.hotkey_groups) { | ||
| 52 | auto* parent_item = new QStandardItem(group.first); | ||
| 53 | parent_item->setEditable(false); | ||
| 54 | for (const auto& hotkey : group.second) { | ||
| 55 | auto* action = new QStandardItem(hotkey.first); | ||
| 56 | auto* keyseq = | ||
| 57 | new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText)); | ||
| 58 | action->setEditable(false); | ||
| 59 | keyseq->setEditable(false); | ||
| 60 | parent_item->appendRow({action, keyseq}); | ||
| 61 | } | ||
| 62 | model->appendRow(parent_item); | ||
| 63 | } | ||
| 64 | |||
| 65 | ui->hotkey_list->expandAll(); | ||
| 66 | } | ||
| 67 | |||
| 68 | void ConfigureHotkeys::Configure(QModelIndex index) { | ||
| 69 | if (index.parent() == QModelIndex()) | ||
| 70 | return; | ||
| 71 | |||
| 72 | index = index.sibling(index.row(), 1); | ||
| 73 | auto* model = ui->hotkey_list->model(); | ||
| 74 | auto previous_key = model->data(index); | ||
| 75 | |||
| 76 | auto* hotkey_dialog = new SequenceDialog; | ||
| 77 | int return_code = hotkey_dialog->exec(); | ||
| 78 | |||
| 79 | auto key_sequence = hotkey_dialog->GetSequence(); | ||
| 80 | |||
| 81 | if (return_code == QDialog::Rejected || key_sequence.isEmpty()) | ||
| 82 | return; | ||
| 83 | |||
| 84 | if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) { | ||
| 85 | QMessageBox::critical(this, tr("Error in inputted key"), | ||
| 86 | tr("You're using a key that's already bound.")); | ||
| 87 | } else { | ||
| 88 | model->setData(index, key_sequence.toString(QKeySequence::NativeText)); | ||
| 89 | EmitHotkeysChanged(); | ||
| 90 | } | ||
| 91 | } | ||
| 92 | |||
| 93 | bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) { | ||
| 94 | return GetUsedKeyList().contains(key_sequence); | ||
| 95 | } | ||
| 96 | |||
| 97 | void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) { | ||
| 98 | for (int key_id = 0; key_id < model->rowCount(); key_id++) { | ||
| 99 | const QStandardItem* parent = model->item(key_id, 0); | ||
| 100 | for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) { | ||
| 101 | const QStandardItem* action = parent->child(key_column_id, 0); | ||
| 102 | const QStandardItem* keyseq = parent->child(key_column_id, 1); | ||
| 103 | for (auto& [group, sub_actions] : registry.hotkey_groups) { | ||
| 104 | if (group != parent->text()) | ||
| 105 | continue; | ||
| 106 | for (auto& [action_name, hotkey] : sub_actions) { | ||
| 107 | if (action_name != action->text()) | ||
| 108 | continue; | ||
| 109 | hotkey.keyseq = QKeySequence(keyseq->text()); | ||
| 110 | } | ||
| 111 | } | ||
| 112 | } | ||
| 113 | } | ||
| 114 | |||
| 115 | registry.SaveHotkeys(); | ||
| 116 | Settings::Apply(); | ||
| 117 | } | ||
| 118 | |||
| 119 | void ConfigureHotkeys::retranslateUi() { | ||
| 120 | ui->retranslateUi(this); | ||
| 121 | } | ||
diff --git a/src/yuzu/configuration/configure_hotkeys.h b/src/yuzu/configuration/configure_hotkeys.h new file mode 100644 index 000000000..cd203aad6 --- /dev/null +++ b/src/yuzu/configuration/configure_hotkeys.h | |||
| @@ -0,0 +1,48 @@ | |||
| 1 | // Copyright 2017 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QWidget> | ||
| 9 | #include "core/settings.h" | ||
| 10 | |||
| 11 | namespace Ui { | ||
| 12 | class ConfigureHotkeys; | ||
| 13 | } | ||
| 14 | |||
| 15 | class HotkeyRegistry; | ||
| 16 | class QStandardItemModel; | ||
| 17 | |||
| 18 | class ConfigureHotkeys : public QWidget { | ||
| 19 | Q_OBJECT | ||
| 20 | |||
| 21 | public: | ||
| 22 | explicit ConfigureHotkeys(QWidget* parent = nullptr); | ||
| 23 | ~ConfigureHotkeys() override; | ||
| 24 | |||
| 25 | void applyConfiguration(HotkeyRegistry& registry); | ||
| 26 | void retranslateUi(); | ||
| 27 | |||
| 28 | void EmitHotkeysChanged(); | ||
| 29 | |||
| 30 | /** | ||
| 31 | * Populates the hotkey list widget using data from the provided registry. | ||
| 32 | * Called everytime the Configure dialog is opened. | ||
| 33 | * @param registry The HotkeyRegistry whose data is used to populate the list. | ||
| 34 | */ | ||
| 35 | void Populate(const HotkeyRegistry& registry); | ||
| 36 | |||
| 37 | signals: | ||
| 38 | void HotkeysChanged(QList<QKeySequence> new_key_list); | ||
| 39 | |||
| 40 | private: | ||
| 41 | void Configure(QModelIndex index); | ||
| 42 | bool IsUsedKey(QKeySequence key_sequence); | ||
| 43 | QList<QKeySequence> GetUsedKeyList() const; | ||
| 44 | |||
| 45 | std::unique_ptr<Ui::ConfigureHotkeys> ui; | ||
| 46 | |||
| 47 | QStandardItemModel* model; | ||
| 48 | }; | ||
diff --git a/src/yuzu/configuration/configure_hotkeys.ui b/src/yuzu/configuration/configure_hotkeys.ui new file mode 100644 index 000000000..0d0b70f38 --- /dev/null +++ b/src/yuzu/configuration/configure_hotkeys.ui | |||
| @@ -0,0 +1,42 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureHotkeys</class> | ||
| 4 | <widget class="QWidget" name="ConfigureHotkeys"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>363</width> | ||
| 10 | <height>388</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Hotkey Settings</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout" name="verticalLayout_2"> | ||
| 19 | <item> | ||
| 20 | <widget class="QLabel" name="label_2"> | ||
| 21 | <property name="text"> | ||
| 22 | <string>Double-click on a binding to change it.</string> | ||
| 23 | </property> | ||
| 24 | </widget> | ||
| 25 | </item> | ||
| 26 | <item> | ||
| 27 | <widget class="QTreeView" name="hotkey_list"> | ||
| 28 | <property name="editTriggers"> | ||
| 29 | <set>QAbstractItemView::NoEditTriggers</set> | ||
| 30 | </property> | ||
| 31 | <property name="sortingEnabled"> | ||
| 32 | <bool>false</bool> | ||
| 33 | </property> | ||
| 34 | </widget> | ||
| 35 | </item> | ||
| 36 | </layout> | ||
| 37 | </item> | ||
| 38 | </layout> | ||
| 39 | </widget> | ||
| 40 | <resources/> | ||
| 41 | <connections/> | ||
| 42 | </ui> \ No newline at end of file | ||
diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index dce399774..4582e7f21 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp | |||
| @@ -2,7 +2,6 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <map> | ||
| 6 | #include <QKeySequence> | 5 | #include <QKeySequence> |
| 7 | #include <QShortcut> | 6 | #include <QShortcut> |
| 8 | #include <QTreeWidgetItem> | 7 | #include <QTreeWidgetItem> |
| @@ -13,47 +12,32 @@ | |||
| 13 | HotkeyRegistry::HotkeyRegistry() = default; | 12 | HotkeyRegistry::HotkeyRegistry() = default; |
| 14 | HotkeyRegistry::~HotkeyRegistry() = default; | 13 | HotkeyRegistry::~HotkeyRegistry() = default; |
| 15 | 14 | ||
| 16 | void HotkeyRegistry::LoadHotkeys() { | ||
| 17 | // Make sure NOT to use a reference here because it would become invalid once we call | ||
| 18 | // beginGroup() | ||
| 19 | for (auto shortcut : UISettings::values.shortcuts) { | ||
| 20 | const QStringList cat = shortcut.first.split('/'); | ||
| 21 | Q_ASSERT(cat.size() >= 2); | ||
| 22 | |||
| 23 | // RegisterHotkey assigns default keybindings, so use old values as default parameters | ||
| 24 | Hotkey& hk = hotkey_groups[cat[0]][cat[1]]; | ||
| 25 | if (!shortcut.second.first.isEmpty()) { | ||
| 26 | hk.keyseq = QKeySequence::fromString(shortcut.second.first); | ||
| 27 | hk.context = static_cast<Qt::ShortcutContext>(shortcut.second.second); | ||
| 28 | } | ||
| 29 | if (hk.shortcut) | ||
| 30 | hk.shortcut->setKey(hk.keyseq); | ||
| 31 | } | ||
| 32 | } | ||
| 33 | |||
| 34 | void HotkeyRegistry::SaveHotkeys() { | 15 | void HotkeyRegistry::SaveHotkeys() { |
| 35 | UISettings::values.shortcuts.clear(); | 16 | UISettings::values.shortcuts.clear(); |
| 36 | for (const auto& group : hotkey_groups) { | 17 | for (const auto& group : hotkey_groups) { |
| 37 | for (const auto& hotkey : group.second) { | 18 | for (const auto& hotkey : group.second) { |
| 38 | UISettings::values.shortcuts.emplace_back( | 19 | UISettings::values.shortcuts.push_back( |
| 39 | UISettings::Shortcut(group.first + '/' + hotkey.first, | 20 | {hotkey.first, group.first, |
| 40 | UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), | 21 | UISettings::ContextualShortcut(hotkey.second.keyseq.toString(), |
| 41 | hotkey.second.context))); | 22 | hotkey.second.context)}); |
| 42 | } | 23 | } |
| 43 | } | 24 | } |
| 44 | } | 25 | } |
| 45 | 26 | ||
| 46 | void HotkeyRegistry::RegisterHotkey(const QString& group, const QString& action, | 27 | void HotkeyRegistry::LoadHotkeys() { |
| 47 | const QKeySequence& default_keyseq, | 28 | // Make sure NOT to use a reference here because it would become invalid once we call |
| 48 | Qt::ShortcutContext default_context) { | 29 | // beginGroup() |
| 49 | auto& hotkey_group = hotkey_groups[group]; | 30 | for (auto shortcut : UISettings::values.shortcuts) { |
| 50 | if (hotkey_group.find(action) != hotkey_group.end()) { | 31 | Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name]; |
| 51 | return; | 32 | if (!shortcut.shortcut.first.isEmpty()) { |
| 33 | hk.keyseq = QKeySequence::fromString(shortcut.shortcut.first, QKeySequence::NativeText); | ||
| 34 | hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.second); | ||
| 35 | } | ||
| 36 | if (hk.shortcut) { | ||
| 37 | hk.shortcut->disconnect(); | ||
| 38 | hk.shortcut->setKey(hk.keyseq); | ||
| 39 | } | ||
| 52 | } | 40 | } |
| 53 | |||
| 54 | auto& hotkey_action = hotkey_groups[group][action]; | ||
| 55 | hotkey_action.keyseq = default_keyseq; | ||
| 56 | hotkey_action.context = default_context; | ||
| 57 | } | 41 | } |
| 58 | 42 | ||
| 59 | QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { | 43 | QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) { |
| @@ -65,24 +49,11 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action | |||
| 65 | return hk.shortcut; | 49 | return hk.shortcut; |
| 66 | } | 50 | } |
| 67 | 51 | ||
| 68 | GHotkeysDialog::GHotkeysDialog(QWidget* parent) : QWidget(parent) { | 52 | QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) { |
| 69 | ui.setupUi(this); | 53 | return hotkey_groups[group][action].keyseq; |
| 70 | } | 54 | } |
| 71 | 55 | ||
| 72 | void GHotkeysDialog::Populate(const HotkeyRegistry& registry) { | 56 | Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group, |
| 73 | for (const auto& group : registry.hotkey_groups) { | 57 | const QString& action) { |
| 74 | QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group.first)); | 58 | return hotkey_groups[group][action].context; |
| 75 | for (const auto& hotkey : group.second) { | ||
| 76 | QStringList columns; | ||
| 77 | columns << hotkey.first << hotkey.second.keyseq.toString(); | ||
| 78 | QTreeWidgetItem* item = new QTreeWidgetItem(columns); | ||
| 79 | toplevel_item->addChild(item); | ||
| 80 | } | ||
| 81 | ui.treeWidget->addTopLevelItem(toplevel_item); | ||
| 82 | } | ||
| 83 | // TODO: Make context configurable as well (hiding the column for now) | ||
| 84 | ui.treeWidget->setColumnCount(2); | ||
| 85 | |||
| 86 | ui.treeWidget->resizeColumnToContents(0); | ||
| 87 | ui.treeWidget->resizeColumnToContents(1); | ||
| 88 | } | 59 | } |
diff --git a/src/yuzu/hotkeys.h b/src/yuzu/hotkeys.h index f38e6c002..4f526dc7e 100644 --- a/src/yuzu/hotkeys.h +++ b/src/yuzu/hotkeys.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <map> | 7 | #include <map> |
| 8 | #include "ui_hotkeys.h" | ||
| 9 | 8 | ||
| 10 | class QDialog; | 9 | class QDialog; |
| 11 | class QKeySequence; | 10 | class QKeySequence; |
| @@ -14,7 +13,7 @@ class QShortcut; | |||
| 14 | 13 | ||
| 15 | class HotkeyRegistry final { | 14 | class HotkeyRegistry final { |
| 16 | public: | 15 | public: |
| 17 | friend class GHotkeysDialog; | 16 | friend class ConfigureHotkeys; |
| 18 | 17 | ||
| 19 | explicit HotkeyRegistry(); | 18 | explicit HotkeyRegistry(); |
| 20 | ~HotkeyRegistry(); | 19 | ~HotkeyRegistry(); |
| @@ -49,22 +48,27 @@ public: | |||
| 49 | QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); | 48 | QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget); |
| 50 | 49 | ||
| 51 | /** | 50 | /** |
| 52 | * Register a hotkey. | 51 | * Returns a QKeySequence object whose signal can be connected to QAction::setShortcut. |
| 53 | * | 52 | * |
| 54 | * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger") | 53 | * @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger"). |
| 55 | * @param action Name of the action (e.g. "Start Emulation", "Load Image") | 54 | * @param action Name of the action (e.g. "Start Emulation", "Load Image"). |
| 56 | * @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the | 55 | */ |
| 57 | * settings file before | 56 | QKeySequence GetKeySequence(const QString& group, const QString& action); |
| 58 | * @param default_context Default context to assign if the hotkey wasn't present in the settings | 57 | |
| 59 | * file before | 58 | /** |
| 60 | * @warning Both the group and action strings will be displayed in the hotkey settings dialog | 59 | * Returns a Qt::ShortcutContext object who can be connected to other |
| 60 | * QAction::setShortcutContext. | ||
| 61 | * | ||
| 62 | * @param group General group this shortcut context belongs to (e.g. "Main Window", | ||
| 63 | * "Debugger"). | ||
| 64 | * @param action Name of the action (e.g. "Start Emulation", "Load Image"). | ||
| 61 | */ | 65 | */ |
| 62 | void RegisterHotkey(const QString& group, const QString& action, | 66 | Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action); |
| 63 | const QKeySequence& default_keyseq = {}, | ||
| 64 | Qt::ShortcutContext default_context = Qt::WindowShortcut); | ||
| 65 | 67 | ||
| 66 | private: | 68 | private: |
| 67 | struct Hotkey { | 69 | struct Hotkey { |
| 70 | Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {} | ||
| 71 | |||
| 68 | QKeySequence keyseq; | 72 | QKeySequence keyseq; |
| 69 | QShortcut* shortcut = nullptr; | 73 | QShortcut* shortcut = nullptr; |
| 70 | Qt::ShortcutContext context = Qt::WindowShortcut; | 74 | Qt::ShortcutContext context = Qt::WindowShortcut; |
| @@ -75,15 +79,3 @@ private: | |||
| 75 | 79 | ||
| 76 | HotkeyGroupMap hotkey_groups; | 80 | HotkeyGroupMap hotkey_groups; |
| 77 | }; | 81 | }; |
| 78 | |||
| 79 | class GHotkeysDialog : public QWidget { | ||
| 80 | Q_OBJECT | ||
| 81 | |||
| 82 | public: | ||
| 83 | explicit GHotkeysDialog(QWidget* parent = nullptr); | ||
| 84 | |||
| 85 | void Populate(const HotkeyRegistry& registry); | ||
| 86 | |||
| 87 | private: | ||
| 88 | Ui::hotkeys ui; | ||
| 89 | }; | ||
diff --git a/src/yuzu/hotkeys.ui b/src/yuzu/hotkeys.ui deleted file mode 100644 index 050fe064e..000000000 --- a/src/yuzu/hotkeys.ui +++ /dev/null | |||
| @@ -1,46 +0,0 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>hotkeys</class> | ||
| 4 | <widget class="QWidget" name="hotkeys"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>363</width> | ||
| 10 | <height>388</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Hotkey Settings</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QVBoxLayout" name="verticalLayout"> | ||
| 17 | <item> | ||
| 18 | <widget class="QTreeWidget" name="treeWidget"> | ||
| 19 | <property name="selectionBehavior"> | ||
| 20 | <enum>QAbstractItemView::SelectItems</enum> | ||
| 21 | </property> | ||
| 22 | <property name="headerHidden"> | ||
| 23 | <bool>false</bool> | ||
| 24 | </property> | ||
| 25 | <column> | ||
| 26 | <property name="text"> | ||
| 27 | <string>Action</string> | ||
| 28 | </property> | ||
| 29 | </column> | ||
| 30 | <column> | ||
| 31 | <property name="text"> | ||
| 32 | <string>Hotkey</string> | ||
| 33 | </property> | ||
| 34 | </column> | ||
| 35 | <column> | ||
| 36 | <property name="text"> | ||
| 37 | <string>Context</string> | ||
| 38 | </property> | ||
| 39 | </column> | ||
| 40 | </widget> | ||
| 41 | </item> | ||
| 42 | </layout> | ||
| 43 | </widget> | ||
| 44 | <resources/> | ||
| 45 | <connections/> | ||
| 46 | </ui> | ||
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2b9db69a3..77b6f7cc8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -514,33 +514,34 @@ void GMainWindow::InitializeRecentFileMenuActions() { | |||
| 514 | } | 514 | } |
| 515 | 515 | ||
| 516 | void GMainWindow::InitializeHotkeys() { | 516 | void GMainWindow::InitializeHotkeys() { |
| 517 | hotkey_registry.RegisterHotkey("Main Window", "Load File", QKeySequence::Open); | ||
| 518 | hotkey_registry.RegisterHotkey("Main Window", "Start Emulation"); | ||
| 519 | hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4)); | ||
| 520 | hotkey_registry.RegisterHotkey("Main Window", "Restart", QKeySequence(Qt::Key_F5)); | ||
| 521 | hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen); | ||
| 522 | hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape), | ||
| 523 | Qt::ApplicationShortcut); | ||
| 524 | hotkey_registry.RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"), | ||
| 525 | Qt::ApplicationShortcut); | ||
| 526 | hotkey_registry.RegisterHotkey("Main Window", "Increase Speed Limit", QKeySequence("+"), | ||
| 527 | Qt::ApplicationShortcut); | ||
| 528 | hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"), | ||
| 529 | Qt::ApplicationShortcut); | ||
| 530 | hotkey_registry.RegisterHotkey("Main Window", "Load Amiibo", QKeySequence(Qt::Key_F2), | ||
| 531 | Qt::ApplicationShortcut); | ||
| 532 | hotkey_registry.RegisterHotkey("Main Window", "Capture Screenshot", | ||
| 533 | QKeySequence(QKeySequence::Print)); | ||
| 534 | hotkey_registry.RegisterHotkey("Main Window", "Change Docked Mode", QKeySequence(Qt::Key_F10)); | ||
| 535 | |||
| 536 | hotkey_registry.LoadHotkeys(); | 517 | hotkey_registry.LoadHotkeys(); |
| 537 | 518 | ||
| 519 | ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Load File")); | ||
| 520 | ui.action_Load_File->setShortcutContext( | ||
| 521 | hotkey_registry.GetShortcutContext("Main Window", "Load File")); | ||
| 522 | |||
| 523 | ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Exit yuzu")); | ||
| 524 | ui.action_Exit->setShortcutContext( | ||
| 525 | hotkey_registry.GetShortcutContext("Main Window", "Exit yuzu")); | ||
| 526 | |||
| 527 | ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Stop Emulation")); | ||
| 528 | ui.action_Stop->setShortcutContext( | ||
| 529 | hotkey_registry.GetShortcutContext("Main Window", "Stop Emulation")); | ||
| 530 | |||
| 531 | ui.action_Show_Filter_Bar->setShortcut( | ||
| 532 | hotkey_registry.GetKeySequence("Main Window", "Toggle Filter Bar")); | ||
| 533 | ui.action_Show_Filter_Bar->setShortcutContext( | ||
| 534 | hotkey_registry.GetShortcutContext("Main Window", "Toggle Filter Bar")); | ||
| 535 | |||
| 536 | ui.action_Show_Status_Bar->setShortcut( | ||
| 537 | hotkey_registry.GetKeySequence("Main Window", "Toggle Status Bar")); | ||
| 538 | ui.action_Show_Status_Bar->setShortcutContext( | ||
| 539 | hotkey_registry.GetShortcutContext("Main Window", "Toggle Status Bar")); | ||
| 540 | |||
| 538 | connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, | 541 | connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated, |
| 539 | this, &GMainWindow::OnMenuLoadFile); | 542 | this, &GMainWindow::OnMenuLoadFile); |
| 540 | connect(hotkey_registry.GetHotkey("Main Window", "Start Emulation", this), | 543 | connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause Emulation", this), |
| 541 | &QShortcut::activated, this, &GMainWindow::OnStartGame); | 544 | &QShortcut::activated, this, [&] { |
| 542 | connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated, | ||
| 543 | this, [&] { | ||
| 544 | if (emulation_running) { | 545 | if (emulation_running) { |
| 545 | if (emu_thread->IsRunning()) { | 546 | if (emu_thread->IsRunning()) { |
| 546 | OnPauseGame(); | 547 | OnPauseGame(); |
| @@ -549,8 +550,8 @@ void GMainWindow::InitializeHotkeys() { | |||
| 549 | } | 550 | } |
| 550 | } | 551 | } |
| 551 | }); | 552 | }); |
| 552 | connect(hotkey_registry.GetHotkey("Main Window", "Restart", this), &QShortcut::activated, this, | 553 | connect(hotkey_registry.GetHotkey("Main Window", "Restart Emulation", this), |
| 553 | [this] { | 554 | &QShortcut::activated, this, [this] { |
| 554 | if (!Core::System::GetInstance().IsPoweredOn()) | 555 | if (!Core::System::GetInstance().IsPoweredOn()) |
| 555 | return; | 556 | return; |
| 556 | BootGame(QString(game_path)); | 557 | BootGame(QString(game_path)); |
| @@ -697,7 +698,6 @@ void GMainWindow::ConnectMenuEvents() { | |||
| 697 | &GMainWindow::ToggleWindowMode); | 698 | &GMainWindow::ToggleWindowMode); |
| 698 | connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, | 699 | connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this, |
| 699 | &GMainWindow::OnDisplayTitleBars); | 700 | &GMainWindow::OnDisplayTitleBars); |
| 700 | ui.action_Show_Filter_Bar->setShortcut(tr("CTRL+F")); | ||
| 701 | connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); | 701 | connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar); |
| 702 | connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); | 702 | connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible); |
| 703 | 703 | ||
| @@ -1662,6 +1662,7 @@ void GMainWindow::OnConfigure() { | |||
| 1662 | auto result = configureDialog.exec(); | 1662 | auto result = configureDialog.exec(); |
| 1663 | if (result == QDialog::Accepted) { | 1663 | if (result == QDialog::Accepted) { |
| 1664 | configureDialog.applyConfiguration(); | 1664 | configureDialog.applyConfiguration(); |
| 1665 | InitializeHotkeys(); | ||
| 1665 | if (UISettings::values.theme != old_theme) | 1666 | if (UISettings::values.theme != old_theme) |
| 1666 | UpdateUITheme(); | 1667 | UpdateUITheme(); |
| 1667 | if (UISettings::values.enable_discord_presence != old_discord_presence) | 1668 | if (UISettings::values.enable_discord_presence != old_discord_presence) |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 7f3aa998e..ba406ae64 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -120,7 +120,6 @@ private: | |||
| 120 | void InitializeWidgets(); | 120 | void InitializeWidgets(); |
| 121 | void InitializeDebugWidgets(); | 121 | void InitializeDebugWidgets(); |
| 122 | void InitializeRecentFileMenuActions(); | 122 | void InitializeRecentFileMenuActions(); |
| 123 | void InitializeHotkeys(); | ||
| 124 | 123 | ||
| 125 | void SetDefaultUIGeometry(); | 124 | void SetDefaultUIGeometry(); |
| 126 | void RestoreUIState(); | 125 | void RestoreUIState(); |
| @@ -196,6 +195,7 @@ private slots: | |||
| 196 | void OnAbout(); | 195 | void OnAbout(); |
| 197 | void OnToggleFilterBar(); | 196 | void OnToggleFilterBar(); |
| 198 | void OnDisplayTitleBars(bool); | 197 | void OnDisplayTitleBars(bool); |
| 198 | void InitializeHotkeys(); | ||
| 199 | void ToggleFullscreen(); | 199 | void ToggleFullscreen(); |
| 200 | void ShowFullscreen(); | 200 | void ShowFullscreen(); |
| 201 | void HideFullscreen(); | 201 | void HideFullscreen(); |
diff --git a/src/yuzu/ui_settings.cpp b/src/yuzu/ui_settings.cpp index a314493fc..4bdc302e0 100644 --- a/src/yuzu/ui_settings.cpp +++ b/src/yuzu/ui_settings.cpp | |||
| @@ -12,5 +12,4 @@ const Themes themes{{ | |||
| 12 | }}; | 12 | }}; |
| 13 | 13 | ||
| 14 | Values values = {}; | 14 | Values values = {}; |
| 15 | |||
| 16 | } // namespace UISettings | 15 | } // namespace UISettings |
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 82aaeedb0..45e705b61 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h | |||
| @@ -15,7 +15,12 @@ | |||
| 15 | namespace UISettings { | 15 | namespace UISettings { |
| 16 | 16 | ||
| 17 | using ContextualShortcut = std::pair<QString, int>; | 17 | using ContextualShortcut = std::pair<QString, int>; |
| 18 | using Shortcut = std::pair<QString, ContextualShortcut>; | 18 | |
| 19 | struct Shortcut { | ||
| 20 | QString name; | ||
| 21 | QString group; | ||
| 22 | ContextualShortcut shortcut; | ||
| 23 | }; | ||
| 19 | 24 | ||
| 20 | using Themes = std::array<std::pair<const char*, const char*>, 2>; | 25 | using Themes = std::array<std::pair<const char*, const char*>, 2>; |
| 21 | extern const Themes themes; | 26 | extern const Themes themes; |
diff --git a/src/yuzu/util/sequence_dialog/sequence_dialog.cpp b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp new file mode 100644 index 000000000..d3edf6ec3 --- /dev/null +++ b/src/yuzu/util/sequence_dialog/sequence_dialog.cpp | |||
| @@ -0,0 +1,37 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <QDialogButtonBox> | ||
| 6 | #include <QKeySequenceEdit> | ||
| 7 | #include <QVBoxLayout> | ||
| 8 | #include "yuzu/util/sequence_dialog/sequence_dialog.h" | ||
| 9 | |||
| 10 | SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) { | ||
| 11 | setWindowTitle(tr("Enter a hotkey")); | ||
| 12 | auto* layout = new QVBoxLayout(this); | ||
| 13 | key_sequence = new QKeySequenceEdit; | ||
| 14 | layout->addWidget(key_sequence); | ||
| 15 | auto* buttons = | ||
| 16 | new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal); | ||
| 17 | buttons->setCenterButtons(true); | ||
| 18 | layout->addWidget(buttons); | ||
| 19 | connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept); | ||
| 20 | connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject); | ||
| 21 | setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); | ||
| 22 | } | ||
| 23 | |||
| 24 | SequenceDialog::~SequenceDialog() = default; | ||
| 25 | |||
| 26 | QKeySequence SequenceDialog::GetSequence() const { | ||
| 27 | // Only the first key is returned. The other 3, if present, are ignored. | ||
| 28 | return QKeySequence(key_sequence->keySequence()[0]); | ||
| 29 | } | ||
| 30 | |||
| 31 | bool SequenceDialog::focusNextPrevChild(bool next) { | ||
| 32 | return false; | ||
| 33 | } | ||
| 34 | |||
| 35 | void SequenceDialog::closeEvent(QCloseEvent*) { | ||
| 36 | reject(); | ||
| 37 | } | ||
diff --git a/src/yuzu/util/sequence_dialog/sequence_dialog.h b/src/yuzu/util/sequence_dialog/sequence_dialog.h new file mode 100644 index 000000000..969c77740 --- /dev/null +++ b/src/yuzu/util/sequence_dialog/sequence_dialog.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // Copyright 2018 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <QDialog> | ||
| 8 | |||
| 9 | class QKeySequenceEdit; | ||
| 10 | |||
| 11 | class SequenceDialog : public QDialog { | ||
| 12 | Q_OBJECT | ||
| 13 | |||
| 14 | public: | ||
| 15 | explicit SequenceDialog(QWidget* parent = nullptr); | ||
| 16 | ~SequenceDialog() override; | ||
| 17 | |||
| 18 | QKeySequence GetSequence() const; | ||
| 19 | void closeEvent(QCloseEvent*) override; | ||
| 20 | |||
| 21 | private: | ||
| 22 | QKeySequenceEdit* key_sequence; | ||
| 23 | bool focusNextPrevChild(bool next) override; | ||
| 24 | }; | ||