mirror of https://github.com/Nheko-Reborn/nheko
This will eventually allow users to assign arbitrary shortcuts to actions to give them the ability to have shortcuts for everything(tm).pull/1568/head
parent
03be9e479a
commit
66ade755eb
@ -0,0 +1,140 @@ |
|||||||
|
#include "ShortcutRegistry.h" |
||||||
|
|
||||||
|
ShortcutRegistry *ShortcutRegistry::s_instance = nullptr; |
||||||
|
|
||||||
|
EditableShortcut::EditableShortcut(QObject *parent) |
||||||
|
: QObject{parent} |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
const QStringList EditableShortcut::shortcuts() const |
||||||
|
{ |
||||||
|
QStringList dest; |
||||||
|
dest.resize(m_shortcuts.size()); |
||||||
|
std::transform(m_shortcuts.begin(), m_shortcuts.end(), dest.begin(), [](const auto &shortcut) { |
||||||
|
return shortcut.toString(); |
||||||
|
}); |
||||||
|
return dest; |
||||||
|
} |
||||||
|
|
||||||
|
void EditableShortcut::setName(const QString &name) |
||||||
|
{ |
||||||
|
if (name == m_name) |
||||||
|
return; |
||||||
|
m_name = name; |
||||||
|
emit nameChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
void EditableShortcut::setDescription(const QString &description) |
||||||
|
{ |
||||||
|
if (description == m_description) |
||||||
|
return; |
||||||
|
m_description = description; |
||||||
|
emit descriptionChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
void EditableShortcut::setShortcut(const QString &shortcut) |
||||||
|
{ |
||||||
|
setShortcuts({shortcut}); |
||||||
|
} |
||||||
|
|
||||||
|
void EditableShortcut::setShortcuts(const QStringList &shortcuts) |
||||||
|
{ |
||||||
|
QList<QKeySequence> temp; |
||||||
|
temp.resize(shortcuts.size()); |
||||||
|
std::transform(shortcuts.begin(), shortcuts.end(), temp.begin(), [](const auto &shortcut) { |
||||||
|
return QKeySequence(shortcut); |
||||||
|
}); |
||||||
|
|
||||||
|
if (temp == m_shortcuts) |
||||||
|
return; |
||||||
|
m_shortcuts = temp; |
||||||
|
emit shortcutsChanged(); |
||||||
|
} |
||||||
|
|
||||||
|
EditableShortcut::EditableShortcut(const QString &name, const QString &description, QObject *parent) |
||||||
|
: QObject{parent} |
||||||
|
, m_name{name} |
||||||
|
, m_description{description} |
||||||
|
{ |
||||||
|
ShortcutRegistry::instance()->registerShortcut(this); |
||||||
|
} |
||||||
|
|
||||||
|
ShortcutRegistry * |
||||||
|
ShortcutRegistry::instance() |
||||||
|
{ |
||||||
|
return s_instance; |
||||||
|
} |
||||||
|
|
||||||
|
ShortcutRegistry *ShortcutRegistry::create(QQmlEngine *qmlEngine, QJSEngine *) |
||||||
|
{ |
||||||
|
// The instance has to exist before it is used. We cannot replace it.
|
||||||
|
Q_ASSERT(s_instance); |
||||||
|
|
||||||
|
// The engine has to have the same thread affinity as the singleton.
|
||||||
|
Q_ASSERT(qmlEngine->thread() == s_instance->thread()); |
||||||
|
|
||||||
|
// There can only be one engine accessing the singleton.
|
||||||
|
static QJSEngine *s_engine = nullptr; |
||||||
|
if (s_engine) |
||||||
|
Q_ASSERT(qmlEngine == s_engine); |
||||||
|
else |
||||||
|
s_engine = qmlEngine; |
||||||
|
|
||||||
|
QJSEngine::setObjectOwnership(s_instance, QJSEngine::CppOwnership); |
||||||
|
return s_instance; |
||||||
|
} |
||||||
|
|
||||||
|
QHash<int, QByteArray> ShortcutRegistry::roleNames() const |
||||||
|
{ |
||||||
|
return {{Roles::Name, "name"}, |
||||||
|
{Roles::Description, "description"}, |
||||||
|
{Roles::Shortcut, "shortcut"}}; |
||||||
|
} |
||||||
|
|
||||||
|
QVariant ShortcutRegistry::data(const QModelIndex &index, int role) const |
||||||
|
{ |
||||||
|
if (!index.isValid() || index.row() >= m_shortcuts.size() || index.row() < 0) |
||||||
|
return {}; |
||||||
|
|
||||||
|
switch (role) |
||||||
|
{ |
||||||
|
case Roles::Name: |
||||||
|
return m_shortcuts[index.row()]->name(); |
||||||
|
case Roles::Description: |
||||||
|
return m_shortcuts[index.row()]->description(); |
||||||
|
case Roles::Shortcut: |
||||||
|
return m_shortcuts[index.row()]->shortcut(); |
||||||
|
default: |
||||||
|
return {}; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
bool ShortcutRegistry::setData(const QModelIndex &index, const QVariant &value, int role) |
||||||
|
{ |
||||||
|
if (!index.isValid() || index.row() >= m_shortcuts.size() || index.row() < 0) |
||||||
|
return false; |
||||||
|
|
||||||
|
switch (role) |
||||||
|
{ |
||||||
|
case Roles::Shortcut: |
||||||
|
if (auto shortcut = QKeySequence(value.toString()); !shortcut.isEmpty()) { |
||||||
|
m_shortcuts[index.row()]->setShortcut(shortcut.toString()); |
||||||
|
return true; |
||||||
|
} else |
||||||
|
return false; |
||||||
|
default: |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
ShortcutRegistry::ShortcutRegistry(QObject *parent) |
||||||
|
: QAbstractListModel{parent} |
||||||
|
{ |
||||||
|
s_instance = this; |
||||||
|
} |
||||||
|
|
||||||
|
void ShortcutRegistry::registerShortcut(EditableShortcut *action) |
||||||
|
{ |
||||||
|
m_shortcuts.push_back(action); |
||||||
|
} |
@ -0,0 +1,81 @@ |
|||||||
|
#pragma once |
||||||
|
|
||||||
|
#include <QAbstractListModel> |
||||||
|
#include <QAction> |
||||||
|
#include <QQmlEngine> |
||||||
|
|
||||||
|
class EditableShortcut : public QObject |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
QML_ELEMENT |
||||||
|
|
||||||
|
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged FINAL) |
||||||
|
Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged FINAL) |
||||||
|
Q_PROPERTY(QString shortcut READ shortcut WRITE setShortcut NOTIFY shortcutsChanged FINAL) |
||||||
|
Q_PROPERTY(QStringList shortcuts READ shortcuts WRITE setShortcuts NOTIFY shortcutsChanged FINAL) |
||||||
|
|
||||||
|
public: |
||||||
|
EditableShortcut(QObject *parent = nullptr); |
||||||
|
EditableShortcut(const QString &name, const QString &description, QObject *parent = nullptr); |
||||||
|
EditableShortcut(const QString &name, const QString &description, const QString &text, QObject *parent = nullptr); |
||||||
|
EditableShortcut(const QString &name, const QString &description, const QIcon &icon, const QString &text, QObject *parent = nullptr); |
||||||
|
|
||||||
|
const QString &name() const { return m_name; } |
||||||
|
const QString &description() const { return m_description; } |
||||||
|
const QString shortcut() const |
||||||
|
{ |
||||||
|
return m_shortcuts.size() > 0 ? m_shortcuts.first().toString() : QString{}; |
||||||
|
} |
||||||
|
const QStringList shortcuts() const; |
||||||
|
|
||||||
|
void setName(const QString &name); |
||||||
|
void setDescription(const QString &description); |
||||||
|
void setShortcut(const QString &shortcut); |
||||||
|
void setShortcuts(const QStringList &shortcuts); |
||||||
|
|
||||||
|
signals: |
||||||
|
void nameChanged(); |
||||||
|
void descriptionChanged(); |
||||||
|
void shortcutsChanged(); |
||||||
|
|
||||||
|
private: |
||||||
|
QString m_name; |
||||||
|
QString m_description; |
||||||
|
QList<QKeySequence> m_shortcuts; |
||||||
|
}; |
||||||
|
|
||||||
|
class ShortcutRegistry : public QAbstractListModel |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
QML_ELEMENT |
||||||
|
QML_SINGLETON |
||||||
|
|
||||||
|
public: |
||||||
|
enum Roles |
||||||
|
{ |
||||||
|
Name, |
||||||
|
Description, |
||||||
|
Shortcut, |
||||||
|
}; |
||||||
|
|
||||||
|
static ShortcutRegistry *instance(); |
||||||
|
static ShortcutRegistry *create(QQmlEngine *qmlEngine, QJSEngine *); |
||||||
|
|
||||||
|
QHash<int, QByteArray> roleNames() const override; |
||||||
|
int rowCount(const QModelIndex & = QModelIndex()) const override |
||||||
|
{ |
||||||
|
return m_shortcuts.size(); |
||||||
|
} |
||||||
|
QVariant data(const QModelIndex &index, int role) const override; |
||||||
|
bool setData(const QModelIndex &index, const QVariant &value, int role) override; |
||||||
|
|
||||||
|
private: |
||||||
|
explicit ShortcutRegistry(QObject *parent = nullptr); |
||||||
|
|
||||||
|
void registerShortcut(EditableShortcut *action); |
||||||
|
|
||||||
|
static ShortcutRegistry *s_instance; |
||||||
|
QList<EditableShortcut *> m_shortcuts; |
||||||
|
|
||||||
|
friend EditableShortcut; |
||||||
|
}; |
Loading…
Reference in new issue