From 20b9d3cd458be5cf2f49a5c79078e3c27d1a27b2 Mon Sep 17 00:00:00 2001 From: vurtun Date: Wed, 30 Dec 2015 16:31:08 +0100 Subject: [PATCH] massive rewrite --- Readme.md | 64 +- demo/allegro5/Makefile | 33 + demo/allegro5/allegro.c | 406 +++ demo/demo.c | 1759 ++++++------ demo/glfw/glfw.c | 95 +- demo/linuxgl/linuxgl.c | 85 +- demo/nanovg/nanovg.c | 53 +- demo/sdl/sdl.c | 74 +- demo/x11/xlib.c | 130 +- example/demo/demo.c | 433 ++- example/filex/filex.c | 153 +- example/nodedit/nodedit.c | 217 +- zahnrad.c | 5536 +++++++++++++++++++++---------------- zahnrad.h | 3311 +++++----------------- 14 files changed, 5604 insertions(+), 6745 deletions(-) create mode 100644 demo/allegro5/Makefile create mode 100644 demo/allegro5/allegro.c diff --git a/Readme.md b/Readme.md index 0ce825f..392f936 100644 --- a/Readme.md +++ b/Readme.md @@ -1,8 +1,6 @@ # Zahnrad [![Coverity Status](https://scan.coverity.com/projects/5863/badge.svg)](https://scan.coverity.com/projects/5863) -# CURRENTLY UNDER HEAVY REFACTORING! (do not use at the moment) - This is a minimal state immediate mode graphical user interface toolkit written in ANSI C and licensed under zlib. It was designed as a simple embeddable user interface for application and does not have any direct dependencies, @@ -50,25 +48,55 @@ draw the GUI. ## Example ```c -enum {EASY, HARD}; -int option = EASY; -float value = 0.6f; +/* init gui state */ +struct zr_context ctx; +zr_init_fixed(&ctx, calloc(1, MAX_MEMORY), MAX_MEMORY, &font, sinf, cosf); -struct zr_context context; -zr_begin(&context, &window, "Show"); -{ - zr_layout_row_static(&context, 30, 80, 1); - if (zr_button_text(&context, "button", ZR_BUTTON_DEFAULT)) { - /* event handling */ +enum {EASY, HARD}; +int op = EASY; +float value = 0.6f; +int i = 20; + +while (1) { + zr_input_begin(&ctx.input); + /* generate input */ + zr_input_end(&ctx.input); + + zr_begin(&ctx, "Show", zr_rect(50, 50, 220, 220), + ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_SCALEABLE| + ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE); + { + /* fixed widget pixel width */ + zr_layout_row_static(&ctx, 30, 80, 1); + if (zr_button_text(&ctx, "button", ZR_BUTTON_DEFAULT)) { + /* event handling */ + } + + /* fixed widget window ration width */ + zr_layout_row_dynamic(&ctx, 30, 2); + if (zr_option(&ctx, "easy", op == EASY)) op = EASY; + if (zr_option(&ctx, "hard", op == HARD)) op = HARD; + + zr_layout_row_dynamic(&ctx, 30, 1); + zr_property_int(&ctx, "Compression:", 0, &i, 100, 10, 1); + + /* custom widget pixel width */ + zr_layout_row_begin(&ctx, ZR_STATIC, 30, 2); + { + zr_layout_row_push(&ctx, 50); + zr_label(&ctx, "Volume:", ZR_TEXT_LEFT); + zr_layout_row_push(&ctx, 110); + zr_slider_float(&ctx, 0, &value, 1.0f, 0.1f); + } + zr_layout_row_end(&ctx); + } + zr_end(ctx); + + struct zr_command *cmd; + zr_foreach(cmd, &ctx) { + /* execute draw command */ } - zr_layout_row_dynamic(&context, 30, 2); - if (zr_option(&context, "easy", option == EASY)) option = EASY; - if (zr_option(&context, "hard", option == HARD)) option = HARD; - zr_label(&context, "Volume:", ZR_TEXT_LEFT); - zr_slider_float(&context, 0, &value, 1.0f, 0.1f); - zr_layout_row_end(&context); } -zr_end(&context, &window); ``` ![example](https://cloud.githubusercontent.com/assets/8057201/10187981/584ecd68-675c-11e5-897c-822ef534a876.png) diff --git a/demo/allegro5/Makefile b/demo/allegro5/Makefile new file mode 100644 index 0000000..5d39fd5 --- /dev/null +++ b/demo/allegro5/Makefile @@ -0,0 +1,33 @@ +# Install +BIN = demo + +# Compiler +CC = clang +DCC = gcc + +# Flags +CFLAGS = -std=c89 -pedantic + +SRC = ../../zahnrad.c allegro.c +OBJ = $(SRC:.c=.o) + +ifeq ($(OS),Windows_NT) +BIN := $(BIN).exe +LIBS = -lmingw32 -lallegro -lallegro_primitives -lm +else +LIBS = -lallegro -lallegro_primitives -lGL -lm -lGLU -lGLEW +endif + +# Modes +.PHONY: gcc +gcc: CC = gcc +gcc: $(BIN) + +.PHONY: clang +clang: CC = clang +clang: $(BIN) + +$(BIN): + @mkdir -p bin + rm -f bin/$(BIN) $(OBJS) + $(CC) $(SRC) $(CFLAGS) -o bin/$(BIN) $(LIBS) diff --git a/demo/allegro5/allegro.c b/demo/allegro5/allegro.c new file mode 100644 index 0000000..fea7769 --- /dev/null +++ b/demo/allegro5/allegro.c @@ -0,0 +1,406 @@ +/* + Copyright (c) 2015 Micha Mettke + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* macros */ +#define DTIME 33 +#define MAX_DRAW_COMMAND_MEMORY (4 * 1024) +#define MAX_VERTEX_MEMORY 128 * 1024 +#define MAX_ELEMENT_MEMORY 64 * 1024 + +#include "../../zahnrad.h" + +#include "../demo.c" + +struct device { + ALLEGRO_DISPLAY *display; + ALLEGRO_EVENT_QUEUE *queue; + ALLEGRO_BITMAP *texture; + ALLEGRO_VERTEX_DECL *vertex_decl; + struct zr_draw_null_texture null; + struct zr_buffer cmds; + struct zr_font font; + void *vertex_buffer; + void *element_buffer; +}; + +struct allegro_vertex { + struct zr_vec2 pos; + struct zr_vec2 uv; + ALLEGRO_COLOR col; +}; + +static void +die(const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fputs("\n", stderr); + exit(EXIT_FAILURE); +} + +static char* +file_load(const char* path, size_t* siz) +{ + char *buf; + FILE *fd = fopen(path, "rb"); + if (!fd) die("Failed to open file: %s\n", path); + fseek(fd, 0, SEEK_END); + *siz = (size_t)ftell(fd); + fseek(fd, 0, SEEK_SET); + buf = (char*)calloc(*siz, 1); + fread(buf, *siz, 1, fd); + fclose(fd); + return buf; +} + +static struct zr_user_font +device_init(struct device *dev, + const char *path, unsigned int font_height, const zr_rune *range) +{ + int glyph_count; + int img_width, img_height; + struct zr_font_glyph *glyphes; + struct zr_baked_font baked_font; + struct zr_user_font user_font; + struct zr_recti custom; + + ALLEGRO_VERTEX_ELEMENT elems[] = { + {ALLEGRO_PRIM_POSITION, ALLEGRO_PRIM_FLOAT_2, offsetof(struct allegro_vertex, pos)}, + {ALLEGRO_PRIM_TEX_COORD, ALLEGRO_PRIM_FLOAT_2, offsetof(struct allegro_vertex, uv)}, + {ALLEGRO_PRIM_COLOR_ATTR, 0, offsetof(struct allegro_vertex, col)}, + {0,0,0} + }; + dev->vertex_decl = al_create_vertex_decl(elems, sizeof(struct allegro_vertex)); + + memset(&baked_font, 0, sizeof(baked_font)); + memset(&user_font, 0, sizeof(user_font)); + memset(&custom, 0, sizeof(custom)); + { + /* bake and upload font texture */ + void *img, *tmp; + size_t ttf_size; + size_t tmp_size, img_size; + const char *custom_data = "...."; + struct zr_font_config config; + char *ttf_blob = file_load(path, &ttf_size); + if (!ttf_blob) + die("[Font]: %s is not a file or cannot be found!\n", path); + + /* setup font configuration */ + memset(&config, 0, sizeof(config)); + config.ttf_blob = ttf_blob; + config.ttf_size = ttf_size; + config.font = &baked_font; + config.coord_type = ZR_COORD_UV; + config.range = range; + config.pixel_snap = zr_false; + config.size = (float)font_height; + config.spacing = zr_vec2(0,0); + config.oversample_h = 1; + config.oversample_v = 1; + + /* query needed amount of memory for the font baking process */ + zr_font_bake_memory(&tmp_size, &glyph_count, &config, 1); + glyphes = (struct zr_font_glyph*)calloc(sizeof(struct zr_font_glyph), (size_t)glyph_count); + tmp = calloc(1, tmp_size); + + /* pack all glyphes and return needed image width, height and memory size*/ + custom.w = 2; custom.h = 2; + if (!zr_font_bake_pack(&img_size, &img_width,&img_height,&custom,tmp,tmp_size,&config, 1)) + die("[Font]: failed to load font!\n"); + + /* bake all glyphes and custom white pixel into image */ + img = calloc(1, img_size); + zr_font_bake(img, img_width, img_height, tmp, tmp_size, glyphes, glyph_count, &config, 1); + zr_font_bake_custom_data(img, img_width, img_height, custom, custom_data, 2, 2, '.', 'X'); + { + /* convert alpha8 image into rgba8 image */ + void *img_rgba = calloc(4, (size_t)(img_height * img_width)); + zr_font_bake_convert(img_rgba, img_width, img_height, img); + free(img); + img = img_rgba; + } + + { + /* create allegro font bitmap */ + ALLEGRO_BITMAP *bitmap = 0; + int flags = al_get_new_bitmap_flags(); + int fmt = al_get_new_bitmap_format(); + al_set_new_bitmap_flags(ALLEGRO_MEMORY_BITMAP|ALLEGRO_MIN_LINEAR|ALLEGRO_MAG_LINEAR); + al_set_new_bitmap_format(ALLEGRO_PIXEL_FORMAT_ABGR_8888_LE); + bitmap = al_create_bitmap(img_width, img_height); + al_set_new_bitmap_flags(flags); + al_set_new_bitmap_format(fmt); + assert(bitmap); + + { + /* copy font texture into bitmap */ + ALLEGRO_LOCKED_REGION * locked_img; + locked_img = al_lock_bitmap(bitmap, al_get_bitmap_format(bitmap), ALLEGRO_LOCK_WRITEONLY); + assert(locked_img); + memcpy(locked_img->data, img, sizeof(uint32_t)*(size_t)(img_width*img_height)); + al_unlock_bitmap(bitmap); + } + + /* convert software texture into hardware texture */ + dev->texture = al_clone_bitmap(bitmap); + al_destroy_bitmap(bitmap); + assert(dev->texture); + } + free(ttf_blob); + free(tmp); + free(img); + } + + /* default white pixel in a texture which is needed to draw primitives */ + dev->null.texture.ptr = dev->texture; + dev->null.uv = zr_vec2((custom.x + 0.5f)/(float)img_width, + (custom.y + 0.5f)/(float)img_height); + + /* setup font with glyphes. IMPORTANT: the font only references the glyphes + this was done to have the possibility to have multible fonts with one + total glyph array. Not quite sure if it is a good thing since the + glyphes have to be freed as well. */ + zr_font_init(&dev->font, (float)font_height, '?', glyphes, &baked_font, dev->null.texture); + user_font = zr_font_ref(&dev->font); + + /* allocate memory for drawing process */ + dev->vertex_buffer = calloc(MAX_VERTEX_MEMORY, 1); + dev->element_buffer = calloc(MAX_ELEMENT_MEMORY, 1); + return user_font; +} + +static void +device_shutdown(struct device *dev) +{ + free(dev->font.glyphs); + free(dev->vertex_buffer); + free(dev->element_buffer); + zr_buffer_free(&dev->cmds); +} + +static void +device_draw(struct device *dev, struct zr_context *ctx, enum zr_anti_aliasing AA) +{ + int op, src, dst; + al_get_blender(&op, &src, &dst); + al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA); + + { + const struct zr_draw_command *cmd; + struct zr_buffer vbuf, ebuf; + int offset = 0; + struct allegro_vertex *vertexes = 0; + int *indicies = 0; + + /* convert from command into hardware format */ + zr_buffer_init_fixed(&vbuf, dev->vertex_buffer, MAX_VERTEX_MEMORY); + zr_buffer_init_fixed(&ebuf, dev->element_buffer, MAX_ELEMENT_MEMORY); + zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, dev->null, AA, 1.0f, 22); + + { + /* allegro does not support 32-bit packed color */ + unsigned int i = 0; + struct zr_draw_vertex *verts = (struct zr_draw_vertex*)dev->vertex_buffer; + vertexes = calloc(sizeof(struct allegro_vertex), ctx->canvas.vertex_count); + for (i = 0; i < ctx->canvas.vertex_count; ++i) { + zr_byte *c; + vertexes[i].pos = verts[i].position; + vertexes[i].uv = verts[i].uv; + c = (zr_byte*)&verts[i].col; + vertexes[i].col = al_map_rgba(c[0], c[1], c[2], c[3]); + } + } + { + /* allegro does not support 16-bit indicies: + * @OPT: define zr_draw_index as int to fix this issue. */ + unsigned int i = 0; + zr_draw_index *elements = (zr_draw_index*)dev->element_buffer; + indicies = calloc(sizeof(int), ctx->canvas.element_count); + for (i = 0; i < ctx->canvas.element_count; ++i) + indicies[i] = elements[i]; + } + + /* iterate over and execute each draw command */ + zr_draw_foreach(cmd, ctx, &dev->cmds) + { + ALLEGRO_BITMAP *texture = cmd->texture.ptr; + if (!cmd->elem_count) continue; + al_set_clipping_rectangle((int)cmd->clip_rect.x, (int)cmd->clip_rect.y, + (int)cmd->clip_rect.w, (int)cmd->clip_rect.h); + al_draw_indexed_prim(vertexes, dev->vertex_decl, texture, &indicies[offset], + (int)cmd->elem_count, ALLEGRO_PRIM_TRIANGLE_LIST); + offset += cmd->elem_count; + } + + free(vertexes); + free(indicies); + zr_clear(ctx); + } + al_set_blender(op, src, dst); + al_set_clipping_rectangle(0,0,al_get_display_width(dev->display), + al_get_display_height(dev->display)); +} + +static void +input_key(struct zr_input *in, ALLEGRO_EVENT *evt, int down) +{ + int sym = evt->keyboard.keycode; + if (sym == ALLEGRO_KEY_RSHIFT || sym == ALLEGRO_KEY_LSHIFT) + zr_input_key(in, ZR_KEY_SHIFT, down); + else if (sym == ALLEGRO_KEY_DELETE) + zr_input_key(in, ZR_KEY_DEL, down); + else if (sym == ALLEGRO_KEY_ENTER) + zr_input_key(in, ZR_KEY_ENTER, down); + else if (sym == ALLEGRO_KEY_TAB) + zr_input_key(in, ZR_KEY_TAB, down); + else if (sym == ALLEGRO_KEY_BACKSPACE) + zr_input_key(in, ZR_KEY_BACKSPACE, down); + else if (sym == ALLEGRO_KEY_LEFT) + zr_input_key(in, ZR_KEY_LEFT, down); + else if (sym == ALLEGRO_KEY_RIGHT) + zr_input_key(in, ZR_KEY_RIGHT, down); + else if (sym == ALLEGRO_KEY_C) + zr_input_key(in, ZR_KEY_COPY, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); + else if (sym == ALLEGRO_KEY_V) + zr_input_key(in, ZR_KEY_PASTE, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); + else if (sym == ALLEGRO_KEY_X) + zr_input_key(in, ZR_KEY_CUT, down && evt->keyboard.modifiers & ALLEGRO_KEYMOD_CTRL); +} + +static void +input_button(struct zr_input *in, ALLEGRO_EVENT *evt, int down) +{ + const int x = evt->mouse.x; + const int y = evt->mouse.y; + if (evt->mouse.button == 1) + zr_input_button(in, ZR_BUTTON_LEFT, x, y, down); + if (evt->mouse.button == 2) + zr_input_button(in, ZR_BUTTON_RIGHT, x, y, down); +} + +static void* mem_alloc(zr_handle unused, size_t size) +{UNUSED(unused); return calloc(1, size);} +static void mem_free(zr_handle unused, void *ptr) +{UNUSED(unused); free(ptr);} + +int +main(int argc, char *argv[]) +{ + /* Platform */ + const char *font_path; + int win_width, win_height; + int width = 0, height = 0; + int running = 1; + + /* GUI */ + struct device dev; + struct demo gui; + + font_path = argv[1]; + if (argc < 2) + die("Missing TTF Font file argument!"); + + /* Allegro */ + al_init(); + al_install_keyboard(); + al_install_mouse(); + al_init_primitives_addon(); + dev.display = al_create_display(WINDOW_WIDTH, WINDOW_HEIGHT); + al_set_window_title(dev.display, "Zahnrad"); + dev.queue = al_create_event_queue(); + al_register_event_source(dev.queue, al_get_display_event_source(dev.display)); + al_register_event_source(dev.queue, al_get_keyboard_event_source()); + al_register_event_source(dev.queue, al_get_mouse_event_source()); + + { + /* GUI */ + struct zr_user_font usrfnt; + struct zr_allocator alloc; + alloc.userdata.ptr = NULL; + alloc.alloc = mem_alloc; + alloc.free = mem_free; + zr_buffer_init(&dev.cmds, &alloc, 1024); + + usrfnt = device_init(&dev, font_path, 14, + zr_font_default_glyph_ranges()); + zr_init(&gui.ctx, &alloc, &usrfnt, sin, cos); + } + + while (running) { + /* Input */ + ALLEGRO_EVENT evt; + zr_input_begin(&gui.ctx.input); + while (al_get_next_event(dev.queue, &evt)) { + if (evt.type == ALLEGRO_EVENT_DISPLAY_CLOSE) goto cleanup; + else if (evt.type == ALLEGRO_EVENT_KEY_UP && evt.keyboard.display == dev.display) + input_key(&gui.ctx.input, &evt, zr_false); + else if (evt.type == ALLEGRO_EVENT_KEY_DOWN && evt.keyboard.display == dev.display) + input_key(&gui.ctx.input, &evt, zr_true); + else if (evt.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN) + input_button(&gui.ctx.input, &evt, zr_true); + else if (evt.type == ALLEGRO_EVENT_MOUSE_BUTTON_UP) + input_button(&gui.ctx.input, &evt, zr_false); + else if (evt.type == ALLEGRO_EVENT_MOUSE_AXES) { + zr_input_scroll(&gui.ctx.input,(float)evt.mouse.z); + zr_input_motion(&gui.ctx.input, evt.mouse.x, evt.mouse.y); + } else if (evt.type == ALLEGRO_EVENT_KEY_CHAR) { + if (evt.keyboard.display == dev.display) + if (evt.keyboard.unichar > 0 && evt.keyboard.unichar < 0x10000) + zr_input_unicode(&gui.ctx.input, (zr_rune)evt.keyboard.unichar); + } + } + zr_input_end(&gui.ctx.input); + + /* GUI */ + running = run_demo(&gui); + + /* Draw */ + al_clear_to_color(al_map_rgba_f(0.2f, 0.2f, 0.2f, 1.0f)); + device_draw(&dev, &gui.ctx, ZR_ANTI_ALIASING_ON); + al_flip_display(); + } + +cleanup: + /* Cleanup */ + if (dev.texture) + al_destroy_bitmap(dev.texture); + if (dev.queue) + al_destroy_event_queue(dev.queue); + if (dev.display) + al_destroy_display(dev.display); + device_shutdown(&dev); + zr_free(&gui.ctx); + return 0; +} + diff --git a/demo/demo.c b/demo/demo.c index 93fa035..ca9a75c 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -13,61 +13,81 @@ enum theme {THEME_BLACK, THEME_WHITE}; struct demo { - int running; - struct zr_input input; - struct zr_command_queue queue; - struct zr_style config_black; - struct zr_style config_white; - struct zr_user_font font; - struct zr_window panel; - struct zr_window sub; - struct zr_window metrics; + void *memory; enum theme theme; - size_t w, h; + struct zr_context ctx; }; static void -copy_callback(zr_handle handle, const char *text, size_t size) -{ - char buffer[1024]; - UNUSED(handle); - if (size >= 1023) return; - memcpy(buffer, text, size); - buffer[size] = '\0'; - clipboard_set(buffer); -} - -static void -paste_callback(zr_handle handle, struct zr_edit_box *box) -{ - size_t len; - const char *text; - UNUSED(handle); - if (!clipboard_is_filled())return; - text = clipboard_get(); - len = strlen(text); - zr_edit_box_add(box, text, len); -} - - -static void -zr_labelf(struct zr_context *panel, enum zr_text_align align, const char *fmt, ...) +zr_labelf(struct zr_context *ctx, enum zr_text_align align, const char *fmt, ...) { char buffer[1024]; va_list args; va_start(args, fmt); vsnprintf(buffer, sizeof(buffer), fmt, args); buffer[1023] = 0; - zr_label(panel, buffer, align); + zr_label(ctx, buffer, align); va_end(args); } -static int -show_test_window(struct zr_window *window, struct zr_style *config, enum theme *theme, - struct demo *demo) +static void +set_style(struct zr_context *ctx, enum theme theme) { - zr_flags ret; - struct zr_context layout; + if (theme == THEME_WHITE) { + ctx->style.colors[ZR_COLOR_TEXT] = zr_rgba(70, 70, 70, 255); + ctx->style.colors[ZR_COLOR_TEXT_HOVERING] = zr_rgba(10, 10, 10, 255); + ctx->style.colors[ZR_COLOR_TEXT_ACTIVE] = zr_rgba(20, 20, 20, 255); + ctx->style.colors[ZR_COLOR_WINDOW] = zr_rgba(175, 175, 175, 255); + ctx->style.colors[ZR_COLOR_HEADER] = zr_rgba(175, 175, 175, 255); + ctx->style.colors[ZR_COLOR_BORDER] = zr_rgba(0, 0, 0, 255); + ctx->style.colors[ZR_COLOR_BUTTON] = zr_rgba(185, 185, 185, 255); + ctx->style.colors[ZR_COLOR_BUTTON_HOVER] = zr_rgba(170, 170, 170, 255); + ctx->style.colors[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(160, 160, 160, 255); + ctx->style.colors[ZR_COLOR_TOGGLE] = zr_rgba(150, 150, 150, 255); + ctx->style.colors[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(120, 120, 120, 255); + ctx->style.colors[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(175, 175, 175, 255); + ctx->style.colors[ZR_COLOR_SELECTABLE] = zr_rgba(190, 190, 190, 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); + ctx->style.colors[ZR_COLOR_SLIDER] = zr_rgba(190, 190, 190, 255); + ctx->style.colors[ZR_COLOR_SLIDER_CURSOR] = zr_rgba(80, 80, 80, 255); + ctx->style.colors[ZR_COLOR_SLIDER_CURSOR_HOVER] = zr_rgba(70, 70, 70, 255); + ctx->style.colors[ZR_COLOR_SLIDER_CURSOR_ACTIVE] = zr_rgba(60, 60, 60, 255); + ctx->style.colors[ZR_COLOR_PROGRESS] = zr_rgba(190, 190, 190, 255); + ctx->style.colors[ZR_COLOR_PROGRESS_CURSOR] = zr_rgba(80, 80, 80, 255); + ctx->style.colors[ZR_COLOR_PROGRESS_CURSOR_HOVER] = zr_rgba(70, 70, 70, 255); + ctx->style.colors[ZR_COLOR_PROGRESS_CURSOR_ACTIVE] = zr_rgba(60, 60, 60, 255); + ctx->style.colors[ZR_COLOR_PROPERTY] = zr_rgba(150, 150, 150, 255); + ctx->style.colors[ZR_COLOR_PROPERTY_HOVER] = zr_rgba(160, 160, 160, 255); + ctx->style.colors[ZR_COLOR_PROPERTY_ACTIVE] = zr_rgba(165, 165, 165, 255); + ctx->style.colors[ZR_COLOR_INPUT] = zr_rgba(150, 150, 150, 255); + ctx->style.colors[ZR_COLOR_INPUT_CURSOR] = zr_rgba(0, 0, 0, 255); + ctx->style.colors[ZR_COLOR_INPUT_TEXT] = zr_rgba(0, 0, 0, 255); + ctx->style.colors[ZR_COLOR_COMBO] = zr_rgba(175, 175, 175, 255); + ctx->style.colors[ZR_COLOR_HISTO] = zr_rgba(160, 160, 160, 255); + ctx->style.colors[ZR_COLOR_HISTO_BARS] = zr_rgba(45, 45, 45, 255); + ctx->style.colors[ZR_COLOR_HISTO_HIGHLIGHT] = zr_rgba( 255, 0, 0, 255); + ctx->style.colors[ZR_COLOR_PLOT] = zr_rgba(160, 160, 160, 255); + ctx->style.colors[ZR_COLOR_PLOT_LINES] = zr_rgba(45, 45, 45, 255); + ctx->style.colors[ZR_COLOR_PLOT_HIGHLIGHT] = zr_rgba(255, 0, 0, 255); + ctx->style.colors[ZR_COLOR_SCROLLBAR] = zr_rgba(180, 180, 180, 255); + ctx->style.colors[ZR_COLOR_SCROLLBAR_CURSOR] = zr_rgba(140, 140, 140, 255); + ctx->style.colors[ZR_COLOR_SCROLLBAR_CURSOR_HOVER] = zr_rgba(150, 150, 150, 255); + ctx->style.colors[ZR_COLOR_SCROLLBAR_CURSOR_ACTIVE] = zr_rgba(160, 160, 160, 255); + ctx->style.colors[ZR_COLOR_TABLE_LINES] = zr_rgba(100, 100, 100, 255); + ctx->style.colors[ZR_COLOR_TAB_HEADER] = zr_rgba(180, 180, 180, 255); + ctx->style.colors[ZR_COLOR_SCALER] = zr_rgba(100, 100, 100, 255); + } + else { + struct zr_user_font fnt = ctx->style.font; + zr_style_default(&ctx->style, ZR_DEFAULT_ALL, &fnt); + } +} + +static int +demo_window(struct zr_layout *layout, struct zr_context *ctx, enum theme *theme) +{ + struct zr_layout menu; /* window flags */ static int show_menu = zr_true; @@ -80,1029 +100,806 @@ show_test_window(struct zr_window *window, struct zr_style *config, enum theme * static int minimizable = zr_true; static int close = zr_true; - /* collapsable headers */ - static int window_option_state = ZR_MINIMIZED; - static int widget_state = ZR_MINIMIZED; - static int graph_state = ZR_MINIMIZED; - static int style_state = ZR_MINIMIZED; - static int group_state = ZR_MINIMIZED; - static int splitter_state = ZR_MINIMIZED; - /* popups */ static enum zr_style_header_align header_align = ZR_HEADER_RIGHT; static int show_app_about = zr_false; - static int show_contextual = zr_false; - static struct zr_rect contextual_bounds; static int show_close_popup = zr_false; static int show_color_picker_popup = zr_false; static int color_picker_index; static struct zr_color color_picker_color; /* window flags */ - config->header.align = header_align; - window->style = config; window_flags = 0; + ctx->style.header.align = header_align; if (border) window_flags |= ZR_WINDOW_BORDER; if (resize) window_flags |= ZR_WINDOW_SCALEABLE; if (moveable) window_flags |= ZR_WINDOW_MOVEABLE; if (no_scrollbar) window_flags |= ZR_WINDOW_NO_SCROLLBAR; - if (window->flags & ZR_WINDOW_ACTIVE) window_flags |= ZR_WINDOW_ACTIVE; - if (window->flags & ZR_WINDOW_ROM) window_flags |= ZR_WINDOW_ROM; - if (window->flags & ZR_WINDOW_MINIMIZED) window_flags |= ZR_WINDOW_MINIMIZED; if (minimizable) window_flags |= ZR_WINDOW_MINIMIZABLE; if (close) window_flags |= ZR_WINDOW_CLOSEABLE; /* main window */ - window->flags = window_flags; - ret = zr_begin(&layout, window, (titlebar)? "Zahnrad":""); - if (ret & ZR_WINDOW_CLOSEABLE) - return 0; - - if (show_menu) + if (zr_begin(ctx, layout, "Demo", zr_rect(30, 30, 400, 600), window_flags)) { - /* menubar */ - enum menu_states {MENU_DEFAULT, MENU_TEST}; - struct zr_context menu; - static int file_state = ZR_MINIMIZED; - static zr_size mprog = 60; - static int mslider = 10; - static int mcheck = zr_true; - static int menu_state = MENU_DEFAULT; - - zr_menubar_begin(&layout); - - zr_layout_row_begin(&layout, ZR_STATIC, 25, 2); - zr_layout_row_push(&layout, 45); - zr_menu_text_begin(&layout, &menu, "MENU", 120, &file_state); + if (show_menu) { - zr_layout_row_dynamic(&menu, 25, 1); - switch (menu_state) { - default: - case MENU_DEFAULT: { + /* menubar */ + enum menu_states {MENU_DEFAULT, MENU_TEST}; + static zr_size mprog = 60; + static int mslider = 10; + static int mcheck = zr_true; + + zr_menubar_begin(ctx); + zr_layout_row_begin(ctx, ZR_STATIC, 25, 2); + zr_layout_row_push(ctx, 45); + if (zr_menu_text_begin(ctx, &menu, "MENU", 120)) + { static size_t prog = 40; static int slider = 10; static int check = zr_true; - zr_progress(&menu, &prog, 100, ZR_MODIFIABLE); - zr_slider_int(&menu, 0, &slider, 16, 1); - zr_checkbox(&menu, "check", &check); - if (zr_menu_item(&menu, ZR_TEXT_CENTERED, "Hide")) { + + zr_layout_row_dynamic(ctx, 25, 1); + zr_progress(ctx, &prog, 100, ZR_MODIFIABLE); + zr_slider_int(ctx, 0, &slider, 16, 1); + zr_checkbox(ctx, "check", &check); + + if (zr_menu_item(ctx, ZR_TEXT_CENTERED, "Hide")) show_menu = zr_false; - zr_menu_close(&menu, &file_state); - } - if (zr_menu_item(&menu, ZR_TEXT_CENTERED, "About")) { + if (zr_menu_item(ctx, ZR_TEXT_CENTERED, "About")) show_app_about = zr_true; - zr_menu_close(&menu, &file_state); - } - if (zr_menu_item_symbol(&menu, ZR_SYMBOL_TRIANGLE_RIGHT, "Windows", ZR_TEXT_LEFT)) - menu_state = MENU_TEST; - if (zr_menu_item(&menu, ZR_TEXT_CENTERED, "Quit")) { + if (zr_menu_item(ctx, ZR_TEXT_CENTERED, "Quit")) show_close_popup = zr_true; - zr_menu_close(&menu, &file_state); - } - } break; - case MENU_TEST: { - if (zr_menu_item_symbol(&menu, (demo->sub.flags & ZR_WINDOW_HIDDEN)? - ZR_SYMBOL_RECT : ZR_SYMBOL_RECT_FILLED, "Demo", ZR_TEXT_RIGHT)) { - if (demo->sub.flags & ZR_WINDOW_HIDDEN) - demo->sub.flags &= ~(unsigned)ZR_WINDOW_HIDDEN; - else demo->sub.flags |= ZR_WINDOW_HIDDEN; - } - if (zr_menu_item_symbol(&menu, (demo->metrics.flags & ZR_WINDOW_HIDDEN)? - ZR_SYMBOL_RECT : ZR_SYMBOL_RECT_FILLED, "Metrics", ZR_TEXT_RIGHT)) { - if (demo->metrics.flags & ZR_WINDOW_HIDDEN) - demo->metrics.flags &= ~(unsigned)ZR_WINDOW_HIDDEN; - else demo->metrics.flags |= ZR_WINDOW_HIDDEN; - } - if (zr_menu_item_symbol(&menu, ZR_SYMBOL_TRIANGLE_LEFT, "BACK", ZR_TEXT_RIGHT)) - menu_state = MENU_DEFAULT; - } break; + zr_menu_end(ctx); } - } - zr_menu_end(&layout, &menu); - zr_layout_row_push(&layout, 60); - zr_progress(&layout, &mprog, 100, ZR_MODIFIABLE); - zr_slider_int(&layout, 0, &mslider, 16, 1); - zr_checkbox(&layout, "check", &mcheck); - - zr_menubar_end(&layout); - } - - if (show_app_about) - { - /* about popup */ - struct zr_context popup; - static struct zr_vec2 about_scrollbar; - static struct zr_rect s = {20, 100, 300, 190}; - zr_flags r = zr_popup_begin(&layout, &popup, ZR_POPUP_STATIC, "About", - ZR_WINDOW_CLOSEABLE, s, about_scrollbar); - if (r & ZR_WINDOW_CLOSEABLE){ - show_app_about = zr_false; - zr_popup_close(&popup); + zr_layout_row_push(ctx, 60); + zr_progress(ctx, &mprog, 100, ZR_MODIFIABLE); + zr_slider_int(ctx, 0, &mslider, 16, 1); + zr_checkbox(ctx, "check", &mcheck); + zr_menubar_end(ctx); } - zr_layout_row_dynamic(&popup, 20, 1); - zr_label(&popup, "Zahnrad", ZR_TEXT_LEFT); - zr_label(&popup, "By Micha Mettke", ZR_TEXT_LEFT); - zr_label(&popup, "Zahnrad is licensed under the MIT License.", ZR_TEXT_LEFT); - zr_label(&popup, "See LICENSE for more information", ZR_TEXT_LEFT); - zr_popup_end(&layout, &popup, &about_scrollbar); - } - - if (show_close_popup) - { - /* close popup */ - struct zr_context popup; - static struct zr_vec2 close_scrollbar = {0,0}; - static const struct zr_rect s = {20, 150, 230, 150}; - zr_flags r = zr_popup_begin(&layout, &popup, ZR_POPUP_STATIC, "Quit", - ZR_WINDOW_CLOSEABLE, s, close_scrollbar); - if (r & ZR_WINDOW_CLOSEABLE) { - show_close_popup = zr_false; - zr_popup_close(&popup); - } - zr_layout_row_dynamic(&popup, 30, 1); - zr_label(&popup, "Are you sure you want to exit?", ZR_TEXT_LEFT); - zr_layout_row_dynamic(&popup, 30, 4); - zr_spacing(&popup, 1); - if (zr_button_text(&popup, "Yes", ZR_BUTTON_DEFAULT)) { - show_close_popup = zr_false; - zr_popup_close(&popup); - return 0; - } - if (zr_button_text(&popup, "No", ZR_BUTTON_DEFAULT)) { - show_close_popup = zr_false; - zr_popup_close(&popup); - } - zr_popup_end(&layout, &popup, NULL); - } - - if (show_color_picker_popup) - { - /* color picker popup */ - struct zr_context popup; - zr_flags res = zr_popup_begin(&layout, &popup, ZR_POPUP_STATIC, "Color Picker", - ZR_WINDOW_CLOSEABLE, zr_rect(10, 100, 360, 280), zr_vec2(0,0)); - if (res & ZR_WINDOW_CLOSEABLE) + if (show_app_about) { - zr_popup_close(&popup); - show_color_picker_popup = zr_false; + /* about popup */ + struct zr_layout popup; + static struct zr_rect s = {20, 100, 300, 190}; + if (zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "About", ZR_WINDOW_CLOSEABLE, s)) + { + zr_layout_row_dynamic(ctx, 20, 1); + zr_label(ctx, "Zahnrad", ZR_TEXT_LEFT); + zr_label(ctx, "By Micha Mettke", ZR_TEXT_LEFT); + zr_label(ctx, "Zahnrad is licensed under the MIT License.", ZR_TEXT_LEFT); + zr_label(ctx, "See LICENSE for more information", ZR_TEXT_LEFT); + } else show_app_about = zr_false; + zr_popup_end(ctx); } - zr_layout_row_dynamic(&popup, 30, 2); - zr_label(&popup, zr_style_color_name((enum zr_style_colors)color_picker_index), ZR_TEXT_LEFT); - zr_button_color(&popup, color_picker_color, ZR_BUTTON_DEFAULT); - - /* color selection */ - zr_layout_row_dynamic(&popup, 30, 2); - color_picker_color.r = (zr_byte)zr_propertyi(&popup, "#R:", 0, color_picker_color.r, 255, 1,1); - color_picker_color.g = (zr_byte)zr_propertyi(&popup, "#G:", 0, color_picker_color.g, 255, 1,1); - color_picker_color.b = (zr_byte)zr_propertyi(&popup, "#B", 0, color_picker_color.b, 255, 1,1); - color_picker_color.a = (zr_byte)zr_propertyi(&popup, "#A", 0, color_picker_color.a, 255, 1,1); - - zr_layout_row_dynamic(&popup, 30, 4); - zr_spacing(&popup, 1); - if (zr_button_text(&popup, "ok", ZR_BUTTON_DEFAULT)) + if (show_close_popup) { - zr_popup_close(&popup); - show_color_picker_popup = zr_false; - config->colors[color_picker_index] = color_picker_color; - } - if (zr_button_text(&popup, "cancel", ZR_BUTTON_DEFAULT)) - { - zr_popup_close(&popup); - show_color_picker_popup = zr_false; - } - zr_popup_end(&layout, &popup, NULL); - } - - /* contextual menu */ - if (zr_input_mouse_clicked(layout.input, ZR_BUTTON_RIGHT, layout.bounds)) { - contextual_bounds = zr_rect(layout.input->mouse.pos.x, layout.input->mouse.pos.y, 100, 200); - show_contextual = zr_true; - } - if (show_contextual) { - struct zr_context menu; - static size_t prog = 40; - static int slider = 10; - - zr_contextual_begin(&layout, &menu, ZR_WINDOW_NO_SCROLLBAR, &show_contextual, contextual_bounds); - zr_layout_row_dynamic(&menu, 25, 1); - zr_checkbox(&menu, "Menu", &show_menu); - zr_progress(&menu, &prog, 100, ZR_MODIFIABLE); - zr_slider_int(&menu, 0, &slider, 16, 1); - if (zr_contextual_item(&menu, "About", ZR_TEXT_CENTERED)) - show_app_about = zr_true; - if (zr_contextual_item(&menu, "Quit", ZR_TEXT_CENTERED)) - show_close_popup = zr_true; - zr_contextual_end(&layout, &menu, &show_contextual); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_TAB, "Window", &window_option_state)) - { - /* window options */ - zr_layout_row_dynamic(&layout, 30, 2); - zr_checkbox(&layout, "Titlebar", &titlebar); - zr_checkbox(&layout, "Menu", &show_menu); - zr_checkbox(&layout, "Border", &border); - zr_checkbox(&layout, "Resizable", &resize); - zr_checkbox(&layout, "Moveable", &moveable); - zr_checkbox(&layout, "No Scrollbar", &no_scrollbar); - zr_checkbox(&layout, "Minimizable", &minimizable); - zr_checkbox(&layout, "Closeable", &close); - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_TAB, "Style", &style_state)) - { - /* style editor */ - static int property_state = ZR_MINIMIZED; - static int rounding_state = ZR_MINIMIZED; - static int color_state = ZR_MINIMIZED; - struct zr_context combo; - static const char *themes[] = {"Black", "White"}; - static int theme_active = zr_false; - - /* theme */ - zr_layout_row_static(&layout, 30, 80, 2); - zr_label(&layout, "Theme:", ZR_TEXT_LEFT); - zr_combo_begin_text(&layout, &combo, themes[*theme], &theme_active, 200, 0); - zr_layout_row_dynamic(&combo, 25, 1); - *theme = zr_combo_item(&combo, themes[THEME_BLACK], ZR_TEXT_CENTERED) ? THEME_BLACK : *theme; - *theme = zr_combo_item(&combo, themes[THEME_WHITE], ZR_TEXT_CENTERED) ? THEME_WHITE : *theme; - zr_combo_end(&layout, &combo, &theme_active, 0); - - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Properties", &property_state)) - { - /* properties */ - size_t i = 0; - zr_layout_row_dynamic(&layout, 30, 3); - for (i = 0; i <= ZR_PROPERTY_SCROLLBAR_SIZE; ++i) { - zr_label(&layout, zr_style_property_name((enum zr_style_properties)i), ZR_TEXT_LEFT); - zr_property_float(&layout, "#X:", 0, &config->properties[i].x, 20, 1, 1); - zr_property_float(&layout, "#Y:", 0, &config->properties[i].y, 20, 1, 1); - } - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Rounding", &rounding_state)) - { - /* rounding */ - size_t i = 0; - zr_layout_row_dynamic(&layout, 30, 2); - for (i = 0; i < ZR_ROUNDING_MAX; ++i) { - zr_label(&layout, zr_style_rounding_name((enum zr_style_rounding)i), ZR_TEXT_LEFT); - zr_property_float(&layout, "#R:", 0, &config->rounding[i], 20, 1, 1); - } - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Color", &color_state)) - { - /* color */ - size_t i = 0; - struct zr_context tab; - static struct zr_vec2 scrollbar; - zr_layout_row_dynamic(&layout, 20, 1); - zr_label(&layout, "Click on the color to modify", ZR_TEXT_LEFT); - zr_layout_row_dynamic(&layout, 400, 1); - zr_group_begin(&layout, &tab, NULL, 0, scrollbar); - for (i = 0; i < ZR_COLOR_COUNT; ++i) { - zr_layout_row_dynamic(&tab, 30, 2); - zr_label(&tab, zr_style_color_name((enum zr_style_colors)i), ZR_TEXT_LEFT); - if (zr_button_color(&tab, config->colors[i], ZR_BUTTON_DEFAULT)) { - show_color_picker_popup = zr_true; - color_picker_index = (int)i; - color_picker_color = config->colors[i]; + /* close popup */ + struct zr_layout popup; + static const struct zr_rect s = {20, 150, 230, 150}; + if(zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "Quit", ZR_WINDOW_CLOSEABLE, s)) + { + zr_layout_row_dynamic(ctx, 30, 1); + zr_label(ctx, "Are you sure you want to exit?", ZR_TEXT_LEFT); + zr_layout_row_dynamic(ctx, 30, 4); + zr_spacing(ctx, 1); + if (zr_button_text(ctx, "Yes", ZR_BUTTON_DEFAULT)) + return 0; + if (zr_button_text(ctx, "No", ZR_BUTTON_DEFAULT)) { + show_close_popup = zr_false; + zr_popup_close(ctx); } + } else show_close_popup = zr_false; + zr_popup_end(ctx); + } + + if (show_color_picker_popup) + { + /* color picker popup */ + struct zr_layout popup; + if (zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "Color Picker", + ZR_WINDOW_CLOSEABLE, zr_rect(10, 100, 360, 280))) + { + zr_layout_row_dynamic(ctx, 30, 2); + zr_label(ctx, zr_style_color_name((enum zr_style_colors)color_picker_index), ZR_TEXT_LEFT); + zr_button_color(ctx, color_picker_color, ZR_BUTTON_DEFAULT); + + /* color selection */ + zr_layout_row_dynamic(ctx, 30, 1); + color_picker_color.r = (zr_byte)zr_propertyi(ctx, "#R:", 0, color_picker_color.r, 255, 1,1); + color_picker_color.g = (zr_byte)zr_propertyi(ctx, "#G:", 0, color_picker_color.g, 255, 1,1); + color_picker_color.b = (zr_byte)zr_propertyi(ctx, "#B", 0, color_picker_color.b, 255, 1,1); + color_picker_color.a = (zr_byte)zr_propertyi(ctx, "#A", 0, color_picker_color.a, 255, 1,1); + + zr_layout_row_dynamic(ctx, 30, 4); + zr_spacing(ctx, 1); + if (zr_button_text(ctx, "ok", ZR_BUTTON_DEFAULT)) { + zr_popup_close(ctx); + show_color_picker_popup = zr_false; + ctx->style.colors[color_picker_index] = color_picker_color; + } + if (zr_button_text(ctx, "cancel", ZR_BUTTON_DEFAULT)) { + zr_popup_close(ctx); + show_color_picker_popup = zr_false; + } + } else show_color_picker_popup = zr_false; + zr_popup_end(ctx); + } + + /* contextual menu */ + if (zr_contextual_begin(ctx, &menu, 0, zr_vec2(100, 200))) { + static size_t prog = 40; + static int slider = 10; + zr_layout_row_dynamic(ctx, 25, 1); + zr_checkbox(ctx, "Menu", &show_menu); + zr_progress(ctx, &prog, 100, ZR_MODIFIABLE); + zr_slider_int(ctx, 0, &slider, 16, 1); + if (zr_contextual_item(ctx, "About", ZR_TEXT_CENTERED)) + show_app_about = zr_true; + if (zr_contextual_item(ctx, "Quit", ZR_TEXT_CENTERED)) + show_close_popup = zr_true; + zr_contextual_end(ctx); + } + + /* window flags */ + if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Window")) { + zr_layout_row_dynamic(ctx, 30, 2); + zr_checkbox(ctx, "Titlebar", &titlebar); + zr_checkbox(ctx, "Menu", &show_menu); + zr_checkbox(ctx, "Border", &border); + zr_checkbox(ctx, "Resizable", &resize); + zr_checkbox(ctx, "Moveable", &moveable); + zr_checkbox(ctx, "No Scrollbar", &no_scrollbar); + zr_checkbox(ctx, "Minimizable", &minimizable); + zr_checkbox(ctx, "Closeable", &close); + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Style")) + { + /* style editor */ + static const char *themes[] = {"Black", "White"}; + enum theme old = *theme; + struct zr_layout combo; + + /* theme */ + zr_layout_row_static(ctx, 30, 80, 2); + zr_label(ctx, "Theme:", ZR_TEXT_LEFT); + + if (zr_combo_begin_text(ctx, &combo, "themes", themes[*theme], 200)) { + zr_layout_row_dynamic(ctx, 25, 1); + *theme = zr_combo_item(ctx, themes[THEME_BLACK], ZR_TEXT_CENTERED) ? THEME_BLACK : *theme; + *theme = zr_combo_item(ctx, themes[THEME_WHITE], ZR_TEXT_CENTERED) ? THEME_WHITE : *theme; + if (old != *theme) set_style(ctx, *theme); + zr_combo_end(ctx); } - zr_group_end(&layout, &tab, &scrollbar); - zr_layout_pop(&layout); - } - zr_layout_pop(&layout); - } - if (zr_layout_push(&layout, ZR_LAYOUT_TAB, "Widgets", &widget_state)) - { - static int text_state = zr_false; - static int main_state = zr_false; - static int button_state = zr_false; - static int combo_state = zr_false; - static int input_state = zr_false; - static int sel_state = zr_false; + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Properties")) { + size_t i = 0; + zr_layout_row_dynamic(ctx, 30, 3); + for (i = 0; i <= ZR_PROPERTY_SCROLLBAR_SIZE; ++i) { + zr_label(ctx, zr_style_property_name((enum zr_style_properties)i), ZR_TEXT_LEFT); + zr_property_float(ctx, "#X:", 0, &ctx->style.properties[i].x, 20, 1, 1); + zr_property_float(ctx, "#Y:", 0, &ctx->style.properties[i].y, 20, 1, 1); + } + zr_layout_pop(ctx); + } - enum options {A,B,C}; - static int checkbox; - static int option; + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Rounding")) { + size_t i = 0; + zr_layout_row_dynamic(ctx, 30, 2); + for (i = 0; i < ZR_ROUNDING_MAX; ++i) { + zr_label(ctx, zr_style_rounding_name((enum zr_style_rounding)i), ZR_TEXT_LEFT); + zr_property_float(ctx, "#R:", 0, &ctx->style.rounding[i], 20, 1, 1); + } + zr_layout_pop(ctx); + } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Text", &text_state)) - { - /* Text Widgets */ - zr_layout_row_dynamic(&layout, 20, 1); - zr_label(&layout, "Label aligned left", ZR_TEXT_LEFT); - zr_label(&layout, "Label aligned centered", ZR_TEXT_CENTERED); - zr_label(&layout, "Label aligned right", ZR_TEXT_RIGHT); - zr_label_colored(&layout, "Blue text", ZR_TEXT_LEFT, zr_rgb(0,0,255)); - zr_label_colored(&layout, "Yellow text", ZR_TEXT_LEFT, zr_rgb(255,255,0)); - zr_text(&layout, "Text without /0", 15, ZR_TEXT_RIGHT); - - zr_layout_row_static(&layout, 100, 200, 1); - zr_label_wrap(&layout, "This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping"); - zr_layout_row_dynamic(&layout, 100, 1); - zr_label_wrap(&layout, "This is another long text to show dynamic window changes on multiline text"); - zr_layout_pop(&layout); + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Colors")){ + size_t i = 0; + struct zr_layout tab; + zr_layout_row_dynamic(ctx, 20, 1); + zr_label(ctx, "Click on the color to modify", ZR_TEXT_LEFT); + zr_layout_row_dynamic(ctx, 400, 1); + if (zr_group_begin(ctx, &tab, "Color_Picker", 0)) { + for (i = 0; i < ZR_COLOR_COUNT; ++i) { + zr_layout_row_dynamic(ctx, 30, 2); + zr_label(ctx, zr_style_color_name((enum zr_style_colors)i), ZR_TEXT_LEFT); + if (zr_button_color(ctx, ctx->style.colors[i], ZR_BUTTON_DEFAULT)) { + show_color_picker_popup = zr_true; + color_picker_index = (int)i; + color_picker_color = ctx->style.colors[i]; + } + } + zr_group_end(ctx); + } + zr_layout_pop(ctx); + } + zr_layout_pop(ctx); } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Button", &button_state)) + if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Widgets")) { - /* Buttons Widgets */ - zr_layout_row_static(&layout, 30, 100, 3); - if (zr_button_text(&layout, "Button", ZR_BUTTON_DEFAULT)) - fprintf(stdout, "Button pressed!\n"); - if (zr_button_text(&layout, "Repeater", ZR_BUTTON_REPEATER)) - fprintf(stdout, "Repeater is being pressed!\n"); - zr_button_color(&layout, zr_rgb(0,0,255), ZR_BUTTON_DEFAULT); + enum options {A,B,C}; + static int checkbox; + static int option; + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Text")) + { + /* Text Widgets */ + zr_layout_row_dynamic(ctx, 20, 1); + zr_label(ctx, "Label aligned left", ZR_TEXT_LEFT); + zr_label(ctx, "Label aligned centered", ZR_TEXT_CENTERED); + zr_label(ctx, "Label aligned right", ZR_TEXT_RIGHT); + zr_label_colored(ctx, "Blue text", ZR_TEXT_LEFT, zr_rgb(0,0,255)); + zr_label_colored(ctx, "Yellow text", ZR_TEXT_LEFT, zr_rgb(255,255,0)); + zr_text(ctx, "Text without /0", 15, ZR_TEXT_RIGHT); - zr_layout_row_static(&layout, 20, 20, 8); - zr_button_symbol(&layout, ZR_SYMBOL_CIRCLE, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_CIRCLE_FILLED, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_RECT, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_RECT_FILLED, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_TRIANGLE_UP, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_TRIANGLE_DOWN, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_TRIANGLE_LEFT, ZR_BUTTON_DEFAULT); - zr_button_symbol(&layout, ZR_SYMBOL_TRIANGLE_RIGHT, ZR_BUTTON_DEFAULT); + zr_layout_row_static(ctx, 100, 200, 1); + zr_label_wrap(ctx, "This is a very long line to hopefully get this text to be wrapped into multiple lines to show line wrapping"); + zr_layout_row_dynamic(ctx, 100, 1); + zr_label_wrap(ctx, "This is another long text to show dynamic window changes on multiline text"); + zr_layout_pop(ctx); + } - zr_layout_row_static(&layout, 30, 100, 2); - zr_button_text_symbol(&layout, ZR_SYMBOL_TRIANGLE_LEFT, "prev", ZR_TEXT_RIGHT, ZR_BUTTON_DEFAULT); - zr_button_text_symbol(&layout, ZR_SYMBOL_TRIANGLE_RIGHT, "next", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT); - zr_layout_pop(&layout); + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Button")) + { + /* Buttons Widgets */ + zr_layout_row_static(ctx, 30, 100, 3); + if (zr_button_text(ctx, "Button", ZR_BUTTON_DEFAULT)) + fprintf(stdout, "Button pressed!\n"); + if (zr_button_text(ctx, "Repeater", ZR_BUTTON_REPEATER)) + fprintf(stdout, "Repeater is being pressed!\n"); + zr_button_color(ctx, zr_rgb(0,0,255), ZR_BUTTON_DEFAULT); + + zr_layout_row_static(ctx, 20, 20, 8); + zr_button_symbol(ctx, ZR_SYMBOL_CIRCLE, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_CIRCLE_FILLED, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_RECT, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_RECT_FILLED, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_UP, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_DOWN, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_LEFT, ZR_BUTTON_DEFAULT); + zr_button_symbol(ctx, ZR_SYMBOL_TRIANGLE_RIGHT, ZR_BUTTON_DEFAULT); + + zr_layout_row_static(ctx, 30, 100, 2); + zr_button_text_symbol(ctx, ZR_SYMBOL_TRIANGLE_LEFT, "prev", ZR_TEXT_RIGHT, ZR_BUTTON_DEFAULT); + zr_button_text_symbol(ctx, ZR_SYMBOL_TRIANGLE_RIGHT, "next", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT); + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Basic")) + { + /* Basic widgets */ + static int int_slider = 5; + static float float_slider = 2.5f; + static size_t prog_value = 40; + static float property_float = 2; + static int property_int = 10; + + static const float ratio[] = {120, 150}; + const struct zr_input *in = &ctx->input; + struct zr_rect bounds; + + zr_layout_row_static(ctx, 30, 100, 1); + zr_checkbox(ctx, "Checkbox", &checkbox); + + zr_layout_row_static(ctx, 30, 80, 3); + option = zr_option(ctx, "optionA", option == A) ? A : option; + option = zr_option(ctx, "optionB", option == B) ? B : option; + option = zr_option(ctx, "optionC", option == C) ? C : option; + + zr_layout_row_static(ctx, 30, 150, 1); + zr_layout_peek(&bounds, ctx); + zr_label(ctx, "Hover me for tooltip", ZR_TEXT_LEFT); + if (zr_input_is_mouse_hovering_rect(in, bounds)) + zr_tooltip(ctx, "This is a tooltip"); + + zr_layout_row(ctx, ZR_STATIC, 30, 2, ratio); + zr_labelf(ctx, ZR_TEXT_LEFT, "Slider int"); + zr_slider_int(ctx, 0, &int_slider, 10, 1); + + zr_label(ctx, "Slider float", ZR_TEXT_LEFT); + zr_slider_float(ctx, 0, &float_slider, 5.0, 0.5f); + zr_labelf(ctx, ZR_TEXT_LEFT, "Progressbar" , prog_value); + zr_progress(ctx, &prog_value, 100, ZR_MODIFIABLE); + + zr_label(ctx, "Property float:", ZR_TEXT_LEFT); + zr_property_float(ctx, "Float:", 0, &property_float, 64.0f, 0.1f, 0.2f); + zr_label(ctx, "Property int:", ZR_TEXT_LEFT); + zr_property_int(ctx, "Int:", 0, &property_int, 100.0f, 1, 1); + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Selectable")) + { + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "List")) + { + static int selected[4] = {zr_false, zr_false, zr_true, zr_false}; + zr_layout_row_static(ctx, 18, 100, 1); + zr_selectable(ctx, "Selectable", ZR_TEXT_LEFT, &selected[0]); + zr_selectable(ctx, "Selectable", ZR_TEXT_LEFT, &selected[1]); + zr_label(ctx, "Not Selectable", ZR_TEXT_LEFT); + zr_selectable(ctx, "Selectable", ZR_TEXT_LEFT, &selected[2]); + zr_selectable(ctx, "Selectable", ZR_TEXT_LEFT, &selected[3]); + zr_layout_pop(ctx); + } + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Grid")) + { + int i; + static int selected[16]; + zr_layout_row_static(ctx, 50, 50, 4); + for (i = 0; i < 16; ++i) { + if (zr_selectable(ctx, "Z", ZR_TEXT_CENTERED, &selected[i])) { + int x = (i % 4), y = i / 4; + if (x > 0) selected[i - 1] ^= 1; + if (x < 3) selected[i + 1] ^= 1; + if (y > 0) selected[i - 4] ^= 1; + if (y < 3) selected[i + 4] ^= 1; + } + } + zr_layout_pop(ctx); + } + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Combo")) + { + /* Combobox Widgets */ + static float graph_selection = 8.0f; + static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"}; + static size_t current_weapon = 0; + static int check_values[5]; + static struct zr_color combo_color = {130, 50, 50, 255}; + static size_t x = 20, y = 40, z = 10, w = 90; + + char buffer[32]; + size_t sum = 0; + struct zr_layout combo; + + /* default combobox */ + zr_layout_row_static(ctx, 30, 200, 1); + if (zr_combo_begin_text(ctx, &combo, "Weapons", 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); + } + + /* slider color combobox */ + if (zr_combo_begin_color(ctx, &combo, "Color", combo_color, 200)) { + float ratios[] = {0.15f, 0.85f}; + zr_layout_row(ctx, ZR_DYNAMIC, 30, 2, ratios); + zr_label(ctx, "R", ZR_TEXT_LEFT); + combo_color.r = (zr_byte)zr_slide_int(ctx, 0, combo_color.r, 255, 5); + zr_label(ctx, "G", ZR_TEXT_LEFT); + combo_color.g = (zr_byte)zr_slide_int(ctx, 0, combo_color.g, 255, 5); + zr_label(ctx, "B", ZR_TEXT_LEFT); + combo_color.b = (zr_byte)zr_slide_int(ctx, 0, combo_color.b, 255, 5); + zr_label(ctx, "A", ZR_TEXT_LEFT); + combo_color.a = (zr_byte)zr_slide_int(ctx, 0, combo_color.a , 255, 5); + zr_combo_end(ctx); + } + + /* progressbar combobox */ + sum = x + y + z + w; + sprintf(buffer, "%lu", sum); + if (zr_combo_begin_text(ctx, &combo, "Progressbar", buffer, 200)) { + zr_layout_row_dynamic(ctx, 30, 1); + zr_progress(ctx, &x, 100, ZR_MODIFIABLE); + zr_progress(ctx, &y, 100, ZR_MODIFIABLE); + zr_progress(ctx, &z, 100, ZR_MODIFIABLE); + zr_progress(ctx, &w, 100, ZR_MODIFIABLE); + zr_combo_end(ctx); + } + + /* checkbox combobox */ + sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]); + sprintf(buffer, "%lu", sum); + if (zr_combo_begin_text(ctx, &combo, "Checkbox", buffer, 200)) { + zr_layout_row_dynamic(ctx, 30, 1); + zr_checkbox(ctx, weapons[0], &check_values[0]); + zr_checkbox(ctx, weapons[1], &check_values[1]); + zr_checkbox(ctx, weapons[2], &check_values[2]); + zr_checkbox(ctx, weapons[3], &check_values[3]); + zr_combo_end(ctx); + } + + /* graph combobox */ + sprintf(buffer, "%.1f", graph_selection); + if (zr_combo_begin_text(ctx, &combo, "Graph", buffer, 250)) { + size_t i = 0; + static const float values[]={30.0f,15.0f,25.0f,10.0f,20.0f,40.0f}; + zr_layout_row_dynamic(ctx, 150, 1); + zr_graph_begin(ctx, ZR_GRAPH_COLUMN, LEN(values), 0, 50); + for (i = 0; i < LEN(values); ++i) { + zr_flags res = zr_graph_push(ctx, values[i]); + if (res & ZR_GRAPH_CLICKED) { + graph_selection = values[i]; + zr_combo_close(ctx); + } + } + zr_graph_end(ctx); + zr_combo_end(ctx); + } + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Input")) + { + static const float ratio[] = {120, 150}; + static char field_buffer[64]; + static char box_buffer[512]; + static char text[9][64]; + static size_t text_len[9]; + static size_t field_len; + static size_t box_len; + int active; + + zr_layout_row(ctx, ZR_STATIC, 25, 2, ratio); + zr_label(ctx, "Default:", ZR_TEXT_LEFT); + + zr_edit_string(ctx, ZR_EDIT_CURSOR, text[0], &text_len[0], 64, zr_filter_default); + zr_label(ctx, "Int:", ZR_TEXT_LEFT); + zr_edit_string(ctx, ZR_EDIT_CURSOR, text[1], &text_len[1], 64, zr_filter_decimal); + zr_label(ctx, "Float:", ZR_TEXT_LEFT); + zr_edit_string(ctx, ZR_EDIT_CURSOR, text[2], &text_len[2], 64, zr_filter_float); + zr_label(ctx, "Hex:", ZR_TEXT_LEFT); + zr_edit_string(ctx, ZR_EDIT_CURSOR, text[4], &text_len[4], 64, zr_filter_hex); + zr_label(ctx, "Octal:", ZR_TEXT_LEFT); + zr_edit_string(ctx, ZR_EDIT_CURSOR, text[5], &text_len[5], 64, zr_filter_oct); + zr_label(ctx, "Binary:", ZR_TEXT_LEFT); + zr_edit_string(ctx, ZR_EDIT_CURSOR, text[6], &text_len[6], 64, zr_filter_binary); + + zr_label(ctx, "Password:", ZR_TEXT_LEFT); + { + size_t i = 0; + size_t old_len = text_len[8]; + char buffer[64]; + for (i = 0; i < text_len[8]; ++i) buffer[i] = '*'; + zr_edit_string(ctx, ZR_EDIT_SIMPLE, buffer, &text_len[8], 64, zr_filter_default); + if (old_len < text_len[8]) + memcpy(&text[8][old_len], &buffer[old_len], text_len[8] - old_len); + } + + zr_label(ctx, "Field:", ZR_TEXT_LEFT); + zr_edit_string(ctx, ZR_EDIT_FIELD, field_buffer, &field_len, 64, zr_filter_default); + + zr_label(ctx, "Box:", ZR_TEXT_LEFT); + zr_layout_row_static(ctx, 75, 278, 1); + zr_edit_string(ctx, ZR_EDIT_BOX, box_buffer, &box_len, 64, zr_filter_default); + + zr_layout_row(ctx, ZR_STATIC, 25, 2, ratio); + active = zr_edit_string(ctx, ZR_EDIT_FIELD, text[7], &text_len[7], 64, zr_filter_ascii); + if (zr_button_text(ctx, "Submit", ZR_BUTTON_DEFAULT) + ||(active && zr_input_is_key_pressed(&ctx->input, ZR_KEY_ENTER))) { + text[7][text_len[7]] = '\n'; + text_len[7]++; + memcpy(&box_buffer[box_len], &text[7], text_len[7]); + box_len += text_len[7]; + text_len[7] = 0; + } + + zr_layout_row_end(ctx); + zr_layout_pop(ctx); + } + zr_layout_pop(ctx); } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Basic", &main_state)) + if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Graph")) { - /* Basic widgets */ - static int int_slider = 5; - static float float_slider = 2.5f; - static size_t prog_value = 40; - static float float_spinner = 2.5f; - static int int_spinner = 20; + float id = 0; + static int col_index = -1; + static int line_index = -1; + float step = (2*3.141592654f) / 32; - static float property_float = 2; - static int property_int = 10; - - static const float ratio[] = {120, 150}; - const struct zr_input *in = zr_input(&layout); + int i; + int index = -1; struct zr_rect bounds; - struct zr_color color; - zr_layout_row_static(&layout, 30, 100, 1); - zr_checkbox(&layout, "Checkbox", &checkbox); + /* column graph */ + zr_layout_row_dynamic(ctx, 100, 1); + zr_layout_peek(&bounds, ctx); + zr_graph_begin(ctx, ZR_GRAPH_COLUMN, 32, 0.0f, 1.0f); + for (i = 0; i < 32; ++i) { + zr_flags res = zr_graph_push(ctx, (float)fabs(sin(id))); + if (res & ZR_GRAPH_HOVERING) + index = (int)i; + if (res & ZR_GRAPH_CLICKED) + col_index = (int)i; + id += step; + } + zr_graph_end(ctx); - zr_layout_row_static(&layout, 30, 80, 3); - option = zr_option(&layout, "optionA", option == A) ? A : option; - option = zr_option(&layout, "optionB", option == B) ? B : option; - option = zr_option(&layout, "optionC", option == C) ? C : option; + if (index != -1) { + char buffer[ZR_MAX_NUMBER_BUFFER]; + sprintf(buffer, "Value: %.2f", (float)fabs(sin(step * (float)index))); + zr_tooltip(ctx, buffer); + } + if (col_index != -1) { + zr_layout_row_dynamic(ctx, 20, 1); + zr_labelf(ctx, ZR_TEXT_LEFT, "Selected value: %.2f", (float)fabs(sin(step * (float)col_index))); + } - zr_layout_row_static(&layout, 30, 150, 1); - zr_layout_peek(&bounds, &layout); - zr_label(&layout, "Hover me for tooltip", ZR_TEXT_LEFT); - if (zr_input_is_mouse_hovering_rect(in, bounds)) - zr_tooltip(&layout, "This is a tooltip"); + /* line graph */ + id = 0; + index = -1; + zr_layout_row_dynamic(ctx, 100, 1); + zr_layout_peek(&bounds, ctx); + zr_graph_begin(ctx, ZR_GRAPH_LINES, 32, -1.0f, 1.0f); + for (i = 0; i < 32; ++i) { + zr_flags res = zr_graph_push(ctx, (float)cos(id)); + if (res & ZR_GRAPH_HOVERING) + index = (int)i; + if (res & ZR_GRAPH_CLICKED) + line_index = (int)i; + id += step; + } + zr_graph_end(ctx); - zr_layout_row(&layout, ZR_STATIC, 30, 2, ratio); - zr_labelf(&layout, ZR_TEXT_LEFT, "Slider int"); - zr_slider_int(&layout, 0, &int_slider, 10, 1); - - zr_label(&layout, "Slider float", ZR_TEXT_LEFT); - zr_slider_float(&layout, 0, &float_slider, 5.0, 0.5f); - zr_labelf(&layout, ZR_TEXT_LEFT, "Progressbar" , prog_value); - zr_progress(&layout, &prog_value, 100, ZR_MODIFIABLE); - - zr_label(&layout, "Property float:", ZR_TEXT_LEFT); - zr_property_float(&layout, "Float:", 0, &property_float, 64.0f, 0.1f, 0.2f); - zr_label(&layout, "Property int:", ZR_TEXT_LEFT); - zr_property_int(&layout, "Int:", 0, &property_int, 100.0f, 1, 1); - zr_layout_pop(&layout); + if (index != -1) { + char buffer[ZR_MAX_NUMBER_BUFFER]; + float val = (float)cos((float)index*step); + sprintf(buffer, "Value: %.2f", val); + zr_tooltip(ctx, buffer); + } + if (line_index != -1) { + zr_layout_row_dynamic(ctx, 20, 1); + zr_labelf(ctx, ZR_TEXT_LEFT, "Selected value: %.2f", (float)cos((float)index*step)); + } + zr_layout_pop(ctx); } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Selectable", &sel_state)) + if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Group")) { - static int basic_state = ZR_MINIMIZED; - static int list_state = ZR_MINIMIZED; - static int grid_state = ZR_MINIMIZED; - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Basic", &basic_state)) - { - zr_layout_row_static(&layout, 18, 100, 2); - zr_select(&layout, "Selected", ZR_TEXT_LEFT, zr_true); - zr_select(&layout, "Not Selected", ZR_TEXT_LEFT, zr_false); - zr_layout_pop(&layout); - } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "List", &list_state)) - { - static int selected[4] = {zr_false, zr_false, zr_true, zr_false}; - zr_layout_row_static(&layout, 18, 100, 1); - zr_selectable(&layout, "Selectable", ZR_TEXT_LEFT, &selected[0]); - zr_selectable(&layout, "Selectable", ZR_TEXT_LEFT, &selected[1]); - zr_label(&layout, "Not Selectable", ZR_TEXT_LEFT); - zr_selectable(&layout, "Selectable", ZR_TEXT_LEFT, &selected[2]); - zr_selectable(&layout, "Selectable", ZR_TEXT_LEFT, &selected[3]); - zr_layout_pop(&layout); - } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Grid", &grid_state)) - { - int i; + static int group_titlebar = zr_false; + static int group_border = zr_true; + static int group_no_scrollbar = zr_false; + static int group_width = 320; + static int group_height = 200; + struct zr_layout tab; + + zr_flags group_flags = 0; + if (group_border) group_flags |= ZR_WINDOW_BORDER; + if (group_no_scrollbar) group_flags |= ZR_WINDOW_NO_SCROLLBAR; + if (group_titlebar) group_flags |= ZR_WINDOW_TITLE; + + zr_layout_row_dynamic(ctx, 30, 3); + zr_checkbox(ctx, "Titlebar", &group_titlebar); + zr_checkbox(ctx, "Border", &group_border); + zr_checkbox(ctx, "No Scrollbar", &group_no_scrollbar); + + zr_layout_row_begin(ctx, ZR_STATIC, 30, 2); + zr_layout_row_push(ctx, 50); + zr_label(ctx, "size:", ZR_TEXT_LEFT); + zr_layout_row_push(ctx, 130); + zr_property_int(ctx, "#Width:", 100, &group_width, 500, 10, 1); + zr_layout_row_push(ctx, 130); + zr_property_int(ctx, "#Height:", 100, &group_height, 500, 10, 1); + zr_layout_row_end(ctx); + + zr_layout_row_static(ctx, (float)group_height, (size_t)group_width, 2); + if (zr_group_begin(ctx, &tab, "Group", group_flags)) { + int i = 0; static int selected[16]; - zr_layout_row_static(&layout, 50, 50, 4); - for (i = 0; i < 16; ++i) { - if (zr_selectable(&layout, "Z", ZR_TEXT_CENTERED, &selected[i])) { - int x = (i % 4), y = i / 4; - if (x > 0) selected[i - 1] ^= 1; - if (x < 3) selected[i + 1] ^= 1; - if (y > 0) selected[i - 4] ^= 1; - if (y < 3) selected[i + 4] ^= 1; - } + zr_layout_row_static(ctx, 18, 100, 1); + for (i = 0; i < 16; ++i) + zr_selectable(ctx, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]); + zr_group_end(ctx); + } + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_TAB, "Splitter")) + { + const struct zr_input *in = &ctx->input; + zr_layout_row_static(ctx, 20, 320, 1); + zr_label(ctx, "Use slider and spinner to change tile size", ZR_TEXT_LEFT); + zr_label(ctx, "Drag the space between tiles to change tile ratio", ZR_TEXT_LEFT); + + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Vertical")) + { + static float a = 100, b = 100, c = 100; + struct zr_rect bounds; + struct zr_layout sub; + + float row_layout[5]; + row_layout[0] = a; + row_layout[1] = 8; + row_layout[2] = b; + row_layout[3] = 8; + row_layout[4] = c; + + /* header */ + zr_layout_row_static(ctx, 30, 100, 2); + zr_label(ctx, "left:", ZR_TEXT_LEFT); + zr_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f); + + zr_label(ctx, "middle:", ZR_TEXT_LEFT); + zr_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f); + + zr_label(ctx, "right:", ZR_TEXT_LEFT); + zr_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f); + + /* tiles */ + zr_layout_row(ctx, ZR_STATIC, 200, 5, row_layout); + zr_style_push_property(&ctx->style, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); + + /* left space */ + if (zr_group_begin(ctx, &sub, "left", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) { + /* TODO: group content */ + zr_group_end(ctx); } - zr_layout_pop(&layout); - } - zr_layout_pop(&layout); - } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Combo", &combo_state)) - { - /* Combobox Widgets */ - static int weapon_active = zr_false; - static int com_color_active = zr_false; - static int prog_active = zr_false; - static int check_active = zr_false; - static const float values[]={8.0f,15.0f,20.0f,30.0f,35.0f,40.0f}; - static float graph_selection = 8.0f; - static int graph_active = 0; - static const char *weapons[] = {"Fist","Pistol","Shotgun","Plasma","BFG"}; - static size_t current_weapon = 0; - static int check_values[5]; - static struct zr_color combo_color = {130, 50, 50, 255}; - static size_t x = 20, y = 40, z = 10, w = 90; - - struct zr_context combo; - char buffer[32]; - size_t sum = 0; - - /* default combobox */ - zr_layout_row_static(&layout, 30, 200, 1); - zr_combo_begin_text(&layout, &combo, weapons[current_weapon], &weapon_active, 200, 0); - { - size_t i = 0; - zr_layout_row_dynamic(&combo, 25, 1); - for (i = 0; i < LEN(weapons); ++i) { - if (zr_combo_item(&combo, weapons[i], ZR_TEXT_LEFT)) - current_weapon = i; + /* scaler */ + zr_layout_peek(&bounds, ctx); + zr_spacing(ctx, 1); + if ((zr_input_is_mouse_hovering_rect(in, bounds) || + zr_input_is_mouse_prev_hovering_rect(in, bounds)) && + zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) + { + a = row_layout[0] + in->mouse.delta.x; + b = row_layout[2] - in->mouse.delta.x; } - } - zr_combo_end(&layout, &combo, &weapon_active, 0); - /* slider color combobox */ - zr_combo_begin_color(&layout, &combo, combo_color, &com_color_active, 200, 0); - { - float ratios[] = {0.15f, 0.85f}; - zr_layout_row(&combo, ZR_DYNAMIC, 30, 2, ratios); - zr_label(&combo, "R", ZR_TEXT_LEFT); - combo_color.r = (zr_byte)zr_slide_int(&combo, 0, combo_color.r, 255, 5); - zr_label(&combo, "G", ZR_TEXT_LEFT); - combo_color.g = (zr_byte)zr_slide_int(&combo, 0, combo_color.g, 255, 5); - zr_label(&combo, "B", ZR_TEXT_LEFT); - combo_color.b = (zr_byte)zr_slide_int(&combo, 0, combo_color.b, 255, 5); - zr_label(&combo, "A", ZR_TEXT_LEFT); - combo_color.a = (zr_byte)zr_slide_int(&combo, 0, combo_color.a , 255, 5); - } - zr_combo_end(&layout, &combo, NULL, 0); - - /* progressbar combobox */ - sum = x + y + z + w; - sprintf(buffer, "%lu", sum); - zr_combo_begin_text(&layout, &combo, buffer, &prog_active, 200, 0); - { - zr_layout_row_dynamic(&combo, 30, 1); - zr_progress(&combo, &x, 100, ZR_MODIFIABLE); - zr_progress(&combo, &y, 100, ZR_MODIFIABLE); - zr_progress(&combo, &z, 100, ZR_MODIFIABLE); - zr_progress(&combo, &w, 100, ZR_MODIFIABLE); - } - zr_combo_end(&layout, &combo, NULL, 0); - - /* checkbox combobox */ - sum = (size_t)(check_values[0] + check_values[1] + check_values[2] + check_values[3] + check_values[4]); - sprintf(buffer, "%lu", sum); - zr_combo_begin_text(&layout, &combo, buffer, &check_active, 200, 0); - { - zr_layout_row_dynamic(&combo, 30, 1); - zr_checkbox(&combo, weapons[0], &check_values[0]); - zr_checkbox(&combo, weapons[1], &check_values[1]); - zr_checkbox(&combo, weapons[2], &check_values[2]); - zr_checkbox(&combo, weapons[3], &check_values[3]); - } - zr_combo_end(&layout, &combo, NULL, 0); - - /* graph combobox */ - sprintf(buffer, "%.1f", graph_selection); - zr_combo_begin_text(&layout, &combo, buffer, &graph_active, 200, 0); - { - size_t i = 0; - struct zr_graph graph; - zr_layout_row_dynamic(&combo, 120, 1); - zr_graph_begin(&combo, &graph, ZR_GRAPH_COLUMN, LEN(values), 0, 50); - for (i = 0; i < LEN(values); ++i) { - zr_flags res = zr_graph_push(&combo, &graph, values[i]); - if (res & ZR_GRAPH_CLICKED) { - graph_selection = values[i]; - zr_combo_close(&combo, &graph_active); - } + /* middle space */ + if (zr_group_begin(ctx, &sub, "center", ZR_WINDOW_BORDER)) { + /* TODO: group content */ + zr_group_end(ctx); } - zr_graph_end(&combo, &graph); - } - zr_combo_end(&layout, &combo, NULL, 0); - zr_layout_pop(&layout); - } - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Input", &input_state)) - { - static char field_buffer[64]; - static char box_buffer[512]; - static char text[9][64]; - static size_t text_len[9]; - static int text_active[9]; - static size_t text_cursor[8]; - static const float ratio[] = {120, 100}; - static struct zr_edit_box box; - static struct zr_edit_box field; - static int input_init = 0; - if (!input_init) + /* scaler */ + zr_layout_peek(&bounds, ctx); + zr_spacing(ctx, 1); + if ((zr_input_is_mouse_hovering_rect(in, bounds) || + zr_input_is_mouse_prev_hovering_rect(in, bounds)) && + zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) + { + b = (row_layout[2] + in->mouse.delta.x); + c = (row_layout[4] - in->mouse.delta.x); + } + + /* right space */ + if (zr_group_begin(ctx, &sub, "right", ZR_WINDOW_BORDER)) { + /* TODO: group content */ + zr_group_end(ctx); + } + + zr_style_pop_property(&ctx->style); + zr_layout_pop(ctx); + } + + if (zr_layout_push(ctx, ZR_LAYOUT_NODE, "Horizontal")) { - struct zr_clipboard clip; - clip.userdata.ptr = 0; - clip.paste = paste_callback; - clip.copy = copy_callback; - zr_edit_box_init_fixed(&field, field_buffer, sizeof(field_buffer), &clip, 0); - zr_edit_box_init_fixed(&box, box_buffer, sizeof(box_buffer), &clip, 0); - input_init = 1; + static float a = 100, b = 100, c = 100; + struct zr_layout sub; + struct zr_rect bounds; + + /* header */ + zr_layout_row_static(ctx, 30, 100, 2); + zr_label(ctx, "top:", ZR_TEXT_LEFT); + zr_slider_float(ctx, 10.0f, &a, 200.0f, 10.0f); + + zr_label(ctx, "middle:", ZR_TEXT_LEFT); + zr_slider_float(ctx, 10.0f, &b, 200.0f, 10.0f); + + zr_label(ctx, "bottom:", ZR_TEXT_LEFT); + zr_slider_float(ctx, 10.0f, &c, 200.0f, 10.0f); + + zr_style_push_property(&ctx->style, ZR_PROPERTY_ITEM_SPACING, zr_vec2(4, 0)); + + /* top space */ + zr_layout_row_dynamic(ctx, a, 1); + if (zr_group_begin(ctx, &sub, "top", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) { + /* TODO: group content */ + zr_group_end(ctx); + } + + /* scaler */ + zr_layout_row_dynamic(ctx, 8, 1); + zr_layout_peek(&bounds, ctx); + zr_spacing(ctx, 1); + if ((zr_input_is_mouse_hovering_rect(in, bounds) || + zr_input_is_mouse_prev_hovering_rect(in, bounds)) && + zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) + { + a = a + in->mouse.delta.y; + b = b - in->mouse.delta.y; + } + + /* middle space */ + zr_layout_row_dynamic(ctx, b, 1); + if (zr_group_begin(ctx, &sub, "middle", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) { + /* TODO: group content */ + zr_group_end(ctx); + } + + /* scaler */ + zr_layout_row_dynamic(ctx, 8, 1); + zr_layout_peek(&bounds, ctx); + zr_spacing(ctx, 1); + if ((zr_input_is_mouse_hovering_rect(in, bounds) || + zr_input_is_mouse_prev_hovering_rect(in, bounds)) && + zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) + { + b = b + in->mouse.delta.y; + c = c - in->mouse.delta.y; + } + + /* bottom space */ + zr_layout_row_dynamic(ctx, c, 1); + if (zr_group_begin(ctx, &sub, "bottom", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER)) { + /* TODO: group content */ + zr_group_end(ctx); + } + + zr_style_pop_property(&ctx->style); + zr_layout_pop(ctx); } - - zr_layout_row(&layout, ZR_STATIC, 25, 2, ratio); - zr_label(&layout, "Default:", ZR_TEXT_LEFT); - zr_edit(&layout, text[0], &text_len[0], 64, &text_active[0], &text_cursor[0], ZR_INPUT_DEFAULT); - zr_label(&layout, "Int:", ZR_TEXT_LEFT); - zr_edit(&layout, text[1], &text_len[1], 64, &text_active[1], &text_cursor[1], ZR_INPUT_DEC); - zr_label(&layout, "Float:", ZR_TEXT_LEFT); - zr_edit(&layout, text[2], &text_len[2], 64, &text_active[2], &text_cursor[2], ZR_INPUT_FLOAT); - zr_label(&layout, "Hex:", ZR_TEXT_LEFT); - zr_edit(&layout, text[4], &text_len[4], 64, &text_active[4], &text_cursor[4], ZR_INPUT_HEX); - zr_label(&layout, "Octal:", ZR_TEXT_LEFT); - zr_edit(&layout, text[5], &text_len[5], 64, &text_active[5], &text_cursor[5], ZR_INPUT_OCT); - zr_label(&layout, "Binary:", ZR_TEXT_LEFT); - zr_edit(&layout, text[6], &text_len[6], 64, &text_active[6], &text_cursor[6], ZR_INPUT_BIN); - zr_label(&layout, "Field:", ZR_TEXT_LEFT); - zr_edit_field(&layout, &field); - zr_label(&layout, "Password:", ZR_TEXT_LEFT); - { - size_t i = 0; - size_t old_len = text_len[8]; - char buffer[16]; - for (i = 0; i < text_len[8]; ++i) - buffer[i] = '*'; - zr_edit(&layout, buffer, &text_len[8], 64, &text_active[8], NULL, ZR_INPUT_DEFAULT); - if (old_len < text_len[8]) - memcpy(&text[8][old_len], &buffer[old_len], text_len[8] - old_len); - } - - zr_label(&layout, "Box:", ZR_TEXT_LEFT); - zr_layout_row_static(&layout, 75, 228, 1); - zr_edit_box(&layout, &box, ZR_MODIFIABLE); - - zr_layout_row(&layout, ZR_STATIC, 25, 2, ratio); - zr_edit(&layout, text[7], &text_len[7], 64, &text_active[7], &text_cursor[7], ZR_INPUT_ASCII); - if (zr_button_text(&layout, "Submit", ZR_BUTTON_DEFAULT) - ||(text_active[7] && zr_input_is_key_pressed(window->input, ZR_KEY_ENTER))) { - - text[7][text_len[7]] = '\n'; - text_len[7]++; - zr_edit_box_add(&box, text[7], text_len[7]); - text_active[7] = 0; - text_cursor[7] = 0; - text_len[7] = 0; - } - - zr_layout_row_end(&layout); - zr_layout_pop(&layout); + zr_layout_pop(ctx); } - zr_layout_pop(&layout); } - - if (zr_layout_push(&layout, ZR_LAYOUT_TAB, "Graph", &graph_state)) - { - static const float values[]={8.0f,15.0f,20.0f,12.0f,30.0f,12.0f,35.0f,40.0f,20.0f}; - static int col_index = -1; - static int line_index = -1; - - size_t i; - float min_value; - float max_value; - int index = -1; - struct zr_rect bounds; - struct zr_graph graph; - char buffer[64]; - - /* find min and max graph value */ - max_value = values[0]; - min_value = values[0]; - for (i = 0; i < LEN(values); ++i) { - if (values[i] > max_value) - max_value = values[i]; - if (values[i] < min_value) - min_value = values[i]; - } - - /* column graph */ - zr_layout_row_dynamic(&layout, 100, 1); - zr_layout_peek(&bounds, &layout); - zr_graph_begin(&layout, &graph, ZR_GRAPH_COLUMN, LEN(values), min_value, max_value); - for (i = 0; i < LEN(values); ++i) { - zr_flags res = zr_graph_push(&layout, &graph, values[i]); - if (res & ZR_GRAPH_HOVERING) - index = (int)i; - if (res & ZR_GRAPH_CLICKED) - col_index = (int)i; - } - zr_graph_end(&layout, &graph); - - if (index != -1) { - sprintf(buffer, "Value: %.2f", values[index]); - zr_tooltip(&layout, buffer); - } - if (col_index != -1) { - zr_layout_row_dynamic(&layout, 20, 1); - zr_labelf(&layout, ZR_TEXT_LEFT, "Selected value: %.2f", values[col_index]); - } - - /* line graph */ - index = -1; - zr_layout_row_dynamic(&layout, 100, 1); - zr_layout_peek(&bounds, &layout); - zr_graph_begin(&layout, &graph, ZR_GRAPH_LINES, LEN(values), min_value, max_value); - for (i = 0; i < LEN(values); ++i) { - zr_flags res = zr_graph_push(&layout, &graph, values[i]); - if (res & ZR_GRAPH_HOVERING) - index = (int)i; - if (res & ZR_GRAPH_CLICKED) - line_index = (int)i; - } - zr_graph_end(&layout, &graph); - - if (index != -1) { - sprintf(buffer, "Value: %.2f", values[index]); - zr_tooltip(&layout, buffer); - } - if (line_index != -1) { - zr_layout_row_dynamic(&layout, 20, 1); - zr_labelf(&layout, ZR_TEXT_LEFT, "Selected value: %.2f", values[line_index]); - } - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_TAB, "Group", &group_state)) - { - static int group_titlebar = zr_false; - static int group_border = zr_true; - static int group_no_scrollbar = zr_false; - static int group_width = 320; - static int group_height = 200; - static struct zr_vec2 scrollbar; - struct zr_context tab; - - zr_flags group_flags = 0; - if (group_border) group_flags |= ZR_WINDOW_BORDER; - if (group_no_scrollbar) group_flags |= ZR_WINDOW_NO_SCROLLBAR; - - zr_layout_row_dynamic(&layout, 30, 3); - zr_checkbox(&layout, "Titlebar", &group_titlebar); - zr_checkbox(&layout, "Border", &group_border); - zr_checkbox(&layout, "No Scrollbar", &group_no_scrollbar); - - zr_layout_row_begin(&layout, ZR_STATIC, 30, 2); - zr_layout_row_push(&layout, 50); - zr_label(&layout, "size:", ZR_TEXT_LEFT); - zr_layout_row_push(&layout, 130); - zr_property_int(&layout, "#Width:", 100, &group_width, 500, 10, 1); - zr_layout_row_push(&layout, 130); - zr_property_int(&layout, "#Height:", 100, &group_height, 500, 10, 1); - zr_layout_row_end(&layout); - - zr_layout_row_static(&layout, (float)group_height, (size_t)group_width, 2); - zr_group_begin(&layout, &tab, group_titlebar ? "Group" : NULL, group_flags, scrollbar); - { - int i = 0; - static int selected[16]; - zr_layout_row_static(&tab, 18, 100, 1); - for (i = 0; i < 16; ++i) - zr_selectable(&tab, (selected[i]) ? "Selected": "Unselected", ZR_TEXT_CENTERED, &selected[i]); - } - zr_group_end(&layout, &tab, &scrollbar); - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_TAB, "Splitter", &splitter_state)) - { - static int vertical_state = ZR_MINIMIZED; - static int horizontal_state = ZR_MINIMIZED; - const struct zr_input *in = window->input; - - zr_layout_row_static(&layout, 20, 320, 1); - zr_label(&layout, "Use slider and spinner to change tile size", ZR_TEXT_LEFT); - zr_label(&layout, "Drag the space between tiles to change tile ratio", ZR_TEXT_LEFT); - - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Vertical", &vertical_state)) - { - static float a = 100, b = 100, c = 100; - struct zr_rect bounds; - struct zr_context sub; - - float row_layout[5]; - row_layout[0] = a; - row_layout[1] = 8; - row_layout[2] = b; - row_layout[3] = 8; - row_layout[4] = c; - - /* header */ - zr_layout_row_static(&layout, 30, 100, 2); - zr_label(&layout, "left:", ZR_TEXT_LEFT); - zr_slider_float(&layout, 10.0f, &a, 200.0f, 10.0f); - - zr_label(&layout, "middle:", ZR_TEXT_LEFT); - zr_slider_float(&layout, 10.0f, &b, 200.0f, 10.0f); - - zr_label(&layout, "right:", ZR_TEXT_LEFT); - zr_slider_float(&layout, 10.0f, &c, 200.0f, 10.0f); - - /* tiles */ - zr_layout_row(&layout, ZR_STATIC, 200, 5, row_layout); - zr_style_push_property(config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); - - /* left space */ - zr_group_begin(&layout, &sub, NULL, ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, zr_vec2(0,0)); - zr_group_end(&layout, &sub, NULL); - - /* scaler */ - zr_layout_peek(&bounds, &layout); - zr_spacing(&layout, 1); - if ((zr_input_is_mouse_hovering_rect(in, bounds) || - zr_input_is_mouse_prev_hovering_rect(in, bounds)) && - zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) - { - a = row_layout[0] + in->mouse.delta.x; - b = row_layout[2] - in->mouse.delta.x; - } - - /* middle space */ - zr_group_begin(&layout, &sub, NULL, ZR_WINDOW_BORDER, zr_vec2(0,0)); - zr_group_end(&layout, &sub, NULL); - - /* scaler */ - zr_layout_peek(&bounds, &layout); - zr_spacing(&layout, 1); - if ((zr_input_is_mouse_hovering_rect(in, bounds) || - zr_input_is_mouse_prev_hovering_rect(in, bounds)) && - zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) - { - b = (row_layout[2] + in->mouse.delta.x); - c = (row_layout[4] - in->mouse.delta.x); - } - - /* right space */ - zr_group_begin(&layout, &sub, NULL, ZR_WINDOW_BORDER, zr_vec2(0,0)); - zr_group_end(&layout, &sub, NULL); - - zr_style_pop_property(config); - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Horizontal", &horizontal_state)) - { - static float a = 100, b = 100, c = 100; - static int a_active, b_active, c_active; - struct zr_context sub; - struct zr_rect bounds; - - /* header */ - zr_layout_row_static(&layout, 30, 100, 2); - zr_label(&layout, "top:", ZR_TEXT_LEFT); - zr_slider_float(&layout, 10.0f, &a, 200.0f, 10.0f); - - zr_label(&layout, "middle:", ZR_TEXT_LEFT); - zr_slider_float(&layout, 10.0f, &b, 200.0f, 10.0f); - - zr_label(&layout, "bottom:", ZR_TEXT_LEFT); - zr_slider_float(&layout, 10.0f, &c, 200.0f, 10.0f); - - zr_style_push_property(config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(4, 0)); - - /* top space */ - zr_layout_row_dynamic(&layout, a, 1); - zr_group_begin(&layout, &sub, NULL, ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, zr_vec2(0,0)); - zr_group_end(&layout, &sub, NULL); - - /* scaler */ - zr_layout_row_dynamic(&layout, 8, 1); - zr_layout_peek(&bounds, &layout); - zr_spacing(&layout, 1); - if ((zr_input_is_mouse_hovering_rect(in, bounds) || - zr_input_is_mouse_prev_hovering_rect(in, bounds)) && - zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) - { - a = a + in->mouse.delta.y; - b = b - in->mouse.delta.y; - } - - /* middle space */ - zr_layout_row_dynamic(&layout, b, 1); - zr_group_begin(&layout, &sub, NULL, ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, zr_vec2(0,0)); - zr_group_end(&layout, &sub, NULL); - - /* scaler */ - zr_layout_row_dynamic(&layout, 8, 1); - zr_layout_peek(&bounds, &layout); - zr_spacing(&layout, 1); - if ((zr_input_is_mouse_hovering_rect(in, bounds) || - zr_input_is_mouse_prev_hovering_rect(in, bounds)) && - zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) - { - b = b + in->mouse.delta.y; - c = c - in->mouse.delta.y; - } - - /* bottom space */ - zr_layout_row_dynamic(&layout, c, 1); - zr_group_begin(&layout, &sub, NULL, ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, zr_vec2(0,0)); - zr_group_end(&layout, &sub, NULL); - - zr_style_pop_property(config); - zr_layout_pop(&layout); - } - zr_layout_pop(&layout); - } - zr_end(&layout, window); - return 1; + zr_end(ctx); + return !zr_window_is_closed(ctx, "Demo"); } -static void -init_demo(struct demo *gui) -{ - gui->running = zr_true; - - /* themes */ - zr_style_default(&gui->config_black, ZR_DEFAULT_ALL, &gui->font); - zr_style_default(&gui->config_white, ZR_DEFAULT_ALL, &gui->font); - - gui->config_white.colors[ZR_COLOR_TEXT] = zr_rgba(70, 70, 70, 255); - gui->config_white.colors[ZR_COLOR_TEXT_HOVERING] = zr_rgba(10, 10, 10, 255); - gui->config_white.colors[ZR_COLOR_TEXT_ACTIVE] = zr_rgba(20, 20, 20, 255); - gui->config_white.colors[ZR_COLOR_WINDOW] = zr_rgba(175, 175, 175, 255); - gui->config_white.colors[ZR_COLOR_HEADER] = zr_rgba(175, 175, 175, 255); - gui->config_white.colors[ZR_COLOR_BORDER] = zr_rgba(0, 0, 0, 255); - gui->config_white.colors[ZR_COLOR_BUTTON] = zr_rgba(185, 185, 185, 255); - gui->config_white.colors[ZR_COLOR_BUTTON_HOVER] = zr_rgba(170, 170, 170, 255); - gui->config_white.colors[ZR_COLOR_BUTTON_ACTIVE] = zr_rgba(160, 160, 160, 255); - gui->config_white.colors[ZR_COLOR_TOGGLE] = zr_rgba(150, 150, 150, 255); - gui->config_white.colors[ZR_COLOR_TOGGLE_HOVER] = zr_rgba(120, 120, 120, 255); - gui->config_white.colors[ZR_COLOR_TOGGLE_CURSOR] = zr_rgba(175, 175, 175, 255); - gui->config_white.colors[ZR_COLOR_SELECTABLE] = zr_rgba(190, 190, 190, 255); - gui->config_white.colors[ZR_COLOR_SELECTABLE_HOVER] = zr_rgba(150, 150, 150, 255); - gui->config_white.colors[ZR_COLOR_SELECTABLE_TEXT] = zr_rgba(70, 70, 70, 255); - gui->config_white.colors[ZR_COLOR_SLIDER] = zr_rgba(190, 190, 190, 255); - gui->config_white.colors[ZR_COLOR_SLIDER_CURSOR] = zr_rgba(80, 80, 80, 255); - gui->config_white.colors[ZR_COLOR_SLIDER_CURSOR_HOVER] = zr_rgba(70, 70, 70, 255); - gui->config_white.colors[ZR_COLOR_SLIDER_CURSOR_ACTIVE] = zr_rgba(60, 60, 60, 255); - gui->config_white.colors[ZR_COLOR_PROGRESS] = zr_rgba(190, 190, 190, 255); - gui->config_white.colors[ZR_COLOR_PROGRESS_CURSOR] = zr_rgba(80, 80, 80, 255); - gui->config_white.colors[ZR_COLOR_PROGRESS_CURSOR_HOVER] = zr_rgba(70, 70, 70, 255); - gui->config_white.colors[ZR_COLOR_PROGRESS_CURSOR_ACTIVE] = zr_rgba(60, 60, 60, 255); - gui->config_white.colors[ZR_COLOR_PROPERTY] = zr_rgba(150, 150, 150, 255); - gui->config_white.colors[ZR_COLOR_PROPERTY_HOVER] = zr_rgba(160, 160, 160, 255); - gui->config_white.colors[ZR_COLOR_PROPERTY_ACTIVE] = zr_rgba(165, 165, 165, 255); - gui->config_white.colors[ZR_COLOR_INPUT] = zr_rgba(150, 150, 150, 255); - gui->config_white.colors[ZR_COLOR_INPUT_CURSOR] = zr_rgba(0, 0, 0, 255); - gui->config_white.colors[ZR_COLOR_INPUT_TEXT] = zr_rgba(0, 0, 0, 255); - gui->config_white.colors[ZR_COLOR_COMBO] = zr_rgba(175, 175, 175, 255); - gui->config_white.colors[ZR_COLOR_HISTO] = zr_rgba(160, 160, 160, 255); - gui->config_white.colors[ZR_COLOR_HISTO_BARS] = zr_rgba(45, 45, 45, 255); - gui->config_white.colors[ZR_COLOR_HISTO_NEGATIVE] = zr_rgba(255, 255, 255, 255); - gui->config_white.colors[ZR_COLOR_HISTO_HIGHLIGHT] = zr_rgba( 255, 0, 0, 255); - gui->config_white.colors[ZR_COLOR_PLOT] = zr_rgba(160, 160, 160, 255); - gui->config_white.colors[ZR_COLOR_PLOT_LINES] = zr_rgba(45, 45, 45, 255); - gui->config_white.colors[ZR_COLOR_PLOT_HIGHLIGHT] = zr_rgba(255, 0, 0, 255); - gui->config_white.colors[ZR_COLOR_SCROLLBAR] = zr_rgba(180, 180, 180, 255); - gui->config_white.colors[ZR_COLOR_SCROLLBAR_CURSOR] = zr_rgba(140, 140, 140, 255); - gui->config_white.colors[ZR_COLOR_SCROLLBAR_CURSOR_HOVER] = zr_rgba(150, 150, 150, 255); - gui->config_white.colors[ZR_COLOR_SCROLLBAR_CURSOR_ACTIVE] = zr_rgba(160, 160, 160, 255); - gui->config_white.colors[ZR_COLOR_TABLE_LINES] = zr_rgba(100, 100, 100, 255); - gui->config_white.colors[ZR_COLOR_TAB_HEADER] = zr_rgba(180, 180, 180, 255); - gui->config_white.colors[ZR_COLOR_SCALER] = zr_rgba(100, 100, 100, 255); - - /* windows */ - zr_window_init(&gui->panel, zr_rect(30, 30, 400, 600), - ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_SCALEABLE| - ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE, - &gui->queue, &gui->config_black, &gui->input); - zr_window_init(&gui->sub, zr_rect(400, 50, 220, 180), - ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_SCALEABLE| - ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE|ZR_WINDOW_HIDDEN, - &gui->queue, &gui->config_black, &gui->input); - zr_window_init(&gui->metrics, zr_rect(200, 400, 250, 300), - ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_SCALEABLE| - ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE|ZR_WINDOW_HIDDEN, - &gui->queue, &gui->config_black, &gui->input); - -} - -static void +static int run_demo(struct demo *gui) { - struct zr_context layout; - struct zr_style *current = (gui->theme == THEME_BLACK) ? &gui->config_black : &gui->config_white; - gui->running = show_test_window(&gui->panel, current, &gui->theme, gui); + static enum theme theme = THEME_BLACK; + struct zr_layout layout; + struct zr_context *ctx = &gui->ctx; - /* ussage example */ - gui->sub.style = current; - zr_begin(&layout, &gui->sub, "Show"); + /* extensive demo window */ + if (!demo_window(&layout, ctx, &theme)) + return 0; + + /* simple demo window */ + if (zr_begin(ctx, &layout, "Show", zr_rect(20, 20, 200, 200), + ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_SCALEABLE| + ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE|ZR_WINDOW_TITLE)) { enum {EASY, HARD}; static int op = EASY; - static float value = 0.5f; - zr_layout_row_static(&layout, 30, 80, 1); - if (zr_button_text(&layout, "button", ZR_BUTTON_DEFAULT)) { + static int property = 20; + + zr_layout_row_static(ctx, 30, 80, 1); + if (zr_button_text(ctx, "button", ZR_BUTTON_DEFAULT)) { /* event handling */ } - zr_layout_row_dynamic(&layout, 30, 2); - if (zr_option(&layout, "easy", op == EASY)) op = EASY; - if (zr_option(&layout, "hard", op == HARD)) op = HARD; - zr_layout_row_begin(&layout, ZR_STATIC, 30, 2); - { - zr_layout_row_push(&layout, 50); - zr_label(&layout, "Volume:", ZR_TEXT_LEFT); - zr_layout_row_push(&layout, 110); - zr_slider_float(&layout, 0, &value, 1.0f, 0.1f); - } - zr_layout_row_end(&layout); + zr_layout_row_dynamic(ctx, 30, 2); + if (zr_option(ctx, "easy", op == EASY)) op = EASY; + if (zr_option(ctx, "hard", op == HARD)) op = HARD; + + zr_layout_row_dynamic(ctx, 30, 1); + zr_property_int(ctx, "Compression:", 0, &property, 100, 10, 1); } - zr_end(&layout, &gui->sub); + zr_end(ctx); /* metrics window */ - gui->metrics.style = current; - zr_begin(&layout, &gui->metrics, "Metrics"); + if (zr_begin(ctx, &layout, "Metrics", zr_rect(50, 600, 250, 300), + ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_SCALEABLE| + ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE)) { - static int prim_state = ZR_MINIMIZED; - static int mem_state = ZR_MINIMIZED; struct zr_memory_status status; - struct zr_command_stats *stats = &gui->panel.buffer.stats; - zr_buffer_info(&status, &gui->queue.buffer); + zr_buffer_info(&status, &ctx->memory); - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Memory", &mem_state)) - { - zr_layout_row_dynamic(&layout, 20, 2); - zr_label(&layout,"Total:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%lu", status.size); - zr_label(&layout,"Used:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%lu", status.allocated); - zr_label(&layout,"Required:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%lu", status.needed); - zr_label(&layout,"Calls:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%lu", status.calls); - zr_layout_pop(&layout); - } - - if (zr_layout_push(&layout, ZR_LAYOUT_NODE, "Primitives", &prim_state)) - { - zr_layout_row_dynamic(&layout, 25, 2); - zr_label(&layout,"Scissor:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->scissors); - zr_label(&layout,"Lines:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->lines); - zr_label(&layout,"Curves:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->curves); - zr_label(&layout,"Rectangles:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->rectangles); - zr_label(&layout,"Circles:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->circles); - zr_label(&layout,"Triangles:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->triangles); - zr_label(&layout,"Images:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->images); - zr_label(&layout,"Text:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->text); - zr_label(&layout,"glyphs:", ZR_TEXT_LEFT); - zr_labelf(&layout, ZR_TEXT_LEFT, "%u", stats->glyphs); - zr_layout_pop(&layout); - } + zr_layout_row_dynamic(ctx, 20, 2); + zr_label(ctx,"Total:", ZR_TEXT_LEFT); + zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", status.size); + zr_label(ctx,"Used:", ZR_TEXT_LEFT); + zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", status.allocated); + zr_label(ctx,"Required:", ZR_TEXT_LEFT); + zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", status.needed); + zr_label(ctx,"Calls:", ZR_TEXT_LEFT); + zr_labelf(ctx, ZR_TEXT_LEFT, "%lu", status.calls); } - zr_end(&layout, &gui->metrics); + zr_end(ctx); + return 1; } diff --git a/demo/glfw/glfw.c b/demo/glfw/glfw.c index 74dfd0c..3ad1291 100644 --- a/demo/glfw/glfw.c +++ b/demo/glfw/glfw.c @@ -84,18 +84,21 @@ file_load(const char* path, size_t* siz) } struct device { + struct zr_buffer cmds; + struct zr_draw_null_texture null; GLuint vbo, vao, ebo; + GLuint prog; GLuint vert_shdr; GLuint frag_shdr; + GLint attrib_pos; GLint attrib_uv; GLint attrib_col; + GLint uniform_tex; GLint uniform_proj; GLuint font_tex; - struct zr_draw_null_texture null; - struct zr_buffer cmds; }; static void @@ -280,12 +283,8 @@ device_shutdown(struct device *dev) glDeleteBuffers(1, &dev->ebo); } -/* this is stupid but needed for C89 since sinf and cosf do not exist */ -static float fsin(float f) {return (float)sin(f);} -static float fcos(float f) {return (float)cos(f);} - static void -device_draw(struct device *dev, struct zr_command_queue *queue, int width, int height, +device_draw(struct device *dev, struct zr_context *ctx, int width, int height, enum zr_anti_aliasing AA) { GLint last_prog, last_tex; @@ -307,7 +306,6 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo); /* setup global state */ - glViewport(0, 0, width, height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -323,13 +321,11 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h { /* convert from command queue into draw list and draw to screen */ - struct zr_draw_list draw_list; const struct zr_draw_command *cmd; void *vertexes, *elements; const zr_draw_index *offset = NULL; /* allocate vertex and element buffer */ - memset(&draw_list, 0, sizeof(draw_list)); glBindVertexArray(dev->vao); glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); @@ -344,15 +340,13 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h struct zr_buffer vbuf, ebuf; zr_buffer_init_fixed(&vbuf, vertexes, MAX_VERTEX_MEMORY); zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - zr_draw_list_init(&draw_list, &dev->cmds, &vbuf, &ebuf, - fsin, fcos, dev->null, AA); - zr_draw_list_load(&draw_list, queue, 1.0f, 22); + zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, dev->null, AA, 1.0f, 22); } glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); /* iterate over and execute each draw command */ - zr_foreach_draw_command(cmd, &draw_list) { + zr_draw_foreach(cmd, ctx, &dev->cmds) { if (!cmd->elem_count) continue; glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); glScissor((GLint)cmd->clip_rect.x, @@ -361,9 +355,7 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); offset += cmd->elem_count; } - - zr_command_queue_clear(queue); - zr_draw_list_clear(&draw_list); + zr_clear(ctx); } /* restore old state */ @@ -388,25 +380,25 @@ input_key(GLFWwindow *window, int key, int scancode, int action, int mods) UNUSED(window); UNUSED(scancode); if (key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_SHIFT) - zr_input_key(&gui.input, ZR_KEY_SHIFT, down); + zr_input_key(&gui.ctx.input, ZR_KEY_SHIFT, down); else if (key == GLFW_KEY_DELETE) - zr_input_key(&gui.input, ZR_KEY_DEL, down); + zr_input_key(&gui.ctx.input, ZR_KEY_DEL, down); else if (key == GLFW_KEY_ENTER) - zr_input_key(&gui.input, ZR_KEY_ENTER, down); + zr_input_key(&gui.ctx.input, ZR_KEY_ENTER, down); else if (key == GLFW_KEY_TAB) - zr_input_key(&gui.input, ZR_KEY_TAB, down); + zr_input_key(&gui.ctx.input, ZR_KEY_TAB, down); else if (key == GLFW_KEY_BACKSPACE) - zr_input_key(&gui.input, ZR_KEY_BACKSPACE, down); + zr_input_key(&gui.ctx.input, ZR_KEY_BACKSPACE, down); else if (key == GLFW_KEY_LEFT) - zr_input_key(&gui.input, ZR_KEY_LEFT, down); + zr_input_key(&gui.ctx.input, ZR_KEY_LEFT, down); else if (key == GLFW_KEY_RIGHT) - zr_input_key(&gui.input, ZR_KEY_RIGHT, down); + zr_input_key(&gui.ctx.input, ZR_KEY_RIGHT, down); else if (key == GLFW_KEY_C) - zr_input_key(&gui.input, ZR_KEY_COPY, down && (mods & GLFW_MOD_CONTROL)); + zr_input_key(&gui.ctx.input, ZR_KEY_COPY, down && (mods & GLFW_MOD_CONTROL)); else if (key == GLFW_KEY_V) - zr_input_key(&gui.input, ZR_KEY_PASTE, down && (mods & GLFW_MOD_CONTROL)); + zr_input_key(&gui.ctx.input, ZR_KEY_PASTE, down && (mods & GLFW_MOD_CONTROL)); else if (key == GLFW_KEY_X) - zr_input_key(&gui.input, ZR_KEY_CUT, down && (mods & GLFW_MOD_CONTROL)); + zr_input_key(&gui.ctx.input, ZR_KEY_CUT, down && (mods & GLFW_MOD_CONTROL)); } static void @@ -417,13 +409,13 @@ input_motion(GLFWwindow *window, double xpos, double ypos) UNUSED(window); mouse_pos_x = x; mouse_pos_y = y; - zr_input_motion(&gui.input, x, y); + zr_input_motion(&gui.ctx.input, x, y); } static void input_button(GLFWwindow *window, int button, int action, int mods) { - struct zr_input *in = &gui.input; + struct zr_input *in = &gui.ctx.input; int x = mouse_pos_x; int y = mouse_pos_y; UNUSED(window); @@ -438,7 +430,7 @@ static void input_text(GLFWwindow *window, unsigned int codepoint) { UNUSED(window); - zr_input_unicode(&gui.input, codepoint); + zr_input_unicode(&gui.ctx.input, codepoint); } static void @@ -446,7 +438,7 @@ input_scroll(GLFWwindow *window, double xoffset, double yoffset) { UNUSED(window); UNUSED(xoffset); - zr_input_scroll(&gui.input, (float)yoffset); + zr_input_scroll(&gui.ctx.input, (float)yoffset); } static void* mem_alloc(zr_handle unused, size_t size) @@ -461,9 +453,9 @@ main(int argc, char *argv[]) const char *font_path; int win_width, win_height; int width = 0, height = 0; + int running = 1; /* GUI */ - struct zr_allocator alloc; struct device device; struct zr_font font; @@ -497,43 +489,42 @@ main(int argc, char *argv[]) if (glewInit() != GLEW_OK) die("Failed to setup GLEW\n"); - /* GUI */ - alloc.userdata.ptr = NULL; - alloc.alloc = mem_alloc; - alloc.free = mem_free; - memset(&gui, 0, sizeof gui); - zr_buffer_init(&device.cmds, &alloc, 1024, 2.0f); - zr_command_queue_init(&gui.queue, &alloc, 1024, 2.0f); - gui.font = font_bake_and_upload(&device, &font, font_path, 14, - zr_font_default_glyph_ranges()); + { + /* GUI */ + struct zr_user_font usrfnt; + struct zr_allocator alloc; + alloc.userdata.ptr = NULL; + alloc.alloc = mem_alloc; + alloc.free = mem_free; + zr_buffer_init(&device.cmds, &alloc, 1024); + usrfnt = font_bake_and_upload(&device, &font, font_path, 14, + zr_font_default_glyph_ranges()); + zr_init(&gui.ctx, &alloc, &usrfnt, sin, cos); + } - init_demo(&gui); device_init(&device); - - while (!glfwWindowShouldClose(win) && gui.running) { + while (!glfwWindowShouldClose(win) && running) { /* Input */ - zr_input_begin(&gui.input); + zr_input_begin(&gui.ctx.input); glfwPollEvents(); - zr_input_end(&gui.input); + zr_input_end(&gui.ctx.input); /* GUI */ glfwGetWindowSize(win, &width, &height); - gui.w = (size_t)width; - gui.h = (size_t)height; - run_demo(&gui); + running = run_demo(&gui); /* Draw */ glViewport(0, 0, width, height); glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.9f, 0.9f, 0.9f, 1.0f); - device_draw(&device, &gui.queue, width, height, ZR_ANTI_ALIASING_ON); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + device_draw(&device, &gui.ctx, width, height, ZR_ANTI_ALIASING_ON); glfwSwapBuffers(win); } cleanup: /* Cleanup */ free(font.glyphs); - zr_command_queue_free(&gui.queue); + zr_free(&gui.ctx); zr_buffer_free(&device.cmds); device_shutdown(&device); glfwTerminate(); diff --git a/demo/linuxgl/linuxgl.c b/demo/linuxgl/linuxgl.c index 5fa5504..72b8a48 100644 --- a/demo/linuxgl/linuxgl.c +++ b/demo/linuxgl/linuxgl.c @@ -143,10 +143,6 @@ struct opengl { float version; int major_version; int minor_version; - /* constants */ - int max_texture_size; - int max_texture_coords; - int max_texture_image_units; /* extensions */ int glsl_available; int vertex_buffer_obj_available; @@ -443,12 +439,8 @@ device_shutdown(struct device *dev) glDeleteVertexArrays(1, &dev->vao); } -/* this is stupid but needed for C89 since sinf and cosf do not exist */ -static float fsin(float f) {return (float)sin(f);} -static float fcos(float f) {return (float)cos(f);} - static void -device_draw(struct device *dev, struct zr_command_queue *queue, int width, int height, +device_draw(struct device *dev, struct zr_context *ctx, int width, int height, enum zr_anti_aliasing AA) { GLint last_prog, last_tex; @@ -485,13 +477,11 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h { /* convert from command queue into draw list and draw to screen */ - struct zr_draw_list draw_list; - const struct zr_draw_command *cmd; void *vertexes, *elements; + const struct zr_draw_command *cmd; const zr_draw_index *offset = NULL; /* allocate vertex and element buffer */ - memset(&draw_list, 0, sizeof(draw_list)); glBindVertexArray(dev->vao); glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); @@ -506,15 +496,13 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h struct zr_buffer vbuf, ebuf; zr_buffer_init_fixed(&vbuf, vertexes, MAX_VERTEX_MEMORY); zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - zr_draw_list_init(&draw_list, &dev->cmds, &vbuf, &ebuf, - fsin, fcos, dev->null, AA); - zr_draw_list_load(&draw_list, queue, 1.0f, 22); + zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, dev->null, AA, 1.0f, 22); } glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); /* iterate over and execute each draw command */ - zr_foreach_draw_command(cmd, &draw_list) { + zr_draw_foreach(cmd, ctx, &dev->cmds) { if (!cmd->elem_count) continue; glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); glScissor((GLint)cmd->clip_rect.x, @@ -523,9 +511,7 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); offset += cmd->elem_count; } - - zr_command_queue_clear(queue); - zr_draw_list_clear(&draw_list); + zr_clear(ctx); } /* restore old state */ @@ -602,14 +588,13 @@ static void mem_free(zr_handle unused, void *ptr) int main(int argc, char **argv) { + int running = 1; const char *font_path; - struct XWindow win; struct opengl gl; - - struct zr_allocator alloc; struct device device; struct demo gui; struct zr_font font; + struct XWindow win; memset(&gl, 0, sizeof(gl)); memset(&win, 0, sizeof(win)); @@ -692,7 +677,7 @@ int main(int argc, char **argv) win.vis->visual, CWBorderPixel|CWColormap|CWEventMask, &win.swa); if (!win.win) die("[X11]: Failed to create window\n"); XFree(win.vis); - XStoreName(win.dpy, win.win, "QuakEd"); + XStoreName(win.dpy, win.win, "Zahnrad"); fprintf(stdout, "[X11]: Mapping window\n"); XMapWindow(win.dpy, win.win); } @@ -840,53 +825,59 @@ int main(int argc, char **argv) win.width = win.attr.width; win.height = win.attr.height; - /* GUI */ - alloc.userdata.ptr = NULL; - alloc.alloc = mem_alloc; - alloc.free = mem_free; - zr_buffer_init(&device.cmds, &alloc, 1024, 2.0f); - zr_command_queue_init(&gui.queue, &alloc, 1024, 2.0f); - gui.font = font_bake_and_upload(&device, &font, font_path, 14, - zr_font_default_glyph_ranges()); + { + /* GUI */ + struct zr_user_font usrfnt; + struct zr_allocator alloc; + alloc.userdata.ptr = NULL; + alloc.alloc = mem_alloc; + alloc.free = mem_free; + + zr_buffer_init(&device.cmds, &alloc, 4024); + usrfnt = font_bake_and_upload(&device, &font, font_path, 14, + zr_font_default_glyph_ranges()); + zr_init(&gui.ctx, &alloc, &usrfnt, sin, cos); + } - init_demo(&gui); device_init(&device); - - /* main loop */ - while (gui.running) { + while (running) { /* input */ XEvent evt; - zr_input_begin(&gui.input); + zr_input_begin(&gui.ctx.input); while (XCheckWindowEvent(win.dpy, win.win, win.swa.event_mask, &evt)) { if (evt.type == KeyPress) - input_key(&win, &gui.input, &evt, zr_true); + input_key(&win, &gui.ctx.input, &evt, zr_true); else if (evt.type == KeyRelease) - input_key(&win, &gui.input, &evt, zr_false); + input_key(&win, &gui.ctx.input, &evt, zr_false); else if (evt.type == ButtonPress) - input_button(&gui.input, &evt, zr_true); + input_button(&gui.ctx.input, &evt, zr_true); else if (evt.type == ButtonRelease) - input_button(&gui.input, &evt, zr_false); + input_button(&gui.ctx.input, &evt, zr_false); else if (evt.type == MotionNotify) - input_motion(&gui.input, &evt); + input_motion(&gui.ctx.input, &evt); + else if (evt.type == Expose || evt.type == ConfigureNotify) { + XGetWindowAttributes(win.dpy, win.win, &win.attr); + win.width = win.attr.width; + win.height = win.attr.height; + } } - zr_input_end(&gui.input); + zr_input_end(&gui.ctx.input); /* GUI */ XGetWindowAttributes(win.dpy, win.win, &win.attr); - gui.w = (size_t)win.width, gui.h = (size_t)win.height; - run_demo(&gui); + running = run_demo(&gui); /* Draw */ glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.9f, 0.9f, 0.9f, 1.0f); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glViewport(0, 0, win.width, win.height); - device_draw(&device, &gui.queue, win.width, win.height, ZR_ANTI_ALIASING_ON); + device_draw(&device, &gui.ctx, win.width, win.height, ZR_ANTI_ALIASING_ON); glXSwapBuffers(win.dpy, win.win); } cleanup: free(font.glyphs); - zr_command_queue_free(&gui.queue); + zr_free(&gui.ctx); zr_buffer_free(&device.cmds); device_shutdown(&device); diff --git a/demo/nanovg/nanovg.c b/demo/nanovg/nanovg.c index 8582134..06f0dc9 100644 --- a/demo/nanovg/nanovg.c +++ b/demo/nanovg/nanovg.c @@ -80,7 +80,7 @@ font_get_width(zr_handle handle, float height, const char *text, size_t len) } static void -draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) +draw(NVGcontext *nvg, struct zr_context *ctx, int width, int height) { const struct zr_command *cmd; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT); @@ -92,7 +92,7 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) glEnable(GL_TEXTURE_2D); nvgBeginFrame(nvg, width, height, ((float)width/(float)height)); - zr_foreach_command(cmd, queue) { + zr_foreach(cmd, ctx) { switch (cmd->type) { case ZR_COMMAND_NOP: break; case ZR_COMMAND_SCISSOR: { @@ -168,7 +168,7 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) default: break; } } - zr_command_queue_clear(queue); + zr_clear(ctx); nvgResetScissor(nvg); nvgEndFrame(nvg); @@ -238,6 +238,7 @@ int main(int argc, char *argv[]) { /* Platform */ + int running = 1; int width, height; const char *font_path; int font_height; @@ -277,41 +278,45 @@ main(int argc, char *argv[]) nvgFontSize(vg, font_height); nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - /* GUI */ - memset(&gui, 0, sizeof gui); - zr_command_queue_init_fixed(&gui.queue, calloc(MAX_MEMORY, 1), MAX_MEMORY); - gui.font.userdata = zr_handle_ptr(vg); - gui.font.width = font_get_width; - nvgTextMetrics(vg, NULL, NULL, &gui.font.height); - init_demo(&gui); + { + /* GUI */ + struct zr_user_font usrfnt; + usrfnt.userdata = zr_handle_ptr(vg); + usrfnt.width = font_get_width; + nvgTextMetrics(vg, NULL, NULL, &usrfnt.height); - while (gui.running) { + memset(&gui, 0, sizeof gui); + gui.memory = calloc(MAX_MEMORY, 1); + zr_init_fixed(&gui.ctx, gui.memory, MAX_MEMORY, &usrfnt, sin, cos); + } + + while (running) { /* Input */ SDL_Event evt; uint64_t dt, started = SDL_GetTicks(); - zr_input_begin(&gui.input); + zr_input_begin(&gui.ctx.input); while (SDL_PollEvent(&evt)) { if (evt.type == SDL_WINDOWEVENT) resize(&evt); else if (evt.type == SDL_QUIT) goto cleanup; - else if (evt.type == SDL_KEYUP) key(&gui.input, &evt, zr_false); - else if (evt.type == SDL_KEYDOWN) key(&gui.input, &evt, zr_true); - else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&gui.input, &evt, zr_true); - else if (evt.type == SDL_MOUSEBUTTONUP) btn(&gui.input, &evt, zr_false); - else if (evt.type == SDL_MOUSEMOTION) motion(&gui.input, &evt); - else if (evt.type == SDL_TEXTINPUT) text(&gui.input, &evt); + else if (evt.type == SDL_KEYUP) key(&gui.ctx.input, &evt, zr_false); + else if (evt.type == SDL_KEYDOWN) key(&gui.ctx.input, &evt, zr_true); + else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&gui.ctx.input, &evt, zr_true); + else if (evt.type == SDL_MOUSEBUTTONUP) btn(&gui.ctx.input, &evt, zr_false); + else if (evt.type == SDL_MOUSEMOTION) motion(&gui.ctx.input, &evt); + else if (evt.type == SDL_TEXTINPUT) text(&gui.ctx.input, &evt); else if (evt.type == SDL_MOUSEWHEEL) - zr_input_scroll(&gui.input,(float)evt.wheel.y); + zr_input_scroll(&gui.ctx.input,(float)evt.wheel.y); } - zr_input_end(&gui.input); + zr_input_end(&gui.ctx.input); /* GUI */ SDL_GetWindowSize(win, &width, &height); - run_demo(&gui); + running = run_demo(&gui); /* Draw */ - glClearColor(0.9f, 0.9f, 0.9f, 1.0f); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - draw(vg, &gui.queue, width, height); + draw(vg, &gui.ctx, width, height); dt = SDL_GetTicks() - started; /*fprintf(stdout, "%lu\n", dt);*/ SDL_GL_SwapWindow(win); @@ -319,7 +324,7 @@ main(int argc, char *argv[]) cleanup: /* Cleanup */ - free(zr_buffer_memory(&gui.queue.buffer)); + free(gui.memory); nvgDeleteGLES3(vg); SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(win); diff --git a/demo/sdl/sdl.c b/demo/sdl/sdl.c index ecb38eb..18a7f44 100644 --- a/demo/sdl/sdl.c +++ b/demo/sdl/sdl.c @@ -274,12 +274,8 @@ device_shutdown(struct device *dev) glDeleteVertexArrays(1, &dev->vao); } -/* this is stupid but needed for C89 since sinf and cosf do not exist */ -static float fsin(float f) {return (float)sin(f);} -static float fcos(float f) {return (float)cos(f);} - static void -device_draw(struct device *dev, struct zr_command_queue *queue, int width, int height, +device_draw(struct device *dev, struct zr_context *ctx, int width, int height, enum zr_anti_aliasing AA) { GLint last_prog, last_tex; @@ -301,7 +297,6 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h glGetIntegerv(GL_VERTEX_ARRAY_BINDING, &last_vbo); /* setup global state */ - glViewport(0, 0, width, height); glEnable(GL_BLEND); glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -317,13 +312,11 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h { /* convert from command queue into draw list and draw to screen */ - struct zr_draw_list draw_list; const struct zr_draw_command *cmd; void *vertexes, *elements; const zr_draw_index *offset = NULL; /* allocate vertex and element buffer */ - memset(&draw_list, 0, sizeof(draw_list)); glBindVertexArray(dev->vao); glBindBuffer(GL_ARRAY_BUFFER, dev->vbo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, dev->ebo); @@ -338,15 +331,13 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h struct zr_buffer vbuf, ebuf; zr_buffer_init_fixed(&vbuf, vertexes, MAX_VERTEX_MEMORY); zr_buffer_init_fixed(&ebuf, elements, MAX_ELEMENT_MEMORY); - zr_draw_list_init(&draw_list, &dev->cmds, &vbuf, &ebuf, - fsin, fcos, dev->null, AA); - zr_draw_list_load(&draw_list, queue, 1.0f, 22); + zr_convert(ctx, &dev->cmds, &vbuf, &ebuf, dev->null, AA, 1.0f, 22); } glUnmapBuffer(GL_ARRAY_BUFFER); glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); /* iterate over and execute each draw command */ - zr_foreach_draw_command(cmd, &draw_list) { + zr_draw_foreach(cmd, ctx, &dev->cmds) { if (!cmd->elem_count) continue; glBindTexture(GL_TEXTURE_2D, (GLuint)cmd->texture.id); glScissor((GLint)cmd->clip_rect.x, @@ -355,9 +346,7 @@ device_draw(struct device *dev, struct zr_command_queue *queue, int width, int h glDrawElements(GL_TRIANGLES, (GLsizei)cmd->elem_count, GL_UNSIGNED_SHORT, offset); offset += cmd->elem_count; } - - zr_command_queue_clear(queue); - zr_draw_list_clear(&draw_list); + zr_clear(ctx); } /* restore old state */ @@ -444,9 +433,9 @@ main(int argc, char *argv[]) SDL_GLContext glContext; int win_width, win_height; int width = 0, height = 0; + int running = 1; /* GUI */ - struct zr_allocator alloc; struct device device; struct demo gui; struct zr_font font; @@ -470,60 +459,59 @@ main(int argc, char *argv[]) if (glewInit() != GLEW_OK) die("Failed to setup GLEW\n"); - /* GUI */ - alloc.userdata.ptr = NULL; - alloc.alloc = mem_alloc; - alloc.free = mem_free; - memset(&gui, 0, sizeof gui); - zr_buffer_init(&device.cmds, &alloc, 1024, 2.0f); - zr_command_queue_init(&gui.queue, &alloc, 1024, 2.0f); - gui.font = font_bake_and_upload(&device, &font, font_path, 14, - zr_font_default_glyph_ranges()); + { + /* GUI */ + struct zr_user_font usrfnt; + struct zr_allocator alloc; + alloc.userdata.ptr = NULL; + alloc.alloc = mem_alloc; + alloc.free = mem_free; + zr_buffer_init(&device.cmds, &alloc, 1024); + usrfnt = font_bake_and_upload(&device, &font, font_path, 14, + zr_font_default_glyph_ranges()); + zr_init(&gui.ctx, &alloc, &usrfnt, sin, cos); + } - init_demo(&gui); device_init(&device); - - while (gui.running) { + while (running) { /* Input */ SDL_Event evt; - zr_input_begin(&gui.input); + zr_input_begin(&gui.ctx.input); while (SDL_PollEvent(&evt)) { if (evt.type == SDL_WINDOWEVENT) resize(&evt); else if (evt.type == SDL_QUIT) goto cleanup; else if (evt.type == SDL_KEYUP) - input_key(&gui.input, &evt, zr_false); + input_key(&gui.ctx.input, &evt, zr_false); else if (evt.type == SDL_KEYDOWN) - input_key(&gui.input, &evt, zr_true); + input_key(&gui.ctx.input, &evt, zr_true); else if (evt.type == SDL_MOUSEBUTTONDOWN) - input_button(&gui.input, &evt, zr_true); + input_button(&gui.ctx.input, &evt, zr_true); else if (evt.type == SDL_MOUSEBUTTONUP) - input_button(&gui.input, &evt, zr_false); + input_button(&gui.ctx.input, &evt, zr_false); else if (evt.type == SDL_MOUSEMOTION) - input_motion(&gui.input, &evt); + input_motion(&gui.ctx.input, &evt); else if (evt.type == SDL_TEXTINPUT) - input_text(&gui.input, &evt); + input_text(&gui.ctx.input, &evt); else if (evt.type == SDL_MOUSEWHEEL) - zr_input_scroll(&gui.input,(float)evt.wheel.y); + zr_input_scroll(&gui.ctx.input,(float)evt.wheel.y); } - zr_input_end(&gui.input); + zr_input_end(&gui.ctx.input); /* GUI */ SDL_GetWindowSize(win, &width, &height); - gui.w = (size_t)width; - gui.h = (size_t)height; - run_demo(&gui); + running = run_demo(&gui); /* Draw */ glClear(GL_COLOR_BUFFER_BIT); - glClearColor(0.9f, 0.9f, 0.9f, 1.0f); - device_draw(&device, &gui.queue, width, height, ZR_ANTI_ALIASING_ON); + glClearColor(0.2f, 0.2f, 0.2f, 1.0f); + device_draw(&device, &gui.ctx, width, height, ZR_ANTI_ALIASING_ON); SDL_GL_SwapWindow(win); } cleanup: /* Cleanup */ free(font.glyphs); - zr_command_queue_free(&gui.queue); + zr_free(&gui.ctx); zr_buffer_free(&device.cmds); device_shutdown(&device); SDL_GL_DeleteContext(glContext); diff --git a/demo/x11/xlib.c b/demo/x11/xlib.c index 5fbc60f..91716b2 100644 --- a/demo/x11/xlib.c +++ b/demo/x11/xlib.c @@ -25,13 +25,13 @@ #include #include #include +#include #include #include /* macros */ #define DTIME 16 -#define CURVE_STEPS 22 #include "../../zahnrad.h" #define UNUSED(a) ((void)(a)) @@ -158,7 +158,7 @@ font_get_text_width(zr_handle handle, float height, const char *text, zr_size le if(!font || !text) return 0; - height = 0; + UNUSED(height); if(font->set) { XmbTextExtents(font->set, (const char*)text, (int)len, NULL, &r); return r.width; @@ -221,8 +221,8 @@ surface_scissor(XSurface *surf, float x, float y, float w, float h) XRectangle clip_rect; clip_rect.x = (short)(x-1); clip_rect.y = (short)(y-1); - clip_rect.width = (unsigned short)(w + 2); - clip_rect.height = (unsigned short)(h + 2); + clip_rect.width = (unsigned short)(w+2); + clip_rect.height = (unsigned short)(h+2); XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted); } @@ -313,49 +313,6 @@ surface_del(XSurface *surf) free(surf); } -static void -draw(XSurface *surf, struct zr_command_queue *queue) -{ - const struct zr_command *cmd; - zr_foreach_command(cmd, queue) { - switch (cmd->type) { - case ZR_COMMAND_NOP: break; - case ZR_COMMAND_SCISSOR: { - const struct zr_command_scissor *s = zr_command(scissor, cmd); - surface_scissor(surf, s->x, s->y, s->w, s->h); - } break; - case ZR_COMMAND_LINE: { - const struct zr_command_line *l = zr_command(line, cmd); - surface_draw_line(surf, l->begin.x, l->begin.y, l->end.x, - l->end.y, l->color); - } break; - case ZR_COMMAND_RECT: { - const struct zr_command_rect *r = zr_command(rect, cmd); - surface_draw_rect(surf, r->x, r->y, r->w, r->h, r->color); - } break; - case ZR_COMMAND_CIRCLE: { - const struct zr_command_circle *c = zr_command(circle, cmd); - surface_draw_circle(surf, c->x, c->y, c->w, c->h, c->color); - } break; - case ZR_COMMAND_TRIANGLE: { - const struct zr_command_triangle *t = zr_command(triangle, cmd); - surface_draw_triangle(surf, t->a.x, t->a.y, t->b.x, t->b.y, - t->c.x, t->c.y, t->color); - } break; - case ZR_COMMAND_TEXT: { - const struct zr_command_text *t = zr_command(text, cmd); - surface_draw_text(surf, t->x, t->y, t->w, t->h, (const char*)t->string, - t->length, (XFont*)t->font->userdata.ptr, t->background, t->foreground); - } break; - case ZR_COMMAND_CURVE: - case ZR_COMMAND_IMAGE: - case ZR_COMMAND_ARC: - default: break; - } - } - zr_command_queue_clear(queue); -} - static void input_key(struct XWindow *xw, struct zr_input *in, XEvent *evt, int down) { @@ -429,8 +386,10 @@ main(int argc, char *argv[]) long started; XWindow xw; struct demo gui; + struct zr_user_font font; + int running = 1; - /* Platform */ + /* X11 */ UNUSED(argc); UNUSED(argv); memset(&xw, 0, sizeof xw); xw.dpy = XOpenDisplay(NULL); @@ -456,41 +415,82 @@ main(int argc, char *argv[]) xw.font = font_create(xw.dpy, "fixed"); /* GUI */ + font.userdata = zr_handle_ptr(xw.font); + font.height = (float)xw.font->height; + font.width = font_get_text_width; memset(&gui, 0, sizeof gui); - zr_command_queue_init_fixed(&gui.queue, calloc(MAX_MEMORY, 1), MAX_MEMORY); - gui.font.userdata = zr_handle_ptr(xw.font); - gui.font.height = (float)xw.font->height; - gui.font.width = font_get_text_width; - init_demo(&gui); + gui.memory = calloc(MAX_MEMORY, 1); + zr_init_fixed(&gui.ctx, gui.memory, MAX_MEMORY, &font, sin, cos); - while (gui.running) { + while (running) { /* Input */ XEvent evt; started = timestamp(); - zr_input_begin(&gui.input); + zr_input_begin(&gui.ctx.input); while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)) { if (evt.type == KeyPress) - input_key(&xw, &gui.input, &evt, zr_true); + input_key(&xw, &gui.ctx.input, &evt, zr_true); else if (evt.type == KeyRelease) - input_key(&xw, &gui.input, &evt, zr_false); + input_key(&xw, &gui.ctx.input, &evt, zr_false); else if (evt.type == ButtonPress) - input_button(&gui.input, &evt, zr_true); + input_button(&gui.ctx.input, &evt, zr_true); else if (evt.type == ButtonRelease) - input_button(&gui.input, &evt, zr_false); + input_button(&gui.ctx.input, &evt, zr_false); else if (evt.type == MotionNotify) - input_motion(&gui.input, &evt); + input_motion(&gui.ctx.input, &evt); else if (evt.type == Expose || evt.type == ConfigureNotify) resize(&xw, xw.surf); } - zr_input_end(&gui.input); + zr_input_end(&gui.ctx.input); /* GUI */ - run_demo(&gui); + running = run_demo(&gui); /* Draw */ XClearWindow(xw.dpy, xw.win); - surface_clear(xw.surf, 0x00FFFFFF); - draw(xw.surf, &gui.queue); + surface_clear(xw.surf, 0x00303030); + { + const struct zr_command *cmd; + zr_foreach(cmd, &gui.ctx) { + switch (cmd->type) { + case ZR_COMMAND_NOP: break; + case ZR_COMMAND_SCISSOR: { + const struct zr_command_scissor *s = zr_command(scissor, cmd); + surface_scissor(xw.surf, s->x, s->y, s->w, s->h); + } break; + case ZR_COMMAND_LINE: { + const struct zr_command_line *l = zr_command(line, cmd); + surface_draw_line(xw.surf, l->begin.x, l->begin.y, l->end.x, + l->end.y, l->color); + } break; + case ZR_COMMAND_RECT: { + const struct zr_command_rect *r = zr_command(rect, cmd); + surface_draw_rect(xw.surf, r->x, r->y, r->w, r->h, r->color); + } break; + case ZR_COMMAND_CIRCLE: { + const struct zr_command_circle *c = zr_command(circle, cmd); + surface_draw_circle(xw.surf, c->x, c->y, c->w, c->h, c->color); + } break; + case ZR_COMMAND_TRIANGLE: { + const struct zr_command_triangle *t = zr_command(triangle, cmd); + surface_draw_triangle(xw.surf, t->a.x, t->a.y, t->b.x, t->b.y, + t->c.x, t->c.y, t->color); + } break; + case ZR_COMMAND_TEXT: { + const struct zr_command_text *t = zr_command(text, cmd); + surface_draw_text(xw.surf, t->x, t->y, t->w, t->h, + (const char*)t->string, t->length, + (XFont*)t->font->userdata.ptr, + t->background, t->foreground); + } break; + case ZR_COMMAND_CURVE: + case ZR_COMMAND_IMAGE: + case ZR_COMMAND_ARC: + default: break; + } + } + zr_clear(&gui.ctx); + } surface_blit(xw.win, xw.surf, xw.width, xw.height); XFlush(xw.dpy); @@ -500,7 +500,7 @@ main(int argc, char *argv[]) sleep_for(DTIME - dt); } - free(zr_buffer_memory(&gui.queue.buffer)); + free(gui.memory); font_del(xw.dpy, xw.font); surface_del(xw.surf); XUnmapWindow(xw.dpy, xw.win); diff --git a/example/demo/demo.c b/example/demo/demo.c index ac4d94f..433412b 100644 --- a/example/demo/demo.c +++ b/example/demo/demo.c @@ -76,17 +76,6 @@ struct icons { int menu[6]; }; -struct gui { - void *memory; - struct zr_window button_demo; - struct zr_window basic_demo; - struct zr_window grid_demo; - struct zr_input input; - struct zr_command_queue queue; - struct zr_style config; - struct zr_user_font font; -}; - static void die(const char *fmt, ...) { @@ -99,71 +88,72 @@ die(const char *fmt, ...) } static void -ui_header(struct zr_context *layout, struct zr_style *config, const char *title) +ui_header(struct zr_context *ctx, const char *title) { - zr_style_reset_font_height(config); - zr_style_push_font_height(config, 18); - zr_layout_row_dynamic(layout, 20, 1); - zr_label(layout, title, ZR_TEXT_LEFT); + zr_style_reset_font_height(&ctx->style); + zr_style_push_font_height(&ctx->style, 18); + zr_layout_row_dynamic(ctx, 20, 1); + zr_label(ctx, title, ZR_TEXT_LEFT); } static void -ui_widget(struct zr_context *layout, struct zr_style *config, float height, float font_height) +ui_widget(struct zr_context *ctx, float height, float font_height) { static const float ratio[] = {0.15f, 0.85f}; - zr_style_reset_font_height(config); - zr_style_push_font_height(config, font_height); - zr_layout_row(layout, ZR_DYNAMIC, height, 2, ratio); - zr_spacing(layout, 1); + zr_style_reset_font_height(&ctx->style); + zr_style_push_font_height(&ctx->style, font_height); + zr_layout_row(ctx, ZR_DYNAMIC, height, 2, ratio); + zr_spacing(ctx, 1); } static void -ui_widget_centered(struct zr_context *layout, struct zr_style *config, float height, float font_height) +ui_widget_centered(struct zr_context *ctx, float height, float font_height) { static const float ratio[] = {0.15f, 0.50f, 0.35f}; - zr_style_reset_font_height(config); - zr_style_push_font_height(config, font_height); - zr_layout_row(layout, ZR_DYNAMIC, height, 3, ratio); - zr_spacing(layout, 1); + zr_style_reset_font_height(&ctx->style); + zr_style_push_font_height(&ctx->style, font_height); + zr_layout_row(ctx, ZR_DYNAMIC, height, 3, ratio); + zr_spacing(ctx, 1); } static int -ui_piemenu(struct zr_context *layout, struct zr_style *config, +ui_piemenu(struct zr_context *ctx, struct zr_vec2 pos, float radius, int *icons, int item_count) { int ret = -1; struct zr_rect total_space; - struct zr_context menu; + struct zr_layout popup; struct zr_rect bounds; int active_item = 0; /* hide popup background */ struct zr_color border; - zr_style_push_color(config, ZR_COLOR_WINDOW, zr_rgba(0,0,0,0)); - border = config->colors[ZR_COLOR_BORDER]; - zr_style_push_color(config, ZR_COLOR_BORDER, zr_rgba(0,0,0,0)); + zr_style_push_color(&ctx->style, ZR_COLOR_WINDOW, zr_rgba(0,0,0,0)); + border = ctx->style.colors[ZR_COLOR_BORDER]; + zr_style_push_color(&ctx->style, ZR_COLOR_BORDER, zr_rgba(0,0,0,0)); /* pie menu popup */ - zr_popup_begin(layout, &menu, ZR_POPUP_STATIC, 0, ZR_WINDOW_NO_SCROLLBAR, - zr_rect(pos.x-layout->clip.x-radius,pos.y-radius-layout->clip.y, - 2*radius,2*radius), zr_vec2(0,0)); - total_space = zr_space(&menu); + total_space = zr_window_get_content_region(ctx); + zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "piemenu", ZR_WINDOW_NO_SCROLLBAR, + zr_rect(pos.x - total_space.x - radius, pos.y - radius - total_space.y, + 2*radius,2*radius)); + total_space = zr_window_get_content_region(ctx); - zr_layout_row_space_begin(&menu, ZR_STATIC, total_space.h, 1); + zr_layout_space_begin(ctx, ZR_STATIC, total_space.h, 1); { int i = 0; - struct zr_command_buffer* out = zr_canvas(&menu); - const struct zr_input *in = zr_input(&menu); + struct zr_command_buffer* out = zr_window_get_canvas(ctx); + const struct zr_input *in = &ctx->input; { /* allocate complete popup space for the menu */ enum zr_widget_state state; - total_space = zr_space(&menu); + total_space = zr_window_get_content_region(ctx); total_space.x = total_space.y = 0; - zr_layout_row_space_push(&menu, total_space); - state = zr_widget(&bounds, &menu); + zr_layout_space_push(ctx, total_space); + state = zr_widget(&bounds, ctx); } /* outer circle */ - zr_command_buffer_push_circle(out, bounds, zr_rgb(50,50,50)); + zr_draw_circle(out, bounds, zr_rgb(50,50,50)); { /* circle buttons */ float step = (2 * 3.141592654f) / (float)(MAX(1,item_count)); @@ -179,14 +169,14 @@ ui_piemenu(struct zr_context *layout, struct zr_style *config, struct zr_image img; struct zr_rect content; float rx, ry, dx, dy, a; - zr_command_buffer_push_arc(out, center.x, center.y, (bounds.w/2.0f), + zr_draw_arc(out, center.x, center.y, (bounds.w/2.0f), a_min, a_max, (active_item == i) ? zr_rgb(45,100,255) : zr_rgb(75,75,75)); /* seperator line */ rx = bounds.w/2.0f; ry = 0; dx = rx * (float)cos(a_min) - ry * (float)sin(a_min); dy = rx * (float)sin(a_min) + ry * (float)cos(a_min); - zr_command_buffer_push_line(out, center.x, center.y, + zr_draw_line(out, center.x, center.y, center.x + dx, center.y + dy, zr_rgb(50,50,50)); /* button content */ @@ -196,7 +186,7 @@ ui_piemenu(struct zr_context *layout, struct zr_style *config, content.x = center.x + ((rx * (float)cos(a) - ry * (float)sin(a)) - content.w/2.0f); content.y = center.y + (rx * (float)sin(a) + ry * (float)cos(a) - content.h/2.0f); img = zr_image_id(icons[i]); - zr_command_buffer_push_image(out, content, &img); + zr_draw_image(out, content, &img); a_min = a_max; a_max += step; } } @@ -207,7 +197,7 @@ ui_piemenu(struct zr_context *layout, struct zr_style *config, inner.x = bounds.x + bounds.w/2 - bounds.w/4; inner.y = bounds.y + bounds.h/2 - bounds.h/4; inner.w = bounds.w/2; inner.h = bounds.h/2; - zr_command_buffer_push_circle(out, inner, zr_rgb(45,45,45)); + zr_draw_circle(out, inner, zr_rgb(45,45,45)); /* active icon content */ bounds.w = inner.w / 2.0f; @@ -215,143 +205,130 @@ ui_piemenu(struct zr_context *layout, struct zr_style *config, bounds.x = inner.x + inner.w/2 - bounds.w/2; bounds.y = inner.y + inner.h/2 - bounds.h/2; img = zr_image_id(icons[active_item]); - zr_command_buffer_push_image(out, bounds, &img); + zr_draw_image(out, bounds, &img); } } - zr_layout_row_space_end(&menu); - zr_popup_end(layout, &menu, 0); - zr_style_reset_colors(config); - zr_style_reset_properties(config); - if (!zr_input_is_mouse_down(zr_input(layout), ZR_BUTTON_RIGHT)) + zr_layout_space_end(ctx); + zr_popup_end(ctx); + zr_style_reset_colors(&ctx->style); + zr_style_reset_properties(&ctx->style); + if (!zr_input_is_mouse_down(&ctx->input, ZR_BUTTON_RIGHT)) return active_item; else return ret; } static void -button_demo(struct zr_window *window, struct zr_style *config, struct icons *img) +button_demo(struct zr_context *ctx, struct icons *img) { - struct zr_context layout; - struct zr_context menu; + struct zr_layout layout; + struct zr_layout menu; static int option = 1; static int toggle0 = 1; static int toggle1 = 0; static int toggle2 = 1; - static int music_active = 0; - static int contextual_active = 0; - static struct zr_rect contextual_bounds; - config->font.height = 20; - zr_begin(&layout, window, "Button Demo"); + ctx->style.font.height = 20; + zr_begin(ctx, &layout, "Button Demo", zr_rect(50,50,255,610), + ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_TITLE); + /*------------------------------------------------ * MENU *------------------------------------------------*/ - zr_menubar_begin(&layout); + zr_menubar_begin(ctx); { /* toolbar */ - zr_layout_row_static(&layout, 40, 40, 4); - zr_menu_icon_begin(&layout, &menu, zr_image_id(img->play), 120, &music_active); + zr_layout_row_static(ctx, 40, 40, 4); + if (zr_menu_icon_begin(ctx, &menu, "Music", zr_image_id(img->play), 120)) { /* settings */ - zr_layout_row_dynamic(&menu, 25, 1); - if (zr_menu_item_icon(&menu, zr_image_id(img->play), "Play", ZR_TEXT_RIGHT)) - zr_menu_close(&menu, &music_active); - if (zr_menu_item_icon(&menu, zr_image_id(img->stop), "Stop", ZR_TEXT_RIGHT)) - zr_menu_close(&menu, &music_active); - if (zr_menu_item_icon(&menu, zr_image_id(img->pause), "Pause", ZR_TEXT_RIGHT)) - zr_menu_close(&menu, &music_active); - if (zr_menu_item_icon(&menu, zr_image_id(img->next), "Next", ZR_TEXT_RIGHT)) - zr_menu_close(&menu, &music_active); - if (zr_menu_item_icon(&menu, zr_image_id(img->prev), "Prev", ZR_TEXT_RIGHT)) - zr_menu_close(&menu, &music_active); + zr_layout_row_dynamic(ctx, 25, 1); + zr_menu_item_icon(ctx, zr_image_id(img->play), "Play", ZR_TEXT_RIGHT); + zr_menu_item_icon(ctx, zr_image_id(img->stop), "Stop", ZR_TEXT_RIGHT); + zr_menu_item_icon(ctx, zr_image_id(img->pause), "Pause", ZR_TEXT_RIGHT); + zr_menu_item_icon(ctx, zr_image_id(img->next), "Next", ZR_TEXT_RIGHT); + zr_menu_item_icon(ctx, zr_image_id(img->prev), "Prev", ZR_TEXT_RIGHT); + zr_menu_end(ctx); } - zr_menu_end(&layout, &menu); - zr_button_image(&layout, zr_image_id(img->tools), ZR_BUTTON_DEFAULT); - zr_button_image(&layout, zr_image_id(img->cloud), ZR_BUTTON_DEFAULT); - zr_button_image(&layout, zr_image_id(img->pen), ZR_BUTTON_DEFAULT); + zr_button_image(ctx, zr_image_id(img->tools), ZR_BUTTON_DEFAULT); + zr_button_image(ctx, zr_image_id(img->cloud), ZR_BUTTON_DEFAULT); + zr_button_image(ctx, zr_image_id(img->pen), ZR_BUTTON_DEFAULT); } - zr_menubar_end(&layout); + zr_menubar_end(ctx); /*------------------------------------------------ * BUTTON *------------------------------------------------*/ - ui_header(&layout, config, "Push buttons"); - ui_widget(&layout, config, 35, 22); - if (zr_button_text(&layout, "Push me", ZR_BUTTON_DEFAULT)) + ui_header(ctx, "Push buttons"); + ui_widget(ctx, 35, 22); + if (zr_button_text(ctx, "Push me", ZR_BUTTON_DEFAULT)) fprintf(stdout, "pushed!\n"); - ui_widget(&layout, config, 35, 22); - if (zr_button_text_image(&layout, zr_image_id(img->rocket), + ui_widget(ctx, 35, 22); + if (zr_button_text_image(ctx, zr_image_id(img->rocket), "Styled", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) fprintf(stdout, "rocket!\n"); /*------------------------------------------------ * REPEATER *------------------------------------------------*/ - ui_header(&layout, config, "Repeater"); - ui_widget(&layout, config, 35, 22); - if (zr_button_text(&layout, "Press me", ZR_BUTTON_REPEATER)) + ui_header(ctx, "Repeater"); + ui_widget(ctx, 35, 22); + if (zr_button_text(ctx, "Press me", ZR_BUTTON_REPEATER)) fprintf(stdout, "pressed!\n"); /*------------------------------------------------ * TOGGLE *------------------------------------------------*/ - ui_header(&layout, config, "Toggle buttons"); - ui_widget(&layout, config, 35, 22); - if (zr_button_text_image(&layout, (toggle0) ? zr_image_id(img->checked): + ui_header(ctx, "Toggle buttons"); + ui_widget(ctx, 35, 22); + if (zr_button_text_image(ctx, (toggle0) ? zr_image_id(img->checked): zr_image_id(img->unchecked), "Toggle", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) toggle0 = !toggle0; - ui_widget(&layout, config, 35, 22); - if (zr_button_text_image(&layout, (toggle1) ? zr_image_id(img->checked): + ui_widget(ctx, 35, 22); + if (zr_button_text_image(ctx, (toggle1) ? zr_image_id(img->checked): zr_image_id(img->unchecked), "Toggle", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) toggle1 = !toggle1; - ui_widget(&layout, config, 35, 22); - if (zr_button_text_image(&layout, (toggle2) ? zr_image_id(img->checked): + ui_widget(ctx, 35, 22); + if (zr_button_text_image(ctx, (toggle2) ? zr_image_id(img->checked): zr_image_id(img->unchecked), "Toggle", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) toggle2 = !toggle2; /*------------------------------------------------ * RADIO *------------------------------------------------*/ - ui_header(&layout, config, "Radio buttons"); - ui_widget(&layout, config, 35, 22); - if (zr_button_text_symbol(&layout, (option == 0)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE, + ui_header(ctx, "Radio buttons"); + ui_widget(ctx, 35, 22); + if (zr_button_text_symbol(ctx, (option == 0)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE, "Select", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) option = 0; - ui_widget(&layout, config, 35, 22); - if (zr_button_text_symbol(&layout, (option == 1)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE, + ui_widget(ctx, 35, 22); + if (zr_button_text_symbol(ctx, (option == 1)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE, "Select", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) option = 1; - ui_widget(&layout, config, 35, 22); - if (zr_button_text_symbol(&layout, (option == 2)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE, + ui_widget(ctx, 35, 22); + if (zr_button_text_symbol(ctx, (option == 2)?ZR_SYMBOL_CIRCLE_FILLED:ZR_SYMBOL_CIRCLE, "Select", ZR_TEXT_LEFT, ZR_BUTTON_DEFAULT)) option = 2; /*------------------------------------------------ * CONTEXTUAL *------------------------------------------------*/ - if (zr_input_mouse_clicked(zr_input(&layout), ZR_BUTTON_RIGHT, layout.bounds) && - layout.flags & ZR_WINDOW_ACTIVE) { - const struct zr_input *in = zr_input(&layout); - contextual_bounds = zr_rect(in->mouse.pos.x, in->mouse.pos.y, 120, 200); - contextual_active = zr_true; - } - if (contextual_active) { - config->font.height = 18; - zr_contextual_begin(&layout, &menu, ZR_WINDOW_NO_SCROLLBAR, &contextual_active, contextual_bounds); - zr_layout_row_dynamic(&menu, 25, 1); - if (zr_contextual_item_icon(&menu, zr_image_id(img->copy), "Clone", ZR_TEXT_RIGHT)) + if (zr_contextual_begin(ctx, &menu, ZR_WINDOW_NO_SCROLLBAR, zr_vec2(120, 200))) { + ctx->style.font.height = 18; + zr_layout_row_dynamic(ctx, 25, 1); + if (zr_contextual_item_icon(ctx, zr_image_id(img->copy), "Clone", ZR_TEXT_RIGHT)) fprintf(stdout, "pressed clone!\n"); - if (zr_contextual_item_icon(&menu, zr_image_id(img->delete), "Delete", ZR_TEXT_RIGHT)) + if (zr_contextual_item_icon(ctx, zr_image_id(img->delete), "Delete", ZR_TEXT_RIGHT)) fprintf(stdout, "pressed delete!\n"); - if (zr_contextual_item_icon(&menu, zr_image_id(img->convert), "Convert", ZR_TEXT_RIGHT)) + if (zr_contextual_item_icon(ctx, zr_image_id(img->convert), "Convert", ZR_TEXT_RIGHT)) fprintf(stdout, "pressed convert!\n"); - if (zr_contextual_item_icon(&menu, zr_image_id(img->edit), "Edit", ZR_TEXT_RIGHT)) + if (zr_contextual_item_icon(ctx, zr_image_id(img->edit), "Edit", ZR_TEXT_RIGHT)) fprintf(stdout, "pressed edit!\n"); - zr_contextual_end(&layout, &menu, &contextual_active); + zr_contextual_end(ctx); } - zr_end(&layout, window); + zr_end(ctx); } static void -basic_demo(struct zr_window *window, struct zr_style *config, struct icons *img) +basic_demo(struct zr_context *ctx, struct icons *img) { static int image_active; static int check0 = 1; @@ -367,106 +344,111 @@ basic_demo(struct zr_window *window, struct zr_style *config, struct icons *img) static int piemenu_active = 0; int i = 0; - struct zr_context layout; - struct zr_context combo; - config->font.height = 20; - zr_begin(&layout, window, "Basic Demo"); + struct zr_layout layout; + struct zr_layout combo; + ctx->style.font.height = 20; + zr_begin(ctx, &layout, "Basic Demo", zr_rect(320, 50, 275, 610), + ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_TITLE); /*------------------------------------------------ * POPUP BUTTON *------------------------------------------------*/ - ui_header(&layout, config, "Popup & Scrollbar & Images"); - ui_widget(&layout, config, 35, 22); - if (zr_button_text_image(&layout, zr_image_id(img->directory), + ui_header(ctx, "Popup & Scrollbar & Images"); + ui_widget(ctx, 35, 22); + if (zr_button_text_image(ctx, zr_image_id(img->directory), "Images", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) image_active = !image_active; /*------------------------------------------------ * SELECTED IMAGE *------------------------------------------------*/ - ui_header(&layout, config, "Selected Image"); - ui_widget_centered(&layout, config, 100, 22); - zr_image(&layout, zr_image_id(img->images[selected_image])); + ui_header(ctx, "Selected Image"); + ui_widget_centered(ctx, 100, 22); + zr_image(ctx, zr_image_id(img->images[selected_image])); /*------------------------------------------------ * IMAGE POPUP *------------------------------------------------*/ if (image_active) { - struct zr_context popup; - static struct zr_vec2 scrollbar; - zr_popup_begin(&layout, &popup, ZR_POPUP_STATIC, 0, 0, - zr_rect(265, 0, 300, 220), scrollbar); - zr_layout_row_static(&popup, 82, 82, 3); + struct zr_layout popup; + zr_popup_begin(ctx, &popup, ZR_POPUP_STATIC, "Image Popup", 0, + zr_rect(265, 0, 300, 220)); + zr_layout_row_static(ctx, 82, 82, 3); for (i = 0; i < 9; ++i) { - if (zr_button_image(&popup, zr_image_id(img->images[i]), ZR_BUTTON_DEFAULT)) { + if (zr_button_image(ctx, zr_image_id(img->images[i]), ZR_BUTTON_DEFAULT)) { selected_image = i; image_active = 0; - zr_popup_close(&popup); + zr_popup_close(ctx); } } - zr_popup_end(&layout, &popup, &scrollbar); + zr_popup_end(ctx); } - /*------------------------------------------------ * COMBOBOX *------------------------------------------------*/ - ui_header(&layout, config, "Combo box"); - ui_widget(&layout, config, 40, 22); - zr_combo_begin_text(&layout, &combo, items[selected_item], &combo_active, 200, 0); - zr_layout_row_dynamic(&combo, 35, 1); - for (i = 0; i < 3; ++i) - if (zr_combo_item(&combo, items[i], ZR_TEXT_LEFT)) - selected_item = i; - zr_combo_end(&layout, &combo, &combo_active, 0); - - ui_widget(&layout, config, 40, 22); - zr_combo_begin_icon(&layout, &combo, items[selected_icon], - zr_image_id(img->images[selected_icon]), &combo2_active, 200, 0); - zr_layout_row_dynamic(&combo, 35, 1); - for (i = 0; i < 3; ++i) - if (zr_combo_item_icon(&combo, zr_image_id(img->images[i]), items[i], ZR_TEXT_RIGHT)) - selected_icon = i; - zr_combo_end(&layout, &combo, &combo2_active, 0); + ui_header(ctx, "Combo box"); + ui_widget(ctx, 40, 22); + if (zr_combo_begin_text(ctx, &combo, "items", items[selected_item], 200)) { + zr_layout_row_dynamic(ctx, 35, 1); + for (i = 0; i < 3; ++i) + if (zr_combo_item(ctx, items[i], ZR_TEXT_LEFT)) + selected_item = i; + zr_combo_end(ctx); + } + ui_widget(ctx, 40, 22); + if (zr_combo_begin_icon(ctx, &combo, "pictures", items[selected_icon], zr_image_id(img->images[selected_icon]), 200)) { + zr_layout_row_dynamic(ctx, 35, 1); + for (i = 0; i < 3; ++i) + if (zr_combo_item_icon(ctx, zr_image_id(img->images[i]), items[i], ZR_TEXT_RIGHT)) + selected_icon = i; + zr_combo_end(ctx); + } /*------------------------------------------------ * CHECKBOX *------------------------------------------------*/ - ui_header(&layout, config, "Checkbox"); - ui_widget(&layout, config, 30, 22); - zr_checkbox(&layout, "Flag 1", &check0); - ui_widget(&layout, config, 30, 22); - zr_checkbox(&layout, "Flag 2", &check1); + ui_header(ctx, "Checkbox"); + ui_widget(ctx, 30, 22); + zr_checkbox(ctx, "Flag 1", &check0); + ui_widget(ctx, 30, 22); + zr_checkbox(ctx, "Flag 2", &check1); /*------------------------------------------------ * PROGRESSBAR *------------------------------------------------*/ - ui_header(&layout, config, "Progressbar"); - ui_widget(&layout, config, 35, 22); - zr_progress(&layout, &prog, 100, zr_true); + ui_header(ctx, "Progressbar"); + ui_widget(ctx, 35, 22); + zr_progress(ctx, &prog, 100, zr_true); /*------------------------------------------------ * SLIDER *------------------------------------------------*/ - ui_header(&layout, config, "Slider"); - ui_widget(&layout, config, 35, 22); - zr_slider_int(&layout, 0, &slider, 100, 10); + ui_header(ctx, "Slider"); + ui_widget(ctx, 35, 22); + zr_slider_int(ctx, 0, &slider, 100, 10); /*------------------------------------------------ * PIEMENU *------------------------------------------------*/ - if (zr_input_is_mouse_down(zr_input(&layout), ZR_BUTTON_RIGHT) && - zr_input_is_mouse_hovering_rect(zr_input(&layout), layout.bounds)) + if (zr_input_is_mouse_down(&ctx->input, ZR_BUTTON_RIGHT) && + zr_input_is_mouse_hovering_rect(&ctx->input, layout.bounds)) piemenu_active = 1; + if (piemenu_active) { - int ret = ui_piemenu(&layout, config, zr_vec2(WINDOW_WIDTH/2-140, WINDOW_HEIGHT/2-140), 140, &img->menu[0], 6); + int ret = ui_piemenu(ctx, zr_vec2(WINDOW_WIDTH/2-140, WINDOW_HEIGHT/2-140), 140, &img->menu[0], 6); if (ret != -1) { fprintf(stdout, "piemenu selected: %d\n", ret); piemenu_active = 0; } } - zr_end(&layout, window); + zr_end(ctx); } +#if 0 +zr_window_init(&gui.grid_demo, zr_rect(600, 350, 275, 250), + ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_NO_SCROLLBAR, + &gui.queue, &gui.config, &gui.input); + static void grid_demo(struct zr_window *window, struct zr_style *config) { @@ -484,27 +466,28 @@ grid_demo(struct zr_window *window, struct zr_style *config) struct zr_context combo; config->font.height = 20; - zr_begin(&layout, window, "Grid Demo"); + zr_begin(ctx, window, "Grid Demo"); config->font.height = 18; - zr_layout_row_dynamic(&layout, 30, 2); - zr_label(&layout, "Floating point:", ZR_TEXT_RIGHT); - zr_edit(&layout, text[0], &text_len[0], 64, &text_active[0], &text_cursor[0], ZR_INPUT_FLOAT); - zr_label(&layout, "Hexadeximal:", ZR_TEXT_RIGHT); - zr_edit(&layout, text[1], &text_len[1], 64, &text_active[1], &text_cursor[1], ZR_INPUT_HEX); - zr_label(&layout, "Binary:", ZR_TEXT_RIGHT); - zr_edit(&layout, text[2], &text_len[2], 64, &text_active[2], &text_cursor[2], ZR_INPUT_BIN); - zr_label(&layout, "Checkbox:", ZR_TEXT_RIGHT); - zr_checkbox(&layout, "Check me", &check); - zr_label(&layout, "Combobox:", ZR_TEXT_RIGHT); - zr_combo_begin_text(&layout, &combo, items[selected_item], &combo_active, 200, 0); + zr_layout_row_dynamic(ctx, 30, 2); + zr_label(ctx, "Floating point:", ZR_TEXT_RIGHT); + zr_edit(ctx, text[0], &text_len[0], 64, &text_active[0], &text_cursor[0], ZR_INPUT_FLOAT); + zr_label(ctx, "Hexadeximal:", ZR_TEXT_RIGHT); + zr_edit(ctx, text[1], &text_len[1], 64, &text_active[1], &text_cursor[1], ZR_INPUT_HEX); + zr_label(ctx, "Binary:", ZR_TEXT_RIGHT); + zr_edit(ctx, text[2], &text_len[2], 64, &text_active[2], &text_cursor[2], ZR_INPUT_BIN); + zr_label(ctx, "Checkbox:", ZR_TEXT_RIGHT); + zr_checkbox(ctx, "Check me", &check); + zr_label(ctx, "Combobox:", ZR_TEXT_RIGHT); + zr_combo_begin_text(ctx, &combo, items[selected_item], &combo_active, 200, 0); zr_layout_row_dynamic(&combo, 30, 1); for (i = 0; i < 3; ++i) if (zr_combo_item(&combo, items[i], ZR_TEXT_LEFT)) selected_item = i; - zr_combo_end(&layout, &combo, &combo_active, 0); - zr_end(&layout, window); + zr_combo_end(ctx, &combo, &combo_active, 0); + zr_end(ctx, window); } +#endif /* ================================================================= * @@ -524,7 +507,7 @@ font_get_width(zr_handle handle, float height, const char *text, zr_size len) } static void -draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) +draw(NVGcontext *nvg, struct zr_context *ctx, int width, int height) { const struct zr_command *cmd; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT); @@ -536,7 +519,7 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) glEnable(GL_TEXTURE_2D); nvgBeginFrame(nvg, width, height, ((float)width/(float)height)); - zr_foreach_command(cmd, queue) { + zr_foreach(cmd, ctx) { switch (cmd->type) { case ZR_COMMAND_NOP: break; case ZR_COMMAND_SCISSOR: { @@ -548,17 +531,15 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) nvgBeginPath(nvg); nvgMoveTo(nvg, l->begin.x, l->begin.y); nvgLineTo(nvg, l->end.x, l->end.y); - nvgFillColor(nvg, nvgRGBA(l->color.r, l->color.g, l->color.b, l->color.a)); - nvgFill(nvg); + nvgStrokeColor(nvg, nvgRGBA(l->color.r, l->color.g, l->color.b, l->color.a)); + nvgStroke(nvg); } break; case ZR_COMMAND_CURVE: { const struct zr_command_curve *q = zr_command(curve, cmd); nvgBeginPath(nvg); nvgMoveTo(nvg, q->begin.x, q->begin.y); - nvgBezierTo(nvg, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, - q->ctrl[1].y, q->end.x, q->end.y); + nvgBezierTo(nvg, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, q->ctrl[1].y, q->end.x, q->end.y); nvgStrokeColor(nvg, nvgRGBA(q->color.r, q->color.g, q->color.b, q->color.a)); - nvgStrokeWidth(nvg, 3); nvgStroke(nvg); } break; case ZR_COMMAND_RECT: { @@ -595,7 +576,6 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) } break; case ZR_COMMAND_TEXT: { const struct zr_command_text *t = zr_command(text, cmd); - const float font_height = t->height; nvgBeginPath(nvg); nvgRoundedRect(nvg, t->x, t->y, t->w, t->h, 0); nvgFillColor(nvg, nvgRGBA(t->background.r, t->background.g, @@ -622,13 +602,14 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) default: break; } } - zr_command_queue_clear(queue); + zr_clear(ctx); nvgResetScissor(nvg); nvgEndFrame(nvg); glPopAttrib(); } + static void key(struct zr_input *in, SDL_Event *evt, int down) { @@ -699,11 +680,11 @@ main(int argc, char *argv[]) unsigned int dt; int i = 0; - /* images */ - struct icons icons; - /* GUI */ - struct gui gui; + struct icons icons; + struct zr_context ctx; + void *memory; + if (argc < 2) { fprintf(stdout,"Missing TTF Font file argument: demo \n"); exit(EXIT_FAILURE); @@ -761,70 +742,60 @@ main(int argc, char *argv[]) icons.menu[4] = nvgCreateImage(vg, "../icon/settings.png", 0); icons.menu[5] = nvgCreateImage(vg, "../icon/volume.png", 0); for (i = 0; i < 9; ++i) { - char buffer[64]; + char buffer[256]; sprintf(buffer, "../images/image%d.jpg", (i+1)); icons.images[i] = nvgCreateImage(vg, buffer, 0); } - /* GUI */ - memset(&gui, 0, sizeof gui); - gui.memory = malloc(MAX_MEMORY); - zr_command_queue_init_fixed(&gui.queue, gui.memory, MAX_MEMORY); + { + /* GUI */ + struct zr_user_font font; + memset(&ctx, 0, sizeof ctx); + memory = malloc(MAX_MEMORY); - gui.font.userdata.ptr = vg; - nvgTextMetrics(vg, NULL, NULL, &gui.font.height); - gui.font.width = font_get_width; - gui.font.height = 20; - zr_style_default(&gui.config, ZR_DEFAULT_ALL, &gui.font); - gui.config.rounding[ZR_ROUNDING_BUTTON] = 3; - - zr_window_init(&gui.button_demo, zr_rect(50, 50, 255, 600), - ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_BORDER_HEADER, - &gui.queue, &gui.config, &gui.input); - zr_window_init(&gui.basic_demo, zr_rect(320, 50, 275, 610), - ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_BORDER_HEADER, - &gui.queue, &gui.config, &gui.input); - zr_window_init(&gui.grid_demo, zr_rect(600, 350, 275, 250), - ZR_WINDOW_BORDER|ZR_WINDOW_MOVEABLE|ZR_WINDOW_BORDER_HEADER|ZR_WINDOW_NO_SCROLLBAR, - &gui.queue, &gui.config, &gui.input); + font.userdata.ptr = vg; + font.width = font_get_width; + font.height = 20; + zr_init_fixed(&ctx, memory, MAX_MEMORY, &font, sin, cos); + ctx.style.rounding[ZR_ROUNDING_BUTTON] = 3; + } while (running) { /* Input */ SDL_Event evt; started = SDL_GetTicks(); - zr_input_begin(&gui.input); + zr_input_begin(&ctx.input); while (SDL_PollEvent(&evt)) { if (evt.type == SDL_WINDOWEVENT && evt.window.event == SDL_WINDOWEVENT_RESIZED) glViewport(0, 0, evt.window.data1, evt.window.data2); else if (evt.type == SDL_QUIT) goto cleanup; else if (evt.type == SDL_KEYUP) - key(&gui.input, &evt, zr_false); + key(&ctx.input, &evt, zr_false); else if (evt.type == SDL_KEYDOWN) - key(&gui.input, &evt, zr_true); + key(&ctx.input, &evt, zr_true); else if (evt.type == SDL_MOUSEBUTTONDOWN) - btn(&gui.input, &evt, zr_true); + btn(&ctx.input, &evt, zr_true); else if (evt.type == SDL_MOUSEBUTTONUP) - btn(&gui.input, &evt, zr_false); + btn(&ctx.input, &evt, zr_false); else if (evt.type == SDL_MOUSEMOTION) - motion(&gui.input, &evt); + motion(&ctx.input, &evt); else if (evt.type == SDL_TEXTINPUT) - text(&gui.input, &evt); + text(&ctx.input, &evt); else if (evt.type == SDL_MOUSEWHEEL) - zr_input_scroll(&gui.input, evt.wheel.y); + zr_input_scroll(&ctx.input, evt.wheel.y); } - zr_input_end(&gui.input); + zr_input_end(&ctx.input); /* GUI */ - button_demo(&gui.button_demo, &gui.config, &icons); - basic_demo(&gui.basic_demo, &gui.config, &icons); - grid_demo(&gui.grid_demo, &gui.config); + button_demo(&ctx, &icons); + basic_demo(&ctx, &icons); /* Draw */ glClearColor(0.1f, 0.1f, 0.1f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); SDL_GetWindowSize(win, &width, &height); - draw(vg, &gui.queue, width, height); + draw(vg, &ctx, width, height); SDL_GL_SwapWindow(win); /* Timing */ @@ -852,7 +823,7 @@ cleanup: for (i = 0; i < 6; ++i) nvgDeleteImage(vg, icons.menu[i]); - free(gui.memory); + free(memory); nvgDeleteGLES2(vg); SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(win); diff --git a/example/filex/filex.c b/example/filex/filex.c index c460a29..e36f982 100644 --- a/example/filex/filex.c +++ b/example/filex/filex.c @@ -386,13 +386,7 @@ struct file_browser { size_t dir_count; /* gui */ - void *memory; struct media media; - struct zr_input input; - struct zr_command_queue queue; - struct zr_style config; - struct zr_user_font font; - struct zr_window window; struct zr_vec2 dir; struct zr_vec2 sel; float ratio_dir; @@ -410,21 +404,11 @@ file_browser_reload_directory_content(struct file_browser *browser, const char * } static void -file_browser_init(struct file_browser *browser, NVGcontext *vg, - struct zr_user_font *font, int width, int height) +file_browser_init(struct file_browser *browser, NVGcontext *vg) { memset(browser, 0, sizeof(*browser)); + browser->ratio_dir = 0.75; browser->ratio_sel = 0.25f; media_init(&browser->media, vg); - { - /* gui */ - browser->font = *font; - browser->memory = calloc(1, MAX_COMMAND_MEMORY); - memset(&browser->input, 0, sizeof(browser->input)); - zr_command_queue_init_fixed(&browser->queue, browser->memory, MAX_COMMAND_MEMORY); - zr_style_default(&browser->config, ZR_DEFAULT_ALL, &browser->font); - zr_window_init(&browser->window, zr_rect(0,0,width,height), 0, &browser->queue, &browser->config, &browser->input); - browser->ratio_dir = 0.75; browser->ratio_sel = 0.25f; - } { /* load files and sub-directory list */ const char *home = getenv("HOME"); @@ -463,30 +447,28 @@ file_browser_free(struct file_browser *browser) } static int -file_browser_run(struct file_browser *browser, int width, int height) +file_browser_run(struct file_browser *browser, struct zr_context *ctx, int width, int height) { - struct zr_context context; + struct zr_layout layout; struct media *media = &browser->media; struct icons *icons = &media->icons; struct zr_rect total_space; - browser->window.bounds.w = width; - browser->window.bounds.h = height; - zr_begin(&context, &browser->window, NULL); + if (zr_begin(ctx, &layout, "File Browser", zr_rect(0,0,width,height), 0)) { - struct zr_context sub; + struct zr_layout sub; float row_layout[3]; /* output path directory selector in the menubar */ - zr_menubar_begin(&context); + zr_menubar_begin(ctx); { char *d = browser->directory; char *begin = d + 1; - zr_layout_row_dynamic(&context, 25, 6); - zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); + zr_layout_row_dynamic(ctx, 25, 6); + zr_style_push_property(&ctx->style, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); while (*d++) { if (*d == '/') { *d = '\0'; - if (zr_button_text(&context, begin, ZR_BUTTON_DEFAULT)) { + if (zr_button_text(ctx, begin, ZR_BUTTON_DEFAULT)) { *d++ = '/'; *d = '\0'; file_browser_reload_directory_content(browser, browser->directory); break; @@ -495,43 +477,43 @@ file_browser_run(struct file_browser *browser, int width, int height) begin = d + 1; } } - zr_style_pop_property(&browser->config); + zr_style_pop_property(&ctx->style); } - zr_menubar_end(&context); + zr_menubar_end(ctx); /* window layout */ - total_space = zr_space(&context); + total_space = zr_window_get_content_region(ctx); row_layout[0] = (total_space.w - 8) * browser->ratio_sel; row_layout[1] = 8; row_layout[2] = (total_space.w - 8) * browser->ratio_dir; - zr_layout_row(&context, ZR_STATIC, total_space.h, 3, row_layout); - zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); + zr_layout_row(ctx, ZR_STATIC, total_space.h, 3, row_layout); + zr_style_push_property(&ctx->style, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 4)); /* output special important directory list in own window */ - zr_group_begin(&context, &sub, NULL, ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, browser->sel); + zr_group_begin(ctx, &sub, "Special", ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER); { struct zr_image home = icons->home.img; struct zr_image desktop = icons->desktop.img; struct zr_image computer = icons->computer.img; - zr_layout_row_dynamic(&sub, 40, 1); - zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(0, 0)); - if (zr_button_text_image(&sub, home, "home", ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) + zr_layout_row_dynamic(ctx, 40, 1); + zr_style_push_property(&ctx->style, 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(&sub,desktop,"desktop",ZR_TEXT_CENTERED, ZR_BUTTON_DEFAULT)) + 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(&sub,computer,"computer",ZR_TEXT_CENTERED,ZR_BUTTON_DEFAULT)) + if (zr_button_text_image(ctx,computer,"computer",ZR_TEXT_CENTERED,ZR_BUTTON_DEFAULT)) file_browser_reload_directory_content(browser, "/"); - zr_style_pop_property(&browser->config); + zr_style_pop_property(&ctx->style); + zr_group_end(ctx); } - zr_group_end(&context, &sub, &browser->sel); { /* scaler */ struct zr_rect bounds; - struct zr_input *in = &browser->input; - zr_layout_peek(&bounds, &context); - zr_spacing(&context, 1); + struct zr_input *in = &ctx->input; + zr_layout_peek(&bounds, ctx); + zr_spacing(ctx, 1); if ((zr_input_is_mouse_hovering_rect(in, bounds) || zr_input_is_mouse_prev_hovering_rect(in, bounds)) && zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) @@ -544,7 +526,7 @@ file_browser_run(struct file_browser *browser, int width, int height) } /* output directory content window */ - zr_group_begin(&context, &sub, NULL, ZR_WINDOW_BORDER, browser->dir); + zr_group_begin(ctx, &sub, "Content", ZR_WINDOW_BORDER); { int index = -1; size_t i = 0, j = 0, k = 0; @@ -557,20 +539,20 @@ file_browser_run(struct file_browser *browser, int width, int height) { /* draw one row of icons */ size_t n = j + cols; - zr_layout_row_dynamic(&sub, 135, cols); - zr_style_push_color(&browser->config, ZR_COLOR_BUTTON, zr_rgb(45, 45, 45)); - zr_style_push_color(&browser->config, ZR_COLOR_BORDER, zr_rgb(45, 45, 45)); + zr_layout_row_dynamic(ctx, 135, cols); + zr_style_push_color(&ctx->style, ZR_COLOR_BUTTON, zr_rgb(45, 45, 45)); + zr_style_push_color(&ctx->style, ZR_COLOR_BORDER, zr_rgb(45, 45, 45)); for (; j < count && j < n; ++j) { if (j < browser->dir_count) { /* draw and execute directory buttons */ - if (zr_button_image(&sub,icons->directory.img,ZR_BUTTON_DEFAULT)) + if (zr_button_image(ctx,icons->directory.img,ZR_BUTTON_DEFAULT)) index = (int)j; } else { /* draw and execute files buttons */ struct icon *icon; size_t fileIndex = ((size_t)j - browser->dir_count); icon = media_icon_for_file(media,browser->files[fileIndex]); - if (zr_button_image(&sub, icon->img, ZR_BUTTON_DEFAULT)) { + if (zr_button_image(ctx, icon->img, 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); @@ -578,19 +560,19 @@ file_browser_run(struct file_browser *browser, int width, int height) } } } - zr_style_pop_color(&browser->config); - zr_style_pop_color(&browser->config); + zr_style_pop_color(&ctx->style); + zr_style_pop_color(&ctx->style); } { /* draw one row of labels */ size_t n = k + cols; - zr_layout_row_dynamic(&sub, 20, cols); + zr_layout_row_dynamic(ctx, 20, cols); for (; k < count && k < n; k++) { if (k < browser->dir_count) { - zr_label(&sub, browser->directories[k], ZR_TEXT_CENTERED); + zr_label(ctx, browser->directories[k], ZR_TEXT_CENTERED); } else { size_t t = k-browser->dir_count; - zr_label(&sub,browser->files[t],ZR_TEXT_CENTERED); + zr_label(ctx,browser->files[t],ZR_TEXT_CENTERED); } } } @@ -606,11 +588,11 @@ file_browser_run(struct file_browser *browser, int width, int height) } file_browser_reload_directory_content(browser, browser->directory); } + zr_group_end(ctx); } - zr_group_end(&context, &sub, &browser->dir); - zr_style_pop_property(&browser->config); + zr_style_pop_property(&ctx->style); } - zr_end(&context, &browser->window); + zr_end(ctx); return 1; } /* ================================================================= @@ -631,7 +613,7 @@ font_get_width(zr_handle handle, float height, const char *text, size_t len) } static void -draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) +draw(NVGcontext *nvg, struct zr_context *ctx, int width, int height) { const struct zr_command *cmd; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT); @@ -643,7 +625,7 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) glEnable(GL_TEXTURE_2D); nvgBeginFrame(nvg, width, height, ((float)width/(float)height)); - zr_foreach_command(cmd, queue) { + zr_foreach(cmd, ctx) { switch (cmd->type) { case ZR_COMMAND_NOP: break; case ZR_COMMAND_SCISSOR: { @@ -724,7 +706,7 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) default: break; } } - zr_command_queue_clear(queue); + zr_clear(ctx); nvgResetScissor(nvg); nvgEndFrame(nvg); @@ -795,15 +777,14 @@ resize(SDL_Event *evt) int main(int argc, char *argv[]) { - int x,y,width, height; + int width, height; SDL_Window *win; SDL_GLContext glContext; NVGcontext *vg = NULL; + struct zr_context ctx; + void *memory; int running = 1; - unsigned int started; - unsigned int dt; - struct zr_user_font font; struct file_browser browser; const char *font_path; int icon_sheet; @@ -820,7 +801,6 @@ main(int argc, char *argv[]) WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN); glContext = SDL_GL_CreateContext(win); SDL_GetWindowSize(win, &width, &height); - SDL_GetWindowPosition(win, &x, &y); /* OpenGL */ glewExperimental = 1; @@ -836,44 +816,47 @@ main(int argc, char *argv[]) nvgFontSize(vg, 14); nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - /* GUI */ - memset(&browser, 0, sizeof browser); - font.userdata.ptr = vg; - nvgTextMetrics(vg, NULL, NULL, &font.height); - font.width = font_get_width; - file_browser_init(&browser, vg, &font, width, height); + { + /* GUI */ + struct zr_user_font font; + memory = malloc(MAX_MEMORY); + font.userdata.ptr = vg; + font.width = font_get_width; + nvgTextMetrics(vg, NULL, NULL, &font.height); + zr_init_fixed(&ctx, memory, MAX_MEMORY, &font, sin, cos); + file_browser_init(&browser, vg); + } while (running) { /* Input */ SDL_Event evt; - started = SDL_GetTicks(); - zr_input_begin(&browser.input); + zr_input_begin(&ctx.input); while (SDL_PollEvent(&evt)) { if (evt.type == SDL_WINDOWEVENT) resize(&evt); else if (evt.type == SDL_QUIT) goto cleanup; - else if (evt.type == SDL_KEYUP) key(&browser.input, &evt, zr_false); - else if (evt.type == SDL_KEYDOWN) key(&browser.input, &evt, zr_true); - else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&browser.input, &evt, zr_true); - else if (evt.type == SDL_MOUSEBUTTONUP) btn(&browser.input, &evt, zr_false); - else if (evt.type == SDL_MOUSEMOTION) motion(&browser.input, &evt); - else if (evt.type == SDL_TEXTINPUT) text(&browser.input, &evt); - else if (evt.type == SDL_MOUSEWHEEL) zr_input_scroll(&browser.input, evt.wheel.y); + else if (evt.type == SDL_KEYUP) key(&ctx.input, &evt, zr_false); + else if (evt.type == SDL_KEYDOWN) key(&ctx.input, &evt, zr_true); + else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&ctx.input, &evt, zr_true); + else if (evt.type == SDL_MOUSEBUTTONUP) btn(&ctx.input, &evt, zr_false); + else if (evt.type == SDL_MOUSEMOTION) motion(&ctx.input, &evt); + else if (evt.type == SDL_TEXTINPUT) text(&ctx.input, &evt); + else if (evt.type == SDL_MOUSEWHEEL) zr_input_scroll(&ctx.input, evt.wheel.y); } - zr_input_end(&browser.input); + zr_input_end(&ctx.input); SDL_GetWindowSize(win, &width, &height); - running = file_browser_run(&browser, width, height); + running = file_browser_run(&browser, &ctx, width, height); /* Draw */ glClearColor(0.4f, 0.4f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - draw(vg, &browser.queue, width, height); + draw(vg, &ctx, width, height); SDL_GL_SwapWindow(win); } cleanup: /* Cleanup */ - free(browser.memory); + free(memory); nvgDeleteGLES2(vg); SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(win); diff --git a/example/nodedit/nodedit.c b/example/nodedit/nodedit.c index 5ffae95..d7892bc 100644 --- a/example/nodedit/nodedit.c +++ b/example/nodedit/nodedit.c @@ -90,7 +90,6 @@ struct node_editor { struct node *end; int node_count; int link_count; - int menu; struct zr_rect bounds; struct node *selected; int show_grid; @@ -98,15 +97,6 @@ struct node_editor { struct node_linking linking; }; -struct gui { - void *memory; - struct zr_window window; - struct zr_input input; - struct zr_command_queue queue; - struct zr_style config; - struct zr_user_font font; -}; - /* ================================================================= * * NODE EDITOR @@ -191,22 +181,21 @@ node_editor_link(struct node_editor *editor, int in_id, int in_slot, } static void -node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, - struct zr_style *config) +node_editor_draw(struct zr_context *ctx, struct node_editor *nodedit) { int i = 0, n = 0; struct zr_rect total_space; - const struct zr_input *in = zr_input(layout); - struct zr_command_buffer *canvas = zr_canvas(layout); + const struct zr_input *in = &ctx->input; + struct zr_command_buffer *canvas = zr_window_get_canvas(ctx); struct node *updated = 0; /* allocate complete window space */ - total_space = zr_space(layout); - zr_layout_row_space_begin(layout, ZR_STATIC, total_space.h, (zr_size)nodedit->node_count); + total_space = zr_window_get_content_region(ctx); + zr_layout_space_begin(ctx, ZR_STATIC, total_space.h, (zr_size)nodedit->node_count); { - struct zr_context node; + struct zr_layout node, menu; struct node *it = nodedit->begin; - struct zr_rect size = zr_layout_row_space_bounds(layout); + struct zr_rect size = zr_layout_space_bounds(ctx); if (nodedit->show_grid) { /* display grid */ @@ -214,56 +203,52 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, const float grid_size = 32.0f; const struct zr_color grid_color = zr_rgb(50, 50, 50); for (x = (float)fmod(size.x - nodedit->scrolling.x, grid_size); x < size.w; x += grid_size) - zr_command_buffer_push_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, grid_color); + zr_draw_line(canvas, x+size.x, size.y, x+size.x, size.y+size.h, grid_color); for (y = (float)fmod(size.y - nodedit->scrolling.y, grid_size); y < size.h; y += grid_size) - zr_command_buffer_push_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, grid_color); + zr_draw_line(canvas, size.x, y+size.y, size.x+size.w, y+size.y, grid_color); } /* execute each node as a moveable group */ - zr_style_push_color(config, ZR_COLOR_WINDOW, zr_rgb(48, 48, 48)); + zr_style_push_color(&ctx->style, ZR_COLOR_WINDOW, zr_rgb(48, 48, 48)); while (it) { - /* calculate node group space */ - zr_layout_row_space_push(layout, zr_rect(it->bounds.x - nodedit->scrolling.x, + + /* calculate scrolled node window position and size */ + zr_layout_space_push(ctx, zr_rect(it->bounds.x - nodedit->scrolling.x, it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h)); /* execute node window */ - zr_group_begin(layout, &node, it->name, - ZR_WINDOW_MOVEABLE|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER, zr_vec2(0,0)); + if (zr_group_begin(ctx, &node, it->name, ZR_WINDOW_MOVEABLE|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_BORDER|ZR_WINDOW_TITLE)) { - int r,g,b; - float ratio[] = {0.25f, 0.75f}; - + static const float ratio[] = {0.25f, 0.75f}; /* always have last selected node on top */ if (zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, node.bounds) && (!(it->prev && zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, - zr_layout_row_space_rect_to_screen(layout, node.bounds)))) && + zr_layout_space_rect_to_screen(ctx, node.bounds)))) && nodedit->end != it) { updated = it; } /* ================= NODE CONTENT =====================*/ - zr_layout_row_dynamic(&node, 30, 1); - r = it->color.r, g = it->color.g, b = it->color.b; - zr_button_color(&node, it->color, ZR_BUTTON_DEFAULT); - zr_layout_row(&node, ZR_DYNAMIC, 30, 2, ratio); + zr_layout_row_dynamic(ctx, 30, 1); + zr_button_color(ctx, it->color, ZR_BUTTON_DEFAULT); + zr_layout_row(ctx, ZR_DYNAMIC, 30, 2, ratio); - zr_label(&node, "R:", ZR_TEXT_LEFT); - zr_slider_int(&node, 0, &r, 255, 10); - zr_label(&node, "G:", ZR_TEXT_LEFT); - zr_slider_int(&node, 0, &g, 255, 10); - zr_label(&node, "B:", ZR_TEXT_LEFT); - zr_slider_int(&node, 0, &b, 255, 10); - it->color.r = (zr_byte)r; it->color.g = (zr_byte)g; it->color.b = (zr_byte)b; + zr_label(ctx, "R:", ZR_TEXT_LEFT); + it->color.r = (zr_byte)zr_slide_int(ctx, 0, it->color.r, 255, 10); + zr_label(ctx, "G:", ZR_TEXT_LEFT); + it->color.g = (zr_byte)zr_slide_int(ctx, 0, it->color.g, 255, 10); + zr_label(ctx, "B:", ZR_TEXT_LEFT); + it->color.b = (zr_byte)zr_slide_int(ctx, 0, it->color.b, 255, 10); /* ====================================================*/ + zr_group_end(ctx); } - zr_group_end(layout, &node, NULL); { /* node connector and linking */ float space; struct zr_rect bounds; - bounds = zr_layout_row_space_rect_to_local(layout, node.bounds); + bounds = zr_layout_space_rect_to_local(ctx, node.bounds); bounds.x += nodedit->scrolling.x; bounds.y += nodedit->scrolling.y; it->bounds = bounds; @@ -275,7 +260,7 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, circle.x = node.bounds.x + node.bounds.w-4; circle.y = node.bounds.y + space * (n+1); circle.w = 8; circle.h = 8; - zr_command_buffer_push_circle(canvas, circle, zr_rgb(100, 100, 100)); + zr_draw_circle(canvas, circle, zr_rgb(100, 100, 100)); /* start linking process */ if (zr_input_is_mouse_click_in_rect(in, ZR_BUTTON_LEFT, circle)) { @@ -290,7 +275,7 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, nodedit->linking.input_slot == n) { struct zr_vec2 l0 = zr_vec2(circle.x + 3, circle.y + 3); struct zr_vec2 l1 = in->mouse.pos; - zr_command_buffer_push_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, + zr_draw_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, l1.x - 50.0f, l1.y, l1.x, l1.y, zr_rgb(100, 100, 100)); } } @@ -302,7 +287,7 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, circle.x = node.bounds.x-4; circle.y = node.bounds.y + space * (n+1); circle.w = 8; circle.h = 8; - zr_command_buffer_push_circle(canvas, circle, zr_rgb(100, 100, 100)); + zr_draw_circle(canvas, circle, zr_rgb(100, 100, 100)); if (zr_input_is_mouse_released(in, ZR_BUTTON_LEFT) && zr_input_is_mouse_hovering_rect(in, circle) && nodedit->linking.active && nodedit->linking.node != it) { @@ -329,34 +314,33 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, struct node *no = node_editor_find(nodedit, link->output_id); float spacei = node.bounds.h / ((ni->output_count) + 1); float spaceo = node.bounds.h / ((no->input_count) + 1); - struct zr_vec2 l0 = zr_layout_row_space_to_screen(layout, + struct zr_vec2 l0 = zr_layout_space_to_screen(ctx, zr_vec2(ni->bounds.x + ni->bounds.w, 3+ni->bounds.y + spacei * (link->input_slot+1))); - struct zr_vec2 l1 = zr_layout_row_space_to_screen(layout, + struct zr_vec2 l1 = zr_layout_space_to_screen(ctx, zr_vec2(no->bounds.x, 3 + no->bounds.y + spaceo * (link->output_slot+1))); l0.x -= nodedit->scrolling.x; l0.y -= nodedit->scrolling.y; l1.x -= nodedit->scrolling.x; l1.y -= nodedit->scrolling.y; - zr_command_buffer_push_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, + zr_draw_curve(canvas, l0.x, l0.y, l0.x + 50.0f, l0.y, l1.x - 50.0f, l1.y, l1.x, l1.y, zr_rgb(100, 100, 100)); } - zr_style_pop_color(config); + zr_style_pop_color(&ctx->style); if (updated) { - /* reshuffle nodes to have last recently selected node on the top */ + /* reshuffle nodes to have last recently selected node on top */ node_editor_pop(nodedit, updated); node_editor_push(nodedit, updated); } - /* node selection + right click popup context menu activation */ - if (!nodedit->menu && zr_input_mouse_clicked(in, ZR_BUTTON_RIGHT, zr_layout_row_space_bounds(layout))) { + /* node selection */ + if (zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, zr_layout_space_bounds(ctx))) { it = nodedit->begin; nodedit->selected = NULL; - nodedit->menu = zr_true; nodedit->bounds = zr_rect(in->mouse.pos.x, in->mouse.pos.y, 100, 200); while (it) { - struct zr_rect b = zr_layout_row_space_rect_to_screen(layout, it->bounds); + struct zr_rect b = zr_layout_space_rect_to_screen(ctx, it->bounds); b.x -= nodedit->scrolling.x; b.y -= nodedit->scrolling.y; if (zr_input_is_mouse_hovering_rect(in, b)) @@ -365,35 +349,22 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, } } - /* popup context menu */ - if (nodedit->menu) { - struct zr_context menu; + /* contextual menu */ + if (zr_contextual_begin(ctx, &menu, 0, zr_vec2(100, 220))) { const char *grid_option[] = {"Show Grid", "Hide Grid"}; - zr_contextual_begin(layout, &menu, ZR_WINDOW_NO_SCROLLBAR, &nodedit->menu, nodedit->bounds); - zr_layout_row_dynamic(&menu, 25, 1); - if (!nodedit->selected) { - /* menu content if no selected node */ - if (zr_contextual_item(&menu, "New", ZR_TEXT_CENTERED)) - node_editor_add(nodedit, "New", zr_rect(400, 260, 180, 220), - zr_rgb(255, 255, 255), 1, 2); - if (zr_contextual_item(&menu, grid_option[nodedit->show_grid],ZR_TEXT_CENTERED)) - nodedit->show_grid = !nodedit->show_grid; - } else { - /* menu content if selected node */ - if (zr_contextual_item(&menu, "Delete", ZR_TEXT_CENTERED)) - fprintf(stdout, "pressed delete!\n"); - if (zr_contextual_item(&menu, "Rename", ZR_TEXT_CENTERED)) - fprintf(stdout, "pressed rename!\n"); - if (zr_contextual_item(&menu, "Copy", ZR_TEXT_CENTERED)) - fprintf(stdout, "pressed copy!\n"); - } - zr_contextual_end(layout, &menu, &nodedit->menu); + zr_layout_row_dynamic(ctx, 25, 1); + if (zr_contextual_item(ctx, "New", ZR_TEXT_CENTERED)) + node_editor_add(nodedit, "New", zr_rect(400, 260, 180, 220), + zr_rgb(255, 255, 255), 1, 2); + if (zr_contextual_item(ctx, grid_option[nodedit->show_grid],ZR_TEXT_CENTERED)) + nodedit->show_grid = !nodedit->show_grid; + zr_contextual_end(ctx); } } - zr_layout_row_space_end(layout); + zr_layout_space_end(ctx); /* window content scrolling */ - if (zr_input_is_mouse_hovering_rect(in, layout->bounds) && + if (zr_input_is_mouse_hovering_rect(in, zr_window_get_bounds(ctx)) && zr_input_is_mouse_down(in, ZR_BUTTON_MIDDLE)) { nodedit->scrolling.x += in->mouse.delta.x; nodedit->scrolling.y += in->mouse.delta.y; @@ -444,7 +415,7 @@ font_get_width(zr_handle handle, float height, const char *text, size_t len) } static void -draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) +draw(NVGcontext *nvg, struct zr_context *ctx, int width, int height) { const struct zr_command *cmd; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT); @@ -456,7 +427,7 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) glEnable(GL_TEXTURE_2D); nvgBeginFrame(nvg, width, height, ((float)width/(float)height)); - zr_foreach_command(cmd, queue) { + zr_foreach(cmd, ctx) { switch (cmd->type) { case ZR_COMMAND_NOP: break; case ZR_COMMAND_SCISSOR: { @@ -468,17 +439,15 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) nvgBeginPath(nvg); nvgMoveTo(nvg, l->begin.x, l->begin.y); nvgLineTo(nvg, l->end.x, l->end.y); - nvgFillColor(nvg, nvgRGBA(l->color.r, l->color.g, l->color.b, l->color.a)); - nvgFill(nvg); + nvgStrokeColor(nvg, nvgRGBA(l->color.r, l->color.g, l->color.b, l->color.a)); + nvgStroke(nvg); } break; case ZR_COMMAND_CURVE: { const struct zr_command_curve *q = zr_command(curve, cmd); nvgBeginPath(nvg); nvgMoveTo(nvg, q->begin.x, q->begin.y); - nvgBezierTo(nvg, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, - q->ctrl[1].y, q->end.x, q->end.y); + nvgBezierTo(nvg, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, q->ctrl[1].y, q->end.x, q->end.y); nvgStrokeColor(nvg, nvgRGBA(q->color.r, q->color.g, q->color.b, q->color.a)); - nvgStrokeWidth(nvg, 3); nvgStroke(nvg); } break; case ZR_COMMAND_RECT: { @@ -530,10 +499,11 @@ draw(NVGcontext *nvg, struct zr_command_queue *queue, int width, int height) nvgFillPaint(nvg, imgpaint); nvgFill(nvg); } break; + case ZR_COMMAND_ARC: default: break; } } - zr_command_queue_clear(queue); + zr_clear(ctx); nvgResetScissor(nvg); nvgEndFrame(nvg); @@ -608,17 +578,20 @@ main(int argc, char *argv[]) int x, y, width, height; const char *font_path; zr_size font_height; + SDL_SysWMinfo info; SDL_Window *win; SDL_GLContext glContext; NVGcontext *vg = NULL; + int running = zr_true; unsigned int started; unsigned int dt; /* GUI */ struct node_editor nodedit; - struct gui gui; + struct zr_context ctx; + void *memory; if (argc < 2) { fprintf(stdout,"Missing TTF Font file argument: gui \n"); @@ -653,67 +626,53 @@ main(int argc, char *argv[]) nvgFontSize(vg, font_height); nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE); - /* GUI */ - memset(&gui, 0, sizeof gui); - gui.memory = malloc(MAX_MEMORY); - zr_command_queue_init_fixed(&gui.queue, gui.memory, MAX_MEMORY); + { + /* GUI */ + struct zr_user_font font; + memset(&ctx, 0, sizeof ctx); + memory = malloc(MAX_MEMORY); - gui.font.userdata.ptr = vg; - nvgTextMetrics(vg, NULL, NULL, &gui.font.height); - gui.font.width = font_get_width; - zr_style_default(&gui.config, ZR_DEFAULT_ALL, &gui.font); - gui.config.header.align = ZR_HEADER_RIGHT; - - zr_window_init(&gui.window, zr_rect(0, 0, width, height), - ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSEABLE, - &gui.queue, &gui.config, &gui.input); + font.userdata.ptr = vg; + nvgTextMetrics(vg, NULL, NULL, &font.height); + font.width = font_get_width; + zr_init_fixed(&ctx, memory, MAX_MEMORY, &font, sin, cos); + ctx.style.header.align = ZR_HEADER_RIGHT; + } node_editor_init(&nodedit); while (running) { /* Input */ SDL_Event evt; started = SDL_GetTicks(); - zr_input_begin(&gui.input); + zr_input_begin(&ctx.input); while (SDL_PollEvent(&evt)) { if (evt.type == SDL_WINDOWEVENT) resize(&evt); else if (evt.type == SDL_QUIT) goto cleanup; - else if (evt.type == SDL_KEYUP) key(&gui.input, &evt, zr_false); - else if (evt.type == SDL_KEYDOWN) key(&gui.input, &evt, zr_true); - else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&gui.input, &evt, zr_true); - else if (evt.type == SDL_MOUSEBUTTONUP) btn(&gui.input, &evt, zr_false); - else if (evt.type == SDL_MOUSEMOTION) motion(&gui.input, &evt); - else if (evt.type == SDL_TEXTINPUT) text(&gui.input, &evt); - else if (evt.type == SDL_MOUSEWHEEL) zr_input_scroll(&gui.input, evt.wheel.y); + else if (evt.type == SDL_KEYUP) key(&ctx.input, &evt, zr_false); + else if (evt.type == SDL_KEYDOWN) key(&ctx.input, &evt, zr_true); + else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&ctx.input, &evt, zr_true); + else if (evt.type == SDL_MOUSEBUTTONUP) btn(&ctx.input, &evt, zr_false); + else if (evt.type == SDL_MOUSEMOTION) motion(&ctx.input, &evt); + else if (evt.type == SDL_TEXTINPUT) text(&ctx.input, &evt); + else if (evt.type == SDL_MOUSEWHEEL) zr_input_scroll(&ctx.input, evt.wheel.y); } - zr_input_end(&gui.input); + zr_input_end(&ctx.input); { int incursor; - struct zr_context layout; - struct zr_rect bounds = gui.window.bounds; - zr_flags ret; - - ret = zr_begin(&layout, &gui.window, "Node Editor"); - if (ret & ZR_WINDOW_CLOSEABLE) - goto cleanup; - - /* borderless os window dragging */ - incursor = zr_input_is_mouse_hovering_rect(&gui.input, - zr_rect(layout.bounds.x, layout.bounds.y, layout.bounds.w, layout.header_h)); - if (zr_input_is_mouse_down(&gui.input, ZR_BUTTON_LEFT) && incursor) { - x += gui.input.mouse.delta.x; - y += gui.input.mouse.delta.y; - SDL_SetWindowPosition(win, x, y); - } - node_editor_draw(&layout, &nodedit, &gui.config); - zr_end(&layout, &gui.window); + struct zr_layout layout; + if (zr_begin(&ctx, &layout, "Nodedit", zr_rect(0,0,width,height), + ZR_WINDOW_BORDER|ZR_WINDOW_NO_SCROLLBAR|ZR_WINDOW_CLOSEABLE)) + node_editor_draw(&ctx, &nodedit); + else goto cleanup; + zr_end(&ctx); } /* GUI */ glClearColor(0.4f, 0.4f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); SDL_GetWindowSize(win, &width, &height); - draw(vg, &gui.queue, width, height); + draw(vg, &ctx, width, height); SDL_GL_SwapWindow(win); /* Timing */ @@ -724,7 +683,7 @@ main(int argc, char *argv[]) cleanup: /* Cleanup */ - free(gui.memory); + free(memory); nvgDeleteGLES2(vg); SDL_GL_DeleteContext(glContext); SDL_DestroyWindow(win); diff --git a/zahnrad.c b/zahnrad.c index 77b10f0..212be91 100644 --- a/zahnrad.c +++ b/zahnrad.c @@ -19,6 +19,163 @@ */ #include "zahnrad.h" +/* ============================================================== + * + * INTERNAL + * + * =============================================================== */ +#define ZR_POOL_DEFAULT_CAPACTIY 16 +#define ZR_VALUE_PAGE_CAPACITY 32 +#define ZR_DEFAULT_COMMAND_BUFFER_SIZE (4*1024) + +enum zr_heading { + ZR_UP, + ZR_RIGHT, + ZR_DOWN, + ZR_LEFT +}; + +enum zr_orientation { + ZR_VERTICAL, + ZR_HORIZONTAL +}; + +struct zr_text_selection { + int active; + /* current selection state */ + zr_size begin; + /* text selection beginning glyph index */ + zr_size end; + /* text selection ending glyph index */ +}; + +struct zr_edit_box { + struct zr_buffer buffer; + /* glyph buffer to add text into */ + int active; + /* flag indicating if the buffer is currently being modified */ + zr_size cursor; + /* current glyph (not byte) cursor position */ + zr_size glyphs; + /* number of glyphs inside the edit box */ + struct zr_clipboard clip; + /* copy paste callbacks */ + zr_filter filter; + /* input filter callback */ + struct zr_text_selection sel; + /* text selection */ + float scrollbar; + /* edit field scrollbar */ + int text_inserted; +}; + +enum zr_internal_window_flags { + ZR_WINDOW_SUB = ZR_FLAG(12), + /* Marks the window as subwindow of another window*/ + ZR_WINDOW_GROUP = ZR_FLAG(13), + /* Marks the window as window widget group */ + ZR_WINDOW_POPUP = ZR_FLAG(14), + /* Marks the window as a popup window */ + ZR_WINDOW_NONBLOCK = ZR_FLAG(15), + /* Marks the window as a nonblock popup window */ + ZR_WINDOW_CONTEXTUAL = ZR_FLAG(16), + /* Marks the window as a combo box or menu */ + ZR_WINDOW_COMBO = ZR_FLAG(17), + /* Marks the window as a combo box */ + ZR_WINDOW_MENU = ZR_FLAG(18), + /* Marks the window as a menu */ + ZR_WINDOW_REMOVE_ROM = ZR_FLAG(19) + /* Removes the read only mode at the end of the window */ +}; + +struct zr_popup { + struct zr_window *win; + enum zr_internal_window_flags type; + zr_ulong name; +}; + +struct zr_edit_state { + zr_hash name; + zr_size cursor; + struct zr_text_selection sel; + float scrollbar; + unsigned int seq; + unsigned int old; + int active, prev; +}; + +struct zr_value { + int active, prev; + char buffer[ZR_MAX_NUMBER_BUFFER]; + zr_size length; + zr_size cursor; + zr_hash name; + unsigned int seq; + unsigned int old; + int state; +}; + +struct zr_table { + unsigned int seq; + zr_hash keys[ZR_VALUE_PAGE_CAPACITY]; + zr_uint values[ZR_VALUE_PAGE_CAPACITY]; + struct zr_table *next, *prev; +}; + +struct zr_window { + zr_hash name; + /* name of this window */ + unsigned int seq; + /* window lifeline */ + struct zr_rect bounds; + /* window size and position */ + zr_flags flags; + /* window flags modifing its behavior */ + struct zr_scroll scrollbar; + /* scrollbar x- and y-offset */ + struct zr_command_buffer buffer; + /* command buffer for queuing drawing calls */ + + /* persistent widget state */ + struct zr_value property; + struct zr_popup popup; + struct zr_edit_state edit; + struct zr_layout *layout; + + struct zr_table *tables; + unsigned short table_count; + unsigned short table_size; + + /* window list */ + struct zr_window *next; + struct zr_window *prev; + struct zr_window *parent; +}; + +union zr_page_data { + struct zr_table tbl; + struct zr_window win; +}; + +struct zr_window_page { + unsigned size; + struct zr_window_page *next; + union zr_page_data win[1]; +}; + +struct zr_pool { + struct zr_allocator alloc; + enum zr_allocation_type type; + unsigned int page_count; + struct zr_window_page *pages; + unsigned capacity; + zr_size size; + zr_size cap; +}; + +/* ============================================================== + * MATH + * =============================================================== */ #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif @@ -29,9 +186,6 @@ #define CLAMP(i,v,x) (MAX(MIN(v,x), i)) #endif -/* ============================================================== - * MATH - * =============================================================== */ #define ZR_PI 3.141592654f #define ZR_PI2 (ZR_PI * 2.0f) #define ZR_4_DIV_PI (1.27323954f) @@ -271,19 +425,6 @@ zr_strsiz(const char *str) return siz; } -static int -zr_strtoi(int *number, const char *buffer, zr_size len) -{ - zr_size i; - ZR_ASSERT(number); - ZR_ASSERT(buffer); - if (!number || !buffer) return 0; - *number = 0; - for (i = 0; i < len; ++i) - *number = *number * 10 + (buffer[i] - '0'); - return 1; -} - static int zr_strtof(float *number, const char *buffer) { @@ -335,38 +476,6 @@ zr_strtof(float *number, const char *buffer) return 1; } -static zr_size -zr_itos(char *buffer, int num) -{ - static const char digit[] = "0123456789"; - int shifter; - zr_size len = 0; - char *p = buffer; - - ZR_ASSERT(buffer); - if (!buffer) - return 0; - - if (num < 0) { - num = ZR_ABS(num); - *p++ = '-'; - } - shifter = num; - - do { - ++p; - shifter = shifter/10; - } while (shifter); - *p = '\0'; - - len = (zr_size)(p - buffer); - do { - *--p = digit[num % 10]; - num = num / 10; - } while (num); - return len; -} - static double zr_pow(double x, int n) { @@ -508,42 +617,61 @@ zr_dtos(char *s, double n) return (zr_size)(c - s); } -static zr_ulong -zr_hash(const void * key, zr_uint len, zr_ulong seed) +static zr_hash +zr_murmur_hash(const void * key, int len, zr_hash seed) { - const zr_ulong m = 0xc6a4a7935bd1e995UL; - const zr_uint r = 47; - zr_ulong h = seed ^ (len * m); - const zr_ulong * data = (const zr_ulong *)key; - const zr_ulong * end = data + (len/8); - const zr_byte * data2 = 0; + /* 32-Bit MurmurHash3 from: https://code.google.com/p/smhasher/wiki/MurmurHash3 */ + #define ZR_ROTL(x,r) ((x) << (r) | ((x) >> (32 - r))) + union {const zr_uint *i; const zr_byte *b;} conv; + const zr_byte *data = (const zr_byte*)key; + const int nblocks = len/4; + zr_uint h1 = seed; + const zr_uint c1 = 0xcc9e2d51; + const zr_uint c2 = 0x1b873593; + const zr_byte *tail; + const zr_uint *blocks; + zr_uint k1; + int i; - while(data != end){ - zr_ulong k = *data++; - k *= m; - k ^= k >> r; - k *= m; - h ^= k; - h *= m; + /* body */ + conv.b = (data + nblocks*4); + blocks = (const zr_uint*)conv.i; + for (i = -nblocks; i; ++i) { + k1 = blocks[i]; + k1 *= c1; + k1 = ZR_ROTL(k1,15); + k1 *= c2; + + h1 ^= k1; + h1 = ZR_ROTL(h1,13); + h1 = h1*5+0xe6546b64; } - data2 = (const zr_byte*)data; - switch(len & 7) - { - case 7: h ^= (zr_ulong)data2[6] << 48; - case 6: h ^= (zr_ulong)data2[5] << 40; - case 5: h ^= (zr_ulong)data2[4] << 32; - case 4: h ^= (zr_ulong)data2[3] << 24; - case 3: h ^= (zr_ulong)data2[2] << 16; - case 2: h ^= (zr_ulong)data2[1] << 8; - case 1: h ^= (zr_ulong)data2[0]; - h *= m; + /* tail */ + tail = (const zr_byte*)(data + nblocks*4); + k1 = 0; + switch (len & 3) { + case 3: k1 ^= (zr_uint)(tail[2] << 16); + case 2: k1 ^= (zr_uint)(tail[1] << 8u); + case 1: k1 ^= tail[0]; + k1 *= c1; + k1 = ZR_ROTL(k1,15); + k1 *= c2; + h1 ^= k1; default: break; - }; - h ^= h >> r; - h *= m; - h ^= h >> r; - return h; + } + + /* finalization */ + h1 ^= (zr_uint)len; + /* fmix32 */ + h1 ^= h1 >> 16; + h1 *= 0x85ebca6b; + h1 ^= h1 >> 13; + h1 *= 0xc2b2ae35; + h1 ^= h1 >> 16; + + #undef ZR_ROTL + return h1; } /* @@ -1126,15 +1254,15 @@ zr_user_font_glyphs_fitting_in_space(const struct zr_user_font *font, const char glyph_len = zr_utf_decode(text, &unicode, text_len); s = font->width(font->userdata, font->height, text, glyph_len); width = last_width = (float)s; - while ((width < space) && text_len) { + while ((width <= space) && text_len) { text_len -= glyph_len; offset += glyph_len; g++; l++; if (has_newline && (unicode == '\n' || unicode == '\r')) { - zr_rune next; + zr_rune next = 0; zr_utf_decode(&text[offset], &next, text_len); if (unicode == '\r') l--; - else if (unicode == '\n' && next == '\r') l -= 2; + else if ((unicode == '\n') && (next == '\r')) l -= 2; else l--; break; } @@ -1287,6 +1415,15 @@ zr_input_is_mouse_click_in_rect(const struct zr_input *i, enum zr_buttons id, btn->clicked) ? zr_true : zr_false; } +int +zr_input_any_mouse_click_in_rect(const struct zr_input *in, struct zr_rect b) +{ + int i, down = 0; + for (i = 0; i < ZR_BUTTON_MAX; ++i) + down = down || zr_input_is_mouse_click_in_rect(in, (enum zr_buttons)i, b); + return down; +} + int zr_input_is_mouse_hovering_rect(const struct zr_input *i, struct zr_rect rect) { @@ -1368,12 +1505,11 @@ zr_input_is_key_down(const struct zr_input *i, enum zr_keys key) /* ============================================================== * - * Buffer + * BUFFER * * ===============================================================*/ void -zr_buffer_init(struct zr_buffer *b, const struct zr_allocator *a, - zr_size initial_size, float grow_factor) +zr_buffer_init(struct zr_buffer *b, const struct zr_allocator *a, zr_size initial_size) { ZR_ASSERT(b); ZR_ASSERT(a); @@ -1385,7 +1521,7 @@ zr_buffer_init(struct zr_buffer *b, const struct zr_allocator *a, b->memory.ptr = a->alloc(a->userdata, initial_size); b->memory.size = initial_size; b->size = initial_size; - b->grow_factor = grow_factor; + b->grow_factor = 2.0f; b->pool = *a; } @@ -1517,25 +1653,7 @@ zr_buffer_alloc(struct zr_buffer *b, enum zr_buffer_allocation_type type, return memory; } -int -zr_buffer_push(struct zr_buffer *buffer, enum zr_buffer_allocation_type type, - void *data, zr_size size, zr_size align) -{ - zr_size i = 0; - zr_byte *dst, *src; - ZR_ASSERT(buffer); - ZR_ASSERT(data); - ZR_ASSERT(size); - - src = (zr_byte*)data; - dst = (zr_byte*)zr_buffer_alloc(buffer, type, size, align); - if (!dst) return zr_false; - for (i = 0; i < size; ++i) - dst[i] = src[i]; - return zr_true; -} - -void +static void zr_buffer_mark(struct zr_buffer *buffer, enum zr_buffer_allocation_type type) { ZR_ASSERT(buffer); @@ -1546,7 +1664,7 @@ zr_buffer_mark(struct zr_buffer *buffer, enum zr_buffer_allocation_type type) else buffer->marker[type].offset = buffer->allocated; } -void +static void zr_buffer_reset(struct zr_buffer *buffer, enum zr_buffer_allocation_type type) { ZR_ASSERT(buffer); @@ -1568,7 +1686,7 @@ zr_buffer_reset(struct zr_buffer *buffer, enum zr_buffer_allocation_type type) } } -void +static void zr_buffer_clear(struct zr_buffer *b) { ZR_ASSERT(b); @@ -1623,14 +1741,13 @@ zr_buffer_total(struct zr_buffer *buffer) * Command buffer * * ===============================================================*/ -void +static void zr_command_buffer_init(struct zr_command_buffer *cmdbuf, struct zr_buffer *buffer, enum zr_command_clipping clip) { ZR_ASSERT(cmdbuf); ZR_ASSERT(buffer); if (!cmdbuf || !buffer) return; - cmdbuf->queue = 0; cmdbuf->base = buffer; cmdbuf->use_clipping = clip; cmdbuf->begin = buffer->allocated; @@ -1638,28 +1755,18 @@ zr_command_buffer_init(struct zr_command_buffer *cmdbuf, cmdbuf->last = buffer->allocated; } -void +static void zr_command_buffer_reset(struct zr_command_buffer *buffer) { ZR_ASSERT(buffer); if (!buffer) return; - zr_zero(&buffer->stats, sizeof(buffer->stats)); buffer->begin = 0; buffer->end = 0; buffer->last = 0; buffer->clip = zr_null_rect; } -void -zr_command_buffer_clear(struct zr_command_buffer *buffer) -{ - ZR_ASSERT(buffer); - if (!buffer) return; - zr_command_buffer_reset(buffer); - zr_buffer_clear(buffer->base); -} - -void* +static void* zr_command_buffer_push(struct zr_command_buffer* b, enum zr_command_type t, zr_size size) { @@ -1689,7 +1796,7 @@ zr_command_buffer_push(struct zr_command_buffer* b, } void -zr_command_buffer_push_scissor(struct zr_command_buffer *b, struct zr_rect r) +zr_draw_scissor(struct zr_command_buffer *b, struct zr_rect r) { struct zr_command_scissor *cmd; ZR_ASSERT(b); @@ -1706,11 +1813,10 @@ zr_command_buffer_push_scissor(struct zr_command_buffer *b, struct zr_rect r) cmd->y = (short)r.y; cmd->w = (unsigned short)MAX(0, r.w); cmd->h = (unsigned short)MAX(0, r.h); - b->stats.scissors++; } void -zr_command_buffer_push_line(struct zr_command_buffer *b, float x0, float y0, +zr_draw_line(struct zr_command_buffer *b, float x0, float y0, float x1, float y1, struct zr_color c) { struct zr_command_line *cmd; @@ -1724,11 +1830,10 @@ zr_command_buffer_push_line(struct zr_command_buffer *b, float x0, float y0, cmd->end.x = (short)x1; cmd->end.y = (short)y1; cmd->color = c; - b->stats.lines++; } void -zr_command_buffer_push_curve(struct zr_command_buffer *b, float ax, float ay, +zr_draw_curve(struct zr_command_buffer *b, float ax, float ay, float ctrl0x, float ctrl0y, float ctrl1x, float ctrl1y, float bx, float by, struct zr_color col) { @@ -1748,11 +1853,10 @@ zr_command_buffer_push_curve(struct zr_command_buffer *b, float ax, float ay, cmd->end.x = (short)bx; cmd->end.y = (short)by; cmd->color = col; - b->stats.curves++; } void -zr_command_buffer_push_rect(struct zr_command_buffer *b, struct zr_rect rect, +zr_draw_rect(struct zr_command_buffer *b, struct zr_rect rect, float rounding, struct zr_color c) { struct zr_command_rect *cmd; @@ -1773,11 +1877,10 @@ zr_command_buffer_push_rect(struct zr_command_buffer *b, struct zr_rect rect, cmd->w = (unsigned short)MAX(0, rect.w); cmd->h = (unsigned short)MAX(0, rect.h); cmd->color = c; - b->stats.rectangles++; } void -zr_command_buffer_push_circle(struct zr_command_buffer *b, struct zr_rect r, +zr_draw_circle(struct zr_command_buffer *b, struct zr_rect r, struct zr_color c) { struct zr_command_circle *cmd; @@ -1797,11 +1900,10 @@ zr_command_buffer_push_circle(struct zr_command_buffer *b, struct zr_rect r, cmd->w = (unsigned short)MAX(r.w, 0); cmd->h = (unsigned short)MAX(r.h, 0); cmd->color = c; - b->stats.circles++; } void -zr_command_buffer_push_arc(struct zr_command_buffer *b, float cx, +zr_draw_arc(struct zr_command_buffer *b, float cx, float cy, float radius, float a_min, float a_max, struct zr_color c) { struct zr_command_arc *cmd; @@ -1817,7 +1919,7 @@ zr_command_buffer_push_arc(struct zr_command_buffer *b, float cx, } void -zr_command_buffer_push_triangle(struct zr_command_buffer *b,float x0,float y0, +zr_draw_triangle(struct zr_command_buffer *b,float x0,float y0, float x1, float y1, float x2, float y2, struct zr_color c) { struct zr_command_triangle *cmd; @@ -1841,11 +1943,10 @@ zr_command_buffer_push_triangle(struct zr_command_buffer *b,float x0,float y0, cmd->c.x = (short)x2; cmd->c.y = (short)y2; cmd->color = c; - b->stats.triangles++; } void -zr_command_buffer_push_image(struct zr_command_buffer *b, struct zr_rect r, +zr_draw_image(struct zr_command_buffer *b, struct zr_rect r, struct zr_image *img) { struct zr_command_image *cmd; @@ -1865,11 +1966,10 @@ zr_command_buffer_push_image(struct zr_command_buffer *b, struct zr_rect r, cmd->w = (unsigned short)MAX(0, r.w); cmd->h = (unsigned short)MAX(0, r.h); cmd->img = *img; - b->stats.images++; } void -zr_command_buffer_push_text(struct zr_command_buffer *b, struct zr_rect r, +zr_draw_text(struct zr_command_buffer *b, struct zr_rect r, const char *string, zr_size length, const struct zr_user_font *font, struct zr_color bg, struct zr_color fg) { @@ -1907,439 +2007,44 @@ zr_command_buffer_push_text(struct zr_command_buffer *b, struct zr_rect r, cmd->height = font->height; zr_memcopy(cmd->string, string, length); cmd->string[length] = '\0'; - b->stats.text++; - b->stats.glyphs += (unsigned int)length; } -const struct zr_command* -zr_command_buffer_begin(struct zr_command_buffer *buffer) -{ - zr_byte *memory; - ZR_ASSERT(buffer); - if (!buffer || !buffer->base) return 0; - if (buffer->last == buffer->begin) return 0; - memory = (zr_byte*)buffer->base->memory.ptr; - return zr_ptr_add_const(struct zr_command, memory, buffer->begin); -} - -const struct zr_command* -zr_command_buffer_next(struct zr_command_buffer *buffer, - struct zr_command *cmd) -{ - zr_byte *memory; - ZR_ASSERT(buffer); - if (!buffer) return 0; - if (!cmd) return 0; - if (cmd->next > buffer->last) return 0; - if (cmd->next > buffer->base->allocated) return 0; - memory = (zr_byte*)buffer->base->memory.ptr; - return zr_ptr_add_const(struct zr_command, memory, cmd->next); -} /* ============================================================== * - * Command Queue - * - * ===============================================================*/ -void -zr_command_queue_init(struct zr_command_queue *queue, - const struct zr_allocator *alloc, zr_size initial_size, float grow_factor) -{ - ZR_ASSERT(alloc); - ZR_ASSERT(queue); - if (!alloc || !queue) return; - zr_zero(queue, sizeof(*queue)); - zr_buffer_init(&queue->buffer, alloc, initial_size, grow_factor); -} - -void -zr_command_queue_init_fixed(struct zr_command_queue *queue, - void *memory, zr_size size) -{ - ZR_ASSERT(size); - ZR_ASSERT(memory); - ZR_ASSERT(queue); - if (!memory || !size || !queue) return; - zr_zero(queue, sizeof(*queue)); - zr_buffer_init_fixed(&queue->buffer, memory, size); -} - -void -zr_command_queue_insert_back(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - struct zr_command_buffer_list *list; - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - if (!queue || !buffer) return; - - list = &queue->list; - if (!list->begin) { - buffer->next = 0; - buffer->prev = 0; - list->begin = buffer; - list->end = buffer; - list->count = 1; - buffer->queue = queue; - return; - } - - list->end->next = buffer; - buffer->prev = list->end; - buffer->next = 0; - list->end = buffer; - list->count++; - buffer->queue = queue; -} - -void -zr_command_queue_insert_front(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - struct zr_command_buffer_list *list; - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - if (!queue || !buffer) return; - - list = &queue->list; - if (!list->begin) { - zr_command_queue_insert_back(queue, buffer); - return; - } - - list->begin->prev = buffer; - buffer->next = list->begin; - buffer->prev = 0; - list->begin = buffer; - list->count++; - buffer->queue = queue; -} - -void -zr_command_queue_remove(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - struct zr_command_buffer_list *list; - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - if (!queue || !buffer) return; - - list = &queue->list; - if (buffer->prev) - buffer->prev->next = buffer->next; - if (buffer->next) - buffer->next->prev = buffer->prev; - if (list->begin == buffer) - list->begin = buffer->next; - if (list->end == buffer) - list->end = buffer->prev; - - buffer->next = 0; - buffer->prev = 0; - list->count--; -} - -int -zr_command_queue_start_child(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - static const zr_size buf_size = sizeof(struct zr_command_sub_buffer); - static const zr_size buf_align = ZR_ALIGNOF(struct zr_command_sub_buffer); - struct zr_command_sub_buffer_stack *stack; - struct zr_command_sub_buffer *buf; - struct zr_command_sub_buffer *end; - zr_size offset; - zr_size size; - void *memory; - - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - if (!queue || !buffer) return zr_false; - - /* allocate header space from the buffer */ - memory = queue->buffer.memory.ptr; - buf = (struct zr_command_sub_buffer*) - zr_buffer_alloc(&queue->buffer, ZR_BUFFER_BACK, buf_size, buf_align); - if (!buf) return zr_false; - zr_zero(buf, sizeof(*buf)); - offset = (zr_size)(((zr_byte*)memory + queue->buffer.memory.size) - (zr_byte*)buf); - - /* setup sub buffer */ - buf->begin = buffer->end; - buf->end = buffer->end; - buf->parent_last = buffer->last; - buf->last = buf->begin; - buf->next = 0; - - /* add first sub-buffer into the stack */ - stack = &queue->stack; - stack->count++; - if (!stack->begin) { - stack->begin = offset; - stack->end = offset; - return zr_true; - } - - /* add sub-buffer at the end of the stack */ - size = queue->buffer.memory.size; - end = zr_ptr_add(struct zr_command_sub_buffer, memory, (size - stack->end)); - end->next = offset; - stack->end = offset; - return zr_true; -} - -void -zr_command_queue_finish_child(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - struct zr_command_sub_buffer *buf; - struct zr_command_sub_buffer_stack *stack; - zr_size offset; - - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - if (!queue || !buffer) return; - if (!queue->stack.count) return; - - stack = &queue->stack; - offset = queue->buffer.memory.size - stack->end; - buf = zr_ptr_add(struct zr_command_sub_buffer, queue->buffer.memory.ptr, offset); - buf->last = buffer->last; - buf->end = buffer->end; -} - -void -zr_command_queue_start(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - if (!queue || !buffer) return; - zr_zero(&buffer->stats, sizeof(buffer->stats)); - buffer->begin = queue->buffer.allocated; - buffer->end = buffer->begin; - buffer->last = buffer->begin; - buffer->clip = zr_null_rect; -} - -void -zr_command_queue_finish(struct zr_command_queue *queue, - struct zr_command_buffer *buffer) -{ - void *memory; - zr_size size; - zr_size i = 0; - struct zr_command_sub_buffer *iter; - struct zr_command_sub_buffer_stack *stack; - - ZR_ASSERT(queue); - ZR_ASSERT(buffer); - - if (!queue || !buffer) return; - stack = &queue->stack; - buffer->end = queue->buffer.allocated; - if (!stack->count) return; - - memory = queue->buffer.memory.ptr; - size = queue->buffer.memory.size; - iter = zr_ptr_add(struct zr_command_sub_buffer, memory, (size - stack->begin)); - - /* fix buffer command list for subbuffers */ - for (i = 0; i < queue->stack.count; ++i) { - struct zr_command *parent_last, *sublast, *last; - - parent_last = zr_ptr_add(struct zr_command, memory, iter->parent_last); - sublast = zr_ptr_add(struct zr_command, memory, iter->last); - last = zr_ptr_add(struct zr_command, memory, buffer->last); - - /* redirect the subbuffer to the end of the current command buffer */ - parent_last->next = iter->end; - if (i == (queue->stack.count-1)) - sublast->next = last->next; - last->next = iter->begin; - buffer->last = iter->last; - buffer->end = iter->end; - iter = zr_ptr_add(struct zr_command_sub_buffer, memory, size - iter->next); - } - queue->stack.count = 0; - queue->stack.begin = 0; - queue->stack.end = 0; -} - -void -zr_command_queue_free(struct zr_command_queue *queue) -{ - ZR_ASSERT(queue); - if (!queue) return; - zr_buffer_clear(&queue->buffer); - zr_buffer_free(&queue->buffer); -} - -void -zr_command_queue_clear(struct zr_command_queue *queue) -{ - ZR_ASSERT(queue); - if (!queue) return; - zr_buffer_clear(&queue->buffer); - queue->build = zr_false; - zr_zero(&queue->stack, sizeof(queue->stack)); -} - -void -zr_command_queue_build(struct zr_command_queue *queue) -{ - struct zr_command_buffer *iter; - struct zr_command_buffer *next; - struct zr_command *cmd; - zr_byte *buffer; - - iter = queue->list.begin; - buffer = (zr_byte*)queue->buffer.memory.ptr; - while (iter != 0) { - next = iter->next; - if (iter->last != iter->begin) { - cmd = zr_ptr_add(struct zr_command, buffer, iter->last); - while (next && next->last == next->begin) - next = next->next; /* skip empty command buffers */ - if (next) { - cmd->next = next->begin; - } else cmd->next = queue->buffer.allocated; - } - iter = next; - } - queue->build = zr_true; -} - -const struct zr_command* -zr_command_queue_begin(struct zr_command_queue *queue) -{ - struct zr_command_buffer *iter; - zr_byte *buffer; - ZR_ASSERT(queue); - if (!queue) return 0; - if (!queue->list.count) return 0; - - /* build one command list out of all command buffers */ - buffer = (zr_byte*)queue->buffer.memory.ptr; - if (!queue->build) - zr_command_queue_build(queue); - - iter = queue->list.begin; - while (iter && iter->begin == iter->end) - iter = iter->next; - if (!iter) return 0; - return zr_ptr_add_const(struct zr_command, buffer, iter->begin); -} - -const struct zr_command* -zr_command_queue_next(struct zr_command_queue *queue, const struct zr_command *cmd) -{ - zr_byte *buffer; - const struct zr_command *next; - ZR_ASSERT(queue); - if (!queue || !cmd || !queue->list.count) return 0; - if (cmd->next >= queue->buffer.allocated) - return 0; - buffer = (zr_byte*)queue->buffer.memory.ptr; - next = zr_ptr_add_const(struct zr_command, buffer, cmd->next); - return next; -} -/* ============================================================== - * - * Draw List + * CANVAS * * ===============================================================*/ #if ZR_COMPILE_WITH_VERTEX_BUFFER -void -zr_draw_list_init(struct zr_draw_list *list, struct zr_buffer *cmds, - struct zr_buffer *vertexes, struct zr_buffer *elements, - zr_sin_f sine, zr_cos_f cosine, struct zr_draw_null_texture null, - enum zr_anti_aliasing AA) +static void +zr_canvas_init(struct zr_canvas *list, zr_sin_f sine, zr_cos_f cosine) { zr_size i = 0; zr_zero(list, sizeof(*list)); list->sin = sine; list->cos = cosine; + for (i = 0; i < ZR_LEN(list->circle_vtx); ++i) { + const float a = ((float)i / (float)ZR_LEN(list->circle_vtx)) * 2 * ZR_PI; + list->circle_vtx[i].x = (float)cosine(a); + list->circle_vtx[i].y = (float)sine(a); + } +} + +static void +zr_canvas_setup(struct zr_canvas *list, struct zr_buffer *cmds, + struct zr_buffer *vertexes, struct zr_buffer *elements, + struct zr_draw_null_texture null, + enum zr_anti_aliasing AA) +{ list->null = null; list->clip_rect = zr_null_rect; list->vertexes = vertexes; list->elements = elements; list->buffer = cmds; list->AA = AA; - for (i = 0; i < ZR_LEN(list->circle_vtx); ++i) { - const float a = ((float)i / (float)ZR_LEN(list->circle_vtx)) * 2 * ZR_PI; - list->circle_vtx[i].x = cosine(a); - list->circle_vtx[i].y = sine(a); - } } -void -zr_draw_list_load(struct zr_draw_list *list, struct zr_command_queue *queue, - float line_thickness, unsigned int curve_segments) -{ - const struct zr_command *cmd; - ZR_ASSERT(list); - ZR_ASSERT(list->vertexes); - ZR_ASSERT(list->elements); - ZR_ASSERT(queue); - line_thickness = MAX(line_thickness, 1.0f); - if (!list || !queue || !list->vertexes || !list->elements) return; - - zr_foreach_command(cmd, queue) { - switch (cmd->type) { - case ZR_COMMAND_NOP: break; - case ZR_COMMAND_SCISSOR: { - const struct zr_command_scissor *s = zr_command(scissor, cmd); - zr_draw_list_add_clip(list, zr_rect(s->x, s->y, s->w, s->h)); - } break; - case ZR_COMMAND_LINE: { - const struct zr_command_line *l = zr_command(line, cmd); - zr_draw_list_add_line(list, zr_vec2(l->begin.x, l->begin.y), - zr_vec2(l->end.x, l->end.y), l->color, line_thickness); - } break; - case ZR_COMMAND_CURVE: { - const struct zr_command_curve *q = zr_command(curve, cmd); - zr_draw_list_add_curve(list, zr_vec2(q->begin.x, q->begin.y), - zr_vec2(q->ctrl[0].x, q->ctrl[0].y), zr_vec2(q->ctrl[1].x, q->ctrl[1].y), - zr_vec2(q->end.x, q->end.y), q->color, curve_segments, line_thickness); - } break; - case ZR_COMMAND_RECT: { - const struct zr_command_rect *r = zr_command(rect, cmd); - zr_draw_list_add_rect_filled(list, zr_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding); - } break; - case ZR_COMMAND_CIRCLE: { - const struct zr_command_circle *c = zr_command(circle, cmd); - zr_draw_list_add_circle_filled(list, zr_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, curve_segments); - } break; - case ZR_COMMAND_ARC: { - const struct zr_command_arc *c = zr_command(arc, cmd); - zr_draw_list_path_arc_to(list, zr_vec2(c->cx, c->cy), c->r, - c->a[0], c->a[1], curve_segments); - zr_draw_list_path_fill(list, c->color); - } break; - case ZR_COMMAND_TRIANGLE: { - const struct zr_command_triangle *t = zr_command(triangle, cmd); - zr_draw_list_add_triangle_filled(list, zr_vec2(t->a.x, t->a.y), - zr_vec2(t->b.x, t->b.y), zr_vec2(t->c.x, t->c.y), t->color); - } break; - case ZR_COMMAND_TEXT: { - const struct zr_command_text *t = zr_command(text, cmd); - zr_draw_list_add_text(list, t->font, zr_rect(t->x, t->y, t->w, t->h), - t->string, t->length, t->height, t->background, t->foreground); - } break; - case ZR_COMMAND_IMAGE: { - const struct zr_command_image *i = zr_command(image, cmd); - zr_draw_list_add_image(list, i->img, zr_rect(i->x, i->y, i->w, i->h), - zr_rgb(255, 255, 255)); - } break; - default: break; - } - } -} - -void -zr_draw_list_clear(struct zr_draw_list *list) +static void +zr_canvas_clear(struct zr_canvas *list) { ZR_ASSERT(list); if (!list) return; @@ -2360,49 +2065,8 @@ zr_draw_list_clear(struct zr_draw_list *list) list->clip_rect = zr_null_rect; } -int -zr_draw_list_is_empty(struct zr_draw_list *list) -{ - ZR_ASSERT(list); - if (!list) return zr_true; - return (list->cmd_count == 0); -} - -const struct zr_draw_command* -zr_draw_list_begin(const struct zr_draw_list *list) -{ - zr_byte *memory; - zr_size offset; - const struct zr_draw_command *cmd; - ZR_ASSERT(list); - ZR_ASSERT(list->buffer); - if (!list || !list->buffer || !list->cmd_count) return 0; - - memory = (zr_byte*)list->buffer->memory.ptr; - offset = list->buffer->memory.size - list->cmd_offset; - cmd = zr_ptr_add(const struct zr_draw_command, memory, offset); - return cmd; -} - -const struct zr_draw_command* -zr_draw_list_next(const struct zr_draw_list *list, const struct zr_draw_command *cmd) -{ - zr_byte *memory; - zr_size offset; - const struct zr_draw_command *end; - ZR_ASSERT(list); - if (!list || !list->buffer || !list->cmd_count) return 0; - - memory = (zr_byte*)list->buffer->memory.ptr; - offset = list->buffer->memory.size - list->cmd_offset; - end = zr_ptr_add(const struct zr_draw_command, memory, offset); - end -= (list->cmd_count-1); - if (cmd <= end) return 0; - return (cmd - 1); -} - static struct zr_vec2* -zr_draw_list_alloc_path(struct zr_draw_list *list, zr_size count) +zr_canvas_alloc_path(struct zr_canvas *list, zr_size count) { void *memory; struct zr_vec2 *points; @@ -2421,7 +2085,7 @@ zr_draw_list_alloc_path(struct zr_draw_list *list, zr_size count) } static struct zr_vec2 -zr_draw_list_path_last(struct zr_draw_list *list) +zr_canvas_path_last(struct zr_canvas *list) { void *memory; struct zr_vec2 *point; @@ -2433,7 +2097,7 @@ zr_draw_list_path_last(struct zr_draw_list *list) } static struct zr_draw_command* -zr_draw_list_push_command(struct zr_draw_list *list, struct zr_rect clip, +zr_canvas_push_command(struct zr_canvas *list, struct zr_rect clip, zr_handle texture) { static const zr_size cmd_align = ZR_ALIGNOF(struct zr_draw_command); @@ -2462,7 +2126,7 @@ zr_draw_list_push_command(struct zr_draw_list *list, struct zr_rect clip, } static struct zr_draw_command* -zr_draw_list_command_last(struct zr_draw_list *list) +zr_canvas_command_last(struct zr_canvas *list) { void *memory; zr_size size; @@ -2475,35 +2139,35 @@ zr_draw_list_command_last(struct zr_draw_list *list) return (cmd - (list->cmd_count-1)); } -void -zr_draw_list_add_clip(struct zr_draw_list *list, struct zr_rect rect) +static void +zr_canvas_add_clip(struct zr_canvas *list, struct zr_rect rect) { ZR_ASSERT(list); if (!list) return; if (!list->cmd_count) { - zr_draw_list_push_command(list, rect, list->null.texture); + zr_canvas_push_command(list, rect, list->null.texture); } else { - struct zr_draw_command *prev = zr_draw_list_command_last(list); - zr_draw_list_push_command(list, rect, prev->texture); + struct zr_draw_command *prev = zr_canvas_command_last(list); + zr_canvas_push_command(list, rect, prev->texture); } } static void -zr_draw_list_push_image(struct zr_draw_list *list, zr_handle texture) +zr_canvas_push_image(struct zr_canvas *list, zr_handle texture) { ZR_ASSERT(list); if (!list) return; if (!list->cmd_count) { - zr_draw_list_push_command(list, zr_null_rect, list->null.texture); + zr_canvas_push_command(list, zr_null_rect, list->null.texture); } else { - struct zr_draw_command *prev = zr_draw_list_command_last(list); + struct zr_draw_command *prev = zr_canvas_command_last(list); if (prev->texture.id != texture.id) - zr_draw_list_push_command(list, prev->clip_rect, texture); + zr_canvas_push_command(list, prev->clip_rect, texture); } } static struct zr_draw_vertex* -zr_draw_list_alloc_vertexes(struct zr_draw_list *list, zr_size count) +zr_canvas_alloc_vertexes(struct zr_canvas *list, zr_size count) { struct zr_draw_vertex *vtx; static const zr_size vtx_align = ZR_ALIGNOF(struct zr_draw_vertex); @@ -2519,7 +2183,7 @@ zr_draw_list_alloc_vertexes(struct zr_draw_list *list, zr_size count) } static zr_draw_index* -zr_draw_list_alloc_elements(struct zr_draw_list *list, zr_size count) +zr_canvas_alloc_elements(struct zr_canvas *list, zr_size count) { zr_draw_index *ids; struct zr_draw_command *cmd; @@ -2531,7 +2195,7 @@ zr_draw_list_alloc_elements(struct zr_draw_list *list, zr_size count) ids = (zr_draw_index*) zr_buffer_alloc(list->elements, ZR_BUFFER_FRONT, elem_size * count, elem_align); if (!ids) return 0; - cmd = zr_draw_list_command_last(list); + cmd = zr_canvas_command_last(list); list->element_count += (unsigned int)count; cmd->elem_count += (unsigned int)count; return ids; @@ -2548,7 +2212,7 @@ zr_draw_vertex(struct zr_vec2 pos, struct zr_vec2 uv, zr_draw_vertex_color col) } static void -zr_draw_list_add_poly_line(struct zr_draw_list *list, struct zr_vec2 *points, +zr_canvas_add_poly_line(struct zr_canvas *list, struct zr_vec2 *points, const unsigned int points_count, struct zr_color color, int closed, float thickness, enum zr_anti_aliasing aliasing) { @@ -2575,8 +2239,8 @@ zr_draw_list_add_poly_line(struct zr_draw_list *list, struct zr_vec2 *points, zr_size index = list->vertex_count; const zr_size idx_count = (thick_line) ? (count * 18) : (count * 12); const zr_size vtx_count = (thick_line) ? (points_count * 4): (points_count *3); - struct zr_draw_vertex *vtx = zr_draw_list_alloc_vertexes(list, vtx_count); - zr_draw_index *ids = zr_draw_list_alloc_elements(list, idx_count); + struct zr_draw_vertex *vtx = zr_canvas_alloc_vertexes(list, vtx_count); + zr_draw_index *ids = zr_canvas_alloc_elements(list, idx_count); zr_size size; struct zr_vec2 *normals, *temp; @@ -2737,8 +2401,8 @@ zr_draw_list_add_poly_line(struct zr_draw_list *list, struct zr_vec2 *points, zr_size idx = list->vertex_count; const zr_size idx_count = count * 6; const zr_size vtx_count = count * 4; - struct zr_draw_vertex *vtx = zr_draw_list_alloc_vertexes(list, vtx_count); - zr_draw_index *ids = zr_draw_list_alloc_elements(list, idx_count); + struct zr_draw_vertex *vtx = zr_canvas_alloc_vertexes(list, vtx_count); + zr_draw_index *ids = zr_canvas_alloc_elements(list, idx_count); if (!vtx || !ids) return; for (i1 = 0; i1 < count; ++i1) { @@ -2777,7 +2441,7 @@ zr_draw_list_add_poly_line(struct zr_draw_list *list, struct zr_vec2 *points, } static void -zr_draw_list_add_poly_convex(struct zr_draw_list *list, struct zr_vec2 *points, +zr_canvas_add_poly_convex(struct zr_canvas *list, struct zr_vec2 *points, const unsigned int points_count, struct zr_color color, enum zr_anti_aliasing aliasing) { static const zr_size pnt_align = ZR_ALIGNOF(struct zr_vec2); @@ -2795,8 +2459,8 @@ zr_draw_list_add_poly_convex(struct zr_draw_list *list, struct zr_vec2 *points, zr_size index = list->vertex_count; const zr_size idx_count = (points_count-2)*3 + points_count*6; const zr_size vtx_count = (points_count*2); - struct zr_draw_vertex *vtx = zr_draw_list_alloc_vertexes(list, vtx_count); - zr_draw_index *ids = zr_draw_list_alloc_elements(list, idx_count); + struct zr_draw_vertex *vtx = zr_canvas_alloc_vertexes(list, vtx_count); + zr_draw_index *ids = zr_canvas_alloc_elements(list, idx_count); unsigned int vtx_inner_idx = (unsigned int)(index + 0); unsigned int vtx_outer_idx = (unsigned int)(index + 1); @@ -2872,8 +2536,8 @@ zr_draw_list_add_poly_convex(struct zr_draw_list *list, struct zr_vec2 *points, zr_size index = list->vertex_count; const zr_size idx_count = (points_count-2)*3; const zr_size vtx_count = points_count; - struct zr_draw_vertex *vtx = zr_draw_list_alloc_vertexes(list, vtx_count); - zr_draw_index *ids = zr_draw_list_alloc_elements(list, idx_count); + struct zr_draw_vertex *vtx = zr_canvas_alloc_vertexes(list, vtx_count); + zr_draw_index *ids = zr_canvas_alloc_elements(list, idx_count); if (!vtx || !ids) return; for (i = 0; i < vtx_count; ++i) { vtx[0] = zr_draw_vertex(points[i], list->null.uv, col); @@ -2888,102 +2552,204 @@ zr_draw_list_add_poly_convex(struct zr_draw_list *list, struct zr_vec2 *points, } } -void -zr_draw_list_add_line(struct zr_draw_list *list, struct zr_vec2 a, +static void +zr_canvas_path_clear(struct zr_canvas *list) +{ + ZR_ASSERT(list); + if (!list) return; + zr_buffer_reset(list->buffer, ZR_BUFFER_FRONT); + list->path_count = 0; + list->path_offset = 0; +} + +static void +zr_canvas_path_line_to(struct zr_canvas *list, struct zr_vec2 pos) +{ + struct zr_vec2 *points = 0; + struct zr_draw_command *cmd = 0; + ZR_ASSERT(list); + if (!list) return; + if (!list->cmd_count) + zr_canvas_add_clip(list, zr_null_rect); + + cmd = zr_canvas_command_last(list); + if (cmd && cmd->texture.ptr != list->null.texture.ptr) + zr_canvas_push_image(list, list->null.texture); + + points = zr_canvas_alloc_path(list, 1); + if (!points) return; + points[0] = pos; +} + +static void +zr_canvas_path_arc_to_fast(struct zr_canvas *list, struct zr_vec2 center, + float radius, int a_min, int a_max) +{ + int a = 0; + ZR_ASSERT(list); + if (!list) return; + if (a_min <= a_max) { + for (a = a_min; a <= a_max; a++) { + const struct zr_vec2 c = list->circle_vtx[(zr_size)a % ZR_LEN(list->circle_vtx)]; + const float x = center.x + c.x * radius; + const float y = center.y + c.y * radius; + zr_canvas_path_line_to(list, zr_vec2(x, y)); + } + } +} + +static void +zr_canvas_path_arc_to(struct zr_canvas *list, struct zr_vec2 center, + float radius, float a_min, float a_max, unsigned int segments) +{ + unsigned int i = 0; + ZR_ASSERT(list); + if (!list) return; + if (radius == 0.0f) return; + for (i = 0; i <= segments; ++i) { + const float a = a_min + ((float)i / (float)segments) * (a_max - a_min); + const float x = center.x + (float)list->cos(a) * radius; + const float y = center.y + (float)list->sin(a) * radius; + zr_canvas_path_line_to(list, zr_vec2(x, y)); + } +} + +static void +zr_canvas_path_rect_to(struct zr_canvas *list, struct zr_vec2 a, + struct zr_vec2 b, float rounding) +{ + float r; + ZR_ASSERT(list); + if (!list) return; + r = rounding; + r = MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); + r = MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); + + if (r == 0.0f) { + zr_canvas_path_line_to(list, a); + zr_canvas_path_line_to(list, zr_vec2(b.x,a.y)); + zr_canvas_path_line_to(list, b); + zr_canvas_path_line_to(list, zr_vec2(a.x,b.y)); + } else { + zr_canvas_path_arc_to_fast(list, zr_vec2(a.x + r, a.y + r), r, 6, 9); + zr_canvas_path_arc_to_fast(list, zr_vec2(b.x - r, a.y + r), r, 9, 12); + zr_canvas_path_arc_to_fast(list, zr_vec2(b.x - r, b.y - r), r, 0, 3); + zr_canvas_path_arc_to_fast(list, zr_vec2(a.x + r, b.y - r), r, 3, 6); + } +} + +static void +zr_canvas_path_curve_to(struct zr_canvas *list, struct zr_vec2 p2, + struct zr_vec2 p3, struct zr_vec2 p4, unsigned int num_segments) +{ + unsigned int i_step; + float t_step; + struct zr_vec2 p1; + + ZR_ASSERT(list); + ZR_ASSERT(list->path_count); + if (!list || !list->path_count) return; + num_segments = MAX(num_segments, 1); + + p1 = zr_canvas_path_last(list); + t_step = 1.0f/(float)num_segments; + for (i_step = 1; i_step <= num_segments; ++i_step) { + float t = t_step * (float)i_step; + float u = 1.0f - t; + float w1 = u*u*u; + float w2 = 3*u*u*t; + float w3 = 3*u*t*t; + float w4 = t * t *t; + float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; + float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; + zr_canvas_path_line_to(list, zr_vec2(x,y)); + } +} + +static void +zr_canvas_path_fill(struct zr_canvas *list, struct zr_color color) +{ + struct zr_vec2 *points; + ZR_ASSERT(list); + if (!list) return; + points = (struct zr_vec2*)zr_buffer_memory(list->buffer); + zr_canvas_add_poly_convex(list, points, list->path_count, color, list->AA); + zr_canvas_path_clear(list); +} + +static void +zr_canvas_path_stroke(struct zr_canvas *list, struct zr_color color, + int closed, float thickness) +{ + struct zr_vec2 *points; + ZR_ASSERT(list); + if (!list) return; + points = (struct zr_vec2*)zr_buffer_memory(list->buffer); + zr_canvas_add_poly_line(list, points, list->path_count, color, + closed, thickness, list->AA); + zr_canvas_path_clear(list); +} + +static void +zr_canvas_add_line(struct zr_canvas *list, struct zr_vec2 a, struct zr_vec2 b, struct zr_color col, float thickness) { ZR_ASSERT(list); if (!list || !col.a) return; - zr_draw_list_path_line_to(list, zr_vec2_add(a, zr_vec2(0.5f, 0.5f))); - zr_draw_list_path_line_to(list, zr_vec2_add(b, zr_vec2(0.5f, 0.5f))); - zr_draw_list_path_stroke(list, col, ZR_STROKE_OPEN, thickness); + zr_canvas_path_line_to(list, zr_vec2_add(a, zr_vec2(0.5f, 0.5f))); + zr_canvas_path_line_to(list, zr_vec2_add(b, zr_vec2(0.5f, 0.5f))); + zr_canvas_path_stroke(list, col, ZR_STROKE_OPEN, thickness); } -void -zr_draw_list_add_rect(struct zr_draw_list *list, struct zr_rect rect, - struct zr_color col, float rounding, float line_thickness) -{ - ZR_ASSERT(list); - if (!list || !col.a) return; - zr_draw_list_path_rect_to(list, zr_vec2(rect.x + 0.5f, rect.y + 0.5f), - zr_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding); - zr_draw_list_path_stroke(list, col, ZR_STROKE_CLOSED, line_thickness); -} - -void -zr_draw_list_add_rect_filled(struct zr_draw_list *list, struct zr_rect rect, +static void +zr_canvas_add_rect(struct zr_canvas *list, struct zr_rect rect, struct zr_color col, float rounding) { ZR_ASSERT(list); if (!list || !col.a) return; - zr_draw_list_path_rect_to(list, zr_vec2(rect.x + 0.5f, rect.y + 0.5f), + zr_canvas_path_rect_to(list, zr_vec2(rect.x + 0.5f, rect.y + 0.5f), zr_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding); - zr_draw_list_path_fill(list, col); + zr_canvas_path_fill(list, col); } -void -zr_draw_list_add_triangle(struct zr_draw_list *list, struct zr_vec2 a, struct zr_vec2 b, - struct zr_vec2 c, struct zr_color col, float line_thickness) -{ - ZR_ASSERT(list); - if (!list) return; - if (!col.a) return; - zr_draw_list_path_line_to(list, a); - zr_draw_list_path_line_to(list, b); - zr_draw_list_path_line_to(list, c); - zr_draw_list_path_stroke(list, col, ZR_STROKE_CLOSED, line_thickness); -} - -void -zr_draw_list_add_triangle_filled(struct zr_draw_list *list, struct zr_vec2 a, +static void +zr_canvas_add_triangle(struct zr_canvas *list, struct zr_vec2 a, struct zr_vec2 b, struct zr_vec2 c, struct zr_color col) { ZR_ASSERT(list); if (!list || !col.a) return; - zr_draw_list_path_line_to(list, a); - zr_draw_list_path_line_to(list, b); - zr_draw_list_path_line_to(list, c); - zr_draw_list_path_fill(list, col); + zr_canvas_path_line_to(list, a); + zr_canvas_path_line_to(list, b); + zr_canvas_path_line_to(list, c); + zr_canvas_path_fill(list, col); } -void -zr_draw_list_add_circle(struct zr_draw_list *list, struct zr_vec2 center, - float radius, struct zr_color col, unsigned int segs, float line_thickness) -{ - float a_max; - ZR_ASSERT(list); - if (!list || !col.a) return; - a_max = ZR_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - zr_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - zr_draw_list_path_stroke(list, col, ZR_STROKE_CLOSED, line_thickness); -} - -void -zr_draw_list_add_circle_filled(struct zr_draw_list *list, struct zr_vec2 center, +static void +zr_canvas_add_circle(struct zr_canvas *list, struct zr_vec2 center, float radius, struct zr_color col, unsigned int segs) { float a_max; ZR_ASSERT(list); if (!list || !col.a) return; a_max = ZR_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; - zr_draw_list_path_arc_to(list, center, radius, 0.0f, a_max, segs); - zr_draw_list_path_fill(list, col); + zr_canvas_path_arc_to(list, center, radius, 0.0f, a_max, segs); + zr_canvas_path_fill(list, col); } -void -zr_draw_list_add_curve(struct zr_draw_list *list, struct zr_vec2 p0, +static void +zr_canvas_add_curve(struct zr_canvas *list, struct zr_vec2 p0, struct zr_vec2 cp0, struct zr_vec2 cp1, struct zr_vec2 p1, struct zr_color col, unsigned int segments, float thickness) { ZR_ASSERT(list); if (!list || !col.a) return; - zr_draw_list_path_line_to(list, p0); - zr_draw_list_path_curve_to(list, cp0, cp1, p1, segments); - zr_draw_list_path_stroke(list, col, ZR_STROKE_OPEN, thickness); + zr_canvas_path_line_to(list, p0); + zr_canvas_path_curve_to(list, cp0, cp1, p1, segments); + zr_canvas_path_stroke(list, col, ZR_STROKE_OPEN, thickness); } static void -zr_draw_list_push_rect_uv(struct zr_draw_list *list, struct zr_vec2 a, +zr_canvas_push_rect_uv(struct zr_canvas *list, struct zr_vec2 a, struct zr_vec2 c, struct zr_vec2 uva, struct zr_vec2 uvc, struct zr_color color) { zr_draw_vertex_color col = zr_color32(color); @@ -3001,8 +2767,8 @@ zr_draw_list_push_rect_uv(struct zr_draw_list *list, struct zr_vec2 a, d = zr_vec2(a.x, c.y); index = (zr_draw_index)list->vertex_count; - vtx = zr_draw_list_alloc_vertexes(list, 4); - idx = zr_draw_list_alloc_elements(list, 6); + vtx = zr_canvas_alloc_vertexes(list, 4); + idx = zr_canvas_alloc_elements(list, 6); if (!vtx || !idx) return; idx[0] = (zr_draw_index)(index+0); idx[1] = (zr_draw_index)(index+1); @@ -3015,14 +2781,14 @@ zr_draw_list_push_rect_uv(struct zr_draw_list *list, struct zr_vec2 a, vtx[3] = zr_draw_vertex(d, uvd, col); } -void -zr_draw_list_add_image(struct zr_draw_list *list, struct zr_image texture, +static void +zr_canvas_add_image(struct zr_canvas *list, struct zr_image texture, struct zr_rect rect, struct zr_color color) { ZR_ASSERT(list); if (!list) return; /* push new command with given texture */ - zr_draw_list_push_image(list, texture.handle); + zr_canvas_push_image(list, texture.handle); if (zr_image_is_subimage(&texture)) { /* add region inside of the texture */ struct zr_vec2 uv[2]; @@ -3030,15 +2796,15 @@ zr_draw_list_add_image(struct zr_draw_list *list, struct zr_image texture, uv[0].y = (float)texture.region[1]/(float)texture.h; uv[1].x = (float)(texture.region[0] + texture.region[2])/(float)texture.w; uv[1].y = (float)(texture.region[1] + texture.region[3])/(float)texture.h; - zr_draw_list_push_rect_uv(list, zr_vec2(rect.x, rect.y), + zr_canvas_push_rect_uv(list, zr_vec2(rect.x, rect.y), zr_vec2(rect.x + rect.w, rect.y + rect.h), uv[0], uv[1], color); - } else zr_draw_list_push_rect_uv(list, zr_vec2(rect.x, rect.y), + } else zr_canvas_push_rect_uv(list, zr_vec2(rect.x, rect.y), zr_vec2(rect.x + rect.w, rect.y + rect.h), zr_vec2(0.0f, 0.0f), zr_vec2(1.0f, 1.0f),color); } -void -zr_draw_list_add_text(struct zr_draw_list *list, const struct zr_user_font *font, +static void +zr_canvas_add_text(struct zr_canvas *list, const struct zr_user_font *font, struct zr_rect rect, const char *text, zr_size len, float font_height, struct zr_color bg, struct zr_color fg) { @@ -3057,8 +2823,8 @@ zr_draw_list_add_text(struct zr_draw_list *list, const struct zr_user_font *font return; /* draw text background */ - zr_draw_list_add_rect_filled(list, rect, bg, 0.0f); - zr_draw_list_push_image(list, font->texture); + zr_canvas_add_rect(list, rect, bg, 0.0f); + zr_canvas_push_image(list, font->texture); /* draw every glyph image */ x = rect.x; @@ -3078,7 +2844,7 @@ zr_draw_list_add_text(struct zr_draw_list *list, const struct zr_user_font *font gy = rect.y + (rect.h/2) - (font->height/2) + g.offset.y * scale; gw = g.width * scale; gh = g.height * scale; char_width = g.xadvance * scale; - zr_draw_list_push_rect_uv(list, zr_vec2(gx,gy), zr_vec2(gx + gw, gy+ gh), + zr_canvas_push_rect_uv(list, zr_vec2(gx,gy), zr_vec2(gx + gw, gy+ gh), g.uv[0], g.uv[1], fg); /* offset next glyph */ @@ -3089,143 +2855,117 @@ zr_draw_list_add_text(struct zr_draw_list *list, const struct zr_user_font *font } } -void -zr_draw_list_path_clear(struct zr_draw_list *list) -{ - ZR_ASSERT(list); - if (!list) return; - zr_buffer_reset(list->buffer, ZR_BUFFER_FRONT); - list->path_count = 0; - list->path_offset = 0; -} - -void -zr_draw_list_path_line_to(struct zr_draw_list *list, struct zr_vec2 pos) -{ - struct zr_vec2 *points; - struct zr_draw_command *cmd; - ZR_ASSERT(list); - if (!list) return; - if (!list->cmd_count) - zr_draw_list_add_clip(list, zr_null_rect); - - cmd = zr_draw_list_command_last(list); - if (cmd->texture.ptr != list->null.texture.ptr) - zr_draw_list_push_image(list, list->null.texture); - - points = zr_draw_list_alloc_path(list, 1); - if (!points) return; - points[0] = pos; -} - static void -zr_draw_list_path_arc_to_fast(struct zr_draw_list *list, struct zr_vec2 center, - float radius, int a_min, int a_max) +zr_canvas_load(struct zr_canvas *list, struct zr_context *queue, + float line_thickness, unsigned int curve_segments) { - int a = 0; + const struct zr_command *cmd; ZR_ASSERT(list); - if (!list) return; - if (a_min <= a_max) { - for (a = a_min; a <= a_max; a++) { - const struct zr_vec2 c = list->circle_vtx[(zr_size)a % ZR_LEN(list->circle_vtx)]; - const float x = center.x + c.x * radius; - const float y = center.y + c.y * radius; - zr_draw_list_path_line_to(list, zr_vec2(x, y)); + ZR_ASSERT(list->vertexes); + ZR_ASSERT(list->elements); + ZR_ASSERT(queue); + line_thickness = MAX(line_thickness, 1.0f); + if (!list || !queue || !list->vertexes || !list->elements) return; + + zr_foreach(cmd, queue) { + switch (cmd->type) { + case ZR_COMMAND_NOP: break; + case ZR_COMMAND_SCISSOR: { + const struct zr_command_scissor *s = zr_command(scissor, cmd); + zr_canvas_add_clip(list, zr_rect(s->x, s->y, s->w, s->h)); + } break; + case ZR_COMMAND_LINE: { + const struct zr_command_line *l = zr_command(line, cmd); + zr_canvas_add_line(list, zr_vec2(l->begin.x, l->begin.y), + zr_vec2(l->end.x, l->end.y), l->color, line_thickness); + } break; + case ZR_COMMAND_CURVE: { + const struct zr_command_curve *q = zr_command(curve, cmd); + zr_canvas_add_curve(list, zr_vec2(q->begin.x, q->begin.y), + zr_vec2(q->ctrl[0].x, q->ctrl[0].y), zr_vec2(q->ctrl[1].x, q->ctrl[1].y), + zr_vec2(q->end.x, q->end.y), q->color, curve_segments, line_thickness); + } break; + case ZR_COMMAND_RECT: { + const struct zr_command_rect *r = zr_command(rect, cmd); + zr_canvas_add_rect(list, zr_rect(r->x, r->y, r->w, r->h), + r->color, (float)r->rounding); + } break; + case ZR_COMMAND_CIRCLE: { + const struct zr_command_circle *c = zr_command(circle, cmd); + zr_canvas_add_circle(list, zr_vec2((float)c->x + (float)c->w/2, + (float)c->y + (float)c->h/2), (float)c->w/2, c->color, curve_segments); + } break; + case ZR_COMMAND_ARC: { + const struct zr_command_arc *c = zr_command(arc, cmd); + zr_canvas_path_arc_to(list, zr_vec2(c->cx, c->cy), c->r, + c->a[0], c->a[1], curve_segments); + zr_canvas_path_fill(list, c->color); + } break; + case ZR_COMMAND_TRIANGLE: { + const struct zr_command_triangle *t = zr_command(triangle, cmd); + zr_canvas_add_triangle(list, zr_vec2(t->a.x, t->a.y), + zr_vec2(t->b.x, t->b.y), zr_vec2(t->c.x, t->c.y), t->color); + } break; + case ZR_COMMAND_TEXT: { + const struct zr_command_text *t = zr_command(text, cmd); + zr_canvas_add_text(list, t->font, zr_rect(t->x, t->y, t->w, t->h), + t->string, t->length, t->height, t->background, t->foreground); + } break; + case ZR_COMMAND_IMAGE: { + const struct zr_command_image *i = zr_command(image, cmd); + zr_canvas_add_image(list, i->img, zr_rect(i->x, i->y, i->w, i->h), + zr_rgb(255, 255, 255)); + } break; + default: break; } } } void -zr_draw_list_path_arc_to(struct zr_draw_list *list, struct zr_vec2 center, - float radius, float a_min, float a_max, unsigned int segments) +zr_convert(struct zr_context *ctx, struct zr_buffer *cmds, + struct zr_buffer *vertexes, struct zr_buffer *elements, + struct zr_draw_null_texture null, enum zr_anti_aliasing AA, + float line_thickness, unsigned int circle_segment_count) { - unsigned int i = 0; - ZR_ASSERT(list); - if (!list) return; - if (radius == 0.0f) return; - for (i = 0; i <= segments; ++i) { - const float a = a_min + ((float)i / (float)segments) * (a_max - a_min); - const float x = center.x + list->cos(a) * radius; - const float y = center.y + list->sin(a) * radius; - zr_draw_list_path_line_to(list, zr_vec2(x, y)); - } + zr_canvas_setup(&ctx->canvas, cmds, vertexes, elements, null, AA); + zr_canvas_load(&ctx->canvas, ctx, line_thickness, circle_segment_count); } -void -zr_draw_list_path_rect_to(struct zr_draw_list *list, struct zr_vec2 a, - struct zr_vec2 b, float rounding) +const struct zr_draw_command* +zr__draw_begin(const struct zr_context *ctx, + const struct zr_buffer *buffer) { - float r; - ZR_ASSERT(list); - if (!list) return; - r = rounding; - r = MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); - r = MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); + zr_byte *memory; + zr_size offset; + const struct zr_draw_command *cmd; + ZR_ASSERT(buffer); + if (!buffer || !buffer->size || !ctx->canvas.cmd_count) return 0; - if (r == 0.0f) { - zr_draw_list_path_line_to(list, a); - zr_draw_list_path_line_to(list, zr_vec2(b.x,a.y)); - zr_draw_list_path_line_to(list, b); - zr_draw_list_path_line_to(list, zr_vec2(a.x,b.y)); - } else { - zr_draw_list_path_arc_to_fast(list, zr_vec2(a.x + r, a.y + r), r, 6, 9); - zr_draw_list_path_arc_to_fast(list, zr_vec2(b.x - r, a.y + r), r, 9, 12); - zr_draw_list_path_arc_to_fast(list, zr_vec2(b.x - r, b.y - r), r, 0, 3); - zr_draw_list_path_arc_to_fast(list, zr_vec2(a.x + r, b.y - r), r, 3, 6); - } + memory = buffer->memory.ptr; + offset = buffer->memory.size - ctx->canvas.cmd_offset; + cmd = zr_ptr_add(const struct zr_draw_command, memory, offset); + return cmd; } -void -zr_draw_list_path_curve_to(struct zr_draw_list *list, struct zr_vec2 p2, - struct zr_vec2 p3, struct zr_vec2 p4, unsigned int num_segments) +const struct zr_draw_command* +zr__draw_next(const struct zr_draw_command *cmd, + const struct zr_buffer *buffer, const struct zr_context *ctx) { - unsigned int i_step; - float t_step; - struct zr_vec2 p1; - - ZR_ASSERT(list); - ZR_ASSERT(list->path_count); - if (!list || !list->path_count) return; - num_segments = MAX(num_segments, 1); - - p1 = zr_draw_list_path_last(list); - t_step = 1.0f/(float)num_segments; - for (i_step = 1; i_step <= num_segments; ++i_step) { - float t = t_step * (float)i_step; - float u = 1.0f - t; - float w1 = u*u*u; - float w2 = 3*u*u*t; - float w3 = 3*u*t*t; - float w4 = t * t *t; - float x = w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x; - float y = w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y; - zr_draw_list_path_line_to(list, zr_vec2(x,y)); - } + zr_byte *memory; + zr_size offset, size; + const struct zr_draw_command *end; + ZR_ASSERT(buffer); + ZR_ASSERT(ctx); + if (!cmd || !buffer || !ctx) return 0; + memory = (zr_byte*)buffer->memory.ptr; + size = buffer->memory.size; + offset = size - ctx->canvas.cmd_offset; + end = zr_ptr_add(const struct zr_draw_command, memory, offset); + end -= (ctx->canvas.cmd_count-1); + if (cmd <= end) return 0; + return (cmd-1); } -void -zr_draw_list_path_fill(struct zr_draw_list *list, struct zr_color color) -{ - struct zr_vec2 *points; - ZR_ASSERT(list); - if (!list) return; - points = (struct zr_vec2*)zr_buffer_memory(list->buffer); - zr_draw_list_add_poly_convex(list, points, list->path_count, color, list->AA); - zr_draw_list_path_clear(list); -} - -void -zr_draw_list_path_stroke(struct zr_draw_list *list, struct zr_color color, - int closed, float thickness) -{ - struct zr_vec2 *points; - ZR_ASSERT(list); - if (!list) return; - points = (struct zr_vec2*)zr_buffer_memory(list->buffer); - zr_draw_list_add_poly_line(list, points, list->path_count, color, - closed, thickness, list->AA); - zr_draw_list_path_clear(list); -} #endif /* * ============================================================== @@ -3302,7 +3042,7 @@ struct zr_font_baker { static const zr_size zr_rect_align = ZR_ALIGNOF(stbrp_rect); static const zr_size zr_range_align = ZR_ALIGNOF(stbtt_pack_range); -static const zr_size char_align = ZR_ALIGNOF(stbtt_packedchar); +static const zr_size zr_char_align = ZR_ALIGNOF(stbtt_packedchar); static const zr_size zr_build_align = ZR_ALIGNOF(struct zr_font_bake_data); static const zr_size zr_baker_align = ZR_ALIGNOF(struct zr_font_baker); @@ -3404,7 +3144,7 @@ void zr_font_bake_memory(zr_size *temp, int *glyph_count, *temp += (zr_size)*glyph_count * sizeof(stbtt_packedchar); *temp += (zr_size)count * sizeof(struct zr_font_bake_data); *temp += sizeof(struct zr_font_baker); - *temp += zr_rect_align + zr_range_align + char_align; + *temp += zr_rect_align + zr_range_align + zr_char_align; *temp += zr_build_align + zr_baker_align; } @@ -3416,7 +3156,7 @@ zr_font_baker(void *memory, int glyph_count, int count) /* setup baker inside a memory block */ baker = (struct zr_font_baker*)ZR_ALIGN_PTR(memory, zr_baker_align); baker->build = (struct zr_font_bake_data*)ZR_ALIGN_PTR((baker + 1), zr_build_align); - baker->packed_chars = (stbtt_packedchar*)ZR_ALIGN_PTR((baker->build + count), char_align); + baker->packed_chars = (stbtt_packedchar*)ZR_ALIGN_PTR((baker->build + count), zr_char_align); baker->rects = (stbrp_rect*)ZR_ALIGN_PTR((baker->packed_chars + glyph_count), zr_rect_align); baker->ranges = (stbtt_pack_range*)ZR_ALIGN_PTR((baker->rects + glyph_count), zr_range_align); return baker; @@ -3805,7 +3545,7 @@ zr_font_ref(struct zr_font *font) * =============================================================== */ static void -zr_edit_buffer_append(zr_edit_buffer *buffer, const char *str, zr_size len) +zr_edit_buffer_append(struct zr_buffer *buffer, const char *str, zr_size len) { char *mem; ZR_ASSERT(buffer); @@ -3817,7 +3557,7 @@ zr_edit_buffer_append(zr_edit_buffer *buffer, const char *str, zr_size len) } static int -zr_edit_buffer_insert(zr_edit_buffer *buffer, zr_size pos, +zr_edit_buffer_insert(struct zr_buffer *buffer, zr_size pos, const char *str, zr_size len) { void *mem; @@ -3827,12 +3567,14 @@ zr_edit_buffer_insert(zr_edit_buffer *buffer, zr_size pos, zr_size copylen; ZR_ASSERT(buffer); if (!buffer || !str || !len || pos > buffer->allocated) return 0; + if (buffer->allocated + len >= buffer->memory.size && buffer->type == ZR_BUFFER_FIXED) return 0; copylen = buffer->allocated - pos; if (!copylen) { zr_edit_buffer_append(buffer, str, len); return 1; } + mem = zr_buffer_alloc(buffer, ZR_BUFFER_FRONT, len * sizeof(char), 0); if (!mem) return 0; @@ -3848,7 +3590,7 @@ zr_edit_buffer_insert(zr_edit_buffer *buffer, zr_size pos, } static void -zr_edit_buffer_remove(zr_edit_buffer *buffer, zr_size len) +zr_edit_buffer_remove(struct zr_buffer *buffer, zr_size len) { ZR_ASSERT(buffer); if (!buffer || len > buffer->allocated) return; @@ -3857,7 +3599,7 @@ zr_edit_buffer_remove(zr_edit_buffer *buffer, zr_size len) } static void -zr_edit_buffer_del(zr_edit_buffer *buffer, zr_size pos, zr_size len) +zr_edit_buffer_del(struct zr_buffer *buffer, zr_size pos, zr_size len) { char *src, *dst; ZR_ASSERT(buffer); @@ -3875,7 +3617,7 @@ zr_edit_buffer_del(zr_edit_buffer *buffer, zr_size pos, zr_size len) } static char* -zr_edit_buffer_at_char(zr_edit_buffer *buffer, zr_size pos) +zr_edit_buffer_at_char(struct zr_buffer *buffer, zr_size pos) { ZR_ASSERT(buffer); if (!buffer || pos > buffer->allocated) return 0; @@ -3883,7 +3625,7 @@ zr_edit_buffer_at_char(zr_edit_buffer *buffer, zr_size pos) } static char* -zr_edit_buffer_at(zr_edit_buffer *buffer, int pos, zr_rune *unicode, +zr_edit_buffer_at(struct zr_buffer *buffer, int pos, zr_rune *unicode, zr_size *len) { int i = 0; @@ -3919,18 +3661,14 @@ zr_edit_buffer_at(zr_edit_buffer *buffer, int pos, zr_rune *unicode, return text + src_len; } -void -zr_edit_box_init(struct zr_edit_box *eb, struct zr_allocator *a, - zr_size initial_size, float grow_fac, const struct zr_clipboard *clip, - zr_filter f) +static void +zr_edit_box_init_buffer(struct zr_edit_box *eb, struct zr_buffer *buffer, + const struct zr_clipboard *clip, zr_filter f) { ZR_ASSERT(eb); - ZR_ASSERT(a); - ZR_ASSERT(initial_size); - if (!eb || !a) return; - + if (!eb) return; zr_zero(eb, sizeof(*eb)); - zr_buffer_init(&eb->buffer, a, initial_size, grow_fac); + eb->buffer = *buffer; if (clip) eb->clip = *clip; if (f) eb->filter = f; else eb->filter = zr_filter_default; @@ -3938,9 +3676,9 @@ zr_edit_box_init(struct zr_edit_box *eb, struct zr_allocator *a, eb->glyphs = 0; } -void -zr_edit_box_init_fixed(struct zr_edit_box *eb, void *memory, zr_size size, - const struct zr_clipboard *clip, zr_filter f) +static void +zr_edit_box_init(struct zr_edit_box *eb, void *memory, zr_size size, + const struct zr_clipboard *clip, zr_filter f) { ZR_ASSERT(eb); if (!eb) return; @@ -3962,24 +3700,6 @@ zr_edit_box_clear(struct zr_edit_box *box) box->cursor = box->glyphs = 0; } -void -zr_edit_box_free(struct zr_edit_box *box) -{ - ZR_ASSERT(box); - if (!box) return; - zr_buffer_free(&box->buffer); - box->cursor = box->glyphs = 0; -} - -void -zr_edit_box_info(struct zr_memory_status *status, struct zr_edit_box *box) -{ - ZR_ASSERT(box); - ZR_ASSERT(status); - if (!box || !status) return; - zr_buffer_info(status, &box->buffer); -} - void zr_edit_box_add(struct zr_edit_box *eb, const char *str, zr_size len) { @@ -4228,7 +3948,7 @@ zr_widget_text(struct zr_command_buffer *o, struct zr_rect b, label.x = MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (float)text_width)); label.w = (float)text_width + 2 * t->padding.x; } else return; - zr_command_buffer_push_text(o, label, (const char*)string, + zr_draw_text(o, label, (const char*)string, len, f, t->background, t->text); } @@ -4332,14 +4052,14 @@ zr_draw_symbol(struct zr_command_buffer *out, enum zr_symbol symbol, case ZR_SYMBOL_RECT_FILLED: { /* simple empty/filled shapes */ if (symbol == ZR_SYMBOL_RECT || symbol == ZR_SYMBOL_RECT_FILLED) { - zr_command_buffer_push_rect(out, content, 0, foreground); + zr_draw_rect(out, content, 0, foreground); if (symbol == ZR_SYMBOL_RECT_FILLED) - zr_command_buffer_push_rect(out, zr_shrink_rect(content, + zr_draw_rect(out, zr_shrink_rect(content, border_width), 0, background); } else { - zr_command_buffer_push_circle(out, content, foreground); + zr_draw_circle(out, content, foreground); if (symbol == ZR_SYMBOL_CIRCLE_FILLED) - zr_command_buffer_push_circle(out, zr_shrink_rect(content, 1), + zr_draw_circle(out, zr_shrink_rect(content, 1), background); } } break; @@ -4353,7 +4073,7 @@ zr_draw_symbol(struct zr_command_buffer *out, enum zr_symbol symbol, (symbol == ZR_SYMBOL_TRIANGLE_LEFT) ? ZR_LEFT: (symbol == ZR_SYMBOL_TRIANGLE_UP) ? ZR_UP: ZR_DOWN; zr_triangle_from_direction(points, content, 0, 0, heading); - zr_command_buffer_push_triangle(out, points[0].x, points[0].y, + zr_draw_triangle(out, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, foreground); } break; case ZR_SYMBOL_MAX: @@ -4362,7 +4082,7 @@ zr_draw_symbol(struct zr_command_buffer *out, enum zr_symbol symbol, } static int -zr_button_behavior(enum zr_widget_states *state, struct zr_rect r, +zr_button_behavior(enum zr_widget_status *state, struct zr_rect r, const struct zr_input *i, enum zr_button_behavior behavior) { int ret = 0; @@ -4382,7 +4102,7 @@ zr_button_behavior(enum zr_widget_states *state, struct zr_rect r, static void zr_button_draw(struct zr_command_buffer *o, struct zr_rect r, - const struct zr_button *b, enum zr_widget_states state) + const struct zr_button *b, enum zr_widget_status state) { struct zr_color background; switch (state) { @@ -4394,13 +4114,13 @@ zr_button_draw(struct zr_command_buffer *o, struct zr_rect r, case ZR_ACTIVE: background = b->active; break; } - zr_command_buffer_push_rect(o, r, b->rounding, b->border); - zr_command_buffer_push_rect(o, zr_shrink_rect(r, b->border_width), + zr_draw_rect(o, r, b->rounding, b->border); + zr_draw_rect(o, zr_shrink_rect(r, b->border_width), b->rounding, background); } static int -zr_do_button(enum zr_widget_states *state, +zr_do_button(enum zr_widget_status *state, struct zr_command_buffer *o, struct zr_rect r, const struct zr_button *b, const struct zr_input *i, enum zr_button_behavior behavior, struct zr_rect *content) @@ -4423,7 +4143,7 @@ zr_do_button(enum zr_widget_states *state, } static int -zr_do_button_text(enum zr_widget_states *state, +zr_do_button_text(enum zr_widget_status *state, struct zr_command_buffer *o, struct zr_rect r, const char *string, enum zr_button_behavior behavior, const struct zr_button_text *b, const struct zr_input *i, @@ -4462,7 +4182,7 @@ zr_do_button_text(enum zr_widget_states *state, } static int -zr_do_button_symbol(enum zr_widget_states *state, +zr_do_button_symbol(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect r, enum zr_symbol symbol, enum zr_button_behavior bh, const struct zr_button_symbol *b, const struct zr_input *in, @@ -4499,7 +4219,7 @@ zr_do_button_symbol(enum zr_widget_states *state, } static int -zr_do_button_image(enum zr_widget_states *state, +zr_do_button_image(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect r, struct zr_image img, enum zr_button_behavior b, const struct zr_button_icon *button, const struct zr_input *in) @@ -4513,12 +4233,12 @@ zr_do_button_image(enum zr_widget_states *state, return zr_false; pressed = zr_do_button(state, out, r, &button->base, in, b, &bounds); - zr_command_buffer_push_image(out, bounds, &img); + zr_draw_image(out, bounds, &img); return pressed; } static int -zr_do_button_text_symbol(enum zr_widget_states *state, +zr_do_button_text_symbol(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect r, enum zr_symbol symbol, const char *text, enum zr_text_align align, enum zr_button_behavior behavior, const struct zr_button_text *b, @@ -4562,7 +4282,7 @@ zr_do_button_text_symbol(enum zr_widget_states *state, } static int -zr_do_button_text_image(enum zr_widget_states *state, +zr_do_button_text_image(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect r, struct zr_image img, const char* text, enum zr_text_align align, enum zr_button_behavior behavior, const struct zr_button_text *b, @@ -4582,7 +4302,7 @@ zr_do_button_text_image(enum zr_widget_states *state, icon.x = (r.x + r.w) - (2 * b->base.padding.x + icon.w); icon.x = MAX(icon.x, 0); } else icon.x = r.x + 2 * b->base.padding.x; - zr_command_buffer_push_image(out, icon, &img); + zr_draw_image(out, icon, &img); return pressed; } @@ -4608,9 +4328,8 @@ struct zr_toggle { static int zr_toggle_behavior(const struct zr_input *in, struct zr_rect select, - enum zr_widget_states *state, int active) + enum zr_widget_status *state, int active) { - int clicked; *state = ZR_INACTIVE; if (in && zr_input_is_mouse_hovering_rect(in, select)) *state = ZR_HOVERED; @@ -4623,7 +4342,7 @@ zr_toggle_behavior(const struct zr_input *in, struct zr_rect select, static void zr_toggle_draw(struct zr_command_buffer *out, - enum zr_widget_states state, + enum zr_widget_status state, const struct zr_toggle *toggle, int active, enum zr_toggle_type type, struct zr_rect r, const char *string, const struct zr_user_font *font) @@ -4654,14 +4373,14 @@ zr_toggle_draw(struct zr_command_buffer *out, /* draw radiobutton/checkbox background */ if (type == ZR_TOGGLE_CHECK) - zr_command_buffer_push_rect(out, select , toggle->rounding, col); - else zr_command_buffer_push_circle(out, select, col); + zr_draw_rect(out, select , toggle->rounding, col); + else zr_draw_circle(out, select, col); /* draw radiobutton/checkbox cursor if active */ if (active) { if (type == ZR_TOGGLE_CHECK) - zr_command_buffer_push_rect(out, cursor, toggle->rounding, toggle->cursor); - else zr_command_buffer_push_circle(out, cursor, toggle->cursor); + zr_draw_rect(out, cursor, toggle->rounding, toggle->cursor); + else zr_draw_circle(out, cursor, toggle->cursor); } /* draw toggle text */ @@ -4686,7 +4405,7 @@ zr_toggle_draw(struct zr_command_buffer *out, } static void -zr_do_toggle(enum zr_widget_states *state, +zr_do_toggle(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect r, int *active, const char *string, enum zr_toggle_type type, const struct zr_toggle *toggle, const struct zr_input *in, @@ -4720,7 +4439,7 @@ struct zr_slider { }; static float -zr_slider_behavior(enum zr_widget_states *state, struct zr_rect *cursor, +zr_slider_behavior(enum zr_widget_status *state, struct zr_rect *cursor, const struct zr_input *in, const struct zr_slider *s, struct zr_rect slider, float slider_min, float slider_max, float slider_value, float slider_step, float slider_steps) @@ -4748,7 +4467,7 @@ zr_slider_behavior(enum zr_widget_states *state, struct zr_rect *cursor, static void zr_slider_draw(struct zr_command_buffer *out, - enum zr_widget_states state, const struct zr_slider *s, + enum zr_widget_status state, const struct zr_slider *s, struct zr_rect bar, struct zr_rect cursor, float slider_min, float slider_max, float slider_value) { @@ -4775,13 +4494,13 @@ zr_slider_draw(struct zr_command_buffer *out, fill.w = (cursor.x + (cursor.w/2.0f)) - bar.x; fill.h = bar.h; - zr_command_buffer_push_rect(out, bar, 0, s->bg); - zr_command_buffer_push_rect(out, fill, 0, col); - zr_command_buffer_push_circle(out, cursor, col); + zr_draw_rect(out, bar, 0, s->bg); + zr_draw_rect(out, fill, 0, col); + zr_draw_circle(out, cursor, col); } static float -zr_do_slider(enum zr_widget_states *state, +zr_do_slider(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect slider, float min, float val, float max, float step, const struct zr_slider *s, const struct zr_input *in) @@ -4792,7 +4511,6 @@ zr_do_slider(enum zr_widget_states *state, float cursor_offset; struct zr_rect cursor; struct zr_rect bar; - struct zr_color col; ZR_ASSERT(s); ZR_ASSERT(out); @@ -4847,7 +4565,7 @@ struct zr_progress { }; static zr_size -zr_progress_behavior(enum zr_widget_states *state, const struct zr_input *in, +zr_progress_behavior(enum zr_widget_status *state, const struct zr_input *in, struct zr_rect r, zr_size max, zr_size value, int modifiable) { *state = ZR_INACTIVE; @@ -4865,7 +4583,7 @@ zr_progress_behavior(enum zr_widget_states *state, const struct zr_input *in, static void zr_progress_draw(struct zr_command_buffer *out, const struct zr_progress *p, - enum zr_widget_states state, struct zr_rect r, zr_size max, zr_size value) + enum zr_widget_status state, struct zr_rect r, zr_size max, zr_size value) { struct zr_color col; float prog_scale; @@ -4880,20 +4598,18 @@ zr_progress_draw(struct zr_command_buffer *out, const struct zr_progress *p, } prog_scale = (float)value / (float)max; - zr_command_buffer_push_rect(out, r, p->rounding, p->background); + zr_draw_rect(out, r, p->rounding, p->background); r.w = (r.w - 2) * prog_scale; - zr_command_buffer_push_rect(out, r, p->rounding, col); + zr_draw_rect(out, r, p->rounding, col); } static zr_size -zr_do_progress(enum zr_widget_states *state, +zr_do_progress(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect r, zr_size value, zr_size max, int modifiable, const struct zr_progress *prog, const struct zr_input *in) { - float prog_scale; zr_size prog_value; - ZR_ASSERT(prog); ZR_ASSERT(out); if (!out || !prog) return 0; @@ -4924,7 +4640,7 @@ struct zr_scrollbar { }; static float -zr_scrollbar_behavior(enum zr_widget_states *state, struct zr_input *in, +zr_scrollbar_behavior(enum zr_widget_status *state, struct zr_input *in, const struct zr_scrollbar *s, struct zr_rect scroll, struct zr_rect cursor, float scroll_offset, float target, float scroll_step, enum zr_orientation o) @@ -4971,7 +4687,7 @@ zr_scrollbar_behavior(enum zr_widget_states *state, struct zr_input *in, static void zr_scrollbar_draw(struct zr_command_buffer *out, const struct zr_scrollbar *s, - enum zr_widget_states state, struct zr_rect scroll, struct zr_rect cursor) + enum zr_widget_status state, struct zr_rect scroll, struct zr_rect cursor) { struct zr_color col; switch (state) { @@ -4983,13 +4699,13 @@ zr_scrollbar_draw(struct zr_command_buffer *out, const struct zr_scrollbar *s, case ZR_ACTIVE: col = s->active; break; } - zr_command_buffer_push_rect(out, zr_shrink_rect(scroll,1), s->rounding, s->border); - zr_command_buffer_push_rect(out, scroll, s->rounding, s->background); - zr_command_buffer_push_rect(out, cursor, s->rounding, col); + zr_draw_rect(out, zr_shrink_rect(scroll,1), s->rounding, s->border); + zr_draw_rect(out, scroll, s->rounding, s->background); + zr_draw_rect(out, cursor, s->rounding, col); } static float -zr_do_scrollbarv(enum zr_widget_states *state, +zr_do_scrollbarv(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect scroll, float offset, float target, float step, const struct zr_scrollbar *s, struct zr_input *i) @@ -5030,7 +4746,7 @@ zr_do_scrollbarv(enum zr_widget_states *state, } static float -zr_do_scrollbarh(enum zr_widget_states *state, +zr_do_scrollbarh(enum zr_widget_status *state, struct zr_command_buffer *out, struct zr_rect scroll, float offset, float target, float step, const struct zr_scrollbar *s, struct zr_input *i) @@ -5039,7 +4755,6 @@ zr_do_scrollbarh(enum zr_widget_states *state, float scroll_step; float scroll_offset; float scroll_off, scroll_ratio; - struct zr_color col; ZR_ASSERT(out); ZR_ASSERT(s); @@ -5173,8 +4888,8 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, r.h = MAX(r.h, font->height + (2 * field->padding.y + 2 * field->border_size)); /* draw editbox background and border */ - zr_command_buffer_push_rect(out, r, field->rounding, field->border); - zr_command_buffer_push_rect(out, zr_shrink_rect(r, field->border_size), + zr_draw_rect(out, r, field->rounding, field->border); + zr_draw_rect(out, zr_shrink_rect(r, field->border_size), field->rounding, field->background); /* check if the editbox is activated/deactivated */ @@ -5271,14 +4986,14 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, label.x = r.x + field->padding.x + field->border_size; label.y = r.y + field->padding.y + field->border_size; label.h = r.h - (2 * field->padding.y + 2 * field->border_size); - zr_command_buffer_push_text(out , label, &buffer[offset], text_len, + zr_draw_text(out , label, &buffer[offset], text_len, font, field->background, field->text); /* draw selected text */ if (box->active && field->show_cursor) { if (box->cursor == box->glyphs) { /* draw the cursor at the end of the string */ - zr_command_buffer_push_rect(out, zr_rect(label.x+(float)text_width, + zr_draw_rect(out, zr_rect(label.x+(float)text_width, label.y, (float)cursor_w, label.h), 0, field->cursor); } else { /* draw text selection */ @@ -5297,16 +5012,16 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, off_end = (zr_size)(end - (char*)box->buffer.memory.ptr); /* calculate selected text width */ - zr_command_buffer_push_scissor(out, label); + zr_draw_scissor(out, label); s = font->width(font->userdata, font->height, buffer + offset, off_begin - offset); label.x += (float)s; s = font->width(font->userdata, font->height, begin, MAX(l, off_end - off_begin)); label.w = (float)s; /* draw selected text */ - zr_command_buffer_push_text(out , label, begin, + zr_draw_text(out , label, begin, MAX(l, off_end - off_begin), font, field->cursor, field->background); - zr_command_buffer_push_scissor(out, clip); + zr_draw_scissor(out, clip); } } } @@ -5340,8 +5055,8 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, row_height = (zr_size)(font->height + field->padding.y); /* draw edit field background and border */ - zr_command_buffer_push_rect(out, r, field->rounding, field->border); - zr_command_buffer_push_rect(out, zr_shrink_rect(r, field->border_size), + zr_draw_rect(out, r, field->rounding, field->border); + zr_draw_rect(out, zr_shrink_rect(r, field->border_size), field->rounding, field->background); /* check if edit field is big enough to show a single row */ @@ -5364,7 +5079,6 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, { /* calulate total number of needed rows */ - zr_size rows = 0; zr_size glyphs = 0; zr_size row_off = 0; zr_size text_len = len; @@ -5508,7 +5222,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, struct zr_rect bounds; float scroll_target, scroll_offset, scroll_step; struct zr_scrollbar scroll = field->scroll; - enum zr_widget_states state; + enum zr_widget_status state; bounds.x = (r.x + r.w) - (field->scrollbar_width + field->border_size); bounds.y = r.y + field->border_size + field->padding.y; @@ -5547,7 +5261,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, zr_unify(&scissor, &out->clip, clip.x, clip.y, clip.x + clip.w, clip.y + clip.h); /* calculate row text space */ - zr_command_buffer_push_scissor(out, scissor); + zr_draw_scissor(out, scissor); label.x = r.x + field->padding.x + field->border_size; label.y = (r.y + field->padding.y + field->border_size) - box->scrollbar; label.h = font->height + field->padding.y; @@ -5566,7 +5280,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, /* draw either unselected or selected row */ if (glyph_off < begin && glyph_off + glyphs >= begin && glyph_off + glyphs <= end+1 && box->active) { /* first case with selection beginning in current row */ - zr_size l = 0, s, sel_begin, sel_len; + zr_size l = 0, sel_begin, sel_len; zr_size unselected_text_width; zr_rune unicode; @@ -5589,24 +5303,24 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, /* draw unselected text part */ unselected_text_width = font->width(font->userdata, font->height, &buffer[offset], glyphs - sel_len); - zr_command_buffer_push_text(out , label, &buffer[offset], + zr_draw_text(out , label, &buffer[offset], glyphs - sel_len, font, field->background, field->text); /* draw selected text part */ label.x += (float)(unselected_text_width); label.w -= (float)(unselected_text_width); - zr_command_buffer_push_text(out , label, &buffer[offset + sel_begin], + zr_draw_text(out , label, &buffer[offset + sel_begin], sel_len, font, field->text, field->background); label.x -= (float)unselected_text_width; label.w += (float)(unselected_text_width); } else if (glyph_off > begin && glyph_off + glyphs < end && box->active) { /* second case with selection spanning over current row */ - zr_command_buffer_push_text(out, label, &buffer[offset], + zr_draw_text(out, label, &buffer[offset], row_len, font, field->text, field->background); } else if (glyph_off >= begin && glyph_off + glyphs > end && box->active && end >= glyph_off && end <= glyph_off + glyphs) { /* third case with selection ending in current row */ - zr_size l = 0, s, sel_end, sel_len; + zr_size l = 0, sel_end, sel_len; zr_size selected_text_width; zr_rune unicode; @@ -5619,20 +5333,20 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, /* draw selected text part */ selected_text_width = font->width(font->userdata, font->height, &buffer[offset], sel_len); - zr_command_buffer_push_text(out , label, &buffer[offset], + zr_draw_text(out , label, &buffer[offset], sel_len, font, field->text, field->background); /* draw unselected text part */ label.x += (float)selected_text_width; label.w -= (float)(selected_text_width); - zr_command_buffer_push_text(out , label, &buffer[offset + sel_end+1], + zr_draw_text(out , label, &buffer[offset + sel_end+1], glyphs - sel_len, font, field->background, field->text); label.x -= (float)selected_text_width; label.w += (float)(selected_text_width); } else if (glyph_off < begin && glyph_off + glyphs >= begin && box->active && glyph_off < end && glyph_off + glyphs > end) { /* fourth case with selection beginning and ending in current row */ - zr_size l = 0, s; + zr_size l = 0; zr_size cur_text_width; zr_size sel_begin, sel_end, sel_len; zr_rune unicode; @@ -5653,27 +5367,27 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, /* draw beginning unselected text part */ cur_text_width = font->width(font->userdata, font->height, &buffer[offset], sel_begin); - zr_command_buffer_push_text(out , label, &buffer[offset], + zr_draw_text(out , label, &buffer[offset], sel_begin, font, field->background, field->text); /* draw selected text part */ label.x += (float)cur_text_width; label.w -= (float)(cur_text_width); - zr_command_buffer_push_text(out, label, &buffer[offset+sel_begin], + zr_draw_text(out, label, &buffer[offset+sel_begin], sel_len, font, field->text, field->background); cur_text_width = font->width(font->userdata, font->height, &buffer[offset+sel_begin], sel_len); /* draw ending unselected text part */ label.x += (float)cur_text_width; label.w -= (float)(cur_text_width); - zr_command_buffer_push_text(out , label, &buffer[offset+sel_end+1], + zr_draw_text(out , label, &buffer[offset+sel_end+1], row_len - (sel_len + sel_begin), font, field->background, field->text); label.x = (float)label_x; label.w = (float)label_w; } else { /* no selection */ label.w = text_width; - zr_command_buffer_push_text(out, label, &buffer[offset], + zr_draw_text(out, label, &buffer[offset], row_len, font, field->background, field->text); } @@ -5687,41 +5401,14 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, if (box->active && field->show_cursor) { if (box->cursor == box->glyphs) { if (len) label.y -= (font->height + field->padding.y); - zr_command_buffer_push_rect(out, zr_rect(label.x+(float)text_width, + zr_draw_rect(out, zr_rect(label.x+(float)text_width, label.y, (float)cursor_w, label.h), 0, field->cursor); } } - zr_command_buffer_push_scissor(out, old_clip); + zr_draw_scissor(out, old_clip); } } -static zr_size -zr_widget_edit_filtered(struct zr_command_buffer *out, struct zr_rect r, - char *buffer, zr_size len, zr_size max, int *active, - zr_size *cursor, const struct zr_edit *field, zr_filter filter, - const struct zr_input *in, const struct zr_user_font *font) -{ - struct zr_edit_box box; - zr_edit_box_init_fixed(&box, buffer, max, 0, filter); - - box.buffer.allocated = len; - box.active = *active; - box.glyphs = zr_utf_len(buffer, len); - if (!cursor) { - box.cursor = box.glyphs; - } else{ - box.cursor = MIN(*cursor, box.glyphs); - box.sel.begin = box.cursor; - box.sel.end = box.cursor; - } - - zr_widget_edit_field(out, r, &box, field, in, font); - *active = box.active; - if (cursor) - *cursor = box.cursor; - return zr_edit_box_len_char(&box); -} - int zr_filter_default(zr_rune unicode) {(void)unicode;return zr_true;} @@ -5777,20 +5464,28 @@ zr_filter_binary(zr_rune unicode) static zr_size zr_widget_edit(struct zr_command_buffer *out, struct zr_rect r, char *buffer, zr_size len, zr_size max, int *active, - zr_size *cursor, const struct zr_edit *field, enum zr_input_filter f, + zr_size *cursor, const struct zr_edit *field, zr_filter filter, const struct zr_input *in, const struct zr_user_font *font) { - static const zr_filter filter[] = { - zr_filter_default, - zr_filter_ascii, - zr_filter_float, - zr_filter_decimal, - zr_filter_hex, - zr_filter_oct, - zr_filter_binary, - }; - return zr_widget_edit_filtered(out, r, buffer, len, max, active, - cursor, field, filter[f], in, font); + struct zr_edit_box box; + zr_edit_box_init(&box, buffer, max, 0, filter); + + box.buffer.allocated = len; + box.active = *active; + box.glyphs = zr_utf_len(buffer, len); + if (!cursor) { + box.cursor = box.glyphs; + } else{ + box.cursor = MIN(*cursor, box.glyphs); + box.sel.begin = box.cursor; + box.sel.end = box.cursor; + } + + zr_widget_edit_field(out, r, &box, field, in, font); + *active = box.active; + if (cursor) + *cursor = box.cursor; + return zr_edit_box_len_char(&box); } /* =============================================================== * @@ -5815,7 +5510,7 @@ struct zr_property { }; static float -zr_drag_behavior(enum zr_widget_states *state, const struct zr_input *in, +zr_drag_behavior(enum zr_widget_status *state, const struct zr_input *in, struct zr_rect drag, float min, float val, float max, float inc_per_pixel) { int left_mouse_down = in && in->mouse.buttons[ZR_BUTTON_LEFT].down; @@ -5838,12 +5533,11 @@ zr_drag_behavior(enum zr_widget_states *state, const struct zr_input *in, } static float -zr_property_behavior(enum zr_widget_states *ws, const struct zr_input *in, +zr_property_behavior(enum zr_widget_status *ws, const struct zr_input *in, struct zr_rect property, struct zr_rect left, struct zr_rect right, struct zr_rect label, struct zr_rect edit, struct zr_rect empty, int *state, float min, float value, float max, float step, float inc_per_pixel) { - int active = 1; if (zr_button_behavior(ws, left, in, ZR_BUTTON_DEFAULT)) value = CLAMP(min, value - step, max); if (zr_button_behavior(ws, right, in, ZR_BUTTON_DEFAULT)) @@ -5872,25 +5566,23 @@ zr_property_draw(struct zr_command_buffer *out, const struct zr_user_font *f) { /* background */ - zr_command_buffer_push_rect(out, property, p->rounding, p->border); - zr_command_buffer_push_rect(out, zr_shrink_rect(property,p->border_size), p->rounding, p->normal); + zr_draw_rect(out, property, p->rounding, p->border); + zr_draw_rect(out, zr_shrink_rect(property,p->border_size), p->rounding, p->normal); /* buttons */ zr_draw_symbol(out, ZR_SYMBOL_TRIANGLE_LEFT, left, p->normal, p->text, 0, f); zr_draw_symbol(out, ZR_SYMBOL_TRIANGLE_RIGHT, right, p->normal, p->text, 0, f); /* label */ - zr_command_buffer_push_text(out, label, name, len, f, p->normal, p->text); + zr_draw_text(out, label, name, len, f, p->normal, p->text); } static float -zr_do_property(enum zr_widget_states *ws, +zr_do_property(enum zr_widget_status *ws, struct zr_command_buffer *out, struct zr_rect property, const char *name, float min, float val, float max, float step, float inc_per_pixel, char *buffer, zr_size *len, int *state, zr_size *cursor, struct zr_property *p, - enum zr_input_filter filter, - const struct zr_input *in, - const struct zr_user_font *f) + zr_filter filter, const struct zr_input *in, const struct zr_user_font *f) { zr_size size; char string[ZR_MAX_NUMBER_BUFFER]; @@ -5978,6 +5670,7 @@ zr_do_property(enum zr_widget_states *ws, field.border = p->normal; field.cursor = p->text; field.text = p->text; + active = (*state == ZR_PROPERTY_EDIT); if (old != ZR_PROPERTY_EDIT && active) { zr_memcopy(buffer, dst, *length); @@ -6056,7 +5749,6 @@ zr_do_property(enum zr_widget_states *ws, COLOR(COMBO, 45, 45, 45, 255)\ COLOR(HISTO, 120, 120, 120, 255)\ COLOR(HISTO_BARS, 45, 45, 45, 255)\ - COLOR(HISTO_NEGATIVE, 255, 255, 255, 255)\ COLOR(HISTO_HIGHLIGHT, 255, 0, 0, 255)\ COLOR(PLOT, 120, 120, 120, 255)\ COLOR(PLOT_LINES, 45, 45, 45, 255)\ @@ -6158,6 +5850,7 @@ zr_style_property(const struct zr_style *style, enum zr_style_properties index) ZR_ASSERT(style); if (!style) return zero; return style->properties[index]; + /* draw open/close symbol */ } struct zr_color @@ -6326,77 +6019,850 @@ zr_style_reset(struct zr_style *style) zr_style_reset_font_height(style); } -/* ============================================================== +/* =============================================================== + * + * POOL + * + * ===============================================================*/ +static int zr_layout_begin(struct zr_context*, const char*); +static void zr_layout_end(struct zr_context*); + +static void +zr_pool_init(struct zr_pool *pool, struct zr_allocator *alloc, unsigned int capacity) +{ + zr_zero(pool, sizeof(*pool)); + pool->alloc = *alloc; + pool->capacity = capacity; + pool->pages = 0; + pool->type = ZR_BUFFER_DYNAMIC; +} + +static void +zr_pool_free(struct zr_pool *pool) +{ + struct zr_window_page *next; + struct zr_window_page *iter = pool->pages; + if (!pool) return; + if (pool->type == ZR_BUFFER_FIXED) return; + while (iter) { + next = iter->next; + pool->alloc.free(pool->alloc.userdata, iter); + iter = next; + } + pool->alloc.free(pool->alloc.userdata, pool); +} + +static void +zr_pool_init_fixed(struct zr_pool *pool, void *memory, zr_size size) +{ + zr_zero(pool, sizeof(*pool)); + /* make sure pages have correct granularity to at least fit one page into memory */ + if (size < sizeof(struct zr_window_page) + ZR_POOL_DEFAULT_CAPACTIY * sizeof(struct zr_window)) + pool->capacity = (unsigned)(size - sizeof(struct zr_window_page)) / sizeof(struct zr_window); + else pool->capacity = ZR_POOL_DEFAULT_CAPACTIY; + pool->pages = memory; + pool->type = ZR_BUFFER_FIXED; + pool->size = size; +} + +static void* +zr_pool_alloc(struct zr_pool *pool) +{ + if (!pool->pages || pool->pages->size >= pool->capacity) { + /* allocate new page */ + struct zr_window_page *page; + if (pool->type == ZR_BUFFER_FIXED) { + if (!pool->pages) { + ZR_ASSERT(pool->pages); + return 0; + } + ZR_ASSERT(pool->pages->size < pool->capacity); + return 0; + } else { + zr_size size = sizeof(struct zr_window_page); + size += ZR_POOL_DEFAULT_CAPACTIY * sizeof(union zr_page_data); + page = pool->alloc.alloc(pool->alloc.userdata, size); + page->size = 0; + page->next = pool->pages; + pool->pages = page; + } + } + return &pool->pages->win[pool->pages->size++]; +} + +/* =============================================================== + * + * CONTEXT + * + * ===============================================================*/ +static void zr_free_table(struct zr_context*, struct zr_table*); +static void zr_remove_table(struct zr_window*, struct zr_table*); + +static void* +zr_create_window(struct zr_context *ctx) +{ + struct zr_window *win = 0; + if (ctx->freelist) { + /* unlink window from free list */ + win = ctx->freelist; + ctx->freelist = win->next; + } else if (ctx->pool) { + /* allocate window from memory pool */ + win = (struct zr_window*) zr_pool_alloc(ctx->pool); + ZR_ASSERT(win); + if (!win) return 0; + } else { + /* allocate new window from the back of the fixed size memory buffer */ + static const zr_size size = sizeof(union zr_page_data); + static const zr_size align = ZR_ALIGNOF(union zr_page_data); + win = zr_buffer_alloc(&ctx->memory, ZR_BUFFER_BACK, size, align); + ZR_ASSERT(win); + if (!win) return 0; + } + zr_zero(win, sizeof(union zr_page_data)); + win->seq = ctx->seq; + return win; +} + +static void +zr_free_window(struct zr_context *ctx, struct zr_window *win) +{ + /* unlink windows from list */ + struct zr_table *n, *it = win->tables; + if (win->next) + win->next->prev = win->next; + if (win->prev) + win->prev->next = win->next; + if (win->popup.win) { + zr_free_window(ctx, win->popup.win); + win->popup.win = 0; + } + + if (win == ctx->begin) + ctx->begin = win->next; + if (win == ctx->end) + ctx->begin = win->prev; + + win->next = 0; + win->prev = 0; + + while (it) { + /* window state tables */ + n = it->next; + if (it->seq != ctx->seq) { + zr_remove_table(win, it); + zr_free_table(ctx, it); + if (it == win->tables) + win->tables = n; + } + it = n; + } + + /* link windows into freelist */ + if (!ctx->freelist) { + ctx->freelist = win; + } else { + win->next = ctx->freelist; + ctx->freelist = win; + } +} + +static struct zr_window* +zr_find_window(struct zr_context *ctx, zr_hash hash) +{ + struct zr_window *iter; + iter = ctx->begin; + while (iter) { + if (iter->name == hash) + return iter; + iter = iter->next; + } + return 0; +} + +static void +zr_insert_window(struct zr_context *ctx, struct zr_window *win) +{ + struct zr_window *end; + ZR_ASSERT(ctx); + ZR_ASSERT(win); + if (!win || !ctx) return; + + if (!ctx->begin) { + win->next = 0; + win->prev = 0; + ctx->begin = win; + ctx->end = win; + ctx->count = 1; + return; + } + + end = ctx->end; + end->next = win; + win->prev = ctx->end; + win->next = 0; + ctx->end = win; + ctx->count++; +} + +static void +zr_start(struct zr_context *ctx, struct zr_window *win) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(win); + if (!ctx || !win) return; + win->buffer.begin = ctx->memory.allocated; + win->buffer.end = win->buffer.begin; + win->buffer.last = win->buffer.begin; + win->buffer.clip = zr_null_rect; +} + + +static void +zr_remove_window(struct zr_context *ctx, struct zr_window *win) +{ + if (win->prev) + win->prev->next = win->next; + if (win->next) + win->next->prev = win->prev; + if (ctx->begin == win) + ctx->begin = win->next; + if (ctx->end == win) + ctx->end = win->prev; + + win->next = 0; + win->prev = 0; + ctx->count--; +} + +static struct zr_table* +zr_create_table(struct zr_context *ctx) +{void *tbl = (void*)zr_create_window(ctx); return (struct zr_table*)tbl;} + +static void +zr_free_table(struct zr_context *ctx, struct zr_table *tbl) +{zr_free_window(ctx, (struct zr_window*)tbl);} + +static void +zr_push_table(struct zr_window *win, struct zr_table *tbl) +{ + if (!win->tables) { + win->tables = tbl; + tbl->next = 0; + tbl->prev = 0; + win->table_count = 1; + win->table_size = 1; + return; + } + win->tables->prev = tbl; + tbl->next = win->tables; + tbl->prev = 0; + win->tables = tbl; + win->table_count++; + win->table_size = 0; +} + +static void +zr_remove_table(struct zr_window *win, struct zr_table *tbl) +{ + if (win->tables == tbl) + win->tables = tbl->next; + if (tbl->next) + tbl->next->prev = tbl->prev; + if (tbl->prev) + tbl->prev->next = tbl->next; + tbl->next = 0; + tbl->prev = 0; +} + +static zr_uint* +zr_find_value(struct zr_window *win, zr_hash name) +{ + unsigned short size = win->table_size; + struct zr_table *iter = win->tables; + while (iter) { + unsigned short i = 0; + for (i = 0; i < size; ++i) { + if (iter->keys[i] == name) { + iter->seq = win->seq; + return &iter->values[i]; + } + } + size = ZR_VALUE_PAGE_CAPACITY; + iter = iter->next; + } + return 0; +} + +static zr_uint* +zr_add_value(struct zr_context *ctx, struct zr_window *win, zr_hash name, zr_uint value) +{ + if (!win->tables || win->table_size == ZR_VALUE_PAGE_CAPACITY) { + struct zr_table *tbl = zr_create_table(ctx); + zr_push_table(win, tbl); + } + win->tables->seq = win->seq; + win->tables->keys[win->table_size] = name; + win->tables->values[win->table_size] = value; + return &win->tables->values[win->table_size++]; +} + +static int +zr_start_child(struct zr_context *ctx, struct zr_window *win) +{ + struct zr_popup_buffer *buf; + ZR_ASSERT(ctx); + ZR_ASSERT(win); + if (!ctx || !win) return zr_false; + + buf = &win->layout->popup_buffer; + buf->begin = win->buffer.end; + buf->end = win->buffer.end; + buf->parent = win->buffer.last; + buf->last = buf->begin; + buf->active = zr_true; + return zr_true; +} + +static void +zr_finish_child(struct zr_context *ctx, struct zr_window *win) +{ + struct zr_popup_buffer *buf; + ZR_ASSERT(ctx); + ZR_ASSERT(win); + if (!ctx || !win) return; + + buf = &win->layout->popup_buffer; + buf->last = win->buffer.last; + buf->end = win->buffer.end; +} + +static void +zr_finish(struct zr_context *ctx, struct zr_window *win) +{ + struct zr_popup_buffer *buf; + struct zr_command *parent_last; + struct zr_command *sublast; + struct zr_command *last; + void *memory; + + ZR_ASSERT(ctx); + ZR_ASSERT(win); + if (!ctx || !win) return; + win->buffer.end = ctx->memory.allocated; + if (!win->layout->popup_buffer.active) return; + + buf = &win->layout->popup_buffer; + memory = ctx->memory.memory.ptr; + + parent_last = zr_ptr_add(struct zr_command, memory, buf->parent); + sublast = zr_ptr_add(struct zr_command, memory, buf->last); + last = zr_ptr_add(struct zr_command, memory, win->buffer.last); + + /* redirect the subbuffer to the end of the current command buffer */ + parent_last->next = buf->end; + sublast->next = last->next; + last->next = buf->begin; + win->buffer.last = buf->last; + win->buffer.end = buf->end; + buf->active = zr_false; +} + +static void +zr_build(struct zr_context *ctx) +{ + struct zr_window *iter; + struct zr_window *next; + struct zr_command *cmd; + zr_byte *buffer; + + iter = ctx->begin; + buffer = (zr_byte*)ctx->memory.memory.ptr; + while (iter != 0) { + next = iter->next; + if (iter->buffer.last != iter->buffer.begin) { + cmd = zr_ptr_add(struct zr_command, buffer, iter->buffer.last); + while (next && next->buffer.last == next->buffer.begin) + next = next->next; /* skip empty command buffers */ + + if (next) { + cmd->next = next->buffer.begin; + } else cmd->next = ctx->memory.allocated; + } + iter = next; + } +} + +const struct zr_command* +zr__begin(struct zr_context *ctx) +{ + struct zr_window *iter; + zr_byte *buffer; + ZR_ASSERT(ctx); + if (!ctx) return 0; + if (!ctx->count) return 0; + + /* build one command list out of all windows */ + buffer = (zr_byte*)ctx->memory.memory.ptr; + if (!ctx->build) { + zr_build(ctx); + ctx->build = zr_true; + } + + iter = ctx->begin; + while (iter && iter->buffer.begin == iter->buffer.end) + iter = iter->next; + if (!iter) return 0; + return zr_ptr_add_const(struct zr_command, buffer, iter->buffer.begin); +} + +const struct zr_command* +zr__next(struct zr_context *ctx, const struct zr_command *cmd) +{ + zr_byte *buffer; + const struct zr_command *next; + ZR_ASSERT(ctx); + if (!ctx || !cmd || !ctx->count) return 0; + if (cmd->next >= ctx->memory.allocated) return 0; + buffer = (zr_byte*)ctx->memory.memory.ptr; + next = zr_ptr_add_const(struct zr_command, buffer, cmd->next); + return next; +} + +void +zr_clear(struct zr_context *ctx) +{ + struct zr_window *iter; + struct zr_window *next; + ZR_ASSERT(ctx); + if (!ctx) return; + if (ctx->pool) + zr_buffer_clear(&ctx->memory); + else zr_buffer_reset(&ctx->memory, ZR_BUFFER_FRONT); + ctx->build = 0; + ctx->memory.calls = 0; +#if ZR_COMPILE_WITH_VERTEX_BUFFER + zr_canvas_clear(&ctx->canvas); +#endif + + /* garbage collector */ + iter = ctx->begin; + while (iter) { + if (iter->flags & ZR_WINDOW_MINIMIZED) { + iter = iter->next; + continue; + } + + if (iter->popup.win && iter->popup.win->seq != ctx->seq) { + zr_free_window(ctx, iter->popup.win); + iter->popup.win = 0; + } + + {struct zr_table *n, *it = iter->tables; + while (it) { + /* window state tables */ + n = it->next; + if (it->seq != ctx->seq) { + zr_remove_table(iter, it); + zr_zero(it, sizeof(union zr_page_data)); + zr_free_table(ctx, it); + if (it == iter->tables) + iter->tables = n; + } + it = n; + }} + + if (iter->seq != ctx->seq) { + next = iter->next; + zr_free_window(ctx, iter); + iter = next; + } else iter = iter->next; + } + ctx->seq++; +} + +static void +zr_setup(struct zr_context *ctx, const struct zr_user_font *font, + zr_sin_f sine, zr_cos_f cosine) +{ + zr_zero(ctx, sizeof(*ctx)); + zr_style_default(&ctx->style, ZR_DEFAULT_ALL, font); +#if ZR_COMPILE_WITH_VERTEX_BUFFER + if (sine && cosine) zr_canvas_init(&ctx->canvas, sine, cosine); +#endif +} + +int +zr_init_fixed(struct zr_context *ctx, void *memory, zr_size size, + const struct zr_user_font *font, zr_sin_f sine, zr_cos_f cosine) +{ + ZR_ASSERT(memory); + if (!memory) return 0; + zr_setup(ctx, font, sine, cosine); + zr_buffer_init_fixed(&ctx->memory, memory, size); + ctx->pool = 0; + return 1; +} + +int +zr_init_custom(struct zr_context *ctx, struct zr_buffer *cmds, + struct zr_buffer *pool, const struct zr_user_font *font, + zr_sin_f sine, zr_cos_f cosine) +{ + ZR_ASSERT(cmds); + ZR_ASSERT(pool); + if (!cmds || !pool) return 0; + zr_setup(ctx, font, sine, cosine); + ctx->memory = *cmds; + if (pool->type == ZR_BUFFER_FIXED) { + /* take memory from buffer and alloc fixed pool */ + void *memory = pool->memory.ptr; + zr_size size = pool->memory.size; + ctx->pool = memory; + ZR_ASSERT(size > sizeof(struct zr_pool)); + size -= sizeof(struct zr_pool); + zr_pool_init_fixed(ctx->pool, (zr_byte*)ctx->pool+sizeof(struct zr_pool), size); + } else { + /* create dynamic pool from buffer allocator */ + struct zr_allocator *alloc = &pool->pool; + ctx->pool = alloc->alloc(alloc->userdata, sizeof(struct zr_pool)); + zr_pool_init(ctx->pool, alloc, ZR_POOL_DEFAULT_CAPACTIY); + } + return 1; +} + +int +zr_init(struct zr_context *ctx, struct zr_allocator *alloc, + const struct zr_user_font *font, zr_sin_f sine, zr_cos_f cosine) +{ + ZR_ASSERT(alloc); + if (!alloc) return 0; + zr_setup(ctx, font, sine, cosine); + zr_buffer_init(&ctx->memory, alloc, ZR_DEFAULT_COMMAND_BUFFER_SIZE); + ctx->pool = alloc->alloc(alloc->userdata, sizeof(struct zr_pool)); + zr_pool_init(ctx->pool, alloc, ZR_POOL_DEFAULT_CAPACTIY); + return 1; +} + +void +zr_free(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + if (!ctx) return; + zr_buffer_free(&ctx->memory); + if (ctx->pool) zr_pool_free(ctx->pool); + + zr_zero(&ctx->input, sizeof(ctx->input)); + zr_zero(&ctx->style, sizeof(ctx->style)); + zr_zero(&ctx->memory, sizeof(ctx->memory)); + + ctx->seq = 0; + ctx->pool = 0; + ctx->build = 0; + ctx->begin = 0; + ctx->end = 0; + ctx->active = 0; + ctx->current = 0; + ctx->freelist = 0; + ctx->count = 0; +} + +int +zr_begin(struct zr_context *ctx, struct zr_layout *layout, + const char *title, struct zr_rect bounds, zr_flags flags) +{ + struct zr_window *win; + zr_hash title_hash; + int title_len; + int ret = 0; + + ZR_ASSERT(ctx); + ZR_ASSERT(title); + ZR_ASSERT(!ctx->current); + if (!ctx || ctx->current || !title) + return 0; + + /* find or create window */ + title_len = (int)zr_strsiz(title); + title_hash = zr_murmur_hash(title, (int)title_len, ZR_WINDOW_TITLE); + win = zr_find_window(ctx, title_hash); + if (!win) { + win = zr_create_window(ctx); + zr_insert_window(ctx, win); + zr_command_buffer_init(&win->buffer, &ctx->memory, ZR_CLIPPING_ON); + ZR_ASSERT(win); + if (!win) return 0; + win->flags = flags; + win->bounds = bounds; + win->name = title_hash; + win->popup.win = 0; + } else win->seq++; + if (win->flags & ZR_WINDOW_HIDDEN) return 0; + + /* overlapping window */ + if (!(win->flags & ZR_WINDOW_SUB) && !(win->flags & ZR_WINDOW_HIDDEN)) + { + int inpanel; + zr_start(ctx, win); + inpanel = zr_input_mouse_clicked(&ctx->input, ZR_BUTTON_LEFT, win->bounds); + if (inpanel && (win != ctx->end)) { + const struct zr_window *iter = win->next; + while (iter) { + /* try to find a panel with higher priorty in the same position */ + if (ZR_INBOX(ctx->input.mouse.prev.x, ctx->input.mouse.prev.y, iter->bounds.x, + iter->bounds.y, iter->bounds.w, iter->bounds.h) && + !(iter->flags & ZR_WINDOW_MINIMIZED) && !(iter->flags & ZR_WINDOW_HIDDEN)) + break; + iter = iter->next; + } + if (!iter) { + /* current panel is active panel in that position so transfer to top + * at the highest priority in stack */ + zr_remove_window(ctx, win); + zr_insert_window(ctx, win); + + win->flags &= ~(zr_flags)ZR_WINDOW_ROM; + ctx->active = win; + } + } + if (ctx->end != win) + win->flags |= ZR_WINDOW_ROM; + } + + win->layout = layout; + ctx->current = win; + ret = zr_layout_begin(ctx, title); + layout->offset = &win->scrollbar; + return ret; +} + +void +zr_end(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + if (!ctx || !ctx->current) return; + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + zr_layout_end(ctx); + ctx->current = 0; +} +/*---------------------------------------------------------------- * * WINDOW * - * ===============================================================*/ -void -zr_window_init(struct zr_window *window, struct zr_rect bounds, - zr_flags flags, struct zr_command_queue *queue, - struct zr_style *style, struct zr_input *input) + * --------------------------------------------------------------*/ +struct zr_rect +zr_window_get_bounds(const struct zr_context *ctx) { - ZR_ASSERT(window); - ZR_ASSERT(style); - ZR_ASSERT(input); - if (!window || !style || !input) - return; - - window->bounds = bounds; - window->flags = flags; - window->style = style; - window->offset.x = 0; - window->offset.y = 0; - window->queue = queue; - window->input = input; - - if (queue) { - zr_command_buffer_init(&window->buffer, &queue->buffer, ZR_CLIP); - zr_command_queue_insert_back(queue, &window->buffer); - } + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return zr_rect(0,0,0,0); + return ctx->current->bounds; +} +struct zr_vec2 +zr_window_get_position(const struct zr_context *ctx) +{ + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return zr_vec2(0,0); + return zr_vec2(ctx->current->bounds.x, ctx->current->bounds.y); } -void -zr_window_link(struct zr_window *window, struct zr_command_queue *queue) +struct zr_vec2 +zr_window_get_size(const struct zr_context *ctx) { - ZR_ASSERT(window); - ZR_ASSERT(window->queue); - if (!window || !window->queue) return; - if (queue) { - zr_command_buffer_init(&window->buffer, &queue->buffer, ZR_CLIP); - zr_command_queue_insert_back(queue, &window->buffer); - } + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return zr_vec2(0,0); + return zr_vec2(ctx->current->bounds.w, ctx->current->bounds.h); } -void -zr_window_unlink(struct zr_window *window) +float +zr_window_get_width(const struct zr_context *ctx) { - ZR_ASSERT(window); - ZR_ASSERT(window->queue); - if (!window || !window->queue) return; - zr_command_queue_remove(window->queue, &window->buffer); - window->queue = 0; + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return 0; + return ctx->current->bounds.w; } -void -zr_window_add_flag(struct zr_window *panel, zr_flags f) -{panel->flags |= f;} +float +zr_window_get_height(const struct zr_context *ctx) +{ + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return 0; + return ctx->current->bounds.h; +} -void -zr_window_remove_flag(struct zr_window *panel, zr_flags f) -{panel->flags &= (zr_flags)~f;} +struct zr_rect +zr_window_get_content_region(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return zr_rect(0,0,0,0); + return ctx->current->layout->clip; +} + +struct zr_vec2 +zr_window_get_content_region_min(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return zr_vec2(0,0); + return zr_vec2(ctx->current->layout->clip.x, ctx->current->layout->clip.y); +} + +struct zr_vec2 +zr_window_get_content_region_max(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return zr_vec2(0,0); + return zr_vec2(ctx->current->layout->clip.x + ctx->current->layout->clip.w, + ctx->current->layout->clip.y + ctx->current->layout->clip.h); +} + +struct zr_vec2 +zr_window_get_content_region_size(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return zr_vec2(0,0); + return zr_vec2(ctx->current->layout->clip.w, ctx->current->layout->clip.h); +} + +struct zr_command_buffer* +zr_window_get_canvas(struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return 0; + return &ctx->current->buffer; +} int -zr_window_has_flag(struct zr_window *panel, zr_flags f) -{return (panel->flags & f) ? zr_true: zr_false;} +zr_window_has_focus(const struct zr_context *ctx) +{ + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current) return 0; + return ctx->current == ctx->active; +} int -zr_window_is_minimized(struct zr_window *panel) -{return panel->flags & ZR_WINDOW_MINIMIZED;} +zr_window_is_collapsed(struct zr_context *ctx, const char *name) +{ + int title_len; + zr_hash title_hash; + struct zr_window *win; + ZR_ASSERT(ctx); + if (!ctx) return 0; -/*------------------------------------------------------------- + title_len = (int)zr_strsiz(name); + title_hash = zr_murmur_hash(name, (int)title_len, ZR_WINDOW_TITLE); + win = zr_find_window(ctx, title_hash); + if (!win) return 0; + return win->flags & ZR_WINDOW_MINIMIZED; +} + +int +zr_window_is_closed(struct zr_context *ctx, const char *name) +{ + int title_len; + zr_hash title_hash; + struct zr_window *win; + ZR_ASSERT(ctx); + if (!ctx) return 0; + + title_len = (int)zr_strsiz(name); + title_hash = zr_murmur_hash(name, (int)title_len, ZR_WINDOW_TITLE); + win = zr_find_window(ctx, title_hash); + if (!win) return 0; + return win->flags & ZR_WINDOW_HIDDEN; +} + +void +zr_window_set_bounds(struct zr_context *ctx, struct zr_rect bounds) +{ + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->bounds = bounds; +} + +void +zr_window_set_position(struct zr_context *ctx, struct zr_vec2 pos) +{ + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->bounds.x = pos.x; + ctx->current->bounds.y = pos.y; +} + +void +zr_window_set_size(struct zr_context *ctx, struct zr_vec2 size) +{ + ZR_ASSERT(ctx); ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + ctx->current->bounds.w = size.x; + ctx->current->bounds.h = size.y; +} + +void +zr_window_collapse(struct zr_context *ctx, const char *name, enum zr_collapse_states c) +{ + int title_len; + zr_hash title_hash; + struct zr_window *win; + ZR_ASSERT(ctx); + if (!ctx) return; + + title_len = (int)zr_strsiz(name); + title_hash = zr_murmur_hash(name, (int)title_len, ZR_WINDOW_TITLE); + win = zr_find_window(ctx, title_hash); + if (!win) return; + if (c == ZR_MINIMIZED) + win->flags |= ZR_WINDOW_MINIMIZED; + else win->flags &= ~(zr_flags)ZR_WINDOW_MINIMIZED; +} + +void +zr_window_collapse_if(struct zr_context *ctx, const char *name, + enum zr_collapse_states c, int cond) +{ + int title_len; + zr_hash title_hash; + struct zr_window *win; + ZR_ASSERT(ctx); + if (!ctx || !cond) return; + + title_len = (int)zr_strsiz(name); + title_hash = zr_murmur_hash(name, (int)title_len, ZR_WINDOW_TITLE); + win = zr_find_window(ctx, title_hash); + if (!win) return; + if (c == ZR_MINIMIZED) + win->flags |= ZR_WINDOW_HIDDEN; + else win->flags &= ~(zr_flags)ZR_WINDOW_HIDDEN; +} + +void +zr_window_set_focus(struct zr_context *ctx, const char *name) +{ + int title_len; + zr_hash title_hash; + struct zr_window *win; + ZR_ASSERT(ctx); + if (!ctx) return; + + title_len = (int)zr_strsiz(name); + title_hash = zr_murmur_hash(name, (int)title_len, ZR_WINDOW_TITLE); + win = zr_find_window(ctx, title_hash); + ctx->active = win; +} + +/*---------------------------------------------------------------- * - * HEADER + * LAYOUT * * --------------------------------------------------------------*/ struct zr_window_header { @@ -6405,8 +6871,8 @@ struct zr_window_header { }; static int -zr_header_button(struct zr_context *layout, struct zr_window_header *header, - zr_rune symbol, enum zr_style_header_align align) +zr_header_button(struct zr_context *ctx, struct zr_window_header *header, + zr_rune symbol, enum zr_style_header_align align) { /* calculate the position of the close icon position and draw it */ zr_glyph glyph; @@ -6417,16 +6883,20 @@ zr_header_button(struct zr_context *layout, struct zr_window_header *header, const struct zr_style *c; struct zr_command_buffer *out; struct zr_vec2 item_padding; + struct zr_window *win; + struct zr_layout *layout; - ZR_ASSERT(layout); - ZR_ASSERT(layout->buffer); - ZR_ASSERT(layout->style); - if (!layout || layout->flags & ZR_WINDOW_HIDDEN) + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !ctx->current || !ctx->current->layout) return zr_false; /* cache configuration data */ - c = layout->style; - out = layout->buffer; + win = ctx->current; + layout = win->layout; + c = &ctx->style; + out = &win->buffer; item_padding = zr_style_property(c, ZR_PROPERTY_ITEM_PADDING); sym.x = header->front; @@ -6444,21 +6914,17 @@ zr_header_button(struct zr_context *layout, struct zr_window_header *header, sym.h = c->font.height + 2 * item_padding.y; if (align == ZR_HEADER_RIGHT) sym.x = header->back - sym.w; - zr_command_buffer_push_text(out, sym, X, len, &c->font, + zr_draw_text(out, sym, X, len, &c->font, c->colors[ZR_COLOR_HEADER],c->colors[ZR_COLOR_TEXT]); } /* check if the icon has been pressed */ if (!(layout->flags & ZR_WINDOW_ROM)) { - float mouse_x = layout->input->mouse.pos.x; - float mouse_y = layout->input->mouse.pos.y; - float clicked_x = layout->input->mouse.buttons[ZR_BUTTON_LEFT].clicked_pos.x; - float clicked_y = layout->input->mouse.buttons[ZR_BUTTON_LEFT].clicked_pos.y; - if (ZR_INBOX(mouse_x, mouse_y, sym.x, sym.y, sym_bw, sym.h)) { - if (ZR_INBOX(clicked_x, clicked_y, sym.x, sym.y, sym_bw, sym.h)) - ret = (layout->input->mouse.buttons[ZR_BUTTON_LEFT].down && - layout->input->mouse.buttons[ZR_BUTTON_LEFT].clicked); - } + struct zr_rect bounds; + enum zr_widget_status status; + bounds.x = sym.x; bounds.y = sym.y; + bounds.w = sym_bw; bounds.h = sym.h; + ret = zr_button_behavior(&status, bounds, &ctx->input, ZR_BUTTON_DEFAULT); } /* update the header space */ @@ -6469,60 +6935,60 @@ zr_header_button(struct zr_context *layout, struct zr_window_header *header, } static int -zr_header_toggle(struct zr_context *layout,struct zr_window_header *header, +zr_header_toggle(struct zr_context *ctx, struct zr_window_header *header, zr_rune active, zr_rune inactive, enum zr_style_header_align align, int state) { - int ret = zr_header_button(layout, header,(state) ? active : inactive, align); - if (ret) return !state; + int ret = zr_header_button(ctx, header,(state) ? active : inactive, align); + if (ret) + return !state; return state; } static int -zr_header_flag(struct zr_context *layout, struct zr_window_header *header, +zr_header_flag(struct zr_context *ctx, struct zr_window_header *header, zr_rune inactive, zr_rune active, enum zr_style_header_align align, enum zr_window_flags flag) { - zr_flags flags = layout->flags; + struct zr_window *win = ctx->current; + struct zr_layout *layout = win->layout; + zr_flags flags = win->flags; int state = (flags & flag) ? zr_true : zr_false; - int ret = zr_header_toggle(layout, header, inactive, active, align, state); + int ret = zr_header_toggle(ctx, header, inactive, active, align, state); if (ret != ((flags & flag) ? zr_true : zr_false)) { /* the state of the toggle icon has been changed */ if (!ret) layout->flags &= ~flag; else layout->flags |= flag; - /* update the state of the panel since the flag have changed */ - layout->valid = !(layout->flags & ZR_WINDOW_HIDDEN) && - !(layout->flags & ZR_WINDOW_MINIMIZED); return zr_true; } return zr_false; } -/*------------------------------------------------------------- - * - * CONTEXT - * - * --------------------------------------------------------------*/ -zr_flags -zr_begin(struct zr_context *context, struct zr_window *window, const char *title) +static int +zr_layout_begin(struct zr_context *ctx, const char *title) { int header_active = 0; - zr_flags ret = 0; - const struct zr_style *c; float scrollbar_size; struct zr_vec2 item_padding; struct zr_vec2 item_spacing; struct zr_vec2 window_padding; struct zr_vec2 scaler_size; - struct zr_command_buffer *out; + struct zr_input *in; + struct zr_window *win; + const struct zr_style *c; + struct zr_layout *layout; + struct zr_command_buffer *out; - ZR_ASSERT(context); - ZR_ASSERT(window); - ZR_ASSERT(window->style); + ZR_ASSERT(ctx); + if (!ctx) return 0; + c = &ctx->style; + in = &ctx->input; + ZR_ASSERT(ctx->current); + win = ctx->current; + ZR_ASSERT(win->layout); + layout = win->layout; - /* cache configuration data */ - c = window->style; - in = window->input; + /* cache style data */ scrollbar_size = zr_style_property(c, ZR_PROPERTY_SCROLLBAR_SIZE).x; window_padding = zr_style_property(c, ZR_PROPERTY_PADDING); item_padding = zr_style_property(c, ZR_PROPERTY_ITEM_PADDING); @@ -6530,136 +6996,76 @@ zr_begin(struct zr_context *context, struct zr_window *window, const char *title scaler_size = zr_style_property(c, ZR_PROPERTY_SCALER_SIZE); /* check arguments */ - if (!window || !context) return ret; - zr_zero(context, sizeof(*context)); - if (window->flags & ZR_WINDOW_HIDDEN) { - context->flags = window->flags; - context->valid = zr_false; - context->style = window->style; - context->buffer = &window->buffer; - return ret; - } - - /* overlapping panels */ - if (window->queue && !(window->flags & ZR_WINDOW_TAB)) - { - context->queue = window->queue; - zr_command_queue_start(window->queue, &window->buffer); - { - int inpanel; - struct zr_command_buffer_list *s = &window->queue->list; - inpanel = zr_input_mouse_clicked(in, ZR_BUTTON_LEFT, window->bounds); - if (inpanel && (&window->buffer != s->end)) { - const struct zr_command_buffer *iter = window->buffer.next; - while (iter) { - /* try to find a panel with higher priorty in the same position */ - const struct zr_window *cur; - cur = ZR_CONTAINER_OF_CONST(iter, struct zr_window, buffer); - if (ZR_INBOX(in->mouse.prev.x, in->mouse.prev.y, cur->bounds.x, - cur->bounds.y, cur->bounds.w, cur->bounds.h) && - !(cur->flags & ZR_WINDOW_MINIMIZED) && !(cur->flags & ZR_WINDOW_HIDDEN)) - break; - iter = iter->next; - } - /* current panel is active panel in that position so transfer to top - * at the highest priority in stack */ - if (!iter) { - zr_command_queue_remove(window->queue, &window->buffer); - zr_command_queue_insert_back(window->queue, &window->buffer); - window->flags &= ~(zr_flags)ZR_WINDOW_ROM; - } - } - if (s->end != &window->buffer) - window->flags |= ZR_WINDOW_ROM; - } - } + zr_zero(layout, sizeof(*layout)); + if (win->flags & ZR_WINDOW_HIDDEN) + return 0; /* move panel position if requested */ - context->header_h = c->font.height + 4 * item_padding.y; - context->header_h += window_padding.y; - if ((window->flags & ZR_WINDOW_MOVEABLE) && !(window->flags & ZR_WINDOW_ROM)) { + layout->header_h = c->font.height + 4 * item_padding.y; + layout->header_h += window_padding.y; + if ((win->flags & ZR_WINDOW_MOVEABLE) && !(win->flags & ZR_WINDOW_ROM)) { int incursor; struct zr_rect move; - move.x = window->bounds.x; - move.y = window->bounds.y; - move.w = window->bounds.w; - move.h = context->header_h; + move.x = win->bounds.x; + move.y = win->bounds.y; + move.w = win->bounds.w; + move.h = layout->header_h; incursor = zr_input_is_mouse_prev_hovering_rect(in, move); if (zr_input_is_mouse_down(in, ZR_BUTTON_LEFT) && incursor) { - window->bounds.x = window->bounds.x + in->mouse.delta.x; - window->bounds.y = window->bounds.y + in->mouse.delta.y; - ret = ZR_WINDOW_MOVEABLE; + win->bounds.x = win->bounds.x + in->mouse.delta.x; + win->bounds.y = win->bounds.y + in->mouse.delta.y; } } - /* setup window context */ - out = &window->buffer; - context->input = in; - context->bounds = window->bounds; - context->at_x = window->bounds.x; - context->at_y = window->bounds.y; - context->width = window->bounds.w; - context->height = window->bounds.h; - context->style = window->style; - context->buffer = &window->buffer; - context->row.index = 0; - context->row.columns = 0; - context->row.height = 0; - context->row.ratio = 0; - context->row.item_width = 0; - context->offset = window->offset; - context->max_x = 0; - context->property = &window->property; + /* setup window layout */ + out = &win->buffer; + layout->bounds = win->bounds; + layout->at_x = win->bounds.x; + layout->at_y = win->bounds.y; + layout->width = win->bounds.w; + layout->height = win->bounds.h; + layout->row.index = 0; + layout->row.columns = 0; + layout->row.height = 0; + layout->row.ratio = 0; + layout->row.item_width = 0; + layout->max_x = 0; + layout->flags = win->flags; - /* window header */ - if (window->flags & ZR_WINDOW_MINIMIZED) { - context->header_h = 0; - context->row.height = 0; + /* calculate window header */ + if (win->flags & ZR_WINDOW_MINIMIZED) { + layout->header_h = 0; + layout->row.height = 0; } else { - context->header_h = 2 * item_spacing.y; - context->row.height = context->header_h + 1; + layout->header_h = 2 * item_spacing.y; + layout->row.height = layout->header_h + 1; } - /* window activation by click inside */ - if (!(window->flags & ZR_WINDOW_TAB) && !(window->flags & ZR_WINDOW_ROM)) { - float clicked_x = in->mouse.buttons[ZR_BUTTON_LEFT].clicked_pos.x; - float clicked_y = in->mouse.buttons[ZR_BUTTON_LEFT].clicked_pos.y; - if (zr_input_is_mouse_down(in, ZR_BUTTON_LEFT)) { - if (ZR_INBOX(clicked_x, clicked_y, window->bounds.x, window->bounds.y, - window->bounds.w, window->bounds.h)) - window->flags |= ZR_WINDOW_ACTIVE; - else window->flags &= (zr_flags)~ZR_WINDOW_ACTIVE; - } - } - - context->flags = window->flags; - context->valid = !(window->flags & ZR_WINDOW_HIDDEN) && - !(window->flags & ZR_WINDOW_MINIMIZED); - /* calculate window footer height */ - if (!(window->flags & ZR_WINDOW_COMBO_MENU) && - (!(window->flags & ZR_WINDOW_NO_SCROLLBAR) || (window->flags & ZR_WINDOW_SCALEABLE))) - context->footer_h = scaler_size.y + item_padding.y; - else context->footer_h = 0; + if (!(win->flags & ZR_WINDOW_NONBLOCK) && + (!(win->flags & ZR_WINDOW_NO_SCROLLBAR) || (win->flags & ZR_WINDOW_SCALEABLE))) + layout->footer_h = scaler_size.y + item_padding.y; + else layout->footer_h = 0; /* calculate the window size */ - if (!(window->flags & ZR_WINDOW_NO_SCROLLBAR)) - context->width = window->bounds.w - scrollbar_size; - context->height = window->bounds.h - (context->header_h + 2 * item_spacing.y); - context->height -= context->footer_h; + if (!(win->flags & ZR_WINDOW_NO_SCROLLBAR)) + layout->width = win->bounds.w - scrollbar_size; + layout->height = win->bounds.h - (layout->header_h + 2 * item_spacing.y); + layout->height -= layout->footer_h; /* draw window background if not a dynamic window */ - if (!(context->flags & ZR_WINDOW_DYNAMIC) && context->valid) { - zr_command_buffer_push_rect(out, context->bounds, 0, c->colors[ZR_COLOR_WINDOW]); + if (!(layout->flags & ZR_WINDOW_DYNAMIC) && !(layout->flags & ZR_WINDOW_MINIMIZED)) { + zr_draw_rect(out, layout->bounds, 0, c->colors[ZR_COLOR_WINDOW]); } else{ - zr_command_buffer_push_rect(out, zr_rect(context->bounds.x, context->bounds.y, - context->bounds.w, context->row.height + window_padding.y), 0, c->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y, + layout->bounds.w, layout->row.height + window_padding.y), 0, c->colors[ZR_COLOR_WINDOW]); } /* window header */ - header_active = (window->flags & (ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE)); - header_active = header_active || (title != 0); - header_active = header_active && !(window->flags & ZR_WINDOW_HIDDEN); + header_active = (win->flags & (ZR_WINDOW_CLOSEABLE|ZR_WINDOW_MINIMIZABLE)); + header_active = header_active || (win->flags & ZR_WINDOW_TITLE); + header_active = header_active && !(win->flags & ZR_WINDOW_HIDDEN) && title; + if (header_active) { zr_flags old; struct zr_rect old_clip = out->clip; @@ -6670,49 +7076,43 @@ zr_begin(struct zr_context *context, struct zr_window *window, const char *title * is possible because the command buffer automatically clips text by using * its clipping rectangle. But since the clipping rect gets reused to calculate * the window clipping rect the old clipping rect has to be stored and reset afterwards. */ - out->clip.x = header.x = context->bounds.x + window_padding.x; - out->clip.y = header.y = context->bounds.y + item_padding.y; - out->clip.w = header.w = MAX(context->bounds.w, 2 * window_padding.x); + out->clip.x = header.x = layout->bounds.x + window_padding.x; + out->clip.y = header.y = layout->bounds.y + item_padding.y; + out->clip.w = header.w = MAX(layout->bounds.w, 2 * window_padding.x); out->clip.h = header.w -= 2 * window_padding.x; /* update the header height and first row height */ - context->header_h = c->font.height + 2 * item_padding.y; - context->header_h += window_padding.y; - context->row.height += context->header_h; + layout->header_h = c->font.height + 2 * item_padding.y; + layout->header_h += window_padding.y; + layout->row.height += layout->header_h; - header.h = context->header_h; + header.h = layout->header_h; header.back = header.x + header.w; header.front = header.x; - context->height = context->bounds.h - (header.h + 2 * item_spacing.y); - context->height -= context->footer_h; + layout->height = layout->bounds.h - (header.h + 2 * item_spacing.y); + layout->height -= layout->footer_h; /* draw header background */ - if (!(context->flags & ZR_WINDOW_BORDER)) { - zr_command_buffer_push_rect(out, zr_rect(context->bounds.x, context->bounds.y, - context->bounds.w, context->header_h), 0, c->colors[ZR_COLOR_HEADER]); + if (!(layout->flags & ZR_WINDOW_BORDER)) { + zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y, + layout->bounds.w, layout->header_h), 0, c->colors[ZR_COLOR_HEADER]); } else { - zr_command_buffer_push_rect(out, zr_rect(context->bounds.x, context->bounds.y+1, - context->bounds.w, context->header_h), 0, c->colors[ZR_COLOR_HEADER]); + zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y+1, + layout->bounds.w, layout->header_h), 0, c->colors[ZR_COLOR_HEADER]); } /* window header icons */ - old = window->flags; - if (window->flags & ZR_WINDOW_CLOSEABLE) - zr_header_flag(context, &header, c->header.close_symbol, c->header.close_symbol, + old = win->flags; + if (win->flags & ZR_WINDOW_CLOSEABLE) + zr_header_flag(ctx, &header, c->header.close_symbol, c->header.close_symbol, c->header.align, ZR_WINDOW_HIDDEN); - if (window->flags & ZR_WINDOW_MINIMIZABLE) - zr_header_flag(context, &header, c->header.maximize_symbol, c->header.minimize_symbol, + if (win->flags & ZR_WINDOW_MINIMIZABLE) + zr_header_flag(ctx, &header, c->header.maximize_symbol, c->header.minimize_symbol, c->header.align, ZR_WINDOW_MINIMIZED); - /* window state change notifcations */ - if ((old & ZR_WINDOW_HIDDEN) ^ (context->flags & ZR_WINDOW_HIDDEN)) - ret |= ZR_WINDOW_CLOSEABLE; - if ((old & ZR_WINDOW_MINIMIZED) ^ (context->flags & ZR_WINDOW_MINIMIZED)) - ret |= ZR_WINDOW_MINIMIZABLE; - - /* window header title */ - if (title) { + { + /* window header title */ zr_size text_len = zr_strsiz(title); struct zr_rect label = {0,0,0,0}; @@ -6730,56 +7130,55 @@ zr_begin(struct zr_context *context, struct zr_window *window, const char *title label.y = header.y; label.h = c->font.height + 2 * item_padding.y; label.w = MAX((float)t + 2 * item_padding.x, 4 * item_padding.x); - zr_command_buffer_push_text(out, label, (const char*)title, text_len, + zr_draw_text(out, label, (const char*)title, text_len, &c->font, c->colors[ZR_COLOR_HEADER], c->colors[ZR_COLOR_TEXT]); } out->clip = old_clip; } /* draw top window border line */ - if (context->flags & ZR_WINDOW_BORDER) { - zr_command_buffer_push_line(out, context->bounds.x, context->bounds.y, - context->bounds.x + context->bounds.w, context->bounds.y, + if (layout->flags & ZR_WINDOW_BORDER) { + zr_draw_line(out, layout->bounds.x, layout->bounds.y, + layout->bounds.x + layout->bounds.w, layout->bounds.y, c->colors[ZR_COLOR_BORDER]); } { /* calculate and set the window clipping rectangle*/ struct zr_rect clip; - if (!(window->flags & ZR_WINDOW_DYNAMIC)) { - context->clip.x = window->bounds.x + window_padding.x; - context->clip.w = context->width - 2 * window_padding.x; + if (!(win->flags & ZR_WINDOW_DYNAMIC)) { + layout->clip.x = win->bounds.x + window_padding.x; + layout->clip.w = layout->width - 2 * window_padding.x; } else { - context->clip.x = window->bounds.x; - context->clip.w = context->width; + layout->clip.x = win->bounds.x; + layout->clip.w = layout->width; } - context->clip.h = window->bounds.h - (context->footer_h + context->header_h); - context->clip.h -= (window_padding.y + item_padding.y); - context->clip.y = window->bounds.y; - if (!(window->flags & ZR_WINDOW_COMBO_MENU)) - context->clip.y += context->header_h; - if (window->flags & ZR_WINDOW_BORDER) { - context->clip.y += 1; - context->clip.h -= 1; + layout->clip.h = win->bounds.h - (layout->footer_h + layout->header_h); + layout->clip.h -= (window_padding.y + item_padding.y); + layout->clip.y = win->bounds.y; + if (!(win->flags & ZR_WINDOW_COMBO) && !(win->flags & ZR_WINDOW_MENU)) + layout->clip.y += layout->header_h; + if (win->flags & ZR_WINDOW_BORDER) { + layout->clip.y += 1; + layout->clip.h -= 2; } - zr_unify(&clip, &context->buffer->clip, context->clip.x, context->clip.y, - context->clip.x + context->clip.w, context->clip.y + context->clip.h); - zr_command_buffer_push_scissor(out, clip); + zr_unify(&clip, &win->buffer.clip, layout->clip.x, layout->clip.y, + layout->clip.x + layout->clip.w, layout->clip.y + layout->clip.h); + zr_draw_scissor(out, clip); - context->buffer->clip.x = context->bounds.x; - context->buffer->clip.w = context->width; - if (!(window->flags & ZR_WINDOW_NO_SCROLLBAR)) - context->buffer->clip.w += scrollbar_size; + win->buffer.clip.x = layout->bounds.x; + win->buffer.clip.w = layout->width; + if (!(win->flags & ZR_WINDOW_NO_SCROLLBAR)) + win->buffer.clip.w += scrollbar_size; } - return ret; + return !(layout->flags & ZR_WINDOW_HIDDEN) && !(layout->flags & ZR_WINDOW_MINIMIZED); } -zr_flags -zr_end(struct zr_context *layout, struct zr_window *window) +static void +zr_layout_end(struct zr_context *ctx) { - zr_flags ret = 0; struct zr_input *in; const struct zr_style *config; struct zr_command_buffer *out; @@ -6790,15 +7189,21 @@ zr_end(struct zr_context *layout, struct zr_window *window) struct zr_vec2 scaler_size; struct zr_rect footer = {0,0,0,0}; - ZR_ASSERT(layout); - ZR_ASSERT(window); - if (!window || !layout) return ret; + struct zr_window *window; + struct zr_layout *layout; + ZR_ASSERT(ctx); + if (!ctx) return; - config = layout->style; - out = layout->buffer; - in = (layout->flags & ZR_WINDOW_ROM) ? 0 :layout->input; - if (!(layout->flags & ZR_WINDOW_TAB)) - zr_command_buffer_push_scissor(out, zr_null_rect); + /* cache configuration data */ + ZR_ASSERT(ctx->current); + window = ctx->current; + layout = window->layout; + config = &ctx->style; + out = &window->buffer; + in = (layout->flags & ZR_WINDOW_ROM) ? 0 :&ctx->input; + + if (!(layout->flags & ZR_WINDOW_SUB)) + zr_draw_scissor(out, zr_null_rect); /* cache configuration data */ item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); @@ -6811,9 +7216,9 @@ zr_end(struct zr_context *layout, struct zr_window *window) layout->at_y += layout->row.height; /* draw footer and fill empty spaces inside a dynamically growing panel */ - if (layout->valid && (layout->flags & ZR_WINDOW_DYNAMIC)) { + if (layout->flags & ZR_WINDOW_DYNAMIC && !(layout->flags & ZR_WINDOW_MINIMIZED)) { layout->height = MIN(layout->at_y - layout->bounds.y, layout->bounds.h); - if ((layout->offset.x == 0) || (layout->flags & ZR_WINDOW_NO_SCROLLBAR)) { + if ((layout->offset->x == 0) || (layout->flags & ZR_WINDOW_NO_SCROLLBAR)) { footer.x = window->bounds.x; footer.y = window->bounds.y + layout->height + item_spacing.y; footer.w = window->bounds.w + scrollbar_size; @@ -6822,24 +7227,24 @@ zr_end(struct zr_context *layout, struct zr_window *window) footer.x = window->bounds.x; footer.w = window->bounds.w + scrollbar_size; footer.h = layout->footer_h; - if (layout->flags & ZR_WINDOW_COMBO_MENU) + if ((layout->flags & ZR_WINDOW_COMBO) || (layout->flags & ZR_WINDOW_MENU)) footer.y = window->bounds.y + layout->height; else footer.y = window->bounds.y + layout->height + layout->footer_h; - zr_command_buffer_push_rect(out, footer, 0, config->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, footer, 0, config->colors[ZR_COLOR_WINDOW]); - if (!(layout->flags & ZR_WINDOW_COMBO_MENU)) { + if (!(layout->flags & ZR_WINDOW_COMBO) && !(layout->flags & ZR_WINDOW_MENU)) { struct zr_rect bounds; bounds.x = layout->bounds.x; bounds.y = window->bounds.y + layout->height; - bounds.w = layout->width; + bounds.w = layout->bounds.w; bounds.h = layout->row.height; - zr_command_buffer_push_rect(out, bounds, 0, config->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, bounds, 0, config->colors[ZR_COLOR_WINDOW]); } } } /* scrollbars */ - if (layout->valid && !(layout->flags & ZR_WINDOW_NO_SCROLLBAR)) { + if (!(layout->flags & ZR_WINDOW_NO_SCROLLBAR) && !(layout->flags & ZR_WINDOW_MINIMIZED)) { struct zr_rect bounds; float scroll_target, scroll_offset, scroll_step; @@ -6852,25 +7257,26 @@ zr_end(struct zr_context *layout, struct zr_window *window) scroll.border = config->colors[ZR_COLOR_BORDER]; { /* vertical scollbar */ - enum zr_widget_states state; + enum zr_widget_status state; bounds.x = layout->bounds.x + layout->width; bounds.y = layout->clip.y; bounds.w = scrollbar_size; bounds.h = layout->clip.h; if (layout->flags & ZR_WINDOW_BORDER) bounds.h -= 1; - scroll_offset = layout->offset.y; + scroll_offset = layout->offset->y; scroll_step = layout->clip.h * 0.10f; scroll_target = (float)(int)(layout->at_y - layout->clip.y); - scroll.has_scrolling = (layout->flags & ZR_WINDOW_ACTIVE); - window->offset.y = zr_do_scrollbarv(&state, out, bounds, scroll_offset, - scroll_target, scroll_step, &scroll, in); + scroll.has_scrolling = (window == ctx->active); + scroll_offset = zr_do_scrollbarv(&state, out, bounds, scroll_offset, + scroll_target, scroll_step, &scroll, in); + layout->offset->y = (unsigned short)scroll_offset; } { /* horizontal scrollbar */ - enum zr_widget_states state; + enum zr_widget_status state; bounds.x = layout->bounds.x + window_padding.x; - if (layout->flags & ZR_WINDOW_TAB) { + if (layout->flags & ZR_WINDOW_SUB) { bounds.h = scrollbar_size; bounds.y = (layout->flags & ZR_WINDOW_BORDER) ? layout->bounds.y + 1 : layout->bounds.y; @@ -6885,41 +7291,40 @@ zr_end(struct zr_context *layout, struct zr_window *window) bounds.y = layout->bounds.y + window->bounds.h - MAX(layout->footer_h, scrollbar_size); bounds.w = layout->width - 2 * window_padding.x; } - scroll_offset = layout->offset.x; + scroll_offset = layout->offset->x; scroll_target = (float)(int)(layout->max_x - bounds.x); scroll_step = layout->max_x * 0.05f; scroll.has_scrolling = zr_false; - window->offset.x = zr_do_scrollbarh(&state, out, bounds, scroll_offset, + scroll_offset = zr_do_scrollbarh(&state, out, bounds, scroll_offset, scroll_target, scroll_step, &scroll, in); + layout->offset->x = (unsigned short)scroll_offset; } - }; + } /* draw the panel scaler into the right corner of the panel footer and * update panel size if user drags the scaler */ - if ((layout->flags & ZR_WINDOW_SCALEABLE) && layout->valid && in) { - float scaler_y; + if ((layout->flags & ZR_WINDOW_SCALEABLE) && in && !(layout->flags & ZR_WINDOW_MINIMIZED)) { struct zr_color col = config->colors[ZR_COLOR_SCALER]; float scaler_w = MAX(0, scaler_size.x - item_padding.x); float scaler_h = MAX(0, scaler_size.y - item_padding.y); float scaler_x = (layout->bounds.x + layout->bounds.w) - (item_padding.x + scaler_w); + float scaler_y; if (layout->flags & ZR_WINDOW_DYNAMIC) scaler_y = footer.y + layout->footer_h - scaler_size.y; else scaler_y = layout->bounds.y + layout->bounds.h - scaler_size.y; - zr_command_buffer_push_triangle(out, scaler_x + scaler_w, scaler_y, + zr_draw_triangle(out, scaler_x + scaler_w, scaler_y, scaler_x + scaler_w, scaler_y + scaler_h, scaler_x, scaler_y + scaler_h, col); if (!(window->flags & ZR_WINDOW_ROM)) { - int incursor; float prev_x = in->mouse.prev.x; float prev_y = in->mouse.prev.y; struct zr_vec2 window_size = zr_style_property(config, ZR_PROPERTY_SIZE); - incursor = ZR_INBOX(prev_x,prev_y,scaler_x,scaler_y,scaler_w,scaler_h); + int incursor = ZR_INBOX(prev_x,prev_y,scaler_x,scaler_y,scaler_w,scaler_h); if (zr_input_is_mouse_down(in, ZR_BUTTON_LEFT) && incursor) { window->bounds.w = MAX(window_size.x, window->bounds.w + in->mouse.delta.x); /* draging in y-direction is only possible if static window */ - ret = ZR_WINDOW_SCALEABLE; if (!(layout->flags & ZR_WINDOW_DYNAMIC)) window->bounds.h = MAX(window_size.y, window->bounds.h + in->mouse.delta.y); } @@ -6930,33 +7335,33 @@ zr_end(struct zr_context *layout, struct zr_window *window) /* draw the border around the complete panel */ const float width = (layout->flags & ZR_WINDOW_NO_SCROLLBAR) ? layout->width: layout->width + scrollbar_size; - const float padding_y = (!layout->valid) ? + const float padding_y = (layout->flags & ZR_WINDOW_MINIMIZED) ? window->bounds.y + layout->header_h: (layout->flags & ZR_WINDOW_DYNAMIC)? layout->footer_h + footer.y: layout->bounds.y + layout->bounds.h; if (window->flags & ZR_WINDOW_BORDER_HEADER) - zr_command_buffer_push_line(out, window->bounds.x, window->bounds.y + layout->header_h, + zr_draw_line(out, window->bounds.x, window->bounds.y + layout->header_h, window->bounds.x + window->bounds.w, window->bounds.y + layout->header_h, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_line(out, window->bounds.x, padding_y, window->bounds.x + width, + zr_draw_line(out, window->bounds.x, padding_y, window->bounds.x + width, padding_y, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_line(out, window->bounds.x, window->bounds.y, window->bounds.x, + zr_draw_line(out, window->bounds.x, window->bounds.y, window->bounds.x, padding_y, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_line(out, window->bounds.x + width, window->bounds.y, + zr_draw_line(out, window->bounds.x + width, window->bounds.y, window->bounds.x + width, padding_y, config->colors[ZR_COLOR_BORDER]); } - if (!(window->flags & ZR_WINDOW_TAB)) { + if (!(window->flags & ZR_WINDOW_SUB)) { /* window is hidden so clear command buffer */ if (layout->flags & ZR_WINDOW_HIDDEN) zr_command_buffer_reset(&window->buffer); /* window is visible and not tab */ - else zr_command_queue_finish(window->queue, &window->buffer); + else zr_finish(ctx, window); } - /* remove ROM flag was set so remove ROM FLAG*/ + /* ZR_WINDOW_REMOVE_ROM flag was set so remove ZR_WINDOW_ROM */ if (layout->flags & ZR_WINDOW_REMOVE_ROM) { layout->flags &= ~(zr_flags)ZR_WINDOW_ROM; layout->flags &= ~(zr_flags)ZR_WINDOW_REMOVE_ROM; @@ -6966,63 +7371,64 @@ zr_end(struct zr_context *layout, struct zr_window *window) /* property garbage collector */ if (window->property.active && window->property.old != window->property.seq && window->property.active == window->property.prev) { - window->property.old = 0; - window->property.seq = 0; - window->property.active = 0; - window->property.prev = 0; + zr_zero(&window->property, sizeof(window->property)); } else { window->property.old = window->property.seq; - window->property.seq = 0; window->property.prev = window->property.active; + window->property.seq = 0; + } + + /* edit garbage collector */ + if (window->edit.active && window->edit.old != window->edit.seq && + window->edit.active == window->edit.prev) { + zr_zero(&window->edit, sizeof(window->edit)); + } else { + window->edit.old = window->edit.seq; + window->edit.prev = window->edit.active; + window->edit.seq = 0; } - return ret; } -struct zr_command_buffer* -zr_canvas(struct zr_context *layout) -{return layout->buffer;} - -const struct zr_input* -zr_input(struct zr_context *layout) -{return layout->input;} - -struct zr_command_queue* -zr_queue(struct zr_context *layout) -{return layout->queue;} - -struct zr_rect -zr_space(struct zr_context *layout) -{ZR_ASSERT(layout); return layout->clip;} - void -zr_menubar_begin(struct zr_context *layout) +zr_menubar_begin(struct zr_context *ctx) { - ZR_ASSERT(layout); - if (!layout || layout->flags & ZR_WINDOW_HIDDEN || layout->flags & ZR_WINDOW_MINIMIZED) + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + layout = ctx->current->layout; + if (layout->flags & ZR_WINDOW_HIDDEN || layout->flags & ZR_WINDOW_MINIMIZED) return; + layout->menu.x = layout->at_x; layout->menu.y = layout->bounds.y + layout->header_h; layout->menu.w = layout->width; - layout->menu.offset = layout->offset; - layout->offset.y = 0; + layout->menu.offset = *layout->offset; + layout->offset->y = 0; } void -zr_menubar_end(struct zr_context *layout) +zr_menubar_end(struct zr_context *ctx) { + struct zr_window *win; + struct zr_layout *layout; struct zr_command_buffer *out; - ZR_ASSERT(layout); - if (!layout || layout->flags & ZR_WINDOW_HIDDEN || layout->flags & ZR_WINDOW_MINIMIZED) + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return; + win = ctx->current; + layout = win->layout; + if (!ctx || layout->flags & ZR_WINDOW_HIDDEN || layout->flags & ZR_WINDOW_MINIMIZED) return; - out = layout->buffer; + out = &win->buffer; layout->menu.h = layout->at_y - layout->menu.y; layout->clip.y = layout->bounds.y + layout->header_h + layout->menu.h + layout->row.height; layout->height -= layout->menu.h; - layout->offset = layout->menu.offset; + *layout->offset = layout->menu.offset; layout->clip.h -= layout->menu.h + layout->row.height; layout->at_y = layout->menu.y + layout->menu.h; - zr_command_buffer_push_scissor(out, layout->clip); + zr_draw_scissor(out, layout->clip); } /* ------------------------------------------------------------- * @@ -7030,24 +7436,22 @@ zr_menubar_end(struct zr_context *layout) * * --------------------------------------------------------------*/ static void -zr_panel_layout(struct zr_context *layout, float height, zr_size cols) +zr_panel_layout(const struct zr_context *ctx, struct zr_window *win, + float height, zr_size cols) { const struct zr_style *config; const struct zr_color *color; struct zr_command_buffer *out; struct zr_vec2 item_spacing; struct zr_vec2 panel_padding; + struct zr_layout *layout; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); - - if (!layout) return; - if (!layout->valid) return; + ZR_ASSERT(ctx); + layout = win->layout; /* prefetch some configuration data */ - config = layout->style; - out = layout->buffer; + config = &ctx->style; + out = &win->buffer; color = &config->colors[ZR_COLOR_WINDOW]; item_spacing = zr_style_property(config, ZR_PROPERTY_ITEM_SPACING); panel_padding = zr_style_property(config, ZR_PROPERTY_PADDING); @@ -7059,55 +7463,54 @@ zr_panel_layout(struct zr_context *layout, float height, zr_size cols) layout->row.height = height + item_spacing.y; layout->row.item_offset = 0; if (layout->flags & ZR_WINDOW_DYNAMIC) - zr_command_buffer_push_rect(out, zr_rect(layout->bounds.x, layout->at_y, + zr_draw_rect(out, zr_rect(layout->bounds.x, layout->at_y, layout->bounds.w, height + panel_padding.y), 0, *color); } static void -zr_row_layout(struct zr_context *layout, - enum zr_layout_format fmt, float height, zr_size cols, - zr_size width) +zr_row_layout(struct zr_context *ctx, enum zr_layout_format fmt, + float height, zr_size cols, zr_size width) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); - - if (!layout) return; - if (!layout->valid) return; - /* update the current row and set the current row layout */ - zr_panel_layout(layout, height, cols); - if (fmt == ZR_DYNAMIC) - layout->row.type = ZR_LAYOUT_DYNAMIC_FIXED; - else layout->row.type = ZR_LAYOUT_STATIC_FIXED; + struct zr_window *win; + ZR_ASSERT(ctx->current); + if (!ctx->current) return; - layout->row.item_width = (float)width; - layout->row.ratio = 0; - layout->row.item_offset = 0; - layout->row.filled = 0; + win = ctx->current; + zr_panel_layout(ctx, win, height, cols); + if (fmt == ZR_DYNAMIC) + win->layout->row.type = ZR_LAYOUT_DYNAMIC_FIXED; + else win->layout->row.type = ZR_LAYOUT_STATIC_FIXED; + + win->layout->row.item_width = (float)width; + win->layout->row.ratio = 0; + win->layout->row.item_offset = 0; + win->layout->row.filled = 0; } void -zr_layout_row_dynamic(struct zr_context *layout, float height, zr_size cols) -{zr_row_layout(layout, ZR_DYNAMIC, height, cols, 0);} +zr_layout_row_dynamic(struct zr_context *ctx, float height, zr_size cols) +{zr_row_layout(ctx, ZR_DYNAMIC, height, cols, 0);} void -zr_layout_row_static(struct zr_context *layout, float height, +zr_layout_row_static(struct zr_context *ctx, float height, zr_size item_width, zr_size cols) -{zr_row_layout(layout, ZR_STATIC, height, cols, item_width);} +{zr_row_layout(ctx, ZR_STATIC, height, cols, item_width);} void -zr_layout_row_begin(struct zr_context *layout, +zr_layout_row_begin(struct zr_context *ctx, enum zr_layout_format fmt, float row_height, zr_size cols) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; - if (!layout) return; - if (!layout->valid) return; + win = ctx->current; + layout = win->layout; - zr_panel_layout(layout, row_height, cols); + zr_panel_layout(ctx, win, row_height, cols); if (fmt == ZR_DYNAMIC) layout->row.type = ZR_LAYOUT_DYNAMIC_ROW; else layout->row.type = ZR_LAYOUT_STATIC_ROW; @@ -7120,11 +7523,16 @@ zr_layout_row_begin(struct zr_context *layout, } void -zr_layout_row_push(struct zr_context *layout, float ratio_or_width) +zr_layout_row_push(struct zr_context *ctx, float ratio_or_width) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - if (!layout || !layout->valid) return; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; if (layout->row.type == ZR_LAYOUT_DYNAMIC_ROW) { float ratio = ratio_or_width; @@ -7136,32 +7544,37 @@ zr_layout_row_push(struct zr_context *layout, float ratio_or_width) } void -zr_layout_row_end(struct zr_context *layout) +zr_layout_row_end(struct zr_context *ctx) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - if (!layout) return; - if (!layout->valid) return; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; layout->row.item_width = 0; layout->row.item_offset = 0; } void -zr_layout_row(struct zr_context *layout, enum zr_layout_format fmt, +zr_layout_row(struct zr_context *ctx, enum zr_layout_format fmt, float height, zr_size cols, const float *ratio) { zr_size i; zr_size n_undef = 0; float r = 0; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; - if (!layout) return; - if (!layout->valid) return; - - zr_panel_layout(layout, height, cols); + win = ctx->current; + layout = win->layout; + zr_panel_layout(ctx, win, height, cols); if (fmt == ZR_DYNAMIC) { /* calculate width of undefined widget ratios */ layout->row.ratio = ratio; @@ -7184,17 +7597,18 @@ zr_layout_row(struct zr_context *layout, enum zr_layout_format fmt, } void -zr_layout_row_space_begin(struct zr_context *layout, +zr_layout_space_begin(struct zr_context *ctx, enum zr_layout_format fmt, float height, zr_size widget_count) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; - if (!layout) return; - if (!layout->valid) return; - - zr_panel_layout(layout, height, widget_count); + win = ctx->current; + layout = win->layout; + zr_panel_layout(ctx, win, height, widget_count); if (fmt == ZR_STATIC) { /* calculate bounds of the free to use panel space */ struct zr_rect clip, space; @@ -7205,7 +7619,7 @@ zr_layout_row_space_begin(struct zr_context *layout, /* setup clipping rect for the free space to prevent overdraw */ zr_unify(&clip, &layout->clip, space.x, space.y, space.x + space.w, space.y + space.h); - zr_command_buffer_push_scissor(layout->buffer, clip); + zr_draw_scissor(&win->buffer, clip); layout->row.type = ZR_LAYOUT_STATIC_FREE; layout->row.clip = layout->clip; @@ -7219,105 +7633,151 @@ zr_layout_row_space_begin(struct zr_context *layout, } void -zr_layout_row_space_push(struct zr_context *layout, struct zr_rect rect) +zr_layout_space_push(struct zr_context *ctx, struct zr_rect rect) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); - if (!layout) return; - if (!layout->valid) return; + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + win = ctx->current; + layout = win->layout; layout->row.item = rect; } struct zr_rect -zr_layout_row_space_bounds(struct zr_context *ctx) +zr_layout_space_bounds(struct zr_context *ctx) { struct zr_rect ret; - ret.x = ctx->clip.x; - ret.y = ctx->clip.y; - ret.w = ctx->clip.w; - ret.h = ctx->row.height; + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + layout = win->layout; + + ret.x = layout->clip.x; + ret.y = layout->clip.y; + ret.w = layout->clip.w; + ret.h = layout->row.height; return ret; } struct zr_vec2 -zr_layout_row_space_to_screen(struct zr_context *layout, struct zr_vec2 ret) +zr_layout_space_to_screen(struct zr_context *ctx, struct zr_vec2 ret) { - ZR_ASSERT(layout); - ret.x += layout->clip.x - layout->offset.x; - ret.y += layout->clip.y - layout->offset.y; + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + layout = win->layout; + + ret.x += layout->clip.x - layout->offset->x; + ret.y += layout->clip.y - layout->offset->y; return ret; } struct zr_vec2 -zr_layout_row_space_to_local(struct zr_context *layout, struct zr_vec2 ret) +zr_layout_space_to_local(struct zr_context *ctx, struct zr_vec2 ret) { - ZR_ASSERT(layout); - ret.x += -layout->clip.x + layout->offset.x; - ret.y += -layout->clip.y + layout->offset.y; + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + layout = win->layout; + + ret.x += -layout->clip.x + layout->offset->x; + ret.y += -layout->clip.y + layout->offset->y; return ret; } struct zr_rect -zr_layout_row_space_rect_to_screen(struct zr_context *layout, struct zr_rect ret) +zr_layout_space_rect_to_screen(struct zr_context *ctx, struct zr_rect ret) { - ZR_ASSERT(layout); - ret.x += layout->clip.x - layout->offset.x; - ret.y += layout->clip.y - layout->offset.y; + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + layout = win->layout; + + ret.x += layout->clip.x - layout->offset->x; + ret.y += layout->clip.y - layout->offset->y; return ret; } struct zr_rect -zr_layout_row_space_rect_to_local(struct zr_context *layout, struct zr_rect ret) +zr_layout_space_rect_to_local(struct zr_context *ctx, struct zr_rect ret) { - ZR_ASSERT(layout); - ret.x += -layout->clip.x + layout->offset.x; - ret.y += -layout->clip.y + layout->offset.y; + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + layout = win->layout; + + ret.x += -layout->clip.x + layout->offset->x; + ret.y += -layout->clip.y + layout->offset->y; return ret; } void -zr_layout_row_space_end(struct zr_context *layout) +zr_layout_space_end(struct zr_context *ctx) { - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - if (!layout) return; - if (!layout->valid) return; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + win = ctx->current; + layout = win->layout; layout->row.item_width = 0; layout->row.item_height = 0; layout->row.item_offset = 0; zr_zero(&layout->row.item, sizeof(layout->row.item)); if (layout->row.type == ZR_LAYOUT_STATIC_FREE) - zr_command_buffer_push_scissor(layout->buffer, layout->clip); + zr_draw_scissor(&win->buffer, layout->clip); } static void -zr_panel_alloc_row(struct zr_context *layout) +zr_panel_alloc_row(const struct zr_context *ctx, struct zr_window *win) { - const struct zr_style *c = layout->style; + struct zr_layout *layout = win->layout; + const struct zr_style *c = &ctx->style; struct zr_vec2 spacing = zr_style_property(c, ZR_PROPERTY_ITEM_SPACING); const float row_height = layout->row.height - spacing.y; - zr_panel_layout(layout, row_height, layout->row.columns); + zr_panel_layout(ctx, win, row_height, layout->row.columns); } static void -zr_layout_widget_space(struct zr_rect *bounds, struct zr_context *layout, - int modify) +zr_layout_widget_space(struct zr_rect *bounds, const struct zr_context *ctx, + struct zr_window *win, int modify) { const struct zr_style *config; float panel_padding, panel_spacing, panel_space; float item_offset = 0, item_width = 0, item_spacing = 0; struct zr_vec2 spacing, padding; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; ZR_ASSERT(bounds); - if (!layout || !layout->style || !bounds) - return; /* cache some configuration data */ - config = layout->style; + config = &ctx->style; spacing = zr_style_property(config, ZR_PROPERTY_ITEM_SPACING); padding = zr_style_property(config, ZR_PROPERTY_PADDING); @@ -7349,7 +7809,7 @@ zr_layout_widget_space(struct zr_rect *bounds, struct zr_context *layout, case ZR_LAYOUT_DYNAMIC_FREE: { /* panel width depended free widget placing */ bounds->x = layout->at_x + (layout->width * layout->row.item.x); - bounds->x -= layout->offset.x; + bounds->x -= layout->offset->x; bounds->y = layout->at_y + (layout->row.height * layout->row.item.y); bounds->w = layout->width * layout->row.item.w; bounds->h = layout->row.height * layout->row.item.h; @@ -7394,9 +7854,9 @@ zr_layout_widget_space(struct zr_rect *bounds, struct zr_context *layout, bounds->x = layout->clip.x + layout->row.item.x; if (((bounds->x + bounds->w) > layout->max_x) && modify) layout->max_x = (bounds->x + bounds->w); - bounds->x -= layout->offset.x; + bounds->x -= layout->offset->x; bounds->y = layout->clip.y + layout->row.item.y; - bounds->y -= layout->offset.y; + bounds->y -= layout->offset->y; bounds->w = layout->row.item.w; bounds->h = layout->row.item.h; return; @@ -7414,43 +7874,59 @@ zr_layout_widget_space(struct zr_rect *bounds, struct zr_context *layout, /* set the bounds of the newly allocated widget */ bounds->w = item_width; bounds->h = layout->row.height - spacing.y; - bounds->y = layout->at_y - layout->offset.y; + bounds->y = layout->at_y - layout->offset->y; bounds->x = layout->at_x + item_offset + item_spacing + padding.x; if (((bounds->x + bounds->w) > layout->max_x) && modify) layout->max_x = bounds->x + bounds->w; - bounds->x -= layout->offset.x; + bounds->x -= layout->offset->x; } static void -zr_panel_alloc_space(struct zr_rect *bounds, struct zr_context *layout) +zr_panel_alloc_space(struct zr_rect *bounds, const struct zr_context *ctx) { + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + /* check if the end of the row has been hit and begin new row if so */ + win = ctx->current; + layout = win->layout; if (layout->row.index >= layout->row.columns) - zr_panel_alloc_row(layout); + zr_panel_alloc_row(ctx, win); /* calculate widget position and size */ - zr_layout_widget_space(bounds, layout, zr_true); + zr_layout_widget_space(bounds, ctx, win, zr_true); layout->row.index++; } void -zr_layout_peek(struct zr_rect *bounds, struct zr_context *layout) +zr_layout_peek(struct zr_rect *bounds, struct zr_context *ctx) { - float y = layout->at_y; - zr_size index = layout->row.index; + float y; + zr_size index; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; + y = layout->at_y; + index = layout->row.index; if (layout->row.index >= layout->row.columns) { layout->at_y += layout->row.height; layout->row.index = 0; } - zr_layout_widget_space(bounds, layout, zr_false); + zr_layout_widget_space(bounds, ctx, win, zr_false); layout->at_y = y; layout->row.index = index; } int -zr_layout_push(struct zr_context *layout, - enum zr_layout_node_type type, - const char *title, int *state) +zr_layout_push(struct zr_context *ctx, enum zr_layout_node_type type, const char *title) { const struct zr_style *config; struct zr_command_buffer *out; @@ -7459,32 +7935,42 @@ zr_layout_push(struct zr_context *layout, struct zr_vec2 panel_padding; struct zr_rect header = {0,0,0,0}; struct zr_rect sym = {0,0,0,0}; - enum zr_widget_states ws; + enum zr_widget_status ws; + zr_hash title_hash; + int title_len; + zr_uint *state = 0; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); - - if (!layout) return zr_false; - if (!layout->valid) return zr_false; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return zr_false; /* cache some data */ - out = layout->buffer; - config = layout->style; + win = ctx->current; + layout = win->layout; + out = &win->buffer; + config = &ctx->style; item_spacing = zr_style_property(config, ZR_PROPERTY_ITEM_SPACING); item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); panel_padding = zr_style_property(config, ZR_PROPERTY_PADDING); /* calculate header bounds and draw background */ - zr_layout_row_dynamic(layout, config->font.height + 2 * item_padding.y, 1); - zr_panel_alloc_space(&header, layout); + zr_layout_row_dynamic(ctx, config->font.height + 2 * item_padding.y, 1); + zr_panel_alloc_space(&header, ctx); if (type == ZR_LAYOUT_TAB) - zr_command_buffer_push_rect(out, header, 0, config->colors[ZR_COLOR_TAB_HEADER]); + zr_draw_rect(out, header, 0, config->colors[ZR_COLOR_TAB_HEADER]); + + /* find or create tab persistent state (open/closed) */ + title_len = (int)zr_strsiz(title); + title_hash = zr_murmur_hash(title, (int)title_len, ZR_WINDOW_HIDDEN); + state = zr_find_value(win, title_hash); + if (!state) state = zr_add_value(ctx, win, title_hash, 0); /* update node state */ if (zr_button_behavior(&ws, header, - (!(layout->flags & ZR_WINDOW_ROM)) ? layout->input : 0, ZR_BUTTON_DEFAULT)) + (!(layout->flags & ZR_WINDOW_ROM)) ? &ctx->input : 0, ZR_BUTTON_DEFAULT)) *state = (*state == ZR_MAXIMIZED) ? ZR_MINIMIZED : ZR_MAXIMIZED; { @@ -7500,7 +7986,7 @@ zr_layout_push(struct zr_context *layout, /* calculate the triangle points and draw triangle */ zr_triangle_from_direction(points, sym, 0, 0, heading); - zr_command_buffer_push_triangle(layout->buffer, points[0].x, points[0].y, + zr_draw_triangle(&win->buffer, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, config->colors[ZR_COLOR_TEXT]); /* calculate the space the icon occupied */ @@ -7520,24 +8006,24 @@ zr_layout_push(struct zr_context *layout, text_len = zr_strsiz(title); color = (type == ZR_LAYOUT_TAB) ? config->colors[ZR_COLOR_TAB_HEADER]: config->colors[ZR_COLOR_WINDOW]; - zr_command_buffer_push_text(out, label, (const char*)title, text_len, + zr_draw_text(out, label, (const char*)title, text_len, &config->font, color, config->colors[ZR_COLOR_TEXT]); } if (type == ZR_LAYOUT_TAB) { /* special node with border around the header */ - zr_command_buffer_push_line(out, header.x, header.y, + zr_draw_line(out, header.x, header.y, header.x + header.w-1, header.y, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_line(out, header.x, header.y, + zr_draw_line(out, header.x, header.y, header.x, header.y + header.h, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_line(out, header.x + header.w-1, header.y, + zr_draw_line(out, header.x + header.w-1, header.y, header.x + header.w-1, header.y + header.h, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_line(out, header.x, header.y + header.h, + zr_draw_line(out, header.x, header.y + header.h, header.x + header.w-1, header.y + header.h, config->colors[ZR_COLOR_BORDER]); } if (*state == ZR_MAXIMIZED) { - layout->at_x = header.x + layout->offset.x; + layout->at_x = header.x + layout->offset->x; layout->width = MAX(layout->width, 2 * panel_padding.x); layout->width -= 2 * panel_padding.x; return zr_true; @@ -7545,19 +8031,20 @@ zr_layout_push(struct zr_context *layout, } void -zr_layout_pop(struct zr_context *layout) +zr_layout_pop(struct zr_context *ctx) { const struct zr_style *config; struct zr_vec2 panel_padding; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; - if (!layout) return; - if (!layout->valid) return; - - config = layout->style; + win = ctx->current; + layout = win->layout; + config = &ctx->style; panel_padding = zr_style_property(config, ZR_PROPERTY_PADDING); layout->at_x -= panel_padding.x; layout->width += 2 * panel_padding.x; @@ -7568,73 +8055,84 @@ zr_layout_pop(struct zr_context *layout) * * --------------------------------------------------------------*/ void -zr_spacing(struct zr_context *l, zr_size cols) +zr_spacing(struct zr_context *ctx, zr_size cols) { zr_size i, index, rows; struct zr_rect nil; - ZR_ASSERT(l); - ZR_ASSERT(l->style); - ZR_ASSERT(l->buffer); - if (!l) return; - if (!l->valid) return; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; /* spacing over row boundries */ - index = (l->row.index + cols) % l->row.columns; - rows = (l->row.index + cols) / l->row.columns; + win = ctx->current; + layout = win->layout; + index = (layout->row.index + cols) % layout->row.columns; + rows = (layout->row.index + cols) / layout->row.columns; if (rows) { for (i = 0; i < rows; ++i) - zr_panel_alloc_row(l); + zr_panel_alloc_row(ctx, win); cols = index; } /* non table layout need to allocate space */ - if (l->row.type != ZR_LAYOUT_DYNAMIC_FIXED && - l->row.type != ZR_LAYOUT_STATIC_FIXED) { + if (layout->row.type != ZR_LAYOUT_DYNAMIC_FIXED && + layout->row.type != ZR_LAYOUT_STATIC_FIXED) { for (i = 0; i < cols; ++i) - zr_panel_alloc_space(&nil, l); + zr_panel_alloc_space(&nil, ctx); } - l->row.index = index; + layout->row.index = index; } void -zr_seperator(struct zr_context *layout) +zr_seperator(struct zr_context *ctx) { struct zr_command_buffer *out; const struct zr_style *config; struct zr_vec2 item_padding; struct zr_vec2 item_spacing; struct zr_rect bounds; - ZR_ASSERT(layout); - if (!layout) return; - out = layout->buffer; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current || !ctx->current->layout) + return; + + win = ctx->current; + layout = win->layout; + out = &win->buffer; + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); item_spacing = zr_style_property(config, ZR_PROPERTY_ITEM_SPACING); bounds.h = 1; bounds.w = MAX(layout->width, 2 * item_spacing.x + 2 * item_padding.x); - bounds.y = (layout->at_y + layout->row.height + item_padding.y) - layout->offset.y; - bounds.x = layout->at_x + item_spacing.x + item_padding.x - layout->offset.x; + bounds.y = (layout->at_y + layout->row.height + item_padding.y) - layout->offset->y; + bounds.x = layout->at_x + item_spacing.x + item_padding.x - layout->offset->x; bounds.w = bounds.w - (2 * item_spacing.x + 2 * item_padding.x); - zr_command_buffer_push_line(out, bounds.x, bounds.y, bounds.x + bounds.w, + zr_draw_line(out, bounds.x, bounds.y, bounds.x + bounds.w, bounds.y + bounds.h, config->colors[ZR_COLOR_BORDER]); } enum zr_widget_state -zr_widget(struct zr_rect *bounds, struct zr_context *layout) +zr_widget(struct zr_rect *bounds, const struct zr_context *ctx) { struct zr_rect *c = 0; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); - - if (!layout) return ZR_WIDGET_INVALID; - if (!layout->valid || !layout->style || !layout->buffer) return ZR_WIDGET_INVALID; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current || !ctx->current->layout) + return ZR_WIDGET_INVALID; /* allocated space for the panel and check if the widget needs to be updated */ - zr_panel_alloc_space(bounds, layout); + win = ctx->current; + layout = win->layout; + zr_panel_alloc_space(bounds, ctx); c = &layout->clip; if (!ZR_INTERSECT(c->x, c->y, c->w, c->h, bounds->x, bounds->y, bounds->w, bounds->h)) return ZR_WIDGET_INVALID; @@ -7644,30 +8142,32 @@ zr_widget(struct zr_rect *bounds, struct zr_context *layout) } enum zr_widget_state -zr_widget_fitting(struct zr_rect *bounds, struct zr_context *layout) +zr_widget_fitting(struct zr_rect *bounds, struct zr_context *ctx) { /* update the bounds to stand without padding */ enum zr_widget_state state; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); - if (!layout) return ZR_WIDGET_INVALID; - if (!layout->valid || !layout->style || !layout->buffer) + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current || !ctx->current->layout) return ZR_WIDGET_INVALID; - state = zr_widget(bounds, layout); + win = ctx->current; + layout = win->layout; + state = zr_widget(bounds, ctx); if (layout->row.index == 1) { - bounds->w += layout->style->properties[ZR_PROPERTY_PADDING].x; - bounds->x -= layout->style->properties[ZR_PROPERTY_PADDING].x; - } else bounds->x -= layout->style->properties[ZR_PROPERTY_ITEM_PADDING].x; + bounds->w += ctx->style.properties[ZR_PROPERTY_PADDING].x; + bounds->x -= ctx->style.properties[ZR_PROPERTY_PADDING].x; + } else bounds->x -= ctx->style.properties[ZR_PROPERTY_ITEM_PADDING].x; if (layout->row.index == layout->row.columns) - bounds->w += layout->style->properties[ZR_PROPERTY_PADDING].x; - else bounds->w += layout->style->properties[ZR_PROPERTY_ITEM_PADDING].x; + bounds->w += ctx->style.properties[ZR_PROPERTY_PADDING].x; + else bounds->w += ctx->style.properties[ZR_PROPERTY_ITEM_PADDING].x; return state; } void -zr_text_colored(struct zr_context *layout, const char *str, zr_size len, +zr_text_colored(struct zr_context *ctx, const char *str, zr_size len, enum zr_text_align alignment, struct zr_color color) { struct zr_rect bounds; @@ -7675,25 +8175,28 @@ zr_text_colored(struct zr_context *layout, const char *str, zr_size len, const struct zr_style *config; struct zr_vec2 item_padding; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return; - if (!layout) return; - if (!layout->valid || !layout->style || !layout->buffer) return; - zr_panel_alloc_space(&bounds, layout); - config = layout->style; + win = ctx->current; + layout = win->layout; + zr_panel_alloc_space(&bounds, ctx); + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); text.padding.x = item_padding.x; text.padding.y = item_padding.y; text.background = config->colors[ZR_COLOR_WINDOW]; text.text = color; - zr_widget_text(layout->buffer, bounds, str, len, &text, alignment, &config->font); + zr_widget_text(&win->buffer, bounds, str, len, &text, alignment, &config->font); } void -zr_text_wrap_colored(struct zr_context *layout, const char *str, +zr_text_wrap_colored(struct zr_context *ctx, const char *str, zr_size len, struct zr_color color) { struct zr_rect bounds; @@ -7701,67 +8204,76 @@ zr_text_wrap_colored(struct zr_context *layout, const char *str, const struct zr_style *config; struct zr_vec2 item_padding; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return; - if (!layout) return; - if (!layout->valid || !layout->style || !layout->buffer) return; - zr_panel_alloc_space(&bounds, layout); - config = layout->style; + win = ctx->current; + layout = win->layout; + zr_panel_alloc_space(&bounds, ctx); + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); text.padding.x = item_padding.x; text.padding.y = item_padding.y; text.background = config->colors[ZR_COLOR_WINDOW]; text.text = color; - zr_widget_text_wrap(layout->buffer, bounds, str, len, &text, &config->font); + zr_widget_text_wrap(&win->buffer, bounds, str, len, &text, &config->font); } void -zr_text_wrap(struct zr_context *l, const char *str, zr_size len) -{zr_text_wrap_colored(l, str, len, l->style->colors[ZR_COLOR_TEXT]);} +zr_text_wrap(struct zr_context *ctx, const char *str, zr_size len) +{zr_text_wrap_colored(ctx, str, len, ctx->style.colors[ZR_COLOR_TEXT]);} void -zr_text(struct zr_context *l, const char *str, zr_size len, +zr_text(struct zr_context *ctx, const char *str, zr_size len, enum zr_text_align alignment) -{zr_text_colored(l, str, len, alignment, l->style->colors[ZR_COLOR_TEXT]);} +{zr_text_colored(ctx, str, len, alignment, ctx->style.colors[ZR_COLOR_TEXT]);} void -zr_label_colored(struct zr_context *layout, const char *text, +zr_label_colored(struct zr_context *ctx, const char *text, enum zr_text_align align, struct zr_color color) -{zr_text_colored(layout, text, zr_strsiz(text), align, color);} +{zr_text_colored(ctx, text, zr_strsiz(text), align, color);} void -zr_label(struct zr_context *layout, const char *text, - enum zr_text_align align) -{zr_text(layout, text, zr_strsiz(text), align);} +zr_label(struct zr_context *ctx, const char *text, enum zr_text_align align) +{zr_text(ctx, text, zr_strsiz(text), align);} void -zr_label_wrap(struct zr_context *l, const char *str) -{zr_text_wrap(l, str, zr_strsiz(str));} +zr_label_wrap(struct zr_context *ctx, const char *str) +{zr_text_wrap(ctx, str, zr_strsiz(str));} void -zr_label_colored_wrap(struct zr_context *l, const char *str, struct zr_color color) -{zr_text_wrap_colored(l, str, zr_strsiz(str), color);} +zr_label_colored_wrap(struct zr_context *ctx, const char *str, struct zr_color color) +{zr_text_wrap_colored(ctx, str, zr_strsiz(str), color);} void -zr_image(struct zr_context *layout, struct zr_image img) +zr_image(struct zr_context *ctx, struct zr_image img) { const struct zr_style *config; struct zr_vec2 item_padding; struct zr_rect bounds; - ZR_ASSERT(layout); - if (!zr_widget(&bounds, layout)) + + struct zr_window *win; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; - config = layout->style; + win = ctx->current; + if (!zr_widget(&bounds, ctx)) + return; + + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); bounds.x += item_padding.x; bounds.y += item_padding.y; bounds.w -= 2 * item_padding.x; bounds.h -= 2 * item_padding.y; - zr_command_buffer_push_image(layout->buffer, bounds, &img); + zr_draw_image(&win->buffer, bounds, &img); } static void @@ -7783,154 +8295,214 @@ zr_fill_button(const struct zr_style *config, struct zr_button *button) enum zr_button_alloc {ZR_BUTTON_NORMAL, ZR_BUTTON_FITTING}; static enum zr_widget_state zr_button(struct zr_button *button, struct zr_rect *bounds, - struct zr_context *layout, enum zr_button_alloc type) + struct zr_context *ctx, enum zr_button_alloc type) { const struct zr_style *config; enum zr_widget_state state; + if (type == ZR_BUTTON_NORMAL) - state = zr_widget(bounds, layout); - else state = zr_widget_fitting(bounds, layout); + state = zr_widget(bounds, ctx); + else state = zr_widget_fitting(bounds, ctx); if (!state) return state; zr_zero(button, sizeof(*button)); - config = layout->style; + config = &ctx->style; zr_fill_button(config, button); return state; } int -zr_button_text(struct zr_context *layout, const char *str, +zr_button_text(struct zr_context *ctx, const char *str, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_text button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_NORMAL); - if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_NORMAL); + if (!state) return zr_false; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; button.alignment = ZR_TEXT_CENTERED; button.normal = config->colors[ZR_COLOR_TEXT]; button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; - return zr_do_button_text(&ws, layout->buffer, bounds, str, behavior, + return zr_do_button_text(&ws, &win->buffer, bounds, str, behavior, &button, i, &config->font); } int -zr_button_color(struct zr_context *layout, +zr_button_color(struct zr_context *ctx, struct zr_color color, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button button; const struct zr_input *i; - enum zr_widget_states ws; + enum zr_widget_status ws; enum zr_widget_state state; - state = zr_button(&button, &bounds, layout, ZR_BUTTON_NORMAL); + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + state = zr_button(&button, &bounds, ctx, ZR_BUTTON_NORMAL); if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; button.normal = color; button.hover = color; button.active = color; - return zr_do_button(&ws, layout->buffer, bounds, &button, i, behavior, &bounds); + return zr_do_button(&ws, &win->buffer, bounds, &button, i, behavior, &bounds); } int -zr_button_symbol(struct zr_context *layout, enum zr_symbol symbol, +zr_button_symbol(struct zr_context *ctx, enum zr_symbol symbol, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_symbol button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_NORMAL); - if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_NORMAL); + if (!state) return zr_false; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; button.normal = config->colors[ZR_COLOR_TEXT]; button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; - return zr_do_button_symbol(&ws, layout->buffer, bounds, symbol, + return zr_do_button_symbol(&ws, &win->buffer, bounds, symbol, behavior, &button, i, &config->font); } int -zr_button_image(struct zr_context *layout, struct zr_image image, +zr_button_image(struct zr_context *ctx, struct zr_image image, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_icon button; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_NORMAL); + + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_NORMAL); if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; button.padding = zr_vec2(0,0); - return zr_do_button_image(&ws, layout->buffer, bounds, image, behavior, &button, i); + return zr_do_button_image(&ws, &win->buffer, bounds, image, behavior, &button, i); } int -zr_button_text_symbol(struct zr_context *layout, enum zr_symbol symbol, +zr_button_text_symbol(struct zr_context *ctx, enum zr_symbol symbol, const char *text, enum zr_text_align align, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_text button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_NORMAL); - if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_NORMAL); + if (!state) return zr_false; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; button.alignment = ZR_TEXT_CENTERED; button.normal = config->colors[ZR_COLOR_TEXT]; button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; - return zr_do_button_text_symbol(&ws, layout->buffer, bounds, symbol, text, align, + return zr_do_button_text_symbol(&ws, &win->buffer, bounds, symbol, text, align, behavior, &button, &config->font, i); } int -zr_button_text_image(struct zr_context *layout, struct zr_image img, +zr_button_text_image(struct zr_context *ctx, struct zr_image img, const char *text, enum zr_text_align align, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_text button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_NORMAL); - if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_NORMAL); + if (!state) return zr_false; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; button.alignment = ZR_TEXT_CENTERED; button.normal = config->colors[ZR_COLOR_TEXT]; button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; - return zr_do_button_text_image(&ws, layout->buffer, bounds, img, text, align, + return zr_do_button_text_image(&ws, &win->buffer, bounds, img, text, align, behavior, &button, &config->font, i); } int -zr_select(struct zr_context *layout, const char *str, +zr_select(struct zr_context *ctx, const char *str, enum zr_text_align align, int value) { struct zr_rect bounds; @@ -7939,22 +8511,23 @@ zr_select(struct zr_context *layout, const char *str, struct zr_vec2 item_padding; struct zr_color background; - ZR_ASSERT(layout); - ZR_ASSERT(layout->style); - ZR_ASSERT(layout->buffer); + struct zr_window *win; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return value; - if (!layout) return value; - if (!layout->valid || !layout->style || !layout->buffer) return value; - zr_panel_alloc_space(&bounds, layout); - config = layout->style; + win = ctx->current; + zr_panel_alloc_space(&bounds, ctx); + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); background = (!value) ? config->colors[ZR_COLOR_WINDOW]: config->colors[ZR_COLOR_SELECTABLE]; - if (zr_input_is_mouse_click_in_rect(layout->input, ZR_BUTTON_LEFT, bounds)) { + if (zr_input_is_mouse_click_in_rect(&ctx->input, ZR_BUTTON_LEFT, bounds)) { background = config->colors[ZR_COLOR_SELECTABLE_HOVER]; - if (zr_input_has_mouse_click_in_rect(layout->input, ZR_BUTTON_LEFT, bounds)) { - if (zr_input_is_mouse_down(layout->input, ZR_BUTTON_LEFT)) + if (zr_input_has_mouse_click_in_rect(&ctx->input, ZR_BUTTON_LEFT, bounds)) { + if (zr_input_is_mouse_down(&ctx->input, ZR_BUTTON_LEFT)) value = !value; } } @@ -7965,33 +8538,33 @@ zr_select(struct zr_context *layout, const char *str, text.text = (!value) ? config->colors[ZR_COLOR_TEXT] : config->colors[ZR_COLOR_SELECTABLE_TEXT]; - zr_command_buffer_push_rect(layout->buffer, bounds, 0, background); - zr_widget_text(layout->buffer, bounds, str, zr_strsiz(str), + zr_draw_rect(&win->buffer, bounds, 0, background); + zr_widget_text(&win->buffer, bounds, str, zr_strsiz(str), &text, align, &config->font); return value; } int -zr_selectable(struct zr_context *layout, const char *str, +zr_selectable(struct zr_context *ctx, const char *str, enum zr_text_align align, int *value) { int old = *value; - int ret = zr_select(layout, str, align, old); + int ret = zr_select(ctx, str, align, old); *value = ret; return ret != old; } static enum zr_widget_state zr_toggle_base(struct zr_toggle *toggle, struct zr_rect *bounds, - struct zr_context *layout) + const struct zr_context *ctx) { const struct zr_style *config; struct zr_vec2 item_padding; enum zr_widget_state state; - state = zr_widget(bounds, layout); + state = zr_widget(bounds, ctx); if (!state) return state; - config = layout->style; + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); toggle->rounding = 0; toggle->padding.x = item_padding.x; @@ -8001,89 +8574,117 @@ zr_toggle_base(struct zr_toggle *toggle, struct zr_rect *bounds, } int -zr_check(struct zr_context *layout, const char *text, int active) +zr_check(struct zr_context *ctx, const char *text, int active) { - zr_checkbox(layout, text, &active); + zr_checkbox(ctx, text, &active); return active; } void -zr_checkbox(struct zr_context *layout, const char *text, int *is_active) +zr_checkbox(struct zr_context *ctx, const char *text, int *is_active) { struct zr_rect bounds; struct zr_toggle toggle; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_toggle_base(&toggle, &bounds, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return; + + win = ctx->current; + layout = win->layout; + state = zr_toggle_base(&toggle, &bounds, ctx); + if (!state) return; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; toggle.rounding = config->rounding[ZR_ROUNDING_CHECK]; toggle.cursor = config->colors[ZR_COLOR_TOGGLE_CURSOR]; toggle.normal = config->colors[ZR_COLOR_TOGGLE]; toggle.hover = config->colors[ZR_COLOR_TOGGLE_HOVER]; - zr_do_toggle(&ws, layout->buffer, bounds, is_active, text, ZR_TOGGLE_CHECK, + zr_do_toggle(&ws, &win->buffer, bounds, is_active, text, ZR_TOGGLE_CHECK, &toggle, i, &config->font); } void -zr_radio(struct zr_context *layout, const char *text, int *active) +zr_radio(struct zr_context *ctx, const char *text, int *active) { - *active = zr_option(layout, text, *active); + *active = zr_option(ctx, text, *active); } int -zr_option(struct zr_context *layout, const char *text, int is_active) +zr_option(struct zr_context *ctx, const char *text, int is_active) { struct zr_rect bounds; struct zr_toggle toggle; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_toggle_base(&toggle, &bounds, layout); - if (!state) return is_active; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return is_active; + + win = ctx->current; + layout = win->layout; + state = zr_toggle_base(&toggle, &bounds, ctx); + if (!state) return is_active; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; toggle.cursor = config->colors[ZR_COLOR_TOGGLE_CURSOR]; toggle.normal = config->colors[ZR_COLOR_TOGGLE]; toggle.hover = config->colors[ZR_COLOR_TOGGLE_HOVER]; - zr_do_toggle(&ws, layout->buffer, bounds, &is_active, text, ZR_TOGGLE_OPTION, - &toggle, i, &config->font); + zr_do_toggle(&ws, &win->buffer, bounds, &is_active, text, ZR_TOGGLE_OPTION, &toggle, i, &config->font); return is_active; } float -zr_slide_float(struct zr_context *layout, float min, float val, float max, float step) -{zr_slider_float(layout, min, &val, max, step); return val;} +zr_slide_float(struct zr_context *ctx, float min, float val, float max, float step) +{zr_slider_float(ctx, min, &val, max, step); return val;} int -zr_slide_int(struct zr_context *layout, int min, int val, int max, int step) -{zr_slider_int(layout, min, &val, max, step); return val;} +zr_slide_int(struct zr_context *ctx, int min, int val, int max, int step) +{zr_slider_int(ctx, min, &val, max, step); return val;} void -zr_slider_float(struct zr_context *layout, float min_value, float *value, +zr_slider_float(struct zr_context *ctx, float min_value, float *value, float max_value, float value_step) { struct zr_rect bounds; struct zr_slider slider; const struct zr_style *config; struct zr_vec2 item_padding; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_widget(&bounds, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; + state = zr_widget(&bounds, ctx); + if (!state) return; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); slider.padding.x = item_padding.x; slider.padding.y = item_padding.y; @@ -8093,37 +8694,45 @@ zr_slider_float(struct zr_context *layout, float min_value, float *value, slider.active = config->colors[ZR_COLOR_SLIDER_CURSOR_ACTIVE]; slider.border = config->colors[ZR_COLOR_BORDER]; slider.rounding = config->rounding[ZR_ROUNDING_SLIDER]; - *value = zr_do_slider(&ws, layout->buffer, bounds, min_value, *value, max_value, + *value = zr_do_slider(&ws, &win->buffer, bounds, min_value, *value, max_value, value_step, &slider, i); } void -zr_slider_int(struct zr_context *layout, int min_value, int *value, +zr_slider_int(struct zr_context *ctx, int min_value, int *value, int max_value, int value_step) { float val = (float)*value; - zr_slider_float(layout, (float)min_value, &val, - (float)max_value, (float)value_step); + zr_slider_float(ctx, (float)min_value, &val, (float)max_value, (float)value_step); *value = (int)val; } void -zr_progress(struct zr_context *layout, zr_size *cur_value, zr_size max_value, +zr_progress(struct zr_context *ctx, zr_size *cur_value, zr_size max_value, int is_modifiable) { struct zr_rect bounds; struct zr_progress prog; const struct zr_style *config; struct zr_vec2 item_padding; - enum zr_widget_states ws; + enum zr_widget_status ws; const struct zr_input *i; enum zr_widget_state state; - state = zr_widget(&bounds, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - config = layout->style; + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; + state = zr_widget(&bounds, ctx); + if (!state) return; + i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); prog.rounding = config->rounding[ZR_ROUNDING_PROGRESS]; prog.padding.x = item_padding.x; @@ -8134,20 +8743,20 @@ zr_progress(struct zr_context *layout, zr_size *cur_value, zr_size max_value, prog.hover = config->colors[ZR_COLOR_PROGRESS_CURSOR_HOVER]; prog.active = config->colors[ZR_COLOR_PROGRESS_CURSOR_ACTIVE]; prog.rounding = config->rounding[ZR_ROUNDING_PROGRESS]; - *cur_value = zr_do_progress(&ws, layout->buffer, bounds, *cur_value, max_value, + *cur_value = zr_do_progress(&ws, &win->buffer, bounds, *cur_value, max_value, is_modifiable, &prog, i); } static enum zr_widget_state zr_edit_base(struct zr_rect *bounds, struct zr_edit *field, - struct zr_context *layout) + struct zr_context *ctx) { const struct zr_style *config; struct zr_vec2 item_padding; - enum zr_widget_state state = zr_widget(bounds, layout); + enum zr_widget_state state = zr_widget(bounds, ctx); if (!state) return state; - config = layout->style; + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); field->border_size = 1; field->scrollbar_width = config->properties[ZR_PROPERTY_SCROLLBAR_SIZE].x; @@ -8168,117 +8777,190 @@ zr_edit_base(struct zr_rect *bounds, struct zr_edit *field, return state; } -void -zr_edit_field(struct zr_context *layout, struct zr_edit_box *box) +int +zr_edit_string(struct zr_context *ctx, zr_flags flags, + char *memory, zr_size *len, zr_size max, zr_filter filter) { - struct zr_rect bounds; - struct zr_edit field; - const struct zr_style *config = layout->style; - const struct zr_input *i; - enum zr_widget_state state; - - state = zr_edit_base(&bounds, &field, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - field.modifiable = 1; - zr_widget_edit_field(layout->buffer, bounds, box, &field, i, &config->font); + int active; + struct zr_buffer buffer; + zr_buffer_init_fixed(&buffer, memory, max); + buffer.allocated = *len; + active = zr_edit_buffer(ctx, flags, &buffer, filter); + *len = buffer.allocated; + return active; } -void -zr_edit_box(struct zr_context *layout, struct zr_edit_box *box, int modifiable) +int +zr_edit_buffer(struct zr_context *ctx, zr_flags flags, + struct zr_buffer *buffer, zr_filter filter) { + struct zr_window *win; struct zr_rect bounds; struct zr_edit field; - const struct zr_style *config = layout->style; struct zr_input *i; enum zr_widget_state state; + zr_hash hash; - state = zr_edit_base(&bounds, &field, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - field.modifiable = modifiable; - zr_widget_edit_box(layout->buffer, bounds, box, &field, i, &config->font); + /* dummy state for non active edit */ + int dummy_active = 0; + zr_size dummy_cursor = 0; + float dummy_scroll = 0; + struct zr_text_selection dummy_sel = {0,0,0}; + + int *active = 0; + zr_size *cursor = 0; + float *scroll = 0; + struct zr_text_selection *sel = 0; + + ZR_ASSERT(ctx); + ZR_ASSERT(buffer); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + if (!ctx || !buffer) return 0; + + win = ctx->current; + state = zr_edit_base(&bounds, &field, ctx); + if (!state) return 0; + i = (state == ZR_WIDGET_ROM || win->layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; + + if (flags & ZR_EDIT_READ_ONLY) + field.modifiable = 1; + + /* calculate hash from name */ + hash = win->edit.seq++; + + /* check if edit is currently hot item */ + if (win->edit.active && hash == win->edit.name) { + active = &win->edit.active; + cursor = &win->edit.cursor; + scroll = &win->edit.scrollbar; + sel = &win->edit.sel; + } else { + active = &dummy_active; + cursor = &dummy_cursor; + scroll = &dummy_scroll; + sel = &dummy_sel; + } + + if (!flags || flags == ZR_EDIT_CURSOR) { + int old = *active; + if (!flags) { + /* simple edit field with only appending and removing at the end of the buffer */ + buffer->allocated = zr_widget_edit(&win->buffer, bounds, buffer->memory.ptr, + buffer->allocated, buffer->memory.size, active, 0, &field, + filter, i, &ctx->style.font); + } else { + /* simple edit field cursor based movement, inserting and removing */ + buffer->allocated = zr_widget_edit(&win->buffer, bounds, buffer->memory.ptr, + buffer->allocated, buffer->memory.size, active, cursor, &field, + filter, i, &ctx->style.font); + } + + if (dummy_active) { + /* set hot edit widget state */ + win->edit.active = 1; + win->edit.name = hash; + win->edit.scrollbar = 0; + win->edit.sel.begin = 0; + win->edit.sel.end = 0; + win->edit.cursor = 0; + } else if (old && !*active) { + win->edit.active = 0; + } + } else { + /* editbox based editing either in single line (edit field) or multiline (edit box) */ + struct zr_edit_box box; + if (flags & ZR_EDIT_CLIPBOARD) + zr_edit_box_init_buffer(&box, buffer, &ctx->clip, filter); + else zr_edit_box_init_buffer(&box, buffer, 0, filter); + + box.active = *active; + box.filter = filter; + box.scrollbar = *scroll; + box.glyphs = zr_utf_len(buffer->memory.ptr, buffer->allocated); + + if (!(flags & ZR_EDIT_CURSOR)) { + box.cursor = MIN(*cursor, box.glyphs); + box.sel.begin = box.cursor; + box.sel.end = box.cursor; + } else { + box.cursor = *cursor; + if (!(flags & ZR_EDIT_SELECTABLE)) { + box.sel.active = 0; + box.sel.begin = box.cursor; + box.sel.end = box.cursor; + } else box.sel = *sel; + } + + if (flags & ZR_EDIT_MULTILINE) + zr_widget_edit_box(&win->buffer, bounds, &box, &field, i, &ctx->style.font); + else zr_widget_edit_field(&win->buffer, bounds, &box, &field, i, &ctx->style.font); + + if (box.active) { + /* update hot edit widget state */ + win->edit.active = 1; + win->edit.name = hash; + win->edit.scrollbar = box.scrollbar; + win->edit.sel = box.sel; + win->edit.cursor = box.cursor; + buffer->allocated = box.buffer.allocated; + } else if (!box.active && *active) { + win->edit.active = 0; + } + } + return *active; } -void -zr_edit(struct zr_context *layout, char *buffer, zr_size *len, - zr_size max, int *active, zr_size *cursor, enum zr_input_filter filter) -{ - struct zr_rect bounds; - struct zr_edit field; - const struct zr_style *config = layout->style; - const struct zr_input *i; - enum zr_widget_state state; - - state = zr_edit_base(&bounds, &field, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - *len = zr_widget_edit(layout->buffer, bounds, buffer, *len, max, active, cursor, - &field, filter, i, &config->font); -} - -void -zr_edit_filtered(struct zr_context *layout, char *buffer, zr_size *len, - zr_size max, int *active, zr_size *cursor, zr_filter filter) -{ - struct zr_rect bounds; - struct zr_edit field; - const struct zr_style *config = layout->style; - const struct zr_input *i; - enum zr_widget_state state; - - state = zr_edit_base(&bounds, &field, layout); - if (!state) return; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; - *len = zr_widget_edit_filtered(layout->buffer, bounds, buffer, *len, max, active, - cursor, &field, filter, i, &config->font); -} - - static void -zr_property(struct zr_context *layout, const char *name, - float min, float *val, float max, float step, float inc_per_pixel, - enum zr_input_filter filter) +zr_property(struct zr_context *ctx, const char *name, + float min, float *val, float max, float step, + float inc_per_pixel, zr_filter filter) { struct zr_rect bounds; struct zr_property prop; const struct zr_style *config; struct zr_vec2 item_padding; - enum zr_widget_states ws; + enum zr_widget_status ws; - char *buffer; - zr_size *len, *cursor; - int *state; - int old_state; + zr_hash hash = 0; + char *buffer = 0; + zr_size *len = 0; + zr_size *cursor = 0; + int *state = 0; + int old_state = 0; - /* dummy state for non active properties */ - int active; - char dummy_buffer[64]; + char dummy_buffer[ZR_MAX_NUMBER_BUFFER]; zr_size dummy_length = 0; zr_size dummy_cursor = 0; int dummy_state = ZR_PROPERTY_DEFAULT; - zr_ulong hash; - /* allocate layout space */ const struct zr_input *i; enum zr_widget_state s; - s = zr_widget(&bounds, layout); + struct zr_window *win; + struct zr_layout *layout; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + win = ctx->current; + layout = win->layout; + s = zr_widget(&bounds, ctx); if (!s) return; - i = (s == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; + i = (s == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; /* calculate hash from name */ if (name[0] == '#') { - hash = zr_hash(name, (zr_uint)zr_strsiz(name), layout->property->seq++); + hash = zr_murmur_hash(name, (int)zr_strsiz(name), win->property.seq++); name++; /* special number hash */ - } else hash = zr_hash(name, (zr_uint)zr_strsiz(name), 42); + } else hash = zr_murmur_hash(name, (int)zr_strsiz(name), 42); - /* check if property is currently hot */ - if (layout->property->active && hash == layout->property->name) { - struct zr_value *p = layout->property; - buffer = p->buffer; - len = &p->length; - cursor = &p->cursor; - state = &p->state; + /* check if property is currently hot item */ + if (win->property.active && hash == win->property.name) { + buffer = win->property.buffer; + len = &win->property.length; + cursor = &win->property.cursor; + state = &win->property.state; } else { buffer = dummy_buffer; len = &dummy_length; @@ -8286,7 +8968,8 @@ zr_property(struct zr_context *layout, const char *name, state = &dummy_state; } - config = layout->style; + /* execute property widget */ + config = &ctx->style; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); prop.border_size = 1; prop.rounding = config->rounding[ZR_ROUNDING_PROPERTY]; @@ -8297,54 +8980,53 @@ zr_property(struct zr_context *layout, const char *name, prop.active = config->colors[ZR_COLOR_PROPERTY_ACTIVE]; prop.text = config->colors[ZR_COLOR_TEXT]; old_state = *state; - *val = zr_do_property(&ws, layout->buffer, bounds, name, min, *val, max, step, + *val = zr_do_property(&ws, &win->buffer, bounds, name, min, *val, max, step, inc_per_pixel, buffer, len, state, cursor, &prop, filter, i, &config->font); - if (*state != ZR_PROPERTY_DEFAULT && !layout->property->active) { + if (*state != ZR_PROPERTY_DEFAULT && !win->property.active) { /* current property is now hot */ - struct zr_value *p = layout->property; - p->active = 1; - zr_memcopy(p->buffer, buffer, *len); - p->length = *len; - p->cursor = *cursor; - p->state = *state; - p->name = hash; + win->property.active = 1; + zr_memcopy(win->property.buffer, buffer, *len); + win->property.length = *len; + win->property.cursor = *cursor; + win->property.state = *state; + win->property.name = hash; } /* check if previously active property is now unactive */ if (*state == ZR_PROPERTY_DEFAULT && old_state != ZR_PROPERTY_DEFAULT) - layout->property->active = 0; + win->property.active = 0; } void -zr_property_float(struct zr_context *layout, const char *name, +zr_property_float(struct zr_context *ctx, const char *name, float min, float *val, float max, float step, float inc_per_pixel) { - zr_property(layout, name, min, val, max, step, inc_per_pixel, ZR_INPUT_FLOAT); + zr_property(ctx, name, min, val, max, step, inc_per_pixel, zr_filter_float); } void -zr_property_int(struct zr_context *layout, const char *name, +zr_property_int(struct zr_context *ctx, const char *name, int min, int *val, int max, int step, int inc_per_pixel) { float value = (float)*val; - zr_property(layout, name, (float)min, &value, (float)max, (float)step, - (float)inc_per_pixel, ZR_INPUT_DEC); + zr_property(ctx, name, (float)min, &value, (float)max, (float)step, + (float)inc_per_pixel, zr_filter_decimal); *val = (int)value; } float -zr_propertyf(struct zr_context *layout, const char *name, float min, float val, float max, +zr_propertyf(struct zr_context *ctx, const char *name, float min, float val, float max, float step, float inc_per_pixel) { - zr_property_float(layout, name, (float)min, &val, (float)max, (float)step, (float)inc_per_pixel); + zr_property_float(ctx, name, (float)min, &val, (float)max, (float)step, (float)inc_per_pixel); return val; } int -zr_propertyi(struct zr_context *layout, const char *name, int min, int val, int max, +zr_propertyi(struct zr_context *ctx, const char *name, int min, int val, int max, int step, int inc_per_pixel) { - zr_property_int(layout, name, min, &val, max, step, inc_per_pixel); + zr_property_int(ctx, name, min, &val, max, step, inc_per_pixel); return val; } @@ -8354,34 +9036,39 @@ zr_propertyi(struct zr_context *layout, const char *name, int min, int val, int * * --------------------------------------------------------------*/ void -zr_graph_begin(struct zr_context *layout, struct zr_graph *graph, - enum zr_graph_type type, zr_size count, float min_value, float max_value) +zr_graph_begin(struct zr_context *ctx, enum zr_graph_type type, + zr_size count, float min_value, float max_value) { struct zr_rect bounds = {0, 0, 0, 0}; const struct zr_style *config; struct zr_command_buffer *out; struct zr_color color; struct zr_vec2 item_padding; - if (!zr_widget(&bounds, layout)) { - zr_zero(graph, sizeof(*graph)); + struct zr_window *win = ctx->current; + struct zr_graph *graph = &win->layout->graph; + + if (!ctx || !ctx->current) return; + if (!zr_widget(&bounds, ctx)) { + zr_zero(graph, sizeof(graph)); return; } /* draw graph background */ - config = layout->style; - out = layout->buffer; + config = &ctx->style; + out = &win->buffer; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); color = (type == ZR_GRAPH_LINES) ? config->colors[ZR_COLOR_PLOT]: config->colors[ZR_COLOR_HISTO]; - zr_command_buffer_push_rect(out, bounds, config->rounding[ZR_ROUNDING_GRAPH], color); + zr_draw_rect(out, bounds, config->rounding[ZR_ROUNDING_GRAPH], color); /* setup basic generic graph */ - graph->valid = zr_true; + zr_zero(graph, sizeof(graph)); graph->type = type; graph->index = 0; graph->count = count; - graph->min = min_value; - graph->max = max_value; + graph->min = MIN(min_value, max_value); + graph->max = MAX(min_value, max_value); + graph->range = graph->max - graph->min; graph->x = bounds.x + item_padding.x; graph->y = bounds.y + item_padding.y; graph->w = bounds.w - 2 * item_padding.x; @@ -8392,24 +9079,19 @@ zr_graph_begin(struct zr_context *layout, struct zr_graph *graph, } static zr_flags -zr_graph_push_line(struct zr_context *layout, +zr_graph_push_line(struct zr_context *ctx, struct zr_window *win, struct zr_graph *g, float value) { - struct zr_command_buffer *out = layout->buffer; - const struct zr_style *config = layout->style; - const struct zr_input *i = layout->input; + struct zr_command_buffer *out = &win->buffer; + const struct zr_style *config = &ctx->style; + const struct zr_input *i = &ctx->input; + struct zr_layout *layout = win->layout; struct zr_color color; zr_flags ret = 0; float step, range, ratio; struct zr_vec2 cur; struct zr_rect bounds; - ZR_ASSERT(g); - ZR_ASSERT(layout); - ZR_ASSERT(out); - if (!g || !layout || !g->valid || g->index >= g->count) - return zr_false; - step = g->w / (float)g->count; range = g->max - g->min; ratio = (value - g->min) / range; @@ -8418,10 +9100,10 @@ zr_graph_push_line(struct zr_context *layout, /* special case for the first data point since it does not have a connection */ g->last.x = g->x; g->last.y = (g->y + g->h) - ratio * (float)g->h; - bounds.x = g->last.x - 3; - bounds.y = g->last.y - 3; - bounds.w = 6; - bounds.h = 6; + bounds.x = g->last.x - 2; + bounds.y = g->last.y - 2; + bounds.w = 4; + bounds.h = 4; color = config->colors[ZR_COLOR_PLOT_LINES]; if (!(layout->flags & ZR_WINDOW_ROM) && @@ -8431,7 +9113,7 @@ zr_graph_push_line(struct zr_context *layout, i->mouse.buttons[ZR_BUTTON_LEFT].clicked) ? ZR_GRAPH_CLICKED: 0; color = config->colors[ZR_COLOR_PLOT_HIGHLIGHT]; } - zr_command_buffer_push_rect(out, bounds, 0, color); + zr_draw_rect(out, bounds, 0, color); g->index++; return ret; } @@ -8439,7 +9121,7 @@ zr_graph_push_line(struct zr_context *layout, /* draw a line between the last data point and the new one */ cur.x = g->x + (float)(step * (float)g->index); cur.y = (g->y + g->h) - (ratio * (float)g->h); - zr_command_buffer_push_line(out, g->last.x, g->last.y, cur.x, cur.y, + zr_draw_line(out, g->last.x, g->last.y, cur.x, cur.y, config->colors[ZR_COLOR_PLOT_LINES]); bounds.x = cur.x - 3; @@ -8447,7 +9129,7 @@ zr_graph_push_line(struct zr_context *layout, bounds.w = 6; bounds.h = 6; - /* user selection of the current data point */ + /* user selection of current data point */ color = config->colors[ZR_COLOR_PLOT_LINES]; if (!(layout->flags & ZR_WINDOW_ROM)) { if (zr_input_is_mouse_hovering_rect(i, bounds)) { @@ -8457,7 +9139,7 @@ zr_graph_push_line(struct zr_context *layout, color = config->colors[ZR_COLOR_PLOT_HIGHLIGHT]; } } - zr_command_buffer_push_rect(out, zr_rect(cur.x - 3, cur.y - 3, 6, 6), 0, color); + zr_draw_rect(out, zr_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); /* save current data point position */ g->last.x = cur.x; @@ -8467,12 +9149,13 @@ zr_graph_push_line(struct zr_context *layout, } static zr_flags -zr_graph_push_column(struct zr_context *layout, +zr_graph_push_column(const struct zr_context *ctx, struct zr_window *win, struct zr_graph *graph, float value) { - struct zr_command_buffer *out = layout->buffer; - const struct zr_style *config = layout->style; - const struct zr_input *in = layout->input; + struct zr_command_buffer *out = &win->buffer; + const struct zr_style *config = &ctx->style; + const struct zr_input *in = &ctx->input; + struct zr_layout *layout = win->layout; struct zr_vec2 item_padding; struct zr_color color; @@ -8481,22 +9164,25 @@ zr_graph_push_column(struct zr_context *layout, struct zr_rect item = {0,0,0,0}; item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); - if (!graph->valid || graph->index >= graph->count) + if (graph->index >= graph->count) return zr_false; if (graph->count) { - float padding = (float)(graph->count-1) * item_padding.x; + float padding = (float)(graph->count-1); item.w = (graph->w - padding) / (float)(graph->count); } - ratio = ZR_ABS(value) / graph->max; - color = (value < 0) ? config->colors[ZR_COLOR_HISTO_NEGATIVE]: - config->colors[ZR_COLOR_HISTO_BARS]; - /* calculate bounds of the current bar graph entry */ - item.h = graph->h * ratio; - item.y = (graph->y + graph->h) - item.h; + color = config->colors[ZR_COLOR_HISTO_BARS]; + item.h = graph->h * ZR_ABS((value/graph->range)); + if (value >= 0) { + ratio = (value + ZR_ABS(graph->min)) / ZR_ABS(graph->range); + item.y = (graph->y + graph->h) - graph->h * ratio; + } else { + ratio = (value - graph->max) / graph->range; + item.y = graph->y + (graph->h * ZR_ABS(ratio)) - item.h; + } item.x = graph->x + ((float)graph->index * item.w); - item.x = item.x + ((float)graph->index * item_padding.x); + item.x = item.x + ((float)graph->index); /* user graph bar selection */ if (!(layout->flags & ZR_WINDOW_ROM) && @@ -8506,34 +9192,45 @@ zr_graph_push_column(struct zr_context *layout, in->mouse.buttons[ZR_BUTTON_LEFT].clicked) ? ZR_GRAPH_CLICKED: 0; color = config->colors[ZR_COLOR_HISTO_HIGHLIGHT]; } - zr_command_buffer_push_rect(out, item, 0, color); + zr_draw_rect(out, item, 0, color); graph->index++; return ret; } zr_flags -zr_graph_push(struct zr_context *layout, struct zr_graph *graph, - float value) +zr_graph_push(struct zr_context *ctx, float value) { - ZR_ASSERT(layout); - ZR_ASSERT(graph); - if (!layout || !graph || !layout->valid) return zr_false; - switch (graph->type) { + struct zr_window *win; + struct zr_layout *layout; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return zr_false; + + win = ctx->current; + layout = win->layout; + switch (win->layout->graph.type) { case ZR_GRAPH_LINES: - return zr_graph_push_line(layout, graph, value); + return zr_graph_push_line(ctx, win, &win->layout->graph, value); case ZR_GRAPH_COLUMN: - return zr_graph_push_column(layout, graph, value); + return zr_graph_push_column(ctx, win, &win->layout->graph, value); case ZR_GRAPH_MAX: default: return zr_false; } } void -zr_graph_end(struct zr_context *layout, struct zr_graph *graph) +zr_graph_end(struct zr_context *ctx) { - ZR_ASSERT(layout); - ZR_ASSERT(graph); - if (!layout || !graph) return; + struct zr_window *win; + struct zr_graph *graph; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) + return; + + win = ctx->current; + graph = &win->layout->graph; graph->type = ZR_GRAPH_MAX; graph->index = 0; graph->count = 0; @@ -8547,177 +9244,337 @@ zr_graph_end(struct zr_context *layout, struct zr_graph *graph) /* ------------------------------------------------------------- * - * GROUPS + * GROUP * * --------------------------------------------------------------*/ -void -zr_group_begin(struct zr_context *p, struct zr_context *g, - const char *title, zr_flags flags, struct zr_vec2 offset) +int +zr_group_begin(struct zr_context *ctx, struct zr_layout *layout, + const char *title, zr_flags flags) { + union {struct zr_scroll *s; zr_uint *i;} value; struct zr_rect bounds; - struct zr_window panel; const struct zr_rect *c; + int title_len; + zr_hash title_hash; - ZR_ASSERT(p); - ZR_ASSERT(g); - if (!p || !g) return; - if (!p->valid) - goto failed; + struct zr_window *win; + struct zr_window panel; + + ZR_ASSERT(ctx); + ZR_ASSERT(title); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current || !title) + return 0; /* allocate space for the group panel inside the panel */ - c = &p->clip; - zr_panel_alloc_space(&bounds, p); - zr_zero(g, sizeof(*g)); + win = ctx->current; + c = &win->layout->clip; + zr_panel_alloc_space(&bounds, ctx); + zr_zero(layout, sizeof(*layout)); + + /* find group persistent scrollbar value */ + title_len = (int)zr_strsiz(title); + title_hash = zr_murmur_hash(title, (int)title_len, ZR_WINDOW_SUB); + value.i = zr_find_value(win, title_hash); + if (!value.i) { + value.i = zr_add_value(ctx, win, title_hash, 0); + *value.i = 0; + } + if (!ZR_INTERSECT(c->x, c->y, c->w, c->h, bounds.x, bounds.y, bounds.w, bounds.h) && - !(flags & ZR_WINDOW_MOVEABLE)) - goto failed; - - /* initialize a fake window to create the layout from */ - flags |= ZR_WINDOW_TAB; - if (p->flags & ZR_WINDOW_ROM) - flags |= ZR_WINDOW_ROM; - zr_window_init(&panel, bounds, flags, 0, p->style, p->input); - - panel.buffer = *p->buffer; - zr_begin(g, &panel, title); - *p->buffer = panel.buffer; - g->buffer = p->buffer; - g->offset = offset; - g->queue = p->queue; - return; - -failed: - /* invalid panels still need correct data */ - g->valid = zr_false; - g->style = p->style; - g->buffer = p->buffer; - g->input = p->input; - g->queue = p->queue; -} - -void -zr_group_end(struct zr_context *p, struct zr_context *g, struct zr_vec2 *scrollbar) -{ - struct zr_window pan; - struct zr_command_buffer *out; - struct zr_rect clip; - - ZR_ASSERT(p); - ZR_ASSERT(g); - if (!p || !g) return; - if (!p->valid) return; - zr_zero(&pan, sizeof(pan)); - - out = p->buffer; - pan.bounds.x = g->bounds.x; - pan.bounds.y = g->bounds.y; - pan.bounds.w = g->width; - pan.bounds.h = g->height; - pan.flags = g->flags|ZR_WINDOW_TAB; - - /* setup clipping rect to finalize group panel drawing back to parent */ - zr_unify(&clip, &p->clip, g->bounds.x, g->clip.y - g->header_h, g->bounds.x + g->bounds.w+1, - g->bounds.y + g->bounds.h + 1); - - zr_command_buffer_push_scissor(out, clip); - zr_end(g, &pan); - zr_command_buffer_push_scissor(out, p->clip); - if (scrollbar) - *scrollbar = pan.offset; -} -/* - * ------------------------------------------------------------- - * - * POPUP - * - * -------------------------------------------------------------- - */ -zr_flags -zr_popup_begin(struct zr_context *parent, struct zr_context *popup, - enum zr_popup_type type, const char *title, zr_flags flags, - struct zr_rect rect, struct zr_vec2 scrollbar) -{ - zr_flags ret; - struct zr_window panel; - ZR_ASSERT(parent); - ZR_ASSERT(popup); - if (!parent || !popup || !parent->valid) { - popup->valid = zr_false; - popup->style = parent->style; - popup->buffer = parent->buffer; - popup->input = parent->input; + !(flags & ZR_WINDOW_MOVEABLE)) { return 0; } - /* calculate bounds of the panel */ - zr_zero(popup, sizeof(*popup)); - rect.x += parent->clip.x; - rect.y += parent->clip.y; - parent->flags |= ZR_WINDOW_ROM; + flags |= ZR_WINDOW_SUB; + if (win->flags & ZR_WINDOW_ROM) + flags |= ZR_WINDOW_ROM; - /* initialize a fake window */ - flags |= ZR_WINDOW_BORDER|ZR_WINDOW_TAB; + /* initialize a fake window to create the layout from */ + zr_zero(&panel, sizeof(panel)); + panel.bounds = bounds; + panel.flags = flags; + panel.scrollbar.x = (unsigned short)value.s->x; + panel.scrollbar.y = (unsigned short)value.s->y; + panel.buffer = win->buffer; + panel.layout = layout; + ctx->current = &panel; + zr_layout_begin(ctx, (flags & ZR_WINDOW_TITLE) ? title: 0); + + win->buffer = panel.buffer; + layout->offset = value.s; + layout->parent = win->layout; + win->layout = layout; + ctx->current = win; + return 1; +} + +void +zr_group_end(struct zr_context *ctx) +{ + struct zr_rect clip; + struct zr_window *win; + struct zr_window pan; + + struct zr_layout *parent; + struct zr_layout *g; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + + /* make sure zr_group_begin was called correctly */ + ZR_ASSERT(ctx->current); + win = ctx->current; + ZR_ASSERT(win->layout); + g = win->layout; + ZR_ASSERT(g->parent); + parent = g->parent; + + /* dummy window */ + zr_zero(&pan, sizeof(pan)); + pan.bounds = g->bounds; + pan.scrollbar.x = (unsigned short)g->offset->x; + pan.scrollbar.y = (unsigned short)g->offset->y; + pan.flags = g->flags|ZR_WINDOW_SUB; + pan.buffer = win->buffer; + pan.layout = g; + + ctx->current = &pan; + zr_unify(&clip, &parent->clip, + g->bounds.x, g->clip.y - g->header_h, + g->bounds.x + g->bounds.w+1, + g->bounds.y + g->bounds.h + 1); + + zr_draw_scissor(&pan.buffer, clip); + zr_end(ctx); + + win->buffer = pan.buffer; + zr_draw_scissor(&win->buffer, parent->clip); + ctx->current = win; + win->layout = parent; + win->bounds = parent->bounds; +} + +/* -------------------------------------------------------------- + * + * POPUP + * + * --------------------------------------------------------------*/ +int +zr_popup_begin(struct zr_context *ctx, struct zr_layout *layout, + enum zr_popup_type type, const char *title, zr_flags flags, struct zr_rect rect) +{ + int ret; + struct zr_window *popup; + struct zr_window *win; + zr_hash title_hash; + int title_len; + + ZR_ASSERT(ctx); + ZR_ASSERT(title); + ZR_ASSERT(ctx->current); + + win = ctx->current; + ZR_ASSERT(!(win->flags & ZR_WINDOW_POPUP)); + title_len = (int)zr_strsiz(title); + title_hash = zr_murmur_hash(title, (int)title_len, ZR_WINDOW_POPUP); + + popup = win->popup.win; + if (!popup) { + popup = zr_create_window(ctx); + win->popup.win = popup; + } + + if (win->popup.name != title_hash) { + zr_zero(popup, sizeof(*popup)); + win->popup.name = title_hash; + } + ctx->current = popup; + rect.x += win->layout->clip.x; + rect.y += win->layout->clip.y; + + popup->parent = win; + popup->bounds = rect; + popup->seq = ctx->seq; + popup->layout = layout; + popup->flags = flags; + popup->flags |= ZR_WINDOW_BORDER|ZR_WINDOW_SUB|ZR_WINDOW_POPUP; if (type == ZR_POPUP_DYNAMIC) - flags |= ZR_WINDOW_DYNAMIC; - zr_window_init(&panel, zr_rect(rect.x, rect.y, rect.w, rect.h),flags, 0, - parent->style, parent->input); + popup->flags |= ZR_WINDOW_DYNAMIC; - /* begin sub-buffer and create panel layout */ - zr_command_buffer_push_scissor(parent->buffer, zr_null_rect); - zr_command_queue_start_child(parent->queue, parent->buffer); - panel.buffer = *parent->buffer; - ret = zr_begin(popup, &panel, title); - *parent->buffer = panel.buffer; - parent->flags |= ZR_WINDOW_ROM; + zr_start_child(ctx, win); + popup->buffer = win->buffer; + zr_draw_scissor(&popup->buffer, zr_null_rect); + ret = zr_layout_begin(ctx, title); + win->buffer = popup->buffer; + layout->offset = &popup->scrollbar; + if (ret) win->layout->flags |= ZR_WINDOW_ROM; + else zr_popup_close(ctx); + return ret; +} - popup->buffer = parent->buffer; - popup->offset = scrollbar; - popup->queue = parent->queue; +static int +zr_nonblock_begin(struct zr_layout *layout, struct zr_context *ctx, + zr_flags flags, struct zr_rect body, struct zr_rect header) +{ + struct zr_window *popup; + struct zr_window *win; + int is_active = zr_true; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + ZR_ASSERT(ctx->current->layout); + + /* try to find group window */ + win = ctx->current; + ZR_ASSERT(!(win->flags & ZR_WINDOW_POPUP)); + popup = win->popup.win; + if (!popup) { + /* create window for nonblocking popup */ + popup = zr_create_window(ctx); + win->popup.win = popup; + zr_command_buffer_init(&popup->buffer, &ctx->memory, ZR_CLIPPING_ON); + } else { + int in_panel, in_body, in_header; + in_panel = zr_input_is_mouse_click_in_rect(&ctx->input, ZR_BUTTON_LEFT, win->layout->bounds); + in_body = zr_input_is_mouse_click_in_rect(&ctx->input, ZR_BUTTON_LEFT, body); + in_header = zr_input_is_mouse_click_in_rect(&ctx->input, ZR_BUTTON_LEFT, header); + if (!in_body && in_panel && !in_header) + is_active = zr_false; + } + + if (!is_active) { + win->layout->flags |= ZR_WINDOW_REMOVE_ROM; + } else { + /* if active create popup otherwise deactive the panel layout */ + popup->bounds = body; + popup->parent = win; + popup->layout = layout; + popup->flags = flags; + popup->flags |= ZR_WINDOW_BORDER|ZR_WINDOW_POPUP; + popup->flags |= ZR_WINDOW_DYNAMIC|ZR_WINDOW_SUB; + + zr_start_child(ctx, win); + ctx->current = popup; + popup->buffer.clip = zr_null_rect; + zr_layout_begin(ctx, 0); + win->layout->flags |= ZR_WINDOW_ROM; + popup->seq = ctx->seq; + layout->offset = &popup->scrollbar; + } + return is_active; +} + +void +zr_popup_close(struct zr_context *ctx) +{ + struct zr_window *popup; + ZR_ASSERT(ctx); + if (!ctx || !ctx->current) return; + popup = ctx->current; + ZR_ASSERT(popup->parent); + ZR_ASSERT(popup->flags & ZR_WINDOW_POPUP); + popup->flags |= ZR_WINDOW_HIDDEN; +} + +void +zr_popup_end(struct zr_context *ctx) +{ + struct zr_window *win; + struct zr_window *popup; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + + popup = ctx->current; + ZR_ASSERT(popup->parent); + win = popup->parent; + if (popup->flags & ZR_WINDOW_HIDDEN) + win->layout->flags |= ZR_WINDOW_REMOVE_ROM; + + zr_draw_scissor(&win->buffer, zr_null_rect); + zr_end(ctx); + zr_finish_child(ctx, win); + ctx->current = win; + zr_draw_scissor(&win->buffer, win->layout->clip); +} +/* ------------------------------------------------------------- + * + * TOOLTIP + * + * -------------------------------------------------------------- */ +int +zr_tooltip_begin(struct zr_context *ctx, struct zr_layout *layout, float width) +{ + int ret; + const struct zr_input *in; + struct zr_rect bounds; + struct zr_window *win; + + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + ZR_ASSERT(win->layout); + if (!ctx || !ctx->current) return 0; + + in = &ctx->input; + bounds.w = width; + bounds.h = zr_null_rect.h; + bounds.x = (in->mouse.pos.x + 1) - win->layout->clip.x; + bounds.y = (in->mouse.pos.y + 1) - win->layout->clip.y; + ret = zr_popup_begin(ctx, layout, ZR_POPUP_DYNAMIC, + "__##Tooltip##__", ZR_WINDOW_NO_SCROLLBAR, bounds); + if (ret) win->layout->flags &= ~(zr_flags)ZR_WINDOW_ROM; return ret; } void -zr_popup_close(struct zr_context *popup) +zr_tooltip_end(struct zr_context *ctx) { - ZR_ASSERT(popup); - if (!popup || !popup->valid) return; - popup->flags |= ZR_WINDOW_HIDDEN; - popup->valid = zr_false; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !ctx->current) return; + zr_popup_close(ctx); + zr_popup_end(ctx); } void -zr_popup_end(struct zr_context *parent, struct zr_context *popup, - struct zr_vec2 *scrollbar) +zr_tooltip(struct zr_context *ctx, const char *text) { - struct zr_window pan; - struct zr_command_buffer *out; + zr_size text_len; + zr_size text_width; + zr_size text_height; - ZR_ASSERT(parent); - ZR_ASSERT(popup); - if (!parent || !popup) return; - if (!parent->valid) return; + const struct zr_style *config; + struct zr_vec2 item_padding; + struct zr_vec2 padding; + struct zr_window *win; + struct zr_layout layout; - zr_zero(&pan, sizeof(pan)); - if (popup->flags & ZR_WINDOW_HIDDEN) { - parent->flags |= ZR_WINDOW_REMOVE_ROM; - popup->valid = zr_true; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + ZR_ASSERT(text); + + /* fetch configuration data */ + config = &ctx->style; + padding = config->properties[ZR_PROPERTY_PADDING]; + item_padding = config->properties[ZR_PROPERTY_ITEM_PADDING]; + + /* calculate size of the text and tooltip */ + text_len = zr_strsiz(text); + text_width = config->font.width(config->font.userdata, config->font.height, text, text_len); + text_width += (zr_size)(2 * padding.x + 2 * item_padding.x); + text_height = (zr_size)(config->font.height + 2 * item_padding.y); + + /* execute tooltip and fill with text */ + if (zr_tooltip_begin(ctx, &layout, (float)text_width)) { + zr_layout_row_dynamic(ctx, (float)text_height, 1); + zr_text(ctx, text, text_len, ZR_TEXT_LEFT); } - - out = parent->buffer; - pan.bounds.x = popup->bounds.x; - pan.bounds.y = popup->bounds.y; - pan.bounds.w = popup->width; - pan.bounds.h = popup->height; - pan.flags = ZR_WINDOW_BORDER|ZR_WINDOW_TAB; - - /* end popup and reset clipping rect back to parent panel */ - zr_command_buffer_push_scissor(out, zr_null_rect); - zr_end(popup, &pan); - zr_command_queue_finish_child(parent->queue, parent->buffer); - zr_command_buffer_push_scissor(out, parent->clip); - if (scrollbar) - *scrollbar = pan.offset; + zr_tooltip_end(ctx); } + /* * ------------------------------------------------------------- * @@ -8725,81 +9582,61 @@ zr_popup_end(struct zr_context *parent, struct zr_context *popup, * * -------------------------------------------------------------- */ -static int -zr_popup_nonblocking_begin(struct zr_context *parent, - struct zr_context *popup, zr_flags flags, int *active, int is_active, - struct zr_rect body, struct zr_vec2 scrollbar) +int +zr_contextual_begin(struct zr_context *ctx, struct zr_layout *layout, + zr_flags flags, struct zr_vec2 size) { - /* deactivate popup if user clicked outside the popup*/ - const struct zr_input *in = parent->input; - if (in && *active) { - int inbody = zr_input_is_mouse_click_in_rect(in, ZR_BUTTON_LEFT, body); - int inpanel = zr_input_is_mouse_click_in_rect(in, ZR_BUTTON_LEFT, parent->bounds); - if (!inbody && inpanel) - is_active = zr_false; - } + int ret; + int is_active = 0; + int is_clicked = 0; + int is_open = 0; - /* recalculate body bounds into local panel position */ - body.x -= parent->clip.x; - body.y -= parent->clip.y; + struct zr_window *win; + struct zr_window *popup; + struct zr_rect body; + static struct zr_rect null_rect; - /* if active create popup otherwise deactive the panel layout */ - if (!is_active && *active) { - zr_popup_begin(parent, popup, ZR_POPUP_DYNAMIC, 0, flags, body, scrollbar); - zr_popup_close(popup); - popup->flags &= ~(zr_flags)ZR_WINDOW_MINIMIZED; - parent->flags &= ~(zr_flags)ZR_WINDOW_ROM; - } else if (!is_active && !*active) { - *active = is_active; - popup->flags |= ZR_WINDOW_MINIMIZED; - return zr_false; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + win = ctx->current; + + popup = win->popup.win; + is_clicked = zr_input_is_mouse_click_in_rect(&ctx->input, ZR_BUTTON_RIGHT, win->layout->bounds); + is_open = (popup && (popup->flags & ZR_WINDOW_CONTEXTUAL) && win->popup.type == ZR_WINDOW_CONTEXTUAL); + if ((is_clicked && is_open && !is_active) || (!is_open && !is_active && !is_clicked)) return 0; + + if (is_clicked) { + body.x = ctx->input.mouse.pos.x; + body.y = ctx->input.mouse.pos.y; } else { - zr_popup_begin(parent, popup, ZR_POPUP_DYNAMIC, 0, flags, body, zr_vec2(0,0)); - popup->flags &= ~(zr_flags)ZR_WINDOW_MINIMIZED; + body.x = popup->bounds.x; + body.y = popup->bounds.y; } - *active = is_active; - return zr_true; -} -static void -zr_popup_nonblocking_end(struct zr_context *parent, - struct zr_context *popup, struct zr_vec2 *scrollbar) -{ - ZR_ASSERT(parent); - ZR_ASSERT(popup); - if (!parent || !popup) return; - if (!parent->valid) return; - if (!(popup->flags & ZR_WINDOW_MINIMIZED)) - zr_popup_end(parent, popup, scrollbar); -} - -void -zr_contextual_begin(struct zr_context *parent, struct zr_context *popup, - zr_flags flags, int *active, struct zr_rect body) -{ - ZR_ASSERT(parent); - ZR_ASSERT(popup); - ZR_ASSERT(active); - if (!parent || !popup || !active) return; - zr_popup_nonblocking_begin(parent, popup, flags, active, *active, body, zr_vec2(0,0)); + body.w = size.x; + body.h = size.y; + ret = zr_nonblock_begin(layout, ctx, flags|ZR_WINDOW_CONTEXTUAL, body, null_rect); + if (ret) win->popup.type = ZR_WINDOW_CONTEXTUAL; + return ret; } static int -zr_contextual_button(struct zr_context *layout, const char *text, +zr_contextual_button(struct zr_context *ctx, const char *text, enum zr_text_align align, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_text button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; + struct zr_window *win = ctx->current; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_FITTING); + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_FITTING); if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; + i = (state == ZR_WIDGET_ROM || win->layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; - config = layout->style; + config = &ctx->style; button.base.border_width = 0; button.base.normal = config->colors[ZR_COLOR_WINDOW]; button.base.border = config->colors[ZR_COLOR_WINDOW]; @@ -8807,26 +9644,27 @@ zr_contextual_button(struct zr_context *layout, const char *text, button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; button.alignment = align; - return zr_do_button_text(&ws, layout->buffer, bounds, text, behavior, + return zr_do_button_text(&ws, &win->buffer, bounds, text, behavior, &button, i, &config->font); } static int -zr_contextual_button_symbol(struct zr_context *layout, enum zr_symbol symbol, +zr_contextual_button_symbol(struct zr_context *ctx, enum zr_symbol symbol, const char *text, enum zr_text_align align, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_text button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; + struct zr_window *win = ctx->current; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_FITTING); + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_FITTING); if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; + i = (state == ZR_WIDGET_ROM || win->layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; - config = layout->style; + config = &ctx->style; button.alignment = ZR_TEXT_CENTERED; button.base.border_width = 0; button.base.normal = config->colors[ZR_COLOR_WINDOW]; @@ -8834,26 +9672,27 @@ zr_contextual_button_symbol(struct zr_context *layout, enum zr_symbol symbol, button.normal = config->colors[ZR_COLOR_TEXT]; button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; - return zr_do_button_text_symbol(&ws, layout->buffer, bounds, symbol, text, align, + return zr_do_button_text_symbol(&ws, &win->buffer, bounds, symbol, text, align, behavior, &button, &config->font, i); } static int -zr_contextual_button_icon(struct zr_context *layout, struct zr_image img, +zr_contextual_button_icon(struct zr_context *ctx, struct zr_image img, const char *text, enum zr_text_align align, enum zr_button_behavior behavior) { struct zr_rect bounds; struct zr_button_text button; const struct zr_style *config; - enum zr_widget_states ws; + enum zr_widget_status ws; + struct zr_window *win = ctx->current; const struct zr_input *i; enum zr_widget_state state; - state = zr_button(&button.base, &bounds, layout, ZR_BUTTON_FITTING); + state = zr_button(&button.base, &bounds, ctx, ZR_BUTTON_FITTING); if (!state) return zr_false; - i = (state == ZR_WIDGET_ROM || layout->flags & ZR_WINDOW_ROM) ? 0 : layout->input; + i = (state == ZR_WIDGET_ROM || win->layout->flags & ZR_WINDOW_ROM) ? 0 : &ctx->input; - config = layout->style; + config = &ctx->style; button.alignment = ZR_TEXT_CENTERED; button.base.border_width = 0; button.base.normal = config->colors[ZR_COLOR_WINDOW]; @@ -8862,72 +9701,69 @@ zr_contextual_button_icon(struct zr_context *layout, struct zr_image img, button.hover = config->colors[ZR_COLOR_TEXT_HOVERING]; button.active = config->colors[ZR_COLOR_TEXT_ACTIVE]; button.alignment = ZR_TEXT_CENTERED; - return zr_do_button_text_image(&ws, layout->buffer, bounds, img, text, align, + return zr_do_button_text_image(&ws, &win->buffer, bounds, img, text, align, behavior, &button, &config->font, i); } int -zr_contextual_item(struct zr_context *menu, const char *title, enum zr_text_align align) +zr_contextual_item(struct zr_context *ctx, const char *title, enum zr_text_align align) { - ZR_ASSERT(menu); - if (zr_contextual_button(menu, title, align, ZR_BUTTON_DEFAULT)) { - zr_contextual_close(menu); + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (zr_contextual_button(ctx, title, align, ZR_BUTTON_DEFAULT)) { + zr_contextual_close(ctx); return zr_true; } return zr_false; } int -zr_contextual_item_icon(struct zr_context *menu, struct zr_image img, +zr_contextual_item_icon(struct zr_context *ctx, struct zr_image img, const char *title, enum zr_text_align align) { - ZR_ASSERT(menu); - if (zr_contextual_button_icon(menu, img, title, align, ZR_BUTTON_DEFAULT)){ - zr_contextual_close(menu); + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (zr_contextual_button_icon(ctx, img, title, align, ZR_BUTTON_DEFAULT)){ + zr_contextual_close(ctx); return zr_true; } return zr_false; } int -zr_contextual_item_symbol(struct zr_context *menu, enum zr_symbol symbol, +zr_contextual_item_symbol(struct zr_context *ctx, enum zr_symbol symbol, const char *title, enum zr_text_align align) { - ZR_ASSERT(menu); - if (zr_contextual_button_symbol(menu, symbol, title, align, ZR_BUTTON_DEFAULT)){ - zr_contextual_close(menu); + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (zr_contextual_button_symbol(ctx, symbol, title, align, ZR_BUTTON_DEFAULT)){ + zr_contextual_close(ctx); return zr_true; } return zr_false; } void -zr_contextual_close(struct zr_context *popup) +zr_contextual_close(struct zr_context *ctx) { - ZR_ASSERT(popup); - if (!popup) return; - zr_popup_close(popup); - popup->flags |= ZR_WINDOW_HIDDEN; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx->current) return; + zr_popup_close(ctx); } void -zr_contextual_end(struct zr_context *parent, struct zr_context *menu, int *state) +zr_contextual_end(struct zr_context *ctx) { - ZR_ASSERT(parent); - ZR_ASSERT(menu); - if (!parent || !menu) - goto failed; - if (!parent->valid) - goto failed; - if ((!parent->valid) || (!menu->valid && !(menu->flags & ZR_WINDOW_HIDDEN))) - goto failed; - zr_popup_nonblocking_end(parent, menu, 0); - if (menu->flags & ZR_WINDOW_HIDDEN) - goto failed; - if (state) *state = zr_true; + struct zr_window *popup; + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + popup = ctx->current; + ZR_ASSERT(popup->parent); + if (popup->flags & ZR_WINDOW_HIDDEN) + popup->seq = 0; + zr_popup_end(ctx); return; -failed: - if (state) *state = zr_false; } /* ------------------------------------------------------------- * @@ -8935,82 +9771,59 @@ failed: * * --------------------------------------------------------------*/ static int -zr_combo_begin(struct zr_context *parent, struct zr_context *combo, - int height, struct zr_vec2 *scrollbar, struct zr_rect header, - int *active, int is_active) +zr_combo_begin(struct zr_layout *layout, struct zr_context *ctx, struct zr_window *win, + const char *id, int height, int is_clicked, struct zr_rect header) { /* calculate the maximum height of the combo box*/ - unsigned int flags; + int is_open = 0; + int is_active = 0; struct zr_rect body; - struct zr_vec2 scroll; + struct zr_window *popup; + zr_hash hash = zr_murmur_hash(id, (int)zr_strsiz(id), ZR_WINDOW_COMBO); body.x = header.x; body.w = header.w; body.y = header.y + header.h-1; body.h = (float)height; - flags = ZR_WINDOW_COMBO_MENU; - if (!scrollbar) { - scroll.x = 0; scroll.y = 0; - flags |= ZR_WINDOW_NO_SCROLLBAR; - } else scroll = *scrollbar; - if (!zr_popup_nonblocking_begin(parent, combo, flags, - active, is_active, body, scroll)) - return 0; + popup = win->popup.win; + is_open = (popup && (popup->flags & ZR_WINDOW_COMBO)); + is_active = (popup && (win->popup.name == hash) && win->popup.type == ZR_WINDOW_COMBO); + if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || + (!is_open && !is_active && !is_clicked)) return 0; + if (!zr_nonblock_begin(layout, ctx, ZR_WINDOW_COMBO|ZR_WINDOW_NO_SCROLLBAR, + body, zr_rect(0,0,0,0))) return 0; + win->popup.type = ZR_WINDOW_COMBO; + win->popup.name = hash; return 1; } -static void -zr_combo_failed(struct zr_context *parent, struct zr_context *combo, struct zr_vec2 *scrollbar) +int +zr_combo_begin_text(struct zr_context *ctx, struct zr_layout *layout, + const char *id, const char *selected, int height) { - zr_zero(combo, sizeof(*combo)); - combo->valid = zr_false; - combo->style = parent->style; - combo->buffer = parent->buffer; - combo->input = parent->input; - combo->queue = parent->queue; - if (scrollbar) { - scrollbar->x = 0; - scrollbar->y = 0; - } -} - -void -zr_combo_begin_text(struct zr_context *parent, struct zr_context *combo, - const char *selected, int *active, int height, struct zr_vec2 *scrollbar) -{ - enum zr_widget_states state; - const struct zr_input *in; - const struct zr_style *config; - struct zr_command_buffer *out; + struct zr_window *win; + enum zr_widget_status state; struct zr_vec2 item_padding; struct zr_rect header; - int is_active; + int is_active = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(combo); - ZR_ASSERT(selected); - ZR_ASSERT(active); - if (!parent || !combo || !selected || !active) return; - if (!parent->valid || !zr_widget(&header, parent)) { - zr_combo_failed(parent, combo, scrollbar); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx || !selected) return 0; + win = ctx->current; + if (!zr_widget(&header, ctx)) + return 0; - zr_zero(combo, sizeof(*combo)); - in = (parent->flags & ZR_WINDOW_ROM) ? 0 : parent->input; - is_active = *active; - out = parent->buffer; - config = parent->style; - item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); - - if (zr_button_behavior(&state, header, in, ZR_BUTTON_DEFAULT)) - is_active = !is_active; + item_padding = zr_style_property(&ctx->style, ZR_PROPERTY_ITEM_PADDING); + if (zr_button_behavior(&state, header, &ctx->input, ZR_BUTTON_DEFAULT)) + is_active = zr_true; /* draw combo box header background and border */ - zr_command_buffer_push_rect(out, header, 0, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_rect(out, zr_shrink_rect(header, 1), 0, - config->colors[ZR_COLOR_COMBO]); + zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + ctx->style.colors[ZR_COLOR_COMBO]); + { /* print currently selected string */ zr_size text_len; @@ -9022,58 +9835,48 @@ zr_combo_begin_text(struct zr_context *parent, struct zr_context *combo, label.w = header.w - (header.h + 2 * item_padding.x); label.h = header.h - 2 * item_padding.y; text_len = zr_strsiz(selected); - zr_command_buffer_push_text(out, label, selected, text_len, &config->font, - config->colors[ZR_COLOR_WINDOW], config->colors[ZR_COLOR_TEXT]); + zr_draw_text(&win->buffer, label, selected, text_len, &ctx->style.font, + ctx->style.colors[ZR_COLOR_WINDOW], ctx->style.colors[ZR_COLOR_TEXT]); /* draw open/close symbol */ - bounds.y = label.y + label.h/2 - config->font.height/2; - bounds.w = bounds.h = config->font.height; + bounds.y = label.y + label.h/2 - ctx->style.font.height/2; + bounds.w = bounds.h = ctx->style.font.height; bounds.x = (header.x + header.w) - (bounds.w + 2 * item_padding.x); - zr_draw_symbol(out, ZR_SYMBOL_TRIANGLE_DOWN, bounds, - config->colors[ZR_COLOR_COMBO], config->colors[ZR_COLOR_TEXT], - 1, &config->font); + zr_draw_symbol(&win->buffer, ZR_SYMBOL_TRIANGLE_DOWN, bounds, + ctx->style.colors[ZR_COLOR_COMBO], ctx->style.colors[ZR_COLOR_TEXT], + 1, &ctx->style.font); } - if (!zr_combo_begin(parent, combo, height, scrollbar, header, active, is_active)) - zr_combo_failed(parent, combo, scrollbar); + return zr_combo_begin(layout, ctx, win, id, height, is_active, header); } -void -zr_combo_begin_color(struct zr_context *parent, struct zr_context *combo, - struct zr_color color, int *active, int height, struct zr_vec2 *scrollbar) +int +zr_combo_begin_color(struct zr_context *ctx, struct zr_layout *layout, + const char *id, struct zr_color color, int height) { - enum zr_widget_states state; - const struct zr_input *in; - const struct zr_style *config; - struct zr_command_buffer *out; + struct zr_window *win; + enum zr_widget_status state; struct zr_vec2 item_padding; struct zr_rect header; - int is_active; + int is_active = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(combo); - ZR_ASSERT(active); - if (!parent || !combo || !active) return; - if (!parent->valid || !zr_widget(&header, parent)) { - zr_combo_failed(parent, combo, scrollbar); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return 0; + win = ctx->current; + if (!zr_widget(&header, ctx)) + return 0; - zr_zero(combo, sizeof(*combo)); - in = (parent->flags & ZR_WINDOW_ROM) ? 0 : parent->input; - is_active = *active; - out = parent->buffer; - config = parent->style; - item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); - if (zr_button_behavior(&state, header, in, ZR_BUTTON_DEFAULT)) + item_padding = zr_style_property(&ctx->style, ZR_PROPERTY_ITEM_PADDING); + if (zr_button_behavior(&state, header, &ctx->input, ZR_BUTTON_DEFAULT)) is_active = !is_active; /* draw combo box header background and border */ - zr_command_buffer_push_rect(out, header, 0, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_rect(out, zr_shrink_rect(header, 1), 0, - config->colors[ZR_COLOR_COMBO]); + zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + ctx->style.colors[ZR_COLOR_COMBO]); + { /* print currently selected string */ - zr_size text_len; struct zr_rect content; struct zr_rect bounds = {0,0,0,0}; @@ -9081,57 +9884,48 @@ zr_combo_begin_color(struct zr_context *parent, struct zr_context *combo, content.y = header.y + 2 * item_padding.y; content.x = header.x + 2 * item_padding.x; content.w = header.w - (header.h + 4 * item_padding.x); - zr_command_buffer_push_rect(out, content, 0, color); + zr_draw_rect(&win->buffer, content, 0, color); /* draw open/close symbol */ - bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f - config->font.height/2; - bounds.w = bounds.h = config->font.height; + bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f - + ctx->style.font.height/2; + bounds.w = bounds.h = ctx->style.font.height; bounds.x = (header.x + header.w) - (bounds.w + 2 * item_padding.x); - zr_draw_symbol(out, ZR_SYMBOL_TRIANGLE_DOWN, bounds, - config->colors[ZR_COLOR_COMBO], config->colors[ZR_COLOR_TEXT], - 1, &config->font); + zr_draw_symbol(&win->buffer, ZR_SYMBOL_TRIANGLE_DOWN, bounds, + ctx->style.colors[ZR_COLOR_COMBO], ctx->style.colors[ZR_COLOR_TEXT], + 1, &ctx->style.font); } - if (!zr_combo_begin(parent, combo, height, scrollbar, header, active, is_active)) - zr_combo_failed(parent, combo, scrollbar); + return zr_combo_begin(layout, ctx, win, id, height, is_active, header); } -void -zr_combo_begin_image(struct zr_context *parent, struct zr_context *combo, - struct zr_image img, int *active, int height, struct zr_vec2 *scrollbar) +int +zr_combo_begin_image(struct zr_context *ctx, struct zr_layout *layout, + const char *id, struct zr_image img, int height) { - enum zr_widget_states state; - const struct zr_input *in; - const struct zr_style *config; - struct zr_command_buffer *out; + struct zr_window *win; + enum zr_widget_status state; struct zr_vec2 item_padding; struct zr_rect header; - int is_active; + int is_active = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(combo); - ZR_ASSERT(active); - if (!parent || !combo || !active) return; - if (!parent->valid || !zr_widget(&header, parent)) { - zr_combo_failed(parent, combo, scrollbar); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return 0; + win = ctx->current; + if (!zr_widget(&header, ctx)) + return 0; - zr_zero(combo, sizeof(*combo)); - in = (parent->flags & ZR_WINDOW_ROM) ? 0 : parent->input; - is_active = *active; - out = parent->buffer; - config = parent->style; - item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); - if (zr_button_behavior(&state, header, in, ZR_BUTTON_DEFAULT)) + item_padding = zr_style_property(&ctx->style, ZR_PROPERTY_ITEM_PADDING); + if (zr_button_behavior(&state, header, &ctx->input, ZR_BUTTON_DEFAULT)) is_active = !is_active; /* draw combo box header background and border */ - zr_command_buffer_push_rect(out, header, 0, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_rect(out, zr_shrink_rect(header, 1), 0, - config->colors[ZR_COLOR_COMBO]); + zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + ctx->style.colors[ZR_COLOR_COMBO]); + { /* print currently selected string */ - zr_size text_len; struct zr_rect content; struct zr_rect bounds = {0,0,0,0}; @@ -9139,55 +9933,46 @@ zr_combo_begin_image(struct zr_context *parent, struct zr_context *combo, content.y = header.y + 2 * item_padding.y; content.x = header.x + 2 * item_padding.x; content.w = header.w - (header.h + 4 * item_padding.x); - zr_command_buffer_push_image(out, content, &img); + zr_draw_image(&win->buffer, content, &img); /* draw open/close symbol */ - bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f - config->font.height/2; - bounds.w = bounds.h = config->font.height; + bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f - + ctx->style.font.height/2; + bounds.w = bounds.h = ctx->style.font.height; bounds.x = (header.x + header.w) - (bounds.w + 2 * item_padding.x); - zr_draw_symbol(out, ZR_SYMBOL_TRIANGLE_DOWN, bounds, - config->colors[ZR_COLOR_COMBO], config->colors[ZR_COLOR_TEXT], - 1, &config->font); + zr_draw_symbol(&win->buffer, ZR_SYMBOL_TRIANGLE_DOWN, bounds, + ctx->style.colors[ZR_COLOR_COMBO], ctx->style.colors[ZR_COLOR_TEXT], + 1, &ctx->style.font); } - if (!zr_combo_begin(parent, combo, height, scrollbar, header, active, is_active)) - zr_combo_failed(parent, combo, scrollbar); + return zr_combo_begin(layout, ctx, win, id, height, is_active, header); } -void -zr_combo_begin_icon(struct zr_context *parent, struct zr_context *combo, - const char *selected, struct zr_image img, int *active, int height, - struct zr_vec2 *scrollbar) +int +zr_combo_begin_icon(struct zr_context *ctx, struct zr_layout *layout, const char *id, + const char *selected, struct zr_image img, int height) { - enum zr_widget_states state; - const struct zr_input *in; - const struct zr_style *config; - struct zr_command_buffer *out; + struct zr_window *win; + enum zr_widget_status state; struct zr_vec2 item_padding; struct zr_rect header; - int is_active; + int is_active = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(combo); - ZR_ASSERT(active); - if (!parent || !combo || !active) return; - if (!parent->valid || !zr_widget(&header, parent)) { - zr_combo_failed(parent, combo, scrollbar); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return 0; + win = ctx->current; + if (!zr_widget(&header, ctx)) + return 0; - zr_zero(combo, sizeof(*combo)); - in = (parent->flags & ZR_WINDOW_ROM) ? 0 : parent->input; - is_active = *active; - out = parent->buffer; - config = parent->style; - item_padding = zr_style_property(config, ZR_PROPERTY_ITEM_PADDING); - if (zr_button_behavior(&state, header, in, ZR_BUTTON_DEFAULT)) + item_padding = zr_style_property(&ctx->style, ZR_PROPERTY_ITEM_PADDING); + if (zr_button_behavior(&state, header, &ctx->input, ZR_BUTTON_DEFAULT)) is_active = !is_active; /* draw combo box header background and border */ - zr_command_buffer_push_rect(out, header, 0, config->colors[ZR_COLOR_BORDER]); - zr_command_buffer_push_rect(out, zr_shrink_rect(header, 1), 0, - config->colors[ZR_COLOR_COMBO]); + zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + ctx->style.colors[ZR_COLOR_COMBO]); + { /* print currently selected string */ zr_size text_len; @@ -9204,64 +9989,43 @@ zr_combo_begin_icon(struct zr_context *parent, struct zr_context *combo, icon.y = content.y; icon.h = content.h; icon.w = icon.h; - zr_command_buffer_push_image(out, icon, &img); + zr_draw_image(&win->buffer, icon, &img); label.x = icon.x + icon.w + 2 * item_padding.x; label.y = content.y; label.w = (content.x + content.w) - (icon.x + icon.w); label.h = content.h; text_len = zr_strsiz(selected); - zr_command_buffer_push_text(out, label, selected, text_len, &config->font, - config->colors[ZR_COLOR_WINDOW], config->colors[ZR_COLOR_TEXT]); + zr_draw_text(&win->buffer, label, selected, text_len, &ctx->style.font, + ctx->style.colors[ZR_COLOR_WINDOW], ctx->style.colors[ZR_COLOR_TEXT]); - /* draw open/close symbol */ - bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f - config->font.height/2; - bounds.w = bounds.h = config->font.height; + bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f - + ctx->style.font.height/2; + bounds.w = bounds.h = ctx->style.font.height; bounds.x = (header.x + header.w) - (bounds.w + 2 * item_padding.x); - zr_draw_symbol(out, ZR_SYMBOL_TRIANGLE_DOWN, bounds, - config->colors[ZR_COLOR_COMBO], config->colors[ZR_COLOR_TEXT], - 1, &config->font); + zr_draw_symbol(&win->buffer, ZR_SYMBOL_TRIANGLE_DOWN, bounds, + ctx->style.colors[ZR_COLOR_COMBO], ctx->style.colors[ZR_COLOR_TEXT], + 1, &ctx->style.font); } - if (!zr_combo_begin(parent, combo, height, scrollbar, header, active, is_active)) - zr_combo_failed(parent, combo, scrollbar); + return zr_combo_begin(layout, ctx, win, id, height, is_active, header); } -int zr_combo_item(struct zr_context *combo, const char *title, enum zr_text_align align) -{return zr_contextual_item(combo, title, align);} +int zr_combo_item(struct zr_context *ctx, const char *title, enum zr_text_align align) +{return zr_contextual_item(ctx, title, align);} -int zr_combo_item_icon(struct zr_context *menu, struct zr_image img, +int zr_combo_item_icon(struct zr_context *ctx, struct zr_image img, const char *title, enum zr_text_align align) -{return zr_contextual_item_icon(menu, img, title, align);} +{return zr_contextual_item_icon(ctx, img, title, align);} -int zr_combo_item_symbol(struct zr_context *menu, enum zr_symbol symbol, +int zr_combo_item_symbol(struct zr_context *ctx, enum zr_symbol symbol, const char *title, enum zr_text_align align) -{return zr_contextual_item_symbol(menu, symbol, title, align);} +{return zr_contextual_item_symbol(ctx, symbol, title, align);} -void zr_combo_end(struct zr_context *parent, struct zr_context *menu, - int *state, struct zr_vec2 *scrollbar) -{ - ZR_ASSERT(parent); - ZR_ASSERT(menu); - if (!parent || !menu) - goto failed; - if (!parent->valid) - goto failed; - if ((!parent->valid) || (!menu->valid && !(menu->flags & ZR_WINDOW_HIDDEN))) - goto failed; - zr_popup_nonblocking_end(parent, menu, scrollbar); - if (menu->flags & ZR_WINDOW_HIDDEN) - goto failed; - if (state) *state = zr_true; - return; -failed: - if (state) *state = zr_false; -} +void zr_combo_end(struct zr_context *ctx) +{zr_contextual_end(ctx);} -void zr_combo_close(struct zr_context *combo, int *state) -{ - zr_contextual_close(combo); - *state = 0; -} +void zr_combo_close(struct zr_context *ctx) +{zr_contextual_close(ctx);} /* * ------------------------------------------------------------- * @@ -9270,270 +10034,144 @@ void zr_combo_close(struct zr_context *combo, int *state) * -------------------------------------------------------------- */ static int -zr_menu_begin(struct zr_context *parent, struct zr_context *menu, - struct zr_rect header, float width, int *active, int is_active) +zr_menu_begin(struct zr_layout *layout, struct zr_context *ctx, struct zr_window *win, + const char *id, int is_clicked, struct zr_rect header, float width) { + /* calculate the maximum height of the combo box*/ + int is_open = 0; + int is_active = 0; struct zr_rect body; + struct zr_window *popup; + zr_hash hash = zr_murmur_hash(id, (int)zr_strsiz(id), ZR_WINDOW_MENU); + body.x = header.x; body.w = width; body.y = header.y + header.h; - body.h = (parent->bounds.y + parent->bounds.h) - body.y; - if (!zr_popup_nonblocking_begin(parent, menu, ZR_WINDOW_COMBO_MENU|ZR_WINDOW_NO_SCROLLBAR, - active, is_active, body, zr_vec2(0,0))) return 0; + body.h = (win->layout->bounds.y + win->layout->bounds.h) - body.y; + + popup = win->popup.win; + is_open = (popup && (popup->flags & ZR_WINDOW_MENU)); + is_active = (popup && (win->popup.name == hash) && win->popup.type == ZR_WINDOW_MENU); + if ((is_clicked && is_open && !is_active) || (is_open && !is_active) || + (!is_open && !is_active && !is_clicked)) return 0; + if (!zr_nonblock_begin(layout, ctx, ZR_WINDOW_MENU|ZR_WINDOW_NO_SCROLLBAR, body, header)) return 0; + win->popup.type = ZR_WINDOW_MENU; + win->popup.name = hash; return 1; } -static void -zr_menu_failed(struct zr_context *parent, struct zr_context *menu) +int +zr_menu_text_begin(struct zr_context *ctx, struct zr_layout *layout, + const char *title, float width) { - zr_zero(menu, sizeof(*menu)); - menu->valid = zr_false; - menu->style = parent->style; - menu->buffer = parent->buffer; - menu->input = parent->input; - menu->queue = parent->queue; -} - -void -zr_menu_text_begin(struct zr_context *parent, struct zr_context *menu, - const char *title, float width, int *active) -{ - const struct zr_input *in; - const struct zr_style *config; + struct zr_window *win; + enum zr_widget_status state; struct zr_rect header; - int is_active; + int is_clicked = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(menu); - ZR_ASSERT(title); - ZR_ASSERT(active); - if (!parent || !menu || !title || !active) return; - if (!parent->valid) { - zr_menu_failed(parent, menu); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return 0; + win = ctx->current; - is_active = *active; - in = parent->input; - config = parent->style; - zr_zero(menu, sizeof(*menu)); { - /* exeucte menu text button for open/closing the popup */ + /* execute menu text button for open/closing the popup */ struct zr_button_text button; - enum zr_widget_states state; zr_zero(&button, sizeof(button)); - zr_button(&button.base, &header, parent, ZR_BUTTON_NORMAL); + if (!zr_button(&button.base, &header, ctx, ZR_BUTTON_NORMAL)) return 0; button.base.rounding = 0; button.base.border_width = 0; - button.base.border = (is_active) ? config->colors[ZR_COLOR_BORDER]: - config->colors[ZR_COLOR_WINDOW]; - button.base.normal = (is_active) ? config->colors[ZR_COLOR_BUTTON_HOVER]: - config->colors[ZR_COLOR_WINDOW]; - button.base.active = config->colors[ZR_COLOR_WINDOW]; + button.base.border = ctx->style.colors[ZR_COLOR_WINDOW]; + button.base.normal = ctx->style.colors[ZR_COLOR_WINDOW]; + button.base.active = ctx->style.colors[ZR_COLOR_WINDOW]; button.alignment = ZR_TEXT_CENTERED; - button.normal = config->colors[ZR_COLOR_TEXT]; - button.active = config->colors[ZR_COLOR_TEXT]; - button.hover = config->colors[ZR_COLOR_TEXT]; - if (zr_do_button_text(&state, parent->buffer, header, title, ZR_BUTTON_DEFAULT, - &button, in, &config->font)) is_active = !is_active; + button.normal = ctx->style.colors[ZR_COLOR_TEXT]; + button.active = ctx->style.colors[ZR_COLOR_TEXT]; + button.hover = ctx->style.colors[ZR_COLOR_TEXT]; + if (zr_do_button_text(&state, &win->buffer, header, title, ZR_BUTTON_DEFAULT, + &button, &ctx->input, &ctx->style.font)) + is_clicked = zr_true; } - if (!zr_menu_begin(parent, menu, header, width, active, is_active)) - zr_menu_failed(parent, menu); + return zr_menu_begin(layout, ctx, win, title, is_clicked, header, width); } -void -zr_menu_icon_begin(struct zr_context *parent, struct zr_context *menu, - struct zr_image img, float width, int *active) +int +zr_menu_icon_begin(struct zr_context *ctx, struct zr_layout *layout, + const char *id, struct zr_image img, float width) { - const struct zr_input *in; - const struct zr_style *config; + struct zr_window *win; + enum zr_widget_status state; struct zr_rect header; - int is_active; + int is_clicked = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(menu); - ZR_ASSERT(active); - if (!parent || !menu || !active) return; - if (!parent->valid) { - zr_menu_failed(parent, menu); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return 0; + win = ctx->current; - is_active = *active; - in = parent->input; - config = parent->style; - zr_zero(menu, sizeof(*menu)); { /* execute menu icon button for open/closing the popup */ struct zr_button_icon button; - enum zr_widget_states state; zr_zero(&button, sizeof(button)); - zr_button(&button.base, &header, parent, ZR_BUTTON_NORMAL); + if (!zr_button(&button.base, &header, ctx, ZR_BUTTON_NORMAL)) return 0; button.base.rounding = 1; - button.base.border = config->colors[ZR_COLOR_BORDER]; - button.base.normal = (is_active) ? config->colors[ZR_COLOR_BUTTON_HOVER]: - config->colors[ZR_COLOR_WINDOW]; - button.base.active = config->colors[ZR_COLOR_WINDOW]; - button.padding = config->properties[ZR_PROPERTY_ITEM_PADDING]; - if (zr_do_button_image(&state, parent->buffer, header, img, ZR_BUTTON_DEFAULT, - &button, in)) is_active = !is_active; + button.base.border = ctx->style.colors[ZR_COLOR_BORDER]; + button.base.normal = ctx->style.colors[ZR_COLOR_WINDOW]; + button.base.active = ctx->style.colors[ZR_COLOR_WINDOW]; + button.padding = ctx->style.properties[ZR_PROPERTY_ITEM_PADDING]; + if (zr_do_button_image(&state, &win->buffer, header, img, ZR_BUTTON_DEFAULT, + &button, &ctx->input)) is_clicked = zr_true; } - if (!zr_menu_begin(parent, menu, header, width, active, is_active)) - zr_menu_failed(parent, menu); + return zr_menu_begin(layout, ctx, win, id, is_clicked, header, width); } -void -zr_menu_symbol_begin(struct zr_context *parent, - struct zr_context *menu, enum zr_symbol sym, float width, int *active) +int +zr_menu_symbol_begin(struct zr_context *ctx, struct zr_layout *layout, + const char *id, enum zr_symbol sym, float width) { - const struct zr_input *in; - const struct zr_style *config; + struct zr_window *win; + enum zr_widget_status state; struct zr_rect header; - int is_active; + int is_clicked = zr_false; - ZR_ASSERT(parent); - ZR_ASSERT(menu); - ZR_ASSERT(active); - if (!parent || !menu || !active) return; - if (!parent->valid) { - zr_menu_failed(parent, menu); - return; - } + ZR_ASSERT(ctx); + ZR_ASSERT(ctx->current); + if (!ctx) return 0; + win = ctx->current; - is_active = *active; - in = parent->input; - config = parent->style; - zr_zero(menu, sizeof(*menu)); { /* execute menu symbol button for open/closing the popup */ struct zr_button_symbol button; - enum zr_widget_states state; zr_zero(&button, sizeof(button)); - zr_button(&button.base, &header, parent, ZR_BUTTON_NORMAL); + if (!zr_button(&button.base, &header, ctx, ZR_BUTTON_NORMAL)) return 0; button.base.rounding = 1; - button.base.border = config->colors[ZR_COLOR_BORDER]; - button.base.normal = (is_active) ? config->colors[ZR_COLOR_BUTTON_HOVER]: - config->colors[ZR_COLOR_WINDOW]; - button.base.active = config->colors[ZR_COLOR_WINDOW]; - button.normal = config->colors[ZR_COLOR_TEXT]; - button.active = config->colors[ZR_COLOR_TEXT]; - button.hover = config->colors[ZR_COLOR_TEXT]; - if (zr_do_button_symbol(&state, parent->buffer, header, sym, ZR_BUTTON_DEFAULT, - &button, in, &config->font)) is_active = !is_active; + button.base.border = ctx->style.colors[ZR_COLOR_BORDER]; + button.base.normal = ctx->style.colors[ZR_COLOR_WINDOW]; + button.base.active = ctx->style.colors[ZR_COLOR_WINDOW]; + button.normal = ctx->style.colors[ZR_COLOR_TEXT]; + button.active = ctx->style.colors[ZR_COLOR_TEXT]; + button.hover = ctx->style.colors[ZR_COLOR_TEXT]; + if (zr_do_button_symbol(&state, &win->buffer, header, sym, ZR_BUTTON_DEFAULT, + &button, &ctx->input, &ctx->style.font)) is_clicked = zr_true; } - if (!zr_menu_begin(parent, menu, header, width, active, is_active)) - zr_menu_failed(parent, menu); - + return zr_menu_begin(layout, ctx, win, id, is_clicked, header, width); } -int zr_menu_item(struct zr_context *menu, enum zr_text_align align, const char *title) -{ - int valid = menu->valid; - int ret = zr_contextual_item(menu, title, align); - menu->valid = valid; - return ret; -} +int zr_menu_item(struct zr_context *ctx, enum zr_text_align align, const char *title) +{return zr_contextual_item(ctx, title, align);} -int zr_menu_item_icon(struct zr_context *menu, struct zr_image img, +int zr_menu_item_icon(struct zr_context *ctx, struct zr_image img, const char *title, enum zr_text_align align) -{ - int valid = menu->valid; - int ret = zr_contextual_item_icon(menu, img, title, align); - menu->valid = valid; - return ret; -} +{ return zr_contextual_item_icon(ctx, img, title, align);} -int zr_menu_item_symbol(struct zr_context *menu, enum zr_symbol symbol, +int zr_menu_item_symbol(struct zr_context *ctx, enum zr_symbol symbol, const char *title, enum zr_text_align align) -{ - int valid = menu->valid; - int ret = zr_contextual_item_symbol(menu, symbol, title, align); - menu->valid = valid; - return ret; -} +{return zr_contextual_item_symbol(ctx, symbol, title, align);} -void zr_menu_close(struct zr_context *menu, int *state) -{zr_contextual_close(menu); *state = zr_false;} +void zr_menu_close(struct zr_context *ctx) +{zr_contextual_close(ctx);} void -zr_menu_end(struct zr_context *parent, struct zr_context *menu) -{ - ZR_ASSERT(parent); - ZR_ASSERT(menu); - if (!parent || !menu) return; - if (!parent->valid) return; - zr_popup_nonblocking_end(parent, menu, 0); -} -/* ------------------------------------------------------------- - * - * TOOLTIP - * - * -------------------------------------------------------------- */ -void -zr_tooltip_begin(struct zr_context *parent, struct zr_context *tip, float width) -{ - const struct zr_input *in; - struct zr_rect bounds; - ZR_ASSERT(tip); - ZR_ASSERT(parent); - if (!tip || !parent || !parent->valid || parent->flags & ZR_WINDOW_ROM) { - zr_zero(tip, sizeof(*tip)); - tip->valid = zr_false; - tip->style = parent->style; - tip->buffer = parent->buffer; - tip->input = parent->input; - tip->queue = parent->queue; - return; - } - - in = parent->input; - bounds.w = width; - bounds.h = zr_null_rect.h; - bounds.x = (in->mouse.pos.x + 1) - parent->clip.x; - bounds.y = (in->mouse.pos.y + 1) - parent->clip.y; - zr_popup_begin(parent, tip, ZR_POPUP_DYNAMIC, 0, ZR_WINDOW_NO_SCROLLBAR, bounds, zr_vec2(0,0)); -} - -void -zr_tooltip_end(struct zr_context *parent, struct zr_context *tip) -{ - if (!parent || !tip || !parent->valid) return; - zr_popup_close(tip); - zr_popup_end(parent, tip, 0); -} - -void -zr_tooltip(struct zr_context *layout, const char *text) -{ - zr_size text_len; - zr_size text_width; - zr_size text_height; - - struct zr_context tip; - const struct zr_style *config; - struct zr_vec2 item_padding; - struct zr_vec2 padding; - - ZR_ASSERT(layout); - ZR_ASSERT(text); - if (!layout || !text || !layout->valid || layout->flags & ZR_WINDOW_ROM) - return; - - /* fetch configuration data */ - config = layout->style; - padding = config->properties[ZR_PROPERTY_PADDING]; - item_padding = config->properties[ZR_PROPERTY_ITEM_PADDING]; - - /* calculate size of the text and tooltip */ - text_len = zr_strsiz(text); - text_width = config->font.width(config->font.userdata, config->font.height, text, text_len); - text_width += (zr_size)(2 * padding.x + 2 * item_padding.x); - text_height = (zr_size)(config->font.height + 2 * item_padding.y); - - /* execute tooltip and fill with text */ - zr_tooltip_begin(layout, &tip, (float)text_width); - zr_layout_row_dynamic(&tip, (float)text_height, 1); - zr_text(&tip, text, text_len, ZR_TEXT_LEFT); - zr_tooltip_end(layout, &tip); -} +zr_menu_end(struct zr_context *ctx) +{zr_contextual_end(ctx);} diff --git a/zahnrad.h b/zahnrad.h index 897fecd..6bbdd87 100644 --- a/zahnrad.h +++ b/zahnrad.h @@ -69,7 +69,7 @@ extern "C" { you can just set this define to zero and the font module will not be compiled and the two headers will not be needed. */ /* - * ============================================================== +* ============================================================== * * BASIC * @@ -78,6 +78,7 @@ extern "C" { #if ZR_COMPILE_WITH_FIXED_TYPES #include typedef uint32_t zr_uint; +typedef uint32_t zr_hash; typedef uint64_t zr_ulong; typedef uint64_t zr_size; typedef uintptr_t zr_ptr; @@ -86,6 +87,7 @@ typedef uint32_t zr_rune; typedef uint8_t zr_byte; #else typedef unsigned int zr_uint; +typedef unsigned int zr_hash; typedef unsigned long zr_ulong; typedef unsigned long zr_size; typedef zr_size zr_ptr; @@ -107,37 +109,11 @@ typedef unsigned char zr_byte; struct zr_user_font; struct zr_edit_box; struct zr_user_font_glyph; -/* - * ============================================================== - * - * UTILITY - * - * =============================================================== - */ -/* Utility - ---------------------------- - The utility API provides a number of object construction function - for some gui specific objects like image handle, vector, color and rectangle. - USAGE - ---------------------------- - Utility function API - zr_get_null_rect -- returns a default clipping rectangle - zr_utf_decode -- decodes a utf-8 glyph into u32 unicode glyph and len - zr_utf_encode -- encodes a u32 unicode glyph into a utf-8 glyph - zr_image_ptr -- create a image handle from pointer - zr_image_id -- create a image handle from integer id - zr_subimage_ptr -- create a sub-image handle from pointer and region - zr_subimage_id -- create a sub-image handle from integer id and region - zr_rect_is_valid -- check if a rectangle inside the image command is valid - zr_rect -- creates a rectangle from x,y-Position and width and height - zr_vec2 -- creates a 2D floating point vector - zr_rgba -- create a gui color struct from rgba color code - zr_rgb -- create a gui color struct from rgb color code -*/ +/*================================================================ + * UTILITY + * ===============================================================*/ enum {zr_false, zr_true}; -enum zr_heading {ZR_UP, ZR_RIGHT, ZR_DOWN, ZR_LEFT}; -enum zr_modify {ZR_FIXED = zr_false, ZR_MODIFIABLE = zr_true}; struct zr_color {zr_byte r,g,b,a;}; struct zr_vec2 {float x,y;}; struct zr_vec2i {short x, y;}; @@ -146,33 +122,27 @@ struct zr_recti {short x,y,w,h;}; typedef char zr_glyph[ZR_UTF_SIZE]; typedef union {void *ptr; int id;} zr_handle; struct zr_image {zr_handle handle; unsigned short w, h; unsigned short region[4];}; +struct zr_scroll {unsigned short x, y;}; +typedef double(*zr_sin_f)(double); +typedef double(*zr_cos_f)(double); -enum zr_symbol { - ZR_SYMBOL_X, - ZR_SYMBOL_UNDERSCORE, - ZR_SYMBOL_CIRCLE, - ZR_SYMBOL_CIRCLE_FILLED, - ZR_SYMBOL_RECT, - ZR_SYMBOL_RECT_FILLED, - ZR_SYMBOL_TRIANGLE_UP, - ZR_SYMBOL_TRIANGLE_DOWN, - ZR_SYMBOL_TRIANGLE_LEFT, - ZR_SYMBOL_TRIANGLE_RIGHT, - ZR_SYMBOL_PLUS, - ZR_SYMBOL_MINUS, - ZR_SYMBOL_MAX -}; - -/* ----------------------- POINTER ---------------------------------*/ +/* pointer */ #define zr_ptr_add(t, p, i) ((t*)((void*)((zr_byte*)(p) + (i)))) #define zr_ptr_sub(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_ptr_sub_const(t, p, i) ((const t*)((const void*)((const zr_byte*)(p) - (i)))) -/* ----------------------- MATH ---------------------------------*/ + +/* math */ struct zr_rect zr_get_null_rect(void); struct zr_rect zr_rect(float x, float y, float w, float h); struct zr_vec2 zr_vec2(float x, float y); -/* ----------------------- COLOR ---------------------------------*/ + +/* UTF-8 */ +zr_size zr_utf_decode(const char*, zr_rune*, zr_size); +zr_size zr_utf_encode(zr_rune, char*, zr_size); +zr_size zr_utf_len(const char*, zr_size byte_len); + +/* color */ struct zr_color zr_rgba(zr_byte r, zr_byte g, zr_byte b, zr_byte a); struct zr_color zr_rgb(zr_byte r, zr_byte g, zr_byte b); struct zr_color zr_rgba_f(float r, float g, float b, float a); @@ -189,7 +159,8 @@ void zr_color_hsv_f(float *out_h, float *out_s, float *out_v, struct zr_color); void zr_color_hsva(int *out_h, int *out_s, int *out_v, int *out_a, struct zr_color); void zr_color_hsva_f(float *out_h, float *out_s, float *out_v, float *out_a, struct zr_color); -/* ----------------------- IMAGE ---------------------------------*/ + +/* image */ zr_handle zr_handle_ptr(void*); zr_handle zr_handle_id(int); struct zr_image zr_image_ptr(void*); @@ -197,20 +168,11 @@ struct zr_image zr_image_id(int); struct zr_image zr_subimage_ptr(void*, unsigned short w, unsigned short h, struct zr_rect); struct zr_image zr_subimage_id(int, unsigned short w, unsigned short h, struct zr_rect); int zr_image_is_subimage(const struct zr_image* img); -/* ----------------------- UTF-8 ---------------------------------*/ -zr_size zr_utf_decode(const char*, zr_rune*, zr_size); -zr_size zr_utf_encode(zr_rune, char*, zr_size); -zr_size zr_utf_len(const char*, zr_size len); /* ============================================================== - * * INPUT - * - * =============================================================== - */ -/* INPUT - ---------------------------- - The input API is responsible for holding the input state by keeping track of + * ===============================================================*/ +/* The input API is responsible for holding the input state by keeping track of mouse, key and text. The core of the API is a persistent zr_input struct which holds the input state while running. It is important to note that no direct os or window handling is done by the input @@ -218,37 +180,7 @@ zr_size zr_utf_len(const char*, zr_size len); expects more work from the user and complicates the usage but on the other hand provides simple abstraction over a big number of platforms, libraries and other already provided functionality. - - USAGE - ---------------------------- - To instantiate the Input API the zr_input structure has to be zeroed in - the beginning of the program by either using memset or setting it to {0}, - since the internal state is persistent over all frames. - - To modify the internal input state you have to first set the zr_input struct - into a modifiable state with zr_input_begin. After the zr_input struct is - now ready you can add input state changes until everything is up to date. - Finally to revert back into a read state you have to call zr_input_end. - - Input function API - zr_input_begin -- begins the modification state - zr_input_motion -- notifies of a cursor motion update - zr_input_key -- notifies of a keyboard key update - zr_input_button -- notifies of a action event - zr_input_char -- adds a text glyph to zr_input - zr_input_end -- ends the modification state - - Input query function API - zr_input_is_mouse_click_in_rect - checks for up/down click in a rectangle - zr_input_is_mouse_hovering_rect - checks if the mouse hovers over a rectangle - zr_input_mouse_clicked - checks if hover + down + clicked in rectangle - zr_input_is_mouse_down - checks if the current mouse button is down - zr_input_is_mouse_released - checks if mouse button previously released - zr_input_is_key_pressed - checks if key was up and now is down - zr_input_is_key_released - checks if key was down and is now up - zr_input_is_key_down - checks if key is currently down */ -/* every key that is being used inside the library */ enum zr_keys { ZR_KEY_SHIFT, ZR_KEY_DEL, @@ -293,7 +225,11 @@ struct zr_mouse { /* number of steps in the up or down scroll direction */ }; -struct zr_key {int down; unsigned int clicked;}; +struct zr_key { + int down; + unsigned int clicked; +}; + struct zr_keyboard { struct zr_key keys[ZR_KEY_MAX]; /* state of every used key */ @@ -310,87 +246,37 @@ struct zr_input { /* current mouse button and position state */ }; +/* gathering input state */ void zr_input_begin(struct zr_input*); -/* this function sets the input state to writeable */ void zr_input_motion(struct zr_input*, int x, int y); -/* this function updates the current mouse position - Input: - - local os window X position - - local os window Y position -*/ void zr_input_key(struct zr_input*, enum zr_keys, int down); -/* this function updates the current state of a key - Input: - - key identifier - - the new state of the key -*/ void zr_input_button(struct zr_input*, enum zr_buttons, int x, int y, int down); -/* this function updates the current state of the button - Input: - - mouse button identifier - - local os window X position - - local os window Y position - - the new state of the button -*/ void zr_input_scroll(struct zr_input*, float y); -/* this function updates the current page scroll delta - Input: - - vector with each direction (< 0 down > 0 up and scroll distance) -*/ void zr_input_glyph(struct zr_input*, const zr_glyph); -/* this function adds a utf-8 glpyh into the internal text frame buffer - Input: - - utf8 glyph to add to the text buffer -*/ void zr_input_char(struct zr_input*, char); -/* this function adds char into the internal text frame buffer - Input: - - character to add to the text buffer -*/ void zr_input_unicode(struct zr_input *in, zr_rune unicode); -/* this function adds a unicode character into the internal text frame buffer - Input: - - unicode character to add to the text buffer -*/ void zr_input_end(struct zr_input*); -/* this function sets the input state to readable */ -int zr_input_has_mouse_click_in_rect(const struct zr_input*,enum zr_buttons, - struct zr_rect); -/* this function returns true if a mouse click inside a rectangle occured in prev frames */ + +/* query input state */ +int zr_input_has_mouse_click_in_rect(const struct zr_input*,enum zr_buttons, struct zr_rect); int zr_input_has_mouse_click_down_in_rect(const struct zr_input*, enum zr_buttons, - struct zr_rect, int down); -/* this function returns true if a mouse down click inside a rectangle occured in prev frames */ + struct zr_rect, int down); int zr_input_is_mouse_click_in_rect(const struct zr_input*, enum zr_buttons, struct zr_rect); -/* this function returns true if a mouse click inside a rectangle occured and was just clicked */ +int zr_input_any_mouse_click_in_rect(const struct zr_input*, struct zr_rect); int zr_input_is_mouse_prev_hovering_rect(const struct zr_input*, struct zr_rect); -/* this function returns true if the mouse hovers over a rectangle */ int zr_input_is_mouse_hovering_rect(const struct zr_input*, struct zr_rect); -/* this function returns true if the mouse hovers over a rectangle */ int zr_input_mouse_clicked(const struct zr_input*, enum zr_buttons, struct zr_rect); -/* this function returns true if a mouse click inside a rectangle occured - and the mouse still hovers over the rectangle*/ int zr_input_is_mouse_down(const struct zr_input*, enum zr_buttons); -/* this function returns true if the current mouse button is down */ int zr_input_is_mouse_pressed(const struct zr_input*, enum zr_buttons); -/* this function returns true if the current mouse button is down and state change*/ int zr_input_is_mouse_released(const struct zr_input*, enum zr_buttons); -/* this function returns true if the mouse button was previously pressed but - was now released */ int zr_input_is_key_pressed(const struct zr_input*, enum zr_keys); -/* this function returns true if the given key was up and is now pressed */ int zr_input_is_key_released(const struct zr_input*, enum zr_keys); -/* this function returns true if the given key was down and is now up */ int zr_input_is_key_down(const struct zr_input*, enum zr_keys); -/* this function returns true if the given key was down and is now up */ /* ============================================================== - * - * BUFFER - * + * MEMORY BUFFER * =============================================================== */ -/* BUFFER - ---------------------------- - A basic (double)-buffer API with linear allocation and resetting as only +/* A basic (double)-buffer API with linear allocation and resetting as only freeing policy. The buffers main purpose is to control all memory management inside the GUI toolkit and still leave memory control as much as possible in the hand of the user. The memory is provided in three different ways. @@ -420,18 +306,6 @@ int zr_input_is_key_down(const struct zr_input*, enum zr_keys); needed you would call zr_buffer_reset. To free all memory that has been allocated by an allocator if the buffer is no longer being used you have to call zr_buffer_clear. - - Buffer function API - zr_buffer_init -- initializes a dynamic buffer - zr_buffer_init_fixed -- initializes a static buffer - zr_buffer_info -- provides buffer memory information - zr_buffer_alloc -- allocates a block of memory from the buffer - zr_buffer_clear -- resets the buffer back to an empty state - zr_buffer_free -- frees all memory if the buffer is dynamic - zr_buffer_mark -- marks the current buffer size for later resetting - zr_buffer_reset -- resets the buffer either back to zero or up to marker if set - zr_buffer_memory -- returns the internal memory - zr_buffer_total -- returns the current total size of the memory */ struct zr_memory_status { void *memory; @@ -458,7 +332,7 @@ struct zr_allocator { /* callback function pointer to finally free all allocated memory */ }; -enum zr_buffer_type { +enum zr_allocation_type { ZR_BUFFER_FIXED, /* fixed size memory buffer */ ZR_BUFFER_DYNAMIC @@ -486,7 +360,7 @@ struct zr_buffer { /* buffer marker to free a buffer to a certain offset */ struct zr_allocator pool; /* allocator callback for dynamic buffers */ - enum zr_buffer_type type; + enum zr_allocation_type type; /* memory type management type */ struct zr_memory memory; /* memory and size of the current memory block */ @@ -502,852 +376,19 @@ struct zr_buffer { /* current size of the buffer */ }; -void zr_buffer_init(struct zr_buffer*, const struct zr_allocator*, - zr_size initial_size, float grow_factor); -/* this function initializes a growing buffer - Input: - - allocator holding your own alloctator and memory allocation callbacks - - initial size of the buffer - - factor to grow the buffer by if the buffer is full - Output: - - dynamically growing buffer -*/ +void zr_buffer_init(struct zr_buffer*, const struct zr_allocator*, zr_size initial_size); void zr_buffer_init_fixed(struct zr_buffer*, void *memory, zr_size size); -/* this function initializes a fixed sized buffer - Input: - - fixed size previously allocated memory block - - size of the memory block - Output: - - fixed size buffer -*/ void zr_buffer_info(struct zr_memory_status*, struct zr_buffer*); -/* this function requests memory information from a buffer - Input: - - buffer to get the inforamtion from - Output: - - buffer memory information -*/ -int zr_buffer_push(struct zr_buffer*,enum zr_buffer_allocation_type type, - void *data, zr_size size, zr_size align); -/* this functions allocates a aligned memory block from a buffer and fill - the block with data - Input: - - buffer to allocate memory from - - size of the requested memory block - - alignment requirement for the memory block - Output: - - 'zr_true' if succesfully pushed 'zr_false' otherwise -*/ -void zr_buffer_mark(struct zr_buffer*, enum zr_buffer_allocation_type); -/* sets a marker either for the back or front buffer for later resetting */ -void zr_buffer_reset(struct zr_buffer*, enum zr_buffer_allocation_type); -/* resets the buffer back to the previously set marker or if not set the begining */ -void zr_buffer_clear(struct zr_buffer*); -/* this functions resets the buffer back into an empty state */ void zr_buffer_free(struct zr_buffer*); -/* this functions frees all memory inside a dynamically growing buffer */ void *zr_buffer_memory(struct zr_buffer*); -/* returns the memory inside the buffer */ zr_size zr_buffer_total(struct zr_buffer*); -/* returns the total size of the buffer */ - -/* ============================================================== - * - * COMMAND BUFFER - * - * ===============================================================*/ -/* COMMAND BUFFER - ---------------------------- - The command buffer API queues draw calls as commands into a buffer and - therefore abstracts over drawing routines and enables defered drawing. - The API offers a number of drawing primitives like lines, rectangles, circles, - triangles, images, text and clipping rectangles, that have to be drawn by the user. - Therefore the command buffer is the main toolkit output besides the actual - widget output. - The actual draw command execution is done by the user and is build up in a - interpreter like fashion by iterating over all commands and executing each - command depending on the command type. - - USAGE - ---------------------------- - To use the command buffer you first have to initiate the command buffer with a - buffer. After the initilization you can add primitives by - calling the appropriate zr_command_buffer_XXX for each primitive. - To iterate over each commands inside the buffer zr_foreach_buffer_command is - provided. Finally to reuse the buffer after the frame use the - zr_command_buffer_clear function. If used without a command queue the command - buffer has be cleared after each frame to reset the buffer back into a - empty state. - - command buffer function API - zr_command_buffer_init -- initializes a command buffer with a buffer - zr_command_buffer_clear -- resets the command buffer and internal buffer - zr_command_buffer_reset -- resets the command buffer but not the buffer - - command queue function API - zr_command_buffer_push -- pushes and enqueues a command into the buffer - zr_command_buffer_push_scissor -- pushes a clipping rectangle into the command buffer - zr_command_buffer_push_line -- pushes a line into the command buffer - zr_command_buffer_push_rect -- pushes a rectange into the command buffer - zr_command_buffer_push_circle -- pushes a circle into the command buffer - zr_command_buffer_push_triangle-- pushes a triangle command into the buffer - zr_command_buffer_push_curve -- pushes a bezier cruve command into the buffer - zr_command_buffer_push_image -- pushes a image draw command into the buffer - zr_command_buffer_push_text -- pushes a text draw command into the buffer - - command iterator function API - zr_command_buffer_begin -- returns the first command in a buffer - zr_command_buffer_next -- returns the next command in a buffer - zr_foreach_buffer_command -- iterates over all commands in a buffer -*/ -/* command type of every used drawing primitive */ -enum zr_command_type { - ZR_COMMAND_NOP, - ZR_COMMAND_SCISSOR, - ZR_COMMAND_LINE, - ZR_COMMAND_CURVE, - ZR_COMMAND_RECT, - ZR_COMMAND_CIRCLE, - ZR_COMMAND_ARC, - ZR_COMMAND_TRIANGLE, - ZR_COMMAND_TEXT, - ZR_COMMAND_IMAGE -}; - -/* command base and header of every comand inside the buffer */ -struct zr_command { - enum zr_command_type type; - /* the type of the current command */ - zr_size next; - /* absolute base pointer offset to the next command */ -}; - -struct zr_command_scissor { - struct zr_command header; - short x, y; - unsigned short w, h; -}; - -struct zr_command_line { - struct zr_command header; - struct zr_vec2i begin; - struct zr_vec2i end; - struct zr_color color; -}; - -struct zr_command_curve { - struct zr_command header; - struct zr_vec2i begin; - struct zr_vec2i end; - struct zr_vec2i ctrl[2]; - struct zr_color color; -}; - -struct zr_command_rect { - struct zr_command header; - unsigned int rounding; - short x, y; - unsigned short w, h; - struct zr_color color; -}; - -struct zr_command_circle { - struct zr_command header; - short x, y; - unsigned short w, h; - struct zr_color color; -}; - -struct zr_command_arc { - struct zr_command header; - short cx, cy; - unsigned short r; - float a[2]; - struct zr_color color; -}; - -struct zr_command_triangle { - struct zr_command header; - struct zr_vec2i a; - struct zr_vec2i b; - struct zr_vec2i c; - struct zr_color color; -}; - -struct zr_command_image { - struct zr_command header; - short x, y; - unsigned short w, h; - struct zr_image img; -}; - -struct zr_command_text { - struct zr_command header; - const struct zr_user_font *font; - struct zr_color background; - struct zr_color foreground; - short x, y; - unsigned short w, h; - float height; - zr_size length; - char string[1]; -}; - -enum zr_command_clipping { - ZR_NOCLIP = zr_false, - ZR_CLIP = zr_true -}; - -struct zr_command_stats { - unsigned int lines; - /* number of lines inside the buffer */ - unsigned int curves; - /* number of lines inside the buffer */ - unsigned int rectangles; - /* number of rectangles in the buffer */ - unsigned int circles; - /* number of circles in the buffer */ - unsigned int triangles; - /* number of triangles in the buffer */ - unsigned int images; - /* number of images in the buffer */ - unsigned int text; - /* number of text commands in the buffer */ - unsigned int glyphs; - /* number of text glyphs in the buffer */ - unsigned int scissors; - /* number of text glyphs in the buffer */ -}; - -struct zr_command_queue; -struct zr_command_buffer { - struct zr_buffer *base; - /* memory buffer to store the command */ - struct zr_rect clip; - /* current clipping rectangle */ - int use_clipping; - /* flag if the command buffer should clip commands */ - struct zr_command_stats stats; - /* stats about the content of the buffer */ - struct zr_command_queue *queue; - struct zr_command_buffer *next; - struct zr_command_buffer *prev; - zr_size begin, end, last; - /* INTERNAL: references into a command queue */ -}; - -void zr_command_buffer_init(struct zr_command_buffer*, struct zr_buffer*, - enum zr_command_clipping); -/* this function intializes the command buffer - Input: - - memory buffer to store the commands into - - clipping flag for removing non-visible draw commands -*/ -void zr_command_buffer_reset(struct zr_command_buffer*); -/* this function clears the command buffer but not the internal memory buffer */ -void zr_command_buffer_clear(struct zr_command_buffer*); -/* this function clears the command buffer and internal memory buffer */ -void *zr_command_buffer_push(struct zr_command_buffer*, unsigned int type, zr_size size); -/* this function push enqueues a command into the buffer - Input: - - buffer to push the command into - - type of the command - - amount of memory that is needed for the specified command -*/ -void zr_command_buffer_push_scissor(struct zr_command_buffer*, struct zr_rect); -/* this function push a clip rectangle command into the buffer - Input: - - buffer to push the clip rectangle command into - - x,y and width and height of the clip rectangle -*/ -void zr_command_buffer_push_line(struct zr_command_buffer*, float, float, - float, float, struct zr_color); -/* this function pushes a line draw command into the buffer - Input: - - buffer to push the clip rectangle command into - - starting point of the line - - ending point of the line - - color of the line to draw -*/ -void zr_command_buffer_push_curve(struct zr_command_buffer*, float, float, - float, float, float, float, - float, float, struct zr_color); -/* this function pushes a quad bezier line draw command into the buffer - Input: - - buffer to push the clip rectangle command into - - starting point (x,y) of the line - - first control point (x,y) of the line - - second control point (x,y) of the line - - ending point (x,y) of the line - - color of the line to draw -*/ -void zr_command_buffer_push_rect(struct zr_command_buffer*, struct zr_rect, - float rounding, struct zr_color color); -/* this function pushes a rectangle draw command into the buffer - Input: - - buffer to push the draw rectangle command into - - rectangle bounds - - rectangle edge rounding - - color of the rectangle to draw -*/ -void zr_command_buffer_push_circle(struct zr_command_buffer*, struct zr_rect, - struct zr_color c); -/* this function pushes a circle draw command into the buffer - Input: - - buffer to push the circle draw command into - - rectangle bounds of the circle - - color of the circle to draw -*/ -void zr_command_buffer_push_arc(struct zr_command_buffer*, float cx, - float cy, float radius, float a_min, - float a_max, struct zr_color); -/* this function pushes an arc draw command into the buffer - Input: - - buffer to push the circle draw command into - - center position (x,y) of the arc - - start and end angle of the arc - - color of the arc -*/ -void zr_command_buffer_push_triangle(struct zr_command_buffer*, float, float, - float, float, float, float, - struct zr_color); -/* this function pushes a triangle draw command into the buffer - Input: - - buffer to push the draw triangle command into - - (x,y) coordinates of all three points - - rectangle diameter of the circle - - color of the triangle to draw -*/ -void zr_command_buffer_push_image(struct zr_command_buffer*, struct zr_rect, - struct zr_image*); -/* this function pushes a image draw command into the buffer - Input: - - buffer to push the draw image command into - - bounds of the image to draw with position, width and height - - rectangle diameter of the circle - - color of the triangle to draw -*/ -void zr_command_buffer_push_text(struct zr_command_buffer*, struct zr_rect, - const char*, zr_size, const struct zr_user_font*, - struct zr_color, struct zr_color); -/* this function pushes a text draw command into the buffer - Input: - - buffer to push the draw text command into - - top left position of the text with x,y position - - maixmal size of the text to draw with width and height - - color of the triangle to draw -*/ -#define zr_command(t, c) ((const struct zr_command_##t*)c) -/* this is a small helper makro to cast from a general to a specific command */ -#define zr_foreach_buffer_command(i, b)\ - for((i)=zr_command_buffer_begin(b); (i)!=NULL; (i)=zr_command_buffer_next(b,i)) -/* this loop header allow to iterate over each command in a command buffer */ -const struct zr_command *zr_command_buffer_begin(struct zr_command_buffer*); -/* this function returns the first command in the command buffer */ -const struct zr_command *zr_command_buffer_next(struct zr_command_buffer*, - struct zr_command*); -/* this function returns the next command of a given command*/ - -/*============================================================== - * - * COMMAND QUEUE - * - * ===============================================================*/ -/* COMMAND QUEUE - ---------------------------- - The command queue extends the command buffer with the possiblity to use - more than one command buffer on one memory buffer and still only need - to iterate over one command list. Therefore it is possible to have multiple - windows without having to manage each windows individual memory. This greatly - simplifies and reduces the amount of code needed with just using command buffers. - - Internally the command queue has a list of command buffers which can be - modified to create a certain sequence, for example the `zr_begin` - function changes the list to create overlapping windows. - - USAGE - ---------------------------- - The command queue owns a memory buffer internaly that needs to be initialized - either as a fixed size or dynamic buffer with functions `zr_commmand_queue_init' - or `zr_command_queue_init_fixed`. Windows are automaticall added to the command - queue in the `zr_window_init` with the `zr_command_queue_add` function - but removing a window requires a manual call of `zr_command_queue_remove`. - Internally the window calls the `zr_command_queue_start` and - `zr_command_queue_finish` function that setup and finilize a command buffer for - command queuing. Finally to iterate over all commands in all command buffers - the iterator API is provided. It allows to iterate over each command in a - foreach loop. - - command queue function API - zr_command_queue_init -- initializes a dynamic command queue - zr_command_queue_init_fixed -- initializes a static command queue - zr_command_queue_clear -- frees all memory if the command queue is dynamic - zr_command_queue_insert_font -- adds a command buffer in the front of the queue - zr_command_queue_insert_back -- adds a command buffer in the back of the queue - zr_command_queue_remove -- removes a command buffer from the queue - zr_command_queue_start -- begins the command buffer filling process - zr_command_queue_start_child -- begins the child command buffer filling process - zr_command_queue_finish_child -- ends the child command buffer filling process - zr_command_queue_finish -- ends the command buffer filling process - - command iterator function API - zr_command_queue_begin -- returns the first command in a queue - zr_command_queue_next -- returns the next command in a queue or NULL - zr_foreach_command -- iterates over all commands in a queue -*/ -struct zr_command_buffer_list { - zr_size count; - /* number of windows inside the stack */ - struct zr_command_buffer *begin; - /* first window inside the window which will be drawn first */ - struct zr_command_buffer *end; - /* currently active window which will be drawn last */ -}; - -struct zr_command_sub_buffer { - zr_size begin; - /* begin of the subbuffer */ - zr_size parent_last; - /* last entry before the sub buffer*/ - zr_size last; - /* last entry in the sub buffer*/ - zr_size end; - /* end of the subbuffer */ - zr_size next; -}; - -struct zr_command_sub_buffer_stack { - zr_size count; - /* number of subbuffers */ - zr_size begin; - /* buffer offset of the first subbuffer*/ - zr_size end; - /* buffer offset of the last subbuffer*/ - zr_size size; - /* real size of the buffer */ -}; - -struct zr_command_queue { - struct zr_buffer buffer; - /* memory buffer the hold all commands */ - struct zr_command_buffer_list list; - /* list of each memory buffer inside the queue */ - struct zr_command_sub_buffer_stack stack; - /* subbuffer stack for overlapping popup windows in windows */ - int build; - /* flag indicating if a complete command list was build inside the queue*/ -}; - -void zr_command_queue_init(struct zr_command_queue*, const struct zr_allocator*, - zr_size initial_size, float grow_factor); -/* this function initializes a growing command queue - Input: - - allocator holding your own alloctator and memory allocation callbacks - - initial size of the buffer - - factor to grow the buffer by if the buffer is full -*/ -void zr_command_queue_init_fixed(struct zr_command_queue*, void*, zr_size); -/* this function initializes a fixed size command queue - Input: - - fixed size previously allocated memory block - - size of the memory block -*/ -void zr_command_queue_insert_back(struct zr_command_queue*, struct zr_command_buffer*); -/* this function adds a command buffer into the back of the queue - Input: - - command buffer to add into the queue -*/ -void zr_command_queue_insert_front(struct zr_command_queue*, struct zr_command_buffer*); -/* this function adds a command buffer into the beginning of the queue - Input: - - command buffer to add into the queue -*/ -void zr_command_queue_remove(struct zr_command_queue*, struct zr_command_buffer*); -/* this function removes a command buffer from the queue - Input: - - command buffer to remove from the queue -*/ -void zr_command_queue_start(struct zr_command_queue*, struct zr_command_buffer*); -/* this function sets up the command buffer to be filled up - Input: - - command buffer to fill with commands -*/ -void zr_command_queue_finish(struct zr_command_queue*, struct zr_command_buffer*); -/* this function finishes the command buffer fill up process - Input: - - the now filled command buffer -*/ -int zr_command_queue_start_child(struct zr_command_queue*, - struct zr_command_buffer*); -/* this function sets up a child buffer inside a command buffer to be filled up - Input: - - command buffer to begin the child buffer in - Output: - - zr_true if successful zr_false otherwise -*/ -void zr_command_queue_finish_child(struct zr_command_queue*, struct zr_command_buffer*); -/* this function finishes the child buffer inside the command buffer fill up process - Input: - - the command buffer to create the child command buffer in -*/ -void zr_command_queue_free(struct zr_command_queue*); -/* this function clears the internal buffer if it is a dynamic buffer */ -void zr_command_queue_clear(struct zr_command_queue*); -/* this function reset the internal buffer and has to be called every frame */ -#define zr_foreach_command(i, q)\ - for((i)=zr_command_queue_begin(q); (i)!=0; (i)=zr_command_queue_next(q,i)) -/* this function iterates over each command inside the command queue - Input: - - iterator zr_command pointer to iterate over all commands - - queue to iterate over -*/ -void zr_command_queue_build(struct zr_command_queue*); -/* this function builds the internal queue commmand list out of all buffers. - * Only needs be called if zr_command_queue_begin is called in parallel */ -const struct zr_command *zr_command_queue_begin(struct zr_command_queue*); -/* this function returns the first command in the command queue */ -const struct zr_command* zr_command_queue_next(struct zr_command_queue*, - const struct zr_command*); -/* this function returns the next command of a given command*/ - -/* =============================================================== - * - * DRAW LIST - * - * ===============================================================*/ -#if ZR_COMPILE_WITH_VERTEX_BUFFER -/* DRAW LIST - ---------------------------- - The optional draw list provides a way to convert the gui library - drawing command output into a hardware accessible format. - This consists of vertex, element and draw batch command buffer output which - can be interpreted by render frameworks (OpenGL, DirectX, ...). - In addition to just provide a way to convert commands the draw list has - a primitives and stateful path drawing API, which allows to draw into the - draw list even with anti-aliasing. - - The draw list consist internaly of three user provided buffers that will be - filled with data. The first buffer is the draw command and temporary - path buffer which permanetly stores all draw batch commands. The vertex and - element buffer are the same buffers as their hardware renderer counter-parts, - in fact it is even possible to directly map one of these buffers and fill - them with data. - - The reason why the draw list is optional or is not the default library output - is that basic commands provide an easy way to abstract over other libraries - which already provide a drawing API and do not need or want the output the - draw list provides. In addition it is way easier and takes less memory - to serialize commands decribing primitives than vertex data. - - USAGE - ---------------------------- - To actually use the draw list you first need the initialize the draw list - by providing three buffers to be filled while drawing. The reason - buffers need to be provided and not memory or an allocator is to provide - more fine grained control over the memory inside the draw list, which in term - requires more work from the user. - - After the draw list has been initialized you can fill the draw list by - a.) converting the content of a command queue into the draw list format - b.) adding primtive filled shapes or only the outline of rectangles, circle, etc. - c.) using the stateful path API for fine grained drawing control - - Finaly for the drawing process you have to iterate over each draw command - inside the `zr_draw_list` by using the function `zr_foreach_draw_command` - which contains drawing state like clip rectangle, current texture and a number - of elements to draw with the current state. - - draw list buffer functions - zr_draw_list_init - initializes a command buffer with memory - zr_draw_list_clear - clears and resets the buffer - zr_draw_list_load - load the draw buffer from a command queue - zr_draw_list_begin - returns the first command in the draw buffer - zr_draw_list_next - returns the next command in the draw buffer or NULL - zr_draw_list_is_empty - returns if the buffer has no vertexes or commands - zr_foreach_draw_command - iterates over all commands in the draw buffer - - draw list primitives drawing functions - zr_draw_list_add_line - pushes a line into the draw list - zr_draw_list_add_rect - pushes a rectangle into the draw list - zr_draw_list_add_rect_filled - pushes a filled rectangle into the draw list - zr_draw_list_add_triangle - pushes a triangle into the draw list - zr_draw_list_add_triangle_filled -pushes a filled triangle into the draw list - zr_draw_list_add_circle - pushes circle into the draw list - zr_draw_list_add_circle_filled - pushes a filled circle into the draw list - zr_draw_list_add_text - pushes text into the draw list - zr_draw_list_add_image - pushes an image into the draw list - - stateful path functions - zr_draw_list_path_clear - resets the current path - zr_draw_list_path_line_to - adds a point into the path - zr_draw_list_path_arc_to - adds a arc into the path - zr_draw_list_path_curve_to - adds a bezier curve into the path - zr_draw_list_path_rect_to - adds a rectangle into the path - zr_draw_list_path_fill - fills the path as a convex polygon - zr_draw_list_path_stroke - connects each point in the path -*/ -typedef unsigned short zr_draw_index; -typedef zr_uint zr_draw_vertex_color; -typedef float(*zr_sin_f)(float); -typedef float(*zr_cos_f)(float); - -enum zr_anti_aliasing { - ZR_ANTI_ALIASING_OFF = zr_false, - /* renderes all primitives without anti-aliasing */ - ZR_ANTI_ALIASING_ON - /* renderes all primitives with anti-aliasing */ -}; - -struct zr_draw_vertex { - struct zr_vec2 position; - struct zr_vec2 uv; - zr_draw_vertex_color col; -}; - -enum zr_draw_list_stroke { - ZR_STROKE_OPEN = zr_false, - /* build up path has no connection back to the beginning */ - ZR_STROKE_CLOSED = zr_true - /* build up path has a connection back to the beginning */ -}; - -struct zr_draw_command { - unsigned int elem_count; - /* number of elements in the current draw batch */ - struct zr_rect clip_rect; - /* current screen clipping rectangle */ - zr_handle texture; - /* current texture to set */ -}; - -struct zr_draw_null_texture { - zr_handle texture; - /* texture handle to a texture with a white pixel */ - struct zr_vec2 uv; - /* coordinates to the white pixel in the texture */ -}; - -struct zr_draw_list { - enum zr_anti_aliasing AA; - /* flag indicating if anti-aliasing should be used to render primtives */ - struct zr_draw_null_texture null; - /* texture with white pixel for easy primitive drawing */ - struct zr_rect clip_rect; - /* current clipping rectangle */ - zr_cos_f cos; zr_sin_f sin; - /* cosine/sine calculation callback since this library does not use libc */ - struct zr_buffer *buffer; - /* buffer to store draw commands and temporarily store path */ - struct zr_buffer *vertexes; - /* buffer to store each draw vertex */ - struct zr_buffer *elements; - /* buffer to store each draw element index */ - unsigned int element_count; - /* total number of elements inside the elements buffer */ - unsigned int vertex_count; - /* total number of vertexes inside the vertex buffer */ - zr_size cmd_offset; - /* offset to the first command in the buffer */ - unsigned int cmd_count; - /* number of commands inside the buffer */ - unsigned int path_count; - /* current number of points inside the path */ - unsigned int path_offset; - /* offset to the first point in the buffer */ - struct zr_vec2 circle_vtx[12]; - /* small lookup table for fast circle drawing */ -}; -/* --------------------------------------------------------------- - * MAIN - * ---------------------------------------------------------------*/ -void zr_draw_list_setup(zr_sin_f sine, zr_cos_f cosine); -/* this function setups global lookup tables. - * IMPORTANT: only needs to be called if you call the draw list API in a multithreaded fashion - Input: - - sine function callback since this library does not use clib (default: just use sinf) - - cosine function callback since this library does not use clib (default: just use cosf) -*/ -void zr_draw_list_init(struct zr_draw_list*, struct zr_buffer *cmds, - struct zr_buffer *vertexes, struct zr_buffer *elements, - zr_sin_f, zr_cos_f, struct zr_draw_null_texture, - enum zr_anti_aliasing AA); -/* this function initializes the draw list - Input: - - command memory buffer to fill with commands and provided temporary memory for path - - vertex memory buffer to fill with draw vertexeses - - element memory buffer to fill with draw indexes - - sine function callback since this library does not use clib (default: just use sinf) - - cosine function callback since this library does not use clib (default: just use cosf) - - special null structure which holds a texture with a white pixel - - Anti-aliasing flag for turning on/off anti-aliased primitives drawing -*/ -void zr_draw_list_load(struct zr_draw_list*, struct zr_command_queue *queue, - float line_thickness, unsigned int curve_segments); -/* this function loads the draw list from command queue commands - Input: - - queue with draw commands to fill the draw list with - - line thickness for all lines and non-filled primitives - - number of segments used for drawing circles and curves -*/ -void zr_draw_list_clear(struct zr_draw_list *list); -/* this function clears all buffers inside the draw list */ -int zr_draw_list_is_empty(struct zr_draw_list *list); -/* this function returns if the draw list is empty */ -#define zr_foreach_draw_command(i, q)\ - for((i)=zr_draw_list_begin(q); (i)!=NULL; (i)=zr_draw_list_next(q,i)) -/* this function iterates over each draw command inside the draw list - Input: - - iterator zr_draw_command pointer to iterate over all commands - - draw list to iterate over -*/ -const struct zr_draw_command *zr_draw_list_begin(const struct zr_draw_list *list); -/* this function returns the first draw command in the draw list */ -const struct zr_draw_command* zr_draw_list_next(const struct zr_draw_list *list, - const struct zr_draw_command*); -/* this function returns the next draw command of a given draw command*/ - -/* --------------------------------------------------------------- - * PRIMITIVES - * ---------------------------------------------------------------*/ -void zr_draw_list_add_clip(struct zr_draw_list*, struct zr_rect); -/* this function pushes a new clipping rectangle into the draw list - Input: - - new clipping rectangle -*/ -void zr_draw_list_add_line(struct zr_draw_list*, struct zr_vec2 a, - struct zr_vec2 b, struct zr_color col, - float thickness); -/* this function pushes a new clipping rectangle into the draw list - Input: - - beginning point of the line - - end point of the line - - used line color - - line thickness in pixel -*/ -void zr_draw_list_add_rect(struct zr_draw_list*, struct zr_rect rect, - struct zr_color col, float rounding, - float line_thickness); -/* this function pushes a rectangle into the draw list - Input: - - rectangle to render into the draw list - - rectangle outline color - - rectangle edge rounding (0 == no edge rounding) - - rectangle outline thickness -*/ -void zr_draw_list_add_rect_filled(struct zr_draw_list*, struct zr_rect rect, - struct zr_color col, float rounding); -/* this function pushes a filled rectangle into the draw list - Input: - - rectangle to render into the draw list - - color to fill the rectangle with - - rectangle edge rounding (0 == no edge rounding) -*/ -void zr_draw_list_add_triangle(struct zr_draw_list*, struct zr_vec2 a, - struct zr_vec2 b, struct zr_vec2 c, - struct zr_color, float line_thickness); -/* this function pushes a triangle into the draw list - Input: - - first point of the triangle - - second point of the triangle - - third point of the triangle - - color of the triangle outline - - triangle outline line thickness -*/ -void zr_draw_list_add_triangle_filled(struct zr_draw_list*, struct zr_vec2 a, - struct zr_vec2 b, struct zr_vec2 c, - struct zr_color col); -/* this function pushes a filled triangle into the draw list - Input: - - first point of the triangle - - second point of the triangle - - third point of the triangle - - color to fill the triangle with -*/ -void zr_draw_list_add_circle(struct zr_draw_list*, struct zr_vec2 center, - float radius, struct zr_color col, unsigned int segs, - float line_thickness); -/* this function pushes a circle outline into the draw list - Input: - - center point of the circle - - circle radius - - circle outlone color - - number of segement that make up the circle -*/ -void zr_draw_list_add_circle_filled(struct zr_draw_list*, struct zr_vec2 center, - float radius, struct zr_color col, unsigned int); -/* this function pushes a filled circle into the draw list - Input: - - center point of the circle - - circle radius - - color to fill the circle with - - number of segement that make up the circle -*/ -void zr_draw_list_add_curve(struct zr_draw_list*, struct zr_vec2 p0, - struct zr_vec2 cp0, struct zr_vec2 cp1, struct zr_vec2 p1, - struct zr_color col, unsigned int segments, float thickness); -/* this function pushes a bezier curve into the draw list - Input: - - beginning point of the curve - - first curve control point - - second curve control point - - end point of the curve - - color of the curve - - number of segement that make up the circle - - line thickness of the curve -*/ -void zr_draw_list_add_text(struct zr_draw_list*, const struct zr_user_font*, - struct zr_rect, const char*, zr_size length, - float font_height, struct zr_color bg, struct zr_color fg); -/* this function renders text - Input: - - user font to draw the text with - - the rectangle the text will be drawn into - - string text to draw - - length of the string to draw - - text background color - - text color -*/ -void zr_draw_list_add_image(struct zr_draw_list *list, struct zr_image texture, - struct zr_rect rect, struct zr_color color); -/* this function renders an image - Input: - - image texture handle to draw - - rectangle with position and size of the image - - color to blend with the image -*/ -/* --------------------------------------------------------------- - * PATH - * ---------------------------------------------------------------*/ -void zr_draw_list_path_clear(struct zr_draw_list*); -/* clears the statefull drawing path previously build */ -void zr_draw_list_path_line_to(struct zr_draw_list*, struct zr_vec2 pos); -/* adds a point into the path that will make up a line or a convex polygon */ -void zr_draw_list_path_arc_to(struct zr_draw_list*, struct zr_vec2 center, - float radius, float a_min, float a_max, - unsigned int segments); -/* adds an arc made up of a number of segments into the path */ -void zr_draw_list_path_rect_to(struct zr_draw_list*, struct zr_vec2 a, - struct zr_vec2 b, float rounding); -/* adds a rectangle into the path */ -void zr_draw_list_path_curve_to(struct zr_draw_list*, struct zr_vec2 p1, - struct zr_vec2 p2, struct zr_vec2 p3, - unsigned int num_segments); -/* adds a bezier curve into the path where the first point has to be already in the path */ -void zr_draw_list_path_fill(struct zr_draw_list*, struct zr_color); -/* uses all points inside the path to draw a convex polygon */ -void zr_draw_list_path_stroke(struct zr_draw_list*, struct zr_color, - int closed, float thickness); -/* uses all points inside the path to draw a line/outline */ -#endif /* ============================================================== * * FONT * * ===============================================================*/ -/* FONT - ---------------------------- - Font handling in this library can be achived in three different ways. +/* Font handling in this library can be achived in three different ways. The first and simplest ways is by just using your font handling mechanism and provide a simple callback for text string width calculation with `zr_user_font`. This requires the default drawing output @@ -1380,24 +421,10 @@ void zr_draw_list_path_stroke(struct zr_draw_list*, struct zr_color, was designed that way to have a typical file format and not a perfectly ready in memory library instance of a font. The reason is more control and seperates the font baking code from the in library used font format. - - USAGE - ---------------------------- - font baking functions - zr_font_bake_memory -- calculates the needed font baking memory - zr_font_bake_pack -- packs all glyphs and calculates needed image memory - zr_font_bake -- renders all glyphs inside an image and setups glyphs - zr_font_bake_custom_data -- renders custom user data into the image - zr_font_bake_convert -- converts the baked image from alpha8 to rgba8 - - font functions - zr_font_init -- initilizes the font - zr_font_ref -- create a user font out of the font - zr_font_find_glyph -- finds and returns a glyph from the font */ typedef zr_size(*zr_text_width_f)(zr_handle, float, const char*, zr_size); typedef void(*zr_query_font_glyph_f)(zr_handle, float, struct zr_user_font_glyph*, - zr_rune codepoint, zr_rune next_codepoint); + zr_rune codepoint, zr_rune next_codepoint); #if ZR_COMPILE_WITH_VERTEX_BUFFER struct zr_user_font_glyph { @@ -1506,9 +533,7 @@ const zr_rune *zr_font_default_glyph_ranges(void); const zr_rune *zr_font_chinese_glyph_ranges(void); const zr_rune *zr_font_cyrillic_glyph_ranges(void); const zr_rune *zr_font_korean_glyph_ranges(void); -/* --------------------------------------------------------------- - * BAKING - * ---------------------------------------------------------------*/ + /* font baking functions (need to be called sequentially top to bottom) */ void zr_font_bake_memory(zr_size *temporary_memory, int *glyph_count, struct zr_font_config*, int count); @@ -1555,8 +580,7 @@ void zr_font_bake(void *image_memory, int image_width, int image_height, */ void zr_font_bake_custom_data(void *img_memory, int img_width, int img_height, struct zr_recti img_dst, const char *texture_data_mask, - int tex_width, int tex_height, - char white, char black); + int tex_width, int tex_height, char white, char black); /* this function bakes custom data in string format with white, black and zero alpha pixels into the font image. The zero alpha pixel is represented as any character beside the black and zero pixel character. @@ -1570,252 +594,217 @@ void zr_font_bake_custom_data(void *img_memory, int img_width, int img_height, Output: - image filled with custom texture data */ -void zr_font_bake_convert(void *out_memory, int img_width, int img_height, - const void *in_memory); -/* this function converts the alpha8 baking input image into a - preallocated rgba8 output image. - Input: - - image pixel size (width, height) - - memory block containing the alpha8 image - Output: - - rgba8 output image -*/ -/* --------------------------------------------------------------- - * FONT - * ---------------------------------------------------------------*/ -void zr_font_init(struct zr_font*, float pixel_height, - zr_rune fallback_codepoint, struct zr_font_glyph*, - const struct zr_baked_font*, zr_handle atlas); -/* this function initializes a font. IMPORTANT: The font only references - * its glyphs since it allows to have multible font glyph in one big array. - Input: - - pixel height of the font can be different than the baked font height - - unicode fallback codepoint for a glyph that will be used if a glyph is requested - that does not exist in the font - - glyph array of all glyphs inside the font - - number of glyphs inside the glyph array - - font information for this font from the baking process - - handle to the baked font image atlas -*/ +void zr_font_bake_convert(void *out_memory, int image_width, int image_height, const void *in_memory); +/* this function converts the alpha8 baking input image into a preallocated rgba8 output image.*/ +void zr_font_init(struct zr_font*, float pixel_height, zr_rune fallback_codepoint, + struct zr_font_glyph*, const struct zr_baked_font*, zr_handle atlas); struct zr_user_font zr_font_ref(struct zr_font*); -/* this function - Output: - - gui font handle used in the library -*/ const struct zr_font_glyph* zr_font_find_glyph(struct zr_font*, zr_rune unicode); -/* this function - Input: - - unicode glyph codepoint of the glyph - Output: - - either the glyph with the given codepoint or a fallback glyph if does not exist -*/ + #endif -/* - * =============================================================== +/* =============================================================== * - * EDIT BOX - * - * =============================================================== - */ -/* EDIT BOX - ---------------------------- - The Editbox is for text input with either a fixed or dynamically growing - buffer. It extends the basic functionality of basic input over `zr_edit` - and `zr_edit_filtered` with basic copy and paste functionality and the possiblity - to use a extending buffer. - - USAGE - ---------------------------- - The Editbox first needs to be initialized either with a fixed size - memory block or a allocator. After that it can be used by either the - `zr_editobx` or `zr_editbox` function. In addition symbols can be - added and removed with `zr_edit_box_add` and `zr_edit_box_remove`. - - Widget function API - zr_edit_box_init -- initialize a dynamically growing edit box - zr_edit_box_init_fixed -- initialize a fixed size edit box - zr_edit_box_reset -- resets the edit box back to the beginning - zr_edit_box_clear -- frees all memory of a dynamic edit box - zr_edit_box_add -- adds a symbol to the editbox - zr_edit_box_remove -- removes a symbol from the editbox - zr_edit_box_get -- returns the string inside the editbox - zr_edit_box_get_const -- returns the const string inside the editbox - zr_edit_box_free -- frees all memory in a dynamic editbox - zr_edit_box_info -- fills a memory info struct with data - zr_edit_box_at -- returns the glyph at the given position - zr_edit_box_at_cursor -- returns the glyph at the cursor position - zr_edit_box_at_char -- returns the char at the given position - zr_edit_box_set_cursor -- sets the cursor to a given glyph - zr_edit_box_get_cursor -- returns the position of the cursor - zr_edit_box_len_char -- returns the length of the string in bytes - zr_edit_box_len -- returns the length of the string in glyphs -*/ -typedef int(*zr_filter)(zr_rune unicode); -typedef void(*zr_paste_f)(zr_handle, struct zr_edit_box*); -typedef void(*zr_copy_f)(zr_handle, const char*, zr_size size); - -struct zr_clipboard { - zr_handle userdata; - /* user memory for callback */ - zr_paste_f paste; - /* paste callback for the edit box */ - zr_copy_f copy; - /* copy callback for the edit box */ -}; - -struct zr_selection { - int active; - /* current selection state */ - zr_size begin; - /* text selection beginning glyph index */ - zr_size end; - /* text selection ending glyph index */ -}; - -typedef struct zr_buffer zr_edit_buffer; -struct zr_edit_box { - zr_edit_buffer buffer; - /* glyph buffer to add text into */ - int active; - /* flag indicating if the buffer is currently being modified */ - zr_size cursor; - /* current glyph (not byte) cursor position */ - zr_size glyphs; - /* number of glyphs inside the edit box */ - struct zr_clipboard clip; - /* copy paste callbacks */ - zr_filter filter; - /* input filter callback */ - struct zr_selection sel; - /* text selection */ - float scrollbar; - /* edit field scrollbar */ - int text_inserted; -}; - -/* filter function */ -int zr_filter_default(zr_rune unicode); -int zr_filter_ascii(zr_rune unicode); -int zr_filter_float(zr_rune unicode); -int zr_filter_decimal(zr_rune unicode); -int zr_filter_hex(zr_rune unicode); -int zr_filter_oct(zr_rune unicode); -int zr_filter_binary(zr_rune unicode); - -/* editbox */ -void zr_edit_box_init(struct zr_edit_box*, struct zr_allocator*, zr_size initial, - float grow_fac, const struct zr_clipboard*, zr_filter); -/* this function initializes the editbox a growing buffer - Input: - - allocator implementation - - initital buffer size - - buffer growing factor - - clipboard implementation for copy&paste or NULL of not needed - - character filtering callback to limit input or NULL of not needed -*/ -void zr_edit_box_init_fixed(struct zr_edit_box*, void *memory, zr_size size, - const struct zr_clipboard*, zr_filter); -/* this function initializes the editbox a static buffer - Input: - - memory block to fill - - sizeo of the memory block - - clipboard implementation for copy&paste or NULL of not needed - - character filtering callback to limit input or NULL of not needed -*/ -void zr_edit_box_clear(struct zr_edit_box*); -/* this function resets the buffer and sets everything back into a clean state */ -void zr_edit_box_free(struct zr_edit_box*); -/* this function frees all internal memory in a dynamically growing buffer */ -void zr_edit_box_info(struct zr_memory_status*, struct zr_edit_box*); -/* this function returns information about the memory in use */ -void zr_edit_box_add(struct zr_edit_box*, const char*, zr_size); -/* this function adds text at the current cursor position - Input: - - string buffer or glyph to copy/add to the buffer - - length of the string buffer or glyph -*/ -void zr_edit_box_remove(struct zr_edit_box*); -/* removes the glyph at the current cursor position */ -char *zr_edit_box_get(struct zr_edit_box*); -/* returns the string buffer inside the edit box */ -const char *zr_edit_box_get_const(struct zr_edit_box*); -/* returns the constant string buffer inside the edit box */ -void zr_edit_box_at(struct zr_edit_box*, zr_size pos, zr_glyph, zr_size*); -/* this function returns the glyph at a given offset - Input: - - glyph offset inside the buffer - Output: - - utf8 glyph at the given position - - byte length of the glyph -*/ -void zr_edit_box_at_cursor(struct zr_edit_box*, zr_glyph, zr_size*); -/* this function returns the glyph at the cursor - Output: - - utf8 glyph at the cursor position - - byte length of the glyph -*/ -char zr_edit_box_at_char(struct zr_edit_box*, zr_size pos); -/* this function returns the character at a given byte position - Input: - - character offset inside the buffer - Output: - - character at the given position -*/ -void zr_edit_box_set_cursor(struct zr_edit_box*, zr_size pos); -/* this function sets the cursor at a given glyph position - Input: - - glyph offset inside the buffer -*/ -zr_size zr_edit_box_get_cursor(struct zr_edit_box *eb); -/* this function returns the cursor glyph position - Output: - - cursor glyph offset inside the buffer -*/ -zr_size zr_edit_box_len_char(struct zr_edit_box*); -/* this function returns length of the buffer in bytes - Output: - - string buffer byte length -*/ -zr_size zr_edit_box_len(struct zr_edit_box*); -/* this function returns length of the buffer in glyphs - Output: - - string buffer glyph length -*/ -/* ============================================================== - * - * STYLE + * CANVAS * * ===============================================================*/ -/* STYLE - ---------------------------- - The window style consists of properties, color and rectangle rounding - information that is used for the general style and looks of window. - In addition for temporary modification the configuration structure consists - of a stack for pushing and pop either color or property values. +enum zr_command_type { + ZR_COMMAND_NOP, + ZR_COMMAND_SCISSOR, + ZR_COMMAND_LINE, + ZR_COMMAND_CURVE, + ZR_COMMAND_RECT, + ZR_COMMAND_CIRCLE, + ZR_COMMAND_ARC, + ZR_COMMAND_TRIANGLE, + ZR_COMMAND_TEXT, + ZR_COMMAND_IMAGE +}; - USAGE - ---------------------------- - To use the configuration file you either initialize every value yourself besides - the internal stack which needs to be initialized to zero or use the default - configuration by calling the function zr_config_default. - To add and remove temporary configuration states the zr_config_push_xxxx - for adding and zr_config_pop_xxxx for removing either color or property values - from the stack. To reset all previously modified values the zr_config_reset_xxx - were added. +/* command base and header of every comand inside the buffer */ +struct zr_command { + enum zr_command_type type; + /* the type of the current command */ + zr_size next; + /* absolute base pointer offset to the next command */ +}; - Configuration function API - zr_style_default -- initializes a default style - zr_style_set_font -- changes the used font - zr_style_property -- returns the property value from an id - zr_style_color -- returns the color value from an id - zr_style_push_property -- push old property onto stack and sets a new value - zr_style_push_color -- push old color onto stack and sets a new value - zr_style_pop_color -- resets an old color value from the internal stack - zr_style_pop_property -- resets an old property value from the internal stack - zr_style_reset_colors -- reverts back all temporary color changes from the style - zr_style_reset_properties -- reverts back all temporary property changes - zr_style_reset -- reverts back all temporary all changes from the config -*/ +struct zr_command_scissor { + struct zr_command header; + short x, y; + unsigned short w, h; +}; + +struct zr_command_line { + struct zr_command header; + struct zr_vec2i begin; + struct zr_vec2i end; + struct zr_color color; +}; + +struct zr_command_curve { + struct zr_command header; + struct zr_vec2i begin; + struct zr_vec2i end; + struct zr_vec2i ctrl[2]; + struct zr_color color; +}; + +struct zr_command_rect { + struct zr_command header; + unsigned int rounding; + short x, y; + unsigned short w, h; + struct zr_color color; +}; + +struct zr_command_circle { + struct zr_command header; + short x, y; + unsigned short w, h; + struct zr_color color; +}; + +struct zr_command_arc { + struct zr_command header; + short cx, cy; + unsigned short r; + float a[2]; + struct zr_color color; +}; + +struct zr_command_triangle { + struct zr_command header; + struct zr_vec2i a; + struct zr_vec2i b; + struct zr_vec2i c; + struct zr_color color; +}; + +struct zr_command_image { + struct zr_command header; + short x, y; + unsigned short w, h; + struct zr_image img; +}; + +struct zr_command_text { + struct zr_command header; + const struct zr_user_font *font; + struct zr_color background; + struct zr_color foreground; + short x, y; + unsigned short w, h; + float height; + zr_size length; + char string[1]; +}; + +enum zr_command_clipping { + ZR_CLIPPING_OFF = zr_false, + ZR_CLIPPING_ON = zr_true +}; + +struct zr_command_buffer { + struct zr_buffer *base; + /* memory buffer to store the command */ + struct zr_rect clip; + /* current clipping rectangle */ + int use_clipping; + /* flag if the command buffer should clip commands */ + zr_size begin, end, last; +}; + +#if ZR_COMPILE_WITH_VERTEX_BUFFER +typedef unsigned short zr_draw_index; +typedef zr_uint zr_draw_vertex_color; + +enum zr_anti_aliasing { + ZR_ANTI_ALIASING_OFF = zr_false, + /* renderes all primitives without anti-aliasing */ + ZR_ANTI_ALIASING_ON + /* renderes all primitives with anti-aliasing */ +}; + +struct zr_draw_vertex { + struct zr_vec2 position; + struct zr_vec2 uv; + zr_draw_vertex_color col; +}; + +enum zr_draw_list_stroke { + ZR_STROKE_OPEN = zr_false, + /* build up path has no connection back to the beginning */ + ZR_STROKE_CLOSED = zr_true + /* build up path has a connection back to the beginning */ +}; + +struct zr_draw_command { + unsigned int elem_count; + /* number of elements in the current draw batch */ + struct zr_rect clip_rect; + /* current screen clipping rectangle */ + zr_handle texture; + /* current texture to set */ +}; + +struct zr_draw_null_texture { + zr_handle texture; + /* texture handle to a texture with a white pixel */ + struct zr_vec2 uv; + /* coordinates to the white pixel in the texture */ +}; + +struct zr_canvas { + enum zr_anti_aliasing AA; + /* flag indicating if anti-aliasing should be used to render primtives */ + struct zr_draw_null_texture null; + /* texture with white pixel for easy primitive drawing */ + struct zr_rect clip_rect; + /* current clipping rectangle */ + zr_cos_f cos; zr_sin_f sin; + /* cosine/sine calculation callback since this library does not use libc */ + struct zr_buffer *buffer; + /* buffer to store draw commands and temporarily store path */ + struct zr_buffer *vertexes; + /* buffer to store each draw vertex */ + struct zr_buffer *elements; + /* buffer to store each draw element index */ + unsigned int element_count; + /* total number of elements inside the elements buffer */ + unsigned int vertex_count; + /* total number of vertexes inside the vertex buffer */ + zr_size cmd_offset; + /* offset to the first command in the buffer */ + unsigned int cmd_count; + /* number of commands inside the buffer */ + unsigned int path_count; + /* current number of points inside the path */ + unsigned int path_offset; + /* offset to the first point in the buffer */ + struct zr_vec2 circle_vtx[12]; + /* small lookup table for fast circle drawing */ +}; + +#endif + +/* drawing routines */ +#define zr_command(t, c) ((const struct zr_command_##t*)c) +void zr_draw_scissor(struct zr_command_buffer*, struct zr_rect); +void zr_draw_line(struct zr_command_buffer*, float, float, float, float, struct zr_color); +void zr_draw_curve(struct zr_command_buffer*, float, float, float, float, float, float, + float, float, struct zr_color); +void zr_draw_rect(struct zr_command_buffer*, struct zr_rect, float rounding, struct zr_color); +void zr_draw_circle(struct zr_command_buffer*, struct zr_rect, struct zr_color c); +void zr_draw_arc(struct zr_command_buffer*, float cx, float cy, float radius, float a_min, + float a_max, struct zr_color); +void zr_draw_triangle(struct zr_command_buffer*, float, float, float, float, float, float, struct zr_color); +void zr_draw_image(struct zr_command_buffer*, struct zr_rect, struct zr_image*); +void zr_draw_text(struct zr_command_buffer*, struct zr_rect, const char*, zr_size, + const struct zr_user_font*, struct zr_color, struct zr_color); + +/* ============================================================== + * STYLE + * ===============================================================*/ enum zr_style_colors { ZR_COLOR_TEXT, ZR_COLOR_TEXT_HOVERING, @@ -1849,7 +838,6 @@ enum zr_style_colors { ZR_COLOR_COMBO, ZR_COLOR_HISTO, ZR_COLOR_HISTO_BARS, - ZR_COLOR_HISTO_NEGATIVE, ZR_COLOR_HISTO_HIGHLIGHT, ZR_COLOR_PLOT, ZR_COLOR_PLOT_LINES, @@ -1891,6 +879,17 @@ enum zr_style_header_align { ZR_HEADER_RIGHT }; +enum zr_style_components { + ZR_DEFAULT_COLOR = 0x01, + /* default all colors inside the configuration struct */ + ZR_DEFAULT_PROPERTIES = 0x02, + /* default all properites inside the configuration struct */ + ZR_DEFAULT_ROUNDING = 0x04, + /* default all rounding values inside the configuration struct */ + ZR_DEFAULT_ALL = 0xFFFF + /* default the complete configuration struct */ +}; + struct zr_saved_property { enum zr_style_properties type; /* identifier of the current modified property */ @@ -1908,37 +907,26 @@ struct zr_saved_color { struct zr_saved_font { struct zr_user_font value; /* user font reference */ - zr_size font_height_begin; + int font_height_begin; /* style font height stack begin */ - zr_size font_height_end; + int font_height_end; /* user font height stack end */ }; -enum zr_style_components { - ZR_DEFAULT_COLOR = 0x01, - /* default all colors inside the configuration struct */ - ZR_DEFAULT_PROPERTIES = 0x02, - /* default all properites inside the configuration struct */ - ZR_DEFAULT_ROUNDING = 0x04, - /* default all rounding values inside the configuration struct */ - ZR_DEFAULT_ALL = 0xFFFF - /* default the complete configuration struct */ -}; - struct zr_style_mod_stack { zr_size property; /* current property stack pushing index */ struct zr_saved_property properties[ZR_MAX_ATTRIB_STACK]; /* saved property stack */ - zr_size color; + int color; /* current color stack pushing index */ struct zr_saved_color colors[ZR_MAX_COLOR_STACK]; /* saved color stack */ - zr_size font; + int font; /* current font stack pushing index */ struct zr_saved_font fonts[ZR_MAX_FONT_STACK]; /* saved user font stack */ - zr_size font_height; + int font_height; /* current font stack pushing index */ float font_heights[ZR_MAX_FONT_HEIGHT_STACK]; /* saved user font stack */ @@ -1970,160 +958,256 @@ struct zr_style { /* modification stack */ }; +/* style setup and access */ +struct zr_style; void zr_style_default(struct zr_style*, zr_flags, const struct zr_user_font*); -/* this function load the window configuration with default values - Input: - - config flags which part of the configuration should be loaded with default values - - user font reference structure describing the font used inside the window - Output: - - configuration structure holding the default window style -*/ void zr_style_set_font(struct zr_style*, const struct zr_user_font*); -/* this function changes the used font and can be used even inside a frame - Input: - - user font reference structure describing the font used inside the window -*/ -struct zr_vec2 zr_style_property(const struct zr_style*, - enum zr_style_properties); -/* this function accesses a configuration property over an identifier - Input: - - Configuration the get the property from - - Configuration property idenfifier describing the property to get - Output: - - Property value that has been asked for -*/ +struct zr_vec2 zr_style_property(const struct zr_style*, enum zr_style_properties); struct zr_color zr_style_color(const struct zr_style*, enum zr_style_colors); -/* this function accesses a configuration color over an identifier - Input: - - Configuration the get the color from - - Configuration color idenfifier describing the color to get - Output: - - color value that has been asked for -*/ + +/* temporarily modify a style value and save the old value in a stack*/ void zr_style_push_property(struct zr_style*, enum zr_style_properties, struct zr_vec2); -/* this function temporarily changes a property in a stack to be reseted later - Input: - - Configuration structure to push the change to - - Property idenfifier to change - - new value of the property -*/ void zr_style_push_color(struct zr_style*, enum zr_style_colors, struct zr_color); -/* this function temporarily changes a color in a stack like fashion to be reseted later - Input: - - Configuration structure to push the change to - - color idenfifier to change - - new color -*/ void zr_style_push_font(struct zr_style*, struct zr_user_font font); -/* this function temporarily changes the used font in a stack like fashion to be reseted later - Input: - - Configuration structure to push the change to - - user font to use from now on -*/ void zr_style_push_font_height(struct zr_style*, float font_height); -/* this function temporarily changes the used font in a stack like fashion to be reseted later - Input: - - Configuration structure to push the change to - - user font to use from now on -*/ + +/* restores a previously saved style value */ void zr_style_pop_color(struct zr_style*); -/* this function reverts back a previously pushed temporary color change - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_pop_property(struct zr_style*); -/* this function reverts back a previously pushed temporary property change - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_pop_font(struct zr_style*); -/* this function reverts back a previously pushed temporary font change - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_pop_font_height(struct zr_style*); -/* this function reverts back a previously pushed temporary font height change - Input: - - Configuration structure to pop the change from and to -*/ + +/* resets the style back into the beginning state */ void zr_style_reset_colors(struct zr_style*); -/* this function reverts back all previously pushed temporary color changes - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_reset_properties(struct zr_style*); -/* this function reverts back all previously pushed temporary color changes - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_reset_font(struct zr_style*); -/* this function reverts back all previously pushed temporary font changes - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_reset_font_height(struct zr_style*); -/* this function reverts back all previously pushed temporary font height changes - Input: - - Configuration structure to pop the change from and to -*/ void zr_style_reset(struct zr_style*); -/* this function reverts back all previously pushed temporary color and - * property changes - Input: - - Configuration structure to pop the change from and to -*/ + +/* return string representation of different styles values */ const char *zr_style_color_name(enum zr_style_colors); -/* this function returns the string name of a given color type */ const char *zr_style_rounding_name(enum zr_style_rounding); -/* this function returns the string name of a given rounding type */ const char *zr_style_property_name(enum zr_style_properties); -/* this function returns the string name of a given property type */ + +/*=============================================================== + * EDIT BOX + * ===============================================================*/ +typedef int(*zr_filter)(zr_rune unicode); +typedef void(*zr_paste_f)(zr_handle, struct zr_edit_box*); +typedef void(*zr_copy_f)(zr_handle, const char*, zr_size size); + +/* filter function */ +int zr_filter_default(zr_rune unicode); +int zr_filter_ascii(zr_rune unicode); +int zr_filter_float(zr_rune unicode); +int zr_filter_decimal(zr_rune unicode); +int zr_filter_hex(zr_rune unicode); +int zr_filter_oct(zr_rune unicode); +int zr_filter_binary(zr_rune unicode); + +/* editbox */ +struct zr_edit_box; +void zr_edit_box_clear(struct zr_edit_box*); +void zr_edit_box_add(struct zr_edit_box*, const char*, zr_size); +void zr_edit_box_remove(struct zr_edit_box*); +char *zr_edit_box_get(struct zr_edit_box*); +const char *zr_edit_box_get_const(struct zr_edit_box*); +void zr_edit_box_at(struct zr_edit_box*, zr_size pos, zr_glyph, zr_size*); +void zr_edit_box_at_cursor(struct zr_edit_box*, zr_glyph, zr_size*); +char zr_edit_box_at_char(struct zr_edit_box*, zr_size pos); +void zr_edit_box_set_cursor(struct zr_edit_box*, zr_size pos); +zr_size zr_edit_box_get_cursor(struct zr_edit_box *eb); +zr_size zr_edit_box_len_char(struct zr_edit_box*); +zr_size zr_edit_box_len(struct zr_edit_box*); /*============================================================== * - * WINDOW + * GUI * - * ============================================================= - WINDOW - The window groups widgets together and allows collective operation - on these widgets like movement, scrolling, window minimizing and closing. - Windows are divided into a persistent state window struct and a temporary - context which is used each frame to fill the window. All direct build up - function therefore work on the context and not on the actual window. - Each window is linked inside a queue which in term allows for an easy - way to buffer output commands but requires that the window is unlinked - from the queue if removed. - - USAGE - The window needs to be initialized by `zr_window_init` and can be updated - by all the `zr_window_set_xxx` function. Important to note is that each - window is linked inside a queue by an internal memory buffer. So if you want - to remove the window you first have to remove the window from the queue - or if you want to change to queue use `zr_window_queue_set`. - - window function API - ------------------ - zr_window_init -- initializes the window with position, size and flags - zr_window_unlink -- remove the window from the command queue - zr_window_link -- links a previously unlinked window into a command queue - zr_window_set_config -- updates the used window configuration - zr_window_add_flag -- adds a behavior flag to the window - zr_window_remove_flag -- removes a behavior flag from the window - zr_window_has_flag -- check if a given behavior flag is set in the window - zr_window_is_minimized -- return wether the window is minimized - - APIs - ----------------- - Window Context API -- The context is temporary state that is used every frame to build a window - Window Header API -- Responsible for creating a header at the top of a window - Window Layout API -- The window layout is responsible for placing widget in the window - Window Widget API -- Different widget that can be placed inside the window - Window Combobox API -- Combobox widget for collapsable popup content - Window Group API -- Create a subwindow inside a window which again can be filled with widgets - Window Popup API -- Popup window with either non-blocking or blocking capabilities - Window Menu API -- Popup menus with currently one single depth -*/ + * =============================================================*/ +#define ZR_UNDEFINED (-1.0f) #define ZR_FLAG(x) (1 << (x)) + +enum zr_modify { + ZR_FIXED = zr_false, + ZR_MODIFIABLE = zr_true +}; + +enum zr_symbol { + ZR_SYMBOL_X, + ZR_SYMBOL_UNDERSCORE, + ZR_SYMBOL_CIRCLE, + ZR_SYMBOL_CIRCLE_FILLED, + ZR_SYMBOL_RECT, + ZR_SYMBOL_RECT_FILLED, + ZR_SYMBOL_TRIANGLE_UP, + ZR_SYMBOL_TRIANGLE_DOWN, + ZR_SYMBOL_TRIANGLE_LEFT, + ZR_SYMBOL_TRIANGLE_RIGHT, + ZR_SYMBOL_PLUS, + ZR_SYMBOL_MINUS, + ZR_SYMBOL_MAX +}; + +struct zr_clipboard { + zr_handle userdata; + /* user memory for callback */ + zr_paste_f paste; + /* paste callback for the edit box */ + zr_copy_f copy; + /* copy callback for the edit box */ +}; + +enum zr_widget_status { + ZR_INACTIVE, + ZR_HOVERED, + ZR_ACTIVE +}; + +enum zr_collapse_states { + ZR_MINIMIZED = zr_false, + ZR_MAXIMIZED = zr_true +}; + +enum zr_widget_state { + ZR_WIDGET_INVALID, + /* The widget cannot be seen and is completly out of view */ + ZR_WIDGET_VALID, + /* The widget is completly inside the window can be updated */ + ZR_WIDGET_ROM + /* The widget is partially visible and cannot be updated */ +}; + +enum zr_text_align { + ZR_TEXT_LEFT, + /* text is aligned on the left */ + ZR_TEXT_CENTERED, + /* text is aligned in the center */ + ZR_TEXT_RIGHT + /* text is aligned on the right */ +}; + +enum zr_button_behavior { + ZR_BUTTON_DEFAULT, + /* default push button behavior */ + ZR_BUTTON_REPEATER + /* repeater behavior will trigger as long as button is down */ +}; + +enum zr_edit_flags { + ZR_EDIT_READ_ONLY = ZR_FLAG(0), + ZR_EDIT_CURSOR = ZR_FLAG(1), + ZR_EDIT_SELECTABLE = ZR_FLAG(2), + ZR_EDIT_CLIPBOARD = ZR_FLAG(3), + ZR_EDIT_MULTILINE = ZR_FLAG(4) +}; + +enum zr_edit_types { + ZR_EDIT_SIMPLE = 0, + ZR_EDIT_FIELD = (ZR_EDIT_CURSOR|ZR_EDIT_SELECTABLE|ZR_EDIT_CLIPBOARD), + ZR_EDIT_BOX = (ZR_EDIT_CURSOR|ZR_EDIT_SELECTABLE|ZR_EDIT_CLIPBOARD|ZR_EDIT_MULTILINE) +}; + +enum zr_graph_type { + ZR_GRAPH_LINES, + /* Line graph with each data point being connected with its previous and next node */ + ZR_GRAPH_COLUMN, + /* Column graph/Histogram with value represented as bars */ + ZR_GRAPH_MAX +}; + +enum zr_graph_event { + ZR_GRAPH_HOVERING = 0x01, + /* mouse hoveres over current value */ + ZR_GRAPH_CLICKED = 0x02 + /* mouse click on current value */ +}; + +enum zr_popup_type { + ZR_POPUP_STATIC, + /* static fixed height non growing popup */ + ZR_POPUP_DYNAMIC + /* dynamically growing popup with maximum height */ +}; + +enum zr_layout_format { + ZR_DYNAMIC, /* row layout which scales with the window */ + ZR_STATIC /* row layout with fixed pixel width */ +}; + +enum zr_layout_node_type { + ZR_LAYOUT_NODE, + /* a node is a space which can be minimized or maximized */ + ZR_LAYOUT_TAB + /* a tab is a node with a header */ +}; + +struct zr_graph { + enum zr_graph_type type; + /* graph type with either line or column graph */ + float x, y; + /* graph canvas space position */ + float w, h; + /* graph canvas space size */ + float min, max, range; + /* min and max value for correct scaling of values */ + struct zr_vec2 last; + /* last line graph point to connect to. Only used by the line graph */ + zr_size index; + /* current graph value index*/ + zr_size count; + /* number of values inside the graph */ +}; + +enum zr_row_layout_type { + ZR_LAYOUT_DYNAMIC_FIXED, + /* fixed widget ratio width window layout */ + ZR_LAYOUT_DYNAMIC_ROW, + /* immediate mode widget specific widget width ratio layout */ + ZR_LAYOUT_DYNAMIC_FREE, + /* free ratio based placing of widget in a local space */ + ZR_LAYOUT_DYNAMIC, + /* retain mode widget specific widget ratio width*/ + ZR_LAYOUT_STATIC_FIXED, + /* fixed widget pixel width window layout */ + ZR_LAYOUT_STATIC_ROW, + /* immediate mode widget specific widget pixel width layout */ + ZR_LAYOUT_STATIC_FREE, + /* free pixel based placing of widget in a local space */ + ZR_LAYOUT_STATIC + /* retain mode widget specific widget pixel width layout */ +}; + +struct zr_row_layout { + enum zr_row_layout_type type; + /* type of the row layout */ + zr_size index; + /* index of the current widget in the current window row */ + float height; + /* height of the current row */ + zr_size columns; + /* number of columns in the current row */ + const float *ratio; + /* row widget width ratio */ + float item_width, item_height; + /* current width of very item */ + float item_offset; + /* x positon offset of the current item */ + float filled; + /* total fill ratio */ + struct zr_rect item; + /* item bounds */ + struct zr_rect clip; + /* temporary clipping rect */ +}; + +struct zr_menu { + float x, y, w, h; + /* menu bounds */ + struct zr_scroll offset; + /* saved window scrollbar offset */ +}; + enum zr_window_flags { ZR_WINDOW_HIDDEN = ZR_FLAG(0), /* Hiddes the window and stops any window interaction and drawing can be set @@ -2152,187 +1236,29 @@ enum zr_window_flags { * used to create perfectly fitting windows as well */ ZR_WINDOW_NO_SCROLLBAR = ZR_FLAG(10), /* Removes the scrollbar from the window */ - ZR_WINDOW_ACTIVE = ZR_FLAG(11), - /* INTERNAL ONLY!: marks the window as active, used by the window stack */ - ZR_WINDOW_TAB = ZR_FLAG(12), - /* INTERNAL ONLY!: marks the window as subwindow of another window(Groups/Tabs)*/ - ZR_WINDOW_COMBO_MENU = ZR_FLAG(13), - /* INTERNAL ONLY!: marks the window as a combo box or menu */ - ZR_WINDOW_REMOVE_ROM = ZR_FLAG(14) - /* INTERNAL ONLY!: removes the read only mode at the end of the window */ + ZR_WINDOW_TITLE = ZR_FLAG(11) + /* Removes the scrollbar from the window */ }; -struct zr_value { - int active, prev; - char buffer[ZR_MAX_NUMBER_BUFFER]; - zr_size length; - zr_size cursor; - zr_ulong name; - unsigned int seq; - unsigned int old; - int state; +struct zr_popup_buffer { + zr_size begin; + /* begin of the subbuffer */ + zr_size parent; + /* last entry before the sub buffer*/ + zr_size last; + /* last entry in the sub buffer*/ + zr_size end; + /* end of the subbuffer */ + int active; }; -struct zr_window { - struct zr_rect bounds; - /* size with width and height and position of the window */ - zr_flags flags; - /* window flags modifing its behavior */ - struct zr_vec2 offset; - /* scrollbar x- and y-offset */ - struct zr_style *style; - /* configuration reference describing the window style */ - struct zr_command_buffer buffer; - /* output command buffer queuing all drawing calls */ - struct zr_command_queue *queue; - /* output command queue which hold the command buffer */ - struct zr_input *input; - /* input state for updating the window and all its widgets */ - struct zr_value property; - /* currently active property */ -}; - -void zr_window_init(struct zr_window*, struct zr_rect bounds, zr_flags flags, - struct zr_command_queue*, struct zr_style*, - struct zr_input *in); -/* this function initilizes and setups the window - Input: - - bounds of the window with x,y position and width and height - - window flags for modified window behavior - - reference to a output command queue to push draw calls into - - configuration file containing the style, color and font for the window - Output: - - a newly initialized window -*/ -void zr_window_unlink(struct zr_window*); -/* this function unlinks the window from its queue */ -void zr_window_link(struct zr_window*, struct zr_command_queue*); -/* this function links a previously unlinked the window into a queue */ -void zr_window_add_flag(struct zr_window*, zr_flags); -/* this function adds window flags to the window */ -void zr_window_remove_flag(struct zr_window*, zr_flags); -/* this function removes window flags from the window */ -int zr_window_has_flag(struct zr_window*, zr_flags); -/* this function checks if a window has given flag(s) */ -int zr_window_is_minimized(struct zr_window*); -/* this function checks if the window is minimized */ -/* -------------------------------------------------------------- - * - * CONTEXT - * - * -------------------------------------------------------------- - CONTEXT - The context is temporary window state that is used in the window drawing - and build up process. The reason the window and context are divided is that - the context has far more state which is not needed outside of the build up - phase. The context is not only useful for normal windows. It is used for - more complex widget or layout as well. This includes a window inside a window, - popup windows, menus, comboboxes, etc. In each case the context allows to - fill a space with widgets. Therefore the context provides the base - and key stone of the flexibility in the library. The context is used - for all APIs for the window. - - USAGE - The context from a window is created by `zr_begin` and finilized by - `zr_end`. Between these two sequence points the context can be used - to setup the window with widgets. Other widgets which also use a context - have each their own `zr_xxx_begin` and `zr_xxx_end` function pair and act - the same as a window context. - - context function API - ------------------ - zr_begin -- starts the window build up process by filling a context with window state - zr_end -- ends the window build up process and update the window state - zr_canvas -- returns the currently used drawing command buffer - zr_input -- returns the from the context used input struct - zr_queue -- returns the queue of the window - zr_space -- returns the drawable space inside the window -*/ -enum zr_orientation { - ZR_VERTICAL, - ZR_HORIZONTAL -}; - -enum zr_widget_states { - ZR_INACTIVE, - ZR_HOVERED, - ZR_ACTIVE -}; - -enum zr_collapse_states { - ZR_MINIMIZED = zr_false, - ZR_MAXIMIZED = zr_true -}; - -enum zr_widget_state { - ZR_WIDGET_INVALID, - /* The widget cannot be seen and is completly out of view */ - ZR_WIDGET_VALID, - /* The widget is completly inside the window can be updated */ - ZR_WIDGET_ROM - /* The widget is partially visible and cannot be updated */ -}; - -enum zr_row_layout_type { - /* INTERNAL */ - ZR_LAYOUT_DYNAMIC_FIXED, - /* fixed widget ratio width window layout */ - ZR_LAYOUT_DYNAMIC_ROW, - /* immediate mode widget specific widget width ratio layout */ - ZR_LAYOUT_DYNAMIC_FREE, - /* free ratio based placing of widget in a local space */ - ZR_LAYOUT_DYNAMIC, - /* retain mode widget specific widget ratio width*/ - ZR_LAYOUT_STATIC_FIXED, - /* fixed widget pixel width window layout */ - ZR_LAYOUT_STATIC_ROW, - /* immediate mode widget specific widget pixel width layout */ - ZR_LAYOUT_STATIC_FREE, - /* free pixel based placing of widget in a local space */ - ZR_LAYOUT_STATIC - /* retain mode widget specific widget pixel width layout */ -}; - -#define ZR_UNDEFINED (-1.0f) -struct zr_row_layout { - enum zr_row_layout_type type; - /* type of the row layout */ - zr_size index; - /* index of the current widget in the current window row */ - float height; - /* height of the current row */ - zr_size columns; - /* number of columns in the current row */ - const float *ratio; - /* row widget width ratio */ - float item_width, item_height; - /* current width of very item */ - float item_offset; - /* x positon offset of the current item */ - float filled; - /* total fill ratio */ - struct zr_rect item; - /* item bounds */ - struct zr_rect clip; - /* temporary clipping rect */ -}; - -struct zr_menu { - float x, y, w, h; - /* menu bounds */ - struct zr_vec2 offset; - /* saved window scrollbar offset */ -}; - -struct zr_context { +struct zr_layout { zr_flags flags; /* window flags modifing its behavior */ struct zr_rect bounds; /* position and size of the window in the os window */ - struct zr_vec2 offset; + struct zr_scroll *offset; /* window scrollbar offset */ - int valid; - /* flag inidicating if the window is visible */ float at_x, at_y, max_x; /* index position of the current widget row and column */ float width, height; @@ -2347,1099 +1273,242 @@ struct zr_context { /* window menubar bounds */ struct zr_row_layout row; /* currently used window row layout */ - struct zr_style *style; - /* configuration data describing the visual style of the window */ - struct zr_input *input; - /* current input state for updating the window and all its widgets */ + struct zr_graph graph; + /* graph state */ + struct zr_popup_buffer popup_buffer; + /* output command buffer queuing all popup drawing calls */ struct zr_command_buffer *buffer; - /* command draw call output command buffer */ - struct zr_command_queue *queue; - /* command draw call output command buffer */ - struct zr_value *property; - /* currently active property */ + struct zr_layout *parent; }; -zr_flags zr_begin(struct zr_context*, struct zr_window*, const char *title); -/* this function begins the window build up process by creating a context to fill - Input: - - input structure holding all user generated state changes - Output: - - window context to fill up with widgets - - flags : - o ZR_WINDOW_MOVABLE if window was moved - o ZR_WINDOW_MINIMIZABLE if window was minimized/maximized - o ZR_WINDOW_CLOSEABLE if window was closed -*/ -zr_flags zr_end(struct zr_context*, struct zr_window*); -/* this function ends the window layout build up process and updates the window. - Output: - - ZR_WINDOW_SCALEABLE if window was scaled -*/ -struct zr_rect zr_space(struct zr_context*); -/* this function returns the drawable space inside the window */ -struct zr_command_buffer* zr_canvas(struct zr_context*); -/* this functions returns the currently used draw command buffer */ -const struct zr_input *zr_input(struct zr_context*); -/* this functions returns the currently used input */ -struct zr_command_queue *zr_queue(struct zr_context*); -/* this functions returns the currently used queue */ +struct zr_context { + unsigned int seq; + struct zr_input input; + struct zr_style style; + struct zr_buffer memory; + struct zr_clipboard clip; + void *pool; -/* -------------------------------------------------------------- - * - * MENUBAR - * - * --------------------------------------------------------------*/ -void zr_menubar_begin(struct zr_context*); -/* this function begins the window menubar build up process */ -void zr_menubar_end(struct zr_context*); -/* this function ends the window menubar build up process */ +#if ZR_COMPILE_WITH_VERTEX_BUFFER + struct zr_canvas canvas; +#endif -/* -------------------------------------------------------------- - * - * LAYOUT - * - * -------------------------------------------------------------- - LAYOUT - The layout API is for positioning of widget inside a window context. In general there - are four different ways to position widget. The first one is a table with - fixed size columns. This like the other three comes in two flavors. First - the scaleable width as a ratio of the window width and the other is a - non-scaleable fixed pixel value for static windows. - Since sometimes widgets with different sizes in a row is needed another set - of row layout has been added. The first set is for dynamically size widgets - in an immediate mode API which sets each size of a widget directly before - it is called or a retain mode API which stores the size of every widget as - an array. - The third way to position widgets is by allocating a fixed space from - the window and directly positioning each widget with position and size. - This requires the least amount of work for the API and the most for the user, - but offers the most positioning freedom. - - fixed width widget layout API - zr_layout_row_dynamic -- scaling fixed column row layout - zr_layout_row_static -- fixed width fixed column row layout - - custom width widget layout API - zr_layout_row -- user defined widget row layout - zr_layout_row_begin -- begins the row build up process - zr_layout_row_push -- pushes the next widget width - zr_layout_row_end -- ends the row build up process - - custom widget placing API - zr_layout_row_space_begin -- creates a free placing space in the window - zr_layout_row_space_push -- pushes a widget into the space - zr_layout_row_space_end -- finishes the free drawingp process - zr_layout_row_space_bounds -- totally allocated space in window - zr_layout_row_space_to_screen -- converts from local space to screen - zr_layout_row_space_to_local -- converts from screen to local space - zr_layout_row_space_rect_to_screen -- converts rect from local space to screen - zr_layout_row_space_rect_to_local -- converts rect from screen to local space - - window tree layout function API - zr_layout_push -- pushes a new node/collapseable header/tab - zr_layout_pop -- pops the the previously added node -*/ -enum zr_layout_format { - ZR_DYNAMIC, /* row layout which scales with the window */ - ZR_STATIC /* row layout with fixed pixel width */ + int build; + struct zr_window *begin; + struct zr_window *end; + struct zr_window *active; + struct zr_window *current; + struct zr_window *freelist; + unsigned int count; }; -enum zr_layout_node_type { - ZR_LAYOUT_NODE, - /* a node is a space which can be minimized or maximized */ - ZR_LAYOUT_TAB - /* a tab is a node with a header */ -}; +/*-------------------------------------------------------------- + * CONTEXT + * -------------------------------------------------------------*/ +int zr_init_fixed(struct zr_context*, void *memory, zr_size size, + const struct zr_user_font*, zr_sin_f, zr_cos_f); +int zr_init_custom(struct zr_context*, struct zr_buffer *cmds, + struct zr_buffer *pool, const struct zr_user_font*, + zr_sin_f, zr_cos_f); +int zr_init(struct zr_context*, struct zr_allocator*, + const struct zr_user_font*, zr_sin_f, zr_cos_f); +void zr_convert(struct zr_context*, struct zr_buffer *cmds, + struct zr_buffer *vertexes, struct zr_buffer *elements, + struct zr_draw_null_texture , enum zr_anti_aliasing, + float line_thickness, unsigned int circle_segment_count); +void zr_clear(struct zr_context*); +void zr_free(struct zr_context*); +/* window */ +int zr_begin(struct zr_context*, struct zr_layout*, const char *title, + struct zr_rect bounds, unsigned int flags); +void zr_end(struct zr_context*); + +struct zr_rect zr_window_get_bounds(const struct zr_context*); +struct zr_vec2 zr_window_get_position(const struct zr_context*); +struct zr_vec2 zr_window_get_size(const struct zr_context*); +float zr_window_get_width(const struct zr_context*); +float zr_window_get_height(const struct zr_context*); +struct zr_rect zr_window_get_content_region(struct zr_context*); +struct zr_vec2 zr_window_get_content_region_min(struct zr_context*); +struct zr_vec2 zr_window_get_content_region_max(struct zr_context*); +struct zr_vec2 zr_window_get_content_region_size(struct zr_context*); +struct zr_command_buffer* zr_window_get_canvas(struct zr_context*); +int zr_window_has_focus(const struct zr_context*); +int zr_window_is_collapsed(struct zr_context*, const char *name); +int zr_window_is_closed(struct zr_context*, const char *name); + +void zr_window_set_bounds(struct zr_context*, struct zr_rect); +void zr_window_set_position(struct zr_context*, struct zr_vec2); +void zr_window_set_size(struct zr_context*, struct zr_vec2); +void zr_window_collapse(struct zr_context *ctx, const char *name, enum zr_collapse_states); +void zr_window_collapse_if(struct zr_context *ctx, const char *name, enum zr_collapse_states, int cond); +void zr_window_set_focus(struct zr_context *ctx, const char *name); + +/* drawing */ +#define zr_foreach(c, ctx) for((c)=zr__begin(ctx); (c)!=0; (c)=zr__next(ctx, c)) +#define zr_draw_foreach(cmd,ctx, b) for((cmd)=zr__draw_begin(ctx, b); (cmd)!=0; (cmd)=zr__draw_next(cmd, b, ctx)) +const struct zr_command* zr__next(struct zr_context*, const struct zr_command*); +const struct zr_command* zr__begin(struct zr_context*); +const struct zr_draw_command* zr__draw_begin(const struct zr_context*, const struct zr_buffer*); +const struct zr_draw_command* zr__draw_next(const struct zr_draw_command*, + const struct zr_buffer*, + const struct zr_context*); + +/*-------------------------------------------------------------- + * Layout + * -------------------------------------------------------------*/ +/* layout query functions */ void zr_layout_peek(struct zr_rect *bounds, struct zr_context*); -/* this function peeks at the next widget position and size that will be - * allocated from the window without actually allocation the space - output: - - widget position and size of the next allocate space in the panel -*/ -/* -------------------------------------------------------------- - * FIXED - * --------------------------------------------------------------*/ + +/* columns based layouting with generated position and width and fixed height*/ void zr_layout_row_dynamic(struct zr_context*, float height, zr_size cols); -/* this function sets the row layout to dynamically fixed size widget - Input: - - height of the row that will be filled - - number of widget inside the row that will divide the space -*/ -void zr_layout_row_static(struct zr_context*, float row_height, - zr_size item_width, zr_size cols); -/* this function sets the row layout to static fixed size widget - Input: - - height of the row that will be filled - - width in pixel measurement of each widget in the row - - number of widget inside the row that will divide the space -*/ -/* -------------------------------------------------------------- - * CUSTOM - * --------------------------------------------------------------*/ +void zr_layout_row_static(struct zr_context*, float height, zr_size item_width, zr_size cols); + +/* widget layouting with custom widget width and fixed height */ void zr_layout_row_begin(struct zr_context*, enum zr_layout_format, float row_height, zr_size cols); -/* this function start a new scaleable row that can be filled with different - sized widget - Input: - - scaleable or fixed row format - - height of the row that will be filled - - number of widget inside the row that will divide the space -*/ void zr_layout_row_push(struct zr_context*, float value); -/* this function pushes a widget into the previously start row with the given - window width ratio or pixel width - Input: - - value with either a ratio for ZR_DYNAMIC or a pixel width for ZR_STATIC layout -*/ void zr_layout_row_end(struct zr_context*); -/* this function ends the previously started scaleable row */ void zr_layout_row(struct zr_context*, enum zr_layout_format, float height, zr_size cols, const float *ratio); -/* this function sets the row layout as an array of ratios/width for - every widget that will be inserted into that row - Input: - - scaleable or fixed row format - - height of the row and there each widget inside - - number of widget inside the row - - window ratio/pixel width array for each widget -*/ -/* -------------------------------------------------------------- - * USER DEFINED - * --------------------------------------------------------------*/ -void zr_layout_row_space_begin(struct zr_context*, enum zr_layout_format, - float height, zr_size widget_count); -/* this functions starts a space where widgets can be added - at any given position and the user has to make sure no overlap occures - Input: - - height of the row and therefore each widget inside - - number of widget that will be added into that space -*/ -struct zr_rect zr_layout_row_space_bounds(struct zr_context*); -/* this functions returns the complete bounds of the space in the panel */ -void zr_layout_row_space_push(struct zr_context*, struct zr_rect); -/* this functions pushes the position and size of the next widget that will - be added into the previously allocated window space - Input: - - rectangle with position and size as a ratio of the next widget to add -*/ -struct zr_vec2 zr_layout_row_space_to_screen(struct zr_context*, struct zr_vec2); -/* this functions calculates a position from local space to screen space - Input: - - position in local layout space - Output: - - position in screen space -*/ -struct zr_vec2 zr_layout_row_space_to_local(struct zr_context*, struct zr_vec2); -/* this functions calculates a position from screen space to local space - Input: - - position in screen layout space - Output: - - position in local layout space -*/ -struct zr_rect zr_layout_row_space_rect_to_screen(struct zr_context*, struct zr_rect); -/* this functions calculates a rectange from local space to screen space - Input: - - rectangle in local layout space - Output: - - rectangle in screen space -*/ -struct zr_rect zr_layout_row_space_rect_to_local(struct zr_context*, struct zr_rect); -/* this functions calculates a rectangle from screen space to local space - Input: - - rectangle in screen space - Output: - - rectangle in local space -*/ -void zr_layout_row_space_end(struct zr_context*); -/* this functions finishes the scaleable space filling process */ -/* -------------------------------------------------------------- - * TREE - * --------------------------------------------------------------*/ -int zr_layout_push(struct zr_context*, enum zr_layout_node_type, - const char *title, int*); -/* this functions pushes either a tree node or collapseable header into - * the current window layout - Input: - - title of the node to push into the window - - type of then node with either default node, collapseable header or tab - - state of the node with either ZR_MINIMIZED or ZR_MAXIMIZED - Output: - - returns the updated state as either zr_true if open and zr_false otherwise - - updates the state of the node pointer to the updated state -*/ + +/* layouting with custom position and width and height of widgets */ +void zr_layout_space_begin(struct zr_context*, enum zr_layout_format, + float height, zr_size widget_count); +void zr_layout_space_push(struct zr_context*, struct zr_rect); +void zr_layout_space_end(struct zr_context*); + +/* utility functions for custom size + position widgets */ +struct zr_rect zr_layout_space_bounds(struct zr_context*); +struct zr_vec2 zr_layout_space_to_screen(struct zr_context*, struct zr_vec2); +struct zr_vec2 zr_layout_space_to_local(struct zr_context*, struct zr_vec2); +struct zr_rect zr_layout_space_rect_to_screen(struct zr_context*, struct zr_rect); +struct zr_rect zr_layout_space_rect_to_local(struct zr_context*, struct zr_rect); + +/* group */ +int zr_group_begin(struct zr_context*, struct zr_layout*, const char *title, zr_flags); +void zr_group_end(struct zr_context *ctx); + +/* tree layout */ +int zr_layout_push(struct zr_context*, enum zr_layout_node_type, const char *title); void zr_layout_pop(struct zr_context*); -/* this functions ends the previously added node */ -/* -------------------------------------------------------------- - * - * WIDGETS - * - * -------------------------------------------------------------- - WIDGET - The layout API uses the layout API to provide and add widget to the window. - IMPORTANT: the widget API does NOT work without a layout so if you have - visual glitches then the problem probably stems from not using the layout - correctly. The window widget API does not implement any widget itself, instead - it uses the general Widget API under the hood and is only responsible for - calling the correct widget API function with correct position, size and style. - All widgets do NOT store any state instead everything has to be managed by - the user. - - USAGE - To use the Widget API you first have to call one of the layout API funtions - to setup the widget. After that you can just call one of the widget functions - at it will automaticall update the widget state as well as `draw` the widget - by adding draw command into the window command buffer. - - window widgets API - zr_widget -- base function for all widgets to allocate space - zr_widget_fitting -- special base function for widget without padding/spacing - zr_spacing -- column seperator and is basically an empty widget - zr_seperator -- adds either a horizontal or vertical seperator - zr_text -- text widget for printing text with length - zr_text_colored -- colored text widget for printing string by length - zr_text_wrap -- wraping text widget for printing text with length - zr_text_wrap_colored -- wraping colored text widget for printing string by length - zr_label -- text widget for printing zero terminated strings - zr_label_colored -- widget for printing colored zero terminiated strings - zr_button_text -- button widget with text content - zr_button_color -- colored button widget without content - zr_button_symbol -- button with triangle either up-/down-/left- or right - zr_button_image -- button widget width icon content - zr_button_text_image -- button widget with text and icon - zr_button_text_symbol -- button widget with text and a triangle - zr_button_fitting -- button widget without border and fitting space - zr_image -- image widget for outputing a image to a window - zr_check -- add a checkbox widget - zr_option -- radiobutton widget - zr_slider_int -- integer slider widget with min,max,step value - zr_slider_float -- float slider widget with min,max,step value - zr_progress -- progressbar widget - zr_edit -- edit textbox widget for text input - zr_edit_filtered -- edit textbox widget for text input with filter input - zr_edit_field -- edit text field with cursor, clipboard and filter - zr_edit_box -- edit text box with cursor, clipboard and filter -*/ -enum zr_text_align { - ZR_TEXT_LEFT, - ZR_TEXT_CENTERED, - ZR_TEXT_RIGHT -}; - -enum zr_button_behavior { - ZR_BUTTON_DEFAULT, - ZR_BUTTON_REPEATER, - ZR_BUTTON_BEHAVIOR_MAX -}; - -enum zr_input_filter { - ZR_INPUT_DEFAULT, - /* everything goes */ - ZR_INPUT_ASCII, - /* ASCII characters (0-127)*/ - ZR_INPUT_FLOAT, - /* only float point numbers */ - ZR_INPUT_DEC, - /* only integer numbers */ - ZR_INPUT_HEX, - /* only hex numbers */ - ZR_INPUT_OCT, - /* only octal numbers */ - ZR_INPUT_BIN - /* only binary numbers */ -}; - -enum zr_widget_state zr_widget(struct zr_rect*, struct zr_context*); -/* this function represents the base of every widget and calculates the bounds - * and allocates space for a widget inside a window. - Output: - - allocated space for a widget to draw into - - state of widget the widget with invisible, renderable and render + updateable -*/ +/*-------------------------------------------------------------- + * Widgets + * -------------------------------------------------------------*/ +/* base function called by all widgets (needs to be called 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*); -/* this function represents calculates the bounds of a perfectly and completly - * fitting widget inside the window and allocates the space inside a window. - Output: - - allocated space for a widget to draw into - - state of widget the widget with invisible, renderable and render + updateable -*/ void zr_spacing(struct zr_context*, zr_size cols); -/* this function creates a seperator to fill space - Input: - - number of columns or widget to jump over -*/ void zr_seperator(struct zr_context*); -/* this function creates a seperator line */ + +/* content output widgets */ void zr_text(struct zr_context*, const char*, zr_size, enum zr_text_align); -/* this function creates a bounded non terminated text widget with either - left, centered or right alignment - Input: - - string pointer to text that should be drawn - - number of bytes the text is long - - text alignment with either left, centered or right alignment -*/ void zr_text_colored(struct zr_context*, const char*, zr_size, enum zr_text_align, struct zr_color); -/* this function creates a bounded non terminated color text widget with either - left, centered or right alignment - Input: - - string pointer to text that should be drawn - - number of bytes the text is long - - text alignment with either left, centered or right alignment - - color the text should be drawn -*/ void zr_text_wrap(struct zr_context*, const char*, zr_size); -/* this function creates a bounded non terminated multiline text widget - Input: - - string pointer to text that should be drawn - - number of bytes the text is long -*/ void zr_text_wrap_colored(struct zr_context*, const char*, zr_size, struct zr_color); -/* this function creates a bounded nonterminated multiline colored text widget - Input: - - string pointer to text that should be drawn - - number of bytes the text is long - - color the text should be drawn -*/ void zr_label(struct zr_context*, const char*, enum zr_text_align); -/* this function creates a zero terminated text widget with either - left, centered or right alignment - Input: - - string pointer to text that should be drawn - - text alignment with either left, centered or right alignment -*/ void zr_label_colored(struct zr_context*, const char*, enum zr_text_align, struct zr_color); -/* this function creates a zero terminated colored text widget with either - left, centered or right alignment - Input: - - string pointer to text that should be drawn - - text alignment with either left, centered or right alignment - - color the label should be drawn -*/ void zr_label_wrap(struct zr_context*, const char*); -/* this function creates a zero terminated wraping text widget with either - left, centered or right alignment - Input: - - string pointer to text that should be drawn -*/ void zr_label_colored_wrap(struct zr_context*, const char*, struct zr_color); -/* this function creates a zero terminated wraping colored text widget with either - left, centered or right alignment - Input: - - string pointer to text that should be drawn - - color the label should be drawn -*/ void zr_image(struct zr_context*, struct zr_image); -/* this function creates an image widget - Input: - - string pointer to text that should be drawn -*/ -int zr_check(struct zr_context*, const char*, int active); -/* this function creates a checkbox widget with either active or inactive state - Input: - - checkbox label describing the content - - state of the checkbox with either active or inactive - Output: - - from user input updated state of the checkbox -*/ -void zr_checkbox(struct zr_context*, const char*, int *active); -/* this function creates a checkbox widget with either active or inactive state - Input: - - checkbox label describing the content - - state of the checkbox with either active or inactive - Output: - - from user input updated state of the checkbox -*/ -void zr_radio(struct zr_context*, const char*, int *active); -/* this function creates a radiobutton widget with either active or inactive state - Input: - - radiobutton label describing the content - - state of the radiobutton with either active or inactive - Output: - - from user input updated state of the radiobutton -*/ -int zr_option(struct zr_context*, const char*, int active); -/* this function creates a radiobutton widget with either active or inactive state - Input: - - radiobutton label describing the content - - state of the radiobutton with either active or inactive - Output: - - from user input updated state of the radiobutton -*/ -int zr_button_text(struct zr_context*, const char*, enum zr_button_behavior); -/* this function creates a text button - Input: - - button label describing the button - - string label - - button behavior with either default or repeater behavior - Output: - - zr_true if the button was transistioned from unpressed to pressed with - default button behavior or pressed if repeater behavior. -*/ -int zr_button_color(struct zr_context*, struct zr_color, enum zr_button_behavior); -/* this function creates a colored button without content - Input: - - color the button should be drawn with - - button behavior with either default or repeater behavior - Output: - - zr_true if the button was transistioned from unpressed to pressed with - default button behavior or pressed if repeater behavior. -*/ -int zr_button_symbol(struct zr_context*, enum zr_symbol, enum zr_button_behavior); -/* this function creates a button with a triangle pointing in one of four directions - Input: - - triangle direction with either up, down, left or right direction - - button behavior with either default or repeater behavior - Output: - - zr_true if the button was transistioned from unpressed to pressed with - default button behavior or pressed if repeater behavior. -*/ -int zr_button_image(struct zr_context*, struct zr_image img, enum zr_button_behavior); -/* this function creates a button with an icon as content - Input: - - icon image handle to draw into the button - - button behavior with either default or repeater behavior - Output: - - zr_true if the button was transistioned from unpressed to pressed with - default button behavior or pressed if repeater behavior. -*/ -int zr_button_text_symbol(struct zr_context*, enum zr_symbol, const char*, - enum zr_text_align, enum zr_button_behavior); -/* this function creates a button with a triangle and text - Input: - - symbol to draw with the text - - button label describing the button - - text alignment with either left, centered or right alignment - - button behavior with either default or repeater behavior - Output: - - zr_true if the button was transistioned from unpressed to pressed with - default button behavior or pressed if repeater behavior. -*/ -int zr_button_text_image(struct zr_context *layout, struct zr_image img, - const char *text, enum zr_text_align align, - enum zr_button_behavior behavior); -/* this function creates a button with an icon and text - Input: - - image or subimage to use as an icon - - button label describing the button - - text alignment with either left, centered or right alignment - - button behavior with either default or repeater behavior - Output: - - zr_true if the button was transistioned from unpressed to pressed with - default button behavior or pressed if repeater behavior. -*/ -int zr_selectable(struct zr_context *layout, const char *str, - enum zr_text_align align, int *value); -/* this function creates a selectable item which is either active or inactive - Input: - - selectable text to draw - - current state of the toggle - Output: - - returns whether the selectable was changed -*/ -int zr_select(struct zr_context *layout, const char *str, - enum zr_text_align align, int value); -/* this function creates a selectable item which is either active or inactive - Input: - - selectable text to draw - - current state of the toggle - Output: - - returns the updated selectable state -*/ -void zr_slider_float(struct zr_context*, float min, float *val, float max, - float step); -/* this function creates a float slider for value manipulation - Input: - - minimal slider value that will not be underflown - - slider value which shall be updated - - maximal slider value that will not be overflown - - step intervall to change the slider with - Output: - - the from user input updated slider value -*/ -void zr_slider_int(struct zr_context*, int min, int *val, int max, - int step); -/* this function creates a int slider for value manipulation - Input: - - minimal slider value that will not be underflown - - slider value which shall be updated - - maximal slider value that will not be overflown - - step intervall to change the slider with - Output: - - the from user input updated slider value -*/ -float zr_slide_float(struct zr_context*, float min, float val, float max, - float step); -/* this function creates a float slider for value manipulation - Input: - - minimal slider value that will not be underflown - - slider value which shall be updated - - maximal slider value that will not be overflown - - step intervall to change the slider with - Output: - - the from user input updated slider value -*/ -int zr_slide_int(struct zr_context*, int min, int val, int max, int step); -/* this function creates a int slider for value manipulation - Input: - - minimal slider value that will not be underflown - - slider value which shall be updated - - maximal slider value that will not be overflown - - step intervall to change the slider with - Output: - - the from user input updated slider value -*/ +/* toggle value */ +int zr_check(struct zr_context*, const char*, int active); +void zr_checkbox(struct zr_context*, const char*, int *active); +void zr_radio(struct zr_context*, const char*, int *active); +int zr_option(struct zr_context*, const char*, int active); +int zr_selectable(struct zr_context*, const char*, enum zr_text_align, int *value); +int zr_select(struct zr_context*, const char*, enum zr_text_align, int value); + +/* buttons (push/press) */ +int zr_button_text(struct zr_context*, const char*, 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, enum zr_button_behavior); +int zr_button_image(struct zr_context*, struct zr_image img, enum zr_button_behavior); +int zr_button_text_symbol(struct zr_context*, enum zr_symbol, const char*, + enum zr_text_align, enum zr_button_behavior); +int zr_button_text_image(struct zr_context*, struct zr_image img, const char*, + enum zr_text_align align, enum zr_button_behavior); + +/* simple value modifier by sliding */ void zr_progress(struct zr_context*, zr_size *cur, zr_size max, int modifyable); -/* this function creates an either user or program controlled progressbar - Input: - - current progressbar value - - maximal progressbar value that will not be overflown - - flag indicating if the progressbar should be changeable by user input - Output: - - the from user input updated progressbar value if modifyable progressbar -*/ -void zr_edit_field(struct zr_context*, struct zr_edit_box*); -/* this function creates an editbox with copy & paste functionality and text buffering */ -void zr_edit_box(struct zr_context*, struct zr_edit_box*, int modifyable); -/* this function creates an multiline editbox with copy & paste functionality and text - buffering. NOTE: this is interhintly slow so please do not use it for heavy workloads. */ -void zr_edit(struct zr_context*, char *buffer, zr_size *len, zr_size max, - int *active, zr_size *cursor, enum zr_input_filter); -/* this function creates an editbox to updated/insert user text input - Input: - - buffer to fill with user input - - current length of the buffer in bytes - - maximal number of bytes the buffer can be filled with - - state of the editbox with active as currently modified by the user - - filter type to limit the glyph the user can input into the editbox - Output: - - length of the buffer after user input update - - current state of the editbox with active(zr_true) or inactive(zr_false) -*/ -void zr_edit_filtered(struct zr_context*, char *buffer, zr_size *len, - zr_size max, int *active, zr_size *cursor, zr_filter); -/* this function creates an editbox to updated/insert filtered user text input - Input: - - buffer to fill with user input - - current length of the buffer in bytes - - maximal number of bytes the buffer can be filled with - - state of the editbox with active as currently modified by the user - - filter callback to limit the glyphs the user can input into the editbox - Output: - - length of the buffer after user input update - - current state of the editbox with active(zr_true) or inactive(zr_false) -*/ +void zr_slider_float(struct zr_context*, float min, float *val, float max, float step); +void zr_slider_int(struct zr_context*, int min, int *val, int max, int step); +float zr_slide_float(struct zr_context*, float min, float val, float max, float step); +int zr_slide_int(struct zr_context*, int min, int val, int max, int step); + +/* extended value modifier by 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); -/* this function creates a float property widget - Input: - - min value that will not be underflown - - current spinner value to be updated by user input - - max value that will not be overflown - - spinner value modificaton stepping intervall - - current state of the spinner with active as currently modfied by user input - Output: - - the from user input updated spinner value - - current state of the editbox with active(zr_true) or inactive(zr_false) -*/ void zr_property_int(struct zr_context *layout, const char *name, int min, int *val, int max, int step, int inc_per_pixel); -/* this function creates a float property widget - Input: - - min value that will not be underflown - - current spinner value to be updated by user input - - max value that will not be overflown - - spinner value modificaton stepping intervall - - current state of the spinner with active as currently modfied by user input - Output: - - the from user input updated spinner value - - current state of the editbox with active(zr_true) or inactive(zr_false) -*/ float zr_propertyf(struct zr_context *layout, const char *name, float min, float val, float max, float step, float inc_per_pixel); -/* this function creates a float property widget - Input: - - min value that will not be underflown - - current spinner value to be updated by user input - - max value that will not be overflown - - spinner value modificaton stepping intervall - - current state of the spinner with active as currently modfied by user input - Output: - - the from user input updated spinner value - - current state of the editbox with active(zr_true) or inactive(zr_false) -*/ int zr_propertyi(struct zr_context *layout, const char *name, int min, int val, int max, int step, int inc_per_pixel); -/* this function creates a float property widget - Input: - - min value that will not be underflown - - current spinner value to be updated by user input - - max value that will not be overflown - - spinner value modificaton stepping intervall - - current state of the spinner with active as currently modfied by user input - Output: - - the from user input updated spinner value - - current state of the editbox with active(zr_true) or inactive(zr_false) -*/ -/* -------------------------------------------------------------- - * - * COMBO BOX - * - * -------------------------------------------------------------- - COMBO BOX - The combo box is a minimizable popup window and extends the old school - text combo box with the possibility to fill combo boxes with any kind of widgets. - The combo box is internaly implemented with a dynamic popup window - and can only be as height as the window allows. - There are two different ways to create a combo box. The first one is a - standart text combo box which has it own function `zr_combo`. The second - way is the more complex immediate mode API which allows to create - any kind of content inside the combo box. In case of the second API it is - additionally possible and sometimes wanted to close the combo box popup - window This can be achived with `zr_combo_close`. - combo box API - zr_combo_begin -- begins the combo box popup window - zr_combo_item -- adds a text item into the combobox - zr_combo_item_icon -- adds a text image item into the combobox - zr_combo_item_symbol -- adds a text symbol item into the combobox - zr_combo_close -- closes the previously opened combo box - zr_combo_end -- ends the combo box build up process -*/ -void zr_combo_begin_text(struct zr_context *parent, struct zr_context *combo, - const char *selected, int *active, int height, struct zr_vec2 *scrollbar); -/* this function begins the combobox build up process with a text header - Input: - - parent window layout the combo box will be placed into - - ouput combo box window layout which will be needed to fill the combo box - - title of the combo box or in the case of the text combo box the selected item - - the current state of the combobox with either zr_true (active) or zr_false else - - the current scrollbar offset of the combo box popup window -*/ -void zr_combo_begin_color(struct zr_context *parent, struct zr_context *combo, - struct zr_color color, int *active, int height, - struct zr_vec2 *scrollbar); -/* this function begins the combobox build up process with a color header - Input: - - parent window layout the combo box will be placed into - - ouput combo box window layout which will be needed to fill the combo box - - title color to show - - the current state of the combobox with either zr_true (active) or zr_false else - - the current scrollbar offset of the combo box popup window -*/ -void zr_combo_begin_image(struct zr_context *parent, struct zr_context *combo, - struct zr_image img, int *active, int height, - struct zr_vec2 *scrollbar); -/* this function begins the combobox build up process with a image header - Input: - - parent window layout the combo box will be placed into - - ouput combo box window layout which will be needed to fill the combo box - - title color to show - - the current state of the combobox with either zr_true (active) or zr_false else - - the current scrollbar offset of the combo box popup window -*/ -void zr_combo_begin_icon(struct zr_context *parent, struct zr_context *combo, - const char *selected, struct zr_image img, int *active, int height, - struct zr_vec2 *scrollbar); -/* this function begins the combobox build up process with a icon text header - Input: - - parent window layout the combo box will be placed into - - ouput combo box window layout which will be needed to fill the combo box - - title color to show - - the current state of the combobox with either zr_true (active) or zr_false else - - the current scrollbar offset of the combo box popup window -*/ -int zr_combo_item(struct zr_context *menu, const char*, enum zr_text_align align); -/* this function execute a combo box item - Input: - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -int zr_combo_item_icon(struct zr_context *menu, struct zr_image, - const char*, enum zr_text_align align); -/* this function execute combo box icon item - Input: - - icon to draw into the combo box item - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -int zr_combo_item_symbol(struct zr_context *menu, enum zr_symbol symbol, - const char*, enum zr_text_align align); -/* this function execute combo box symbol item - Input: - - symbol to draw into the combo box item - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -void zr_combo_close(struct zr_context *combo, int *state); -/* this function closes a opened combobox */ -void zr_combo_end(struct zr_context *parent, struct zr_context *menu, - int *state, struct zr_vec2 *scrollbar); -/* this function ends the combobox build up process */ -/* -------------------------------------------------------------- - * - * GRAPH - * - * -------------------------------------------------------------- - GRAPH - The graph widget provided a way to visualize data in either a line or - column graph. +/* text manipulation */ +int zr_edit_string(struct zr_context*, zr_flags, char *buffer, zr_size *len, zr_size max, zr_filter); +int zr_edit_buffer(struct zr_context*, zr_flags, struct zr_buffer*, zr_filter); - USAGE - To create a graph three different ways are provided. The first one - is an immediate mode API which allows the push values one by one - into the graph. The second one is a retain mode function which takes - an array of float values and converts them into a graph. The final - function is based on a callback and is mainly a good option if you - want to draw a mathematical function like for example sine or cosine. +/* simple graph */ +void zr_graph_begin(struct zr_context*, enum zr_graph_type, zr_size num, float min, float max); +zr_flags zr_graph_push(struct zr_context*, float); +void zr_graph_end(struct zr_context*); - graph widget API - zr_graph_begin -- immediate mode graph building begin sequence point - zr_graph_push -- push a value into a graph - zr_graph_end -- immediate mode graph building end sequence point - zr_graph -- retained mode graph with array of values - zr_graph_ex -- ratained mode graph with getter callback -*/ -enum zr_graph_type { - ZR_GRAPH_LINES, - /* Line graph with each data point being connected with its previous and next node */ - ZR_GRAPH_COLUMN, - /* Column graph/Histogram with value represented as bars */ - ZR_GRAPH_MAX -}; +/*-------------------------------------------------------------- + * Popups + * -------------------------------------------------------------*/ +int zr_popup_begin(struct zr_context*, struct zr_layout*, enum zr_popup_type, + const char *title, zr_flags, struct zr_rect bounds); +void zr_popup_close(struct zr_context*); +void zr_popup_end(struct zr_context*); -enum zr_graph_event { - ZR_GRAPH_HOVERING = 0x01, - /* Mouse hoveres over current value */ - ZR_GRAPH_CLICKED = 0x02 - /* Mouse click on current value */ -}; +/* abstract combo box */ +int zr_combo_begin_text(struct zr_context*, struct zr_layout*, const char *id, + const char *selected, int max_height); +int zr_combo_begin_color(struct zr_context*, struct zr_layout*, const char *id, + struct zr_color color, int max_height); +int zr_combo_begin_image(struct zr_context*, struct zr_layout*, const char *id, + struct zr_image img, int max_height); +int zr_combo_begin_icon(struct zr_context*, struct zr_layout*, const char *id, + const char *selected, struct zr_image img, int height); +int zr_combo_item(struct zr_context*, const char*, enum zr_text_align); +int zr_combo_item_icon(struct zr_context*, struct zr_image, const char*, enum zr_text_align align); +int zr_combo_item_symbol(struct zr_context*, enum zr_symbol symbol, const char*, enum zr_text_align align); +void zr_combo_close(struct zr_context*); +void zr_combo_end(struct zr_context*); -struct zr_graph { - int valid; - /* graph valid flag to make sure that the graph is visible */ - enum zr_graph_type type; - /* graph type with either line or column graph */ - float x, y; - /* graph canvas space position */ - float w, h; - /* graph canvas space size */ - float min, max; - /* min and max value for correct scaling of values */ - struct zr_vec2 last; - /* last line graph point to connect to. Only used by the line graph */ - zr_size index; - /* current graph value index*/ - zr_size count; - /* number of values inside the graph */ -}; +/* contextual menu */ +int zr_contextual_begin(struct zr_context*, struct zr_layout*, zr_flags flags, struct zr_vec2 size); +int zr_contextual_item(struct zr_context*, const char*, enum zr_text_align align); +int zr_contextual_item_icon(struct zr_context*, struct zr_image, const char*, enum zr_text_align); +int zr_contextual_item_symbol(struct zr_context*, enum zr_symbol, const char*, enum zr_text_align); +void zr_contextual_close(struct zr_context*); +void zr_contextual_end(struct zr_context*); -void zr_graph_begin(struct zr_context*, struct zr_graph*, enum zr_graph_type, - zr_size count, float min, float max); -/* this function begins a graph building widget - Input: - - type of the graph with either lines or bars - - minimal graph value for the lower bounds of the graph - - maximal graph value for the upper bounds of the graph - Output: - - graph stack object that can be filled with values -*/ -zr_flags zr_graph_push(struct zr_context*,struct zr_graph*,float); -/* this function pushes a value inside the pushed graph - Input: - - value data point to fill into the graph either as point or as bar - Output: - - event with either currently pushed value is hovered and/or clicked -*/ -void zr_graph_end(struct zr_context *layout, struct zr_graph*); -/* this function ends the graph */ -/* -------------------------------------------------------------- - * - * GROUP - * - * -------------------------------------------------------------- - GROUP - A group window represents a window inside a window. The group thereby has a fixed height - but just like a normal window has a scrollbar. It main promise is to group together - a group of widgets into a small space inside a window and to provide a scrollable - space inside a window. - - USAGE - To create a group you first have to allocate space in a window. This is done - by the group row layout API and works the same as widgets. After that the - `zr_group_begin` has to be called with the parent layout to create - the group in and a group layout to create a new window inside the window. - Just like a window layout structures the group layout only has a lifetime - between the `zr_group_begin` and `zr_group_end` and does - not have to be persistent. - - group window API - zr_group_begin -- adds a scrollable fixed space inside the window - zr_group_begin -- ends the scrollable space -*/ -void zr_group_begin(struct zr_context*, struct zr_context *tab, - const char *title, zr_flags, struct zr_vec2); -/* this function adds a grouped group window into the parent window - IMPORTANT: You need to set the height of the group with zr_row_layout - Input: - - group title to write into the header - - group scrollbar offset - Output: - - group layout to fill with widgets -*/ -void zr_group_end(struct zr_context*, struct zr_context*, struct zr_vec2 *scrollbar); -/* this function finishes the previously started group layout - Output: - - The from user input updated group scrollbar pixel offset -*/ -/* -------------------------------------------------------------- - * - * POPUP - * - * -------------------------------------------------------------- - POPUP - The popup extends the normal window with an overlapping blocking - window that needs to be closed before the underlining main window can - be used again. Therefore popups are designed for messages,tooltips and - are used to create the combo box. Internally the popup creates a subbuffer - inside a command queue that will be drawn after the complete parent window. - - USAGE - To create an popup the `zr_window_popup_begin` function needs to be called - with the parent window local position and size and the wanted type with - static or dynamic window. A static window has a fixed size and behaves like a - normal window inside a window, but a dynamic window only takes up as much - height as needed up to a given maximum height. Dynamic windows are for example - combo boxes while static window make sense for messsages or tooltips. - To close a popup you can use the `zr_pop_close` function which takes - care of the closing process. Finally `zr_popup_end` finializes the popup. - - window blocking popup API - zr_popup_begin -- adds a popup inside a window - zr_popup_close -- closes the popup window - zr_popup_end -- ends the popup building process - - window non-blocking popup API - zr_popup_menu_begin -- begin a popup context menu - zr_popup_menu_close -- closes a popup context menu - zr_popup_menu_end -- ends the popup building process -*/ -enum zr_popup_type { - ZR_POPUP_STATIC, - /* static fixed height non growing popup */ - ZR_POPUP_DYNAMIC - /* dynamically growing popup with maximum height */ -}; - -zr_flags zr_popup_begin(struct zr_context *parent, struct zr_context *popup, - enum zr_popup_type, const char *title, - zr_flags, struct zr_rect bounds, struct zr_vec2 offset); -/* this function adds a overlapping blocking popup menu - Input: - - type of the popup as either growing or static - - additonal popup window flags - - popup position and size of the popup (NOTE: local position) - - scrollbar offset of wanted - Output: - - popup layout to fill with widgets -*/ -void zr_popup_close(struct zr_context *popup); -/* this functions closes a previously opened popup */ -void zr_popup_end(struct zr_context *parent, struct zr_context *popup, - struct zr_vec2 *scrollbar); -/* this function finishes the previously started popup layout - Output: - - The from user input updated popup scrollbar pixel offset -*/ -/* -------------------------------------------------------------- - * - * CONTEXTUAL - * - * -------------------------------------------------------------- - CONTEXTUAL - A contextual menu is a dynamic non-blocking popup window. It was mainly - designed to create a typical right-click menu with items but can be filled with - any content. The reason special menu items were added was to make the content - fit the menu. Since the contextual menu is non-blocking in contrast to - normal popups a click outside of the menu results in a closed menu. In addition - if one of the menu items function is called a call to one of the items results - in a closed menu as well. The final method of closing the contextual menu is - by hand by calling the close function. - - contextual API - zr_contextual_begin -- begins the contextual menu popup window - zr_contextual_item -- adds a text item into the contextual menu - zr_contextual_item_icon -- adds a text image item into the contextual menu - zr_contextual_item_symbol -- adds a text symbol item into the contextual menu - zr_contextual_close -- closes the previously opened contextual menu - zr_contextual_end -- ends the contextual menu build up process -*/ -void zr_contextual_begin(struct zr_context *parent, struct zr_context *popup, - zr_flags flags, int *active, struct zr_rect body); -/* this function adds a context menu popup - Input: - - type of the popup as either growing or static - - additonal popup window flags - - popup position and size of the popup (NOTE: local position) - - scrollbar offset of wanted - Output: - - popup layout to fill with widgets -*/ -int zr_contextual_item(struct zr_context *menu, const char*, enum zr_text_align align); -/* this function execute contextual menu item - Input: - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -int zr_contextual_item_icon(struct zr_context *menu, struct zr_image, - const char*, enum zr_text_align align); -/* this function execute contextual menu item - Input: - - icon to draw into the menu item - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -int zr_contextual_item_symbol(struct zr_context *menu, enum zr_symbol symbol, - const char*, enum zr_text_align align); -/* this function execute contextual menu item - Input: - - symbol to draw into the menu item - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -void zr_contextual_close(struct zr_context *popup); -/* this functions closes the context menu - Output: - - update state of the context menu -*/ -void zr_contextual_end(struct zr_context *parent, struct zr_context *popup, int*); -/* this functions closes a previously opened context menu */ - -/*---------------------------------------------------------------- - * - * MENU - * - * -------------------------------------------------------------- - MENU - The menu widget provides a overlapping popup window which can - be opened/closed by clicking on the menu button. It is normally - placed at the top of the window and is independent of the parent - scrollbar offset. But if needed the menu can even be placed inside the window. - At the moment the menu only allows a single depth but that will change - in the future. - - menu widget API - zr_menu_xxx_begin -- begins the menu item build up processs - zr_menu_item -- adds a item into the menu - zr_menu_item_icon -- adds a text + image item into the menu - zr_menu_item_symbol -- adds a text + symbol item into the menu - zr_menu_close -- closes the menu - zr_menu_end -- ends the menu item build up process -*/ -void zr_menu_text_begin(struct zr_context *parent, struct zr_context *menu, - const char *title, float width, int *active); -/* this function begins the menu build up process and provides a clickable text button - * to open and close the menu popup panel - Input: - - parent window layout the menu will be placed into - - ouput menu window layout - - title of the menu to - - the current state of the menu with either zr_true (open) or zr_false else -*/ -void zr_menu_icon_begin(struct zr_context *parent, struct zr_context *menu, - struct zr_image, float width, int *active); -/* this function begins the menu build up process and provides a clickable icon button - * to open and close the menu popup panel - Input: - - parent window layout the menu will be placed into - - ouput menu window layout - - title of the menu to - - the current state of the menu with either zr_true (open) or zr_false else -*/ -void zr_menu_symbol_begin(struct zr_context *parent, struct zr_context *menu, - enum zr_symbol, float width, int *active); -/* this function begins the menu build up process and provides a clickable symbol button - * to open and close the menu popup panel - Input: - - parent window layout the menu will be placed into - - ouput menu window layout - - symbol to add into the button - - the current state of the menu with either zr_true (open) or zr_false else -*/ -int zr_menu_item(struct zr_context *menu, enum zr_text_align align, const char*); -/* this function execute a menu item - Input: - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -int zr_menu_item_icon(struct zr_context *menu, struct zr_image, - const char*, enum zr_text_align align); -/* this function execute menu text icon item - Input: - - icon to draw into the menu item - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -int zr_menu_item_symbol(struct zr_context *menu, enum zr_symbol symbol, - const char*, enum zr_text_align align); -/* this function execute menu text symbol item - Input: - - symbol to draw into the menu item - - text alignment of the title - - title of the item - Output - - `zr_true` if has been clicked `zr_false` otherwise -*/ -void zr_menu_close(struct zr_context *menu, int*); -/* this function closes a opened menu */ -void zr_menu_end(struct zr_context *parent, struct zr_context *menu); -/* this function ends the menu build up process */ - -/* -------------------------------------------------------------- - * - * TOOLTIP - * - * -------------------------------------------------------------- - TOOLTIP - The tooltip widget can be used to provide the user with information - by creating a popup window under the mouse cursor which decribes a function. - To use it you should first test if the mouse hovers over the thing you want - to provide information for before calling this. - - tooltip widget API - zr_tooltip -- creates a simple tooltip popup under the mouse cursor - zr_tooltip_begin -- begins a start window popup to be filled - zr_tooltip_end -- ends the window popup -*/ +/* tooltip */ void zr_tooltip(struct zr_context*, const char *text); -/* this function create a simple text tooltip window under the mouse cursor, - Input: - - output text to display inside the tooltip -*/ -void zr_tooltip_begin(struct zr_context *parent, struct zr_context *tip, - float width); -/* this function begins a popup tooltip window under the mouse cursor - Input: - - width of the tooltip window -*/ -void zr_tooltip_end(struct zr_context *parent, struct zr_context *tip); -/* this function ends the tooltip window */ +int zr_tooltip_begin(struct zr_context*, struct zr_layout*, float width); +void zr_tooltip_end(struct zr_context*); + +/*-------------------------------------------------------------- + * MENU + * -------------------------------------------------------------*/ +void zr_menubar_begin(struct zr_context*); +void zr_menubar_end(struct zr_context*); + +int zr_menu_text_begin(struct zr_context*, struct zr_layout*, const char *title, float width); +int zr_menu_icon_begin(struct zr_context*, struct zr_layout*, const char *id, struct zr_image, float width); +int zr_menu_symbol_begin(struct zr_context*, struct zr_layout*, const char *id, enum zr_symbol, float width); +int zr_menu_item(struct zr_context*, enum zr_text_align align, const char*); +int zr_menu_item_icon(struct zr_context*, struct zr_image, const char*, enum zr_text_align); +int zr_menu_item_symbol(struct zr_context*, enum zr_symbol, const char*, enum zr_text_align); +void zr_menu_close(struct zr_context*); +void zr_menu_end(struct zr_context*); #ifdef __cplusplus }