From 098dc82f1bb17a1c87cae3424679622fb7831fe0 Mon Sep 17 00:00:00 2001 From: vurtun Date: Mon, 9 Mar 2015 20:04:45 +0100 Subject: [PATCH] changed api --- Makefile | 2 +- gui.c | 485 +++++++++++++++++++++++++++++++++++++++++++----------- gui.h | 175 ++++++++++++++++---- mono.font | Bin 266492 -> 0 bytes opengl.c | 157 ++++++++++++++---- 5 files changed, 651 insertions(+), 168 deletions(-) delete mode 100644 mono.font diff --git a/Makefile b/Makefile index 0716705..5884d9f 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ DCC = clang # Flags CFLAGS = -std=c89 -pedantic-errors -Wno-deprecated-declarations -D_POSIX_C_SOURCE=200809L CFLAGS += -g -Wall -Wextra -Werror -Wformat -Wunreachable-code -CFLAGS += -Winline -Wshadow -Wwrite-strings -Wno-unused-variable -Wno-unused-parameter -Wno-unused-function +CFLAGS += -Winline -Wshadow -Wwrite-strings CFLAGS += -Wstrict-prototypes -Wold-style-definition CFLAGS += -Wredundant-decls -Wnested-externs -Wmissing-include-dirs CFLAGS += -Wshadow -Wpointer-arith -Wcast-qual -Wmissing-prototypes diff --git a/gui.c b/gui.c index b6a6510..70462e6 100644 --- a/gui.c +++ b/gui.c @@ -126,10 +126,13 @@ utf_encode(gui_long u, gui_char *c, gui_size clen) void gui_input_begin(struct gui_input *in) { + gui_size i; if (!in) return; in->mouse_clicked = 0; in->text_len = 0; vec2_mov(in->mouse_prev, in->mouse_pos); + for (i = 0; i < GUI_KEY_MAX; i++) + in->keys[i].clicked = 0; } void @@ -142,7 +145,9 @@ void gui_input_key(struct gui_input *in, enum gui_keys key, gui_int down) { if (!in) return; - in->keys[key] = down; + if (in->keys[key].down == down) return; + in->keys[key].down = down; + in->keys[key].clicked++; } void @@ -328,14 +333,13 @@ gui_rectf(struct gui_draw_queue *que, gui_float x, gui_float y, } static void -gui_text(struct gui_draw_queue *que, const struct gui_font *font, gui_float x, +gui_string(struct gui_draw_queue *que, const struct gui_font *font, gui_float x, gui_float y, gui_float w, gui_float h, struct gui_color col, const gui_char *t, gui_size len) { struct gui_draw_command *cmd; struct gui_rect clip; gui_size text_len; - gui_float off = 0; gui_long unicode; const struct gui_font_glyph *g; @@ -411,64 +415,85 @@ gui_end(struct gui_draw_queue *que) } gui_int -gui_button(struct gui_draw_queue *que, const struct gui_input *in, - const struct gui_font *font, struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - const char *str, gui_int l) +gui_button(struct gui_draw_queue *que, const struct gui_button *button, + const struct gui_font *font, const struct gui_input *in) { gui_int text_width; gui_int label_x, label_y; gui_int label_w, label_h; gui_int ret = gui_false; - const gui_char *t = (const gui_char*)str; + gui_int mouse_x, mouse_y; + gui_int clicked_x, clicked_y; + struct gui_color fc, bg, hc; + gui_int x, y, w, h; + const gui_char *t; - if (!que || !in) return gui_false; - if (!in->mouse_down && in->mouse_clicked) { - const gui_int clicked_x = in->mouse_clicked_pos.x; - const gui_int clicked_y = in->mouse_clicked_pos.y; + if (!que || !in || !button) + return gui_false; + + x = button->x, y = button->y; + w = button->w, h = button->h; + t = (const gui_char*)button->text; + mouse_x = in->mouse_pos.x; + mouse_y = in->mouse_pos.y; + clicked_x = in->mouse_clicked_pos.x; + clicked_y = in->mouse_clicked_pos.y; + fc = button->font; + bg = button->background; + hc = button->highlight; + + if (INBOX(mouse_x, mouse_y, x, y, x+w, y+h)) { if (INBOX(clicked_x, clicked_y, x, y, x+w, y+h)) - ret = gui_true; + ret = (in->mouse_down && in->mouse_clicked); + fc = bg; bg = hc; } gui_rectf(que, x, y, w, h, bg); - gui_rect(que, x+1, y+1, w-1, h-1, fg); - if (!font || !str || !l) return ret; + gui_rect(que, x+1, y+1, w-1, h-1, button->foreground); + if (!font || !button->text || !button->length) return ret; - text_width = gui_font_text_width(font, t, l); - if (text_width > (w - 2 * pad)) { - label_x = x + pad; - label_y = y + pad; - label_w = w - 2 * pad; - label_h = h - 2 * pad; + text_width = gui_font_text_width(font, t, button->length); + if (text_width > (w - 2 * button->pad_x)) { + label_x = x + button->pad_x; + label_y = y + button->pad_y; + label_w = w - 2 * button->pad_x; + label_h = h - 2 * button->pad_y; } else { - label_w = w - 2 * pad; - label_h = h - 2 * pad; + label_w = w - 2 * button->pad_x; + label_h = h - 2 * button->pad_y; label_x = x + (label_w - text_width) / 2; label_y = y + (label_h - font->height) / 2; } - gui_text(que, font, label_x, label_y, label_w, label_h, fg, t, l); + gui_string(que, font, label_x, label_y, label_w, label_h, fc, t, button->length); return ret; } gui_int -gui_toggle(struct gui_draw_queue *que, const struct gui_input *in, - const struct gui_font *font, struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - const char *str, gui_int len, gui_int active) +gui_toggle(struct gui_draw_queue *que, const struct gui_toggle *toggle, + const struct gui_font *font, const struct gui_input *in) { gui_int select_size; + gui_int x, y, w, h; + gui_int active; gui_int select_x, select_y; gui_int cursor_x, cursor_y; gui_int cursor_pad, cursor_size; gui_int label_x, label_w; - const struct gui_color white = {255, 255, 255, 255}; - const gui_char *t = (const gui_char*)str; + struct gui_color fg, bg; + const gui_char *t; - w = MAX(w, font->height + 2 * pad); - h = MAX(h, font->height + 2 * pad); + if (!que || !toggle || !font || !in) return 0; + active = toggle->active; + t = (const gui_char*)toggle->text; + x = toggle->x, y = toggle->y; + w = toggle->w, h = toggle->h; + w = MAX(w, font->height + 2 * toggle->pad_x); + h = MAX(h, font->height + 2 * toggle->pad_y); + fg = toggle->foreground; + bg = toggle->background; - select_x = x + pad; - select_y = y + pad; + select_x = x + toggle->pad_x; + select_y = y + toggle->pad_y; select_size = font->height; cursor_pad = select_size / 8; @@ -476,8 +501,8 @@ gui_toggle(struct gui_draw_queue *que, const struct gui_input *in, cursor_y = select_y + cursor_pad; cursor_size = select_size - 2 * cursor_pad; - label_x = x + select_size + pad * 2; - label_w = w - select_size + 3 * pad; + label_x = x + select_size + toggle->pad_x * 2; + label_w = w - select_size + 3 * toggle->pad_x; if (!in->mouse_down && in->mouse_clicked) { const gui_int clicked_x = in->mouse_clicked_pos.x; @@ -490,34 +515,37 @@ gui_toggle(struct gui_draw_queue *que, const struct gui_input *in, gui_rectf(que, select_x, select_y, select_size, select_size, bg); if (active) gui_rectf(que, cursor_x, cursor_y, cursor_size, cursor_size, fg); - gui_text(que, font, label_x, y + pad, label_w, h - 2 * pad, white, t, len); + gui_string(que, font, label_x, y + toggle->pad_y, label_w, + h - 2 * toggle->pad_y, toggle->font, t, toggle->length); return active; } gui_float -gui_slider(struct gui_draw_queue *que, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - gui_float min, gui_float value, gui_float max, gui_float step) +gui_slider(struct gui_draw_queue *que, const struct gui_slider *slider, + const struct gui_input *in) { + gui_float min, max, value, step; + gui_int x, y, w, h; gui_int mouse_x, mouse_y; gui_int clicked_x, clicked_y; - gui_int cursor_x; - gui_int cursor_y; + gui_int cursor_x, cursor_y, cursor_h; gui_float cursor_w; - gui_int cursor_h; - if (step == 0.0f) return value; - w = MAX(w, 2 * pad); - h = MAX(h, 2 * pad); - max = MAX(min, max); - min = MIN(min, max); - value = CLAMP(min, value, max); + if (!que || !slider || !in) return 0; + if (slider->step == 0.0f) return slider->value; + x = slider->x, y = slider->y; + w = slider->w, h = slider->h; + w = MAX(slider->w, 2 * slider->pad_x); + h = MAX(slider->h, 2 * slider->pad_y); + max = MAX(slider->min, slider->max); + min = MIN(slider->min, slider->max); + value = CLAMP(min, slider->value, max); + step = slider->step; - cursor_w = (w - 2 * pad) / (((max - min) + step) / step); - cursor_h = h - 2 * pad; - cursor_x = x + pad + (cursor_w * (value - min)); - cursor_y = y + pad; + cursor_w = (w - 2 * slider->pad_x) / (((max - min) + step) / step); + cursor_h = h - 2 * slider->pad_y; + cursor_x = x + slider->pad_x + (cursor_w * (value - min)); + cursor_y = y + slider->pad_y; if (!que || !in) return 0; mouse_x = in->mouse_pos.x; @@ -533,7 +561,7 @@ gui_slider(struct gui_draw_queue *que, const struct gui_input *in, const gui_float tmp = mouse_x - cursor_x + (cursor_w / 2); gui_float next_value = value + step * ((tmp < 0) ? -1.0f : 1.0f); next_value = CLAMP(min, next_value, max); - cursor_next_x = x + pad + (cursor_w * (next_value - min)); + cursor_next_x = x + slider->pad_x + (cursor_w * (next_value - min)); if (INBOX(mouse_x, mouse_y, cursor_next_x, cursor_y, cursor_next_x + cursor_w, cursor_y + cursor_h)) { @@ -541,59 +569,228 @@ gui_slider(struct gui_draw_queue *que, const struct gui_input *in, cursor_x = cursor_next_x; } } - gui_rectf(que, x, y, w, h, bg); - gui_rectf(que, cursor_x, cursor_y, cursor_w, cursor_h, fg); + gui_rectf(que, x, y, w, h, slider->background); + gui_rectf(que, cursor_x, cursor_y, cursor_w, cursor_h, slider->foreground); return value; } gui_int -gui_progress(struct gui_draw_queue *que, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - gui_size value, gui_size max, gui_bool modifyable) +gui_progress(struct gui_draw_queue *que, const struct gui_progress *prog, + const struct gui_input *in) { gui_float scale; gui_int mouse_x, mouse_y; gui_int cursor_x, cursor_y; gui_int cursor_w, cursor_h; + gui_int x, y, w, h; + gui_size value; - if (!que || !in) return 0; + if (!que || !in || !prog) return 0; mouse_x = in->mouse_pos.x; mouse_y = in->mouse_pos.y; - w = MAX(w, 2 * pad + 1); - h = MAX(h, 2 * pad + 1); - value = MIN(value, max); + x = prog->x, y = prog->y; + w = prog->w, h = prog->h; + w = MAX(prog->w, 2 * prog->pad_x + 1); + h = MAX(prog->h, 2 * prog->pad_y + 1); + value = MIN(prog->current, prog->max); - if (modifyable && in->mouse_down && INBOX(mouse_x, mouse_y, x, y, x+w, y+h)) { + if (prog->modifyable && in->mouse_down && INBOX(mouse_x, mouse_y, x, y, x+w, y+h)) { gui_float ratio = (gui_float)(mouse_x - x) / (gui_float)w; - value = (gui_size)((gui_float)max * ratio); + value = (gui_size)((gui_float)prog->max * ratio); } - if (!max) return value; - value = MIN(value, max); - scale = (gui_float)value / (gui_float)max; - cursor_h = h - 2 * pad; - cursor_w = (w - 2 * pad) * scale; - cursor_x = x + pad; - cursor_y = y + pad; - gui_rectf(que, x, y, w, h, bg); - gui_rectf(que, cursor_x, cursor_y, cursor_w, cursor_h, fg); + if (!prog->max) return value; + value = MIN(value, prog->max); + scale = (gui_float)value / (gui_float)prog->max; + cursor_h = h - 2 * prog->pad_y; + cursor_w = (w - 2 * prog->pad_x) * scale; + cursor_x = x + prog->pad_x; + cursor_y = y + prog->pad_y; + gui_rectf(que, x, y, w, h, prog->background); + gui_rectf(que, cursor_x, cursor_y, cursor_w, cursor_h, prog->foreground); return value; } gui_int -gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, - gui_int offset, gui_int dst) +gui_input(struct gui_draw_queue *que, const struct gui_input_field *input, + const struct gui_font *font, const struct gui_input *in) +{ + gui_int offset = 0; + gui_int label_x, label_y; + gui_int label_w, label_h; + gui_int x, y, w, h; + gui_int active; + const gui_char *t; + gui_int mouse_x, mouse_y; + gui_int text_width; + + if (!que || !in || !font || !input) + return 0; + + mouse_x = in->mouse_clicked_pos.x; + mouse_y = in->mouse_clicked_pos.y; + x = input->x, y = input->y; + w = MAX(input->w, 2 * input->pad_x); + h = MAX(input->h, font->height); + active = input->active; + t = input->buffer; + + if (in->mouse_clicked && in->mouse_down) + active = INBOX(mouse_x, mouse_y, x, y, x + w, y + h); + if (active) { + const struct gui_key *del = &in->keys[GUI_KEY_DEL]; + const struct gui_key *bs = &in->keys[GUI_KEY_BACKSPACE]; + const struct gui_key *enter = &in->keys[GUI_KEY_ENTER]; + const struct gui_key *esc = &in->keys[GUI_KEY_ESCAPE]; + if (in->text_len && *input->length < input->max) { + gui_long unicode; + gui_size i = 0, l = 0; + gui_size ulen = utf_decode(in->text, &unicode, in->text_len); + while (ulen && (l + ulen) <= in->text_len && *input->length < input->max) { + for (i = 0; i < ulen; i++) + input->buffer[(*input->length)++] = in->text[l + i]; + l = l + ulen; + ulen = utf_decode(in->text + l, &unicode, in->text_len - l); + } + } + if ((del->down && del->clicked) || (bs->down && bs->clicked)) + if (*input->length > 0) *input->length = *input->length - 1; + if ((enter->down && enter->clicked) || (esc->down && esc->clicked)) + active = gui_false; + } + + label_x = x + input->pad_x; + label_y = y + input->pad_y; + label_w = w - 2 * input->pad_x; + label_h = h - 2 * input->pad_y; + text_width = gui_font_text_width(font, t, *input->length); + while (text_width > label_w) { + offset += 1; + text_width = gui_font_text_width(font, &t[offset], *input->length - offset); + } + + gui_rectf(que, x, y, w, h, input->background); + gui_rect(que, x + 1, y, w - 1, h, input->foreground); + gui_string(que, font, label_x, label_y, label_w, label_h, input->font, + &t[offset], *input->length); + return active; +} + +void +gui_plot(struct gui_draw_queue *que, const struct gui_plot *plot) +{ + gui_int i; + gui_int last_x; + gui_int last_y; + gui_float max, min; + gui_float range, ratio; + gui_int step; + gui_int canvas_x, canvas_y; + gui_int canvas_w, canvas_h; + gui_int x, y, w, h; + + if (!que || !plot) return; + + x = plot->x, y = plot->y; + w = plot->w, h = plot->h; + gui_rectf(que, x, y, w, h, plot->background); + max = plot->values[0], min = plot->values[0]; + for (i = 0; i < plot->value_count; ++i) { + if (plot->values[i] > max) + max = plot->values[i]; + if (plot->values[i] < min) + min = plot->values[i]; + } + range = max - min; + + canvas_x = x + plot->pad_x; + canvas_y = y + plot->pad_y; + canvas_w = w - 2 * plot->pad_x; + canvas_h = h - 2 * plot->pad_y; + step = canvas_w / plot->value_count; + + ratio = (plot->values[0] - min) / range; + last_x = canvas_x; + last_y = (canvas_y + canvas_h) - ratio * (gui_float)canvas_h; + gui_rectf(que, last_x - 3, last_y - 3, 6, 6, plot->foreground); + for (i = 1; i < plot->value_count; i++) { + gui_int cur_x, cur_y; + ratio = (plot->values[i] - min) / range; + cur_x = canvas_x + step * i; + cur_y = (canvas_y + canvas_h) - (ratio * (gui_float)canvas_h); + gui_line(que, last_x, last_y, cur_x, cur_y, plot->foreground); + gui_rectf(que, cur_x - 3, cur_y - 3, 6, 6, plot->foreground); + last_x = cur_x; + last_y = cur_y; + } +} + +gui_int +gui_histo(struct gui_draw_queue *que, const struct gui_histo *histo, + const struct gui_input *in) +{ + gui_int i; + gui_float max; + gui_int canvas_x, canvas_y; + gui_int canvas_w, canvas_h; + gui_int item_w; + gui_int selected = -1; + gui_int x, y, w, h; + struct gui_color fg, nc; + + if (!que || !histo || !in) + return selected; + + x = histo->x, y = histo->y; + w = histo->w, h = histo->h; + fg = histo->foreground; + nc = histo->negative; + max = histo->values[0]; + for (i = 0; i < histo->value_count; ++i) { + if (ABS(histo->values[i]) > max) + max = histo->values[i]; + } + + gui_rectf(que, x, y, w, h, histo->background); + canvas_x = x + histo->pad_x; + canvas_y = y + histo->pad_y; + canvas_w = w - 2 * histo->pad_x; + canvas_h = h - 2 * histo->pad_y; + item_w = (canvas_w - (histo->value_count-1) * histo->pad_x) / (histo->value_count); + + for (i = 0; i < histo->value_count; i++) { + const gui_int mouse_x = in->mouse_pos.x; + const gui_int mouse_y = in->mouse_pos.y; + const gui_float ratio = ABS(histo->values[i]) / max; + const gui_int item_h = (gui_int)((gui_float)canvas_h * ratio); + const gui_int item_x = canvas_x + (i * item_w) + (i * histo->pad_y); + const gui_int item_y = (canvas_y + canvas_h) - item_h; + struct gui_color col = (histo->values[i] < 0) ? nc: fg; + if (INBOX(mouse_x, mouse_y, item_x, item_y, item_x + item_w, item_y + item_h)) { + selected = (in->mouse_down && in->mouse_clicked) ? i : -1; + col = histo->highlight; + } + gui_rectf(que, item_x, item_y, item_w, item_h, col); + } + return selected; +} + +gui_int +gui_scroll(struct gui_draw_queue *que, const struct gui_scroll *scroll, + const struct gui_input *in) { gui_int mouse_x, mouse_y; gui_int prev_x, prev_y; + gui_int x, y, w, h; + gui_int step, offset; - gui_bool up, down; + gui_bool u, d; gui_int button_size, button_half, button_y; gui_int bar_h, bar_y; + struct gui_button up, down; + struct gui_color fg, bg; + gui_int target; gui_float ratio; gui_float off; @@ -607,8 +804,13 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, gui_int xpad, ypad, xmid; if (!que || !in) return 0; - gui_rectf(que, x, y, w, h, bg); - if (dst <= h) return 0; + x = scroll->x, y = scroll->y; + w = scroll->w, h = scroll->h; + target = scroll->target; + fg = scroll->foreground; + bg = scroll->background; + gui_rectf(que, x, y, w, h, scroll->background); + if (scroll->target <= h) return 0; mouse_x = in->mouse_pos.x; mouse_y = in->mouse_pos.y; @@ -617,6 +819,7 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, w = MAX(w, 0); h = MAX(h, 2 * w); + step = CLAMP(0, scroll->step, h); pad = w / 4; button_size = w; @@ -624,14 +827,32 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, button_y = y + h - button_size; bar_h = h - 2 * button_size; bar_y = y + button_size; + offset = CLAMP(0, scroll->offset, scroll->target - bar_h); - ratio = (gui_float)bar_h/(gui_float)dst; - off = (gui_float)offset/(gui_float)dst; + ratio = (gui_float)bar_h/(gui_float)scroll->target; + off = (gui_float)offset/(gui_float)scroll->target; cursor_h = (gui_int)(ratio * (gui_float)bar_h); cursor_y = bar_y + (gui_int)(off * bar_h); cursor_w = w; cursor_x = x; + up.x = x, up.y = y; + up.w = button_size, up.h = button_size; + up.pad_y = 0, up.pad_x = 0; + up.text = NULL, up.length = 0; + up.font = fg, up.background = fg; + up.foreground = bg, up.highlight = fg; + + down.x = x, down.y = y + h - button_size; + down.w = button_size, down.h = button_size; + down.pad_y = 0, down.pad_x = 0; + down.text = NULL, down.length = 0; + down.font = fg, down.background = fg; + down.foreground = bg, down.highlight = fg; + + u = gui_button(que, &up, NULL, in); + d = gui_button(que, &down, NULL, in); + xpad = x + pad; ypad = button_y + pad; xmid = x + button_half; @@ -639,10 +860,8 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, yoff = y + (button_size - pad); boff = button_y + (button_size - pad); - up = gui_button(que, in, NULL, fg, bg, x, y, button_size, button_size, 0, NULL, 0); - down = gui_button(que, in, NULL, fg, bg, x, button_y, button_size, button_size, 0,NULL, 0); - gui_trianglef(que, xmid, y + pad, xoff, yoff, xpad, yoff, bg); - gui_trianglef(que, xpad, ypad, xoff, ypad, xmid, boff, bg); + gui_trianglef(que, xmid, y + pad, xoff, yoff, xpad, yoff, scroll->background); + gui_trianglef(que, xpad, ypad, xoff, ypad, xmid, boff, scroll->background); cursor_px = cursor_x + cursor_w; cursor_py = cursor_y + cursor_h; @@ -651,13 +870,12 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, if (in->mouse_down && inscroll && incursor) { const gui_float pixel = in->mouse_delta.y; - const gui_float delta = (pixel / (gui_float)bar_h) * (gui_float)dst; - offset = CLAMP(0, offset + delta, dst - bar_h); + const gui_float delta = (pixel / (gui_float)bar_h) * (gui_float)target; + offset = CLAMP(0, offset + delta, target - bar_h); cursor_y += pixel; - } else if (up || down) { - const gui_int h2 = h/2; - offset = (down) ? MIN(offset + h2, dst - bar_h) : MAX(0, offset - h2); - off = (gui_float)offset / (gui_float)dst; + } else if (u || d) { + offset = (d) ? MIN(offset + step, target - bar_h): MAX(0, offset - step); + off = (gui_float)offset / (gui_float)scroll->target; cursor_y = bar_y + (gui_int)(off * bar_h); } @@ -666,11 +884,78 @@ gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, return offset; } -gui_int gui_input(struct gui_draw_queue *que, const struct gui_input *in, - const struct gui_font *font, struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, - gui_char *buffer, gui_int *len, gui_bool active) +void gui_panel_init(struct gui_panel *panel, const struct gui_config *config, + const struct gui_font *font, const struct gui_input *input) { - return active; + panel->config = config; + panel->font = font; + panel->input = input; + panel->x = 0; panel->y = 0; + panel->at_x = 0; panel->at_y = 0; + panel->width = 0; + panel->flags = 0; + panel->index = 0; + panel->row_columns = 0; + panel->row_height = 0; + 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) +{ + panel->x = x; panel->y = y; + panel->at_x = x; panel->at_y = y; + panel->width = w; + panel->flags = f; + panel->index = 0; + panel->row_columns = 0; + panel->row_height = 0; + panel->queue = q; + return 0; +} + +void +gui_panel_row(struct gui_panel *panel, gui_int height, gui_int cols) +{ + panel->at_y += panel->row_height; + panel->at_x = panel->x; + panel->index = 0; + panel->row_columns = cols; + panel->row_height = height; +} + +static void +gui_panel_bounds(struct gui_rect *bounds, const struct gui_panel *panel) +{ + +} + +gui_int +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; + + button.text = str; + button.length = len; + button.x = bounds.x; + button.y = bounds.y; + button.w = bounds.w; + button.h = bounds.h; + button.pad_x = config->item_padding.x; + button.pad_y = config->item_padding.y; + button.background = config->colors[GUI_COLOR_BUTTON]; + button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER]; + button.font = config->colors[GUI_COLOR_TEXT]; + button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER]; + return gui_button(panel->queue, &button, panel->font, panel->input); +} + +void gui_panel_end(struct gui_panel *panel) +{ + panel->height = panel->at_y - panel->y; } diff --git a/gui.h b/gui.h index 27d2747..cd23e9e 100644 --- a/gui.h +++ b/gui.h @@ -3,8 +3,8 @@ vurtun MIT licence */ -#ifndef TINY_GUI_H_ -#define TINY_GUI_H_ +#ifndef GUI_H_ +#define GUI_H_ #define GUI_UTF_SIZE 4 #define GUI_INPUT_MAX 16 @@ -27,6 +27,7 @@ struct gui_color {gui_byte r,g,b,a;}; struct gui_texCoord {gui_float u,v;}; struct gui_vec2 {gui_float x,y;}; struct gui_rect {gui_float x,y,w,h;}; +struct gui_key {gui_int down, clicked;}; struct gui_vertex { struct gui_vec2 pos; @@ -63,7 +64,7 @@ enum gui_keys { }; struct gui_input { - gui_bool keys[GUI_KEY_MAX]; + struct gui_key keys[GUI_KEY_MAX]; gui_char text[GUI_INPUT_MAX]; gui_size text_len; struct gui_vec2 mouse_pos; @@ -92,6 +93,103 @@ struct gui_font { const struct gui_font_glyph *fallback; }; +struct gui_button { + gui_int x, y; + gui_int w, h; + gui_int pad_x, pad_y; + const char *text; + gui_int length; + struct gui_color font; + struct gui_color background; + struct gui_color foreground; + struct gui_color highlight; +}; + +struct gui_toggle { + gui_int x, y; + gui_int w, h; + gui_int pad_x, pad_y; + gui_int active; + const char *text; + gui_int length; + struct gui_color font; + struct gui_color background; + struct gui_color foreground; + struct gui_color highlight; +}; + +struct gui_slider { + gui_int x, y; + gui_int w, h; + gui_int pad_x; + gui_int pad_y; + gui_float min, max; + gui_float value; + gui_float step; + struct gui_color background; + struct gui_color foreground; +}; + +struct gui_progress { + gui_int x, y; + gui_int w, h; + gui_int pad_x; + gui_int pad_y; + gui_size current; + gui_size max; + gui_bool modifyable; + struct gui_color background; + struct gui_color foreground; +}; + +struct gui_scroll { + gui_int x, y; + gui_int w, h; + gui_int offset; + gui_int target; + gui_int step; + struct gui_color background; + struct gui_color foreground; +}; + +struct gui_input_field { + gui_int x, y; + gui_int w, h; + gui_int pad_x; + gui_int pad_y; + gui_char *buffer; + gui_int *length; + gui_int max; + gui_bool active; + struct gui_color background; + struct gui_color foreground; + struct gui_color font; +}; + +struct gui_plot { + gui_int x, y; + gui_int w, h; + gui_int pad_x; + gui_int pad_y; + gui_int value_count; + const gui_float *values; + struct gui_color background; + struct gui_color foreground; +}; + +struct gui_histo { + gui_int x, y; + gui_int w, h; + gui_int pad_x; + gui_int pad_y; + gui_int value_count; + const gui_float *values; + struct gui_color background; + struct gui_color foreground; + struct gui_color negative; + struct gui_color highlight; +}; + enum gui_panel_flags { GUI_PANEL_BORDER = 0x01, GUI_PANEL_TITLEBAR = 0x02, @@ -136,9 +234,17 @@ struct gui_panel { gui_flags flags; gui_int x, y; gui_int at_x, at_y; - gui_int width; + gui_int width, height; + gui_int index; + gui_int row_height; + gui_int row_columns; + struct gui_draw_queue *queue; + const struct gui_font *font; + const struct gui_input *input; + const 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); void gui_input_key(struct gui_input *in, enum gui_keys key, gui_int down); @@ -146,41 +252,38 @@ void gui_input_button(struct gui_input *in, gui_int x, gui_int y, gui_int down); void gui_input_char(struct gui_input *in, gui_glyph glyph); void gui_input_end(struct gui_input *in); +/* Output */ void gui_begin(struct gui_draw_queue *que, gui_byte *memory, gui_size size); 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); -gui_int gui_button(struct gui_draw_queue *que, const struct gui_input *in, - const struct gui_font *font, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - const char *str, gui_int len); -gui_int gui_toggle(struct gui_draw_queue *que, const struct gui_input *in, - const struct gui_font *font, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - const char *str, gui_int len, gui_int active); -gui_float gui_slider(struct gui_draw_queue *que, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - gui_float min, gui_float v, gui_float max, gui_float step); -gui_int gui_progress(struct gui_draw_queue *que, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, - gui_size cur, gui_size max, gui_bool modifyable); -gui_int gui_scroll(struct gui_draw_queue *que, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, - gui_int offset, gui_int dst); -gui_int gui_input(struct gui_draw_queue *que, const struct gui_input *in, - const struct gui_font *font, - struct gui_color bg, struct gui_color fg, - gui_int x, gui_int y, gui_int w, gui_int h, - gui_char *buffer, gui_int *len, gui_bool active); -gui_int gui_panel_begin(struct gui_panel *panel, const char *title, gui_flags f, - const struct gui_config *c, const struct gui_input *i); +/* 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); +gui_int gui_toggle(struct gui_draw_queue *que, const struct gui_toggle *toggle, + const struct gui_font *font, const struct gui_input *in); +gui_float gui_slider(struct gui_draw_queue *que, const struct gui_slider *slider, + const struct gui_input *in); +gui_int gui_progress(struct gui_draw_queue *que, const struct gui_progress *prog, + const struct gui_input *in); +gui_int gui_scroll(struct gui_draw_queue *que, const struct gui_scroll *scroll, + const struct gui_input *in); +gui_int gui_input(struct gui_draw_queue *que, const struct gui_input_field *f, + const struct gui_font *font, const struct gui_input *in); +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); +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); gui_int gui_panel_toggle(struct gui_panel *panel, const char *str, gui_int len, gui_int active); @@ -189,7 +292,11 @@ gui_float gui_panel_slider(struct gui_panel *panel, gui_float min, gui_float v, gui_float gui_panel_progress(struct gui_panel *panel, gui_size cur, gui_size max, gui_bool modifyable); gui_int gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_int *len, - gui_bool active); + 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); void gui_panel_end(struct gui_panel *panel); #endif diff --git a/mono.font b/mono.font deleted file mode 100644 index c900de20ad2ad761643fc9c5f5a5b2dc35911b9b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 266492 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 diff --git a/opengl.c b/opengl.c index 8efaf74..07a89c9 100644 --- a/opengl.c +++ b/opengl.c @@ -32,6 +32,7 @@ #define WIN_HEIGHT 600 #define DTIME 33 #define MAX_VERTEX_BUFFER (16 * 1024) +#define INPUT_MAX 64 #define MIN(a,b)((a) < (b) ? (a) : (b)) #define MAX(a,b)((a) < (b) ? (b) : (a)) @@ -133,6 +134,9 @@ kpress(struct GUI *gui, XEvent* e) gui_input_key(&gui->in, GUI_KEY_ENTER, gui_true); else if (*keysym == XK_BackSpace) gui_input_key(&gui->in, GUI_KEY_BACKSPACE, gui_true); + else if ((*keysym >= 'a' && *keysym <= 'z') || + (*keysym >= '0' && *keysym <= '9')) + gui_input_char(&gui->in, (unsigned char*)keysym); } static void @@ -167,7 +171,7 @@ brelease(struct GUI *con, XEvent *evt) { const float x = evt->xbutton.x; const float y = evt->xbutton.y; - struct XWindow *xw = con->win; + UNUSED(evt); if (evt->xbutton.button == Button1) gui_input_button(&con->in, x, y, gui_false); } @@ -177,7 +181,7 @@ bmotion(struct GUI *gui, XEvent *evt) { const gui_int x = evt->xbutton.x; const gui_int y = evt->xbutton.y; - struct XWindow *xw = gui->win; + UNUSED(evt); gui_input_motion(&gui->in, x, y); } @@ -185,6 +189,7 @@ static void resize(struct GUI *con, XEvent* evt) { struct XWindow *xw = con->win; + UNUSED(evt); XGetWindowAttributes(xw->dpy, xw->win, &xw->gwa); glViewport(0, 0, xw->gwa.width, xw->gwa.height); } @@ -223,12 +228,16 @@ ldbmp(gui_byte *data, uint32_t *width, uint32_t *height) int32_t i; header = data; - if (!width || !height) die("[BMP]: width or height is NULL!"); - if (header[0] != 'B' || header[1] != 'M') die("[BMP]: invalid file"); + if (!width || !height) + die("[BMP]: width or height is NULL!"); + if (header[0] != 'B' || header[1] != 'M') + die("[BMP]: invalid file"); *width = *(uint32_t*)&(header[0x12]); *height = *(uint32_t*)&(header[0x12]); ioff = *(uint32_t*)(&header[0x0A]); + if (*width <= 0 || *height <= 0) + die("[BMP]: invalid image size"); data = data + ioff; reader = data; @@ -237,15 +246,10 @@ ldbmp(gui_byte *data, uint32_t *width, uint32_t *height) for (i = *height-1; i >= 0; i--) { writer = target + (i * *width * 4); for (j = 0; j < *width; j++) { - gui_byte a = *(reader + (j * 4) + 0); - gui_byte r = *(reader + (j * 4) + 1); - gui_byte g = *(reader + (j * 4) + 2); - gui_byte b = *(reader + (j * 4) + 3); - - *writer++ = r; - *writer++ = g; - *writer++ = b; - *writer++ = a; + *writer++ = *(reader + (j * 4) + 1); + *writer++ = *(reader + (j * 4) + 2); + *writer++ = *(reader + (j * 4) + 3); + *writer++ = *(reader + (j * 4) + 0); *writer += 4; } reader += *width * 4; @@ -395,23 +399,111 @@ draw(int width, int height, const struct gui_draw_queue *que) int main(int argc, char *argv[]) { - GLenum err; struct XWindow xw; struct GUI gui; long dt, started; gui_byte *buffer; - gui_size buffer_size = MAX_VERTEX_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}; - gui_float slider = 5.0f; - gui_float prog = 60.0f; - gui_float offset = 300; - gui_int select = gui_false; - const char *selection[] = {"Inactive", "Active"}; + 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; - /* x11 */ + const char *selection[] = {"Inactive", "Active"}; + gui_char input[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; + + /* Window */ UNUSED(argc); UNUSED(argv); memset(&xw, 0, sizeof xw); memset(&gui, 0, sizeof gui); @@ -441,7 +533,7 @@ main(int argc, char *argv[]) /* OpenGL */ xw.glc = glXCreateContext(xw.dpy, xw.vi, NULL, GL_TRUE); glXMakeCurrent(xw.dpy, xw.win, xw.glc); - buffer = xcalloc(MAX_VERTEX_BUFFER, 1); + buffer = xcalloc(buffer_size, 1); xw.running = 1; gui.win = &xw; @@ -462,17 +554,16 @@ main(int argc, char *argv[]) /* ------------------------- GUI --------------------------*/ gui_begin(&gui.out, buffer, MAX_VERTEX_BUFFER); - if (gui_button(&gui.out, &gui.in, gui.font, colorA, colorB, 50,50,150,30,5,"button",6)) - fprintf(stdout, "Button pressed!\n"); - slider = gui_slider(&gui.out, &gui.in, colorA, colorB, - 50, 100, 150, 30, 2, 0.0f, slider, 10.0f, 1.0f); - prog = gui_progress(&gui.out, &gui.in, colorA, colorB, - 50, 150, 150, 30, 2, prog, 100.0f, gui_true); - select = gui_toggle(&gui.out, &gui.in, gui.font, colorA, colorB, - 50, 200, 150, 30, 2, selection[select], - strlen(selection[select]), select); - offset = gui_scroll(&gui.out, &gui.in, colorA, colorB, - 250, 50, 16, 300, offset, 600); + if (gui_button(&gui.out, &button, gui.font, &gui.in)) + 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_end(&gui.out); /* ---------------------------------------------------------*/