all repos — mgba @ 74ac89a584b068b9d9c02e5117eddbe6da22d9c5

mGBA Game Boy Advance Emulator

src/platform/qt/LoadSaveState.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 "LoadSaveState.h"
  7
  8#include "GameController.h"
  9#include "GamepadAxisEvent.h"
 10#include "GamepadButtonEvent.h"
 11#include "VFileDevice.h"
 12
 13#include <QKeyEvent>
 14#include <QPainter>
 15
 16extern "C" {
 17#include "gba/serialize.h"
 18#include "gba/video.h"
 19}
 20
 21using namespace QGBA;
 22
 23LoadSaveState::LoadSaveState(GameController* controller, QWidget* parent)
 24	: QWidget(parent)
 25	, m_controller(controller)
 26	, m_currentFocus(0)
 27	, m_mode(LoadSave::LOAD)
 28{
 29	m_ui.setupUi(this);
 30
 31	m_slots[0] = m_ui.state1;
 32	m_slots[1] = m_ui.state2;
 33	m_slots[2] = m_ui.state3;
 34	m_slots[3] = m_ui.state4;
 35	m_slots[4] = m_ui.state5;
 36	m_slots[5] = m_ui.state6;
 37	m_slots[6] = m_ui.state7;
 38	m_slots[7] = m_ui.state8;
 39	m_slots[8] = m_ui.state9;
 40
 41	int i;
 42	for (i = 0; i < NUM_SLOTS; ++i) {
 43		loadState(i + 1);
 44		m_slots[i]->installEventFilter(this);
 45		connect(m_slots[i], &QAbstractButton::clicked, this, [this, i]() { triggerState(i + 1); });
 46	}
 47
 48	QAction* escape = new QAction(this);
 49	escape->connect(escape, SIGNAL(triggered()), this, SLOT(close()));
 50	escape->setShortcut(QKeySequence("Esc"));
 51	escape->setShortcutContext(Qt::WidgetWithChildrenShortcut);
 52	addAction(escape);
 53}
 54
 55void LoadSaveState::setMode(LoadSave mode) {
 56	m_mode = mode;
 57	QString text = mode == LoadSave::LOAD ? tr("Load State") : tr("Save State");
 58	setWindowTitle(text);
 59	m_ui.lsLabel->setText(text);
 60}
 61
 62bool LoadSaveState::eventFilter(QObject* object, QEvent* event) {
 63	if (event->type() == QEvent::KeyPress) {
 64		int column = m_currentFocus % 3;
 65		int row = m_currentFocus / 3;
 66		switch (static_cast<QKeyEvent*>(event)->key()) {
 67		case Qt::Key_Up:
 68			row += 2;
 69			break;
 70		case Qt::Key_Down:
 71			row += 1;
 72			break;
 73		case Qt::Key_Left:
 74			column += 2;
 75			break;
 76		case Qt::Key_Right:
 77			column += 1;
 78			break;
 79		case Qt::Key_1:
 80		case Qt::Key_2:
 81		case Qt::Key_3:
 82		case Qt::Key_4:
 83		case Qt::Key_5:
 84		case Qt::Key_6:
 85		case Qt::Key_7:
 86		case Qt::Key_8:
 87		case Qt::Key_9:
 88			triggerState(static_cast<QKeyEvent*>(event)->key() - Qt::Key_1 + 1);
 89			break;
 90		case Qt::Key_Enter:
 91		case Qt::Key_Return:
 92			triggerState(m_currentFocus + 1);
 93			break;
 94		default:
 95			return false;
 96		}
 97		column %= 3;
 98		row %= 3;
 99		m_currentFocus = column + row * 3;
100		m_slots[m_currentFocus]->setFocus();
101		return true;
102	}
103	if (event->type() == QEvent::Enter) {
104		int i;
105		for (i = 0; i < 9; ++i) {
106			if (m_slots[i] == object) {
107				m_currentFocus = i;
108				m_slots[m_currentFocus]->setFocus();
109				return true;
110			}
111		}
112	}
113	if (event->type() == GamepadButtonEvent::Down() || event->type() == GamepadAxisEvent::Type()) {
114		int column = m_currentFocus % 3;
115		int row = m_currentFocus - column;
116		GBAKey key = GBA_KEY_NONE;
117		if (event->type() == GamepadButtonEvent::Down()) {
118			key = static_cast<GamepadButtonEvent*>(event)->gbaKey();
119		} else if (event->type() == GamepadAxisEvent::Type()) {
120			GamepadAxisEvent* gae = static_cast<GamepadAxisEvent*>(event);
121			if (gae->isNew()) {
122				key = gae->gbaKey();
123			} else {
124				return false;
125			}
126		}
127		switch (key) {
128		case GBA_KEY_UP:
129			row += 6;
130			break;
131		case GBA_KEY_DOWN:
132			row += 3;
133			break;
134		case GBA_KEY_LEFT:
135			column += 2;
136			break;
137		case GBA_KEY_RIGHT:
138			column += 1;
139			break;
140		case GBA_KEY_B:
141			event->accept();
142			close();
143			return true;
144		case GBA_KEY_A:
145		case GBA_KEY_START:
146			event->accept();
147			triggerState(m_currentFocus + 1);
148			return true;
149		default:
150			return false;
151		}
152		column %= 3;
153		row %= 9;
154		m_currentFocus = column + row;
155		m_slots[m_currentFocus]->setFocus();
156		event->accept();
157		return true;
158	}
159	return false;
160}
161
162void LoadSaveState::loadState(int slot) {
163	GBAThread* thread = m_controller->thread();
164	VFile* vf = GBAGetState(thread->gba, thread->stateDir, slot, false);
165	if (!vf) {
166		m_slots[slot - 1]->setText(tr("Empty"));
167		return;
168	}
169	VFileDevice vdev(vf);
170	QImage stateImage;
171	stateImage.load(&vdev, "PNG");
172	if (!stateImage.isNull()) {
173		QPixmap statePixmap;
174		statePixmap.convertFromImage(stateImage);
175		m_slots[slot - 1]->setIcon(statePixmap);
176		m_slots[slot - 1]->setText(QString());
177	} else {
178		m_slots[slot - 1]->setText(tr("Slot %1").arg(slot));
179	}
180}
181
182void LoadSaveState::triggerState(int slot) {
183	if (m_mode == LoadSave::SAVE) {
184		m_controller->saveState(slot);
185	} else {
186		m_controller->loadState(slot);
187	}
188	close();
189}
190
191void LoadSaveState::closeEvent(QCloseEvent* event) {
192	emit closed();
193	QWidget::closeEvent(event);
194}
195
196void LoadSaveState::showEvent(QShowEvent* event) {
197	m_slots[m_currentFocus]->setFocus();
198	QWidget::showEvent(event);
199}
200
201void LoadSaveState::paintEvent(QPaintEvent*) {
202	QPainter painter(this);
203	QRect full(QPoint(), size());
204	painter.drawPixmap(full, m_currentImage);
205	painter.fillRect(full, QColor(0, 0, 0, 128));
206}