Files
basic1/lib/game_launcher.cpp
Adolfo Reyna 38ffdac749 Add pagination to game launcher - 4 games per page
- GameLauncher now displays only 4 games per page to keep menu in bounds
- Added page navigation with page indicator (Page X/Y)
- KEY0 navigates between pages and within page
- KEY1 selects the highlighted game
- Touch selection works on current page only
- Helper methods: get_total_pages(), get_page_start_index(), get_page_end_index()
- Updated both lib/ and emulator/ versions for consistency
2026-02-12 20:39:38 -05:00

196 lines
7.0 KiB
C++

// ============================================================================
// GAME LAUNCHER IMPLEMENTATION
// ============================================================================
// Menu system for selecting and launching games
#include "game_launcher.h"
#include "input_manager.h"
#include "display/low_level_render.h"
#include "display/low_level_gui.h"
#include <stdio.h>
GameLauncher::GameLauncher(uint16_t width, uint16_t height,
LowLevelRenderer* renderer, LowLevelGUI* gui, InputManager* input_manager)
: width(width), height(height), renderer(renderer), gui(gui), input_manager(input_manager),
selected_index(0), selected_game(nullptr), current_page(0) {
}
void GameLauncher::register_game(const char* name, const char* description,
std::function<Game*(uint16_t, uint16_t, LowLevelRenderer*, LowLevelGUI*, InputManager*)> factory) {
GameEntry entry;
entry.name = name;
entry.description = description;
entry.factory = factory;
games.push_back(entry);
printf("Registered game: %s - %s\n", name, description);
}
void GameLauncher::draw() {
// Draw main window
LowLevelWindow* window = gui->draw_new_window(10, 10, width - 20, height - 20, "Game Launcher");
renderer->set_font(&font_5x5_obj);
// Draw title with page indicator
int total_pages = get_total_pages();
char title[64];
snprintf(title, sizeof(title), "Select a Game: (Page %d/%d)", current_page + 1, total_pages);
renderer->draw_string_scaled(30, 40, title, 2);
// Get games for current page
int page_start = get_page_start_index();
int page_end = get_page_end_index();
// Draw game list with GUI buttons for current page only
for (int i = page_start; i < page_end && i < (int)games.size(); i++) {
int item_index = i - page_start;
int y = MENU_Y_START + (item_index * MENU_ITEM_HEIGHT);
// Draw button (pressed/highlighted if selected)
bool is_selected = (i == selected_index);
gui->draw_button(window, 20, y, games[i].name, is_selected, true);
// Draw description below button
renderer->set_font(&font_5x5_obj); // Restore small font for description
renderer->set_text_color(true); // Normal text color
renderer->draw_string_scaled(50, y + 36, games[i].description, 1);
}
// Draw pagination controls at bottom
char nav_text[128];
if (total_pages > 1) {
snprintf(nav_text, sizeof(nav_text), "KEY0: Next Page | KEY1: Select");
} else {
snprintf(nav_text, sizeof(nav_text), "KEY0: Navigate | KEY1: Select");
}
const char* instructions;
if (input_manager->has_buttons()) {
instructions = nav_text;
} else {
instructions = "Touch game to play";
}
renderer->set_font(&font_5x5_obj);
renderer->draw_string_scaled(30, height - 35, instructions, 2);
}
bool GameLauncher::update(const InputEvent& event) {
bool needs_refresh = false;
switch (event.type) {
case INPUT_TOUCH_DOWN: {
printf("Touch at (%d,%d) in launcher\n", event.x, event.y);
// Check if touch is on a game entry for current page
int page_start = get_page_start_index();
int page_end = get_page_end_index();
for (int i = page_start; i < page_end && i < (int)games.size(); i++) {
int item_index = i - page_start;
int y = MENU_Y_START + (item_index * MENU_ITEM_HEIGHT);
// Touch area is the entire menu item
if (event.y >= y - 5 && event.y < y + MENU_ITEM_HEIGHT - 5) {
// Game selected - create instance
printf("Selected game: %s\n", games[i].name);
selected_game = games[i].factory(width, height, renderer, gui, input_manager);
if (selected_game) {
selected_game->init();
return true; // Signal game selected
}
break;
}
}
break;
}
case INPUT_BUTTON_0: {
// Navigate within current page or switch pages
int page_start = get_page_start_index();
int page_end = get_page_end_index();
int total_pages = get_total_pages();
// If multiple games on current page, navigate within page first
if (page_end - page_start > 1) {
// Move within current page
int old_index = selected_index;
selected_index++;
if (selected_index >= page_end) {
// Moving to next page
if (current_page + 1 < total_pages) {
current_page++;
selected_index = get_page_start_index();
} else {
// Wrap to first page
current_page = 0;
selected_index = 0;
}
} else if (selected_index < page_start) {
selected_index = page_start;
}
} else {
// Single game on page, move to next page
if (current_page + 1 < total_pages) {
current_page++;
selected_index = get_page_start_index();
} else {
// Wrap to first page
current_page = 0;
selected_index = 0;
}
}
needs_refresh = true;
printf("Menu selection: %d (%s), Page: %d\n", selected_index, games[selected_index].name, current_page);
break;
}
case INPUT_BUTTON_1: {
// Select current game
if (selected_index >= 0 && selected_index < (int)games.size()) {
printf("Selected game: %s\n", games[selected_index].name);
selected_game = games[selected_index].factory(width, height, renderer, gui, input_manager);
if (selected_game) {
selected_game->init();
return true; // Signal game selected
}
}
break;
}
default:
break;
}
return needs_refresh;
}
Game* GameLauncher::get_selected_game() {
return selected_game;
}
void GameLauncher::reset() {
// Clean up current game if any
if (selected_game) {
delete selected_game;
selected_game = nullptr;
}
selected_index = 0;
current_page = 0;
printf("Launcher reset - returning to menu\n");
}
int GameLauncher::get_total_pages() const {
if (games.empty()) return 1;
return (games.size() + GAMES_PER_PAGE - 1) / GAMES_PER_PAGE;
}
int GameLauncher::get_page_start_index() const {
return current_page * GAMES_PER_PAGE;
}
int GameLauncher::get_page_end_index() const {
return (current_page + 1) * GAMES_PER_PAGE;
}