comparison nuklear_ui/blastem_nuklear.c @ 1645:84ef1eb2c96a

Added code for actually saving new controller bindings to an appropriate key in the config file
author Michael Pavone <pavone@retrodev.com>
date Fri, 30 Nov 2018 00:35:05 -0800
parents 2c3536082c0f
children 60b199cbb3f7
comparison
equal deleted inserted replaced
1644:cf4e387a8db6 1645:84ef1eb2c96a
254 void view_load_state(struct nk_context *context) 254 void view_load_state(struct nk_context *context)
255 { 255 {
256 view_choose_state(context, 1); 256 view_choose_state(context, 1);
257 } 257 }
258 258
259 static void menu(struct nk_context *context, uint32_t num_entries, const menu_item *items) 259 typedef void (*menu_handler)(uint32_t index);
260
261 static void menu(struct nk_context *context, uint32_t num_entries, const menu_item *items, menu_handler handler)
260 { 262 {
261 const uint32_t button_height = context->style.font->height * 1.75; 263 const uint32_t button_height = context->style.font->height * 1.75;
262 const uint32_t ideal_button_width = context->style.font->height * 10; 264 const uint32_t ideal_button_width = context->style.font->height * 10;
263 const uint32_t button_space = 6; 265 const uint32_t button_space = 6;
264 266
271 nk_layout_space_begin(context, NK_STATIC, top + button_height * num_entries, num_entries); 273 nk_layout_space_begin(context, NK_STATIC, top + button_height * num_entries, num_entries);
272 for (uint32_t i = 0; i < num_entries; i++) 274 for (uint32_t i = 0; i < num_entries; i++)
273 { 275 {
274 nk_layout_space_push(context, nk_rect(left, top + i * button_height, button_width, button_height-button_space)); 276 nk_layout_space_push(context, nk_rect(left, top + i * button_height, button_width, button_height-button_space));
275 if (nk_button_label(context, items[i].title)) { 277 if (nk_button_label(context, items[i].title)) {
276 push_view(items[i].next_view); 278 if (items[i].next_view) {
277 if (!current_view) { 279 push_view(items[i].next_view);
278 exit(0); 280 if (current_view == view_save_state || current_view == view_load_state) {
279 } 281 free_slot_info(slots);
280 if (current_view == view_save_state || current_view == view_load_state) { 282 slots = NULL;
281 free_slot_info(slots); 283 }
282 slots = NULL; 284 } else {
285 handler(i);
283 } 286 }
284 } 287 }
285 } 288 }
286 nk_layout_space_end(context); 289 nk_layout_space_end(context);
287 } 290 }
582 conf_names = tern_insert_ptr(conf_names, "ui.toggle_keyboard_captured", "Toggle Keyboard Capture"); 585 conf_names = tern_insert_ptr(conf_names, "ui.toggle_keyboard_captured", "Toggle Keyboard Capture");
583 } 586 }
584 return tern_find_ptr_default(conf_names, option, (void *)option); 587 return tern_find_ptr_default(conf_names, option, (void *)option);
585 } 588 }
586 589
590 static uint8_t controller_binding_changed;
587 static void bind_option_group(struct nk_context *context, char *name, const char **options, uint32_t num_options) 591 static void bind_option_group(struct nk_context *context, char *name, const char **options, uint32_t num_options)
588 { 592 {
589 float margin = context->style.font->height * 2; 593 float margin = context->style.font->height * 2;
590 nk_layout_row_static(context, (context->style.font->height + 3) * ((num_options + 2) / 3) + context->style.font->height*2.1, render_width() - margin, 1); 594 nk_layout_row_static(context, (context->style.font->height + 3) * ((num_options + 2) / 3) + context->style.font->height*2.1, render_width() - margin, 1);
591 if (nk_group_begin(context, name, NK_WINDOW_TITLE|NK_WINDOW_NO_SCROLLBAR)) { 595 if (nk_group_begin(context, name, NK_WINDOW_TITLE|NK_WINDOW_NO_SCROLLBAR)) {
592 nk_layout_row_static(context, context->style.font->height, (render_width() - margin - context->style.font->height) / 3, 3); 596 nk_layout_row_static(context, context->style.font->height, (render_width() - margin - context->style.font->height) / 3, 3);
593 for (int i = 0; i < num_options; i++) 597 for (int i = 0; i < num_options; i++)
594 { 598 {
595 if (nk_button_label(context, translate_binding_option(options[i]))) { 599 if (nk_button_label(context, translate_binding_option(options[i]))) {
596 *current_bind_dest = options[i]; 600 *current_bind_dest = options[i];
601 controller_binding_changed = 1;
597 pop_view(); 602 pop_view();
598 } 603 }
599 } 604 }
600 nk_group_end(context); 605 nk_group_end(context);
601 } 606 }
763 bindings->triggers[axis-SDL_CONTROLLER_AXIS_TRIGGERLEFT] = val.ptrval; 768 bindings->triggers[axis-SDL_CONTROLLER_AXIS_TRIGGERLEFT] = val.ptrval;
764 break; 769 break;
765 } 770 }
766 } 771 }
767 772
773 enum {
774 SIMILAR_CONTROLLERS,
775 IDENTICAL_CONTROLLERS,
776 BY_INDEX,
777 DEFAULT,
778 NUM_DEST_TYPES
779 };
780
781 //it would be cleaner to generate this algorithmically for 4th and up,
782 //but BlastEm only supports 8 controllers currently so it's not worth the effort
783 static const char *by_index_names[] = {
784 "Use for 1st controller",
785 "Use for 2nd controller",
786 "Use for 3rd controller",
787 "Use for 4th controller",
788 "Use for 5th controller",
789 "Use for 6th controller",
790 "Use for 7th controller",
791 "Use for 8th controller",
792 };
793
794 static void save_stick_binds(char *axes_key, size_t axes_key_size, const char **bindings, char *prefix)
795 {
796 for (int i = 0; i < NUM_AXIS_DIRS; i++)
797 {
798 char axis = (i / 2) ? 'x' : 'y';
799 char *suffix = (i % 2) ? ".negative" : ".positive";
800 size_t prefix_len = strlen(prefix), suffix_len = strlen(suffix);
801 size_t full_key_size = axes_key_size + prefix_len + 1 + suffix_len + 2;
802 char *full_key = malloc(full_key_size);
803 memcpy(full_key, axes_key, axes_key_size);
804 memcpy(full_key + axes_key_size, prefix, prefix_len);
805 full_key[axes_key_size+prefix_len] = axis;
806 memcpy(full_key + axes_key_size + prefix_len + 1, suffix, suffix_len +1);
807 full_key[axes_key_size + prefix_len + 1 + suffix_len + 1] = 0;
808
809 if (bindings[i]) {
810 tern_insert_path(config, full_key, (tern_val){.ptrval = strdup(bindings[i])}, TVAL_PTR);
811 } else {
812 tern_val prev_val;
813 uint8_t prev_type = tern_delete_path(&config, full_key, &prev_val);
814 if (prev_type == TVAL_PTR) {
815 free(prev_val.ptrval);
816 }
817 }
818
819 free(full_key);
820 }
821 }
822
823 static pad_bind_config *bindings;
824 static void handle_dest_clicked(uint32_t dest)
825 {
826 char key_buf[12];
827 char *key;
828 switch (dest)
829 {
830 case SIMILAR_CONTROLLERS:
831 key = make_controller_type_key(&selected_controller_info);
832 break;
833 case IDENTICAL_CONTROLLERS:
834 key = render_joystick_type_id(selected_controller);
835 break;
836 case BY_INDEX:
837 snprintf(key_buf, sizeof(key_buf), "%d", selected_controller);
838 key = key_buf;
839 break;
840 default:
841 key = "default";
842 break;
843 }
844 static const char base_path[] = "bindings\0pads";
845 size_t pad_key_size = sizeof(base_path) + strlen(key) + 1;
846 char *pad_key = malloc(pad_key_size);
847 memcpy(pad_key, base_path, sizeof(base_path));
848 strcpy(pad_key + sizeof(base_path), key);
849 static const char dpad_base[] = "dpads\0""0";
850 size_t dpad_key_size = pad_key_size + sizeof(dpad_base);
851 char *dpad_key = malloc(dpad_key_size);
852 memcpy(dpad_key, pad_key, pad_key_size);
853 memcpy(dpad_key + pad_key_size, dpad_base, sizeof(dpad_base));
854 static const char button_base[] = "buttons";
855 size_t button_key_size = pad_key_size + sizeof(button_base);
856 char *button_key = malloc(button_key_size);
857 memcpy(button_key, pad_key, pad_key_size);
858 memcpy(button_key + pad_key_size, button_base, sizeof(button_base));
859
860 char *final_key;
861 for (int i = 0; i < SDL_CONTROLLER_BUTTON_MAX; i++)
862 {
863 char *base;
864 const char *suffix;
865 size_t base_key_len;
866 if ( i < SDL_CONTROLLER_BUTTON_DPAD_UP) {
867 suffix = SDL_GameControllerGetStringForButton(i);
868 base_key_len = button_key_size;
869 base = button_key;
870
871
872 } else {
873 static const char *dir_keys[] = {"up", "down", "left", "right"};
874 suffix = dir_keys[i - SDL_CONTROLLER_BUTTON_DPAD_UP];
875 base = dpad_key;
876 base_key_len = dpad_key_size;
877 }
878 size_t suffix_len = strlen(suffix);
879 final_key = malloc(base_key_len + suffix_len + 2);
880 memcpy(final_key, base, base_key_len);
881 memcpy(final_key + base_key_len, suffix, suffix_len + 1);
882 final_key[base_key_len + suffix_len + 1] = 0;
883 if (bindings->button_binds[i]) {
884 tern_insert_path(config, final_key, (tern_val){.ptrval = strdup(bindings->button_binds[i])}, TVAL_PTR);
885 } else {
886 tern_val prev_val;
887 uint8_t prev_type = tern_delete_path(&config, final_key, &prev_val);
888 if (prev_type == TVAL_PTR) {
889 free(prev_val.ptrval);
890 }
891 }
892 free(final_key);
893 }
894 free(button_key);
895 free(dpad_key);
896
897 static const char axes_base[] = "axes";
898 size_t axes_key_size = pad_key_size + sizeof(axes_base);
899 char *axes_key = malloc(axes_key_size);
900 memcpy(axes_key, pad_key, pad_key_size);
901 memcpy(axes_key + pad_key_size, axes_base, sizeof(axes_base));
902
903 save_stick_binds(axes_key, axes_key_size,bindings->left_stick, "left");
904 save_stick_binds(axes_key, axes_key_size,bindings->right_stick, "right");
905 for (int i = SDL_CONTROLLER_AXIS_TRIGGERLEFT; i < SDL_CONTROLLER_AXIS_MAX; i++)
906 {
907 const char *suffix = SDL_GameControllerGetStringForAxis(i);
908 size_t suffix_len = strlen(suffix);
909 final_key = malloc(axes_key_size + suffix_len + 2);
910 memcpy(final_key, axes_key, axes_key_size);
911 memcpy(final_key + axes_key_size, suffix, suffix_len + 1);
912 final_key[axes_key_size + suffix_len + 1] = 0;
913 if (bindings->triggers[i - SDL_CONTROLLER_AXIS_TRIGGERLEFT]) {
914 tern_insert_path(config, final_key, (tern_val){.ptrval = strdup(bindings->triggers[i - SDL_CONTROLLER_AXIS_TRIGGERLEFT])}, TVAL_PTR);
915 } else {
916 tern_val prev_val;
917 uint8_t prev_type = tern_delete_path(&config, final_key, &prev_val);
918 if (prev_type == TVAL_PTR) {
919 free(prev_val.ptrval);
920 }
921 }
922 free(final_key);
923 }
924 free(axes_key);
925
926 free(pad_key);
927 if (dest == SIMILAR_CONTROLLERS) {
928 free(key);
929 }
930 pop_view();
931 config_dirty = 1;
932 }
933
934 void view_select_binding_dest(struct nk_context *context)
935 {
936 static menu_item options[NUM_DEST_TYPES];
937 options[IDENTICAL_CONTROLLERS].title = "Use for identical controllers";
938 options[DEFAULT].title = "Use as default";
939 options[BY_INDEX].title = by_index_names[selected_controller];
940 options[SIMILAR_CONTROLLERS].title = make_human_readable_type_name(&selected_controller_info);
941
942 if (nk_begin(context, "Select Binding Dest", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) {
943 menu(context, NUM_DEST_TYPES, options, handle_dest_clicked);
944 nk_end(context);
945 }
946 free((char *)options[SIMILAR_CONTROLLERS].title);
947 }
948
768 void view_controller_bindings(struct nk_context *context) 949 void view_controller_bindings(struct nk_context *context)
769 { 950 {
770 static pad_bind_config *bindings;
771 if (nk_begin(context, "Controller Bindings", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) { 951 if (nk_begin(context, "Controller Bindings", nk_rect(0, 0, render_width(), render_height()), NK_WINDOW_NO_SCROLLBAR)) {
772 if (!bindings) { 952 if (!bindings) {
773 bindings = calloc(1, sizeof(*bindings)); 953 bindings = calloc(1, sizeof(*bindings));
774 tern_node *pad = get_binding_node_for_pad(selected_controller); 954 tern_node *pad = get_binding_node_for_pad(selected_controller);
775 if (pad) { 955 if (pad) {
890 1070
891 def_font->handle.height = orig_height; 1071 def_font->handle.height = orig_height;
892 nk_layout_row_static(context, orig_height + 4, (render_width() - 2*orig_height) / 4, 1); 1072 nk_layout_row_static(context, orig_height + 4, (render_width() - 2*orig_height) / 4, 1);
893 if (nk_button_label(context, "Back")) { 1073 if (nk_button_label(context, "Back")) {
894 pop_view(); 1074 pop_view();
1075 if (controller_binding_changed) {
1076 push_view(view_select_binding_dest);
1077 }
895 } 1078 }
896 nk_end(context); 1079 nk_end(context);
897 } 1080 }
898 } 1081 }
899 1082
981 mapping_string[mapping_pos] = 0; 1164 mapping_string[mapping_pos] = 0;
982 save_controller_mapping(selected_controller, mapping_string); 1165 save_controller_mapping(selected_controller, mapping_string);
983 free(mapping_string); 1166 free(mapping_string);
984 pop_view(); 1167 pop_view();
985 push_view(view_controller_bindings); 1168 push_view(view_controller_bindings);
1169 controller_binding_changed = 0;
986 } 1170 }
987 } 1171 }
988 } 1172 }
989 button_pressed = -1; 1173 button_pressed = -1;
990 hat_moved = -1; 1174 hat_moved = -1;
1029 save_controller_info(selected_controller, &selected_controller_info); 1213 save_controller_info(selected_controller, &selected_controller_info);
1030 pop_view(); 1214 pop_view();
1031 SDL_GameController *controller = render_get_controller(selected_controller); 1215 SDL_GameController *controller = render_get_controller(selected_controller);
1032 if (controller) { 1216 if (controller) {
1033 push_view(view_controller_bindings); 1217 push_view(view_controller_bindings);
1218 controller_binding_changed = 0;
1034 SDL_GameControllerClose(controller); 1219 SDL_GameControllerClose(controller);
1035 } else { 1220 } else {
1036 current_button = SDL_CONTROLLER_BUTTON_A; 1221 current_button = SDL_CONTROLLER_BUTTON_A;
1037 button_pressed = -1; 1222 button_pressed = -1;
1038 last_button = -1; 1223 last_button = -1;
1125 selected_controller_info = info; 1310 selected_controller_info = info;
1126 if (info.type == TYPE_UNKNOWN || info.type == TYPE_GENERIC_MAPPING) { 1311 if (info.type == TYPE_UNKNOWN || info.type == TYPE_GENERIC_MAPPING) {
1127 push_view(view_controller_type); 1312 push_view(view_controller_type);
1128 } else { 1313 } else {
1129 push_view(view_controller_bindings); 1314 push_view(view_controller_bindings);
1315 controller_binding_changed = 0;
1130 } 1316 }
1131 1317
1132 } 1318 }
1133 nk_layout_row_end(context); 1319 nk_layout_row_end(context);
1134 } 1320 }
1525 {"System", view_system_settings}, 1711 {"System", view_system_settings},
1526 {"Back", view_back} 1712 {"Back", view_back}
1527 }; 1713 };
1528 1714
1529 if (nk_begin(context, "Settings Menu", nk_rect(0, 0, render_width(), render_height()), 0)) { 1715 if (nk_begin(context, "Settings Menu", nk_rect(0, 0, render_width(), render_height()), 0)) {
1530 menu(context, sizeof(items)/sizeof(*items), items); 1716 menu(context, sizeof(items)/sizeof(*items), items, NULL);
1531 nk_end(context); 1717 nk_end(context);
1532 } 1718 }
1719 }
1720
1721 void exit_handler(uint32_t index)
1722 {
1723 exit(0);
1533 } 1724 }
1534 1725
1535 void view_pause(struct nk_context *context) 1726 void view_pause(struct nk_context *context)
1536 { 1727 {
1537 static menu_item items[] = { 1728 static menu_item items[] = {
1543 {"Settings", view_settings}, 1734 {"Settings", view_settings},
1544 {"Exit", NULL} 1735 {"Exit", NULL}
1545 }; 1736 };
1546 1737
1547 if (nk_begin(context, "Main Menu", nk_rect(0, 0, render_width(), render_height()), 0)) { 1738 if (nk_begin(context, "Main Menu", nk_rect(0, 0, render_width(), render_height()), 0)) {
1548 menu(context, sizeof(items)/sizeof(*items), items); 1739 menu(context, sizeof(items)/sizeof(*items), items, exit_handler);
1549 nk_end(context); 1740 nk_end(context);
1550 } 1741 }
1551 } 1742 }
1552 1743
1553 void view_menu(struct nk_context *context) 1744 void view_menu(struct nk_context *context)
1558 {"About", view_about}, 1749 {"About", view_about},
1559 {"Exit", NULL} 1750 {"Exit", NULL}
1560 }; 1751 };
1561 1752
1562 if (nk_begin(context, "Main Menu", nk_rect(0, 0, render_width(), render_height()), 0)) { 1753 if (nk_begin(context, "Main Menu", nk_rect(0, 0, render_width(), render_height()), 0)) {
1563 menu(context, sizeof(items)/sizeof(*items), items); 1754 menu(context, sizeof(items)/sizeof(*items), items, exit_handler);
1564 nk_end(context); 1755 nk_end(context);
1565 } 1756 }
1566 } 1757 }
1567 1758
1568 void blastem_nuklear_render(void) 1759 void blastem_nuklear_render(void)