diff --git a/demo/common/nuklear_console_demo.c b/demo/common/nuklear_console_demo.c index 30fa483..bbcf6f1 100644 --- a/demo/common/nuklear_console_demo.c +++ b/demo/common/nuklear_console_demo.c @@ -143,6 +143,11 @@ void nk_console_demo_list_view_item_clicked(struct nk_console* widget, void* use nk_console_show_message(widget, message); } +void nk_console_demo_navigate_to_path(struct nk_console* button, void* user_data) { + NK_UNUSED(button); + nk_console_navigate_to_path(button, (const char*)user_data); +} + struct nk_console* nuklear_console_demo_init(struct nk_context* ctx, void* user_data, struct nk_image image) { console = nk_console_init(ctx); @@ -450,6 +455,22 @@ struct nk_console* nuklear_console_demo_init(struct nk_context* ctx, void* user_ calc->tooltip = "Demo rows and grids!"; } + // Open Path + struct nk_console* open_path = nk_console_button(console, "Open Path"); + { + nk_console_label(open_path, "Navigate anywhere with nk_console_navigate_to_path():"); + struct nk_console* b; + b = nk_console_button(open_path, "Widgets"); + nk_console_add_event_handler(b, NK_CONSOLE_EVENT_CLICKED, &nk_console_demo_navigate_to_path, "Widgets", NULL); + b = nk_console_button(open_path, "Widgets/Labels"); + nk_console_add_event_handler(b, NK_CONSOLE_EVENT_CLICKED, &nk_console_demo_navigate_to_path, "Widgets/Labels", NULL); + b = nk_console_button(open_path, "Widgets/Sliders"); + nk_console_add_event_handler(b, NK_CONSOLE_EVENT_CLICKED, &nk_console_demo_navigate_to_path, "Widgets/Sliders", NULL); + b = nk_console_button(open_path, "Calculator"); + nk_console_add_event_handler(b, NK_CONSOLE_EVENT_CLICKED, &nk_console_demo_navigate_to_path, "Calculator", NULL); + nk_console_button_onclick(open_path, "Back", &nk_console_button_back); + } + nk_console_button(console, "Save Game")->disabled = nk_true; struct nk_console* quit_button = nk_console_button_onclick(console, "Quit Game", &button_clicked); nk_console_add_event(quit_button, NK_CONSOLE_EVENT_FOCUS, &nk_console_quit_button_focused); diff --git a/nuklear_console.h b/nuklear_console.h index 982321e..b8d3df1 100644 --- a/nuklear_console.h +++ b/nuklear_console.h @@ -237,6 +237,33 @@ NK_API void nk_console_set_user_data(nk_console* console, void* user_data); */ NK_API void nk_console_navigate_back(nk_console* leaving_parent); +/** + * Get a widget by a slash-separated path of labels, starting from the top-level console. + * + * Example: nk_console_find_by_path(console, "Widgets/Labels") + * A leading slash is optional: "/Widgets" and "Widgets" are equivalent. + * + * @param console Any widget within the console family. + * @param path Slash-separated widget labels (e.g. "Widgets/Labels"). + * + * @return The matching widget, or NULL if not found. + */ +NK_API nk_console* nk_console_find_by_path(nk_console* console, const char* path); + +/** + * Navigate to a widget by a slash-separated path of labels. + * + * If the target widget has children, it becomes the active parent. If it has no children, its parent becomes the active parent and the widget is selected as the active widget. + * + * Example: nk_console_navigate_to_path(console, "Widgets/Labels") + * + * @param console Any widget within the console family. + * @param path Slash-separated widget labels (e.g. "Widgets/Labels"). + * + * @return nk_true if navigation succeeded, nk_false if the path was not found. + */ +NK_API nk_bool nk_console_navigate_to_path(nk_console* console, const char* path); + #if defined(__cplusplus) } #endif @@ -1206,6 +1233,79 @@ NK_API void nk_console_navigate_back(nk_console* leaving_parent) { nk_console_trigger_event(leaving_parent, NK_CONSOLE_EVENT_BACK); } +NK_API nk_console* nk_console_find_by_path(nk_console* console, const char* path) { + if (console == NULL || path == NULL) { + return NULL; + } + + nk_console* current = nk_console_get_top(console); + if (path[0] == '\0') { + return current; + } + if (path[0] == '/') { + path++; + } + + char segment[256]; + while (path[0] != '\0') { + const char* slash = strchr(path, '/'); + int len = (slash != NULL) ? (int)(slash - path) : (int)nk_strlen(path); + if (len == 0) { + path++; + continue; + } + + int copy_len = len < 255 ? len : 255; + NK_MEMCPY(segment, path, (nk_size)copy_len); + segment[copy_len] = '\0'; + + nk_console* found = NULL; + if (current->children != NULL) { + for (size_t i = 0; i < cvector_size(current->children); i++) { + nk_console* child = current->children[i]; + if (child == NULL || child->label == NULL) { + continue; + } + int label_len = child->label_length > 0 + ? child->label_length + : (int)nk_strlen(child->label); + if (label_len == copy_len && + strncmp(child->label, segment, (size_t)copy_len) == 0) { + found = child; + break; + } + } + } + if (found == NULL) { + return NULL; + } + current = found; + path += len; + if (path[0] == '/') { + path++; + } + } + return current; +} + +NK_API nk_bool nk_console_navigate_to_path(nk_console* console, const char* path) { + nk_console* target = nk_console_find_by_path(console, path); + if (target == NULL) { + return nk_false; + } + + if (target->children != NULL) { + nk_console_set_active_parent(target); + } + else { + if (target->parent != NULL) { + nk_console_set_active_parent(target->parent); + } + nk_console_set_active_widget(target); + } + return nk_true; +} + NK_API nk_bool nk_console_button_pushed(nk_console* console, int button) { if (console == NULL) { return nk_false;