bsnes/target-ethos/general/library.cpp

299 lines
8.9 KiB
C++

LibraryManager* libraryManager = nullptr;
LibraryBrowser::LibraryBrowser(Emulator::Interface& emulator) : emulator(emulator) {
setMargin(5);
informationType.setText({
"Title:\n",
"Serial:"
});
for(auto& media : emulator.media) {
mediaMode.append(media.name);
}
unsigned height = Font::size(program->normalFont, " ").height;
append(folders, {~0, ~0}, 5);
append(informationLayout, {~0, 0});
informationLayout.append(informationType, {0, height * 2}, 5);
informationLayout.append(information, {~0, height * 2}, 5);
informationLayout.append(mediaMode, {0, 0});
folders.onActivate = {&LibraryBrowser::onActivate, this};
folders.onChange = {&LibraryBrowser::onChange, this};
mediaMode.onChange = {&LibraryBrowser::setMode, this};
}
void LibraryBrowser::onActivate() {
if(folders.selected() == false) return;
if(libraryManager->loadButton.enabled() == false) return;
unsigned selection = folders.selection();
string pathname = {this->pathname, folders.text(selection, 0), typeSuffix};
libraryManager->loaded.append(folders.text(selection, 0));
libraryManager->setInformation(false);
if(libraryManager->slotLoad == false) {
utility->loadMedia(pathname);
} else {
libraryManager->loadPathname = pathname;
libraryManager->setModal(false);
}
}
void LibraryBrowser::onChange() {
if(folders.selected() == false) return information.setText("");
string manifest = {pathname, folders.text(folders.selection(), 0), typeSuffix, "manifest.bml"};
auto document = Markup::Document(file::read(manifest));
information.setText({
document["information/title"].text(), "\n",
document["information/serial"].text()
});
}
void LibraryBrowser::refresh() {
folders.reset();
lstring pathnames = directory::ifolders(pathname, typeMask);
unsigned selection = 0;
for(auto& pathname : pathnames) {
folders.append(string{pathname}.rtrim<1>(typeSuffix));
folders.setImage(selection++, 0, {resource::game, sizeof resource::game});
}
folders.setSelection(0);
onChange();
}
void LibraryBrowser::setMode() {
config->library.mediaMode = mediaMode.selection();
auto& media = emulator.media[mediaMode.selection()];
pathname = {utility->libraryPath(), media.name, "/"};
type = media.type;
typeMask = {"*.", type};
typeSuffix = {".", type, "/"};
refresh();
folders.setFocused();
libraryManager->synchronize();
}
LibraryImport::LibraryImport() {
setMargin(5);
information.setText({
"higan manages games in a library. To play a game, you must first import the game.\n"
"After doing so, the game will appear inside your library, and can then be loaded and played."
});
importButton.setText("Import Game ...");
append(information, {~0, 0}, 5);
append(importButton, {0, 0});
importButton.onActivate = {&LibraryImport::onImportActivate, this};
}
void LibraryImport::onImportActivate() {
if(program->ananke.open() == false) {
MessageWindow().setText("ananke must be installed to use this feature").warning();
return;
}
function<string ()> browse = program->ananke.sym("ananke_browse");
if(!browse) return;
audio.clear(); //ananke's browser is modal
string pathname = browse();
pathname.rtrim<1>("/");
if(pathname.empty()) return;
//after importing game, take user to the relevant game list to show the newly imported title
string type = extension(pathname);
for(signed bootable = 1; bootable >= 0; bootable--) {
unsigned selection = 0;
for(auto& browser : libraryManager->browsers) {
unsigned mode = 0;
for(auto& media : browser->emulator.media) {
if(type == media.type && media.bootable == bootable) {
browser->mediaMode.setSelection(mode);
libraryManager->libraryFrame.setSelection(selection);
libraryManager->onChange();
//find game in list and select it
string name = notdir(nall::basename(pathname));
for(unsigned n = 0; n < browser->folders.rows(); n++) {
if(browser->folders.text(n, 0) == name) {
browser->folders.setSelection(n);
browser->onChange();
break;
}
}
return;
}
mode++;
}
selection++;
}
}
}
LibraryManager::LibraryManager() {
libraryManager = this;
setTitle("Game Library");
setGeometry({128, 128, 640, 680});
windowManager->append(this, "LibraryManager");
layout.setMargin(5);
bootstrap();
libraryFrame.append("Import");
libraryFrame.setLayout(browsers.size(), libraryImport);
loadButton.setText("Load");
unsigned height = Font::size(program->normalFont, " ").height;
append(layout);
layout.append(libraryFrame, {~0, ~0}, 5);
layout.append(informationLayout, {~0, 0});
informationLayout.append(information, {~0, height * 3}, 5);
informationLayout.append(skipButton, {80, 0}, 5);
informationLayout.append(loadButton, {80, 0});
onClose = skipButton.onActivate = [&] {
setModal(false);
setVisible(false);
};
libraryFrame.onChange = {&LibraryManager::onChange, this};
loadButton.onActivate = {&LibraryManager::onLoad, this};
//initial config value of -1 defaults to import tab on first launch of higan
if(config->library.selection < 0) config->library.selection = browsers.size();
libraryFrame.setSelection(config->library.selection);
if(libraryFrame.selection() < browsers.size()) {
browsers[libraryFrame.selection()]->mediaMode.setSelection(config->library.mediaMode);
browsers[libraryFrame.selection()]->setMode();
}
}
void LibraryManager::bootstrap() {
unsigned selection = 0;
for(auto& emulator : program->emulator) {
LibraryBrowser* browser = new LibraryBrowser(*emulator);
libraryFrame.append(emulator->information.name);
libraryFrame.setLayout(selection++, *browser);
browsers.append(browser);
}
}
string LibraryManager::load(const string& type) {
requestedLoadType = type;
unsigned selection = 0;
for(auto& browser : browsers) {
unsigned mode = 0;
for(auto& media : browser->emulator.media) {
if(type == media.type && media.bootable == false) {
libraryFrame.setSelection(selection);
browser->mediaMode.setSelection(mode);
browser->setMode();
slotLoad = true;
loadPathname = "";
show();
setModal();
slotLoad = false;
browser->mediaMode.setSelection(config->library.mediaMode = 0);
return loadPathname;
}
mode++;
}
selection++;
}
return ""; //should never occur
}
void LibraryManager::onChange() {
unsigned selection = libraryFrame.selection();
config->library.selection = selection;
if(selection < browsers.size()) {
browsers[selection]->setMode();
} else {
loadButton.setEnabled(false);
}
}
void LibraryManager::onLoad() {
unsigned selection = libraryFrame.selection();
if(selection < browsers.size()) browsers[selection]->onActivate();
}
void LibraryManager::setInformation(bool load) {
string text;
if(loaded.size() == 0) {
text = {" \nPlease select a game to load ...\n "};
} else if(loaded.size() == 1 && load == false) {
text = {" \n", loaded[0], "\n "};
} else if(loaded.size() == 1 && load == true) {
text = {loaded[0], " \nPlease select a slot game to load ...\n "};
} else if(loaded.size() == 2 && load == false) {
text = {loaded[0], "\n", loaded[1], "\n "};
} else if(loaded.size() == 2 && load == true) {
text = {loaded[0], "\n", loaded[1], "\nPlease select a slot game to load ..."};
} else if(loaded.size() == 3) {
text = {loaded[0], "\n", loaded[1], "\n", loaded[2]};
}
information.setText(text);
}
void LibraryManager::show() {
if(slotLoad == false) {
loaded.reset();
requestedLoadType.reset();
skipButton.setText("Cancel");
} else {
skipButton.setText("Skip");
}
setInformation(true);
setVisible();
setFocused();
onChange();
}
//set library to show a specific media type, and then show the library
void LibraryManager::show(const string& type) {
unsigned selection = 0;
for(auto& browser : browsers) {
unsigned mode = 0;
for(auto& media : browser->emulator.media) {
if(media.bootable && media.type == type) {
libraryFrame.setSelection(selection);
browser->mediaMode.setSelection(mode);
browser->setMode();
return show();
}
mode++;
}
selection++;
}
}
void LibraryManager::synchronize() {
if(libraryFrame.selection() < browsers.size()) {
auto& emulator = browsers[libraryFrame.selection()]->emulator;
auto& media = emulator.media[browsers[libraryFrame.selection()]->mediaMode.selection()];
if(requestedLoadType.empty()) {
loadButton.setEnabled(media.bootable);
} else {
bool enabled = (requestedLoadType == media.type);
//allow Super Game Boy to load Game Boy Color games
if(requestedLoadType == "gb" && loaded.size() == 1 && media.type == "gbc") enabled = true;
loadButton.setEnabled(enabled);
}
} else {
loadButton.setEnabled(false);
}
}