mirror of
https://github.com/Nheko-Reborn/nheko.git
synced 2024-11-26 04:58:49 +03:00
Begin work on adding editable shortcuts
This will eventually allow users to assign arbitrary shortcuts to actions to give them the ability to have shortcuts for everything(tm).
This commit is contained in:
parent
03be9e479a
commit
66ade755eb
6 changed files with 264 additions and 8 deletions
|
@ -397,6 +397,8 @@ set(SRC_FILES
|
||||||
src/ui/RoomSettings.h
|
src/ui/RoomSettings.h
|
||||||
src/ui/RoomSummary.cpp
|
src/ui/RoomSummary.cpp
|
||||||
src/ui/RoomSummary.h
|
src/ui/RoomSummary.h
|
||||||
|
src/ui/ShortcutRegistry.cpp
|
||||||
|
src/ui/ShortcutRegistry.h
|
||||||
src/ui/Theme.cpp
|
src/ui/Theme.cpp
|
||||||
src/ui/Theme.h
|
src/ui/Theme.h
|
||||||
src/ui/UIA.cpp
|
src/ui/UIA.cpp
|
||||||
|
|
|
@ -111,8 +111,16 @@ Pane {
|
||||||
|
|
||||||
onActivated: Qt.quit()
|
onActivated: Qt.quit()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditableShortcut {
|
||||||
|
id: quickSwitcherShortcut
|
||||||
|
|
||||||
|
name: qsTr("Room search")
|
||||||
|
description: qsTr("Opens a search bar for quick switching between rooms")
|
||||||
|
shortcut: "Ctrl+K"
|
||||||
|
}
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Ctrl+K"
|
sequence: quickSwitcherShortcut.shortcut
|
||||||
|
|
||||||
onActivated: {
|
onActivated: {
|
||||||
var component = Qt.createComponent("qrc:/resources/qml/QuickSwitcher.qml");
|
var component = Qt.createComponent("qrc:/resources/qml/QuickSwitcher.qml");
|
||||||
|
@ -125,19 +133,43 @@ Pane {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Shortcut {
|
|
||||||
|
EditableShortcut {
|
||||||
|
id: nextRoomWithActivityShortcut
|
||||||
|
|
||||||
|
name: qsTr("Next room with activity")
|
||||||
|
description: qsTr("Switches to the next unread room in the roomlist")
|
||||||
// Add alternative shortcut, because sometimes Alt+A is stolen by the TextEdit
|
// Add alternative shortcut, because sometimes Alt+A is stolen by the TextEdit
|
||||||
sequences: ["Alt+A", "Ctrl+Shift+A"]
|
shortcuts: ["Alt+A", "Ctrl+Shift+A"]
|
||||||
|
}
|
||||||
|
Shortcut {
|
||||||
|
sequences: nextRoomWithActivityShortcut.shortcuts
|
||||||
|
|
||||||
onActivated: Rooms.nextRoomWithActivity()
|
onActivated: Rooms.nextRoomWithActivity()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditableShortcut {
|
||||||
|
id: nextRoomShortcut
|
||||||
|
|
||||||
|
name: qsTr("Next room")
|
||||||
|
description: qsTr("Switches to the room below the room that is currently open")
|
||||||
|
shortcut: "Ctrl+Down"
|
||||||
|
}
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Ctrl+Down"
|
sequence: nextRoomShortcut.shortcut
|
||||||
|
|
||||||
onActivated: Rooms.nextRoom()
|
onActivated: Rooms.nextRoom()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditableShortcut {
|
||||||
|
id: previousRoomShortcut
|
||||||
|
|
||||||
|
name: qsTr("Previous room")
|
||||||
|
description: qsTr("Switches to the room above the room that is currently open")
|
||||||
|
shortcut: "Ctrl+Up"
|
||||||
|
}
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequence: "Ctrl+Up"
|
sequence: previousRoomShortcut.shortcut
|
||||||
|
|
||||||
onActivated: Rooms.previousRoom()
|
onActivated: Rooms.previousRoom()
|
||||||
}
|
}
|
||||||
|
|
|
@ -395,6 +395,7 @@ Pane {
|
||||||
|
|
||||||
onActivated: searchButton.searchActive = !searchButton.searchActive
|
onActivated: searchButton.searchActive = !searchButton.searchActive
|
||||||
}
|
}
|
||||||
|
|
||||||
TapHandler {
|
TapHandler {
|
||||||
gesturePolicy: TapHandler.ReleaseWithinBounds
|
gesturePolicy: TapHandler.ReleaseWithinBounds
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ Window {
|
||||||
Component.onCompleted: Nheko.setWindowRole(imageOverlay, "imageoverlay")
|
Component.onCompleted: Nheko.setWindowRole(imageOverlay, "imageoverlay")
|
||||||
|
|
||||||
Shortcut {
|
Shortcut {
|
||||||
sequences: [StandardKey.Cancel]
|
sequence: StandardKey.Cancel
|
||||||
onActivated: imageOverlay.close()
|
onActivated: imageOverlay.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
140
src/ui/ShortcutRegistry.cpp
Normal file
140
src/ui/ShortcutRegistry.cpp
Normal file
|
@ -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);
|
||||||
|
}
|
81
src/ui/ShortcutRegistry.h
Normal file
81
src/ui/ShortcutRegistry.h
Normal file
|
@ -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 a new issue