src/platform/qt/ShortcutController.cpp (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6#include "ShortcutController.h"
7
8#include "GamepadButtonEvent.h"
9
10#include <QAction>
11#include <QMenu>
12
13using namespace QGBA;
14
15ShortcutController::ShortcutController(QObject* parent)
16 : QAbstractItemModel(parent)
17{
18}
19
20QVariant ShortcutController::data(const QModelIndex& index, int role) const {
21 if (role != Qt::DisplayRole || !index.isValid()) {
22 return QVariant();
23 }
24 const QModelIndex& parent = index.parent();
25 if (parent.isValid()) {
26 const ShortcutMenu& menu = m_menus[parent.row()];
27 const ShortcutItem& item = menu.shortcuts()[index.row()];
28 switch (index.column()) {
29 case 0:
30 return item.visibleName();
31 case 1:
32 return item.action()->shortcut().toString(QKeySequence::NativeText);
33 case 2:
34 if (item.button() >= 0) {
35 return item.button();
36 }
37 return QVariant();
38 }
39 } else if (index.column() == 0) {
40 return m_menus[index.row()].visibleName();
41 }
42 return QVariant();
43}
44
45QVariant ShortcutController::headerData(int section, Qt::Orientation orientation, int role) const {
46 if (role != Qt::DisplayRole) {
47 return QAbstractItemModel::headerData(section, orientation, role);
48 }
49 if (orientation == Qt::Horizontal) {
50 switch (section) {
51 case 0:
52 return tr("Action");
53 case 1:
54 return tr("Keyboard");
55 case 2:
56 return tr("Gamepad");
57 }
58 }
59 return section;
60}
61
62QModelIndex ShortcutController::index(int row, int column, const QModelIndex& parent) const {
63 if (!parent.isValid()) {
64 return createIndex(row, column, -1);
65 }
66 return createIndex(row, column, parent.row());
67}
68
69QModelIndex ShortcutController::parent(const QModelIndex& index) const {
70 if (!index.isValid()) {
71 return QModelIndex();
72 }
73 if (index.internalId() == -1) {
74 return QModelIndex();
75 }
76 return createIndex(index.internalId(), 0, -1);
77}
78
79int ShortcutController::columnCount(const QModelIndex& index) const {
80 return 3;
81}
82
83int ShortcutController::rowCount(const QModelIndex& index) const {
84 if (index.parent().isValid()) {
85 return 0;
86 }
87 if (index.isValid()) {
88 return m_menus[index.row()].shortcuts().count();
89 }
90 return m_menus.count();
91}
92
93void ShortcutController::addAction(QMenu* menu, QAction* action, const QString& name) {
94 ShortcutMenu* smenu = nullptr;
95 int row = 0;
96 for (auto iter = m_menus.end(); iter-- != m_menus.begin(); ++row) {
97 if (iter->menu() == menu) {
98 smenu = &(*iter);
99 break;
100 }
101 }
102 if (!smenu) {
103 return;
104 }
105 QModelIndex parent = createIndex(row, 0, -1);
106 beginInsertRows(parent, smenu->shortcuts().count(), smenu->shortcuts().count());
107 smenu->addAction(action, name);
108 endInsertRows();
109 emit dataChanged(createIndex(smenu->shortcuts().count() - 1, 0, row), createIndex(smenu->shortcuts().count() - 1, 2, row));
110}
111
112void ShortcutController::addMenu(QMenu* menu) {
113 beginInsertRows(QModelIndex(), m_menus.count(), m_menus.count());
114 m_menus.append(ShortcutMenu(menu));
115 endInsertRows();
116 emit dataChanged(createIndex(m_menus.count() - 1, 0, -1), createIndex(m_menus.count() - 1, 0, -1));
117}
118
119const QAction* ShortcutController::actionAt(const QModelIndex& index) const {
120 if (!index.isValid()) {
121 return nullptr;
122 }
123 const QModelIndex& parent = index.parent();
124 if (!parent.isValid()) {
125 return nullptr;
126 }
127 if (parent.row() > m_menus.count()) {
128 return nullptr;
129 }
130 const ShortcutMenu& menu = m_menus[parent.row()];
131 if (index.row() > menu.shortcuts().count()) {
132 return nullptr;
133 }
134 const ShortcutItem& item = menu.shortcuts()[index.row()];
135 return item.action();
136}
137
138void ShortcutController::updateKey(const QModelIndex& index, const QKeySequence& keySequence) {
139 if (!index.isValid()) {
140 return;
141 }
142 const QModelIndex& parent = index.parent();
143 if (!parent.isValid()) {
144 return;
145 }
146 ShortcutMenu& menu = m_menus[parent.row()];
147 ShortcutItem& item = menu.shortcuts()[index.row()];
148 item.action()->setShortcut(keySequence);
149 emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId()));
150}
151
152void ShortcutController::updateButton(const QModelIndex& index, int button) {
153 if (!index.isValid()) {
154 return;
155 }
156 const QModelIndex& parent = index.parent();
157 if (!parent.isValid()) {
158 return;
159 }
160 ShortcutMenu& menu = m_menus[parent.row()];
161 ShortcutItem& item = menu.shortcuts()[index.row()];
162 int oldButton = item.button();
163 item.setButton(button);
164 if (oldButton >= 0) {
165 m_buttons.take(oldButton);
166 }
167 m_buttons[button] = &item;
168 emit dataChanged(createIndex(index.row(), 0, index.internalId()), createIndex(index.row(), 2, index.internalId()));
169}
170
171bool ShortcutController::eventFilter(QObject*, QEvent* event) {
172 if (event->type() == GamepadButtonEvent::Down()) {
173 auto item = m_buttons.find(static_cast<GamepadButtonEvent*>(event)->value());
174 if (item == m_buttons.end()) {
175 return false;
176 }
177 QAction* action = item.value()->action();
178 if (action->isEnabled()) {
179 action->trigger();
180 }
181 event->accept();
182 return true;
183 }
184 return false;
185}
186
187ShortcutController::ShortcutItem::ShortcutItem(QAction* action, const QString& name)
188 : m_action(action)
189 , m_name(name)
190 , m_button(-1)
191{
192 m_visibleName = action->text()
193 .remove(QRegExp("&(?!&)"))
194 .remove("...");
195}
196
197ShortcutController::ShortcutMenu::ShortcutMenu(QMenu* menu)
198 : m_menu(menu)
199{
200 m_visibleName = menu->title()
201 .remove(QRegExp("&(?!&)"))
202 .remove("...");
203}
204
205void ShortcutController::ShortcutMenu::addAction(QAction* action, const QString& name) {
206 m_shortcuts.append(ShortcutItem(action, name));
207}