Mercurial > repos > blastem
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) |