Qt: Get submenus working with the shortcut editor
Jeffrey Pfau jeffrey@endrift.com
Sun, 04 Jan 2015 15:46:35 -0800
3 files changed,
131 insertions(+),
109 deletions(-)
M
src/platform/qt/ShortcutController.cpp
→
src/platform/qt/ShortcutController.cpp
@@ -14,6 +14,7 @@ using namespace QGBA;
ShortcutController::ShortcutController(QObject* parent) : QAbstractItemModel(parent) + , m_rootMenu(nullptr) { }@@ -21,23 +22,21 @@ QVariant ShortcutController::data(const QModelIndex& index, int role) const {
if (role != Qt::DisplayRole || !index.isValid()) { return QVariant(); } - const QModelIndex& parent = index.parent(); - if (parent.isValid()) { - const ShortcutMenu& menu = m_menus[parent.row()]; - const ShortcutItem& item = menu.shortcuts()[index.row()]; - switch (index.column()) { - case 0: - return item.visibleName(); - case 1: - return item.action()->shortcut().toString(QKeySequence::NativeText); - case 2: - if (item.button() >= 0) { - return item.button(); - } - return QVariant(); + int row = index.row(); + const ShortcutItem* item = static_cast<const ShortcutItem*>(index.internalPointer()); + switch (index.column()) { + case 0: + return item->visibleName(); + case 1: + if (item->action()) { + return item->action()->shortcut().toString(QKeySequence::NativeText); + } + break; + case 2: + if (item->button() >= 0) { + return item->button(); } - } else if (index.column() == 0) { - return m_menus[index.row()].visibleName(); + break; } return QVariant(); }@@ -60,20 +59,22 @@ return section;
} QModelIndex ShortcutController::index(int row, int column, const QModelIndex& parent) const { - if (!parent.isValid()) { - return createIndex(row, column, -1); + const ShortcutItem* pmenu = &m_rootMenu; + if (parent.isValid()) { + pmenu = static_cast<ShortcutItem*>(parent.internalPointer()); } - return createIndex(row, column, parent.row()); + return createIndex(row, column, const_cast<ShortcutItem*>(&pmenu->items()[row])); } QModelIndex ShortcutController::parent(const QModelIndex& index) const { - if (!index.isValid()) { + if (!index.isValid() || !index.internalPointer()) { return QModelIndex(); } - if (index.internalId() == -1) { + ShortcutItem* item = static_cast<ShortcutItem*>(index.internalPointer()); + if (!item->parent() || !item->parent()->parent()) { return QModelIndex(); } - return createIndex(index.internalId(), 0, -1); + return createIndex(item->parent()->parent()->items().indexOf(*item->parent()), 0, item->parent()); } int ShortcutController::columnCount(const QModelIndex& index) const {@@ -81,58 +82,67 @@ return 3;
} int ShortcutController::rowCount(const QModelIndex& index) const { - if (index.parent().isValid()) { - return 0; - } - if (index.isValid()) { - return m_menus[index.row()].shortcuts().count(); + if (!index.isValid()) { + return m_rootMenu.items().count(); } - return m_menus.count(); + const ShortcutItem* item = static_cast<const ShortcutItem*>(index.internalPointer()); + return item->items().count(); } void ShortcutController::addAction(QMenu* menu, QAction* action, const QString& name) { - ShortcutMenu* smenu = nullptr; - int row = 0; - for (auto iter = m_menus.end(); iter-- != m_menus.begin(); ++row) { - if (iter->menu() == menu) { - smenu = &(*iter); - break; - } - } + ShortcutItem* smenu = m_menuMap[menu]; if (!smenu) { return; } - QModelIndex parent = createIndex(row, 0, -1); - beginInsertRows(parent, smenu->shortcuts().count(), smenu->shortcuts().count()); + ShortcutItem* pmenu = smenu->parent(); + int row = pmenu->items().indexOf(*smenu); + QModelIndex parent = createIndex(row, 0, smenu); + beginInsertRows(parent, smenu->items().count(), smenu->items().count()); smenu->addAction(action, name); endInsertRows(); - emit dataChanged(createIndex(smenu->shortcuts().count() - 1, 0, row), createIndex(smenu->shortcuts().count() - 1, 2, row)); + ShortcutItem* item = &smenu->items().last(); + emit dataChanged(createIndex(smenu->items().count() - 1, 0, item), createIndex(smenu->items().count() - 1, 2, item)); } -void ShortcutController::addMenu(QMenu* menu) { - beginInsertRows(QModelIndex(), m_menus.count(), m_menus.count()); - m_menus.append(ShortcutMenu(menu)); +void ShortcutController::addMenu(QMenu* menu, QMenu* parentMenu) { + ShortcutItem* smenu = m_menuMap[parentMenu]; + if (!smenu) { + smenu = &m_rootMenu; + } + QModelIndex parent; + ShortcutItem* pmenu = smenu->parent(); + if (pmenu) { + int row = pmenu->items().indexOf(*smenu); + parent = createIndex(row, 0, smenu); + } + beginInsertRows(parent, smenu->items().count(), smenu->items().count()); + smenu->addSubmenu(menu); endInsertRows(); - emit dataChanged(createIndex(m_menus.count() - 1, 0, -1), createIndex(m_menus.count() - 1, 0, -1)); + ShortcutItem* item = &smenu->items().last(); + emit dataChanged(createIndex(smenu->items().count() - 1, 0, item), createIndex(smenu->items().count() - 1, 2, item)); + m_menuMap[menu] = item; } -const QAction* ShortcutController::actionAt(const QModelIndex& index) const { +ShortcutController::ShortcutItem* ShortcutController::itemAt(const QModelIndex& index) { if (!index.isValid()) { return nullptr; } - const QModelIndex& parent = index.parent(); - if (!parent.isValid()) { - return nullptr; - } - if (parent.row() > m_menus.count()) { + return static_cast<ShortcutItem*>(index.internalPointer()); +} + +const ShortcutController::ShortcutItem* ShortcutController::itemAt(const QModelIndex& index) const { + if (!index.isValid()) { return nullptr; } - const ShortcutMenu& menu = m_menus[parent.row()]; - if (index.row() > menu.shortcuts().count()) { + return static_cast<const ShortcutItem*>(index.internalPointer()); +} + +const QAction* ShortcutController::actionAt(const QModelIndex& index) const { + const ShortcutItem* item = itemAt(index); + if (!item) { return nullptr; } - const ShortcutItem& item = menu.shortcuts()[index.row()]; - return item.action(); + return item->action(); } void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence& keySequence) {@@ -143,10 +153,9 @@ const QModelIndex& parent = index.parent();
if (!parent.isValid()) { return; } - ShortcutMenu& menu = m_menus[parent.row()]; - ShortcutItem& item = menu.shortcuts()[index.row()]; - item.action()->setShortcut(keySequence); - emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId())); + ShortcutItem* item = itemAt(index); + item->action()->setShortcut(keySequence); + emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), 2, index.internalPointer())); } void ShortcutController::updateButton(const QModelIndex& index, int button) {@@ -157,15 +166,14 @@ const QModelIndex& parent = index.parent();
if (!parent.isValid()) { return; } - ShortcutMenu& menu = m_menus[parent.row()]; - ShortcutItem& item = menu.shortcuts()[index.row()]; - int oldButton = item.button(); - item.setButton(button); + ShortcutItem* item = itemAt(index); + int oldButton = item->button(); + item->setButton(button); if (oldButton >= 0) { m_buttons.take(oldButton); } - m_buttons[button] = &item; - emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId())); + m_buttons[button] = item; + emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), 2, index.internalPointer())); } bool ShortcutController::eventFilter(QObject*, QEvent* event) {@@ -184,24 +192,35 @@ }
return false; } -ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name) +ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent) : m_action(action) + , m_menu(nullptr) , m_name(name) , m_button(-1) + , m_parent(parent) { m_visibleName = action->text() .remove(QRegExp("&(?!&)")) .remove("..."); } -ShortcutController::ShortcutMenu::ShortcutMenu(QMenu* menu) - : m_menu(menu) +ShortcutController::ShortcutItem::ShortcutItem(QMenu* menu, ShortcutItem* parent) + : m_action(nullptr) + , m_menu(menu) + , m_button(-1) + , m_parent(parent) { - m_visibleName = menu->title() - .remove(QRegExp("&(?!&)")) - .remove("..."); + if (menu) { + m_visibleName = menu->title() + .remove(QRegExp("&(?!&)")) + .remove("..."); + } } -void ShortcutController::ShortcutMenu::addAction(QAction* action, const QString& name) { - m_shortcuts.append(ShortcutItem(action, name)); +void ShortcutController::ShortcutItem::addAction(QAction* action, const QString& name) { + m_items.append(ShortcutItem(action, name, this)); +} + +void ShortcutController::ShortcutItem::addSubmenu(QMenu* menu) { + m_items.append(ShortcutItem(menu, this)); }
M
src/platform/qt/ShortcutController.h
→
src/platform/qt/ShortcutController.h
@@ -17,6 +17,39 @@
class ShortcutController : public QAbstractItemModel { Q_OBJECT +private: + class ShortcutItem { + public: + ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent = nullptr); + ShortcutItem(QMenu* action, ShortcutItem* parent = nullptr); + + QAction* action() { return m_action; } + const QAction* action() const { return m_action; } + QMenu* menu() { return m_menu; } + const QMenu* menu() const { return m_menu; } + const QString& visibleName() const { return m_visibleName; } + const QString& name() const { return m_name; } + QList<ShortcutItem>& items() { return m_items; } + const QList<ShortcutItem>& items() const { return m_items; } + ShortcutItem* parent() { return m_parent; } + const ShortcutItem* parent() const { return m_parent; } + void addAction(QAction* action, const QString& name); + void addSubmenu(QMenu* menu); + int button() const { return m_button; } + void setButton(int button) { m_button = button; } + + bool operator==(const ShortcutItem& other) const { return m_menu == other.m_menu && m_action == other.m_action; } + + private: + QAction* m_action; + QMenu* m_menu; + QString m_name; + QString m_visibleName; + int m_button; + QList<ShortcutItem> m_items; + ShortcutItem* m_parent; + }; + public: ShortcutController(QObject* parent = nullptr);@@ -30,9 +63,12 @@ virtual int columnCount(const QModelIndex& parent = QModelIndex()) const override;
virtual int rowCount(const QModelIndex& parent = QModelIndex()) const override; void addAction(QMenu* menu, QAction* action, const QString& name); - void addMenu(QMenu* menu); + void addMenu(QMenu* menu, QMenu* parent = nullptr); + ShortcutItem* itemAt(const QModelIndex& index); + const ShortcutItem* itemAt(const QModelIndex& index) const; const QAction* actionAt(const QModelIndex& index) const; + void updateKey(const QModelIndex& index, const QKeySequence& keySequence); void updateButton(const QModelIndex& index, int button);@@ -40,42 +76,8 @@ protected:
bool eventFilter(QObject*, QEvent*) override; private: - class ShortcutItem { - public: - ShortcutItem(QAction* action, const QString& name); - - QAction* action() { return m_action; } - const QAction* action() const { return m_action; } - const QString& visibleName() const { return m_visibleName; } - const QString& name() const { return m_name; } - int button() const { return m_button; } - void setButton(int button) { m_button = button; } - - private: - QAction* m_action; - QString m_name; - QString m_visibleName; - int m_button; - }; - - class ShortcutMenu { - public: - ShortcutMenu(QMenu* action); - - QMenu* menu() { return m_menu; } - const QMenu* menu() const { return m_menu; } - const QString& visibleName() const { return m_visibleName; } - QList<ShortcutItem>& shortcuts() { return m_shortcuts; } - const QList<ShortcutItem>& shortcuts() const { return m_shortcuts; } - void addAction(QAction* action, const QString& name); - - private: - QMenu* m_menu; - QString m_visibleName; - QList<ShortcutItem> m_shortcuts; - }; - - QList<ShortcutMenu> m_menus; + ShortcutItem m_rootMenu; + QMap<QMenu*, ShortcutItem*> m_menuMap; QMap<int, ShortcutItem*> m_buttons; };
M
src/platform/qt/Window.cpp
→
src/platform/qt/Window.cpp
@@ -533,13 +533,14 @@
QMenu* avMenu = menubar->addMenu(tr("Audio/&Video")); m_shortcutController->addMenu(avMenu); QMenu* frameMenu = avMenu->addMenu(tr("Frame size")); + m_shortcutController->addMenu(frameMenu, avMenu); for (int i = 1; i <= 6; ++i) { QAction* setSize = new QAction(tr("%1x").arg(QString::number(i)), avMenu); connect(setSize, &QAction::triggered, [this, i]() { showNormal(); resizeFrame(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i); }); - frameMenu->addAction(setSize); + addControlledAction(frameMenu, setSize, tr("frame%1x").arg(QString::number(i))); } addControlledAction(frameMenu, frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F")), "fullscreen");