changed tab to layout tree

This commit is contained in:
vurtun 2015-07-30 22:19:06 +02:00
parent b16822bede
commit 4299c3e3b0
6 changed files with 842 additions and 438 deletions

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

View File

@ -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);
}

496
gui.c
View File

@ -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);

324
gui.h
View File

@ -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