# HG changeset patch # User Michael Pavone # Date 1512148963 28800 # Node ID e890971f37579b381a26a536f113973c60054d56 # Parent 919c0c33885e02c74134b858328c98ae93b47585 Somewhat fleshed out video settings view diff -r 919c0c33885e -r e890971f3757 nuklear_ui/blastem_nuklear.c --- 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); diff -r 919c0c33885e -r e890971f3757 tern.c --- 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; diff -r 919c0c33885e -r e890971f3757 tern.h --- 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);