diff --git a/gui.c b/gui.c index 70462e6..4e82fcf 100644 --- a/gui.c +++ b/gui.c @@ -123,6 +123,60 @@ utf_encode(gui_long u, gui_char *c, gui_size clen) return len; } +struct gui_color +gui_make_color(gui_byte r, gui_byte g, gui_byte b, gui_byte a) +{ + struct gui_color col; + col.r = r; col.g = g; + col.b = b; col.a = a; + return col; +} + +struct gui_vec2 +gui_make_vec2(gui_float x, gui_float y) +{ + struct gui_vec2 vec; + vec.x = x; vec.y = y; + return vec; +} + +void +gui_default_config(struct gui_config *config) +{ + if (!config) return; + config->global_alpha = 1.0f; + config->header_height = 50.0f; + config->scrollbar_width = 16; + config->scroll_factor = 2; + config->panel_padding = gui_make_vec2(8.0f, 8.0f); + config->panel_min_size = gui_make_vec2(32.0f, 32.0f); + config->item_spacing = gui_make_vec2(8.0f, 4.0f); + config->item_padding = gui_make_vec2(4.0f, 4.0f); + config->colors[GUI_COLOR_TEXT] = gui_make_color(255, 255, 255, 255); + config->colors[GUI_COLOR_PANEL] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_BORDER] = gui_make_color(0, 0, 0, 255); + config->colors[GUI_COLOR_TITLEBAR] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_BUTTON] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_BUTTON_HOVER] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_BUTTON_BORDER] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_TOGGLE] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_TOGGLE_ACTIVE] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_SCROLL] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_SCROLL_CURSOR] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_SLIDER] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_SLIDER_CURSOR] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_PROGRESS] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_PROGRESS_CURSOR] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_INPUT] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_INPUT_BORDER] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_HISTO] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_HISTO_BARS] = gui_make_color(45, 45, 45, 255); + config->colors[GUI_COLOR_HISTO_NEGATIVE] = gui_make_color(255, 255, 255, 255); + config->colors[GUI_COLOR_HISTO_HIGHLIGHT] = gui_make_color(255, 0, 0, 255); + config->colors[GUI_COLOR_PLOT] = gui_make_color(100, 100, 100, 255); + config->colors[GUI_COLOR_PLOT_LINES] = gui_make_color(45, 45, 45, 255); +} + void gui_input_begin(struct gui_input *in) { @@ -884,14 +938,16 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_scroll *scroll, return offset; } -void gui_panel_init(struct gui_panel *panel, const struct gui_config *config, +void +gui_panel_init(struct gui_panel *panel, const struct gui_config *config, const struct gui_font *font, const struct gui_input *input) { panel->config = config; panel->font = font; panel->input = input; - panel->x = 0; panel->y = 0; - panel->at_x = 0; panel->at_y = 0; + panel->x = 0; + panel->y = 0; + panel->at_y = 0; panel->width = 0; panel->flags = 0; panel->index = 0; @@ -900,34 +956,60 @@ void gui_panel_init(struct gui_panel *panel, const struct gui_config *config, panel->queue = NULL; } -gui_int gui_panel_begin(struct gui_panel *panel, struct gui_draw_queue *q, - const char *t, gui_flags f, gui_int x, gui_int y, gui_int w) +gui_int +gui_panel_begin(struct gui_panel *panel, struct gui_draw_queue *q, + const char *t, gui_flags f, gui_int x, gui_int y, gui_int w, gui_int h) { - panel->x = x; panel->y = y; - panel->at_x = x; panel->at_y = y; + const struct gui_config *config = panel->config; + const struct gui_color *header = &config->colors[GUI_COLOR_TITLEBAR]; + gui_rectf(panel->queue, x ,y, w, config->header_height, *header); + if (panel->flags & GUI_PANEL_SCROLLBAR) panel->height = h; + + UNUSED(t); + panel->queue = q; + panel->x = x; + panel->y = y; panel->width = w; + panel->at_y = y; panel->flags = f; panel->index = 0; panel->row_columns = 0; - panel->row_height = 0; - panel->queue = q; + panel->row_height = config->header_height; return 0; } void gui_panel_row(struct gui_panel *panel, gui_int height, gui_int cols) { + const struct gui_config *config = panel->config; + const struct gui_color *color = &config->colors[GUI_COLOR_PANEL]; panel->at_y += panel->row_height; - panel->at_x = panel->x; panel->index = 0; panel->row_columns = cols; panel->row_height = height; + gui_rectf(panel->queue, panel->x, panel->at_y, panel->width, height, *color); } static void -gui_panel_bounds(struct gui_rect *bounds, const struct gui_panel *panel) +gui_panel_alloc(struct gui_rect *bounds, struct gui_panel *panel) { + const struct gui_config *config = panel->config; + gui_int padding, spacing, space; + gui_int item_offset, item_width, item_spacing; + padding = 2 * config->panel_padding.x; + spacing = (panel->row_columns - 1) * config->item_spacing.x; + space = panel->width - padding - spacing; + + item_width = space / panel->row_columns; + item_offset = config->item_padding.x + panel->index * item_width; + item_spacing = panel->index * config->item_spacing.x; + + bounds->x = panel->x + item_offset + item_spacing; + bounds->y = panel->at_y; + bounds->w = item_width; + bounds->h = panel->row_height - config->item_spacing.y; + panel->index++; } gui_int @@ -936,8 +1018,7 @@ gui_panel_button(struct gui_panel *panel, const char *str, gui_int len) struct gui_rect bounds; struct gui_button button; const struct gui_config *config = panel->config; - gui_panel_bounds(&bounds, panel); - panel->at_x += button.w; + gui_panel_alloc(&bounds, panel); button.text = str; button.length = len; @@ -954,8 +1035,149 @@ gui_panel_button(struct gui_panel *panel, const char *str, gui_int len) return gui_button(panel->queue, &button, panel->font, panel->input); } -void gui_panel_end(struct gui_panel *panel) +gui_int +gui_panel_toggle(struct gui_panel *panel, const char *text, gui_int length, + gui_int is_active) { - panel->height = panel->at_y - panel->y; + struct gui_rect bounds; + struct gui_toggle toggle; + const struct gui_config *config = panel->config; + gui_panel_alloc(&bounds, panel); + + toggle.x = bounds.x; + toggle.y = bounds.y; + toggle.w = bounds.w; + toggle.h = bounds.h; + toggle.pad_x = config->item_padding.x; + toggle.pad_y = config->item_padding.y; + toggle.active = is_active; + toggle.text = text; + toggle.length = length; + toggle.font = config->colors[GUI_COLOR_TEXT]; + toggle.background = config->colors[GUI_COLOR_TOGGLE]; + toggle.foreground = config->colors[GUI_COLOR_TOGGLE_ACTIVE]; + return gui_toggle(panel->queue, &toggle, panel->font, panel->input); +} + +gui_float +gui_panel_slider(struct gui_panel *panel, gui_float min_value, gui_float value, + gui_float max_value, gui_float value_step) +{ + struct gui_rect bounds; + struct gui_slider slider; + const struct gui_config *config = panel->config; + gui_panel_alloc(&bounds, panel); + + slider.x = bounds.x; + slider.y = bounds.y; + slider.w = bounds.w; + slider.h = bounds.h; + slider.pad_x = config->item_padding.x; + slider.pad_y = config->item_padding.y; + slider.value = value; + slider.min = min_value; + slider.max = max_value; + slider.step = value_step; + slider.background = config->colors[GUI_COLOR_SLIDER]; + slider.foreground = config->colors[GUI_COLOR_SLIDER_CURSOR]; + return gui_slider(panel->queue, &slider, panel->input); +} + +gui_float +gui_panel_progress(struct gui_panel *panel, gui_size cur_value, gui_size max_value, + gui_bool is_modifyable) +{ + struct gui_rect bounds; + struct gui_progress prog; + const struct gui_config *config = panel->config; + gui_panel_alloc(&bounds, panel); + + prog.x = bounds.x; + prog.y = bounds.y; + prog.w = bounds.w; + prog.h = bounds.h; + prog.pad_x = config->item_padding.x; + prog.pad_y = config->item_padding.y; + prog.current = cur_value; + prog.max = max_value; + prog.modifyable = is_modifyable; + prog.background = config->colors[GUI_COLOR_PROGRESS]; + prog.foreground = config->colors[GUI_COLOR_PROGRESS_CURSOR]; + return gui_progress(panel->queue, &prog, panel->input); +} + +gui_int +gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_int *length, + gui_int max_length, gui_bool is_active) +{ + struct gui_rect bounds; + struct gui_input_field field; + const struct gui_config *config = panel->config; + gui_panel_alloc(&bounds, panel); + + field.x = bounds.x; + field.y = bounds.y; + field.w = bounds.w; + field.h = bounds.h; + field.pad_x = config->item_padding.x; + field.pad_y = config->item_padding.y; + field.buffer = buffer; + field.length = length; + field.max = max_length; + field.active = is_active; + field.font = config->colors[GUI_COLOR_TEXT]; + field.background = config->colors[GUI_COLOR_INPUT]; + field.foreground = config->colors[GUI_COLOR_BORDER]; + return gui_input(panel->queue, &field, panel->font, panel->input); +} + +void +gui_panel_plot(struct gui_panel *panel, const gui_float *values, gui_int count) +{ + struct gui_rect bounds; + struct gui_plot plot; + const struct gui_config *config = panel->config; + gui_panel_alloc(&bounds, panel); + + plot.x = bounds.x; + plot.y = bounds.y; + plot.w = bounds.w; + plot.h = bounds.h; + plot.pad_x = config->item_padding.x; + plot.pad_y = config->item_padding.y; + plot.value_count = count; + plot.values = values; + plot.background = config->colors[GUI_COLOR_PLOT]; + plot.foreground = config->colors[GUI_COLOR_PLOT_LINES]; + gui_plot(panel->queue, &plot); +} + +gui_int +gui_panel_histo(struct gui_panel *panel, const gui_float *values, gui_int count) +{ + struct gui_rect bounds; + struct gui_histo histo; + const struct gui_config *config = panel->config; + gui_panel_alloc(&bounds, panel); + + histo.x = bounds.x; + histo.y = bounds.y; + histo.w = bounds.w; + histo.h = bounds.h; + histo.pad_x = config->item_padding.x; + histo.pad_y = config->item_padding.y; + histo.value_count = count; + histo.values = values; + histo.background = config->colors[GUI_COLOR_HISTO]; + histo.foreground = config->colors[GUI_COLOR_HISTO_BARS]; + histo.negative = config->colors[GUI_COLOR_HISTO_NEGATIVE]; + histo.highlight = config->colors[GUI_COLOR_HISTO_HIGHLIGHT]; + return gui_histo(panel->queue, &histo, panel->input); +} + +void gui_panel_end(struct gui_panel *panel) +{ + if (!(panel->flags & GUI_PANEL_SCROLLBAR)) + panel->height = panel->at_y - panel->y; } diff --git a/gui.h b/gui.h index cd23e9e..50e5d47 100644 --- a/gui.h +++ b/gui.h @@ -6,6 +6,24 @@ #ifndef GUI_H_ #define GUI_H_ +/* + * ------------- TODO-List ------------ + * - fix input bug + * - plot input handling + * - fine tune progressbar input handling + * - fine tune slider input handling + * - make additional widgets hoverable + * - panel row call only on change + * - panel clip rects + * - panel + * o flags + * o widgets + * o combobox + * o listView + * o treeView + * o textBox + * --------------------------------------- + */ #define GUI_UTF_SIZE 4 #define GUI_INPUT_MAX 16 @@ -115,7 +133,6 @@ struct gui_toggle { struct gui_color font; struct gui_color background; struct gui_color foreground; - struct gui_color highlight; }; struct gui_slider { @@ -190,20 +207,10 @@ struct gui_histo { struct gui_color highlight; }; -enum gui_panel_flags { - GUI_PANEL_BORDER = 0x01, - GUI_PANEL_TITLEBAR = 0x02, - GUI_PANEL_MINIMIZABLE = 0x04, - GUI_PANEL_CLOSEABLE = 0x08, - GUI_PANEL_SCALEABLE = 0x10, - GUI_PANEL_SCROLLBAR = 0x20 -}; - enum gui_colors { GUI_COLOR_TEXT, GUI_COLOR_PANEL, GUI_COLOR_BORDER, - GUI_COLOR_FRAME, GUI_COLOR_TITLEBAR, GUI_COLOR_BUTTON, GUI_COLOR_BUTTON_HOVER, @@ -216,24 +223,42 @@ enum gui_colors { GUI_COLOR_SLIDER_CURSOR, GUI_COLOR_PROGRESS, GUI_COLOR_PROGRESS_CURSOR, + GUI_COLOR_INPUT, + GUI_COLOR_INPUT_BORDER, + GUI_COLOR_HISTO, + GUI_COLOR_HISTO_BARS, + GUI_COLOR_HISTO_NEGATIVE, + GUI_COLOR_HISTO_HIGHLIGHT, + GUI_COLOR_PLOT, + GUI_COLOR_PLOT_LINES, GUI_COLOR_COUNT }; struct gui_config { gui_float global_alpha; - struct gui_vec2 window_padding; - struct gui_vec2 window_min_size; - struct gui_vec2 frame_padding; + gui_float header_height; + struct gui_vec2 panel_padding; + struct gui_vec2 panel_min_size; struct gui_vec2 item_spacing; struct gui_vec2 item_padding; - gui_int scroll_width; + gui_int scrollbar_width; + gui_int scroll_factor; struct gui_color colors[GUI_COLOR_COUNT]; }; +enum gui_panel_flags { + GUI_PANEL_BORDER = 0x01, + GUI_PANEL_TITLEBAR = 0x02, + GUI_PANEL_MINIMIZABLE = 0x04, + GUI_PANEL_CLOSEABLE = 0x08, + GUI_PANEL_SCALEABLE = 0x10, + GUI_PANEL_SCROLLBAR = 0x20 +}; + struct gui_panel { gui_flags flags; gui_int x, y; - gui_int at_x, at_y; + gui_int at_y; gui_int width, height; gui_int index; gui_int row_height; @@ -244,6 +269,11 @@ struct gui_panel { const struct gui_config *config; }; +/* Utility */ +struct gui_color gui_make_color(gui_byte r, gui_byte g, gui_byte b, gui_byte a); +struct gui_vec2 gui_make_vec2(gui_float x, gui_float y); +void gui_default_config(struct gui_config *config); + /* Input */ void gui_input_begin(struct gui_input *in); void gui_input_motion(struct gui_input *in, gui_int x, gui_int y); @@ -258,7 +288,6 @@ gui_size gui_end(struct gui_draw_queue *que); const struct gui_draw_command *gui_next(const struct gui_draw_queue *que, const struct gui_draw_command *cmd); - /* Widgets */ gui_int gui_button(struct gui_draw_queue *que, const struct gui_button *button, const struct gui_font *font, const struct gui_input *in); @@ -276,12 +305,12 @@ gui_int gui_histo(struct gui_draw_queue *que, const struct gui_histo *histo, const struct gui_input *in); void gui_plot(struct gui_draw_queue *que, const struct gui_plot *plot); - /* Panel */ void gui_panel_init(struct gui_panel *panel, const struct gui_config *config, const struct gui_font *font, const struct gui_input *input); gui_int gui_panel_begin(struct gui_panel *panel, struct gui_draw_queue *q, - const char *t, gui_flags f, gui_int x, gui_int y, gui_int w); + const char *t, gui_flags f, + gui_int x, gui_int y, gui_int w, gui_int h); void gui_panel_row(struct gui_panel *panel, gui_int height, gui_int cols); void gui_panel_space(struct gui_panel *panel, gui_int cols); gui_int gui_panel_button(struct gui_panel *panel, const char *str, gui_int len); @@ -294,9 +323,9 @@ gui_float gui_panel_progress(struct gui_panel *panel, gui_size cur, gui_size max gui_int gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_int *len, gui_int max, gui_bool active); void gui_panel_plot(struct gui_panel *panel, const gui_float *values, - gui_int value_count, gui_int offset, const char *text); -void gui_panel_histo(struct gui_panel *panel, const gui_float *values, - gui_int value_count, gui_int offset, const char *text); + gui_int value_count); +gui_int gui_panel_histo(struct gui_panel *panel, const gui_float *values, + gui_int value_count); void gui_panel_end(struct gui_panel *panel); #endif diff --git a/opengl.c b/opengl.c index 07a89c9..3d186b0 100644 --- a/opengl.c +++ b/opengl.c @@ -58,6 +58,8 @@ struct GUI { struct gui_draw_queue out; struct gui_input in; struct gui_font *font; + struct gui_config config; + struct gui_panel panel; }; /* functions */ @@ -404,104 +406,16 @@ main(int argc, char *argv[]) long dt, started; gui_byte *buffer; const gui_size buffer_size = MAX_VERTEX_BUFFER; - const struct gui_color colorA = {100, 100, 100, 255}; - const struct gui_color colorB = {45, 45, 45, 255}; - const struct gui_color colorC = {255, 255, 255, 255}; - const struct gui_color colorD = {255, 0, 0, 255}; static GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE,24, GLX_DOUBLEBUFFER, None}; - struct gui_button button; - struct gui_slider slider; - struct gui_progress prog; - struct gui_toggle toggle; - struct gui_input_field field; - struct gui_plot plot; - struct gui_histo histo; - struct gui_scroll scroll; - - const char *selection[] = {"Inactive", "Active"}; - gui_char input[INPUT_MAX]; + gui_char input_text[INPUT_MAX]; gui_int input_len = 0; - const gui_float values[] = {10.0f, 12.0f, 25.0f, 15.0f, 18.0f, 30.0f, 32.0f, 15.0f}; - strcpy((char*)input, "input"); - input_len = strlen((char*)input); - - button.x = 50, button.y = 50; - button.w = 150, button.h = 30; - button.pad_x = 5, button.pad_y = 5; - button.text = "button"; - button.length = 6; - button.background = colorB; - button.foreground = colorA; - button.font = colorC; - button.highlight = colorA; - - slider.x = 50, slider.y = 100; - slider.w = 150, slider.h = 30; - slider.pad_x = 2, slider.pad_y = 2; - slider.min = 0.0f; - slider.value = 5.0f; - slider.max = 10.0f; - slider.step = 1.0f; - slider.foreground = colorB; - slider.background = colorA; - - prog.x = 50, prog.y = 150; - prog.w = 150, prog.h = 30; - prog.pad_x = 2, prog.pad_y = 2; - prog.current = 60.0f; - prog.max = 100.0f; - prog.modifyable = gui_true; - prog.foreground = colorB; - prog.background = colorA; - - toggle.x = 50, toggle.y = 200; - toggle.w = 150, toggle.h = 30; - toggle.pad_x = 2, toggle.pad_y = 2; - toggle.active = gui_false; - toggle.text = selection[toggle.active]; - toggle.length = strlen(selection[toggle.active]); - toggle.foreground = colorB; - toggle.background = colorA; - toggle.font = colorC; - toggle.highlight = colorA; - - field.x = 50, field.y = 250; - field.w = 150, field.h = 30; - field.pad_x = 5, field.pad_y = 5; - field.buffer = input; - field.length = &input_len; - field.max = INPUT_MAX; - field.active = gui_false; - field.foreground = colorA; - field.background = colorB; - field.font = colorC; - - plot.x = 50, plot.y = 300; - plot.w = 150, plot.h = 100; - plot.pad_x = 5, plot.pad_y = 5; - plot.values = values; - plot.value_count = LEN(values); - plot.foreground = colorB; - plot.background = colorA; - - histo.x = 50, histo.y = 430; - histo.w = 150, histo.h = 100; - histo.pad_x = 5, histo.pad_y = 5; - histo.values = values; - histo.value_count = LEN(values); - histo.foreground = colorB; - histo.background = colorA; - histo.negative = colorC; - histo.highlight = colorD; - - scroll.x = 250, scroll.y = 50; - scroll.w = 16, scroll.h = 300; - scroll.offset = 300; - scroll.target = 600; - scroll.step = 150; - scroll.foreground = colorB; - scroll.background = colorA; + gui_int typing = 0; + gui_float slider = 5.0f; + gui_float prog = 60.0f; + gui_int selected = gui_false; + const char *s[] = {"inactive", "active"}; + const gui_float values[] = {10.0f, 12.5f, 18.0f, 15.0f, 25.0f, 30.0f, 5.0f}; /* Window */ UNUSED(argc); UNUSED(argv); @@ -535,9 +449,13 @@ main(int argc, char *argv[]) glXMakeCurrent(xw.dpy, xw.win, xw.glc); buffer = xcalloc(buffer_size, 1); - xw.running = 1; + /* GUI */ gui.win = &xw; gui.font = ldfont("mono.font", 16); + gui_default_config(&gui.config); + gui_panel_init(&gui.panel, &gui.config, gui.font, &gui.in); + + xw.running = 1; while (xw.running) { XEvent ev; started = timestamp(); @@ -554,21 +472,28 @@ main(int argc, char *argv[]) /* ------------------------- GUI --------------------------*/ gui_begin(&gui.out, buffer, MAX_VERTEX_BUFFER); - if (gui_button(&gui.out, &button, gui.font, &gui.in)) + gui_panel_begin(&gui.panel, &gui.out, "Console", 0, 50, 50, 200, 0); + gui_panel_row(&gui.panel, 30, 1); + if (gui_panel_button(&gui.panel, "button", 6)) fprintf(stdout, "button pressed!\n"); - slider.value = gui_slider(&gui.out, &slider, &gui.in); - prog.current = gui_progress(&gui.out, &prog, &gui.in); - toggle.active = gui_toggle(&gui.out, &toggle, gui.font, &gui.in); - toggle.text = selection[toggle.active]; - field.active = gui_input(&gui.out, &field, gui.font, &gui.in); - gui_plot(&gui.out, &plot); - gui_histo(&gui.out, &histo, &gui.in); - scroll.offset = gui_scroll(&gui.out, &scroll, &gui.in); + gui_panel_row(&gui.panel, 30, 1); + slider = gui_panel_slider(&gui.panel, 0.0f, slider, 10.0f, 1.0f); + gui_panel_row(&gui.panel, 30, 1); + prog = gui_panel_progress(&gui.panel, prog, 100, gui_true); + gui_panel_row(&gui.panel, 30, 1); + selected = gui_panel_toggle(&gui.panel, s[selected], strlen(s[selected]), selected); + gui_panel_row(&gui.panel, 30, 1); + typing = gui_panel_input(&gui.panel, input_text, &input_len, INPUT_MAX, typing); + gui_panel_row(&gui.panel, 100, 1); + gui_panel_plot(&gui.panel, values, LEN(values)); + gui_panel_row(&gui.panel, 100, 1); + gui_panel_histo(&gui.panel, values, LEN(values)); + gui_panel_end(&gui.panel); gui_end(&gui.out); /* ---------------------------------------------------------*/ /* Draw */ - glClearColor(45.0f/255.0f,45.0f/255.0f,45.0f/255.0f,1); + glClearColor(1.0f, 1.0f, 1.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); draw(xw.gwa.width, xw.gwa.height, &gui.out); glXSwapBuffers(xw.dpy, xw.win);