diff --git a/Readme.md b/Readme.md index ebbe14f..10c2a9c 100644 --- a/Readme.md +++ b/Readme.md @@ -1,8 +1,7 @@ # GUI This is a bloat free stateless immediate mode graphical user interface toolkit written in ANSI C. It was designed as a embeddable user interface for graphical -application and does not have any direct dependencies. The main design goals is -an embeddable immediate mode toolkit that is simple, efficient, portable and lightweight. +application and does not have any direct dependencies. ## Features - Immediate mode graphical user interface toolkit @@ -25,9 +24,9 @@ Summary: It is only responsible for the actual user interface ## Target applications - Graphical tools/editors -- Library testbed UI +- Library testbeds - Game engine debugging UI -- Graphical overlays +- Graphical overlay ## Gallery ![gui screenshot](/screen/demo.png?raw=true) diff --git a/demo/demo.c b/demo/demo.c index 7b45ba9..e3dd9df 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -228,7 +228,7 @@ static void init_show(struct show_window *win, struct gui_config *config, struct gui_font *font, struct gui_panel_stack *stack) { - gui_panel_hook_init(&win->hook, 120, 160, 300, 550, + gui_panel_hook_init(&win->hook, 120, 160, 300, 545, GUI_PANEL_BORDER|GUI_PANEL_MOVEABLE| GUI_PANEL_CLOSEABLE|GUI_PANEL_SCALEABLE| GUI_PANEL_MINIMIZABLE, config, font); @@ -295,33 +295,34 @@ style_tab(struct gui_panel_layout *panel, struct gui_config *config) gui_panel_row(panel, 30, 2); gui_panel_label(panel, "scrollbar width:", GUI_TEXT_LEFT); - tx = gui_panel_spinner(panel, 0, (gui_int)config->scrollbar_width, 20, 1, NULL); - config->scrollbar_width = (float)tx; + tx = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_SCROLLBAR_WIDTH].x, 20, 1, NULL); + config->properties[GUI_PROPERTY_SCROLLBAR_WIDTH].x = (float)tx; + config->properties[GUI_PROPERTY_SCROLLBAR_WIDTH].y = (float)tx; gui_panel_row(panel, 30, 3); gui_panel_label(panel, "padding:", GUI_TEXT_LEFT); - tx = gui_panel_spinner(panel, 0, (gui_int)config->panel_padding.x, 20, 1, NULL); - ty = gui_panel_spinner(panel, 0, (gui_int)config->panel_padding.y, 20, 1, NULL); - config->panel_padding.x = (float)tx; - config->panel_padding.y = (float)ty; + tx = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_PADDING].x, 20, 1, NULL); + ty = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_PADDING].y, 20, 1, NULL); + config->properties[GUI_PROPERTY_PADDING].x = (float)tx; + config->properties[GUI_PROPERTY_PADDING].y = (float)ty; gui_panel_label(panel, "item spacing:", GUI_TEXT_LEFT); - tx = gui_panel_spinner(panel, 0, (gui_int)config->item_spacing.x, 20, 1, NULL); - ty = gui_panel_spinner(panel, 0, (gui_int)config->item_spacing.y, 20, 1, NULL); - config->item_spacing.x = (float)tx; - config->item_spacing.y = (float)ty; + tx = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_ITEM_SPACING].x, 20, 1, NULL); + ty = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_ITEM_SPACING].y, 20, 1, NULL); + config->properties[GUI_PROPERTY_ITEM_SPACING].x = (float)tx; + config->properties[GUI_PROPERTY_ITEM_SPACING].y = (float)ty; gui_panel_label(panel, "item padding:", GUI_TEXT_LEFT); - tx = gui_panel_spinner(panel, 0, (gui_int)config->item_padding.x, 20, 1, NULL); - ty = gui_panel_spinner(panel, 0, (gui_int)config->item_padding.y, 20, 1, NULL); - config->item_padding.x = (float)tx; - config->item_padding.y = (float)ty; + tx = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_ITEM_PADDING].x, 20, 1, NULL); + ty = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_ITEM_PADDING].y, 20, 1, NULL); + config->properties[GUI_PROPERTY_ITEM_PADDING].x = (float)tx; + config->properties[GUI_PROPERTY_ITEM_PADDING].y = (float)ty; gui_panel_label(panel, "scaler size:", GUI_TEXT_LEFT); - tx = gui_panel_spinner(panel, 0, (gui_int)config->scaler_size.x, 20, 1, NULL); - ty = gui_panel_spinner(panel, 0, (gui_int)config->scaler_size.y, 20, 1, NULL); - config->scaler_size.x = (float)tx; - config->scaler_size.y = (float)ty; + tx = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_SCALER_SIZE].x, 20, 1, NULL); + ty = gui_panel_spinner(panel, 0, (gui_int)config->properties[GUI_PROPERTY_SCALER_SIZE].y, 20, 1, NULL); + config->properties[GUI_PROPERTY_SCALER_SIZE].x = (float)tx; + config->properties[GUI_PROPERTY_SCALER_SIZE].y = (float)ty; } static struct gui_color @@ -590,11 +591,12 @@ update_menu(struct menubar_window *win, struct gui_layout *layout, struct gui_input *in, struct gui_canvas *canvas, struct demo_gui *demo) { /* TODO(vurtun): probably want this to be a little bit more extensive*/ + gui_size cols; const char *tabs[] = {"General", "Curves"}; struct level {const char *name; const int next;}; static const struct level levels[][32] = { - {{"File", 1}, {"Edit", 2}, {"Tools", 3}, {"Create", 4}, {"Window", 5}, {"Quit", 0}, {NULL, -1}}, - {{"Back", 0}, {"New", 0}, {"Open", 0}, {NULL, -1}}, + {{"File", 1}, {"Edit", 2}, {"Tools", 3}, {"Create", 4}, {"Window", 5}, {NULL, -1}}, + {{"Back", 0}, {"New", 0}, {"Open", 0}, {"Quit", 0}, {NULL, -1}}, {{"Back", 0}, {"Undo", 0}, {"Redo", 0}, {"Copy", 0}, {"Paste", 0}, {NULL, -1}}, {{"Back", 0}, {"Selection", 6}, {"Transform", 7}, {NULL, -1}}, {{"Back", 0}, {"Sphere", 0}, {"Cube", 0}, {"Cylinder", 0}, {NULL, -1}}, @@ -609,7 +611,7 @@ update_menu(struct menubar_window *win, struct gui_layout *layout, struct demo_img *images = &demo->images; gui_panel_hook_begin_tiled(&panel, &win->hook, layout, GUI_SLOT_TOP, 0, NULL, canvas, in); - gui_panel_row(&panel, 25, 16); + gui_panel_row(&panel, 20, 12); while (iter->name) { if (gui_panel_button_text(&panel, iter->name, GUI_BUTTON_DEFAULT)) { fprintf(stdout, "button: %s pressed!\n", iter->name); @@ -620,9 +622,14 @@ update_menu(struct menubar_window *win, struct gui_layout *layout, } iter++; } - gui_panel_row(&panel, 100, 1); + + gui_panel_row(&panel, 85, 1); + gui_config_push_property(&demo->config, GUI_PROPERTY_PADDING, 15, 5); + gui_config_push_property(&demo->config, GUI_PROPERTY_ITEM_PADDING, 1, 1); win->selection = gui_panel_shelf_begin(&panel, &tab, tabs, LEN(tabs), win->selection, 0); - gui_panel_row(&tab, 36, 26); + + cols = gui_panel_row_columns(&tab, 40); + gui_panel_row(&tab, 40, cols); if (win->selection == 1) { if (gui_panel_button_image(&tab, images->select, GUI_BUTTON_DEFAULT)) fprintf(stdout, "select button pressed!\n"); @@ -651,6 +658,8 @@ update_menu(struct menubar_window *win, struct gui_layout *layout, fprintf(stdout, "paint button pressed!\n"); } gui_panel_shelf_end(&panel, &tab); + gui_config_pop_property(&demo->config); + gui_config_pop_property(&demo->config); gui_panel_hook_end(&panel, &win->hook); } @@ -670,11 +679,12 @@ update_status(struct status_window *win, struct gui_layout *layout, static void update_toolbar(struct toolbar_window *win, struct gui_layout *layout, struct demo_img *images, - struct gui_input *in, struct gui_canvas *canvas) + struct gui_input *in, struct gui_canvas *canvas, struct gui_config *config) { struct gui_panel_layout panel; + gui_config_push_property(config, GUI_PROPERTY_PADDING, 5, 10); gui_panel_hook_begin_tiled(&panel, &win->hook, layout, GUI_SLOT_LEFT, 0, NULL, canvas, in); - gui_panel_row(&panel, 40, 1); + gui_panel_row(&panel, 45, 1); if (gui_panel_button_image(&panel, images->select, GUI_BUTTON_DEFAULT)) fprintf(stdout, "select button pressed!\n"); if (gui_panel_button_image(&panel, images->lasso, GUI_BUTTON_DEFAULT)) @@ -688,6 +698,7 @@ update_toolbar(struct toolbar_window *win, struct gui_layout *layout, struct dem if (gui_panel_button_image(&panel, images->scale, GUI_BUTTON_DEFAULT)) fprintf(stdout, "scale button pressed!\n"); gui_panel_hook_end(&panel, &win->hook); + gui_config_pop_property(config); } static void @@ -701,7 +712,7 @@ init_demo(struct demo_gui *gui, struct gui_font *font) memory->memory = calloc(MAX_MEMORY, 1); memory->size = MAX_MEMORY; gui_buffer_init_fixed(buffer, memory, GUI_BUFFER_CLIPPING); - gui_default_config(config); + gui_config_default(config); /* background panels */ gui_panel_hook_init(&gui->settings.hook, 0, 0, 0, 0, 0, config, font); @@ -709,9 +720,8 @@ init_demo(struct demo_gui *gui, struct gui_font *font) gui_panel_hook_init(&gui->tool.hook, 0, 0, 0, 0, GUI_PANEL_NO_HEADER, config, font); gui_panel_hook_init(&gui->menu.hook, 0, 0, 0, 0, GUI_PANEL_NO_HEADER, config, font); gui->settings.brush_tab = GUI_MINIMIZED; - gui->settings.paint_tab = GUI_MINIMIZED; - gui->settings.flood_tab = GUI_MINIMIZED; gui->settings.color_tab = GUI_MINIMIZED; + gui->settings.texture_tab = GUI_MINIMIZED; /* floating windows */ gui_stack_clear(&gui->floating); @@ -733,8 +743,8 @@ background_demo(struct demo_gui *gui, struct gui_input *input, struct gui_comman /* setup layout split to fit screen */ ratio.right = 400.0f / gui->width; - ratio.top = 160.0f / gui->height; - ratio.left = 85.0f / gui->width; + ratio.top = 140.0f / gui->height; + ratio.left = 70.0f / gui->width; ratio.bottom = 52.0f / gui->height; ratio.centerv = 1.0f - (ratio.top + ratio.bottom); ratio.centerh = 1.0f - (ratio.right + ratio.left); @@ -764,7 +774,7 @@ background_demo(struct demo_gui *gui, struct gui_input *input, struct gui_comman /* toolbar window */ gui_buffer_lock(&canvas, buffer, &sub, 0, gui->width, gui->height); - update_toolbar(tool, &gui->layout, &gui->images, input, &canvas); + update_toolbar(tool, &gui->layout, &gui->images, input, &canvas, &gui->config); gui_buffer_unlock(gui_hook_output(&tool->hook), buffer, &sub, &canvas, NULL); gui_layout_end(&gui->background, &gui->layout); diff --git a/demo/xlib.c b/demo/xlib.c index 604b819..25266df 100644 --- a/demo/xlib.c +++ b/demo/xlib.c @@ -12,10 +12,7 @@ #include "../gui.h" /* macros */ -#define WIN_WIDTH 800 -#define WIN_HEIGHT 600 #define DTIME 16 - #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) < (b) ? (b) : (a)) #define CLAMP(i,v,x) (MAX(MIN(v,x), i)) @@ -422,7 +419,7 @@ main(int argc, char *argv[]) xw.swa.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask | ButtonPress | ButtonReleaseMask | ButtonMotionMask | Button1MotionMask | PointerMotionMask; - xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WIN_WIDTH, WIN_HEIGHT, 0, + xw.win = XCreateWindow(xw.dpy, xw.root, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, XDefaultDepth(xw.dpy, xw.screen), InputOutput, xw.vis, CWEventMask | CWColormap, &xw.swa); XStoreName(xw.dpy, xw.win, "X11"); @@ -460,7 +457,7 @@ main(int argc, char *argv[]) /* GUI */ gui.width = xw.width; gui.height = xw.height; - running = run_demo(&gui, &in); + run_demo(&gui, &in); /* Draw */ XClearWindow(xw.dpy, xw.win); diff --git a/gui.c b/gui.c index 8036765..7f36c89 100644 --- a/gui.c +++ b/gui.c @@ -484,7 +484,7 @@ gui_toggle(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float select_y = y + toggle->padding.y; select_size = font->height + 2 * toggle->padding.y; - cursor_pad = (gui_float)(gui_int)(select_size / 8); + cursor_pad = (gui_float)(gui_int)(select_size / 6); cursor_size = select_size - cursor_pad * 2; cursor_x = select_x + cursor_pad; cursor_y = select_y + cursor_pad; @@ -1268,16 +1268,17 @@ gui_list_next(const struct gui_command_list *list, const struct gui_command *cmd } void -gui_default_config(struct gui_config *config) +gui_config_default(struct gui_config *config) { ASSERT(config); if (!config) return; - config->scrollbar_width = 16; - vec2_load(config->panel_padding, 15.0f, 10.0f); - vec2_load(config->panel_min_size, 64.0f, 64.0f); - vec2_load(config->item_spacing, 10.0f, 4.0f); - vec2_load(config->item_padding, 3.0f, 3.0f); - vec2_load(config->scaler_size, 16.0f, 16.0f); + zero(config, sizeof(*config)); + vec2_load(config->properties[GUI_PROPERTY_SCROLLBAR_WIDTH], 16, 16); + vec2_load(config->properties[GUI_PROPERTY_PADDING], 15.0f, 10.0f); + vec2_load(config->properties[GUI_PROPERTY_SIZE], 64.0f, 64.0f); + vec2_load(config->properties[GUI_PROPERTY_ITEM_SPACING], 10.0f, 4.0f); + vec2_load(config->properties[GUI_PROPERTY_ITEM_PADDING], 3.0f, 3.0f); + vec2_load(config->properties[GUI_PROPERTY_SCALER_SIZE], 16.0f, 16.0f); col_load(config->colors[GUI_COLOR_TEXT], 100, 100, 100, 255); col_load(config->colors[GUI_COLOR_PANEL], 45, 45, 45, 255); col_load(config->colors[GUI_COLOR_HEADER], 40, 40, 40, 255); @@ -1322,6 +1323,102 @@ gui_default_config(struct gui_config *config) col_load(config->colors[GUI_COLOR_SCALER], 100, 100, 100, 255); } +struct gui_vec2 +gui_config_property(const struct gui_config *config, enum gui_panel_properties index) +{ + static struct gui_vec2 zero; + ASSERT(config); + if (!config) return zero; + return config->properties[index]; +} + +struct gui_color +gui_config_color(const struct gui_config *config, enum gui_panel_colors index) +{ + static struct gui_color zero; + ASSERT(config); + if (!config) return zero; + return config->colors[index]; +} + +void +gui_config_push_color(struct gui_config *config, enum gui_panel_colors index, + struct gui_color color) +{ + struct gui_saved_color *c; + ASSERT(config); + if (!config) return; + if (config->color >= GUI_MAX_COLOR_STACK) return; + c = &config->color_stack[config->color++]; + c->value = config->colors[index]; + c->type = index; + config->colors[index] = color; +} + +void +gui_config_push_property(struct gui_config *config, enum gui_panel_properties index, + gui_float x, gui_float y) +{ + struct gui_saved_property *p; + ASSERT(config); + if (!config) return; + if (config->property >= GUI_MAX_ATTRIB_STACK) return; + p = &config->property_stack[config->property++]; + p->value = config->properties[index]; + p->type = index; + config->properties[index].x = x; + config->properties[index].y = y; +} + +void +gui_config_pop_color(struct gui_config *config) +{ + struct gui_saved_color *c; + ASSERT(config); + if (!config) return; + if (!config->colors) return; + c = &config->color_stack[--config->color]; + config->colors[c->type] = c->value; +} + +void +gui_config_pop_property(struct gui_config *config) +{ + struct gui_saved_property *p; + ASSERT(config); + if (!config) return; + if (!config->properties) return; + p = &config->property_stack[--config->property]; + config->properties[p->type] = p->value; +} + +void +gui_config_reset_colors(struct gui_config *config) +{ + ASSERT(config); + if (!config) return; + while (config->color) + gui_config_pop_color(config); +} + +void +gui_config_reset_properties(struct gui_config *config) +{ + ASSERT(config); + if (!config) return; + while (config->property) + gui_config_pop_property(config); +} + +void +gui_config_reset(struct gui_config *config) +{ + ASSERT(config); + if (!config) return; + gui_config_reset_colors(config); + gui_config_reset_properties(config); +} + void gui_panel_init(struct gui_panel *panel, gui_float x, gui_float y, gui_float w, gui_float h, gui_flags flags, const struct gui_config *config, const struct gui_font *font) @@ -1356,6 +1453,13 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, gui_float footer_h; gui_bool ret = gui_true; + float scrollbar_width; + struct gui_vec2 panel_size; + struct gui_vec2 item_padding; + struct gui_vec2 item_spacing; + struct gui_vec2 panel_padding; + struct gui_vec2 scaler_size; + ASSERT(panel); ASSERT(layout); ASSERT(canvas); @@ -1371,10 +1475,17 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, return gui_false; } - /* calculate header */ config = panel->config; - layout->header_height = panel->font.height + 3 * config->item_padding.y; - layout->header_height += config->panel_padding.y; + scrollbar_width = gui_config_property(config, GUI_PROPERTY_SCROLLBAR_WIDTH).x; + panel_size = gui_config_property(config, GUI_PROPERTY_SIZE); + panel_padding = gui_config_property(config, GUI_PROPERTY_PADDING); + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + scaler_size = gui_config_property(config, GUI_PROPERTY_SCALER_SIZE); + + /* calculate header */ + layout->header_height = panel->font.height + 3 * item_padding.y; + layout->header_height += panel_padding.y; /* make sure input can be NULL */ mouse_x = (in) ? in->mouse_pos.x : -1; @@ -1402,15 +1513,15 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, /* panel scaling logic */ if (panel->flags & GUI_PANEL_SCALEABLE) { gui_bool incursor; - gui_float scaler_w = MAX(0, config->scaler_size.x - config->item_padding.x); - gui_float scaler_h = MAX(0, config->scaler_size.y - config->item_padding.y); - gui_float scaler_x = (panel->x + panel->w) - (config->item_padding.x + scaler_w); - gui_float scaler_y = panel->y + panel->h - config->scaler_size.y; + gui_float scaler_w = MAX(0, scaler_size.x - item_padding.x); + gui_float scaler_h = MAX(0, scaler_size.y - item_padding.y); + gui_float scaler_x = (panel->x + panel->w) - (item_padding.x + scaler_w); + gui_float scaler_y = panel->y + panel->h - scaler_size.y; incursor = in && INBOX(prev_x, prev_y, scaler_x, scaler_y, scaler_w, scaler_h); if (in && in->mouse_down && incursor) { - gui_float min_x = config->panel_min_size.x; - gui_float min_y = config->panel_min_size.y; + gui_float min_x = panel_size.x; + gui_float min_y = panel_size.y; panel->w = CLAMP(min_x, panel->w+in->mouse_delta.x, (gui_float)canvas->width-panel->x); panel->h = CLAMP(min_y,panel->h+in->mouse_delta.y,(gui_float)canvas->height-panel->y); } @@ -1437,15 +1548,15 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, /* special case for shelfs which do not have a header */ if (!(panel->flags & GUI_PANEL_NO_HEADER)) { header = &config->colors[GUI_COLOR_HEADER]; - header_x = panel->x + config->panel_padding.x; - header_w = panel->w - 2 * config->panel_padding.x; + header_x = panel->x + panel_padding.x; + header_w = panel->w - 2 * panel_padding.x; canvas->draw_rect(canvas->userdata, panel->x, panel->y, panel->w, layout->header_height, *header); } else layout->header_height = 1; - layout->row_height = layout->header_height + 2 * config->item_spacing.y; + layout->row_height = layout->header_height + 2 * item_spacing.y; /* add footer at the end of the panel */ - footer_h = config->scaler_size.y + config->item_padding.y; + footer_h = scaler_size.y + item_padding.y; if ((panel->flags & GUI_PANEL_SCALEABLE) && (panel->flags & GUI_PANEL_SCROLLBAR) && !panel->minimized) { @@ -1475,7 +1586,7 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, if (panel->flags & GUI_PANEL_SCALEABLE) layout->clip.h = panel->h - (footer_h + layout->header_height); else layout->clip.h = panel->h - layout->header_height; - layout->clip.h -= (config->panel_padding.y + config->item_padding.y); + layout->clip.h -= (panel_padding.y + item_padding.y); } else layout->clip.h = null_rect.h; @@ -1484,15 +1595,15 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, const gui_char *X = (const gui_char*)"x"; const gui_size text_width = panel->font.width(panel->font.userdata, X, 1); const gui_float close_x = header_x; - const gui_float close_y = panel->y + config->panel_padding.y; - const gui_float close_w = (gui_float)text_width + 2 * config->item_padding.x; - const gui_float close_h = panel->font.height + 2 * config->item_padding.y; + const gui_float close_y = panel->y + panel_padding.y; + const gui_float close_w = (gui_float)text_width + 2 * item_padding.x; + const gui_float close_h = panel->font.height + 2 * item_padding.y; canvas->draw_text(canvas->userdata, close_x, close_y, close_w, close_h, X, 1, &panel->font, config->colors[GUI_COLOR_HEADER], config->colors[GUI_COLOR_TEXT]); header_w -= close_w; - header_x += close_h - config->item_padding.x; + header_x += close_h - item_padding.x; if (in && INBOX(mouse_x, mouse_y, close_x, close_y, close_w, close_h)) { if (INBOX(clicked_x, clicked_y, close_x, close_y, close_w, close_h)) { ret = !(in->mouse_down && in->mouse_clicked); @@ -1511,15 +1622,15 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, text_width = panel->font.width(panel->font.userdata, score, 1); min_x = header_x; - min_y = panel->y + config->panel_padding.y; - min_w = (gui_float)text_width + 3 * config->item_padding.x; - min_h = panel->font.height + 2 * config->item_padding.y; + min_y = panel->y + panel_padding.y; + min_w = (gui_float)text_width + 3 * item_padding.x; + min_h = panel->font.height + 2 * item_padding.y; canvas->draw_text(canvas->userdata, min_x, min_y, min_w, min_h, score, 1, &panel->font, config->colors[GUI_COLOR_HEADER], config->colors[GUI_COLOR_TEXT]); header_w -= min_w; - header_x += min_w - config->item_padding.x; + header_x += min_w - item_padding.x; if (in && INBOX(mouse_x, mouse_y, min_x, min_y, min_w, min_h)) { if (INBOX(clicked_x, clicked_y, min_x, min_y, min_w, min_h)) if (in->mouse_down && in->mouse_clicked) @@ -1531,10 +1642,10 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, /* panel title */ if (text && !(panel->flags & GUI_PANEL_NO_HEADER)) { const gui_size text_len = strsiz(text); - const gui_float label_x = header_x + config->item_padding.x; - const gui_float label_y = panel->y + config->panel_padding.y; - const gui_float label_w = header_w - (3 * config->item_padding.x); - const gui_float label_h = panel->font.height + 2 * config->item_padding.y; + const gui_float label_x = header_x + item_padding.x; + const gui_float label_y = panel->y + panel_padding.y; + const gui_float label_w = header_w - (3 * item_padding.x); + const gui_float label_h = panel->font.height + 2 * item_padding.y; canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h, (const gui_char*)text, text_len, &panel->font, config->colors[GUI_COLOR_HEADER], config->colors[GUI_COLOR_TEXT]); @@ -1543,8 +1654,8 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, /* panels have an empty space at the bottom that needs to be filled */ if (panel->flags & GUI_PANEL_SCROLLBAR) { const struct gui_color *color = &config->colors[GUI_COLOR_PANEL]; - layout->width = panel->w - config->scrollbar_width; - layout->height = panel->h - (layout->header_height + 2 * config->item_spacing.y); + layout->width = panel->w - scrollbar_width; + layout->height = panel->h - (layout->header_height + 2 * item_spacing.y); if (panel->flags & GUI_PANEL_SCALEABLE) layout->height -= footer_h; if (layout->valid) canvas->draw_rect(canvas->userdata, panel->x, panel->y + layout->header_height, @@ -1555,7 +1666,7 @@ gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel *panel, if (panel->flags & GUI_PANEL_BORDER) { const struct gui_color *color = &config->colors[GUI_COLOR_BORDER]; const gui_float width = (panel->flags & GUI_PANEL_SCROLLBAR) ? - layout->width + config->scrollbar_width : layout->width; + layout->width + scrollbar_width : layout->width; canvas->draw_line(canvas->userdata, panel->x, panel->y, panel->x + panel->w, panel->y, *color); @@ -1654,6 +1765,8 @@ gui_panel_row(struct gui_panel_layout *layout, gui_float height, gui_size cols) { const struct gui_config *config; const struct gui_color *color; + struct gui_vec2 item_spacing; + struct gui_vec2 panel_padding; ASSERT(layout); if (!layout) return; @@ -1663,13 +1776,36 @@ gui_panel_row(struct gui_panel_layout *layout, gui_float height, gui_size cols) ASSERT(layout->canvas); config = layout->config; color = &config->colors[GUI_COLOR_PANEL]; + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + panel_padding = gui_config_property(config, GUI_PROPERTY_PADDING); layout->index = 0; layout->at_y += layout->row_height; layout->row_columns = cols; - layout->row_height = height + config->item_spacing.y; + layout->row_height = height + item_spacing.y; layout->canvas->draw_rect(layout->canvas->userdata, layout->at_x, layout->at_y, - layout->width, height + config->panel_padding.y, *color); + layout->width, height + panel_padding.y, *color); +} + +gui_size +gui_panel_row_columns(const struct gui_panel_layout *layout, gui_size widget_size) +{ + struct gui_vec2 item_spacing; + struct gui_vec2 panel_padding; + gui_size cols = 0, size; + ASSERT(layout); + ASSERT(widget_size); + if (!layout || !widget_size) + return 0; + + item_spacing = gui_config_property(layout->config, GUI_PROPERTY_ITEM_SPACING); + panel_padding = gui_config_property(layout->config, GUI_PROPERTY_PADDING); + + cols = (gui_size)(layout->width / widget_size); + size = (cols * (gui_size)item_spacing.x) + 2 * (gui_size)panel_padding.x + widget_size * cols; + while ((size > layout->width) && --cols) + size = (cols * (gui_size)item_spacing.x) + 2 * (gui_size)panel_padding.x + widget_size * cols; + return cols; } void @@ -1686,7 +1822,8 @@ gui_panel_seperator(struct gui_panel_layout *layout, gui_size cols) if (layout->index + cols > layout->row_columns) { gui_size i; const struct gui_config *config = layout->config; - const gui_float row_height = layout->row_height - config->item_spacing.y; + const struct gui_vec2 item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + const gui_float row_height = layout->row_height - item_spacing.y; gui_size rows = (layout->index + cols) / layout->row_columns; for (i = 0; i < rows; ++i) gui_panel_row(layout, row_height, layout->row_columns); @@ -1700,6 +1837,8 @@ gui_panel_alloc_space(struct gui_rect *bounds, struct gui_panel_layout *layout) const struct gui_config *config; gui_float panel_padding, panel_spacing, panel_space; gui_float item_offset, item_width, item_spacing; + struct gui_vec2 spacing; + struct gui_vec2 padding; ASSERT(layout); ASSERT(layout->config); @@ -1708,23 +1847,25 @@ gui_panel_alloc_space(struct gui_rect *bounds, struct gui_panel_layout *layout) return; config = layout->config; + spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + padding = gui_config_property(config, GUI_PROPERTY_PADDING); if (layout->index >= layout->row_columns) { - const gui_float row_height = layout->row_height - config->item_spacing.y; + const gui_float row_height = layout->row_height - spacing.y; gui_panel_row(layout, row_height, layout->row_columns); } - panel_padding = 2 * config->panel_padding.x; - panel_spacing = (gui_float)(layout->row_columns - 1) * config->item_spacing.x; + panel_padding = 2 * padding.x; + panel_spacing = (gui_float)(layout->row_columns - 1) * spacing.x; panel_space = layout->width - panel_padding - panel_spacing; item_width = panel_space / (gui_float)layout->row_columns; item_offset = (gui_float)layout->index * item_width; - item_spacing = (gui_float)layout->index * config->item_spacing.x; + item_spacing = (gui_float)layout->index * spacing.x; - bounds->x = layout->at_x + item_offset + item_spacing + config->panel_padding.x; + bounds->x = layout->at_x + item_offset + item_spacing + padding.x; bounds->y = layout->at_y - layout->offset; bounds->w = item_width; - bounds->h = layout->row_height - config->item_spacing.y; + bounds->h = layout->row_height - spacing.y; layout->index++; } @@ -1752,6 +1893,7 @@ gui_panel_text_colored(struct gui_panel_layout *layout, const char *str, gui_siz struct gui_rect bounds; struct gui_text text; const struct gui_config *config; + struct gui_vec2 item_padding; ASSERT(layout); ASSERT(layout->config); @@ -1762,9 +1904,10 @@ gui_panel_text_colored(struct gui_panel_layout *layout, const char *str, gui_siz if (!layout->valid) return; gui_panel_alloc_space(&bounds, layout); config = layout->config; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); - text.padding.x = config->item_padding.x; - text.padding.y = config->item_padding.y; + text.padding.x = item_padding.x; + text.padding.y = item_padding.y; text.foreground = color; text.background = config->colors[GUI_COLOR_PANEL]; gui_text(layout->canvas,bounds.x,bounds.y,bounds.w,bounds.h, str, len, @@ -1798,11 +1941,14 @@ gui_panel_button(struct gui_button *button, struct gui_rect *bounds, struct gui_panel_layout *layout) { const struct gui_config *config; + struct gui_vec2 item_padding; if (!gui_panel_widget(bounds, layout)) return gui_false; config = layout->config; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + button->border = 1; - button->padding.x = config->item_padding.x; - button->padding.y = config->item_padding.y; + button->padding.x = item_padding.x; + button->padding.y = item_padding.y; return gui_true; } @@ -1916,12 +2062,14 @@ gui_panel_toggle_base(struct gui_toggle *toggle, struct gui_rect *bounds, struct gui_panel_layout *layout) { const struct gui_config *config; + struct gui_vec2 item_padding; if (!gui_panel_widget(bounds, layout)) return gui_false; config = layout->config; - toggle->padding.x = config->item_padding.x; - toggle->padding.y = config->item_padding.y; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + toggle->padding.x = item_padding.x; + toggle->padding.y = item_padding.y; toggle->font = config->colors[GUI_COLOR_TEXT]; return gui_true; } @@ -1981,12 +2129,14 @@ gui_panel_slider(struct gui_panel_layout *layout, gui_float min_value, gui_float struct gui_rect bounds; struct gui_slider slider; const struct gui_config *config; + struct gui_vec2 item_padding; if (!gui_panel_widget(&bounds, layout)) return value; config = layout->config; - slider.padding.x = config->item_padding.x; - slider.padding.y = config->item_padding.y; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + slider.padding.x = item_padding.x; + slider.padding.y = item_padding.y; slider.background = config->colors[GUI_COLOR_SLIDER]; slider.foreground = config->colors[GUI_COLOR_SLIDER_CURSOR]; return gui_slider(layout->canvas, bounds.x, bounds.y, bounds.w, bounds.h, @@ -2000,12 +2150,14 @@ gui_panel_progress(struct gui_panel_layout *layout, gui_size cur_value, gui_size struct gui_rect bounds; struct gui_slider prog; const struct gui_config *config; + struct gui_vec2 item_padding; if (!gui_panel_widget(&bounds, layout)) return cur_value; config = layout->config; - prog.padding.x = config->item_padding.x; - prog.padding.y = config->item_padding.y; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + prog.padding.x = item_padding.x; + prog.padding.y = item_padding.y; prog.background = config->colors[GUI_COLOR_PROGRESS]; prog.foreground = config->colors[GUI_COLOR_PROGRESS_CURSOR]; return gui_progress(layout->canvas, bounds.x, bounds.y, bounds.w, bounds.h, @@ -2017,12 +2169,14 @@ gui_panel_edit_base(struct gui_rect *bounds, struct gui_edit *field, struct gui_panel_layout *layout) { const struct gui_config *config; + struct gui_vec2 item_padding; if (!gui_panel_widget(bounds, layout)) return gui_false; config = layout->config; - field->padding.x = config->item_padding.x; - field->padding.y = config->item_padding.y; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + field->padding.x = item_padding.x; + field->padding.y = item_padding.y; field->show_cursor = gui_true; field->background = config->colors[GUI_COLOR_INPUT]; field->foreground = config->colors[GUI_COLOR_INPUT_BORDER]; @@ -2059,6 +2213,8 @@ gui_panel_shell(struct gui_panel_layout *layout, gui_char *buffer, gui_size *len struct gui_rect bounds; struct gui_edit field; struct gui_button button; + struct gui_vec2 item_padding; + struct gui_vec2 item_spacing; gui_float button_x, button_y; gui_float button_w, button_h; gui_float field_x, field_y; @@ -2070,15 +2226,18 @@ gui_panel_shell(struct gui_panel_layout *layout, gui_char *buffer, gui_size *len return *active; config = layout->config; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + width = layout->font.width(layout->font.userdata, (const gui_char*)"submit", 6); button.border = 1; button_y = bounds.y; button_h = bounds.h; - button_w = (gui_float)width + config->item_padding.x * 2; + button_w = (gui_float)width + item_padding.x * 2; button_w += button.border * 2; button_x = bounds.x + bounds.w - button_w; - button.padding.x = config->item_padding.x; - button.padding.y = config->item_padding.y; + button.padding.x = item_padding.x; + button.padding.y = item_padding.y; button.background = config->colors[GUI_COLOR_BUTTON]; button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER]; button.content = config->colors[GUI_COLOR_TEXT]; @@ -2089,10 +2248,10 @@ gui_panel_shell(struct gui_panel_layout *layout, gui_char *buffer, gui_size *len field_x = bounds.x; field_y = bounds.y; - field_w = bounds.w - button_w - config->item_spacing.x; + field_w = bounds.w - button_w - item_spacing.x; field_h = bounds.h; - field.padding.x = config->item_padding.x; - field.padding.y = config->item_padding.y; + field.padding.x = item_padding.x; + field.padding.y = item_padding.y; field.show_cursor = gui_true; field.cursor = config->colors[GUI_COLOR_INPUT_CURSOR]; field.background = config->colors[GUI_COLOR_INPUT]; @@ -2112,6 +2271,7 @@ gui_panel_spinner(struct gui_panel_layout *layout, gui_int min, gui_int value, struct gui_edit field; char string[MAX_NUMBER_BUFFER]; gui_size len, old_len; + struct gui_vec2 item_padding; struct gui_button button; gui_float button_x, button_y; @@ -2123,19 +2283,20 @@ gui_panel_spinner(struct gui_panel_layout *layout, gui_int min, gui_int value, if (!gui_panel_widget(&bounds, layout)) return value; + config = layout->config; + canvas = layout->canvas; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + value = CLAMP(min, value, max); len = itos(string, value); is_active = (active) ? *active : gui_false; old_len = len; - config = layout->config; - canvas = layout->canvas; - /* up button */ button.border = 1; button_y = bounds.y; button_h = bounds.h / 2; - button_w = bounds.h - config->item_padding.x; + button_w = bounds.h - item_padding.x; button_x = bounds.x + bounds.w - button_w; button.padding.x = MAX(3, (button_h - layout->font.height) / 2); button.padding.y = MAX(3, (button_h - layout->font.height) / 2); @@ -2160,8 +2321,8 @@ gui_panel_spinner(struct gui_panel_layout *layout, gui_int min, gui_int value, field_y = bounds.y; field_w = bounds.w - button_w; field_h = bounds.h; - field.padding.x = config->item_padding.x; - field.padding.y = config->item_padding.y; + field.padding.x = item_padding.x; + field.padding.y = item_padding.y; field.show_cursor = gui_false; field.background = config->colors[GUI_COLOR_SPINNER]; field.foreground = config->colors[GUI_COLOR_SPINNER_BORDER]; @@ -2187,6 +2348,8 @@ gui_panel_selector(struct gui_panel_layout *layout, const char *items[], struct gui_button button; const struct gui_config *config; const struct gui_canvas *canvas; + struct gui_vec2 item_padding; + gui_bool button_up_clicked; gui_bool button_down_clicked; gui_float button_x, button_y; @@ -2200,6 +2363,7 @@ gui_panel_selector(struct gui_panel_layout *layout, const char *items[], config = layout->config; canvas = layout->canvas; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); canvas->draw_rect(canvas->userdata, bounds.x, bounds.y, bounds.w, bounds.h, config->colors[GUI_COLOR_SELECTOR_BORDER]); canvas->draw_rect(canvas->userdata, bounds.x + 1, bounds.y + 1, bounds.w - 2, bounds.h - 2, @@ -2209,7 +2373,7 @@ gui_panel_selector(struct gui_panel_layout *layout, const char *items[], button.border = 1; button_y = bounds.y; button_h = bounds.h / 2; - button_w = bounds.h - config->item_padding.x; + button_w = bounds.h - item_padding.x; button_x = bounds.x + bounds.w - button_w; button.padding.x = MAX(3, (button_h - layout->font.height) / 2); button.padding.y = MAX(3, (button_h - layout->font.height) / 2); @@ -2229,10 +2393,10 @@ gui_panel_selector(struct gui_panel_layout *layout, const char *items[], item_current+1 : (button_up_clicked && item_current > 0) ? item_current-1 : item_current; /* current item */ - label_x = bounds.x + config->item_padding.x; - label_y = bounds.y + config->item_padding.y; - label_w = bounds.w - (button_w + 2 * config->item_padding.x); - label_h = bounds.h - 2 * config->item_padding.y; + label_x = bounds.x + item_padding.x; + label_y = bounds.y + item_padding.y; + label_w = bounds.w - (button_w + 2 * item_padding.x); + label_h = bounds.h - 2 * item_padding.y; text_len = strsiz(items[item_current]); canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h, (const gui_char*)items[item_current], text_len, &layout->font, @@ -2248,6 +2412,7 @@ gui_panel_graph_begin(struct gui_panel_layout *layout, struct gui_graph *graph, const struct gui_config *config; const struct gui_canvas *canvas; struct gui_color color; + struct gui_vec2 item_padding; if (!gui_panel_widget(&bounds, layout)) { zero(graph, sizeof(*graph)); return; @@ -2255,6 +2420,7 @@ gui_panel_graph_begin(struct gui_panel_layout *layout, struct gui_graph *graph, config = layout->config; canvas = layout->canvas; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); color = (type == GUI_GRAPH_LINES) ? config->colors[GUI_COLOR_PLOT]: config->colors[GUI_COLOR_HISTO]; canvas->draw_rect(canvas->userdata, bounds.x, bounds.y, bounds.w, bounds.h,color); @@ -2265,12 +2431,12 @@ gui_panel_graph_begin(struct gui_panel_layout *layout, struct gui_graph *graph, graph->count = count; graph->min = min_value; graph->max = max_value; - graph->x = bounds.x + config->item_padding.x; - graph->y = bounds.y + config->item_padding.y; - graph->w = bounds.w - 2 * config->item_padding.x; - graph->h = bounds.h - 2 * config->item_padding.y; - graph->w = MAX(graph->w, 2 * config->item_padding.x); - graph->h = MAX(graph->h, 2 * config->item_padding.y); + graph->x = bounds.x + item_padding.x; + graph->y = bounds.y + item_padding.y; + graph->w = bounds.w - 2 * item_padding.x; + graph->h = bounds.h - 2 * item_padding.y; + graph->w = MAX(graph->w, 2 * item_padding.x); + graph->h = MAX(graph->h, 2 * item_padding.y); graph->last.x = 0; graph->last.y = 0; } @@ -2331,16 +2497,19 @@ gui_panel_graph_push_histo(struct gui_panel_layout *layout, const struct gui_canvas *canvas = layout->canvas; const struct gui_config *config = layout->config; const struct gui_input *in = layout->input; + struct gui_vec2 item_padding; struct gui_color color; gui_float ratio; gui_bool selected = gui_false; gui_float item_x, item_y; gui_float item_w = 0.0f, item_h = 0.0f; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + if (!graph->valid || graph->index >= graph->count) return gui_false; if (graph->count) { - gui_float padding = (gui_float)(graph->count-1) * config->item_padding.x; + gui_float padding = (gui_float)(graph->count-1) * item_padding.x; item_w = (graph->w - padding) / (gui_float)(graph->count); } @@ -2351,7 +2520,7 @@ gui_panel_graph_push_histo(struct gui_panel_layout *layout, item_h = graph->h * ratio; item_y = (graph->y + graph->h) - item_h; item_x = graph->x + ((gui_float)graph->index * item_w); - item_x = item_x + ((gui_float)graph->index * config->item_padding.y); + item_x = item_x + ((gui_float)graph->index * item_padding.y); if (in && 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; @@ -2467,9 +2636,12 @@ gui_panel_table_hline(struct gui_panel_layout *layout, gui_size row_height) { const struct gui_canvas *canvas = layout->canvas; const struct gui_config *config = layout->config; + const struct gui_vec2 item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + const struct gui_vec2 item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + gui_float y = layout->at_y + (gui_float)row_height - layout->offset; - gui_float x = layout->at_x + config->item_spacing.x + config->item_padding.x; - gui_float w = layout->width - (2 * config->item_spacing.x + 2 * config->item_padding.x); + gui_float x = layout->at_x + item_spacing.x + item_padding.x; + gui_float w = layout->width - (2 * item_spacing.x + 2 * item_padding.x); canvas->draw_line(canvas->userdata, x, y, x + w, y, config->colors[GUI_COLOR_TABLE_LINES]); } @@ -2513,13 +2685,17 @@ void gui_panel_table_row(struct gui_panel_layout *layout) { const struct gui_config *config; + struct gui_vec2 item_padding; + struct gui_vec2 item_spacing; ASSERT(layout); if (!layout) return; config = layout->config; - gui_panel_row(layout, layout->row_height - config->item_spacing.y, layout->row_columns); + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + gui_panel_row(layout, layout->row_height - item_spacing.y, layout->row_columns); if (layout->tbl_flags & GUI_TABLE_HBODY) - gui_panel_table_hline(layout, (gui_size)(layout->row_height - config->item_spacing.y)); + gui_panel_table_hline(layout, (gui_size)(layout->row_height - item_spacing.y)); if (layout->tbl_flags & GUI_TABLE_VBODY) gui_panel_table_vline(layout, layout->row_columns); } @@ -2574,6 +2750,7 @@ gui_panel_tab_end(struct gui_panel_layout *parent, struct gui_panel_layout *tab) { struct gui_panel panel; const struct gui_canvas *canvas; + struct gui_vec2 item_spacing; ASSERT(tab); ASSERT(parent); if (!parent || !tab || !parent->valid) @@ -2584,7 +2761,8 @@ gui_panel_tab_end(struct gui_panel_layout *parent, struct gui_panel_layout *tab) panel.flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_TAB; gui_panel_end(tab, &panel); - parent->at_y += tab->height + tab->config->item_spacing.y; + item_spacing = gui_config_property(parent->config, GUI_PROPERTY_ITEM_SPACING); + parent->at_y += tab->height + item_spacing.y; canvas = parent->canvas; canvas->scissor(canvas->userdata, parent->clip.x,parent->clip.y,parent->clip.w,parent->clip.h); } @@ -2661,6 +2839,9 @@ gui_panel_shelf_begin(struct gui_panel_layout *parent, struct gui_panel_layout * const struct gui_config *config; const struct gui_canvas *canvas; const struct gui_font *font; + struct gui_vec2 item_spacing; + struct gui_vec2 item_padding; + struct gui_vec2 panel_padding; struct gui_rect bounds; struct gui_rect clip; @@ -2686,6 +2867,9 @@ gui_panel_shelf_begin(struct gui_panel_layout *parent, struct gui_panel_layout * config = parent->config; canvas = parent->canvas; font = &parent->font; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + panel_padding = gui_config_property(config, GUI_PROPERTY_PADDING); gui_panel_alloc_space(&bounds, parent); zero(shelf, sizeof(*shelf)); @@ -2697,7 +2881,7 @@ gui_panel_shelf_begin(struct gui_panel_layout *parent, struct gui_panel_layout * header_x = bounds.x; header_y = bounds.y; header_w = bounds.w; - header_h = config->panel_padding.y + 3 * config->item_padding.y + parent->font.height; + header_h = panel_padding.y + 3 * item_padding.y + parent->font.height; item_width = (header_w - (gui_float)size) / (gui_float)size; /* shelf selection tabs */ @@ -2706,21 +2890,21 @@ gui_panel_shelf_begin(struct gui_panel_layout *parent, struct gui_panel_layout * gui_float button_x, button_y; gui_float button_w, button_h; gui_size text_width = font->width(font->userdata, (const gui_char*)tabs[i], strsiz(tabs[i])); - text_width = text_width + (gui_size)(2 * config->item_spacing.x); + text_width = text_width + (gui_size)(2 * item_spacing.x); button_y = header_y; button_h = header_h; button_x = header_x; button_w = MIN(item_width, text_width); button.border = 1; - button.padding.x = config->item_padding.x; - button.padding.y = config->item_padding.y; + button.padding.x = item_padding.x; + button.padding.y = item_padding.y; button.foreground = config->colors[GUI_COLOR_BORDER]; header_x += MIN(item_width, text_width); if ((button_x + button_w) >= (bounds.x + bounds.w)) break; if (active != i) { - button_y += config->item_padding.y; - button_h -= config->item_padding.y; + button_y += item_padding.y; + button_h -= item_padding.y; button.background = config->colors[GUI_COLOR_SHELF]; button.content = config->colors[GUI_COLOR_SHELF_TEXT]; button.highlight = config->colors[GUI_COLOR_SHELF]; @@ -2786,6 +2970,12 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) { const struct gui_config *config; const struct gui_canvas *canvas; + gui_float scrollbar_width; + struct gui_vec2 item_padding; + struct gui_vec2 item_spacing; + struct gui_vec2 panel_padding; + struct gui_vec2 scaler_size; + ASSERT(layout); ASSERT(panel); if (!panel || !layout) return; @@ -2793,6 +2983,11 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) config = layout->config; canvas = layout->canvas; + item_padding = gui_config_property(config, GUI_PROPERTY_ITEM_PADDING); + item_spacing = gui_config_property(config, GUI_PROPERTY_ITEM_SPACING); + panel_padding = gui_config_property(config, GUI_PROPERTY_PADDING); + scrollbar_width = gui_config_property(config, GUI_PROPERTY_SCROLLBAR_WIDTH).x; + scaler_size = gui_config_property(config, GUI_PROPERTY_SCALER_SIZE); if (!(panel->flags & GUI_PANEL_TAB)) canvas->scissor(canvas->userdata, layout->x, layout->y, layout->w + 1, layout->h + 1); @@ -2808,7 +3003,7 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) scroll_x = layout->at_x + layout->width; scroll_y = (panel->flags & GUI_PANEL_BORDER) ? layout->y + 1 : layout->y; scroll_y += layout->header_height; - scroll_w = config->scrollbar_width; + scroll_w = scrollbar_width; scroll_h = layout->height; scroll_offset = layout->offset; scroll_step = layout->height * 0.25f; @@ -2816,23 +3011,23 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) scroll.foreground = config->colors[GUI_COLOR_SCROLLBAR_CURSOR]; scroll.border = config->colors[GUI_COLOR_SCROLLBAR_BORDER]; if (panel->flags & GUI_PANEL_BORDER) scroll_h -= 1; - scroll_target = (layout->at_y-layout->y)-(layout->header_height+2*config->item_spacing.y); + scroll_target = (layout->at_y - layout->y) - (layout->header_height + 2 * item_spacing.y); panel->offset = gui_scroll(canvas, scroll_x, scroll_y, scroll_w, scroll_h, scroll_offset, scroll_target, scroll_step, &scroll, layout->input); - panel_y = layout->y + layout->height + layout->header_height - config->panel_padding.y; - canvas->draw_rect(canvas->userdata,layout->x,panel_y,layout->width,config->panel_padding.y, + panel_y = layout->y + layout->height + layout->header_height - panel_padding.y; + canvas->draw_rect(canvas->userdata, layout->x, panel_y, layout->width, panel_padding.y, config->colors[GUI_COLOR_PANEL]); } else layout->height = layout->at_y - layout->y; /* draws the scaling triangle in the footer of the panel */ if ((panel->flags & GUI_PANEL_SCALEABLE) && layout->valid) { struct gui_color col = config->colors[GUI_COLOR_SCALER]; - gui_float scaler_w = MAX(0, config->scaler_size.x - config->item_padding.x); - gui_float scaler_h = MAX(0, config->scaler_size.y - config->item_padding.y); - gui_float scaler_x = (layout->x + layout->w) - (config->item_padding.x + scaler_w); - gui_float scaler_y = layout->y + layout->h - config->scaler_size.y; + gui_float scaler_w = MAX(0, scaler_size.x - item_padding.x); + gui_float scaler_h = MAX(0, scaler_size.y - item_padding.y); + gui_float scaler_x = (layout->x + layout->w) - (item_padding.x + scaler_w); + gui_float scaler_y = layout->y + layout->h - scaler_size.y; canvas->draw_triangle(canvas->userdata, scaler_x + scaler_w, scaler_y, scaler_x + scaler_w, scaler_y + scaler_h, scaler_x, scaler_y + scaler_h, col); } @@ -2840,12 +3035,12 @@ gui_panel_end(struct gui_panel_layout *layout, struct gui_panel *panel) /* draw the border for the body of the panel */ if (panel->flags & GUI_PANEL_BORDER) { const gui_float width = (panel->flags & GUI_PANEL_SCROLLBAR) ? - layout->width + config->scrollbar_width : layout->width; + layout->width + scrollbar_width : layout->width; const gui_float padding_y = (!layout->valid) ? panel->y + layout->header_height: (panel->flags & GUI_PANEL_SCROLLBAR) ? panel->y + layout->h : - panel->y + layout->height + config->item_padding.y; + panel->y + layout->height + item_padding.y; canvas->draw_line(canvas->userdata, panel->x, padding_y, panel->x + width, padding_y, config->colors[GUI_COLOR_BORDER]); diff --git a/gui.h b/gui.h index 9d96def..15760cd 100644 --- a/gui.h +++ b/gui.h @@ -13,6 +13,8 @@ extern "C" { /* Constants */ #define GUI_UTF_SIZE 4 #define GUI_INPUT_MAX 16 +#define GUI_MAX_COLOR_STACK 8 +#define GUI_MAX_ATTRIB_STACK 8 #define GUI_UTF_INVALID 0xFFFD #define GUI_HOOK_PANEL_NAME panel #define GUI_HOOK_OUTPUT_NAME list @@ -340,7 +342,7 @@ struct gui_command_list { gui_size count; }; -/* Panel */ +/* Configuration */ enum gui_panel_colors { GUI_COLOR_TEXT, GUI_COLOR_PANEL, @@ -387,16 +389,37 @@ enum gui_panel_colors { GUI_COLOR_COUNT }; -struct gui_config { - struct gui_vec2 panel_padding; - struct gui_vec2 panel_min_size; - struct gui_vec2 item_spacing; - struct gui_vec2 item_padding; - struct gui_vec2 scaler_size; - gui_float scrollbar_width; - struct gui_color colors[GUI_COLOR_COUNT]; +enum gui_panel_properties { + GUI_PROPERTY_ITEM_SPACING, + GUI_PROPERTY_ITEM_PADDING, + GUI_PROPERTY_PADDING, + GUI_PROPERTY_SCALER_SIZE, + GUI_PROPERTY_SCROLLBAR_WIDTH, + GUI_PROPERTY_SIZE, + GUI_PROPERTY_MAX }; +struct gui_saved_property { + enum gui_panel_properties type; + struct gui_vec2 value; +}; + +struct gui_saved_color { + enum gui_panel_colors type; + struct gui_color value; +}; + +struct gui_config { + struct gui_vec2 properties[GUI_PROPERTY_MAX]; + struct gui_color colors[GUI_COLOR_COUNT]; + /* internal */ + struct gui_saved_property property_stack[GUI_MAX_ATTRIB_STACK]; + struct gui_saved_color color_stack[GUI_MAX_COLOR_STACK]; + gui_size color, property; +}; + + +/* Panel */ enum gui_panel_tab { GUI_MAXIMIZED = gui_false, GUI_MINIMIZED = gui_true @@ -590,12 +613,25 @@ gui_float gui_scroll(const struct gui_canvas*, gui_float x, gui_float y, gui_float step, const struct gui_scroll*, const struct gui_input*); +/* Config */ +void gui_config_default(struct gui_config*); +struct gui_vec2 gui_config_property(const struct gui_config*, enum gui_panel_properties); +struct gui_color gui_config_color(const struct gui_config*, enum gui_panel_colors); +void gui_config_push_color(struct gui_config*, enum gui_panel_colors, struct gui_color); +void gui_config_push_property(struct gui_config*, enum gui_panel_properties, gui_float x, gui_float y); +void gui_config_pop_color(struct gui_config*); +void gui_config_pop_property(struct gui_config*); +void gui_config_reset_colors(struct gui_config*); +void gui_config_reset_properties(struct gui_config*); +void gui_config_reset(struct gui_config*); + + /* Panel */ -void gui_default_config(struct gui_config*); void gui_panel_init(struct gui_panel*, gui_float x, gui_float y, gui_float w, gui_float h, gui_flags, const struct gui_config *config, const struct gui_font*); gui_bool gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel*, const char *title, const struct gui_canvas*, const struct gui_input*); +gui_size gui_panel_row_columns(const struct gui_panel_layout *layout, gui_size widget_size); void gui_panel_row(struct gui_panel_layout*, gui_float height, gui_size cols); gui_bool gui_panel_widget(struct gui_rect*, struct gui_panel_layout*); void gui_panel_seperator(struct gui_panel_layout*, gui_size cols); diff --git a/screen/screenshot.png b/screen/screenshot.png index c90da4b..9794347 100644 Binary files a/screen/screenshot.png and b/screen/screenshot.png differ