Skip to content

Commit a6861d8

Browse files
committed
Memcard manager undo buffer.
1 parent 31d8180 commit a6861d8

File tree

4 files changed

+91
-11
lines changed

4 files changed

+91
-11
lines changed

src/core/sio.cc

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -313,14 +313,14 @@ uint8_t PCSX::SIO::sioRead8() {
313313
case 0x0002:
314314
if (PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd1Inserted>()) {
315315
memcpy(g_mcd1Data + (m_mcdAddrLow | (m_mcdAddrHigh << 8)) * 128, &m_buffer[1], 128);
316-
SaveMcd(PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd1>().string().c_str(),
316+
saveMcd(PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd1>().string().c_str(),
317317
g_mcd1Data, (m_mcdAddrLow | (m_mcdAddrHigh << 8)) * 128, 128);
318318
}
319319
break;
320320
case 0x2002:
321321
if (PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd2Inserted>()) {
322322
memcpy(g_mcd2Data + (m_mcdAddrLow | (m_mcdAddrHigh << 8)) * 128, &m_buffer[1], 128);
323-
SaveMcd(PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd2>().string().c_str(),
323+
saveMcd(PCSX::g_emulator->settings.get<PCSX::Emulator::SettingMcd2>().string().c_str(),
324324
g_mcd2Data, (m_mcdAddrLow | (m_mcdAddrHigh << 8)) * 128, 128);
325325
}
326326
break;
@@ -439,7 +439,7 @@ void PCSX::SIO::LoadMcds(const PCSX::u8string mcd1, const PCSX::u8string mcd2) {
439439
LoadMcd(2, mcd2);
440440
}
441441

442-
void PCSX::SIO::SaveMcd(const PCSX::u8string mcd, const char *data, uint32_t adr, size_t size) {
442+
void PCSX::SIO::saveMcd(const PCSX::u8string mcd, const char *data, uint32_t adr, size_t size) {
443443
const char *fname = reinterpret_cast<const char *>(mcd.c_str());
444444
FILE *f = fopen(fname, "r+b");
445445

@@ -966,17 +966,17 @@ bool PCSX::SIO::copyMcdFile(McdBlock block) {
966966

967967
// Back up the entire memory card to a file
968968
// mcd: The memory card to back up (1 or 2)
969-
void PCSX::SIO::SaveMcd(int mcd) {
969+
void PCSX::SIO::saveMcd(int mcd) {
970970
const auto data = getMcdData(mcd);
971971
switch (mcd) {
972972
case 1: {
973973
const auto path = g_emulator->settings.get<Emulator::SettingMcd1>().string();
974-
SaveMcd(path, data, 0, MCD_SIZE);
974+
saveMcd(path, data, 0, MCD_SIZE);
975975
break;
976976
}
977977
case 2: {
978978
const auto path = g_emulator->settings.get<Emulator::SettingMcd2>().string();
979-
SaveMcd(path, data, 0, MCD_SIZE);
979+
saveMcd(path, data, 0, MCD_SIZE);
980980
break;
981981
}
982982
}

src/core/sio.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,8 @@ class SIO {
128128

129129
void LoadMcd(int mcd, const PCSX::u8string str);
130130
void LoadMcds(const PCSX::u8string mcd1, const PCSX::u8string mcd2);
131-
void SaveMcd(const PCSX::u8string mcd, const char *data, uint32_t adr, size_t size);
132-
void SaveMcd(int mcd);
131+
void saveMcd(const PCSX::u8string mcd, const char *data, uint32_t adr, size_t size);
132+
void saveMcd(int mcd);
133133
void CreateMcd(const PCSX::u8string mcd);
134134
void ConvertMcd(const PCSX::u8string mcd, const char *data);
135135

src/gui/widgets/memcard_manager.cc

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,43 @@ bool PCSX::Widgets::MemcardManager::draw(GUI* gui, const char* title) {
5454
return false;
5555
}
5656

57+
const bool undoDisabled = m_undo.size() == 0;
58+
if (undoDisabled) ImGui::BeginDisabled();
59+
bool isLatest = m_undo.size() == m_undoIndex;
60+
const bool wasLatest = isLatest;
61+
if (ImGui::SliderInt(_("Undo"), &m_undoIndex, 0, m_undo.size(), "")) {
62+
isLatest = m_undo.size() == m_undoIndex;
63+
const auto dataCard1 = g_emulator->m_sio->getMcdData(1);
64+
const auto dataCard2 = g_emulator->m_sio->getMcdData(2);
65+
if (isLatest) {
66+
std::memcpy(dataCard1, m_latest.get(), SIO::MCD_SIZE);
67+
std::memcpy(dataCard2, m_latest.get() + SIO::MCD_SIZE, SIO::MCD_SIZE);
68+
} else {
69+
if (wasLatest) {
70+
std::unique_ptr<uint8_t[]> latest(new uint8_t[SIO::MCD_SIZE * 2]);
71+
std::memcpy(latest.get(), dataCard1, SIO::MCD_SIZE);
72+
std::memcpy(latest.get() + SIO::MCD_SIZE, dataCard2, SIO::MCD_SIZE);
73+
m_latest.swap(latest);
74+
}
75+
std::memcpy(dataCard1, m_undo[m_undoIndex].second.get(), SIO::MCD_SIZE);
76+
std::memcpy(dataCard2, m_undo[m_undoIndex].second.get() + SIO::MCD_SIZE, SIO::MCD_SIZE);
77+
}
78+
g_emulator->m_sio->saveMcd(1);
79+
g_emulator->m_sio->saveMcd(2);
80+
}
81+
ImGui::TextUnformatted(_("Undo version: "));
82+
ImGui::SameLine();
83+
if (isLatest) {
84+
ImGui::TextUnformatted(_("Latest"));
85+
} else {
86+
ImGui::TextUnformatted(m_undo[m_undoIndex].first.c_str());
87+
}
88+
if (undoDisabled) ImGui::EndDisabled();
89+
if (ImGui::Button(_("Clear Undo buffer"))) {
90+
m_undo.clear();
91+
m_undoIndex = 0;
92+
}
93+
5794
// Insert or remove memory cards. Send a SIO IRQ to the emulator if this happens as well.
5895
if (ImGui::Checkbox(_("Memory Card 1 inserted"),
5996
&g_emulator->settings.get<Emulator::SettingMcd1Inserted>().value)) {
@@ -125,15 +162,29 @@ bool PCSX::Widgets::MemcardManager::draw(GUI* gui, const char* title) {
125162
// can't handle multiple buttons with the same name well
126163
auto buttonName = fmt::format(_("Erase##{}"), i);
127164
if (ImGui::SmallButton(buttonName.c_str())) {
165+
auto latest = getLatest();
128166
g_emulator->m_sio->eraseMcdFile(block);
167+
saveUndoBuffer(std::move(latest),
168+
fmt::format(_("Erased file {}({}) off card {}"), block.number,
169+
gui->hasJapanese() ? block.titleUtf8 : block.titleAscii, block.mcd));
170+
g_emulator->m_sio->saveMcd(card);
129171
}
130172
ImGui::SameLine();
131173

132174
buttonName = fmt::format(_("Copy##{}"), i);
133175
if (otherFreeSpace >= size) {
134176
if (ImGui::SmallButton(buttonName.c_str())) {
177+
auto latest = getLatest();
135178
bool success = g_emulator->m_sio->copyMcdFile(block);
136-
if (!success) gui->addNotification("Error while copying save file");
179+
if (!success) {
180+
gui->addNotification("Error while copying save file");
181+
} else {
182+
saveUndoBuffer(
183+
std::move(latest),
184+
fmt::format(_("Copied file {}({}) from card {} to card {}"), block.number,
185+
gui->hasJapanese() ? block.titleUtf8 : block.titleAscii, card, othercard));
186+
g_emulator->m_sio->saveMcd(othercard);
187+
}
137188
}
138189
} else {
139190
ImGui::BeginDisabled();
@@ -145,11 +196,18 @@ bool PCSX::Widgets::MemcardManager::draw(GUI* gui, const char* title) {
145196
buttonName = fmt::format(_("Move##{}"), i);
146197
if (otherFreeSpace >= size) {
147198
if (ImGui::SmallButton(buttonName.c_str())) {
199+
auto latest = getLatest();
148200
bool success = g_emulator->m_sio->copyMcdFile(block);
149201
if (!success) {
150202
gui->addNotification("Error while copying save file");
151203
} else {
152204
g_emulator->m_sio->eraseMcdFile(block);
205+
saveUndoBuffer(
206+
std::move(latest),
207+
fmt::format(_("Moved file {}({}) from card {} to card {}"), block.number,
208+
gui->hasJapanese() ? block.titleUtf8 : block.titleAscii, card, othercard));
209+
g_emulator->m_sio->saveMcd(1);
210+
g_emulator->m_sio->saveMcd(2);
153211
}
154212
}
155213
} else {
@@ -295,3 +353,8 @@ void PCSX::Widgets::MemcardManager::copyToClipboard(const SIO::McdBlock& block)
295353
const auto pixels = getIconRGBA8888(block);
296354
clip::set_image(pixels);
297355
}
356+
357+
void PCSX::Widgets::MemcardManager::saveUndoBuffer(std::unique_ptr<uint8_t[]>&& tosave, const std::string& action) {
358+
m_undo.resize(m_undoIndex++);
359+
m_undo.push_back({action, std::move(tosave)});
360+
}

src/gui/widgets/memcard_manager.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,11 @@
1919

2020
#pragma once
2121

22+
#include <memory>
2223
#include <string>
24+
#include <string_view>
25+
#include <utility>
26+
#include <vector>
2327

2428
#include "GL/gl3w.h"
2529
#include "clip/clip.h"
@@ -44,17 +48,30 @@ class MemcardManager {
4448

4549
private:
4650
int m_iconSize = 32; // The width and length of the icon images
47-
int m_selectedBlock;
4851
bool m_drawPocketstationIcons = false;
52+
std::vector<std::pair<std::string, std::unique_ptr<uint8_t[]>>> m_undo;
4953

50-
GLuint m_iconTextures[15];
54+
GLuint m_iconTextures[15] = {0};
5155

5256
clip::image getIconRGBA8888(const SIO::McdBlock& block);
5357

5458
void drawIcon(const SIO::McdBlock& block);
5559
void exportPNG(const SIO::McdBlock& block);
5660
void copyToClipboard(const SIO::McdBlock& block);
5761
void getPocketstationIcon(uint32_t* pixels, const SIO::McdBlock& block);
62+
63+
void saveUndoBuffer(std::unique_ptr<uint8_t[]>&& tosave, const std::string& action);
64+
65+
std::unique_ptr<uint8_t[]> getLatest() {
66+
std::unique_ptr<uint8_t[]> data(new uint8_t[SIO::MCD_SIZE * 2]);
67+
std::memcpy(data.get(), g_emulator->m_sio->getMcdData(1), SIO::MCD_SIZE);
68+
std::memcpy(data.get() + SIO::MCD_SIZE, g_emulator->m_sio->getMcdData(2), SIO::MCD_SIZE);
69+
70+
return data;
71+
}
72+
73+
int m_undoIndex = 0;
74+
std::unique_ptr<uint8_t[]> m_latest;
5875
};
5976

6077
} // namespace Widgets

0 commit comments

Comments
 (0)