src/platform/qt/input/InputModel.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 "InputModel.h"
7
8#include "GamepadButtonEvent.h"
9#include "InputIndex.h"
10
11#include <QAction>
12#include <QKeyEvent>
13#include <QMenu>
14
15using namespace QGBA;
16
17QString InputModel::InputModelItem::visibleName() const {
18 if (item) {
19 return item->visibleName();
20 }
21 if (menu) {
22 return menu->title()
23 .remove(QRegExp("&(?!&)"))
24 .remove("...");
25 }
26 return QString();
27}
28
29InputModel::InputModel(const InputIndex& index, QObject* parent)
30 : QAbstractItemModel(parent)
31{
32 clone(index);
33}
34
35InputModel::InputModel(QObject* parent)
36 : QAbstractItemModel(parent)
37{
38}
39
40void InputModel::clone(const InputIndex& index) {
41 emit beginResetModel();
42 m_index.clone(&index);
43 m_menus.clear();
44 m_topLevelMenus.clear();
45 QList<const QMenu*> menus;
46 for (auto& item : m_index.items()) {
47 const QMenu* menu = item->menu();
48 if (!menus.contains(menu)) {
49 menus.append(menu);
50 m_menus.insert(menu);
51 }
52 }
53 for (auto& menu : menus) {
54 if (m_menus.contains(menu->parent())) {
55 m_tree[menu->parent()].append(menu);
56 } else {
57 m_topLevelMenus.append(menu);
58 }
59 }
60 for (auto& item : m_index.items()) {
61 const QMenu* menu = item->menu();
62 m_tree[menu].append(item);
63 }
64 emit endResetModel();
65}
66
67QVariant InputModel::data(const QModelIndex& index, int role) const {
68 if (role != Qt::DisplayRole || !index.isValid()) {
69 return QVariant();
70 }
71 int row = index.row();
72 const InputModelItem* item = static_cast<const InputModelItem*>(index.internalPointer());
73 switch (index.column()) {
74 case 0:
75 return item->visibleName();
76 case 1:
77 if (item->item && item->item->shortcut() > 0) {
78 return QKeySequence(item->item->shortcut()).toString(QKeySequence::NativeText);
79 }
80 break;
81 case 2:
82 if (!item->item) {
83 break;
84 }
85 if (item->item->button() >= 0) {
86 return item->item->button();
87 }
88 if (item->item->axis() >= 0) {
89 char d = '\0';
90 if (item->item->direction() == GamepadAxisEvent::POSITIVE) {
91 d = '+';
92 }
93 if (item->item->direction() == GamepadAxisEvent::NEGATIVE) {
94 d = '-';
95 }
96 return QString("%1%2").arg(d).arg(item->item->axis());
97 }
98 break;
99 }
100 return QVariant();
101}
102
103QVariant InputModel::headerData(int section, Qt::Orientation orientation, int role) const {
104 if (role != Qt::DisplayRole) {
105 return QAbstractItemModel::headerData(section, orientation, role);
106 }
107 if (orientation == Qt::Horizontal) {
108 switch (section) {
109 case 0:
110 return tr("Action");
111 case 1:
112 return tr("Keyboard");
113 case 2:
114 return tr("Gamepad");
115 }
116 }
117 return section;
118}
119
120QModelIndex InputModel::index(int row, int column, const QModelIndex& parent) const {
121 if (parent.isValid()) {
122 InputModelItem* p = static_cast<InputModelItem*>(parent.internalPointer());
123 if (row >= m_tree[p->obj].count()) {
124 return QModelIndex();
125 }
126 return createIndex(row, column, const_cast<InputModelItem*>(&m_tree[p->obj][row]));
127 }
128 if (row >= m_topLevelMenus.count()) {
129 return QModelIndex();
130 }
131 return createIndex(row, column, const_cast<InputModelItem*>(&m_topLevelMenus[row]));
132}
133
134QModelIndex InputModel::parent(const QModelIndex& index) const {
135 if (!index.isValid() || !index.internalPointer()) {
136 return QModelIndex();
137 }
138 const QObject* obj = static_cast<const InputModelItem*>(index.internalPointer())->obj;
139 if (m_menus.contains(obj->parent())) {
140 return this->index(obj->parent());
141 } else {
142 return QModelIndex();
143 }
144}
145
146QModelIndex InputModel::index(const QObject* item, int column) const {
147 if (!item) {
148 return QModelIndex();
149 }
150 const QObject* parent = item->parent();
151 if (parent && m_tree.contains(parent)) {
152 int index = m_tree[parent].indexOf(item);
153 return createIndex(index, column, const_cast<InputModelItem*>(&m_tree[parent][index]));
154 }
155 if (m_topLevelMenus.contains(item)) {
156 int index = m_topLevelMenus.indexOf(item);
157 return createIndex(index, column, const_cast<InputModelItem*>(&m_topLevelMenus[index]));
158 }
159 return QModelIndex();
160}
161
162int InputModel::columnCount(const QModelIndex& index) const {
163 return 3;
164}
165
166int InputModel::rowCount(const QModelIndex& index) const {
167 if (!index.isValid() || !index.internalPointer()) {
168 return m_topLevelMenus.count();
169 }
170 const QObject* obj = static_cast<const InputModelItem*>(index.internalPointer())->obj;
171 if (!m_tree.contains(obj)) {
172 return 0;
173 }
174 return m_tree[obj].count();
175}
176
177InputItem* InputModel::itemAt(const QModelIndex& index) {
178 if (!index.isValid() || !index.internalPointer()) {
179 return nullptr;
180 }
181 return static_cast<InputModelItem*>(index.internalPointer())->item;
182}
183
184const InputItem* InputModel::itemAt(const QModelIndex& index) const {
185 if (!index.isValid() || !index.internalPointer()) {
186 return nullptr;
187 }
188 return static_cast<const InputModelItem*>(index.internalPointer())->item;
189
190}