Merge pull request #4437 from adityaruplaha/hotkey-config-squashed
citra-qt: Make hotkeys configurable via the GUI (Attempt 2)
This commit is contained in:
commit
f620c862f3
|
@ -41,6 +41,8 @@ add_executable(citra-qt
|
||||||
configuration/configure_general.h
|
configuration/configure_general.h
|
||||||
configuration/configure_graphics.cpp
|
configuration/configure_graphics.cpp
|
||||||
configuration/configure_graphics.h
|
configuration/configure_graphics.h
|
||||||
|
configuration/configure_hotkeys.cpp
|
||||||
|
configuration/configure_hotkeys.h
|
||||||
configuration/configure_input.cpp
|
configuration/configure_input.cpp
|
||||||
configuration/configure_input.h
|
configuration/configure_input.h
|
||||||
configuration/configure_motion_touch.cpp
|
configuration/configure_motion_touch.cpp
|
||||||
|
@ -109,8 +111,10 @@ add_executable(citra-qt
|
||||||
updater/updater.cpp
|
updater/updater.cpp
|
||||||
updater/updater.h
|
updater/updater.h
|
||||||
updater/updater_p.h
|
updater/updater_p.h
|
||||||
util/clickable_label.h
|
|
||||||
util/clickable_label.cpp
|
util/clickable_label.cpp
|
||||||
|
util/clickable_label.h
|
||||||
|
util/sequence_dialog/sequence_dialog.cpp
|
||||||
|
util/sequence_dialog/sequence_dialog.h
|
||||||
util/spinbox.cpp
|
util/spinbox.cpp
|
||||||
util/spinbox.h
|
util/spinbox.h
|
||||||
util/util.cpp
|
util/util.cpp
|
||||||
|
@ -126,6 +130,7 @@ set(UIS
|
||||||
configuration/configure_debug.ui
|
configuration/configure_debug.ui
|
||||||
configuration/configure_general.ui
|
configuration/configure_general.ui
|
||||||
configuration/configure_graphics.ui
|
configuration/configure_graphics.ui
|
||||||
|
configuration/configure_hotkeys.ui
|
||||||
configuration/configure_input.ui
|
configuration/configure_input.ui
|
||||||
configuration/configure_motion_touch.ui
|
configuration/configure_motion_touch.ui
|
||||||
configuration/configure_system.ui
|
configuration/configure_system.ui
|
||||||
|
@ -140,7 +145,6 @@ set(UIS
|
||||||
multiplayer/moderation_dialog.ui
|
multiplayer/moderation_dialog.ui
|
||||||
aboutdialog.ui
|
aboutdialog.ui
|
||||||
cheats.ui
|
cheats.ui
|
||||||
hotkeys.ui
|
|
||||||
main.ui
|
main.ui
|
||||||
compatdb.ui
|
compatdb.ui
|
||||||
)
|
)
|
||||||
|
|
|
@ -3,10 +3,11 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <array>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
#include <QKeySequence>
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include "citra_qt/configuration/config.h"
|
#include "citra_qt/configuration/config.h"
|
||||||
#include "citra_qt/ui_settings.h"
|
|
||||||
#include "common/file_util.h"
|
#include "common/file_util.h"
|
||||||
#include "core/hle/service/service.h"
|
#include "core/hle/service/service.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
|
@ -19,7 +20,6 @@ Config::Config() {
|
||||||
FileUtil::CreateFullPath(qt_config_loc);
|
FileUtil::CreateFullPath(qt_config_loc);
|
||||||
qt_config =
|
qt_config =
|
||||||
std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
|
std::make_unique<QSettings>(QString::fromStdString(qt_config_loc), QSettings::IniFormat);
|
||||||
|
|
||||||
Reload();
|
Reload();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,6 +50,31 @@ const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs> Config:
|
||||||
},
|
},
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
// This shouldn't have anything except static initializers (no functions). So
|
||||||
|
// QKeySequnce(...).toString() is NOT ALLOWED HERE.
|
||||||
|
// This must be in alphabetical order according to action name as it must have the same order as
|
||||||
|
// UISetting::values.shortcuts, which is alphabetically ordered.
|
||||||
|
const std::array<UISettings::Shortcut, 19> Config::default_hotkeys{
|
||||||
|
{{"Advance Frame", "Main Window", {"\\", Qt::ApplicationShortcut}},
|
||||||
|
{"Capture Screenshot", "Main Window", {"Ctrl+P", Qt::ApplicationShortcut}},
|
||||||
|
{"Continue/Pause Emulation", "Main Window", {"F4", Qt::WindowShortcut}},
|
||||||
|
{"Decrease Speed Limit", "Main Window", {"-", Qt::ApplicationShortcut}},
|
||||||
|
{"Exit Citra", "Main Window", {"Ctrl+Q", Qt::WindowShortcut}},
|
||||||
|
{"Exit Fullscreen", "Main Window", {"Esc", Qt::WindowShortcut}},
|
||||||
|
{"Fullscreen", "Main Window", {"F11", Qt::WindowShortcut}},
|
||||||
|
{"Increase Speed Limit", "Main Window", {"+", Qt::ApplicationShortcut}},
|
||||||
|
{"Load Amiibo", "Main Window", {"F2", Qt::ApplicationShortcut}},
|
||||||
|
{"Load File", "Main Window", {"Ctrl+O", Qt::WindowShortcut}},
|
||||||
|
{"Remove Amiibo", "Main Window", {"F3", Qt::ApplicationShortcut}},
|
||||||
|
{"Restart Emulation", "Main Window", {"F6", Qt::WindowShortcut}},
|
||||||
|
{"Stop Emulation", "Main Window", {"F5", Qt::WindowShortcut}},
|
||||||
|
{"Swap Screens", "Main Window", {"F9", Qt::WindowShortcut}},
|
||||||
|
{"Toggle Filter Bar", "Main Window", {"Ctrl+F", Qt::WindowShortcut}},
|
||||||
|
{"Toggle Frame Advancing", "Main Window", {"Ctrl+A", Qt::ApplicationShortcut}},
|
||||||
|
{"Toggle Screen Layout", "Main Window", {"F10", Qt::WindowShortcut}},
|
||||||
|
{"Toggle Speed Limit", "Main Window", {"Ctrl+Z", Qt::ApplicationShortcut}},
|
||||||
|
{"Toggle Status Bar", "Main Window", {"Ctrl+S", Qt::WindowShortcut}}}};
|
||||||
|
|
||||||
void Config::ReadValues() {
|
void Config::ReadValues() {
|
||||||
qt_config->beginGroup("Controls");
|
qt_config->beginGroup("Controls");
|
||||||
|
|
||||||
|
@ -318,20 +343,15 @@ void Config::ReadValues() {
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Shortcuts");
|
qt_config->beginGroup("Shortcuts");
|
||||||
QStringList groups = qt_config->childGroups();
|
for (auto [name, group, shortcut] : default_hotkeys) {
|
||||||
for (auto group : groups) {
|
auto [keyseq, context] = shortcut;
|
||||||
qt_config->beginGroup(group);
|
qt_config->beginGroup(group);
|
||||||
|
qt_config->beginGroup(name);
|
||||||
QStringList hotkeys = qt_config->childGroups();
|
UISettings::values.shortcuts.push_back(
|
||||||
for (auto hotkey : hotkeys) {
|
{name,
|
||||||
qt_config->beginGroup(hotkey);
|
group,
|
||||||
UISettings::values.shortcuts.emplace_back(UISettings::Shortcut(
|
{ReadSetting("KeySeq", keyseq).toString(), ReadSetting("Context", context).toInt()}});
|
||||||
group + "/" + hotkey,
|
|
||||||
UISettings::ContextualShortcut(ReadSetting("KeySeq").toString(),
|
|
||||||
ReadSetting("Context").toInt())));
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
|
||||||
|
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
@ -563,9 +583,16 @@ void Config::SaveValues() {
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
qt_config->beginGroup("Shortcuts");
|
qt_config->beginGroup("Shortcuts");
|
||||||
for (auto shortcut : UISettings::values.shortcuts) {
|
// Lengths of UISettings::values.shortcuts & default_hotkeys are same.
|
||||||
WriteSetting(shortcut.first + "/KeySeq", shortcut.second.first);
|
// However, their ordering must also be the same.
|
||||||
WriteSetting(shortcut.first + "/Context", shortcut.second.second);
|
for (std::size_t i = 0; i < default_hotkeys.size(); i++) {
|
||||||
|
auto [name, group, shortcut] = UISettings::values.shortcuts[i];
|
||||||
|
qt_config->beginGroup(group);
|
||||||
|
qt_config->beginGroup(name);
|
||||||
|
WriteSetting("KeySeq", shortcut.first, default_hotkeys[i].shortcut.first);
|
||||||
|
WriteSetting("Context", shortcut.second, default_hotkeys[i].shortcut.second);
|
||||||
|
qt_config->endGroup();
|
||||||
|
qt_config->endGroup();
|
||||||
}
|
}
|
||||||
qt_config->endGroup();
|
qt_config->endGroup();
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <QVariant>
|
#include <QVariant>
|
||||||
|
#include "citra_qt/ui_settings.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
|
||||||
class QSettings;
|
class QSettings;
|
||||||
|
@ -31,6 +32,8 @@ private:
|
||||||
void WriteSetting(const QString& name, const QVariant& value);
|
void WriteSetting(const QString& name, const QVariant& value);
|
||||||
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
|
void WriteSetting(const QString& name, const QVariant& value, const QVariant& default_value);
|
||||||
|
|
||||||
|
static const std::array<UISettings::Shortcut, 19> default_hotkeys;
|
||||||
|
|
||||||
std::unique_ptr<QSettings> qt_config;
|
std::unique_ptr<QSettings> qt_config;
|
||||||
std::string qt_config_loc;
|
std::string qt_config_loc;
|
||||||
};
|
};
|
||||||
|
|
|
@ -38,6 +38,11 @@
|
||||||
<string>Input</string>
|
<string>Input</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="ConfigureHotkeys" name="hotkeysTab">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>Hotkeys</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
<widget class="ConfigureGraphics" name="graphicsTab">
|
<widget class="ConfigureGraphics" name="graphicsTab">
|
||||||
<attribute name="title">
|
<attribute name="title">
|
||||||
<string>Graphics</string>
|
<string>Graphics</string>
|
||||||
|
@ -118,6 +123,12 @@
|
||||||
<header>configuration/configure_input.h</header>
|
<header>configuration/configure_input.h</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>ConfigureHotkeys</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>configuration/configure_hotkeys.h</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
<customwidget>
|
<customwidget>
|
||||||
<class>ConfigureGraphics</class>
|
<class>ConfigureGraphics</class>
|
||||||
<extends>QWidget</extends>
|
<extends>QWidget</extends>
|
||||||
|
|
|
@ -10,18 +10,27 @@
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
#include "ui_configure.h"
|
#include "ui_configure.h"
|
||||||
|
|
||||||
ConfigureDialog::ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry)
|
ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry)
|
||||||
: QDialog(parent), ui(new Ui::ConfigureDialog) {
|
: QDialog(parent), registry(registry), ui(new Ui::ConfigureDialog) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
ui->generalTab->PopulateHotkeyList(registry);
|
ui->hotkeysTab->Populate(registry);
|
||||||
|
|
||||||
this->PopulateSelectionList();
|
this->PopulateSelectionList();
|
||||||
connect(ui->uiTab, &ConfigureUi::languageChanged, this, &ConfigureDialog::onLanguageChanged);
|
connect(ui->uiTab, &ConfigureUi::languageChanged, this, &ConfigureDialog::onLanguageChanged);
|
||||||
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
|
connect(ui->selectorList, &QListWidget::itemSelectionChanged, this,
|
||||||
&ConfigureDialog::UpdateVisibleTabs);
|
&ConfigureDialog::UpdateVisibleTabs);
|
||||||
|
|
||||||
adjustSize();
|
adjustSize();
|
||||||
|
|
||||||
ui->selectorList->setCurrentRow(0);
|
ui->selectorList->setCurrentRow(0);
|
||||||
|
|
||||||
|
// Set up used key list synchronisation
|
||||||
|
connect(ui->inputTab, &ConfigureInput::InputKeysChanged, ui->hotkeysTab,
|
||||||
|
&ConfigureHotkeys::OnInputKeysChanged);
|
||||||
|
connect(ui->hotkeysTab, &ConfigureHotkeys::HotkeysChanged, ui->inputTab,
|
||||||
|
&ConfigureInput::OnHotkeysChanged);
|
||||||
|
|
||||||
|
// Synchronise lists upon initialisation
|
||||||
|
ui->inputTab->EmitInputKeysChanged();
|
||||||
|
ui->hotkeysTab->EmitHotkeysChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigureDialog::~ConfigureDialog() = default;
|
ConfigureDialog::~ConfigureDialog() = default;
|
||||||
|
@ -43,6 +52,7 @@ void ConfigureDialog::applyConfiguration() {
|
||||||
ui->systemTab->applyConfiguration();
|
ui->systemTab->applyConfiguration();
|
||||||
ui->inputTab->applyConfiguration();
|
ui->inputTab->applyConfiguration();
|
||||||
ui->inputTab->ApplyProfile();
|
ui->inputTab->ApplyProfile();
|
||||||
|
ui->hotkeysTab->applyConfiguration(registry);
|
||||||
ui->graphicsTab->applyConfiguration();
|
ui->graphicsTab->applyConfiguration();
|
||||||
ui->audioTab->applyConfiguration();
|
ui->audioTab->applyConfiguration();
|
||||||
ui->cameraTab->applyConfiguration();
|
ui->cameraTab->applyConfiguration();
|
||||||
|
@ -61,7 +71,7 @@ void ConfigureDialog::PopulateSelectionList() {
|
||||||
{QT_TR_NOOP("General"), QT_TR_NOOP("Web"), QT_TR_NOOP("Debug"), QT_TR_NOOP("UI")}},
|
{QT_TR_NOOP("General"), QT_TR_NOOP("Web"), QT_TR_NOOP("Debug"), QT_TR_NOOP("UI")}},
|
||||||
{tr("System"), {QT_TR_NOOP("System"), QT_TR_NOOP("Audio"), QT_TR_NOOP("Camera")}},
|
{tr("System"), {QT_TR_NOOP("System"), QT_TR_NOOP("Audio"), QT_TR_NOOP("Camera")}},
|
||||||
{tr("Graphics"), {QT_TR_NOOP("Graphics")}},
|
{tr("Graphics"), {QT_TR_NOOP("Graphics")}},
|
||||||
{tr("Controls"), {QT_TR_NOOP("Input")}}}};
|
{tr("Controls"), {QT_TR_NOOP("Input"), QT_TR_NOOP("Hotkeys")}}}};
|
||||||
|
|
||||||
for (const auto& entry : items) {
|
for (const auto& entry : items) {
|
||||||
auto* item = new QListWidgetItem(entry.first);
|
auto* item = new QListWidgetItem(entry.first);
|
||||||
|
@ -91,6 +101,7 @@ void ConfigureDialog::retranslateUi() {
|
||||||
ui->generalTab->retranslateUi();
|
ui->generalTab->retranslateUi();
|
||||||
ui->systemTab->retranslateUi();
|
ui->systemTab->retranslateUi();
|
||||||
ui->inputTab->retranslateUi();
|
ui->inputTab->retranslateUi();
|
||||||
|
ui->hotkeysTab->retranslateUi();
|
||||||
ui->graphicsTab->retranslateUi();
|
ui->graphicsTab->retranslateUi();
|
||||||
ui->audioTab->retranslateUi();
|
ui->audioTab->retranslateUi();
|
||||||
ui->cameraTab->retranslateUi();
|
ui->cameraTab->retranslateUi();
|
||||||
|
@ -105,9 +116,11 @@ void ConfigureDialog::UpdateVisibleTabs() {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const QHash<QString, QWidget*> widgets = {
|
const QHash<QString, QWidget*> widgets = {
|
||||||
{"General", ui->generalTab}, {"System", ui->systemTab}, {"Input", ui->inputTab},
|
{"General", ui->generalTab}, {"System", ui->systemTab},
|
||||||
{"Graphics", ui->graphicsTab}, {"Audio", ui->audioTab}, {"Camera", ui->cameraTab},
|
{"Input", ui->inputTab}, {"Hotkeys", ui->hotkeysTab},
|
||||||
{"Debug", ui->debugTab}, {"Web", ui->webTab}, {"UI", ui->uiTab}};
|
{"Graphics", ui->graphicsTab}, {"Audio", ui->audioTab},
|
||||||
|
{"Camera", ui->cameraTab}, {"Debug", ui->debugTab},
|
||||||
|
{"Web", ui->webTab}, {"UI", ui->uiTab}};
|
||||||
|
|
||||||
ui->tabWidget->clear();
|
ui->tabWidget->clear();
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ class ConfigureDialog : public QDialog {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit ConfigureDialog(QWidget* parent, const HotkeyRegistry& registry);
|
explicit ConfigureDialog(QWidget* parent, HotkeyRegistry& registry);
|
||||||
~ConfigureDialog() override;
|
~ConfigureDialog() override;
|
||||||
|
|
||||||
void applyConfiguration();
|
void applyConfiguration();
|
||||||
|
@ -35,4 +35,5 @@ private:
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
||||||
std::unique_ptr<Ui::ConfigureDialog> ui;
|
std::unique_ptr<Ui::ConfigureDialog> ui;
|
||||||
|
HotkeyRegistry& registry;
|
||||||
};
|
};
|
||||||
|
|
|
@ -32,10 +32,6 @@ void ConfigureGeneral::setConfiguration() {
|
||||||
ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1);
|
ui->region_combobox->setCurrentIndex(Settings::values.region_value + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
|
|
||||||
ui->hotkeysDialog->Populate(registry);
|
|
||||||
}
|
|
||||||
|
|
||||||
void ConfigureGeneral::ResetDefaults() {
|
void ConfigureGeneral::ResetDefaults() {
|
||||||
QMessageBox::StandardButton answer = QMessageBox::question(
|
QMessageBox::StandardButton answer = QMessageBox::question(
|
||||||
this, tr("Citra"),
|
this, tr("Citra"),
|
||||||
|
@ -60,5 +56,4 @@ void ConfigureGeneral::applyConfiguration() {
|
||||||
|
|
||||||
void ConfigureGeneral::retranslateUi() {
|
void ConfigureGeneral::retranslateUi() {
|
||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
ui->hotkeysDialog->retranslateUi();
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,6 @@ public:
|
||||||
explicit ConfigureGeneral(QWidget* parent = nullptr);
|
explicit ConfigureGeneral(QWidget* parent = nullptr);
|
||||||
~ConfigureGeneral() override;
|
~ConfigureGeneral() override;
|
||||||
|
|
||||||
void PopulateHotkeyList(const HotkeyRegistry& registry);
|
|
||||||
void ResetDefaults();
|
void ResetDefaults();
|
||||||
void applyConfiguration();
|
void applyConfiguration();
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>345</width>
|
<width>345</width>
|
||||||
<height>504</height>
|
<height>357</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -21,9 +21,7 @@
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>General</string>
|
<string>General</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_check_exit">
|
<widget class="QCheckBox" name="toggle_check_exit">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -32,8 +30,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -41,9 +37,7 @@
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Updates</string>
|
<string>Updates</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_update">
|
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_update">
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="toggle_update_check">
|
<widget class="QCheckBox" name="toggle_update_check">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -59,8 +53,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
|
@ -68,19 +60,15 @@
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>Emulation</string>
|
<string>Emulation</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Region:</string>
|
<string>Region:</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<widget class="QComboBox" name="region_combobox">
|
<widget class="QComboBox" name="region_combobox">
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@ -125,26 +113,6 @@
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
|
||||||
<string>Hotkeys</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
|
||||||
<item>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
|
||||||
<item>
|
|
||||||
<widget class="GHotkeysDialog" name="hotkeysDialog" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item alignment="Qt::AlignRight">
|
<item alignment="Qt::AlignRight">
|
||||||
|
@ -154,18 +122,23 @@
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>40</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
|
||||||
<customwidget>
|
|
||||||
<class>GHotkeysDialog</class>
|
|
||||||
<extends>QWidget</extends>
|
|
||||||
<header>hotkeys.h</header>
|
|
||||||
<container>1</container>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
</ui>
|
</ui>
|
||||||
|
|
|
@ -0,0 +1,125 @@
|
||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
#include "citra_qt/configuration/configure_hotkeys.h"
|
||||||
|
#include "citra_qt/hotkeys.h"
|
||||||
|
#include "citra_qt/util/sequence_dialog/sequence_dialog.h"
|
||||||
|
#include "core/settings.h"
|
||||||
|
#include "ui_configure_hotkeys.h"
|
||||||
|
|
||||||
|
ConfigureHotkeys::ConfigureHotkeys(QWidget* parent)
|
||||||
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureHotkeys>()) {
|
||||||
|
ui->setupUi(this);
|
||||||
|
setFocusPolicy(Qt::ClickFocus);
|
||||||
|
|
||||||
|
model = new QStandardItemModel(this);
|
||||||
|
model->setColumnCount(3);
|
||||||
|
model->setHorizontalHeaderLabels({tr("Action"), tr("Hotkey"), tr("Context")});
|
||||||
|
|
||||||
|
connect(ui->hotkey_list, &QTreeView::doubleClicked, this, &ConfigureHotkeys::Configure);
|
||||||
|
ui->hotkey_list->setModel(model);
|
||||||
|
|
||||||
|
// TODO(Kloen): Make context configurable as well (hiding the column for now)
|
||||||
|
ui->hotkey_list->hideColumn(2);
|
||||||
|
|
||||||
|
ui->hotkey_list->setColumnWidth(0, 200);
|
||||||
|
ui->hotkey_list->resizeColumnToContents(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
ConfigureHotkeys::~ConfigureHotkeys() = default;
|
||||||
|
|
||||||
|
void ConfigureHotkeys::EmitHotkeysChanged() {
|
||||||
|
emit HotkeysChanged(GetUsedKeyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QKeySequence> ConfigureHotkeys::GetUsedKeyList() {
|
||||||
|
QList<QKeySequence> list;
|
||||||
|
for (int r = 0; r < model->rowCount(); r++) {
|
||||||
|
QStandardItem* parent = model->item(r, 0);
|
||||||
|
for (int r2 = 0; r2 < parent->rowCount(); r2++) {
|
||||||
|
QStandardItem* keyseq = parent->child(r2, 1);
|
||||||
|
list << QKeySequence::fromString(keyseq->text(), QKeySequence::NativeText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureHotkeys::Populate(const HotkeyRegistry& registry) {
|
||||||
|
for (const auto& group : registry.hotkey_groups) {
|
||||||
|
QStandardItem* parent_item = new QStandardItem(group.first);
|
||||||
|
parent_item->setEditable(false);
|
||||||
|
for (const auto& hotkey : group.second) {
|
||||||
|
QStandardItem* action = new QStandardItem(hotkey.first);
|
||||||
|
QStandardItem* keyseq =
|
||||||
|
new QStandardItem(hotkey.second.keyseq.toString(QKeySequence::NativeText));
|
||||||
|
action->setEditable(false);
|
||||||
|
keyseq->setEditable(false);
|
||||||
|
parent_item->appendRow({action, keyseq});
|
||||||
|
}
|
||||||
|
model->appendRow(parent_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->hotkey_list->expandAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureHotkeys::OnInputKeysChanged(QList<QKeySequence> new_key_list) {
|
||||||
|
input_keys_list = new_key_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureHotkeys::Configure(QModelIndex index) {
|
||||||
|
if (index.parent() == QModelIndex())
|
||||||
|
return;
|
||||||
|
|
||||||
|
index = index.sibling(index.row(), 1);
|
||||||
|
auto* model = ui->hotkey_list->model();
|
||||||
|
auto previous_key = model->data(index);
|
||||||
|
|
||||||
|
auto* hotkey_dialog = new SequenceDialog;
|
||||||
|
int return_code = hotkey_dialog->exec();
|
||||||
|
|
||||||
|
auto key_sequence = hotkey_dialog->GetSequence();
|
||||||
|
|
||||||
|
if (return_code == QDialog::Rejected || key_sequence.isEmpty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (IsUsedKey(key_sequence) && key_sequence != QKeySequence(previous_key.toString())) {
|
||||||
|
QMessageBox::critical(this, tr("Error in inputted key"),
|
||||||
|
tr("You're using a key that's already bound."));
|
||||||
|
} else {
|
||||||
|
model->setData(index, key_sequence.toString(QKeySequence::NativeText));
|
||||||
|
EmitHotkeysChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ConfigureHotkeys::IsUsedKey(QKeySequence key_sequence) {
|
||||||
|
return input_keys_list.contains(key_sequence) || GetUsedKeyList().contains(key_sequence);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureHotkeys::applyConfiguration(HotkeyRegistry& registry) {
|
||||||
|
for (int key_id = 0; key_id < model->rowCount(); key_id++) {
|
||||||
|
QStandardItem* parent = model->item(key_id, 0);
|
||||||
|
for (int key_column_id = 0; key_column_id < parent->rowCount(); key_column_id++) {
|
||||||
|
QStandardItem* action = parent->child(key_column_id, 0);
|
||||||
|
QStandardItem* keyseq = parent->child(key_column_id, 1);
|
||||||
|
for (auto& [group, sub_actions] : registry.hotkey_groups) {
|
||||||
|
if (group != parent->text())
|
||||||
|
continue;
|
||||||
|
for (auto& [action_name, hotkey] : sub_actions) {
|
||||||
|
if (action_name != action->text())
|
||||||
|
continue;
|
||||||
|
hotkey.keyseq = QKeySequence(keyseq->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registry.SaveHotkeys();
|
||||||
|
Settings::Apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureHotkeys::retranslateUi() {
|
||||||
|
ui->retranslateUi(this);
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
// Copyright 2017 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QWidget>
|
||||||
|
#include "core/settings.h"
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class ConfigureHotkeys;
|
||||||
|
}
|
||||||
|
|
||||||
|
class HotkeyRegistry;
|
||||||
|
class QStandardItemModel;
|
||||||
|
|
||||||
|
class ConfigureHotkeys : public QWidget {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit ConfigureHotkeys(QWidget* parent = nullptr);
|
||||||
|
~ConfigureHotkeys();
|
||||||
|
|
||||||
|
void applyConfiguration(HotkeyRegistry& registry);
|
||||||
|
void retranslateUi();
|
||||||
|
|
||||||
|
void EmitHotkeysChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Populates the hotkey list widget using data from the provided registry.
|
||||||
|
* Called everytime the Configure dialog is opened.
|
||||||
|
* @param registry The HotkeyRegistry whose data is used to populate the list.
|
||||||
|
*/
|
||||||
|
void Populate(const HotkeyRegistry& registry);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void OnInputKeysChanged(QList<QKeySequence> new_key_list);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void HotkeysChanged(QList<QKeySequence> new_key_list);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void Configure(QModelIndex index);
|
||||||
|
bool IsUsedKey(QKeySequence key_sequence);
|
||||||
|
QList<QKeySequence> GetUsedKeyList();
|
||||||
|
|
||||||
|
std::unique_ptr<Ui::ConfigureHotkeys> ui;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of keyboard keys currently registered to any of the 3DS inputs.
|
||||||
|
* These can't be bound to any hotkey.
|
||||||
|
* Synchronised with ConfigureInput via signal-slot.
|
||||||
|
*/
|
||||||
|
QList<QKeySequence> input_keys_list;
|
||||||
|
|
||||||
|
QStandardItemModel* model;
|
||||||
|
};
|
|
@ -0,0 +1,42 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ConfigureHotkeys</class>
|
||||||
|
<widget class="QWidget" name="ConfigureHotkeys">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>363</width>
|
||||||
|
<height>388</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Hotkey Settings</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>Double-click on a binding to change it.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QTreeView" name="hotkey_list">
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="sortingEnabled">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -276,6 +276,30 @@ void ConfigureInput::ApplyProfile() {
|
||||||
Settings::values.current_input_profile_index = ui->profile->currentIndex();
|
Settings::values.current_input_profile_index = ui->profile->currentIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::EmitInputKeysChanged() {
|
||||||
|
emit InputKeysChanged(GetUsedKeyboardKeys());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureInput::OnHotkeysChanged(QList<QKeySequence> new_key_list) {
|
||||||
|
hotkey_list = new_key_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QKeySequence> ConfigureInput::GetUsedKeyboardKeys() {
|
||||||
|
QList<QKeySequence> list;
|
||||||
|
for (int button = 0; button < Settings::NativeButton::NumButtons; button++) {
|
||||||
|
auto button_param = buttons_param[button];
|
||||||
|
|
||||||
|
if (button_param.Get("engine", "") == "keyboard") {
|
||||||
|
list << QKeySequence(button_param.Get("code", 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(adityaruplaha): Add home button to list when we finally emulate it
|
||||||
|
// Button ID of home button is 14: Referred from citra_qt/configuration/config.cpp
|
||||||
|
list.removeOne(list.indexOf(QKeySequence(buttons_param[14].Get("code", 0))));
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
void ConfigureInput::loadConfiguration() {
|
void ConfigureInput::loadConfiguration() {
|
||||||
std::transform(Settings::values.current_input_profile.buttons.begin(),
|
std::transform(Settings::values.current_input_profile.buttons.begin(),
|
||||||
Settings::values.current_input_profile.buttons.end(), buttons_param.begin(),
|
Settings::values.current_input_profile.buttons.end(), buttons_param.begin(),
|
||||||
|
@ -332,11 +356,14 @@ void ConfigureInput::updateButtonLabels() {
|
||||||
}
|
}
|
||||||
analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
|
analog_map_stick[analog_id]->setText(tr("Set Analog Stick"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EmitInputKeysChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInput::handleClick(QPushButton* button,
|
void ConfigureInput::handleClick(QPushButton* button,
|
||||||
std::function<void(const Common::ParamPackage&)> new_input_setter,
|
std::function<void(const Common::ParamPackage&)> new_input_setter,
|
||||||
InputCommon::Polling::DeviceType type) {
|
InputCommon::Polling::DeviceType type) {
|
||||||
|
previous_key_code = QKeySequence(button->text())[0];
|
||||||
button->setText(tr("[press key]"));
|
button->setText(tr("[press key]"));
|
||||||
button->setFocus();
|
button->setFocus();
|
||||||
|
|
||||||
|
@ -378,16 +405,26 @@ void ConfigureInput::keyPressEvent(QKeyEvent* event) {
|
||||||
if (!input_setter || !event)
|
if (!input_setter || !event)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (event->key() != Qt::Key_Escape) {
|
if (event->key() != Qt::Key_Escape && event->key() != previous_key_code) {
|
||||||
if (want_keyboard_keys) {
|
if (want_keyboard_keys) {
|
||||||
|
// Check if key is already bound
|
||||||
|
if (hotkey_list.contains(QKeySequence(event->key())) ||
|
||||||
|
GetUsedKeyboardKeys().contains(QKeySequence(event->key()))) {
|
||||||
|
setPollingResult({}, true);
|
||||||
|
QMessageBox::critical(this, tr("Error!"),
|
||||||
|
tr("You're using a key that's already bound."));
|
||||||
|
return;
|
||||||
|
}
|
||||||
setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
|
setPollingResult(Common::ParamPackage{InputCommon::GenerateKeyboardParam(event->key())},
|
||||||
false);
|
false);
|
||||||
} else {
|
} else {
|
||||||
// Escape key wasn't pressed and we don't want any keyboard keys, so don't stop polling
|
// Escape key wasn't pressed and we don't want any keyboard keys, so don't stop
|
||||||
|
// polling
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setPollingResult({}, true);
|
setPollingResult({}, true);
|
||||||
|
previous_key_code = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureInput::retranslateUi() {
|
void ConfigureInput::retranslateUi() {
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <QKeyEvent>
|
#include <QKeyEvent>
|
||||||
|
#include <QKeySequence>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
#include "common/param_package.h"
|
#include "common/param_package.h"
|
||||||
#include "core/settings.h"
|
#include "core/settings.h"
|
||||||
|
@ -38,9 +39,15 @@ public:
|
||||||
|
|
||||||
/// Load configuration settings.
|
/// Load configuration settings.
|
||||||
void loadConfiguration();
|
void loadConfiguration();
|
||||||
|
void EmitInputKeysChanged();
|
||||||
|
|
||||||
// Save the current input profile index
|
/// Save the current input profile index
|
||||||
void ApplyProfile();
|
void ApplyProfile();
|
||||||
|
public slots:
|
||||||
|
void OnHotkeysChanged(QList<QKeySequence> new_key_list);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void InputKeysChanged(QList<QKeySequence> new_key_list);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::unique_ptr<Ui::ConfigureInput> ui;
|
std::unique_ptr<Ui::ConfigureInput> ui;
|
||||||
|
@ -72,10 +79,20 @@ private:
|
||||||
|
|
||||||
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
|
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of keys currently registered to hotkeys.
|
||||||
|
* These can't be bound to any input key.
|
||||||
|
* Synchronised with ConfigureHotkeys via signal-slot.
|
||||||
|
*/
|
||||||
|
QList<QKeySequence> hotkey_list;
|
||||||
|
|
||||||
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
|
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
|
||||||
/// keyboard events are ignored.
|
/// keyboard events are ignored.
|
||||||
bool want_keyboard_keys = false;
|
bool want_keyboard_keys = false;
|
||||||
|
|
||||||
|
/// Generates list of all used keys
|
||||||
|
QList<QKeySequence> GetUsedKeyboardKeys();
|
||||||
|
|
||||||
/// Restore all buttons to their default values.
|
/// Restore all buttons to their default values.
|
||||||
void restoreDefaults();
|
void restoreDefaults();
|
||||||
/// Clear all input configuration
|
/// Clear all input configuration
|
||||||
|
@ -89,6 +106,9 @@ private:
|
||||||
std::function<void(const Common::ParamPackage&)> new_input_setter,
|
std::function<void(const Common::ParamPackage&)> new_input_setter,
|
||||||
InputCommon::Polling::DeviceType type);
|
InputCommon::Polling::DeviceType type);
|
||||||
|
|
||||||
|
/// The key code of the previous state of the key being currently bound.
|
||||||
|
int previous_key_code;
|
||||||
|
|
||||||
/// Finish polling and configure input using the input_setter
|
/// Finish polling and configure input using the input_setter
|
||||||
void setPollingResult(const Common::ParamPackage& params, bool abort);
|
void setPollingResult(const Common::ParamPackage& params, bool abort);
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <QKeySequence>
|
#include <QKeySequence>
|
||||||
#include <QShortcut>
|
#include <QShortcut>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
@ -12,47 +11,32 @@
|
||||||
HotkeyRegistry::HotkeyRegistry() = default;
|
HotkeyRegistry::HotkeyRegistry() = default;
|
||||||
HotkeyRegistry::~HotkeyRegistry() = default;
|
HotkeyRegistry::~HotkeyRegistry() = default;
|
||||||
|
|
||||||
void HotkeyRegistry::LoadHotkeys() {
|
|
||||||
// Make sure NOT to use a reference here because it would become invalid once we call
|
|
||||||
// beginGroup()
|
|
||||||
for (auto shortcut : UISettings::values.shortcuts) {
|
|
||||||
const QStringList cat = shortcut.first.split('/');
|
|
||||||
Q_ASSERT(cat.size() >= 2);
|
|
||||||
|
|
||||||
// RegisterHotkey assigns default keybindings, so use old values as default parameters
|
|
||||||
Hotkey& hk = hotkey_groups[cat[0]][cat[1]];
|
|
||||||
if (!shortcut.second.first.isEmpty()) {
|
|
||||||
hk.keyseq = QKeySequence::fromString(shortcut.second.first);
|
|
||||||
hk.context = static_cast<Qt::ShortcutContext>(shortcut.second.second);
|
|
||||||
}
|
|
||||||
if (hk.shortcut)
|
|
||||||
hk.shortcut->setKey(hk.keyseq);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void HotkeyRegistry::SaveHotkeys() {
|
void HotkeyRegistry::SaveHotkeys() {
|
||||||
UISettings::values.shortcuts.clear();
|
UISettings::values.shortcuts.clear();
|
||||||
for (const auto& group : hotkey_groups) {
|
for (const auto& group : hotkey_groups) {
|
||||||
for (const auto& hotkey : group.second) {
|
for (const auto& hotkey : group.second) {
|
||||||
UISettings::values.shortcuts.emplace_back(
|
UISettings::values.shortcuts.push_back(
|
||||||
UISettings::Shortcut(group.first + '/' + hotkey.first,
|
{hotkey.first, group.first,
|
||||||
UISettings::ContextualShortcut(hotkey.second.keyseq.toString(),
|
UISettings::ContextualShortcut(hotkey.second.keyseq.toString(),
|
||||||
hotkey.second.context)));
|
hotkey.second.context)});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HotkeyRegistry::RegisterHotkey(const QString& group, const QString& action,
|
void HotkeyRegistry::LoadHotkeys() {
|
||||||
const QKeySequence& default_keyseq,
|
// Make sure NOT to use a reference here because it would become invalid once we call
|
||||||
Qt::ShortcutContext default_context) {
|
// beginGroup()
|
||||||
auto& hotkey_group = hotkey_groups[group];
|
for (auto shortcut : UISettings::values.shortcuts) {
|
||||||
if (hotkey_group.find(action) != hotkey_group.end()) {
|
Hotkey& hk = hotkey_groups[shortcut.group][shortcut.name];
|
||||||
return;
|
if (!shortcut.shortcut.first.isEmpty()) {
|
||||||
|
hk.keyseq = QKeySequence::fromString(shortcut.shortcut.first, QKeySequence::NativeText);
|
||||||
|
hk.context = static_cast<Qt::ShortcutContext>(shortcut.shortcut.second);
|
||||||
|
}
|
||||||
|
if (hk.shortcut) {
|
||||||
|
hk.shortcut->disconnect();
|
||||||
|
hk.shortcut->setKey(hk.keyseq);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto& hotkey_action = hotkey_groups[group][action];
|
|
||||||
hotkey_action.keyseq = default_keyseq;
|
|
||||||
hotkey_action.context = default_context;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) {
|
QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action, QWidget* widget) {
|
||||||
|
@ -64,28 +48,13 @@ QShortcut* HotkeyRegistry::GetHotkey(const QString& group, const QString& action
|
||||||
return hk.shortcut;
|
return hk.shortcut;
|
||||||
}
|
}
|
||||||
|
|
||||||
GHotkeysDialog::GHotkeysDialog(QWidget* parent) : QWidget(parent) {
|
QKeySequence HotkeyRegistry::GetKeySequence(const QString& group, const QString& action) {
|
||||||
ui.setupUi(this);
|
Hotkey& hk = hotkey_groups[group][action];
|
||||||
|
return hk.keyseq;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GHotkeysDialog::Populate(const HotkeyRegistry& registry) {
|
Qt::ShortcutContext HotkeyRegistry::GetShortcutContext(const QString& group,
|
||||||
for (const auto& group : registry.hotkey_groups) {
|
const QString& action) {
|
||||||
QTreeWidgetItem* toplevel_item = new QTreeWidgetItem(QStringList(group.first));
|
Hotkey& hk = hotkey_groups[group][action];
|
||||||
for (const auto& hotkey : group.second) {
|
return hk.context;
|
||||||
QStringList columns;
|
|
||||||
columns << hotkey.first << hotkey.second.keyseq.toString();
|
|
||||||
QTreeWidgetItem* item = new QTreeWidgetItem(columns);
|
|
||||||
toplevel_item->addChild(item);
|
|
||||||
}
|
|
||||||
ui.treeWidget->addTopLevelItem(toplevel_item);
|
|
||||||
}
|
|
||||||
// TODO: Make context configurable as well (hiding the column for now)
|
|
||||||
ui.treeWidget->setColumnCount(2);
|
|
||||||
|
|
||||||
ui.treeWidget->resizeColumnToContents(0);
|
|
||||||
ui.treeWidget->resizeColumnToContents(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void GHotkeysDialog::retranslateUi() {
|
|
||||||
ui.retranslateUi(this);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "ui_hotkeys.h"
|
|
||||||
|
|
||||||
class QDialog;
|
class QDialog;
|
||||||
class QKeySequence;
|
class QKeySequence;
|
||||||
|
@ -14,7 +13,7 @@ class QShortcut;
|
||||||
|
|
||||||
class HotkeyRegistry final {
|
class HotkeyRegistry final {
|
||||||
public:
|
public:
|
||||||
friend class GHotkeysDialog;
|
friend class ConfigureHotkeys;
|
||||||
|
|
||||||
explicit HotkeyRegistry();
|
explicit HotkeyRegistry();
|
||||||
~HotkeyRegistry();
|
~HotkeyRegistry();
|
||||||
|
@ -49,22 +48,27 @@ public:
|
||||||
QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget);
|
QShortcut* GetHotkey(const QString& group, const QString& action, QWidget* widget);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a hotkey.
|
* Returns a QKeySequence object whose signal can be connected to QAction::setShortcut.
|
||||||
*
|
*
|
||||||
* @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger")
|
* @param group General group this hotkey belongs to (e.g. "Main Window", "Debugger").
|
||||||
* @param action Name of the action (e.g. "Start Emulation", "Load Image")
|
* @param action Name of the action (e.g. "Start Emulation", "Load Image").
|
||||||
* @param default_keyseq Default key sequence to assign if the hotkey wasn't present in the
|
|
||||||
* settings file before
|
|
||||||
* @param default_context Default context to assign if the hotkey wasn't present in the settings
|
|
||||||
* file before
|
|
||||||
* @warning Both the group and action strings will be displayed in the hotkey settings dialog
|
|
||||||
*/
|
*/
|
||||||
void RegisterHotkey(const QString& group, const QString& action,
|
QKeySequence GetKeySequence(const QString& group, const QString& action);
|
||||||
const QKeySequence& default_keyseq = {},
|
|
||||||
Qt::ShortcutContext default_context = Qt::WindowShortcut);
|
/**
|
||||||
|
* Returns a Qt::ShortcutContext object who can be connected to other
|
||||||
|
* QAction::setShortcutContext.
|
||||||
|
*
|
||||||
|
* @param group General group this shortcut context belongs to (e.g. "Main Window",
|
||||||
|
* "Debugger").
|
||||||
|
* @param action Name of the action (e.g. "Start Emulation", "Load Image").
|
||||||
|
*/
|
||||||
|
Qt::ShortcutContext GetShortcutContext(const QString& group, const QString& action);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Hotkey {
|
struct Hotkey {
|
||||||
|
Hotkey() : shortcut(nullptr), context(Qt::WindowShortcut) {}
|
||||||
|
|
||||||
QKeySequence keyseq;
|
QKeySequence keyseq;
|
||||||
QShortcut* shortcut = nullptr;
|
QShortcut* shortcut = nullptr;
|
||||||
Qt::ShortcutContext context = Qt::WindowShortcut;
|
Qt::ShortcutContext context = Qt::WindowShortcut;
|
||||||
|
@ -75,16 +79,3 @@ private:
|
||||||
|
|
||||||
HotkeyGroupMap hotkey_groups;
|
HotkeyGroupMap hotkey_groups;
|
||||||
};
|
};
|
||||||
|
|
||||||
class GHotkeysDialog : public QWidget {
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit GHotkeysDialog(QWidget* parent = nullptr);
|
|
||||||
void retranslateUi();
|
|
||||||
|
|
||||||
void Populate(const HotkeyRegistry& registry);
|
|
||||||
|
|
||||||
private:
|
|
||||||
Ui::hotkeys ui;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<ui version="4.0">
|
|
||||||
<class>hotkeys</class>
|
|
||||||
<widget class="QWidget" name="hotkeys">
|
|
||||||
<property name="geometry">
|
|
||||||
<rect>
|
|
||||||
<x>0</x>
|
|
||||||
<y>0</y>
|
|
||||||
<width>363</width>
|
|
||||||
<height>388</height>
|
|
||||||
</rect>
|
|
||||||
</property>
|
|
||||||
<property name="windowTitle">
|
|
||||||
<string>Hotkey Settings</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
|
||||||
<item>
|
|
||||||
<widget class="QTreeWidget" name="treeWidget">
|
|
||||||
<property name="selectionBehavior">
|
|
||||||
<enum>QAbstractItemView::SelectItems</enum>
|
|
||||||
</property>
|
|
||||||
<property name="headerHidden">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Action</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Hotkey</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
<column>
|
|
||||||
<property name="text">
|
|
||||||
<string>Context</string>
|
|
||||||
</property>
|
|
||||||
</column>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
<resources/>
|
|
||||||
<connections/>
|
|
||||||
</ui>
|
|
|
@ -344,40 +344,35 @@ void GMainWindow::InitializeRecentFileMenuActions() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void GMainWindow::InitializeHotkeys() {
|
void GMainWindow::InitializeHotkeys() {
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Start Emulation");
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Continue/Pause", QKeySequence(Qt::Key_F4));
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Restart", QKeySequence(Qt::Key_F5));
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Swap Screens", QKeySequence(Qt::Key_F9));
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Toggle Screen Layout",
|
|
||||||
QKeySequence(Qt::Key_F10));
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Fullscreen", QKeySequence::FullScreen);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Exit Fullscreen", QKeySequence(Qt::Key_Escape),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Toggle Speed Limit", QKeySequence("CTRL+Z"),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Increase Speed Limit", QKeySequence("+"),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Decrease Speed Limit", QKeySequence("-"),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Toggle Frame Advancing", QKeySequence("CTRL+A"),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Advance Frame", QKeySequence(Qt::Key_Backslash),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Load Amiibo", QKeySequence(Qt::Key_F2),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Remove Amiibo", QKeySequence(Qt::Key_F3),
|
|
||||||
Qt::ApplicationShortcut);
|
|
||||||
hotkey_registry.RegisterHotkey("Main Window", "Capture Screenshot", QKeySequence(tr("CTRL+P")));
|
|
||||||
|
|
||||||
hotkey_registry.LoadHotkeys();
|
hotkey_registry.LoadHotkeys();
|
||||||
|
|
||||||
|
ui.action_Load_File->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Load File"));
|
||||||
|
ui.action_Load_File->setShortcutContext(
|
||||||
|
hotkey_registry.GetShortcutContext("Main Window", "Load File"));
|
||||||
|
|
||||||
|
ui.action_Exit->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Exit Citra"));
|
||||||
|
ui.action_Exit->setShortcutContext(
|
||||||
|
hotkey_registry.GetShortcutContext("Main Window", "Exit Citra"));
|
||||||
|
|
||||||
|
ui.action_Stop->setShortcut(hotkey_registry.GetKeySequence("Main Window", "Stop Emulation"));
|
||||||
|
ui.action_Stop->setShortcutContext(
|
||||||
|
hotkey_registry.GetShortcutContext("Main Window", "Stop Emulation"));
|
||||||
|
|
||||||
|
ui.action_Show_Filter_Bar->setShortcut(
|
||||||
|
hotkey_registry.GetKeySequence("Main Window", "Toggle Filter Bar"));
|
||||||
|
ui.action_Show_Filter_Bar->setShortcutContext(
|
||||||
|
hotkey_registry.GetShortcutContext("Main Window", "Toggle Filter Bar"));
|
||||||
|
|
||||||
|
ui.action_Show_Status_Bar->setShortcut(
|
||||||
|
hotkey_registry.GetKeySequence("Main Window", "Toggle Status Bar"));
|
||||||
|
ui.action_Show_Status_Bar->setShortcutContext(
|
||||||
|
hotkey_registry.GetShortcutContext("Main Window", "Toggle Status Bar"));
|
||||||
|
|
||||||
connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated,
|
connect(hotkey_registry.GetHotkey("Main Window", "Load File", this), &QShortcut::activated,
|
||||||
this, &GMainWindow::OnMenuLoadFile);
|
this, &GMainWindow::OnMenuLoadFile);
|
||||||
connect(hotkey_registry.GetHotkey("Main Window", "Start Emulation", this),
|
|
||||||
&QShortcut::activated, this, &GMainWindow::OnStartGame);
|
connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause Emulation", this),
|
||||||
connect(hotkey_registry.GetHotkey("Main Window", "Continue/Pause", this), &QShortcut::activated,
|
&QShortcut::activated, this, [&] {
|
||||||
this, [&] {
|
|
||||||
if (emulation_running) {
|
if (emulation_running) {
|
||||||
if (emu_thread->IsRunning()) {
|
if (emu_thread->IsRunning()) {
|
||||||
OnPauseGame();
|
OnPauseGame();
|
||||||
|
@ -386,8 +381,8 @@ void GMainWindow::InitializeHotkeys() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
connect(hotkey_registry.GetHotkey("Main Window", "Restart", this), &QShortcut::activated, this,
|
connect(hotkey_registry.GetHotkey("Main Window", "Restart Emulation", this),
|
||||||
[this] {
|
&QShortcut::activated, this, [this] {
|
||||||
if (!Core::System::GetInstance().IsPoweredOn())
|
if (!Core::System::GetInstance().IsPoweredOn())
|
||||||
return;
|
return;
|
||||||
BootGame(QString(game_path));
|
BootGame(QString(game_path));
|
||||||
|
@ -546,7 +541,6 @@ void GMainWindow::ConnectMenuEvents() {
|
||||||
&GMainWindow::ToggleWindowMode);
|
&GMainWindow::ToggleWindowMode);
|
||||||
connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this,
|
connect(ui.action_Display_Dock_Widget_Headers, &QAction::triggered, this,
|
||||||
&GMainWindow::OnDisplayTitleBars);
|
&GMainWindow::OnDisplayTitleBars);
|
||||||
ui.action_Show_Filter_Bar->setShortcut(tr("CTRL+F"));
|
|
||||||
connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
|
connect(ui.action_Show_Filter_Bar, &QAction::triggered, this, &GMainWindow::OnToggleFilterBar);
|
||||||
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
|
connect(ui.action_Show_Status_Bar, &QAction::triggered, statusBar(), &QStatusBar::setVisible);
|
||||||
|
|
||||||
|
@ -1332,6 +1326,7 @@ void GMainWindow::OnConfigure() {
|
||||||
auto result = configureDialog.exec();
|
auto result = configureDialog.exec();
|
||||||
if (result == QDialog::Accepted) {
|
if (result == QDialog::Accepted) {
|
||||||
configureDialog.applyConfiguration();
|
configureDialog.applyConfiguration();
|
||||||
|
InitializeHotkeys();
|
||||||
if (UISettings::values.theme != old_theme)
|
if (UISettings::values.theme != old_theme)
|
||||||
UpdateUITheme();
|
UpdateUITheme();
|
||||||
if (UISettings::values.enable_discord_presence != old_discord_presence)
|
if (UISettings::values.enable_discord_presence != old_discord_presence)
|
||||||
|
|
|
@ -96,7 +96,6 @@ private:
|
||||||
void InitializeWidgets();
|
void InitializeWidgets();
|
||||||
void InitializeDebugWidgets();
|
void InitializeDebugWidgets();
|
||||||
void InitializeRecentFileMenuActions();
|
void InitializeRecentFileMenuActions();
|
||||||
void InitializeHotkeys();
|
|
||||||
|
|
||||||
void SetDefaultUIGeometry();
|
void SetDefaultUIGeometry();
|
||||||
void SyncMenuUISettings();
|
void SyncMenuUISettings();
|
||||||
|
@ -171,6 +170,7 @@ private slots:
|
||||||
void OnOpenCitraFolder();
|
void OnOpenCitraFolder();
|
||||||
void OnToggleFilterBar();
|
void OnToggleFilterBar();
|
||||||
void OnDisplayTitleBars(bool);
|
void OnDisplayTitleBars(bool);
|
||||||
|
void InitializeHotkeys();
|
||||||
void ToggleFullscreen();
|
void ToggleFullscreen();
|
||||||
void ChangeScreenLayout();
|
void ChangeScreenLayout();
|
||||||
void ToggleScreenLayout();
|
void ToggleScreenLayout();
|
||||||
|
|
|
@ -14,5 +14,4 @@ const Themes themes{{
|
||||||
}};
|
}};
|
||||||
|
|
||||||
Values values = {};
|
Values values = {};
|
||||||
|
|
||||||
} // namespace UISettings
|
} // namespace UISettings
|
||||||
|
|
|
@ -17,7 +17,12 @@
|
||||||
namespace UISettings {
|
namespace UISettings {
|
||||||
|
|
||||||
using ContextualShortcut = std::pair<QString, int>;
|
using ContextualShortcut = std::pair<QString, int>;
|
||||||
using Shortcut = std::pair<QString, ContextualShortcut>;
|
|
||||||
|
struct Shortcut {
|
||||||
|
QString name;
|
||||||
|
QString group;
|
||||||
|
ContextualShortcut shortcut;
|
||||||
|
};
|
||||||
|
|
||||||
using Themes = std::array<std::pair<const char*, const char*>, 4>;
|
using Themes = std::array<std::pair<const char*, const char*>, 4>;
|
||||||
extern const Themes themes;
|
extern const Themes themes;
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <QDialogButtonBox>
|
||||||
|
#include <QKeySequenceEdit>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include "citra_qt/util/sequence_dialog/sequence_dialog.h"
|
||||||
|
|
||||||
|
SequenceDialog::SequenceDialog(QWidget* parent) : QDialog(parent) {
|
||||||
|
setWindowTitle(tr("Enter a hotkey"));
|
||||||
|
auto* layout = new QVBoxLayout(this);
|
||||||
|
key_sequence = new QKeySequenceEdit;
|
||||||
|
layout->addWidget(key_sequence);
|
||||||
|
auto* buttons =
|
||||||
|
new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal);
|
||||||
|
buttons->setCenterButtons(true);
|
||||||
|
layout->addWidget(buttons);
|
||||||
|
connect(buttons, &QDialogButtonBox::accepted, this, &QDialog::accept);
|
||||||
|
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||||
|
}
|
||||||
|
|
||||||
|
SequenceDialog::~SequenceDialog() = default;
|
||||||
|
|
||||||
|
QKeySequence SequenceDialog::GetSequence() {
|
||||||
|
// Only the first key is returned. The other 3, if present, are ignored.
|
||||||
|
return QKeySequence(key_sequence->keySequence()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SequenceDialog::focusNextPrevChild(bool next) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SequenceDialog::closeEvent(QCloseEvent*) {
|
||||||
|
reject();
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
// Copyright 2018 Citra Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
class QKeySequenceEdit;
|
||||||
|
|
||||||
|
class SequenceDialog : public QDialog {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit SequenceDialog(QWidget* parent = nullptr);
|
||||||
|
~SequenceDialog();
|
||||||
|
|
||||||
|
QKeySequence GetSequence();
|
||||||
|
void closeEvent(QCloseEvent*) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QKeySequenceEdit* key_sequence;
|
||||||
|
bool focusNextPrevChild(bool next) override;
|
||||||
|
};
|
Reference in New Issue