changeset 1522:63659fb92db4 nuklear_ui

Key binding menu is now functional
author Michael Pavone <pavone@retrodev.com>
date Tue, 06 Feb 2018 22:42:16 -0800
parents a51721408c15
children c416ace65ff1
files Makefile nuklear_ui/blastem_nuklear.c tern.c tern.h
diffstat 4 files changed, 148 insertions(+), 4 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Mon Feb 05 23:39:14 2018 -0800
+++ b/Makefile	Tue Feb 06 22:42:16 2018 -0800
@@ -65,8 +65,8 @@
 endif #Windows
 
 ifdef DEBUG
-CFLAGS:=-ggdb $(CFLAGS)
-LDFLAGS:=-ggdb $(LDFLAGS)
+CFLAGS:=-g3 $(CFLAGS)
+LDFLAGS:=-g3 $(LDFLAGS)
 else
 ifdef NOLTO
 CFLAGS:=-O2 $(CFLAGS)
--- a/nuklear_ui/blastem_nuklear.c	Mon Feb 05 23:39:14 2018 -0800
+++ b/nuklear_ui/blastem_nuklear.c	Tue Feb 06 22:42:16 2018 -0800
@@ -235,6 +235,7 @@
 	*binding_lookup = tern_insert_ptr(*binding_lookup, val.ptrval, strdup(key));
 }
 
+static int32_t keycode;
 static const char *set_binding;
 char *set_label;
 void binding_group(struct nk_context *context, char *name, const char **binds, const char **bind_names, uint32_t num_binds, tern_node *binding_lookup)
@@ -254,6 +255,7 @@
 			if (nk_button_label(context, tern_find_ptr_default(binding_lookup, binds[i], "Not Set"))) {
 				set_binding = binds[i];
 				set_label = strdup(label);
+				keycode = 0;
 			}
 			if (label_alloc) {
 				free(label_alloc);
@@ -263,6 +265,61 @@
 	}
 }
 
+static char *get_key_name(int32_t keycode)
+{
+	char *name = NULL;
+	if (keycode > ' ' && keycode < 0x80) {
+		//key corresponds to a printable non-whitespace character
+		name = malloc(2);
+		name[0] = keycode;
+		name[1] = 0;
+	} else {
+		switch (keycode)
+		{
+		case RENDERKEY_UP: name = "up"; break;
+		case RENDERKEY_DOWN: name = "down"; break;
+		case RENDERKEY_LEFT: name = "left"; break;
+		case RENDERKEY_RIGHT: name = "right"; break;
+		case '\r': name = "enter"; break;
+		case ' ': name = "space"; break;
+		case '\t': name = "tab"; break;
+		case '\b': name = "backspace"; break;
+		case RENDERKEY_ESC: name = "esc"; break;
+		case RENDERKEY_DEL: name = "delete"; break;
+		case RENDERKEY_LSHIFT: name = "lshift"; break;
+		case RENDERKEY_RSHIFT: name = "rshift"; break;
+		case RENDERKEY_LCTRL: name = "lctrl"; break;
+		case RENDERKEY_RCTRL: name = "rctrl"; break;
+		case RENDERKEY_LALT: name = "lalt"; break;
+		case RENDERKEY_RALT: name = "ralt"; break;
+		case RENDERKEY_HOME: name = "home"; break;
+		case RENDERKEY_END: name = "end"; break;
+		case RENDERKEY_PAGEUP: name = "pageup"; break;
+		case RENDERKEY_PAGEDOWN: name = "pagedown"; break;
+		case RENDERKEY_F1: name = "f1"; break;
+		case RENDERKEY_F2: name = "f2"; break;
+		case RENDERKEY_F3: name = "f3"; break;
+		case RENDERKEY_F4: name = "f4"; break;
+		case RENDERKEY_F5: name = "f5"; break;
+		case RENDERKEY_F6: name = "f6"; break;
+		case RENDERKEY_F7: name = "f7"; break;
+		case RENDERKEY_F8: name = "f8"; break;
+		case RENDERKEY_F9: name = "f9"; break;
+		case RENDERKEY_F10: name = "f10"; break;
+		case RENDERKEY_F11: name = "f11"; break;
+		case RENDERKEY_F12: name = "f12"; break;
+		case RENDERKEY_SELECT: name = "select"; break;
+		case RENDERKEY_PLAY: name = "play"; break;
+		case RENDERKEY_SEARCH: name = "search"; break;
+		case RENDERKEY_BACK: name = "back"; break;
+		}
+		if (name) {
+			name = strdup(name);
+		}
+	}
+	return name;
+}
+
 void view_key_bindings(struct nk_context *context)
 {
 	const char *controller1_binds[] = {
@@ -282,7 +339,7 @@
 		"ui.screenshot", "ui.sms_pause", "ui.toggle_keyboard_cpatured", "ui.release_mouse"
 	};
 	const char *general_names[] = {
-		"Show Menu", "Quick Save", "Toggle Fullscreen", "Soft Reset", "Reload Media"
+		"Show Menu", "Quick Save", "Toggle Fullscreen", "Soft Reset", "Reload Media",
 		"Internal Screenshot", "SMS Pause", "Capture Keyboard", "Release Mouse"
 	};
 	const char *speed_binds[] = {
@@ -331,6 +388,36 @@
 		if (nk_button_label(context, "Cancel")) {
 			free(set_label);
 			set_binding = set_label = NULL;
+		} else if (keycode) {
+			char *name = get_key_name(keycode);
+			if (name) {
+				uint32_t prefix_len = strlen("bindings") + strlen("keys") + 2;
+				char * old = tern_find_ptr(binding_lookup, set_binding);
+				if (old) {
+					uint32_t suffix_len = strlen(old) + 1;
+					char *old_path = malloc(prefix_len + suffix_len + 1);
+					memcpy(old_path, "bindings\0keys\0", prefix_len);
+					memcpy(old_path + prefix_len, old, suffix_len);
+					old_path[prefix_len + suffix_len] = 0;
+					tern_val old_val;
+					if (tern_delete_path(&config, old_path, &old_val) == TVAL_PTR) {
+						free(old_val.ptrval);
+					}
+				}
+				uint32_t suffix_len = strlen(name) + 1;
+				char *path = malloc(prefix_len + suffix_len + 1);
+				memcpy(path, "bindings\0keys\0", prefix_len);
+				memcpy(path + prefix_len, name, suffix_len);
+				path[prefix_len + suffix_len] = 0;
+				
+				config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(set_binding)}, TVAL_PTR);
+				free(path);
+				free(name);
+				tern_free(binding_lookup);
+				binding_lookup = NULL;
+			}
+			free(set_label);
+			set_binding = set_label = NULL;
 		}
 		nk_end(context);
 	}
@@ -753,6 +840,9 @@
 }
 static void handle_event(SDL_Event *event)
 {
+	if (event->type == SDL_KEYDOWN) {
+		keycode = event->key.keysym.sym;
+	}
 	nk_sdl_handle_event(event);
 }
 
--- a/tern.c	Mon Feb 05 23:39:14 2018 -0800
+++ b/tern.c	Tue Feb 06 22:42:16 2018 -0800
@@ -138,6 +138,39 @@
 	return NULL;
 }
 
+uint8_t tern_delete(tern_node **head, char const *key, tern_val *out)
+{
+	tern_node *cur = *head, **last = head;
+	while (cur)
+	{
+		if (cur->el == *key) {
+			if (*key) {
+				last = &cur->straight.next;
+				cur = cur->straight.next;
+				key++;
+			} else {
+				break;
+			}
+		} else if (*key < cur->el) {
+			last = &cur->left;
+			cur = cur->left;
+		} else {
+			last = &cur->right;
+			cur = cur->right;
+		}
+	}
+	if (!cur) {
+		return TVAL_NONE;
+	}
+	*last = cur->right;
+	uint8_t valtype = cur->valtype;
+	if (out) {
+		*out = cur->straight.value;
+	}
+	free(cur);
+	return valtype;
+}
+
 tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype)
 {
 	tern_val ret;
@@ -193,6 +226,25 @@
 	}
 }
 
+uint8_t tern_delete_path(tern_node **head, char const *key, tern_val *out)
+{
+	const char *next_key = key + strlen(key) + 1;
+	if (*next_key) {
+		tern_node *child = tern_find_node(*head, key);
+		if (!child) {
+			return TVAL_NONE;
+		}
+		tern_node *tmp = child;
+		uint8_t valtype = tern_delete_path(&tmp, next_key, out);
+		if (tmp != child) {
+			*head = tern_insert_node(*head, key, tmp);
+		}
+		return valtype;
+	} else {
+		return tern_delete(head, key, out);
+	}
+}
+
 uint32_t tern_count(tern_node *head)
 {
 	uint32_t count = 0;
@@ -220,7 +272,7 @@
 	if (head->left) {
 		tern_foreach_int(head->left, fun, data, keybuf, pos);
 	}
-	if (head->el) {
+	if (head->el && head->straight.next) {
 		if (pos == MAX_ITER_KEY) {
 			fatal_error("tern_foreach_int: exceeded maximum key size");
 		}
--- a/tern.h	Mon Feb 05 23:39:14 2018 -0800
+++ b/tern.h	Tue Feb 06 22:42:16 2018 -0800
@@ -43,8 +43,10 @@
 void * tern_find_ptr_default(tern_node * head, char const * key, void * def);
 void * tern_find_ptr(tern_node * head, char const * key);
 tern_node *tern_find_node(tern_node *head, char const *key);
+uint8_t tern_delete(tern_node **head, char const *key, tern_val *out);
 tern_val tern_find_path_default(tern_node *head, char const *key, tern_val def, uint8_t req_valtype);
 tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype);
+uint8_t tern_delete_path(tern_node **head, char const *key, tern_val *out);
 tern_node * tern_insert_ptr(tern_node * head, char const * key, void * value);
 tern_node * tern_insert_node(tern_node *head, char const *key, tern_node *value);
 tern_node *tern_insert_path(tern_node *head, char const *key, tern_val val, uint8_t valtype);