mirror of https://github.com/bsnes-emu/bsnes.git
641 lines
21 KiB
C++
641 lines
21 KiB
C++
#include <nall/nall.hpp>
|
|
using namespace nall;
|
|
|
|
#include <hiro/hiro.hpp>
|
|
using namespace hiro;
|
|
|
|
#include "genius.hpp"
|
|
unique_pointer<ListWindow> listWindow;
|
|
unique_pointer<GameWindow> gameWindow;
|
|
unique_pointer<MemoryWindow> memoryWindow;
|
|
unique_pointer<OscillatorWindow> oscillatorWindow;
|
|
|
|
//
|
|
|
|
ListWindow::ListWindow() {
|
|
listWindow = this;
|
|
|
|
fileMenu.setText("File");
|
|
newAction.setText("New").onActivate([&] { newDatabase(); });
|
|
openAction.setText("Open ...").onActivate([&] {
|
|
if(auto location = BrowserDialog().setParent(*this).setFilters({"*.bml"}).openFile()) {
|
|
loadDatabase(location);
|
|
}
|
|
});
|
|
saveAction.setText("Save").onActivate([&] {
|
|
if(!location) return saveAsAction.doActivate();
|
|
saveDatabase(location);
|
|
});
|
|
saveAsAction.setText("Save As ...").onActivate([&] {
|
|
if(auto location = BrowserDialog().setParent(*this).setFilters({"*.bml"}).saveFile()) {
|
|
saveDatabase(location);
|
|
}
|
|
});
|
|
quitAction.setText("Quit").onActivate([&] { quit(); });
|
|
|
|
helpMenu.setText("Help");
|
|
aboutAction.setText("About ...").onActivate([&] {
|
|
MessageDialog().setParent(*this).setTitle("About").setText({
|
|
"genius\n",
|
|
"Author: byuu\n",
|
|
"Website: https://byuu.org/"
|
|
}).information();
|
|
});
|
|
|
|
layout.setMargin(5);
|
|
gameList.onActivate([&] { modifyButton.doActivate(); });
|
|
gameList.onChange([&] { updateWindow(); });
|
|
appendButton.setText("Append").onActivate([&] {
|
|
setEnabled(false);
|
|
gameWindow->show();
|
|
});
|
|
modifyButton.setText("Modify").onActivate([&] {
|
|
if(auto item = gameList.selected()) {
|
|
setEnabled(false);
|
|
gameWindow->show(games[item.offset()]);
|
|
}
|
|
});
|
|
removeButton.setText("Remove").onActivate([&] { removeGame(); });
|
|
|
|
onClose([&] { quit(); });
|
|
|
|
setSize({820, 600});
|
|
reloadList();
|
|
updateWindow();
|
|
setCentered();
|
|
}
|
|
|
|
auto ListWindow::quit() -> void {
|
|
if(!modified || MessageDialog().setParent(*this).setText({
|
|
"Are you sure you want to quit without saving your changes?"
|
|
}).question() == "Yes") {
|
|
Application::quit();
|
|
}
|
|
}
|
|
|
|
auto ListWindow::reloadList() -> void {
|
|
gameList.reset();
|
|
gameList.append(TableViewHeader()
|
|
.append(TableViewColumn().setText("Name").setExpandable())
|
|
.append(TableViewColumn().setText("Region"))
|
|
.append(TableViewColumn().setText("Revision"))
|
|
.append(TableViewColumn().setText("Board"))
|
|
);
|
|
for(auto& game : games) {
|
|
gameList.append(TableViewItem()
|
|
.append(TableViewCell().setText(game.name))
|
|
.append(TableViewCell().setText(game.region))
|
|
.append(TableViewCell().setText(game.revision))
|
|
.append(TableViewCell().setText(game.board))
|
|
);
|
|
}
|
|
Application::processEvents();
|
|
gameList.resizeColumns();
|
|
}
|
|
|
|
auto ListWindow::updateWindow() -> void {
|
|
modifyButton.setEnabled((bool)gameList.selected());
|
|
removeButton.setEnabled((bool)gameList.selected());
|
|
string name = Location::base(location);
|
|
if(!name) name = "(Untitled)";
|
|
setTitle({modified ? "*" : "", name, " [", games.size(), "] - genius"});
|
|
}
|
|
|
|
auto ListWindow::newDatabase() -> void {
|
|
games.reset();
|
|
modified = false;
|
|
location = "";
|
|
reloadList();
|
|
updateWindow();
|
|
}
|
|
|
|
auto ListWindow::loadDatabase(string location) -> void {
|
|
auto document = BML::unserialize(string::read(location));
|
|
|
|
games.reset();
|
|
for(auto node : document.find("game")) {
|
|
Game game;
|
|
game.sha256 = node["sha256"].text();
|
|
game.label = node["label"].text();
|
|
game.name = node["name"].text();
|
|
game.region = node["region"].text();
|
|
game.revision = node["revision"].text();
|
|
game.board = node["board"].text();
|
|
for(auto object : node["board"]) {
|
|
Component component;
|
|
if(object.name() == "memory") {
|
|
component.type = Component::Type::Memory;
|
|
component.memory.type = object["type"].text();
|
|
component.memory.size = object["size"].text();
|
|
component.memory.content = object["content"].text();
|
|
component.memory.manufacturer = object["manufacturer"].text();
|
|
component.memory.architecture = object["architecture"].text();
|
|
component.memory.identifier = object["identifier"].text();
|
|
component.memory.Volatile = (bool)object["volatile"];
|
|
}
|
|
if(object.name() == "oscillator") {
|
|
component.type = Component::Type::Oscillator;
|
|
component.oscillator.frequency = object["frequency"].text();
|
|
}
|
|
game.components.append(component);
|
|
}
|
|
game.note = node["note"].text();
|
|
games.append(game);
|
|
}
|
|
|
|
modified = false;
|
|
this->location = location;
|
|
reloadList();
|
|
updateWindow();
|
|
}
|
|
|
|
auto ListWindow::saveDatabase(string location) -> void {
|
|
file fp{location, file::mode::write};
|
|
if(!fp) return MessageDialog().setParent(*this).setText({
|
|
"Error: failed to write file.\n\n",
|
|
"Name: ", location
|
|
}).error(), void();
|
|
|
|
auto copy = games;
|
|
copy.sort([](auto x, auto y) {
|
|
return string::icompare(
|
|
{x.name, "\n", x.region, "\n", x.revision},
|
|
{y.name, "\n", y.region, "\n", y.revision}
|
|
) < 0;
|
|
});
|
|
|
|
fp.print("database\n");
|
|
fp.print(" revision: ", chrono::local::date(), "\n\n");
|
|
|
|
for(auto& game : copy) {
|
|
fp.print("game\n");
|
|
fp.print(" sha256: ", game.sha256, "\n");
|
|
if(game.label)
|
|
fp.print(" label: ", game.label, "\n");
|
|
fp.print(" name: ", game.name, "\n");
|
|
fp.print(" region: ", game.region, "\n");
|
|
fp.print(" revision: ", game.revision, "\n");
|
|
if(game.board)
|
|
fp.print(" board: ", game.board, "\n");
|
|
else if(game.components)
|
|
fp.print(" board\n");
|
|
for(auto& component : game.components) {
|
|
if(component.type == Component::Type::Memory) {
|
|
fp.print(" memory\n");
|
|
fp.print(" type: ", component.memory.type, "\n");
|
|
fp.print(" size: ", component.memory.size, "\n");
|
|
fp.print(" content: ", component.memory.content, "\n");
|
|
if(component.memory.manufacturer)
|
|
fp.print(" manufacturer: ", component.memory.manufacturer, "\n");
|
|
if(component.memory.architecture)
|
|
fp.print(" architecture: ", component.memory.architecture, "\n");
|
|
if(component.memory.identifier)
|
|
fp.print(" identifier: ", component.memory.identifier, "\n");
|
|
if(component.memory.Volatile)
|
|
fp.print(" volatile\n");
|
|
}
|
|
|
|
if(component.type == Component::Type::Oscillator) {
|
|
fp.print(" oscillator\n");
|
|
fp.print(" frequency: ", component.oscillator.frequency, "\n");
|
|
}
|
|
}
|
|
if(game.note)
|
|
fp.print(" note: ", game.note, "\n");
|
|
fp.print("\n");
|
|
}
|
|
|
|
modified = false;
|
|
this->location = location;
|
|
updateWindow();
|
|
}
|
|
|
|
auto ListWindow::appendGame(Game game) -> void {
|
|
modified = true;
|
|
auto offset = games.size();
|
|
games.append(game);
|
|
reloadList();
|
|
gameList.item(offset).setSelected().setFocused();
|
|
updateWindow();
|
|
}
|
|
|
|
auto ListWindow::modifyGame(Game game) -> void {
|
|
if(auto item = gameList.selected()) {
|
|
modified = true;
|
|
auto offset = item.offset();
|
|
games[offset] = game;
|
|
reloadList();
|
|
gameList.item(offset).setSelected().setFocused();
|
|
updateWindow();
|
|
}
|
|
}
|
|
|
|
auto ListWindow::removeGame() -> void {
|
|
if(auto item = gameList.selected()) {
|
|
if(MessageDialog().setParent(*this).setText({
|
|
"Are you sure you want to permanently remove this game?\n\n",
|
|
"Name: ", item.cell(0).text()
|
|
}).question() == "Yes") {
|
|
modified = true;
|
|
games.remove(item.offset());
|
|
reloadList();
|
|
updateWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
GameWindow::GameWindow() {
|
|
gameWindow = this;
|
|
|
|
layout.setMargin(5);
|
|
hashLabel.setText("SHA256:").setAlignment(1.0);
|
|
hashEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
|
|
regionLabel.setText("Region:").setAlignment(1.0);
|
|
regionEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
|
|
revisionLabel.setText("Revision:");
|
|
revisionEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
|
|
boardLabel.setText("Board:");
|
|
boardEdit.setFont(Font().setFamily(Font::Mono)).onChange([&] { modified = true, updateWindow(); });
|
|
nameLabel.setText("Name:").setAlignment(1.0);
|
|
nameEdit.onChange([&] { modified = true, updateWindow(); });
|
|
labelLabel.setText("Label:").setAlignment(1.0);
|
|
labelEdit.onChange([&] { modified = true, updateWindow(); });
|
|
noteLabel.setText("Note:").setAlignment(1.0);
|
|
noteEdit.onChange([&] { modified = true, updateWindow(); });
|
|
componentLabel.setText("Tree:").setAlignment({1.0, 0.0});
|
|
componentTree.onActivate([&] { modifyComponentButton.doActivate(); });
|
|
componentTree.onChange([&] { updateWindow(); });
|
|
appendMemoryButton.setText("Memory").onActivate([&] {
|
|
setEnabled(false);
|
|
memoryWindow->show();
|
|
});
|
|
appendOscillatorButton.setText("Oscillator").onActivate([&] {
|
|
setEnabled(false);
|
|
oscillatorWindow->show();
|
|
});
|
|
modifyComponentButton.setText("Modify").onActivate([&] {
|
|
if(auto item = componentTree.selected()) {
|
|
setEnabled(false);
|
|
auto path = item.path().split("/");
|
|
auto offset = path(0).natural();
|
|
Component component = game.components[offset];
|
|
if(component.type == Component::Type::Memory) {
|
|
memoryWindow->show(component.memory);
|
|
}
|
|
if(component.type == Component::Type::Oscillator) {
|
|
oscillatorWindow->show(component.oscillator);
|
|
}
|
|
}
|
|
});
|
|
removeComponentButton.setText("Remove").onActivate([&] { removeComponent(); });
|
|
acceptButton.setText("Accept").onActivate([&] { accept(); });
|
|
cancelButton.setText("Cancel").onActivate([&] { cancel(); });
|
|
|
|
onClose([&] { cancel(); });
|
|
|
|
setSize({640, 480});
|
|
setDismissable();
|
|
}
|
|
|
|
auto GameWindow::show(Game game) -> void {
|
|
this->game = game;
|
|
modified = false;
|
|
create = !game.sha256;
|
|
|
|
hashEdit.setText(game.sha256);
|
|
regionEdit.setText(game.region);
|
|
revisionEdit.setText(game.revision);
|
|
boardEdit.setText(game.board);
|
|
nameEdit.setText(game.name);
|
|
labelEdit.setText(game.label);
|
|
noteEdit.setText(game.note);
|
|
acceptButton.setText(create ? "Create" : "Apply");
|
|
|
|
reloadList();
|
|
updateWindow();
|
|
setCentered(*listWindow);
|
|
setVisible();
|
|
|
|
if(create) {
|
|
hashEdit.setFocused();
|
|
} else {
|
|
cancelButton.setFocused();
|
|
}
|
|
}
|
|
|
|
auto GameWindow::accept() -> void {
|
|
game.sha256 = hashEdit.text().strip();
|
|
game.region = regionEdit.text().strip();
|
|
game.revision = revisionEdit.text().strip();
|
|
game.board = boardEdit.text().strip();
|
|
game.name = nameEdit.text().strip();
|
|
game.label = labelEdit.text().strip();
|
|
game.note = noteEdit.text().strip();
|
|
|
|
if(create) {
|
|
listWindow->appendGame(game);
|
|
} else {
|
|
listWindow->modifyGame(game);
|
|
}
|
|
|
|
memoryWindow->setVisible(false);
|
|
setVisible(false);
|
|
listWindow->setEnabled();
|
|
listWindow->setFocused();
|
|
}
|
|
|
|
auto GameWindow::cancel() -> void {
|
|
if(!modified || MessageDialog().setParent(*this).setText({
|
|
"Are you sure you want to discard your changes to this game?"
|
|
}).question() == "Yes") {
|
|
memoryWindow->setVisible(false);
|
|
setVisible(false);
|
|
listWindow->setEnabled();
|
|
listWindow->setFocused();
|
|
}
|
|
}
|
|
|
|
auto GameWindow::reloadList() -> void {
|
|
componentTree.reset();
|
|
uint counter = 1;
|
|
for(auto& component : game.components) {
|
|
TreeViewItem item;
|
|
|
|
string index = {"[", counter++, "] "};
|
|
if(component.type == Component::Type::Memory) {
|
|
item.setText({index, "Memory"});
|
|
item.append(TreeViewItem().setText({"Type: ", component.memory.type}));
|
|
item.append(TreeViewItem().setText({"Size: ", component.memory.size}));
|
|
item.append(TreeViewItem().setText({"Content: ", component.memory.content}));
|
|
if(component.memory.manufacturer)
|
|
item.append(TreeViewItem().setText({"Manufacturer: ", component.memory.manufacturer}));
|
|
if(component.memory.architecture)
|
|
item.append(TreeViewItem().setText({"Architecture: ", component.memory.architecture}));
|
|
if(component.memory.identifier)
|
|
item.append(TreeViewItem().setText({"Identifier: ", component.memory.identifier}));
|
|
if(component.memory.Volatile)
|
|
item.append(TreeViewItem().setText({"Volatile"}));
|
|
}
|
|
|
|
if(component.type == Component::Type::Oscillator) {
|
|
item.setText({index, "Oscillator"});
|
|
item.append(TreeViewItem().setText({"Frequency: ", component.oscillator.frequency}));
|
|
}
|
|
|
|
componentTree.append(item);
|
|
}
|
|
|
|
Application::processEvents();
|
|
for(auto& item : componentTree.items()) item.setExpanded();
|
|
}
|
|
|
|
auto GameWindow::updateWindow() -> void {
|
|
bool valid = true;
|
|
bool hashValid = hashEdit.text().strip().size() == 64;
|
|
hashEdit.setEditable(!hashValid).setBackgroundColor(
|
|
!create || hashValid ? Color{192, 255, 192}
|
|
: (valid = false, Color{255, 224, 224}));
|
|
regionEdit.setBackgroundColor(regionEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
revisionEdit.setBackgroundColor(revisionEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
boardEdit.setBackgroundColor(boardEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
|
|
nameEdit.setBackgroundColor(nameEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
labelEdit.setBackgroundColor(labelEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
|
|
noteEdit.setBackgroundColor(noteEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
|
|
modifyComponentButton.setEnabled((bool)componentTree.selected());
|
|
removeComponentButton.setEnabled((bool)componentTree.selected());
|
|
acceptButton.setEnabled(valid);
|
|
setTitle({modified ? "*" : "", create ? "Add New Game" : "Modify Game Details"});
|
|
if(create && hashValid && hashEdit.focused()) regionEdit.setFocused();
|
|
}
|
|
|
|
auto GameWindow::appendComponent(Component component) -> void {
|
|
modified = true;
|
|
auto offset = game.components.size();
|
|
game.components.append(component);
|
|
reloadList();
|
|
componentTree.item(offset).setSelected().setFocused();
|
|
updateWindow();
|
|
}
|
|
|
|
auto GameWindow::modifyComponent(Component component) -> void {
|
|
if(auto item = componentTree.selected()) {
|
|
modified = true;
|
|
auto path = item.path().split("/");
|
|
auto offset = path(0).natural();
|
|
game.components[offset] = component;
|
|
reloadList();
|
|
componentTree.item(offset).setSelected().setFocused();
|
|
updateWindow();
|
|
}
|
|
}
|
|
|
|
auto GameWindow::removeComponent() -> void {
|
|
if(auto item = componentTree.selected()) {
|
|
if(MessageDialog().setParent(*this).setText({
|
|
"Are you sure you want to permanently remove this component?"
|
|
}).question() == "Yes") {
|
|
modified = true;
|
|
auto path = item.path().split("/");
|
|
auto offset = path(0).natural();
|
|
game.components.remove(offset);
|
|
reloadList();
|
|
updateWindow();
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
MemoryWindow::MemoryWindow() {
|
|
memoryWindow = this;
|
|
|
|
layout.setMargin(5);
|
|
typeLabel.setText("Type:").setAlignment(1.0);
|
|
typeEdit.append(ComboEditItem().setText("ROM"));
|
|
typeEdit.append(ComboEditItem().setText("EEPROM"));
|
|
typeEdit.append(ComboEditItem().setText("Flash"));
|
|
typeEdit.append(ComboEditItem().setText("RAM"));
|
|
typeEdit.append(ComboEditItem().setText("RTC"));
|
|
typeEdit.onChange([&] { modified = true, updateWindow(); });
|
|
sizeLabel.setText("Size:").setAlignment(1.0);
|
|
sizeEdit.onChange([&] { modified = true, updateWindow(); });
|
|
contentLabel.setText("Content:").setAlignment(1.0);
|
|
contentEdit.append(ComboEditItem().setText("Program"));
|
|
contentEdit.append(ComboEditItem().setText("Data"));
|
|
contentEdit.append(ComboEditItem().setText("Character"));
|
|
contentEdit.append(ComboEditItem().setText("Save"));
|
|
contentEdit.append(ComboEditItem().setText("Time"));
|
|
contentEdit.onChange([&] { modified = true, updateWindow(); });
|
|
manufacturerLabel.setText("Manufacturer:").setAlignment(1.0);
|
|
manufacturerEdit.onChange([&] { modified = true, updateWindow(); });
|
|
architectureLabel.setText("Architecture:").setAlignment(1.0);
|
|
architectureEdit.onChange([&] { modified = true, updateWindow(); });
|
|
identifierLabel.setText("Identifier:").setAlignment(1.0);
|
|
identifierEdit.onChange([&] { modified = true, updateWindow(); });
|
|
volatileOption.setText("Volatile").onToggle([&] { modified = true, updateWindow(); });
|
|
acceptButton.setText("Accept").onActivate([&] { accept(); });
|
|
cancelButton.setText("Cancel").onActivate([&] { cancel(); });
|
|
|
|
onClose([&] { cancel(); });
|
|
|
|
setSize({320, layout.minimumSize().height()});
|
|
setDismissable();
|
|
}
|
|
|
|
auto MemoryWindow::show(Memory memory) -> void {
|
|
this->memory = memory;
|
|
modified = false;
|
|
create = !memory.type;
|
|
|
|
typeEdit.setText(memory.type);
|
|
sizeEdit.setText(memory.size);
|
|
contentEdit.setText(memory.content);
|
|
manufacturerEdit.setText(memory.manufacturer);
|
|
architectureEdit.setText(memory.architecture);
|
|
identifierEdit.setText(memory.identifier);
|
|
volatileOption.setChecked(memory.Volatile);
|
|
|
|
updateWindow();
|
|
setCentered(*gameWindow);
|
|
setVisible();
|
|
|
|
typeEdit.setFocused();
|
|
}
|
|
|
|
auto MemoryWindow::accept() -> void {
|
|
memory.type = typeEdit.text().strip();
|
|
memory.size = sizeEdit.text().strip();
|
|
memory.content = contentEdit.text().strip();
|
|
memory.manufacturer = manufacturerEdit.text().strip();
|
|
memory.architecture = architectureEdit.text().strip();
|
|
memory.identifier = identifierEdit.text().strip();
|
|
memory.Volatile = volatileOption.checked() && (memory.type == "RAM" || memory.type == "RTC");
|
|
|
|
Component component{Component::Type::Memory};
|
|
component.memory = memory;
|
|
if(create) {
|
|
gameWindow->appendComponent(component);
|
|
} else {
|
|
gameWindow->modifyComponent(component);
|
|
}
|
|
|
|
setVisible(false);
|
|
gameWindow->setEnabled();
|
|
gameWindow->setFocused();
|
|
}
|
|
|
|
auto MemoryWindow::cancel() -> void {
|
|
if(!modified || MessageDialog().setParent(*this).setText({
|
|
"Are you sure you want to discard your changes to this memory?"
|
|
}).question() == "Yes") {
|
|
setVisible(false);
|
|
gameWindow->setEnabled();
|
|
gameWindow->setFocused();
|
|
}
|
|
}
|
|
|
|
auto MemoryWindow::updateWindow() -> void {
|
|
bool valid = true;
|
|
typeEdit.setBackgroundColor(typeEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
sizeEdit.setBackgroundColor(sizeEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
contentEdit.setBackgroundColor(contentEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
manufacturerEdit.setBackgroundColor(manufacturerEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
|
|
architectureEdit.setBackgroundColor(architectureEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
|
|
identifierEdit.setBackgroundColor(identifierEdit.text().strip() ? Color{} : (Color{255, 255, 240}));
|
|
volatileOption.setEnabled(typeEdit.text().strip() == "RAM" || typeEdit.text().strip() == "RTC");
|
|
acceptButton.setEnabled(valid);
|
|
setTitle({modified ? "*" : "", create ? "Add New Memory" : "Modify Memory Details"});
|
|
}
|
|
|
|
//
|
|
|
|
OscillatorWindow::OscillatorWindow() {
|
|
oscillatorWindow = this;
|
|
|
|
layout.setMargin(5);
|
|
frequencyLabel.setText("Frequency:").setAlignment(1.0);
|
|
frequencyEdit.onChange([&] { modified = true, updateWindow(); });
|
|
acceptButton.setText("Accept").onActivate([&] { accept(); });
|
|
cancelButton.setText("Cancel").onActivate([&] { cancel(); });
|
|
|
|
onClose([&] { cancel(); });
|
|
|
|
setSize({320, layout.minimumSize().height()});
|
|
setDismissable();
|
|
}
|
|
|
|
auto OscillatorWindow::show(Oscillator oscillator) -> void {
|
|
this->oscillator = oscillator;
|
|
modified = false;
|
|
create = !oscillator.frequency;
|
|
|
|
frequencyEdit.setText(oscillator.frequency);
|
|
|
|
updateWindow();
|
|
setCentered(*gameWindow);
|
|
setVisible();
|
|
|
|
frequencyEdit.setFocused();
|
|
}
|
|
|
|
auto OscillatorWindow::accept() -> void {
|
|
oscillator.frequency = frequencyEdit.text().strip();
|
|
|
|
Component component{Component::Type::Oscillator};
|
|
component.oscillator = oscillator;
|
|
if(create) {
|
|
gameWindow->appendComponent(component);
|
|
} else {
|
|
gameWindow->modifyComponent(component);
|
|
}
|
|
|
|
setVisible(false);
|
|
gameWindow->setEnabled();
|
|
gameWindow->setFocused();
|
|
}
|
|
|
|
auto OscillatorWindow::cancel() -> void {
|
|
if(!modified || MessageDialog().setParent(*this).setText({
|
|
"Are you sure you want to discard your changes to this property?"
|
|
}).question() == "Yes") {
|
|
setVisible(false);
|
|
gameWindow->setEnabled();
|
|
gameWindow->setFocused();
|
|
}
|
|
}
|
|
|
|
auto OscillatorWindow::updateWindow() -> void {
|
|
bool valid = true;
|
|
frequencyEdit.setBackgroundColor(frequencyEdit.text().strip() ? Color{} : (valid = false, Color{255, 224, 224}));
|
|
acceptButton.setEnabled(valid);
|
|
setTitle({modified ? "*" : "", create ? "Add New Property" : "Modify Property Details"});
|
|
}
|
|
|
|
//
|
|
|
|
#include <nall/main.hpp>
|
|
auto nall::main(string_vector args) -> void {
|
|
Application::setName("genius");
|
|
new ListWindow;
|
|
new GameWindow;
|
|
new MemoryWindow;
|
|
new OscillatorWindow;
|
|
|
|
//internal command used to synchronize all genius databases from an old format to a new format
|
|
//if enabled, use with extreme caution and make backups first
|
|
/*if(args.size() == 3 && args[1] == "--sync") {
|
|
for(auto& filename : directory::contents(args[2], "*.bml")) {
|
|
if(filename.beginsWith("Boards")) continue;
|
|
print(filename, "\n");
|
|
listWindow->loadDatabase({args[2], filename});
|
|
listWindow->saveDatabase({args[2], filename});
|
|
}
|
|
return print("[Done]\n");
|
|
}*/
|
|
|
|
listWindow->setVisible();
|
|
Application::run();
|
|
}
|