Implement main menu and layout switching in TUI; add components for applying BPS patches, loading ROMs, and palette editing
This commit is contained in:
215
src/cli/tui.cc
215
src/cli/tui.cc
@@ -11,51 +11,65 @@ namespace cli {
|
|||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
bool HandleInput(ftxui::Event &event, int &selected) {
|
void SwitchComponents(ftxui::ScreenInteractive &screen, LayoutID layout) {
|
||||||
|
app_context.current_layout = layout;
|
||||||
|
screen.ExitLoopClosure()();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HandleInput(ftxui::ScreenInteractive &screen, ftxui::Event &event,
|
||||||
|
int &selected) {
|
||||||
if (event == Event::ArrowDown || event == Event::Character('j')) {
|
if (event == Event::ArrowDown || event == Event::Character('j')) {
|
||||||
selected++;
|
selected++;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (event == Event::ArrowUp || event == Event::Character('k')) {
|
if (event == Event::ArrowUp || event == Event::Character('k')) {
|
||||||
if (selected != 0)
|
if (selected != 0) selected--;
|
||||||
selected--;
|
return true;
|
||||||
|
}
|
||||||
|
if (event == Event::Character('q')) {
|
||||||
|
SwitchComponents(screen, LayoutID::kExit);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} // namespace
|
|
||||||
|
|
||||||
void ShowMain() {
|
void MainMenuComponent(ftxui::ScreenInteractive &screen) {
|
||||||
Context context;
|
// Tracks which menu item is selected.
|
||||||
|
static int selected = 0;
|
||||||
std::vector<std::string> entries = {
|
|
||||||
"Palette Editor", "Tile Editor", "Sprite Editor", "Map Editor", "Exit",
|
|
||||||
};
|
|
||||||
int selected = 0;
|
|
||||||
|
|
||||||
|
// Create menu.
|
||||||
MenuOption option;
|
MenuOption option;
|
||||||
auto menu = Menu(&entries, &selected, option);
|
auto menu = Menu(&kMainMenuEntries, &selected, option);
|
||||||
menu = CatchEvent(
|
menu = CatchEvent(
|
||||||
menu, [&selected](Event event) { return HandleInput(event, selected); });
|
menu, [&](Event event) { return HandleInput(screen, event, selected); });
|
||||||
|
|
||||||
auto layout = Container::Vertical({
|
// This renderer displays the menu vertically.
|
||||||
menu,
|
auto renderer = Renderer(menu, [&] {
|
||||||
});
|
|
||||||
auto main_component = Renderer(layout, [&] {
|
|
||||||
return vbox({
|
return vbox({
|
||||||
|
text("The Legend of Zelda: A Link to the Past") | center |
|
||||||
|
color(Color::Blue),
|
||||||
|
separator(),
|
||||||
menu->Render(),
|
menu->Render(),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
auto screen = ScreenInteractive::FitComponent();
|
|
||||||
|
|
||||||
// Exit the loop when "Exit" is selected
|
// Catch events like pressing Enter to switch layout or pressing 'q' to exit.
|
||||||
main_component = CatchEvent(main_component, [&](Event event) {
|
auto main_component = CatchEvent(renderer, [&](Event event) {
|
||||||
if (event == Event::Return && selected == 4) {
|
if (event == Event::Return) {
|
||||||
screen.ExitLoopClosure()();
|
if (selected == (int)MainMenuEntry::kApplyBpsPatch) {
|
||||||
return true;
|
SwitchComponents(screen, LayoutID::kApplyBpsPatch);
|
||||||
|
return true;
|
||||||
|
} else if (selected == (int)MainMenuEntry::kPaletteEditor) {
|
||||||
|
SwitchComponents(screen, LayoutID::kPaletteEditor);
|
||||||
|
return true;
|
||||||
|
} else if (selected == (int)MainMenuEntry::kExit) {
|
||||||
|
SwitchComponents(screen, LayoutID::kExit);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (event == Event::Character('q')) {
|
if (event == Event::Character('q')) {
|
||||||
screen.ExitLoopClosure()();
|
SwitchComponents(screen, LayoutID::kExit);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@@ -64,7 +78,154 @@ void ShowMain() {
|
|||||||
screen.Loop(main_component);
|
screen.Loop(main_component);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DrawPaletteEditor(Rom *rom) { auto palette_groups = rom->palette_group(); }
|
void ApplyBpsPatchComponent(ftxui::ScreenInteractive &screen) {
|
||||||
|
// Text inputs for user to enter file paths (or any relevant data).
|
||||||
|
static std::string patch_file;
|
||||||
|
static std::string base_file;
|
||||||
|
|
||||||
} // namespace cli
|
auto patch_file_input = Input(&patch_file, "Patch file path");
|
||||||
} // namespace yaze
|
auto base_file_input = Input(&base_file, "Base file path");
|
||||||
|
|
||||||
|
// Button to apply the patch.
|
||||||
|
auto apply_button = Button("Apply Patch", [&] {
|
||||||
|
// Once the file paths are entered by the user,
|
||||||
|
// you can load the files and apply the BPS patch here.
|
||||||
|
|
||||||
|
// ...
|
||||||
|
// Load or open patch_file
|
||||||
|
// Load or open base_file
|
||||||
|
// >>>> Place your BPS patching code here <<<<
|
||||||
|
// ...
|
||||||
|
|
||||||
|
// After applying, you could either stay here or return to main menu.
|
||||||
|
});
|
||||||
|
|
||||||
|
// Button to return to main menu without applying.
|
||||||
|
auto return_button = Button("Back to Main Menu", [&] {
|
||||||
|
SwitchComponents(screen, LayoutID::kMainMenu);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Layout components vertically.
|
||||||
|
auto container = Container::Vertical({
|
||||||
|
patch_file_input,
|
||||||
|
base_file_input,
|
||||||
|
apply_button,
|
||||||
|
return_button,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto renderer = Renderer(container, [&] {
|
||||||
|
return vbox({text("Apply BPS Patch") | center, separator(),
|
||||||
|
text("Enter Patch File:"), patch_file_input->Render(),
|
||||||
|
text("Enter Base File:"), base_file_input->Render(),
|
||||||
|
separator(),
|
||||||
|
hbox({
|
||||||
|
apply_button->Render() | center,
|
||||||
|
separator(),
|
||||||
|
return_button->Render() | center,
|
||||||
|
}) | center}) |
|
||||||
|
center;
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.Loop(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LoadRomComponent(ftxui::ScreenInteractive &screen) {
|
||||||
|
static std::string rom_file;
|
||||||
|
auto rom_file_input = Input(&rom_file, "ROM file path");
|
||||||
|
|
||||||
|
auto load_button = Button("Load ROM", [&] {
|
||||||
|
// Load the ROM file here.
|
||||||
|
auto rom_status = app_context.rom.LoadFromFile(rom_file);
|
||||||
|
if (!rom_status.ok()) {
|
||||||
|
app_context.error_message = rom_status.message();
|
||||||
|
SwitchComponents(screen, LayoutID::kError);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// If the ROM is loaded successfully, switch to the main menu.
|
||||||
|
SwitchComponents(screen, LayoutID::kMainMenu);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto back_button =
|
||||||
|
Button("Back", [&] { SwitchComponents(screen, LayoutID::kMainMenu); });
|
||||||
|
|
||||||
|
auto container = Container::Vertical({
|
||||||
|
rom_file_input,
|
||||||
|
load_button,
|
||||||
|
back_button,
|
||||||
|
});
|
||||||
|
|
||||||
|
auto renderer = Renderer(container, [&] {
|
||||||
|
return vbox({text("Load ROM") | center, separator(),
|
||||||
|
text("Enter ROM File:"), rom_file_input->Render(), separator(),
|
||||||
|
hbox({
|
||||||
|
load_button->Render() | center,
|
||||||
|
separator(),
|
||||||
|
back_button->Render() | center,
|
||||||
|
}) | center}) |
|
||||||
|
center;
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.Loop(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PaletteEditorComponent(ftxui::ScreenInteractive &screen) {
|
||||||
|
// Replace with actual data or inputs relevant to the palette editor.
|
||||||
|
auto back_button =
|
||||||
|
Button("Back", [&] { app_context.current_layout = LayoutID::kMainMenu; });
|
||||||
|
|
||||||
|
auto renderer = Renderer(back_button, [&] {
|
||||||
|
return vbox({text("Palette Editor") | center, separator(),
|
||||||
|
text("Implement your palette editing interface here."),
|
||||||
|
separator(), back_button->Render() | center}) |
|
||||||
|
center;
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.Loop(renderer);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void ShowMain() {
|
||||||
|
auto screen = ScreenInteractive::FitComponent();
|
||||||
|
while (true) {
|
||||||
|
switch (app_context.current_layout) {
|
||||||
|
case LayoutID::kMainMenu: {
|
||||||
|
MainMenuComponent(screen);
|
||||||
|
} break;
|
||||||
|
case LayoutID::kApplyBpsPatch: {
|
||||||
|
ApplyBpsPatchComponent(screen);
|
||||||
|
} break;
|
||||||
|
case LayoutID::kPaletteEditor: {
|
||||||
|
PaletteEditorComponent(screen);
|
||||||
|
} break;
|
||||||
|
case LayoutID::kGenerateSaveFile: {
|
||||||
|
// Implement the save file generation interface here.
|
||||||
|
} break;
|
||||||
|
case LayoutID::kLoadRom: {
|
||||||
|
LoadRomComponent(screen);
|
||||||
|
} break;
|
||||||
|
case LayoutID::kError: {
|
||||||
|
// Display error message and return to main menu.
|
||||||
|
auto error_button = Button("Back to Main Menu", [&] {
|
||||||
|
app_context.error_message.clear();
|
||||||
|
SwitchComponents(screen, LayoutID::kMainMenu);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto error_renderer = Renderer(error_button, [&] {
|
||||||
|
return vbox({text("Error") | center, separator(),
|
||||||
|
text(app_context.error_message), separator(),
|
||||||
|
error_button->Render() | center}) |
|
||||||
|
center;
|
||||||
|
});
|
||||||
|
|
||||||
|
screen.Loop(error_renderer);
|
||||||
|
} break;
|
||||||
|
case LayoutID::kExit:
|
||||||
|
default:
|
||||||
|
return; // Exit the application.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cli
|
||||||
|
} // namespace yaze
|
||||||
|
|||||||
@@ -4,22 +4,49 @@
|
|||||||
#include <ftxui/component/component.hpp>
|
#include <ftxui/component/component.hpp>
|
||||||
#include <ftxui/dom/elements.hpp>
|
#include <ftxui/dom/elements.hpp>
|
||||||
#include <ftxui/screen/screen.hpp>
|
#include <ftxui/screen/screen.hpp>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "app/rom.h"
|
#include "app/rom.h"
|
||||||
|
|
||||||
namespace yaze {
|
namespace yaze {
|
||||||
namespace cli {
|
namespace cli {
|
||||||
|
|
||||||
struct Context {
|
const std::vector<std::string> kMainMenuEntries = {
|
||||||
bool is_loaded = false;
|
"Apply BPS Patch",
|
||||||
|
"Generate Save File",
|
||||||
ftxui::Component layout;
|
"Load ROM",
|
||||||
ftxui::Component main_component;
|
"Palette Editor",
|
||||||
|
"Exit",
|
||||||
};
|
};
|
||||||
|
|
||||||
void ShowMain();
|
enum class MainMenuEntry {
|
||||||
|
kApplyBpsPatch,
|
||||||
|
kGenerateSaveFile,
|
||||||
|
kLoadRom,
|
||||||
|
kPaletteEditor,
|
||||||
|
kExit,
|
||||||
|
};
|
||||||
|
|
||||||
void DrawPaletteEditor(Rom *rom);
|
enum LayoutID {
|
||||||
|
kApplyBpsPatch,
|
||||||
|
kGenerateSaveFile,
|
||||||
|
kLoadRom,
|
||||||
|
kPaletteEditor,
|
||||||
|
kExit,
|
||||||
|
kMainMenu,
|
||||||
|
kError,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Context {
|
||||||
|
Rom rom;
|
||||||
|
LayoutID current_layout = LayoutID::kMainMenu;
|
||||||
|
std::string error_message;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Context app_context;
|
||||||
|
|
||||||
|
void ShowMain();
|
||||||
|
|
||||||
} // namespace cli
|
} // namespace cli
|
||||||
} // namespace yaze
|
} // namespace yaze
|
||||||
|
|||||||
Reference in New Issue
Block a user