diff --git a/demo/demo.c b/demo/demo.c index 198f4ed..3a90fe0 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -3,14 +3,30 @@ #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 -struct show_window { - struct gui_panel hook; - gui_flags header_flags; +struct tree_node { + gui_tree_node_state state; + const char *name; + struct tree_node *parent; + struct tree_node *children[8]; + int count; +}; + +struct test_tree { + struct tree_node root; + struct tree_node *clipboard[16]; + int count; +}; + +struct state { /* input buffer */ gui_char input_buffer[MAX_BUFFER]; struct gui_edit_box input; + gui_char in_buf[MAX_BUFFER]; + gui_size in_len; + gui_bool in_active; /* widgets state */ + gui_size menu_item; gui_bool scaleable; gui_bool checkbox; gui_float slider; @@ -19,31 +35,27 @@ struct show_window { gui_bool spinner_active; gui_size item_current; gui_size shelf_selection; - gui_int combo_selection; gui_bool toggle; gui_int option; - gui_size text_box; + + /* tree */ + struct test_tree tree; + struct tree_node nodes[8]; + gui_float tree_offset; + /* tabs */ - gui_bool combobox_tab; - gui_bool widget_tab; - gui_bool table_tab; + enum gui_node_state config_tab; + enum gui_node_state widget_tab; + enum gui_node_state style_tab; + enum gui_node_state round_tab; + enum gui_node_state color_tab; + enum gui_node_state flag_tab; + /* scrollbars */ gui_float shelf_scrollbar; gui_float table_scrollbar; - gui_float time_scrollbar; - /* menu */ - gui_size menu_item; -}; + gui_float tree_scrollbar; -struct control_window { - struct gui_panel hook; - gui_flags show_flags; - gui_flags header_flags; - /* tabs */ - gui_bool flag_tab; - gui_bool style_tab; - gui_bool round_tab; - gui_bool color_tab; /* color picker */ gui_bool picker_active; gui_bool spinner_r_active; @@ -52,23 +64,102 @@ struct control_window { gui_bool spinner_a_active; gui_size current_color; struct gui_color color; + }; struct demo_gui { gui_bool running; - unsigned int ms; void *memory; - struct gui_command_buffer show_buffer; - struct gui_command_buffer control_buffer; + struct gui_command_buffer buffer; struct gui_config config; struct gui_font font; - struct control_window control; - struct show_window show; - struct gui_stack stack; + struct gui_panel panel; + struct state state; }; static void -widget_panel(struct gui_panel_layout *panel, struct show_window *demo) +tree_remove_node(struct tree_node *parent, struct tree_node *child) +{ + int i = 0; + child->parent = NULL; + if (!parent->count) return; + if (parent->count == 1) { + parent->count = 0; + return; + } + for (i = 0; i < parent->count; ++i) { + if (parent->children[i] == child) + break; + } + if (i == parent->count) return; + if (i == parent->count - 1) { + parent->count--; + return; + } else{ + parent->children[i] = parent->children[parent->count-1]; + parent->count--; + } +} + +static void +tree_add_node(struct tree_node *parent, struct tree_node *child) +{ + assert(parent->count < 8); + child->parent = parent; + parent->children[parent->count++] = child; +} + +static void +tree_push_node(struct test_tree *tree, struct tree_node *node) +{ + assert(tree->count < 16); + tree->clipboard[tree->count++] = node; +} + +static struct tree_node* +tree_pop_node(struct test_tree *tree) +{ + assert(tree->count > 0); + return tree->clipboard[--tree->count]; +} + +static int +upload_tree(struct test_tree *base, struct gui_tree *tree, struct tree_node *node) +{ + int i = 0, n = 0; + enum gui_tree_node_operation op; + if (node->count) { + i = 0; + op = gui_panel_tree_begin_node(tree, node->name, &node->state); + while (i < node->count) + i += upload_tree(base, tree, node->children[i]); + gui_panel_tree_end_node(tree); + } + else op = gui_panel_tree_leaf(tree, node->name, &node->state); + + switch (op) { + case GUI_NODE_NOP: break; + case GUI_NODE_CUT: + tree_remove_node(node->parent, node); + tree_push_node(base, node); + return 0; + case GUI_NODE_DELETE: + tree_remove_node(node->parent, node); break; + return 0; + case GUI_NODE_PASTE: + i = 0; n = base->count; + while (i < n) { + tree_add_node(node, tree_pop_node(base)); + i++; + } + case GUI_NODE_CLONE: + default:break; + } + return 1; +} + +static void +widget_panel(struct gui_panel_layout *panel, struct state *demo) { const char *items[] = {"Fist", "Pistol", "Shotgun", "Railgun", "BFG"}; @@ -129,6 +220,8 @@ widget_panel(struct gui_panel_layout *panel, struct show_window *demo) demo->item_current = gui_panel_selector(panel, items, LEN(items), demo->item_current); demo->spinner = gui_panel_spinner(panel, 0, demo->spinner, 250, 10, &demo->spinner_active); + demo->in_len = gui_panel_edit(panel, demo->in_buf, demo->in_len, MAX_BUFFER, + &demo->in_active, GUI_INPUT_DEFAULT); if (demo->scaleable) { gui_panel_layout_flux_row_begin(panel, 30, 2); @@ -154,7 +247,6 @@ widget_panel(struct gui_panel_layout *panel, struct show_window *demo) } } gui_panel_layout_static_row_end(panel); - } } @@ -189,26 +281,7 @@ table_panel(struct gui_panel_layout *panel) } static void -init_show(struct show_window *win, struct gui_config *config, - struct gui_command_buffer *buffer, struct gui_stack *stack) -{ - memset(win, 0, sizeof(*win)); - gui_panel_init(&win->hook, 20, 20, 310, 550, - GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE| - GUI_PANEL_SCALEABLE, buffer, config); - gui_stack_push(stack, &win->hook); - gui_edit_box_init_fixed(&win->input, win->input_buffer, MAX_BUFFER, NULL, NULL); - - win->header_flags = GUI_CLOSEABLE|GUI_MINIMIZABLE; - win->widget_tab = GUI_MAXIMIZED; - win->combobox_tab = GUI_MINIMIZED; - win->slider = 10.0f; - win->progressbar = 50; - win->spinner = 100; -} - -static void -update_menu(struct gui_panel_layout *layout, struct show_window *win, struct gui_config *config) +update_menu(struct gui_panel_layout *layout, struct state *win, struct gui_config *config) { int i = 0; enum level_id {LEVEL_MENU,LEVEL_FILE,LEVEL_OPEN,LEVEL_EDIT}; @@ -268,18 +341,12 @@ update_menu(struct gui_panel_layout *layout, struct show_window *win, struct gui {EDIT_DELETE, LEVEL_EDIT, ITEM_EDIT_DELETE} }; - const struct level *lvl = &levels[win->menu_item]; - const struct combi *iter = &combis[lvl->list]; { /* calculate column row count to fit largets menu item */ - gui_size cols, max = 0; - for (i = 0; i < lvl->items; ++i) { - gui_size text_w, w; - const struct item *item = &items[iter->item]; - text_w = config->font.width(config->font.userdata,item->name,strlen(item->name)); - w = text_w + (gui_size)config->properties[GUI_PROPERTY_ITEM_PADDING].x * 2; - if (w > max) max = w; - iter++; + gui_int max = 0; + for (i = 0; i < (int)LEN(levels); ++i) { + if (levels[0].items > max) + max = levels[0].items; } gui_panel_layout_flux_fixed(layout, 18, 5); } @@ -287,9 +354,10 @@ update_menu(struct gui_panel_layout *layout, struct show_window *win, struct gui /* output current menu level entries */ gui_panel_menu_begin(layout); { + const struct level *lvl = &levels[win->menu_item]; + const struct combi *iter = &combis[lvl->list]; gui_config_push_color(config, GUI_COLOR_BUTTON_BORDER, 45, 45, 45, 250); gui_config_push_property(config, GUI_PROPERTY_ITEM_SPACING, 0, 4.0f); - iter = &combis[lvl->list]; for (i = 0; i < lvl->items; ++i) { const struct item *item = &items[iter->item]; if (gui_panel_button_text(layout, item->name, GUI_BUTTON_DEFAULT)) { @@ -321,38 +389,7 @@ update_menu(struct gui_panel_layout *layout, struct show_window *win, struct gui } static void -update_show(struct show_window *show, struct gui_stack *stack, struct gui_input *in, struct gui_config *config) -{ - struct gui_panel_layout tab; - struct gui_panel_layout layout; - static const char *shelfs[] = {"Histogram", "Lines"}; - gui_panel_begin_stacked(&layout, &show->hook, stack, in); - gui_panel_header(&layout, "Show", show->header_flags, 0, GUI_HEADER_RIGHT); - update_menu(&layout, show, config); - { - /* Widgets */ - show->widget_tab = gui_panel_tab_begin(&layout, &tab, "Widgets",GUI_BORDER, show->widget_tab); - widget_panel(&tab, show); - gui_panel_tab_end(&layout, &tab); - - /* Graph */ - gui_panel_layout_flux_fixed(&layout, 180, 1); - show->shelf_selection = gui_panel_shelf_begin(&layout, &tab, shelfs, - LEN(shelfs), show->shelf_selection, show->shelf_scrollbar); - graph_panel(&tab, show->shelf_selection); - show->shelf_scrollbar = gui_panel_shelf_end(&layout, &tab); - - /* Table */ - gui_panel_layout_flux_fixed(&layout, 180, 1); - gui_panel_group_begin(&layout, &tab, "Table", show->table_scrollbar); - table_panel(&tab); - show->table_scrollbar = gui_panel_group_end(&layout, &tab); - } - gui_panel_end(&layout, &show->hook); -} - -static void -update_flags(struct gui_panel_layout *panel, struct control_window *control) +update_flags(struct gui_panel_layout *panel) { gui_size n = 0; gui_flags res = 0; @@ -360,11 +397,11 @@ update_flags(struct gui_panel_layout *panel, struct control_window *control) const char *options[]={"Hidden","Border","Header Border", "Moveable","Scaleable", "Minimized"}; gui_panel_layout_flux_fixed(panel, 30, 2); do { - if (gui_panel_check(panel,options[n++],(control->show_flags & i)?gui_true:gui_false)) + if (gui_panel_check(panel,options[n++],(panel->flags & i)?gui_true:gui_false)) res |= i; i = i << 1; } while (i <= GUI_PANEL_MINIMIZED); - control->show_flags = res; + panel->flags = res; } static void @@ -402,7 +439,7 @@ round_tab(struct gui_panel_layout *panel, struct gui_config *config) } static struct gui_color -color_picker(struct gui_panel_layout *panel, struct control_window *control, +color_picker(struct gui_panel_layout *panel, struct state *control, const char *name, struct gui_color color) { int i; @@ -430,7 +467,7 @@ color_picker(struct gui_panel_layout *panel, struct control_window *control, } static void -color_tab(struct gui_panel_layout *panel, struct control_window *control, struct gui_config *config) +color_tab(struct gui_panel_layout *panel, struct state *control, struct gui_config *config) { gui_size i = 0; static const char *labels[] = {"Text:", "Panel:", "Header:", "Border:", "Button:", @@ -442,7 +479,8 @@ color_tab(struct gui_panel_layout *panel, struct control_window *control, struct "Selector:", "Selector Border:", "Selector Triangle:", "Selector Text:", "Histo:", "Histo Bars:", "Histo Negative:", "Histo Hovering:", "Plot:", "Plot Lines:", "Plot Hightlight:", "Scrollbar:", "Scrollbar Cursor:", "Scrollbar Border:", - "Table lines:", "Shelf:", "Shelf Text:", "Shelf Active:", "Shelf Active Text:", "Scaler:", + "Table lines:", "Tab header", "Tab border", + "Shelf:", "Shelf Text:", "Shelf Active:", "Shelf Active Text:", "Scaler:", "Tiled Scaler" }; @@ -472,89 +510,143 @@ color_tab(struct gui_panel_layout *panel, struct control_window *control, struct } } -static void -init_control(struct control_window *win, struct gui_config *config, - struct gui_command_buffer *buffer, struct gui_stack *stack) -{ - memset(win, 0, sizeof(*win)); - gui_panel_init(&win->hook, 380, 20, 350, 500, - GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE|GUI_PANEL_SCALEABLE, buffer, config); - gui_stack_push(stack, &win->hook); - win->show_flags = win->hook.flags; - win->color_tab = GUI_MINIMIZED; -} - -static gui_bool -update_control(struct control_window *control, struct gui_stack *stack, - struct gui_input *in, struct gui_config *config) -{ - gui_bool running; - struct gui_panel_layout layout; - struct gui_panel_layout tab; - - gui_panel_begin_stacked(&layout, &control->hook, stack, in); - running = !gui_panel_header(&layout, "Control", GUI_CLOSEABLE|GUI_MINIMIZABLE, - GUI_CLOSEABLE, GUI_HEADER_LEFT); - { - control->flag_tab = gui_panel_tab_begin(&layout, &tab, "Options", GUI_BORDER, control->flag_tab); - update_flags(&tab, control); - gui_panel_tab_end(&layout, &tab); - - control->style_tab = gui_panel_tab_begin(&layout, &tab, "Properties", GUI_BORDER, control->style_tab); - properties_tab(&tab, config); - gui_panel_tab_end(&layout, &tab); - - control->round_tab = gui_panel_tab_begin(&layout, &tab, "Rounding", GUI_BORDER, control->round_tab); - round_tab(&tab, config); - gui_panel_tab_end(&layout, &tab); - - control->color_tab = gui_panel_tab_begin(&layout, &tab, "Color", GUI_BORDER, control->color_tab); - color_tab(&tab, control, config); - gui_panel_tab_end(&layout, &tab); - } - gui_panel_end(&layout, &control->hook); - return running; -} - static void init_demo(struct demo_gui *gui, struct gui_font *font) { struct gui_config *config = &gui->config; + struct state *win = &gui->state; gui->font = *font; gui->running = gui_true; - gui_command_buffer_init_fixed(&gui->show_buffer, gui->memory, MAX_MEMORY/2, GUI_CLIP); - gui_command_buffer_init_fixed(&gui->control_buffer, - gui_ptr_add(void*, gui->memory, (MAX_MEMORY/2)), MAX_MEMORY/2, GUI_CLIP); + gui_command_buffer_init_fixed(&gui->buffer, gui->memory, MAX_MEMORY, GUI_CLIP); gui_config_default(config, GUI_DEFAULT_ALL, font); + gui_panel_init(&gui->panel, 30, 30, 280, 530, + GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE|GUI_PANEL_SCALEABLE, &gui->buffer, config); - gui_stack_clear(&gui->stack); - init_show(&gui->show, config, &gui->show_buffer, &gui->stack); - init_control(&gui->control, config, &gui->control_buffer, &gui->stack); - gui->control.header_flags = gui->show.header_flags; + gui_edit_box_init_fixed(&win->input, win->input_buffer, MAX_BUFFER, NULL, NULL); + win->config_tab = GUI_MINIMIZED; + win->widget_tab = GUI_MINIMIZED; + win->style_tab = GUI_MINIMIZED; + win->round_tab = GUI_MINIMIZED; + win->color_tab = GUI_MINIMIZED; + win->flag_tab = GUI_MINIMIZED; + win->scaleable = gui_true; + + win->slider = 2.0f; + win->progressbar = 50; + win->spinner = 100; + + { + struct test_tree *tree = &win->tree; + tree->root.state = GUI_NODE_ACTIVE; + tree->root.name = "Primitives"; + tree->root.parent = NULL; + tree->root.count = 2; + tree->root.children[0] = &win->nodes[0]; + tree->root.children[1] = &win->nodes[4]; + + win->nodes[0].state = 0; + win->nodes[0].name = "Boxes"; + win->nodes[0].parent = &tree->root; + win->nodes[0].count = 2; + win->nodes[0].children[0] = &win->nodes[1]; + win->nodes[0].children[1] = &win->nodes[2]; + + win->nodes[1].state = 0; + win->nodes[1].name = "Box0"; + win->nodes[1].parent = &win->nodes[0]; + win->nodes[1].count = 0; + + win->nodes[2].state = 0; + win->nodes[2].name = "Box1"; + win->nodes[2].parent = &win->nodes[0]; + win->nodes[2].count = 0; + + win->nodes[4].state = GUI_NODE_ACTIVE; + win->nodes[4].name = "Cylinders"; + win->nodes[4].parent = &tree->root; + win->nodes[4].count = 2; + win->nodes[4].children[0] = &win->nodes[5]; + win->nodes[4].children[1] = &win->nodes[6]; + + win->nodes[5].state = 0; + win->nodes[5].name = "Cylinder0"; + win->nodes[5].parent = &win->nodes[4]; + win->nodes[5].count = 0; + + win->nodes[6].state = 0; + win->nodes[6].name = "Cylinder1"; + win->nodes[6].parent = &win->nodes[4]; + win->nodes[6].count = 0; + } } static void run_demo(struct demo_gui *gui, struct gui_input *input) { - gui_flags prev; - struct control_window *control = &gui->control; - struct show_window *show = &gui->show; + struct gui_panel_layout layout; + struct state *state = &gui->state; + struct gui_panel_layout tab; + struct gui_config *config = &gui->config; + static const char *shelfs[] = {"Histogram", "Lines"}; - gui->running = update_control(control, &gui->stack, input, &gui->config); + gui_panel_begin(&layout, &gui->panel, input); + { + /* Header + Menubar */ + gui->running = !gui_panel_header(&layout, "Demo", + GUI_CLOSEABLE|GUI_MINIMIZABLE, GUI_CLOSEABLE, GUI_HEADER_RIGHT); + update_menu(&layout, state, config); - if (show->hook.flags & GUI_PANEL_ACTIVE) - show->hook.flags = control->show_flags|GUI_PANEL_ACTIVE; - else show->hook.flags = control->show_flags; - gui->show.header_flags = gui->control.header_flags; + /* Panel style configuration */ + if (gui_panel_layout_push(&layout, GUI_LAYOUT_TAB, "Style", &state->config_tab)) + { + if (gui_panel_layout_push(&layout, GUI_LAYOUT_NODE, "Options", &state->flag_tab)) { + update_flags(&layout); + gui_panel_layout_pop(&layout); + } + if (gui_panel_layout_push(&layout, GUI_LAYOUT_NODE, "Properties", &state->style_tab)) { + properties_tab(&layout, config); + gui_panel_layout_pop(&layout); + } + if (gui_panel_layout_push(&layout, GUI_LAYOUT_NODE, "Rounding", &state->round_tab)) { + round_tab(&layout, config); + gui_panel_layout_pop(&layout); + } + if (gui_panel_layout_push(&layout, GUI_LAYOUT_NODE, "Color", &state->color_tab)) { + color_tab(&layout, state, config); + gui_panel_layout_pop(&layout); + } + gui_panel_layout_pop(&layout); + } - prev = show->hook.flags; - update_show(show, &gui->stack, input, &gui->config); - if (show->hook.flags & GUI_PANEL_HIDDEN) - control->show_flags |= GUI_PANEL_HIDDEN; - if (show->hook.flags & GUI_PANEL_MINIMIZED && !(prev & GUI_PANEL_MINIMIZED)) - control->show_flags |= GUI_PANEL_MINIMIZED; - else if (prev & GUI_PANEL_MINIMIZED && !(show->hook.flags & GUI_PANEL_MINIMIZED)) - control->show_flags &= ~(gui_flags)GUI_PANEL_MINIMIZED; + /* Widgets examples */ + if (gui_panel_layout_push(&layout, GUI_LAYOUT_TAB, "Widgets", &state->widget_tab)) { + widget_panel(&layout, state); + gui_panel_layout_pop(&layout); + } + + /* Shelf + Graphes */ + gui_panel_layout_flux_fixed(&layout, 180, 1); + state->shelf_selection = gui_panel_shelf_begin(&layout, &tab, shelfs, + LEN(shelfs), state->shelf_selection, state->shelf_scrollbar); + graph_panel(&tab, state->shelf_selection); + state->shelf_scrollbar = gui_panel_shelf_end(&layout, &tab); + + /* Tables */ + gui_panel_layout_flux_fixed(&layout, 180, 1); + gui_panel_group_begin(&layout, &tab, "Table", state->table_scrollbar); + table_panel(&tab); + state->table_scrollbar = gui_panel_group_end(&layout, &tab); + + { + /* Tree */ + struct gui_tree tree; + gui_panel_layout_flux_fixed(&layout, 250, 1); + gui_panel_tree_begin(&layout, &tree, "Tree", 20, state->tree_offset); + upload_tree(&state->tree, &tree, &state->tree.root); + state->tree_offset = gui_panel_tree_end(&layout, &tree); + } + } + gui_panel_end(&layout, &gui->panel); } diff --git a/demo/nanovg.c b/demo/nanovg.c index 1880b40..8a8292d 100644 --- a/demo/nanovg.c +++ b/demo/nanovg.c @@ -122,7 +122,7 @@ draw_image(NVGcontext *ctx, gui_handle img, float x, float y, float w, float h, } static void -execute(NVGcontext *nvg, struct gui_command_buffer *list, int width, int height) +draw(NVGcontext *nvg, struct gui_command_buffer *list, int width, int height) { const struct gui_command *cmd; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT); @@ -174,14 +174,6 @@ execute(NVGcontext *nvg, struct gui_command_buffer *list, int width, int height) glPopAttrib(); } -static void -draw(NVGcontext *nvg,struct gui_stack *stack, int width, int height) -{ - struct gui_panel*iter; - gui_foreach_panel(iter, stack) - execute(nvg, iter->buffer, width, height); -} - static void key(struct gui_input *in, SDL_Event *evt, gui_bool down) { @@ -323,13 +315,11 @@ main(int argc, char *argv[]) /* Draw */ glClearColor(0.4f, 0.4f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - draw(vg, &gui.stack, width, height); - gui.ms = SDL_GetTicks() - started; + draw(vg, &gui.buffer, width, height); SDL_GL_SwapWindow(win); /* Timing */ dt = SDL_GetTicks() - started; - gui.ms = dt; if (dt < DTIME) SDL_Delay(DTIME - dt); } diff --git a/demo/opengl.c b/demo/opengl.c index f142ad7..597eb7b 100644 --- a/demo/opengl.c +++ b/demo/opengl.c @@ -406,7 +406,7 @@ draw_circle(float x, float y, float r, const gui_byte *c) } static void -execute(struct gui_command_buffer *list, int width, int height) +draw(struct gui_command_buffer *list, int width, int height) { const struct gui_command *cmd; glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT); @@ -472,14 +472,6 @@ execute(struct gui_command_buffer *list, int width, int height) glPopAttrib(); } -static void -draw(struct gui_stack *stack, int width, int height) -{ - struct gui_panel*iter; - gui_foreach_panel(iter, stack) - execute(iter->buffer, width, height); -} - static void key(struct gui_input *in, SDL_Event *evt, gui_bool down) { @@ -608,12 +600,11 @@ main(int argc, char *argv[]) /* Draw */ glClearColor(0.4f, 0.4f, 0.4f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); - draw(&gui.stack, width, height); + draw(&gui.buffer, width, height); SDL_GL_SwapWindow(win); /* Timing */ dt = SDL_GetTicks() - started; - gui.ms = dt; if (dt < DTIME) SDL_Delay(DTIME - dt); } diff --git a/demo/xlib.c b/demo/xlib.c index f7f3e3c..717f618 100644 --- a/demo/xlib.c +++ b/demo/xlib.c @@ -324,7 +324,7 @@ surface_del(XSurface *surf) } static void -execute(XSurface *surf, struct gui_command_buffer *buffer) +draw(XSurface *surf, struct gui_command_buffer *buffer) { const struct gui_command *cmd; gui_foreach_command(cmd, buffer) { @@ -367,14 +367,6 @@ execute(XSurface *surf, struct gui_command_buffer *buffer) } } -static void -draw(XSurface *surf, struct gui_stack *stack) -{ - struct gui_panel *iter; - gui_foreach_panel(iter, stack) - execute(surf, iter->buffer); -} - static void key(struct XWindow *xw, struct gui_input *in, XEvent *evt, gui_bool down) { @@ -498,13 +490,12 @@ main(int argc, char *argv[]) /* Draw */ XClearWindow(xw.dpy, xw.win); surface_clear(xw.surf, 0x00646464); - draw(xw.surf, &gui.stack); + draw(xw.surf, &gui.buffer); surface_blit(xw.win, xw.surf, xw.width, xw.height); XFlush(xw.dpy); /* Timing */ dt = timestamp() - started; - gui.ms = (unsigned int)dt; if (dt < DTIME) sleep_for(DTIME - dt); } diff --git a/gui.c b/gui.c index dbec4ea..d1f5c3d 100644 --- a/gui.c +++ b/gui.c @@ -1010,7 +1010,7 @@ gui_edit_box_init(struct gui_edit_box *eb, struct gui_allocator *a, gui_buffer_init(&eb->buffer, a, initial_size, grow_fac); if (clip) eb->clip = *clip; if (f) eb->filter = f; - else eb->filter = gui_filter_input_default; + else eb->filter = gui_filter_default; eb->cursor = 0; eb->glyphes = 0; } @@ -1025,7 +1025,7 @@ gui_edit_box_init_fixed(struct gui_edit_box *eb, void *memory, gui_size size, gui_buffer_init_fixed(&eb->buffer, memory, size); if (clip) eb->clip = *clip; if (f) eb->filter = f; - else eb->filter = gui_filter_input_default; + else eb->filter = gui_filter_default; eb->cursor = 0; eb->glyphes = 0; } @@ -1773,14 +1773,14 @@ gui_editbox(struct gui_command_buffer *out, gui_float x, gui_float y, gui_float } gui_bool -gui_filter_input_default(gui_long unicode) +gui_filter_default(gui_long unicode) { (void)unicode; return gui_true; } gui_bool -gui_filter_input_ascii(gui_long unicode) +gui_filter_ascii(gui_long unicode) { if (unicode < 0 || unicode > 128) return gui_false; @@ -1788,7 +1788,7 @@ gui_filter_input_ascii(gui_long unicode) } gui_bool -gui_filter_input_float(gui_long unicode) +gui_filter_float(gui_long unicode) { if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-') return gui_false; @@ -1796,7 +1796,7 @@ gui_filter_input_float(gui_long unicode) } gui_bool -gui_filter_input_decimal(gui_long unicode) +gui_filter_decimal(gui_long unicode) { if (unicode < '0' || unicode > '9') return gui_false; @@ -1804,7 +1804,7 @@ gui_filter_input_decimal(gui_long unicode) } gui_bool -gui_filter_input_hex(gui_long unicode) +gui_filter_hex(gui_long unicode) { if ((unicode < '0' || unicode > '9') && (unicode < 'a' || unicode > 'f') && @@ -1814,7 +1814,7 @@ gui_filter_input_hex(gui_long unicode) } gui_bool -gui_filter_input_oct(gui_long unicode) +gui_filter_oct(gui_long unicode) { if (unicode < '0' || unicode > '7') return gui_false; @@ -1822,7 +1822,7 @@ gui_filter_input_oct(gui_long unicode) } gui_bool -gui_filter_input_binary(gui_long unicode) +gui_filter_binary(gui_long unicode) { if (unicode < '0' || unicode > '1') return gui_false; @@ -1853,13 +1853,13 @@ gui_edit(struct gui_command_buffer *out, gui_float x, gui_float y, gui_float w, const struct gui_input *in, const struct gui_font *font) { static const gui_filter filter[] = { - gui_filter_input_default, - gui_filter_input_ascii, - gui_filter_input_float, - gui_filter_input_decimal, - gui_filter_input_hex, - gui_filter_input_oct, - gui_filter_input_binary, + gui_filter_default, + gui_filter_ascii, + gui_filter_float, + gui_filter_decimal, + gui_filter_hex, + gui_filter_oct, + gui_filter_binary, }; return gui_edit_filtered(out, x, y, w, h, buffer, len, max, active, field, filter[f], in, font); @@ -2109,6 +2109,7 @@ gui_config_default_properties(struct gui_config *config) config->properties[GUI_PROPERTY_ITEM_SPACING] = gui_vec2(4.0f, 4.0f); config->properties[GUI_PROPERTY_ITEM_PADDING] = gui_vec2(4.0f, 4.0f); config->properties[GUI_PROPERTY_SCALER_SIZE] = gui_vec2(16.0f, 16.0f); + config->properties[GUI_PROPERTY_NODE_SPACING] = gui_vec2(4.0f, 4.0f); } static void @@ -2128,7 +2129,7 @@ gui_config_default_color(struct gui_config *config) config->colors[GUI_COLOR_TEXT] = gui_rgba(135, 135, 135, 255); config->colors[GUI_COLOR_PANEL] = gui_rgba(45, 45, 45, 255); config->colors[GUI_COLOR_HEADER] = gui_rgba(40, 40, 40, 255); - config->colors[GUI_COLOR_BORDER] = gui_rgba(100, 100, 100, 255); + config->colors[GUI_COLOR_BORDER] = gui_rgba(25, 25, 25, 255); config->colors[GUI_COLOR_BUTTON] = gui_rgba(50, 50, 50, 255); config->colors[GUI_COLOR_BUTTON_HOVER] = gui_rgba(35, 35, 35, 255); config->colors[GUI_COLOR_BUTTON_TOGGLE] = gui_rgba(35, 35, 35, 255); @@ -2169,6 +2170,8 @@ gui_config_default_color(struct gui_config *config) config->colors[GUI_COLOR_SCROLLBAR_CURSOR] = gui_rgba(70, 70, 70, 255); config->colors[GUI_COLOR_SCROLLBAR_BORDER] = gui_rgba(45, 45, 45, 255); config->colors[GUI_COLOR_TABLE_LINES] = gui_rgba(100, 100, 100, 255); + config->colors[GUI_COLOR_TAB_HEADER] = gui_rgba(40, 40, 40, 255); + config->colors[GUI_COLOR_TAB_BORDER] = gui_rgba(25, 25, 25, 255); config->colors[GUI_COLOR_SHELF] = gui_rgba(45, 45, 45, 255); config->colors[GUI_COLOR_SHELF_TEXT] = gui_rgba(150, 150, 150, 255); config->colors[GUI_COLOR_SHELF_ACTIVE] = gui_rgba(30, 30, 30, 255); @@ -2469,7 +2472,6 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, if (!(panel->flags & GUI_PANEL_TAB)) { gui_float clicked_x = (in) ? in->mouse_clicked_pos.x : -1; gui_float clicked_y = (in) ? in->mouse_clicked_pos.y : -1; - panel->flags |= GUI_PANEL_SCROLLBAR; if (in && in->mouse_down) { if (GUI_INBOX(clicked_x, clicked_y, panel->x, panel->y, panel->w, panel->h)) panel->flags |= GUI_PANEL_ACTIVE; @@ -2482,7 +2484,6 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, /* calculate the panel footer bounds */ layout->footer_h = scaler_size.y + item_padding.y; if ((layout->flags & GUI_PANEL_SCALEABLE) && - (layout->flags & GUI_PANEL_SCROLLBAR) && !(layout->flags & GUI_PANEL_MINIMIZED)) { gui_float footer_x, footer_y, footer_w; footer_x = panel->x; @@ -2493,7 +2494,7 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, } /* draw panel background if fixed panel size */ - if (layout->flags & GUI_PANEL_SCROLLBAR) { + { const struct gui_color *color = &c->colors[GUI_COLOR_PANEL]; layout->width = panel->w - scrollbar_width; layout->height = panel->h - (layout->header.h + 2 * item_spacing.y); @@ -2513,12 +2514,12 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, layout->clip.x = panel->x; layout->clip.y = panel->y; layout->clip.w = panel->w; - if (layout->flags & GUI_PANEL_SCROLLBAR) { + { if (layout->flags & GUI_PANEL_SCALEABLE) layout->clip.h = panel->h - (layout->footer_h + layout->header.h); else layout->clip.h = panel->h - layout->header.h; layout->clip.h -= (panel_padding.y + item_padding.y); - } else layout->clip.h = gui_null_rect.h; + } gui_command_buffer_push_scissor(out, layout->clip.x, layout->clip.y, layout->clip.w, layout->clip.h); } @@ -2791,7 +2792,7 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) scrollbar_width = gui_config_property(config, GUI_PROPERTY_SCROLLBAR_WIDTH).x; scaler_size = gui_config_property(config, GUI_PROPERTY_SCALER_SIZE); - if (layout->flags & GUI_PANEL_SCROLLBAR && layout->valid) { + if (layout->valid) { struct gui_scroll scroll; gui_float panel_y; gui_float scroll_x, scroll_y; @@ -2837,13 +2838,9 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) if (layout->flags & GUI_PANEL_BORDER) { /* draw the border around the complete panel */ - const gui_float width = (layout->flags & GUI_PANEL_SCROLLBAR) ? - layout->width + scrollbar_width : layout->width; + const gui_float width = layout->width + scrollbar_width; const gui_float padding_y = (!layout->valid) ? - panel->y + layout->header.h: - (panel->flags & GUI_PANEL_SCROLLBAR) ? - layout->y + layout->h : - panel->y + layout->height + item_padding.y; + panel->y + layout->header.h: layout->y + layout->h; if (panel->flags & GUI_PANEL_BORDER_HEADER) gui_command_buffer_push_line(out, panel->x, panel->y + layout->header.h, @@ -2904,7 +2901,7 @@ gui_panel_header_begin(struct gui_panel_layout *layout) layout->header.back = layout->header.x + layout->header.w; /* setup and draw panel layout footer and header background */ - if (layout->flags & GUI_PANEL_SCROLLBAR) { + { const struct gui_color *color = &c->colors[GUI_COLOR_PANEL]; layout->height = layout->h - (layout->header.h + 2 * item_spacing.y); if (layout->flags & GUI_PANEL_SCALEABLE) layout->height -= layout->footer_h; @@ -3165,7 +3162,7 @@ gui_panel_header_end(struct gui_panel_layout *layout) item_padding = gui_config_property(c, GUI_PROPERTY_ITEM_PADDING); /* draw scrollbar panel footer */ - if (layout->flags & GUI_PANEL_SCROLLBAR) { + { const struct gui_color *color = &c->colors[GUI_COLOR_PANEL]; if (layout->valid) gui_command_buffer_push_rect(out, layout->x, layout->y + layout->header.h, @@ -3175,8 +3172,7 @@ gui_panel_header_end(struct gui_panel_layout *layout) /* draw panel header border */ if (layout->flags & GUI_PANEL_BORDER) { gui_float scrollbar_width = gui_config_property(c, GUI_PROPERTY_SCROLLBAR_WIDTH).x; - const gui_float width = (layout->flags & GUI_PANEL_SCROLLBAR) ? - layout->width + scrollbar_width : layout->width; + const gui_float width = layout->width + scrollbar_width; /* draw the header border lines */ gui_command_buffer_push_line(out, layout->x, layout->y, layout->x, @@ -3193,12 +3189,12 @@ gui_panel_header_end(struct gui_panel_layout *layout) layout->clip.x = layout->x; layout->clip.w = layout->w; layout->clip.y = layout->y + layout->header.h; - if (layout->flags & GUI_PANEL_SCROLLBAR) { - if (layout->flags & GUI_PANEL_SCALEABLE) - layout->clip.h = layout->h - (layout->footer_h + layout->header.h); - else layout->clip.h = layout->h - layout->header.h; - layout->clip.h -= (panel_padding.y + item_padding.y); - } else layout->clip.h = gui_null_rect.h; + + if (layout->flags & GUI_PANEL_SCALEABLE) + layout->clip.h = layout->h - (layout->footer_h + layout->header.h); + else layout->clip.h = layout->h - layout->header.h; + layout->clip.h -= (panel_padding.y + item_padding.y); + gui_command_buffer_push_scissor(out, layout->clip.x, layout->clip.y, layout->clip.w, layout->clip.h); } @@ -3276,12 +3272,10 @@ gui_panel_menu_end(struct gui_panel_layout *layout) layout->height -= layout->menu.h; layout->offset = layout->menu.offset; - if (layout->flags & GUI_PANEL_SCROLLBAR) { - if (layout->flags & GUI_PANEL_SCALEABLE) - layout->clip.h = layout->h - (layout->footer_h + layout->header.h + layout->menu.h); - else layout->clip.h = layout->h - (layout->header.h + layout->menu.h); - layout->clip.h -= (panel_padding.y + item_padding.y); - } else layout->clip.h = gui_null_rect.h; + if (layout->flags & GUI_PANEL_SCALEABLE) + layout->clip.h = layout->h - (layout->footer_h + layout->header.h + layout->menu.h); + else layout->clip.h = layout->h - (layout->header.h + layout->menu.h); + layout->clip.h -= (panel_padding.y + item_padding.y); gui_command_buffer_push_scissor(out, layout->clip.x, layout->clip.y, layout->clip.w, layout->clip.h); } @@ -3574,6 +3568,8 @@ gui_panel_layout_static_begin(struct gui_panel_layout *layout, gui_float height, gui_unify(&clip, &layout->clip, space.x, space.y, space.x + space.w, space.y + space.h); gui_command_buffer_push_scissor(layout->buffer, clip.x, clip.y, clip.w, clip.h); + layout->row.clip = layout->clip; + layout->clip = clip; } void @@ -3598,6 +3594,7 @@ gui_panel_layout_static_end(struct gui_panel_layout *layout) layout->row.item_width = 0; layout->row.item_height = 0; layout->row.item_offset = 0; + layout->clip = layout->row.clip; gui_command_buffer_push_scissor(layout->buffer, layout->clip.x, layout->clip.y, layout->clip.w, layout->clip.h); } @@ -3722,6 +3719,136 @@ gui_panel_alloc_space(struct gui_rect *bounds, struct gui_panel_layout *layout) layout->row.index++; } +gui_bool +gui_panel_layout_push(struct gui_panel_layout *layout, + enum gui_panel_layout_node_type type, + const char *title, enum gui_node_state *state) +{ + const struct gui_config *config; + struct gui_command_buffer *out; + struct gui_vec2 item_spacing; + struct gui_vec2 item_padding; + struct gui_vec2 panel_padding; + struct gui_vec2 node_spacing; + struct gui_rect header; + struct gui_rect sym; + + GUI_ASSERT(layout); + GUI_ASSERT(layout->config); + GUI_ASSERT(layout->buffer); + + if (!layout) return gui_false; + if (!layout->valid) return gui_false; + + /* cache some data */ + out = layout->buffer; + config = layout->config; + + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + panel_padding = gui_config_property(config, GUI_PROPERTY_PADDING); + node_spacing = gui_config_property(config, GUI_PROPERTY_NODE_SPACING); + + /* calculate header bounds and draw background */ + gui_panel_layout(layout, config->font.height + 4 * item_padding.y, 1); + gui_panel_alloc_space(&header, layout); + if (type == GUI_LAYOUT_TAB) + gui_command_buffer_push_rect(out, header.x, header.y, header.w, header.h, + 0, config->colors[GUI_COLOR_TAB_HEADER]); + + { + /* and draw closing/open icon */ + enum gui_heading heading; + struct gui_vec2 points[3]; + heading = (*state == GUI_MAXIMIZED) ? GUI_DOWN : GUI_RIGHT; + + sym.w = sym.h = config->font.height; + sym.y = header.y + item_padding.y + config->font.height/2; + sym.x = header.x + panel_padding.x; + + /* calculate the triangle point positions and draw triangle */ + gui_triangle_from_direction(points, sym.x, sym.y, sym.w, sym.h, 0, 0, heading); + gui_command_buffer_push_triangle(layout->buffer, points[0].x, points[0].y, + points[1].x, points[1].y, points[2].x, points[2].y, config->colors[GUI_COLOR_TEXT]); + + /* calculate the space the icon occupied */ + sym.w = config->font.height + 2 * item_padding.x; + } + { + /* draw node label */ + struct gui_color color; + struct gui_rect label; + gui_size text_len; + + header.w = MAX(header.w, sym.w + item_spacing.y + panel_padding.x); + label.x = sym.x + sym.w + item_spacing.x; + label.y = sym.y; + label.w = header.w - (sym.w + item_spacing.y + panel_padding.x); + label.h = config->font.height; + text_len = gui_strsiz(title); + color = (type == GUI_LAYOUT_TAB) ? config->colors[GUI_COLOR_TAB_HEADER]: + config->colors[GUI_COLOR_PANEL]; + + gui_command_buffer_push_text(out, label.x, label.y, label.w, label.h, + (const gui_char*)title, text_len, &config->font, + color, config->colors[GUI_COLOR_TEXT]); + } + + /* update node state */ + if (layout->input) { + gui_float clicked_x = layout->input->mouse_clicked_pos.x; + gui_float clicked_y = layout->input->mouse_clicked_pos.y; + gui_float mouse_x = layout->input->mouse_pos.x; + gui_float mouse_y = layout->input->mouse_pos.y; + if (GUI_INBOX(mouse_x, mouse_y, sym.x, sym.y, sym.w, sym.h)) { + if (GUI_INBOX(clicked_x, clicked_y, sym.x, sym.y, sym.w, sym.h)) { + if (layout->input->mouse_down && layout->input->mouse_clicked) + *state = (*state == GUI_MAXIMIZED) ? GUI_MINIMIZED : GUI_MAXIMIZED; + } + } + } + + if (type == GUI_LAYOUT_TAB) { + /* special node with border around the header */ + gui_command_buffer_push_line(out, header.x, header.y, + header.x + header.w, header.y, config->colors[GUI_COLOR_TAB_BORDER]); + gui_command_buffer_push_line(out, header.x, header.y, + header.x, header.y + header.h, config->colors[GUI_COLOR_TAB_BORDER]); + gui_command_buffer_push_line(out, header.x + header.w, header.y, + header.x + header.w, header.y + header.h, config->colors[GUI_COLOR_TAB_BORDER]); + gui_command_buffer_push_line(out, header.x, header.y + header.h, + header.x + header.w, header.y + header.h, config->colors[GUI_COLOR_TAB_BORDER]); + } + + if (*state == GUI_MAXIMIZED) { + layout->at_x = header.x + node_spacing.x; + layout->width = MAX(layout->width, 2 * panel_padding.x + node_spacing.x); + layout->width -= 2 * panel_padding.x + node_spacing.x; + return gui_true; + } else return gui_false; +} + +void +gui_panel_layout_pop(struct gui_panel_layout *layout) +{ + const struct gui_config *config; + struct gui_vec2 panel_padding; + struct gui_vec2 node_spacing; + + GUI_ASSERT(layout); + GUI_ASSERT(layout->config); + GUI_ASSERT(layout->buffer); + + if (!layout) return; + if (!layout->valid) return; + + config = layout->config; + panel_padding = gui_config_property(config, GUI_PROPERTY_PADDING); + node_spacing = gui_config_property(config, GUI_PROPERTY_NODE_SPACING); + layout->at_x -= panel_padding.x + node_spacing.x; + layout->width += 2 * panel_padding.x + node_spacing.x; +} + /* * ------------------------------------------------------------- * @@ -4586,13 +4713,14 @@ gui_panel_graph_ex(struct gui_panel_layout *layout, enum gui_graph_type type, static void gui_panel_table_horizontal_line(struct gui_panel_layout *l, gui_size row_height) { + gui_float x, y, w; struct gui_command_buffer *out = l->buffer; const struct gui_config *c = l->config; const struct gui_vec2 item_padding = gui_config_property(c, GUI_PROPERTY_ITEM_PADDING); const struct gui_vec2 item_spacing = gui_config_property(c, GUI_PROPERTY_ITEM_SPACING); + if (!l->valid) return; /* draws a horizontal line under the current item */ - gui_float x, y, w; w = MAX(l->width, (2 * item_spacing.x + 2 * item_padding.x)); y = (l->at_y + (gui_float)row_height + item_padding.y) - l->offset; x = l->at_x + item_spacing.x + item_padding.x; @@ -4610,6 +4738,7 @@ gui_panel_table_vertical_line(struct gui_panel_layout *layout, gui_size cols) GUI_ASSERT(layout); GUI_ASSERT(cols); if (!layout || !cols) return; + if (!layout->valid) return; out = layout->buffer; config = layout->config; @@ -4650,6 +4779,7 @@ gui_panel_table_row(struct gui_panel_layout *layout) struct gui_vec2 item_spacing; GUI_ASSERT(layout); if (!layout) return; + if (!layout->valid) return; config = layout->config; item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); @@ -4667,6 +4797,190 @@ gui_panel_table_end(struct gui_panel_layout *layout) layout->is_table = gui_false; } +/* + * ------------------------------------------------------------- + * + * TREE + * + * -------------------------------------------------------------- + */ +void +gui_panel_tree_begin(struct gui_panel_layout *p, struct gui_tree *tree, + const char *title, gui_float height, gui_float offset) +{ + struct gui_vec2 padding; + const struct gui_config *config; + gui_panel_group_begin(p, &tree->group, title, offset); + gui_panel_layout(&tree->group, height, 1); + + config = tree->group.config; + padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + + tree->at_x = 0; + tree->skip = -1; + tree->depth = 0; + tree->x_off = tree->group.config->font.height + 2 * padding.x; +} + +static enum gui_tree_node_operation +gui_panel_tree_node(struct gui_tree *tree, enum gui_tree_node_symbol symbol, + const char *title, struct gui_image *img, gui_tree_node_state *state) +{ + struct gui_text text; + struct gui_rect bounds = {0,0,0,0}; + struct gui_rect sym, label, icon; + + const struct gui_input *i; + const struct gui_config *config; + struct gui_vec2 item_padding; + struct gui_color col; + + enum gui_tree_node_operation op = GUI_NODE_NOP; + struct gui_panel_layout *layout = &tree->group; + if (tree->skip >= 0 || !gui_panel_widget(&bounds, layout)) { + if (!tree->depth) tree->at_x = bounds.x; + return op; + } + + if (tree->depth){ + bounds.w = (bounds.x + bounds.w) - tree->at_x; + bounds.x = tree->at_x; + } else tree->at_x = bounds.x; + + /* fetch some configuration constants */ + i = layout->input; + config = layout->config; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + col = gui_config_color(config, GUI_COLOR_TEXT); + + /* calculate symbol bounds */ + sym.x = bounds.x; + sym.y = bounds.y + (bounds.h/2) - (config->font.height/2); + sym.w = config->font.height; + sym.h = config->font.height; + + if (img) { + icon.x = sym.x + sym.w + item_padding.x; + icon.y = sym.y; + icon.w = bounds.h; + icon.h = bounds.h; + label.x = icon.x + icon.w + item_padding.x; + } else label.x = sym.x + sym.w + item_padding.x; + + /* calculate text bounds */ + label.y = bounds.y; + label.h = bounds.h; + label.w = bounds.w - (sym.w + 2 * item_padding.x); + + /* output symbol */ + if (symbol == GUI_TREE_NODE_TRIANGLE) { + /* parent node */ + struct gui_vec2 points[3]; + enum gui_heading heading; + if (gui_input_clicked(i, &sym)) { + if (*state & GUI_NODE_ACTIVE) + *state &= ~(gui_flags)GUI_NODE_ACTIVE; + else *state |= GUI_NODE_ACTIVE; + } + + heading = (*state & GUI_NODE_ACTIVE) ? GUI_DOWN : GUI_RIGHT; + gui_triangle_from_direction(points, sym.x, sym.y, sym.w, sym.h, 0, 0, heading); + gui_command_buffer_push_triangle(layout->buffer, points[0].x, points[0].y, + points[1].x, points[1].y, points[2].x, points[2].y, col); + } else { + /* leaf node */ + gui_command_buffer_push_circle(layout->buffer, sym.x, sym.y, sym.w, sym.h, col); + } + + /* node selection */ + if (gui_input_clicked(i, &label)) { + if (*state & GUI_NODE_SELECTED) + *state &= ~(gui_flags)GUI_NODE_SELECTED; + else *state |= GUI_NODE_SELECTED; + } + + { + /* tree node opderations */ + if (gui_input_pressed(i, GUI_KEY_DEL) && (*state & GUI_NODE_SELECTED)) { + *state &= ~(gui_flags)GUI_NODE_SELECTED; + op = GUI_NODE_DELETE; + } + if (gui_input_pressed(i, GUI_KEY_COPY) && (*state & GUI_NODE_SELECTED)) { + *state &= ~(gui_flags)GUI_NODE_SELECTED; + op = GUI_NODE_CLONE; + } + if (gui_input_pressed(i, GUI_KEY_CUT) && (*state & GUI_NODE_SELECTED)) { + *state &= ~(gui_flags)GUI_NODE_SELECTED; + op = GUI_NODE_CUT; + } + if (gui_input_pressed(i, GUI_KEY_PASTE) && (*state & GUI_NODE_SELECTED)) { + *state &= ~(gui_flags)GUI_NODE_SELECTED; + op = GUI_NODE_PASTE; + } + } + + /* output label */ + text.padding.x = item_padding.x; + text.padding.y = item_padding.y; + text.foreground = config->colors[GUI_COLOR_TEXT]; + text.background = (*state & GUI_NODE_SELECTED) ? + config->colors[GUI_COLOR_BUTTON_HOVER]: + config->colors[GUI_COLOR_PANEL]; + gui_text(layout->buffer,label.x,label.y,label.w,label.h, title, gui_strsiz(title), + &text, GUI_TEXT_LEFT, &config->font); + return op; +} + +enum gui_tree_node_operation +gui_panel_tree_begin_node(struct gui_tree *tree, const char *title, + gui_tree_node_state *state) +{ + enum gui_tree_node_operation op; + op = gui_panel_tree_node(tree, GUI_TREE_NODE_TRIANGLE, title, 0, state); + tree->at_x += tree->x_off; + if (tree->skip < 0 && !(*state & GUI_NODE_ACTIVE)) + tree->skip = tree->depth; + tree->depth++; + return op; +} + +enum gui_tree_node_operation +gui_panel_tree_begin_node_icon(struct gui_tree *tree, const char *title, + struct gui_image img, gui_tree_node_state *state) +{ + enum gui_tree_node_operation op; + op = gui_panel_tree_node(tree, GUI_TREE_NODE_TRIANGLE, title, &img, state); + tree->at_x += tree->x_off; + if (tree->skip < 0 && !(*state & GUI_NODE_ACTIVE)) + tree->skip = tree->depth; + tree->depth++; + return op; +} + +enum gui_tree_node_operation +gui_panel_tree_leaf(struct gui_tree *tree, const char *title, + gui_tree_node_state *state) +{return gui_panel_tree_node(tree, GUI_TREE_NODE_BULLET, title, 0, state);} + +enum gui_tree_node_operation +gui_panel_tree_leaf_icon(struct gui_tree *tree, const char *title, struct gui_image img, + gui_tree_node_state *state) +{return gui_panel_tree_node(tree, GUI_TREE_NODE_BULLET, title, &img, state);} + +void +gui_panel_tree_end_node(struct gui_tree *tree) +{ + GUI_ASSERT(tree->depth); + tree->depth--; + tree->at_x -= tree->x_off; + if (tree->skip == tree->depth) + tree->skip = -1; +} + +gui_float +gui_panel_tree_end(struct gui_panel_layout *p, struct gui_tree* tree) +{return gui_panel_group_end(p, &tree->group);} + /* * ------------------------------------------------------------- * @@ -4674,88 +4988,6 @@ gui_panel_table_end(struct gui_panel_layout *layout) * * -------------------------------------------------------------- */ -gui_bool -gui_panel_tab_begin(struct gui_panel_layout *parent, struct gui_panel_layout *tab, - const char *title, gui_bool border, gui_bool minimized) -{ - struct gui_rect bounds; - struct gui_command_buffer *out; - struct gui_panel panel; - struct gui_rect clip; - gui_flags flags = 0; - - GUI_ASSERT(parent); - GUI_ASSERT(tab); - if (!parent || !tab) return gui_true; - out = parent->buffer; - gui_zero(tab, sizeof(*tab)); - tab->valid = !minimized; - - if (!parent->valid) { - tab->valid = gui_false; - tab->config = parent->config; - tab->buffer = parent->buffer; - tab->input = parent->input; - return minimized; - } - - /* NOTE: tabs need to allocate a complete row since the size of the tab is - * not known beforehand. */ - parent->row.index = 0; - gui_panel_layout_flux_fixed(parent, 0, 1); - gui_panel_alloc_space(&bounds, parent); - - /* create a fake panel to create a panel layout from */ - flags = GUI_PANEL_TAB; - if (border) flags |= GUI_PANEL_BORDER|GUI_PANEL_BORDER_HEADER; - if (minimized) flags |= GUI_PANEL_MINIMIZED; - gui_panel_init(&panel, bounds.x, bounds.y, bounds.w, - gui_null_rect.h,flags,out,parent->config); - - gui_panel_begin(tab, &panel, parent->input); - gui_unify(&clip, &parent->clip, tab->clip.x, tab->clip.y, tab->clip.x + tab->clip.w, - tab->clip.y + tab->clip.h); - gui_command_buffer_push_scissor(out, clip.x, clip.y, clip.w, clip.h); - gui_panel_header(tab, title, GUI_MINIMIZABLE, 0, GUI_HEADER_LEFT); - - /* calculate the tab clipping rect */ - gui_unify(&clip, &parent->clip, tab->clip.x, tab->clip.y, tab->clip.x + tab->clip.w, - tab->clip.y + tab->clip.h); - gui_command_buffer_push_scissor(out, clip.x, clip.y, clip.w, clip.h); - tab->clip = clip; - return (tab->flags & GUI_PANEL_MINIMIZED) ? gui_true : gui_false; -} - -void -gui_panel_tab_end(struct gui_panel_layout *p, struct gui_panel_layout *t) -{ - struct gui_panel panel; - struct gui_command_buffer *out; - struct gui_vec2 item_spacing; - struct gui_vec2 panel_padding; - GUI_ASSERT(t); - GUI_ASSERT(p); - if (!p || !t || !p->valid) - return; - - /* setup fake panel to end the tab */ - panel.x = t->at_x; - panel.y = t->y; - panel.w = t->width; - panel.h = t->height; - panel.flags = t->flags|GUI_PANEL_BORDER|GUI_PANEL_BORDER_HEADER; - gui_panel_end(t, &panel); - - /*calculate the from the tab occupied space and allocate it in the parent panel */ - item_spacing = gui_config_property(p->config, GUI_PROPERTY_ITEM_SPACING); - panel_padding = gui_config_property(p->config, GUI_PROPERTY_PADDING); - if (t->valid) - p->at_y += t->height + 2 * item_spacing.y; - else p->at_y += t->height - panel_padding.x + 2 * item_spacing.y; - out = p->buffer; - gui_command_buffer_push_scissor(out, p->clip.x, p->clip.y, p->clip.w, p->clip.h); -} - void gui_panel_group_begin(struct gui_panel_layout *p, struct gui_panel_layout *g, const char *title, gui_float offset) @@ -4782,7 +5014,7 @@ gui_panel_group_begin(struct gui_panel_layout *p, struct gui_panel_layout *g, /* initialize a fake panel to create the layout from */ out = p->buffer; - flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB; + flags = GUI_PANEL_BORDER|GUI_PANEL_TAB; gui_panel_init(&panel, bounds.x, bounds.y,bounds.w,bounds.h,flags, out, p->config); gui_panel_begin(g, &panel, p->input); g->offset = offset; @@ -4827,7 +5059,7 @@ gui_panel_group_end(struct gui_panel_layout *p, struct gui_panel_layout *g) pan.y = g->y; pan.w = g->width; pan.h = g->height; - pan.flags = GUI_PANEL_BORDER|GUI_PANEL_TAB|GUI_PANEL_SCROLLBAR; + pan.flags = GUI_PANEL_BORDER|GUI_PANEL_TAB; /* setup clipping rect to finalize group panel drawing*/ gui_unify(&clip, &p->clip, g->clip.x, g->clip.y, g->x + g->w, g->y + g->h); @@ -4939,7 +5171,7 @@ gui_panel_shelf_begin(struct gui_panel_layout *parent, struct gui_panel_layout * bounds.h -= header_h; /* setup fake panel to create a panel layout from */ - flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB; + flags = GUI_PANEL_BORDER|GUI_PANEL_TAB; gui_panel_init(&panel, bounds.x, bounds.y, bounds.w, bounds.h, flags, out, config); gui_panel_begin(shelf, &panel, parent->input); shelf->offset = offset; @@ -4975,7 +5207,7 @@ gui_panel_shelf_end(struct gui_panel_layout *p, struct gui_panel_layout *s) out = p->buffer; pan.x = s->at_x; pan.y = s->y; - pan.flags = GUI_PANEL_BORDER|GUI_PANEL_TAB|GUI_PANEL_SCROLLBAR; + pan.flags = GUI_PANEL_BORDER|GUI_PANEL_TAB; gui_unify(&clip, &p->clip, s->clip.x, s->clip.y, s->x + s->w, s->y + s->h); gui_command_buffer_push_scissor(out, clip.x, clip.y, clip.w, clip.h); diff --git a/gui.h b/gui.h index fda12fa..e307b63 100644 --- a/gui.h +++ b/gui.h @@ -25,8 +25,6 @@ extern "C" { #endif /* Constants */ -#define GUI_BORDER gui_true -#define GUI_NO_BORDER gui_false #define GUI_UTF_INVALID 0xFFFD #define GUI_UTF_SIZE 4 /* describes the number of bytes a glyph consists of*/ @@ -702,21 +700,27 @@ struct gui_clipboard { typedef struct gui_buffer gui_edit_buffer; struct gui_edit_box { gui_edit_buffer buffer; + /* glyph buffer to add text into */ gui_bool active; + /* flag indicating if the buffer is currently being modified */ gui_size cursor; + /* current glyph (not byte) cursor position */ gui_size glyphes; + /* number of glyphes inside the edit box */ struct gui_clipboard clip; + /* copy paste callbacks */ gui_filter filter; + /* input filter callback */ }; /* filter function */ -gui_bool gui_filter_input_default(gui_long unicode); -gui_bool gui_filter_input_ascii(gui_long unicode); -gui_bool gui_filter_input_float(gui_long unicode); -gui_bool gui_filter_input_decimal(gui_long unicode); -gui_bool gui_filter_input_hex(gui_long unicode); -gui_bool gui_filter_input_oct(gui_long unicode); -gui_bool gui_filter_input_binary(gui_long unicode); +gui_bool gui_filter_default(gui_long unicode); +gui_bool gui_filter_ascii(gui_long unicode); +gui_bool gui_filter_float(gui_long unicode); +gui_bool gui_filter_decimal(gui_long unicode); +gui_bool gui_filter_hex(gui_long unicode); +gui_bool gui_filter_oct(gui_long unicode); +gui_bool gui_filter_binary(gui_long unicode); /* editbox */ void gui_edit_box_init(struct gui_edit_box*, struct gui_allocator*, gui_size initial, @@ -1377,6 +1381,8 @@ enum gui_config_colors { GUI_COLOR_SCROLLBAR_CURSOR, GUI_COLOR_SCROLLBAR_BORDER, GUI_COLOR_TABLE_LINES, + GUI_COLOR_TAB_HEADER, + GUI_COLOR_TAB_BORDER, GUI_COLOR_SHELF, GUI_COLOR_SHELF_TEXT, GUI_COLOR_SHELF_ACTIVE, @@ -1403,6 +1409,7 @@ enum gui_config_properties { GUI_PROPERTY_SCALER_SIZE, GUI_PROPERTY_SCROLLBAR_WIDTH, GUI_PROPERTY_SIZE, + GUI_PROPERTY_NODE_SPACING, GUI_PROPERTY_MAX }; @@ -1584,86 +1591,6 @@ enum gui_widget_state { GUI_ROM /* The widget is partially visible and cannot be updated */ }; -enum gui_table_lines { - GUI_TABLE_HHEADER = 0x01, - /* Horizontal table header lines */ - GUI_TABLE_VHEADER = 0x02, - /* Vertical table header lines */ - GUI_TABLE_HBODY = 0x04, - /* Horizontal table body lines */ - GUI_TABLE_VBODY = 0x08 - /* Vertical table body lines */ -}; - -enum gui_graph_type { - GUI_GRAPH_LINES, - /* Line graph with each data point being connected with its previous and next node */ - GUI_GRAPH_COLUMN, - /* Column graph/Histogram with value represented as bars */ - GUI_GRAPH_MAX -}; - -struct gui_graph { - gui_bool valid; - /* graph valid flag to make sure that the graph is visible */ - enum gui_graph_type type; - /* graph type with either line or column graph */ - gui_float x, y; - /* graph canvas space position */ - gui_float w, h; - /* graph canvas space size */ - gui_float min, max; - /* min and max value for correct scaling of values */ - struct gui_vec2 last; - /* last line graph point to connect to. Only used by the line graph */ - gui_size index; - /* current graph value index*/ - gui_size count; - /* number of values inside the graph */ -}; - -enum gui_panel_tab { - GUI_MAXIMIZED = gui_false, - /* Flag indicating that the panel tab is open */ - GUI_MINIMIZED = gui_true - /* Flag indicating that the panel tab is closed */ -}; - -enum gui_panel_header_flags { - GUI_CLOSEABLE = 0x01, - /* adds a closeable icon into the header */ - GUI_MINIMIZABLE = 0x02, - /* adds a minimize icon into the header */ - GUI_SCALEABLE = 0x04, - /* adds a scaleable flag icon into the header */ - GUI_MOVEABLE = 0x08 - /* adds a moveable flag icon into the header */ -}; - -enum gui_panel_header_symbol { - GUI_SYMBOL_X, - GUI_SYMBOL_UNDERSCORE, - GUI_SYMBOL_CIRCLE, - GUI_SYMBOL_CIRCLE_FILLED, - GUI_SYMBOL_RECT, - GUI_SYMBOL_RECT_FILLED, - GUI_SYMBOL_TRIANGLE_UP, - GUI_SYMBOL_TRIANGLE_DOWN, - GUI_SYMBOL_TRIANGLE_LEFT, - GUI_SYMBOL_TRIANGLE_RIGHT, - GUI_SYMBOL_PLUS, - GUI_SYMBOL_MINUS, - GUI_SYMBOL_IMAGE, - GUI_SYMBOL_MAX -}; - -enum gui_panel_header_align { - GUI_HEADER_LEFT, - /* header elements are added at the left side of the header */ - GUI_HEADER_RIGHT - /* header elements are added at the right side of the header */ -}; - enum gui_panel_flags { GUI_PANEL_HIDDEN = 0x01, /* Hiddes the panel and stops any panel interaction and drawing can be set @@ -1683,9 +1610,6 @@ enum gui_panel_flags { /* marks the panel as minimized */ GUI_PANEL_ACTIVE = 0x40, /* INTERNAL ONLY!: marks the panel as active, used by the panel stack */ - GUI_PANEL_SCROLLBAR = 0x80, - /* INTERNAL ONLY!: adds a scrollbar to the panel which enables fixed size - * panels with unlimited amount of space to fill */ GUI_PANEL_TAB = 0x100, /* INTERNAL ONLY!: Marks the panel as an subpanel of another panel(Groups/Tabs/Shelf)*/ GUI_PANEL_DO_NOT_RESET = 0x200 @@ -1730,6 +1654,16 @@ enum gui_panel_row_layout_type { /* retain mode widget specific widget pixel width layout */ }; +enum gui_node_state { + GUI_MINIMIZED = gui_false, + GUI_MAXIMIZED = gui_true +}; + +enum gui_panel_layout_node_type { + GUI_LAYOUT_NODE, + GUI_LAYOUT_TAB +}; + #define GUI_UNDEFINED (-1.0f) struct gui_panel_row_layout { enum gui_panel_row_layout_type type; @@ -1750,19 +1684,22 @@ struct gui_panel_row_layout { /* total fill ratio */ struct gui_rect item; /* item bounds */ + struct gui_rect clip; + /* temporary clipping rect */ }; struct gui_panel_header { gui_float x, y, w, h; /* header bounds */ gui_float front, back; - /* header filling stack */ + /* visual header filling deque */ }; struct gui_panel_menu { gui_float x, y, w, h; /* menu bounds */ gui_float offset; + /* saved panel scrollbar offset */ }; struct gui_panel_layout { @@ -1942,6 +1879,41 @@ void gui_panel_end(struct gui_panel_layout*, struct gui_panel*); gui_panel_menu_begin -- marks the beginning of the menubar building process gui_panel_menu_end -- marks the end the menubar build up process */ +enum gui_panel_header_flags { + GUI_CLOSEABLE = 0x01, + /* adds a closeable icon into the header */ + GUI_MINIMIZABLE = 0x02, + /* adds a minimize icon into the header */ + GUI_SCALEABLE = 0x04, + /* adds a scaleable flag icon into the header */ + GUI_MOVEABLE = 0x08 + /* adds a moveable flag icon into the header */ +}; + +enum gui_panel_header_symbol { + GUI_SYMBOL_X, + GUI_SYMBOL_UNDERSCORE, + GUI_SYMBOL_CIRCLE, + GUI_SYMBOL_CIRCLE_FILLED, + GUI_SYMBOL_RECT, + GUI_SYMBOL_RECT_FILLED, + GUI_SYMBOL_TRIANGLE_UP, + GUI_SYMBOL_TRIANGLE_DOWN, + GUI_SYMBOL_TRIANGLE_LEFT, + GUI_SYMBOL_TRIANGLE_RIGHT, + GUI_SYMBOL_PLUS, + GUI_SYMBOL_MINUS, + GUI_SYMBOL_IMAGE, + GUI_SYMBOL_MAX +}; + +enum gui_panel_header_align { + GUI_HEADER_LEFT, + /* header elements are added at the left side of the header */ + GUI_HEADER_RIGHT + /* header elements are added at the right side of the header */ +}; + void gui_panel_header_begin(struct gui_panel_layout*); /* this function begins the panel header build up process */ gui_bool gui_panel_header_button(struct gui_panel_layout *layout, @@ -2061,7 +2033,27 @@ void gui_panel_menu_end(struct gui_panel_layout*); gui_panel_layout_static_begin -- creates a free drawing space in the panel gui_panel_layout_static_widget -- pushes a widget into the space gui_panel_layout_static_end -- finishes the free drawingp process + + panel tree layout function API + gui_panel_layout_push -- pushes a new node/collapseable header/tab + gui_panel_layout_pop -- pops the the previously added node + */ +gui_bool gui_panel_layout_push(struct gui_panel_layout*, + enum gui_panel_layout_node_type, + const char *title, enum gui_node_state*); +/* this functions pushes either a tree node, collapseable header or tab into + * the current panel layout + Input: + - title of the node to push into the panel + - type of then node with either default node, collapseable header or tab + - state of the node with either GUI_MINIMIZED or GUI_MAXIMIZED + Output: + - returns the updated state as either gui_true if open and gui_false otherwise + - updates the state of the node pointer to the updated state +*/ +void gui_panel_layout_pop(struct gui_panel_layout*); +/* this functions ends the previously added node */ void gui_panel_layout_flux_fixed(struct gui_panel_layout*, gui_float row_height, gui_size cols); /* this function sets the current row layout to a scaleable table like layout where each widget occupies a fixed ratio of the panel width @@ -2442,8 +2434,84 @@ gui_size gui_panel_selector(struct gui_panel_layout*, const char *items[], gui_panel_table_begin -- begin table build up process gui_panel_table_row -- seperates tables rows gui_panel_table_end -- ends the table build up process - + gui_panel_tree_begin -- begins the tree build up processs + gui_panel_tree_begin_node -- adds and opens a normal node to the tree + gui_panel_tree_begin_node_icon -- adds a opens a node with an icon to the tree + gui_panel_tree_end_node -- ends and closes a previously added node + gui_panel_tree_leaf -- adds a leaf node to a prev opened node + gui_panel_tree_leaf_icon -- adds a leaf icon node to a prev opended node + gui_panel_tree_end -- ends the tree build up process */ +enum gui_table_lines { + GUI_TABLE_HHEADER = 0x01, + /* Horizontal table header lines */ + GUI_TABLE_VHEADER = 0x02, + /* Vertical table header lines */ + GUI_TABLE_HBODY = 0x04, + /* Horizontal table body lines */ + GUI_TABLE_VBODY = 0x08 + /* Vertical table body lines */ +}; + +enum gui_graph_type { + GUI_GRAPH_LINES, + /* Line graph with each data point being connected with its previous and next node */ + GUI_GRAPH_COLUMN, + /* Column graph/Histogram with value represented as bars */ + GUI_GRAPH_MAX +}; + +struct gui_graph { + gui_bool valid; + /* graph valid flag to make sure that the graph is visible */ + enum gui_graph_type type; + /* graph type with either line or column graph */ + gui_float x, y; + /* graph canvas space position */ + gui_float w, h; + /* graph canvas space size */ + gui_float min, max; + /* min and max value for correct scaling of values */ + struct gui_vec2 last; + /* last line graph point to connect to. Only used by the line graph */ + gui_size index; + /* current graph value index*/ + gui_size count; + /* number of values inside the graph */ +}; + +typedef gui_flags gui_tree_node_state; +enum gui_tree_nodes_states { + GUI_NODE_ACTIVE = 0x01, + /* the node is currently opened */ + GUI_NODE_SELECTED = 0x02 + /* the node has been seleted by the user */ +}; + +enum gui_tree_node_operation { + GUI_NODE_NOP, + /* node did not receive a command */ + GUI_NODE_CUT, + /* cut the node from the current tree and add into a buffer */ + GUI_NODE_CLONE, + /* copy current node and add copy into the parent node */ + GUI_NODE_PASTE, + /* paste all node in the buffer into the tree */ + GUI_NODE_DELETE + /* remove the node from the parent tree */ +}; + +struct gui_tree { + struct gui_panel_layout group; + /* panel to add the tree into */ + gui_float x_off, at_x; + /* current x position of the next node */ + gui_int skip; + /* flag that indicates that a node will be skipped */ + gui_int depth; + /* current depth of the tree */ +}; + void gui_panel_graph_begin(struct gui_panel_layout*, struct gui_graph*, enum gui_graph_type, gui_size count, gui_float min, gui_float max); @@ -2499,6 +2567,60 @@ void gui_panel_table_end(struct gui_panel_layout*); /* this function finished the table build up process and reverts the panel back to its normal state. */ +void gui_panel_tree_begin(struct gui_panel_layout*, struct gui_tree*, + const char*, gui_float row_height, gui_float offset); +/* this function begins the tree building process + Input: + - title describing the tree or NULL + - height of every node inside the panel + - scrollbar offset + Output: + - tree build up state structure +*/ +enum gui_tree_node_operation gui_panel_tree_begin_node(struct gui_tree*, const char*, + gui_tree_node_state*); +/* this function begins a parent node + Input: + - title of the node + - current node state + Output: + - operation identifier what should be done with this node +*/ +enum gui_tree_node_operation gui_panel_tree_begin_node_icon(struct gui_tree*, + const char*, struct gui_image, + gui_tree_node_state*); +/* this function begins a text icon parent node + Input: + - title of the node + - icon of the node + - current node state + Output: + - operation identifier what should be done with this node +*/ +void gui_panel_tree_end_node(struct gui_tree*); +/* this function ends a parent node */ +enum gui_tree_node_operation gui_panel_tree_leaf(struct gui_tree*, const char*, + gui_tree_node_state*); +/* this function pushes a leaf node to the tree + Input: + - title of the node + - current leaf node state + Output: + - operation identifier what should be done with this node +*/ +enum gui_tree_node_operation gui_panel_tree_leaf_icon(struct gui_tree*, + const char*, struct gui_image, + gui_tree_node_state*); +/* this function pushes a leaf icon node to the tree + Input: + - title of the node + - icon of the node + - current leaf node state + Output: + - operation identifier what should be done with this node +*/ +gui_float gui_panel_tree_end(struct gui_panel_layout*, struct gui_tree*); +/* this function ends a the tree building process */ /* * ------------------------------------------------------------- * GROUP @@ -2509,20 +2631,6 @@ void gui_panel_table_end(struct gui_panel_layout*); gui_panel_shelf_begin -- begins a shelf with a number of selectable tabs gui_panel_shelf_end -- ends a previously started shelf build up process */ -gui_bool gui_panel_tab_begin(struct gui_panel_layout*, struct gui_panel_layout *tab, - const char*, gui_bool border, gui_bool minimized); -/* this function adds a tab subpanel into the parent panel - Input: - - tab title to write into the header - - state of the tab with either collapsed(GUI_MINIMIZED) or open state - Output: - - tab layout to fill with widgets - - wether the tab is currently collapsed(gui_true) or open(gui_false) -*/ -void gui_panel_tab_end(struct gui_panel_layout*, struct gui_panel_layout *tab); -/* this function finishes the previously started tab and allocated the needed - tab space in the parent panel -*/ void gui_panel_group_begin(struct gui_panel_layout*, struct gui_panel_layout *tab, const char *title, gui_float offset); /* this function adds a grouped subpanel into the parent panel