Qt: Get submenus working with the shortcut editor

This commit is contained in:
Jeffrey Pfau 2015-01-04 15:46:35 -08:00
parent 33c4b17941
commit a1480e2698
3 changed files with 131 additions and 109 deletions

View File

@ -14,6 +14,7 @@ using namespace QGBA;
ShortcutController::ShortcutController(QObject* parent) ShortcutController::ShortcutController(QObject* parent)
: QAbstractItemModel(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()) { if (role != Qt::DisplayRole || !index.isValid()) {
return QVariant(); return QVariant();
} }
const QModelIndex& parent = index.parent(); int row = index.row();
if (parent.isValid()) { const ShortcutItem* item = static_cast<const ShortcutItem*>(index.internalPointer());
const ShortcutMenu& menu = m_menus[parent.row()]; switch (index.column()) {
const ShortcutItem& item = menu.shortcuts()[index.row()]; case 0:
switch (index.column()) { return item->visibleName();
case 0: case 1:
return item.visibleName(); if (item->action()) {
case 1: return item->action()->shortcut().toString(QKeySequence::NativeText);
return item.action()->shortcut().toString(QKeySequence::NativeText);
case 2:
if (item.button() >= 0) {
return item.button();
}
return QVariant();
} }
} else if (index.column() == 0) { break;
return m_menus[index.row()].visibleName(); case 2:
if (item->button() >= 0) {
return item->button();
}
break;
} }
return QVariant(); return QVariant();
} }
@ -60,20 +59,22 @@ QVariant ShortcutController::headerData(int section, Qt::Orientation orientation
} }
QModelIndex ShortcutController::index(int row, int column, const QModelIndex& parent) const { QModelIndex ShortcutController::index(int row, int column, const QModelIndex& parent) const {
if (!parent.isValid()) { const ShortcutItem* pmenu = &m_rootMenu;
return createIndex(row, column, -1); 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 { QModelIndex ShortcutController::parent(const QModelIndex& index) const {
if (!index.isValid()) { if (!index.isValid() || !index.internalPointer()) {
return QModelIndex(); return QModelIndex();
} }
if (index.internalId() == -1) { ShortcutItem* item = static_cast<ShortcutItem*>(index.internalPointer());
if (!item->parent() || !item->parent()->parent()) {
return QModelIndex(); 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 { int ShortcutController::columnCount(const QModelIndex& index) const {
@ -81,58 +82,67 @@ int ShortcutController::columnCount(const QModelIndex& index) const {
} }
int ShortcutController::rowCount(const QModelIndex& index) const { int ShortcutController::rowCount(const QModelIndex& index) const {
if (index.parent().isValid()) { if (!index.isValid()) {
return 0; return m_rootMenu.items().count();
} }
if (index.isValid()) { const ShortcutItem* item = static_cast<const ShortcutItem*>(index.internalPointer());
return m_menus[index.row()].shortcuts().count(); return item->items().count();
}
return m_menus.count();
} }
void ShortcutController::addAction(QMenu* menu, QAction* action, const QString& name) { void ShortcutController::addAction(QMenu* menu, QAction* action, const QString& name) {
ShortcutMenu* smenu = nullptr; ShortcutItem* smenu = m_menuMap[menu];
int row = 0;
for (auto iter = m_menus.end(); iter-- != m_menus.begin(); ++row) {
if (iter->menu() == menu) {
smenu = &(*iter);
break;
}
}
if (!smenu) { if (!smenu) {
return; return;
} }
QModelIndex parent = createIndex(row, 0, -1); ShortcutItem* pmenu = smenu->parent();
beginInsertRows(parent, smenu->shortcuts().count(), smenu->shortcuts().count()); int row = pmenu->items().indexOf(*smenu);
QModelIndex parent = createIndex(row, 0, smenu);
beginInsertRows(parent, smenu->items().count(), smenu->items().count());
smenu->addAction(action, name); smenu->addAction(action, name);
endInsertRows(); 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) { void ShortcutController::addMenu(QMenu* menu, QMenu* parentMenu) {
beginInsertRows(QModelIndex(), m_menus.count(), m_menus.count()); ShortcutItem* smenu = m_menuMap[parentMenu];
m_menus.append(ShortcutMenu(menu)); 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(); 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()) { if (!index.isValid()) {
return nullptr; return nullptr;
} }
const QModelIndex& parent = index.parent(); return static_cast<ShortcutItem*>(index.internalPointer());
if (!parent.isValid()) { }
const ShortcutController::ShortcutItem* ShortcutController::itemAt(const QModelIndex& index) const {
if (!index.isValid()) {
return nullptr; return nullptr;
} }
if (parent.row() > m_menus.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; return nullptr;
} }
const ShortcutMenu& menu = m_menus[parent.row()]; return item->action();
if (index.row() > menu.shortcuts().count()) {
return nullptr;
}
const ShortcutItem& item = menu.shortcuts()[index.row()];
return item.action();
} }
void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence& keySequence) { void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence& keySequence) {
@ -143,10 +153,9 @@ void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence&
if (!parent.isValid()) { if (!parent.isValid()) {
return; return;
} }
ShortcutMenu& menu = m_menus[parent.row()]; ShortcutItem* item = itemAt(index);
ShortcutItem& item = menu.shortcuts()[index.row()]; item->action()->setShortcut(keySequence);
item.action()->setShortcut(keySequence); emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), 2, index.internalPointer()));
emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId()));
} }
void ShortcutController::updateButton(const QModelIndex& index, int button) { void ShortcutController::updateButton(const QModelIndex& index, int button) {
@ -157,15 +166,14 @@ void ShortcutController::updateButton(const QModelIndex& index, int button) {
if (!parent.isValid()) { if (!parent.isValid()) {
return; return;
} }
ShortcutMenu& menu = m_menus[parent.row()]; ShortcutItem* item = itemAt(index);
ShortcutItem& item = menu.shortcuts()[index.row()]; int oldButton = item->button();
int oldButton = item.button(); item->setButton(button);
item.setButton(button);
if (oldButton >= 0) { if (oldButton >= 0) {
m_buttons.take(oldButton); m_buttons.take(oldButton);
} }
m_buttons[button] = &item; m_buttons[button] = item;
emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId())); emit dataChanged(createIndex(index.row(), 0, index.internalPointer()), createIndex(index.row(), 2, index.internalPointer()));
} }
bool ShortcutController::eventFilter(QObject*, QEvent* event) { bool ShortcutController::eventFilter(QObject*, QEvent* event) {
@ -184,24 +192,35 @@ bool ShortcutController::eventFilter(QObject*, QEvent* event) {
return false; return false;
} }
ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name) ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name, ShortcutItem* parent)
: m_action(action) : m_action(action)
, m_menu(nullptr)
, m_name(name) , m_name(name)
, m_button(-1) , m_button(-1)
, m_parent(parent)
{ {
m_visibleName = action->text() m_visibleName = action->text()
.remove(QRegExp("&(?!&)")) .remove(QRegExp("&(?!&)"))
.remove("..."); .remove("...");
} }
ShortcutController::ShortcutMenu::ShortcutMenu(QMenu* menu) ShortcutController::ShortcutItem::ShortcutItem(QMenu* menu, ShortcutItem* parent)
: m_menu(menu) : m_action(nullptr)
, m_menu(menu)
, m_button(-1)
, m_parent(parent)
{ {
m_visibleName = menu->title() if (menu) {
.remove(QRegExp("&(?!&)")) m_visibleName = menu->title()
.remove("..."); .remove(QRegExp("&(?!&)"))
.remove("...");
}
} }
void ShortcutController::ShortcutMenu::addAction(QAction* action, const QString& name) { void ShortcutController::ShortcutItem::addAction(QAction* action, const QString& name) {
m_shortcuts.append(ShortcutItem(action, name)); m_items.append(ShortcutItem(action, name, this));
}
void ShortcutController::ShortcutItem::addSubmenu(QMenu* menu) {
m_items.append(ShortcutItem(menu, this));
} }

View File

@ -17,6 +17,39 @@ namespace QGBA {
class ShortcutController : public QAbstractItemModel { class ShortcutController : public QAbstractItemModel {
Q_OBJECT 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: public:
ShortcutController(QObject* parent = nullptr); ShortcutController(QObject* parent = nullptr);
@ -30,9 +63,12 @@ public:
virtual int rowCount(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 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; const QAction* actionAt(const QModelIndex& index) const;
void updateKey(const QModelIndex& index, const QKeySequence& keySequence); void updateKey(const QModelIndex& index, const QKeySequence& keySequence);
void updateButton(const QModelIndex& index, int button); void updateButton(const QModelIndex& index, int button);
@ -40,42 +76,8 @@ protected:
bool eventFilter(QObject*, QEvent*) override; bool eventFilter(QObject*, QEvent*) override;
private: private:
class ShortcutItem { ShortcutItem m_rootMenu;
public: QMap<QMenu*, ShortcutItem*> m_menuMap;
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;
QMap<int, ShortcutItem*> m_buttons; QMap<int, ShortcutItem*> m_buttons;
}; };

View File

@ -533,13 +533,14 @@ void Window::setupMenu(QMenuBar* menubar) {
QMenu* avMenu = menubar->addMenu(tr("Audio/&Video")); QMenu* avMenu = menubar->addMenu(tr("Audio/&Video"));
m_shortcutController->addMenu(avMenu); m_shortcutController->addMenu(avMenu);
QMenu* frameMenu = avMenu->addMenu(tr("Frame size")); QMenu* frameMenu = avMenu->addMenu(tr("Frame size"));
m_shortcutController->addMenu(frameMenu, avMenu);
for (int i = 1; i <= 6; ++i) { for (int i = 1; i <= 6; ++i) {
QAction* setSize = new QAction(tr("%1x").arg(QString::number(i)), avMenu); QAction* setSize = new QAction(tr("%1x").arg(QString::number(i)), avMenu);
connect(setSize, &QAction::triggered, [this, i]() { connect(setSize, &QAction::triggered, [this, i]() {
showNormal(); showNormal();
resizeFrame(VIDEO_HORIZONTAL_PIXELS * i, VIDEO_VERTICAL_PIXELS * i); 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"); addControlledAction(frameMenu, frameMenu->addAction(tr("Fullscreen"), this, SLOT(toggleFullScreen()), QKeySequence("Ctrl+F")), "fullscreen");