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