added tree widget to panel API

This commit is contained in:
vurtun 2015-07-16 01:35:21 +02:00
parent fb1b02b177
commit e4fa5fad12
3 changed files with 317 additions and 52 deletions

View File

@ -3,6 +3,20 @@
#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600
struct tree_node {
enum gui_tree_node_state state;
const char *name;
struct tree_node *parent;
struct tree_node *children[4];
int count;
};
struct test_tree {
struct tree_node root;
struct tree_node *clipboard[16];
int count;
};
struct show_window {
struct gui_panel hook;
/* input buffer */
@ -30,6 +44,9 @@ struct show_window {
gui_float table_scrollbar;
gui_float time_scrollbar;
/* tree */
struct test_tree tree;
struct tree_node nodes[8];
gui_float tree_offset;
};
struct control_window {
@ -89,13 +106,12 @@ widget_panel(struct gui_panel_layout *panel, struct show_window *demo)
fprintf(stdout, "right triangle button pressed!\n");
if (gui_panel_button_text_triangle(panel,GUI_LEFT,"previous",GUI_TEXT_RIGHT,GUI_BUTTON_DEFAULT))
fprintf(stdout, "left triangle button pressed!\n");
demo->toggle = gui_panel_button_toggle(panel, "toggle", demo->toggle);
demo->checkbox = gui_panel_check(panel, "checkbox", demo->checkbox);
gui_panel_row(panel, 30, 2);
if (gui_panel_option(panel, "option 0", demo->option == 0)) demo->option = 0;
if (gui_panel_option(panel, "option 1", demo->option == 1)) demo->option = 1;
{
char buffer[MAX_BUFFER];
const gui_float ratio[] = {0.8f, 0.2f};
@ -112,7 +128,7 @@ 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);
gui_panel_row_begin(panel, 30);
gui_panel_row_begin(panel, 30, 2);
gui_panel_row_push_widget(panel, 0.7f);
gui_panel_editbox(panel, &demo->input);
gui_panel_row_push_widget(panel, 0.3f);
@ -121,7 +137,6 @@ widget_panel(struct gui_panel_layout *panel, struct show_window *demo)
fprintf(stdout, "command executed!\n");
}
gui_panel_row_end(panel);
}
static void
@ -137,20 +152,6 @@ graph_panel(struct gui_panel_layout *panel, gui_size current)
}
}
static void
time_panel(struct gui_panel_layout *panel, unsigned int ms)
{
char buffer[MAX_BUFFER];
ms = MAX(1, ms);
gui_panel_row(panel, 20, 2);
gui_panel_label(panel, "FPS:", GUI_TEXT_LEFT);
sprintf(buffer, "%.2f", 1.0f/((float)ms/1000.0f));
gui_panel_label(panel, buffer, GUI_TEXT_CENTERED);
gui_panel_label(panel, "MS:", GUI_TEXT_LEFT);
sprintf(buffer, "%d", ms);
gui_panel_label(panel, buffer, GUI_TEXT_CENTERED);
}
static void
table_panel(struct gui_panel_layout *panel)
{
@ -180,16 +181,84 @@ init_show(struct show_window *win, struct gui_config *config,
gui_stack_push(stack, &win->hook);
gui_edit_box_init_fixed(&win->input, win->input_buffer, MAX_BUFFER, NULL, NULL);
win->widget_tab = GUI_MAXIMIZED;
win->widget_tab = GUI_MINIMIZED;
win->combobox_tab = GUI_MINIMIZED;
win->slider = 10.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 = 3;
win->nodes[0].children[0] = &win->nodes[1];
win->nodes[0].children[1] = &win->nodes[2];
win->nodes[0].children[2] = &win->nodes[3];
win->nodes[1].state = 0;
win->nodes[1].name = "Box0";
win->nodes[1].parent = &win->nodes[1];
win->nodes[1].count = 0;
win->nodes[2].state = 0;
win->nodes[2].name = "Box1";
win->nodes[2].parent = &win->nodes[1];
win->nodes[2].count = 0;
win->nodes[3].state = 0;
win->nodes[3].name = "Box2";
win->nodes[3].parent = &win->nodes[1];
win->nodes[3].count = 0;
win->nodes[4].state = GUI_NODE_ACTIVE;
win->nodes[4].name = "Cylinders";
win->nodes[4].parent = &tree->root;
win->nodes[4].count = 3;
win->nodes[4].children[0] = &win->nodes[5];
win->nodes[4].children[1] = &win->nodes[6];
win->nodes[4].children[2] = &win->nodes[7];
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;
win->nodes[7].state = 0;
win->nodes[7].name = "Cylinder2";
win->nodes[7].parent = &win->nodes[4];
win->nodes[7].count = 0;
}
}
static void
update_show(struct show_window *show, struct gui_stack *stack, struct gui_input *in,
unsigned int ms)
upload_tree(struct gui_tree *tree, struct tree_node *node)
{
int i = 0;
if (node->count) {
gui_panel_tree_begin_node(tree, node->name, &node->state);
for (i = 0; i < node->count; ++i)
upload_tree(tree, node->children[i]);
gui_panel_tree_end_node(tree);
}
else gui_panel_tree_leaf(tree, node->name, &node->state);
}
static void
update_show(struct show_window *show, struct gui_stack *stack, struct gui_input *in)
{
struct gui_panel_layout tab;
struct gui_panel_layout layout;
@ -204,11 +273,6 @@ update_show(struct show_window *show, struct gui_stack *stack, struct gui_input
widget_panel(&tab, show);
gui_panel_tab_end(&layout, &tab);
gui_panel_row(&layout, 110, 1);
gui_panel_group_begin(&layout, &tab, "Time", show->time_scrollbar);
time_panel(&tab, ms);
show->time_scrollbar = gui_panel_group_end(&layout, &tab);
gui_panel_row(&layout, 180, 1);
show->shelf_selection = gui_panel_shelf_begin(&layout, &tab, shelfs,
LEN(shelfs), show->shelf_selection, show->shelf_scrollbar);
@ -219,6 +283,14 @@ update_show(struct show_window *show, struct gui_stack *stack, struct gui_input
gui_panel_group_begin(&layout, &tab, "Table", show->table_scrollbar);
table_panel(&tab);
show->table_scrollbar = gui_panel_group_end(&layout, &tab);
{
struct gui_tree tree;
gui_panel_row(&layout, 250, 1);
gui_panel_tree_begin(&layout, &tree, "Models", 20, show->tree_offset);
upload_tree(&tree, &show->tree.root);
show->tree_offset = gui_panel_tree_end(&layout, &tree);
}
gui_panel_end(&layout, &show->hook);
}
@ -413,7 +485,7 @@ run_demo(struct demo_gui *gui, struct gui_input *input)
if (show->hook.flags & GUI_PANEL_ACTIVE)
show->hook.flags = control->show_flags|GUI_PANEL_ACTIVE;
else show->hook.flags = control->show_flags;
update_show(show, &gui->stack, input, gui->ms);
update_show(show, &gui->stack, input);
if (show->hook.flags & GUI_PANEL_HIDDEN)
control->show_flags |= GUI_PANEL_HIDDEN;
}

211
gui.c
View File

@ -45,6 +45,7 @@ template<typename T> struct gui_alignof{struct Big {T x; char c;}; enum {
#define GUI_ALIGN(x, mask) ((x) + (mask-1)) & ~(mask-1)
#define GUI_OFFSETOF(st, m) ((gui_size)(&((st *)0)->m))
enum gui_tree_node_symbol {GUI_TREE_NODE_BULLET, GUI_TREE_NODE_TRIANGLE};
static const struct gui_rect gui_null_rect = {-9999.0f, -9999.0f, 2*9999.0f, 2*9999.0f};
static const gui_byte gui_utfbyte[GUI_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
static const gui_byte gui_utfmask[GUI_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
@ -470,6 +471,28 @@ gui_input_end(struct gui_input *in)
gui_vec2_sub(in->mouse_delta, in->mouse_pos, in->mouse_prev);
}
static gui_bool
gui_input_clicked(const struct gui_input *i, struct gui_rect *b)
{
if (!i) return gui_false;
if (!GUI_INBOX(i->mouse_pos.x, i->mouse_pos.y, b->x, b->y, b->w, b->h))
return gui_false;
if (!GUI_INBOX(i->mouse_clicked_pos.x,i->mouse_clicked_pos.y,b->x,b->y,b->w,b->h))
return gui_false;
return (i->mouse_down && i->mouse_clicked) ? gui_true : gui_false;
}
static gui_bool
gui_input_pressed(const struct gui_input *i, enum gui_keys key)
{
const struct gui_key *k;
if (!i) return gui_false;
k = &i->keys[key];
if (k->down && k->clicked)
return gui_true;
return gui_false;
}
/*
* ==============================================================
*
@ -1597,29 +1620,20 @@ gui_editbox(struct gui_command_buffer *out, gui_float x, gui_float y, gui_float
len = gui_edit_box_len(box);
buffer = gui_edit_box_get(box);
if (box->active && in) {
const struct gui_key *bs = &in->keys[GUI_KEY_BACKSPACE];
const struct gui_key *del = &in->keys[GUI_KEY_DEL];
const struct gui_key *enter = &in->keys[GUI_KEY_ENTER];
const struct gui_key *space = &in->keys[GUI_KEY_SPACE];
const struct gui_key *copy = &in->keys[GUI_KEY_COPY];
const struct gui_key *paste = &in->keys[GUI_KEY_PASTE];
const struct gui_key *left = &in->keys[GUI_KEY_LEFT];
const struct gui_key *right = &in->keys[GUI_KEY_RIGHT];
/* update input buffer by user input */
if ((del->down && del->clicked) || (bs->down && bs->clicked))
if (gui_input_pressed(in,GUI_KEY_DEL)||gui_input_pressed(in,GUI_KEY_BACKSPACE))
gui_edit_box_remove(box);
if (enter->down && enter->clicked)
if (gui_input_pressed(in, GUI_KEY_ENTER))
box->active = gui_false;
if (copy->down && copy->clicked && box->clip.copy)
if (gui_input_pressed(in, GUI_KEY_COPY) && box->clip.copy)
box->clip.copy(box->clip.userdata, buffer, len);
if (paste->down && paste->clicked && box->clip.paste)
if (gui_input_pressed(in, GUI_KEY_PASTE) && box->clip.paste)
box->buffer.allocated = box->clip.paste(box->clip.userdata, buffer, max);
if (space->down && space->clicked)
if (gui_input_pressed(in, GUI_KEY_SPACE))
gui_edit_box_add(box, " ", 1);
if (left->down && left->clicked)
if (gui_input_pressed(in, GUI_KEY_LEFT))
box->cursor = (gui_size)MAX(0, (gui_int)box->cursor-1);
if (right->down && right->clicked)
if (gui_input_pressed(in, GUI_KEY_RIGHT))
box->cursor = MIN((!box->glyphes) ? 0 : box->glyphes, box->cursor+1);
if (in->text_len)
gui_edit_box_buffer_input(box, in);
@ -2683,8 +2697,9 @@ gui_panel_begin_tiled(struct gui_panel_layout *tile, struct gui_panel *panel,
rx = 1.0f - ((bounds.w / (gui_float)layout->width) +
layout->slots[GUI_SLOT_CENTER].ratio.x);
layout->slots[GUI_SLOT_RIGHT].ratio.x = rx;
layout->slots[GUI_SLOT_RIGHT].offset.x = layout->slots[GUI_SLOT_CENTER].offset.x+
layout->slots[GUI_SLOT_CENTER].ratio.x;
layout->slots[GUI_SLOT_RIGHT].offset.x =
layout->slots[GUI_SLOT_CENTER].offset.x +
layout->slots[GUI_SLOT_CENTER].ratio.x;
}
bounds.w -= config->scaler_width;
break;
@ -2714,8 +2729,9 @@ gui_panel_begin_tiled(struct gui_panel_layout *tile, struct gui_panel *panel,
lx = 1.0f - ((bounds.w / (gui_float)layout->width) +
layout->slots[GUI_SLOT_CENTER].ratio.x);
layout->slots[GUI_SLOT_LEFT].ratio.x = lx;
layout->slots[GUI_SLOT_RIGHT].offset.x = layout->slots[GUI_SLOT_CENTER].offset.x+
layout->slots[GUI_SLOT_CENTER].ratio.x;
layout->slots[GUI_SLOT_RIGHT].offset.x =
layout->slots[GUI_SLOT_CENTER].offset.x +
layout->slots[GUI_SLOT_CENTER].ratio.x;
}
bounds.x += config->scaler_width;
@ -3247,7 +3263,7 @@ gui_panel_button_text_triangle(struct gui_panel_layout *layout, enum gui_heading
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
return gui_button_text_triangle(layout->buffer, bounds.x, bounds.y, bounds.w,
bounds.h, heading, text, align, behavior, &button, &config->font, layout->input);
bounds.h, heading,text,align,behavior,&button,&config->font,layout->input);
}
gui_bool
@ -3569,7 +3585,7 @@ gui_panel_graph_push_line(struct gui_panel_layout *l,
/* special case for the first data point since it does not have a connection */
g->last.x = g->x;
g->last.y = (g->y + g->h) - ratio * (gui_float)g->h;
if (i && GUI_INBOX(i->mouse_pos.x, i->mouse_pos.y, g->last.x-3, g->last.y-3, 6, 6)){
if (i && GUI_INBOX(i->mouse_pos.x,i->mouse_pos.y,g->last.x-3,g->last.y-3,6,6)){
selected = (i->mouse_down && i->mouse_clicked) ? gui_true: gui_false;
color = config->colors[GUI_COLOR_PLOT_HIGHLIGHT];
}
@ -3632,7 +3648,7 @@ gui_panel_graph_push_column(struct gui_panel_layout *layout,
item_x = item_x + ((gui_float)graph->index * item_padding.x);
/* user graph bar selection */
if (in && GUI_INBOX(in->mouse_pos.x, in->mouse_pos.y, item_x, item_y, item_w, item_h)) {
if (in && GUI_INBOX(in->mouse_pos.x,in->mouse_pos.y,item_x,item_y,item_w,item_h)) {
selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)graph->index: selected;
color = config->colors[GUI_COLOR_HISTO_HIGHLIGHT];
}
@ -3890,7 +3906,7 @@ gui_panel_tab_end(struct gui_panel_layout *p, struct gui_panel_layout *t)
panel.flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_TAB;
gui_panel_end(t, &panel);
/* calculate the from the tab occupied space and allocate the space in the parent 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)
@ -4117,6 +4133,153 @@ gui_panel_shelf_end(struct gui_panel_layout *p, struct gui_panel_layout *s)
return pan.offset;
}
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_row(&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, enum gui_tree_node_state *state)
{
struct gui_rect bounds;
struct gui_rect sym, label;
struct gui_text text;
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){
tree->at_x = bounds.x;
} else {
bounds.w = (bounds.x + bounds.w) - tree->at_x;
bounds.x = tree->at_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;
/* calculate text bounds */
label.y = bounds.y;
label.h = bounds.h;
label.x = sym.x + sym.w + item_padding.x;
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);
}
/* 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))
op = GUI_NODE_DELETE;
if (gui_input_pressed(i, GUI_KEY_COPY) && (*state & GUI_NODE_SELECTED))
op = GUI_NODE_CLONE;
if (gui_input_pressed(i, GUI_KEY_CUT) && (*state & GUI_NODE_SELECTED))
op = GUI_NODE_CUT;
if (gui_input_pressed(i, GUI_KEY_PASTE) && (*state & 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,
enum gui_tree_node_state *state)
{
enum gui_tree_node_operation op;
op = gui_panel_tree_node(tree, GUI_TREE_NODE_TRIANGLE, title, 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,
enum gui_tree_node_state *state)
{return gui_panel_tree_node(tree, GUI_TREE_NODE_BULLET, title, 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);
}
void
gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel)
{

32
gui.h
View File

@ -187,6 +187,7 @@ enum gui_keys {
GUI_KEY_BACKSPACE,
GUI_KEY_SPACE,
GUI_KEY_COPY,
GUI_KEY_CUT,
GUI_KEY_PASTE,
GUI_KEY_LEFT,
GUI_KEY_RIGHT,
@ -1704,6 +1705,28 @@ struct gui_panel_layout {
/* command draw call output command buffer */
};
enum gui_tree_node_state {
GUI_NODE_ACTIVE = 0x01,
GUI_NODE_SELECTED = 0x02,
GUI_NODE_DRAGGED = 0x04
};
enum gui_tree_node_operation {
GUI_NODE_NOP,
GUI_NODE_CUT,
GUI_NODE_CLONE,
GUI_NODE_PASTE,
GUI_NODE_DELETE
};
struct gui_tree {
struct gui_panel_layout group;
gui_float x_off;
gui_float at_x;
gui_int skip;
gui_int depth;
};
struct gui_layout;
void gui_panel_init(struct gui_panel*, gui_float x, gui_float y, gui_float w,
gui_float h, gui_flags, struct gui_command_buffer*,
@ -2140,6 +2163,14 @@ gui_float gui_panel_shelf_end(struct gui_panel_layout*, struct gui_panel_layout*
Output:
- The from user input updated shelf scrollbar pixel offset
*/
void gui_panel_tree_begin(struct gui_panel_layout*, struct gui_tree*,
const char*, gui_float row_height, gui_float offset);
enum gui_tree_node_operation gui_panel_tree_begin_node(struct gui_tree*, const char*,
enum gui_tree_node_state*);
void gui_panel_tree_end_node(struct gui_tree*);
enum gui_tree_node_operation gui_panel_tree_leaf(struct gui_tree*, const char*,
enum gui_tree_node_state*);
gui_float gui_panel_tree_end(struct gui_panel_layout*, struct gui_tree*);
void gui_panel_end(struct gui_panel_layout*, struct gui_panel*);
/* this function ends the panel layout build up process and updates the panel
*/
@ -2298,7 +2329,6 @@ void gui_layout_update_state(struct gui_layout*, gui_uint state);
Input:
- new state of the layout with either active or inactive
*/
#ifdef __cplusplus
}
#endif