all repos — mgba @ 6b84383d1ad29d9dd39a62a80c1c8c5878979f45

mGBA Game Boy Advance Emulator

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}