bsnes/higan/target-bsnes/tools/cheat-editor.cpp

229 lines
6.3 KiB
C++

CheatDatabase::CheatDatabase() {
cheatDatabase = this;
layout.setMargin(5);
selectAllButton.setText("Select All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(true);
});
unselectAllButton.setText("Unselect All").onActivate([&] {
for(auto item : cheatList.items()) item.setChecked(false);
});
addCheatsButton.setText("Add Cheats").onActivate([&] {
addCheats();
});
setSize({800, 400});
setAlignment({0.5, 1.0});
setDismissable();
}
auto CheatDatabase::findCheats() -> void {
auto sha256 = emulator->sha256();
auto document = BML::unserialize(string::read(locate("cheats.bml")));
for(auto game : document.find("cartridge")) {
if(game["sha256"].text() != sha256) continue;
cheatList.reset();
for(auto cheat : game.find("cheat")) {
cheatList.append(ListViewItem()
.setCheckable()
.setText(cheat["description"].text())
.setProperty("code", cheat["code"].text())
);
}
setTitle(game["name"].text());
setVisible();
return;
}
MessageDialog().setParent(*toolsWindow).setText("Sorry, no cheats were found for this game.").information();
}
auto CheatDatabase::addCheats() -> void {
for(auto item : cheatList.items()) {
if(item.checked()) {
toolsWindow->cheatEditor.addCheat({item.text(), item.property("code"), false});
}
}
setVisible(false);
}
//
CheatWindow::CheatWindow() {
cheatWindow = this;
layout.setMargin(5);
nameLabel.setText("Name:");
nameValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); });
nameValue.onChange([&] { doChange(); });
codeLabel.setText("Code:");
codeValue.onActivate([&] { if(acceptButton.enabled()) acceptButton.doActivate(); });
codeValue.onChange([&] { doChange(); });
enableOption.setText("Enable");
acceptButton.onActivate([&] { doAccept(); });
cancelButton.setText("Cancel").onActivate([&] { setVisible(false); });
setSize({400, layout.minimumSize().height()});
setDismissable();
}
auto CheatWindow::show(Cheat cheat) -> void {
nameValue.setText(cheat.name);
codeValue.setText(cheat.code);
enableOption.setChecked(cheat.enable);
doChange();
setTitle(!cheat.name ? "Add Cheat" : "Edit Cheat");
setCentered(*toolsWindow);
setVisible();
setFocused();
nameValue.setFocused();
acceptButton.setText(!cheat.name ? "Add" : "Edit");
}
auto CheatWindow::doChange() -> void {
bool valid = true;
nameValue.setBackgroundColor(nameValue.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
codeValue.setBackgroundColor(codeValue.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
acceptButton.setEnabled(valid);
}
auto CheatWindow::doAccept() -> void {
Cheat cheat = {nameValue.text().strip(), codeValue.text().strip(), enableOption.checked()};
if(acceptButton.text() == "Add") {
toolsWindow->cheatEditor.addCheat(cheat);
} else {
toolsWindow->cheatEditor.editCheat(cheat);
}
setVisible(false);
}
//
CheatEditor::CheatEditor(TabFrame* parent) : TabFrameItem(parent) {
setIcon(Icon::Edit::Replace);
setText("Cheat Editor");
layout.setMargin(5);
cheatList.setBatchable();
cheatList.onActivate([&] {
editButton.doActivate();
});
cheatList.onChange([&] {
auto batched = cheatList.batched();
editButton.setEnabled(batched.size() == 1);
removeButton.setEnabled(batched.size() >= 1);
});
cheatList.onToggle([&](TableViewCell) {
synchronizeCodes();
});
findCheatsButton.setText("Find Cheats ...").onActivate([&] {
cheatDatabase->findCheats();
});
addButton.setText("Add").onActivate([&] {
cheatWindow->show();
});
editButton.setText("Edit").onActivate([&] {
if(auto item = cheatList.selected()) {
cheatWindow->show(cheats[item.offset()]);
}
});
removeButton.setText("Remove").onActivate([&] {
removeCheats();
});
//do not display "Find Cheats" button if there is no cheat database available
if(!file::exists(locate("cheats.bml"))) findCheatsButton.setVisible(false);
}
auto CheatEditor::refresh() -> void {
cheatList.reset();
cheatList.append(TableViewHeader().setVisible(false)
.append(TableViewColumn())
.append(TableViewColumn().setExpandable())
);
for(auto& cheat : cheats) {
cheatList.append(TableViewItem()
.append(TableViewCell().setCheckable().setChecked(cheat.enable))
.append(TableViewCell().setText(cheat.name))
);
}
cheatList.resizeColumns().doChange();
}
auto CheatEditor::addCheat(Cheat cheat) -> void {
cheats.append(cheat);
cheats.sort();
refresh();
for(uint index : range(cheats)) {
if(cheats[index] == cheat) { cheatList.item(index).setSelected(); break; }
}
cheatList.doChange();
synchronizeCodes();
}
auto CheatEditor::editCheat(Cheat cheat) -> void {
if(auto item = cheatList.selected()) {
cheats[item.offset()] = cheat;
cheats.sort();
refresh();
for(uint index : range(cheats)) {
if(cheats[index] == cheat) { cheatList.item(index).setSelected(); break; }
}
cheatList.doChange();
synchronizeCodes();
}
}
auto CheatEditor::removeCheats() -> void {
if(auto batched = cheatList.batched()) {
if(MessageDialog("Are you sure you want to permanently remove the selected cheat(s)?")
.setParent(*toolsWindow).question() == "Yes") {
for(uint index : rrange(batched)) cheats.remove(batched[index].offset());
cheats.sort();
refresh();
synchronizeCodes();
}
}
}
auto CheatEditor::loadCheats() -> void {
cheats.reset();
auto location = program->cheatPath();
auto document = BML::unserialize(string::read(location));
for(auto cheat : document.find("cheat")) {
cheats.append({cheat["name"].text(), cheat["code"].text(), (bool)cheat["enable"]});
}
cheats.sort();
refresh();
synchronizeCodes();
}
auto CheatEditor::saveCheats() -> void {
string document;
for(auto cheat : cheats) {
document.append("cheat\n");
document.append(" name: ", cheat.name, "\n");
document.append(" code: ", cheat.code, "\n");
if(cheat.enable)
document.append(" enable\n");
document.append("\n");
}
auto location = program->cheatPath();
if(document) {
file::write(location, document);
} else {
file::remove(location);
}
}
auto CheatEditor::synchronizeCodes() -> void {
string_vector codes;
for(auto& cheat : cheats) {
if(cheat.enable) codes.append(cheat.code);
}
emulator->cheatSet(codes);
}