Add ShortcutsEditor to customize shortcuts for QAction's
This commit is contained in:
parent
ebb17476a7
commit
88fbf9f28b
9 changed files with 520 additions and 3 deletions
|
@ -2639,6 +2639,8 @@
|
||||||
<addaction name="actionUse_Encounter_Json"/>
|
<addaction name="actionUse_Encounter_Json"/>
|
||||||
<addaction name="actionMonitor_Project_Files"/>
|
<addaction name="actionMonitor_Project_Files"/>
|
||||||
<addaction name="actionUse_Poryscript"/>
|
<addaction name="actionUse_Poryscript"/>
|
||||||
|
<addaction name="separator"/>
|
||||||
|
<addaction name="actionEdit_Shortcuts"/>
|
||||||
</widget>
|
</widget>
|
||||||
<addaction name="menuFile"/>
|
<addaction name="menuFile"/>
|
||||||
<addaction name="menuEdit"/>
|
<addaction name="menuEdit"/>
|
||||||
|
@ -2905,6 +2907,11 @@
|
||||||
<string>Export Map Stitch Image...</string>
|
<string>Export Map Stitch Image...</string>
|
||||||
</property>
|
</property>
|
||||||
</action>
|
</action>
|
||||||
|
<action name="actionEdit_Shortcuts">
|
||||||
|
<property name="text">
|
||||||
|
<string>Edit Shortcuts...</string>
|
||||||
|
</property>
|
||||||
|
</action>
|
||||||
</widget>
|
</widget>
|
||||||
<layoutdefault spacing="6" margin="11"/>
|
<layoutdefault spacing="6" margin="11"/>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
|
48
forms/shortcutseditor.ui
Normal file
48
forms/shortcutseditor.ui
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>ShortcutsEditor</class>
|
||||||
|
<widget class="QDialog" name="ShortcutsEditor">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>540</width>
|
||||||
|
<height>640</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Shortcuts Editor</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QScrollArea" name="scrollArea_Shortcuts">
|
||||||
|
<property name="widgetResizable">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<widget class="QWidget" name="scrollAreaWidgetContents_Shortcuts">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>516</width>
|
||||||
|
<height>580</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults</set>
|
||||||
|
</property>
|
||||||
|
<property name="centerButtons">
|
||||||
|
<bool>false</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
|
@ -5,6 +5,8 @@
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QByteArrayList>
|
#include <QByteArrayList>
|
||||||
#include <QSize>
|
#include <QSize>
|
||||||
|
#include <QKeySequence>
|
||||||
|
#include <QMultiMap>
|
||||||
|
|
||||||
enum MapSortOrder {
|
enum MapSortOrder {
|
||||||
Group = 0,
|
Group = 0,
|
||||||
|
@ -192,4 +194,37 @@ private:
|
||||||
|
|
||||||
extern ProjectConfig projectConfig;
|
extern ProjectConfig projectConfig;
|
||||||
|
|
||||||
|
class QAction;
|
||||||
|
|
||||||
|
class ShortcutsConfig : public KeyValueConfigBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ShortcutsConfig() :
|
||||||
|
shortcuts(QMultiMap<QString, QKeySequence>()),
|
||||||
|
defaultShortcuts(QMultiMap<QString, QKeySequence>())
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
}
|
||||||
|
virtual void reset() override { shortcuts.clear(); }
|
||||||
|
void setDefaultShortcuts(const QList<QAction *> &actions);
|
||||||
|
QList<QKeySequence> getDefaultShortcuts(QAction *action) const;
|
||||||
|
void setUserShortcuts(const QList<QAction *> &actions);
|
||||||
|
QList<QKeySequence> getUserShortcuts(QAction *action) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual QString getConfigFilepath() override;
|
||||||
|
virtual void parseConfigKeyValue(QString key, QString value) override;
|
||||||
|
virtual QMap<QString, QString> getKeyValueMap() override;
|
||||||
|
virtual void onNewConfigFileCreated() override {};
|
||||||
|
virtual void setUnreadKeys() override {};
|
||||||
|
|
||||||
|
private:
|
||||||
|
QMultiMap<QString, QKeySequence> shortcuts;
|
||||||
|
QMultiMap<QString, QKeySequence> defaultShortcuts;
|
||||||
|
|
||||||
|
QString getKey(QObject *object) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern ShortcutsConfig shortcutsConfig;
|
||||||
|
|
||||||
#endif // CONFIG_H
|
#endif // CONFIG_H
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#include "filterchildrenproxymodel.h"
|
#include "filterchildrenproxymodel.h"
|
||||||
#include "newmappopup.h"
|
#include "newmappopup.h"
|
||||||
#include "newtilesetdialog.h"
|
#include "newtilesetdialog.h"
|
||||||
|
#include "shortcutseditor.h"
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class MainWindow;
|
class MainWindow;
|
||||||
|
@ -147,6 +148,7 @@ private slots:
|
||||||
void on_actionUse_Encounter_Json_triggered(bool checked);
|
void on_actionUse_Encounter_Json_triggered(bool checked);
|
||||||
void on_actionMonitor_Project_Files_triggered(bool checked);
|
void on_actionMonitor_Project_Files_triggered(bool checked);
|
||||||
void on_actionUse_Poryscript_triggered(bool checked);
|
void on_actionUse_Poryscript_triggered(bool checked);
|
||||||
|
void on_actionEdit_Shortcuts_triggered();
|
||||||
|
|
||||||
void on_mainTabBar_tabBarClicked(int index);
|
void on_mainTabBar_tabBarClicked(int index);
|
||||||
|
|
||||||
|
@ -231,6 +233,7 @@ private:
|
||||||
Ui::MainWindow *ui;
|
Ui::MainWindow *ui;
|
||||||
TilesetEditor *tilesetEditor = nullptr;
|
TilesetEditor *tilesetEditor = nullptr;
|
||||||
RegionMapEditor *regionMapEditor = nullptr;
|
RegionMapEditor *regionMapEditor = nullptr;
|
||||||
|
ShortcutsEditor *shortcutsEditor = nullptr;
|
||||||
MapImageExporter *mapImageExporter = nullptr;
|
MapImageExporter *mapImageExporter = nullptr;
|
||||||
FilterChildrenProxyModel *mapListProxyModel;
|
FilterChildrenProxyModel *mapListProxyModel;
|
||||||
NewMapPopup *newmapprompt = nullptr;
|
NewMapPopup *newmapprompt = nullptr;
|
||||||
|
@ -294,6 +297,7 @@ private:
|
||||||
void initEditor();
|
void initEditor();
|
||||||
void initMiscHeapObjects();
|
void initMiscHeapObjects();
|
||||||
void initMapSortOrder();
|
void initMapSortOrder();
|
||||||
|
void initUserShortcuts();
|
||||||
void setProjectSpecificUIVisibility();
|
void setProjectSpecificUIVisibility();
|
||||||
void loadUserSettings();
|
void loadUserSettings();
|
||||||
void applyMapListFilter(QString filterText);
|
void applyMapListFilter(QString filterText);
|
||||||
|
|
80
include/ui/shortcutseditor.h
Normal file
80
include/ui/shortcutseditor.h
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
#ifndef SHORTCUTSEDITOR_H
|
||||||
|
#define SHORTCUTSEDITOR_H
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
#include <QMap>
|
||||||
|
|
||||||
|
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<QString, QAction *> 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<QKeySequence> shortcuts() const;
|
||||||
|
void setShortcuts(const QList<QKeySequence> &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<QKeySequenceEdit *> kse_children;
|
||||||
|
QList<QKeySequence> ks_list;
|
||||||
|
|
||||||
|
void updateShortcuts() { setShortcuts(shortcuts()); }
|
||||||
|
void focusLast();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onEditingFinished();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHORTCUTSEDITOR_H
|
|
@ -71,6 +71,7 @@ SOURCES += src/core/block.cpp \
|
||||||
src/ui/newtilesetdialog.cpp \
|
src/ui/newtilesetdialog.cpp \
|
||||||
src/ui/flowlayout.cpp \
|
src/ui/flowlayout.cpp \
|
||||||
src/ui/mapruler.cpp \
|
src/ui/mapruler.cpp \
|
||||||
|
src/ui/shortcutseditor.cpp \
|
||||||
src/config.cpp \
|
src/config.cpp \
|
||||||
src/editor.cpp \
|
src/editor.cpp \
|
||||||
src/main.cpp \
|
src/main.cpp \
|
||||||
|
@ -140,6 +141,7 @@ HEADERS += include/core/block.h \
|
||||||
include/ui/overlay.h \
|
include/ui/overlay.h \
|
||||||
include/ui/flowlayout.h \
|
include/ui/flowlayout.h \
|
||||||
include/ui/mapruler.h \
|
include/ui/mapruler.h \
|
||||||
|
include/ui/shortcutseditor.h \
|
||||||
include/config.h \
|
include/config.h \
|
||||||
include/editor.h \
|
include/editor.h \
|
||||||
include/mainwindow.h \
|
include/mainwindow.h \
|
||||||
|
@ -156,7 +158,8 @@ FORMS += forms/mainwindow.ui \
|
||||||
forms/newmappopup.ui \
|
forms/newmappopup.ui \
|
||||||
forms/aboutporymap.ui \
|
forms/aboutporymap.ui \
|
||||||
forms/newtilesetdialog.ui \
|
forms/newtilesetdialog.ui \
|
||||||
forms/mapimageexporter.ui
|
forms/mapimageexporter.ui \
|
||||||
|
forms/shortcutseditor.ui
|
||||||
|
|
||||||
RESOURCES += \
|
RESOURCES += \
|
||||||
resources/images.qrc \
|
resources/images.qrc \
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <QTextStream>
|
#include <QTextStream>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
KeyValueConfigBase::~KeyValueConfigBase() {
|
KeyValueConfigBase::~KeyValueConfigBase() {
|
||||||
|
|
||||||
|
@ -414,7 +415,7 @@ ProjectConfig projectConfig;
|
||||||
|
|
||||||
QString ProjectConfig::getConfigFilepath() {
|
QString ProjectConfig::getConfigFilepath() {
|
||||||
// porymap config file is in the same directory as porymap itself.
|
// 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) {
|
void ProjectConfig::parseConfigKeyValue(QString key, QString value) {
|
||||||
|
@ -703,3 +704,84 @@ void ProjectConfig::setCustomScripts(QList<QString> scripts) {
|
||||||
QList<QString> ProjectConfig::getCustomScripts() {
|
QList<QString> ProjectConfig::getCustomScripts() {
|
||||||
return this->customScripts;
|
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<QString, QString> ShortcutsConfig::getKeyValueMap() {
|
||||||
|
QMap<QString, QString> 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<QAction *> &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<QKeySequence> ShortcutsConfig::getDefaultShortcuts(QAction *action) const {
|
||||||
|
return defaultShortcuts.values(getKey(action));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutsConfig::setUserShortcuts(const QList<QAction *> &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<QKeySequence> 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();
|
||||||
|
}
|
||||||
|
|
|
@ -92,6 +92,7 @@ void MainWindow::initWindow() {
|
||||||
this->initEditor();
|
this->initEditor();
|
||||||
this->initMiscHeapObjects();
|
this->initMiscHeapObjects();
|
||||||
this->initMapSortOrder();
|
this->initMapSortOrder();
|
||||||
|
this->initUserShortcuts();
|
||||||
this->restoreWindowState();
|
this->restoreWindowState();
|
||||||
|
|
||||||
setWindowDisabled(true);
|
setWindowDisabled(true);
|
||||||
|
@ -106,6 +107,13 @@ void MainWindow::initExtraShortcuts() {
|
||||||
ui->actionZoom_In->setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+=")});
|
ui->actionZoom_In->setShortcuts({QKeySequence("Ctrl++"), QKeySequence("Ctrl+=")});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MainWindow::initUserShortcuts() {
|
||||||
|
shortcutsConfig.load();
|
||||||
|
shortcutsConfig.setDefaultShortcuts(findChildren<QAction *>());
|
||||||
|
for (auto *action : findChildren<QAction *>())
|
||||||
|
action->setShortcuts(shortcutsConfig.getUserShortcuts(action));
|
||||||
|
}
|
||||||
|
|
||||||
void MainWindow::initCustomUI() {
|
void MainWindow::initCustomUI() {
|
||||||
// Set up the tab bar
|
// Set up the tab bar
|
||||||
ui->mainTabBar->addTab("Map");
|
ui->mainTabBar->addTab("Map");
|
||||||
|
@ -158,9 +166,11 @@ void MainWindow::initEditor() {
|
||||||
this->loadUserSettings();
|
this->loadUserSettings();
|
||||||
|
|
||||||
undoAction = editor->editGroup.createUndoAction(this, tr("&Undo"));
|
undoAction = editor->editGroup.createUndoAction(this, tr("&Undo"));
|
||||||
|
undoAction->setObjectName("action_Undo");
|
||||||
undoAction->setShortcut(QKeySequence("Ctrl+Z"));
|
undoAction->setShortcut(QKeySequence("Ctrl+Z"));
|
||||||
|
|
||||||
redoAction = editor->editGroup.createRedoAction(this, tr("&Redo"));
|
redoAction = editor->editGroup.createRedoAction(this, tr("&Redo"));
|
||||||
|
redoAction->setObjectName("action_Redo");
|
||||||
redoAction->setShortcuts({QKeySequence("Ctrl+Y"), QKeySequence("Ctrl+Shift+Z")});
|
redoAction->setShortcuts({QKeySequence("Ctrl+Y"), QKeySequence("Ctrl+Shift+Z")});
|
||||||
|
|
||||||
ui->menuEdit->addAction(undoAction);
|
ui->menuEdit->addAction(undoAction);
|
||||||
|
@ -171,7 +181,8 @@ void MainWindow::initEditor() {
|
||||||
undoView->setAttribute(Qt::WA_QuitOnClose, false);
|
undoView->setAttribute(Qt::WA_QuitOnClose, false);
|
||||||
|
|
||||||
// Show the EditHistory dialog with Ctrl+E
|
// 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"));
|
showHistory->setShortcut(QKeySequence("Ctrl+E"));
|
||||||
connect(showHistory, &QAction::triggered, [undoView](){ undoView->show(); });
|
connect(showHistory, &QAction::triggered, [undoView](){ undoView->show(); });
|
||||||
|
|
||||||
|
@ -1403,6 +1414,19 @@ void MainWindow::on_actionUse_Poryscript_triggered(bool checked)
|
||||||
projectConfig.setUsePoryScript(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()
|
void MainWindow::on_actionPencil_triggered()
|
||||||
{
|
{
|
||||||
on_toolButton_Paint_clicked();
|
on_toolButton_Paint_clicked();
|
||||||
|
|
234
src/ui/shortcutseditor.cpp
Normal file
234
src/ui/shortcutseditor.cpp
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
#include "shortcutseditor.h"
|
||||||
|
#include "ui_shortcutseditor.h"
|
||||||
|
#include "config.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QAbstractButton>
|
||||||
|
#include <QtEvents>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QKeySequenceEdit>
|
||||||
|
#include <QAction>
|
||||||
|
|
||||||
|
|
||||||
|
ShortcutsEditor::ShortcutsEditor(QWidget *parent) :
|
||||||
|
QDialog(parent),
|
||||||
|
ui(new Ui::ShortcutsEditor),
|
||||||
|
actions(QMap<QString, QAction *>())
|
||||||
|
{
|
||||||
|
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<QAction *>())
|
||||||
|
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<ActionShortcutEdit *>(QString(), Qt::FindDirectChildrenOnly);
|
||||||
|
for (auto *ase : ase_children)
|
||||||
|
ase->applyShortcuts();
|
||||||
|
shortcutsConfig.setUserShortcuts(actions.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShortcutsEditor::resetShortcuts() {
|
||||||
|
auto ase_children = ase_container->findChildren<ActionShortcutEdit *>(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<ActionShortcutEdit *>(sender());
|
||||||
|
if (!sender_ase)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto *child_kse : findChildren<QKeySequenceEdit *>()) {
|
||||||
|
if (child_kse->keySequence().isEmpty() || child_kse->parent() == sender())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (sender_ase->contains(child_kse->keySequence())) {
|
||||||
|
auto *current_ase = qobject_cast<ActionShortcutEdit *>(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<QKeySequenceEdit *>()),
|
||||||
|
ks_list(QList<QKeySequence>())
|
||||||
|
{
|
||||||
|
setLayout(new QHBoxLayout(this));
|
||||||
|
layout()->setContentsMargins(0, 0, 0, 0);
|
||||||
|
setCount(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ActionShortcutEdit::eventFilter(QObject *watched, QEvent *event) {
|
||||||
|
auto *watched_kse = qobject_cast<QKeySequenceEdit *>(watched);
|
||||||
|
if (!watched_kse)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (event->type() == QEvent::KeyPress) {
|
||||||
|
auto *keyEvent = static_cast<QKeyEvent *>(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<QKeySequence> ActionShortcutEdit::shortcuts() const {
|
||||||
|
QList<QKeySequence> 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<QKeySequence> &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<QKeySequenceEdit *>(sender());
|
||||||
|
if (!kse)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (ks_list.contains(kse->keySequence()))
|
||||||
|
removeOne(kse->keySequence());
|
||||||
|
updateShortcuts();
|
||||||
|
focusLast();
|
||||||
|
emit editingFinished();
|
||||||
|
}
|
Loading…
Reference in a new issue