From b09849f41ad1dfc78a527a859d8781ef53532a3b Mon Sep 17 00:00:00 2001 From: vurtun Date: Mon, 7 Mar 2016 18:17:15 +0100 Subject: [PATCH] Added script to UI bytecode compile + file browser This is quite a big commit which adds an experimental text script to UI bytecode compiler. The compiler is still under heavy development and can and will be under heavy changes, so use with caution. In addition I added the old file browser for unix like platforms back into the demo. At the moment it only supports windows but the only part of the file browser that is platform dependend is the directory content loader which should be easy to implement in other platforms as well. --- demo/demo.c | 585 +++++++++++++++++++++++++++-- demo/glfw/glfw.c | 28 +- demo/icon/computer.png | Bin 0 -> 620 bytes demo/icon/default.png | Bin 0 -> 460 bytes demo/icon/desktop.png | Bin 0 -> 583 bytes demo/icon/directory.png | Bin 2927 -> 533 bytes demo/icon/font.png | Bin 0 -> 561 bytes demo/icon/home.png | Bin 10649 -> 819 bytes demo/icon/img.png | Bin 0 -> 648 bytes demo/icon/movie.png | Bin 0 -> 626 bytes demo/icon/music.png | Bin 0 -> 610 bytes demo/icon/text.png | Bin 0 -> 601 bytes demo/linuxgl/linuxgl.c | 28 +- demo/sdl/sdl.c | 28 +- zahnrad.c | 789 +++++++++++++++++++++++++++++++++++++++- zahnrad.h | 43 ++- 16 files changed, 1450 insertions(+), 51 deletions(-) create mode 100644 demo/icon/computer.png create mode 100644 demo/icon/default.png create mode 100644 demo/icon/desktop.png create mode 100644 demo/icon/font.png create mode 100644 demo/icon/img.png create mode 100644 demo/icon/movie.png create mode 100644 demo/icon/music.png create mode 100644 demo/icon/text.png diff --git a/demo/demo.c b/demo/demo.c index 6b728c1..f4247e2 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -1,6 +1,9 @@ #include #include +#include #include +#include +#include #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) @@ -32,13 +35,26 @@ struct icons { struct zr_image prev; struct zr_image next; struct zr_image tools; - struct zr_image directory; + struct zr_image dir; struct zr_image copy; struct zr_image convert; struct zr_image del; struct zr_image edit; struct zr_image images[9]; struct zr_image menu[6]; + + struct zr_image desktop; + struct zr_image home; + struct zr_image computer; + struct zr_image directory; + + struct zr_image default_file; + struct zr_image text_file; + struct zr_image music_file; + struct zr_image font_file; + struct zr_image img_file; + struct zr_image movie_file; + }; enum theme {THEME_BLACK, THEME_WHITE, THEME_RED, THEME_BLUE, THEME_DARK}; @@ -49,6 +65,7 @@ struct demo { enum theme theme; struct zr_memory_status status; + int show_filex; int show_simple; int show_replay; int show_demo; @@ -186,8 +203,8 @@ set_style(struct zr_context *ctx, enum theme theme) ctx->style.colors[ZR_COLOR_BUTTON_HOVER] = zr_rgba(142, 187, 229, 255); ctx->style.colors[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(147, 192, 234, 255); ctx->style.colors[ZR_COLOR_TOGGLE] = zr_rgba(177, 210, 210, 255); - ctx->style.colors[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(245, 245, 245, 255); - ctx->style.colors[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(142, 187, 229, 255); + ctx->style.colors[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(182, 215, 215, 255); + ctx->style.colors[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(137, 182, 224, 255); ctx->style.colors[ZR_COLOR_SELECTABLE] = zr_rgba(147, 192, 234, 255); ctx->style.colors[ZR_COLOR_SELECTABLE_HOVER] = zr_rgba(150, 150, 150, 255); ctx->style.colors[ZR_COLOR_SELECTABLE_TEXT] = zr_rgba(70, 70, 70, 255); @@ -229,8 +246,8 @@ set_style(struct zr_context *ctx, enum theme theme) ctx->style.colors[ZR_COLOR_HEADER] = zr_rgba(51, 51, 56, 220); ctx->style.colors[ZR_COLOR_BORDER] = zr_rgba(46, 46, 46, 255); ctx->style.colors[ZR_COLOR_BUTTON] = zr_rgba(48, 83, 111, 255); - ctx->style.colors[ZR_COLOR_BUTTON_HOVER] = zr_rgba(53, 88, 116, 255); - ctx->style.colors[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(58, 93, 121, 255); + ctx->style.colors[ZR_COLOR_BUTTON_HOVER] = zr_rgba(58, 93, 121, 255); + ctx->style.colors[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(63, 98, 126, 255); ctx->style.colors[ZR_COLOR_TOGGLE] = zr_rgba(50, 58, 61, 255); ctx->style.colors[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(55, 63, 66, 255); ctx->style.colors[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(48, 83, 111, 255); @@ -286,6 +303,7 @@ control_window(struct zr_context *ctx, struct demo *gui) gui->show_node = !zr_window_is_closed(ctx, "Node Editor"); gui->show_demo = !zr_window_is_closed(ctx, "Demo"); #ifndef DEMO_DO_NOT_DRAW_IMAGES + gui->show_filex = !zr_window_is_closed(ctx, "File Browser"); gui->show_grid = !zr_window_is_closed(ctx, "Grid Demo"); gui->show_basic = !zr_window_is_closed(ctx, "Basic Demo"); gui->show_button = !zr_window_is_closed(ctx, "Button Demo"); @@ -306,6 +324,8 @@ control_window(struct zr_context *ctx, struct demo *gui) zr_window_close(ctx, "Basic Demo"); if (zr_checkbox(ctx, "Button", &gui->show_button) && !gui->show_button) zr_window_close(ctx, "Button Demo"); + if (zr_checkbox(ctx, "Filex", &gui->show_filex) && !gui->show_filex) + zr_window_close(ctx, "File Browser"); #endif zr_layout_pop(ctx); } @@ -704,7 +724,7 @@ demo_window(struct demo *gui, struct zr_context *ctx) { /* Combobox Widgets * In this library comboboxes are not limited to being a popup - * list of selected text. Instead it is a abstract concept of + * list of selectable text. Instead it is a abstract concept of * having something that is *selected* or displayed, a popup window * which opens if something needs to be modified and the content * of the popup which causes the *selected* or displayed value to @@ -729,16 +749,14 @@ demo_window(struct demo *gui, struct zr_context *ctx) * which only show the currently activated time/data and hide the * selection logic inside the combobox popup. */ - enum color_mode {COL_RGB, COL_HSV}; static float chart_selection = 8.0f; - static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"}; - static size_t current_weapon = 0; + static int current_weapon = 0; static int check_values[5]; static float position[3]; - static int col_mode = COL_RGB; static struct zr_color combo_color = {130, 50, 50, 255}; static struct zr_color combo_color2 = {130, 180, 50, 255}; static size_t prog_a = 20, prog_b = 40, prog_c = 10, prog_d = 90; + static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"}; char buffer[64]; size_t sum = 0; @@ -746,15 +764,7 @@ demo_window(struct demo *gui, struct zr_context *ctx) /* default combobox */ zr_layout_row_static(ctx, 25, 200, 1); - if (zr_combo_begin_text(ctx, &combo, weapons[current_weapon], 200)) { - size_t i = 0; - zr_layout_row_dynamic(ctx, 25, 1); - for (i = 0; i < LEN(weapons); ++i) { - if (zr_combo_item(ctx, weapons[i], ZR_TEXT_LEFT)) - current_weapon = i; - } - zr_combo_end(ctx); - } + current_weapon = zr_combo(ctx, weapons, LEN(weapons), current_weapon, 25); /* slider color combobox */ if (zr_combo_begin_color(ctx, &combo, combo_color, 200)) { @@ -773,6 +783,8 @@ demo_window(struct demo *gui, struct zr_context *ctx) /* complex color combobox */ if (zr_combo_begin_color(ctx, &combo, combo_color2, 400)) { + enum color_mode {COL_RGB, COL_HSV}; + static int col_mode = COL_RGB; #ifndef DEMO_DO_NOT_USE_COLOR_PICKER zr_layout_row_dynamic(ctx, 120, 1); combo_color2 = zr_color_picker(ctx, combo_color2, ZR_RGBA); @@ -838,7 +850,7 @@ demo_window(struct demo *gui, struct zr_context *ctx) sprintf(buffer, "%.1f", chart_selection); if (zr_combo_begin_text(ctx, &combo, buffer, 250)) { size_t i = 0; - static const float values[]={30.0f,15.0f,25.0f,10.0f,20.0f,40.0f}; + static const float values[]={26.0f,13.0f,30.0f,15.0f,25.0f,10.0f,20.0f,40.0f, 12.0f, 8.0f, 22.0f, 28.0f, 5.0f}; zr_layout_row_dynamic(ctx, 150, 1); zr_chart_begin(ctx, ZR_CHART_COLUMN, LEN(values), 0, 50); for (i = 0; i < LEN(values); ++i) { @@ -1406,7 +1418,6 @@ demo_window(struct demo *gui, struct zr_context *ctx) /* tiles */ zr_layout_row(ctx, ZR_STATIC, 200, 5, row_layout); - zr_push_property(ctx, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); /* left space */ if (zr_group_begin(ctx, &sub, "left", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR)) { @@ -1466,7 +1477,6 @@ demo_window(struct demo *gui, struct zr_context *ctx) zr_group_end(ctx); } - zr_pop_property(ctx); zr_layout_pop(ctx); } @@ -1882,7 +1892,7 @@ basic_demo(struct zr_context *ctx, struct icons *img) *------------------------------------------------*/ ui_header(ctx, "Popup & Scrollbar & Images"); ui_widget(ctx, 35, 22); - if (zr_button_text_image(ctx, img->directory, + if (zr_button_text_image(ctx, img->dir, "Images", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) image_active = !image_active; @@ -1972,6 +1982,435 @@ basic_demo(struct zr_context *ctx, struct icons *img) ctx->style.font.height = 14; zr_end(ctx); } +/* =============================================================== + * + * FILE BROWSER + * + * ===============================================================*/ +/* sorry only works for posix systems right now because of the directory function */ +enum file_groups { + FILE_GROUP_DEFAULT, + FILE_GROUP_TEXT, + FILE_GROUP_MUSIC, + FILE_GROUP_FONT, + FILE_GROUP_IMAGE, + FILE_GROUP_MOVIE, + FILE_GROUP_MAX +}; + +enum file_types { + FILE_DEFAULT, + FILE_TEXT, + FILE_C_SOURCE, + FILE_CPP_SOURCE, + FILE_HEADER, + FILE_CPP_HEADER, + FILE_MP3, + FILE_WAV, + FILE_OGG, + FILE_TTF, + FILE_BMP, + FILE_PNG, + FILE_JPEG, + FILE_PCX, + FILE_TGA, + FILE_GIF, + FILE_MAX +}; + +struct file_group { + enum file_groups group; + const char *name; + struct zr_image *icon; +}; + +struct file { + enum file_types type; + const char *suffix; + enum file_groups group; +}; + +struct media { + int font; + int icon_sheet; + struct icons *icons; + struct file_group group[FILE_GROUP_MAX]; + struct file files[FILE_MAX]; +}; + +#define MAX_PATH_LEN 512 +struct file_browser { + /* path */ + char file[MAX_PATH_LEN]; + char home[MAX_PATH_LEN]; + char desktop[MAX_PATH_LEN]; + char directory[MAX_PATH_LEN]; + + /* directory content */ + char **files; + char **directories; + size_t file_count; + size_t dir_count; + struct media media; +}; + +#ifndef DEMO_DO_NOT_DRAW_IMAGES +#ifdef __unix__ + +#include +#include + +#ifndef _WIN32 +# include +#endif + +static char* +str_duplicate(const char *src) +{ + char *ret; + size_t len = strlen(src); + if (!len) return 0; + ret = malloc(len+1); + if (!ret) return 0; + memcpy(ret, src, len); + ret[len] = '\0'; + return ret; +} + +static void +dir_free_list(char **list, size_t size) +{ + size_t i; + for (i = 0; i < size; ++i) + free(list[i]); + free(list); +} + +static char** +dir_list(const char *dir, int return_subdirs, size_t *count) +{ + size_t n = 0; + char buffer[MAX_PATH_LEN]; + char **results = NULL; + const DIR *none = NULL; + size_t capacity = 32; + size_t size; + DIR *z; + + assert(dir); + assert(count); + strncpy(buffer, dir, MAX_PATH_LEN); + n = strlen(buffer); + + if (n > 0 && (buffer[n-1] != '/')) + buffer[n++] = '/'; + + size = 0; + + z = opendir(dir); + if (z != none) { + int nonempty = 1; + struct dirent *data = readdir(z); + nonempty = (data != NULL); + if (!nonempty) return NULL; + + do { + DIR *y; + char *p; + int is_subdir; + if (data->d_name[0] == '.') + continue; + + strncpy(buffer + n, data->d_name, MAX_PATH_LEN-n); + y = opendir(buffer); + is_subdir = (y != NULL); + if (y != NULL) closedir(y); + + if ((return_subdirs && is_subdir) || (!is_subdir && !return_subdirs)){ + if (!size) { + results = calloc(sizeof(char*), capacity); + } else if (size >= capacity) { + capacity = capacity * 2; + results = realloc(results, capacity * sizeof(char*)); + } + p = str_duplicate(data->d_name); + results[size++] = p; + } + } while ((data = readdir(z)) != NULL); + } + + if (z) closedir(z); + *count = size; + return results; +} + +static struct file_group +FILE_GROUP(enum file_groups group, const char *name, struct zr_image *icon) +{ + struct file_group fg; + fg.group = group; + fg.name = name; + fg.icon = icon; + return fg; +} + +static struct file +FILE_DEF(enum file_types type, const char *suffix, enum file_groups group) +{ + struct file fd; + fd.type = type; + fd.suffix = suffix; + fd.group = group; + return fd; +} + +static struct zr_image* +media_icon_for_file(struct media *media, const char *file) +{ + int i = 0; + const char *s = file; + char suffix[4]; + int found = 0; + memset(suffix, 0, sizeof(suffix)); + + /* extract suffix .xxx from file */ + while (*s++ != '\0') { + if (found && i < 3) + suffix[i++] = *s; + + if (*s == '.') { + if (found){ + found = 0; + break; + } + found = 1; + } + } + + /* check for all file definition of all groups for fitting suffix*/ + for (i = 0; i < FILE_MAX && found; ++i) { + struct file *d = &media->files[i]; + { + const char *f = d->suffix; + s = suffix; + while (f && *f && *s && *s == *f) { + s++; f++; + } + + /* found correct file definition so */ + if (f && *s == '\0' && *f == '\0') + return media->group[d->group].icon; + } + } + return &media->icons->default_file; +} + +static void +media_init(struct media *media, struct icons *icons) +{ + /* file groups */ + media->icons = icons; + media->group[FILE_GROUP_DEFAULT] = FILE_GROUP(FILE_GROUP_DEFAULT,"default",&icons->default_file); + media->group[FILE_GROUP_TEXT] = FILE_GROUP(FILE_GROUP_TEXT, "textual", &icons->text_file); + media->group[FILE_GROUP_MUSIC] = FILE_GROUP(FILE_GROUP_MUSIC, "music", &icons->music_file); + media->group[FILE_GROUP_FONT] = FILE_GROUP(FILE_GROUP_FONT, "font", &icons->font_file); + media->group[FILE_GROUP_IMAGE] = FILE_GROUP(FILE_GROUP_IMAGE, "image", &icons->img_file); + media->group[FILE_GROUP_MOVIE] = FILE_GROUP(FILE_GROUP_MOVIE, "movie", &icons->movie_file); + + /* files */ + media->files[FILE_DEFAULT] = FILE_DEF(FILE_DEFAULT, NULL, FILE_GROUP_DEFAULT); + media->files[FILE_TEXT] = FILE_DEF(FILE_TEXT, "txt", FILE_GROUP_TEXT); + media->files[FILE_C_SOURCE] = FILE_DEF(FILE_C_SOURCE, "c", FILE_GROUP_TEXT); + media->files[FILE_CPP_SOURCE] = FILE_DEF(FILE_CPP_SOURCE, "cpp", FILE_GROUP_TEXT); + media->files[FILE_HEADER] = FILE_DEF(FILE_HEADER, "h", FILE_GROUP_TEXT); + media->files[FILE_CPP_HEADER] = FILE_DEF(FILE_HEADER, "hpp", FILE_GROUP_TEXT); + media->files[FILE_MP3] = FILE_DEF(FILE_MP3, "mp3", FILE_GROUP_MUSIC); + media->files[FILE_WAV] = FILE_DEF(FILE_WAV, "wav", FILE_GROUP_MUSIC); + media->files[FILE_OGG] = FILE_DEF(FILE_OGG, "ogg", FILE_GROUP_MUSIC); + media->files[FILE_TTF] = FILE_DEF(FILE_TTF, "ttf", FILE_GROUP_FONT); + media->files[FILE_BMP] = FILE_DEF(FILE_BMP, "bmp", FILE_GROUP_IMAGE); + media->files[FILE_PNG] = FILE_DEF(FILE_PNG, "png", FILE_GROUP_IMAGE); + media->files[FILE_JPEG] = FILE_DEF(FILE_JPEG, "jpg", FILE_GROUP_IMAGE); + media->files[FILE_PCX] = FILE_DEF(FILE_PCX, "pcx", FILE_GROUP_IMAGE); + media->files[FILE_TGA] = FILE_DEF(FILE_TGA, "tga", FILE_GROUP_IMAGE); + media->files[FILE_GIF] = FILE_DEF(FILE_GIF, "gif", FILE_GROUP_IMAGE); +} + +static void +file_browser_reload_directory_content(struct file_browser *browser, const char *path) +{ + strncpy(browser->directory, path, MAX_PATH_LEN); + dir_free_list(browser->files, browser->file_count); + dir_free_list(browser->directories, browser->dir_count); + browser->files = dir_list(path, 0, &browser->file_count); + browser->directories = dir_list(path, 1, &browser->dir_count); +} + +static void +file_browser_init(struct file_browser *browser, struct icons *icons) +{ + memset(browser, 0, sizeof(*browser)); + media_init(&browser->media, icons); + { + /* load files and sub-directory list */ + const char *home = getenv("HOME"); +#ifdef _WIN32 + if (!home) home = getenv("USERPROFILE"); +#else + if (!home) home = getpwuid(getuid())->pw_dir; + { + size_t l; + strncpy(browser->home, home, MAX_PATH_LEN); + l = strlen(browser->home); + strcpy(browser->home + l, "/"); + strcpy(browser->directory, browser->home); + } +#endif + { + size_t l; + strcpy(browser->desktop, browser->home); + l = strlen(browser->desktop); + strcpy(browser->desktop + l, "desktop/"); + } + browser->files = dir_list(browser->directory, 0, &browser->file_count); + browser->directories = dir_list(browser->directory, 1, &browser->dir_count); + } +} + +static void +file_browser_free(struct file_browser *browser) +{ + if (browser->files) + dir_free_list(browser->files, browser->file_count); + if (browser->directories) + dir_free_list(browser->directories, browser->dir_count); + browser->files = NULL; + browser->directories = NULL; + memset(browser, 0, sizeof(*browser)); +} + +static int +file_browser_run(struct file_browser *browser, struct zr_context *ctx) +{ + int ret = 0; + struct zr_panel layout; + struct media *media = &browser->media; + struct icons *icons = media->icons; + struct zr_rect total_space; + + if (zr_begin(ctx, &layout, "File Browser", zr_rect(50, 50, 800, 600), + ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSABLE|ZR_WINDOW_MOVABLE)) + { + struct zr_panel sub; + static float ratio[] = {0.25f, ZR_UNDEFINED}; + + /* output path directory selector in the menubar */ + zr_menubar_begin(ctx); + { + char *d = browser->directory; + char *begin = d + 1; + zr_layout_row_dynamic(ctx, 25, 6); + zr_push_property(ctx, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 0)); + while (*d++) { + if (*d == '/') { + *d = '\0'; + if (zr_button_text(ctx, begin, ZR_BUTTON_DEFAULT)) { + *d++ = '/'; *d = '\0'; + file_browser_reload_directory_content(browser, browser->directory); + break; + } + *d = '/'; + begin = d + 1; + } + } + zr_pop_property(ctx); + } + zr_menubar_end(ctx); + + /* window layout */ + total_space = zr_window_get_content_region(ctx); + zr_layout_row(ctx, ZR_DYNAMIC, total_space.h, 2, ratio); + zr_group_begin(ctx, &sub, "Special", ZR_WINDOW_NO_SCROLLBAR); + { + struct zr_image home = icons->home; + struct zr_image desktop = icons->desktop; + struct zr_image computer = icons->computer; + + zr_layout_row_dynamic(ctx, 40, 1); + zr_push_property(ctx, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 0)); + if (zr_button_text_image(ctx, home, "home", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) + file_browser_reload_directory_content(browser, browser->home); + if (zr_button_text_image(ctx,desktop,"desktop",ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) + file_browser_reload_directory_content(browser, browser->desktop); + if (zr_button_text_image(ctx,computer,"computer",ZR_TEXT_CENTERED,ZR_BUTTON_DEFAULT)) + file_browser_reload_directory_content(browser, "/"); + zr_pop_property(ctx); + zr_group_end(ctx); + } + + /* output directory content window */ + zr_group_begin(ctx, &sub, "Content", 0); + { + int index = -1; + size_t i = 0, j = 0, k = 0; + size_t rows = 0, cols = 0; + size_t count = browser->dir_count + browser->file_count; + + cols = 4; + rows = count / cols; + for (i = 0; i <= rows; i += 1) { + {size_t n = j + cols; + zr_layout_row_dynamic(ctx, 135, (int)cols); + for (; j < count && j < n; ++j) { + /* draw one row of icons */ + if (j < browser->dir_count) { + /* draw and execute directory buttons */ + if (zr_button_image(ctx,icons->directory,ZR_BUTTON_DEFAULT)) + index = (int)j; + } else { + /* draw and execute files buttons */ + struct zr_image *icon; + size_t fileIndex = ((size_t)j - browser->dir_count); + icon = media_icon_for_file(media,browser->files[fileIndex]); + if (zr_button_image(ctx, *icon, ZR_BUTTON_DEFAULT)) { + strncpy(browser->file, browser->directory, MAX_PATH_LEN); + n = strlen(browser->file); + strncpy(browser->file + n, browser->files[fileIndex], MAX_PATH_LEN - n); + ret = 1; + } + } + }} + {size_t n = k + cols; + zr_layout_row_dynamic(ctx, 20, (int)cols); + for (; k < count && k < n; k++) { + /* draw one row of labels */ + if (k < browser->dir_count) { + zr_label(ctx, browser->directories[k], ZR_TEXT_CENTERED); + } else { + size_t t = k-browser->dir_count; + zr_label(ctx,browser->files[t],ZR_TEXT_CENTERED); + } + }} + } + + if (index != -1) { + size_t n = strlen(browser->directory); + strncpy(browser->directory + n, browser->directories[index], MAX_PATH_LEN - n); + n = strlen(browser->directory); + if (n < MAX_PATH_LEN - 1) { + browser->directory[n] = '/'; + browser->directory[n+1] = '\0'; + } + file_browser_reload_directory_content(browser, browser->directory); + } + zr_group_end(ctx); + } + } + zr_end(ctx); + return ret; +} +#endif +#endif /* =============================================================== * @@ -2078,8 +2517,8 @@ node_editor_add(struct node_editor *editor, const char *name, struct zr_rect bou node->input_count = in_count; node->output_count = out_count; node->color = col; - strcpy(node->name, name); node->bounds = bounds; + strcpy(node->name, name); node_editor_push(editor, node); } @@ -2106,6 +2545,18 @@ node_editor_demo(struct zr_context *ctx, struct node_editor *nodedit) struct node *updated = 0; struct zr_panel layout; + /* This is a simple node editor just to show a simple implementation and that + * it is possible to achieve with this library. While all nodes inside this + * example use a simple color modifier as content you could change them + * to have your custom content depending on the node time. + * Biggest difference to most usual implementation is that this example does + * not has connectors on the right position of the proprety that it links. + * This is mainly done out of lazyness and could be implemented as well but + * requires calculating the position of all rows and add connectors. + * In addition adding and removing nodes is quite limited at the + * moment since it is based on a simple array. If this is to be converted + * into something more serious it is probably best to extend it.*/ + if (zr_begin(ctx, &layout, "Node Editor", zr_rect(50, 50, 650, 650), ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSABLE|ZR_WINDOW_MOVABLE)) { @@ -2307,6 +2758,7 @@ node_editor_init(struct node_editor *editor) static void record_window(struct zr_context *ctx, struct zr_buffer *buffer) { + /* **EXPERIMENTAL** */ /* Recording a UI begins by calling `zr_recording_begin` and ends with * `zr_recording_end`. All supported API call between these two calls * are saved inside the buffer and can later be replayed with `zr_exec`. @@ -2341,6 +2793,73 @@ record_window(struct zr_context *ctx, struct zr_buffer *buffer) zr_recording_end(ctx); } +/* =============================================================== + * + * COMPILED WINDOW + * + * ===============================================================*/ +static void +compile_log(void *userdata, zr_size line, const char *fmt, ...) +{ + int l = (int)line; + char buffer[1024]; + va_list args; + + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + buffer[1023] = 0; + fprintf(stderr, "[COMPILER] error (%d): %s\n", l, buffer); + va_end(args); +} + +static void +compile_window(struct zr_context *ctx, struct zr_buffer *buffer) +{ + /* **EXPERIMENTAL** */ + const char script[] = + "begin('Recorded', 420, 350, 200, 350, 317)" + "layout_row_static(30, 150, 1)" + "button_text(0, 'Test', 0)" + "slider(1, 0, 5, 10, 1)" + "progress(2, 20, 100, 1)" + "property(3, 'Compression:', 0, 20, 100, 10, 1, 0);" + "select(4, 'select me', 18, 0)" + "check(5, 'check me', 1)" + "layout_row_static(30, 50, 3)" + "option(6, 'RGB', 1)" + "option(8, 'HSV', 0)" + "option(9, 'HEX', 0)" + "layout_push(10, 1, 'Tab', 0)" + "layout_row_static(30, 150, 1)" + "button_text(11, 'Test', 0)" + "layout_pop()" + "end()"; + + enum zr_compiler_status ret; + UNUSED(ctx); + ret = zr_compile(buffer, script, sizeof(script), compile_log, 0); + if (ret == ZR_COMPILER_OK) return; + else if (ret == ZR_COMPILER_INVALID_VALUE) + fprintf(stdout, "[Zahnrad]: compiling error: invalid valid\n"); + else if (ret == ZR_COMPILER_INVALID_ARG) + fprintf(stdout, "[Zahnrad]: compiling error: invalid operation argument\n"); + else if (ret == ZR_COMPILER_OP_NOT_FOUND) + fprintf(stdout, "[Zahnrad]: compiling error: invalid operation\n"); + else if (ret == ZR_COMPILER_MISSING_COMMA) + fprintf(stdout, "[Zahnrad]: compiling error: missing comma between arguments\n"); + else if (ret == ZR_COMPILER_WRONG_ARG_TYPE) + fprintf(stdout, "[Zahnrad]: compiling error: argument has wrong type\n"); + else if (ret == ZR_COMPILER_NO_MEMORY) + fprintf(stdout, "[Zahnrad]: out of memory\n"); + else if (ret == ZR_COMPILER_INVALID_SCRIPT) + fprintf(stdout, "[Zahnrad]: script is not correct\n"); +} + +/* =============================================================== + * + * REPLAY WINDOW + * + * ===============================================================*/ static void replay_window(struct zr_context *ctx, struct zr_buffer *record) { @@ -2385,8 +2904,8 @@ replay_window(struct zr_context *ctx, struct zr_buffer *record) ctx->next_id = 0; {const union zr_event *evt; - /* To execute a previously recorded UI you need to provide two buffer. The - * first one is to store events into and the other is for runtime memory. + /* To execute a previously recorded or compile UI you need to provide two buffer. + * The first one is to store events into and the other is for runtime memory. * For event memory I would recommend using a fixed size `zr_event` array * since the number of events generated is small most of the time. Runtime * memory is only used for `zr_panel`s so only the max number of panels @@ -2399,7 +2918,7 @@ replay_window(struct zr_context *ctx, struct zr_buffer *record) * bring a huge performance boost. (NOTICE: some functions like zr_begin generate * heartbeat events which do not have any impact and are only used while using * the API in immediate mode and can easily be ignored). You can also use - * an event mask to only specify which events should be generated and ignore + * an event mask to specify which events should be generated and ignore * all other. This example here uses a default event mask by passing `0` to * zr_exec which allows all events, but you could also create your own: * @@ -2527,6 +3046,7 @@ run_demo(struct demo *gui) static char record_memory[4*1024]; static struct zr_buffer record; static struct node_editor nodedit; + static struct file_browser filex; struct zr_context *ctx = &gui->ctx; if (!init) { @@ -2535,16 +3055,18 @@ run_demo(struct demo *gui) gui->show_replay = 0; gui->show_simple = 0; - #ifndef DEMO_DO_NOT_DRAW_IMAGES gui->show_grid = 0; gui->show_basic = 0; gui->show_button = 0; - #endif memset(&nodedit, 0, sizeof(nodedit)); zr_buffer_init_fixed(&record, record_memory, sizeof(record_memory)); - record_window(ctx, &record); + compile_window(ctx, &record); + /*record_window(ctx, &record);*/ node_editor_init(&nodedit); +#ifndef DEMO_DO_NOT_DRAW_IMAGES + file_browser_init(&filex, &gui->icons); +#endif init = 1; } @@ -2559,12 +3081,15 @@ run_demo(struct demo *gui) node_editor_demo(ctx, &nodedit); #ifndef DEMO_DO_NOT_DRAW_IMAGES + if (gui->show_filex) + file_browser_run(&filex, ctx); if (gui->show_grid) grid_demo(ctx); if (gui->show_button) button_demo(ctx, &gui->icons); if (gui->show_basic) basic_demo(ctx, &gui->icons); + if (!ret) file_browser_free(&filex); #endif zr_buffer_info(&gui->status, &gui->ctx.memory); return ret; diff --git a/demo/glfw/glfw.c b/demo/glfw/glfw.c index 90cbb2a..7bf0a73 100644 --- a/demo/glfw/glfw.c +++ b/demo/glfw/glfw.c @@ -580,7 +580,7 @@ main(int argc, char *argv[]) gui.icons.next = icon_load("../../icon/next.png"); gui.icons.prev = icon_load("../../icon/prev.png"); gui.icons.tools = icon_load("../../icon/tools.png"); - gui.icons.directory = icon_load("../../icon/directory.png"); + gui.icons.dir = icon_load("../../icon/directory.png"); gui.icons.copy = icon_load("../../icon/copy.png"); gui.icons.convert = icon_load("../../icon/export.png"); gui.icons.del = icon_load("../../icon/delete.png"); @@ -591,6 +591,18 @@ main(int argc, char *argv[]) gui.icons.menu[3] = icon_load("../../icon/wifi.png"); gui.icons.menu[4] = icon_load("../../icon/settings.png"); gui.icons.menu[5] = icon_load("../../icon/volume.png"); + + gui.icons.home = icon_load("../../icon/home.png"); + gui.icons.directory = icon_load("../../icon/directory.png"); + gui.icons.computer = icon_load("../../icon/computer.png"); + gui.icons.desktop = icon_load("../../icon/desktop.png"); + gui.icons.default_file = icon_load("../../icon/default.png"); + gui.icons.text_file = icon_load("../../icon/text.png"); + gui.icons.music_file = icon_load("../../icon/music.png"); + gui.icons.font_file = icon_load("../../icon/font.png"); + gui.icons.img_file = icon_load("../../icon/img.png"); + gui.icons.movie_file = icon_load("../../icon/movie.png"); + for (i = 0; i < 9; ++i) { char buffer[256]; sprintf(buffer, "../../images/image%d.png", (i+1)); @@ -627,8 +639,20 @@ main(int argc, char *argv[]) glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id); - glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id); + + glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id); + for (i = 0; i < 9; ++i) glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id); for (i = 0; i < 6; ++i) diff --git a/demo/icon/computer.png b/demo/icon/computer.png new file mode 100644 index 0000000000000000000000000000000000000000..29db8fc867c57f556e011f6a830324310c1a1fad GIT binary patch literal 620 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 diff --git a/demo/icon/font.png b/demo/icon/font.png new file mode 100644 index 0000000000000000000000000000000000000000..918e9bfe1ea44c569be31bf73f6af53b301c3edf GIT binary patch literal 561 zcmV-10?z%3P)FwDX-&%Eb7XN0nx!k!fNT3xAtIlwhQ0}6Yl6y9k2d>T0z@MA8M6_9RJIE|*dT*MP5-ipS%zF~*oM49#Y!P(Txl$RR?)7?& z`Fx)KY`5DvfQ8s^*LBm2!+k`*gcq8jVKDSr+^^U;_LS5&Hc;gTVl; zHE%zEsrd1bqp&92H>vCCu~W}8q1zCQbM_|vmDXG^oX zeex85TQ{$B|K6R0-*O7HnOS{3dj`P#^t{%gDmoOAN{3c;?kY1>O659wS(P$WN}-g( zbzL0Cxim1>|4yf4tgE`w$ZEISu~;mG|3<$7k0ygyH7*Qe00000NkvXXu0mjfN^t?l literal 0 HcmV?d00001 diff --git a/demo/icon/home.png b/demo/icon/home.png index fc7ab168e75898e7065313ac1a2db6b4104e6a2c..85606267225863537d186d63ebb2ed7014c9e4ae 100644 GIT binary patch literal 819 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 diff --git a/demo/icon/img.png b/demo/icon/img.png new file mode 100644 index 0000000000000000000000000000000000000000..198595728da27a9b294fb9a83fd5234e0f8f488a GIT binary patch literal 648 zcmV;30(bq1P)Ui5sZRGrF2`gX~#oqZIdO5p8Ue_nBnoA@63DeE9i&piJhJ} z5YlHafn$IL=)e}RIV!2}AvWT-PNUjbfT+pQ2*1=&Miy5#UoMlac9UlBX*x0Gyec;(9)h9S#u= zS^KKM(haWNxl5^3qTOx_zXDj3lan%+%TcLR4sJXPuy0T@zZ2Lgo6U{@KSb~RAL6(WSdwr%WCi1_$8N-3nSV;GXX z9T2->{|{krceuiXrhTxy%p>_9|hmOcMGwxu{|2$Z&!Kv=r;d~!}f*aILgma i2BFjG9I>zeAHM*|L6h|(d1^HP0000mI)V literal 0 HcmV?d00001 diff --git a/demo/icon/movie.png b/demo/icon/movie.png new file mode 100644 index 0000000000000000000000000000000000000000..5227883e6c4d28773043acce6ededc1fe34ded22 GIT binary patch literal 626 zcmV-&0*(ENP)T{#D-;S&%1S2+M3;h&CNB|?Xn2J@MjBouU8Fn!Jt9)lf)J5N z?utl}k|tUMo6Xu+Tv+j+hrS}K(a z#u$plBA(}=l%m`1(r7feyu9S}^mGGIe)<@gODU<wdVf*o?frV$;k=h@i^_p z^*%gwQ&PauXoT-rtCIF5HdU;n550eUjt_y-pF9RL6T M07*qoM6N<$f_*?A&j0`b literal 0 HcmV?d00001 diff --git a/demo/icon/music.png b/demo/icon/music.png new file mode 100644 index 0000000000000000000000000000000000000000..0f1415c8756311c4852151f1a0f4055e08b26b97 GIT binary patch literal 610 zcmV-o0-gPdP)I`orN2EPQ-(&Md=rc&3|7-y16j#sR2} zVjD0z1Y|idTPZd6Jg*!C0T^RR0odwM6q(6nV&%aL04{URr@dZ}h=_dOr^RAHT5DRZ zR;0D2<#L%S&+{k?iR~nSlWw=`4u?YkK)>Hdr_+J!x+s-OP)b2c2`MFn5Rg*lTE)OZ zqtUoJ8jX^V<#IU%5JF)1=4pCnjO79W0Q31AzVBl&7{GO1)a!NFww*G2^!Q;4aEVoO zfd)Xx7(=VoLc86DloG{a5su@)w(SH60B0Y9#JX0i?KJ!y>&I7BN~H{i5CD*zv)9cU z{yi82$8nOOXBPorCoF4d7-Jx!1dv@w4BQ3VT1srFlu8UgoqWXc``0-AJjT~=X9s`1 zLf#XIZC<>6h99#jlvJ4h{EpKvV|Z7tT^txEwtIQ}9KV8daK|W zK~y-))s(%;;y@IJ-x-}5R{Vij7(}d0Bgk4g^9{M~N1e=Zga0synw49#W}hG8I|&qD|S&N(>eV2put{~5KOeT|;&qjq`D;A4z z90x)OWHK2DA>N`(5&{5%AV4mc!(cGLdcD3Q3(u8G1>^DfC7~vSKx+-oIr{zn-9*Fu zi0s*>AP52oA>cR;R;yKv?CS%6hcLR#7{hQlyrZL({_`$JhP_@7p6A8Lo>4tjsZ>(? z{a$Z28+|w&w3JdSrSvP6%Vm|^-}pjP8kP90Oxw0$+xGW_rfI71XW;w3en&~dSPy;Q nm$h2$$JYUUr`zo&@n7i!nhp9}Dig&U00000NkvXXu0mjfhOhtA literal 0 HcmV?d00001 diff --git a/demo/linuxgl/linuxgl.c b/demo/linuxgl/linuxgl.c index 69f1f42..3ab7bf1 100644 --- a/demo/linuxgl/linuxgl.c +++ b/demo/linuxgl/linuxgl.c @@ -943,7 +943,7 @@ int main(int argc, char **argv) gui.icons.next = icon_load("../../icon/next.png"); gui.icons.prev = icon_load("../../icon/prev.png"); gui.icons.tools = icon_load("../../icon/tools.png"); - gui.icons.directory = icon_load("../../icon/directory.png"); + gui.icons.dir = icon_load("../../icon/directory.png"); gui.icons.copy = icon_load("../../icon/copy.png"); gui.icons.convert = icon_load("../../icon/export.png"); gui.icons.del = icon_load("../../icon/delete.png"); @@ -954,6 +954,18 @@ int main(int argc, char **argv) gui.icons.menu[3] = icon_load("../../icon/wifi.png"); gui.icons.menu[4] = icon_load("../../icon/settings.png"); gui.icons.menu[5] = icon_load("../../icon/volume.png"); + + gui.icons.home = icon_load("../../icon/home.png"); + gui.icons.directory = icon_load("../../icon/directory.png"); + gui.icons.computer = icon_load("../../icon/computer.png"); + gui.icons.desktop = icon_load("../../icon/desktop.png"); + gui.icons.default_file = icon_load("../../icon/default.png"); + gui.icons.text_file = icon_load("../../icon/text.png"); + gui.icons.music_file = icon_load("../../icon/music.png"); + gui.icons.font_file = icon_load("../../icon/font.png"); + gui.icons.img_file = icon_load("../../icon/img.png"); + gui.icons.movie_file = icon_load("../../icon/movie.png"); + for (i = 0; i < 9; ++i) { char buffer[256]; sprintf(buffer, "../../images/image%d.png", (i+1)); @@ -1012,8 +1024,20 @@ cleanup: glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id); - glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id); + + glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id); + for (i = 0; i < 9; ++i) glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id); for (i = 0; i < 6; ++i) diff --git a/demo/sdl/sdl.c b/demo/sdl/sdl.c index fa88027..8db7664 100644 --- a/demo/sdl/sdl.c +++ b/demo/sdl/sdl.c @@ -555,7 +555,7 @@ main(int argc, char *argv[]) gui.icons.next = icon_load("../../icon/next.png"); gui.icons.prev = icon_load("../../icon/prev.png"); gui.icons.tools = icon_load("../../icon/tools.png"); - gui.icons.directory = icon_load("../../icon/directory.png"); + gui.icons.dir = icon_load("../../icon/directory.png"); gui.icons.copy = icon_load("../../icon/copy.png"); gui.icons.convert = icon_load("../../icon/export.png"); gui.icons.del = icon_load("../../icon/delete.png"); @@ -566,6 +566,18 @@ main(int argc, char *argv[]) gui.icons.menu[3] = icon_load("../../icon/wifi.png"); gui.icons.menu[4] = icon_load("../../icon/settings.png"); gui.icons.menu[5] = icon_load("../../icon/volume.png"); + + gui.icons.home = icon_load("../../icon/home.png"); + gui.icons.directory = icon_load("../../icon/directory.png"); + gui.icons.computer = icon_load("../../icon/computer.png"); + gui.icons.desktop = icon_load("../../icon/desktop.png"); + gui.icons.default_file = icon_load("../../icon/default.png"); + gui.icons.text_file = icon_load("../../icon/text.png"); + gui.icons.music_file = icon_load("../../icon/music.png"); + gui.icons.font_file = icon_load("../../icon/font.png"); + gui.icons.img_file = icon_load("../../icon/img.png"); + gui.icons.movie_file = icon_load("../../icon/movie.png"); + for (i = 0; i < 9; ++i) { char buffer[256]; sprintf(buffer, "../../images/image%d.png", (i+1)); @@ -620,8 +632,20 @@ cleanup: glDeleteTextures(1,(const GLuint*)&gui.icons.next.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.prev.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.tools.handle.id); - glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.dir.handle.id); glDeleteTextures(1,(const GLuint*)&gui.icons.del.handle.id); + + glDeleteTextures(1,(const GLuint*)&gui.icons.home.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.directory.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.computer.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.desktop.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.default_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.text_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.music_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.font_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.img_file.handle.id); + glDeleteTextures(1,(const GLuint*)&gui.icons.movie_file.handle.id); + for (i = 0; i < 9; ++i) glDeleteTextures(1, (const GLuint*)&gui.icons.images[i].handle.id); for (i = 0; i < 6; ++i) diff --git a/zahnrad.c b/zahnrad.c index a8c65d4..394cc1b 100644 --- a/zahnrad.c +++ b/zahnrad.c @@ -223,10 +223,9 @@ enum zr_param_types { ZR_TYPE_UINT = 'u', ZR_TYPE_FLOAT = 'f', ZR_TYPE_HASH = 'h', - ZR_TYPE_OFFSET = 's', ZR_TYPE_FLAGS = 'g', - ZR_TYPE_IMAGE = 'm', ZR_TYPE_CHEAT = 'c', + ZR_TYPE_IMAGE = 'm', ZR_TYPE_COLOR = 'l', ZR_TYPE_PTR = 'p' }; @@ -254,7 +253,7 @@ enum zr_param_types { ZR_OP(layout_space_begin, ZR_STACK_NOP, ZR_FMT("oifi"))\ ZR_OP(layout_space_push, ZR_STACK_NOP, ZR_FMT("of"))\ ZR_OP(layout_space_end, ZR_STACK_NOP, ZR_FMT("o"))\ - ZR_OP(layout_push, ZR_STACK_INC|ZR_STACK_GEN, ZR_FMT("ohici"))\ + ZR_OP(layout_push, ZR_STACK_INC|ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohici"))\ ZR_OP(layout_pop, ZR_STACK_DEC|ZR_STACK_TXT, ZR_FMT("o"))\ ZR_OP(text, ZR_STACK_NOP|ZR_STACK_TXT, ZR_FMT("ocugl"))\ ZR_OP(text_wrap, ZR_STACK_NOP|ZR_STACK_TXT, ZR_FMT("ocul"))\ @@ -265,9 +264,9 @@ enum zr_param_types { ZR_OP(button_image, ZR_STACK_GEN, ZR_FMT("ohmffffffi"))\ ZR_OP(button_text_symbol, ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohici"))\ ZR_OP(button_text_image, ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohmffffffcgi"))\ - ZR_OP(check, ZR_STACK_GEN, ZR_FMT("ohci"))\ - ZR_OP(option, ZR_STACK_GEN, ZR_FMT("ohci"))\ - ZR_OP(select, ZR_STACK_GEN, ZR_FMT("ohcfi"))\ + ZR_OP(check, ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohci"))\ + ZR_OP(option, ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohci"))\ + ZR_OP(select, ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohcgi"))\ ZR_OP(slider, ZR_STACK_GEN, ZR_FMT("ohffff"))\ ZR_OP(progress, ZR_STACK_GEN, ZR_FMT("ohiii"))\ ZR_OP(property, ZR_STACK_GEN|ZR_STACK_TXT, ZR_FMT("ohcfffffi"))\ @@ -323,6 +322,7 @@ struct zr_event_queue { #define zr_ptr_add(t, p, i) ((t*)((void*)((zr_byte*)(p) + (i)))) #define zr_ptr_add_const(t, p, i) ((const t*)((const void*)((const zr_byte*)(p) + (i)))) +#define zr_zero_struct(s) zr_zero(&s, sizeof(s)) /* ============================================================== * ALIGNMENT @@ -673,8 +673,6 @@ zr_memset(void *ptr, int c0, zr_size size) #undef wmask } -#define zr_zero_struct(s) zr_zero(&s, sizeof(s)) - static void zr_zero(void *ptr, zr_size size) { @@ -691,6 +689,16 @@ zr_strsiz(const char *str) return siz; } +static int +zr_stricmpn(const char *a, const char *b, int len) +{ + int i = 0; + for (i = 0; i < len && a[i] && b[i]; ++i) + if (a[i] != b[i]) return 1; + if (i != len) return 1; + return 0; +} + static int zr_strtof(float *number, const char *buffer) { @@ -12426,6 +12434,148 @@ void zr_combo_end(struct zr_context *ctx) void zr_combo_close(struct zr_context *ctx) {zr_contextual_close(ctx);} + +int +zr_combo(struct zr_context *ctx, const char **items, int count, + int selected, int item_height) +{ + int i = 0; + int max_height; + struct zr_panel combo; + struct zr_vec2 item_padding; + struct zr_vec2 window_padding; + + ZR_ASSERT(ctx); + ZR_ASSERT(items); + if (!ctx || !items ||!count) + return selected; + + item_padding = zr_get_property(ctx, ZR_PROPERTY_ITEM_PADDING); + window_padding = zr_get_property(ctx, ZR_PROPERTY_PADDING); + max_height = (count+1) * item_height + (int)item_padding.y * 3 + (int)window_padding.y * 2; + if (zr_combo_begin_text(ctx, &combo, items[selected], max_height)) { + zr_layout_row_dynamic(ctx, (float)item_height, 1); + for (i = 0; i < count; ++i) { + if (zr_combo_item(ctx, items[i], ZR_TEXT_LEFT)) + selected = i; + } + zr_combo_end(ctx); + } + return selected; +} + +int +zr_combo_string(struct zr_context *ctx, const char *items_seperated_by_zeros, + int selected, int count, int item_height) +{ + int i; + int max_height; + struct zr_panel combo; + struct zr_vec2 item_padding; + struct zr_vec2 window_padding; + const char *current_item; + zr_size length; + + ZR_ASSERT(ctx); + ZR_ASSERT(items_seperated_by_zeros); + if (!ctx || !items_seperated_by_zeros) + return selected; + + /* calculate popup window */ + item_padding = zr_get_property(ctx, ZR_PROPERTY_ITEM_PADDING); + window_padding = zr_get_property(ctx, ZR_PROPERTY_PADDING); + max_height = (count+1) * item_height + (int)item_padding.y * 3 + (int)window_padding.y * 2; + + /* find selected item */ + current_item = items_seperated_by_zeros; + length = zr_strsiz(current_item); + for (i = 0; i < selected; ++i) { + current_item = current_item + length + 1; + length = zr_strsiz(current_item); + } + + current_item = items_seperated_by_zeros; + if (zr_combo_begin_text(ctx, &combo, current_item, max_height)) { + zr_layout_row_dynamic(ctx, (float)item_height, 1); + for (i = 0; i < count; ++i) { + if (zr_combo_item(ctx, current_item, ZR_TEXT_LEFT)) + selected = i; + + length = zr_strsiz(current_item); + current_item = current_item + length + 1; + } + zr_combo_end(ctx); + } + return selected; +} + +int +zr_combo_callback(struct zr_context *ctx, void(item_getter)(void*, int, const char**), + void *userdata, int selected, int count, int item_height) +{ + int i; + int max_height; + struct zr_panel combo; + struct zr_vec2 item_padding; + struct zr_vec2 window_padding; + const char *item; + + ZR_ASSERT(ctx); + ZR_ASSERT(item_getter); + if (!ctx || !item_getter) + return selected; + + item_padding = zr_get_property(ctx, ZR_PROPERTY_ITEM_PADDING); + window_padding = zr_get_property(ctx, ZR_PROPERTY_PADDING); + max_height = (count+1) * item_height + (int)item_padding.y * 3 + (int)window_padding.y * 2; + + item_getter(userdata, selected, &item); + if (zr_combo_begin_text(ctx, &combo, item, max_height)) { + zr_layout_row_dynamic(ctx, (float)item_height, 1); + for (i = 0; i < count; ++i) { + item_getter(userdata, i, &item); + if (zr_combo_item(ctx, item, ZR_TEXT_LEFT)) + selected = i; + } + zr_combo_end(ctx); + } + return selected; +} + +void +zr_combobox(struct zr_context *ctx, const char **items, int count, int *selected, + int item_height) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(items); + ZR_ASSERT(selected); + if (!ctx || !items || !selected) return; + *selected = zr_combo(ctx, items, count, *selected, item_height); +} + +void +zr_combobox_string(struct zr_context *ctx, const char *items_seperated_by_zeros, + int *selected, int count, int item_height) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(items_seperated_by_zeros); + ZR_ASSERT(selected); + if (!ctx || !items_seperated_by_zeros || !selected) return; + *selected = zr_combo_string(ctx, items_seperated_by_zeros, *selected, count, item_height); +} + +void +zr_combobox_callback(struct zr_context *ctx, + void(item_getter)(void* data, int id, const char **out_text), + void *userdata, int *selected, int count, int item_height) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(item_getter); + ZR_ASSERT(selected); + if (!ctx || !item_getter || !selected) return; + *selected = zr_combo_callback(ctx, item_getter, userdata, *selected, count, item_height); +} + /* * ------------------------------------------------------------- * @@ -12604,16 +12754,17 @@ zr_menu_end(struct zr_context *ctx) * =============================================================== */ static int zr_op_handle(struct zr_context*, union zr_param*, struct zr_event_queue*); static const struct zr_instruction { + const char *keyword; const char *name; zr_flags flags; int(*func)(struct zr_context*, union zr_param *in, struct zr_event_queue*); const char *fmt; unsigned short argc; } zr_op_table[ZR_OP_MAX] = { -#define ZR_OPCODE(a, b, c) {"zr_op_"#a, b, zr_op_##a, c}, +#define ZR_OPCODE(a, b, c) {#a, "zr_op_"#a, b, zr_op_##a, c}, ZR_OPCODES(ZR_OPCODE) #undef ZR_OPCODE - {0,0,0,"o",1} + {0,0,0,0,"o",1} }; void @@ -13833,7 +13984,7 @@ zr_color_pick(struct zr_context *ctx, struct zr_color *color, /* ============================================================== * - * RETAIN + * RECORDING * * =============================================================== */ void @@ -13912,6 +14063,622 @@ zr_store_op(struct zr_buffer *buffer, union zr_param *p, int count) } } +/* ============================================================== + * + * COMPILER + * + * =============================================================== */ +#define ZR_LEXER_DEFAULT_PUNCTION_MAP(PUNCTUATION)\ + PUNCTUATION(">>=", ZR_PUNCT_RSHIFT_ASSIGN)\ + PUNCTUATION("<<=", ZR_PUNCT_LSHIFT_ASSIGN)\ + PUNCTUATION("...", ZR_PUNCT_PARAMS)\ + PUNCTUATION("&&", ZR_PUNCT_LOGIC_AND)\ + PUNCTUATION("||", ZR_PUNCT_LOGIC_OR)\ + PUNCTUATION(">=", ZR_PUNCT_LOGIC_GEQ)\ + PUNCTUATION("<=", ZR_PUNCT_LOGIC_LEQ)\ + PUNCTUATION("==", ZR_PUNCT_LOGIC_EQ)\ + PUNCTUATION("!=", ZR_PUNCT_LOGIC_UNEQ)\ + PUNCTUATION("*=", ZR_PUNCT_MUL_ASSIGN)\ + PUNCTUATION("/=", ZR_PUNCT_DIV_ASSIGN)\ + PUNCTUATION("%=", ZR_PUNCT_MOD_ASSIGN)\ + PUNCTUATION("+=", ZR_PUNCT_ADD_ASSIGN)\ + PUNCTUATION("-=", ZR_PUNCT_SUB_ASSIGN)\ + PUNCTUATION("++", ZR_PUNCT_INC)\ + PUNCTUATION("--", ZR_PUNCT_DEC)\ + PUNCTUATION("&=", ZR_PUNCT_BIN_AND_ASSIGN)\ + PUNCTUATION("|=", ZR_PUNCT_BIN_OR_ASSIGN)\ + PUNCTUATION("^=", ZR_PUNCT_BIN_XOR_ASSIGN)\ + PUNCTUATION(">>", ZR_PUNCT_RSHIFT)\ + PUNCTUATION("<<", ZR_PUNCT_LSHIFT)\ + PUNCTUATION("->", ZR_PUNCT_POINTER)\ + PUNCTUATION("::", ZR_PUNCT_CPP1)\ + PUNCTUATION(".*", ZR_PUNCT_CPP2)\ + PUNCTUATION("*", ZR_PUNCT_MUL)\ + PUNCTUATION("/", ZR_PUNCT_DIV)\ + PUNCTUATION("%", ZR_PUNCT_MOD)\ + PUNCTUATION("+", ZR_PUNCT_ADD)\ + PUNCTUATION("-", ZR_PUNCT_SUB)\ + PUNCTUATION("=", ZR_PUNCT_ASSIGN)\ + PUNCTUATION("&", ZR_PUNCT_BIN_AND)\ + PUNCTUATION("|", ZR_PUNCT_BIN_OR)\ + PUNCTUATION("^", ZR_PUNCT_BIN_XOR)\ + PUNCTUATION("~", ZR_PUNCT_BIN_NOT)\ + PUNCTUATION("!", ZR_PUNCT_LOGIC_NOT)\ + PUNCTUATION(">", ZR_PUNCT_LOGIC_GREATER)\ + PUNCTUATION("<", ZR_PUNCT_LOGIC_LESS)\ + PUNCTUATION(".", ZR_PUNCT_REF)\ + PUNCTUATION(",", ZR_PUNCT_COMMA)\ + PUNCTUATION(";", ZR_PUNCT_SEMICOLON)\ + PUNCTUATION(":", ZR_PUNCT_COLON)\ + PUNCTUATION("?", ZR_PUNCT_QUESTIONMARK)\ + PUNCTUATION("(", ZR_PUNCT_PARENTHESE_OPEN)\ + PUNCTUATION(")", ZR_PUNCT_PARENTHESE_CLOSE)\ + PUNCTUATION("{", ZR_PUNCT_BRACE_OPEN)\ + PUNCTUATION("}", ZR_PUNCT_BRACE_CLOSE)\ + PUNCTUATION("[", ZR_PUNCT_BRACKET_OPEN)\ + PUNCTUATION("]", ZR_PUNCT_BRACKET_CLOSE)\ + PUNCTUATION("\\", ZR_PUNCT_BACKSLASH)\ + PUNCTUATION("#", ZR_PUNCT_PRECOMPILER)\ + PUNCTUATION("$", ZR_PUNCT_DOLLAR) + +enum zr_lexer_default_punctuation_ids { +#define PUNCTUATION(chars, id) id, + ZR_LEXER_DEFAULT_PUNCTION_MAP(PUNCTUATION) +#undef PUNCTUATION + ZR_PUNCT_MAX +}; + +static const struct zr_punctuation { + const char *string; int id; +} zr_lexer_default_punctuations[] = { +#define PUNCTUATION(chars, id) {chars, id}, + ZR_LEXER_DEFAULT_PUNCTION_MAP(PUNCTUATION) +#undef PUNCTUATION + {0, 0} +}; + +enum zr_token_type { + ZR_TOKEN_STRING, + ZR_TOKEN_LITERAL, + ZR_TOKEN_NUMBER, + ZR_TOKEN_NAME, + ZR_TOKEN_PUNCT +}; + +struct zr_token { + enum zr_token_type type; + zr_size line; + int line_crossed; + struct {unsigned long i; double f;} value; + const char *str; + zr_size len; + int punct; +}; + +struct zr_lexer { + const char *last; + const char *current; + const char *end; + zr_size length; + zr_size line; + zr_size last_line; + zr_compile_log_f log; + void *userdata; + int error; +}; + +static int +zr_skip_white_space(struct zr_lexer *lexer, int current_line) +{ + while (1) { + /* skip white spaces */ + while (*lexer->current <= ' ' && lexer->current < lexer->end) { + if (!*lexer->current || lexer->current == lexer->end) + return 0; + if (*lexer->current == '\n') { + lexer->line++; + if (current_line) { + lexer->current++; + return 1; + } + } + lexer->current++; + } + + /* skip comments */ + if (*lexer->current == '/' && lexer->current < lexer->end) { + if (lexer->current+1 >= lexer->end) + return 0; + + if (*(lexer->current + 1) == '/') { + /* C++ style comments */ + lexer->current++; + do { + lexer->current++; + if ((lexer->current >= lexer->end) || !*lexer->current) + return 0; + } while (*lexer->current != '\n'); + lexer->line++; + lexer->current++; + if (current_line) + return 1; + if (lexer->current >= lexer->end || !*lexer->current) + return 0; + continue; + } else if ((*lexer->current + 1) == '*') { + /* C style comments */ + lexer->current++; + while (1) { + lexer->current++; + if (lexer->current >= lexer->end || !*lexer->current) + return 0; + if (*lexer->current == '\n') { + lexer->line++; + } else if (*lexer->current == '/' && lexer->current+1 < lexer->end) { + if (*(lexer->current-1) == '*') break; + if (*(lexer->current+1) == '*' && lexer->log) { + lexer->log(lexer->userdata, lexer->line, "nested comment"); + } + } + } + lexer->current++; + if (lexer->current >= lexer->end || !*lexer->current) + return 0; + lexer->current++; + if (lexer->current >= lexer->end || !*lexer->current) + return 0; + continue; + } + } + break; + } + return 1; +} + +static int +zr_read_string(struct zr_lexer *lexer, struct zr_token *token, int quote) +{ + zr_size tmpline; + const char *tmp; + + if (quote == '\"') + token->type = ZR_TOKEN_STRING; + else token->type = ZR_TOKEN_LITERAL; + lexer->current++; + if (lexer->current >= lexer->end) + return 0; + + token->len = 0; + token->str = lexer->current; + while (lexer->current < lexer->end) { + if (*lexer->current == quote) { + lexer->current++; + if (lexer->current >= lexer->end) + return 0; + + tmp = lexer->current; + tmpline = lexer->line; + if (!zr_skip_white_space(lexer, 0)) { + lexer->current = tmp; + lexer->line = tmpline; + break; + } + if (*lexer->current == '\0') { + if (lexer->log) + lexer->log(lexer->userdata, lexer->line, + "expecting string after '\' terminated line"); + lexer->error = 1; + return 0; + } + break; + } else { + if (*lexer->current == '\0') { + if (lexer->log) + lexer->log(lexer->userdata, lexer->line, "missing trailing quote"); + lexer->error = 1; + return 0; + } + if (*lexer->current == '\n') { + if (lexer->log) + lexer->log(lexer->userdata, lexer->line, "newline inside string"); + lexer->error = 1; + return 0; + } + lexer->current++; + } + } + if (token->str) + token->len = (zr_size)(lexer->current - token->str) - 1; + return 1; +} + +static int +zr_read_name(struct zr_lexer *lexer, struct zr_token *token) +{ + char c; + token->type = ZR_TOKEN_NAME; + token->str = lexer->current; + token->len = 0; + do { + token->len++; + lexer->current++; + if (lexer->current >= lexer->end) + break; + c = *lexer->current; + } while ((c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_'); + return 1; +} + +static int +zr_read_number(struct zr_lexer *lexer, struct zr_token *token) +{ + int dot; + char c, c2; + + token->type = ZR_TOKEN_NUMBER; + token->value.f = 0; + token->value.i = 0; + token->str = 0; + token->len = 0; + + c = *lexer->current; + if ((lexer->current + 1) < lexer->end) + c2 = *(lexer->current + 1); + else c2 = 0; + + /* decimal or floating point number */ + dot = 0; + token->str = lexer->current; + while (1) { + if (c >= '0' && c <= '9') { + } else if (c == '.') dot++; + else break; + token->len++; + if (lexer->current+1 >= lexer->end) break; + c = *(++lexer->current); + } + if (c == 'e' && dot == 0) + dot++; /* scientific notation */ + if (dot) { + if (c == 'e') { + if (lexer->current+1 >= lexer->end) + return 0; + + token->len++; + c = *(++lexer->current); + if (c == '-' || c == '+') { + token->len++; + if (lexer->current+1 >= lexer->end) + return 0; + c = *(++lexer->current); + } + while (c >= '0' && c <= '9') { + if (lexer->current+1 >= lexer->end) break; + c = *(++lexer->current); + token->len++; + } + } + } + return 1; +} + +static int +zr_read_punctuation(struct zr_lexer *lexer, struct zr_token *token) +{ + int l, i; + const char *p; + const struct zr_punctuation *punc; + + token->len = 0; + token->str = lexer->current; + for (i = 0; zr_lexer_default_punctuations[i].string; ++i) { + punc = &zr_lexer_default_punctuations[i]; + p = punc->string; + for (l = 0; p[l] && lexer->current < lexer->end && lexer->current[l]; ++l) { + if (lexer->current[l] != p[l]) + break; + } + if (!p[l]) { + token->len += (zr_size)l; + lexer->current += l; + token->type = ZR_TOKEN_PUNCT; + token->punct = punc->id; + return 1; + } + } + return 0; +} + +static int +zr_parse(struct zr_lexer *lexer, struct zr_token *token) +{ + int c; + if (!lexer->current) return 0; + if (lexer->current >= lexer->end) return 0; + if (lexer->error == 1) return 0; + + zr_zero_struct(*token); + lexer->last = lexer->current; + lexer->last_line = lexer->line; + lexer->error = 0; + if (!zr_skip_white_space(lexer, 0)) + return 0; + + token->line = lexer->line; + token->line_crossed = (lexer->line - lexer->last_line) ? 1 : 0; + + c = *lexer->current; + if ((c >= '0' && c <= '9') || + (c == '.' && (*(lexer->current + 1)) >= '0' && + (c == '.' && (*(lexer->current + 1)) <= '9'))) { + if (!zr_read_number(lexer, token)) return 0; + } else if (c == '\"' || c == '\'') { + if (!zr_read_string(lexer, token, c)) return 0; + } else if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_') { + if (!zr_read_name(lexer, token)) return 0; + } else if (!zr_read_punctuation(lexer, token)) { + if (lexer->log) + lexer->log(lexer->userdata, lexer->line, "unkown punctuation"); + lexer->error = 1; + return 0; + } + return 1; +} + +static int +zr_check_type(struct zr_lexer *lexer, enum zr_token_type type, + int subtype, struct zr_token *token) +{ + struct zr_token tok; + if (!zr_parse(lexer, &tok)) + return 0; + if (tok.type == type && (tok.punct == subtype)) { + *token = tok; + return 1; + } + /* unread token */ + lexer->current = lexer->last; + lexer->line = lexer->last_line; + return 0; +} + +static double +zr_token_parse_number(const char *p, zr_size length) +{ + int i, div, pow; + double m; + zr_size len = 0; + double f = 0; + while (len < length && p[len] != '.' && p[len] != 'e') { + f = f * 10.0 + (double)(p[len] - '0'); + len++; + } + + if (len < length && p[len] == '.') { + len++; + for (m = 0.1; len < length; len++) { + f = f + (double)(p[len] - '0') * m; + m *= 0.1; + } + } + if (len < length && p[len] == 'e' ) { + len++; + if (p[len] == '-') { + div = 1; + len++; + } else if (p[len] == '+') { + div = 0; + len++; + } else div = 0; + pow = 0; + for (pow = 0; len < length; len++) + pow = pow * 10 + (int)(p[len] - '0'); + for (m = 1.0, i = 0; i < pow; ++i) + m *= 100.0; + if (div) f /= m; + else f *= m; + } + return f; +} + +enum zr_compiler_status +zr_compile(struct zr_buffer *program, const char *script, + zr_size len, zr_compile_log_f log, void *userdata) +{ + unsigned short opcode; + zr_size i = 0; + struct zr_lexer lexer; + + ZR_ASSERT(program); + ZR_ASSERT(script); + if (!program || !script) + return ZR_COMPILER_INVALID_VALUE; + + /* setup lexer */ + zr_zero_struct(lexer); + lexer.error = 0; + lexer.current = script; + lexer.end = script + len; + lexer.length = len; + lexer.line = 0; + lexer.log = log; + lexer.userdata = userdata; + + while (!lexer.error && *lexer.current && lexer.current < lexer.end) { + struct zr_token tok; + struct zr_token name; + char buffer[1024]; + + /* parse function name */ + if (!zr_parse(&lexer, &name) || name.type != ZR_TOKEN_NAME) { + if (!lexer.current || !(lexer.current < lexer.end)) + break; + ZR_ASSERT(!ZR_COMPILER_INVALID_SCRIPT); + return ZR_COMPILER_INVALID_SCRIPT; + } + if (!zr_check_type(&lexer, ZR_TOKEN_PUNCT, ZR_PUNCT_PARENTHESE_OPEN, &tok)) { + ZR_ASSERT(!ZR_COMPILER_INVALID_SCRIPT); + return ZR_COMPILER_INVALID_SCRIPT; + } + + /* try to find instruction */ + for (opcode = 0; opcode < ZR_OP_MAX; ++opcode) { + if (!zr_stricmpn(zr_op_table[opcode].keyword, name.str, (int)name.len)) + break; + } + if (opcode == ZR_OP_MAX) { + ZR_ASSERT(!ZR_COMPILER_OP_NOT_FOUND); + return ZR_COMPILER_OP_NOT_FOUND; + } + + /* parse widget arguments */ + {union zr_param p[32]; + const struct zr_instruction *op = &zr_op_table[opcode]; + ZR_ASSERT(op->argc < ZR_LEN(p)); + if (op->argc >= ZR_LEN(p)) { + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_COUNT); + return ZR_COMPILER_WRONG_ARG_COUNT; + } + + for (i = 0; i < op->argc; ++i) + { + double value; + int has_comma = 1; + if (op->fmt[i] != ZR_TYPE_PTR && op->fmt[i] != ZR_TYPE_IMAGE && op->fmt[i] != ZR_TYPE_OP) { + if (!zr_parse(&lexer, &tok)) { + if (log) log(userdata, lexer.line, "missing argument in %.*s at index %d", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_INVALID_SCRIPT); + return ZR_COMPILER_INVALID_SCRIPT; + } + } + + switch (op->fmt[i]) { + case ZR_TYPE_OP: { + p[i].h.op = opcode; + p[i].h.next = zr_op_table[opcode].argc; + has_comma = 0; + } break; + + case ZR_TYPE_INT: { + if (tok.type != ZR_TOKEN_NUMBER) { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a number", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + value = zr_token_parse_number(tok.str, tok.len); + p[i].i = (int)value; + } break; + + case ZR_TYPE_UINT: { + if (tok.type != ZR_TOKEN_NUMBER) { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a number", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + value = zr_token_parse_number(tok.str, tok.len); + if (value < 0) value = 0; + p[i].ui = (unsigned int)value; + } break; + + case ZR_TYPE_FLOAT: { + if (tok.type != ZR_TOKEN_NUMBER) { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a number", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + value = zr_token_parse_number(tok.str, tok.len); + p[i].f = (float)value; + } break; + + case ZR_TYPE_HASH: { + if (tok.type == ZR_TOKEN_NUMBER) { + value = zr_token_parse_number(tok.str, tok.len); + if (value < 0) value = 0; + p[i].hash = (zr_hash)value; + } else if (tok.type == ZR_TOKEN_STRING || tok.type == ZR_TOKEN_LITERAL) { + p[i].hash = zr_murmur_hash(tok.str, (int)tok.len, 0); + } else { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a number or string", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + } break; + + case ZR_TYPE_FLAGS: { + if (tok.type != ZR_TOKEN_NUMBER) { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a number", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + value = zr_token_parse_number(tok.str, tok.len); + if (value < 0) value = 0; + p[i].flags = (zr_flags)value; + } break; + + case ZR_TYPE_CHEAT: { + zr_size length = ZR_MIN(tok.len, ZR_LEN(buffer)-1); + if (tok.type != ZR_TOKEN_STRING && tok.type != ZR_TOKEN_LITERAL) { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a string", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + + zr_memcopy(buffer, tok.str, length); + buffer[length] = '\0'; + p[i].cheat = buffer; + } break; + + case ZR_TYPE_COLOR: { + char hex_color[16]; + zr_size length = ZR_MIN(tok.len, ZR_LEN(hex_color)-1); + if (tok.type != ZR_TOKEN_STRING && tok.type != ZR_TOKEN_LITERAL) { + if (log) log(userdata, lexer.line, "argument in %.*s at index %d is not a hex color string", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_WRONG_ARG_TYPE); + return ZR_COMPILER_WRONG_ARG_TYPE; + } + + zr_memcopy(hex_color, tok.str, length); + hex_color[length] = '\0'; + p[i].color = zr_rgba_hex(hex_color); + } break; + case ZR_TYPE_IMAGE: p[i].img.ptr = 0; has_comma = 0; break; + case ZR_TYPE_PTR: p[i].ptr = 0; has_comma = 0; break; + default: + ZR_ASSERT(!ZR_COMPILER_INVALID_ARG); + return ZR_COMPILER_INVALID_ARG; + } + if (has_comma && (int)i < op->argc-1 && !zr_check_type(&lexer, ZR_TOKEN_PUNCT, ZR_PUNCT_COMMA, &tok)) { + if (log) log(userdata, lexer.line, "missing argument or ',' in %.*s after argument %d", name.len, name.str, i+1); + ZR_ASSERT(!ZR_COMPILER_MISSING_COMMA); + return ZR_COMPILER_MISSING_COMMA; + } + + } + /* parse ')' at end of line */ + if (!zr_check_type(&lexer, ZR_TOKEN_PUNCT, ZR_PUNCT_PARENTHESE_CLOSE, &tok)) { + if (log) log(userdata, lexer.line, "expected ')' at the end of widget: %.*s", name.len, name.str); + ZR_ASSERT(!ZR_COMPILER_INVALID_ARG); + return ZR_COMPILER_INVALID_ARG; + } + zr_check_type(&lexer, ZR_TOKEN_PUNCT, ZR_PUNCT_SEMICOLON, &tok); + zr_store_op(program, p, op->argc);} + } + + {union zr_param p; + p.h.op = ZR_OP_list_end; + p.h.next = zr_op_table[p.h.op].argc; + zr_store_op(program, &p, 1);} + return ZR_COMPILER_OK; +} + +/* ============================================================== + * + * INTERPRETER + * + * =============================================================== */ static int zr_op_handle(struct zr_context *ctx, union zr_param *p, struct zr_event_queue *queue) diff --git a/zahnrad.h b/zahnrad.h index 4c0cc5b..b032431 100644 --- a/zahnrad.h +++ b/zahnrad.h @@ -1710,11 +1710,29 @@ void zr_set_user_data(struct zr_context*, zr_handle handle); #endif /*-------------------------------------------------------------- - * RECORDING + * INTERPRETER * -------------------------------------------------------------*/ +/* generate UI bytecode from source code */ void zr_recording_begin(struct zr_context*, struct zr_buffer*); void zr_recording_end(struct zr_context*); +/* generate UI bytecode from script */ +enum zr_compiler_status { + ZR_COMPILER_OK, + ZR_COMPILER_INVALID_VALUE, + ZR_COMPILER_INVALID_ARG, + ZR_COMPILER_OP_NOT_FOUND, + ZR_COMPILER_MISSING_COMMA, + ZR_COMPILER_WRONG_ARG_TYPE, + ZR_COMPILER_NO_MEMORY, + ZR_COMPILER_WRONG_ARG_COUNT, + ZR_COMPILER_INVALID_SCRIPT +}; +typedef void(*zr_compile_log_f)(void *userdata, zr_size line, const char *error, ...); +enum zr_compiler_status zr_compile(struct zr_buffer *program, const char *script, + zr_size len, zr_compile_log_f, void *log_usr); + +/* run recorded or compiled UI bytecode */ int zr_exec(struct zr_context*, struct zr_buffer *event_buffer, int *event_count, const struct zr_event_mask*, struct zr_buffer *program, struct zr_buffer *runtime); @@ -1864,7 +1882,7 @@ void zr_layout_pop(struct zr_context*); /*-------------------------------------------------------------- * WIDGETS * -------------------------------------------------------------*/ -/* base widget calls for custom widgets (used by all widgets internally) */ +/* base widget calls for custom widgets */ enum zr_widget_state zr_widget(struct zr_rect*, const struct zr_context*); enum zr_widget_state zr_widget_fitting(struct zr_rect*, struct zr_context*); @@ -1898,7 +1916,7 @@ int zr_option(struct zr_context*, const char*, int active); int zr_selectable(struct zr_context*, const char*, zr_flags alignment, int *value); int zr_select(struct zr_context*, const char*, zr_flags alignment, int value); -/* buttons (push/repeater) */ +/* buttons */ int zr_button_text(struct zr_context *ctx, const char *title, enum zr_button_behavior); int zr_button_color(struct zr_context*, struct zr_color, enum zr_button_behavior); int zr_button_symbol(struct zr_context*, enum zr_symbol_type, enum zr_button_behavior); @@ -1922,7 +1940,7 @@ struct zr_color zr_color_picker(struct zr_context*, struct zr_color, void zr_color_pick(struct zr_context*, struct zr_color*, enum zr_color_picker_format); -/* extended value modifier by dragging, increment/decrement and text input */ +/* extended value (dragging, increment/decrement and text input) */ void zr_property_float(struct zr_context *layout, const char *name, float min, float *val, float max, float step, float inc_per_pixel); @@ -1974,6 +1992,23 @@ int zr_combo_item_symbol(struct zr_context*, enum zr_symbol_type, void zr_combo_close(struct zr_context*); void zr_combo_end(struct zr_context*); +/* combobox */ +int zr_combo(struct zr_context*, const char **items, int count, int selected, + int item_height); +int zr_combo_string(struct zr_context*, const char *items_seperated_by_zeros, + int selected, int count, int item_height); +int zr_combo_callback(struct zr_context*, + void(item_getter)(void* data, int id, const char **out_text), + void *userdata, int selected, int count, int item_height); + +void zr_combobox(struct zr_context*, const char **items, int count, int *selected, + int item_height); +void zr_combobox_string(struct zr_context*, const char *items_seperated_by_zeros, + int *selected, int count, int item_height); +void zr_combobox_callback(struct zr_context*, + void(item_getter)(void* data, int id, const char **out_text), + void *userdata, int *selected, int count, int item_height); + /* contextual menu */ int zr_contextual_begin(struct zr_context*, struct zr_panel*, zr_flags, struct zr_vec2, struct zr_rect trigger_bounds);