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; +}