diff --git a/include/menu.h b/include/menu.h new file mode 100644 index 0000000..855f41a --- /dev/null +++ b/include/menu.h @@ -0,0 +1,48 @@ +#ifndef MENU_H +#define MENU_H + +void init_menu_SDL(); +void deinit_menu_SDL(); +void init_menu_zones(); +void init_menu_system_values(); +void run_menu_loop(); + +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; + +////------ Defines to be shared ------- +#define STEP_CHANGE_VOLUME 10 +#define STEP_CHANGE_BRIGHTNESS 10 +#define NOTIF_SECONDS_DISP 2 + +////------ Menu commands ------- +#define SHELL_CMD_VOLUME_GET "volume get" +#define SHELL_CMD_VOLUME_SET "volume set" +#define SHELL_CMD_BRIGHTNESS_GET "brightness get" +#define SHELL_CMD_BRIGHTNESS_SET "brightness set" +#define SHELL_CMD_NOTIF "notif_set" +#define SHELL_CMD_NOTIF_CLEAR "notif_clear" +#define SHELL_CMD_WRITE_QUICK_LOAD_CMD "write_args_quick_load_file" +#define SHELL_CMD_TURN_AMPLI_ON "start_audio_amp 1" +#define SHELL_CMD_TURN_AMPLI_OFF "start_audio_amp 0" +#define SHELL_CMD_CANCEL_SCHED_POWERDOWN "cancel_sched_powerdown" +#define SHELL_CMD_INSTANT_PLAY "instant_play" +#define SHELL_CMD_SHUTDOWN_FUNKEY "shutdown_funkey" +#define SHELL_CMD_KEYMAP_DEFAULT "keymap default" +#define SHELL_CMD_KEYMAP_RESUME "keymap resume" + +////------ Global variables ------- +extern int volume_percentage; +extern int brightness_percentage; + +extern int stop_menu_loop; + +#endif //MENU_H diff --git a/root@192.168.137.145 b/root@192.168.137.145 new file mode 100755 index 0000000..297116d Binary files /dev/null and b/root@192.168.137.145 differ diff --git a/src/menu.c b/src/menu.c new file mode 100644 index 0000000..5ef13cd --- /dev/null +++ b/src/menu.c @@ -0,0 +1,742 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../include/constant.h" +#include "../include/misc.h" +#include "../include/menu.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 SCROLL_SPEED_PX 30 +#define FPS_MENU 50 +#define ARROWS_PADDING 8 + +#define MENU_ZONE_WIDTH HW_SCREEN_WIDTH +#define MENU_ZONE_HEIGHT HW_SCREEN_HEIGHT +#define MENU_BG_SQUARE_WIDTH 180 +#define MENU_BG_SQUARE_HEIGHT 140 + +#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 MENU_PNG_ARROW_TOP_PATH "/usr/games/menu_resources/arrow_top.png" +#define MENU_PNG_ARROW_BOTTOM_PATH "/usr/games/menu_resources/arrow_bottom.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 -------------- +extern SDL_Surface * hw_screen; +static SDL_Surface * backup_hw_screen = NULL; +static SDL_Surface * draw_screen = NULL; + +static int backup_key_repeat_delay, backup_key_repeat_interval; + +static TTF_Font *menu_title_font = NULL; +static TTF_Font *menu_info_font = NULL; +static TTF_Font *menu_small_info_font = NULL; +static SDL_Surface *img_arrow_top = NULL; +static SDL_Surface *img_arrow_bottom = NULL; +static SDL_Surface ** menu_zone_surfaces = NULL; +static int * idx_menus = NULL; +static int nb_menu_zones = 0; +static int menuItem = 0; +int stop_menu_loop = 0; + +static SDL_Color text_color = {GRAY_MAIN_R, GRAY_MAIN_G, GRAY_MAIN_B}; +static int padding_y_from_center_menu_zone = 18; +static uint16_t width_progress_bar = 100; +static uint16_t height_progress_bar = 20; +static uint16_t x_volume_bar = 0; +static uint16_t y_volume_bar = 0; +static uint16_t x_brightness_bar = 0; +static uint16_t y_brightness_bar = 0; + +int volume_percentage = 0; +int brightness_percentage = 0; + +/// -------------- STATIC FUNCTIONS DECLARATION -------------- + +/// -------------- FUNCTIONS IMPLEMENTATION -------------- +void init_menu_SDL(){ + MENU_DEBUG_PRINTF("Init Menu\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 hw_screen at init ------ + backup_hw_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, + hw_screen->w, hw_screen->h, 16, 0, 0, 0, 0); + + draw_screen = SDL_CreateRGBSurface(SDL_SWSURFACE, + hw_screen->w, hw_screen->h, 16, 0, 0, 0, 0); + if(draw_screen == NULL){ + MENU_ERROR_PRINTF("ERROR Could not create draw_screen: %s\n", SDL_GetError()); + } + + /// ------ Load arrows imgs ------- + img_arrow_top = IMG_Load(MENU_PNG_ARROW_TOP_PATH); + if(!img_arrow_top) { + MENU_ERROR_PRINTF("ERROR IMG_Load: %s\n", IMG_GetError()); + } + img_arrow_bottom = IMG_Load(MENU_PNG_ARROW_BOTTOM_PATH); + if(!img_arrow_bottom) { + MENU_ERROR_PRINTF("ERROR IMG_Load: %s\n", IMG_GetError()); + } + + /// ------ Init menu zones ------ + init_menu_zones(); +} + +void deinit_menu_SDL(){ + MENU_DEBUG_PRINTF("End Menu \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]); + } + + if(backup_hw_screen != NULL){ + SDL_FreeSurface(backup_hw_screen); + } + if(draw_screen != NULL){ + SDL_FreeSurface(draw_screen); + } + + SDL_FreeSurface(img_arrow_top); + SDL_FreeSurface(img_arrow_bottom); + + /// ------ Free Menu memory and reset vars ----- + if(idx_menus){ + free(idx_menus); + } + idx_menus=NULL; + nb_menu_zones = 0; +} + + +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){ + + /// ------ 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 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 = malloc(nb_menu_zones*sizeof(int)); + menu_zone_surfaces = malloc(nb_menu_zones*sizeof(SDL_Surface*)); + } + else{ + int *temp = realloc(idx_menus, nb_menu_zones*sizeof(int)); + idx_menus = temp; + menu_zone_surfaces = 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 init_menu_zones(){ + /// Init Volume Menu + add_menu_zone(MENU_TYPE_VOLUME); + /// Init Brightness Menu + add_menu_zone(MENU_TYPE_BRIGHTNESS); + /// Init Exit Menu + add_menu_zone(MENU_TYPE_EXIT); + /// Init Powerdown Menu + //add_menu_zone(MENU_TYPE_POWERDOWN); +} + + +void 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); + pclose(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); + pclose(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); + } + } + + /// ------ 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()); + } +} + +void menu_screen_refresh(int menuItem, int prevItem, int scroll, uint8_t menu_confirmation, uint8_t menu_action){ + /// --------- Vars --------- + int print_arrows = (scroll==0)?1:0; + + /// --------- Clear HW screen ---------- + //SDL_FillRect(draw_screen, NULL, SDL_MapRGB(draw_screen->format, 255, 0, 0)); + if(SDL_BlitSurface(backup_hw_screen, NULL, draw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not Clear draw_screen: %s\n", SDL_GetError()); + } + + /// --------- Setup Blit Window ---------- + SDL_Rect menu_blit_window; + menu_blit_window.x = 0; + menu_blit_window.w = HW_SCREEN_WIDTH; + + /// --------- Blit prev menu Zone going away ---------- + menu_blit_window.y = scroll; + menu_blit_window.h = HW_SCREEN_HEIGHT; + if(SDL_BlitSurface(menu_zone_surfaces[prevItem], &menu_blit_window, draw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not Blit surface on draw_screen: %s\n", SDL_GetError()); + } + + /// --------- Blit new menu Zone going in (only during animations) ---------- + if(scroll>0){ + menu_blit_window.y = HW_SCREEN_HEIGHT-scroll; + menu_blit_window.h = HW_SCREEN_HEIGHT; + if(SDL_BlitSurface(menu_zone_surfaces[menuItem], NULL, draw_screen, &menu_blit_window)){ + MENU_ERROR_PRINTF("ERROR Could not Blit surface on draw_screen: %s\n", SDL_GetError()); + } + } + else if(scroll<0){ + menu_blit_window.y = HW_SCREEN_HEIGHT+scroll; + menu_blit_window.h = HW_SCREEN_HEIGHT; + if(SDL_BlitSurface(menu_zone_surfaces[menuItem], &menu_blit_window, draw_screen, NULL)){ + MENU_ERROR_PRINTF("ERROR Could not Blit surface on draw_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(draw_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(draw_screen, x_volume_bar, y_volume_bar, + width_progress_bar, height_progress_bar, brightness_percentage, 100/STEP_CHANGE_BRIGHTNESS); + 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 = (draw_screen->w - MENU_ZONE_WIDTH)/2 + (MENU_ZONE_WIDTH - text_surface->w)/2; + text_pos.y = draw_screen->h - MENU_ZONE_HEIGHT/2 - text_surface->h/2 + 2*padding_y_from_center_menu_zone; + SDL_BlitSurface(text_surface, NULL, draw_screen, &text_pos); + } + break; + default: + break; + } + + /// ------ Free Surfaces ------- + if(text_surface) + SDL_FreeSurface(text_surface); + } + + /// --------- Print arrows -------- + if(print_arrows){ + /// Top arrow + SDL_Rect pos_arrow_top; + pos_arrow_top.x = (draw_screen->w - img_arrow_top->w)/2; + pos_arrow_top.y = (draw_screen->h - MENU_BG_SQUARE_HEIGHT)/4 - img_arrow_top->h/2; + SDL_BlitSurface(img_arrow_top, NULL, draw_screen, &pos_arrow_top); + + /// Bottom arrow + SDL_Rect pos_arrow_bottom; + pos_arrow_bottom.x = (draw_screen->w - img_arrow_bottom->w)/2; + pos_arrow_bottom.y = draw_screen->h - + (draw_screen->h - MENU_BG_SQUARE_HEIGHT)/4 - img_arrow_bottom->h/2; + SDL_BlitSurface(img_arrow_bottom, NULL, draw_screen, &pos_arrow_bottom); + } + + /// --------- Screen Rotate -------- + //SDL_Rotate_270(hw_screen, draw_screen); + //SDL_BlitSurface(draw_screen, NULL, hw_screen, NULL); + + /// ---- Fast blit ---- + memcpy(hw_screen->pixels, draw_screen->pixels, hw_screen->h*hw_screen->w*sizeof(uint16_t)); + + /// --------- Render Screen ---------- + SDL_Flip(hw_screen); +} + + +void run_menu_loop() +{ + MENU_DEBUG_PRINTF("Launch Menu\n"); + + SDL_Event event; + uint32_t prev_ms = SDL_GetTicks(); + uint32_t cur_ms = SDL_GetTicks(); + int scroll=0; + int start_scroll=0; + uint8_t screen_refresh = 1; + char shell_cmd[100]; + uint8_t menu_confirmation = 0; + stop_menu_loop = 0; + char fname[MAXPATHLEN]; + + /// ------ Load default keymap ------ + system(SHELL_CMD_KEYMAP_DEFAULT); + + /// ------ Get init values ------- + init_menu_system_values(); + int prevItem=menuItem; + + /// ------ Copy currently displayed screen ------- + memcpy(backup_hw_screen->pixels, (uint16_t *)hw_screen->pixels, + HW_SCREEN_WIDTH * HW_SCREEN_HEIGHT * sizeof(uint16_t)); + + /* Stop Ampli */ + system(SHELL_CMD_TURN_AMPLI_OFF); + + /// -------- 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; + exit_game = true; + 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; + start_scroll=1; + + /// ------ 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; + start_scroll=-1; + + /// ------ 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); + system(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); + system(shell_cmd); + + /// ------ 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); + system(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); + system(shell_cmd); + + /// ------ Refresh screen ------ + screen_refresh = 1; + } + break; + + case SDLK_a: + case SDLK_RETURN: + if(idx_menus[menuItem] == MENU_TYPE_EXIT){ + MENU_DEBUG_PRINTF("Exit game\n"); + if(menu_confirmation){ + MENU_DEBUG_PRINTF("Exit game - confirmed\n"); + + /// ----- Exit game and back to launcher ---- + exit_game = true; + 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 ---- + execlp(SHELL_CMD_SHUTDOWN_FUNKEY, SHELL_CMD_SHUTDOWN_FUNKEY, NULL); + MENU_ERROR_PRINTF("Failed to run command %s\n", SHELL_CMD_SHUTDOWN_FUNKEY); + exit(0); + } + 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) || (start_scroll>0)){ + scroll+=MIN(SCROLL_SPEED_PX, MENU_ZONE_HEIGHT-scroll); + start_scroll = 0; + screen_refresh = 1; + } + else if ((scroll<0) || (start_scroll<0)){ + scroll-=MIN(SCROLL_SPEED_PX, MENU_ZONE_HEIGHT+scroll); + start_scroll = 0; + 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; + } + + /// ------ Restore last keymap ------ + system(SHELL_CMD_KEYMAP_RESUME); + + /// ------ Reset prev key repeat params ------- + if(SDL_EnableKeyRepeat(backup_key_repeat_delay, backup_key_repeat_interval)){ + MENU_ERROR_PRINTF("ERROR with SDL_EnableKeyRepeat: %s\n", SDL_GetError()); + } + + /* Start Ampli */ + system(SHELL_CMD_TURN_AMPLI_ON); + + /// ------ Reset last screen ------ + SDL_BlitSurface(backup_hw_screen, NULL, hw_screen, NULL); + SDL_Flip(hw_screen); +} +