This repository has been archived on 2022-06-22. You can view files and clone it, but cannot push or open issues or pull requests.
LaiNES/src/menu.cpp
2020-05-11 00:39:52 +09:00

152 lines
3.2 KiB
C++

#include <algorithm>
#include <dirent.h>
#include <unistd.h>
#include "cartridge.hpp"
#include "menu.hpp"
namespace GUI {
using namespace std;
Entry::Entry(string label, function<void()> callback) : callback(callback)
{
set_label(label);
}
Entry::~Entry()
{
SDL_DestroyTexture(whiteTexture);
SDL_DestroyTexture(redTexture);
}
void Entry::set_label(string label)
{
this->label = label;
if (whiteTexture != nullptr) SDL_DestroyTexture(whiteTexture);
if (redTexture != nullptr) SDL_DestroyTexture(redTexture);
whiteTexture = gen_text(label, { 255, 255, 255 });
redTexture = gen_text(label, { 255, 0, 0 });
}
void Entry::render(int x, int y) {
render_texture(selected ? redTexture : whiteTexture, x, y);
}
ControlEntry::ControlEntry(string action, SDL_Scancode* key) : key(key),
Entry::Entry(
action,
[&]{ keyEntry->set_label(SDL_GetScancodeName(*(this->key) = query_key())); })
{
this->keyEntry = new Entry(SDL_GetScancodeName(*key), []{});
}
ControlEntry::ControlEntry(string action, int* button) : button(button),
Entry::Entry(
action,
[&]{ keyEntry->set_label(to_string(*(this->button) = query_button())); })
{
this->keyEntry = new Entry(to_string(*button), []{});
}
void Menu::add(Entry* entry)
{
if (entries.empty())
entry->select();
entries.push_back(entry);
}
void Menu::clear()
{
for (auto entry : entries)
delete entry;
entries.clear();
cursor = 0;
}
void Menu::sort_by_label()
{
if (entries.empty())
return;
entries[0]->unselect();
sort(entries.begin(), entries.end(), [](Entry* a, Entry* b) {
return a->get_label() < b->get_label();
});
entries[0]->select();
}
void Menu::update(u8 const* keys)
{
int oldCursor = cursor;
if (keys[SDL_SCANCODE_DOWN] and cursor < entries.size() - 1)
{
cursor++;
if (cursor == bottom) {
bottom += 1;
top += 1;
}
}
else if (keys[SDL_SCANCODE_UP] and cursor > 0)
{
cursor--;
if (cursor < top) {
top -= 1;
bottom -= 1;
}
}
entries[oldCursor]->unselect();
entries[cursor]->select();
if (keys[SDL_SCANCODE_RETURN])
entries[cursor]->trigger();
}
void Menu::render()
{
for (int i = top; i < entries.size() && i < bottom; ++i)
{
int y = (i - top) * FONT_SZ;
entries[i]->render(TEXT_CENTER, y);
}
}
void FileMenu::change_dir(string dir)
{
clear();
struct dirent* dirp;
DIR* dp = opendir(dir.c_str());
while ((dirp = readdir(dp)) != NULL)
{
string name = dirp->d_name;
string path = dir + "/" + name;
if (name[0] == '.' and name != "..") continue;
if (dirp->d_type == DT_DIR)
add(new Entry(name + "/",
[=]{ change_dir(path); }));
else if (name.size() > 4 and name.substr(name.size() - 4) == ".nes")
add(new Entry(name,
[=]{ Cartridge::load(path.c_str()); toggle_pause(); }));
}
closedir(dp);
sort_by_label();
}
FileMenu::FileMenu()
{
char cwd[512];
change_dir(getcwd(cwd, 512));
}
}