added layout tabs

This commit is contained in:
vurtun 2015-03-31 18:29:45 +02:00
parent 4fb9870f33
commit 260b7da2cc
4 changed files with 263 additions and 74 deletions

View File

@ -5,9 +5,9 @@ Work in progress
- Immediate mode graphical user interface
- Suited for embedding into graphical applications
- Written in C89 (ANSI C)
- Small (~2.5kLOC)
- Small (~3kLOC)
- Focus on portability and ease of use
- No hidden state or global variables
- No global hidden state
- No direct dependencies (not even libc)
- Renderer and platform independent
- Complete memory management control

View File

@ -20,7 +20,7 @@
#define WIN_WIDTH 800
#define WIN_HEIGHT 600
#define MAX_MEMORY (256 * 1024)
#define MAX_PANELS 16
#define MAX_PANELS 8
#define DTIME 33
#define MAX_BUFFER 64
@ -37,6 +37,29 @@ static void brelease(struct gui_input*, SDL_Event*);
static void bmotion(struct gui_input*, SDL_Event*);
static GLuint ldbmp(gui_byte*, uint32_t*, uint32_t*);
/* types */
struct widget {
gui_char cmd_buf[MAX_BUFFER];
gui_size cmd_len;
gui_bool cmd_act;
gui_bool check;
gui_int option;
gui_float slider;
gui_size prog;
gui_int spinner;
gui_bool spin_act;
gui_size item_cur;
gui_float list_off;
gui_bool list_sel[5];
};
struct layout {
gui_size current_tab;
gui_float offset;
gui_float group_offset;
gui_bool minimized;
};
/* gobals */
static void
die(const char *fmt, ...)
@ -339,6 +362,92 @@ draw(int width, int height, struct gui_draw_call_list **list, gui_size count)
glPopAttrib();
}
static void
widget_panel(struct gui_context *ctx, struct gui_panel *panel, struct widget *demo)
{
const gui_float values[] = {8.0f, 15.0f, 20.0f, 12.0f, 30.0f};
const char *items[] = {"Fist", "Pistol", "Shotgun", "Railgun", "BFG"};
gui_begin_panel(ctx, panel, "Widgets",
GUI_PANEL_HEADER|GUI_PANEL_CLOSEABLE|GUI_PANEL_MINIMIZABLE|GUI_PANEL_BORDER|
GUI_PANEL_MOVEABLE|GUI_PANEL_SCROLLBAR|GUI_PANEL_SCALEABLE);
gui_panel_layout(panel, 30, 1);
if (gui_panel_button_text(panel, "button", GUI_BUTTON_SWITCH))
fprintf(stdout, "button pressed!\n");
demo->check = gui_panel_check(panel, "advanced", demo->check);
gui_panel_layout(panel, 30, 2);
if (gui_panel_option(panel, "easy", demo->option == 0)) demo->option = 0;
if (gui_panel_option(panel, "hard", demo->option == 1)) demo->option = 1;
gui_panel_layout(panel, 30, 1);
demo->slider = gui_panel_slider(panel, 0, demo->slider, 10, 1.0f, GUI_HORIZONTAL);
demo->prog = gui_panel_progress(panel, demo->prog, 100, gui_true, GUI_HORIZONTAL);
gui_panel_shell(panel, demo->cmd_buf, &demo->cmd_len, MAX_BUFFER, &demo->cmd_act);
demo->spin_act = gui_panel_spinner(panel, 0, &demo->spinner, 1024, 10, demo->spin_act);
demo->item_cur = gui_panel_selector(panel, items, LEN(items), demo->item_cur);
gui_panel_layout(panel, 100, 1);
gui_panel_plot(panel, values, LEN(values));
gui_panel_histo(panel, values, LEN(values));
gui_panel_layout(panel, 150, 1);
demo->list_off = gui_panel_list(panel, demo->list_sel, items, LEN(items), demo->list_off, 30);
gui_end_panel(ctx, panel, NULL);
}
static void
layout_panel(struct gui_context *ctx, struct gui_panel *panel, struct layout *l)
{
struct gui_panel tab;
enum {MOUSE, KEYBOARD, GAMEPAD};
const char *shelfs[] = {"Mouse", "Keyboard", "Gamepad"};
gui_begin_panel(ctx, panel, "Layouts",
GUI_PANEL_HEADER|GUI_PANEL_CLOSEABLE|GUI_PANEL_MINIMIZABLE|
GUI_PANEL_MOVEABLE|GUI_PANEL_BORDER);
/* Tabs */
gui_panel_layout(panel, 100, 1);
l->minimized = gui_panel_tab_begin(panel, &tab, "Options", l->minimized);
gui_panel_layout(&tab, 30, 1);
if (gui_panel_button_text(&tab, "button", GUI_BUTTON_SWITCH))
fprintf(stdout, "tab button pressed!\n");
gui_panel_tab_end(panel, &tab);
/* Shelf */
gui_panel_layout(panel, 200, 2);
l->current_tab = gui_panel_shelf_begin(panel, &tab, shelfs, LEN(shelfs), l->current_tab);
gui_panel_layout(&tab, 30, 1);
if (l->current_tab == MOUSE) {
if (gui_panel_button_text(&tab, "button0", GUI_BUTTON_SWITCH))
fprintf(stdout, "shelf button0 pressed!\n");
} else if (l->current_tab == KEYBOARD) {
if (gui_panel_button_text(&tab, "button1", GUI_BUTTON_SWITCH))
fprintf(stdout, "shelf button1 pressed!\n");
} else {
if (gui_panel_button_text(&tab, "button2", GUI_BUTTON_SWITCH))
fprintf(stdout, "shelf button2 pressed!\n");
}
gui_panel_shelf_end(panel, &tab);
/* Group */
gui_panel_group_begin(panel, &tab, "Options", l->group_offset);
gui_panel_layout(&tab, 30, 1);
if (gui_panel_button_text(&tab, "button", GUI_BUTTON_SWITCH))
fprintf(stdout, "group button pressed!\n");
l->group_offset = gui_panel_group_end(panel, &tab);
gui_end_panel(ctx, panel, NULL);
}
static gui_bool
msgbox_panel(struct gui_context *ctx, struct gui_panel *panel)
{
gui_begin_panel(ctx, panel, "Error",
GUI_PANEL_HEADER|GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE);
gui_panel_layout(panel, 30, 2);
if (gui_panel_button_text(panel, "ok", GUI_BUTTON_SWITCH)) return gui_false;
if (gui_panel_button_text(panel, "cancel", GUI_BUTTON_SWITCH)) return gui_false;
gui_end_panel(ctx, panel, NULL);
return gui_true;
}
int
main(int argc, char *argv[])
{
@ -348,32 +457,18 @@ main(int argc, char *argv[])
SDL_Window *win;
SDL_GLContext glContext;
struct gui_context *ctx;
struct gui_font *font;
struct gui_panel *panel;
struct gui_panel *subpanel;
struct gui_panel tab;
struct gui_config config;
struct gui_memory memory;
struct gui_config config;
struct gui_input input;
struct gui_output output;
struct gui_font *font;
struct gui_context *ctx;
struct gui_panel *panel;
struct gui_panel *subpanel;
struct gui_panel *groups;
gui_char cmd_buf[MAX_BUFFER];
gui_size cmd_len = 0;
gui_bool cmd_act = gui_false;
gui_bool check = gui_false;
gui_int option = 0;
gui_float slider = 2.0f;
gui_size prog = 60;
gui_int spinner = 100;
gui_bool spin_act = gui_false;
const gui_float values[] = {8.0f, 15.0f, 20.0f, 12.0f, 30.0f};
const char *items[] = {"Fist", "Pistol", "Shotgun", "Railgun", "BFG"};
gui_size item_cur = 0;
gui_float list_off = 0.0f;
gui_bool list_sel[5];
gui_bool minimized = gui_true;
memset(list_sel, 0, sizeof list_sel);
struct widget widgets;
struct layout layout;
/* Window */
UNUSED(argc); UNUSED(argv);
@ -402,8 +497,18 @@ main(int argc, char *argv[])
config.colors[GUI_COLOR_TEXT].g = 255;
config.colors[GUI_COLOR_TEXT].b = 255;
config.colors[GUI_COLOR_TEXT].a = 255;
panel = gui_panel_new(ctx, 20, 20, 200, 400, &config, font);
subpanel = gui_panel_new(ctx, 250, 20, 200, 200, &config, font);
groups = gui_panel_new(ctx, 230, 150, 550, 400, &config, font);
/* State */
memset(&layout, 0, sizeof layout);
memset(&widgets, 0, sizeof widgets);
widgets.spinner = 100;
widgets.slider = 2.0f;
widgets.prog = 60;
layout.minimized = gui_true;
running = gui_true;
while (running) {
@ -425,39 +530,9 @@ main(int argc, char *argv[])
/* ------------------------- GUI --------------------------*/
gui_begin(ctx, (gui_float)width, (gui_float)height);
gui_begin_panel(ctx, panel, "Demo",
GUI_PANEL_HEADER|GUI_PANEL_CLOSEABLE|GUI_PANEL_MINIMIZABLE|
GUI_PANEL_MOVEABLE|GUI_PANEL_SCROLLBAR|GUI_PANEL_SCALEABLE);
gui_panel_layout(panel, 30, 1);
if (gui_panel_button_text(panel, "button", GUI_BUTTON_SWITCH))
fprintf(stdout, "button pressed!\n");
check = gui_panel_check(panel, "advanced", check);
gui_panel_layout(panel, 30, 2);
if (gui_panel_option(panel, "easy", option == 0)) option = 0;
if (gui_panel_option(panel, "hard", option == 1)) option = 1;
gui_panel_layout(panel, 30, 1);
slider = gui_panel_slider(panel, 0, slider, 10, 1.0f, GUI_HORIZONTAL);
prog = gui_panel_progress(panel, prog, 100, gui_true, GUI_HORIZONTAL);
gui_panel_shell(panel, cmd_buf, &cmd_len, MAX_BUFFER, &cmd_act);
spin_act = gui_panel_spinner(panel, 0, &spinner, 1024, 10, spin_act);
item_cur = gui_panel_selector(panel, items, LEN(items), item_cur);
gui_panel_layout(panel, 100, 1);
gui_panel_plot(panel, values, LEN(values));
gui_panel_histo(panel, values, LEN(values));
minimized = gui_panel_tab_begin(panel, &tab, "Options", minimized);
gui_panel_layout(&tab, 30, 1);
if (gui_panel_button_text(&tab, "button", GUI_BUTTON_SWITCH))
fprintf(stdout, "tab button pressed!\n");
gui_panel_tab_end(panel, &tab);
list_off = gui_panel_list(panel, list_sel, items, LEN(items), list_off, 30);
gui_end_panel(ctx, panel, NULL);
gui_begin_panel(ctx, subpanel, "Error",
GUI_PANEL_HEADER|GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE);
gui_panel_layout(subpanel, 30, 2);
if (gui_panel_button_text(subpanel, "ok", GUI_BUTTON_SWITCH)) break;
if (gui_panel_button_text(subpanel, "cancel", GUI_BUTTON_SWITCH)) break;
gui_end_panel(ctx, subpanel, NULL);
widget_panel(ctx, panel, &widgets);
layout_panel(ctx, groups, &layout);
if (!msgbox_panel(ctx, subpanel)) break;
gui_end(ctx, &output, NULL);
/* ---------------------------------------------------------*/

136
gui.c
View File

@ -1603,12 +1603,12 @@ gui_panel_begin(struct gui_panel *panel, struct gui_draw_buffer *out,
clip.h -= (config->panel_padding.y + config->item_padding.y);
else clip.h = null_rect.h;
} else {
panel->header_height = config->panel_padding.y + config->item_padding.y;
clip.x = x; clip.y = y;
clip.w = w; clip.h = h;
if (panel->flags & GUI_PANEL_SCROLLBAR)
clip.h -= config->panel_padding.y;
clip.h -= panel->header_height;
else clip.h = null_rect.h;
panel->header_height = config->panel_padding.y + config->item_padding.y;
}
if (panel->flags & GUI_PANEL_CLOSEABLE && panel->flags & GUI_PANEL_HEADER) {
@ -1680,11 +1680,11 @@ gui_panel_layout(struct gui_panel *panel, gui_float height, gui_size cols)
const struct gui_color *color;
assert(panel);
assert(panel->config);
assert(panel->out);
if (!panel) return;
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
assert(panel->config);
assert(panel->out);
config = panel->config;
color = &config->colors[GUI_COLOR_PANEL];
@ -2230,7 +2230,6 @@ gui_panel_spinner(struct gui_panel *panel, gui_int min, gui_int *value,
button.pad_x = MAX(3, button.h - panel->font->height);
button.pad_y = MAX(3, button.h - panel->font->height);
button.behavior = GUI_BUTTON_SWITCH;
button.behavior = GUI_BUTTON_SWITCH;
button.background = config->colors[GUI_COLOR_BUTTON];
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
button.content = config->colors[GUI_COLOR_TEXT];
@ -2453,33 +2452,142 @@ gui_panel_tab_begin(struct gui_panel *panel, struct gui_panel* tab,
assert(panel);
assert(tab);
if (!panel || !tab) return minimized;
if ((panel->flags & GUI_PANEL_HIDDEN) || panel->minimized)
return minimized;
if (!panel->minimized && !(panel->flags & GUI_PANEL_HIDDEN)) {
flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_HEADER;
} else flags = GUI_PANEL_HIDDEN;
old_height = panel->row_height;
old_cols = panel->row_columns;
gui_panel_layout(panel, 0, 1);
panel->index = 0;
panel->row_columns = 1;
panel->row_height = 0;
gui_panel_alloc_space(&bounds, panel);
panel->row_height = old_height;
panel->row_columns = old_cols;
panel->row_height = old_height;
gui_panel_init(tab, panel->config, panel->font);
tab->minimized = minimized;
flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_HEADER;
gui_panel_begin(tab, panel->out, panel->in, title,
bounds.x, bounds.y, bounds.w, null_rect.h, flags);
bounds.x, bounds.y + 1, bounds.w, null_rect.h, flags);
return tab->minimized;
}
void
gui_panel_tab_end(struct gui_panel *panel, struct gui_panel *tab)
{
assert(panel);
assert(tab);
if (!panel || !tab) return;
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
gui_panel_end(tab);
panel->at_y -= panel->row_height;
panel->at_y += tab->height + tab->config->item_spacing.y;
}
void
gui_panel_group_begin(struct gui_panel *panel, struct gui_panel* group,
const char *title, gui_float offset)
{
struct gui_rect bounds;
gui_flags flags;
assert(panel);
assert(group);
if (!panel || !group) return;
if ((panel->flags & GUI_PANEL_HIDDEN) || panel->minimized) return;
gui_panel_alloc_space(&bounds, panel);
gui_panel_init(group, panel->config, panel->font);
flags = GUI_PANEL_BORDER|GUI_PANEL_HEADER|GUI_PANEL_SCROLLBAR;
group->offset = offset;
gui_panel_begin(group, panel->out, panel->in, title,
bounds.x, bounds.y, bounds.w, bounds.h, flags);
}
gui_float
gui_panel_group_end(struct gui_panel *panel, struct gui_panel* group)
{
assert(panel);
assert(group);
if (!panel || !group) return 0;
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
gui_panel_end(group);
return group->offset;
}
gui_size
gui_panel_shelf_begin(struct gui_panel *panel, struct gui_panel *shelf,
const char *tabs[], gui_size tab_count, gui_size current)
{
gui_size i;
gui_flags flags;
struct gui_rect bounds;
const struct gui_config *config;
gui_float header_x, header_y;
gui_float header_w, header_h;
gui_float item_width;
assert(panel);
assert(tabs);
assert(shelf);
assert(current < tab_count);
if (!panel || !shelf || !tabs || current >= tab_count)
return current;
if ((panel->flags & GUI_PANEL_HIDDEN) || panel->minimized)
return current;
config = panel->config;
gui_panel_alloc_space(&bounds, panel);
header_x = bounds.x;
header_y = bounds.y;
header_w = bounds.w;
header_h = config->panel_padding.y + 2 * config->item_padding.y + panel->font->height;
item_width = header_w / (gui_float)tab_count;
for (i = 0; i < tab_count; i++) {
struct gui_button button;
button.y = header_y;
button.h = header_h;
button.x = header_x + (gui_float)i * item_width;
button.w = item_width;
button.pad_x = config->item_padding.x;
button.pad_y = config->item_padding.y;
button.behavior = GUI_BUTTON_SWITCH;
if (current == i) {
button.background = config->colors[GUI_COLOR_BUTTON_HOVER];
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
button.content = config->colors[GUI_COLOR_BUTTON];
button.highlight = config->colors[GUI_COLOR_BUTTON];
button.highlight_content = config->colors[GUI_COLOR_TEXT];
} else {
button.background = config->colors[GUI_COLOR_BUTTON];
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
button.content = config->colors[GUI_COLOR_TEXT];
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
}
if (gui_widget_button_text(panel->out, &button, tabs[i], strsiz(tabs[i]),
panel->font, panel->in)) current = i;
}
bounds.y += header_h;
bounds.h -= header_h;
gui_panel_init(shelf, panel->config, panel->font);
flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB;
gui_panel_begin(shelf, panel->out, panel->in, NULL,
bounds.x, bounds.y, bounds.w, bounds.h, flags);
return current;
}
void
gui_panel_shelf_end(struct gui_panel *panel, struct gui_panel *tab)
{
assert(panel);
assert(tab);
if (!panel || !tab) return;
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
gui_panel_end(tab);
}
void
gui_panel_end(struct gui_panel *panel)
{
@ -2677,7 +2785,6 @@ gui_begin(struct gui_context *ctx, gui_float w, gui_float h)
if (!ctx) return;
ctx->width = w;
ctx->height = h;
iter = ctx->stack_begin;
}
gui_bool
@ -2759,7 +2866,8 @@ gui_begin_panel(struct gui_context *ctx, struct gui_panel *panel,
out->clips = global->clips;
out->clip_capacity = global->clip_capacity;
in = (ctx->active == cpanel) ? ctx->input : NULL;
return gui_panel_begin(panel, out, in, title, cpanel->x, cpanel->y, cpanel->w, cpanel->h, flags);
return gui_panel_begin(panel, out, in, title, cpanel->x, cpanel->y,
cpanel->w, cpanel->h, flags);
}
void

10
gui.h
View File

@ -429,11 +429,17 @@ gui_int gui_panel_plot(struct gui_panel*, const gui_float *values,
gui_size value_count);
gui_int gui_panel_histo(struct gui_panel*, const gui_float *values,
gui_size value_count);
gui_float gui_panel_list(struct gui_panel*, gui_bool *selected, const char *items[],
gui_size item_count, gui_float offset, gui_float item_height);
gui_bool gui_panel_tab_begin(struct gui_panel*, struct gui_panel* tab,
const char *title, gui_bool minimized);
void gui_panel_tab_end(struct gui_panel *panel, struct gui_panel *tab);
gui_float gui_panel_list(struct gui_panel*, gui_bool *selected, const char *items[],
gui_size item_count, gui_float offset, gui_float item_height);
void gui_panel_group_begin(struct gui_panel*, struct gui_panel* tab,
const char *title, gui_float offset);
gui_float gui_panel_group_end(struct gui_panel*, struct gui_panel* tab);
gui_size gui_panel_shelf_begin(struct gui_panel*, struct gui_panel *shelf,
const char *tabs[], gui_size tab_count, gui_size current);
void gui_panel_shelf_end(struct gui_panel *panel, struct gui_panel *tab);
void gui_panel_end(struct gui_panel*);
/* Context */