all repos — mgba @ 50005e0703fe9d6827875f4b2f870895e4033d0e

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