From 48ecfdef3ad4c5fca56bd36bcba5ae9825c0b57b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Madar=C3=A1sz?= Date: Sat, 28 Oct 2023 14:16:41 +0200 Subject: [PATCH] sync fwk --- bind/v4k.lua | 20 +- engine/joint/v4k.h | 1058 ++++++++++++++++-------- engine/split/3rd_nuklear.h | 9 +- engine/split/3rd_nuklear_filebrowser.h | 116 ++- engine/split/v4k.c.inl | 32 +- engine/split/v4k.h.inl | 30 +- engine/split/v4k.x.inl | 1 + engine/split/v4k_ai.c | 2 +- engine/split/v4k_begin.c | 3 + engine/split/v4k_config.h | 2 + engine/split/v4k_editor.c | 229 +++++ engine/split/v4k_editor.h | 2 + engine/split/v4k_obj.c | 69 +- engine/split/v4k_obj.h | 31 +- engine/split/v4k_reflect.c | 3 +- engine/split/v4k_ui.c | 302 ++++++- engine/split/v4k_ui.h | 1 + engine/split/v4k_window.c | 225 +---- engine/v4k | 126 ++- engine/v4k.c | 866 ++++++++++++------- engine/v4k.h | 66 +- 21 files changed, 2119 insertions(+), 1074 deletions(-) create mode 100644 engine/split/v4k_begin.c diff --git a/bind/v4k.lua b/bind/v4k.lua index 9b84397..844b263 100644 --- a/bind/v4k.lua +++ b/bind/v4k.lua @@ -2128,6 +2128,7 @@ typedef union json_t { char* s; double f; int64_t i; uintptr_t p; union json_t* int* engine_geti(const char *key); char** engine_gets(const char *key); int engine_send(const char *cmd, const char *optional_value); + int ui_debug(); char* dialog_load(); char* dialog_save(); int gizmo(vec3 *pos, vec3 *rot, vec3 *sca); @@ -2493,8 +2494,8 @@ enum { NETWORK_USERID = 7, NETWORK_COUNT , NETWORK_CAPACITY }; void server_send_bin(int64_t handle, const void *ptr, int len); void server_drop(int64_t handle); int64_t client_join(const char *ip, int port); -typedef struct obj { struct { union { uintptr_t objheader; struct { uintptr_t objtype:8; uintptr_t objsizew:8; uintptr_t objrefs:8; uintptr_t objheap:1; uintptr_t objcomps:1; uintptr_t objunused:64-8-8-8-1-1-16-3; uintptr_t objid:16+3; }; }; ifdef(debug,const char *objname;) }; } obj; -typedef struct entity { struct { union { uintptr_t objheader; struct { uintptr_t objtype:8; uintptr_t objsizew:8; uintptr_t objrefs:8; uintptr_t objheap:1; uintptr_t objcomps:1; uintptr_t objunused:64-8-8-8-1-1-16-3; uintptr_t objid:16+3; }; }; union { struct { uintptr_t objenabled:32, objflagged:32; }; uintptr_t cflags; }; void *c[32]; }; } entity; +typedef struct obj { struct { ifdef(debug, const char *objname;) union { uintptr_t objheader; struct { uintptr_t objtype:8; uintptr_t objsizew:8; uintptr_t objrefs:8; uintptr_t objheap:1; uintptr_t objcomps:1; uintptr_t objunused:64-8-8-8-1-1-16-3; uintptr_t objid:16+3; }; }; struct obj** objchildren; }; } obj; +typedef struct entity { struct { struct { ifdef(debug, const char *objname;) union { uintptr_t objheader; struct { uintptr_t objtype:8; uintptr_t objsizew:8; uintptr_t objrefs:8; uintptr_t objheap:1; uintptr_t objcomps:1; uintptr_t objunused:64-8-8-8-1-1-16-3; uintptr_t objid:16+3; }; }; struct obj** objchildren; }; union { struct { uintptr_t objenabled:32, objflagged:32; }; uintptr_t cflags; }; void *c[32]; }; } entity; obj *objtmp; void* obj_malloc(unsigned sz); void* obj_free(void *o); @@ -2559,16 +2560,16 @@ void* obj_free(void *o); obj* obj_loadmpack(void *o, const char *sav); int obj_push(const void *o); int obj_pop(void *o); - bool obj_addcomponent(void *object, unsigned c, void *ptr); - bool obj_hascomponent(void *object, unsigned c); - void* obj_getcomponent(void *object, unsigned c); - bool obj_delcomponent(void *object, unsigned c); - bool obj_usecomponent(void *object, unsigned c); - bool obj_offcomponent(void *object, unsigned c); + bool obj_addcomponent(entity *e, unsigned c, void *ptr); + bool obj_hascomponent(entity *e, unsigned c); + void* obj_getcomponent(entity *e, unsigned c); + bool obj_delcomponent(entity *e, unsigned c); + bool obj_usecomponent(entity *e, unsigned c); + bool obj_offcomponent(entity *e, unsigned c); char* entity_save(entity *self); void* obj_clone(const void *src); void* obj_merge(void *dst, const void *src); - void* obj_mutate(void **dst, const void *src); + void* obj_mutate(void *dst, const void *src); void* obj_make(const char *str); typedef enum OBJTYPE_BUILTINS { OBJTYPE_obj = 0, @@ -3324,6 +3325,7 @@ PANEL_OPEN = 1, int ui_hover(); int ui_active(); int ui_demo(int do_windows); + void *ui_handle(); enum VIDEO_FLAGS { VIDEO_YCBCR = 0, VIDEO_RGB = 2, diff --git a/engine/joint/v4k.h b/engine/joint/v4k.h index fb1a2e2..a336a0a 100644 --- a/engine/joint/v4k.h +++ b/engine/joint/v4k.h @@ -13960,7 +13960,20 @@ int gladLoadGL( GLADloadfunc load) { * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ -* ALTERNATIVE B - MIT-0 (No Attribution clause) +* ALTERNATIVE B - 0-BSD License (https://opensource.org/licenses/FPL-1.0.0) +* ------------------------------------------------------------------------------ +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* ------------------------------------------------------------------------------ +* ALTERNATIVE C - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software @@ -13974,19 +13987,6 @@ int gladLoadGL( GLADloadfunc load) { * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* ------------------------------------------------------------------------------ -* ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) -* ------------------------------------------------------------------------------ -* Permission to use, copy, modify, and/or distribute this software for any -* purpose with or without fee is hereby granted. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * @@ -14006,7 +14006,7 @@ int gladLoadGL( GLADloadfunc load) { * -- * * "I dedicate any and all copyright interest in this software to the three -* license terms listed above. I make this dedication for the benefit of the +* licensing terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." @@ -14258,6 +14258,8 @@ extern "C" { #define VA_SELECT_10TH(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10 // VA_SPLIT() expands to A) 1 item OR B) 1 item + ',' + va_args[1..N] #define VA_SPLIT(...) VA_FIRST(__VA_ARGS__) VA_REST(__VA_ARGS__) +// VA_COUNT() counts number of va args +#define VA_COUNT(...) (int)(sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1) #if is(cl) && !is(cpp) #define INLINE __inline @@ -15753,6 +15755,8 @@ API int* engine_geti(const char *key); API char** engine_gets(const char *key); API int engine_send(const char *cmd, const char *optional_value); +API int ui_debug(); + // open file dialog API char* dialog_load(); @@ -16693,6 +16697,8 @@ API int64_t client_join(const char *ip, int port); #endif #define OBJHEADER \ + struct { \ + ifdef(debug, const char *objname;) \ union { \ uintptr_t objheader; \ struct { \ @@ -16704,10 +16710,12 @@ API int64_t client_join(const char *ip, int port); uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \ uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \ }; \ + }; \ + array(struct obj*) objchildren; \ }; #define OBJ \ - struct { OBJHEADER ifdef(debug,const char *objname;) }; + OBJHEADER // ---------------------------------------------------------------------------- // syntax sugars @@ -16756,6 +16764,9 @@ API int64_t client_join(const char *ip, int port); // OBJTYPEDEF(entity,1) typedef struct entity { ENTITY } entity; +#define entity_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) +#define entity_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) + // ---------------------------------------------------------------------------- // heap/stack ctor/dtor @@ -16770,16 +16781,16 @@ static __thread obj *objtmp; obj_ctor(PTR)) #define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \ objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \ - *(TYPE*)objtmp = ((TYPE){ {0}, __VA_ARGS__}), \ + *(TYPE*)objtmp = ((TYPE){ {0,}, __VA_ARGS__}), \ ((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \ ( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \ OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \ ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \ obj_setname(objtmp, NAME)) -#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, sizeof(array(obj*)), __VA_ARGS__) -#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, sizeof(array(obj*)), __VA_ARGS__) -#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, sizeof(array(obj*)), __VA_ARGS__) +#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, 0, __VA_ARGS__) +#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) +#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) void* obj_malloc(unsigned sz); void* obj_free(void *o); @@ -16934,12 +16945,12 @@ API int obj_pop(void *o); // ---------------------------------------------------------------------------- // components -API bool obj_addcomponent(void *object, unsigned c, void *ptr); -API bool obj_hascomponent(void *object, unsigned c); -API void* obj_getcomponent(void *object, unsigned c); -API bool obj_delcomponent(void *object, unsigned c); -API bool obj_usecomponent(void *object, unsigned c); -API bool obj_offcomponent(void *object, unsigned c); +API bool obj_addcomponent(entity *e, unsigned c, void *ptr); +API bool obj_hascomponent(entity *e, unsigned c); +API void* obj_getcomponent(entity *e, unsigned c); +API bool obj_delcomponent(entity *e, unsigned c); +API bool obj_usecomponent(entity *e, unsigned c); +API bool obj_offcomponent(entity *e, unsigned c); API char* entity_save(entity *self); @@ -16955,7 +16966,7 @@ API char* entity_save(entity *self); API void* obj_clone(const void *src); API void* obj_merge(void *dst, const void *src); // @testme -API void* obj_mutate(void **dst, const void *src); +API void* obj_mutate(void *dst, const void *src); API void* obj_make(const char *str); // built-ins @@ -18313,6 +18324,7 @@ API int ui_hover(); // ui_is_hover()? API int ui_active(); // ui_is_active()? API int ui_demo(int do_windows); +API void *ui_handle(); #line 0 #line 1 "engine/split/v4k_video.h" @@ -230475,6 +230487,9 @@ nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type) { +if(body.x < 10) body.x = 0; //< @r-lyeh: popup snapping to the left +if((body.x+body.w)>window_width()) body.x-=body.w-(window_width()-body.x); //< @r-lyeh: prevent popups to be printed outside of window client / right border + struct nk_window *popup; struct nk_window *win; struct nk_panel *panel; @@ -230956,7 +230971,7 @@ nk_menu_begin(struct nk_context *ctx, struct nk_window *win, is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) + if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR_X/*|NK_WINDOW_NO_SCROLLBAR*/, body, header, NK_PANEL_MENU)) //< @r-lyeh: our popups are huge. enable Y scrollbars return 0; win->popup.type = NK_PANEL_MENU; @@ -232190,6 +232205,7 @@ nk_tree_state_base_(struct nk_context *ctx, enum nk_tree_type type, NK_INTERN int nk_tree_base_(struct nk_context *ctx, enum nk_tree_type type, struct nk_image *img, const char *title, enum nk_collapse_states initial_state, + enum nk_collapse_states *forced_state, //< @r-lyeh const char *hash, int len, int line) { struct nk_window *win = ctx->current; @@ -232207,7 +232223,8 @@ nk_tree_base_(struct nk_context *ctx, enum nk_tree_type type, state = nk_add_value(ctx, win, tree_hash, 0); *state = initial_state; } - return nk_tree_state_base_(ctx, type, img, title, (enum nk_collapse_states*)state); + return nk_tree_state_base_(ctx, type, img, title, + forced_state ? forced_state : (enum nk_collapse_states*)state); //< @r-lyeh } #endif NK_API nk_bool @@ -240395,6 +240412,7 @@ void nk_glfw3_shutdown(struct nk_glfw* glfw) #endif #endif #line 0 +static char *ui_filter = 0; #line 1 "engine/split/3rd_nuklear_filebrowser.h" // file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain) // - rlyeh, public domain @@ -240414,8 +240432,56 @@ void nk_glfw3_shutdown(struct nk_glfw* glfw) #else #include // getcwd() #include // getpwuid() +#define _popen popen +#define _pclose pclose #endif +const char** old_file_list(const char *cwd, const char *masks) { + ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); + + static __thread array(char*) list = 0; + const char *arg0 = cwd; // app_path(); + int larg0 = strlen(arg0); + + for( int i = 0; i < array_count(list); ++i ) { + FREE(list[i]); + } + array_resize(list, 0);//array_free(list); + + for each_substring(masks,";",it) { + int recurse = !!strstr(it, "**"); + #if is(win32) + char *glob = va("dir %s/b/o:n \"%s\\%s\" 2> NUL", recurse ? "/s":"", cwd, it); + #else // linux, osx + char *glob = va("find %s %s -name \"%s\" | sort", cwd, !recurse ? "-maxdepth 1":"-type f", it); + #endif + for( FILE *in = _popen(glob, "r"); in; _pclose(in), in = 0) { + char buf[1024], *line = buf; + while( fgets(buf, sizeof(buf), in) ) { + // clean up + if( strstr(line, arg0) ) line = buf + larg0; + if( !memcmp(line, "./", 2) ) line += 2; + int len = strlen(line); while( len > 0 && line[len-1] < 32 ) line[--len] = 0; + if( line[0] == '\0' ) continue; + // do not insert system folders/files + for(int i = 0; i < len; ++i ) if(line[i] == '\\') line[i] = '/'; + if( line[0] == '.' ) if( !strcmp(line,".git") || !strcmp(line,".vs") || !strcmp(line,".") || !strcmp(line,"..") ) continue; + if( strstr(line, "/.") ) continue; + // insert copy + #if is(win32) + char *copy = STRDUP(line); // full path already provided + #else + // while(line[0] == '/') ++line; + char *copy = STRDUP(va("%s%s", cwd, line)); // need to prepend path + #endif + array_push(list, copy); + } + } + } + array_push(list, 0); // terminator + return (const char**)list; +} + #if 1 #define BROWSER_PRINTF(...) do {} while(0) #else @@ -240479,6 +240545,10 @@ struct browser { size_t file_count; size_t dir_count; + /* filtered directory content */ + array(char*) ffiles; + array(char*) fdirectories; + /* view mode */ bool listing; float zooming; @@ -240515,8 +240585,8 @@ static void browser_reload_directory_content(struct browser *browser, const char BROWSER_PRINTF("searching at %s\n", path); - array(char*) list = file_list(path); - for( int i = 0, end = array_count(list); i < end; ++i ) { + const char** list = old_file_list(path, "*"); + for( int i = 0; list[i]; ++i ) { char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); @@ -240581,6 +240651,9 @@ static void browser_free(struct browser *browser) { for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]); array_free(browser->files); array_free(browser->directories); + array_free(browser->ffiles); + array_free(browser->fdirectories); + memset(browser, 0, sizeof(*browser)); } @@ -240661,10 +240734,33 @@ if( cols < 1 ) cols=1; /* output directory content window */ if(nk_group_begin(ctx, "Content", windowed ? NK_WINDOW_NO_SCROLLBAR : 0)) { + + array(char*) *directories = &browser->directories; + array(char*) *files = &browser->files; + + if( ui_filter && ui_filter[0] ) { + array_resize(browser->fdirectories, 0); + array_resize(browser->ffiles, 0); + + for each_array(browser->directories,char*,k) + if( strstri(k, ui_filter) ) + array_push(browser->fdirectories, k); + + for each_array(browser->files,char*,k) + if( strstri(k, ui_filter) ) + array_push(browser->ffiles, k); + + directories = &browser->fdirectories; + files = &browser->ffiles; + } + + int dir_count = array_count(*directories); + int file_count = array_count(*files); + int index = -1; size_t i = 0, j = 0, k = 0; size_t rows = 0; - size_t count = browser->dir_count + browser->file_count; + size_t count = dir_count + file_count; rows = count / cols; for (i = 0; i <= rows; i += 1) { @@ -240672,16 +240768,18 @@ if( cols < 1 ) cols=1; {size_t n = j + cols; nk_layout_row_dynamic(ctx, icon_height, (int)cols); for (; j < count && j < n; ++j) { + size_t t = j-dir_count; + /* draw one row of icons */ - if (j < browser->dir_count) { + if (j < dir_count) { /* draw and execute directory buttons */ if (nk_button_image(ctx,media.custom_folders[BROWSER_FOLDER])) index = (int)j; } else { /* draw and execute files buttons */ struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(browser->files[fileIndex]); + size_t fileIndex = ((size_t)j - dir_count); + icon = media_icon_for_file((*files)[fileIndex]); if (nk_button_image(ctx, *icon)) { snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); clicked = 1; @@ -240692,30 +240790,32 @@ if( cols < 1 ) cols=1; {size_t n = k + cols; nk_layout_row_dynamic(ctx, 20, (int)cols); for (; k < count && k < n; k++) { + size_t t = k-dir_count; + /* draw one row of labels */ - if (k < browser->dir_count) { - nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED); + if (k < dir_count) { + nk_label(ctx, (*directories)[k], NK_TEXT_CENTERED); } else { - size_t t = k-browser->dir_count; - nk_label(ctx,browser->files[t],NK_TEXT_CENTERED); + nk_label(ctx, (*files)[t], NK_TEXT_CENTERED); } }} if(tiny) {size_t n = j + cols; nk_layout_row_dynamic(ctx, icon_height, (int)cols); for (; j < count && j < n; ++j) { + size_t t = j-dir_count; + /* draw one row of icons */ - if (j < browser->dir_count) { + if (j < dir_count) { /* draw and execute directory buttons */ - if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], browser->directories[j],NK_TEXT_RIGHT)) + if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], (*directories)[j], NK_TEXT_RIGHT)) index = (int)j; } else { /* draw and execute files buttons */ struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(browser->files[fileIndex]); - size_t t = j-browser->dir_count; - if (nk_button_image_label(ctx, *icon, browser->files[t],NK_TEXT_RIGHT)) { + size_t fileIndex = ((size_t)j - dir_count); + icon = media_icon_for_file((*files)[fileIndex]); + if (nk_button_image_label(ctx, *icon, (*files)[t],NK_TEXT_RIGHT)) { snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); clicked = 1; } @@ -240727,7 +240827,7 @@ if( cols < 1 ) cols=1; struct nk_rect bounds = nk_widget_bounds(ctx); if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds) ) { - char *name = j < browser->dir_count ? browser->directories[j] : browser->files[j-browser->dir_count]; + char *name = j < dir_count ? (*directories)[j] : (*files)[j-dir_count]; char fullpath[PATH_MAX]; snprintf(fullpath, PATH_MAX, "%s%s", browser->directory, name); @@ -332028,7 +332128,20 @@ int main() { * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ -* ALTERNATIVE B - MIT-0 (No Attribution clause) +* ALTERNATIVE B - 0-BSD License (https://opensource.org/licenses/FPL-1.0.0) +* ------------------------------------------------------------------------------ +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* ------------------------------------------------------------------------------ +* ALTERNATIVE C - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software @@ -332042,19 +332155,6 @@ int main() { * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* ------------------------------------------------------------------------------ -* ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) -* ------------------------------------------------------------------------------ -* Permission to use, copy, modify, and/or distribute this software for any -* purpose with or without fee is hereby granted. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * @@ -332074,7 +332174,7 @@ int main() { * -- * * "I dedicate any and all copyright interest in this software to the three -* license terms listed above. I make this dedication for the benefit of the +* licensing terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." @@ -332114,6 +332214,12 @@ API void *ui_handle(); //----------------------------------------------------------------------------- // C files +#line 1 "engine/split/v4k_begin.c" +#define do_threadlock(mutexptr) \ + for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \ + for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) ) +#line 0 + #line 1 "engine/split/v4k_ds.c" // ----------------------------------------------------------------------------- @@ -345142,6 +345248,7 @@ static map(unsigned, array(reflect_t)) members; void reflect_init() { if(!reflects) map_init_int(reflects); + if(!members) map_init_int(members); } AUTORUN { reflect_init(); @@ -345229,7 +345336,7 @@ void ui_reflect_(const reflect_t *R, const char *filter, int mask) { if( buf ) *buf = '\0'; struct nk_context *ui_ctx = (struct nk_context *)ui_handle(); - for ui_push_hspace(16) { + /*for ui_push_hspace(16)*/ { array(reflect_t) *T = map_find(members, intern(R->name)); /**/ if( T ) {ui_label(strcatf(&buf,"S struct %s@%s", R->name, R->info+1)); for each_array_ptr(*T, reflect_t, it) if(strmatchi(it->name,filter)) ui_reflect_(it,filter,'M'); } else if( R->addr ) ui_label(strcatf(&buf,"F func %s()@%s", R->name, R->info+1)); @@ -353042,6 +353149,124 @@ bool id_valid(uintptr_t id) { #line 0 #line 1 "engine/split/v4k_ui.c" +// ---------------------------------------------------------------------------------------- +// ui extensions first + +static float +nk_text_width(struct nk_context *ctx, const char *str, unsigned len) { + const struct nk_style *style = &ctx->style; + const struct nk_user_font *f = style->font; + float pixels_width = f->width(f->userdata, f->height, str, len ? (int)len : (int)strlen(str)); + return pixels_width; +} + +static nk_bool +nk_hovered_text(struct nk_context *ctx, const char *str, int len, + nk_flags align, nk_bool value) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + #if 1 //< @r-lyeh: sim button logic + struct nk_rect touch; + touch.x = bounds.x - style->selectable.touch_padding.x; + touch.y = bounds.y - style->selectable.touch_padding.y; + touch.w = bounds.w + style->selectable.touch_padding.x * 2; + touch.h = bounds.h + style->selectable.touch_padding.y * 2; + int clicked = !!nk_button_behavior(&ctx->last_widget_state, touch, in, NK_BUTTON_DEFAULT); + in = 0; //< @r-lyeh: do not pass any input + #endif + + nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, + str, len, align, &value, &style->selectable, in, style->font); + + return clicked; //< @r-lyeh: return sim button logic instead of prev function call +} + +#define ui_push_hspace(px) \ + (int xx = px; xx; xx = 0) \ + for(struct nk_context *ctx = (struct nk_context*)ui_handle(); ctx; ctx = 0 ) \ + for(struct nk_panel *layout = ui_ctx->current->layout; layout; ) \ + for( xx = (layout->at_x += px, layout->bounds.w -= px, 0); layout; layout->at_x -= px, layout->bounds.w += px, layout = 0 ) + +// helper macros to instance an overlayed toolbar within the regions of an existing widget +#define UI_TOOLBAR_OVERLAY_DECLARE(...) \ + __VA_ARGS__; \ + struct nk_rect toolbar_bounds; nk_layout_peek(&toolbar_bounds, ui_ctx); \ + struct nk_vec2 item_padding = ui_ctx->style.text.padding; \ + struct nk_text text; \ + text.padding.x = item_padding.x; \ + text.padding.y = item_padding.y; \ + text.background = ui_ctx->style.window.background; +#define UI_TOOLBAR_OVERLAY(CHOICE,TEXT,COLOR,ALIGNMENT) \ + do { \ + text.text = COLOR; \ + nk_widget_text(&ui_ctx->current->buffer, toolbar_bounds, TEXT, strlen(TEXT), &text, ALIGNMENT, ui_ctx->style.font); \ + int clicked_x = input_down(MOUSE_L) && nk_input_is_mouse_hovering_rect(&ui_ctx->input, toolbar_bounds); \ + if( clicked_x ) clicked_x = (int)((ui_ctx->input.mouse.pos.x - toolbar_bounds.x) - (ALIGNMENT == NK_TEXT_RIGHT ? bounds.w : 0) ); \ + CHOICE = 1 + (ALIGNMENT == NK_TEXT_RIGHT ? -1 : +1) * clicked_x / (UI_ICON_FONTSIZE + UI_ICON_SPACING_X); /* divided by px per ICON_MD_ glyph approximately */ \ + int glyphs = strlen(TEXT) / 4 /*3:MD,4:MDI*/; CHOICE *= !!clicked_x * (CHOICE <= glyphs); } while(0) + +// menu macros that work not only standalone but also contained within a panel or window +#define UI_MENU(N, ...) do { \ + enum { MENUROW_HEIGHT = 25 }; \ + int embedded = !!ui_ctx->current; \ + struct nk_rect total_space = {0,0,window_width(),window_height()}; \ + if( embedded ) total_space = nk_window_get_bounds(ui_ctx), total_space.w -= 10; \ + vec2 popup_space = { total_space.w * 0.33, total_space.h * 0.85 }; \ + int created = !embedded && nk_begin(ui_ctx, "MENU_" STRINGIZE(__COUNTER__), nk_rect(0, 0, window_width(), UI_MENUROW_HEIGHT), NK_WINDOW_NO_SCROLLBAR); \ + if ( embedded || created ) { \ + int align = NK_TEXT_LEFT, Nth = (N), ITEM_WIDTH = 30, span = 0; \ + nk_menubar_begin(ui_ctx); \ + nk_layout_row_begin(ui_ctx, NK_STATIC, MENUROW_HEIGHT, Nth); \ + __VA_ARGS__; \ + nk_menubar_end(ui_ctx); \ + if( created ) nk_end(ui_ctx); \ + } } while(0) +#define UI_MENU_POPUP(title, ...) { \ + int hspace = maxi(ITEM_WIDTH, nk_text_width(ui_ctx,(title),0)); \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align, nk_vec2(popup_space.w,popup_space.h))) { \ + __VA_ARGS__; \ + nk_menu_end(ui_ctx); \ + }} +#define UI_MENU_ITEM(title, ...) { \ + int hspace = maxi(ITEM_WIDTH, nk_text_width(ui_ctx,(title),0)); \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align, nk_vec2(1,1))) { \ + __VA_ARGS__; \ + nk_menu_close(ui_ctx); \ + nk_menu_end(ui_ctx); \ + }} +#define UI_MENU_ALIGN_RIGHT(px) { \ + int hspace = total_space.w - span - (px) - 1.5 * ITEM_WIDTH; \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align = NK_TEXT_RIGHT, nk_vec2(1,1))) { \ + nk_menu_close(ui_ctx); \ + nk_menu_end(ui_ctx); \ + }} + +// ---------------------------------------------------------------------------------------- +// ui #ifndef UI_ICONS_SMALL //#define UI_ICONS_SMALL 1 @@ -353360,7 +353585,6 @@ vec2 ui_toolbar_(array(ui_item_t) ui_items, vec2 ui_results) { // old method: nk_layout_row_dynamic(ui_ctx, UI_MENUBAR_ICON_HEIGHT/*h*/, array_count(ui_items)); { const struct nk_style *style = &ui_ctx->style; - const struct nk_user_font *f = style->font; nk_layout_row_template_begin(ui_ctx, UI_MENUBAR_ICON_HEIGHT/*h*/); for(int i = 0; i < array_count(ui_items); ++i) { @@ -353370,7 +353594,7 @@ vec2 ui_toolbar_(array(ui_item_t) ui_items, vec2 ui_results) { char *tooltip = strchr(first_token, '@'); int len = tooltip ? (int)(tooltip - first_token /*- 1*/) : strlen(first_token); - float pixels_width = f->width(f->userdata, f->height, first_token, len); + float pixels_width = nk_text_width(ui_ctx, first_token, len); pixels_width += style->window.header.label_padding.x * 2 + style->window.header.padding.x * 2; if( pixels_width < 5 ) pixels_width = 5; nk_layout_row_template_push_static(ui_ctx, pixels_width); @@ -354448,20 +354672,19 @@ int ui_panel_end() { } static unsigned ui_collapse_state = 0; -static bool ui_collapse_next_open = 0; int ui_collapse(const char *label, const char *id) { // mask: 0(closed),1(open),2(created) - int open = label[0] == '!'; label += open; + int start_open = label[0] == '!'; label += start_open; uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL; for(int i = 0; id[i]; ++i) hash = (hash ^ id[i]) * mult; ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue; - ui_collapse_state = nk_tree_base_(ui_ctx, NK_TREE_NODE, 0, label, ui_collapse_next_open ? NK_MAXIMIZED : NK_MINIMIZED, id, strlen(id), 0); - return ui_collapse_next_open = 0, ui_collapse_state & 1; // |1 open, |2 clicked, |4 toggled -} -int ui_collapseo(const char *label, const char *id) { // mask: 0(closed),1(open),2(created) - ui_collapse_next_open = true; - return ui_collapse(label, id); + int forced = ui_filter && ui_filter[0]; + enum nk_collapse_states forced_open = NK_MAXIMIZED; + + ui_collapse_state = nk_tree_base_(ui_ctx, NK_TREE_NODE, 0, label, start_open ? NK_MAXIMIZED : NK_MINIMIZED, forced ? &forced_open : NULL, id, strlen(id), 0); + + return ui_collapse_state & 1; // |1 open, |2 clicked, |4 toggled } int ui_collapse_clicked() { return ui_collapse_state >> 1; // |1 clicked, |2 toggled @@ -354618,10 +354841,12 @@ if( font ) nk_style_pop_font(ui_ctx); return ui_label_icon_clicked_L.x; } -int ui_label(const char *text) { - int align = text[0] == '>' ? (text++, NK_TEXT_RIGHT) : text[0] == '=' ? (text++, NK_TEXT_CENTERED) : text[0] == '<' ? (text++, NK_TEXT_LEFT) : NK_TEXT_LEFT; +int ui_label(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + + int align = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT; nk_layout_row_dynamic(ui_ctx, 0, 1); - return ui_label_(text, align); + return ui_label_(label, align); } static int nk_label_(struct nk_context *ui_ctx, const char *text_, int align2 ) { @@ -354645,6 +354870,8 @@ ui_label_icon_clicked_R.x = is_hovering ? ( (int)((input->mouse.pos.x - bounds.x int ui_label2(const char *label, const char *text_) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); int align1 = NK_TEXT_LEFT; @@ -354699,7 +354926,9 @@ int ui_button_transparent(const char *text) { #endif static -int ui_button_(const char *text) { +int ui_button_(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + if( 1 ) { #if UI_BUTTON_MONOCHROME nk_style_push_color(ui_ctx, &ui_ctx->style.button.text_normal, nk_rgba(0,0,0,ui_alpha)); @@ -354730,8 +354959,8 @@ int ui_button_(const char *text) { struct nk_rect bounds = nk_widget_bounds(ui_ctx); - const char *split = strchr(text, '@'), *tooltip = split + 1; - int ret = nk_button_text(ui_ctx, text, split ? (int)(split - text) : strlen(text) ); + const char *split = strchr(label, '@'), *tooltip = split + 1; + int ret = nk_button_text(ui_ctx, label, split ? (int)(split - label) : strlen(label) ); const struct nk_input *in = &ui_ctx->input; if (split && nk_input_is_mouse_hovering_rect(in, bounds) && !ui_has_active_popups && nk_window_has_focus(ui_ctx)) { @@ -354752,6 +354981,23 @@ int ui_button_(const char *text) { } int ui_buttons(int buttons, ...) { + static array(char*) args = 0; + array_resize(args, 0); + + int num_skips = 0; + va_list list; + va_start(list, buttons); + for( int i = 0; i < buttons; ++i ) { + const char *label = va_arg(list, const char*); + int skip = ui_filter && ui_filter[0] && !strstri(label, ui_filter); + array_push(args, skip ? NULL : (char*)label); + num_skips += skip; + } + va_end(list); + + if( num_skips == array_count(args) ) return 0; + buttons = array_count(args) - num_skips; + nk_layout_row_dynamic(ui_ctx, 0, buttons); float ui_hue_old = ui_hue; @@ -354766,10 +355012,8 @@ int ui_buttons(int buttons, ...) { layout->bounds.w -= indent; int rc = 0; - va_list list; - va_start(list, buttons); - for( int i = 0; i < buttons; ++i ) { - if( ui_button_( va_arg(list, const char*) ) ) rc = i+1; + for( int i = 0, end = array_count(args); i < end; ++i ) { + if( args[i] && ui_button_( args[i] ) ) rc = i+1; ui_hue_cycle( 3 ); } va_end(list); @@ -354786,6 +355030,8 @@ int ui_button(const char *s) { } int ui_toggle(const char *label, bool *value) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354795,6 +355041,8 @@ int ui_toggle(const char *label, bool *value) { } int ui_color4f(const char *label, float *color4) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float c[4] = { color4[0]*255, color4[1]*255, color4[2]*255, color4[3]*255 }; int ret = ui_color4(label, c); for( int i = 0; i < 4; ++i ) color4[i] = c[i] / 255.0f; @@ -354804,6 +355052,8 @@ int ui_color4f(const char *label, float *color4) { static enum color_mode {COL_RGB, COL_HSV} ui_color_mode = COL_RGB; int ui_color4(const char *label, float *color4) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354850,6 +355100,8 @@ int ui_color3f(const char *label, float *color3) { } int ui_color3(const char *label, float *color3) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354886,6 +355138,8 @@ int ui_color3(const char *label, float *color3) { } int ui_list(const char *label, const char **items, int num_items, int *selector) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354896,6 +355150,8 @@ int ui_list(const char *label, const char **items, int num_items, int *selector) } int ui_slider(const char *label, float *slider) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + // return ui_slider2(label, slider, va("%.2f ", *slider)); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354906,6 +355162,8 @@ int ui_slider(const char *label, float *slider) { return chg; } int ui_slider2(const char *label, float *slider, const char *caption) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354930,6 +355188,8 @@ int ui_slider2(const char *label, float *slider, const char *caption) { } int ui_bool(const char *label, bool *enabled ) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354944,6 +355204,8 @@ int ui_bool(const char *label, bool *enabled ) { } int ui_int(const char *label, int *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354953,6 +355215,8 @@ int ui_int(const char *label, int *v) { } int ui_unsigned(const char *label, unsigned *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354962,11 +355226,15 @@ int ui_unsigned(const char *label, unsigned *v) { } int ui_short(const char *label, short *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int i = *v, ret = ui_int( label, &i ); return *v = (short)i, ret; } int ui_float(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354975,6 +355243,8 @@ int ui_float(const char *label, float *v) { } int ui_double(const char *label, double *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -354983,6 +355253,8 @@ int ui_double(const char *label, double *v) { } int ui_clampf(const char *label, float *v, float minf, float maxf) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + if( minf > maxf ) return ui_clampf(label, v, maxf, minf); nk_layout_row_dynamic(ui_ctx, 0, 2); @@ -354995,6 +355267,8 @@ int ui_clampf(const char *label, float *v, float minf, float maxf) { static bool ui_float_sign = 0; int ui_float2(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -355013,6 +355287,8 @@ int ui_float2(const char *label, float *v) { } int ui_float3(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -355032,6 +355308,8 @@ int ui_float3(const char *label, float *v) { } int ui_float4(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -355053,6 +355331,8 @@ int ui_float4(const char *label, float *v) { } int ui_mat33(const char *label, float M[9]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 3; int changed = 0; changed |= ui_label(label); @@ -355062,6 +355342,8 @@ int ui_mat33(const char *label, float M[9]) { return changed; } int ui_mat34(const char *label, float M[12]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 3; int changed = 0; changed |= ui_label(label); @@ -355071,6 +355353,8 @@ int ui_mat34(const char *label, float M[12]) { return changed; } int ui_mat44(const char *label, float M[16]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 4; int changed = 0; changed |= ui_label(label); @@ -355082,6 +355366,8 @@ int ui_mat44(const char *label, float M[16]) { } int ui_buffer(const char *label, char *buffer, int buflen) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 1 + (label && label[0])); if(label && label[0]) ui_label_(label, NK_TEXT_LEFT); @@ -355090,6 +355376,8 @@ int ui_buffer(const char *label, char *buffer, int buflen) { } int ui_string(const char *label, char **str) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + char *bak = va("%s%c", *str ? *str : "", '\0'); int rc = ui_buffer(label, bak, strlen(bak)+2); if( *str ) 0[*str] = '\0'; @@ -355098,6 +355386,8 @@ int ui_string(const char *label, char **str) { } int ui_separator() { + if( /*label &&*/ ui_filter && ui_filter[0] ) return 0; // if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, UI_SEPARATOR_HEIGHT, 1); ui_hue_cycle( 1 ); @@ -355114,6 +355404,8 @@ int ui_separator() { } int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, sh < 30 || id == texture_checker().id ? 0 : sh, 1 + (label && label[0])); if( label && label[0] ) ui_label_(label, NK_TEXT_LEFT); @@ -355143,31 +355435,35 @@ int ui_subtexture(const char *label, texture_t t, unsigned x, unsigned y, unsign return ui_subimage(label, t.id, t.w,t.h, x,y,w,h); } -int ui_colormap( const char *map_name, colormap_t *cm ) { +int ui_colormap( const char *label, colormap_t *cm ) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int ret = 0; if( !cm->texture ) { - const char *title = va("%s (no image)", map_name); + const char *title = va("%s (no image)", label); if( ui_image( title, texture_checker().id, 0,0 ) ) { ret = 2; } } else { unsigned w = cm->texture->w, h = cm->texture->h; - ui_label(va("%s (%s)", map_name, cm->texture->filename) ); // @fixme: labelf would crash? + ui_label(va("%s (%s)", label, cm->texture->filename) ); // @fixme: labelf would crash? const char *fmt[] = { "", "R", "RG", "RGB", "RGBA" }; - const char *title = va("%s %dx%d %s", map_name, w, h, fmt[cm->texture->n]); + const char *title = va("%s %dx%d %s", label, w, h, fmt[cm->texture->n]); if( ui_image( title, cm->texture->id, 128, 128 ) ) { ret = 2; } } - if( ui_color4f( va("%s Color", map_name), (float *) &cm->color ) ) { + if( ui_color4f( va("%s Color", label), (float *) &cm->color ) ) { ret = 1; } return ret; } int ui_radio(const char *label, const char **items, int num_items, int *selector) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int ret = 0; if( label && label[0] ) ui_label(label); for( int i = 0; i < num_items; i++ ) { @@ -355180,20 +355476,24 @@ int ui_radio(const char *label, const char **items, int num_items, int *selector return ret; } -int ui_section(const char *section) { +int ui_section(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + //ui_separator(); - return ui_label(va("*%s", section)); + return ui_label(va("*%s", label)); } -int ui_dialog(const char *title, const char *text, int choices, bool *show) { // @fixme: return +int ui_dialog(const char *label, const char *text, int choices, bool *show) { // @fixme: return + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_has_active_popups = 0; if(*show) { static struct nk_rect s = {0, 0, 300, 190}; - if (nk_popup_begin(ui_ctx, NK_POPUP_STATIC, title, NK_WINDOW_BORDER|NK_WINDOW_CLOSABLE, s)) { + if (nk_popup_begin(ui_ctx, NK_POPUP_STATIC, label, NK_WINDOW_BORDER|NK_WINDOW_CLOSABLE, s)) { nk_layout_row_dynamic(ui_ctx, 20, 1); - for( char label[1024]; *text && sscanf(text, "%[^\r\n]", label); ) { - nk_label(ui_ctx, label, NK_TEXT_LEFT); - text += strlen(label); while(*text && *text < 32) text++; + for( char t[1024]; *text && sscanf(text, "%[^\r\n]", t); ) { + nk_label(ui_ctx, t, NK_TEXT_LEFT); + text += strlen(t); while(*text && *text < 32) text++; } if( choices ) { @@ -355214,6 +355514,8 @@ int ui_dialog(const char *title, const char *text, int choices, bool *show) { // #define ui_bitmask_template(X) \ int ui_bitmask##X(const char *label, uint##X##_t *enabled) { \ + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; \ +\ /* @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive */ \ nk_layout_row_dynamic(ui_ctx, 1, 1); \ struct nk_rect bounds = nk_widget_bounds(ui_ctx); \ @@ -355341,9 +355643,46 @@ int ui_browse(const char **output, bool *inlined) { struct browser *browser = browsers + windowed; // select instance char **result = results + windowed; // select instance - struct nk_rect bounds = {0,0,400,300}; // @fixme: how to retrieve inlined region below? (inlined) - if( windowed || (!windowed && *inlined) ) bounds = nk_window_get_content_region(ui_ctx); - else { struct nk_rect b; nk_layout_peek(&b, ui_ctx); bounds.w = b.w; } + struct nk_rect bounds = {0}; // // {0,0,400,300}; + // #define P(b) printf(FILELINE " (%3d,%3d) %3d,%3d\n", (int)b.x,(int)b.y, (int)b.w,(int)b.h) + // if(ui_ctx->current) bounds = nk_layout_space_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_layout_widget_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_widget_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_window_get_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_window_get_content_region(ui_ctx), P(bounds); + // if(ui_ctx->current) nk_layout_peek(&bounds, ui_ctx), P(bounds); + // // if(ui_ctx->current) nk_layout_widget_space(&bounds, ui_ctx, ui_ctx->current, nk_false), P(bounds); // note: cant be used within a panel + // #undef P + + // panel + // v4k_ui.c:2497 ( 6, 34) 310, 24 + // v4k_ui.c:2498 ( 16, 62) 286, 24 + // v4k_ui.c:2499 ( 16, 86) 296, 24 + // v4k_ui.c:2500 ( 0, 0) 327,613 + // v4k_ui.c:2501 ( 6, 34) 310,572 << ok + // v4k_ui.c:2502 ( 16, 86) 296, 24 + // v4k_ui.c:2503 (316, 62) 297, 24 + + // window + // v4k_ui.c:2497 (188,152) 711, 4 + // v4k_ui.c:2498 (188,152) 711, 4 + // v4k_ui.c:2499 (-2147483648,156) -2147483648, 4 + // v4k_ui.c:2500 (182,118) 728,409 + // v4k_ui.c:2501 (188,152) 711,368 << ok + // v4k_ui.c:2502 (-2147483648,156) -2147483648, 4 + // v4k_ui.c:2503 (-2147483648,152) -2147483648, 4 + + // popup + // v4k_ui.c:2497 ( 9, 30) 350, 24 + // v4k_ui.c:2498 ( 19, 58) 326, 24 + // v4k_ui.c:2499 ( 19, 82) 336, 24 + // v4k_ui.c:2500 ( 4, 29) 360,460 + // v4k_ui.c:2501 ( 9, 30) 350,458 << ok + // v4k_ui.c:2502 ( 19, 82) 336, 24 + // v4k_ui.c:2503 (359, 58) 336, 24 + + bounds = nk_window_get_content_region(ui_ctx); + if( !windowed && *inlined ) bounds.h *= 0.80; clicked = browser_run(ui_ctx, browser, windowed, bounds); if( clicked ) { @@ -356372,229 +356711,8 @@ int window_frame_begin() { // generate Debug panel contents if( may_render_debug_panel ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { - - static int time_factor = 0; - static int playing = 0; - static int paused = 0; - int advance_frame = 0; - - static int do_filter = 0; - static int do_profile = 0; - static int do_extra = 0; - - char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", - do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, - ICON_MD_PLAY_ARROW, - paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, - ICON_MD_FAST_FORWARD, - ICON_MD_STOP, - ICON_MD_REPLAY, - ICON_MD_FACE, - ICON_MD_MENU - ); - - if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; - int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); - if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; - if( choice == 2 ) playing = 1, paused = 0; - if( choice == 3 ) advance_frame = !!paused, paused = 1; - if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; - if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; - if( choice == 6 ) window_reload(); - if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; - if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; - - static char *filter = 0; - if( do_filter ) { - ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter); - if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) - do_filter = 0; - } - } else { - if( filter ) filter[0] = '\0'; - } - char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*"; - - static char *username = 0; - static char *userpass = 0; - if( do_profile ) { - ui_string(ICON_MD_FACE " Username", &username); - ui_string(ICON_MD_FACE " Password", &userpass); - } - - if( do_extra ) { - int choice2 = ui_label2_toolbar(NULL, - ICON_MD_VIEW_IN_AR - ICON_MD_MESSAGE - ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE - ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO - ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF - - ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 - - ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU - ); - } - - int open = 0, clicked_or_toggled = 0; - - #define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id)) - - #define EDITOR_UI_COLLAPSE(f,...) \ - for( int macro(p) = (open = ui_collapse_filtered(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) - - - EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { - // @todo. parse /bugs.ini, includes saved screenshots & videos. - // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) - } - - - // Art and bookmarks - EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { - bool inlined = true; - const char *file = 0; - if( ui_browse(&file, &inlined) ) { - const char *sep = ifdef(win32, "\"", "'"); - app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); - } - } - EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } - - - // E,C,S,W - EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { - EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { - //node_edit(editor.edit.down,&editor.edit); - } - - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } - - // node_edit(&editor.init,&editor.init); - // node_edit(&editor.draw,&editor.draw); - // node_edit(&editor.tick,&editor.tick); - // node_edit(&editor.edit,&editor.edit); - // node_edit(&editor.quit,&editor.quit); - } - - EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { - // @todo - } - EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { - ui_audio(); - } - EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { - ui_camera( camera_get_active() ); - } - EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { - // @todo: fps lock, fps target, aspect ratio, fullscreen - char *text = va("%s;%s;%s", - window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, - ICON_MD_PHOTO_CAMERA, - record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM - ); - - int choice = ui_toolbar(text); - if( choice == 1 ) engine_send("key_fullscreen",0); - if( choice == 2 ) engine_send("key_screenshot",0); - if( choice == 3 ) engine_send("key_record",0); - } - EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { - ui_keyboard(); - } - EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { - ui_mouse(); - } - EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { - for( int q = 0; q < 4; ++q ) { - for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { - ui_gamepad(q); - } - } - } - - - EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { - // @todo - } - EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { - ui_shaders(); - } - EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { - ui_fxs(); - } - EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") { - int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); - if( choice == 1 ) ui_layout_all_reset("*"); - if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); - - for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { - bool visible = ui_visible(*k); - if( ui_bool( *k, &visible ) ) { - ui_show( *k, ui_visible(*k) ^ true ); - } - } - } - - - EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { - // @todo. // mem,fps,gfx,net,hdd,... also logging - } - EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { - // @todo - // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR - } - EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { - ui_profiler(); - } - EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { - // @todo - } - - - - // logic: either plug icon (power saving off) or one of the following ones (power saving on): - // if 0% batt (no batt): battery alert - // if discharging: battery levels [alert,0..6,full] - // if charging: battery charging - int battery_read = app_battery(); - int battery_level = abs(battery_read); - int battery_discharging = battery_read < 0 && battery_level < 100; - const char *power_icon_label = ICON_MD_POWER " Power"; - if( battery_level ) { - const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? - ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, - ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, - ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, - }; - power_icon_label = (const char*)va("%s Power %d%%", - battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, - battery_level); - } - - EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { - int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); - if( choice == 1 ) engine_send("key_battery","0"); - if( choice == 2 ) engine_send("key_battery","1"); - } - - EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { - ui_reflect("*"); - } - - EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { - // @todo. include VCS - EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { - // @todo - } - } + API int ui_debug(); + ui_debug(); (has_menu ? ui_window_end : ui_panel_end)(); } @@ -357284,13 +357402,13 @@ void *obj_unref(void *oo) { // scene tree array(obj*)* obj_children(const void *o) { - array(obj*) *c = obj_payload(o); + array(obj*) *c = &((obj*)o)->objchildren; if(!(*c)) array_push((*c), NULL); // default parenting: none. @todo: optimize & move this at construction time return c; } obj* obj_parent(const void *o) { array(obj*) *c = obj_children(o); - return (*c) ? 0[*c] : NULL; + return 0[*c]; // (*c) ? 0[*c] : NULL; } obj* obj_root(const void *o) { while( obj_parent(o) ) o = obj_parent(o); @@ -357822,33 +357940,27 @@ void test_obj_serialization(void *o1, void *o2) { // ---------------------------------------------------------------------------- // components -bool obj_addcomponent(void *object, unsigned c, void *ptr) { - entity *e = (entity*)object; +bool obj_addcomponent(entity *e, unsigned c, void *ptr) { e->cflags |= (3ULL << c); e->c[c & (OBJCOMPONENTS_MAX-1)] = ptr; return 1; } -bool obj_hascomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_hascomponent(entity *e, unsigned c) { return !!(e->cflags & (3ULL << c)); } -void* obj_getcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +void* obj_getcomponent(entity *e, unsigned c) { return e->c[c & (OBJCOMPONENTS_MAX-1)]; } -bool obj_delcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_delcomponent(entity *e, unsigned c) { e->cflags &= ~(3ULL << c); e->c[c & (OBJCOMPONENTS_MAX-1)] = NULL; return 1; } -bool obj_usecomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_usecomponent(entity *e, unsigned c) { e->cflags |= (1ULL << c); return 1; } -bool obj_offcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_offcomponent(entity *e, unsigned c) { e->cflags &= ~(1ULL << c); return 0; } @@ -357858,17 +357970,23 @@ char *entity_save(entity *self) { return sav; } -AUTORUN { +static +void entity_register() { + do_once { STRUCT(entity, uintptr_t, cflags); - -// struct { OBJHEADER union { struct { uintptr_t objenabled : 32, objflagged : 32; }; uintptr_t cflags; }; void* c[32]; }; - obj_extend(entity, save); } +} + +AUTORUN{ + entity_register(); +} static void test_obj_ecs() { - entity *e = obj_new(entity); + entity_register(); // why is this required here? autorun init fiasco? + + entity *e = entity_new(entity); puts(obj_save(e)); for( int i = 0; i < 32; ++i) test(0 == obj_hascomponent(e, i)); @@ -357881,27 +357999,14 @@ void test_obj_ecs() { // ---------------------------------------------------------------------------- // reflection -void *obj_clone(const void *src) { - obj *ptr = obj_malloc( sizeof(obj) + obj_size(src) + sizeof(array(obj*)) ); - ptr->objheader = ((const obj *)src)->objheader; - obj_loadini(ptr, obj_saveini(src)); - return ptr; -} +void* obj_mutate(void *dst, const void *src) { + ((obj*)dst)->objheader = ((const obj *)src)->objheader; -void* obj_merge(void *dst, const void *src) { // @testme - char *bin = obj_savebin(src); - return obj_mergebin(dst, bin); -} - -void* obj_mutate(void **dst, const void *src) { #if 0 // mutate a class. ie, convert a given object class into a different one, // while preserving the original metas, components and references as much as possible. // @todo iterate per field - if(!*dst_) return *dst_ = obj_clone(src); - - void *dst = *dst_; dtor(dst); unsigned src_sz = obj_sizeof(src); @@ -357923,6 +358028,20 @@ void* obj_mutate(void **dst, const void *src) { return dst; } +void *obj_clone(const void *src) { + int sz = sizeof(obj) + obj_size(src) + sizeof(array(obj*)); + enum { N = 8 }; sz = ((sz + (N - 1)) & -N); // Round up to N-byte boundary + obj *ptr = obj_malloc( sz ); + obj_mutate(ptr, src); // ptr->objheader = ((const obj *)src)->objheader; + obj_loadini(ptr, obj_saveini(src)); + return ptr; +} + +void* obj_merge(void *dst, const void *src) { // @testme + char *bin = obj_savebin(src); + return obj_mergebin(dst, bin); +} + void *obj_make(const char *str) { const char *T; const char *I = strchr(str, '['); // is_ini @@ -357970,7 +358089,7 @@ vec3 rnd3() { // random uniform int less3(vec3 *lhs, vec3 *rhs) { if(lhs->x != rhs->x) return lhs->x - rhs->x; if(lhs->y != rhs->y) return lhs->y - rhs->y; - if(lhs->z != rhs->z) return lhs->z - rhs->z; + if(lhs->z != rhs->z) return lhs->z - rhs->z; // @testme: remove superfluous if check return 0; } uint64_t hash3(vec3 *v) { @@ -358981,6 +359100,235 @@ int engine_tick() { } else { // window_fps_lock( editor_hz ); window_fps_unlock( ); + } + + return 0; +} + +int ui_debug() { + static int time_factor = 0; + static int playing = 0; + static int paused = 0; + int advance_frame = 0; + +#if 0 + static int do_filter = 0; + static int do_profile = 0; + static int do_extra = 0; + + char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", + do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, + ICON_MD_PLAY_ARROW, + paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, + ICON_MD_FAST_FORWARD, + ICON_MD_STOP, + ICON_MD_REPLAY, + ICON_MD_FACE, + ICON_MD_MENU + ); + + if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; + int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); + if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; + if( choice == 2 ) playing = 1, paused = 0; + if( choice == 3 ) advance_frame = !!paused, paused = 1; + if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; + if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; + if( choice == 6 ) window_reload(); + if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; + if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; + + if( do_filter ) { + char *bak = ui_filter; ui_filter = 0; + ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak); + ui_filter = bak; + if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) + do_filter = 0; + } + } else { + if( ui_filter ) ui_filter[0] = '\0'; + } + char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*"; + + static char *username = 0; + static char *userpass = 0; + if( do_profile ) { + ui_string(ICON_MD_FACE " Username", &username); + ui_string(ICON_MD_FACE " Password", &userpass); + } + + if( do_extra ) { + int choice2 = ui_label2_toolbar(NULL, + ICON_MD_VIEW_IN_AR + ICON_MD_MESSAGE + ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE + ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO + ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF + + ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 + + ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU + ); + } +#endif + + int open = 0, clicked_or_toggled = 0; + + + #define EDITOR_UI_COLLAPSE(f,...) \ + for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) + + + EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { + // @todo. parse /bugs.ini, includes saved screenshots & videos. + // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) + } + + + // Art and bookmarks + EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { + bool inlined = true; + const char *file = 0; + if( ui_browse(&file, &inlined) ) { + const char *sep = ifdef(win32, "\"", "'"); + app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); + } + } + EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } + + + // E,C,S,W + EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { + EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { + //node_edit(editor.edit.down,&editor.edit); + } + + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } + + // node_edit(&editor.init,&editor.init); + // node_edit(&editor.draw,&editor.draw); + // node_edit(&editor.tick,&editor.tick); + // node_edit(&editor.edit,&editor.edit); + // node_edit(&editor.quit,&editor.quit); + } + + EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { + // @todo + } + EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { + ui_audio(); + } + EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { + ui_camera( camera_get_active() ); + } + EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { + // @todo: fps lock, fps target, aspect ratio, fullscreen + char *text = va("%s;%s;%s", + window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, + ICON_MD_PHOTO_CAMERA, + record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM + ); + + int choice = ui_toolbar(text); + if( choice == 1 ) engine_send("key_fullscreen",0); + if( choice == 2 ) engine_send("key_screenshot",0); + if( choice == 3 ) engine_send("key_record",0); + } + EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { + ui_keyboard(); + } + EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { + ui_mouse(); + } + EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { + for( int q = 0; q < 4; ++q ) { + for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { + ui_gamepad(q); + } + } + } + + + EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { + // @todo + } + EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { + ui_shaders(); + } + EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { + ui_fxs(); + } + EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") { + int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); + if( choice == 1 ) ui_layout_all_reset("*"); + if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); + + for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { + bool visible = ui_visible(*k); + if( ui_bool( *k, &visible ) ) { + ui_show( *k, ui_visible(*k) ^ true ); + } + } + } + + + EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { + // @todo. // mem,fps,gfx,net,hdd,... also logging + } + EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { + // @todo + // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR + } + EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { + ui_profiler(); + } + EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { + // @todo + } + + + + // logic: either plug icon (power saving off) or one of the following ones (power saving on): + // if 0% batt (no batt): battery alert + // if discharging: battery levels [alert,0..6,full] + // if charging: battery charging + int battery_read = app_battery(); + int battery_level = abs(battery_read); + int battery_discharging = battery_read < 0 && battery_level < 100; + const char *power_icon_label = ICON_MD_POWER " Power"; + if( battery_level ) { + const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? + ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, + ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, + ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, + }; + power_icon_label = (const char*)va("%s Power %d%%", + battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, + battery_level); + } + + EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { + int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); + if( choice == 1 ) engine_send("key_battery","0"); + if( choice == 2 ) engine_send("key_battery","1"); + } + + EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { + ui_reflect("*"); + } + + EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { + // @todo. include VCS + EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { + // @todo + } } return 0; diff --git a/engine/split/3rd_nuklear.h b/engine/split/3rd_nuklear.h index 6dd3e9c..e51db55 100644 --- a/engine/split/3rd_nuklear.h +++ b/engine/split/3rd_nuklear.h @@ -20995,6 +20995,9 @@ nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type) { +if(body.x < 10) body.x = 0; //< @r-lyeh: popup snapping to the left +if((body.x+body.w)>window_width()) body.x-=body.w-(window_width()-body.x); //< @r-lyeh: prevent popups to be printed outside of window client / right border + struct nk_window *popup; struct nk_window *win; struct nk_panel *panel; @@ -21476,7 +21479,7 @@ nk_menu_begin(struct nk_context *ctx, struct nk_window *win, is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) + if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR_X/*|NK_WINDOW_NO_SCROLLBAR*/, body, header, NK_PANEL_MENU)) //< @r-lyeh: our popups are huge. enable Y scrollbars return 0; win->popup.type = NK_PANEL_MENU; @@ -22710,6 +22713,7 @@ nk_tree_state_base_(struct nk_context *ctx, enum nk_tree_type type, NK_INTERN int nk_tree_base_(struct nk_context *ctx, enum nk_tree_type type, struct nk_image *img, const char *title, enum nk_collapse_states initial_state, + enum nk_collapse_states *forced_state, //< @r-lyeh const char *hash, int len, int line) { struct nk_window *win = ctx->current; @@ -22727,7 +22731,8 @@ nk_tree_base_(struct nk_context *ctx, enum nk_tree_type type, state = nk_add_value(ctx, win, tree_hash, 0); *state = initial_state; } - return nk_tree_state_base_(ctx, type, img, title, (enum nk_collapse_states*)state); + return nk_tree_state_base_(ctx, type, img, title, + forced_state ? forced_state : (enum nk_collapse_states*)state); //< @r-lyeh } #endif NK_API nk_bool diff --git a/engine/split/3rd_nuklear_filebrowser.h b/engine/split/3rd_nuklear_filebrowser.h index e4a790a..89cd2dd 100644 --- a/engine/split/3rd_nuklear_filebrowser.h +++ b/engine/split/3rd_nuklear_filebrowser.h @@ -16,8 +16,56 @@ #else #include // getcwd() #include // getpwuid() +#define _popen popen +#define _pclose pclose #endif +const char** old_file_list(const char *cwd, const char *masks) { + ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); + + static __thread array(char*) list = 0; + const char *arg0 = cwd; // app_path(); + int larg0 = strlen(arg0); + + for( int i = 0; i < array_count(list); ++i ) { + FREE(list[i]); + } + array_resize(list, 0);//array_free(list); + + for each_substring(masks,";",it) { + int recurse = !!strstr(it, "**"); + #if is(win32) + char *glob = va("dir %s/b/o:n \"%s\\%s\" 2> NUL", recurse ? "/s":"", cwd, it); + #else // linux, osx + char *glob = va("find %s %s -name \"%s\" | sort", cwd, !recurse ? "-maxdepth 1":"-type f", it); + #endif + for( FILE *in = _popen(glob, "r"); in; _pclose(in), in = 0) { + char buf[1024], *line = buf; + while( fgets(buf, sizeof(buf), in) ) { + // clean up + if( strstr(line, arg0) ) line = buf + larg0; + if( !memcmp(line, "./", 2) ) line += 2; + int len = strlen(line); while( len > 0 && line[len-1] < 32 ) line[--len] = 0; + if( line[0] == '\0' ) continue; + // do not insert system folders/files + for(int i = 0; i < len; ++i ) if(line[i] == '\\') line[i] = '/'; + if( line[0] == '.' ) if( !strcmp(line,".git") || !strcmp(line,".vs") || !strcmp(line,".") || !strcmp(line,"..") ) continue; + if( strstr(line, "/.") ) continue; + // insert copy + #if is(win32) + char *copy = STRDUP(line); // full path already provided + #else + // while(line[0] == '/') ++line; + char *copy = STRDUP(va("%s%s", cwd, line)); // need to prepend path + #endif + array_push(list, copy); + } + } + } + array_push(list, 0); // terminator + return (const char**)list; +} + #if 1 #define BROWSER_PRINTF(...) do {} while(0) #else @@ -81,6 +129,10 @@ struct browser { size_t file_count; size_t dir_count; + /* filtered directory content */ + array(char*) ffiles; + array(char*) fdirectories; + /* view mode */ bool listing; float zooming; @@ -117,8 +169,8 @@ static void browser_reload_directory_content(struct browser *browser, const char BROWSER_PRINTF("searching at %s\n", path); - array(char*) list = file_list(path); - for( int i = 0, end = array_count(list); i < end; ++i ) { + const char** list = old_file_list(path, "*"); + for( int i = 0; list[i]; ++i ) { char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); @@ -183,6 +235,9 @@ static void browser_free(struct browser *browser) { for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]); array_free(browser->files); array_free(browser->directories); + array_free(browser->ffiles); + array_free(browser->fdirectories); + memset(browser, 0, sizeof(*browser)); } @@ -263,10 +318,33 @@ if( cols < 1 ) cols=1; /* output directory content window */ if(nk_group_begin(ctx, "Content", windowed ? NK_WINDOW_NO_SCROLLBAR : 0)) { + + array(char*) *directories = &browser->directories; + array(char*) *files = &browser->files; + + if( ui_filter && ui_filter[0] ) { + array_resize(browser->fdirectories, 0); + array_resize(browser->ffiles, 0); + + for each_array(browser->directories,char*,k) + if( strstri(k, ui_filter) ) + array_push(browser->fdirectories, k); + + for each_array(browser->files,char*,k) + if( strstri(k, ui_filter) ) + array_push(browser->ffiles, k); + + directories = &browser->fdirectories; + files = &browser->ffiles; + } + + int dir_count = array_count(*directories); + int file_count = array_count(*files); + int index = -1; size_t i = 0, j = 0, k = 0; size_t rows = 0; - size_t count = browser->dir_count + browser->file_count; + size_t count = dir_count + file_count; rows = count / cols; for (i = 0; i <= rows; i += 1) { @@ -274,16 +352,18 @@ if( cols < 1 ) cols=1; {size_t n = j + cols; nk_layout_row_dynamic(ctx, icon_height, (int)cols); for (; j < count && j < n; ++j) { + size_t t = j-dir_count; + /* draw one row of icons */ - if (j < browser->dir_count) { + if (j < dir_count) { /* draw and execute directory buttons */ if (nk_button_image(ctx,media.custom_folders[BROWSER_FOLDER])) index = (int)j; } else { /* draw and execute files buttons */ struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(browser->files[fileIndex]); + size_t fileIndex = ((size_t)j - dir_count); + icon = media_icon_for_file((*files)[fileIndex]); if (nk_button_image(ctx, *icon)) { snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); clicked = 1; @@ -294,30 +374,32 @@ if( cols < 1 ) cols=1; {size_t n = k + cols; nk_layout_row_dynamic(ctx, 20, (int)cols); for (; k < count && k < n; k++) { + size_t t = k-dir_count; + /* draw one row of labels */ - if (k < browser->dir_count) { - nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED); + if (k < dir_count) { + nk_label(ctx, (*directories)[k], NK_TEXT_CENTERED); } else { - size_t t = k-browser->dir_count; - nk_label(ctx,browser->files[t],NK_TEXT_CENTERED); + nk_label(ctx, (*files)[t], NK_TEXT_CENTERED); } }} if(tiny) {size_t n = j + cols; nk_layout_row_dynamic(ctx, icon_height, (int)cols); for (; j < count && j < n; ++j) { + size_t t = j-dir_count; + /* draw one row of icons */ - if (j < browser->dir_count) { + if (j < dir_count) { /* draw and execute directory buttons */ - if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], browser->directories[j],NK_TEXT_RIGHT)) + if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], (*directories)[j], NK_TEXT_RIGHT)) index = (int)j; } else { /* draw and execute files buttons */ struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(browser->files[fileIndex]); - size_t t = j-browser->dir_count; - if (nk_button_image_label(ctx, *icon, browser->files[t],NK_TEXT_RIGHT)) { + size_t fileIndex = ((size_t)j - dir_count); + icon = media_icon_for_file((*files)[fileIndex]); + if (nk_button_image_label(ctx, *icon, (*files)[t],NK_TEXT_RIGHT)) { snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); clicked = 1; } @@ -329,7 +411,7 @@ if( cols < 1 ) cols=1; struct nk_rect bounds = nk_widget_bounds(ctx); if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds) ) { - char *name = j < browser->dir_count ? browser->directories[j] : browser->files[j-browser->dir_count]; + char *name = j < dir_count ? (*directories)[j] : (*files)[j-dir_count]; char fullpath[PATH_MAX]; snprintf(fullpath, PATH_MAX, "%s%s", browser->directory, name); diff --git a/engine/split/v4k.c.inl b/engine/split/v4k.c.inl index 18e683a..1b27b6b 100644 --- a/engine/split/v4k.c.inl +++ b/engine/split/v4k.c.inl @@ -27,7 +27,20 @@ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ -* ALTERNATIVE B - MIT-0 (No Attribution clause) +* ALTERNATIVE B - 0-BSD License (https://opensource.org/licenses/FPL-1.0.0) +* ------------------------------------------------------------------------------ +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* ------------------------------------------------------------------------------ +* ALTERNATIVE C - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software @@ -41,19 +54,6 @@ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* ------------------------------------------------------------------------------ -* ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) -* ------------------------------------------------------------------------------ -* Permission to use, copy, modify, and/or distribute this software for any -* purpose with or without fee is hereby granted. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * @@ -73,7 +73,7 @@ * -- * * "I dedicate any and all copyright interest in this software to the three -* license terms listed above. I make this dedication for the benefit of the +* licensing terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." @@ -113,6 +113,8 @@ API void *ui_handle(); //----------------------------------------------------------------------------- // C files +{{FILE:v4k_begin.c}} + {{FILE:v4k_ds.c}} {{FILE:v4k_string.c}} diff --git a/engine/split/v4k.h.inl b/engine/split/v4k.h.inl index 67032ef..d77a14a 100644 --- a/engine/split/v4k.h.inl +++ b/engine/split/v4k.h.inl @@ -27,7 +27,20 @@ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ -* ALTERNATIVE B - MIT-0 (No Attribution clause) +* ALTERNATIVE B - 0-BSD License (https://opensource.org/licenses/FPL-1.0.0) +* ------------------------------------------------------------------------------ +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* ------------------------------------------------------------------------------ +* ALTERNATIVE C - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software @@ -41,19 +54,6 @@ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* ------------------------------------------------------------------------------ -* ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) -* ------------------------------------------------------------------------------ -* Permission to use, copy, modify, and/or distribute this software for any -* purpose with or without fee is hereby granted. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * @@ -73,7 +73,7 @@ * -- * * "I dedicate any and all copyright interest in this software to the three -* license terms listed above. I make this dedication for the benefit of the +* licensing terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." diff --git a/engine/split/v4k.x.inl b/engine/split/v4k.x.inl index 4afe7fb..88ccaf4 100644 --- a/engine/split/v4k.x.inl +++ b/engine/split/v4k.x.inl @@ -136,6 +136,7 @@ errno_t fopen_s( #define NK_DTOA(s,n) strcpy(s, va("%f", n)) // override cos built-in nk_dtoa() will freeze while parsing UINT_MAX otherwise {{FILE:3rd_nuklear.h}} {{FILE:3rd_nuklear_glfw_gl3.h}} +static char *ui_filter = 0; {{FILE:3rd_nuklear_filebrowser.h}} //--- #ifdef ENABLE_ASSIMP diff --git a/engine/split/v4k_ai.c b/engine/split/v4k_ai.c index 26b61f4..1c4e99e 100644 --- a/engine/split/v4k_ai.c +++ b/engine/split/v4k_ai.c @@ -15,7 +15,7 @@ vec3 rnd3() { // random uniform int less3(vec3 *lhs, vec3 *rhs) { if(lhs->x != rhs->x) return lhs->x - rhs->x; if(lhs->y != rhs->y) return lhs->y - rhs->y; - if(lhs->z != rhs->z) return lhs->z - rhs->z; + if(lhs->z != rhs->z) return lhs->z - rhs->z; // @testme: remove superfluous if check return 0; } uint64_t hash3(vec3 *v) { diff --git a/engine/split/v4k_begin.c b/engine/split/v4k_begin.c new file mode 100644 index 0000000..cac4f95 --- /dev/null +++ b/engine/split/v4k_begin.c @@ -0,0 +1,3 @@ +#define do_threadlock(mutexptr) \ + for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \ + for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) ) diff --git a/engine/split/v4k_config.h b/engine/split/v4k_config.h index ee36496..7c36d1a 100644 --- a/engine/split/v4k_config.h +++ b/engine/split/v4k_config.h @@ -227,6 +227,8 @@ #define VA_SELECT_10TH(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10 // VA_SPLIT() expands to A) 1 item OR B) 1 item + ',' + va_args[1..N] #define VA_SPLIT(...) VA_FIRST(__VA_ARGS__) VA_REST(__VA_ARGS__) +// VA_COUNT() counts number of va args +#define VA_COUNT(...) (int)(sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1) #if is(cl) && !is(cpp) #define INLINE __inline diff --git a/engine/split/v4k_editor.c b/engine/split/v4k_editor.c index b652656..99a7323 100644 --- a/engine/split/v4k_editor.c +++ b/engine/split/v4k_editor.c @@ -186,6 +186,235 @@ int engine_tick() { } else { // window_fps_lock( editor_hz ); window_fps_unlock( ); + } + + return 0; +} + +int ui_debug() { + static int time_factor = 0; + static int playing = 0; + static int paused = 0; + int advance_frame = 0; + +#if 0 + static int do_filter = 0; + static int do_profile = 0; + static int do_extra = 0; + + char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", + do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, + ICON_MD_PLAY_ARROW, + paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, + ICON_MD_FAST_FORWARD, + ICON_MD_STOP, + ICON_MD_REPLAY, + ICON_MD_FACE, + ICON_MD_MENU + ); + + if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; + int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); + if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; + if( choice == 2 ) playing = 1, paused = 0; + if( choice == 3 ) advance_frame = !!paused, paused = 1; + if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; + if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; + if( choice == 6 ) window_reload(); + if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; + if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; + + if( do_filter ) { + char *bak = ui_filter; ui_filter = 0; + ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak); + ui_filter = bak; + if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) + do_filter = 0; + } + } else { + if( ui_filter ) ui_filter[0] = '\0'; + } + char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*"; + + static char *username = 0; + static char *userpass = 0; + if( do_profile ) { + ui_string(ICON_MD_FACE " Username", &username); + ui_string(ICON_MD_FACE " Password", &userpass); + } + + if( do_extra ) { + int choice2 = ui_label2_toolbar(NULL, + ICON_MD_VIEW_IN_AR + ICON_MD_MESSAGE + ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE + ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO + ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF + + ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 + + ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU + ); + } +#endif + + int open = 0, clicked_or_toggled = 0; + + + #define EDITOR_UI_COLLAPSE(f,...) \ + for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) + + + EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { + // @todo. parse /bugs.ini, includes saved screenshots & videos. + // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) + } + + + // Art and bookmarks + EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { + bool inlined = true; + const char *file = 0; + if( ui_browse(&file, &inlined) ) { + const char *sep = ifdef(win32, "\"", "'"); + app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); + } + } + EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } + + + // E,C,S,W + EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { + EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { + //node_edit(editor.edit.down,&editor.edit); + } + + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } + + // node_edit(&editor.init,&editor.init); + // node_edit(&editor.draw,&editor.draw); + // node_edit(&editor.tick,&editor.tick); + // node_edit(&editor.edit,&editor.edit); + // node_edit(&editor.quit,&editor.quit); + } + + EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { + // @todo + } + EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { + ui_audio(); + } + EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { + ui_camera( camera_get_active() ); + } + EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { + // @todo: fps lock, fps target, aspect ratio, fullscreen + char *text = va("%s;%s;%s", + window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, + ICON_MD_PHOTO_CAMERA, + record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM + ); + + int choice = ui_toolbar(text); + if( choice == 1 ) engine_send("key_fullscreen",0); + if( choice == 2 ) engine_send("key_screenshot",0); + if( choice == 3 ) engine_send("key_record",0); + } + EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { + ui_keyboard(); + } + EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { + ui_mouse(); + } + EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { + for( int q = 0; q < 4; ++q ) { + for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { + ui_gamepad(q); + } + } + } + + + EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { + // @todo + } + EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { + ui_shaders(); + } + EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { + ui_fxs(); + } + EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") { + int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); + if( choice == 1 ) ui_layout_all_reset("*"); + if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); + + for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { + bool visible = ui_visible(*k); + if( ui_bool( *k, &visible ) ) { + ui_show( *k, ui_visible(*k) ^ true ); + } + } + } + + + EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { + // @todo. // mem,fps,gfx,net,hdd,... also logging + } + EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { + // @todo + // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR + } + EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { + ui_profiler(); + } + EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { + // @todo + } + + + + // logic: either plug icon (power saving off) or one of the following ones (power saving on): + // if 0% batt (no batt): battery alert + // if discharging: battery levels [alert,0..6,full] + // if charging: battery charging + int battery_read = app_battery(); + int battery_level = abs(battery_read); + int battery_discharging = battery_read < 0 && battery_level < 100; + const char *power_icon_label = ICON_MD_POWER " Power"; + if( battery_level ) { + const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? + ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, + ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, + ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, + }; + power_icon_label = (const char*)va("%s Power %d%%", + battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, + battery_level); + } + + EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { + int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); + if( choice == 1 ) engine_send("key_battery","0"); + if( choice == 2 ) engine_send("key_battery","1"); + } + + EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { + ui_reflect("*"); + } + + EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { + // @todo. include VCS + EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { + // @todo + } } return 0; diff --git a/engine/split/v4k_editor.h b/engine/split/v4k_editor.h index 7abb8ec..a76a343 100644 --- a/engine/split/v4k_editor.h +++ b/engine/split/v4k_editor.h @@ -14,6 +14,8 @@ API int* engine_geti(const char *key); API char** engine_gets(const char *key); API int engine_send(const char *cmd, const char *optional_value); +API int ui_debug(); + // open file dialog API char* dialog_load(); diff --git a/engine/split/v4k_obj.c b/engine/split/v4k_obj.c index 8f1935b..1d2d6fa 100644 --- a/engine/split/v4k_obj.c +++ b/engine/split/v4k_obj.c @@ -159,13 +159,13 @@ void *obj_unref(void *oo) { // scene tree array(obj*)* obj_children(const void *o) { - array(obj*) *c = obj_payload(o); + array(obj*) *c = &((obj*)o)->objchildren; if(!(*c)) array_push((*c), NULL); // default parenting: none. @todo: optimize & move this at construction time return c; } obj* obj_parent(const void *o) { array(obj*) *c = obj_children(o); - return (*c) ? 0[*c] : NULL; + return 0[*c]; // (*c) ? 0[*c] : NULL; } obj* obj_root(const void *o) { while( obj_parent(o) ) o = obj_parent(o); @@ -697,33 +697,27 @@ void test_obj_serialization(void *o1, void *o2) { // ---------------------------------------------------------------------------- // components -bool obj_addcomponent(void *object, unsigned c, void *ptr) { - entity *e = (entity*)object; +bool obj_addcomponent(entity *e, unsigned c, void *ptr) { e->cflags |= (3ULL << c); e->c[c & (OBJCOMPONENTS_MAX-1)] = ptr; return 1; } -bool obj_hascomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_hascomponent(entity *e, unsigned c) { return !!(e->cflags & (3ULL << c)); } -void* obj_getcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +void* obj_getcomponent(entity *e, unsigned c) { return e->c[c & (OBJCOMPONENTS_MAX-1)]; } -bool obj_delcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_delcomponent(entity *e, unsigned c) { e->cflags &= ~(3ULL << c); e->c[c & (OBJCOMPONENTS_MAX-1)] = NULL; return 1; } -bool obj_usecomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_usecomponent(entity *e, unsigned c) { e->cflags |= (1ULL << c); return 1; } -bool obj_offcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_offcomponent(entity *e, unsigned c) { e->cflags &= ~(1ULL << c); return 0; } @@ -733,17 +727,23 @@ char *entity_save(entity *self) { return sav; } -AUTORUN { +static +void entity_register() { + do_once { STRUCT(entity, uintptr_t, cflags); - -// struct { OBJHEADER union { struct { uintptr_t objenabled : 32, objflagged : 32; }; uintptr_t cflags; }; void* c[32]; }; - obj_extend(entity, save); } +} + +AUTORUN{ + entity_register(); +} static void test_obj_ecs() { - entity *e = obj_new(entity); + entity_register(); // why is this required here? autorun init fiasco? + + entity *e = entity_new(entity); puts(obj_save(e)); for( int i = 0; i < 32; ++i) test(0 == obj_hascomponent(e, i)); @@ -756,27 +756,14 @@ void test_obj_ecs() { // ---------------------------------------------------------------------------- // reflection -void *obj_clone(const void *src) { - obj *ptr = obj_malloc( sizeof(obj) + obj_size(src) + sizeof(array(obj*)) ); - ptr->objheader = ((const obj *)src)->objheader; - obj_loadini(ptr, obj_saveini(src)); - return ptr; -} +void* obj_mutate(void *dst, const void *src) { + ((obj*)dst)->objheader = ((const obj *)src)->objheader; -void* obj_merge(void *dst, const void *src) { // @testme - char *bin = obj_savebin(src); - return obj_mergebin(dst, bin); -} - -void* obj_mutate(void **dst, const void *src) { #if 0 // mutate a class. ie, convert a given object class into a different one, // while preserving the original metas, components and references as much as possible. // @todo iterate per field - if(!*dst_) return *dst_ = obj_clone(src); - - void *dst = *dst_; dtor(dst); unsigned src_sz = obj_sizeof(src); @@ -798,6 +785,20 @@ void* obj_mutate(void **dst, const void *src) { return dst; } +void *obj_clone(const void *src) { + int sz = sizeof(obj) + obj_size(src) + sizeof(array(obj*)); + enum { N = 8 }; sz = ((sz + (N - 1)) & -N); // Round up to N-byte boundary + obj *ptr = obj_malloc( sz ); + obj_mutate(ptr, src); // ptr->objheader = ((const obj *)src)->objheader; + obj_loadini(ptr, obj_saveini(src)); + return ptr; +} + +void* obj_merge(void *dst, const void *src) { // @testme + char *bin = obj_savebin(src); + return obj_mergebin(dst, bin); +} + void *obj_make(const char *str) { const char *T; const char *I = strchr(str, '['); // is_ini diff --git a/engine/split/v4k_obj.h b/engine/split/v4k_obj.h index 5829932..377c4ba 100644 --- a/engine/split/v4k_obj.h +++ b/engine/split/v4k_obj.h @@ -20,6 +20,8 @@ #endif #define OBJHEADER \ + struct { \ + ifdef(debug, const char *objname;) \ union { \ uintptr_t objheader; \ struct { \ @@ -31,10 +33,12 @@ uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \ uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \ }; \ + }; \ + array(struct obj*) objchildren; \ }; #define OBJ \ - struct { OBJHEADER ifdef(debug,const char *objname;) }; + OBJHEADER // ---------------------------------------------------------------------------- // syntax sugars @@ -83,6 +87,9 @@ // OBJTYPEDEF(entity,1) typedef struct entity { ENTITY } entity; +#define entity_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) +#define entity_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) + // ---------------------------------------------------------------------------- // heap/stack ctor/dtor @@ -97,16 +104,16 @@ static __thread obj *objtmp; obj_ctor(PTR)) #define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \ objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \ - *(TYPE*)objtmp = ((TYPE){ {0}, __VA_ARGS__}), \ + *(TYPE*)objtmp = ((TYPE){ {0,}, __VA_ARGS__}), \ ((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \ ( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \ OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \ ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \ obj_setname(objtmp, NAME)) -#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, sizeof(array(obj*)), __VA_ARGS__) -#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, sizeof(array(obj*)), __VA_ARGS__) -#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, sizeof(array(obj*)), __VA_ARGS__) +#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, 0, __VA_ARGS__) +#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) +#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) void* obj_malloc(unsigned sz); void* obj_free(void *o); @@ -261,12 +268,12 @@ API int obj_pop(void *o); // ---------------------------------------------------------------------------- // components -API bool obj_addcomponent(void *object, unsigned c, void *ptr); -API bool obj_hascomponent(void *object, unsigned c); -API void* obj_getcomponent(void *object, unsigned c); -API bool obj_delcomponent(void *object, unsigned c); -API bool obj_usecomponent(void *object, unsigned c); -API bool obj_offcomponent(void *object, unsigned c); +API bool obj_addcomponent(entity *e, unsigned c, void *ptr); +API bool obj_hascomponent(entity *e, unsigned c); +API void* obj_getcomponent(entity *e, unsigned c); +API bool obj_delcomponent(entity *e, unsigned c); +API bool obj_usecomponent(entity *e, unsigned c); +API bool obj_offcomponent(entity *e, unsigned c); API char* entity_save(entity *self); @@ -282,7 +289,7 @@ API char* entity_save(entity *self); API void* obj_clone(const void *src); API void* obj_merge(void *dst, const void *src); // @testme -API void* obj_mutate(void **dst, const void *src); +API void* obj_mutate(void *dst, const void *src); API void* obj_make(const char *str); // built-ins diff --git a/engine/split/v4k_reflect.c b/engine/split/v4k_reflect.c index 8a3017a..969d35a 100644 --- a/engine/split/v4k_reflect.c +++ b/engine/split/v4k_reflect.c @@ -9,6 +9,7 @@ static map(unsigned, array(reflect_t)) members; void reflect_init() { if(!reflects) map_init_int(reflects); + if(!members) map_init_int(members); } AUTORUN { reflect_init(); @@ -96,7 +97,7 @@ void ui_reflect_(const reflect_t *R, const char *filter, int mask) { if( buf ) *buf = '\0'; struct nk_context *ui_ctx = (struct nk_context *)ui_handle(); - for ui_push_hspace(16) { + /*for ui_push_hspace(16)*/ { array(reflect_t) *T = map_find(members, intern(R->name)); /**/ if( T ) {ui_label(strcatf(&buf,"S struct %s@%s", R->name, R->info+1)); for each_array_ptr(*T, reflect_t, it) if(strmatchi(it->name,filter)) ui_reflect_(it,filter,'M'); } else if( R->addr ) ui_label(strcatf(&buf,"F func %s()@%s", R->name, R->info+1)); diff --git a/engine/split/v4k_ui.c b/engine/split/v4k_ui.c index 19a2ac2..3e590f7 100644 --- a/engine/split/v4k_ui.c +++ b/engine/split/v4k_ui.c @@ -1,3 +1,121 @@ +// ---------------------------------------------------------------------------------------- +// ui extensions first + +static float +nk_text_width(struct nk_context *ctx, const char *str, unsigned len) { + const struct nk_style *style = &ctx->style; + const struct nk_user_font *f = style->font; + float pixels_width = f->width(f->userdata, f->height, str, len ? (int)len : (int)strlen(str)); + return pixels_width; +} + +static nk_bool +nk_hovered_text(struct nk_context *ctx, const char *str, int len, + nk_flags align, nk_bool value) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + #if 1 //< @r-lyeh: sim button logic + struct nk_rect touch; + touch.x = bounds.x - style->selectable.touch_padding.x; + touch.y = bounds.y - style->selectable.touch_padding.y; + touch.w = bounds.w + style->selectable.touch_padding.x * 2; + touch.h = bounds.h + style->selectable.touch_padding.y * 2; + int clicked = !!nk_button_behavior(&ctx->last_widget_state, touch, in, NK_BUTTON_DEFAULT); + in = 0; //< @r-lyeh: do not pass any input + #endif + + nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, + str, len, align, &value, &style->selectable, in, style->font); + + return clicked; //< @r-lyeh: return sim button logic instead of prev function call +} + +#define ui_push_hspace(px) \ + (int xx = px; xx; xx = 0) \ + for(struct nk_context *ctx = (struct nk_context*)ui_handle(); ctx; ctx = 0 ) \ + for(struct nk_panel *layout = ui_ctx->current->layout; layout; ) \ + for( xx = (layout->at_x += px, layout->bounds.w -= px, 0); layout; layout->at_x -= px, layout->bounds.w += px, layout = 0 ) + +// helper macros to instance an overlayed toolbar within the regions of an existing widget +#define UI_TOOLBAR_OVERLAY_DECLARE(...) \ + __VA_ARGS__; \ + struct nk_rect toolbar_bounds; nk_layout_peek(&toolbar_bounds, ui_ctx); \ + struct nk_vec2 item_padding = ui_ctx->style.text.padding; \ + struct nk_text text; \ + text.padding.x = item_padding.x; \ + text.padding.y = item_padding.y; \ + text.background = ui_ctx->style.window.background; +#define UI_TOOLBAR_OVERLAY(CHOICE,TEXT,COLOR,ALIGNMENT) \ + do { \ + text.text = COLOR; \ + nk_widget_text(&ui_ctx->current->buffer, toolbar_bounds, TEXT, strlen(TEXT), &text, ALIGNMENT, ui_ctx->style.font); \ + int clicked_x = input_down(MOUSE_L) && nk_input_is_mouse_hovering_rect(&ui_ctx->input, toolbar_bounds); \ + if( clicked_x ) clicked_x = (int)((ui_ctx->input.mouse.pos.x - toolbar_bounds.x) - (ALIGNMENT == NK_TEXT_RIGHT ? bounds.w : 0) ); \ + CHOICE = 1 + (ALIGNMENT == NK_TEXT_RIGHT ? -1 : +1) * clicked_x / (UI_ICON_FONTSIZE + UI_ICON_SPACING_X); /* divided by px per ICON_MD_ glyph approximately */ \ + int glyphs = strlen(TEXT) / 4 /*3:MD,4:MDI*/; CHOICE *= !!clicked_x * (CHOICE <= glyphs); } while(0) + +// menu macros that work not only standalone but also contained within a panel or window +#define UI_MENU(N, ...) do { \ + enum { MENUROW_HEIGHT = 25 }; \ + int embedded = !!ui_ctx->current; \ + struct nk_rect total_space = {0,0,window_width(),window_height()}; \ + if( embedded ) total_space = nk_window_get_bounds(ui_ctx), total_space.w -= 10; \ + vec2 popup_space = { total_space.w * 0.33, total_space.h * 0.85 }; \ + int created = !embedded && nk_begin(ui_ctx, "MENU_" STRINGIZE(__COUNTER__), nk_rect(0, 0, window_width(), UI_MENUROW_HEIGHT), NK_WINDOW_NO_SCROLLBAR); \ + if ( embedded || created ) { \ + int align = NK_TEXT_LEFT, Nth = (N), ITEM_WIDTH = 30, span = 0; \ + nk_menubar_begin(ui_ctx); \ + nk_layout_row_begin(ui_ctx, NK_STATIC, MENUROW_HEIGHT, Nth); \ + __VA_ARGS__; \ + nk_menubar_end(ui_ctx); \ + if( created ) nk_end(ui_ctx); \ + } } while(0) +#define UI_MENU_POPUP(title, ...) { \ + int hspace = maxi(ITEM_WIDTH, nk_text_width(ui_ctx,(title),0)); \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align, nk_vec2(popup_space.w,popup_space.h))) { \ + __VA_ARGS__; \ + nk_menu_end(ui_ctx); \ + }} +#define UI_MENU_ITEM(title, ...) { \ + int hspace = maxi(ITEM_WIDTH, nk_text_width(ui_ctx,(title),0)); \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align, nk_vec2(1,1))) { \ + __VA_ARGS__; \ + nk_menu_close(ui_ctx); \ + nk_menu_end(ui_ctx); \ + }} +#define UI_MENU_ALIGN_RIGHT(px) { \ + int hspace = total_space.w - span - (px) - 1.5 * ITEM_WIDTH; \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align = NK_TEXT_RIGHT, nk_vec2(1,1))) { \ + nk_menu_close(ui_ctx); \ + nk_menu_end(ui_ctx); \ + }} + +// ---------------------------------------------------------------------------------------- +// ui #ifndef UI_ICONS_SMALL //#define UI_ICONS_SMALL 1 @@ -316,7 +434,6 @@ vec2 ui_toolbar_(array(ui_item_t) ui_items, vec2 ui_results) { // old method: nk_layout_row_dynamic(ui_ctx, UI_MENUBAR_ICON_HEIGHT/*h*/, array_count(ui_items)); { const struct nk_style *style = &ui_ctx->style; - const struct nk_user_font *f = style->font; nk_layout_row_template_begin(ui_ctx, UI_MENUBAR_ICON_HEIGHT/*h*/); for(int i = 0; i < array_count(ui_items); ++i) { @@ -326,7 +443,7 @@ vec2 ui_toolbar_(array(ui_item_t) ui_items, vec2 ui_results) { char *tooltip = strchr(first_token, '@'); int len = tooltip ? (int)(tooltip - first_token /*- 1*/) : strlen(first_token); - float pixels_width = f->width(f->userdata, f->height, first_token, len); + float pixels_width = nk_text_width(ui_ctx, first_token, len); pixels_width += style->window.header.label_padding.x * 2 + style->window.header.padding.x * 2; if( pixels_width < 5 ) pixels_width = 5; nk_layout_row_template_push_static(ui_ctx, pixels_width); @@ -1404,20 +1521,19 @@ int ui_panel_end() { } static unsigned ui_collapse_state = 0; -static bool ui_collapse_next_open = 0; int ui_collapse(const char *label, const char *id) { // mask: 0(closed),1(open),2(created) - int open = label[0] == '!'; label += open; + int start_open = label[0] == '!'; label += start_open; uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL; for(int i = 0; id[i]; ++i) hash = (hash ^ id[i]) * mult; ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue; - ui_collapse_state = nk_tree_base_(ui_ctx, NK_TREE_NODE, 0, label, ui_collapse_next_open ? NK_MAXIMIZED : NK_MINIMIZED, id, strlen(id), 0); - return ui_collapse_next_open = 0, ui_collapse_state & 1; // |1 open, |2 clicked, |4 toggled -} -int ui_collapseo(const char *label, const char *id) { // mask: 0(closed),1(open),2(created) - ui_collapse_next_open = true; - return ui_collapse(label, id); + int forced = ui_filter && ui_filter[0]; + enum nk_collapse_states forced_open = NK_MAXIMIZED; + + ui_collapse_state = nk_tree_base_(ui_ctx, NK_TREE_NODE, 0, label, start_open ? NK_MAXIMIZED : NK_MINIMIZED, forced ? &forced_open : NULL, id, strlen(id), 0); + + return ui_collapse_state & 1; // |1 open, |2 clicked, |4 toggled } int ui_collapse_clicked() { return ui_collapse_state >> 1; // |1 clicked, |2 toggled @@ -1574,10 +1690,12 @@ if( font ) nk_style_pop_font(ui_ctx); return ui_label_icon_clicked_L.x; } -int ui_label(const char *text) { - int align = text[0] == '>' ? (text++, NK_TEXT_RIGHT) : text[0] == '=' ? (text++, NK_TEXT_CENTERED) : text[0] == '<' ? (text++, NK_TEXT_LEFT) : NK_TEXT_LEFT; +int ui_label(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + + int align = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT; nk_layout_row_dynamic(ui_ctx, 0, 1); - return ui_label_(text, align); + return ui_label_(label, align); } static int nk_label_(struct nk_context *ui_ctx, const char *text_, int align2 ) { @@ -1601,6 +1719,8 @@ ui_label_icon_clicked_R.x = is_hovering ? ( (int)((input->mouse.pos.x - bounds.x int ui_label2(const char *label, const char *text_) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); int align1 = NK_TEXT_LEFT; @@ -1655,7 +1775,9 @@ int ui_button_transparent(const char *text) { #endif static -int ui_button_(const char *text) { +int ui_button_(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + if( 1 ) { #if UI_BUTTON_MONOCHROME nk_style_push_color(ui_ctx, &ui_ctx->style.button.text_normal, nk_rgba(0,0,0,ui_alpha)); @@ -1686,8 +1808,8 @@ int ui_button_(const char *text) { struct nk_rect bounds = nk_widget_bounds(ui_ctx); - const char *split = strchr(text, '@'), *tooltip = split + 1; - int ret = nk_button_text(ui_ctx, text, split ? (int)(split - text) : strlen(text) ); + const char *split = strchr(label, '@'), *tooltip = split + 1; + int ret = nk_button_text(ui_ctx, label, split ? (int)(split - label) : strlen(label) ); const struct nk_input *in = &ui_ctx->input; if (split && nk_input_is_mouse_hovering_rect(in, bounds) && !ui_has_active_popups && nk_window_has_focus(ui_ctx)) { @@ -1708,6 +1830,23 @@ int ui_button_(const char *text) { } int ui_buttons(int buttons, ...) { + static array(char*) args = 0; + array_resize(args, 0); + + int num_skips = 0; + va_list list; + va_start(list, buttons); + for( int i = 0; i < buttons; ++i ) { + const char *label = va_arg(list, const char*); + int skip = ui_filter && ui_filter[0] && !strstri(label, ui_filter); + array_push(args, skip ? NULL : (char*)label); + num_skips += skip; + } + va_end(list); + + if( num_skips == array_count(args) ) return 0; + buttons = array_count(args) - num_skips; + nk_layout_row_dynamic(ui_ctx, 0, buttons); float ui_hue_old = ui_hue; @@ -1722,10 +1861,8 @@ int ui_buttons(int buttons, ...) { layout->bounds.w -= indent; int rc = 0; - va_list list; - va_start(list, buttons); - for( int i = 0; i < buttons; ++i ) { - if( ui_button_( va_arg(list, const char*) ) ) rc = i+1; + for( int i = 0, end = array_count(args); i < end; ++i ) { + if( args[i] && ui_button_( args[i] ) ) rc = i+1; ui_hue_cycle( 3 ); } va_end(list); @@ -1742,6 +1879,8 @@ int ui_button(const char *s) { } int ui_toggle(const char *label, bool *value) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1751,6 +1890,8 @@ int ui_toggle(const char *label, bool *value) { } int ui_color4f(const char *label, float *color4) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float c[4] = { color4[0]*255, color4[1]*255, color4[2]*255, color4[3]*255 }; int ret = ui_color4(label, c); for( int i = 0; i < 4; ++i ) color4[i] = c[i] / 255.0f; @@ -1760,6 +1901,8 @@ int ui_color4f(const char *label, float *color4) { static enum color_mode {COL_RGB, COL_HSV} ui_color_mode = COL_RGB; int ui_color4(const char *label, float *color4) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1806,6 +1949,8 @@ int ui_color3f(const char *label, float *color3) { } int ui_color3(const char *label, float *color3) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1842,6 +1987,8 @@ int ui_color3(const char *label, float *color3) { } int ui_list(const char *label, const char **items, int num_items, int *selector) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1852,6 +1999,8 @@ int ui_list(const char *label, const char **items, int num_items, int *selector) } int ui_slider(const char *label, float *slider) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + // return ui_slider2(label, slider, va("%.2f ", *slider)); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1862,6 +2011,8 @@ int ui_slider(const char *label, float *slider) { return chg; } int ui_slider2(const char *label, float *slider, const char *caption) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1886,6 +2037,8 @@ int ui_slider2(const char *label, float *slider, const char *caption) { } int ui_bool(const char *label, bool *enabled ) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1900,6 +2053,8 @@ int ui_bool(const char *label, bool *enabled ) { } int ui_int(const char *label, int *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1909,6 +2064,8 @@ int ui_int(const char *label, int *v) { } int ui_unsigned(const char *label, unsigned *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1918,11 +2075,15 @@ int ui_unsigned(const char *label, unsigned *v) { } int ui_short(const char *label, short *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int i = *v, ret = ui_int( label, &i ); return *v = (short)i, ret; } int ui_float(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1931,6 +2092,8 @@ int ui_float(const char *label, float *v) { } int ui_double(const char *label, double *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1939,6 +2102,8 @@ int ui_double(const char *label, double *v) { } int ui_clampf(const char *label, float *v, float minf, float maxf) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + if( minf > maxf ) return ui_clampf(label, v, maxf, minf); nk_layout_row_dynamic(ui_ctx, 0, 2); @@ -1951,6 +2116,8 @@ int ui_clampf(const char *label, float *v, float minf, float maxf) { static bool ui_float_sign = 0; int ui_float2(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1969,6 +2136,8 @@ int ui_float2(const char *label, float *v) { } int ui_float3(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -1988,6 +2157,8 @@ int ui_float3(const char *label, float *v) { } int ui_float4(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -2009,6 +2180,8 @@ int ui_float4(const char *label, float *v) { } int ui_mat33(const char *label, float M[9]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 3; int changed = 0; changed |= ui_label(label); @@ -2018,6 +2191,8 @@ int ui_mat33(const char *label, float M[9]) { return changed; } int ui_mat34(const char *label, float M[12]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 3; int changed = 0; changed |= ui_label(label); @@ -2027,6 +2202,8 @@ int ui_mat34(const char *label, float M[12]) { return changed; } int ui_mat44(const char *label, float M[16]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 4; int changed = 0; changed |= ui_label(label); @@ -2038,6 +2215,8 @@ int ui_mat44(const char *label, float M[16]) { } int ui_buffer(const char *label, char *buffer, int buflen) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 1 + (label && label[0])); if(label && label[0]) ui_label_(label, NK_TEXT_LEFT); @@ -2046,6 +2225,8 @@ int ui_buffer(const char *label, char *buffer, int buflen) { } int ui_string(const char *label, char **str) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + char *bak = va("%s%c", *str ? *str : "", '\0'); int rc = ui_buffer(label, bak, strlen(bak)+2); if( *str ) 0[*str] = '\0'; @@ -2054,6 +2235,8 @@ int ui_string(const char *label, char **str) { } int ui_separator() { + if( /*label &&*/ ui_filter && ui_filter[0] ) return 0; // if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, UI_SEPARATOR_HEIGHT, 1); ui_hue_cycle( 1 ); @@ -2070,6 +2253,8 @@ int ui_separator() { } int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, sh < 30 || id == texture_checker().id ? 0 : sh, 1 + (label && label[0])); if( label && label[0] ) ui_label_(label, NK_TEXT_LEFT); @@ -2099,31 +2284,35 @@ int ui_subtexture(const char *label, texture_t t, unsigned x, unsigned y, unsign return ui_subimage(label, t.id, t.w,t.h, x,y,w,h); } -int ui_colormap( const char *map_name, colormap_t *cm ) { +int ui_colormap( const char *label, colormap_t *cm ) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int ret = 0; if( !cm->texture ) { - const char *title = va("%s (no image)", map_name); + const char *title = va("%s (no image)", label); if( ui_image( title, texture_checker().id, 0,0 ) ) { ret = 2; } } else { unsigned w = cm->texture->w, h = cm->texture->h; - ui_label(va("%s (%s)", map_name, cm->texture->filename) ); // @fixme: labelf would crash? + ui_label(va("%s (%s)", label, cm->texture->filename) ); // @fixme: labelf would crash? const char *fmt[] = { "", "R", "RG", "RGB", "RGBA" }; - const char *title = va("%s %dx%d %s", map_name, w, h, fmt[cm->texture->n]); + const char *title = va("%s %dx%d %s", label, w, h, fmt[cm->texture->n]); if( ui_image( title, cm->texture->id, 128, 128 ) ) { ret = 2; } } - if( ui_color4f( va("%s Color", map_name), (float *) &cm->color ) ) { + if( ui_color4f( va("%s Color", label), (float *) &cm->color ) ) { ret = 1; } return ret; } int ui_radio(const char *label, const char **items, int num_items, int *selector) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int ret = 0; if( label && label[0] ) ui_label(label); for( int i = 0; i < num_items; i++ ) { @@ -2136,20 +2325,24 @@ int ui_radio(const char *label, const char **items, int num_items, int *selector return ret; } -int ui_section(const char *section) { +int ui_section(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + //ui_separator(); - return ui_label(va("*%s", section)); + return ui_label(va("*%s", label)); } -int ui_dialog(const char *title, const char *text, int choices, bool *show) { // @fixme: return +int ui_dialog(const char *label, const char *text, int choices, bool *show) { // @fixme: return + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_has_active_popups = 0; if(*show) { static struct nk_rect s = {0, 0, 300, 190}; - if (nk_popup_begin(ui_ctx, NK_POPUP_STATIC, title, NK_WINDOW_BORDER|NK_WINDOW_CLOSABLE, s)) { + if (nk_popup_begin(ui_ctx, NK_POPUP_STATIC, label, NK_WINDOW_BORDER|NK_WINDOW_CLOSABLE, s)) { nk_layout_row_dynamic(ui_ctx, 20, 1); - for( char label[1024]; *text && sscanf(text, "%[^\r\n]", label); ) { - nk_label(ui_ctx, label, NK_TEXT_LEFT); - text += strlen(label); while(*text && *text < 32) text++; + for( char t[1024]; *text && sscanf(text, "%[^\r\n]", t); ) { + nk_label(ui_ctx, t, NK_TEXT_LEFT); + text += strlen(t); while(*text && *text < 32) text++; } if( choices ) { @@ -2170,6 +2363,8 @@ int ui_dialog(const char *title, const char *text, int choices, bool *show) { // #define ui_bitmask_template(X) \ int ui_bitmask##X(const char *label, uint##X##_t *enabled) { \ + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; \ +\ /* @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive */ \ nk_layout_row_dynamic(ui_ctx, 1, 1); \ struct nk_rect bounds = nk_widget_bounds(ui_ctx); \ @@ -2297,9 +2492,46 @@ int ui_browse(const char **output, bool *inlined) { struct browser *browser = browsers + windowed; // select instance char **result = results + windowed; // select instance - struct nk_rect bounds = {0,0,400,300}; // @fixme: how to retrieve inlined region below? (inlined) - if( windowed || (!windowed && *inlined) ) bounds = nk_window_get_content_region(ui_ctx); - else { struct nk_rect b; nk_layout_peek(&b, ui_ctx); bounds.w = b.w; } + struct nk_rect bounds = {0}; // // {0,0,400,300}; + // #define P(b) printf(FILELINE " (%3d,%3d) %3d,%3d\n", (int)b.x,(int)b.y, (int)b.w,(int)b.h) + // if(ui_ctx->current) bounds = nk_layout_space_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_layout_widget_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_widget_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_window_get_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_window_get_content_region(ui_ctx), P(bounds); + // if(ui_ctx->current) nk_layout_peek(&bounds, ui_ctx), P(bounds); + // // if(ui_ctx->current) nk_layout_widget_space(&bounds, ui_ctx, ui_ctx->current, nk_false), P(bounds); // note: cant be used within a panel + // #undef P + + // panel + // v4k_ui.c:2497 ( 6, 34) 310, 24 + // v4k_ui.c:2498 ( 16, 62) 286, 24 + // v4k_ui.c:2499 ( 16, 86) 296, 24 + // v4k_ui.c:2500 ( 0, 0) 327,613 + // v4k_ui.c:2501 ( 6, 34) 310,572 << ok + // v4k_ui.c:2502 ( 16, 86) 296, 24 + // v4k_ui.c:2503 (316, 62) 297, 24 + + // window + // v4k_ui.c:2497 (188,152) 711, 4 + // v4k_ui.c:2498 (188,152) 711, 4 + // v4k_ui.c:2499 (-2147483648,156) -2147483648, 4 + // v4k_ui.c:2500 (182,118) 728,409 + // v4k_ui.c:2501 (188,152) 711,368 << ok + // v4k_ui.c:2502 (-2147483648,156) -2147483648, 4 + // v4k_ui.c:2503 (-2147483648,152) -2147483648, 4 + + // popup + // v4k_ui.c:2497 ( 9, 30) 350, 24 + // v4k_ui.c:2498 ( 19, 58) 326, 24 + // v4k_ui.c:2499 ( 19, 82) 336, 24 + // v4k_ui.c:2500 ( 4, 29) 360,460 + // v4k_ui.c:2501 ( 9, 30) 350,458 << ok + // v4k_ui.c:2502 ( 19, 82) 336, 24 + // v4k_ui.c:2503 (359, 58) 336, 24 + + bounds = nk_window_get_content_region(ui_ctx); + if( !windowed && *inlined ) bounds.h *= 0.80; clicked = browser_run(ui_ctx, browser, windowed, bounds); if( clicked ) { diff --git a/engine/split/v4k_ui.h b/engine/split/v4k_ui.h index 11f857a..faca236 100644 --- a/engine/split/v4k_ui.h +++ b/engine/split/v4k_ui.h @@ -86,3 +86,4 @@ API int ui_hover(); // ui_is_hover()? API int ui_active(); // ui_is_active()? API int ui_demo(int do_windows); +API void *ui_handle(); diff --git a/engine/split/v4k_window.c b/engine/split/v4k_window.c index 60f01eb..b3633e4 100644 --- a/engine/split/v4k_window.c +++ b/engine/split/v4k_window.c @@ -536,229 +536,8 @@ int window_frame_begin() { // generate Debug panel contents if( may_render_debug_panel ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { - - static int time_factor = 0; - static int playing = 0; - static int paused = 0; - int advance_frame = 0; - - static int do_filter = 0; - static int do_profile = 0; - static int do_extra = 0; - - char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", - do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, - ICON_MD_PLAY_ARROW, - paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, - ICON_MD_FAST_FORWARD, - ICON_MD_STOP, - ICON_MD_REPLAY, - ICON_MD_FACE, - ICON_MD_MENU - ); - - if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; - int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); - if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; - if( choice == 2 ) playing = 1, paused = 0; - if( choice == 3 ) advance_frame = !!paused, paused = 1; - if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; - if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; - if( choice == 6 ) window_reload(); - if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; - if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; - - static char *filter = 0; - if( do_filter ) { - ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter); - if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) - do_filter = 0; - } - } else { - if( filter ) filter[0] = '\0'; - } - char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*"; - - static char *username = 0; - static char *userpass = 0; - if( do_profile ) { - ui_string(ICON_MD_FACE " Username", &username); - ui_string(ICON_MD_FACE " Password", &userpass); - } - - if( do_extra ) { - int choice2 = ui_label2_toolbar(NULL, - ICON_MD_VIEW_IN_AR - ICON_MD_MESSAGE - ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE - ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO - ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF - - ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 - - ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU - ); - } - - int open = 0, clicked_or_toggled = 0; - - #define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id)) - - #define EDITOR_UI_COLLAPSE(f,...) \ - for( int macro(p) = (open = ui_collapse_filtered(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) - - - EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { - // @todo. parse /bugs.ini, includes saved screenshots & videos. - // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) - } - - - // Art and bookmarks - EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { - bool inlined = true; - const char *file = 0; - if( ui_browse(&file, &inlined) ) { - const char *sep = ifdef(win32, "\"", "'"); - app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); - } - } - EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } - - - // E,C,S,W - EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { - EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { - //node_edit(editor.edit.down,&editor.edit); - } - - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } - - // node_edit(&editor.init,&editor.init); - // node_edit(&editor.draw,&editor.draw); - // node_edit(&editor.tick,&editor.tick); - // node_edit(&editor.edit,&editor.edit); - // node_edit(&editor.quit,&editor.quit); - } - - EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { - // @todo - } - EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { - ui_audio(); - } - EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { - ui_camera( camera_get_active() ); - } - EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { - // @todo: fps lock, fps target, aspect ratio, fullscreen - char *text = va("%s;%s;%s", - window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, - ICON_MD_PHOTO_CAMERA, - record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM - ); - - int choice = ui_toolbar(text); - if( choice == 1 ) engine_send("key_fullscreen",0); - if( choice == 2 ) engine_send("key_screenshot",0); - if( choice == 3 ) engine_send("key_record",0); - } - EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { - ui_keyboard(); - } - EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { - ui_mouse(); - } - EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { - for( int q = 0; q < 4; ++q ) { - for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { - ui_gamepad(q); - } - } - } - - - EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { - // @todo - } - EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { - ui_shaders(); - } - EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { - ui_fxs(); - } - EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") { - int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); - if( choice == 1 ) ui_layout_all_reset("*"); - if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); - - for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { - bool visible = ui_visible(*k); - if( ui_bool( *k, &visible ) ) { - ui_show( *k, ui_visible(*k) ^ true ); - } - } - } - - - EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { - // @todo. // mem,fps,gfx,net,hdd,... also logging - } - EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { - // @todo - // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR - } - EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { - ui_profiler(); - } - EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { - // @todo - } - - - - // logic: either plug icon (power saving off) or one of the following ones (power saving on): - // if 0% batt (no batt): battery alert - // if discharging: battery levels [alert,0..6,full] - // if charging: battery charging - int battery_read = app_battery(); - int battery_level = abs(battery_read); - int battery_discharging = battery_read < 0 && battery_level < 100; - const char *power_icon_label = ICON_MD_POWER " Power"; - if( battery_level ) { - const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? - ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, - ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, - ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, - }; - power_icon_label = (const char*)va("%s Power %d%%", - battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, - battery_level); - } - - EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { - int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); - if( choice == 1 ) engine_send("key_battery","0"); - if( choice == 2 ) engine_send("key_battery","1"); - } - - EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { - ui_reflect("*"); - } - - EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { - // @todo. include VCS - EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { - // @todo - } - } + API int ui_debug(); + ui_debug(); (has_menu ? ui_window_end : ui_panel_end)(); } diff --git a/engine/v4k b/engine/v4k index 62f6d8f..0a9496d 100644 --- a/engine/v4k +++ b/engine/v4k @@ -211989,6 +211989,9 @@ nk_nonblock_begin(struct nk_context *ctx, nk_flags flags, struct nk_rect body, struct nk_rect header, enum nk_panel_type panel_type) { +if(body.x < 10) body.x = 0; //< @r-lyeh: popup snapping to the left +if((body.x+body.w)>window_width()) body.x-=body.w-(window_width()-body.x); //< @r-lyeh: prevent popups to be printed outside of window client / right border + struct nk_window *popup; struct nk_window *win; struct nk_panel *panel; @@ -212470,7 +212473,7 @@ nk_menu_begin(struct nk_context *ctx, struct nk_window *win, is_active = (popup && (win->popup.name == hash) && win->popup.type == NK_PANEL_MENU); if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || (!is_open && !is_active && !is_clicked)) return 0; - if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR, body, header, NK_PANEL_MENU)) + if (!nk_nonblock_begin(ctx, NK_WINDOW_NO_SCROLLBAR_X/*|NK_WINDOW_NO_SCROLLBAR*/, body, header, NK_PANEL_MENU)) //< @r-lyeh: our popups are huge. enable Y scrollbars return 0; win->popup.type = NK_PANEL_MENU; @@ -213704,6 +213707,7 @@ nk_tree_state_base_(struct nk_context *ctx, enum nk_tree_type type, NK_INTERN int nk_tree_base_(struct nk_context *ctx, enum nk_tree_type type, struct nk_image *img, const char *title, enum nk_collapse_states initial_state, + enum nk_collapse_states *forced_state, //< @r-lyeh const char *hash, int len, int line) { struct nk_window *win = ctx->current; @@ -213721,7 +213725,8 @@ nk_tree_base_(struct nk_context *ctx, enum nk_tree_type type, state = nk_add_value(ctx, win, tree_hash, 0); *state = initial_state; } - return nk_tree_state_base_(ctx, type, img, title, (enum nk_collapse_states*)state); + return nk_tree_state_base_(ctx, type, img, title, + forced_state ? forced_state : (enum nk_collapse_states*)state); //< @r-lyeh } #endif NK_API nk_bool @@ -221909,6 +221914,7 @@ void nk_glfw3_shutdown(struct nk_glfw* glfw) #endif #endif #line 0 +static char *ui_filter = 0; #line 1 "engine/split/3rd_nuklear_filebrowser.h" // file browser for nuklear, based on https://github.com/vurtun/nuklear/blob/master/example/file_browser.c (public domain) // - rlyeh, public domain @@ -221928,8 +221934,56 @@ void nk_glfw3_shutdown(struct nk_glfw* glfw) #else #include // getcwd() #include // getpwuid() +#define _popen popen +#define _pclose pclose #endif +const char** old_file_list(const char *cwd, const char *masks) { + ASSERT(strend(cwd, "/"), "Error: dirs like '%s' must end with slash", cwd); + + static __thread array(char*) list = 0; + const char *arg0 = cwd; // app_path(); + int larg0 = strlen(arg0); + + for( int i = 0; i < array_count(list); ++i ) { + FREE(list[i]); + } + array_resize(list, 0);//array_free(list); + + for each_substring(masks,";",it) { + int recurse = !!strstr(it, "**"); + #if is(win32) + char *glob = va("dir %s/b/o:n \"%s\\%s\" 2> NUL", recurse ? "/s":"", cwd, it); + #else // linux, osx + char *glob = va("find %s %s -name \"%s\" | sort", cwd, !recurse ? "-maxdepth 1":"-type f", it); + #endif + for( FILE *in = _popen(glob, "r"); in; _pclose(in), in = 0) { + char buf[1024], *line = buf; + while( fgets(buf, sizeof(buf), in) ) { + // clean up + if( strstr(line, arg0) ) line = buf + larg0; + if( !memcmp(line, "./", 2) ) line += 2; + int len = strlen(line); while( len > 0 && line[len-1] < 32 ) line[--len] = 0; + if( line[0] == '\0' ) continue; + // do not insert system folders/files + for(int i = 0; i < len; ++i ) if(line[i] == '\\') line[i] = '/'; + if( line[0] == '.' ) if( !strcmp(line,".git") || !strcmp(line,".vs") || !strcmp(line,".") || !strcmp(line,"..") ) continue; + if( strstr(line, "/.") ) continue; + // insert copy + #if is(win32) + char *copy = STRDUP(line); // full path already provided + #else + // while(line[0] == '/') ++line; + char *copy = STRDUP(va("%s%s", cwd, line)); // need to prepend path + #endif + array_push(list, copy); + } + } + } + array_push(list, 0); // terminator + return (const char**)list; +} + #if 1 #define BROWSER_PRINTF(...) do {} while(0) #else @@ -221993,6 +222047,10 @@ struct browser { size_t file_count; size_t dir_count; + /* filtered directory content */ + array(char*) ffiles; + array(char*) fdirectories; + /* view mode */ bool listing; float zooming; @@ -222029,8 +222087,8 @@ static void browser_reload_directory_content(struct browser *browser, const char BROWSER_PRINTF("searching at %s\n", path); - array(char*) list = file_list(path); - for( int i = 0, end = array_count(list); i < end; ++i ) { + const char** list = old_file_list(path, "*"); + for( int i = 0; list[i]; ++i ) { char *absolute = file_pathabs(ifndef(win32, list[i], va("%s/%s", path, list[i]))); // ../dir/./file.ext -> c:/prj/dir/file.ext BROWSER_PRINTF("%s->%s %d->", list[i], absolute, file_directory(absolute) ); @@ -222095,6 +222153,9 @@ static void browser_free(struct browser *browser) { for(int i = 0; i < array_count(browser->directories); ++i) FREE(browser->directories[i]); array_free(browser->files); array_free(browser->directories); + array_free(browser->ffiles); + array_free(browser->fdirectories); + memset(browser, 0, sizeof(*browser)); } @@ -222175,10 +222236,33 @@ if( cols < 1 ) cols=1; /* output directory content window */ if(nk_group_begin(ctx, "Content", windowed ? NK_WINDOW_NO_SCROLLBAR : 0)) { + + array(char*) *directories = &browser->directories; + array(char*) *files = &browser->files; + + if( ui_filter && ui_filter[0] ) { + array_resize(browser->fdirectories, 0); + array_resize(browser->ffiles, 0); + + for each_array(browser->directories,char*,k) + if( strstri(k, ui_filter) ) + array_push(browser->fdirectories, k); + + for each_array(browser->files,char*,k) + if( strstri(k, ui_filter) ) + array_push(browser->ffiles, k); + + directories = &browser->fdirectories; + files = &browser->ffiles; + } + + int dir_count = array_count(*directories); + int file_count = array_count(*files); + int index = -1; size_t i = 0, j = 0, k = 0; size_t rows = 0; - size_t count = browser->dir_count + browser->file_count; + size_t count = dir_count + file_count; rows = count / cols; for (i = 0; i <= rows; i += 1) { @@ -222186,16 +222270,18 @@ if( cols < 1 ) cols=1; {size_t n = j + cols; nk_layout_row_dynamic(ctx, icon_height, (int)cols); for (; j < count && j < n; ++j) { + size_t t = j-dir_count; + /* draw one row of icons */ - if (j < browser->dir_count) { + if (j < dir_count) { /* draw and execute directory buttons */ if (nk_button_image(ctx,media.custom_folders[BROWSER_FOLDER])) index = (int)j; } else { /* draw and execute files buttons */ struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(browser->files[fileIndex]); + size_t fileIndex = ((size_t)j - dir_count); + icon = media_icon_for_file((*files)[fileIndex]); if (nk_button_image(ctx, *icon)) { snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); clicked = 1; @@ -222206,30 +222292,32 @@ if( cols < 1 ) cols=1; {size_t n = k + cols; nk_layout_row_dynamic(ctx, 20, (int)cols); for (; k < count && k < n; k++) { + size_t t = k-dir_count; + /* draw one row of labels */ - if (k < browser->dir_count) { - nk_label(ctx, browser->directories[k], NK_TEXT_CENTERED); + if (k < dir_count) { + nk_label(ctx, (*directories)[k], NK_TEXT_CENTERED); } else { - size_t t = k-browser->dir_count; - nk_label(ctx,browser->files[t],NK_TEXT_CENTERED); + nk_label(ctx, (*files)[t], NK_TEXT_CENTERED); } }} if(tiny) {size_t n = j + cols; nk_layout_row_dynamic(ctx, icon_height, (int)cols); for (; j < count && j < n; ++j) { + size_t t = j-dir_count; + /* draw one row of icons */ - if (j < browser->dir_count) { + if (j < dir_count) { /* draw and execute directory buttons */ - if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], browser->directories[j],NK_TEXT_RIGHT)) + if (nk_button_image_label(ctx,media.custom_folders[BROWSER_FOLDER], (*directories)[j], NK_TEXT_RIGHT)) index = (int)j; } else { /* draw and execute files buttons */ struct nk_image *icon; - size_t fileIndex = ((size_t)j - browser->dir_count); - icon = media_icon_for_file(browser->files[fileIndex]); - size_t t = j-browser->dir_count; - if (nk_button_image_label(ctx, *icon, browser->files[t],NK_TEXT_RIGHT)) { + size_t fileIndex = ((size_t)j - dir_count); + icon = media_icon_for_file((*files)[fileIndex]); + if (nk_button_image_label(ctx, *icon, (*files)[t],NK_TEXT_RIGHT)) { snprintf(browser->file, BROWSER_MAX_PATH, "%s%s", browser->directory, browser->files[fileIndex]); clicked = 1; } @@ -222241,7 +222329,7 @@ if( cols < 1 ) cols=1; struct nk_rect bounds = nk_widget_bounds(ctx); if (nk_input_is_mouse_hovering_rect(&ctx->input, bounds) ) { - char *name = j < browser->dir_count ? browser->directories[j] : browser->files[j-browser->dir_count]; + char *name = j < dir_count ? (*directories)[j] : (*files)[j-dir_count]; char fullpath[PATH_MAX]; snprintf(fullpath, PATH_MAX, "%s%s", browser->directory, name); diff --git a/engine/v4k.c b/engine/v4k.c index 0c6fe3c..04b1cea 100644 --- a/engine/v4k.c +++ b/engine/v4k.c @@ -27,7 +27,20 @@ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ -* ALTERNATIVE B - MIT-0 (No Attribution clause) +* ALTERNATIVE B - 0-BSD License (https://opensource.org/licenses/FPL-1.0.0) +* ------------------------------------------------------------------------------ +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* ------------------------------------------------------------------------------ +* ALTERNATIVE C - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software @@ -41,19 +54,6 @@ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* ------------------------------------------------------------------------------ -* ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) -* ------------------------------------------------------------------------------ -* Permission to use, copy, modify, and/or distribute this software for any -* purpose with or without fee is hereby granted. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * @@ -73,7 +73,7 @@ * -- * * "I dedicate any and all copyright interest in this software to the three -* license terms listed above. I make this dedication for the benefit of the +* licensing terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." @@ -113,6 +113,12 @@ API void *ui_handle(); //----------------------------------------------------------------------------- // C files +#line 1 "engine/split/v4k_begin.c" +#define do_threadlock(mutexptr) \ + for( int init_ = !!(mutexptr) || (thread_mutex_init( (mutexptr) = CALLOC(1, sizeof(thread_mutex_t)) ), 1); init_; init_ = 0) \ + for( int lock_ = (thread_mutex_lock( mutexptr ), 1); lock_; lock_ = (thread_mutex_unlock( mutexptr ), 0) ) +#line 0 + #line 1 "engine/split/v4k_ds.c" // ----------------------------------------------------------------------------- @@ -13141,6 +13147,7 @@ static map(unsigned, array(reflect_t)) members; void reflect_init() { if(!reflects) map_init_int(reflects); + if(!members) map_init_int(members); } AUTORUN { reflect_init(); @@ -13228,7 +13235,7 @@ void ui_reflect_(const reflect_t *R, const char *filter, int mask) { if( buf ) *buf = '\0'; struct nk_context *ui_ctx = (struct nk_context *)ui_handle(); - for ui_push_hspace(16) { + /*for ui_push_hspace(16)*/ { array(reflect_t) *T = map_find(members, intern(R->name)); /**/ if( T ) {ui_label(strcatf(&buf,"S struct %s@%s", R->name, R->info+1)); for each_array_ptr(*T, reflect_t, it) if(strmatchi(it->name,filter)) ui_reflect_(it,filter,'M'); } else if( R->addr ) ui_label(strcatf(&buf,"F func %s()@%s", R->name, R->info+1)); @@ -21041,6 +21048,124 @@ bool id_valid(uintptr_t id) { #line 0 #line 1 "engine/split/v4k_ui.c" +// ---------------------------------------------------------------------------------------- +// ui extensions first + +static float +nk_text_width(struct nk_context *ctx, const char *str, unsigned len) { + const struct nk_style *style = &ctx->style; + const struct nk_user_font *f = style->font; + float pixels_width = f->width(f->userdata, f->height, str, len ? (int)len : (int)strlen(str)); + return pixels_width; +} + +static nk_bool +nk_hovered_text(struct nk_context *ctx, const char *str, int len, + nk_flags align, nk_bool value) +{ + struct nk_window *win; + struct nk_panel *layout; + const struct nk_input *in; + const struct nk_style *style; + + enum nk_widget_layout_states state; + struct nk_rect bounds; + + NK_ASSERT(ctx); + NK_ASSERT(ctx->current); + NK_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) + return 0; + + win = ctx->current; + layout = win->layout; + style = &ctx->style; + + state = nk_widget(&bounds, ctx); + if (!state) return 0; + in = (state == NK_WIDGET_ROM || layout->flags & NK_WINDOW_ROM) ? 0 : &ctx->input; + + #if 1 //< @r-lyeh: sim button logic + struct nk_rect touch; + touch.x = bounds.x - style->selectable.touch_padding.x; + touch.y = bounds.y - style->selectable.touch_padding.y; + touch.w = bounds.w + style->selectable.touch_padding.x * 2; + touch.h = bounds.h + style->selectable.touch_padding.y * 2; + int clicked = !!nk_button_behavior(&ctx->last_widget_state, touch, in, NK_BUTTON_DEFAULT); + in = 0; //< @r-lyeh: do not pass any input + #endif + + nk_do_selectable(&ctx->last_widget_state, &win->buffer, bounds, + str, len, align, &value, &style->selectable, in, style->font); + + return clicked; //< @r-lyeh: return sim button logic instead of prev function call +} + +#define ui_push_hspace(px) \ + (int xx = px; xx; xx = 0) \ + for(struct nk_context *ctx = (struct nk_context*)ui_handle(); ctx; ctx = 0 ) \ + for(struct nk_panel *layout = ui_ctx->current->layout; layout; ) \ + for( xx = (layout->at_x += px, layout->bounds.w -= px, 0); layout; layout->at_x -= px, layout->bounds.w += px, layout = 0 ) + +// helper macros to instance an overlayed toolbar within the regions of an existing widget +#define UI_TOOLBAR_OVERLAY_DECLARE(...) \ + __VA_ARGS__; \ + struct nk_rect toolbar_bounds; nk_layout_peek(&toolbar_bounds, ui_ctx); \ + struct nk_vec2 item_padding = ui_ctx->style.text.padding; \ + struct nk_text text; \ + text.padding.x = item_padding.x; \ + text.padding.y = item_padding.y; \ + text.background = ui_ctx->style.window.background; +#define UI_TOOLBAR_OVERLAY(CHOICE,TEXT,COLOR,ALIGNMENT) \ + do { \ + text.text = COLOR; \ + nk_widget_text(&ui_ctx->current->buffer, toolbar_bounds, TEXT, strlen(TEXT), &text, ALIGNMENT, ui_ctx->style.font); \ + int clicked_x = input_down(MOUSE_L) && nk_input_is_mouse_hovering_rect(&ui_ctx->input, toolbar_bounds); \ + if( clicked_x ) clicked_x = (int)((ui_ctx->input.mouse.pos.x - toolbar_bounds.x) - (ALIGNMENT == NK_TEXT_RIGHT ? bounds.w : 0) ); \ + CHOICE = 1 + (ALIGNMENT == NK_TEXT_RIGHT ? -1 : +1) * clicked_x / (UI_ICON_FONTSIZE + UI_ICON_SPACING_X); /* divided by px per ICON_MD_ glyph approximately */ \ + int glyphs = strlen(TEXT) / 4 /*3:MD,4:MDI*/; CHOICE *= !!clicked_x * (CHOICE <= glyphs); } while(0) + +// menu macros that work not only standalone but also contained within a panel or window +#define UI_MENU(N, ...) do { \ + enum { MENUROW_HEIGHT = 25 }; \ + int embedded = !!ui_ctx->current; \ + struct nk_rect total_space = {0,0,window_width(),window_height()}; \ + if( embedded ) total_space = nk_window_get_bounds(ui_ctx), total_space.w -= 10; \ + vec2 popup_space = { total_space.w * 0.33, total_space.h * 0.85 }; \ + int created = !embedded && nk_begin(ui_ctx, "MENU_" STRINGIZE(__COUNTER__), nk_rect(0, 0, window_width(), UI_MENUROW_HEIGHT), NK_WINDOW_NO_SCROLLBAR); \ + if ( embedded || created ) { \ + int align = NK_TEXT_LEFT, Nth = (N), ITEM_WIDTH = 30, span = 0; \ + nk_menubar_begin(ui_ctx); \ + nk_layout_row_begin(ui_ctx, NK_STATIC, MENUROW_HEIGHT, Nth); \ + __VA_ARGS__; \ + nk_menubar_end(ui_ctx); \ + if( created ) nk_end(ui_ctx); \ + } } while(0) +#define UI_MENU_POPUP(title, ...) { \ + int hspace = maxi(ITEM_WIDTH, nk_text_width(ui_ctx,(title),0)); \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align, nk_vec2(popup_space.w,popup_space.h))) { \ + __VA_ARGS__; \ + nk_menu_end(ui_ctx); \ + }} +#define UI_MENU_ITEM(title, ...) { \ + int hspace = maxi(ITEM_WIDTH, nk_text_width(ui_ctx,(title),0)); \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align, nk_vec2(1,1))) { \ + __VA_ARGS__; \ + nk_menu_close(ui_ctx); \ + nk_menu_end(ui_ctx); \ + }} +#define UI_MENU_ALIGN_RIGHT(px) { \ + int hspace = total_space.w - span - (px) - 1.5 * ITEM_WIDTH; \ + nk_layout_row_push(ui_ctx, hspace); span += hspace; \ + if (nk_menu_begin_label(ui_ctx, (title), align = NK_TEXT_RIGHT, nk_vec2(1,1))) { \ + nk_menu_close(ui_ctx); \ + nk_menu_end(ui_ctx); \ + }} + +// ---------------------------------------------------------------------------------------- +// ui #ifndef UI_ICONS_SMALL //#define UI_ICONS_SMALL 1 @@ -21359,7 +21484,6 @@ vec2 ui_toolbar_(array(ui_item_t) ui_items, vec2 ui_results) { // old method: nk_layout_row_dynamic(ui_ctx, UI_MENUBAR_ICON_HEIGHT/*h*/, array_count(ui_items)); { const struct nk_style *style = &ui_ctx->style; - const struct nk_user_font *f = style->font; nk_layout_row_template_begin(ui_ctx, UI_MENUBAR_ICON_HEIGHT/*h*/); for(int i = 0; i < array_count(ui_items); ++i) { @@ -21369,7 +21493,7 @@ vec2 ui_toolbar_(array(ui_item_t) ui_items, vec2 ui_results) { char *tooltip = strchr(first_token, '@'); int len = tooltip ? (int)(tooltip - first_token /*- 1*/) : strlen(first_token); - float pixels_width = f->width(f->userdata, f->height, first_token, len); + float pixels_width = nk_text_width(ui_ctx, first_token, len); pixels_width += style->window.header.label_padding.x * 2 + style->window.header.padding.x * 2; if( pixels_width < 5 ) pixels_width = 5; nk_layout_row_template_push_static(ui_ctx, pixels_width); @@ -22447,20 +22571,19 @@ int ui_panel_end() { } static unsigned ui_collapse_state = 0; -static bool ui_collapse_next_open = 0; int ui_collapse(const char *label, const char *id) { // mask: 0(closed),1(open),2(created) - int open = label[0] == '!'; label += open; + int start_open = label[0] == '!'; label += start_open; uint64_t hash = 14695981039346656037ULL, mult = 0x100000001b3ULL; for(int i = 0; id[i]; ++i) hash = (hash ^ id[i]) * mult; ui_hue = (hash & 0x3F) / (float)0x3F; ui_hue += !ui_hue; - ui_collapse_state = nk_tree_base_(ui_ctx, NK_TREE_NODE, 0, label, ui_collapse_next_open ? NK_MAXIMIZED : NK_MINIMIZED, id, strlen(id), 0); - return ui_collapse_next_open = 0, ui_collapse_state & 1; // |1 open, |2 clicked, |4 toggled -} -int ui_collapseo(const char *label, const char *id) { // mask: 0(closed),1(open),2(created) - ui_collapse_next_open = true; - return ui_collapse(label, id); + int forced = ui_filter && ui_filter[0]; + enum nk_collapse_states forced_open = NK_MAXIMIZED; + + ui_collapse_state = nk_tree_base_(ui_ctx, NK_TREE_NODE, 0, label, start_open ? NK_MAXIMIZED : NK_MINIMIZED, forced ? &forced_open : NULL, id, strlen(id), 0); + + return ui_collapse_state & 1; // |1 open, |2 clicked, |4 toggled } int ui_collapse_clicked() { return ui_collapse_state >> 1; // |1 clicked, |2 toggled @@ -22617,10 +22740,12 @@ if( font ) nk_style_pop_font(ui_ctx); return ui_label_icon_clicked_L.x; } -int ui_label(const char *text) { - int align = text[0] == '>' ? (text++, NK_TEXT_RIGHT) : text[0] == '=' ? (text++, NK_TEXT_CENTERED) : text[0] == '<' ? (text++, NK_TEXT_LEFT) : NK_TEXT_LEFT; +int ui_label(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + + int align = label[0] == '>' ? (label++, NK_TEXT_RIGHT) : label[0] == '=' ? (label++, NK_TEXT_CENTERED) : label[0] == '<' ? (label++, NK_TEXT_LEFT) : NK_TEXT_LEFT; nk_layout_row_dynamic(ui_ctx, 0, 1); - return ui_label_(text, align); + return ui_label_(label, align); } static int nk_label_(struct nk_context *ui_ctx, const char *text_, int align2 ) { @@ -22644,6 +22769,8 @@ ui_label_icon_clicked_R.x = is_hovering ? ( (int)((input->mouse.pos.x - bounds.x int ui_label2(const char *label, const char *text_) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); int align1 = NK_TEXT_LEFT; @@ -22698,7 +22825,9 @@ int ui_button_transparent(const char *text) { #endif static -int ui_button_(const char *text) { +int ui_button_(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + if( 1 ) { #if UI_BUTTON_MONOCHROME nk_style_push_color(ui_ctx, &ui_ctx->style.button.text_normal, nk_rgba(0,0,0,ui_alpha)); @@ -22729,8 +22858,8 @@ int ui_button_(const char *text) { struct nk_rect bounds = nk_widget_bounds(ui_ctx); - const char *split = strchr(text, '@'), *tooltip = split + 1; - int ret = nk_button_text(ui_ctx, text, split ? (int)(split - text) : strlen(text) ); + const char *split = strchr(label, '@'), *tooltip = split + 1; + int ret = nk_button_text(ui_ctx, label, split ? (int)(split - label) : strlen(label) ); const struct nk_input *in = &ui_ctx->input; if (split && nk_input_is_mouse_hovering_rect(in, bounds) && !ui_has_active_popups && nk_window_has_focus(ui_ctx)) { @@ -22751,6 +22880,23 @@ int ui_button_(const char *text) { } int ui_buttons(int buttons, ...) { + static array(char*) args = 0; + array_resize(args, 0); + + int num_skips = 0; + va_list list; + va_start(list, buttons); + for( int i = 0; i < buttons; ++i ) { + const char *label = va_arg(list, const char*); + int skip = ui_filter && ui_filter[0] && !strstri(label, ui_filter); + array_push(args, skip ? NULL : (char*)label); + num_skips += skip; + } + va_end(list); + + if( num_skips == array_count(args) ) return 0; + buttons = array_count(args) - num_skips; + nk_layout_row_dynamic(ui_ctx, 0, buttons); float ui_hue_old = ui_hue; @@ -22765,10 +22911,8 @@ int ui_buttons(int buttons, ...) { layout->bounds.w -= indent; int rc = 0; - va_list list; - va_start(list, buttons); - for( int i = 0; i < buttons; ++i ) { - if( ui_button_( va_arg(list, const char*) ) ) rc = i+1; + for( int i = 0, end = array_count(args); i < end; ++i ) { + if( args[i] && ui_button_( args[i] ) ) rc = i+1; ui_hue_cycle( 3 ); } va_end(list); @@ -22785,6 +22929,8 @@ int ui_button(const char *s) { } int ui_toggle(const char *label, bool *value) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22794,6 +22940,8 @@ int ui_toggle(const char *label, bool *value) { } int ui_color4f(const char *label, float *color4) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + float c[4] = { color4[0]*255, color4[1]*255, color4[2]*255, color4[3]*255 }; int ret = ui_color4(label, c); for( int i = 0; i < 4; ++i ) color4[i] = c[i] / 255.0f; @@ -22803,6 +22951,8 @@ int ui_color4f(const char *label, float *color4) { static enum color_mode {COL_RGB, COL_HSV} ui_color_mode = COL_RGB; int ui_color4(const char *label, float *color4) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22849,6 +22999,8 @@ int ui_color3f(const char *label, float *color3) { } int ui_color3(const char *label, float *color3) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22885,6 +23037,8 @@ int ui_color3(const char *label, float *color3) { } int ui_list(const char *label, const char **items, int num_items, int *selector) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22895,6 +23049,8 @@ int ui_list(const char *label, const char **items, int num_items, int *selector) } int ui_slider(const char *label, float *slider) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + // return ui_slider2(label, slider, va("%.2f ", *slider)); nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22905,6 +23061,8 @@ int ui_slider(const char *label, float *slider) { return chg; } int ui_slider2(const char *label, float *slider, const char *caption) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22929,6 +23087,8 @@ int ui_slider2(const char *label, float *slider, const char *caption) { } int ui_bool(const char *label, bool *enabled ) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22943,6 +23103,8 @@ int ui_bool(const char *label, bool *enabled ) { } int ui_int(const char *label, int *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22952,6 +23114,8 @@ int ui_int(const char *label, int *v) { } int ui_unsigned(const char *label, unsigned *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22961,11 +23125,15 @@ int ui_unsigned(const char *label, unsigned *v) { } int ui_short(const char *label, short *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int i = *v, ret = ui_int( label, &i ); return *v = (short)i, ret; } int ui_float(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22974,6 +23142,8 @@ int ui_float(const char *label, float *v) { } int ui_double(const char *label, double *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -22982,6 +23152,8 @@ int ui_double(const char *label, double *v) { } int ui_clampf(const char *label, float *v, float minf, float maxf) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + if( minf > maxf ) return ui_clampf(label, v, maxf, minf); nk_layout_row_dynamic(ui_ctx, 0, 2); @@ -22994,6 +23166,8 @@ int ui_clampf(const char *label, float *v, float minf, float maxf) { static bool ui_float_sign = 0; int ui_float2(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -23012,6 +23186,8 @@ int ui_float2(const char *label, float *v) { } int ui_float3(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -23031,6 +23207,8 @@ int ui_float3(const char *label, float *v) { } int ui_float4(const char *label, float *v) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 2); ui_label_(label, NK_TEXT_LEFT); @@ -23052,6 +23230,8 @@ int ui_float4(const char *label, float *v) { } int ui_mat33(const char *label, float M[9]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 3; int changed = 0; changed |= ui_label(label); @@ -23061,6 +23241,8 @@ int ui_mat33(const char *label, float M[9]) { return changed; } int ui_mat34(const char *label, float M[12]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 3; int changed = 0; changed |= ui_label(label); @@ -23070,6 +23252,8 @@ int ui_mat34(const char *label, float M[12]) { return changed; } int ui_mat44(const char *label, float M[16]) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_float_sign = 4; int changed = 0; changed |= ui_label(label); @@ -23081,6 +23265,8 @@ int ui_mat44(const char *label, float M[16]) { } int ui_buffer(const char *label, char *buffer, int buflen) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, 0, 1 + (label && label[0])); if(label && label[0]) ui_label_(label, NK_TEXT_LEFT); @@ -23089,6 +23275,8 @@ int ui_buffer(const char *label, char *buffer, int buflen) { } int ui_string(const char *label, char **str) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + char *bak = va("%s%c", *str ? *str : "", '\0'); int rc = ui_buffer(label, bak, strlen(bak)+2); if( *str ) 0[*str] = '\0'; @@ -23097,6 +23285,8 @@ int ui_string(const char *label, char **str) { } int ui_separator() { + if( /*label &&*/ ui_filter && ui_filter[0] ) return 0; // if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, UI_SEPARATOR_HEIGHT, 1); ui_hue_cycle( 1 ); @@ -23113,6 +23303,8 @@ int ui_separator() { } int ui_subimage(const char *label, handle id, unsigned iw, unsigned ih, unsigned sx, unsigned sy, unsigned sw, unsigned sh) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + nk_layout_row_dynamic(ui_ctx, sh < 30 || id == texture_checker().id ? 0 : sh, 1 + (label && label[0])); if( label && label[0] ) ui_label_(label, NK_TEXT_LEFT); @@ -23142,31 +23334,35 @@ int ui_subtexture(const char *label, texture_t t, unsigned x, unsigned y, unsign return ui_subimage(label, t.id, t.w,t.h, x,y,w,h); } -int ui_colormap( const char *map_name, colormap_t *cm ) { +int ui_colormap( const char *label, colormap_t *cm ) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int ret = 0; if( !cm->texture ) { - const char *title = va("%s (no image)", map_name); + const char *title = va("%s (no image)", label); if( ui_image( title, texture_checker().id, 0,0 ) ) { ret = 2; } } else { unsigned w = cm->texture->w, h = cm->texture->h; - ui_label(va("%s (%s)", map_name, cm->texture->filename) ); // @fixme: labelf would crash? + ui_label(va("%s (%s)", label, cm->texture->filename) ); // @fixme: labelf would crash? const char *fmt[] = { "", "R", "RG", "RGB", "RGBA" }; - const char *title = va("%s %dx%d %s", map_name, w, h, fmt[cm->texture->n]); + const char *title = va("%s %dx%d %s", label, w, h, fmt[cm->texture->n]); if( ui_image( title, cm->texture->id, 128, 128 ) ) { ret = 2; } } - if( ui_color4f( va("%s Color", map_name), (float *) &cm->color ) ) { + if( ui_color4f( va("%s Color", label), (float *) &cm->color ) ) { ret = 1; } return ret; } int ui_radio(const char *label, const char **items, int num_items, int *selector) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + int ret = 0; if( label && label[0] ) ui_label(label); for( int i = 0; i < num_items; i++ ) { @@ -23179,20 +23375,24 @@ int ui_radio(const char *label, const char **items, int num_items, int *selector return ret; } -int ui_section(const char *section) { +int ui_section(const char *label) { + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + //ui_separator(); - return ui_label(va("*%s", section)); + return ui_label(va("*%s", label)); } -int ui_dialog(const char *title, const char *text, int choices, bool *show) { // @fixme: return +int ui_dialog(const char *label, const char *text, int choices, bool *show) { // @fixme: return + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; + ui_has_active_popups = 0; if(*show) { static struct nk_rect s = {0, 0, 300, 190}; - if (nk_popup_begin(ui_ctx, NK_POPUP_STATIC, title, NK_WINDOW_BORDER|NK_WINDOW_CLOSABLE, s)) { + if (nk_popup_begin(ui_ctx, NK_POPUP_STATIC, label, NK_WINDOW_BORDER|NK_WINDOW_CLOSABLE, s)) { nk_layout_row_dynamic(ui_ctx, 20, 1); - for( char label[1024]; *text && sscanf(text, "%[^\r\n]", label); ) { - nk_label(ui_ctx, label, NK_TEXT_LEFT); - text += strlen(label); while(*text && *text < 32) text++; + for( char t[1024]; *text && sscanf(text, "%[^\r\n]", t); ) { + nk_label(ui_ctx, t, NK_TEXT_LEFT); + text += strlen(t); while(*text && *text < 32) text++; } if( choices ) { @@ -23213,6 +23413,8 @@ int ui_dialog(const char *title, const char *text, int choices, bool *show) { // #define ui_bitmask_template(X) \ int ui_bitmask##X(const char *label, uint##X##_t *enabled) { \ + if( label && ui_filter && ui_filter[0] ) if( !strstri(label, ui_filter) ) return 0; \ +\ /* @fixme: better way to retrieve widget width? nk_layout_row_dynamic() seems excessive */ \ nk_layout_row_dynamic(ui_ctx, 1, 1); \ struct nk_rect bounds = nk_widget_bounds(ui_ctx); \ @@ -23340,9 +23542,46 @@ int ui_browse(const char **output, bool *inlined) { struct browser *browser = browsers + windowed; // select instance char **result = results + windowed; // select instance - struct nk_rect bounds = {0,0,400,300}; // @fixme: how to retrieve inlined region below? (inlined) - if( windowed || (!windowed && *inlined) ) bounds = nk_window_get_content_region(ui_ctx); - else { struct nk_rect b; nk_layout_peek(&b, ui_ctx); bounds.w = b.w; } + struct nk_rect bounds = {0}; // // {0,0,400,300}; + // #define P(b) printf(FILELINE " (%3d,%3d) %3d,%3d\n", (int)b.x,(int)b.y, (int)b.w,(int)b.h) + // if(ui_ctx->current) bounds = nk_layout_space_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_layout_widget_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_widget_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_window_get_bounds(ui_ctx), P(bounds); + // if(ui_ctx->current) bounds = nk_window_get_content_region(ui_ctx), P(bounds); + // if(ui_ctx->current) nk_layout_peek(&bounds, ui_ctx), P(bounds); + // // if(ui_ctx->current) nk_layout_widget_space(&bounds, ui_ctx, ui_ctx->current, nk_false), P(bounds); // note: cant be used within a panel + // #undef P + + // panel + // v4k_ui.c:2497 ( 6, 34) 310, 24 + // v4k_ui.c:2498 ( 16, 62) 286, 24 + // v4k_ui.c:2499 ( 16, 86) 296, 24 + // v4k_ui.c:2500 ( 0, 0) 327,613 + // v4k_ui.c:2501 ( 6, 34) 310,572 << ok + // v4k_ui.c:2502 ( 16, 86) 296, 24 + // v4k_ui.c:2503 (316, 62) 297, 24 + + // window + // v4k_ui.c:2497 (188,152) 711, 4 + // v4k_ui.c:2498 (188,152) 711, 4 + // v4k_ui.c:2499 (-2147483648,156) -2147483648, 4 + // v4k_ui.c:2500 (182,118) 728,409 + // v4k_ui.c:2501 (188,152) 711,368 << ok + // v4k_ui.c:2502 (-2147483648,156) -2147483648, 4 + // v4k_ui.c:2503 (-2147483648,152) -2147483648, 4 + + // popup + // v4k_ui.c:2497 ( 9, 30) 350, 24 + // v4k_ui.c:2498 ( 19, 58) 326, 24 + // v4k_ui.c:2499 ( 19, 82) 336, 24 + // v4k_ui.c:2500 ( 4, 29) 360,460 + // v4k_ui.c:2501 ( 9, 30) 350,458 << ok + // v4k_ui.c:2502 ( 19, 82) 336, 24 + // v4k_ui.c:2503 (359, 58) 336, 24 + + bounds = nk_window_get_content_region(ui_ctx); + if( !windowed && *inlined ) bounds.h *= 0.80; clicked = browser_run(ui_ctx, browser, windowed, bounds); if( clicked ) { @@ -24371,229 +24610,8 @@ int window_frame_begin() { // generate Debug panel contents if( may_render_debug_panel ) { if( has_menu ? ui_window("Debug " ICON_MD_SETTINGS, 0) : ui_panel("Debug " ICON_MD_SETTINGS, 0) ) { - - static int time_factor = 0; - static int playing = 0; - static int paused = 0; - int advance_frame = 0; - - static int do_filter = 0; - static int do_profile = 0; - static int do_extra = 0; - - char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", - do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, - ICON_MD_PLAY_ARROW, - paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, - ICON_MD_FAST_FORWARD, - ICON_MD_STOP, - ICON_MD_REPLAY, - ICON_MD_FACE, - ICON_MD_MENU - ); - - if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; - int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); - if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; - if( choice == 2 ) playing = 1, paused = 0; - if( choice == 3 ) advance_frame = !!paused, paused = 1; - if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; - if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; - if( choice == 6 ) window_reload(); - if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; - if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; - - static char *filter = 0; - if( do_filter ) { - ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &filter); - if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) - do_filter = 0; - } - } else { - if( filter ) filter[0] = '\0'; - } - char *filter_mask = filter && filter[0] ? va("*%s*", filter) : "*"; - - static char *username = 0; - static char *userpass = 0; - if( do_profile ) { - ui_string(ICON_MD_FACE " Username", &username); - ui_string(ICON_MD_FACE " Password", &userpass); - } - - if( do_extra ) { - int choice2 = ui_label2_toolbar(NULL, - ICON_MD_VIEW_IN_AR - ICON_MD_MESSAGE - ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE - ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO - ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF - - ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 - - ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU - ); - } - - int open = 0, clicked_or_toggled = 0; - - #define ui_collapse_filtered(lbl,id) (strmatchi(lbl,filter_mask) && ui_collapse(lbl,id)) - - #define EDITOR_UI_COLLAPSE(f,...) \ - for( int macro(p) = (open = ui_collapse_filtered(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) - - - EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { - // @todo. parse /bugs.ini, includes saved screenshots & videos. - // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) - } - - - // Art and bookmarks - EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { - bool inlined = true; - const char *file = 0; - if( ui_browse(&file, &inlined) ) { - const char *sep = ifdef(win32, "\"", "'"); - app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); - } - } - EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } - - - // E,C,S,W - EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { - EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } - EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { - //node_edit(editor.edit.down,&editor.edit); - } - - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } - //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } - - // node_edit(&editor.init,&editor.init); - // node_edit(&editor.draw,&editor.draw); - // node_edit(&editor.tick,&editor.tick); - // node_edit(&editor.edit,&editor.edit); - // node_edit(&editor.quit,&editor.quit); - } - - EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { - // @todo - } - EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { - ui_audio(); - } - EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { - ui_camera( camera_get_active() ); - } - EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { - // @todo: fps lock, fps target, aspect ratio, fullscreen - char *text = va("%s;%s;%s", - window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, - ICON_MD_PHOTO_CAMERA, - record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM - ); - - int choice = ui_toolbar(text); - if( choice == 1 ) engine_send("key_fullscreen",0); - if( choice == 2 ) engine_send("key_screenshot",0); - if( choice == 3 ) engine_send("key_record",0); - } - EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { - ui_keyboard(); - } - EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { - ui_mouse(); - } - EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { - for( int q = 0; q < 4; ++q ) { - for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { - ui_gamepad(q); - } - } - } - - - EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { - // @todo - } - EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { - ui_shaders(); - } - EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { - ui_fxs(); - } - EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") { - int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); - if( choice == 1 ) ui_layout_all_reset("*"); - if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); - - for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { - bool visible = ui_visible(*k); - if( ui_bool( *k, &visible ) ) { - ui_show( *k, ui_visible(*k) ^ true ); - } - } - } - - - EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { - // @todo. // mem,fps,gfx,net,hdd,... also logging - } - EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { - // @todo - // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR - } - EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { - ui_profiler(); - } - EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { - // @todo - } - - - - // logic: either plug icon (power saving off) or one of the following ones (power saving on): - // if 0% batt (no batt): battery alert - // if discharging: battery levels [alert,0..6,full] - // if charging: battery charging - int battery_read = app_battery(); - int battery_level = abs(battery_read); - int battery_discharging = battery_read < 0 && battery_level < 100; - const char *power_icon_label = ICON_MD_POWER " Power"; - if( battery_level ) { - const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? - ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, - ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, - ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, - }; - power_icon_label = (const char*)va("%s Power %d%%", - battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, - battery_level); - } - - EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { - int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); - if( choice == 1 ) engine_send("key_battery","0"); - if( choice == 2 ) engine_send("key_battery","1"); - } - - EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { - ui_reflect("*"); - } - - EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { - // @todo. include VCS - EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { - // @todo - } - } + API int ui_debug(); + ui_debug(); (has_menu ? ui_window_end : ui_panel_end)(); } @@ -25283,13 +25301,13 @@ void *obj_unref(void *oo) { // scene tree array(obj*)* obj_children(const void *o) { - array(obj*) *c = obj_payload(o); + array(obj*) *c = &((obj*)o)->objchildren; if(!(*c)) array_push((*c), NULL); // default parenting: none. @todo: optimize & move this at construction time return c; } obj* obj_parent(const void *o) { array(obj*) *c = obj_children(o); - return (*c) ? 0[*c] : NULL; + return 0[*c]; // (*c) ? 0[*c] : NULL; } obj* obj_root(const void *o) { while( obj_parent(o) ) o = obj_parent(o); @@ -25821,33 +25839,27 @@ void test_obj_serialization(void *o1, void *o2) { // ---------------------------------------------------------------------------- // components -bool obj_addcomponent(void *object, unsigned c, void *ptr) { - entity *e = (entity*)object; +bool obj_addcomponent(entity *e, unsigned c, void *ptr) { e->cflags |= (3ULL << c); e->c[c & (OBJCOMPONENTS_MAX-1)] = ptr; return 1; } -bool obj_hascomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_hascomponent(entity *e, unsigned c) { return !!(e->cflags & (3ULL << c)); } -void* obj_getcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +void* obj_getcomponent(entity *e, unsigned c) { return e->c[c & (OBJCOMPONENTS_MAX-1)]; } -bool obj_delcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_delcomponent(entity *e, unsigned c) { e->cflags &= ~(3ULL << c); e->c[c & (OBJCOMPONENTS_MAX-1)] = NULL; return 1; } -bool obj_usecomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_usecomponent(entity *e, unsigned c) { e->cflags |= (1ULL << c); return 1; } -bool obj_offcomponent(void *object, unsigned c) { - entity *e = (entity*)object; +bool obj_offcomponent(entity *e, unsigned c) { e->cflags &= ~(1ULL << c); return 0; } @@ -25857,17 +25869,23 @@ char *entity_save(entity *self) { return sav; } -AUTORUN { +static +void entity_register() { + do_once { STRUCT(entity, uintptr_t, cflags); - -// struct { OBJHEADER union { struct { uintptr_t objenabled : 32, objflagged : 32; }; uintptr_t cflags; }; void* c[32]; }; - obj_extend(entity, save); } +} + +AUTORUN{ + entity_register(); +} static void test_obj_ecs() { - entity *e = obj_new(entity); + entity_register(); // why is this required here? autorun init fiasco? + + entity *e = entity_new(entity); puts(obj_save(e)); for( int i = 0; i < 32; ++i) test(0 == obj_hascomponent(e, i)); @@ -25880,27 +25898,14 @@ void test_obj_ecs() { // ---------------------------------------------------------------------------- // reflection -void *obj_clone(const void *src) { - obj *ptr = obj_malloc( sizeof(obj) + obj_size(src) + sizeof(array(obj*)) ); - ptr->objheader = ((const obj *)src)->objheader; - obj_loadini(ptr, obj_saveini(src)); - return ptr; -} +void* obj_mutate(void *dst, const void *src) { + ((obj*)dst)->objheader = ((const obj *)src)->objheader; -void* obj_merge(void *dst, const void *src) { // @testme - char *bin = obj_savebin(src); - return obj_mergebin(dst, bin); -} - -void* obj_mutate(void **dst, const void *src) { #if 0 // mutate a class. ie, convert a given object class into a different one, // while preserving the original metas, components and references as much as possible. // @todo iterate per field - if(!*dst_) return *dst_ = obj_clone(src); - - void *dst = *dst_; dtor(dst); unsigned src_sz = obj_sizeof(src); @@ -25922,6 +25927,20 @@ void* obj_mutate(void **dst, const void *src) { return dst; } +void *obj_clone(const void *src) { + int sz = sizeof(obj) + obj_size(src) + sizeof(array(obj*)); + enum { N = 8 }; sz = ((sz + (N - 1)) & -N); // Round up to N-byte boundary + obj *ptr = obj_malloc( sz ); + obj_mutate(ptr, src); // ptr->objheader = ((const obj *)src)->objheader; + obj_loadini(ptr, obj_saveini(src)); + return ptr; +} + +void* obj_merge(void *dst, const void *src) { // @testme + char *bin = obj_savebin(src); + return obj_mergebin(dst, bin); +} + void *obj_make(const char *str) { const char *T; const char *I = strchr(str, '['); // is_ini @@ -25969,7 +25988,7 @@ vec3 rnd3() { // random uniform int less3(vec3 *lhs, vec3 *rhs) { if(lhs->x != rhs->x) return lhs->x - rhs->x; if(lhs->y != rhs->y) return lhs->y - rhs->y; - if(lhs->z != rhs->z) return lhs->z - rhs->z; + if(lhs->z != rhs->z) return lhs->z - rhs->z; // @testme: remove superfluous if check return 0; } uint64_t hash3(vec3 *v) { @@ -26980,6 +26999,235 @@ int engine_tick() { } else { // window_fps_lock( editor_hz ); window_fps_unlock( ); + } + + return 0; +} + +int ui_debug() { + static int time_factor = 0; + static int playing = 0; + static int paused = 0; + int advance_frame = 0; + +#if 0 + static int do_filter = 0; + static int do_profile = 0; + static int do_extra = 0; + + char *EDITOR_TOOLBAR_ICONS = va("%s;%s;%s;%s;%s;%s;%s;%s", + do_filter ? ICON_MD_CLOSE : ICON_MD_SEARCH, + ICON_MD_PLAY_ARROW, + paused ? ICON_MD_SKIP_NEXT : ICON_MD_PAUSE, + ICON_MD_FAST_FORWARD, + ICON_MD_STOP, + ICON_MD_REPLAY, + ICON_MD_FACE, + ICON_MD_MENU + ); + + if( input_down(KEY_F) ) if( input(KEY_LCTRL) || input(KEY_RCTRL) ) do_filter ^= 1; + int choice = ui_toolbar(EDITOR_TOOLBAR_ICONS); + if( choice == 1 ) do_filter ^= 1, do_profile = 0, do_extra = 0; + if( choice == 2 ) playing = 1, paused = 0; + if( choice == 3 ) advance_frame = !!paused, paused = 1; + if( choice == 4 ) paused = 0, time_factor = (++time_factor) % 4; + if( choice == 5 ) playing = 0, paused = 0, advance_frame = 0, time_factor = 0; + if( choice == 6 ) window_reload(); + if( choice == 7 ) do_filter = 0, do_profile ^= 1, do_extra = 0; + if( choice == 8 ) do_filter = 0, do_profile = 0, do_extra ^= 1; + + if( do_filter ) { + char *bak = ui_filter; ui_filter = 0; + ui_string(ICON_MD_CLOSE " Filter " ICON_MD_SEARCH, &bak); + ui_filter = bak; + if( ui_label_icon_clicked_L.x > 0 && ui_label_icon_clicked_L.x <= 24 ) { // if clicked on CANCEL icon (1st icon) + do_filter = 0; + } + } else { + if( ui_filter ) ui_filter[0] = '\0'; + } + char *filter_mask = ui_filter && ui_filter[0] ? va("*%s*", ui_filter) : "*"; + + static char *username = 0; + static char *userpass = 0; + if( do_profile ) { + ui_string(ICON_MD_FACE " Username", &username); + ui_string(ICON_MD_FACE " Password", &userpass); + } + + if( do_extra ) { + int choice2 = ui_label2_toolbar(NULL, + ICON_MD_VIEW_IN_AR + ICON_MD_MESSAGE + ICON_MD_TIPS_AND_UPDATES ICON_MD_LIGHTBULB ICON_MD_LIGHTBULB_OUTLINE + ICON_MD_IMAGE_SEARCH ICON_MD_INSERT_PHOTO + ICON_MD_VIDEOGAME_ASSET ICON_MD_VIDEOGAME_ASSET_OFF + + ICON_MD_VOLUME_UP ICON_MD_VOLUME_OFF // audio_volume_master(-1) > 0 + + ICON_MD_TROUBLESHOOT ICON_MD_SCHEMA ICON_MD_MENU + ); + } +#endif + + int open = 0, clicked_or_toggled = 0; + + + #define EDITOR_UI_COLLAPSE(f,...) \ + for( int macro(p) = (open = ui_collapse(f,__VA_ARGS__)), macro(dummy) = (clicked_or_toggled = ui_collapse_clicked()); macro(p); ui_collapse_end(), macro(p) = 0) + + + EDITOR_UI_COLLAPSE(ICON_MD_BUG_REPORT " Bugs 0", "Debug.Bugs") { + // @todo. parse /bugs.ini, includes saved screenshots & videos. + // @todo. screenshot include parseable level, position screen markers (same info as /bugs.ini) + } + + + // Art and bookmarks + EDITOR_UI_COLLAPSE(ICON_MD_FOLDER_SPECIAL " Art", "Debug.Art") { + bool inlined = true; + const char *file = 0; + if( ui_browse(&file, &inlined) ) { + const char *sep = ifdef(win32, "\"", "'"); + app_exec(va("%s %s%s%s", ifdef(win32, "start \"\"", ifdef(osx, "open", "xdg-open")), sep, file, sep)); + } + } + EDITOR_UI_COLLAPSE(ICON_MD_BOOKMARK " Bookmarks", "Debug.Bookmarks") { /* @todo */ } + + + // E,C,S,W + EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Scene", "Debug.Scene") { + EDITOR_UI_COLLAPSE(ICON_MD_BUBBLE_CHART/*ICON_MD_SCATTER_PLOT*/ " Entities", "Debug.Entities") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_TUNE " Components", "Debug.Components") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_PRECISION_MANUFACTURING " Systems", "Debug.Systems") { /* @todo */ } + EDITOR_UI_COLLAPSE(ICON_MD_PUBLIC " Levels", "Debug.Levels") { + //node_edit(editor.edit.down,&editor.edit); + } + + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Init", "Debug.HierarchyInit") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Draw", "Debug.HierarchyDraw") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Tick", "Debug.HierarchyTick") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Edit", "Debug.HierarchyEdit") { /* @todo */ } + //EDITOR_UI_COLLAPSE(ICON_MD_ACCOUNT_TREE " Quit", "Debug.HierarchyQuit") { /* @todo */ } + + // node_edit(&editor.init,&editor.init); + // node_edit(&editor.draw,&editor.draw); + // node_edit(&editor.tick,&editor.tick); + // node_edit(&editor.edit,&editor.edit); + // node_edit(&editor.quit,&editor.quit); + } + + EDITOR_UI_COLLAPSE(ICON_MD_ROCKET_LAUNCH " AI", "Debug.AI") { + // @todo + } + EDITOR_UI_COLLAPSE(ICON_MD_VOLUME_UP " Audio", "Debug.Audio") { + ui_audio(); + } + EDITOR_UI_COLLAPSE(ICON_MD_VIDEOCAM " Camera", "Debug.Camera") { + ui_camera( camera_get_active() ); + } + EDITOR_UI_COLLAPSE(ICON_MD_MONITOR " Display", "Debug.Display") { + // @todo: fps lock, fps target, aspect ratio, fullscreen + char *text = va("%s;%s;%s", + window_has_fullscreen() ? ICON_MD_FULLSCREEN_EXIT : ICON_MD_FULLSCREEN, + ICON_MD_PHOTO_CAMERA, + record_active() ? ICON_MD_VIDEOCAM_OFF : ICON_MD_VIDEOCAM + ); + + int choice = ui_toolbar(text); + if( choice == 1 ) engine_send("key_fullscreen",0); + if( choice == 2 ) engine_send("key_screenshot",0); + if( choice == 3 ) engine_send("key_record",0); + } + EDITOR_UI_COLLAPSE(ICON_MD_KEYBOARD " Keyboard", "Debug.Keyboard") { + ui_keyboard(); + } + EDITOR_UI_COLLAPSE(ICON_MD_MOUSE " Mouse", "Debug.Mouse") { + ui_mouse(); + } + EDITOR_UI_COLLAPSE(ICON_MD_GAMEPAD " Gamepads", "Debug.Gamepads") { + for( int q = 0; q < 4; ++q ) { + for( int r = (open = ui_collapse(va("Gamepad #%d",q+1), va("Debug.Gamepads%d",q))), dummy = (clicked_or_toggled = ui_collapse_clicked()); r; ui_collapse_end(), r = 0) { + ui_gamepad(q); + } + } + } + + + EDITOR_UI_COLLAPSE(ICON_MD_CONTENT_PASTE " Scripts", "Debug.Scripts") { + // @todo + } + EDITOR_UI_COLLAPSE(ICON_MD_STAR_HALF " Shaders", "Debug.Shaders") { + ui_shaders(); + } + EDITOR_UI_COLLAPSE(ICON_MD_MOVIE " FXs", "Debug.FXs") { + ui_fxs(); + } + EDITOR_UI_COLLAPSE(ICON_MD_VIEW_QUILT " UI", "Debug.UI") { + int choice = ui_toolbar(ICON_MD_RECYCLING " Reset layout;" ICON_MD_SAVE_AS " Save layout"); + if( choice == 1 ) ui_layout_all_reset("*"); + if( choice == 2 ) file_delete(WINDOWS_INI), ui_layout_all_save_disk("*"); + + for each_map_ptr_sorted(ui_windows, char*, k, unsigned, v) { + bool visible = ui_visible(*k); + if( ui_bool( *k, &visible ) ) { + ui_show( *k, ui_visible(*k) ^ true ); + } + } + } + + + EDITOR_UI_COLLAPSE(ICON_MD_SAVINGS " Budgets", "Debug.Budgets") { + // @todo. // mem,fps,gfx,net,hdd,... also logging + } + EDITOR_UI_COLLAPSE(ICON_MD_WIFI/*ICON_MD_SIGNAL_CELLULAR_ALT*/ " Network 0/0 KiB", "Debug.Network") { + // @todo + // SIGNAL_CELLULAR_1_BAR SIGNAL_CELLULAR_2_BAR + } + EDITOR_UI_COLLAPSE(va(ICON_MD_SPEED " Profiler %5.2f/%dfps", window_fps(), (int)window_fps_target()), "Debug.Profiler") { + ui_profiler(); + } + EDITOR_UI_COLLAPSE(va(ICON_MD_STORAGE " Storage %s", xstats()), "Debug.Storage") { + // @todo + } + + + + // logic: either plug icon (power saving off) or one of the following ones (power saving on): + // if 0% batt (no batt): battery alert + // if discharging: battery levels [alert,0..6,full] + // if charging: battery charging + int battery_read = app_battery(); + int battery_level = abs(battery_read); + int battery_discharging = battery_read < 0 && battery_level < 100; + const char *power_icon_label = ICON_MD_POWER " Power"; + if( battery_level ) { + const char *battery_levels[9] = { // @todo: remap [7%..100%] -> [0..1] ? + ICON_MD_BATTERY_ALERT,ICON_MD_BATTERY_0_BAR,ICON_MD_BATTERY_1_BAR, + ICON_MD_BATTERY_2_BAR,ICON_MD_BATTERY_3_BAR,ICON_MD_BATTERY_4_BAR, + ICON_MD_BATTERY_5_BAR,ICON_MD_BATTERY_6_BAR,ICON_MD_BATTERY_FULL, + }; + power_icon_label = (const char*)va("%s Power %d%%", + battery_discharging ? battery_levels[(int)((9-1)*clampf(battery_level/100.f,0,1))] : ICON_MD_BATTERY_CHARGING_FULL, + battery_level); + } + + EDITOR_UI_COLLAPSE(power_icon_label, "Debug.Power") { + int choice = ui_toolbar( ICON_MD_POWER ";" ICON_MD_BOLT ); + if( choice == 1 ) engine_send("key_battery","0"); + if( choice == 2 ) engine_send("key_battery","1"); + } + + EDITOR_UI_COLLAPSE(ICON_MD_WATER " Reflection", "Debug.Reflect") { + ui_reflect("*"); + } + + EDITOR_UI_COLLAPSE(ICON_MD_EXTENSION " Plugins", "Debug.Plugins") { + // @todo. include VCS + EDITOR_UI_COLLAPSE(ICON_MD_BUILD " Cook", "Debug.Cook") { + // @todo + } } return 0; diff --git a/engine/v4k.h b/engine/v4k.h index fe1e258..e421341 100644 --- a/engine/v4k.h +++ b/engine/v4k.h @@ -27,7 +27,20 @@ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * ------------------------------------------------------------------------------ -* ALTERNATIVE B - MIT-0 (No Attribution clause) +* ALTERNATIVE B - 0-BSD License (https://opensource.org/licenses/FPL-1.0.0) +* ------------------------------------------------------------------------------ +* Permission to use, copy, modify, and/or distribute this software for any +* purpose with or without fee is hereby granted. +* +* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE +* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +* PERFORMANCE OF THIS SOFTWARE. +* ------------------------------------------------------------------------------ +* ALTERNATIVE C - MIT-0 (No Attribution clause) * ------------------------------------------------------------------------------ * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software @@ -41,19 +54,6 @@ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* ------------------------------------------------------------------------------ -* ALTERNATIVE C - Zero BSD License (https://opensource.org/licenses/FPL-1.0.0) -* ------------------------------------------------------------------------------ -* Permission to use, copy, modify, and/or distribute this software for any -* purpose with or without fee is hereby granted. -* -* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -* FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE -* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -* PERFORMANCE OF THIS SOFTWARE. * * ## License: Contributed Code ------------------------------------------------ * @@ -73,7 +73,7 @@ * -- * * "I dedicate any and all copyright interest in this software to the three -* license terms listed above. I make this dedication for the benefit of the +* licensing terms listed above. I make this dedication for the benefit of the * public at large and to the detriment of my heirs and successors. I intend * this dedication to be an overt act of relinquishment in perpetuity of all * present and future rights to this software under copyright law." @@ -325,6 +325,8 @@ extern "C" { #define VA_SELECT_10TH(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, ...) A10 // VA_SPLIT() expands to A) 1 item OR B) 1 item + ',' + va_args[1..N] #define VA_SPLIT(...) VA_FIRST(__VA_ARGS__) VA_REST(__VA_ARGS__) +// VA_COUNT() counts number of va args +#define VA_COUNT(...) (int)(sizeof((int[]){0, ##__VA_ARGS__})/sizeof(int)-1) #if is(cl) && !is(cpp) #define INLINE __inline @@ -1820,6 +1822,8 @@ API int* engine_geti(const char *key); API char** engine_gets(const char *key); API int engine_send(const char *cmd, const char *optional_value); +API int ui_debug(); + // open file dialog API char* dialog_load(); @@ -2760,6 +2764,8 @@ API int64_t client_join(const char *ip, int port); #endif #define OBJHEADER \ + struct { \ + ifdef(debug, const char *objname;) \ union { \ uintptr_t objheader; \ struct { \ @@ -2771,10 +2777,12 @@ API int64_t client_join(const char *ip, int port); uintptr_t objunused:64-8-8-8-1-1-ID_INDEX_BITS-ID_COUNT_BITS; /*19*/ \ uintptr_t objid:ID_INDEX_BITS+ID_COUNT_BITS; /*16+3*/ \ }; \ + }; \ + array(struct obj*) objchildren; \ }; #define OBJ \ - struct { OBJHEADER ifdef(debug,const char *objname;) }; + OBJHEADER // ---------------------------------------------------------------------------- // syntax sugars @@ -2823,6 +2831,9 @@ API int64_t client_join(const char *ip, int port); // OBJTYPEDEF(entity,1) typedef struct entity { ENTITY } entity; +#define entity_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) +#define entity_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) + // ---------------------------------------------------------------------------- // heap/stack ctor/dtor @@ -2837,16 +2848,16 @@ static __thread obj *objtmp; obj_ctor(PTR)) #define OBJ_CTOR(TYPE, NAME, HEAP, PAYLOAD_SIZE, ...) (TYPE*)( \ objtmp = (HEAP ? MALLOC(sizeof(TYPE)+(PAYLOAD_SIZE)) : ALLOCA(sizeof(TYPE)+(PAYLOAD_SIZE))), \ - *(TYPE*)objtmp = ((TYPE){ {0}, __VA_ARGS__}), \ + *(TYPE*)objtmp = ((TYPE){ {0,}, __VA_ARGS__}), \ ((PAYLOAD_SIZE) ? memset((char*)objtmp + sizeof(TYPE), 0, (PAYLOAD_SIZE)) : objtmp), \ ( OBJTYPES[ OBJTYPE(TYPE) ] = #TYPE ), \ OBJ_CTOR_PTR(objtmp, HEAP,sizeof(TYPE),OBJTYPE(TYPE)), \ ifdef(debug, (obj_printf)(objtmp, va("%s", callstack(+16))), 0), \ obj_setname(objtmp, NAME)) -#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, sizeof(array(obj*)), __VA_ARGS__) -#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, sizeof(array(obj*)), __VA_ARGS__) -#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, sizeof(array(obj*)), __VA_ARGS__) +#define obj(TYPE, ...) *OBJ_CTOR(TYPE, #TYPE, 0, 0, __VA_ARGS__) +#define obj_new(TYPE, ...) OBJ_CTOR(TYPE, #TYPE, 1, 0, __VA_ARGS__) +#define obj_new_ext(TYPE, NAME, ...) OBJ_CTOR(TYPE, NAME, 1, 0, __VA_ARGS__) void* obj_malloc(unsigned sz); void* obj_free(void *o); @@ -3001,12 +3012,12 @@ API int obj_pop(void *o); // ---------------------------------------------------------------------------- // components -API bool obj_addcomponent(void *object, unsigned c, void *ptr); -API bool obj_hascomponent(void *object, unsigned c); -API void* obj_getcomponent(void *object, unsigned c); -API bool obj_delcomponent(void *object, unsigned c); -API bool obj_usecomponent(void *object, unsigned c); -API bool obj_offcomponent(void *object, unsigned c); +API bool obj_addcomponent(entity *e, unsigned c, void *ptr); +API bool obj_hascomponent(entity *e, unsigned c); +API void* obj_getcomponent(entity *e, unsigned c); +API bool obj_delcomponent(entity *e, unsigned c); +API bool obj_usecomponent(entity *e, unsigned c); +API bool obj_offcomponent(entity *e, unsigned c); API char* entity_save(entity *self); @@ -3022,7 +3033,7 @@ API char* entity_save(entity *self); API void* obj_clone(const void *src); API void* obj_merge(void *dst, const void *src); // @testme -API void* obj_mutate(void **dst, const void *src); +API void* obj_mutate(void *dst, const void *src); API void* obj_make(const char *str); // built-ins @@ -4380,6 +4391,7 @@ API int ui_hover(); // ui_is_hover()? API int ui_active(); // ui_is_active()? API int ui_demo(int do_windows); +API void *ui_handle(); #line 0 #line 1 "engine/split/v4k_video.h"