all repos — mgba @ 73dd9ed3f8f5db02b18266f1373e15a652165839

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