From ebb17476a7afecd6f9e8aa33db394874f9382b1a Mon Sep 17 00:00:00 2001 From: BigBahss Date: Sat, 31 Oct 2020 20:28:16 -0400 Subject: [PATCH 01/12] Prevent capturing '=' in config key --- src/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.cpp b/src/config.cpp index 3c9fe33d..15df7d43 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -36,7 +36,7 @@ void KeyValueConfigBase::load() { QTextStream in(&file); in.setCodec("UTF-8"); QList configLines; - QRegularExpression re("^(?.+)=(?.*)$"); + QRegularExpression re("^(?[^=]+)=(?.*)$"); while (!in.atEnd()) { QString line = in.readLine().trimmed(); int commentIndex = line.indexOf("#"); From 88fbf9f28b5f5a135904ace167053a3207f2b89c Mon Sep 17 00:00:00 2001 From: BigBahss Date: Sun, 1 Nov 2020 07:35:20 -0500 Subject: [PATCH 02/12] Add ShortcutsEditor to customize shortcuts for QAction's --- forms/mainwindow.ui | 7 ++ forms/shortcutseditor.ui | 48 +++++++ include/config.h | 35 ++++++ include/mainwindow.h | 4 + include/ui/shortcutseditor.h | 80 ++++++++++++ porymap.pro | 5 +- src/config.cpp | 84 ++++++++++++- src/mainwindow.cpp | 26 +++- src/ui/shortcutseditor.cpp | 234 +++++++++++++++++++++++++++++++++++ 9 files changed, 520 insertions(+), 3 deletions(-) create mode 100644 forms/shortcutseditor.ui create mode 100644 include/ui/shortcutseditor.h create mode 100644 src/ui/shortcutseditor.cpp diff --git a/forms/mainwindow.ui b/forms/mainwindow.ui index f1061bdb..f953c243 100644 --- a/forms/mainwindow.ui +++ b/forms/mainwindow.ui @@ -2639,6 +2639,8 @@ + + @@ -2905,6 +2907,11 @@ Export Map Stitch Image... + + + Edit Shortcuts... + + diff --git a/forms/shortcutseditor.ui b/forms/shortcutseditor.ui new file mode 100644 index 00000000..31b7014a --- /dev/null +++ b/forms/shortcutseditor.ui @@ -0,0 +1,48 @@ + + + ShortcutsEditor + + + + 0 + 0 + 540 + 640 + + + + Shortcuts Editor + + + + + + true + + + + + 0 + 0 + 516 + 580 + + + + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults + + + false + + + + + + + + diff --git a/include/config.h b/include/config.h index 008eeeb7..4c4543d4 100644 --- a/include/config.h +++ b/include/config.h @@ -5,6 +5,8 @@ #include #include #include +#include +#include enum MapSortOrder { Group = 0, @@ -192,4 +194,37 @@ private: extern ProjectConfig projectConfig; +class QAction; + +class ShortcutsConfig : public KeyValueConfigBase +{ +public: + ShortcutsConfig() : + shortcuts(QMultiMap()), + defaultShortcuts(QMultiMap()) + { + reset(); + } + virtual void reset() override { shortcuts.clear(); } + void setDefaultShortcuts(const QList &actions); + QList getDefaultShortcuts(QAction *action) const; + void setUserShortcuts(const QList &actions); + QList getUserShortcuts(QAction *action) const; + +protected: + virtual QString getConfigFilepath() override; + virtual void parseConfigKeyValue(QString key, QString value) override; + virtual QMap getKeyValueMap() override; + virtual void onNewConfigFileCreated() override {}; + virtual void setUnreadKeys() override {}; + +private: + QMultiMap shortcuts; + QMultiMap defaultShortcuts; + + QString getKey(QObject *object) const; +}; + +extern ShortcutsConfig shortcutsConfig; + #endif // CONFIG_H diff --git a/include/mainwindow.h b/include/mainwindow.h index a9180402..f406f87f 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -21,6 +21,7 @@ #include "filterchildrenproxymodel.h" #include "newmappopup.h" #include "newtilesetdialog.h" +#include "shortcutseditor.h" namespace Ui { class MainWindow; @@ -147,6 +148,7 @@ private slots: void on_actionUse_Encounter_Json_triggered(bool checked); void on_actionMonitor_Project_Files_triggered(bool checked); void on_actionUse_Poryscript_triggered(bool checked); + void on_actionEdit_Shortcuts_triggered(); void on_mainTabBar_tabBarClicked(int index); @@ -231,6 +233,7 @@ private: Ui::MainWindow *ui; TilesetEditor *tilesetEditor = nullptr; RegionMapEditor *regionMapEditor = nullptr; + ShortcutsEditor *shortcutsEditor = nullptr; MapImageExporter *mapImageExporter = nullptr; FilterChildrenProxyModel *mapListProxyModel; NewMapPopup *newmapprompt = nullptr; @@ -294,6 +297,7 @@ private: void initEditor(); void initMiscHeapObjects(); void initMapSortOrder(); + void initUserShortcuts(); void setProjectSpecificUIVisibility(); void loadUserSettings(); void applyMapListFilter(QString filterText); diff --git a/include/ui/shortcutseditor.h b/include/ui/shortcutseditor.h new file mode 100644 index 00000000..b5aadc92 --- /dev/null +++ b/include/ui/shortcutseditor.h @@ -0,0 +1,80 @@ +#ifndef SHORTCUTSEDITOR_H +#define SHORTCUTSEDITOR_H + +#include +#include + +class QAbstractButton; +class QAction; +class QKeySequenceEdit; +class ActionShortcutEdit; + + +namespace Ui { +class ShortcutsEditor; +} + +class ShortcutsEditor : public QDialog +{ + Q_OBJECT + +public: + explicit ShortcutsEditor(QWidget *parent = nullptr); + ~ShortcutsEditor(); + +private: + Ui::ShortcutsEditor *ui; + QMap actions; + QWidget *ase_container; + + void populateShortcuts(); + void saveShortcuts(); + void resetShortcuts(); + void promptUser(ActionShortcutEdit *current, ActionShortcutEdit *sender); + +private slots: + void checkForDuplicates(); + void dialogButtonClicked(QAbstractButton *button); +}; + + +// A collection of QKeySequenceEdit's in a QHBoxLayout with a cooresponding QAction +class ActionShortcutEdit : public QWidget +{ + Q_OBJECT + +public: + explicit ActionShortcutEdit(QWidget *parent = nullptr, QAction *action = nullptr, int count = 1); + + bool eventFilter(QObject *watched, QEvent *event) override; + + int count() const { return kse_children.count(); } + void setCount(int count); + QList shortcuts() const; + void setShortcuts(const QList &keySequences); + void applyShortcuts(); + bool removeOne(const QKeySequence &keySequence); + bool contains(const QKeySequence &keySequence); + bool contains(QKeySequenceEdit *keySequenceEdit); + QKeySequence last() const { return shortcuts().last(); } + + QAction *action; + +public slots: + void clear(); + +signals: + void editingFinished(); + +private: + QVector kse_children; + QList ks_list; + + void updateShortcuts() { setShortcuts(shortcuts()); } + void focusLast(); + +private slots: + void onEditingFinished(); +}; + +#endif // SHORTCUTSEDITOR_H diff --git a/porymap.pro b/porymap.pro index 0da4a14b..f970606c 100644 --- a/porymap.pro +++ b/porymap.pro @@ -71,6 +71,7 @@ SOURCES += src/core/block.cpp \ src/ui/newtilesetdialog.cpp \ src/ui/flowlayout.cpp \ src/ui/mapruler.cpp \ + src/ui/shortcutseditor.cpp \ src/config.cpp \ src/editor.cpp \ src/main.cpp \ @@ -140,6 +141,7 @@ HEADERS += include/core/block.h \ include/ui/overlay.h \ include/ui/flowlayout.h \ include/ui/mapruler.h \ + include/ui/shortcutseditor.h \ include/config.h \ include/editor.h \ include/mainwindow.h \ @@ -156,7 +158,8 @@ FORMS += forms/mainwindow.ui \ forms/newmappopup.ui \ forms/aboutporymap.ui \ forms/newtilesetdialog.ui \ - forms/mapimageexporter.ui + forms/mapimageexporter.ui \ + forms/shortcutseditor.ui RESOURCES += \ resources/images.qrc \ diff --git a/src/config.cpp b/src/config.cpp index 15df7d43..2c009b36 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -11,6 +11,7 @@ #include #include #include +#include KeyValueConfigBase::~KeyValueConfigBase() { @@ -414,7 +415,7 @@ ProjectConfig projectConfig; QString ProjectConfig::getConfigFilepath() { // porymap config file is in the same directory as porymap itself. - return QDir(this->projectDir).filePath("porymap.project.cfg");; + return QDir(this->projectDir).filePath("porymap.project.cfg"); } void ProjectConfig::parseConfigKeyValue(QString key, QString value) { @@ -703,3 +704,84 @@ void ProjectConfig::setCustomScripts(QList scripts) { QList ProjectConfig::getCustomScripts() { return this->customScripts; } + +ShortcutsConfig shortcutsConfig; + +QString ShortcutsConfig::getConfigFilepath() { + QString settingsPath = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); + QDir dir(settingsPath); + if (!dir.exists()) + dir.mkpath(settingsPath); + + QString configPath = dir.absoluteFilePath("porymap.shortcuts.cfg"); + + return configPath; +} + +void ShortcutsConfig::parseConfigKeyValue(QString key, QString value) { + QStringList keySeqs = value.split(' '); + if (keySeqs.isEmpty()) + shortcuts.insert(key, value); + else for (auto keySeq : keySeqs) + shortcuts.insert(key, keySeq); +} + +QMap ShortcutsConfig::getKeyValueMap() { + QMap map; + for (auto key : shortcuts.uniqueKeys()) { + auto keySeqs = shortcuts.values(key); + QStringList values; + for (auto keySeq : keySeqs) + values.append(keySeq.toString()); + QString value = values.join(' '); + map.insert(key, value); + } + return map; +} + +// Call this before applying user shortcuts to be able to restore default shortcuts. +void ShortcutsConfig::setDefaultShortcuts(const QList &actions) { + defaultShortcuts.clear(); + for (auto *action : actions) { + const QString key = getKey(action); + bool addToUserShortcuts = !shortcuts.contains(key); + for (auto shortcut : action->shortcuts()) { + defaultShortcuts.insert(key, shortcut); + if (addToUserShortcuts) + shortcuts.insert(key, shortcut); + } + } + save(); +} + +QList ShortcutsConfig::getDefaultShortcuts(QAction *action) const { + return defaultShortcuts.values(getKey(action)); +} + +void ShortcutsConfig::setUserShortcuts(const QList &actions) { + shortcuts.clear(); + for (auto *action : actions) { + const QString key = getKey(action); + if (action->shortcuts().isEmpty()) + shortcuts.insert(key, QKeySequence()); + else for (auto shortcut : action->shortcuts()) + shortcuts.insert(key, shortcut); + } + save(); +} + +QList ShortcutsConfig::getUserShortcuts(QAction *action) const { + return shortcuts.values(getKey(action)); +} + +QString ShortcutsConfig::getKey(QObject *object) const { + QString key = object->objectName(); + QRegularExpression re("[A-Z]"); + int i = key.indexOf(re); + while (i != -1) { + if (key.at(i - 1) != '_') + key.insert(i++, '_'); + i = key.indexOf(re, i + 1); + } + return key.toLower(); +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index f239d4d6..eb4a2de9 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -92,6 +92,7 @@ void MainWindow::initWindow() { this->initEditor(); this->initMiscHeapObjects(); this->initMapSortOrder(); + this->initUserShortcuts(); this->restoreWindowState(); setWindowDisabled(true); @@ -106,6 +107,13 @@ void MainWindow::initExtraShortcuts() { ui->actionZoom_In->setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+=")}); } +void MainWindow::initUserShortcuts() { + shortcutsConfig.load(); + shortcutsConfig.setDefaultShortcuts(findChildren()); + for (auto *action : findChildren()) + action->setShortcuts(shortcutsConfig.getUserShortcuts(action)); +} + void MainWindow::initCustomUI() { // Set up the tab bar ui->mainTabBar->addTab("Map"); @@ -158,9 +166,11 @@ void MainWindow::initEditor() { this->loadUserSettings(); undoAction = editor->editGroup.createUndoAction(this, tr("&Undo")); + undoAction->setObjectName("action_Undo"); undoAction->setShortcut(QKeySequence("Ctrl+Z")); redoAction = editor->editGroup.createRedoAction(this, tr("&Redo")); + redoAction->setObjectName("action_Redo"); redoAction->setShortcuts({QKeySequence("Ctrl+Y"), QKeySequence("Ctrl+Shift+Z")}); ui->menuEdit->addAction(undoAction); @@ -171,7 +181,8 @@ void MainWindow::initEditor() { undoView->setAttribute(Qt::WA_QuitOnClose, false); // Show the EditHistory dialog with Ctrl+E - QAction *showHistory = new QAction("Show Edit History..."); + QAction *showHistory = new QAction("Show Edit History...", this); + showHistory->setObjectName("action_ShowEditHistory"); showHistory->setShortcut(QKeySequence("Ctrl+E")); connect(showHistory, &QAction::triggered, [undoView](){ undoView->show(); }); @@ -1403,6 +1414,19 @@ void MainWindow::on_actionUse_Poryscript_triggered(bool checked) projectConfig.setUsePoryScript(checked); } +void MainWindow::on_actionEdit_Shortcuts_triggered() +{ + if (!shortcutsEditor) + shortcutsEditor = new ShortcutsEditor(this); + + if (shortcutsEditor->isHidden()) + shortcutsEditor->show(); + else if (shortcutsEditor->isMinimized()) + shortcutsEditor->showNormal(); + else + shortcutsEditor->activateWindow(); +} + void MainWindow::on_actionPencil_triggered() { on_toolButton_Paint_clicked(); diff --git a/src/ui/shortcutseditor.cpp b/src/ui/shortcutseditor.cpp new file mode 100644 index 00000000..97a3ebf4 --- /dev/null +++ b/src/ui/shortcutseditor.cpp @@ -0,0 +1,234 @@ +#include "shortcutseditor.h" +#include "ui_shortcutseditor.h" +#include "config.h" +#include "log.h" + +#include +#include +#include +#include +#include +#include + + +ShortcutsEditor::ShortcutsEditor(QWidget *parent) : + QDialog(parent), + ui(new Ui::ShortcutsEditor), + actions(QMap()) +{ + ui->setupUi(this); + ase_container = ui->scrollAreaWidgetContents_Shortcuts; + connect(ui->buttonBox, &QDialogButtonBox::clicked, + this, &ShortcutsEditor::dialogButtonClicked); + populateShortcuts(); +} + +ShortcutsEditor::~ShortcutsEditor() +{ + delete ui; +} + +void ShortcutsEditor::populateShortcuts() { + if (!parent()) + return; + + for (auto action : parent()->findChildren()) + if (!action->text().isEmpty() && !action->objectName().isEmpty()) + actions.insert(action->text().remove('&'), action); + + auto *formLayout = new QFormLayout(ase_container); + for (auto *action : actions) { + auto userShortcuts = shortcutsConfig.getUserShortcuts(action); + auto *ase = new ActionShortcutEdit(ase_container, action, 2); + connect(ase, &ActionShortcutEdit::editingFinished, + this, &ShortcutsEditor::checkForDuplicates); + ase->setShortcuts(userShortcuts); + formLayout->addRow(action->text(), ase); + } +} + +void ShortcutsEditor::saveShortcuts() { + auto ase_children = ase_container->findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto *ase : ase_children) + ase->applyShortcuts(); + shortcutsConfig.setUserShortcuts(actions.values()); +} + +void ShortcutsEditor::resetShortcuts() { + auto ase_children = ase_container->findChildren(QString(), Qt::FindDirectChildrenOnly); + for (auto *ase : ase_children) + ase->setShortcuts(shortcutsConfig.getDefaultShortcuts(ase->action)); +} + +void ShortcutsEditor::promptUser(ActionShortcutEdit *current, ActionShortcutEdit *sender) { + auto result = QMessageBox::question( + this, + "porymap", + QString("Shortcut \"%1\" is already used by \"%2\", would you like to replace it?") + .arg(sender->last().toString()).arg(current->action->text()), + QMessageBox::Yes | QMessageBox::No, QMessageBox::No); + + if (result == QMessageBox::Yes) + current->removeOne(sender->last()); + else if (result == QMessageBox::No) + sender->removeOne(sender->last()); +} + +void ShortcutsEditor::checkForDuplicates() { + auto *sender_ase = qobject_cast(sender()); + if (!sender_ase) + return; + + for (auto *child_kse : findChildren()) { + if (child_kse->keySequence().isEmpty() || child_kse->parent() == sender()) + continue; + + if (sender_ase->contains(child_kse->keySequence())) { + auto *current_ase = qobject_cast(child_kse->parent()); + if (!current_ase) + continue; + + promptUser(current_ase, sender_ase); + activateWindow(); + return; + } + } +} + +void ShortcutsEditor::dialogButtonClicked(QAbstractButton *button) { + auto buttonRole = ui->buttonBox->buttonRole(button); + if (buttonRole == QDialogButtonBox::AcceptRole) { + saveShortcuts(); + hide(); + } else if (buttonRole == QDialogButtonBox::ApplyRole) { + saveShortcuts(); + } else if (buttonRole == QDialogButtonBox::RejectRole) { + hide(); + } else if (buttonRole == QDialogButtonBox::ResetRole) { + resetShortcuts(); + } +} + + +ActionShortcutEdit::ActionShortcutEdit(QWidget *parent, QAction *action, int count) : + QWidget(parent), + action(action), + kse_children(QVector()), + ks_list(QList()) +{ + setLayout(new QHBoxLayout(this)); + layout()->setContentsMargins(0, 0, 0, 0); + setCount(count); +} + +bool ActionShortcutEdit::eventFilter(QObject *watched, QEvent *event) { + auto *watched_kse = qobject_cast(watched); + if (!watched_kse) + return false; + + if (event->type() == QEvent::KeyPress) { + auto *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) { + watched_kse->clearFocus(); + return true; + } else if (keyEvent->key() == Qt::Key_Backspace) { + removeOne(watched_kse->keySequence()); + return true; + } else { + watched_kse->clear(); + } + } + return false; +} + +void ActionShortcutEdit::setCount(int count) { + if (count < 1) + count = 1; + + while (kse_children.count() > count) { + layout()->removeWidget(kse_children.last()); + delete kse_children.last(); + kse_children.removeLast(); + } + + while (kse_children.count() < count) { + auto *kse = new QKeySequenceEdit(this); + connect(kse, &QKeySequenceEdit::editingFinished, + this, &ActionShortcutEdit::onEditingFinished); + kse->installEventFilter(this); + layout()->addWidget(kse); + kse_children.append(kse); + } +} + +QList ActionShortcutEdit::shortcuts() const { + QList current_ks_list; + for (auto *kse : kse_children) + if (!kse->keySequence().isEmpty()) + current_ks_list.append(kse->keySequence()); + return current_ks_list; +} + +void ActionShortcutEdit::setShortcuts(const QList &keySequences) { + clear(); + ks_list = keySequences; + int minCount = qMin(kse_children.count(), ks_list.count()); + for (int i = 0; i < minCount; ++i) + kse_children[i]->setKeySequence(ks_list[i]); +} + +void ActionShortcutEdit::applyShortcuts() { + action->setShortcuts(shortcuts()); +} + +bool ActionShortcutEdit::removeOne(const QKeySequence &keySequence) { + for (auto *kse : kse_children) { + if (kse->keySequence() == keySequence) { + ks_list.removeOne(keySequence); + kse->clear(); + updateShortcuts(); + return true; + } + } + return false; +} + +bool ActionShortcutEdit::contains(const QKeySequence &keySequence) { + for (auto ks : shortcuts()) + if (ks == keySequence) + return true; + return false; +} + +bool ActionShortcutEdit::contains(QKeySequenceEdit *keySequenceEdit) { + for (auto *kse : kse_children) + if (kse == keySequenceEdit) + return true; + return false; +} + +void ActionShortcutEdit::clear() { + for (auto *kse : kse_children) + kse->clear(); +} + +void ActionShortcutEdit::focusLast() { + for (int i = count() - 1; i >= 0; --i) { + if (!kse_children[i]->keySequence().isEmpty()) { + kse_children[i]->setFocus(); + return; + } + } +} + +void ActionShortcutEdit::onEditingFinished() { + auto *kse = qobject_cast(sender()); + if (!kse) + return; + + if (ks_list.contains(kse->keySequence())) + removeOne(kse->keySequence()); + updateShortcuts(); + focusLast(); + emit editingFinished(); +} From ed2f8bf180c7c8e266962f978a55dc8b6790196d Mon Sep 17 00:00:00 2001 From: BigBahss Date: Tue, 3 Nov 2020 03:18:34 -0500 Subject: [PATCH 03/12] Add custom Shortcut class --- include/ui/shortcut.h | 65 ++++++++++++++++++ porymap.pro | 2 + src/ui/shortcut.cpp | 153 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 220 insertions(+) create mode 100644 include/ui/shortcut.h create mode 100644 src/ui/shortcut.cpp diff --git a/include/ui/shortcut.h b/include/ui/shortcut.h new file mode 100644 index 00000000..8b0e87ce --- /dev/null +++ b/include/ui/shortcut.h @@ -0,0 +1,65 @@ +#ifndef SHORTCUT_H +#define SHORTCUT_H + +#include +#include +#include + + +// Alternative to QShortcut that adds support for multiple QKeySequences. +// Use this to allow the shortcut to be editable in ShortcutsEditor. +class Shortcut : public QObject +{ + Q_OBJECT + +public: + explicit Shortcut(QWidget *parent); + Shortcut(const QKeySequence &key, QWidget *parent, + const char *member = nullptr, const char *ambiguousMember = nullptr, + Qt::ShortcutContext shortcutContext = Qt::WindowShortcut); + Shortcut(const QList &keys, QWidget *parent, + const char *member = nullptr, const char *ambiguousMember = nullptr, + Qt::ShortcutContext shortcutContext = Qt::WindowShortcut); + ~Shortcut(); + + void addKey(const QKeySequence &key); + void setKey(const QKeySequence &key); + QKeySequence key() const; + + void addKeys(const QList &keys); + void setKeys(const QList &keys); + QList keys() const; + + void setEnabled(bool enable); + bool isEnabled() const; + + void setContext(Qt::ShortcutContext context); + Qt::ShortcutContext context() const; + + void setWhatsThis(const QString &text); + QString whatsThis() const; + + void setAutoRepeat(bool on); + bool autoRepeat() const; + + int id() const; + QList ids() const; + + inline QWidget *parentWidget() const + { return static_cast(QObject::parent()); } + +signals: + void activated(); + void activatedAmbiguously(); + +protected: + bool event(QEvent *e) override; + +private: + const char *sc_member; + const char *sc_ambiguousmember; + Qt::ShortcutContext sc_context; + QVector sc_vec; +}; + +#endif // SHORTCUT_H diff --git a/porymap.pro b/porymap.pro index f970606c..593b1112 100644 --- a/porymap.pro +++ b/porymap.pro @@ -71,6 +71,7 @@ SOURCES += src/core/block.cpp \ src/ui/newtilesetdialog.cpp \ src/ui/flowlayout.cpp \ src/ui/mapruler.cpp \ + src/ui/shortcut.cpp \ src/ui/shortcutseditor.cpp \ src/config.cpp \ src/editor.cpp \ @@ -141,6 +142,7 @@ HEADERS += include/core/block.h \ include/ui/overlay.h \ include/ui/flowlayout.h \ include/ui/mapruler.h \ + include/ui/shortcut.h \ include/ui/shortcutseditor.h \ include/config.h \ include/editor.h \ diff --git a/src/ui/shortcut.cpp b/src/ui/shortcut.cpp new file mode 100644 index 00000000..0dd2f30a --- /dev/null +++ b/src/ui/shortcut.cpp @@ -0,0 +1,153 @@ +#include "shortcut.h" + +#include +#include + + +Shortcut::Shortcut(QWidget *parent) : + QObject(parent), + sc_member(nullptr), + sc_ambiguousmember(nullptr), + sc_context(Qt::WindowShortcut), + sc_vec(QVector({new QShortcut(parent)})) +{ } + +Shortcut::Shortcut(const QKeySequence &key, QWidget *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext shortcutContext) : + QObject(parent), + sc_member(member), + sc_ambiguousmember(ambiguousMember), + sc_context(shortcutContext), + sc_vec(QVector()) +{ + setKey(key); +} + +Shortcut::Shortcut(const QList &keys, QWidget *parent, + const char *member, const char *ambiguousMember, + Qt::ShortcutContext shortcutContext) : + QObject(parent), + sc_member(member), + sc_ambiguousmember(ambiguousMember), + sc_context(shortcutContext), + sc_vec(QVector()) +{ + setKeys(keys); +} + +Shortcut::~Shortcut() +{ + for (auto *sc : sc_vec) + delete sc; +} + +void Shortcut::addKey(const QKeySequence &key) { + sc_vec.append(new QShortcut(key, parentWidget(), sc_member, sc_ambiguousmember, sc_context)); +} + +void Shortcut::setKey(const QKeySequence &key) { + if (sc_vec.isEmpty()) { + addKey(key); + } else { + while (sc_vec.count() != 1) + delete sc_vec.takeLast(); + sc_vec.first()->setKey(key); + } +} + +QKeySequence Shortcut::key() const { + return sc_vec.first()->key(); +} + +void Shortcut::addKeys(const QList &keys) { + for (auto key : keys) + addKey(key); +} + +void Shortcut::setKeys(const QList &keys) { + if (keys.isEmpty()) + return; + + while (sc_vec.count() < keys.count()) + addKey(QKeySequence()); + + while (sc_vec.count() > keys.count()) + delete sc_vec.takeLast(); + + for (int i = 0; i < keys.count(); ++i) + sc_vec[i]->setKey(keys[i]); +} + +QList Shortcut::keys() const { + QList ks_list = QList(); + for (auto *sc : sc_vec) + ks_list.append(sc->key()); + return ks_list; +} + +void Shortcut::setEnabled(bool enable) { + for (auto *sc : sc_vec) + sc->setEnabled(enable); +} + +bool Shortcut::isEnabled() const { + return sc_vec.first()->isEnabled(); +} + +void Shortcut::setContext(Qt::ShortcutContext context) { + sc_context = context; + for (auto *sc : sc_vec) + sc->setContext(context); +} + +Qt::ShortcutContext Shortcut::context() const { + return sc_context; +} + +void Shortcut::setWhatsThis(const QString &text) { + for (auto *sc : sc_vec) + sc->setWhatsThis(text); +} + +QString Shortcut::whatsThis() const { + return sc_vec.first()->whatsThis(); +} + +void Shortcut::setAutoRepeat(bool on) { + for (auto *sc : sc_vec) + sc->setAutoRepeat(on); +} + +bool Shortcut::autoRepeat() const { + return sc_vec.first()->autoRepeat(); +} + +int Shortcut::id() const { + return sc_vec.first()->id(); +} + +QList Shortcut::ids() const { + QList id_list({id()}); + for (auto *sc : sc_vec) + id_list.append(sc->id()); + return id_list; +} + +bool Shortcut::event(QEvent *e) { + if (isEnabled() && e->type() == QEvent::Shortcut) { + auto se = static_cast(e); + if (ids().contains(se->shortcutId()) && keys().contains(se->key())) { + if (QWhatsThis::inWhatsThisMode()) { + QWhatsThis::showText(QCursor::pos(), whatsThis()); + } else { + if (se->isAmbiguous()) + emit activatedAmbiguously(); + else + emit activated(); + } + return true; + } + } + return false; +} From eabd2d66185f5c16d0bc30537ca1f33068907a08 Mon Sep 17 00:00:00 2001 From: BigBahss Date: Tue, 3 Nov 2020 05:58:10 -0500 Subject: [PATCH 04/12] Convert QShortcut's to Shortcut's and add them to config --- include/config.h | 26 +++++---- src/config.cpp | 114 +++++++++++++++++++++++++++------------ src/mainwindow.cpp | 26 ++++++--- src/ui/tileseteditor.cpp | 2 +- 4 files changed, 116 insertions(+), 52 deletions(-) diff --git a/include/config.h b/include/config.h index 4c4543d4..9c802a39 100644 --- a/include/config.h +++ b/include/config.h @@ -195,21 +195,29 @@ private: extern ProjectConfig projectConfig; class QAction; +class Shortcut; class ShortcutsConfig : public KeyValueConfigBase { public: ShortcutsConfig() : - shortcuts(QMultiMap()), + userShortcuts(QMultiMap()), defaultShortcuts(QMultiMap()) - { - reset(); - } - virtual void reset() override { shortcuts.clear(); } - void setDefaultShortcuts(const QList &actions); + { } + + virtual void reset() override { userShortcuts.clear(); } + + void setDefaultShortcuts( + const QList &actions = QList(), + const QList &shortcuts = QList()); QList getDefaultShortcuts(QAction *action) const; - void setUserShortcuts(const QList &actions); + QList getDefaultShortcuts(Shortcut *shortcut) const; + + void setUserShortcuts( + const QList &actions = QList(), + const QList &shortcuts = QList()); QList getUserShortcuts(QAction *action) const; + QList getUserShortcuts(Shortcut *shortcut) const; protected: virtual QString getConfigFilepath() override; @@ -219,10 +227,10 @@ protected: virtual void setUnreadKeys() override {}; private: - QMultiMap shortcuts; + QMultiMap userShortcuts; QMultiMap defaultShortcuts; - QString getKey(QObject *object) const; + QString cfgKey(QObject *object) const; }; extern ShortcutsConfig shortcutsConfig; diff --git a/src/config.cpp b/src/config.cpp index 2c009b36..0c9cbee9 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -1,5 +1,6 @@ #include "config.h" #include "log.h" +#include "shortcut.h" #include #include #include @@ -719,69 +720,114 @@ QString ShortcutsConfig::getConfigFilepath() { } void ShortcutsConfig::parseConfigKeyValue(QString key, QString value) { - QStringList keySeqs = value.split(' '); - if (keySeqs.isEmpty()) - shortcuts.insert(key, value); - else for (auto keySeq : keySeqs) - shortcuts.insert(key, keySeq); + QStringList keySequences = value.split(' '); + for (auto keySequence : keySequences) + userShortcuts.insert(key, keySequence); } QMap ShortcutsConfig::getKeyValueMap() { QMap map; - for (auto key : shortcuts.uniqueKeys()) { - auto keySeqs = shortcuts.values(key); + for (auto cfg_key : userShortcuts.uniqueKeys()) { + auto keySequences = userShortcuts.values(cfg_key); QStringList values; - for (auto keySeq : keySeqs) - values.append(keySeq.toString()); + for (auto keySequence : keySequences) + values.append(keySequence.toString()); QString value = values.join(' '); - map.insert(key, value); + map.insert(cfg_key, value); } return map; } // Call this before applying user shortcuts to be able to restore default shortcuts. -void ShortcutsConfig::setDefaultShortcuts(const QList &actions) { +void ShortcutsConfig::setDefaultShortcuts(const QList &actions, const QList &shortcuts) { defaultShortcuts.clear(); + for (auto *action : actions) { - const QString key = getKey(action); - bool addToUserShortcuts = !shortcuts.contains(key); - for (auto shortcut : action->shortcuts()) { - defaultShortcuts.insert(key, shortcut); + if (action->text().isEmpty() || action->objectName().isEmpty()) + continue; + const QString cfg_key = cfgKey(action); + bool addToUserShortcuts = !userShortcuts.contains(cfg_key); + if (action->shortcuts().isEmpty()) { + defaultShortcuts.insert(cfg_key, QKeySequence()); if (addToUserShortcuts) - shortcuts.insert(key, shortcut); + userShortcuts.insert(cfg_key, QKeySequence()); + } else { + for (auto keySequence : action->shortcuts()) { + defaultShortcuts.insert(cfg_key, keySequence); + if (addToUserShortcuts) + userShortcuts.insert(cfg_key, keySequence); + } } } + + for (auto *shortcut : shortcuts) { + if (shortcut->objectName().isEmpty()) + continue; + const QString cfg_key = cfgKey(shortcut); + bool addToUserShortcuts = !userShortcuts.contains(cfg_key); + for (auto keySequence : shortcut->keys()) { + defaultShortcuts.insert(cfg_key, keySequence); + if (addToUserShortcuts) + userShortcuts.insert(cfg_key, keySequence); + } + } + save(); } QList ShortcutsConfig::getDefaultShortcuts(QAction *action) const { - return defaultShortcuts.values(getKey(action)); + return defaultShortcuts.values(cfgKey(action)); } -void ShortcutsConfig::setUserShortcuts(const QList &actions) { - shortcuts.clear(); +QList ShortcutsConfig::getDefaultShortcuts(Shortcut *shortcut) const { + return defaultShortcuts.values(cfgKey(shortcut)); +} + +void ShortcutsConfig::setUserShortcuts(const QList &actions, const QList &shortcuts) { + userShortcuts.clear(); + for (auto *action : actions) { - const QString key = getKey(action); + if (action->text().isEmpty() || action->objectName().isEmpty()) + continue; + const QString cfg_key = cfgKey(action); if (action->shortcuts().isEmpty()) - shortcuts.insert(key, QKeySequence()); - else for (auto shortcut : action->shortcuts()) - shortcuts.insert(key, shortcut); + userShortcuts.insert(cfg_key, QKeySequence()); + else + for (auto keySequence : action->shortcuts()) + userShortcuts.insert(cfg_key, keySequence); } + + for (auto *shortcut : shortcuts) { + if (shortcut->objectName().isEmpty()) + continue; + const QString cfg_key = cfgKey(shortcut); + if (shortcut->keys().isEmpty()) + userShortcuts.insert(cfg_key, QKeySequence()); + else + for (auto keySequence : shortcut->keys()) + userShortcuts.insert(cfg_key, keySequence); + } + save(); } QList ShortcutsConfig::getUserShortcuts(QAction *action) const { - return shortcuts.values(getKey(action)); + return userShortcuts.values(cfgKey(action)); } -QString ShortcutsConfig::getKey(QObject *object) const { - QString key = object->objectName(); - QRegularExpression re("[A-Z]"); - int i = key.indexOf(re); - while (i != -1) { - if (key.at(i - 1) != '_') - key.insert(i++, '_'); - i = key.indexOf(re, i + 1); - } - return key.toLower(); +QList ShortcutsConfig::getUserShortcuts(Shortcut *shortcut) const { + return userShortcuts.values(cfgKey(shortcut)); +} + +// Converts a camelCase object name to snake_case. +QString ShortcutsConfig::cfgKey(QObject *object) const { + QString cfg_key = object->objectName(); + QRegularExpression re("[A-Z]"); + int i = cfg_key.indexOf(re); + while (i != -1) { + if (cfg_key.at(i - 1) != '_') + cfg_key.insert(i++, '_'); + i = cfg_key.indexOf(re, i + 1); + } + return cfg_key.toLower(); } diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index eb4a2de9..2b242876 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -14,11 +14,11 @@ #include "draggablepixmapitem.h" #include "editcommands.h" #include "flowlayout.h" +#include "shortcut.h" #include #include #include -#include #include #include #include @@ -99,19 +99,29 @@ void MainWindow::initWindow() { } void MainWindow::initExtraShortcuts() { - new QShortcut(QKeySequence("Ctrl+0"), this, SLOT(resetMapViewScale())); - new QShortcut(QKeySequence("Ctrl+G"), ui->checkBox_ToggleGrid, SLOT(toggle())); - new QShortcut(QKeySequence("Ctrl+D"), this, SLOT(duplicate())); - new QShortcut(QKeySequence::Delete, this, SLOT(on_toolButton_deleteObject_clicked())); - new QShortcut(QKeySequence("Backspace"), this, SLOT(on_toolButton_deleteObject_clicked())); - ui->actionZoom_In->setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+=")}); + auto *shortcutReset_Zoom = new Shortcut(QKeySequence("Ctrl+0"), this, SLOT(resetMapViewScale())); + shortcutReset_Zoom->setObjectName("shortcutReset_Zoom"); + + auto *shortcutToggle_Grid = new Shortcut(QKeySequence("Ctrl+G"), ui->checkBox_ToggleGrid, SLOT(toggle())); + shortcutToggle_Grid->setObjectName("shortcutToggle_Grid"); + + auto *shortcutDuplicate_Events = new Shortcut(QKeySequence("Ctrl+D"), this, SLOT(duplicate())); + shortcutDuplicate_Events->setObjectName("shortcutDuplicate_Events"); + + auto *shortcutDelete_Object = new Shortcut( + {QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(on_toolButton_deleteObject_clicked())); + shortcutDelete_Object->setObjectName("shortcutDelete_Object"); + + ui->actionZoom_In->setShortcuts({ui->actionZoom_In->shortcut(), QKeySequence("Ctrl+=")}); } void MainWindow::initUserShortcuts() { shortcutsConfig.load(); - shortcutsConfig.setDefaultShortcuts(findChildren()); + shortcutsConfig.setDefaultShortcuts(findChildren(), findChildren()); for (auto *action : findChildren()) action->setShortcuts(shortcutsConfig.getUserShortcuts(action)); + for (auto *shortcut : findChildren()) + shortcut->setKeys(shortcutsConfig.getUserShortcuts(shortcut)); } void MainWindow::initCustomUI() { diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 950b8d46..1c6b620e 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -86,7 +86,7 @@ void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTi void TilesetEditor::initUi() { ui->setupUi(this); - new QShortcut(QKeySequence("Ctrl+Shift+Z"), this, SLOT(on_actionRedo_triggered())); + ui->actionRedo->setShortcuts({ui->actionRedo->shortcut(), QKeySequence("Ctrl+Shift+Z")}); this->tileXFlip = ui->checkBox_xFlip->isChecked(); this->tileYFlip = ui->checkBox_yFlip->isChecked(); this->paletteId = ui->spinBox_paletteSelector->value(); From 43d3257d89b1a2ff73de0d624c284bad1035d281 Mon Sep 17 00:00:00 2001 From: BigBahss Date: Thu, 5 Nov 2020 06:32:31 -0500 Subject: [PATCH 05/12] Extract functions in ShortcutsConfig --- include/config.h | 27 +++++++-- src/config.cpp | 133 ++++++++++++++++++++++++-------------------- src/ui/shortcut.cpp | 2 +- 3 files changed, 96 insertions(+), 66 deletions(-) diff --git a/include/config.h b/include/config.h index 9c802a39..a690ce90 100644 --- a/include/config.h +++ b/include/config.h @@ -207,15 +207,15 @@ public: virtual void reset() override { userShortcuts.clear(); } - void setDefaultShortcuts( - const QList &actions = QList(), - const QList &shortcuts = QList()); + void setDefaultShortcuts(const QList &actions); + void setDefaultShortcuts(const QList &shortcuts); + void setDefaultShortcuts(const QList &actions, const QList &shortcuts); QList getDefaultShortcuts(QAction *action) const; QList getDefaultShortcuts(Shortcut *shortcut) const; - void setUserShortcuts( - const QList &actions = QList(), - const QList &shortcuts = QList()); + void setUserShortcuts(const QList &actions); + void setUserShortcuts(const QList &shortcuts); + void setUserShortcuts(const QList &actions, const QList &shortcuts); QList getUserShortcuts(QAction *action) const; QList getUserShortcuts(Shortcut *shortcut) const; @@ -230,6 +230,21 @@ private: QMultiMap userShortcuts; QMultiMap defaultShortcuts; + enum StoreType { + User, + Default + }; + + void storeShortcuts( + StoreType storeType, + const QList &actions); + void storeShortcuts( + StoreType storeType, + const QList &shortcuts); + void storeShortcut( + StoreType storeType, + const QString &cfgKey, + const QList &keySequences); QString cfgKey(QObject *object) const; }; diff --git a/src/config.cpp b/src/config.cpp index 0c9cbee9..e78ee25c 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -738,40 +738,22 @@ QMap ShortcutsConfig::getKeyValueMap() { return map; } +// Call this before applying user shortcuts to be able to restore default shortcuts. +void ShortcutsConfig::setDefaultShortcuts(const QList &actions) { + storeShortcuts(StoreType::Default, actions); + save(); +} + +// Call this before applying user shortcuts to be able to restore default shortcuts. +void ShortcutsConfig::setDefaultShortcuts(const QList &shortcuts) { + storeShortcuts(StoreType::Default, shortcuts); + save(); +} + // Call this before applying user shortcuts to be able to restore default shortcuts. void ShortcutsConfig::setDefaultShortcuts(const QList &actions, const QList &shortcuts) { - defaultShortcuts.clear(); - - for (auto *action : actions) { - if (action->text().isEmpty() || action->objectName().isEmpty()) - continue; - const QString cfg_key = cfgKey(action); - bool addToUserShortcuts = !userShortcuts.contains(cfg_key); - if (action->shortcuts().isEmpty()) { - defaultShortcuts.insert(cfg_key, QKeySequence()); - if (addToUserShortcuts) - userShortcuts.insert(cfg_key, QKeySequence()); - } else { - for (auto keySequence : action->shortcuts()) { - defaultShortcuts.insert(cfg_key, keySequence); - if (addToUserShortcuts) - userShortcuts.insert(cfg_key, keySequence); - } - } - } - - for (auto *shortcut : shortcuts) { - if (shortcut->objectName().isEmpty()) - continue; - const QString cfg_key = cfgKey(shortcut); - bool addToUserShortcuts = !userShortcuts.contains(cfg_key); - for (auto keySequence : shortcut->keys()) { - defaultShortcuts.insert(cfg_key, keySequence); - if (addToUserShortcuts) - userShortcuts.insert(cfg_key, keySequence); - } - } - + storeShortcuts(StoreType::Default, actions); + storeShortcuts(StoreType::Default, shortcuts); save(); } @@ -783,31 +765,19 @@ QList ShortcutsConfig::getDefaultShortcuts(Shortcut *shortcut) con return defaultShortcuts.values(cfgKey(shortcut)); } +void ShortcutsConfig::setUserShortcuts(const QList &actions) { + storeShortcuts(StoreType::User, actions); + save(); +} + +void ShortcutsConfig::setUserShortcuts(const QList &shortcuts) { + storeShortcuts(StoreType::User, shortcuts); + save(); +} + void ShortcutsConfig::setUserShortcuts(const QList &actions, const QList &shortcuts) { - userShortcuts.clear(); - - for (auto *action : actions) { - if (action->text().isEmpty() || action->objectName().isEmpty()) - continue; - const QString cfg_key = cfgKey(action); - if (action->shortcuts().isEmpty()) - userShortcuts.insert(cfg_key, QKeySequence()); - else - for (auto keySequence : action->shortcuts()) - userShortcuts.insert(cfg_key, keySequence); - } - - for (auto *shortcut : shortcuts) { - if (shortcut->objectName().isEmpty()) - continue; - const QString cfg_key = cfgKey(shortcut); - if (shortcut->keys().isEmpty()) - userShortcuts.insert(cfg_key, QKeySequence()); - else - for (auto keySequence : shortcut->keys()) - userShortcuts.insert(cfg_key, keySequence); - } - + storeShortcuts(StoreType::User, actions); + storeShortcuts(StoreType::User, shortcuts); save(); } @@ -819,13 +789,58 @@ QList ShortcutsConfig::getUserShortcuts(Shortcut *shortcut) const return userShortcuts.values(cfgKey(shortcut)); } -// Converts a camelCase object name to snake_case. +void ShortcutsConfig::storeShortcuts(StoreType storeType, const QList &actions) { + for (auto *action : actions) + if (!action->text().isEmpty() && !action->objectName().isEmpty()) + storeShortcut(storeType, cfgKey(action), action->shortcuts()); +} + +void ShortcutsConfig::storeShortcuts(StoreType storeType, const QList &shortcuts) { + for (auto *shortcut : shortcuts) + if (!shortcut->whatsThis().isEmpty() && !shortcut->objectName().isEmpty()) + storeShortcut(storeType, cfgKey(shortcut), shortcut->keys()); +} + +void ShortcutsConfig::storeShortcut( + StoreType storeType, + const QString &cfgKey, + const QList &keySequences) +{ + bool storeUser = (storeType == User) || !userShortcuts.contains(cfgKey); + + if (storeType == Default) + defaultShortcuts.remove(cfgKey); + if (storeUser) + userShortcuts.remove(cfgKey); + + if (keySequences.isEmpty()) { + if (storeType == Default) + defaultShortcuts.insert(cfgKey, QKeySequence()); + if (storeUser) + userShortcuts.insert(cfgKey, QKeySequence()); + } else { + for (auto keySequence : keySequences) { + if (storeType == Default) + defaultShortcuts.insert(cfgKey, keySequence); + if (storeUser) + userShortcuts.insert(cfgKey, keySequence); + } + } +} + +/* Creates a config key from the object's name prepended with the parent + * window's object name, and converts camelCase to snake_case. */ QString ShortcutsConfig::cfgKey(QObject *object) const { - QString cfg_key = object->objectName(); + auto cfg_key = QString(); + auto *parentWidget = static_cast(object->parent()); + if (parentWidget) + cfg_key = parentWidget->window()->objectName() + '_'; + cfg_key += object->objectName(); + QRegularExpression re("[A-Z]"); int i = cfg_key.indexOf(re); while (i != -1) { - if (cfg_key.at(i - 1) != '_') + if (i != 0 && cfg_key.at(i - 1) != '_') cfg_key.insert(i++, '_'); i = cfg_key.indexOf(re, i + 1); } diff --git a/src/ui/shortcut.cpp b/src/ui/shortcut.cpp index 0dd2f30a..e94b4095 100644 --- a/src/ui/shortcut.cpp +++ b/src/ui/shortcut.cpp @@ -128,7 +128,7 @@ int Shortcut::id() const { } QList Shortcut::ids() const { - QList id_list({id()}); + QList id_list; for (auto *sc : sc_vec) id_list.append(sc->id()); return id_list; From f5964fbe7f0350960bf7debb66714c70f7bd8e7e Mon Sep 17 00:00:00 2001 From: BigBahss Date: Fri, 6 Nov 2020 10:20:31 -0500 Subject: [PATCH 06/12] Refactor ActionShortcutEdit into MultiKeyEdit --- include/ui/multikeyedit.h | 50 +++++++++++ porymap.pro | 2 + src/ui/multikeyedit.cpp | 175 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 227 insertions(+) create mode 100644 include/ui/multikeyedit.h create mode 100644 src/ui/multikeyedit.cpp diff --git a/include/ui/multikeyedit.h b/include/ui/multikeyedit.h new file mode 100644 index 00000000..c1736280 --- /dev/null +++ b/include/ui/multikeyedit.h @@ -0,0 +1,50 @@ +#ifndef MULTIKEYEDIT_H +#define MULTIKEYEDIT_H + +#include +#include + +class QLineEdit; + + +// A collection of QKeySequenceEdit's laid out horizontally. +class MultiKeyEdit : public QWidget +{ + Q_OBJECT + +public: + MultiKeyEdit(QWidget *parent = nullptr, int fieldCount = 2); + + bool eventFilter(QObject *watched, QEvent *event) override; + + int fieldCount() const; + void setFieldCount(int count); + QList keySequences() const; + bool removeOne(const QKeySequence &keySequence); + bool contains(const QKeySequence &keySequence) const; + void setContextMenuPolicy(Qt::ContextMenuPolicy policy); + +public slots: + void clear(); + void setKeySequences(const QList &keySequences); + void addKeySequence(const QKeySequence &keySequence); + +signals: + void keySequenceChanged(const QKeySequence &keySequence); + void editingFinished(); + void customContextMenuRequested(const QPoint &pos); + +private: + QVector keySequenceEdit_vec; + QList keySequence_list; // Used to track changes + + void addNewKeySequenceEdit(); + void alignKeySequencesLeft(); + void setFocusToLastNonEmptyKeySequenceEdit(); + +private slots: + void onEditingFinished(); + void showDefaultContextMenu(QLineEdit *lineEdit, const QPoint &pos); +}; + +#endif // MULTIKEYEDIT_H diff --git a/porymap.pro b/porymap.pro index 593b1112..af5a6205 100644 --- a/porymap.pro +++ b/porymap.pro @@ -73,6 +73,7 @@ SOURCES += src/core/block.cpp \ src/ui/mapruler.cpp \ src/ui/shortcut.cpp \ src/ui/shortcutseditor.cpp \ + src/ui/multikeyedit.cpp \ src/config.cpp \ src/editor.cpp \ src/main.cpp \ @@ -144,6 +145,7 @@ HEADERS += include/core/block.h \ include/ui/mapruler.h \ include/ui/shortcut.h \ include/ui/shortcutseditor.h \ + include/ui/multikeyedit.h \ include/config.h \ include/editor.h \ include/mainwindow.h \ diff --git a/src/ui/multikeyedit.cpp b/src/ui/multikeyedit.cpp new file mode 100644 index 00000000..5f66328e --- /dev/null +++ b/src/ui/multikeyedit.cpp @@ -0,0 +1,175 @@ +#include "multikeyedit.h" + +#include +#include +#include +#include +#include + + +MultiKeyEdit::MultiKeyEdit(QWidget *parent, int fieldCount) : + QWidget(parent), + keySequenceEdit_vec(QVector()), + keySequence_list(QList()) +{ + setLayout(new QHBoxLayout(this)); + layout()->setContentsMargins(0, 0, 0, 0); + setFieldCount(fieldCount); +} + +bool MultiKeyEdit::eventFilter(QObject *watched, QEvent *event) { + if (event->type() == QEvent::KeyPress) { + auto *watched_kse = qobject_cast(watched); + if (!watched_kse) + return false; + + auto *keyEvent = static_cast(event); + if (keyEvent->key() == Qt::Key_Escape) { + watched_kse->clearFocus(); + return true; + } else { + watched_kse->clear(); + } + } + + if (event->type() == QEvent::ContextMenu) { + auto *watched_lineEdit = qobject_cast(watched); + if (!watched_lineEdit) + return false; + + auto *contextMenuEvent = static_cast(event); + if (contextMenuPolicy() == Qt::DefaultContextMenu) { + showDefaultContextMenu(watched_lineEdit, contextMenuEvent->pos()); + return true; + } + } + + return false; +} + +int MultiKeyEdit::fieldCount() const { + return keySequenceEdit_vec.count(); +} + +void MultiKeyEdit::setFieldCount(int count) { + if (count < 1) + count = 1; + + while (keySequenceEdit_vec.count() < count) + addNewKeySequenceEdit(); + + while (keySequenceEdit_vec.count() > count) + delete keySequenceEdit_vec.takeLast(); + + alignKeySequencesLeft(); +} + +QList MultiKeyEdit::keySequences() const { + QList current_keySequences; + for (auto *kse : keySequenceEdit_vec) + if (!kse->keySequence().isEmpty()) + current_keySequences.append(kse->keySequence()); + return current_keySequences; +} + +bool MultiKeyEdit::removeOne(const QKeySequence &keySequence) { + for (auto *keySequenceEdit : keySequenceEdit_vec) { + if (keySequenceEdit->keySequence() == keySequence) { + keySequence_list.removeOne(keySequence); + keySequenceEdit->clear(); + alignKeySequencesLeft(); + return true; + } + } + return false; +} + +bool MultiKeyEdit::contains(const QKeySequence &keySequence) const { + for (auto current_keySequence : keySequences()) + if (current_keySequence == keySequence) + return true; + return false; +} + +void MultiKeyEdit::setContextMenuPolicy(Qt::ContextMenuPolicy policy) { + QWidget::setContextMenuPolicy(policy); + auto lineEdit_children = findChildren(); + for (auto *lineEdit : lineEdit_children) + lineEdit->setContextMenuPolicy(policy); +} + +void MultiKeyEdit::clear() { + for (auto *keySequenceEdit : keySequenceEdit_vec) + keySequenceEdit->clear(); + keySequence_list.clear(); +} + +void MultiKeyEdit::setKeySequences(const QList &keySequences) { + clear(); + keySequence_list = keySequences; + int minCount = qMin(keySequenceEdit_vec.count(), keySequence_list.count()); + for (int i = 0; i < minCount; ++i) + keySequenceEdit_vec[i]->setKeySequence(keySequence_list[i]); +} + +void MultiKeyEdit::addKeySequence(const QKeySequence &keySequence) { + keySequenceEdit_vec.last()->setKeySequence(keySequence); + alignKeySequencesLeft(); +} + +void MultiKeyEdit::addNewKeySequenceEdit() { + auto *keySequenceEdit = new QKeySequenceEdit(this); + keySequenceEdit->installEventFilter(this); + connect(keySequenceEdit, &QKeySequenceEdit::editingFinished, + this, &MultiKeyEdit::onEditingFinished); + connect(keySequenceEdit, &QKeySequenceEdit::keySequenceChanged, + this, &MultiKeyEdit::keySequenceChanged); + + auto *lineEdit = keySequenceEdit->findChild(); + lineEdit->installEventFilter(this); + connect(lineEdit, &QLineEdit::customContextMenuRequested, + this, &MultiKeyEdit::customContextMenuRequested); + + layout()->addWidget(keySequenceEdit); + keySequenceEdit_vec.append(keySequenceEdit); +} + +// Shift all key sequences left if there are any empty QKeySequenceEdit's. +void MultiKeyEdit::alignKeySequencesLeft() { + blockSignals(true); + setKeySequences(keySequences()); + blockSignals(false); +} + +void MultiKeyEdit::setFocusToLastNonEmptyKeySequenceEdit() { + for (auto it = keySequenceEdit_vec.rbegin(); it != keySequenceEdit_vec.rend(); ++it) { + if (!(*it)->keySequence().isEmpty()) { + (*it)->setFocus(); + return; + } + } +} + +void MultiKeyEdit::onEditingFinished() { + auto *keySequenceEdit = qobject_cast(sender()); + if (keySequenceEdit && keySequence_list.contains(keySequenceEdit->keySequence())) + removeOne(keySequenceEdit->keySequence()); + alignKeySequencesLeft(); + setFocusToLastNonEmptyKeySequenceEdit(); + + emit editingFinished(); +} + +/* QKeySequenceEdit doesn't send or receive context menu events, but it owns QLineEdit that does. + * This QLineEdit hijacks those events and so we need to filter/connect to it directly, rather than + * the QKeySequenceEdit. I wouldn't be surprised if Qt fixed this in the future, in which case any + * context menu related code in this class might need to change. */ +void MultiKeyEdit::showDefaultContextMenu(QLineEdit *lineEdit, const QPoint &pos) { + QMenu menu(this); + QAction clearAction("Clear Shortcut", &menu); + connect(&clearAction, &QAction::triggered, lineEdit, [&lineEdit]() { + lineEdit->clear(); + }); + menu.addAction(&clearAction); + menu.exec(lineEdit->mapToGlobal(pos)); +} From 2fb3bf4e26b4af7ae41a8dfb513aab946606ff5f Mon Sep 17 00:00:00 2001 From: BigBahss Date: Sun, 8 Nov 2020 08:36:02 -0500 Subject: [PATCH 07/12] Redesign ShortcutsEditor to take an obj list and refactor config to reflect that --- forms/shortcutseditor.ui | 101 ++++++++---- include/config.h | 48 +++--- include/mainwindow.h | 7 +- include/ui/shortcut.h | 8 +- include/ui/shortcutseditor.h | 77 +++------ src/config.cpp | 121 +++++++------- src/mainwindow.cpp | 47 ++++-- src/ui/shortcutseditor.cpp | 312 ++++++++++++++--------------------- 8 files changed, 356 insertions(+), 365 deletions(-) diff --git a/forms/shortcutseditor.ui b/forms/shortcutseditor.ui index 31b7014a..fab28d98 100644 --- a/forms/shortcutseditor.ui +++ b/forms/shortcutseditor.ui @@ -1,47 +1,88 @@ ShortcutsEditor - + 0 0 - 540 - 640 + 800 + 700 Shortcuts Editor - - - - - true - - - - - 0 - 0 - 516 - 580 - + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + QFrame::Plain + + + 0 + + + true + + + + + 0 + 0 + 794 + 642 + + + - - - - - - QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults - - - false - - - - + + + + + QFrame::Box + + + QFrame::Raised + + + + + + QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults + + + false + + + + + + + + diff --git a/include/config.h b/include/config.h index a690ce90..6d7753ac 100644 --- a/include/config.h +++ b/include/config.h @@ -201,53 +201,49 @@ class ShortcutsConfig : public KeyValueConfigBase { public: ShortcutsConfig() : - userShortcuts(QMultiMap()), - defaultShortcuts(QMultiMap()) - { } - - virtual void reset() override { userShortcuts.clear(); } + user_shortcuts({ }), + default_shortcuts({ }) + { } - void setDefaultShortcuts(const QList &actions); - void setDefaultShortcuts(const QList &shortcuts); - void setDefaultShortcuts(const QList &actions, const QList &shortcuts); - QList getDefaultShortcuts(QAction *action) const; - QList getDefaultShortcuts(Shortcut *shortcut) const; + virtual void reset() override { user_shortcuts.clear(); } - void setUserShortcuts(const QList &actions); - void setUserShortcuts(const QList &shortcuts); - void setUserShortcuts(const QList &actions, const QList &shortcuts); - QList getUserShortcuts(QAction *action) const; - QList getUserShortcuts(Shortcut *shortcut) const; + void setDefaultShortcuts(const QObjectList &objects); + void setDefaultShortcuts(const QMultiMap &objects_keySequences); + QList defaultShortcuts(const QObject *object) const; + + void setUserShortcuts(const QObjectList &objects); + void setUserShortcuts(const QMultiMap &objects_keySequences); + QList userShortcuts(const QObject *object) const; + + static bool objectNameIsValid(const QObject *object); protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; virtual QMap getKeyValueMap() override; - virtual void onNewConfigFileCreated() override {}; - virtual void setUnreadKeys() override {}; + virtual void onNewConfigFileCreated() override { }; + virtual void setUnreadKeys() override { }; private: - QMultiMap userShortcuts; - QMultiMap defaultShortcuts; + QMultiMap user_shortcuts; + QMultiMap default_shortcuts; enum StoreType { User, Default }; + QString cfgKey(const QObject *object) const; + QList currentShortcuts(const QObject *object) const; + + void storeShortcutsFromList(StoreType storeType, const QObjectList &objects); void storeShortcuts( - StoreType storeType, - const QList &actions); - void storeShortcuts( - StoreType storeType, - const QList &shortcuts); - void storeShortcut( StoreType storeType, const QString &cfgKey, const QList &keySequences); - QString cfgKey(QObject *object) const; }; +// Call setDefaultShortcuts() prior to applying user shortcuts. extern ShortcutsConfig shortcutsConfig; #endif // CONFIG_H diff --git a/include/mainwindow.h b/include/mainwindow.h index f406f87f..6cb2f37d 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -129,6 +129,7 @@ private slots: void openNewMapPopupWindow(int, QVariant); void onNewMapCreated(); void onMapCacheCleared(); + void applyUserShortcuts(); void on_action_NewMap_triggered(); void on_actionNew_Tileset_triggered(); @@ -292,12 +293,12 @@ private: void initWindow(); void initCustomUI(); - void initExtraShortcuts(); void initExtraSignals(); void initEditor(); void initMiscHeapObjects(); void initMapSortOrder(); - void initUserShortcuts(); + void initShortcuts(); + void initExtraShortcuts(); void setProjectSpecificUIVisibility(); void loadUserSettings(); void applyMapListFilter(QString filterText); @@ -312,6 +313,8 @@ private: bool isProjectOpen(); void showExportMapImageWindow(bool stitchMode); void redrawMetatileSelection(); + + QObjectList shortcutableObjects() const; }; enum MapListUserRoles { diff --git a/include/ui/shortcut.h b/include/ui/shortcut.h index 8b0e87ce..58980a3b 100644 --- a/include/ui/shortcut.h +++ b/include/ui/shortcut.h @@ -6,11 +6,17 @@ #include -// Alternative to QShortcut that adds support for multiple QKeySequences. +// Alternative to QShortcut that adds support for multiple key sequences. // Use this to allow the shortcut to be editable in ShortcutsEditor. class Shortcut : public QObject { Q_OBJECT + Q_DECLARE_PRIVATE(QShortcut) + Q_PROPERTY(QKeySequence key READ key WRITE setKey) + Q_PROPERTY(QString whatsThis READ whatsThis WRITE setWhatsThis) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled) + Q_PROPERTY(bool autoRepeat READ autoRepeat WRITE setAutoRepeat) + Q_PROPERTY(Qt::ShortcutContext context READ context WRITE setContext) public: explicit Shortcut(QWidget *parent); diff --git a/include/ui/shortcutseditor.h b/include/ui/shortcutseditor.h index b5aadc92..85d3fa69 100644 --- a/include/ui/shortcutseditor.h +++ b/include/ui/shortcutseditor.h @@ -1,80 +1,57 @@ #ifndef SHORTCUTSEDITOR_H #define SHORTCUTSEDITOR_H +#include "shortcut.h" + +#include #include #include +#include +#include +class QFormLayout; +class MultiKeyEdit; class QAbstractButton; -class QAction; -class QKeySequenceEdit; -class ActionShortcutEdit; namespace Ui { class ShortcutsEditor; } -class ShortcutsEditor : public QDialog +class ShortcutsEditor : public QMainWindow { Q_OBJECT public: - explicit ShortcutsEditor(QWidget *parent = nullptr); + explicit ShortcutsEditor(const QObjectList &objectList, QWidget *parent = nullptr); ~ShortcutsEditor(); +signals: + void shortcutsSaved(); + private: Ui::ShortcutsEditor *ui; - QMap actions; - QWidget *ase_container; + QWidget *main_container; + QMultiMap labels_objects; + QHash contexts_layouts; + QHash multiKeyEdits_objects; - void populateShortcuts(); + void parseObjectList(const QObjectList &objectList); + QString getLabel(const QObject *object) const; + bool stringPropertyIsNotEmpty(const QObject *object, const char *name) const; + void populateMainContainer(); + QString getShortcutContext(const QObject *object) const; + void addNewContextGroup(const QString &shortcutContext); + void addNewMultiKeyEdit(const QObject *object, const QString &shortcutContext); + QList siblings(MultiKeyEdit *multiKeyEdit) const; + void promptUserOnDuplicateFound(MultiKeyEdit *current, MultiKeyEdit *sender); + void removeKeySequence(const QKeySequence &keySequence, MultiKeyEdit *multiKeyEdit); void saveShortcuts(); void resetShortcuts(); - void promptUser(ActionShortcutEdit *current, ActionShortcutEdit *sender); private slots: - void checkForDuplicates(); + void checkForDuplicates(const QKeySequence &keySequence); void dialogButtonClicked(QAbstractButton *button); }; - -// A collection of QKeySequenceEdit's in a QHBoxLayout with a cooresponding QAction -class ActionShortcutEdit : public QWidget -{ - Q_OBJECT - -public: - explicit ActionShortcutEdit(QWidget *parent = nullptr, QAction *action = nullptr, int count = 1); - - bool eventFilter(QObject *watched, QEvent *event) override; - - int count() const { return kse_children.count(); } - void setCount(int count); - QList shortcuts() const; - void setShortcuts(const QList &keySequences); - void applyShortcuts(); - bool removeOne(const QKeySequence &keySequence); - bool contains(const QKeySequence &keySequence); - bool contains(QKeySequenceEdit *keySequenceEdit); - QKeySequence last() const { return shortcuts().last(); } - - QAction *action; - -public slots: - void clear(); - -signals: - void editingFinished(); - -private: - QVector kse_children; - QList ks_list; - - void updateShortcuts() { setShortcuts(shortcuts()); } - void focusLast(); - -private slots: - void onEditingFinished(); -}; - #endif // SHORTCUTSEDITOR_H diff --git a/src/config.cpp b/src/config.cpp index e78ee25c..a50f3c3f 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -13,6 +13,7 @@ #include #include #include +#include KeyValueConfigBase::~KeyValueConfigBase() { @@ -722,13 +723,13 @@ QString ShortcutsConfig::getConfigFilepath() { void ShortcutsConfig::parseConfigKeyValue(QString key, QString value) { QStringList keySequences = value.split(' '); for (auto keySequence : keySequences) - userShortcuts.insert(key, keySequence); + user_shortcuts.insert(key, keySequence); } QMap ShortcutsConfig::getKeyValueMap() { QMap map; - for (auto cfg_key : userShortcuts.uniqueKeys()) { - auto keySequences = userShortcuts.values(cfg_key); + for (auto cfg_key : user_shortcuts.uniqueKeys()) { + auto keySequences = user_shortcuts.values(cfg_key); QStringList values; for (auto keySequence : keySequences) values.append(keySequence.toString()); @@ -738,99 +739,77 @@ QMap ShortcutsConfig::getKeyValueMap() { return map; } -// Call this before applying user shortcuts to be able to restore default shortcuts. -void ShortcutsConfig::setDefaultShortcuts(const QList &actions) { - storeShortcuts(StoreType::Default, actions); +void ShortcutsConfig::setDefaultShortcuts(const QObjectList &objects) { + storeShortcutsFromList(StoreType::Default, objects); save(); } -// Call this before applying user shortcuts to be able to restore default shortcuts. -void ShortcutsConfig::setDefaultShortcuts(const QList &shortcuts) { - storeShortcuts(StoreType::Default, shortcuts); +void ShortcutsConfig::setDefaultShortcuts(const QMultiMap &objects_keySequences) { + for (auto *object : objects_keySequences.uniqueKeys()) + storeShortcuts(StoreType::Default, cfgKey(object), objects_keySequences.values(object)); save(); } -// Call this before applying user shortcuts to be able to restore default shortcuts. -void ShortcutsConfig::setDefaultShortcuts(const QList &actions, const QList &shortcuts) { - storeShortcuts(StoreType::Default, actions); - storeShortcuts(StoreType::Default, shortcuts); +QList ShortcutsConfig::defaultShortcuts(const QObject *object) const { + return default_shortcuts.values(cfgKey(object)); +} + +void ShortcutsConfig::setUserShortcuts(const QObjectList &objects) { + storeShortcutsFromList(StoreType::User, objects); save(); } -QList ShortcutsConfig::getDefaultShortcuts(QAction *action) const { - return defaultShortcuts.values(cfgKey(action)); -} - -QList ShortcutsConfig::getDefaultShortcuts(Shortcut *shortcut) const { - return defaultShortcuts.values(cfgKey(shortcut)); -} - -void ShortcutsConfig::setUserShortcuts(const QList &actions) { - storeShortcuts(StoreType::User, actions); +void ShortcutsConfig::setUserShortcuts(const QMultiMap &objects_keySequences) { + for (auto *object : objects_keySequences.uniqueKeys()) + storeShortcuts(StoreType::User, cfgKey(object), objects_keySequences.values(object)); save(); } -void ShortcutsConfig::setUserShortcuts(const QList &shortcuts) { - storeShortcuts(StoreType::User, shortcuts); - save(); +QList ShortcutsConfig::userShortcuts(const QObject *object) const { + return user_shortcuts.values(cfgKey(object)); } -void ShortcutsConfig::setUserShortcuts(const QList &actions, const QList &shortcuts) { - storeShortcuts(StoreType::User, actions); - storeShortcuts(StoreType::User, shortcuts); - save(); +void ShortcutsConfig::storeShortcutsFromList(StoreType storeType, const QObjectList &objects) { + for (const auto *object : objects) + if (objectNameIsValid(object)) + storeShortcuts(storeType, cfgKey(object), currentShortcuts(object)); } -QList ShortcutsConfig::getUserShortcuts(QAction *action) const { - return userShortcuts.values(cfgKey(action)); -} - -QList ShortcutsConfig::getUserShortcuts(Shortcut *shortcut) const { - return userShortcuts.values(cfgKey(shortcut)); -} - -void ShortcutsConfig::storeShortcuts(StoreType storeType, const QList &actions) { - for (auto *action : actions) - if (!action->text().isEmpty() && !action->objectName().isEmpty()) - storeShortcut(storeType, cfgKey(action), action->shortcuts()); -} - -void ShortcutsConfig::storeShortcuts(StoreType storeType, const QList &shortcuts) { - for (auto *shortcut : shortcuts) - if (!shortcut->whatsThis().isEmpty() && !shortcut->objectName().isEmpty()) - storeShortcut(storeType, cfgKey(shortcut), shortcut->keys()); -} - -void ShortcutsConfig::storeShortcut( +void ShortcutsConfig::storeShortcuts( StoreType storeType, const QString &cfgKey, const QList &keySequences) { - bool storeUser = (storeType == User) || !userShortcuts.contains(cfgKey); + bool storeUser = (storeType == User) || !user_shortcuts.contains(cfgKey); if (storeType == Default) - defaultShortcuts.remove(cfgKey); + default_shortcuts.remove(cfgKey); if (storeUser) - userShortcuts.remove(cfgKey); + user_shortcuts.remove(cfgKey); if (keySequences.isEmpty()) { if (storeType == Default) - defaultShortcuts.insert(cfgKey, QKeySequence()); + default_shortcuts.insert(cfgKey, QKeySequence()); if (storeUser) - userShortcuts.insert(cfgKey, QKeySequence()); + user_shortcuts.insert(cfgKey, QKeySequence()); } else { for (auto keySequence : keySequences) { if (storeType == Default) - defaultShortcuts.insert(cfgKey, keySequence); + default_shortcuts.insert(cfgKey, keySequence); if (storeUser) - userShortcuts.insert(cfgKey, keySequence); + user_shortcuts.insert(cfgKey, keySequence); } } } +bool ShortcutsConfig::objectNameIsValid(const QObject *object) { + // Qt internal action names start with "_q_" so we filter those out. + return !object->objectName().isEmpty() && !object->objectName().startsWith("_q_"); +} + /* Creates a config key from the object's name prepended with the parent * window's object name, and converts camelCase to snake_case. */ -QString ShortcutsConfig::cfgKey(QObject *object) const { +QString ShortcutsConfig::cfgKey(const QObject *object) const { auto cfg_key = QString(); auto *parentWidget = static_cast(object->parent()); if (parentWidget) @@ -838,11 +817,31 @@ QString ShortcutsConfig::cfgKey(QObject *object) const { cfg_key += object->objectName(); QRegularExpression re("[A-Z]"); - int i = cfg_key.indexOf(re); + int i = cfg_key.indexOf(re, 1); while (i != -1) { - if (i != 0 && cfg_key.at(i - 1) != '_') + if (cfg_key.at(i - 1) != '_') cfg_key.insert(i++, '_'); i = cfg_key.indexOf(re, i + 1); } return cfg_key.toLower(); } + +QList ShortcutsConfig::currentShortcuts(const QObject *object) const { + if (object->inherits("QAction")) { + const auto *action = qobject_cast(object); + return action->shortcuts(); + } else if (object->inherits("QAbstractButton")) { + const auto *button = qobject_cast(object); + return { button->shortcut() }; + } else if (object->inherits("Shortcut")) { + const auto *shortcut = qobject_cast(object); + return shortcut->keys(); + } else if (object->inherits("QShortcut")) { + const auto *qshortcut = qobject_cast(object); + return { qshortcut->key() }; + } else if (object->property("shortcut").isValid()) { + return { object->property("shortcut").value() }; + } else { + return { }; + } +} diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 2b242876..5085483b 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -88,40 +88,63 @@ void MainWindow::initWindow() { porymapConfig.load(); this->initCustomUI(); this->initExtraSignals(); - this->initExtraShortcuts(); this->initEditor(); this->initMiscHeapObjects(); this->initMapSortOrder(); - this->initUserShortcuts(); + this->initShortcuts(); this->restoreWindowState(); setWindowDisabled(true); } +void MainWindow::initShortcuts() { + initExtraShortcuts(); + + shortcutsConfig.load(); + shortcutsConfig.setDefaultShortcuts(shortcutableObjects()); + applyUserShortcuts(); +} + void MainWindow::initExtraShortcuts() { auto *shortcutReset_Zoom = new Shortcut(QKeySequence("Ctrl+0"), this, SLOT(resetMapViewScale())); - shortcutReset_Zoom->setObjectName("shortcutReset_Zoom"); + shortcutReset_Zoom->setObjectName("shortcutZoom_Reset"); + shortcutReset_Zoom->setWhatsThis("Zoom Reset"); auto *shortcutToggle_Grid = new Shortcut(QKeySequence("Ctrl+G"), ui->checkBox_ToggleGrid, SLOT(toggle())); shortcutToggle_Grid->setObjectName("shortcutToggle_Grid"); + shortcutToggle_Grid->setWhatsThis("Toggle Grid"); auto *shortcutDuplicate_Events = new Shortcut(QKeySequence("Ctrl+D"), this, SLOT(duplicate())); shortcutDuplicate_Events->setObjectName("shortcutDuplicate_Events"); + shortcutDuplicate_Events->setWhatsThis("Duplicate Selected Event(s)"); auto *shortcutDelete_Object = new Shortcut( {QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(on_toolButton_deleteObject_clicked())); shortcutDelete_Object->setObjectName("shortcutDelete_Object"); + shortcutDelete_Object->setWhatsThis("Delete Selected Event(s)"); ui->actionZoom_In->setShortcuts({ui->actionZoom_In->shortcut(), QKeySequence("Ctrl+=")}); } -void MainWindow::initUserShortcuts() { - shortcutsConfig.load(); - shortcutsConfig.setDefaultShortcuts(findChildren(), findChildren()); +QObjectList MainWindow::shortcutableObjects() const { + QObjectList shortcutable_objects; for (auto *action : findChildren()) - action->setShortcuts(shortcutsConfig.getUserShortcuts(action)); + if (!action->objectName().isEmpty()) + shortcutable_objects.append(qobject_cast(action)); for (auto *shortcut : findChildren()) - shortcut->setKeys(shortcutsConfig.getUserShortcuts(shortcut)); + if (!shortcut->objectName().isEmpty()) + shortcutable_objects.append(qobject_cast(shortcut)); + + return shortcutable_objects; +} + +void MainWindow::applyUserShortcuts() { + for (auto *action : findChildren()) + if (!action->objectName().isEmpty()) + action->setShortcuts(shortcutsConfig.userShortcuts(action)); + for (auto *shortcut : findChildren()) + if (!shortcut->objectName().isEmpty()) + shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); } void MainWindow::initCustomUI() { @@ -1426,8 +1449,12 @@ void MainWindow::on_actionUse_Poryscript_triggered(bool checked) void MainWindow::on_actionEdit_Shortcuts_triggered() { - if (!shortcutsEditor) - shortcutsEditor = new ShortcutsEditor(this); + if (!shortcutsEditor) { + shortcutsEditor = new ShortcutsEditor(shortcutableObjects(), this); + connect(shortcutsEditor, &QObject::destroyed, [=](QObject *) { shortcutsEditor = nullptr; }); + connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved, + this, &MainWindow::applyUserShortcuts); + } if (shortcutsEditor->isHidden()) shortcutsEditor->show(); diff --git a/src/ui/shortcutseditor.cpp b/src/ui/shortcutseditor.cpp index 97a3ebf4..efafc556 100644 --- a/src/ui/shortcutseditor.cpp +++ b/src/ui/shortcutseditor.cpp @@ -1,26 +1,32 @@ #include "shortcutseditor.h" #include "ui_shortcutseditor.h" #include "config.h" +#include "multikeyedit.h" #include "log.h" +#include #include #include #include #include -#include -#include +#include +#include -ShortcutsEditor::ShortcutsEditor(QWidget *parent) : - QDialog(parent), +ShortcutsEditor::ShortcutsEditor(const QObjectList &objectList, QWidget *parent) : + QMainWindow(parent), ui(new Ui::ShortcutsEditor), - actions(QMap()) + main_container(nullptr) { ui->setupUi(this); - ase_container = ui->scrollAreaWidgetContents_Shortcuts; + setAttribute(Qt::WA_DeleteOnClose); + main_container = ui->scrollAreaWidgetContents_Shortcuts; + main_container->setLayout(new QVBoxLayout(main_container)); connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &ShortcutsEditor::dialogButtonClicked); - populateShortcuts(); + + parseObjectList(objectList); + populateMainContainer(); } ShortcutsEditor::~ShortcutsEditor() @@ -28,207 +34,143 @@ ShortcutsEditor::~ShortcutsEditor() delete ui; } -void ShortcutsEditor::populateShortcuts() { - if (!parent()) - return; +void ShortcutsEditor::saveShortcuts() { + QMultiMap objects_keySequences; + for (auto it = multiKeyEdits_objects.cbegin(); it != multiKeyEdits_objects.cend(); ++it) + for (auto keySequence : it.key()->keySequences()) + objects_keySequences.insert(it.value(), keySequence); - for (auto action : parent()->findChildren()) - if (!action->text().isEmpty() && !action->objectName().isEmpty()) - actions.insert(action->text().remove('&'), action); + shortcutsConfig.setUserShortcuts(objects_keySequences); + emit shortcutsSaved(); +} - auto *formLayout = new QFormLayout(ase_container); - for (auto *action : actions) { - auto userShortcuts = shortcutsConfig.getUserShortcuts(action); - auto *ase = new ActionShortcutEdit(ase_container, action, 2); - connect(ase, &ActionShortcutEdit::editingFinished, - this, &ShortcutsEditor::checkForDuplicates); - ase->setShortcuts(userShortcuts); - formLayout->addRow(action->text(), ase); +// Restores default shortcuts but doesn't save until Apply or OK is clicked. +void ShortcutsEditor::resetShortcuts() { + for (auto it = multiKeyEdits_objects.begin(); it != multiKeyEdits_objects.end(); ++it) { + it.key()->blockSignals(true); + const auto defaults = shortcutsConfig.defaultShortcuts(it.value()); + it.key()->setKeySequences(defaults); + it.key()->blockSignals(false); } } -void ShortcutsEditor::saveShortcuts() { - auto ase_children = ase_container->findChildren(QString(), Qt::FindDirectChildrenOnly); - for (auto *ase : ase_children) - ase->applyShortcuts(); - shortcutsConfig.setUserShortcuts(actions.values()); +void ShortcutsEditor::parseObjectList(const QObjectList &objectList) { + for (auto *object : objectList) { + const auto label = getLabel(object); + if (!label.isEmpty() && ShortcutsConfig::objectNameIsValid(object)) + labels_objects.insert(label, object); + } } -void ShortcutsEditor::resetShortcuts() { - auto ase_children = ase_container->findChildren(QString(), Qt::FindDirectChildrenOnly); - for (auto *ase : ase_children) - ase->setShortcuts(shortcutsConfig.getDefaultShortcuts(ase->action)); +QString ShortcutsEditor::getLabel(const QObject *object) const { + if (stringPropertyIsNotEmpty(object, "text")) + return object->property("text").toString().remove('&'); + else if (stringPropertyIsNotEmpty(object, "whatsThis")) + return object->property("whatsThis").toString().remove('&'); + else + return QString(); } -void ShortcutsEditor::promptUser(ActionShortcutEdit *current, ActionShortcutEdit *sender) { - auto result = QMessageBox::question( - this, - "porymap", - QString("Shortcut \"%1\" is already used by \"%2\", would you like to replace it?") - .arg(sender->last().toString()).arg(current->action->text()), - QMessageBox::Yes | QMessageBox::No, QMessageBox::No); +bool ShortcutsEditor::stringPropertyIsNotEmpty(const QObject *object, const char *name) const { + return object->property(name).isValid() && !object->property(name).toString().isEmpty(); +} + +void ShortcutsEditor::populateMainContainer() { + for (auto object : labels_objects) { + const auto shortcutContext = getShortcutContext(object); + if (!contexts_layouts.contains(shortcutContext)) + addNewContextGroup(shortcutContext); + + addNewMultiKeyEdit(object, shortcutContext); + } +} + +// The context for which the object's shortcut is active (Displayed in group box title). +// Uses the parent window's objectName and adds spaces between words. +QString ShortcutsEditor::getShortcutContext(const QObject *object) const { + auto objectParentWidget = static_cast(object->parent()); + auto context = objectParentWidget->window()->objectName(); + QRegularExpression re("[A-Z]"); + int i = context.indexOf(re, 1); + while (i != -1) { + if (context.at(i - 1) != ' ') + context.insert(i++, ' '); + i = context.indexOf(re, i + 1); + } + return context; +} + +// Seperate shortcuts into context groups for duplicate checking. +void ShortcutsEditor::addNewContextGroup(const QString &shortcutContext) { + auto *groupBox = new QGroupBox(shortcutContext, main_container); + main_container->layout()->addWidget(groupBox); + auto *formLayout = new QFormLayout(groupBox); + contexts_layouts.insert(shortcutContext, formLayout); +} + +void ShortcutsEditor::addNewMultiKeyEdit(const QObject *object, const QString &shortcutContext) { + auto *container = contexts_layouts.value(shortcutContext)->parentWidget(); + auto *multiKeyEdit = new MultiKeyEdit(container); + multiKeyEdit->setKeySequences(shortcutsConfig.userShortcuts(object)); + connect(multiKeyEdit, &MultiKeyEdit::keySequenceChanged, + this, &ShortcutsEditor::checkForDuplicates); + contexts_layouts.value(shortcutContext)->addRow(labels_objects.key(object), multiKeyEdit); + multiKeyEdits_objects.insert(multiKeyEdit, object); +} + +void ShortcutsEditor::checkForDuplicates(const QKeySequence &keySequence) { + if (keySequence.isEmpty()) + return; + + auto *sender_multiKeyEdit = qobject_cast(sender()); + if (!sender_multiKeyEdit) + return; + + for (auto *sibling_multiKeyEdit : siblings(sender_multiKeyEdit)) + if (sibling_multiKeyEdit->contains(keySequence)) + promptUserOnDuplicateFound(sender_multiKeyEdit, sibling_multiKeyEdit); +} + +QList ShortcutsEditor::siblings(MultiKeyEdit *multiKeyEdit) const { + auto list = multiKeyEdit->parent()->findChildren(QString(), Qt::FindDirectChildrenOnly); + list.removeOne(multiKeyEdit); + return list; +} + +void ShortcutsEditor::promptUserOnDuplicateFound(MultiKeyEdit *sender, MultiKeyEdit *sibling) { + const auto duplicateKeySequence = sender->keySequences().last(); + const auto siblingLabel = getLabel(multiKeyEdits_objects.value(sibling)); + const auto message = QString( + "Shortcut '%1' is already used by '%2', would you like to replace it?") + .arg(duplicateKeySequence.toString()).arg(siblingLabel); + + const auto result = QMessageBox::question( + this, "porymap", message, QMessageBox::Yes | QMessageBox::No, QMessageBox::No); if (result == QMessageBox::Yes) - current->removeOne(sender->last()); - else if (result == QMessageBox::No) - sender->removeOne(sender->last()); + removeKeySequence(duplicateKeySequence, sibling); + else + removeKeySequence(duplicateKeySequence, sender); + + activateWindow(); } -void ShortcutsEditor::checkForDuplicates() { - auto *sender_ase = qobject_cast(sender()); - if (!sender_ase) - return; - - for (auto *child_kse : findChildren()) { - if (child_kse->keySequence().isEmpty() || child_kse->parent() == sender()) - continue; - - if (sender_ase->contains(child_kse->keySequence())) { - auto *current_ase = qobject_cast(child_kse->parent()); - if (!current_ase) - continue; - - promptUser(current_ase, sender_ase); - activateWindow(); - return; - } - } +void ShortcutsEditor::removeKeySequence(const QKeySequence &keySequence, MultiKeyEdit *multiKeyEdit) { + multiKeyEdit->blockSignals(true); + multiKeyEdit->removeOne(keySequence); + multiKeyEdit->blockSignals(false); } void ShortcutsEditor::dialogButtonClicked(QAbstractButton *button) { auto buttonRole = ui->buttonBox->buttonRole(button); if (buttonRole == QDialogButtonBox::AcceptRole) { saveShortcuts(); - hide(); + close(); } else if (buttonRole == QDialogButtonBox::ApplyRole) { saveShortcuts(); } else if (buttonRole == QDialogButtonBox::RejectRole) { - hide(); + close(); } else if (buttonRole == QDialogButtonBox::ResetRole) { resetShortcuts(); } } - - -ActionShortcutEdit::ActionShortcutEdit(QWidget *parent, QAction *action, int count) : - QWidget(parent), - action(action), - kse_children(QVector()), - ks_list(QList()) -{ - setLayout(new QHBoxLayout(this)); - layout()->setContentsMargins(0, 0, 0, 0); - setCount(count); -} - -bool ActionShortcutEdit::eventFilter(QObject *watched, QEvent *event) { - auto *watched_kse = qobject_cast(watched); - if (!watched_kse) - return false; - - if (event->type() == QEvent::KeyPress) { - auto *keyEvent = static_cast(event); - if (keyEvent->key() == Qt::Key_Escape) { - watched_kse->clearFocus(); - return true; - } else if (keyEvent->key() == Qt::Key_Backspace) { - removeOne(watched_kse->keySequence()); - return true; - } else { - watched_kse->clear(); - } - } - return false; -} - -void ActionShortcutEdit::setCount(int count) { - if (count < 1) - count = 1; - - while (kse_children.count() > count) { - layout()->removeWidget(kse_children.last()); - delete kse_children.last(); - kse_children.removeLast(); - } - - while (kse_children.count() < count) { - auto *kse = new QKeySequenceEdit(this); - connect(kse, &QKeySequenceEdit::editingFinished, - this, &ActionShortcutEdit::onEditingFinished); - kse->installEventFilter(this); - layout()->addWidget(kse); - kse_children.append(kse); - } -} - -QList ActionShortcutEdit::shortcuts() const { - QList current_ks_list; - for (auto *kse : kse_children) - if (!kse->keySequence().isEmpty()) - current_ks_list.append(kse->keySequence()); - return current_ks_list; -} - -void ActionShortcutEdit::setShortcuts(const QList &keySequences) { - clear(); - ks_list = keySequences; - int minCount = qMin(kse_children.count(), ks_list.count()); - for (int i = 0; i < minCount; ++i) - kse_children[i]->setKeySequence(ks_list[i]); -} - -void ActionShortcutEdit::applyShortcuts() { - action->setShortcuts(shortcuts()); -} - -bool ActionShortcutEdit::removeOne(const QKeySequence &keySequence) { - for (auto *kse : kse_children) { - if (kse->keySequence() == keySequence) { - ks_list.removeOne(keySequence); - kse->clear(); - updateShortcuts(); - return true; - } - } - return false; -} - -bool ActionShortcutEdit::contains(const QKeySequence &keySequence) { - for (auto ks : shortcuts()) - if (ks == keySequence) - return true; - return false; -} - -bool ActionShortcutEdit::contains(QKeySequenceEdit *keySequenceEdit) { - for (auto *kse : kse_children) - if (kse == keySequenceEdit) - return true; - return false; -} - -void ActionShortcutEdit::clear() { - for (auto *kse : kse_children) - kse->clear(); -} - -void ActionShortcutEdit::focusLast() { - for (int i = count() - 1; i >= 0; --i) { - if (!kse_children[i]->keySequence().isEmpty()) { - kse_children[i]->setFocus(); - return; - } - } -} - -void ActionShortcutEdit::onEditingFinished() { - auto *kse = qobject_cast(sender()); - if (!kse) - return; - - if (ks_list.contains(kse->keySequence())) - removeOne(kse->keySequence()); - updateShortcuts(); - focusLast(); - emit editingFinished(); -} From 9a3609ee6d7c9fa37a78963caf11a4b4b4ba6371 Mon Sep 17 00:00:00 2001 From: BigBahss Date: Mon, 9 Nov 2020 02:56:22 -0500 Subject: [PATCH 08/12] Fix MultiKeyEdit clear action not re-aligning key sequences --- src/ui/multikeyedit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/multikeyedit.cpp b/src/ui/multikeyedit.cpp index 5f66328e..34ac19c8 100644 --- a/src/ui/multikeyedit.cpp +++ b/src/ui/multikeyedit.cpp @@ -167,8 +167,8 @@ void MultiKeyEdit::onEditingFinished() { void MultiKeyEdit::showDefaultContextMenu(QLineEdit *lineEdit, const QPoint &pos) { QMenu menu(this); QAction clearAction("Clear Shortcut", &menu); - connect(&clearAction, &QAction::triggered, lineEdit, [&lineEdit]() { - lineEdit->clear(); + connect(&clearAction, &QAction::triggered, lineEdit, [this, &lineEdit]() { + removeOne(lineEdit->text()); }); menu.addAction(&clearAction); menu.exec(lineEdit->mapToGlobal(pos)); From f044672d2edf82b79f1a6db075a788d062028fa6 Mon Sep 17 00:00:00 2001 From: BigBahss Date: Mon, 9 Nov 2020 05:50:15 -0500 Subject: [PATCH 09/12] Add support for sub-editor shortcut customization --- include/mainwindow.h | 5 ++ include/ui/regionmapeditor.h | 6 +++ include/ui/shortcutseditor.h | 5 +- include/ui/tileseteditor.h | 7 +++ src/mainwindow.cpp | 91 ++++++++++++++++++++++++++---------- src/ui/regionmapeditor.cpp | 28 +++++++++++ src/ui/shortcutseditor.cpp | 24 +++++++--- src/ui/tileseteditor.cpp | 32 ++++++++++++- 8 files changed, 165 insertions(+), 33 deletions(-) diff --git a/include/mainwindow.h b/include/mainwindow.h index 6cb2f37d..59e13ed7 100644 --- a/include/mainwindow.h +++ b/include/mainwindow.h @@ -310,6 +310,11 @@ private: void closeSupplementaryWindows(); void setWindowDisabled(bool); + void initTilesetEditor(); + bool initRegionMapEditor(); + void initShortcutsEditor(); + void connectSubEditorsToShortcutsEditor(); + bool isProjectOpen(); void showExportMapImageWindow(bool stitchMode); void redrawMetatileSelection(); diff --git a/include/ui/regionmapeditor.h b/include/ui/regionmapeditor.h index 484103f3..cba14251 100644 --- a/include/ui/regionmapeditor.h +++ b/include/ui/regionmapeditor.h @@ -47,6 +47,11 @@ public: void resize(int width, int height); + QObjectList shortcutableObjects() const; + +public slots: + void applyUserShortcuts(); + private: Ui::RegionMapEditor *ui; Project *project; @@ -81,6 +86,7 @@ private: RegionMapPixmapItem *region_map_item = nullptr; CityMapPixmapItem *city_map_item = nullptr; + void initShortcuts(); void displayRegionMap(); void displayRegionMapImage(); void displayRegionMapLayout(); diff --git a/include/ui/shortcutseditor.h b/include/ui/shortcutseditor.h index 85d3fa69..31b0279e 100644 --- a/include/ui/shortcutseditor.h +++ b/include/ui/shortcutseditor.h @@ -23,9 +23,12 @@ class ShortcutsEditor : public QMainWindow Q_OBJECT public: - explicit ShortcutsEditor(const QObjectList &objectList, QWidget *parent = nullptr); + explicit ShortcutsEditor(QWidget *parent = nullptr); + explicit ShortcutsEditor(const QObjectList &shortcutableObjects, QWidget *parent = nullptr); ~ShortcutsEditor(); + void setShortcutableObjects(const QObjectList &shortcutableObjects); + signals: void shortcutsSaved(); diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index 283f9cde..6cf7350c 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -42,6 +42,11 @@ public: void updateTilesets(QString primaryTilsetLabel, QString secondaryTilesetLabel); bool selectMetatile(uint16_t metatileId); + QObjectList shortcutableObjects() const; + +public slots: + void applyUserShortcuts(); + private slots: void onHoveredMetatileChanged(uint16_t); void onHoveredMetatileCleared(); @@ -102,6 +107,7 @@ private: void initTileSelector(); void initSelectedTileItem(); void initMetatileLayersItem(); + void initShortcuts(); void restoreWindowState(); void initMetatileHistory(); void setTilesets(QString primaryTilesetLabel, QString secondaryTilesetLabel); @@ -112,6 +118,7 @@ private: void refresh(); void saveMetatileLabel(); void closeEvent(QCloseEvent*); + Ui::TilesetEditor *ui; History metatileHistory; TilesetEditorMetatileSelector *metatileSelector = nullptr; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 5085483b..489365aa 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -129,10 +129,10 @@ void MainWindow::initExtraShortcuts() { QObjectList MainWindow::shortcutableObjects() const { QObjectList shortcutable_objects; for (auto *action : findChildren()) - if (!action->objectName().isEmpty()) + if (ShortcutsConfig::objectNameIsValid(action)) shortcutable_objects.append(qobject_cast(action)); for (auto *shortcut : findChildren()) - if (!shortcut->objectName().isEmpty()) + if (ShortcutsConfig::objectNameIsValid(shortcut)) shortcutable_objects.append(qobject_cast(shortcut)); return shortcutable_objects; @@ -140,10 +140,10 @@ QObjectList MainWindow::shortcutableObjects() const { void MainWindow::applyUserShortcuts() { for (auto *action : findChildren()) - if (!action->objectName().isEmpty()) + if (ShortcutsConfig::objectNameIsValid(action)) action->setShortcuts(shortcutsConfig.userShortcuts(action)); for (auto *shortcut : findChildren()) - if (!shortcut->objectName().isEmpty()) + if (ShortcutsConfig::objectNameIsValid(shortcut)) shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); } @@ -1449,12 +1449,8 @@ void MainWindow::on_actionUse_Poryscript_triggered(bool checked) void MainWindow::on_actionEdit_Shortcuts_triggered() { - if (!shortcutsEditor) { - shortcutsEditor = new ShortcutsEditor(shortcutableObjects(), this); - connect(shortcutsEditor, &QObject::destroyed, [=](QObject *) { shortcutsEditor = nullptr; }); - connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved, - this, &MainWindow::applyUserShortcuts); - } + if (!shortcutsEditor) + initShortcutsEditor(); if (shortcutsEditor->isHidden()) shortcutsEditor->show(); @@ -1464,6 +1460,35 @@ void MainWindow::on_actionEdit_Shortcuts_triggered() shortcutsEditor->activateWindow(); } +void MainWindow::initShortcutsEditor() { + shortcutsEditor = new ShortcutsEditor(this); + connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved, + this, &MainWindow::applyUserShortcuts); + connect(shortcutsEditor, &QObject::destroyed, [=](QObject *) { shortcutsEditor = nullptr; }); + + connectSubEditorsToShortcutsEditor(); + + shortcutsEditor->setShortcutableObjects(shortcutableObjects()); +} + +void MainWindow::connectSubEditorsToShortcutsEditor() { + /* Initialize sub-editors so that their children are added to MainWindow's object tree and will + * be returned by shortcutableObjects() to be passed to ShortcutsEditor. */ + if (!tilesetEditor) + initTilesetEditor(); + connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved, + tilesetEditor, &TilesetEditor::applyUserShortcuts); + + // TODO: Remove this check when the region map editor supports pokefirered. + if (projectConfig.getBaseGameVersion() != BaseGameVersion::pokefirered) { + if (!regionMapEditor) + initRegionMapEditor(); + if (regionMapEditor) + connect(shortcutsEditor, &ShortcutsEditor::shortcutsSaved, + regionMapEditor, &RegionMapEditor::applyUserShortcuts); + } +} + void MainWindow::on_actionPencil_triggered() { on_toolButton_Paint_clicked(); @@ -2551,9 +2576,7 @@ void MainWindow::on_checkBox_ToggleBorder_stateChanged(int selected) void MainWindow::on_actionTileset_Editor_triggered() { if (!this->tilesetEditor) { - this->tilesetEditor = new TilesetEditor(this->editor->project, this->editor->map, this); - connect(this->tilesetEditor, SIGNAL(tilesetsSaved(QString, QString)), this, SLOT(onTilesetsSaved(QString, QString))); - connect(this->tilesetEditor, &QObject::destroyed, [=](QObject *) { this->tilesetEditor = nullptr; }); + initTilesetEditor(); } if (!this->tilesetEditor->isVisible()) { @@ -2566,6 +2589,12 @@ void MainWindow::on_actionTileset_Editor_triggered() this->tilesetEditor->selectMetatile(this->editor->metatile_selector_item->getSelectedMetatiles()->at(0)); } +void MainWindow::initTilesetEditor() { + this->tilesetEditor = new TilesetEditor(this->editor->project, this->editor->map, this); + connect(this->tilesetEditor, SIGNAL(tilesetsSaved(QString, QString)), this, SLOT(onTilesetsSaved(QString, QString))); + connect(this->tilesetEditor, &QObject::destroyed, [=](QObject *) { this->tilesetEditor = nullptr; }); +} + void MainWindow::on_toolButton_ExpandAll_clicked() { if (ui->mapList) { @@ -2680,20 +2709,9 @@ void MainWindow::on_horizontalSlider_MetatileZoom_valueChanged(int value) { void MainWindow::on_actionRegion_Map_Editor_triggered() { if (!this->regionMapEditor) { - this->regionMapEditor = new RegionMapEditor(this, this->editor->project); - bool success = this->regionMapEditor->loadRegionMapData() - && this->regionMapEditor->loadCityMaps(); - if (!success) { - delete this->regionMapEditor; - this->regionMapEditor = nullptr; - QMessageBox msgBox(this); - QString errorMsg = QString("There was an error opening the region map data. Please see %1 for full error details.\n\n%3") - .arg(getLogPath()) - .arg(getMostRecentError()); - msgBox.critical(nullptr, "Error Opening Region Map Editor", errorMsg); + if (!initRegionMapEditor()) { return; } - connect(this->regionMapEditor, &QObject::destroyed, [=](QObject *) { this->regionMapEditor = nullptr; }); } if (!this->regionMapEditor->isVisible()) { @@ -2705,6 +2723,26 @@ void MainWindow::on_actionRegion_Map_Editor_triggered() { } } +bool MainWindow::initRegionMapEditor() { + this->regionMapEditor = new RegionMapEditor(this, this->editor->project); + bool success = this->regionMapEditor->loadRegionMapData() + && this->regionMapEditor->loadCityMaps(); + if (!success) { + delete this->regionMapEditor; + this->regionMapEditor = nullptr; + QMessageBox msgBox(this); + QString errorMsg = QString("There was an error opening the region map data. Please see %1 for full error details.\n\n%3") + .arg(getLogPath()) + .arg(getMostRecentError()); + msgBox.critical(nullptr, "Error Opening Region Map Editor", errorMsg); + + return false; + } + connect(this->regionMapEditor, &QObject::destroyed, [=](QObject *) { this->regionMapEditor = nullptr; }); + + return true; +} + void MainWindow::closeSupplementaryWindows() { if (this->tilesetEditor) delete this->tilesetEditor; @@ -2714,6 +2752,8 @@ void MainWindow::closeSupplementaryWindows() { delete this->mapImageExporter; if (this->newmapprompt) delete this->newmapprompt; + if (this->shortcutsEditor) + delete this->shortcutsEditor; } void MainWindow::closeEvent(QCloseEvent *event) { @@ -2740,6 +2780,7 @@ void MainWindow::closeEvent(QCloseEvent *event) { ); porymapConfig.save(); projectConfig.save(); + shortcutsConfig.save(); QMainWindow::closeEvent(event); } diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index ce3440dd..b025b90e 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -1,6 +1,7 @@ #include "regionmapeditor.h" #include "ui_regionmapeditor.h" #include "imageexport.h" +#include "shortcut.h" #include "config.h" #include "log.h" @@ -92,6 +93,33 @@ bool RegionMapEditor::loadCityMaps() { return true; } +void RegionMapEditor::initShortcuts() { + shortcutsConfig.load(); + shortcutsConfig.setDefaultShortcuts(shortcutableObjects()); + applyUserShortcuts(); +} + +QObjectList RegionMapEditor::shortcutableObjects() const { + QObjectList shortcutable_objects; + for (auto *action : findChildren()) + if (ShortcutsConfig::objectNameIsValid(action)) + shortcutable_objects.append(qobject_cast(action)); + for (auto *shortcut : findChildren()) + if (ShortcutsConfig::objectNameIsValid(shortcut)) + shortcutable_objects.append(qobject_cast(shortcut)); + + return shortcutable_objects; +} + +void RegionMapEditor::applyUserShortcuts() { + for (auto *action : findChildren()) + if (ShortcutsConfig::objectNameIsValid(action)) + action->setShortcuts(shortcutsConfig.userShortcuts(action)); + for (auto *shortcut : findChildren()) + if (ShortcutsConfig::objectNameIsValid(shortcut)) + shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); +} + void RegionMapEditor::displayRegionMap() { displayRegionMapTileSelector(); displayCityMapTileSelector(); diff --git a/src/ui/shortcutseditor.cpp b/src/ui/shortcutseditor.cpp index efafc556..0e0843f0 100644 --- a/src/ui/shortcutseditor.cpp +++ b/src/ui/shortcutseditor.cpp @@ -13,7 +13,7 @@ #include -ShortcutsEditor::ShortcutsEditor(const QObjectList &objectList, QWidget *parent) : +ShortcutsEditor::ShortcutsEditor(QWidget *parent) : QMainWindow(parent), ui(new Ui::ShortcutsEditor), main_container(nullptr) @@ -21,12 +21,16 @@ ShortcutsEditor::ShortcutsEditor(const QObjectList &objectList, QWidget *parent) ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); main_container = ui->scrollAreaWidgetContents_Shortcuts; - main_container->setLayout(new QVBoxLayout(main_container)); + auto *formLayout = new QVBoxLayout(main_container); + formLayout->setSpacing(12); connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &ShortcutsEditor::dialogButtonClicked); - - parseObjectList(objectList); - populateMainContainer(); +} + +ShortcutsEditor::ShortcutsEditor(const QObjectList &shortcutableObjects, QWidget *parent) : + ShortcutsEditor(parent) +{ + setShortcutableObjects(shortcutableObjects); } ShortcutsEditor::~ShortcutsEditor() @@ -34,11 +38,19 @@ ShortcutsEditor::~ShortcutsEditor() delete ui; } +void ShortcutsEditor::setShortcutableObjects(const QObjectList &shortcutableObjects) { + parseObjectList(shortcutableObjects); + populateMainContainer(); +} + void ShortcutsEditor::saveShortcuts() { QMultiMap objects_keySequences; - for (auto it = multiKeyEdits_objects.cbegin(); it != multiKeyEdits_objects.cend(); ++it) + for (auto it = multiKeyEdits_objects.cbegin(); it != multiKeyEdits_objects.cend(); ++it) { + if (it.key()->keySequences().isEmpty()) + objects_keySequences.insert(it.value(), QKeySequence()); for (auto keySequence : it.key()->keySequences()) objects_keySequences.insert(it.value(), keySequence); + } shortcutsConfig.setUserShortcuts(objects_keySequences); emit shortcutsSaved(); diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 1c6b620e..5e0b9eed 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -6,6 +6,7 @@ #include "paletteutil.h" #include "imageexport.h" #include "config.h" +#include "shortcut.h" #include #include #include @@ -86,7 +87,6 @@ void TilesetEditor::setTilesets(QString primaryTilesetLabel, QString secondaryTi void TilesetEditor::initUi() { ui->setupUi(this); - ui->actionRedo->setShortcuts({ui->actionRedo->shortcut(), QKeySequence("Ctrl+Shift+Z")}); this->tileXFlip = ui->checkBox_xFlip->isChecked(); this->tileYFlip = ui->checkBox_yFlip->isChecked(); this->paletteId = ui->spinBox_paletteSelector->value(); @@ -102,6 +102,7 @@ void TilesetEditor::initUi() { this->initMetatileLayersItem(); this->initTileSelector(); this->initSelectedTileItem(); + this->initShortcuts(); this->metatileSelector->select(0); this->restoreWindowState(); } @@ -209,6 +210,35 @@ void TilesetEditor::initSelectedTileItem() { this->ui->graphicsView_selectedTile->setFixedSize(this->selectedTilePixmapItem->pixmap().width() + 2, this->selectedTilePixmapItem->pixmap().height() + 2); } +void TilesetEditor::initShortcuts() { + ui->actionRedo->setShortcuts({ui->actionRedo->shortcut(), QKeySequence("Ctrl+Shift+Z")}); + + shortcutsConfig.load(); + shortcutsConfig.setDefaultShortcuts(shortcutableObjects()); + applyUserShortcuts(); +} + +QObjectList TilesetEditor::shortcutableObjects() const { + QObjectList shortcutable_objects; + for (auto *action : findChildren()) + if (ShortcutsConfig::objectNameIsValid(action)) + shortcutable_objects.append(qobject_cast(action)); + for (auto *shortcut : findChildren()) + if (ShortcutsConfig::objectNameIsValid(shortcut)) + shortcutable_objects.append(qobject_cast(shortcut)); + + return shortcutable_objects; +} + +void TilesetEditor::applyUserShortcuts() { + for (auto *action : findChildren()) + if (ShortcutsConfig::objectNameIsValid(action)) + action->setShortcuts(shortcutsConfig.userShortcuts(action)); + for (auto *shortcut : findChildren()) + if (ShortcutsConfig::objectNameIsValid(shortcut)) + shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); +} + void TilesetEditor::restoreWindowState() { logInfo("Restoring tileset editor geometry from previous session."); QMap geometry = porymapConfig.getTilesetEditorGeometry(); From bb6786f24eda12377c0a111a3c8c9d9bdeaa400a Mon Sep 17 00:00:00 2001 From: BigBahss Date: Thu, 12 Nov 2020 23:48:03 -0500 Subject: [PATCH 10/12] Add extra shortcuts to main window and sub-editors --- include/config.h | 5 +---- include/ui/tileseteditor.h | 1 + src/config.cpp | 26 ++++++-------------------- src/mainwindow.cpp | 33 +++++++++++++++++++++++++++------ src/ui/regionmapeditor.cpp | 17 ++++++++++++----- src/ui/shortcutseditor.cpp | 6 +++--- src/ui/tileseteditor.cpp | 25 +++++++++++++++++++------ 7 files changed, 69 insertions(+), 44 deletions(-) diff --git a/include/config.h b/include/config.h index 6d7753ac..4b0db13c 100644 --- a/include/config.h +++ b/include/config.h @@ -207,16 +207,14 @@ public: virtual void reset() override { user_shortcuts.clear(); } + // Call this before applying user shortcuts so that the user can restore defaults. void setDefaultShortcuts(const QObjectList &objects); - void setDefaultShortcuts(const QMultiMap &objects_keySequences); QList defaultShortcuts(const QObject *object) const; void setUserShortcuts(const QObjectList &objects); void setUserShortcuts(const QMultiMap &objects_keySequences); QList userShortcuts(const QObject *object) const; - static bool objectNameIsValid(const QObject *object); - protected: virtual QString getConfigFilepath() override; virtual void parseConfigKeyValue(QString key, QString value) override; @@ -243,7 +241,6 @@ private: const QList &keySequences); }; -// Call setDefaultShortcuts() prior to applying user shortcuts. extern ShortcutsConfig shortcutsConfig; #endif // CONFIG_H diff --git a/include/ui/tileseteditor.h b/include/ui/tileseteditor.h index 6cf7350c..1af92f35 100644 --- a/include/ui/tileseteditor.h +++ b/include/ui/tileseteditor.h @@ -108,6 +108,7 @@ private: void initSelectedTileItem(); void initMetatileLayersItem(); void initShortcuts(); + void initExtraShortcuts(); void restoreWindowState(); void initMetatileHistory(); void setTilesets(QString primaryTilesetLabel, QString secondaryTilesetLabel); diff --git a/src/config.cpp b/src/config.cpp index a50f3c3f..ae562334 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -730,11 +730,10 @@ QMap ShortcutsConfig::getKeyValueMap() { QMap map; for (auto cfg_key : user_shortcuts.uniqueKeys()) { auto keySequences = user_shortcuts.values(cfg_key); - QStringList values; + QStringList keySequenceStrings; for (auto keySequence : keySequences) - values.append(keySequence.toString()); - QString value = values.join(' '); - map.insert(cfg_key, value); + keySequenceStrings.append(keySequence.toString()); + map.insert(cfg_key, keySequenceStrings.join(' ')); } return map; } @@ -744,12 +743,6 @@ void ShortcutsConfig::setDefaultShortcuts(const QObjectList &objects) { save(); } -void ShortcutsConfig::setDefaultShortcuts(const QMultiMap &objects_keySequences) { - for (auto *object : objects_keySequences.uniqueKeys()) - storeShortcuts(StoreType::Default, cfgKey(object), objects_keySequences.values(object)); - save(); -} - QList ShortcutsConfig::defaultShortcuts(const QObject *object) const { return default_shortcuts.values(cfgKey(object)); } @@ -761,7 +754,8 @@ void ShortcutsConfig::setUserShortcuts(const QObjectList &objects) { void ShortcutsConfig::setUserShortcuts(const QMultiMap &objects_keySequences) { for (auto *object : objects_keySequences.uniqueKeys()) - storeShortcuts(StoreType::User, cfgKey(object), objects_keySequences.values(object)); + if (!object->objectName().isEmpty() && !object->objectName().startsWith("_q_")) + storeShortcuts(StoreType::User, cfgKey(object), objects_keySequences.values(object)); save(); } @@ -771,7 +765,7 @@ QList ShortcutsConfig::userShortcuts(const QObject *object) const void ShortcutsConfig::storeShortcutsFromList(StoreType storeType, const QObjectList &objects) { for (const auto *object : objects) - if (objectNameIsValid(object)) + if (!object->objectName().isEmpty() && !object->objectName().startsWith("_q_")) storeShortcuts(storeType, cfgKey(object), currentShortcuts(object)); } @@ -802,11 +796,6 @@ void ShortcutsConfig::storeShortcuts( } } -bool ShortcutsConfig::objectNameIsValid(const QObject *object) { - // Qt internal action names start with "_q_" so we filter those out. - return !object->objectName().isEmpty() && !object->objectName().startsWith("_q_"); -} - /* Creates a config key from the object's name prepended with the parent * window's object name, and converts camelCase to snake_case. */ QString ShortcutsConfig::cfgKey(const QObject *object) const { @@ -830,9 +819,6 @@ QList ShortcutsConfig::currentShortcuts(const QObject *object) con if (object->inherits("QAction")) { const auto *action = qobject_cast(object); return action->shortcuts(); - } else if (object->inherits("QAbstractButton")) { - const auto *button = qobject_cast(object); - return { button->shortcut() }; } else if (object->inherits("Shortcut")) { const auto *shortcut = qobject_cast(object); return shortcut->keys(); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 489365aa..dcc90c9c 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -106,6 +106,8 @@ void MainWindow::initShortcuts() { } void MainWindow::initExtraShortcuts() { + ui->actionZoom_In->setShortcuts({ui->actionZoom_In->shortcut(), QKeySequence("Ctrl+=")}); + auto *shortcutReset_Zoom = new Shortcut(QKeySequence("Ctrl+0"), this, SLOT(resetMapViewScale())); shortcutReset_Zoom->setObjectName("shortcutZoom_Reset"); shortcutReset_Zoom->setWhatsThis("Zoom Reset"); @@ -123,27 +125,46 @@ void MainWindow::initExtraShortcuts() { shortcutDelete_Object->setObjectName("shortcutDelete_Object"); shortcutDelete_Object->setWhatsThis("Delete Selected Event(s)"); - ui->actionZoom_In->setShortcuts({ui->actionZoom_In->shortcut(), QKeySequence("Ctrl+=")}); + auto *shortcutToggle_Border = new Shortcut(QKeySequence(), ui->checkBox_ToggleBorder, SLOT(toggle())); + shortcutToggle_Border->setObjectName("shortcutToggle_Border"); + shortcutToggle_Border->setWhatsThis("Toggle Border"); + + auto *shortcutToggle_Smart_Paths = new Shortcut(QKeySequence(), ui->checkBox_smartPaths, SLOT(toggle())); + shortcutToggle_Smart_Paths->setObjectName("shortcutToggle_Smart_Paths"); + shortcutToggle_Smart_Paths->setWhatsThis("Toggle Smart Paths"); + + auto *shortcutExpand_All = new Shortcut(QKeySequence(), this, SLOT(on_toolButton_ExpandAll_clicked())); + shortcutExpand_All->setObjectName("shortcutExpand_All"); + shortcutExpand_All->setWhatsThis("Map List: Expand all folders"); + + auto *shortcutCollapse_All = new Shortcut(QKeySequence(), this, SLOT(on_toolButton_CollapseAll_clicked())); + shortcutCollapse_All->setObjectName("shortcutCollapse_All"); + shortcutCollapse_All->setWhatsThis("Map List: Collapse all folders"); + + auto *shortcutNew_Event = new Shortcut(QKeySequence(), this, SLOT(on_toolButton_Open_Scripts_clicked())); + shortcutNew_Event->setObjectName("shortcut_Open_Scripts"); + shortcutNew_Event->setWhatsThis("Open Map Scripts"); } QObjectList MainWindow::shortcutableObjects() const { QObjectList shortcutable_objects; + for (auto *action : findChildren()) - if (ShortcutsConfig::objectNameIsValid(action)) + if (!action->objectName().isEmpty()) shortcutable_objects.append(qobject_cast(action)); for (auto *shortcut : findChildren()) - if (ShortcutsConfig::objectNameIsValid(shortcut)) + if (!shortcut->objectName().isEmpty()) shortcutable_objects.append(qobject_cast(shortcut)); - + return shortcutable_objects; } void MainWindow::applyUserShortcuts() { for (auto *action : findChildren()) - if (ShortcutsConfig::objectNameIsValid(action)) + if (!action->objectName().isEmpty()) action->setShortcuts(shortcutsConfig.userShortcuts(action)); for (auto *shortcut : findChildren()) - if (ShortcutsConfig::objectNameIsValid(shortcut)) + if (!shortcut->objectName().isEmpty()) shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); } diff --git a/src/ui/regionmapeditor.cpp b/src/ui/regionmapeditor.cpp index b025b90e..a116aa5a 100644 --- a/src/ui/regionmapeditor.cpp +++ b/src/ui/regionmapeditor.cpp @@ -25,6 +25,7 @@ RegionMapEditor::RegionMapEditor(QWidget *parent, Project *project_) : this->project = project_; this->region_map = new RegionMap; this->ui->action_RegionMap_Resize->setVisible(false); + this->initShortcuts(); this->restoreWindowState(); } @@ -94,6 +95,11 @@ bool RegionMapEditor::loadCityMaps() { } void RegionMapEditor::initShortcuts() { + auto *shortcut_RM_Options_delete = new Shortcut( + {QKeySequence("Del"), QKeySequence("Backspace")}, this, SLOT(on_pushButton_RM_Options_delete_clicked())); + shortcut_RM_Options_delete->setObjectName("shortcut_RM_Options_delete"); + shortcut_RM_Options_delete->setWhatsThis("Map Layout: Delete Square"); + shortcutsConfig.load(); shortcutsConfig.setDefaultShortcuts(shortcutableObjects()); applyUserShortcuts(); @@ -101,22 +107,23 @@ void RegionMapEditor::initShortcuts() { QObjectList RegionMapEditor::shortcutableObjects() const { QObjectList shortcutable_objects; + for (auto *action : findChildren()) - if (ShortcutsConfig::objectNameIsValid(action)) + if (!action->objectName().isEmpty()) shortcutable_objects.append(qobject_cast(action)); for (auto *shortcut : findChildren()) - if (ShortcutsConfig::objectNameIsValid(shortcut)) + if (!shortcut->objectName().isEmpty()) shortcutable_objects.append(qobject_cast(shortcut)); - + return shortcutable_objects; } void RegionMapEditor::applyUserShortcuts() { for (auto *action : findChildren()) - if (ShortcutsConfig::objectNameIsValid(action)) + if (!action->objectName().isEmpty()) action->setShortcuts(shortcutsConfig.userShortcuts(action)); for (auto *shortcut : findChildren()) - if (ShortcutsConfig::objectNameIsValid(shortcut)) + if (!shortcut->objectName().isEmpty()) shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); } diff --git a/src/ui/shortcutseditor.cpp b/src/ui/shortcutseditor.cpp index 0e0843f0..0f9e77ac 100644 --- a/src/ui/shortcutseditor.cpp +++ b/src/ui/shortcutseditor.cpp @@ -21,8 +21,8 @@ ShortcutsEditor::ShortcutsEditor(QWidget *parent) : ui->setupUi(this); setAttribute(Qt::WA_DeleteOnClose); main_container = ui->scrollAreaWidgetContents_Shortcuts; - auto *formLayout = new QVBoxLayout(main_container); - formLayout->setSpacing(12); + auto *main_layout = new QVBoxLayout(main_container); + main_layout->setSpacing(12); connect(ui->buttonBox, &QDialogButtonBox::clicked, this, &ShortcutsEditor::dialogButtonClicked); } @@ -69,7 +69,7 @@ void ShortcutsEditor::resetShortcuts() { void ShortcutsEditor::parseObjectList(const QObjectList &objectList) { for (auto *object : objectList) { const auto label = getLabel(object); - if (!label.isEmpty() && ShortcutsConfig::objectNameIsValid(object)) + if (!label.isEmpty() && !object->objectName().isEmpty() && !object->objectName().startsWith("_q_")) labels_objects.insert(label, object); } } diff --git a/src/ui/tileseteditor.cpp b/src/ui/tileseteditor.cpp index 5e0b9eed..a63b6680 100644 --- a/src/ui/tileseteditor.cpp +++ b/src/ui/tileseteditor.cpp @@ -211,31 +211,44 @@ void TilesetEditor::initSelectedTileItem() { } void TilesetEditor::initShortcuts() { - ui->actionRedo->setShortcuts({ui->actionRedo->shortcut(), QKeySequence("Ctrl+Shift+Z")}); + initExtraShortcuts(); shortcutsConfig.load(); shortcutsConfig.setDefaultShortcuts(shortcutableObjects()); applyUserShortcuts(); } +void TilesetEditor::initExtraShortcuts() { + ui->actionRedo->setShortcuts({ui->actionRedo->shortcut(), QKeySequence("Ctrl+Shift+Z")}); + + auto *shortcut_xFlip = new Shortcut(QKeySequence(), ui->checkBox_xFlip, SLOT(toggle())); + shortcut_xFlip->setObjectName("shortcut_xFlip"); + shortcut_xFlip->setWhatsThis("X Flip"); + + auto *shortcut_yFlip = new Shortcut(QKeySequence(), ui->checkBox_yFlip, SLOT(toggle())); + shortcut_yFlip->setObjectName("shortcut_yFlip"); + shortcut_yFlip->setWhatsThis("Y Flip"); +} + QObjectList TilesetEditor::shortcutableObjects() const { QObjectList shortcutable_objects; + for (auto *action : findChildren()) - if (ShortcutsConfig::objectNameIsValid(action)) + if (!action->objectName().isEmpty()) shortcutable_objects.append(qobject_cast(action)); for (auto *shortcut : findChildren()) - if (ShortcutsConfig::objectNameIsValid(shortcut)) + if (!shortcut->objectName().isEmpty()) shortcutable_objects.append(qobject_cast(shortcut)); - + return shortcutable_objects; } void TilesetEditor::applyUserShortcuts() { for (auto *action : findChildren()) - if (ShortcutsConfig::objectNameIsValid(action)) + if (!action->objectName().isEmpty()) action->setShortcuts(shortcutsConfig.userShortcuts(action)); for (auto *shortcut : findChildren()) - if (ShortcutsConfig::objectNameIsValid(shortcut)) + if (!shortcut->objectName().isEmpty()) shortcut->setKeys(shortcutsConfig.userShortcuts(shortcut)); } From 300a41c149efa7334f151f663e497cf9b21e992e Mon Sep 17 00:00:00 2001 From: BigBahss Date: Fri, 13 Nov 2020 02:52:37 -0500 Subject: [PATCH 11/12] Add clear button to MultiKeyEdit --- include/ui/multikeyedit.h | 2 ++ src/ui/multikeyedit.cpp | 10 ++++++++++ 2 files changed, 12 insertions(+) diff --git a/include/ui/multikeyedit.h b/include/ui/multikeyedit.h index c1736280..27231330 100644 --- a/include/ui/multikeyedit.h +++ b/include/ui/multikeyedit.h @@ -23,6 +23,8 @@ public: bool removeOne(const QKeySequence &keySequence); bool contains(const QKeySequence &keySequence) const; void setContextMenuPolicy(Qt::ContextMenuPolicy policy); + bool isClearButtonEnabled() const; + void setClearButtonEnabled(bool enable); public slots: void clear(); diff --git a/src/ui/multikeyedit.cpp b/src/ui/multikeyedit.cpp index 34ac19c8..09943861 100644 --- a/src/ui/multikeyedit.cpp +++ b/src/ui/multikeyedit.cpp @@ -98,6 +98,15 @@ void MultiKeyEdit::setContextMenuPolicy(Qt::ContextMenuPolicy policy) { lineEdit->setContextMenuPolicy(policy); } +bool MultiKeyEdit::isClearButtonEnabled() const { + return findChild()->isClearButtonEnabled(); +} + +void MultiKeyEdit::setClearButtonEnabled(bool enable) { + for (auto *lineEdit : findChildren()) + lineEdit->setClearButtonEnabled(enable); +} + void MultiKeyEdit::clear() { for (auto *keySequenceEdit : keySequenceEdit_vec) keySequenceEdit->clear(); @@ -126,6 +135,7 @@ void MultiKeyEdit::addNewKeySequenceEdit() { this, &MultiKeyEdit::keySequenceChanged); auto *lineEdit = keySequenceEdit->findChild(); + lineEdit->setClearButtonEnabled(true); lineEdit->installEventFilter(this); connect(lineEdit, &QLineEdit::customContextMenuRequested, this, &MultiKeyEdit::customContextMenuRequested); From b310ccba79d5b476cf25b10486a8b51ef602ec4e Mon Sep 17 00:00:00 2001 From: BigBahss Date: Fri, 13 Nov 2020 09:06:03 -0500 Subject: [PATCH 12/12] Fix map sorting via shortcut --- src/mainwindow.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index dcc90c9c..b6996ced 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -280,7 +280,7 @@ void MainWindow::initMapSortOrder() { mapSortOrderActionGroup->addAction(ui->actionSort_by_Area); mapSortOrderActionGroup->addAction(ui->actionSort_by_Layout); - connect(ui->toolButton_MapSortOrder, &QToolButton::triggered, this, &MainWindow::mapSortOrder_changed); + connect(mapSortOrderActionGroup, &QActionGroup::triggered, this, &MainWindow::mapSortOrder_changed); QAction* sortOrder = ui->toolButton_MapSortOrder->menu()->actions()[mapSortOrder]; ui->toolButton_MapSortOrder->setIcon(sortOrder->icon());