diff --git a/src/menu/options.c b/src/menu/options.c index 3fda60a6..252f7725 100644 --- a/src/menu/options.c +++ b/src/menu/options.c @@ -6,6 +6,7 @@ * Copyright (C) 2011, Alexeyew Andrew */ +#include #include "menu.h" #include "options.h" #include "global.h" @@ -36,9 +37,8 @@ void allocate_bindings(MenuData *m) m->context = (void*)binds; } -void free_bindings(void *menu) +void free_bindings(MenuData *m) { - MenuData *m = (MenuData*)menu; OptionBinding *binds = (OptionBinding*)m->context; int i, j; @@ -55,6 +55,60 @@ void free_bindings(void *menu) free(binds); } +void menu_save_config(MenuData *m, char *filename) +{ + char *buf; + buf = malloc(strlen((char*)filename)+strlen((char*)get_config_path())+3); + strcpy(buf, (char*)get_config_path()); + strcat(buf, "/"); + strcat(buf, filename); + + FILE *out = fopen(buf, "w"); + free(buf); + + if(!out) + { + perror("fopen"); + return; + } + + fputs("# Generated by taisei\n", out); + + int i; + for(i = 0; i < m->ecount; ++i) + { + OptionBinding *binds = (OptionBinding*)m->context; + OptionBinding *bind = &(binds[i]); + + if(!bind->enabled) + continue; + + switch(bind->type) + { + case BT_IntValue: + fprintf(out, "%s = %i\n", bind->optname, tconfig.intval[bind->configentry]); + break; + + case BT_KeyBinding: + fprintf(out, "%s = K%i # SDL key name: %s\n", bind->optname, tconfig.intval[bind->configentry], + SDL_GetKeyName(tconfig.intval[bind->configentry])); + break; + + default: + printf("FIXME: unhandled BindingType %i, option '%s' will NOT be saved!\n", bind->type, bind->optname); + } + } + + printf("Saved config '%s'\n", filename); +} + +void options_menu_destroy(void *menu) +{ + MenuData *m = (MenuData*)menu; + menu_save_config(m, CONFIG_FILE); + free_bindings(menu); +} + OptionBinding* bind_option_to_entry(MenuData *m, int entry, char *optname, int cfgentry, BindingGetter getter, BindingSetter setter) { OptionBinding *binds = (OptionBinding*)m->context; @@ -66,6 +120,21 @@ OptionBinding* bind_option_to_entry(MenuData *m, int entry, char *optname, int c bind->optname = malloc((strlen(optname) + 1) * sizeof(char)); strcpy(bind->optname, optname); bind->enabled = True; + bind->type = BT_IntValue; + + return bind; +} + +OptionBinding* bind_keybinding_to_entry(MenuData *m, int entry, char *optname, int cfgentry) +{ + OptionBinding *binds = (OptionBinding*)m->context; + OptionBinding *bind = &(binds[entry]); + + bind->configentry = cfgentry; + bind->optname = malloc((strlen(optname) + 1) * sizeof(char)); + strcpy(bind->optname, optname); + bind->enabled = True; + bind->type = BT_KeyBinding; return bind; } @@ -111,7 +180,7 @@ void bindings_initvalues(MenuData *m) int i; for(i = 0; i < m->ecount; ++i) - if(binds[i].enabled) + if(binds[i].enabled && binds[i].type == BT_IntValue) binds[i].selected = binds[i].getter(&(binds[i])); } @@ -174,17 +243,32 @@ void create_options_menu(MenuData *m) { create_menu(m); m->type = MT_Persistent; - m->ondestroy = free_bindings; + m->ondestroy = options_menu_destroy; - add_menu_entry(m, "Fullscreen", do_nothing, NULL); + add_menu_entry(m, "Fullscreen", do_nothing, NULL); // entry 0 add_menu_entry(m, "Audio", do_nothing, NULL); add_menu_entry(m, "Shader", do_nothing, NULL); add_menu_entry(m, " ", NULL, NULL); - add_menu_entry(m, "Customize controls", NULL, NULL); - add_menu_entry(m, "Back", backtomain, m); + add_menu_entry(m, "Move up", do_nothing, NULL); // entry 4 + add_menu_entry(m, "Move down", do_nothing, NULL); + add_menu_entry(m, "Move left", do_nothing, NULL); + add_menu_entry(m, "Move right", do_nothing, NULL); + add_menu_entry(m, " ", NULL, NULL); + add_menu_entry(m, "Fire", do_nothing, NULL); // entry 9 + add_menu_entry(m, "Focus", do_nothing, NULL); + add_menu_entry(m, "Bomb", do_nothing, NULL); + add_menu_entry(m, " ", NULL, NULL); + add_menu_entry(m, "Toggle fullscreen", do_nothing, NULL); // entry 13 + // UNCOMMENT after akari/screenshot is merged + //add_menu_entry(m, "Take a screenshot", do_nothing, NULL); + add_menu_entry(m, " ", NULL, NULL); + //add_menu_entry(m, "Customize controls", NULL, NULL); + add_menu_entry(m, "Return to the main menu", backtomain, m); allocate_bindings(m); + // this sucks but you have to specify the positional number of the menu entry as the second argument to bind_option_to_entry or bind_keybinding_to_entry + b = bind_option_to_entry(m, 0, "fullscreen", FULLSCREEN, bind_common_onoffget, bind_fullscreen_set); bind_onoff(b); @@ -196,6 +280,19 @@ void create_options_menu(MenuData *m) { bind_noshader_set); bind_onoff(b); + bind_keybinding_to_entry(m, 4, "key_up", KEY_UP); + bind_keybinding_to_entry(m, 5, "key_down", KEY_DOWN); + bind_keybinding_to_entry(m, 6, "key_left", KEY_LEFT); + bind_keybinding_to_entry(m, 7, "key_right", KEY_RIGHT); + + bind_keybinding_to_entry(m, 9, "key_shot", KEY_SHOT); + bind_keybinding_to_entry(m, 10, "key_focus", KEY_FOCUS); + bind_keybinding_to_entry(m, 11, "key_bomb", KEY_BOMB); + + bind_keybinding_to_entry(m, 13, "key_fullscreen", KEY_FULLSCREEN); + // UNCOMMENT after akari/screeenshot is merged + //bind_keybinding_to_entry(m, 14, "key_screenshot", KEY_SCREENSHOT); + bindings_initvalues(m); } @@ -249,19 +346,29 @@ void draw_options_menu(MenuData *menu) { bind = &(binds[i]); - if(bind->enabled && bind->valcount > 0) + if(bind->enabled) { - int len = 0, j; - for(j = bind->valcount - 1; j+1; --j) + int j, origin = SCREEN_W - 220; + switch(bind->type) { - len += strlen(bind->values[j]); - - if(bind->selected == j) - glColor4f(1,1,0,0.7); - else - glColor4f(0.5,0.5,0.5,0.7); - - draw_text(AL_Right, SCREEN_W - 200 - (len*20), 20*i, bind->values[j], _fonts.standard); + case BT_IntValue: + for(j = bind->valcount-1; j+1; --j) + { + if(j != bind->valcount-1) + origin -= strlen(bind->values[j+1])/2.0 * 20; + + if(bind->selected == j) + glColor4f(1,1,0,0.7); + else + glColor4f(0.5,0.5,0.5,0.7); + + draw_text(AL_Right, origin, 20*i, bind->values[j], _fonts.standard); + } + break; + + case BT_KeyBinding: + draw_text(AL_Right, origin, 20*i, SDL_GetKeyName(tconfig.intval[bind->configentry]), _fonts.standard); + break; } } } @@ -307,8 +414,10 @@ void options_menu_input(MenuData *menu) { OptionBinding *binds = (OptionBinding*)menu->context; OptionBinding *bind = &(binds[menu->selected]); - if(bind->enabled) - binding_setnext(bind); + if(bind->enabled) switch(bind->type) + { + case BT_IntValue: binding_setnext(bind); break; + } else menu->quit = 1; } else if(sym == tconfig.intval[KEY_LEFT]) { @@ -316,14 +425,14 @@ void options_menu_input(MenuData *menu) { OptionBinding *binds = (OptionBinding*)menu->context; OptionBinding *bind = &(binds[menu->selected]); - if(bind->enabled) + if(bind->enabled && bind->type == BT_IntValue) binding_setprev(bind); } else if(sym == tconfig.intval[KEY_RIGHT]) { menu->selected = menu->cursor; OptionBinding *binds = (OptionBinding*)menu->context; OptionBinding *bind = &(binds[menu->selected]); - if(bind->enabled) + if(bind->enabled && bind->type == BT_IntValue) binding_setnext(bind); } else if(sym == SDLK_ESCAPE) { menu->quit = 2; diff --git a/src/menu/options.h b/src/menu/options.h index 5ffac836..1a8449d7 100644 --- a/src/menu/options.h +++ b/src/menu/options.h @@ -19,6 +19,11 @@ int options_menu_loop(MenuData *m); typedef int (*BindingGetter)(void*); typedef int (*BindingSetter)(void*, int); +typedef enum BindingType { + BT_IntValue, + BT_KeyBinding +} BindingType; + typedef struct OptionBinding { char **values; int valcount; @@ -28,6 +33,7 @@ typedef struct OptionBinding { int configentry; int enabled; char *optname; + BindingType type; } OptionBinding; void draw_options_menu_bg(MenuData*);