gs_ddt.h (5914B)
1 #ifndef GS_DDT_H_ 2 #define GS_DDT_H_ 3 4 typedef void(*gs_ddt_func)(int argc, char** argv); 5 6 typedef struct gs_ddt_command_s { 7 gs_ddt_func func; 8 const char* name; 9 const char* desc; 10 } gs_ddt_command_t; 11 12 typedef struct gs_ddt_s { 13 char tb[2048]; // text buffer 14 char cb[524]; // "command" buffer 15 16 float y; 17 float size; 18 float open_speed; 19 float close_speed; 20 21 int open; 22 int last_open_state; 23 int close_complete; 24 int autoscroll; 25 26 gs_ddt_command_t* commands; 27 int commands_len; 28 } gs_ddt_t; 29 30 extern void gs_ddt_printf(gs_ddt_t* ddt, const char* fmt, ...); 31 extern void gs_ddt(gs_ddt_t* ddt, gs_gui_context_t* ctx, gs_gui_rect_t screen, const gs_gui_selector_desc_t* desc); 32 // A gui context must be begun before this is ran 33 34 #ifdef GS_DDT_IMPL 35 36 void 37 gs_ddt_printf(gs_ddt_t* ddt, const char* fmt, ...) 38 { 39 char tmp[512] = {0}; 40 va_list args; 41 42 va_start(args, fmt); 43 vsnprintf(tmp, sizeof(tmp), fmt, args); 44 va_end(args); 45 46 int n = sizeof(ddt->tb) - strlen(ddt->tb) - 1; 47 int resize = strlen(tmp) - n; 48 if (resize > 0) { 49 memmove(ddt->tb, ddt->tb + resize, sizeof(ddt->tb) - resize); 50 n = sizeof(ddt->tb) - strlen(ddt->tb) - 1; 51 } 52 strncat(ddt->tb, tmp, n); 53 } 54 55 void 56 gs_ddt(gs_ddt_t* ddt, gs_gui_context_t* ctx, gs_gui_rect_t screen, const gs_gui_selector_desc_t* desc) 57 { 58 if (ddt->open) { 59 ddt->y = gs_interp_linear(ddt->y, screen.h * ddt->size, ddt->open_speed); 60 ddt->close_complete = 0; 61 } else if (!ddt->open && ddt->y > 0 && !ddt->close_complete) { 62 ddt->y = gs_interp_linear(ddt->y, -1, ddt->close_speed); 63 } else if (!ddt->open) { 64 ddt->close_complete = 1; 65 return; 66 } 67 68 const float sz = gs_min(ddt->y, 26); 69 if (gs_gui_window_begin_ex(ctx, "gs_ddt_content", gs_gui_rect(screen.x, screen.y, screen.w, ddt->y - sz), NULL, NULL, 70 GS_GUI_OPT_FORCESETRECT | GS_GUI_OPT_NOTITLE | GS_GUI_OPT_NORESIZE | GS_GUI_OPT_NODOCK | GS_GUI_OPT_FORCEFOCUS | GS_GUI_OPT_HOLDFOCUS)) { 71 gs_gui_layout_row(ctx, 1, (int[]){-1}, 0); 72 gs_gui_text(ctx, ddt->tb); 73 if (ddt->autoscroll) gs_gui_get_current_container(ctx)->scroll.y = sizeof(ddt->tb)*7+100; 74 gs_gui_container_t* ctn = gs_gui_get_current_container(ctx); 75 gs_gui_bring_to_front(ctx, ctn); 76 gs_gui_window_end(ctx); 77 } 78 79 if (gs_gui_window_begin_ex(ctx, "gs_ddt_input", gs_gui_rect(screen.x, screen.y + ddt->y - sz, screen.w, sz), NULL, NULL, 80 GS_GUI_OPT_FORCESETRECT | GS_GUI_OPT_NOTITLE | GS_GUI_OPT_NORESIZE | GS_GUI_OPT_NODOCK | GS_GUI_OPT_NOHOVER | GS_GUI_OPT_NOINTERACT)) { 81 int len = strlen(ddt->cb); 82 gs_gui_layout_row(ctx, 3, (int[]){14, len * 7+2, 10}, 0); 83 gs_gui_text(ctx, "$>"); 84 gs_gui_text(ctx, ddt->cb); 85 86 // handle text input 87 int32_t n = gs_min(sizeof(ddt->cb) - len - 1, (int32_t) strlen(ctx->input_text)); 88 if (!ddt->open || !ddt->last_open_state) { 89 90 } else if (ctx->key_pressed & GS_GUI_KEY_RETURN) { 91 gs_ddt_printf(ddt, "$ %s\n", ddt->cb); 92 93 if (*ddt->cb && ddt->commands) { 94 char* tmp = ddt->cb; 95 int argc = 1; 96 while((tmp = strchr(tmp, ' '))) { 97 argc++; 98 tmp++; 99 } 100 101 tmp = ddt->cb; 102 char* last_pos = ddt->cb; 103 char* argv[argc]; 104 int i = 0; 105 while((tmp = strchr(tmp, ' '))) { 106 *tmp = 0; 107 argv[i++] = last_pos; 108 last_pos = ++tmp; 109 } 110 argv[argc-1] = last_pos; 111 112 for (int i = 0; i < ddt->commands_len; i++) { 113 if (ddt->commands[i].name && ddt->commands[i].func && strcmp(argv[0], ddt->commands[i].name) == 0) { 114 ddt->commands[i].func(argc, argv); 115 goto ddt_command_found; 116 } 117 } 118 gs_ddt_printf(ddt, "[gs_ddt]: unrecognized command '%s'\n", argv[0]); 119 ddt_command_found: 120 ddt->cb[0] = '\0'; 121 } 122 } else if (ctx->key_pressed & GS_GUI_KEY_BACKSPACE && len > 0) { 123 // skip utf-8 continuation bytes 124 while ((ddt->cb[--len] & 0xc0) == 0x80 && len > 0); 125 ddt->cb[len] = '\0'; 126 } else if (n > 0) { 127 memcpy(ddt->cb + len, ctx->input_text, n); 128 len += n; 129 ddt->cb[len] = '\0'; 130 } 131 132 // blinking cursor 133 gs_gui_get_layout(ctx)->body.x -= 5; 134 if ((int)(gs_platform_elapsed_time() / 666.0f) & 1) 135 gs_gui_text(ctx, "|"); 136 137 gs_gui_container_t* ctn = gs_gui_get_current_container(ctx); 138 gs_gui_bring_to_front(ctx, ctn); 139 140 gs_gui_window_end(ctx); 141 } 142 143 ddt->last_open_state = ddt->open; 144 } 145 #endif // GS_DDT_IMPL 146 147 #endif // GS_DDT_H_