This commit is contained in:
vurtun 2015-03-12 22:53:28 +01:00
parent b7be69dcf0
commit 6df135829c
5 changed files with 224 additions and 178 deletions

View File

@ -31,5 +31,5 @@ gcc: $(BIN)
$(BIN): $(BIN):
@mkdir -p bin @mkdir -p bin
rm -f bin/$(BIN) $(OBJS) rm -f bin/$(BIN) $(OBJS)
$(CC) $(SRC) -D_POSIX_C_SOURCE=200809L $(CFLAGS) -o bin/$(BIN) -lX11 -lGL -lGLU $(CC) $(SRC) -D_POSIX_C_SOURCE=200809L $(CFLAGS) -o bin/$(BIN) -lX11 -lGL -lGLU -lm

305
gui.c
View File

@ -15,7 +15,9 @@
#define ABS(a) (((a) < 0) ? -(a) : (a)) #define ABS(a) (((a) < 0) ? -(a) : (a))
#define UNUSED(a) ((void)(a)) #define UNUSED(a) ((void)(a))
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
#define INBOX(x, y, x0, y0, x1, y1) (BETWEEN(x, x0, x1) && BETWEEN(y, y0, y1)) #define INBOX(px, py, x, y, w, h) (BETWEEN(px, x, x+w) && BETWEEN(py, y, y+h))
#define ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0)
#define ALIGN(x, mask) (void*)((unsigned long)((gui_byte*)(x) + (mask-1)) & ~(mask-1))
#define ASSERT_LINE(p, l, f) \ #define ASSERT_LINE(p, l, f) \
typedef char PASTE(assertion_failed_##f##_,l)[2*!!(p)-1]; typedef char PASTE(assertion_failed_##f##_,l)[2*!!(p)-1];
@ -42,8 +44,8 @@ fsqrt(float x)
ASSERT(sizeof(int) == sizeof(float)); ASSERT(sizeof(int) == sizeof(float));
val.f = x; val.f = x;
val.i = 0x5f375a86 - (val.i>>1); val.i = 0x5f375a86 - (val.i >> 1);
val.f = val.f*(1.5f-xhalf*val.f*val.f); val.f = val.f * (1.5f - xhalf * val.f * val.f);
return 1.0f/val.f; return 1.0f/val.f;
} }
@ -150,7 +152,7 @@ gui_default_config(struct gui_config *config)
config->global_alpha = 1.0f; config->global_alpha = 1.0f;
config->scrollbar_width = 16; config->scrollbar_width = 16;
config->scroll_factor = 2; config->scroll_factor = 2;
config->panel_padding = gui_make_vec2(10.0f, 10.0f); config->panel_padding = gui_make_vec2(15.0f, 10.0f);
config->panel_min_size = gui_make_vec2(32.0f, 32.0f); config->panel_min_size = gui_make_vec2(32.0f, 32.0f);
config->item_spacing = gui_make_vec2(8.0f, 8.0f); config->item_spacing = gui_make_vec2(8.0f, 8.0f);
config->item_padding = gui_make_vec2(4.0f, 4.0f); config->item_padding = gui_make_vec2(4.0f, 4.0f);
@ -241,48 +243,57 @@ static gui_size
gui_font_text_width(const struct gui_font *font, const gui_char *t, gui_size l) gui_font_text_width(const struct gui_font *font, const gui_char *t, gui_size l)
{ {
gui_long unicode; gui_long unicode;
gui_size len = 0; gui_size text_width = 0;
const struct gui_font_glyph *g; const struct gui_font_glyph *glyph;
gui_size text_len = 0; gui_size text_len = 0;
gui_size ulen; gui_size glyph_len;
if (!t || !l) return 0; if (!t || !l) return 0;
ulen = utf_decode(t, &unicode, l); glyph_len = utf_decode(t, &unicode, l);
while (text_len <= l && ulen) { while (text_len <= l && glyph_len) {
if (unicode == UTF_INVALID) return 0; if (unicode == UTF_INVALID) return 0;
g = (unicode < font->glyph_count) ? &font->glyphes[unicode] : font->fallback; glyph = (unicode < font->glyph_count) ? &font->glyphes[unicode] : font->fallback;
g = (g->code == 0) ? font->fallback : g; glyph = (glyph->code == 0) ? font->fallback : glyph;
len += (gui_size)(g->xadvance * font->scale); text_width += (gui_size)(glyph->xadvance * font->scale);
ulen = utf_decode(t + text_len, &unicode, l - text_len); glyph_len = utf_decode(t + text_len, &unicode, l - text_len);
text_len += ulen; text_len += glyph_len;
} }
return len; return text_width;
} }
void void
gui_begin(struct gui_draw_buffer *buffer, gui_byte *memory, gui_size size) gui_begin(struct gui_draw_buffer *buffer, void *memory, gui_size size)
{ {
if (!buffer || !memory || !size) return; void *vertexes, *aligned;
buffer->begin = memory + size - sizeof(struct gui_draw_command); gui_size cmd_siz, aligning;
buffer->vertexes = memory; static const gui_size align = ALIGNOF(struct gui_vertex);
buffer->end = buffer->begin; if (!buffer || !memory || !size)
buffer->memory = memory; return;
buffer->size = size;
buffer->vertex_write = 0; cmd_siz = size / 6;
buffer->vertex_count = 0; vertexes = (gui_byte*)memory + cmd_siz;
buffer->command_count = 0; aligned = ALIGN(vertexes, align);
aligning = (gui_size)((gui_byte*)aligned - (gui_byte*)vertexes);
buffer->command_capacity = cmd_siz / sizeof(struct gui_draw_command);
buffer->vertex_capacity = (size - cmd_siz - aligning) / sizeof(struct gui_vertex);
buffer->commands = memory;
buffer->vertexes = aligned;
buffer->command_size = 0;
buffer->vertex_size = 0;
buffer->allocated = 0; buffer->allocated = 0;
buffer->needed = 0;
} }
gui_size gui_size
gui_end(struct gui_draw_buffer *buffer) gui_end(struct gui_draw_buffer *buffer)
{ {
gui_size allocated; gui_size needed;
if (!buffer) return 0; if (!buffer) return 0;
allocated = buffer->allocated; needed = buffer->needed;
buffer->allocated = 0; buffer->allocated = 0;
buffer->vertex_count = 0; buffer->command_capacity = 0;
return allocated; buffer->vertex_capacity = 0;
return needed;
} }
static gui_int static gui_int
@ -294,41 +305,24 @@ gui_push(struct gui_draw_buffer *buffer, gui_size count,
gui_size cmd_memory = 0; gui_size cmd_memory = 0;
gui_size vertex_size; gui_size vertex_size;
gui_size current; gui_size current;
struct gui_draw_command cmd; struct gui_draw_command *cmd;
buffer->needed += count * sizeof(struct gui_vertex);
buffer->needed += sizeof(struct gui_draw_command);
if (!buffer || !rect) return gui_false; if (!buffer || !rect) return gui_false;
if (!buffer->end || !buffer->begin || buffer->end > buffer->begin) if (!buffer->commands || !buffer->command_capacity ||
buffer->command_size >= buffer->command_capacity)
return gui_false; return gui_false;
vertex_size = sizeof(struct gui_vertex) * (buffer->vertex_count + count); if (!buffer->vertexes || !buffer->vertex_capacity ||
if (buffer->vertexes + vertex_size >= buffer->end) (buffer->vertex_size + count) >= buffer->vertex_capacity)
return gui_false; return gui_false;
cmd.vertex_count = count; cmd = &buffer->commands[buffer->command_size++];
cmd.clip_rect = *rect; cmd->vertex_count = count;
cmd.texture = tex; cmd->clip_rect = *rect;
memcopy(buffer->end, &cmd, sizeof(struct gui_draw_command)); cmd->texture = tex;
buffer->end -= sizeof(struct gui_draw_command);
buffer->vertex_count += count;
buffer->allocated += count * sizeof(struct gui_vertex); buffer->allocated += count * sizeof(struct gui_vertex);
buffer->allocated += sizeof(struct gui_draw_command); buffer->allocated += sizeof(struct gui_draw_command);
buffer->command_count++;
return gui_true;
}
gui_int
gui_get_command(struct gui_draw_command *cmd, const struct gui_draw_buffer *buffer,
gui_size index)
{
gui_byte *iter;
gui_size size = 0;
if (!buffer || !buffer->memory || !buffer->begin || !buffer->end || !buffer->size)
return gui_false;
if (!cmd || buffer->begin == buffer->end)
return gui_false;
if (index >= buffer->command_count)
return gui_false;
iter = buffer->begin - (index * sizeof(struct gui_draw_command));
memcopy(cmd, iter, sizeof(struct gui_draw_command));
return gui_true; return gui_true;
} }
@ -336,22 +330,18 @@ static void
gui_vertex(struct gui_draw_buffer *buffer, gui_float x, gui_float y, gui_vertex(struct gui_draw_buffer *buffer, gui_float x, gui_float y,
struct gui_color col, gui_float u, gui_float v) struct gui_color col, gui_float u, gui_float v)
{ {
gui_size i; struct gui_vertex *vertex;
gui_byte *dst;
struct gui_vertex vertex;
if (!buffer) return; if (!buffer) return;
i = buffer->vertex_write; if (!buffer->vertexes || !buffer->vertex_capacity ||
if (i >= buffer->vertex_count) return; buffer->vertex_size >= buffer->vertex_capacity)
return;
vertex.pos.x = x; vertex = &buffer->vertexes[buffer->vertex_size++];
vertex.pos.y = y; vertex->color = col;
vertex.color = col; vertex->pos.x = x;
vertex.uv.u = u; vertex->pos.y = y;
vertex.uv.v = v; vertex->uv.u = u;
vertex->uv.v = v;
dst = buffer->vertexes + i * sizeof(struct gui_vertex);
memcopy(dst, &vertex, sizeof(struct gui_vertex));
buffer->vertex_write++;
} }
static void static void
@ -505,8 +495,8 @@ gui_button(struct gui_draw_buffer *buffer, const struct gui_button *button,
bg = button->background; bg = button->background;
hc = button->highlight; hc = button->highlight;
if (INBOX(mouse_x, mouse_y, x, y, x+w, y+h)) { if (INBOX(mouse_x, mouse_y, x, y, w, h)) {
if (INBOX(clicked_x, clicked_y, x, y, x+w, y+h)) if (INBOX(clicked_x, clicked_y, x, y, w, h))
ret = (in->mouse_down && in->mouse_clicked); ret = (in->mouse_down && in->mouse_clicked);
fc = bg; bg = hc; fc = bg; bg = hc;
} }
@ -570,9 +560,7 @@ gui_toggle(struct gui_draw_buffer *buffer, const struct gui_toggle *toggle,
if (!in->mouse_down && in->mouse_clicked) { if (!in->mouse_down && in->mouse_clicked) {
const gui_float clicked_x = in->mouse_clicked_pos.x; const gui_float clicked_x = in->mouse_clicked_pos.x;
const gui_float clicked_y = in->mouse_clicked_pos.y; const gui_float clicked_y = in->mouse_clicked_pos.y;
const gui_float cursor_px = cursor_x + cursor_size; if (INBOX(clicked_x, clicked_y, cursor_x, cursor_y, cursor_size, cursor_size))
const gui_float cursor_py = cursor_y + cursor_size;
if (INBOX(clicked_x, clicked_y, cursor_x, cursor_y, cursor_px, cursor_py))
active = !active; active = !active;
} }
@ -617,8 +605,8 @@ gui_slider(struct gui_draw_buffer *buffer, const struct gui_slider *slider,
clicked_y = in->mouse_clicked_pos.y; clicked_y = in->mouse_clicked_pos.y;
if (in->mouse_down && if (in->mouse_down &&
INBOX(clicked_x, clicked_y, x, y, x + w, y + h) && INBOX(clicked_x, clicked_y, x, y, w, h) &&
INBOX(mouse_x, mouse_y, x, y, x + w, y + h)) INBOX(mouse_x, mouse_y, x, y, w, h))
{ {
const float d = mouse_x - (cursor_x + cursor_w / 2.0f); const float d = mouse_x - (cursor_x + cursor_w / 2.0f);
const float pxstep = (w - 2 * slider->pad_x) / steps; const float pxstep = (w - 2 * slider->pad_x) / steps;
@ -653,7 +641,7 @@ gui_progress(struct gui_draw_buffer *buffer, const struct gui_progress *prog,
h = MAX(prog->h, 2 * prog->pad_y + 1); h = MAX(prog->h, 2 * prog->pad_y + 1);
value = MIN(prog->current, prog->max); value = MIN(prog->current, prog->max);
if (prog->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, w, h)) {
gui_float ratio = (gui_float)(mouse_x - x) / (gui_float)w; gui_float ratio = (gui_float)(mouse_x - x) / (gui_float)w;
value = (gui_size)((gui_float)prog->max * ratio); value = (gui_size)((gui_float)prog->max * ratio);
} }
@ -671,7 +659,8 @@ gui_progress(struct gui_draw_buffer *buffer, const struct gui_progress *prog,
} }
gui_int gui_int
gui_input(struct gui_draw_buffer *buffer, const struct gui_input_field *input, gui_input(struct gui_draw_buffer *buf, gui_char *buffer, gui_size *length,
const struct gui_input_field *input,
const struct gui_font *font, const struct gui_input *in) const struct gui_font *font, const struct gui_input *in)
{ {
gui_size offset = 0; gui_size offset = 0;
@ -679,7 +668,6 @@ gui_input(struct gui_draw_buffer *buffer, const struct gui_input_field *input,
gui_float label_w, label_h; gui_float label_w, label_h;
gui_float x, y, w, h; gui_float x, y, w, h;
gui_int active; gui_int active;
const gui_char *t;
gui_float mouse_x, mouse_y; gui_float mouse_x, mouse_y;
gui_size text_width; gui_size text_width;
@ -692,49 +680,48 @@ gui_input(struct gui_draw_buffer *buffer, const struct gui_input_field *input,
w = MAX(input->w, 2 * input->pad_x); w = MAX(input->w, 2 * input->pad_x);
h = MAX(input->h, font->height); h = MAX(input->h, font->height);
active = input->active; active = input->active;
t = input->buffer;
if (in->mouse_clicked && in->mouse_down) if (in->mouse_clicked && in->mouse_down)
active = INBOX(mouse_x, mouse_y, x, y, x + w, y + h); active = INBOX(mouse_x, mouse_y, x, y, w, h);
if (active) { if (active) {
const struct gui_key *del = &in->keys[GUI_KEY_DEL]; const struct gui_key *del = &in->keys[GUI_KEY_DEL];
const struct gui_key *bs = &in->keys[GUI_KEY_BACKSPACE]; const struct gui_key *bs = &in->keys[GUI_KEY_BACKSPACE];
const struct gui_key *enter = &in->keys[GUI_KEY_ENTER]; const struct gui_key *enter = &in->keys[GUI_KEY_ENTER];
const struct gui_key *esc = &in->keys[GUI_KEY_ESCAPE]; const struct gui_key *esc = &in->keys[GUI_KEY_ESCAPE];
const struct gui_key *space = &in->keys[GUI_KEY_SPACE]; const struct gui_key *space = &in->keys[GUI_KEY_SPACE];
if (in->text_len && *input->length < input->max) { if (in->text_len && *length < input->max) {
gui_long unicode; gui_long unicode;
gui_size i = 0, l = 0; gui_size i = 0, l = 0;
gui_size ulen = utf_decode(in->text, &unicode, in->text_len); gui_size ulen = utf_decode(in->text, &unicode, in->text_len);
while (ulen && (l + ulen) <= in->text_len && *input->length < input->max) { while (ulen && (l + ulen) <= in->text_len && *length < input->max) {
for (i = 0; i < ulen; i++) for (i = 0; i < ulen; i++)
input->buffer[(*input->length)++] = in->text[l + i]; buffer[(*length)++] = in->text[l + i];
l = l + ulen; l = l + ulen;
ulen = utf_decode(in->text + l, &unicode, in->text_len - l); ulen = utf_decode(in->text + l, &unicode, in->text_len - l);
} }
} }
if ((del->down && del->clicked) || (bs->down && bs->clicked)) if ((del->down && del->clicked) || (bs->down && bs->clicked))
if (*input->length > 0) *input->length = *input->length - 1; if (*length > 0) *length = *length - 1;
if ((enter->down && enter->clicked) || (esc->down && esc->clicked)) if ((enter->down && enter->clicked) || (esc->down && esc->clicked))
active = gui_false; active = gui_false;
if ((space->down && space->clicked) && (*input->length < input->max)) if ((space->down && space->clicked) && (*length < input->max))
input->buffer[(*input->length)++] = ' '; buffer[(*length)++] = ' ';
} }
label_x = x + input->pad_x; label_x = x + input->pad_x;
label_y = y + input->pad_y; label_y = y + input->pad_y;
label_w = w - 2 * input->pad_x; label_w = w - 2 * input->pad_x;
label_h = h - 2 * input->pad_y; label_h = h - 2 * input->pad_y;
text_width = gui_font_text_width(font, t, *input->length); text_width = gui_font_text_width(font, buffer, *length);
while (text_width > label_w) { while (text_width > label_w) {
offset += 1; offset += 1;
text_width = gui_font_text_width(font, &t[offset], *input->length - offset); text_width = gui_font_text_width(font, &buffer[offset], *length - offset);
} }
gui_rectf(buffer, x, y, w, h, input->background); gui_rectf(buf, x, y, w, h, input->background);
gui_rect(buffer, x + 1, y, w - 1, h, input->foreground); gui_rect(buf, x + 1, y, w - 1, h, input->foreground);
gui_string(buffer, font, label_x, label_y, label_w, label_h, input->font, gui_string(buf, font, label_x, label_y, label_w, label_h, input->font,
&t[offset], *input->length); &buffer[offset], *length);
return active; return active;
} }
@ -785,10 +772,11 @@ gui_plot(struct gui_draw_buffer *buffer, const struct gui_plot *plot,
ratio = (plot->values[0] - min) / range; ratio = (plot->values[0] - min) / range;
last_x = canvas_x; last_x = canvas_x;
last_y = (canvas_y + canvas_h) - ratio * (gui_float)canvas_h; last_y = (canvas_y + canvas_h) - ratio * (gui_float)canvas_h;
if (INBOX(mouse_x, mouse_y, last_x-3, last_y-3, last_x + 3, last_y + 3)) { if (INBOX(mouse_x, mouse_y, last_x-3, last_y-3, 6, 6)) {
selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1; selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1;
col = plot->highlight; col = plot->highlight;
} }
gui_rectf(buffer, last_x - 3, last_y - 3, 6, 6, col); gui_rectf(buffer, last_x - 3, last_y - 3, 6, 6, col);
for (i = 1; i < plot->value_count; i++) { for (i = 1; i < plot->value_count; i++) {
gui_float cur_x, cur_y; gui_float cur_x, cur_y;
@ -796,7 +784,7 @@ gui_plot(struct gui_draw_buffer *buffer, const struct gui_plot *plot,
cur_x = canvas_x + (gui_float)(step * i); cur_x = canvas_x + (gui_float)(step * i);
cur_y = (canvas_y + canvas_h) - (ratio * (gui_float)canvas_h); cur_y = (canvas_y + canvas_h) - (ratio * (gui_float)canvas_h);
gui_line(buffer, last_x, last_y, cur_x, cur_y, plot->foreground); gui_line(buffer, last_x, last_y, cur_x, cur_y, plot->foreground);
if (INBOX(mouse_x, mouse_y, cur_x-3, cur_y-3, cur_x + 3, cur_y + 3)) { if (INBOX(mouse_x, mouse_y, cur_x-3, cur_y-3, 6, 6)) {
selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1; selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1;
col = plot->highlight; col = plot->highlight;
} else col = plot->foreground; } else col = plot->foreground;
@ -852,7 +840,7 @@ gui_histo(struct gui_draw_buffer *buffer, const struct gui_histo *histo,
const gui_float item_x = canvas_x + (j * item_w) + (j * histo->pad_y); const gui_float item_x = canvas_x + (j * item_w) + (j * histo->pad_y);
const gui_float item_y = (canvas_y + canvas_h) - item_h; const gui_float item_y = (canvas_y + canvas_h) - item_h;
struct gui_color col = (histo->values[i] < 0) ? nc: fg; 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)) { if (INBOX(mouse_x, mouse_y, item_x, item_y, item_w, item_h)) {
selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1; selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1;
col = histo->highlight; col = histo->highlight;
} }
@ -934,7 +922,6 @@ gui_scroll(struct gui_draw_buffer *buffer, const struct gui_scroll *scroll,
down.text = NULL, down.length = 0; down.text = NULL, down.length = 0;
down.font = fg, down.background = fg; down.font = fg, down.background = fg;
down.foreground = bg, down.highlight = fg; down.foreground = bg, down.highlight = fg;
u = gui_button(buffer, &up, NULL, in); u = gui_button(buffer, &up, NULL, in);
d = gui_button(buffer, &down, NULL, in); d = gui_button(buffer, &down, NULL, in);
@ -944,15 +931,11 @@ gui_scroll(struct gui_draw_buffer *buffer, const struct gui_scroll *scroll,
xoff = x + (button_size - pad); xoff = x + (button_size - pad);
yoff = y + (button_size - pad); yoff = y + (button_size - pad);
boff = button_y + (button_size - pad); boff = button_y + (button_size - pad);
gui_trianglef(buffer, xmid, y + pad, xoff, yoff, xpad, yoff, scroll->background); gui_trianglef(buffer, xmid, y + pad, xoff, yoff, xpad, yoff, scroll->background);
gui_trianglef(buffer, xpad, ypad, xoff, ypad, xmid, boff, scroll->background); gui_trianglef(buffer, xpad, ypad, xoff, ypad, xmid, boff, scroll->background);
cursor_px = cursor_x + cursor_w; inscroll = INBOX(mouse_x, mouse_y, x, y, w, h);
cursor_py = cursor_y + cursor_h; incursor = INBOX(prev_x, prev_y, cursor_x, cursor_y, cursor_w, cursor_h);
inscroll = INBOX(mouse_x, mouse_y, x, y, x + w, y + h);
incursor = INBOX(prev_x, prev_y, cursor_x, cursor_y, cursor_px, cursor_py);
if (in->mouse_down && inscroll && incursor) { if (in->mouse_down && inscroll && incursor) {
const gui_float pixel = in->mouse_delta.y; const gui_float pixel = in->mouse_delta.y;
const gui_float delta = (pixel / (gui_float)bar_h) * (gui_float)target; const gui_float delta = (pixel / (gui_float)bar_h) * (gui_float)target;
@ -997,6 +980,7 @@ gui_panel_begin(struct gui_panel *panel, struct gui_draw_buffer *out,
gui_size text_len = 0; gui_size text_len = 0;
gui_float header_height = 0; gui_float header_height = 0;
gui_float label_x, label_y, label_w, label_h; gui_float label_x, label_y, label_w, label_h;
const struct gui_config *config = panel->config; const struct gui_config *config = panel->config;
const struct gui_color *header = &config->colors[GUI_COLOR_TITLEBAR]; const struct gui_color *header = &config->colors[GUI_COLOR_TITLEBAR];
const gui_float mouse_x = panel->in->mouse_pos.x; const gui_float mouse_x = panel->in->mouse_pos.x;
@ -1021,35 +1005,43 @@ gui_panel_begin(struct gui_panel *panel, struct gui_draw_buffer *out,
panel->height = h; panel->height = h;
if (panel->flags & GUI_PANEL_CLOSEABLE) { if (panel->flags & GUI_PANEL_CLOSEABLE) {
const gui_char *X = (gui_char*)"X"; gui_size text_width;
gui_size text_width = gui_font_text_width(panel->font, X, 1);
gui_float close_x, close_y, close_w, close_h; gui_float close_x, close_y, close_w, close_h;
close_x = (x + w) - (text_width + config->panel_padding.x); const gui_char *X = (const gui_char*)"x";
text_width = gui_font_text_width(panel->font, X, 1);
close_x = (x + w) - ((gui_float)text_width + config->panel_padding.x);
close_y = y + config->panel_padding.y; close_y = y + config->panel_padding.y;
close_w = text_width + config->panel_padding.x; close_w = (gui_float)text_width + config->panel_padding.x;
close_h = panel->font->height + 2 * config->item_padding.y; close_h = panel->font->height + 2 * config->item_padding.y;
w -= (text_width + config->panel_padding.x); w -= ((gui_float)text_width + config->panel_padding.x);
gui_string(panel->out, panel->font, close_x, close_y, close_w, close_h, gui_string(panel->out, panel->font, close_x, close_y, close_w, close_h,
config->colors[GUI_COLOR_TEXT], X, 1); config->colors[GUI_COLOR_TEXT], X, 1);
if (INBOX(mouse_x, mouse_y, close_x, close_y, close_x+close_w, close_y+close_h)) { if (INBOX(mouse_x, mouse_y, close_x, close_y, close_w, close_h)) {
if (INBOX(clicked_x, clicked_y, close_x, close_y, close_x+close_w, close_y+close_h)) if (INBOX(clicked_x, clicked_y, close_x, close_y, close_w, close_h))
ret = !(panel->in->mouse_down && panel->in->mouse_clicked); ret = !(panel->in->mouse_down && panel->in->mouse_clicked);
} }
} }
if (panel->flags & GUI_PANEL_MINIMIZABLE) { if (panel->flags & GUI_PANEL_MINIMIZABLE) {
const gui_char *score = (gui_char*)"-"; gui_size text_width;
gui_float min_x, min_y, min_w, min_h; gui_float min_x, min_y, min_w, min_h;
gui_size text_width = gui_font_text_width(panel->font, score, 1); const gui_char *score = (panel->minimized) ?
min_x = (x + w) - (text_width + config->item_padding.y); (const gui_char*)"+":
(const gui_char*)"-";
text_width = gui_font_text_width(panel->font, score, 1);
min_x = (x + w) - ((gui_float)text_width + config->item_padding.y);
min_y = y + config->panel_padding.y; min_y = y + config->panel_padding.y;
min_w = text_width; min_w = (gui_float)text_width;
min_h = panel->font->height + 2 * config->item_padding.y; min_h = panel->font->height + 2 * config->item_padding.y;
w -= text_width; w -= (gui_float)text_width;
gui_string(panel->out, panel->font, min_x, min_y, min_w, min_h, gui_string(panel->out, panel->font, min_x, min_y, min_w, min_h,
config->colors[GUI_COLOR_TEXT], score, 1); config->colors[GUI_COLOR_TEXT], score, 1);
if (INBOX(mouse_x, mouse_y, min_x, min_y, min_x+min_w, min_y+min_h)) { if (INBOX(mouse_x, mouse_y, min_x, min_y, min_w, min_h)) {
if (INBOX(clicked_x, clicked_y, min_x, min_y, min_x+min_w, min_y+min_h)) if (INBOX(clicked_x, clicked_y, min_x, min_y, min_w, min_h))
if (panel->in->mouse_down && panel->in->mouse_clicked) if (panel->in->mouse_down && panel->in->mouse_clicked)
panel->minimized = !panel->minimized; panel->minimized = !panel->minimized;
} }
@ -1080,8 +1072,20 @@ gui_panel_row(struct gui_panel *panel, gui_float height, gui_size cols)
height + config->panel_padding.y, *color); height + config->panel_padding.y, *color);
} }
void
gui_panel_seperator(struct gui_panel *panel, gui_size cols)
{
const struct gui_config *config;
if (!panel) return;
config = panel->config;
cols = MIN(cols, panel->row_columns - panel->index);
panel->index += cols;
if (panel->index >= panel->row_columns)
gui_panel_row(panel, panel->row_height - config->item_spacing.y, panel->row_columns);
}
static void static void
gui_panel_alloc(struct gui_rect *bounds, struct gui_panel *panel) gui_panel_alloc_space(struct gui_rect *bounds, struct gui_panel *panel)
{ {
const struct gui_config *config = panel->config; const struct gui_config *config = panel->config;
gui_float padding, spacing, space; gui_float padding, spacing, space;
@ -1109,9 +1113,12 @@ gui_panel_button(struct gui_panel *panel, const char *str, gui_size len)
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_button button; struct gui_button button;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (panel->minimized) return 0;
gui_panel_alloc(&bounds, panel); if (!panel || !panel->config || !panel->in || !panel->out) return 0;
if (!panel->font || panel->minimized) return 0;
gui_panel_alloc_space(&bounds, panel);
config = panel->config;
button.text = str; button.text = str;
button.length = len; button.length = len;
@ -1134,9 +1141,12 @@ gui_panel_toggle(struct gui_panel *panel, const char *text, gui_size length,
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_toggle toggle; struct gui_toggle toggle;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (panel->minimized) return is_active;
gui_panel_alloc(&bounds, panel); if (!panel || !panel->config || !panel->in || !panel->out) return is_active;
if (!panel->font || panel->minimized) return is_active;
gui_panel_alloc_space(&bounds, panel);
config = panel->config;
toggle.x = bounds.x; toggle.x = bounds.x;
toggle.y = bounds.y; toggle.y = bounds.y;
@ -1159,9 +1169,12 @@ gui_panel_slider(struct gui_panel *panel, gui_float min_value, gui_float value,
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_slider slider; struct gui_slider slider;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (!panel || !panel->config || !panel->in || !panel->out) return value;
if (panel->minimized) return value; if (panel->minimized) return value;
gui_panel_alloc(&bounds, panel); gui_panel_alloc_space(&bounds, panel);
config = panel->config;
slider.x = bounds.x; slider.x = bounds.x;
slider.y = bounds.y; slider.y = bounds.y;
@ -1184,9 +1197,12 @@ gui_panel_progress(struct gui_panel *panel, gui_size cur_value, gui_size max_val
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_progress prog; struct gui_progress prog;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (!panel || !panel->config || !panel->in || !panel->out) return cur_value;
if (panel->minimized) return cur_value; if (panel->minimized) return cur_value;
gui_panel_alloc(&bounds, panel); gui_panel_alloc_space(&bounds, panel);
config = panel->config;
prog.x = bounds.x; prog.x = bounds.x;
prog.y = bounds.y; prog.y = bounds.y;
@ -1208,9 +1224,12 @@ gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size *length,
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_input_field field; struct gui_input_field field;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (panel->minimized) return gui_false;
gui_panel_alloc(&bounds, panel); if (!panel || !panel->config || !panel->in || !panel->out) return is_active;
if (!panel->font || panel->minimized) return is_active;
gui_panel_alloc_space(&bounds, panel);
config = panel->config;
field.x = bounds.x; field.x = bounds.x;
field.y = bounds.y; field.y = bounds.y;
@ -1218,14 +1237,12 @@ gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size *length,
field.h = bounds.h; field.h = bounds.h;
field.pad_x = config->item_padding.x; field.pad_x = config->item_padding.x;
field.pad_y = config->item_padding.y; field.pad_y = config->item_padding.y;
field.buffer = buffer;
field.length = length;
field.max = max_length; field.max = max_length;
field.active = is_active; field.active = is_active;
field.font = config->colors[GUI_COLOR_TEXT]; field.font = config->colors[GUI_COLOR_TEXT];
field.background = config->colors[GUI_COLOR_INPUT]; field.background = config->colors[GUI_COLOR_INPUT];
field.foreground = config->colors[GUI_COLOR_INPUT_BORDER]; field.foreground = config->colors[GUI_COLOR_INPUT_BORDER];
return gui_input(panel->out, &field, panel->font, panel->in); return gui_input(panel->out, buffer, length, &field, panel->font, panel->in);
} }
gui_int gui_int
@ -1233,9 +1250,12 @@ gui_panel_plot(struct gui_panel *panel, const gui_float *values, gui_size count)
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_plot plot; struct gui_plot plot;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (!panel || !panel->config || !panel->in || !panel->out) return -1;
if (panel->minimized) return -1; if (panel->minimized) return -1;
gui_panel_alloc(&bounds, panel); gui_panel_alloc_space(&bounds, panel);
config = panel->config;
plot.x = bounds.x; plot.x = bounds.x;
plot.y = bounds.y; plot.y = bounds.y;
@ -1256,9 +1276,12 @@ gui_panel_histo(struct gui_panel *panel, const gui_float *values, gui_size count
{ {
struct gui_rect bounds; struct gui_rect bounds;
struct gui_histo histo; struct gui_histo histo;
const struct gui_config *config = panel->config; const struct gui_config *config;
if (!panel || !panel->config || !panel->in || !panel->out) return -1;
if (panel->minimized) return -1; if (panel->minimized) return -1;
gui_panel_alloc(&bounds, panel); gui_panel_alloc_space(&bounds, panel);
config = panel->config;
histo.x = bounds.x; histo.x = bounds.x;
histo.y = bounds.y; histo.y = bounds.y;

62
gui.h
View File

@ -8,8 +8,19 @@
/* /*
* ------------- TODO-List ------------ * ------------- TODO-List ------------
* - cleanup
* - widgets
* o Text
* o Text Wrapped
* o Image
* o Counter
* o Image Button
* - panel * - panel
* o flags * o Moveable
* o Scaleable
* o Scrollbar
* o Tabs
* o Icon
* o combobox * o combobox
* o listView * o listView
* o treeView * o treeView
@ -34,6 +45,7 @@ typedef gui_char gui_glyph[GUI_UTF_SIZE];
enum {gui_false, gui_true}; enum {gui_false, gui_true};
struct gui_color {gui_byte r,g,b,a;}; struct gui_color {gui_byte r,g,b,a;};
struct gui_colorf {gui_float r,g,b,a;};
struct gui_texCoord {gui_float u,v;}; struct gui_texCoord {gui_float u,v;};
struct gui_vec2 {gui_float x,y;}; struct gui_vec2 {gui_float x,y;};
struct gui_rect {gui_float x,y,w,h;}; struct gui_rect {gui_float x,y,w,h;};
@ -52,15 +64,14 @@ struct gui_draw_command {
}; };
struct gui_draw_buffer { struct gui_draw_buffer {
gui_byte *vertexes; struct gui_vertex *vertexes;
gui_byte *begin; gui_size vertex_capacity;
gui_byte *end; gui_size vertex_size;
gui_byte *memory; struct gui_draw_command *commands;
gui_size size; gui_size command_capacity;
gui_size vertex_write; gui_size command_size;
gui_size vertex_count;
gui_size command_count;
gui_size allocated; gui_size allocated;
gui_size needed;
}; };
enum gui_keys { enum gui_keys {
@ -104,6 +115,17 @@ struct gui_font {
const struct gui_font_glyph *fallback; const struct gui_font_glyph *fallback;
}; };
struct gui_text {
gui_float x, y;
gui_float w, h;
gui_float pad_x, pad_y;
const char *text;
gui_size length;
struct gui_color font;
struct gui_color background;
struct gui_color foreground;
};
struct gui_button { struct gui_button {
gui_float x, y; gui_float x, y;
gui_float w, h; gui_float w, h;
@ -164,8 +186,6 @@ struct gui_input_field {
gui_float x, y; gui_float x, y;
gui_float w, h; gui_float w, h;
gui_float pad_x, pad_y; gui_float pad_x, pad_y;
gui_char *buffer;
gui_size *length;
gui_size max; gui_size max;
gui_bool active; gui_bool active;
struct gui_color background; struct gui_color background;
@ -237,9 +257,9 @@ struct gui_config {
}; };
enum gui_panel_flags { enum gui_panel_flags {
GUI_PANEL_MINIMIZABLE = 0x04, GUI_PANEL_MINIMIZABLE = 0x01,
GUI_PANEL_CLOSEABLE = 0x08, GUI_PANEL_CLOSEABLE = 0x02,
GUI_PANEL_SCROLLBAR = 0x20 GUI_PANEL_SCROLLBAR = 0x04
}; };
struct gui_panel { struct gui_panel {
@ -271,12 +291,14 @@ void gui_input_char(struct gui_input *in, gui_glyph glyph);
void gui_input_end(struct gui_input *in); void gui_input_end(struct gui_input *in);
/* Output */ /* Output */
void gui_begin(struct gui_draw_buffer *buf, gui_byte *memory, gui_size size); void gui_begin(struct gui_draw_buffer *buf, void *memory, gui_size size);
gui_size gui_end(struct gui_draw_buffer *buf); gui_size gui_end(struct gui_draw_buffer *buf);
gui_int gui_get_command(struct gui_draw_command *cmd,
const struct gui_draw_buffer *buf, gui_size index);
/* Widgets */ /* Widgets */
void gui_text(struct gui_draw_buffer *buf, const struct gui_text *text,
const struct gui_font *font);
void gui_text_wrap(struct gui_draw_buffer *buf, const struct gui_text *text,
const struct gui_font *font);
gui_int gui_button(struct gui_draw_buffer *buf, const struct gui_button *button, gui_int gui_button(struct gui_draw_buffer *buf, const struct gui_button *button,
const struct gui_font *font, const struct gui_input *in); const struct gui_font *font, const struct gui_input *in);
gui_int gui_toggle(struct gui_draw_buffer *buf, const struct gui_toggle *toggle, gui_int gui_toggle(struct gui_draw_buffer *buf, const struct gui_toggle *toggle,
@ -287,7 +309,8 @@ gui_size gui_progress(struct gui_draw_buffer *buf, const struct gui_progress *pr
const struct gui_input *in); const struct gui_input *in);
gui_size gui_scroll(struct gui_draw_buffer *buf, const struct gui_scroll *scroll, gui_size gui_scroll(struct gui_draw_buffer *buf, const struct gui_scroll *scroll,
const struct gui_input *in); const struct gui_input *in);
gui_int gui_input(struct gui_draw_buffer *buf, const struct gui_input_field *f, gui_int gui_input(struct gui_draw_buffer *buf, gui_char *buffer, gui_size *length,
const struct gui_input_field *input,
const struct gui_font *font, const struct gui_input *in); const struct gui_font *font, const struct gui_input *in);
gui_int gui_histo(struct gui_draw_buffer *buf, const struct gui_histo *histo, gui_int gui_histo(struct gui_draw_buffer *buf, const struct gui_histo *histo,
const struct gui_input *in); const struct gui_input *in);
@ -301,7 +324,8 @@ gui_int gui_panel_begin(struct gui_panel *panel, struct gui_draw_buffer *q,
const char *t, gui_flags f, const char *t, gui_flags f,
gui_float x, gui_float y, gui_float w, gui_float h); gui_float x, gui_float y, gui_float w, gui_float h);
void gui_panel_row(struct gui_panel *panel, gui_float height, gui_size cols); void gui_panel_row(struct gui_panel *panel, gui_float height, gui_size cols);
void gui_panel_space(struct gui_panel *panel, gui_int cols); void gui_panel_seperator(struct gui_panel *panel, gui_size cols);
void gui_panel_text(struct gui_panel *panel, const char *str, gui_size len);
gui_int gui_panel_button(struct gui_panel *panel, const char *str, gui_size len); gui_int gui_panel_button(struct gui_panel *panel, const char *str, gui_size len);
gui_int gui_panel_toggle(struct gui_panel *panel, const char *str, gui_size len, gui_int gui_panel_toggle(struct gui_panel *panel, const char *str, gui_size len,
gui_int active); gui_int active);

BIN
mono.font

Binary file not shown.

View File

@ -360,13 +360,13 @@ static void
draw(int width, int height, const struct gui_draw_buffer *buffer) draw(int width, int height, const struct gui_draw_buffer *buffer)
{ {
gui_size i = 0; gui_size i = 0;
struct gui_draw_command cmd; const struct gui_draw_command *cmd;
GLint offset = 0; GLint offset = 0;
static const size_t v = sizeof(struct gui_vertex); static const size_t v = sizeof(struct gui_vertex);
static const size_t p = offsetof(struct gui_vertex, pos); static const size_t p = offsetof(struct gui_vertex, pos);
static const size_t t = offsetof(struct gui_vertex, uv); static const size_t t = offsetof(struct gui_vertex, uv);
static const size_t c = offsetof(struct gui_vertex, color); static const size_t c = offsetof(struct gui_vertex, color);
gui_byte *vertexes; const gui_byte *vertexes;
if (!buffer) return; if (!buffer) return;
glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT);
@ -388,21 +388,21 @@ draw(int width, int height, const struct gui_draw_buffer *buffer)
glPushMatrix(); glPushMatrix();
glLoadIdentity(); glLoadIdentity();
vertexes = buffer->vertexes; vertexes = (const gui_char*)buffer->vertexes;
glVertexPointer(2, GL_FLOAT, (GLsizei)v, (void*)(vertexes + p)); glVertexPointer(2, GL_FLOAT, (GLsizei)v, (const void*)(vertexes + p));
glTexCoordPointer(2, GL_FLOAT, (GLsizei)v, (void*)(vertexes + t)); glTexCoordPointer(2, GL_FLOAT, (GLsizei)v, (const void*)(vertexes + t));
glColorPointer(4, GL_UNSIGNED_BYTE, (GLsizei)v, (void*)(vertexes + c)); glColorPointer(4, GL_UNSIGNED_BYTE, (GLsizei)v, (const void*)(vertexes + c));
for (i = 0; i < buffer->command_count; ++i) { for (i = 0; i < buffer->command_size; ++i) {
gui_get_command(&cmd, buffer, i); cmd = &buffer->commands[i];
const int x = (int)cmd.clip_rect.x; const int x = (int)cmd->clip_rect.x;
const int y = height - (int)(cmd.clip_rect.y + cmd.clip_rect.h); const int y = height - (int)(cmd->clip_rect.y + cmd->clip_rect.h);
const int w = (int)cmd.clip_rect.w; const int w = (int)cmd->clip_rect.w;
const int h = (int)cmd.clip_rect.h; const int h = (int)cmd->clip_rect.h;
glScissor(x, y, w, h); glScissor(x, y, w, h);
glBindTexture(GL_TEXTURE_2D, (GLuint)(unsigned long)cmd.texture); glBindTexture(GL_TEXTURE_2D, (GLuint)(unsigned long)cmd->texture);
glDrawArrays(GL_TRIANGLES, offset, (GLsizei)cmd.vertex_count); glDrawArrays(GL_TRIANGLES, offset, (GLsizei)cmd->vertex_count);
offset += (GLint)cmd.vertex_count; offset += (GLint)cmd->vertex_count;
} }
glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_COLOR_ARRAY);
@ -422,7 +422,6 @@ main(int argc, char *argv[])
struct GUI gui; struct GUI gui;
long dt, started; long dt, started;
gui_byte *buffer; gui_byte *buffer;
const gui_size buffer_size = MAX_BUFFER;
static GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE,24, GLX_DOUBLEBUFFER, None}; static GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE,24, GLX_DOUBLEBUFFER, None};
gui_char input_text[INPUT_MAX]; gui_char input_text[INPUT_MAX];
@ -462,7 +461,7 @@ main(int argc, char *argv[])
/* OpenGL */ /* OpenGL */
xw.glc = glXCreateContext(xw.dpy, xw.vi, NULL, GL_TRUE); xw.glc = glXCreateContext(xw.dpy, xw.vi, NULL, GL_TRUE);
glXMakeCurrent(xw.dpy, xw.win, xw.glc); glXMakeCurrent(xw.dpy, xw.win, xw.glc);
buffer = xcalloc(buffer_size, 1); buffer = xcalloc(MAX_BUFFER, 1);
/* GUI */ /* GUI */
gui.win = &xw; gui.win = &xw;