From 6eb1a04901ceeae86dc1d8a75f470f039d6be0bb Mon Sep 17 00:00:00 2001 From: Vincent-FK Date: Sun, 15 Nov 2020 15:55:57 +0100 Subject: [PATCH] add menu Signed-off-by: Vincent-FK --- RetroFE/Source/CMakeLists.txt | 2 + RetroFE/Source/Menu/MenuMode.cpp | 861 +++++++++++++++++++++++++++++++ RetroFE/Source/Menu/MenuMode.h | 128 +++++ RetroFE/Source/RetroFE.cpp | 28 +- 4 files changed, 1017 insertions(+), 2 deletions(-) create mode 100644 RetroFE/Source/Menu/MenuMode.cpp create mode 100644 RetroFE/Source/Menu/MenuMode.h diff --git a/RetroFE/Source/CMakeLists.txt b/RetroFE/Source/CMakeLists.txt index fa98324..0333c91 100755 --- a/RetroFE/Source/CMakeLists.txt +++ b/RetroFE/Source/CMakeLists.txt @@ -153,6 +153,7 @@ set(RETROFE_HEADERS "${RETROFE_DIR}/Source/Graphics/PageBuilder.h" "${RETROFE_DIR}/Source/Graphics/Page.h" "${RETROFE_DIR}/Source/Menu/Menu.h" + "${RETROFE_DIR}/Source/Menu/MenuMode.h" "${RETROFE_DIR}/Source/Sound/Sound.h" "${RETROFE_DIR}/Source/Utility/Log.h" "${RETROFE_DIR}/Source/Utility/Utils.h" @@ -206,6 +207,7 @@ set(RETROFE_SOURCES "${RETROFE_DIR}/Source/Graphics/Component/VideoComponent.cpp" "${RETROFE_DIR}/Source/Graphics/Component/Video.cpp" "${RETROFE_DIR}/Source/Menu/Menu.cpp" + "${RETROFE_DIR}/Source/Menu/MenuMode.cpp" "${RETROFE_DIR}/Source/Sound/Sound.cpp" "${RETROFE_DIR}/Source/Utility/Log.cpp" "${RETROFE_DIR}/Source/Utility/Utils.cpp" diff --git a/RetroFE/Source/Menu/MenuMode.cpp b/RetroFE/Source/Menu/MenuMode.cpp new file mode 100644 index 0000000..c735b0e --- /dev/null +++ b/RetroFE/Source/Menu/MenuMode.cpp @@ -0,0 +1,861 @@ +#include "MenuMode.h" +#include +#include "../SDL.h" + +/// -------------- DEFINES -------------- +//#define MENU_DEBUG +#define MENU_ERROR + +#ifdef MENU_DEBUG +#define MENU_DEBUG_PRINTF(...) printf(__VA_ARGS__); +#else +#define MENU_DEBUG_PRINTF(...) +#endif //MENU_DEBUG + +#ifdef MENU_ERROR +#define MENU_ERROR_PRINTF(...) printf(__VA_ARGS__); +#else +#define MENU_ERROR_PRINTF(...) +#endif //MENU_ERROR + +#define SCREEN_HORIZONTAL_SIZE 240 //RES_HW_SCREEN_HORIZONTAL +#define SCREEN_VERTICAL_SIZE 240 //RES_HW_SCREEN_VERTICAL + +#define SCROLL_SPEED_PX 240 //This means no animations but also no tearing effect +#define FPS_MENU 30 + +#define MENU_ZONE_WIDTH SCREEN_HORIZONTAL_SIZE +#define MENU_ZONE_HEIGHT SCREEN_VERTICAL_SIZE + +#define MENU_FONT_NAME_TITLE "/usr/games/menu_resources/OpenSans-Bold.ttf" +#define MENU_FONT_SIZE_TITLE 22 +#define MENU_FONT_NAME_INFO "/usr/games/menu_resources/OpenSans-Bold.ttf" +#define MENU_FONT_SIZE_INFO 16 +#define MENU_FONT_NAME_SMALL_INFO "/usr/games/menu_resources/OpenSans-Regular.ttf" +#define MENU_FONT_SIZE_SMALL_INFO 13 +#define MENU_PNG_BG_PATH "/usr/games/menu_resources/zone_bg.png" + +#define GRAY_MAIN_R 85 +#define GRAY_MAIN_G 85 +#define GRAY_MAIN_B 85 +#define WHITE_MAIN_R 236 +#define WHITE_MAIN_G 236 +#define WHITE_MAIN_B 236 + +#define MAX_SAVE_SLOTS 9 + +#define MAXPATHLEN 512 + + +/// -------------- STATIC VARIABLES -------------- +SDL_Surface * MenuMode::backup_hw_screen = NULL; +int MenuMode::backup_key_repeat_delay=0; +int MenuMode::backup_key_repeat_interval=0; +TTF_Font *MenuMode::menu_title_font = NULL; +TTF_Font *MenuMode::menu_info_font = NULL; +TTF_Font *MenuMode::menu_small_info_font = NULL; +SDL_Surface ** MenuMode::menu_zone_surfaces = NULL; +int * MenuMode::idx_menus = NULL; +int MenuMode::nb_menu_zones = 0; +int MenuMode::stop_menu_loop = 0; + +SDL_Color MenuMode::text_color = {GRAY_MAIN_R, GRAY_MAIN_G, GRAY_MAIN_B}; +int MenuMode::padding_y_from_center_menu_zone = 18; +uint16_t MenuMode::width_progress_bar = 100; +uint16_t MenuMode::height_progress_bar = 20; +uint16_t MenuMode::x_volume_bar = 0; +uint16_t MenuMode::y_volume_bar = 0; +uint16_t MenuMode::x_brightness_bar = 0; +uint16_t MenuMode::y_brightness_bar = 0; + +int MenuMode::volume_percentage = 0; +int MenuMode::brightness_percentage = 0; + +#undef X +#define X(a, b) b, +const char *MenuMode::aspect_ratio_name[] = {ASPECT_RATIOS}; + +int MenuMode::aspect_ratio = ASPECT_RATIOS_TYPE_STRECHED; +int MenuMode::aspect_ratio_factor_percent = 50; +int MenuMode::aspect_ratio_factor_step = 10; + +int MenuMode::savestate_slot = 0; + + + +/// -------------- FUNCTIONS IMPLEMENTATION -------------- +void MenuMode::init( ) +{ + MENU_DEBUG_PRINTF("Init MenuMode\n"); + /// ----- Loading the fonts ----- + menu_title_font = TTF_OpenFont(MENU_FONT_NAME_TITLE, MENU_FONT_SIZE_TITLE); + if(!menu_title_font){ + MENU_ERROR_PRINTF("ERROR in init_menu_SDL: Could not open menu font %s, %s\n", MENU_FONT_NAME_TITLE, SDL_GetError()); + } + menu_info_font = TTF_OpenFont(MENU_FONT_NAME_INFO, MENU_FONT_SIZE_INFO); + if(!menu_info_font){ + MENU_ERROR_PRINTF("ERROR in init_menu_SDL: Could not open menu font %s, %s\n", MENU_FONT_NAME_INFO, SDL_GetError()); + } + menu_small_info_font = TTF_OpenFont(MENU_FONT_NAME_SMALL_INFO, MENU_FONT_SIZE_SMALL_INFO); + if(!menu_small_info_font){ + MENU_ERROR_PRINTF("ERROR in init_menu_SDL: Could not open menu font %s, %s\n", MENU_FONT_NAME_SMALL_INFO, SDL_GetError()); + } + + /// ----- Copy virtual_hw_screen at init ------ + SDL_Surface * virtual_hw_screen = SDL::getWindow(); + backup_hw_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, + virtual_hw_screen->w, virtual_hw_screen->h, 32, 0, 0, 0, 0); + if(backup_hw_screen == NULL){ + MENU_ERROR_PRINTF("ERROR in init_menu_SDL: Could not create backup_hw_screen: %s\n", SDL_GetError()); + } + + + /// ------ Save prev key repeat params and set new Key repeat ------- + SDL_GetKeyRepeat(&backup_key_repeat_delay, &backup_key_repeat_interval); + if(SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)){ + MENU_ERROR_PRINTF("ERROR with SDL_EnableKeyRepeat: %s\n", SDL_GetError()); + } + + /// ------ Init menu zones ------ + init_menu_zones(); + + return; +} + + +void MenuMode::end( ) +{ + MENU_DEBUG_PRINTF("End MenuMode \n"); + /// ------ Close font ------- + TTF_CloseFont(menu_title_font); + TTF_CloseFont(menu_info_font); + TTF_CloseFont(menu_small_info_font); + + /// ------ Free Surfaces ------- + for(int i=0; i < nb_menu_zones; i++){ + SDL_FreeSurface(menu_zone_surfaces[i]); + } + SDL_FreeSurface(backup_hw_screen); + + /// ------ reset initial key repeat values ------ + if(SDL_EnableKeyRepeat(backup_key_repeat_delay, backup_key_repeat_interval)){ + MENU_ERROR_PRINTF("ERROR with SDL_EnableKeyRepeat: %s\n", SDL_GetError()); + } + return; +} + + +void MenuMode::draw_progress_bar(SDL_Surface * surface, uint16_t x, uint16_t y, uint16_t width, + uint16_t height, uint8_t percentage, uint16_t nb_bars){ + /// ------ Init Variables ------ + uint16_t line_width = 1; //px + uint16_t padding_bars_ratio = 3; + uint16_t nb_full_bars = 0; + + /// ------ Check values ------ + percentage = (percentage > 100)?100:percentage; + x = (x > (surface->w-1))?(surface->w-1):x; + y = (y > surface->h-1)?(surface->h-1):y; + width = (width < line_width*2+1)?(line_width*2+1):width; + width = (width > surface->w-x-1)?(surface->w-x-1):width; + height = (height < line_width*2+1)?(line_width*2+1):height; + height = (height > surface->h-y-1)?(surface->h-y-1):height; + uint16_t nb_bars_max = ( width * padding_bars_ratio / (line_width*2+1) + 1 ) / (padding_bars_ratio+1); + nb_bars = (nb_bars > nb_bars_max)?nb_bars_max:nb_bars; + uint16_t bar_width = (width / nb_bars)*padding_bars_ratio/(padding_bars_ratio+1)+1; + uint16_t bar_padding_x = bar_width/padding_bars_ratio; + nb_full_bars = nb_bars*percentage/100; + + /// ------ draw full bars ------ + for (int i = 0; i < nb_full_bars; ++i) + { + /// ---- draw one bar ---- + //MENU_DEBUG_PRINTF("Drawing filled bar %d\n", i); + SDL_Rect rect = {x+ i*(bar_width +bar_padding_x), + y, bar_width, height}; + SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, GRAY_MAIN_R, GRAY_MAIN_G, GRAY_MAIN_B)); + } + + /// ------ draw full bars ------ + for (int i = 0; i < (nb_bars-nb_full_bars); ++i) + { + /// ---- draw one bar ---- + //MENU_DEBUG_PRINTF("Drawing empty bar %d\n", i); + SDL_Rect rect = {x+ i*(bar_width +bar_padding_x) + nb_full_bars*(bar_width +bar_padding_x), + y, bar_width, height}; + SDL_FillRect(surface, &rect, SDL_MapRGB(surface->format, GRAY_MAIN_R, GRAY_MAIN_G, GRAY_MAIN_B)); + + SDL_Rect rect2 = {x+ i*(bar_width +bar_padding_x) + line_width + nb_full_bars*(bar_width +bar_padding_x), + y + line_width, bar_width - line_width*2, height - line_width*2}; + SDL_FillRect(surface, &rect2, SDL_MapRGB(surface->format, WHITE_MAIN_R, WHITE_MAIN_R, WHITE_MAIN_R)); + } + + +} + + +void MenuMode::add_menu_zone(ENUM_MENU_TYPE menu_type){ + /// ------ Increase nb of menu zones ------- + nb_menu_zones++; + + /// ------ Realoc idx Menus array ------- + if(!idx_menus){ + idx_menus = (int*) malloc(nb_menu_zones*sizeof(int)); + menu_zone_surfaces = (SDL_Surface**) malloc(nb_menu_zones*sizeof(SDL_Surface*)); + } + else{ + int *temp = (int*) realloc(idx_menus, nb_menu_zones*sizeof(int)); + idx_menus = temp; + menu_zone_surfaces = (SDL_Surface**) realloc(menu_zone_surfaces, nb_menu_zones*sizeof(SDL_Surface*)); + } + idx_menus[nb_menu_zones-1] = menu_type; + + /// ------ Reinit menu surface with height increased ------- + menu_zone_surfaces[nb_menu_zones-1] = IMG_Load(MENU_PNG_BG_PATH); + if(!menu_zone_surfaces[nb_menu_zones-1]) { + MENU_ERROR_PRINTF("ERROR IMG_Load: %s\n", IMG_GetError()); + } + /// --------- Init Common Variables -------- + SDL_Surface *text_surface = NULL; + SDL_Surface *surface = menu_zone_surfaces[nb_menu_zones-1]; + SDL_Rect text_pos; + + /// --------- Add new zone --------- + switch(menu_type){ + case MENU_TYPE_VOLUME: + MENU_DEBUG_PRINTF("Init MENU_TYPE_VOLUME\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "VOLUME", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 - padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + + x_volume_bar = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - width_progress_bar)/2; + y_volume_bar = surface->h - MENU_ZONE_HEIGHT/2 - height_progress_bar/2 + padding_y_from_center_menu_zone; + draw_progress_bar(surface, x_volume_bar, y_volume_bar, + width_progress_bar, height_progress_bar, 0, 100/STEP_CHANGE_VOLUME); + break; + case MENU_TYPE_BRIGHTNESS: + MENU_DEBUG_PRINTF("Init MENU_TYPE_BRIGHTNESS\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "BRIGHTNESS", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 - padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + + x_brightness_bar = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - width_progress_bar)/2; + y_brightness_bar = surface->h - MENU_ZONE_HEIGHT/2 - height_progress_bar/2 + padding_y_from_center_menu_zone; + draw_progress_bar(surface, x_brightness_bar, y_brightness_bar, + width_progress_bar, height_progress_bar, 0, 100/STEP_CHANGE_BRIGHTNESS); + break; + case MENU_TYPE_SAVE: + MENU_DEBUG_PRINTF("Init MENU_TYPE_SAVE\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "SAVE", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 - padding_y_from_center_menu_zone*2; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + break; + case MENU_TYPE_LOAD: + MENU_DEBUG_PRINTF("Init MENU_TYPE_LOAD\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "LOAD", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 - padding_y_from_center_menu_zone*2; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + break; + case MENU_TYPE_ASPECT_RATIO: + MENU_DEBUG_PRINTF("Init MENU_TYPE_ASPECT_RATIO\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "ASPECT RATIO", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 - padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + break; + case MENU_TYPE_EXIT: + MENU_DEBUG_PRINTF("Init MENU_TYPE_EXIT\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "EXIT GAME", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + break; + case MENU_TYPE_POWERDOWN: + MENU_DEBUG_PRINTF("Init MENU_TYPE_POWERDOWN\n"); + /// ------ Text ------ + text_surface = TTF_RenderText_Blended(menu_title_font, "POWERDOWN", text_color); + text_pos.x = (surface->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = surface->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2; + SDL_BlitSurface(text_surface, NULL, surface, &text_pos); + break; + default: + MENU_DEBUG_PRINTF("Warning - In add_menu_zone, unknown MENU_TYPE: %d\n", menu_type); + break; + } + + /// ------ Free Surfaces ------- + SDL_FreeSurface(text_surface); +} + +void MenuMode::init_menu_zones(){ + /// Init Volume Menu + add_menu_zone(MENU_TYPE_VOLUME); + /// Init Brightness Menu + add_menu_zone(MENU_TYPE_BRIGHTNESS); + /// Init Save Menu + //add_menu_zone(MENU_TYPE_SAVE); + /// Init Load Menu + //add_menu_zone(MENU_TYPE_LOAD); + /// Init Aspect Ratio Menu + //add_menu_zone(MENU_TYPE_ASPECT_RATIO); + /// Init Exit Menu + //add_menu_zone(MENU_TYPE_EXIT); + /// Init Powerdown Menu + add_menu_zone(MENU_TYPE_POWERDOWN); +} + + +void MenuMode::init_menu_system_values(){ + FILE *fp; + char res[100]; + + /// ------- Get system volume percentage -------- + fp = popen(SHELL_CMD_VOLUME_GET, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", SHELL_CMD_VOLUME_GET ); + volume_percentage = 50; ///wrong value: setting default to 50 + } + else{ + fgets(res, sizeof(res)-1, fp); + + /// Check if Volume is a number (at least the first char) + if(res[0] < '0' || res[0] > '9'){ + MENU_ERROR_PRINTF("Wrong return value: %s for volume cmd: %s\n",res, SHELL_CMD_VOLUME_GET); + volume_percentage = 50; ///wrong value: setting default to 50 + } + else{ + volume_percentage = atoi(res); + MENU_DEBUG_PRINTF("System volume = %d%%\n", volume_percentage); + } + } + + /// ------- Get system brightness percentage ------- + fp = popen(SHELL_CMD_BRIGHTNESS_GET, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", SHELL_CMD_BRIGHTNESS_GET ); + brightness_percentage = 50; ///wrong value: setting default to 50 + } + else{ + fgets(res, sizeof(res)-1, fp); + + /// Check if brightness is a number (at least the first char) + if(res[0] < '0' || res[0] > '9'){ + MENU_ERROR_PRINTF("Wrong return value: %s for volume cmd: %s\n",res, SHELL_CMD_BRIGHTNESS_GET); + brightness_percentage = 50; ///wrong value: setting default to 50 + } + else{ + brightness_percentage = atoi(res); + MENU_DEBUG_PRINTF("System brightness = %d%%\n", brightness_percentage); + } + } + + /// Get save slot from game + savestate_slot = (savestate_slot%MAX_SAVE_SLOTS); // security +} + +void MenuMode::menu_screen_refresh(int menuItem, int prevItem, int scroll, uint8_t menu_confirmation, uint8_t menu_action){ + /// --------- Clear HW screen ---------- + SDL_Surface * virtual_hw_screen = SDL::getWindow(); + if(SDL_BlitSurface(backup_hw_screen, NULL, virtual_hw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not Clear virtual_hw_screen: %s\n", SDL_GetError()); + } + + /// --------- Setup Blit Window ---------- + SDL_Rect menu_blit_window; + menu_blit_window.x = 0; + menu_blit_window.w = SCREEN_HORIZONTAL_SIZE; + + /// --------- Blit prev menu Zone going away ---------- + menu_blit_window.y = scroll; + menu_blit_window.h = SCREEN_VERTICAL_SIZE; + if(SDL_BlitSurface(menu_zone_surfaces[prevItem], &menu_blit_window, virtual_hw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not Blit surface on virtual_hw_screen: %s\n", SDL_GetError()); + } + + /// --------- Blit new menu Zone going in (only during animations) ---------- + if(scroll>0){ + menu_blit_window.y = SCREEN_VERTICAL_SIZE-scroll; + menu_blit_window.h = SCREEN_VERTICAL_SIZE; + if(SDL_BlitSurface(menu_zone_surfaces[menuItem], NULL, virtual_hw_screen, &menu_blit_window)){ + MENU_ERROR_PRINTF("ERROR Could not Blit surface on virtual_hw_screen: %s\n", SDL_GetError()); + } + } + else if(scroll<0){ + menu_blit_window.y = SCREEN_VERTICAL_SIZE+scroll; + menu_blit_window.h = SCREEN_VERTICAL_SIZE; + if(SDL_BlitSurface(menu_zone_surfaces[menuItem], &menu_blit_window, virtual_hw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not Blit surface on virtual_hw_screen: %s\n", SDL_GetError()); + } + } + /// --------- No Scroll ? Blitting menu-specific info + else{ + SDL_Surface * text_surface = NULL; + char text_tmp[40]; + SDL_Rect text_pos; + char fname[MAXPATHLEN]; + memset(fname, 0, MAXPATHLEN); + + switch(idx_menus[menuItem]){ + case MENU_TYPE_VOLUME: + draw_progress_bar(virtual_hw_screen, x_volume_bar, y_volume_bar, + width_progress_bar, height_progress_bar, volume_percentage, 100/STEP_CHANGE_VOLUME); + break; + + case MENU_TYPE_BRIGHTNESS: + draw_progress_bar(virtual_hw_screen, x_volume_bar, y_volume_bar, + width_progress_bar, height_progress_bar, brightness_percentage, 100/STEP_CHANGE_BRIGHTNESS); + break; + + case MENU_TYPE_SAVE: + /// ---- Write slot ----- + sprintf(text_tmp, "IN SLOT < %d >", savestate_slot+1); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + text_pos.x = (virtual_hw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = virtual_hw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2; + SDL_BlitSurface(text_surface, NULL, virtual_hw_screen, &text_pos); + + if(menu_action){ + sprintf(text_tmp, "Saving..."); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + } + else{ + if(menu_confirmation){ + sprintf(text_tmp, "Are you sure ?"); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + } + else{ + /*/// ---- Write current Save state ---- + get_savestate_filename(savestate_slot, fname); + file_open(savestate_file, fname, read); + if(file_check_valid(savestate_file)) + { + file_close(savestate_file); + printf("Found Save slot: %s\n", fname); + char *p = strrchr (fname, '/'); + char *basename = p ? p + 1 : (char *) fname; + char file_name_short[24]; + snprintf(file_name_short, 24, "%s", basename); + text_surface = TTF_RenderText_Blended(menu_small_info_font, file_name_short, text_color); + } + else{ + text_surface = TTF_RenderText_Blended(menu_info_font, "Free", text_color); + }*/ + } + } + text_pos.x = (virtual_hw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = virtual_hw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 + 2*padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, virtual_hw_screen, &text_pos); + break; + + case MENU_TYPE_LOAD: + /// ---- Write slot ----- + sprintf(text_tmp, "FROM SLOT < %d >", savestate_slot+1); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + text_pos.x = (virtual_hw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = virtual_hw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2; + SDL_BlitSurface(text_surface, NULL, virtual_hw_screen, &text_pos); + + if(menu_action){ + sprintf(text_tmp, "Loading..."); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + } + else{ + if(menu_confirmation){ + sprintf(text_tmp, "Are you sure ?"); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + } + else{ + /*/// ---- Write current Load state ---- + get_savestate_filename(savestate_slot, fname); + file_open(savestate_file, fname, read); + if(file_check_valid(savestate_file)) + { + file_close(savestate_file); + printf("Found Load slot: %s\n", fname); + char *p = strrchr (fname, '/'); + char *basename = p ? p + 1 : (char *) fname; + char file_name_short[24]; + snprintf(file_name_short, 24, "%s", basename); + text_surface = TTF_RenderText_Blended(menu_small_info_font, file_name_short, text_color); + } + else{ + text_surface = TTF_RenderText_Blended(menu_info_font, "Free", text_color); + }*/ + } + } + text_pos.x = (virtual_hw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = virtual_hw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 + 2*padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, virtual_hw_screen, &text_pos); + break; + + case MENU_TYPE_ASPECT_RATIO: + sprintf(text_tmp, "< %s >", aspect_ratio_name[aspect_ratio]); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + text_pos.x = (virtual_hw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = virtual_hw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 + padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, virtual_hw_screen, &text_pos); + break; + + case MENU_TYPE_EXIT: + case MENU_TYPE_POWERDOWN: + if(menu_confirmation){ + sprintf(text_tmp, "Are you sure ?"); + text_surface = TTF_RenderText_Blended(menu_info_font, text_tmp, text_color); + text_pos.x = (virtual_hw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = virtual_hw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 + 2*padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, virtual_hw_screen, &text_pos); + } + break; + default: + break; + } + + /// ------ Free Surfaces ------- + if(text_surface) + SDL_FreeSurface(text_surface); + } + + /// --------- Screen Rotate -------- + /*SDL_Copy_Rotate_270((uint16_t *)virtual_hw_screen->pixels, (uint16_t *)hw_screen->pixels, + RES_HW_SCREEN_HORIZONTAL, RES_HW_SCREEN_VERTICAL, + RES_HW_SCREEN_HORIZONTAL, RES_HW_SCREEN_VERTICAL);*/ + /*SDL_BlitSurface(virtual_hw_screen, NULL, virtual_hw_screen, NULL);*/ + + /// --------- Flip Screen ---------- + //SDL_Flip(hw_screen); + SDL::renderAndFlipWindow(); +} + + +void MenuMode::launch( ) +{ + MENU_DEBUG_PRINTF("Launch MenuMode\n"); + + SDL_Event event; + uint32_t prev_ms = SDL_GetTicks(); + uint32_t cur_ms = SDL_GetTicks(); + static int menuItem=0; + int prevItem=menuItem; + int scroll=0; + uint8_t screen_refresh = 1; + char shell_cmd[100]; + FILE *fp; + uint8_t menu_confirmation = 0; + stop_menu_loop = 0; + char fname[MAXPATHLEN]; + + /// ------ Get init values ------- + init_menu_system_values(); + + /// ------ Copy currently displayed screen ------- + SDL_Surface * virtual_hw_screen = SDL::getWindow(); + if(SDL_BlitSurface(virtual_hw_screen, NULL, backup_hw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not copy virtual_hw_screen: %s\n", SDL_GetError()); + } + + /// -------- Main loop --------- + while (!stop_menu_loop) + { + /// -------- Handle Keyboard Events --------- + if(!scroll){ + while (SDL_PollEvent(&event)) + switch(event.type) + { + case SDL_QUIT: + stop_menu_loop = 1; + break; + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_b: + if(menu_confirmation){ + /// ------ Reset menu confirmation ------ + menu_confirmation = 0; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + /*else{ + stop_menu_loop = 1; + }*/ + break; + + case SDLK_q: + case SDLK_ESCAPE: + stop_menu_loop = 1; + break; + + case SDLK_d: + case SDLK_DOWN: + MENU_DEBUG_PRINTF("DOWN\n"); + /// ------ Start scrolling to new menu ------- + menuItem++; + if (menuItem>=nb_menu_zones) menuItem=0; + scroll=SCROLL_SPEED_PX; + + /// ------ Reset menu confirmation ------ + menu_confirmation = 0; + + /// ------ Refresh screen ------ + screen_refresh = 1; + break; + + case SDLK_u: + case SDLK_UP: + MENU_DEBUG_PRINTF("UP\n"); + /// ------ Start scrolling to new menu ------- + menuItem--; + if (menuItem<0) menuItem=nb_menu_zones-1; + scroll=-SCROLL_SPEED_PX; + + /// ------ Reset menu confirmation ------ + menu_confirmation = 0; + + /// ------ Refresh screen ------ + screen_refresh = 1; + break; + + case SDLK_l: + case SDLK_LEFT: + //MENU_DEBUG_PRINTF("LEFT\n"); + if(idx_menus[menuItem] == MENU_TYPE_VOLUME){ + MENU_DEBUG_PRINTF("Volume DOWN\n"); + /// ----- Compute new value ----- + volume_percentage = (volume_percentage < STEP_CHANGE_VOLUME)? + 0:(volume_percentage-STEP_CHANGE_VOLUME); + + /// ----- Shell cmd ---- + sprintf(shell_cmd, "%s %d", SHELL_CMD_VOLUME_SET, volume_percentage); + fp = popen(shell_cmd, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", shell_cmd); + } + + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_BRIGHTNESS){ + MENU_DEBUG_PRINTF("Brightness DOWN\n"); + /// ----- Compute new value ----- + brightness_percentage = (brightness_percentage < STEP_CHANGE_BRIGHTNESS)? + 0:(brightness_percentage-STEP_CHANGE_BRIGHTNESS); + + /// ----- Shell cmd ---- + sprintf(shell_cmd, "%s %d", SHELL_CMD_BRIGHTNESS_SET, brightness_percentage); + fp = popen(shell_cmd, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", shell_cmd); + } + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_SAVE){ + MENU_DEBUG_PRINTF("Save Slot DOWN\n"); + savestate_slot = (!savestate_slot)?(MAX_SAVE_SLOTS-1):(savestate_slot-1); + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_LOAD){ + MENU_DEBUG_PRINTF("Load Slot DOWN\n"); + //idx_load_slot = (!idx_load_slot)?(MAX_SAVE_SLOTS-1):(idx_load_slot-1); + savestate_slot = (!savestate_slot)?(MAX_SAVE_SLOTS-1):(savestate_slot-1); + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_ASPECT_RATIO){ + MENU_DEBUG_PRINTF("Aspect Ratio DOWN\n"); + aspect_ratio = (!aspect_ratio)?(NB_ASPECT_RATIOS_TYPES-1):(aspect_ratio-1); + /// ------ Refresh screen ------ + screen_refresh = 1; + } + break; + + case SDLK_r: + case SDLK_RIGHT: + //MENU_DEBUG_PRINTF("RIGHT\n"); + if(idx_menus[menuItem] == MENU_TYPE_VOLUME){ + MENU_DEBUG_PRINTF("Volume UP\n"); + /// ----- Compute new value ----- + volume_percentage = (volume_percentage > 100 - STEP_CHANGE_VOLUME)? + 100:(volume_percentage+STEP_CHANGE_VOLUME); + + /// ----- Shell cmd ---- + sprintf(shell_cmd, "%s %d", SHELL_CMD_VOLUME_SET, volume_percentage); + fp = popen(shell_cmd, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", shell_cmd); + } + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_BRIGHTNESS){ + MENU_DEBUG_PRINTF("Brightness UP\n"); + /// ----- Compute new value ----- + brightness_percentage = (brightness_percentage > 100 - STEP_CHANGE_BRIGHTNESS)? + 100:(brightness_percentage+STEP_CHANGE_BRIGHTNESS); + + /// ----- Shell cmd ---- + sprintf(shell_cmd, "%s %d", SHELL_CMD_BRIGHTNESS_SET, brightness_percentage); + fp = popen(shell_cmd, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", shell_cmd); + } + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_SAVE){ + MENU_DEBUG_PRINTF("Save Slot UP\n"); + savestate_slot = (savestate_slot+1)%MAX_SAVE_SLOTS; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_LOAD){ + MENU_DEBUG_PRINTF("Load Slot UP\n"); + //idx_load_slot = (idx_load_slot+1)%MAX_SAVE_SLOTS; + savestate_slot = (savestate_slot+1)%MAX_SAVE_SLOTS; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + else if(idx_menus[menuItem] == MENU_TYPE_ASPECT_RATIO){ + MENU_DEBUG_PRINTF("Aspect Ratio UP\n"); + aspect_ratio = (aspect_ratio+1)%NB_ASPECT_RATIOS_TYPES; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + break; + + case SDLK_a: + case SDLK_RETURN: + if(idx_menus[menuItem] == MENU_TYPE_SAVE){ + if(menu_confirmation){ + MENU_DEBUG_PRINTF("Saving in slot %d\n", savestate_slot); + /// ------ Refresh Screen ------- + menu_screen_refresh(menuItem, prevItem, scroll, menu_confirmation, 1); + + /// ------ Save game ------ + /*u16 *current_screen = copy_screen(); + get_savestate_filename_noshot(savestate_slot, fname); + save_state(fname, current_screen); + + /// ----- Hud Msg ----- + sprintf(hud_msg, "SAVED IN SLOT %d", savestate_slot); + set_hud_msg(hud_msg, 4);*/ + + stop_menu_loop = 1; + } + else{ + MENU_DEBUG_PRINTF("Save game - asking confirmation\n"); + menu_confirmation = 1; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + } + else if(idx_menus[menuItem] == MENU_TYPE_LOAD){ + if(menu_confirmation){ + MENU_DEBUG_PRINTF("Loading in slot %d\n", savestate_slot); + /// ------ Refresh Screen ------- + menu_screen_refresh(menuItem, prevItem, scroll, menu_confirmation, 1); + + /// ------ Load game ------ + /*get_savestate_filename_noshot(savestate_slot, fname); + load_state(fname); + + /// ----- Hud Msg ----- + sprintf(hud_msg, "LOADED FROM SLOT %d", savestate_slot); + set_hud_msg(hud_msg, 4);*/ + + stop_menu_loop = 1; + } + else{ + MENU_DEBUG_PRINTF("Save game - asking confirmation\n"); + menu_confirmation = 1; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + } + else if(idx_menus[menuItem] == MENU_TYPE_EXIT){ + MENU_DEBUG_PRINTF("Exit game\n"); + if(menu_confirmation){ + MENU_DEBUG_PRINTF("Exit game - confirmed\n"); + /// ----- The game should be saved here ---- + + /// ----- Exit game and back to launcher ---- + //quit(); + stop_menu_loop = 1; + } + else{ + MENU_DEBUG_PRINTF("Exit game - asking confirmation\n"); + menu_confirmation = 1; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + } + else if(idx_menus[menuItem] == MENU_TYPE_POWERDOWN){ + if(menu_confirmation){ + MENU_DEBUG_PRINTF("Powerdown - confirmed\n"); + /// ----- Shell cmd ---- + sprintf(shell_cmd, "%s", SHELL_CMD_POWERDOWN); + fp = popen(shell_cmd, "r"); + if (fp == NULL) { + MENU_ERROR_PRINTF("Failed to run command %s\n", shell_cmd); + } + } + else{ + MENU_DEBUG_PRINTF("Powerdown - asking confirmation\n"); + menu_confirmation = 1; + /// ------ Refresh screen ------ + screen_refresh = 1; + } + } + break; + + default: + //MENU_DEBUG_PRINTF("Keydown: %d\n", event.key.keysym.sym); + break; + } + break; + } + } + + /// --------- Handle Scroll effect --------- + if (scroll>0){ + scroll+=SCROLL_SPEED_PX; + screen_refresh = 1; + } + if (scroll<0){ + scroll-=SCROLL_SPEED_PX; + screen_refresh = 1; + } + if (scroll>MENU_ZONE_HEIGHT || scroll<-MENU_ZONE_HEIGHT) { + prevItem=menuItem; + scroll=0; + screen_refresh = 1; + } + + /// --------- Handle FPS --------- + cur_ms = SDL_GetTicks(); + if(cur_ms-prev_ms < 1000/FPS_MENU){ + SDL_Delay(1000/FPS_MENU - (cur_ms-prev_ms)); + } + prev_ms = SDL_GetTicks(); + + + /// --------- Refresh screen + if(screen_refresh){ + menu_screen_refresh(menuItem, prevItem, scroll, menu_confirmation, 0); + } + + /// --------- reset screen refresh --------- + screen_refresh = 0; + } + return; +} diff --git a/RetroFE/Source/Menu/MenuMode.h b/RetroFE/Source/Menu/MenuMode.h new file mode 100644 index 0000000..73ad66e --- /dev/null +++ b/RetroFE/Source/Menu/MenuMode.h @@ -0,0 +1,128 @@ +#pragma once + +#include +#include +#include + +typedef enum{ + MENU_TYPE_VOLUME, + MENU_TYPE_BRIGHTNESS, + MENU_TYPE_SAVE, + MENU_TYPE_LOAD, + MENU_TYPE_ASPECT_RATIO, + MENU_TYPE_EXIT, + MENU_TYPE_POWERDOWN, + NB_MENU_TYPES, +} ENUM_MENU_TYPE; + + +///------ Definition of the different aspect ratios +#define ASPECT_RATIOS \ + X(ASPECT_RATIOS_TYPE_MANUAL, "MANUAL ZOOM") \ + X(ASPECT_RATIOS_TYPE_STRECHED, "STRECHED") \ + X(ASPECT_RATIOS_TYPE_CROPPED, "CROPPED") \ + X(ASPECT_RATIOS_TYPE_SCALED, "SCALED") \ + X(NB_ASPECT_RATIOS_TYPES, "") + +////------ Enumeration of the different aspect ratios ------ +#undef X +#define X(a, b) a, +typedef enum {ASPECT_RATIOS} ENUM_ASPECT_RATIOS_TYPES; + +////------ Defines to be shared ------- +#define STEP_CHANGE_VOLUME 10 +#define STEP_CHANGE_BRIGHTNESS 10 + +////------ Menu commands ------- +#define SHELL_CMD_VOLUME_GET "/root/shell_cmds/volume_get.sh" +#define SHELL_CMD_VOLUME_SET "/root/shell_cmds/volume_set.sh" +#define SHELL_CMD_BRIGHTNESS_GET "/root/shell_cmds/brightness_get.sh" +#define SHELL_CMD_BRIGHTNESS_SET "/root/shell_cmds/brightness_set.sh" +#define SHELL_CMD_POWERDOWN "shutdown -h now" + +class MenuMode +{ + +public: + //MenuMode(); + static void init(); + static void end(); + static void launch( ); + + /*static SDL_Surface * draw_screen; + + static int backup_key_repeat_delay, backup_key_repeat_interval; + static SDL_Surface * backup_hw_screen; + + static TTF_Font *menu_title_font; + static TTF_Font *menu_info_font; + static TTF_Font *menu_small_info_font; + static SDL_Surface ** menu_zone_surfaces; + static int * idx_menus; + static int nb_menu_zones; + + static int stop_menu_loop; + + static SDL_Color text_color; + static int padding_y_from_center_menu_zone; + static uint16_t width_progress_bar; + static uint16_t height_progress_bar; + static uint16_t x_volume_bar; + static uint16_t y_volume_bar; + static uint16_t x_brightness_bar; + static uint16_t y_brightness_bar; + + static int volume_percentage; + static int brightness_percentage; + + static const char *aspect_ratio_name[]; + static int aspect_ratio; + static int aspect_ratio_factor_percent; + static int aspect_ratio_factor_step; + + static int savestate_slot;*/ + +private: + static void draw_progress_bar(SDL_Surface * surface, uint16_t x, uint16_t y, uint16_t width, + uint16_t height, uint8_t percentage, uint16_t nb_bars); + static void add_menu_zone(ENUM_MENU_TYPE menu_type); + static void init_menu_zones(); + static void init_menu_system_values(); + static void menu_screen_refresh(int menuItem, int prevItem, int scroll, uint8_t menu_confirmation, uint8_t menu_action); + + //static SDL_Surface * hw_screen; + //static SDL_Surface * virtual_hw_screen; // this one is not rotated + static SDL_Surface * draw_screen; + + static int backup_key_repeat_delay; + static int backup_key_repeat_interval; + static SDL_Surface * backup_hw_screen; + + static TTF_Font *menu_title_font; + static TTF_Font *menu_info_font; + static TTF_Font *menu_small_info_font; + static SDL_Surface ** menu_zone_surfaces; + static int * idx_menus; + static int nb_menu_zones; + + static int stop_menu_loop; + + static SDL_Color text_color; + static int padding_y_from_center_menu_zone; + static uint16_t width_progress_bar; + static uint16_t height_progress_bar; + static uint16_t x_volume_bar; + static uint16_t y_volume_bar; + static uint16_t x_brightness_bar; + static uint16_t y_brightness_bar; + + static int volume_percentage; + static int brightness_percentage; + + static const char *aspect_ratio_name[]; + static int aspect_ratio; + static int aspect_ratio_factor_percent; + static int aspect_ratio_factor_step; + + static int savestate_slot; +}; diff --git a/RetroFE/Source/RetroFE.cpp b/RetroFE/Source/RetroFE.cpp index 85bcdd5..d400a8e 100644 --- a/RetroFE/Source/RetroFE.cpp +++ b/RetroFE/Source/RetroFE.cpp @@ -22,6 +22,7 @@ #include "Collection/Item.h" #include "Execute/Launcher.h" #include "Menu/Menu.h" +#include "Menu/MenuMode.h" #include "Utility/Log.h" #include "Utility/Utils.h" #include "Collection/MenuParser.h" @@ -225,6 +226,8 @@ void RetroFE::allocateGraphicsMemory( ) { SDL::initialize( config_ ); currentPage_->initializeFonts( ); + // Init MenuMode + MenuMode::init( ); } // Allocate textures @@ -243,6 +246,9 @@ bool RetroFE::deInitialize( ) bool retVal = true; + // Deinit menuMode + MenuMode::end( ); + // Free textures freeGraphicsMemory( ); @@ -395,6 +401,9 @@ void RetroFE::run( ) if(! SDL::initialize( config_ ) ) return; fontcache_.initialize( ); + // Initialize MenuMode + MenuMode::init(); + // Define control configuration std::string controlsConfPath = Utils::combinePath( Configuration::absolutePath, "controls.conf" ); if ( !config_.import( "controls", controlsConfPath ) ) @@ -824,9 +833,17 @@ void RetroFE::run( ) nextPageItem_ = currentPage_->getSelectedItem( ); launchEnter( ); l.run(nextPageItem_->collectionInfo->name, nextPageItem_); + +/********************************/ +#warning to remove + //bypass + state = RETROFE_QUIT_REQUEST; + break; +/********************************/ + launchExit( ); currentPage_->exitGame( ); - state = RETROFE_LAUNCH_EXIT; + state = RETROFE_QUIT_REQUEST; } break; @@ -952,6 +969,12 @@ void RetroFE::run( ) state = RETROFE_MENUMODE_START_LOAD_ART; }*/ + /// Launch menu + menuMode_ = true; + printf("Menu launched here\n"); + MenuMode::launch(); + menuMode_ = false; + /// Clear events SDL_Event ev; while ( SDL_PollEvent( &ev ) ); @@ -1000,6 +1023,7 @@ void RetroFE::run( ) // Handle screen updates and attract mode if ( running ) { + // Handle FPS lastTime = currentTime_; currentTime_ = static_cast( SDL_GetTicks( ) ) / 1000; @@ -1009,7 +1033,7 @@ void RetroFE::run( ) } deltaTime = currentTime_ - lastTime; - double sleepTime = 1000.0/60.0 - deltaTime*1000; + double sleepTime = 1000.0/FPS - deltaTime*1000; if ( sleepTime > 0 ) { SDL_Delay( static_cast( sleepTime ) );