changeset 1491:e890971f3757 nuklear_ui

Somewhat fleshed out video settings view
author Michael Pavone <pavone@retrodev.com>
date Fri, 01 Dec 2017 09:22:43 -0800
parents 919c0c33885e
children bdeb2a1d0385
files nuklear_ui/blastem_nuklear.c tern.c tern.h
diffstat 3 files changed, 120 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/nuklear_ui/blastem_nuklear.c	Wed Nov 29 08:53:47 2017 -0800
+++ b/nuklear_ui/blastem_nuklear.c	Fri Dec 01 09:22:43 2017 -0800
@@ -16,7 +16,31 @@
 
 typedef void (*view_fun)(struct nk_context *);
 static view_fun current_view;
-static view_fun previous_view;
+static view_fun *previous_views;
+static uint32_t view_storage;
+static uint32_t num_prev;
+
+static void push_view(view_fun new_view)
+{
+	if (num_prev == view_storage) {
+		view_storage = view_storage ? 2*view_storage : 2;
+		previous_views = realloc(previous_views, view_storage*sizeof(view_fun));
+	}
+	previous_views[num_prev++] = current_view;
+	current_view = new_view;
+}
+
+static void pop_view()
+{
+	if (num_prev) {
+		current_view = previous_views[--num_prev];
+	}
+}
+
+static void clear_view_stack()
+{
+	num_prev = 0;
+}
 
 void view_play(struct nk_context *context)
 {
@@ -69,7 +93,7 @@
 		}
 		nk_layout_row_static(context, 52, width > 600 ? 300 : width / 2, 2);
 		if (nk_button_label(context, "Back")) {
-			current_view = previous_view;
+			pop_view();
 		}
 		if (nk_button_label(context, "Open")) {
 			char *full_path = path_append(current_path, entries[selected_entry].name);
@@ -91,6 +115,7 @@
 					lockon_media(full_path);
 					free(full_path);
 				}
+				clear_view_stack();
 				current_view = view_play;
 			}
 		}
@@ -143,7 +168,7 @@
 		}
 		nk_layout_row_static(context, 52, width > 600 ? 300 : width / 2, 2);
 		if (nk_button_label(context, "Back")) {
-			current_view = previous_view;
+			pop_view();
 		}
 		if (is_load) {
 			if (nk_button_label(context, "Load")) {
@@ -187,8 +212,7 @@
 	{
 		nk_layout_space_push(context, nk_rect(left, top + i * button_height, button_width, button_height-button_space));
 		if (nk_button_label(context, items[i].title)) {
-			previous_view = current_view;
-			current_view = items[i].next_view;
+			push_view(items[i].next_view);
 			if (!current_view) {
 				exit(0);
 			}
@@ -209,9 +233,72 @@
 {
 	
 }
+
+void settings_toggle(struct nk_context *context, char *label, char *path, uint8_t def)
+{
+	uint8_t curval = !strcmp("on", tern_find_path_default(config, path, (tern_val){.ptrval = def ? "on": "off"}, TVAL_PTR).ptrval);
+	nk_label(context, label, NK_TEXT_LEFT);
+	uint8_t newval = nk_check_label(context, "", curval);
+	if (newval != curval) {
+		config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(newval ? "on" : "off")}, TVAL_PTR);
+	}
+}
+
+void settings_int_input(struct nk_context *context, char *label, char *path, char *def)
+{
+	char buffer[12];
+	nk_label(context, label, NK_TEXT_LEFT);
+	uint32_t curval;
+	char *curstr = tern_find_path_default(config, path, (tern_val){.ptrval = def}, TVAL_PTR).ptrval;
+	uint32_t len = strlen(curstr);
+	if (len > 11) {
+		len = 11;
+	}
+	memcpy(buffer, curstr, len);
+	nk_edit_string(context, NK_EDIT_SIMPLE, buffer, &len, sizeof(buffer)-1, nk_filter_decimal);
+	buffer[len] = 0;
+	if (strcmp(buffer, curstr)) {
+		config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR);
+	}
+}
+
+void settings_int_property(struct nk_context *context, char *label, char *name, char *path, int def, int min, int max)
+{
+	char *curstr = tern_find_path(config, path, TVAL_PTR).ptrval;
+	int curval = curstr ? atoi(curstr) : def;
+	nk_label(context, label, NK_TEXT_LEFT);
+	int val = curval;
+	nk_property_int(context, name, min, &val, max, 1, 1.0f);
+	if (val != curval) {
+		char buffer[12];
+		sprintf(buffer, "%d", val);
+		config = tern_insert_path(config, path, (tern_val){.ptrval = strdup(buffer)}, TVAL_PTR);
+	}
+}
+
 void view_video_settings(struct nk_context *context)
 {
-	
+	uint32_t width = render_width();
+	uint32_t height = render_height();
+	if (nk_begin(context, "Video Settings", nk_rect(0, 0, width, height), 0)) {
+		nk_layout_row_static(context, 30, width > 300 ? 300 : width, 2);
+		settings_toggle(context, "Fullscreen", "video\0fullscreen\0", 0);
+		settings_toggle(context, "Open GL", "video\0gl\0", 1);
+		settings_toggle(context, "Scanlines", "video\0scanlines\0", 0);
+		settings_int_input(context, "Windowed Width", "video\0width\0", "640");
+		settings_int_property(context, "NTSC Overscan", "Top", "video\0ntsc\0overscan\0top\0", 2, 0, 32);
+		settings_int_property(context, "", "Bottom", "video\0ntsc\0overscan\0bottom\0", 17, 0, 32);
+		settings_int_property(context, "", "Left", "video\0ntsc\0overscan\0left\0", 13, 0, 32);
+		settings_int_property(context, "", "Right", "video\0ntsc\0overscan\0right\0", 14, 0, 32);
+		settings_int_property(context, "PAL Overscan", "Top", "video\0pal\0overscan\0top\0", 2, 0, 32);
+		settings_int_property(context, "", "Bottom", "video\0pal\0overscan\0bottom\0", 17, 0, 32);
+		settings_int_property(context, "", "Left", "video\0pal\0overscan\0left\0", 13, 0, 32);
+		settings_int_property(context, "", "Right", "video\0pal\0overscan\0right\0", 14, 0, 32);
+		if (nk_button_label(context, "Back")) {
+			pop_view();
+		}
+		nk_end(context);
+	}
 }
 void view_audio_settings(struct nk_context *context)
 {
@@ -222,6 +309,13 @@
 	
 }
 
+void view_back(struct nk_context *context)
+{
+	pop_view();
+	pop_view();
+	current_view(context);
+}
+
 void view_settings(struct nk_context *context)
 {
 	static menu_item items[] = {
@@ -230,11 +324,10 @@
 		{"Video", view_video_settings},
 		{"Audio", view_audio_settings},
 		{"System", view_system_settings},
-		{"Back", NULL}
+		{"Back", view_back}
 	};
 	
 	const uint32_t num_buttons = 6;
-	items[num_buttons-1].next_view = previous_view;
 	if (nk_begin(context, "Settings Menu", nk_rect(0, 0, render_width(), render_height()), 0)) {
 		menu(context, sizeof(items)/sizeof(*items), items);
 		nk_end(context);
--- a/tern.c	Wed Nov 29 08:53:47 2017 -0800
+++ b/tern.c	Fri Dec 01 09:22:43 2017 -0800
@@ -45,6 +45,12 @@
 		(*cur)->left = NULL;
 		(*cur)->right = NULL;
 		(*cur)->el = 0;
+		(*cur)->valtype = TVAL_NONE;
+	}
+	if ((*cur)->valtype == TVAL_PTR) {
+		//not freeing tern nodes can also cause leaks, but handling freeing those here is problematic
+		//since updating a sub-tree may involve creating a new root node
+		free((*cur)->straight.value.ptrval);
 	}
 	(*cur)->straight.value = value;
 	(*cur)->valtype = valtype;
@@ -175,6 +181,18 @@
 	return tern_insert(head, key, val, TVAL_NODE);
 }
 
+tern_node *tern_insert_path(tern_node *head, char const *key, tern_val val, uint8_t valtype)
+{
+	const char *next_key = key + strlen(key) + 1;
+	if (*next_key) {
+		tern_node *child = tern_find_node(head, key);
+		child = tern_insert_path(child, next_key, val, valtype);
+		return tern_insert_node(head, key, child);
+	} else {
+		return tern_insert(head, key, val, valtype);
+	}
+}
+
 uint32_t tern_count(tern_node *head)
 {
 	uint32_t count = 0;
--- a/tern.h	Wed Nov 29 08:53:47 2017 -0800
+++ b/tern.h	Fri Dec 01 09:22:43 2017 -0800
@@ -47,6 +47,7 @@
 tern_val tern_find_path(tern_node *head, char const *key, uint8_t valtype);
 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);
 uint32_t tern_count(tern_node *head);
 void tern_foreach(tern_node *head, iter_fun fun, void *data);
 char * tern_int_key(uint32_t key, char * buf);