2015-03-03 19:24:02 +03:00
|
|
|
/*
|
|
|
|
Copyright (c) 2015
|
|
|
|
vurtun <polygone@gmx.net>
|
|
|
|
MIT licence
|
|
|
|
*/
|
|
|
|
#include "gui.h"
|
|
|
|
|
2015-03-27 19:19:49 +03:00
|
|
|
#ifndef NDEBUG
|
|
|
|
#include <assert.h>
|
|
|
|
#else
|
|
|
|
#define assert(expr)
|
|
|
|
#endif
|
|
|
|
|
2015-03-03 19:24:02 +03:00
|
|
|
#define NULL (void*)0
|
|
|
|
#define UTF_INVALID 0xFFFD
|
2015-03-14 19:05:30 +03:00
|
|
|
#define MAX_NUMBER_BUFFER 64
|
2015-03-03 19:24:02 +03:00
|
|
|
#define PASTE(a,b) a##b
|
|
|
|
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
|
|
|
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
|
|
|
#define CLAMP(i,v,x) (MAX(MIN(v,x), i))
|
2015-03-23 19:18:18 +03:00
|
|
|
#define SATURATE(x) (MAX(0, MIN(1.0f, x)))
|
2015-03-03 19:24:02 +03:00
|
|
|
#define LEN(a) (sizeof(a)/sizeof(a)[0])
|
|
|
|
#define ABS(a) (((a) < 0) ? -(a) : (a))
|
|
|
|
#define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b))
|
2015-03-13 00:53:28 +03:00
|
|
|
#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)
|
2015-03-23 19:18:18 +03:00
|
|
|
#define ALIGN(x, mask) (void*)((gui_size)((gui_byte*)(x) + (mask-1)) & ~(mask-1))
|
2015-03-03 19:24:02 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
#define col_load(c,j,k,l,m) (c).r = (j), (c).g = (k), (c).b = (l), (c).a = (m)
|
2015-03-03 19:24:02 +03:00
|
|
|
#define vec2_load(v,a,b) (v).x = (a), (v).y = (b)
|
2015-03-04 16:54:48 +03:00
|
|
|
#define vec2_mov(to,from) (to).x = (from).x, (to).y = (from).y
|
2015-03-03 19:24:02 +03:00
|
|
|
#define vec2_len(v) ((float)fsqrt((v).x*(v).x+(v).y*(v).y))
|
|
|
|
#define vec2_sub(r,a,b) do {(r).x=(a).x-(b).x; (r).y=(a).y-(b).y;} while(0)
|
|
|
|
#define vec2_muls(r, v, s) do {(r).x=(v).x*(s); (r).y=(v).y*(s);} while(0)
|
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
struct gui_context_panel {
|
|
|
|
struct gui_panel panel;
|
2015-03-25 16:15:42 +03:00
|
|
|
gui_float x, y, w, h;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_list list;
|
2015-03-23 19:18:18 +03:00
|
|
|
struct gui_context_panel *next;
|
2015-03-30 15:07:39 +03:00
|
|
|
struct gui_context_panel *prev;
|
2015-03-23 19:18:18 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
struct gui_context {
|
|
|
|
gui_float width, height;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_buffer global_buffer;
|
|
|
|
struct gui_command_buffer current_buffer;
|
2015-03-23 19:18:18 +03:00
|
|
|
const struct gui_input *input;
|
2015-03-24 19:12:42 +03:00
|
|
|
struct gui_context_panel *active;
|
2015-03-30 15:07:39 +03:00
|
|
|
struct gui_context_panel *panel_pool;
|
|
|
|
struct gui_context_panel *free_list;
|
|
|
|
struct gui_context_panel *stack_begin;
|
|
|
|
struct gui_context_panel *stack_end;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_list **output_list;
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_size panel_capacity;
|
|
|
|
gui_size panel_size;
|
|
|
|
};
|
|
|
|
|
2015-03-20 20:01:27 +03:00
|
|
|
static const gui_texture null_tex;
|
2015-03-25 16:15:42 +03:00
|
|
|
static const struct gui_rect null_rect = {0.0f, 0.0f, 9999.0f, 9999.0f};
|
2015-03-14 19:05:30 +03:00
|
|
|
static const gui_char utfbyte[GUI_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
|
|
|
static const gui_char utfmask[GUI_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
|
|
|
static const long utfmin[GUI_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x100000};
|
|
|
|
static const long utfmax[GUI_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
2015-03-03 19:24:02 +03:00
|
|
|
|
2015-03-11 16:00:59 +03:00
|
|
|
static void*
|
|
|
|
memcopy(void *dst, const void *src, gui_size size)
|
|
|
|
{
|
|
|
|
gui_size i = 0;
|
|
|
|
char *d = dst;
|
|
|
|
const char *s = src;
|
|
|
|
for (i = 0; i < size; ++i)
|
|
|
|
d[i] = s[i];
|
|
|
|
return dst;
|
|
|
|
}
|
|
|
|
|
2015-03-17 16:42:49 +03:00
|
|
|
static gui_size
|
|
|
|
strsiz(const char *str)
|
|
|
|
{
|
|
|
|
gui_size siz = 0;
|
2015-03-23 19:18:18 +03:00
|
|
|
while (str && *str++ != '\0') siz++;
|
2015-03-17 16:42:49 +03:00
|
|
|
return siz;
|
|
|
|
}
|
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
static gui_int
|
|
|
|
strtoi(gui_int *number, const char *buffer, gui_size len)
|
|
|
|
{
|
|
|
|
gui_size i;
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!number || !buffer)
|
2015-03-14 19:05:30 +03:00
|
|
|
return 0;
|
|
|
|
*number = 0;
|
2015-03-23 19:18:18 +03:00
|
|
|
for (i = 0; i < len; ++i)
|
2015-03-14 19:05:30 +03:00
|
|
|
*number = *number * 10 + (buffer[i] - '0');
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gui_size
|
|
|
|
itos(char *buffer, gui_int num)
|
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
static const char digit[] = "0123456789";
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_int shifter;
|
|
|
|
gui_size len = 0;
|
|
|
|
char *p = buffer;
|
|
|
|
if (!buffer)
|
|
|
|
return 0;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
if (num < 0) {
|
|
|
|
num = ABS(num);
|
|
|
|
*p++ = '-';
|
|
|
|
}
|
|
|
|
shifter = num;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
do {
|
|
|
|
++p;
|
|
|
|
shifter = shifter/10;
|
|
|
|
} while (shifter);
|
|
|
|
*p = '\0';
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
len = (gui_size)(p - buffer);
|
|
|
|
do {
|
|
|
|
*--p = digit[num % 10];
|
|
|
|
num = num / 10;
|
|
|
|
} while (num);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2015-04-17 12:50:47 +03:00
|
|
|
static void
|
|
|
|
unify(struct gui_rect *clip, const struct gui_rect *a, const struct gui_rect *b)
|
2015-03-16 11:51:33 +03:00
|
|
|
{
|
2015-04-17 12:50:47 +03:00
|
|
|
clip->x = MAX(a->x, b->x);
|
|
|
|
clip->y = MAX(a->y, b->y);
|
|
|
|
clip->w = MIN(a->x + a->w, b->x + b->w) - clip->x;
|
|
|
|
clip->h = MIN(a->y + a->h, b->y + b->h) - clip->y;
|
|
|
|
clip->w = MAX(0, clip->w);
|
|
|
|
clip->h = MAX(0, clip->h);
|
2015-03-16 11:51:33 +03:00
|
|
|
}
|
|
|
|
|
2015-03-03 19:24:02 +03:00
|
|
|
static gui_size
|
|
|
|
utf_validate(long *u, gui_size i)
|
|
|
|
{
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!u) return 0;
|
2015-03-03 19:24:02 +03:00
|
|
|
if (!BETWEEN(*u, utfmin[i], utfmax[i]) ||
|
|
|
|
BETWEEN(*u, 0xD800, 0xDFFF))
|
|
|
|
*u = UTF_INVALID;
|
|
|
|
for (i = 1; *u > utfmax[i]; ++i);
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
|
2015-03-05 21:50:56 +03:00
|
|
|
static gui_long
|
2015-03-03 19:24:02 +03:00
|
|
|
utf_decode_byte(gui_char c, gui_size *i)
|
|
|
|
{
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!i) return 0;
|
2015-03-03 19:24:02 +03:00
|
|
|
for(*i = 0; *i < LEN(utfmask); ++(*i)) {
|
|
|
|
if ((c & utfmask[*i]) == utfbyte[*i])
|
|
|
|
return c & ~utfmask[*i];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gui_size
|
2015-03-05 21:50:56 +03:00
|
|
|
utf_decode(const gui_char *c, gui_long *u, gui_size clen)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
|
|
|
gui_size i, j, len, type;
|
2015-03-05 21:50:56 +03:00
|
|
|
gui_long udecoded;
|
2015-03-03 19:24:02 +03:00
|
|
|
|
|
|
|
*u = UTF_INVALID;
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!c || !u) return 0;
|
2015-03-03 19:24:02 +03:00
|
|
|
if (!clen) return 0;
|
|
|
|
udecoded = utf_decode_byte(c[0], &len);
|
|
|
|
if (!BETWEEN(len, 1, GUI_UTF_SIZE))
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
for (i = 1, j = 1; i < clen && j < len; ++i, ++j) {
|
|
|
|
udecoded = (udecoded << 6) | utf_decode_byte(c[i], &type);
|
|
|
|
if (type != 0)
|
|
|
|
return j;
|
|
|
|
}
|
|
|
|
if (j < len)
|
|
|
|
return 0;
|
|
|
|
*u = udecoded;
|
|
|
|
utf_validate(u, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gui_char
|
2015-03-05 21:50:56 +03:00
|
|
|
utf_encode_byte(gui_long u, gui_size i)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-11 16:00:59 +03:00
|
|
|
return (gui_char)(utfbyte[i] | (u & ~utfmask[i]));
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static gui_size
|
2015-03-05 21:50:56 +03:00
|
|
|
utf_encode(gui_long u, gui_char *c, gui_size clen)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
|
|
|
gui_size len, i;
|
|
|
|
len = utf_validate(&u, 0);
|
2015-03-04 13:59:02 +03:00
|
|
|
if (clen < len || !len)
|
2015-03-03 19:24:02 +03:00
|
|
|
return 0;
|
|
|
|
for (i = len - 1; i != 0; --i) {
|
|
|
|
c[i] = utf_encode_byte(u, 0);
|
|
|
|
u >>= 6;
|
|
|
|
}
|
|
|
|
c[0] = utf_encode_byte(u, len);
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
static void
|
|
|
|
gui_triangle_from_direction(struct gui_vec2 *result, gui_float x, gui_float y,
|
|
|
|
gui_float w, gui_float h, gui_float pad_x, gui_float pad_y,
|
2015-03-17 16:42:49 +03:00
|
|
|
enum gui_heading direction)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float w_half, h_half;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(result);
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
w = MAX(4 * pad_x, w);
|
|
|
|
h = MAX(4 * pad_y, h);
|
|
|
|
w = w - 2 * pad_x;
|
|
|
|
h = h - 2 * pad_y;
|
|
|
|
w_half = w / 2.0f;
|
|
|
|
h_half = h / 2.0f;
|
|
|
|
x = x + pad_x;
|
|
|
|
y = y + pad_y;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
if (direction == GUI_UP) {
|
|
|
|
result[0].x = x + w_half;
|
|
|
|
result[0].y = y;
|
|
|
|
result[1].x = x;
|
|
|
|
result[1].y = y + h;
|
|
|
|
result[2].x = x + w;
|
|
|
|
result[2].y = y + h;
|
|
|
|
} else if (direction == GUI_RIGHT) {
|
|
|
|
result[0].x = x;
|
|
|
|
result[0].y = y;
|
|
|
|
result[1].x = x;
|
|
|
|
result[1].y = y + h;
|
|
|
|
result[2].x = x + w;
|
|
|
|
result[2].y = y + h_half;
|
|
|
|
} else if (direction == GUI_DOWN) {
|
|
|
|
result[0].x = x;
|
|
|
|
result[0].y = y;
|
|
|
|
result[1].x = x + w_half;
|
|
|
|
result[1].y = y + h;
|
|
|
|
result[2].x = x + w;
|
|
|
|
result[2].y = y;
|
|
|
|
} else {
|
|
|
|
result[0].x = x;
|
|
|
|
result[0].y = y + h_half;
|
|
|
|
result[1].x = x + w;
|
|
|
|
result[1].y = y + h;
|
|
|
|
result[2].x = x + w;
|
|
|
|
result[2].y = y;
|
|
|
|
}
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
2015-03-03 19:24:02 +03:00
|
|
|
void
|
|
|
|
gui_input_begin(struct gui_input *in)
|
|
|
|
{
|
2015-03-09 22:04:45 +03:00
|
|
|
gui_size i;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(in);
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!in) return;
|
2015-03-03 19:24:02 +03:00
|
|
|
in->mouse_clicked = 0;
|
2015-03-07 19:02:37 +03:00
|
|
|
in->text_len = 0;
|
2015-03-04 16:54:48 +03:00
|
|
|
vec2_mov(in->mouse_prev, in->mouse_pos);
|
2015-03-09 22:04:45 +03:00
|
|
|
for (i = 0; i < GUI_KEY_MAX; i++)
|
|
|
|
in->keys[i].clicked = 0;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_input_motion(struct gui_input *in, gui_int x, gui_int y)
|
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(in);
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!in) return;
|
2015-04-03 18:40:47 +03:00
|
|
|
in->mouse_pos.x = (gui_float)x;
|
|
|
|
in->mouse_pos.y = (gui_float)y;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-04-04 19:26:22 +03:00
|
|
|
gui_input_key(struct gui_input *in, enum gui_keys key, gui_bool down)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(in);
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!in) return;
|
2015-03-09 22:04:45 +03:00
|
|
|
if (in->keys[key].down == down) return;
|
|
|
|
in->keys[key].down = down;
|
|
|
|
in->keys[key].clicked++;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_input_button(struct gui_input *in, gui_int x, gui_int y, gui_bool down)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(in);
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!in) return;
|
2015-03-03 19:24:02 +03:00
|
|
|
if (in->mouse_down == down) return;
|
2015-04-03 18:40:47 +03:00
|
|
|
in->mouse_clicked_pos.x = (gui_float)x;
|
|
|
|
in->mouse_clicked_pos.y = (gui_float)y;
|
2015-03-03 19:24:02 +03:00
|
|
|
in->mouse_down = down;
|
|
|
|
in->mouse_clicked++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-03-26 00:52:25 +03:00
|
|
|
gui_input_char(struct gui_input *in, const gui_glyph glyph)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
|
|
|
gui_size len = 0;
|
2015-03-05 21:50:56 +03:00
|
|
|
gui_long unicode;
|
2015-03-27 19:19:49 +03:00
|
|
|
assert(in);
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!in) return;
|
2015-03-03 19:24:02 +03:00
|
|
|
len = utf_decode(glyph, &unicode, GUI_UTF_SIZE);
|
2015-03-07 19:02:37 +03:00
|
|
|
if (len && ((in->text_len + len) < GUI_INPUT_MAX)) {
|
|
|
|
utf_encode(unicode, &in->text[in->text_len], GUI_INPUT_MAX - in->text_len);
|
|
|
|
in->text_len += len;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_input_end(struct gui_input *in)
|
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(in);
|
2015-03-04 13:59:02 +03:00
|
|
|
if (!in) return;
|
2015-03-03 19:24:02 +03:00
|
|
|
vec2_sub(in->mouse_delta, in->mouse_pos, in->mouse_prev);
|
|
|
|
}
|
|
|
|
|
2015-04-10 19:35:17 +03:00
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_command_list_init(struct gui_command_list *list, void *memory,
|
|
|
|
gui_size size)
|
2015-04-10 19:35:17 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
list->capacity = size;
|
|
|
|
list->begin = memory;
|
|
|
|
list->end = list->begin;
|
|
|
|
list->size = 0;
|
|
|
|
list->needed = 0;
|
|
|
|
list->count = 0;
|
2015-04-10 19:35:17 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_command_list_clear(struct gui_command_list *list)
|
2015-04-10 19:35:17 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
list->count = 0;
|
|
|
|
list->size = 0;
|
|
|
|
list->needed = 0;
|
|
|
|
list->end = list->begin;
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
|
2015-03-11 16:00:59 +03:00
|
|
|
void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_output_begin(struct gui_command_buffer *buffer, const struct gui_memory *memory)
|
2015-03-16 11:51:33 +03:00
|
|
|
{
|
|
|
|
void *cmds;
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_size clip_size;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(memory);
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!buffer || !memory)
|
2015-04-05 18:19:44 +03:00
|
|
|
return;
|
2015-03-23 19:18:18 +03:00
|
|
|
|
2015-04-05 18:19:44 +03:00
|
|
|
buffer->clips = memory->memory;
|
2015-04-15 15:37:19 +03:00
|
|
|
buffer->clip_capacity = memory->max_depth;
|
2015-03-16 11:51:33 +03:00
|
|
|
buffer->clip_size = 0;
|
2015-04-15 15:37:19 +03:00
|
|
|
cmds = buffer->clips + memory->max_depth;
|
|
|
|
clip_size = (gui_size)((gui_byte*)cmds - (gui_byte*)memory->memory);
|
|
|
|
gui_command_list_init(&buffer->cmds, cmds, memory->size - clip_size);
|
2015-03-11 16:00:59 +03:00
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
static void*
|
|
|
|
gui_buffer_push(struct gui_command_buffer *buffer, enum gui_command_type type,
|
|
|
|
gui_size size)
|
2015-03-11 16:00:59 +03:00
|
|
|
{
|
2015-04-16 16:31:11 +03:00
|
|
|
gui_size alignment;
|
2015-04-15 15:37:19 +03:00
|
|
|
void *unaligned;
|
|
|
|
const gui_size align = ALIGNOF(struct gui_command);
|
|
|
|
struct gui_command_list *list = &buffer->cmds;
|
|
|
|
struct gui_command *cmd;
|
|
|
|
list->needed += size;
|
2015-04-16 16:31:11 +03:00
|
|
|
if ((list->size + size) > list->capacity) return NULL;
|
2015-03-16 11:51:33 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
cmd = list->end;
|
|
|
|
unaligned = (gui_byte*)list->end + size;
|
|
|
|
list->end = ALIGN(unaligned, align);
|
2015-04-16 16:31:11 +03:00
|
|
|
alignment = (gui_size)((gui_byte*)list->end - (gui_byte*)unaligned);
|
|
|
|
list->size += size + alignment;
|
|
|
|
list->needed += alignment;
|
2015-04-15 15:37:19 +03:00
|
|
|
list->count++;
|
2015-03-16 11:51:33 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
cmd->type = type;
|
|
|
|
cmd->next = list->end;
|
|
|
|
return cmd;
|
2015-03-11 16:00:59 +03:00
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
static gui_bool
|
|
|
|
gui_buffer_push_clip(struct gui_command_buffer *buffer, const struct gui_rect *rect)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_clip *cmd;
|
2015-03-16 11:51:33 +03:00
|
|
|
struct gui_rect clip;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
|
|
|
assert(rect);
|
2015-03-16 11:51:33 +03:00
|
|
|
if (!buffer || !rect || buffer->clip_size >= buffer->clip_capacity)
|
|
|
|
return gui_false;
|
2015-03-13 00:53:28 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
cmd = gui_buffer_push(buffer, GUI_COMMAND_CLIP, sizeof(*cmd));
|
2015-04-16 14:05:51 +03:00
|
|
|
if (!cmd) return gui_false;
|
2015-04-17 12:50:47 +03:00
|
|
|
unify(&clip, rect, (!buffer->clip_size) ? &null_rect : &buffer->clips[buffer->clip_size-1]);
|
2015-03-16 11:51:33 +03:00
|
|
|
buffer->clips[buffer->clip_size] = clip;
|
|
|
|
buffer->clip_size++;
|
2015-04-15 15:37:19 +03:00
|
|
|
cmd->x = clip.x;
|
|
|
|
cmd->y = clip.y;
|
|
|
|
cmd->w = clip.w;
|
|
|
|
cmd->h = clip.h;
|
2015-03-16 11:51:33 +03:00
|
|
|
return gui_true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_pop_clip(struct gui_command_buffer *buffer)
|
2015-03-16 11:51:33 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_clip *cmd;
|
|
|
|
const struct gui_rect *clip;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
2015-03-27 17:18:38 +03:00
|
|
|
if (!buffer || !buffer->clip_capacity) return;
|
2015-03-16 11:51:33 +03:00
|
|
|
if (buffer->clip_size == 0) {
|
|
|
|
buffer->clips[buffer->clip_size] = null_rect;
|
|
|
|
buffer->clip_size = 1;
|
|
|
|
} else {
|
|
|
|
buffer->clip_size--;
|
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
clip = (!buffer->clip_size) ? &null_rect : &buffer->clips[buffer->clip_size-1];
|
|
|
|
cmd = gui_buffer_push(buffer, GUI_COMMAND_CLIP, sizeof(*cmd));
|
2015-04-16 14:05:51 +03:00
|
|
|
if (!cmd) return;
|
2015-04-15 15:37:19 +03:00
|
|
|
cmd->x = clip->x;
|
|
|
|
cmd->y = clip->y;
|
|
|
|
cmd->w = clip->w;
|
|
|
|
cmd->h = clip->h;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(struct gui_command_buffer *buffer, gui_float x, gui_float y,
|
|
|
|
gui_float w, gui_float h, struct gui_color color)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_rect *rect;
|
|
|
|
rect = gui_buffer_push(buffer, GUI_COMMAND_RECT, sizeof(*rect));
|
|
|
|
if (!rect) return;
|
|
|
|
rect->color = color;
|
|
|
|
rect->x = x; rect->y = y;
|
|
|
|
rect->w = w; rect->h = h;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_line(struct gui_command_buffer *buffer, gui_float x1, gui_float y1,
|
|
|
|
gui_float x2, gui_float y2, struct gui_color color)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_line *line;
|
|
|
|
line = gui_buffer_push(buffer, GUI_COMMAND_LINE, sizeof(*line));
|
|
|
|
if (!line) return;
|
|
|
|
line->color = color;
|
|
|
|
line->from.x = x1;
|
|
|
|
line->from.y = y1;
|
|
|
|
line->to.x = x2;
|
|
|
|
line->to.y = y2;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_circle(struct gui_command_buffer *buffer, gui_float x, gui_float y,
|
|
|
|
gui_float r, struct gui_color color)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_circle *circle;
|
|
|
|
circle = gui_buffer_push(buffer, GUI_COMMAND_CIRCLE, sizeof(*circle));
|
|
|
|
if (!circle) return;
|
|
|
|
circle->x = x; circle->y = y;
|
|
|
|
circle->color = color;
|
|
|
|
circle->radius = r;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_triangle(struct gui_command_buffer *buffer, struct gui_vec2 *pos,
|
|
|
|
struct gui_color color)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_triangle *triangle;
|
|
|
|
triangle = gui_buffer_push(buffer, GUI_COMMAND_TRIANGLE, sizeof(*triangle));
|
|
|
|
if (!triangle) return;
|
|
|
|
triangle->pnt[0] = pos[0];
|
|
|
|
triangle->pnt[1] = pos[1];
|
|
|
|
triangle->pnt[2] = pos[2];
|
|
|
|
triangle->color = color;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_bitmap(struct gui_command_buffer *buffer, gui_float x, gui_float y,
|
|
|
|
gui_float w, gui_float h, gui_texture texture)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_bitmap *bitmap;
|
|
|
|
bitmap = gui_buffer_push(buffer, GUI_COMMAND_BITMAP, sizeof(*bitmap));
|
|
|
|
if (!bitmap) return;
|
|
|
|
bitmap->x = x; bitmap->y = y;
|
|
|
|
bitmap->w = w; bitmap->h = h;
|
|
|
|
bitmap->texture = texture;
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_text(struct gui_command_buffer *buffer, void *font, gui_float x, gui_float y,
|
|
|
|
gui_float w, gui_float h, const gui_char *str, gui_size len,
|
|
|
|
struct gui_color bg, struct gui_color fg)
|
|
|
|
{
|
|
|
|
struct gui_rect rect;
|
|
|
|
struct gui_command_text *text;
|
|
|
|
|
|
|
|
rect.x = x; rect.y = y;
|
|
|
|
rect.w = w; rect.h = h;
|
|
|
|
if (!gui_buffer_push_clip(buffer, &rect)) return;
|
|
|
|
text = gui_buffer_push(buffer, GUI_COMMAND_TEXT, sizeof(*text) + len + 1);
|
|
|
|
if (!text) return;
|
|
|
|
|
|
|
|
text->x = x; text->y = y;
|
|
|
|
text->w = w; text->h = h;
|
|
|
|
text->background = bg;
|
|
|
|
text->foreground = fg;
|
|
|
|
text->length = len;
|
|
|
|
text->font = font;
|
|
|
|
memcopy(text->string, str, len);
|
|
|
|
text->string[len] = '\0';
|
|
|
|
gui_buffer_pop_clip(buffer);
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
void
|
|
|
|
gui_output_end(struct gui_command_buffer *buffer, struct gui_command_list *list,
|
|
|
|
struct gui_memory_status* status)
|
2015-03-20 12:58:11 +03:00
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
2015-03-20 12:58:11 +03:00
|
|
|
if (!buffer) return;
|
2015-04-15 15:37:19 +03:00
|
|
|
if (status) {
|
|
|
|
status->allocated = buffer->cmds.size;
|
|
|
|
status->needed = buffer->cmds.needed;
|
2015-03-05 21:50:56 +03:00
|
|
|
}
|
2015-03-05 20:14:47 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (list) *list = buffer->cmds;
|
|
|
|
gui_command_list_clear(&buffer->cmds);
|
|
|
|
buffer->clip_size = 0;
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_text(struct gui_command_buffer *buffer, const struct gui_text *text,
|
2015-03-13 22:01:31 +03:00
|
|
|
const struct gui_font *font)
|
|
|
|
{
|
|
|
|
gui_float label_x;
|
|
|
|
gui_float label_y;
|
|
|
|
gui_float label_w;
|
|
|
|
gui_float label_h;
|
2015-04-08 12:54:33 +03:00
|
|
|
gui_size text_width;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(text);
|
|
|
|
assert(font);
|
2015-03-13 22:01:31 +03:00
|
|
|
if (!buffer || !text || !font)
|
|
|
|
return;
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
text_width = font->width(font->user, (const gui_char*)text->string, text->length);
|
2015-03-13 22:01:31 +03:00
|
|
|
label_y = text->y + text->pad_y;
|
|
|
|
label_h = MAX(0, text->h - 2 * text->pad_y);
|
2015-04-08 12:54:33 +03:00
|
|
|
if (text->align == GUI_TEXT_LEFT) {
|
|
|
|
label_x = text->x + text->pad_x;
|
|
|
|
label_w = MAX(0, text->w - 2 * text->pad_x);
|
|
|
|
} else if (text->align == GUI_TEXT_CENTERED) {
|
2015-04-15 15:37:19 +03:00
|
|
|
label_w = 3 * text->pad_x + (gui_float)text_width;
|
|
|
|
label_x = (text->x + text->pad_x + ((text->w - 2 * text->pad_x)/2)) - (label_w/2);
|
|
|
|
} else if (text->align == GUI_TEXT_RIGHT) {
|
2015-04-08 12:54:33 +03:00
|
|
|
label_x = MAX(text->x, (text->x + text->w) - (2 * text->pad_x + (gui_float)text_width));
|
|
|
|
label_w = (gui_float)text_width + 2 * text->pad_x;
|
2015-04-10 19:35:17 +03:00
|
|
|
} else return;
|
2015-04-08 12:54:33 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, text->x, text->y, text->w, text->h, text->background);
|
|
|
|
gui_buffer_push_text(buffer, font->user, label_x, label_y, label_w, label_h,
|
|
|
|
(const gui_char*)text->string, text->length, text->background, text->foreground);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
/*
|
2015-03-13 22:01:31 +03:00
|
|
|
void
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_widget_image(struct gui_draw_buffer *buffer, const struct gui_image *image)
|
2015-03-13 22:01:31 +03:00
|
|
|
{
|
|
|
|
gui_float image_x;
|
|
|
|
gui_float image_y;
|
|
|
|
gui_float image_w;
|
|
|
|
gui_float image_h;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(image);
|
2015-03-16 11:51:33 +03:00
|
|
|
if (!buffer || !image) return;
|
2015-03-24 15:08:42 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
image_x = image->x + image->pad_x;
|
|
|
|
image_y = image->y + image->pad_y;
|
|
|
|
image_w = MAX(0, image->w - 2 * image->pad_x);
|
|
|
|
image_h = MAX(0, image->h - 2 * image->pad_y);
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_draw_rectf(buffer, image->x, image->y, image->w, image->h, image->background);
|
|
|
|
gui_draw_image(buffer, image_x, image_y, image_w, image_h,
|
2015-03-27 03:57:45 +03:00
|
|
|
image->texture, image->uv[0], image->uv[1], image->color);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
*/
|
2015-03-13 22:01:31 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
static gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_button(struct gui_command_buffer *buffer, const struct gui_button *button,
|
|
|
|
const struct gui_input *in)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool ret = gui_false;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_color background;
|
|
|
|
struct gui_color highlight;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
|
|
|
assert(button);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !button)
|
2015-03-09 22:04:45 +03:00
|
|
|
return gui_false;
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
background = button->background;
|
2015-03-27 03:57:45 +03:00
|
|
|
if (in && INBOX(in->mouse_pos.x,in->mouse_pos.y,button->x,button->y,button->w,button->h)) {
|
2015-03-13 22:01:31 +03:00
|
|
|
background = button->highlight;
|
|
|
|
if (INBOX(in->mouse_clicked_pos.x, in->mouse_clicked_pos.y,
|
2015-03-20 12:58:11 +03:00
|
|
|
button->x, button->y, button->w, button->h)) {
|
2015-04-10 19:35:17 +03:00
|
|
|
if (button->behavior == GUI_BUTTON_DEFAULT)
|
2015-03-14 19:05:30 +03:00
|
|
|
ret = (in->mouse_down && in->mouse_clicked);
|
|
|
|
else
|
|
|
|
ret = in->mouse_down;
|
|
|
|
}
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
|
|
|
|
gui_buffer_push_rect(buffer, button->x, button->y, button->w, button->h, button->foreground);
|
|
|
|
gui_buffer_push_rect(buffer, button->x + button->border, button->y + button->border,
|
|
|
|
button->w - button->border * 2, button->h - 2 * button->border, background);
|
2015-03-20 12:58:11 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_button_text(struct gui_command_buffer *buffer, const struct gui_button *button,
|
|
|
|
const char *string, gui_size length, const struct gui_font *font,
|
2015-03-20 12:58:11 +03:00
|
|
|
const struct gui_input *in)
|
|
|
|
{
|
|
|
|
gui_bool ret = gui_false;
|
|
|
|
gui_float button_w, button_h;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_text text;
|
|
|
|
struct gui_color font_color;
|
|
|
|
struct gui_color bg_color;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(button);
|
2015-04-15 15:37:19 +03:00
|
|
|
assert(string);
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(font);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !button)
|
2015-03-20 12:58:11 +03:00
|
|
|
return gui_false;
|
|
|
|
|
|
|
|
font_color = button->content;
|
2015-04-15 15:37:19 +03:00
|
|
|
bg_color = button->background;
|
2015-03-20 12:58:11 +03:00
|
|
|
button_w = MAX(button->w, font->height + 2 * button->pad_x);
|
|
|
|
button_h = MAX(button->h, font->height + 2 * button->pad_y);
|
2015-04-15 15:37:19 +03:00
|
|
|
if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, button->x, button->y, button_w, button_h)) {
|
2015-03-20 12:58:11 +03:00
|
|
|
font_color = button->highlight_content;
|
2015-04-15 15:37:19 +03:00
|
|
|
bg_color = button->highlight;
|
2015-03-08 21:19:07 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
ret = gui_widget_button(buffer, button, in);
|
|
|
|
|
|
|
|
text.x = button->x + button->border;
|
|
|
|
text.y = button->y + button->border;
|
|
|
|
text.w = button->w - 2 * button->border;
|
|
|
|
text.h = button->h - 2 * button->border;
|
|
|
|
text.pad_x = button->pad_x;
|
|
|
|
text.pad_y = button->pad_y;
|
|
|
|
text.string = string;
|
|
|
|
text.length = length;
|
|
|
|
text.align = GUI_TEXT_CENTERED;
|
|
|
|
text.font = font->user;
|
|
|
|
text.background = bg_color;
|
|
|
|
text.foreground = font_color;
|
|
|
|
gui_widget_text(buffer, &text, font);
|
2015-03-03 19:24:02 +03:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_button_triangle(struct gui_command_buffer *buffer, struct gui_button* button,
|
2015-03-17 16:42:49 +03:00
|
|
|
enum gui_heading heading, const struct gui_input *in)
|
2015-03-13 22:01:31 +03:00
|
|
|
{
|
|
|
|
gui_bool pressed;
|
2015-03-20 12:58:11 +03:00
|
|
|
struct gui_color col;
|
2015-03-13 22:01:31 +03:00
|
|
|
struct gui_vec2 points[3];
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
pressed = gui_widget_button(buffer, button, in);
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_triangle_from_direction(points, button->x, button->y, button->w, button->h,
|
2015-03-17 16:42:49 +03:00
|
|
|
button->pad_x, button->pad_y, heading);
|
2015-03-26 01:30:24 +03:00
|
|
|
col = (in && INBOX(in->mouse_pos.x,in->mouse_pos.y,button->x,button->y,button->w,button->h)) ?
|
2015-03-20 12:58:11 +03:00
|
|
|
button->highlight_content : button->foreground;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_triangle(buffer, points, col);
|
2015-03-13 22:01:31 +03:00
|
|
|
return pressed;
|
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
/*
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_button_icon(struct gui_command_buffer *buffer, struct gui_button* button,
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_texture tex, struct gui_texCoord from, struct gui_texCoord to,
|
|
|
|
const struct gui_input *in)
|
|
|
|
{
|
|
|
|
gui_bool pressed;
|
|
|
|
struct gui_image image;
|
2015-03-27 03:57:45 +03:00
|
|
|
struct gui_color col;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(button);
|
|
|
|
if (!buffer || !button)
|
|
|
|
return gui_false;
|
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
pressed = gui_widget_button(buffer, button, in);
|
2015-03-27 03:57:45 +03:00
|
|
|
image.x = button->x + button->pad_x;
|
|
|
|
image.y = button->y + button->pad_y;
|
|
|
|
image.w = button->w - 2 * button->pad_x;
|
|
|
|
image.h = button->h - 2 * button->pad_y;
|
2015-03-13 22:01:31 +03:00
|
|
|
image.pad_x = button->pad_x;
|
|
|
|
image.pad_y = button->pad_y;
|
|
|
|
image.texture = tex;
|
|
|
|
image.uv[0] = from;
|
|
|
|
image.uv[1] = to;
|
2015-03-27 03:57:45 +03:00
|
|
|
col = (in && INBOX(in->mouse_pos.x,in->mouse_pos.y,button->x,button->y,button->w,button->h)) ?
|
|
|
|
button->highlight: button->background;
|
|
|
|
image.background = col;
|
|
|
|
image.color = color;
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_widget_image(buffer, &image);
|
2015-03-13 22:01:31 +03:00
|
|
|
return pressed;
|
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
*/
|
2015-03-13 22:01:31 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_toggle(struct gui_command_buffer *buffer, const struct gui_toggle *toggle,
|
|
|
|
gui_bool active, const struct gui_font *font, const struct gui_input *in)
|
2015-03-07 19:02:37 +03:00
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool toggle_active;
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float select_size;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float toggle_w, toggle_h;
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float select_x, select_y;
|
|
|
|
gui_float cursor_x, cursor_y;
|
|
|
|
gui_float cursor_pad, cursor_size;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(toggle);
|
|
|
|
assert(font);
|
|
|
|
if (!buffer || !toggle || !font)
|
2015-03-13 22:01:31 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
toggle_w = MAX(toggle->w, font->height + 2 * toggle->pad_x);
|
|
|
|
toggle_h = MAX(toggle->h, font->height + 2 * toggle->pad_y);
|
2015-04-15 15:37:19 +03:00
|
|
|
toggle_active = active;
|
2015-03-13 22:01:31 +03:00
|
|
|
|
|
|
|
select_x = toggle->x + toggle->pad_x;
|
|
|
|
select_y = toggle->y + toggle->pad_y;
|
2015-04-16 12:58:13 +03:00
|
|
|
select_size = font->height + 2 * toggle->pad_y;
|
2015-03-07 19:02:37 +03:00
|
|
|
|
2015-04-16 14:05:51 +03:00
|
|
|
cursor_pad = (gui_float)(gui_int)(select_size / 8);
|
|
|
|
cursor_size = select_size - cursor_pad * 2;
|
2015-03-07 19:02:37 +03:00
|
|
|
cursor_x = select_x + cursor_pad;
|
|
|
|
cursor_y = select_y + cursor_pad;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (in && !in->mouse_down && in->mouse_clicked)
|
2015-03-13 22:01:31 +03:00
|
|
|
if (INBOX(in->mouse_clicked_pos.x, in->mouse_clicked_pos.y,
|
2015-04-15 15:37:19 +03:00
|
|
|
cursor_x, cursor_y, cursor_size, cursor_size))
|
|
|
|
toggle_active = !toggle_active;
|
|
|
|
|
|
|
|
if (toggle->type == GUI_TOGGLE_CHECK) {
|
|
|
|
gui_buffer_push_rect(buffer, select_x, select_y, select_size, select_size,
|
|
|
|
toggle->background);
|
|
|
|
if (toggle_active)
|
|
|
|
gui_buffer_push_rect(buffer, cursor_x, cursor_y, cursor_size, cursor_size,
|
|
|
|
toggle->foreground);
|
|
|
|
} else {
|
2015-04-16 14:05:51 +03:00
|
|
|
select_x += select_size / 2;
|
|
|
|
select_y += select_size / 2;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_circle(buffer, select_x, select_y, select_size/2, toggle->background);
|
2015-04-16 12:58:13 +03:00
|
|
|
if (toggle_active) {
|
|
|
|
cursor_x += cursor_size / 2;
|
|
|
|
cursor_y += cursor_size / 2;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_circle(buffer, cursor_x, cursor_y, cursor_size/2, toggle->foreground);
|
2015-04-16 12:58:13 +03:00
|
|
|
}
|
2015-03-07 19:02:37 +03:00
|
|
|
}
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
if (font && toggle->text && toggle->length) {
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_text text;
|
|
|
|
text.x = toggle->x + select_size + toggle->pad_x * 2;
|
|
|
|
text.w = toggle_w - select_size + 3 * toggle->pad_x;
|
|
|
|
text.y = toggle->y + toggle->pad_y;
|
|
|
|
text.h = toggle_h - 2 * toggle->pad_y;
|
|
|
|
text.pad_x = 0; text.pad_y = 0;
|
|
|
|
text.string = (const char*)toggle->text;
|
|
|
|
text.length = toggle->length;
|
|
|
|
text.align = GUI_TEXT_LEFT;
|
|
|
|
text.font = font->user;
|
2015-04-16 12:58:13 +03:00
|
|
|
text.background = toggle->foreground;
|
2015-04-15 15:37:19 +03:00
|
|
|
text.foreground = toggle->font;
|
|
|
|
gui_widget_text(buffer, &text, font);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
return toggle_active;
|
2015-03-07 19:02:37 +03:00
|
|
|
}
|
|
|
|
|
2015-03-08 21:19:07 +03:00
|
|
|
gui_float
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_slider(struct gui_command_buffer *buffer, const struct gui_slider *slider,
|
2015-03-09 22:04:45 +03:00
|
|
|
const struct gui_input *in)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-04-07 19:20:28 +03:00
|
|
|
gui_float slider_range;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float slider_min, slider_max;
|
|
|
|
gui_float slider_value, slider_steps;
|
|
|
|
gui_float slider_w, slider_h;
|
2015-04-07 19:20:28 +03:00
|
|
|
gui_float cursor_offset;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float cursor_x, cursor_y;
|
|
|
|
gui_float cursor_w, cursor_h;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(slider);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !slider)
|
2015-03-13 22:01:31 +03:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
slider_w = MAX(slider->w, 2 * slider->pad_x);
|
|
|
|
slider_h = MAX(slider->h, 2 * slider->pad_y);
|
|
|
|
slider_max = MAX(slider->min, slider->max);
|
|
|
|
slider_min = MIN(slider->min, slider->max);
|
|
|
|
slider_value = CLAMP(slider_min, slider->value, slider_max);
|
2015-04-07 19:20:28 +03:00
|
|
|
slider_range = slider_max - slider_min;
|
|
|
|
slider_steps = slider_range / slider->step;
|
2015-03-13 22:01:31 +03:00
|
|
|
|
2015-04-07 19:20:28 +03:00
|
|
|
cursor_offset = (slider_value - slider_min) / slider->step;
|
|
|
|
cursor_w = (slider_w - 2 * slider->pad_x) / (slider_steps + 1);
|
2015-03-13 22:01:31 +03:00
|
|
|
cursor_h = slider_h - 2 * slider->pad_y;
|
2015-04-07 19:20:28 +03:00
|
|
|
cursor_x = slider->x + slider->pad_x + (cursor_w * cursor_offset);
|
2015-03-13 22:01:31 +03:00
|
|
|
cursor_y = slider->y + slider->pad_y;
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (in && in->mouse_down &&
|
|
|
|
INBOX(in->mouse_pos.x, in->mouse_pos.y, slider->x, slider->y, slider_w, slider_h) &&
|
|
|
|
INBOX(in->mouse_clicked_pos.x,in->mouse_clicked_pos.y, slider->x, slider->y,
|
|
|
|
slider_w, slider_h))
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-24 19:12:42 +03:00
|
|
|
const float d = in->mouse_pos.x - (cursor_x + cursor_w / 2.0f);
|
2015-03-13 22:01:31 +03:00
|
|
|
const float pxstep = (slider_w - 2 * slider->pad_x) / slider_steps;
|
2015-03-11 20:17:37 +03:00
|
|
|
if (ABS(d) >= pxstep) {
|
2015-04-07 19:20:28 +03:00
|
|
|
const gui_float steps = (gui_float)((gui_int)(ABS(d) / pxstep));
|
|
|
|
slider_value += (d > 0) ? (slider->step * steps) : -(slider->step * steps);
|
2015-03-13 22:01:31 +03:00
|
|
|
slider_value = CLAMP(slider_min, slider_value, slider_max);
|
|
|
|
cursor_x = slider->x + slider->pad_x + (cursor_w * (slider_value - slider_min));
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, slider->x, slider->y, slider_w, slider_h, slider->background);
|
|
|
|
gui_buffer_push_rect(buffer, cursor_x, cursor_y, cursor_w, cursor_h, slider->foreground);
|
2015-03-17 16:42:49 +03:00
|
|
|
return slider_value;
|
|
|
|
}
|
|
|
|
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_size
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_progress(struct gui_command_buffer *buffer, const struct gui_progress *prog,
|
2015-03-09 22:04:45 +03:00
|
|
|
const struct gui_input *in)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float prog_scale;
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float cursor_x, cursor_y;
|
|
|
|
gui_float cursor_w, cursor_h;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float prog_w, prog_h;
|
|
|
|
gui_size prog_value;
|
2015-03-04 13:59:02 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
|
|
|
assert(prog);
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !prog) return 0;
|
2015-03-13 22:01:31 +03:00
|
|
|
prog_w = MAX(prog->w, 2 * prog->pad_x + 1);
|
|
|
|
prog_h = MAX(prog->h, 2 * prog->pad_y + 1);
|
|
|
|
prog_value = MIN(prog->current, prog->max);
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (in && prog->modifyable && in->mouse_down &&
|
2015-03-13 22:01:31 +03:00
|
|
|
INBOX(in->mouse_pos.x, in->mouse_pos.y, prog->x, prog->y, prog_w, prog_h)){
|
|
|
|
gui_float ratio = (gui_float)(in->mouse_pos.x - prog->x) / (gui_float)prog_w;
|
|
|
|
prog_value = (gui_size)((gui_float)prog->max * ratio);
|
|
|
|
}
|
2015-03-04 16:54:48 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
if (!prog->max) return prog_value;
|
|
|
|
prog_value = MIN(prog_value, prog->max);
|
|
|
|
prog_scale = (gui_float)prog_value / (gui_float)prog->max;
|
2015-03-04 16:54:48 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
cursor_h = prog_h - 2 * prog->pad_y;
|
|
|
|
cursor_w = (prog_w - 2 * prog->pad_x) * prog_scale;
|
|
|
|
cursor_x = prog->x + prog->pad_x;
|
|
|
|
cursor_y = prog->y + prog->pad_y;
|
2015-03-04 16:54:48 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, prog->x, prog->y, prog_w, prog_h, prog->background);
|
|
|
|
gui_buffer_push_rect(buffer, cursor_x, cursor_y, cursor_w, cursor_h, prog->foreground);
|
2015-03-17 16:42:49 +03:00
|
|
|
return prog_value;
|
|
|
|
}
|
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
static gui_bool
|
|
|
|
gui_filter_input(gui_long unicode, gui_size len, enum gui_input_filter filter)
|
|
|
|
{
|
|
|
|
if (filter == GUI_INPUT_DEFAULT) {
|
|
|
|
return gui_true;
|
|
|
|
} else if (filter == GUI_INPUT_FLOAT) {
|
|
|
|
if (len > 1)
|
|
|
|
return gui_false;
|
2015-03-16 11:51:33 +03:00
|
|
|
if ((unicode < '0' || unicode > '9') && unicode != '.' && unicode != '-')
|
2015-03-14 19:05:30 +03:00
|
|
|
return gui_false;
|
|
|
|
return gui_true;
|
|
|
|
} else if (filter == GUI_INPUT_DEC) {
|
|
|
|
if (len > 1)
|
|
|
|
return gui_false;
|
|
|
|
if (unicode < '0' || unicode > '9')
|
|
|
|
return gui_false;
|
|
|
|
return gui_true;
|
|
|
|
} else if (filter == GUI_INPUT_HEX) {
|
|
|
|
if (len > 1)
|
|
|
|
return gui_false;
|
|
|
|
if ((unicode < '0' || unicode > '9') &&
|
|
|
|
(unicode < 'a' || unicode > 'f') &&
|
|
|
|
(unicode < 'A' || unicode > 'B'))
|
|
|
|
return gui_false;
|
|
|
|
return gui_true;
|
|
|
|
} else if (filter == GUI_INPUT_OCT) {
|
|
|
|
if (len > 1)
|
|
|
|
return gui_false;
|
|
|
|
if (unicode < '0' || unicode > '7')
|
|
|
|
return gui_false;
|
|
|
|
return gui_true;
|
|
|
|
} else if (filter == GUI_INPUT_BIN) {
|
|
|
|
if (len > 1)
|
|
|
|
return gui_false;
|
|
|
|
if (unicode < '0' || unicode > '1')
|
|
|
|
return gui_false;
|
|
|
|
return gui_true;
|
|
|
|
}
|
|
|
|
return gui_false;
|
|
|
|
}
|
|
|
|
|
2015-03-16 11:51:33 +03:00
|
|
|
static gui_size
|
|
|
|
gui_buffer_input(gui_char *buffer, gui_size length, gui_size max,
|
2015-03-14 19:05:30 +03:00
|
|
|
enum gui_input_filter filter, const struct gui_input *in)
|
|
|
|
{
|
|
|
|
gui_long unicode;
|
2015-03-16 11:51:33 +03:00
|
|
|
gui_size text_len = 0, glyph_len = 0;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
|
|
|
assert(in);
|
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
glyph_len = utf_decode(in->text, &unicode, in->text_len);
|
2015-03-16 11:51:33 +03:00
|
|
|
while (glyph_len && (text_len + glyph_len) <= in->text_len && (length + text_len) < max) {
|
2015-03-14 19:05:30 +03:00
|
|
|
if (gui_filter_input(unicode, glyph_len, filter)) {
|
|
|
|
gui_size i = 0;
|
|
|
|
for (i = 0; i < glyph_len; i++)
|
2015-03-16 11:51:33 +03:00
|
|
|
buffer[length++] = in->text[text_len + i];
|
2015-03-14 19:05:30 +03:00
|
|
|
}
|
|
|
|
text_len = text_len + glyph_len;
|
|
|
|
glyph_len = utf_decode(in->text + text_len, &unicode, in->text_len - text_len);
|
|
|
|
}
|
2015-03-16 11:51:33 +03:00
|
|
|
return text_len;
|
2015-03-14 19:05:30 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_input(struct gui_command_buffer *buf, gui_char *buffer, gui_size *length,
|
2015-04-16 14:05:51 +03:00
|
|
|
const struct gui_input_field *input, const struct gui_font *font,
|
|
|
|
const struct gui_input *in)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float input_w, input_h;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool input_active;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buf);
|
|
|
|
assert(font);
|
|
|
|
assert(input);
|
|
|
|
assert(length);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !font || !input)
|
2015-03-09 22:04:45 +03:00
|
|
|
return 0;
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
input_w = MAX(input->w, 2 * input->pad_x);
|
|
|
|
input_h = MAX(input->h, font->height);
|
|
|
|
input_active = input->active;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buf, input->x, input->y, input_w, input_h, input->background);
|
|
|
|
gui_buffer_push_rect(buf, input->x + 1, input->y, input_w - 1, input_h, input->foreground);
|
2015-04-05 18:19:44 +03:00
|
|
|
if (in && in->mouse_clicked && in->mouse_down)
|
2015-03-13 22:01:31 +03:00
|
|
|
input_active = INBOX(in->mouse_pos.x, in->mouse_pos.y,
|
|
|
|
input->x, input->y, input_w, input_h);
|
2015-03-09 22:04:45 +03:00
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (input_active && in) {
|
2015-03-09 22:04:45 +03:00
|
|
|
const struct gui_key *bs = &in->keys[GUI_KEY_BACKSPACE];
|
2015-04-05 18:19:44 +03:00
|
|
|
const struct gui_key *del = &in->keys[GUI_KEY_DEL];
|
2015-03-09 22:04:45 +03:00
|
|
|
const struct gui_key *esc = &in->keys[GUI_KEY_ESCAPE];
|
2015-04-05 18:19:44 +03:00
|
|
|
const struct gui_key *enter = &in->keys[GUI_KEY_ENTER];
|
2015-03-11 20:17:37 +03:00
|
|
|
const struct gui_key *space = &in->keys[GUI_KEY_SPACE];
|
2015-03-13 22:01:31 +03:00
|
|
|
|
2015-03-09 22:04:45 +03:00
|
|
|
if ((del->down && del->clicked) || (bs->down && bs->clicked))
|
2015-03-13 00:53:28 +03:00
|
|
|
if (*length > 0) *length = *length - 1;
|
2015-03-09 22:04:45 +03:00
|
|
|
if ((enter->down && enter->clicked) || (esc->down && esc->clicked))
|
2015-03-13 22:01:31 +03:00
|
|
|
input_active = gui_false;
|
2015-03-13 00:53:28 +03:00
|
|
|
if ((space->down && space->clicked) && (*length < input->max))
|
|
|
|
buffer[(*length)++] = ' ';
|
2015-03-14 19:05:30 +03:00
|
|
|
if (in->text_len && *length < input->max)
|
2015-03-16 11:51:33 +03:00
|
|
|
*length += gui_buffer_input(buffer, *length, input->max, input->filter, in);
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-16 11:51:33 +03:00
|
|
|
if (font && buffer && length) {
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_size offset = 0;
|
2015-03-16 11:51:33 +03:00
|
|
|
gui_float label_x, label_y, label_h;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float label_w = input_w - 2 * input->pad_x;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_size cursor_width = (gui_size)font->width(font->user, (const gui_char*)"X", 1);
|
2015-03-16 11:51:33 +03:00
|
|
|
|
|
|
|
gui_size text_len = *length;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_size text_width = font->width(font->user, buffer, text_len);
|
2015-03-16 11:51:33 +03:00
|
|
|
while (text_len && (text_width + cursor_width) > (gui_size)label_w) {
|
|
|
|
gui_long unicode;
|
|
|
|
offset += utf_decode(&buffer[offset], &unicode, text_len);
|
|
|
|
text_len -= offset;
|
2015-04-15 15:37:19 +03:00
|
|
|
text_width = font->width(font->user, &buffer[offset], text_len);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
2015-03-16 11:51:33 +03:00
|
|
|
|
|
|
|
label_x = input->x + input->pad_x;
|
|
|
|
label_y = input->y + input->pad_y;
|
|
|
|
label_h = input_h - 2 * input->pad_y;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_text(buf, font->user, label_x, label_y, label_w, label_h,
|
2015-04-16 21:05:43 +03:00
|
|
|
&buffer[offset], text_len, input->foreground, input->background);
|
2015-03-16 11:51:33 +03:00
|
|
|
if (input_active && input->show_cursor) {
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buf, label_x + (gui_float)text_width, label_y,
|
2015-04-16 14:05:51 +03:00
|
|
|
(gui_float)cursor_width, label_h, input->background);
|
2015-03-16 11:51:33 +03:00
|
|
|
}
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
return input_active;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-11 20:17:37 +03:00
|
|
|
gui_int
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_plot(struct gui_command_buffer *buffer, const struct gui_plot *plot,
|
2015-03-11 20:17:37 +03:00
|
|
|
const struct gui_input *in)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_size i;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_color col;
|
2015-04-10 19:35:17 +03:00
|
|
|
gui_float canvas_x, canvas_y;
|
|
|
|
gui_float canvas_w, canvas_h;
|
|
|
|
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_size plot_step;
|
2015-04-10 19:35:17 +03:00
|
|
|
gui_float plot_last_x;
|
|
|
|
gui_float plot_last_y;
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_float plot_w, plot_h;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_int plot_selected = -1;
|
|
|
|
gui_float plot_max_value, plot_min_value;
|
|
|
|
gui_float plot_value_range, plot_value_ratio;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
|
|
|
assert(plot);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !plot)
|
2015-03-13 22:01:31 +03:00
|
|
|
return plot_selected;
|
2015-03-09 22:04:45 +03:00
|
|
|
|
2015-03-11 20:17:37 +03:00
|
|
|
col = plot->foreground;
|
2015-03-13 22:01:31 +03:00
|
|
|
plot_w = MAX(plot->w, 2 * plot->pad_x);
|
|
|
|
plot_h = MAX(plot->h, 2 * plot->pad_y);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, plot->x, plot->y, plot_w, plot_h, plot->background);
|
2015-03-11 20:17:37 +03:00
|
|
|
if (!plot->value_count)
|
2015-03-13 22:01:31 +03:00
|
|
|
return plot_selected;
|
2015-03-11 16:00:59 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
plot_max_value = plot->values[0];
|
|
|
|
plot_min_value = plot->values[0];
|
2015-03-09 22:04:45 +03:00
|
|
|
for (i = 0; i < plot->value_count; ++i) {
|
2015-03-13 22:01:31 +03:00
|
|
|
if (plot->values[i] > plot_max_value)
|
|
|
|
plot_max_value = plot->values[i];
|
|
|
|
if (plot->values[i] < plot_min_value)
|
|
|
|
plot_min_value = plot->values[i];
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
2015-03-13 22:01:31 +03:00
|
|
|
|
|
|
|
canvas_x = plot->x + plot->pad_x;
|
|
|
|
canvas_y = plot->y + plot->pad_y;
|
|
|
|
canvas_w = MAX(1 + 2 * plot->pad_x, plot_w - 2 * plot->pad_x);
|
|
|
|
canvas_h = MAX(1 + 2 * plot->pad_y, plot_h - 2 * plot->pad_y);
|
|
|
|
|
|
|
|
plot_step = (gui_size)canvas_w / plot->value_count;
|
|
|
|
plot_value_range = plot_max_value - plot_min_value;
|
|
|
|
plot_value_ratio = (plot->values[0] - plot_min_value) / plot_value_range;
|
|
|
|
|
2015-03-27 03:57:45 +03:00
|
|
|
plot_last_x = canvas_x;
|
|
|
|
plot_last_y = (canvas_y + canvas_h) - plot_value_ratio * (gui_float)canvas_h;
|
|
|
|
if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, plot_last_x-3, plot_last_y-3, 6, 6)) {
|
2015-03-13 22:01:31 +03:00
|
|
|
plot_selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1;
|
2015-03-11 20:17:37 +03:00
|
|
|
col = plot->highlight;
|
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, plot_last_x - 3, plot_last_y - 3, 6, 6, col);
|
2015-03-13 00:53:28 +03:00
|
|
|
|
2015-03-09 22:04:45 +03:00
|
|
|
for (i = 1; i < plot->value_count; i++) {
|
2015-03-27 03:57:45 +03:00
|
|
|
gui_float plot_cur_x, plot_cur_y;
|
2015-03-13 22:01:31 +03:00
|
|
|
plot_value_ratio = (plot->values[i] - plot_min_value) / plot_value_range;
|
2015-03-27 03:57:45 +03:00
|
|
|
plot_cur_x = canvas_x + (gui_float)(plot_step * i);
|
|
|
|
plot_cur_y = (canvas_y + canvas_h) - (plot_value_ratio * (gui_float)canvas_h);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_line(buffer, plot_last_x, plot_last_y, plot_cur_x, plot_cur_y,
|
|
|
|
plot->foreground);
|
2015-03-27 03:57:45 +03:00
|
|
|
|
|
|
|
if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, plot_cur_x-3, plot_cur_y-3, 6, 6)) {
|
2015-03-13 22:01:31 +03:00
|
|
|
plot_selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : plot_selected;
|
2015-03-11 20:17:37 +03:00
|
|
|
col = plot->highlight;
|
|
|
|
} else col = plot->foreground;
|
2015-03-27 03:57:45 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, plot_cur_x - 3, plot_cur_y - 3, 6, 6, col);
|
2015-03-27 03:57:45 +03:00
|
|
|
plot_last_x = plot_cur_x, plot_last_y = plot_cur_y;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
2015-03-13 22:01:31 +03:00
|
|
|
return plot_selected;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gui_int
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_histo(struct gui_command_buffer *buffer, const struct gui_histo *histo,
|
2015-03-09 22:04:45 +03:00
|
|
|
const struct gui_input *in)
|
|
|
|
{
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_size i;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_int selected = -1;
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float canvas_x, canvas_y;
|
|
|
|
gui_float canvas_w, canvas_h;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float histo_max_value;
|
|
|
|
gui_float histo_w, histo_h;
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float item_w = 0.0f;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(buffer);
|
|
|
|
assert(histo);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !histo)
|
2015-03-09 22:04:45 +03:00
|
|
|
return selected;
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
histo_w = MAX(histo->w, 2 * histo->pad_x);
|
|
|
|
histo_h = MAX(histo->h, 2 * histo->pad_y);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, histo->x, histo->y, histo_w, histo_h, histo->background);
|
2015-03-13 22:01:31 +03:00
|
|
|
|
|
|
|
histo_max_value = histo->values[0];
|
2015-03-09 22:04:45 +03:00
|
|
|
for (i = 0; i < histo->value_count; ++i) {
|
2015-03-13 22:01:31 +03:00
|
|
|
if (ABS(histo->values[i]) > histo_max_value)
|
|
|
|
histo_max_value = histo->values[i];
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
canvas_x = histo->x + histo->pad_x;
|
|
|
|
canvas_y = histo->y + histo->pad_y;
|
|
|
|
canvas_w = histo_w - 2 * histo->pad_x;
|
|
|
|
canvas_h = histo_h - 2 * histo->pad_y;
|
2015-03-11 16:00:59 +03:00
|
|
|
if (histo->value_count) {
|
|
|
|
gui_float padding = (gui_float)(histo->value_count-1) * histo->pad_x;
|
|
|
|
item_w = (canvas_w - padding) / (gui_float)(histo->value_count);
|
|
|
|
}
|
2015-03-09 22:04:45 +03:00
|
|
|
|
|
|
|
for (i = 0; i < histo->value_count; i++) {
|
2015-03-13 22:01:31 +03:00
|
|
|
const gui_float histo_ratio = ABS(histo->values[i]) / histo_max_value;
|
|
|
|
struct gui_color item_color = (histo->values[i] < 0) ? histo->negative: histo->foreground;
|
|
|
|
const gui_float item_h = canvas_h * histo_ratio;
|
2015-03-11 16:00:59 +03:00
|
|
|
const gui_float item_y = (canvas_y + canvas_h) - item_h;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float item_x = canvas_x + ((gui_float)i * item_w);
|
|
|
|
item_x = item_x + ((gui_float)i * histo->pad_y);
|
2015-03-24 15:08:42 +03:00
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, item_x, item_y, item_w, item_h)) {
|
2015-03-13 22:01:31 +03:00
|
|
|
selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i: selected;
|
|
|
|
item_color = histo->highlight;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, item_x, item_y, item_w, item_h, item_color);
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
return selected;
|
|
|
|
}
|
|
|
|
|
2015-03-16 16:02:47 +03:00
|
|
|
gui_float
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_scroll(struct gui_command_buffer *buffer, const struct gui_scroll *scroll,
|
2015-03-09 22:04:45 +03:00
|
|
|
const struct gui_input *in)
|
2015-03-03 19:24:02 +03:00
|
|
|
{
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_bool button_up_pressed;
|
|
|
|
gui_bool button_down_pressed;
|
|
|
|
struct gui_button button;
|
|
|
|
|
2015-03-16 16:02:47 +03:00
|
|
|
gui_float scroll_step;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_float scroll_offset;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_float scroll_off, scroll_ratio;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_float scroll_y, scroll_w, scroll_h;
|
2015-03-13 22:01:31 +03:00
|
|
|
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float cursor_x, cursor_y;
|
|
|
|
gui_float cursor_w, cursor_h;
|
2015-03-05 17:37:11 +03:00
|
|
|
gui_bool inscroll, incursor;
|
2015-03-04 16:54:48 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(buffer);
|
|
|
|
assert(scroll);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!buffer || !scroll) return 0;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
scroll_w = MAX(scroll->w, 0);
|
|
|
|
scroll_h = MAX(scroll->h, 2 * scroll_w);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(buffer, scroll->x, scroll->y, scroll_w, scroll_h, scroll->background);
|
|
|
|
gui_buffer_push_rect(buffer, scroll->x, scroll->y, scroll_w, scroll_h, scroll->border);
|
2015-03-13 22:01:31 +03:00
|
|
|
if (scroll->target <= scroll_h) return 0;
|
|
|
|
|
|
|
|
button.x = scroll->x;
|
|
|
|
button.y = scroll->y;
|
|
|
|
button.w = scroll_w;
|
|
|
|
button.h = scroll_w;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
2015-03-13 22:01:31 +03:00
|
|
|
button.pad_x = scroll_w / 4;
|
|
|
|
button.pad_y = scroll_w / 4;
|
|
|
|
button.background = scroll->foreground;
|
|
|
|
button.foreground = scroll->background;
|
|
|
|
button.highlight = scroll->foreground;
|
2015-04-16 21:05:43 +03:00
|
|
|
button.highlight_content = scroll->background;
|
2015-04-10 19:35:17 +03:00
|
|
|
button.behavior = GUI_BUTTON_DEFAULT;
|
2015-03-23 19:18:18 +03:00
|
|
|
button_up_pressed = gui_widget_button_triangle(buffer, &button, GUI_UP, in);
|
2015-03-13 22:01:31 +03:00
|
|
|
button.y = scroll->y + scroll_h - button.h;
|
2015-03-23 19:18:18 +03:00
|
|
|
button_down_pressed = gui_widget_button_triangle(buffer, &button, GUI_DOWN, in);
|
2015-03-13 22:01:31 +03:00
|
|
|
|
|
|
|
scroll_h = scroll_h - 2 * button.h;
|
|
|
|
scroll_y = scroll->y + button.h;
|
2015-03-16 16:02:47 +03:00
|
|
|
scroll_step = MIN(scroll->step, scroll_h);
|
|
|
|
scroll_offset = MIN(scroll->offset, scroll->target - scroll_h);
|
|
|
|
scroll_ratio = scroll_h / scroll->target;
|
|
|
|
scroll_off = scroll_offset / scroll->target;
|
2015-03-13 22:01:31 +03:00
|
|
|
|
|
|
|
cursor_h = scroll_ratio * scroll_h;
|
|
|
|
cursor_y = scroll_y + (scroll_off * scroll_h);
|
|
|
|
cursor_w = scroll_w;
|
|
|
|
cursor_x = scroll->x;
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (in) {
|
2015-03-27 18:54:23 +03:00
|
|
|
inscroll = INBOX(in->mouse_pos.x,in->mouse_pos.y,scroll->x,scroll->y,scroll_w,scroll_h);
|
|
|
|
incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,cursor_x,cursor_y,cursor_w, cursor_h);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (in->mouse_down && inscroll && incursor) {
|
|
|
|
const gui_float pixel = in->mouse_delta.y;
|
|
|
|
const gui_float delta = (pixel / scroll_h) * scroll->target;
|
|
|
|
scroll_offset = CLAMP(0, scroll_offset + delta, scroll->target - scroll_h);
|
|
|
|
cursor_y += pixel;
|
|
|
|
} else if (button_up_pressed || button_down_pressed) {
|
|
|
|
scroll_offset = (button_down_pressed) ?
|
|
|
|
MIN(scroll_offset + scroll_step, scroll->target - scroll_h):
|
|
|
|
MAX(0, scroll_offset - scroll_step);
|
|
|
|
scroll_off = scroll_offset / scroll->target;
|
|
|
|
cursor_y = scroll_y + (scroll_off * scroll_h);
|
|
|
|
}
|
2015-03-04 13:59:02 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
|
|
|
|
gui_buffer_push_rect(buffer, cursor_x, cursor_y, cursor_w, cursor_h, scroll->foreground);
|
|
|
|
gui_buffer_push_rect(buffer, cursor_x+1, cursor_y, cursor_w-1, cursor_h, scroll->background);
|
2015-03-13 22:01:31 +03:00
|
|
|
return scroll_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_default_config(struct gui_config *config)
|
|
|
|
{
|
|
|
|
if (!config) return;
|
|
|
|
config->scrollbar_width = 16;
|
2015-03-23 19:18:18 +03:00
|
|
|
vec2_load(config->panel_padding, 15.0f, 10.0f);
|
|
|
|
vec2_load(config->panel_min_size, 64.0f, 64.0f);
|
|
|
|
vec2_load(config->item_spacing, 8.0f, 8.0f);
|
|
|
|
vec2_load(config->item_padding, 4.0f, 4.0f);
|
2015-03-25 16:15:42 +03:00
|
|
|
vec2_load(config->scaler_size, 16.0f, 16.0f);
|
2015-03-23 19:18:18 +03:00
|
|
|
col_load(config->colors[GUI_COLOR_TEXT], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_PANEL], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_BORDER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_TITLEBAR], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_BUTTON], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_BUTTON_HOVER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_BUTTON_HOVER_FONT], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_BUTTON_BORDER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_CHECK], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_CHECK_ACTIVE], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_OPTION], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_OPTION_ACTIVE], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SCROLL], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SLIDER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SLIDER_CURSOR], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_PROGRESS], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_PROGRESS_CURSOR], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_INPUT], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_INPUT_BORDER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SPINNER], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SPINNER_BORDER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SELECTOR], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SELECTOR_BORDER], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_HISTO], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_HISTO_BARS], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_HISTO_NEGATIVE], 255, 255, 255, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_HISTO_HIGHLIGHT], 255, 0, 0, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_PLOT], 100, 100, 100, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_PLOT_LINES], 45, 45, 45, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_PLOT_HIGHLIGHT], 255, 0, 0, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SCROLLBAR], 41, 41, 41, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SCROLLBAR_CURSOR], 70, 70, 70, 255);
|
|
|
|
col_load(config->colors[GUI_COLOR_SCROLLBAR_BORDER], 45, 45, 45, 255);
|
2015-04-07 19:20:28 +03:00
|
|
|
col_load(config->colors[GUI_COLOR_SCALER], 100, 100, 100, 255);
|
2015-03-03 19:24:02 +03:00
|
|
|
}
|
|
|
|
|
2015-03-10 15:50:27 +03:00
|
|
|
void
|
|
|
|
gui_panel_init(struct gui_panel *panel, const struct gui_config *config,
|
2015-03-23 19:18:18 +03:00
|
|
|
const struct gui_font *font)
|
2015-03-08 21:19:07 +03:00
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->flags = 0;
|
2015-03-10 15:50:27 +03:00
|
|
|
panel->x = 0;
|
|
|
|
panel->y = 0;
|
|
|
|
panel->at_y = 0;
|
2015-03-09 22:04:45 +03:00
|
|
|
panel->width = 0;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->height = 0;
|
2015-03-09 22:04:45 +03:00
|
|
|
panel->index = 0;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->header_height = 0;
|
2015-03-09 22:04:45 +03:00
|
|
|
panel->row_height = 0;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->row_columns = 0;
|
2015-03-16 11:51:33 +03:00
|
|
|
panel->offset = 0;
|
2015-03-11 20:17:37 +03:00
|
|
|
panel->minimized = gui_false;
|
2015-03-11 16:00:59 +03:00
|
|
|
panel->out = NULL;
|
2015-03-23 19:18:18 +03:00
|
|
|
panel->in = NULL;
|
2015-04-15 15:37:19 +03:00
|
|
|
panel->font = *font;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->config = config;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_panel_begin(struct gui_panel *panel, struct gui_command_buffer *out,
|
2015-03-23 19:18:18 +03:00
|
|
|
const struct gui_input *in, const char *text, gui_float x, gui_float y,
|
|
|
|
gui_float w, gui_float h, gui_flags f)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
const struct gui_color *header;
|
2015-03-16 11:51:33 +03:00
|
|
|
struct gui_rect clip;
|
2015-03-24 15:08:42 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_float mouse_x, mouse_y;
|
|
|
|
gui_float clicked_x, clicked_y;
|
2015-04-03 18:40:47 +03:00
|
|
|
gui_float header_x, header_w;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool ret = gui_true;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(panel);
|
|
|
|
assert(out);
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!panel || !out)
|
2015-03-20 12:58:11 +03:00
|
|
|
return gui_false;
|
2015-03-27 17:01:23 +03:00
|
|
|
if (panel->flags & GUI_PANEL_HIDDEN)
|
|
|
|
return gui_false;
|
2015-03-13 00:53:28 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->out = out;
|
2015-03-23 19:18:18 +03:00
|
|
|
panel->in = in;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->x = x;
|
|
|
|
panel->y = y;
|
|
|
|
panel->width = w;
|
|
|
|
panel->at_y = y;
|
|
|
|
panel->index = 0;
|
|
|
|
panel->row_columns = 0;
|
2015-04-10 19:35:17 +03:00
|
|
|
panel->flags = f;
|
|
|
|
if (!(panel->flags & GUI_PANEL_TAB))
|
|
|
|
panel->flags |= GUI_PANEL_SCROLLBAR;
|
2015-03-13 00:53:28 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
config = panel->config;
|
|
|
|
header = &config->colors[GUI_COLOR_TITLEBAR];
|
2015-04-10 19:35:17 +03:00
|
|
|
header_x = x + config->panel_padding.x;
|
|
|
|
header_w = w - 2 * config->panel_padding.x;
|
2015-03-24 19:12:42 +03:00
|
|
|
mouse_x = (panel->in) ? panel->in->mouse_pos.x : -1;
|
|
|
|
mouse_y = (panel->in) ? panel->in->mouse_pos.y: -1;
|
|
|
|
clicked_x = (panel->in) ? panel->in->mouse_clicked_pos.x: - 1;
|
|
|
|
clicked_y = (panel->in) ? panel->in->mouse_clicked_pos.y: - 1;
|
2015-03-20 12:58:11 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
panel->header_height = panel->font.height + 3 * config->item_padding.y;
|
2015-04-07 19:37:06 +03:00
|
|
|
panel->header_height += config->panel_padding.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(out, x, y, w, panel->header_height, *header);
|
2015-04-07 19:37:06 +03:00
|
|
|
|
|
|
|
clip.x = x; clip.w = w;
|
|
|
|
clip.y = y + panel->header_height - 1;
|
|
|
|
clip.h = h - panel->header_height - 1;
|
|
|
|
if (panel->flags & GUI_PANEL_SCROLLBAR)
|
|
|
|
clip.h -= (config->panel_padding.y + config->item_padding.y);
|
|
|
|
else clip.h = null_rect.h;
|
|
|
|
|
|
|
|
if (panel->flags & GUI_PANEL_CLOSEABLE) {
|
2015-04-03 18:40:47 +03:00
|
|
|
const gui_char *X = (const gui_char*)"x";
|
2015-04-15 15:37:19 +03:00
|
|
|
const gui_size text_width = panel->font.width(panel->font.user, X, 1);
|
|
|
|
const gui_float close_x = header_x;
|
2015-03-20 12:58:11 +03:00
|
|
|
const gui_float close_y = y + config->panel_padding.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
const gui_float close_w = (gui_float)text_width + 2 * config->item_padding.x;
|
|
|
|
const gui_float close_h = panel->font.height + 2 * config->item_padding.y;
|
|
|
|
gui_buffer_push_text(panel->out, panel->font.user, close_x, close_y, close_w, close_h,
|
|
|
|
X, 1, config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
|
2015-03-24 15:08:42 +03:00
|
|
|
|
2015-04-03 18:40:47 +03:00
|
|
|
header_w -= close_w;
|
|
|
|
header_x += close_h - config->item_padding.x;
|
2015-03-13 00:53:28 +03:00
|
|
|
if (INBOX(mouse_x, mouse_y, close_x, close_y, close_w, close_h)) {
|
2015-03-27 17:01:23 +03:00
|
|
|
if (INBOX(clicked_x, clicked_y, close_x, close_y, close_w, close_h)) {
|
2015-03-11 20:17:37 +03:00
|
|
|
ret = !(panel->in->mouse_down && panel->in->mouse_clicked);
|
2015-03-27 17:01:23 +03:00
|
|
|
if (ret) panel->flags |= GUI_PANEL_HIDDEN;
|
|
|
|
}
|
2015-03-11 20:17:37 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:37:06 +03:00
|
|
|
if (panel->flags & GUI_PANEL_MINIMIZABLE) {
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_size text_width;
|
2015-03-11 20:17:37 +03:00
|
|
|
gui_float min_x, min_y, min_w, min_h;
|
2015-03-13 00:53:28 +03:00
|
|
|
const gui_char *score = (panel->minimized) ?
|
|
|
|
(const gui_char*)"+":
|
|
|
|
(const gui_char*)"-";
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
text_width = panel->font.width(panel->font.user, score, 1);
|
|
|
|
min_x = header_x;
|
2015-03-11 20:17:37 +03:00
|
|
|
min_y = y + config->panel_padding.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
min_w = (gui_float)text_width + 3 * config->item_padding.x;
|
|
|
|
min_h = panel->font.height + 2 * config->item_padding.y;
|
|
|
|
gui_buffer_push_text(panel->out, panel->font.user, min_x, min_y, min_w, min_h,
|
|
|
|
score, 1, config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
|
|
|
|
|
2015-03-24 15:08:42 +03:00
|
|
|
|
2015-04-03 18:40:47 +03:00
|
|
|
header_w -= min_w;
|
|
|
|
header_x += min_w - config->item_padding.x;
|
2015-03-13 00:53:28 +03:00
|
|
|
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_w, min_h))
|
2015-03-11 20:17:37 +03:00
|
|
|
if (panel->in->mouse_down && panel->in->mouse_clicked)
|
|
|
|
panel->minimized = !panel->minimized;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:37:06 +03:00
|
|
|
if (text) {
|
2015-04-03 18:40:47 +03:00
|
|
|
const gui_size text_len = strsiz(text);
|
|
|
|
const gui_float label_x = header_x + config->item_padding.x;
|
|
|
|
const gui_float label_y = y + config->panel_padding.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
const gui_float label_w = header_w - (3 * config->item_padding.x);
|
|
|
|
const gui_float label_h = panel->font.height + 2 * config->item_padding.y;
|
|
|
|
gui_buffer_push_text(panel->out, panel->font.user, label_x, label_y, label_w, label_h,
|
|
|
|
(const gui_char*)text, text_len, config->colors[GUI_COLOR_PANEL],
|
|
|
|
config->colors[GUI_COLOR_TEXT]);
|
2015-04-03 18:40:47 +03:00
|
|
|
}
|
|
|
|
|
2015-03-17 16:42:49 +03:00
|
|
|
panel->row_height = panel->header_height;
|
2015-03-16 11:51:33 +03:00
|
|
|
if (panel->flags & GUI_PANEL_SCROLLBAR) {
|
2015-03-20 12:58:11 +03:00
|
|
|
const struct gui_color *color = &config->colors[GUI_COLOR_PANEL];
|
2015-03-16 11:51:33 +03:00
|
|
|
panel->width -= config->scrollbar_width;
|
2015-04-07 19:37:06 +03:00
|
|
|
panel->height = h - panel->header_height;
|
2015-03-20 12:58:11 +03:00
|
|
|
if (!panel->minimized)
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(panel->out, x, y + panel->header_height, w,
|
|
|
|
h - panel->header_height, *color);
|
2015-03-16 11:51:33 +03:00
|
|
|
}
|
|
|
|
|
2015-03-17 16:42:49 +03:00
|
|
|
if (panel->flags & GUI_PANEL_BORDER) {
|
|
|
|
const struct gui_color *color;
|
|
|
|
color = &config->colors[GUI_COLOR_BORDER];
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_line(panel->out, x, y, x + w, y, *color);
|
2015-03-17 16:42:49 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_clip(out, &clip);
|
2015-03-11 20:17:37 +03:00
|
|
|
return ret;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-04-07 19:20:28 +03:00
|
|
|
void
|
|
|
|
gui_panel_show(struct gui_panel *panel)
|
|
|
|
{
|
|
|
|
panel->flags = panel->flags & (gui_flags)(~GUI_PANEL_HIDDEN);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_panel_hide(struct gui_panel *panel)
|
|
|
|
{
|
|
|
|
panel->flags |= GUI_PANEL_HIDDEN;
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:47:32 +03:00
|
|
|
gui_bool
|
|
|
|
gui_panel_is_hidden(const struct gui_panel *panel)
|
|
|
|
{
|
|
|
|
return panel->flags & GUI_PANEL_HIDDEN;
|
|
|
|
}
|
|
|
|
|
2015-03-09 22:04:45 +03:00
|
|
|
void
|
2015-03-16 11:51:33 +03:00
|
|
|
gui_panel_layout(struct gui_panel *panel, gui_float height, gui_size cols)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
const struct gui_color *color;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
2015-03-20 12:58:11 +03:00
|
|
|
if (!panel) return;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
|
2015-03-31 19:29:45 +03:00
|
|
|
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
2015-03-20 12:58:11 +03:00
|
|
|
config = panel->config;
|
|
|
|
color = &config->colors[GUI_COLOR_PANEL];
|
|
|
|
|
2015-03-09 22:04:45 +03:00
|
|
|
panel->index = 0;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->at_y += panel->row_height;
|
2015-03-09 22:04:45 +03:00
|
|
|
panel->row_columns = cols;
|
2015-03-11 20:17:37 +03:00
|
|
|
panel->row_height = height + config->item_spacing.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(panel->out, panel->x, panel->at_y, panel->width,
|
|
|
|
height + config->panel_padding.y, *color);
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-13 00:53:28 +03:00
|
|
|
void
|
|
|
|
gui_panel_seperator(struct gui_panel *panel, gui_size cols)
|
|
|
|
{
|
|
|
|
const struct gui_config *config;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
2015-03-13 00:53:28 +03:00
|
|
|
if (!panel) return;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-13 00:53:28 +03:00
|
|
|
config = panel->config;
|
|
|
|
cols = MIN(cols, panel->row_columns - panel->index);
|
|
|
|
panel->index += cols;
|
2015-03-13 22:01:31 +03:00
|
|
|
if (panel->index >= panel->row_columns) {
|
|
|
|
const gui_float row_height = panel->row_height - config->item_spacing.y;
|
2015-03-16 11:51:33 +03:00
|
|
|
gui_panel_layout(panel, row_height, panel->row_columns);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
2015-03-13 00:53:28 +03:00
|
|
|
}
|
|
|
|
|
2015-03-09 22:04:45 +03:00
|
|
|
static void
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(struct gui_rect *bounds, struct gui_panel *panel)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
const struct gui_config *config;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_float panel_padding, panel_spacing, panel_space;
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_float item_offset, item_width, item_spacing;
|
2015-03-27 18:54:23 +03:00
|
|
|
|
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(bounds);
|
|
|
|
|
|
|
|
config = panel->config;
|
2015-03-13 22:01:31 +03:00
|
|
|
if (panel->index >= panel->row_columns) {
|
|
|
|
const gui_float row_height = panel->row_height - config->item_spacing.y;
|
2015-03-16 11:51:33 +03:00
|
|
|
gui_panel_layout(panel, row_height, panel->row_columns);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
2015-03-10 15:50:27 +03:00
|
|
|
|
2015-04-03 22:09:21 +03:00
|
|
|
panel_padding = 2 * config->panel_padding.x;
|
2015-03-20 12:58:11 +03:00
|
|
|
panel_spacing = (gui_float)(panel->row_columns - 1) * config->item_spacing.x;
|
|
|
|
panel_space = panel->width - panel_padding - panel_spacing;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
item_width = panel_space / (gui_float)panel->row_columns;
|
2015-03-11 17:08:34 +03:00
|
|
|
item_offset = (gui_float)panel->index * item_width;
|
2015-03-11 16:00:59 +03:00
|
|
|
item_spacing = (gui_float)panel->index * config->item_spacing.x;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
2015-03-11 17:08:34 +03:00
|
|
|
bounds->x = panel->x + item_offset + item_spacing + config->panel_padding.x;
|
2015-03-16 11:51:33 +03:00
|
|
|
bounds->y = panel->at_y - panel->offset;
|
2015-03-10 15:50:27 +03:00
|
|
|
bounds->w = item_width;
|
|
|
|
bounds->h = panel->row_height - config->item_spacing.y;
|
|
|
|
panel->index++;
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
void
|
2015-04-08 12:54:33 +03:00
|
|
|
gui_panel_text(struct gui_panel *panel, const char *str, gui_size len,
|
|
|
|
enum gui_text_align alignment)
|
2015-03-13 22:01:31 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_text text;
|
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(str && len);
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
|
|
|
|
|
|
|
text.x = bounds.x;
|
|
|
|
text.y = bounds.y;
|
|
|
|
text.w = bounds.w;
|
|
|
|
text.h = bounds.h;
|
|
|
|
text.pad_x = config->item_padding.x;
|
|
|
|
text.pad_y = config->item_padding.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
text.string = str;
|
2015-03-13 22:01:31 +03:00
|
|
|
text.length = len;
|
2015-04-08 12:54:33 +03:00
|
|
|
text.align = alignment;
|
2015-04-15 15:37:19 +03:00
|
|
|
text.font = panel->font.user;
|
|
|
|
text.foreground = config->colors[GUI_COLOR_TEXT];
|
2015-03-13 22:01:31 +03:00
|
|
|
text.background = config->colors[GUI_COLOR_PANEL];
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_widget_text(panel->out, &text, &panel->font);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_panel_button_text(struct gui_panel *panel, const char *str,
|
2015-03-14 19:05:30 +03:00
|
|
|
enum gui_button_behavior behavior)
|
2015-03-13 22:01:31 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_button button;
|
|
|
|
const struct gui_config *config;
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_size len;
|
2015-03-13 22:01:31 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-30 01:51:07 +03:00
|
|
|
len = strsiz(str);
|
2015-03-13 22:01:31 +03:00
|
|
|
|
|
|
|
button.x = bounds.x;
|
|
|
|
button.y = bounds.y;
|
|
|
|
button.w = bounds.w;
|
|
|
|
button.h = bounds.h;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
2015-03-14 19:05:30 +03:00
|
|
|
button.behavior = behavior;
|
2015-03-13 22:01:31 +03:00
|
|
|
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];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
2015-03-13 22:01:31 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
|
2015-04-15 15:37:19 +03:00
|
|
|
return gui_widget_button_text(panel->out, &button, str, len, &panel->font, panel->in);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool gui_panel_button_color(struct gui_panel *panel, const struct gui_color color,
|
2015-03-17 16:42:49 +03:00
|
|
|
enum gui_button_behavior behavior)
|
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_button button;
|
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
|
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-17 16:42:49 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
|
|
|
|
|
|
|
button.x = bounds.x;
|
|
|
|
button.y = bounds.y;
|
|
|
|
button.w = bounds.w;
|
|
|
|
button.h = bounds.h;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
2015-03-17 16:42:49 +03:00
|
|
|
button.behavior = behavior;
|
|
|
|
button.pad_x = config->item_padding.x;
|
|
|
|
button.pad_y = config->item_padding.y;
|
|
|
|
button.background = color;
|
|
|
|
button.foreground = color;
|
|
|
|
button.highlight = color;
|
2015-03-20 12:58:11 +03:00
|
|
|
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
|
2015-03-23 19:18:18 +03:00
|
|
|
return gui_widget_button(panel->out, &button, panel->in);
|
2015-03-17 16:42:49 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-17 16:42:49 +03:00
|
|
|
gui_panel_button_triangle(struct gui_panel *panel, enum gui_heading heading,
|
2015-03-14 19:05:30 +03:00
|
|
|
enum gui_button_behavior behavior)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_button button;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
|
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-09 22:04:45 +03:00
|
|
|
|
|
|
|
button.x = bounds.x;
|
|
|
|
button.y = bounds.y;
|
|
|
|
button.w = bounds.w;
|
|
|
|
button.h = bounds.h;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
2015-03-14 19:05:30 +03:00
|
|
|
button.behavior = behavior;
|
2015-03-09 22:04:45 +03:00
|
|
|
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];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
2015-03-09 22:04:45 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
|
2015-03-23 19:18:18 +03:00
|
|
|
return gui_widget_button_triangle(panel->out, &button, heading, panel->in);
|
2015-03-13 22:01:31 +03:00
|
|
|
}
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
/*
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-27 21:07:22 +03:00
|
|
|
gui_panel_button_icon(struct gui_panel *panel, gui_texture tex,
|
2015-03-14 19:05:30 +03:00
|
|
|
struct gui_texCoord from, struct gui_texCoord to,
|
|
|
|
enum gui_button_behavior behavior)
|
2015-03-13 22:01:31 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_button button;
|
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
|
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-13 22:01:31 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-13 22:01:31 +03:00
|
|
|
config = panel->config;
|
|
|
|
button.x = bounds.x;
|
|
|
|
button.y = bounds.y;
|
|
|
|
button.w = bounds.w;
|
|
|
|
button.h = bounds.h;
|
2015-03-14 19:05:30 +03:00
|
|
|
button.behavior = behavior;
|
2015-03-13 22:01:31 +03:00
|
|
|
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];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
2015-03-13 22:01:31 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER];
|
2015-03-27 21:07:22 +03:00
|
|
|
return gui_widget_button_icon(panel->out, &button, tex, from, to, panel->in);
|
2015-03-09 22:04:45 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
*/
|
2015-03-09 22:04:45 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_panel_button_toggle(struct gui_panel *panel, const char *str, gui_bool value)
|
2015-03-17 16:42:49 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_button button;
|
|
|
|
const struct gui_config *config;
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_size len;
|
2015-03-17 16:42:49 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(str);
|
|
|
|
|
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-17 16:42:49 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-30 01:51:07 +03:00
|
|
|
len = strsiz(str);
|
2015-03-17 16:42:49 +03:00
|
|
|
|
|
|
|
button.x = bounds.x;
|
|
|
|
button.y = bounds.y;
|
|
|
|
button.w = bounds.w;
|
|
|
|
button.h = bounds.h;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
2015-04-10 19:35:17 +03:00
|
|
|
button.behavior = GUI_BUTTON_DEFAULT;
|
2015-03-17 16:42:49 +03:00
|
|
|
button.pad_x = config->item_padding.x;
|
|
|
|
button.pad_y = config->item_padding.y;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-17 16:42:49 +03:00
|
|
|
if (!value) {
|
|
|
|
button.background = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
2015-04-03 22:09:21 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.highlight_content = config->colors[GUI_COLOR_TEXT];
|
2015-03-17 16:42:49 +03:00
|
|
|
} else {
|
|
|
|
button.background = config->colors[GUI_COLOR_BUTTON_HOVER];
|
|
|
|
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
|
2015-03-20 12:58:11 +03:00
|
|
|
button.content = config->colors[GUI_COLOR_BUTTON];
|
2015-04-03 22:09:21 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
|
|
|
|
button.highlight_content = config->colors[GUI_COLOR_BUTTON];
|
2015-03-17 16:42:49 +03:00
|
|
|
}
|
2015-04-15 15:37:19 +03:00
|
|
|
if (gui_widget_button_text(panel->out, &button, str, len, &panel->font, panel->in))
|
2015-03-17 16:42:49 +03:00
|
|
|
value = !value;
|
|
|
|
return value;
|
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_panel_check(struct gui_panel *panel, const char *text, gui_bool is_active)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_toggle toggle;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_size length;
|
2015-03-13 00:53:28 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(text);
|
|
|
|
|
|
|
|
if (!panel || !panel->config || !panel->out) return is_active;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return is_active;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-30 01:51:07 +03:00
|
|
|
length = strsiz(text);
|
2015-03-10 15:50:27 +03:00
|
|
|
|
|
|
|
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;
|
2015-03-13 22:01:31 +03:00
|
|
|
toggle.text = (const gui_char*)text;
|
2015-03-10 15:50:27 +03:00
|
|
|
toggle.length = length;
|
2015-03-20 12:58:11 +03:00
|
|
|
toggle.type = GUI_TOGGLE_CHECK;
|
2015-03-10 15:50:27 +03:00
|
|
|
toggle.font = config->colors[GUI_COLOR_TEXT];
|
2015-03-20 12:58:11 +03:00
|
|
|
toggle.background = config->colors[GUI_COLOR_CHECK];
|
|
|
|
toggle.foreground = config->colors[GUI_COLOR_CHECK_ACTIVE];
|
2015-04-15 15:37:19 +03:00
|
|
|
return gui_widget_toggle(panel->out, &toggle, is_active, &panel->font, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gui_bool
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_panel_option(struct gui_panel *panel, const char *text, gui_bool is_active)
|
2015-03-20 12:58:11 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_toggle toggle;
|
|
|
|
const struct gui_config *config;
|
2015-03-30 01:51:07 +03:00
|
|
|
gui_size length;
|
2015-03-20 12:58:11 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(text);
|
|
|
|
|
|
|
|
if (!panel || !panel->config || !panel->out) return is_active;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return is_active;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-30 01:51:07 +03:00
|
|
|
length = strsiz(text);
|
2015-03-20 12:58:11 +03:00
|
|
|
|
|
|
|
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.text = (const gui_char*)text;
|
|
|
|
toggle.length = length;
|
|
|
|
toggle.type = GUI_TOGGLE_OPTION;
|
|
|
|
toggle.font = config->colors[GUI_COLOR_TEXT];
|
|
|
|
toggle.background = config->colors[GUI_COLOR_CHECK];
|
|
|
|
toggle.foreground = config->colors[GUI_COLOR_CHECK_ACTIVE];
|
2015-04-15 15:37:19 +03:00
|
|
|
return gui_widget_toggle(panel->out, &toggle, is_active, &panel->font, panel->in);
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gui_float
|
|
|
|
gui_panel_slider(struct gui_panel *panel, gui_float min_value, gui_float value,
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_float max_value, gui_float value_step)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_slider slider;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return value;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return value;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
|
|
|
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];
|
2015-04-15 15:37:19 +03:00
|
|
|
return gui_widget_slider(panel->out, &slider, panel->in);
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_size
|
2015-03-10 15:50:27 +03:00
|
|
|
gui_panel_progress(struct gui_panel *panel, gui_size cur_value, gui_size max_value,
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_bool is_modifyable)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_progress prog;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return cur_value;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return cur_value;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
|
|
|
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];
|
2015-04-15 15:37:19 +03:00
|
|
|
return gui_widget_progress(panel->out, &prog, panel->in);
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size *length,
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_size max_length, enum gui_input_filter filter, gui_bool is_active)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_input_field field;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(buffer);
|
|
|
|
assert(length);
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
|
|
|
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.max = max_length;
|
2015-03-14 19:05:30 +03:00
|
|
|
field.filter = filter;
|
2015-03-10 15:50:27 +03:00
|
|
|
field.active = is_active;
|
2015-03-16 11:51:33 +03:00
|
|
|
field.show_cursor = gui_true;
|
2015-03-10 15:50:27 +03:00
|
|
|
field.font = config->colors[GUI_COLOR_TEXT];
|
|
|
|
field.background = config->colors[GUI_COLOR_INPUT];
|
2015-03-11 20:17:37 +03:00
|
|
|
field.foreground = config->colors[GUI_COLOR_INPUT_BORDER];
|
2015-04-15 15:37:19 +03:00
|
|
|
return gui_widget_input(panel->out, buffer, length, &field, &panel->font, panel->in);
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_panel_spinner(struct gui_panel *panel, gui_int min, gui_int *value,
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_int max, gui_int step, gui_bool active)
|
2015-03-14 19:05:30 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
const struct gui_config *config;
|
2015-03-20 12:58:11 +03:00
|
|
|
struct gui_input_field field;
|
|
|
|
char string[MAX_NUMBER_BUFFER];
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_size len, old_len;
|
|
|
|
|
|
|
|
struct gui_button button;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool is_active, updated = gui_false;
|
|
|
|
gui_bool button_up_clicked, button_down_clicked;
|
2015-03-14 19:05:30 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(value);
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-14 19:05:30 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
*value = CLAMP(min, *value, max);
|
|
|
|
len = itos(string, *value);
|
2015-03-23 19:18:18 +03:00
|
|
|
is_active = active;
|
2015-03-20 12:58:11 +03:00
|
|
|
old_len = len;
|
|
|
|
|
|
|
|
button.y = bounds.y;
|
|
|
|
button.h = bounds.h / 2;
|
2015-04-16 23:04:34 +03:00
|
|
|
button.w = bounds.h - config->item_padding.x;
|
|
|
|
button.x = bounds.x + bounds.w - button.w;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
|
|
|
button.pad_x = MAX(3, button.h - panel->font.height);
|
|
|
|
button.pad_y = MAX(3, button.h - panel->font.height);
|
2015-04-10 19:35:17 +03:00
|
|
|
button.behavior = GUI_BUTTON_DEFAULT;
|
2015-03-20 12:58:11 +03:00
|
|
|
button.background = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
|
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
2015-04-03 22:09:21 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.highlight_content = config->colors[GUI_COLOR_TEXT];
|
2015-03-23 19:18:18 +03:00
|
|
|
button_up_clicked = gui_widget_button_triangle(panel->out, &button, GUI_UP, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
button.y = bounds.y + button.h;
|
2015-03-23 19:18:18 +03:00
|
|
|
button_down_clicked = gui_widget_button_triangle(panel->out, &button, GUI_DOWN, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
if (button_up_clicked || button_down_clicked) {
|
|
|
|
*value += (button_up_clicked) ? step : -step;
|
|
|
|
*value = CLAMP(min, *value, max);
|
|
|
|
}
|
|
|
|
|
|
|
|
field.x = bounds.x;
|
|
|
|
field.y = bounds.y;
|
|
|
|
field.w = bounds.w - button.w;
|
|
|
|
field.h = bounds.h;
|
|
|
|
field.pad_x = config->item_padding.x;
|
|
|
|
field.pad_y = config->item_padding.y;
|
|
|
|
field.max = MAX_NUMBER_BUFFER;
|
|
|
|
field.filter = GUI_INPUT_FLOAT;
|
|
|
|
field.active = is_active;
|
|
|
|
field.show_cursor = gui_false;
|
|
|
|
field.font = config->colors[GUI_COLOR_TEXT];
|
|
|
|
field.background = config->colors[GUI_COLOR_SPINNER];
|
|
|
|
field.foreground = config->colors[GUI_COLOR_SPINNER_BORDER];
|
2015-03-23 19:18:18 +03:00
|
|
|
is_active = gui_widget_input(panel->out, (gui_char*)string, &len, &field,
|
2015-04-15 15:37:19 +03:00
|
|
|
&panel->font, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
if (old_len != len)
|
|
|
|
strtoi(value, string, len);
|
|
|
|
return is_active;
|
|
|
|
}
|
|
|
|
|
|
|
|
gui_size
|
|
|
|
gui_panel_selector(struct gui_panel *panel, const char *items[],
|
|
|
|
gui_size item_count, gui_size item_current)
|
|
|
|
{
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_size text_len;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_float label_x, label_y;
|
|
|
|
gui_float label_w, label_h;
|
2015-03-23 19:18:18 +03:00
|
|
|
|
2015-03-20 12:58:11 +03:00
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_button button;
|
2015-03-23 19:18:18 +03:00
|
|
|
const struct gui_config *config;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_bool button_up_clicked, button_down_clicked;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(items);
|
|
|
|
assert(item_count);
|
|
|
|
assert(item_current < item_count);
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return 0;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(panel->out, bounds.x, bounds.y, bounds.w, bounds.h,
|
2015-03-20 12:58:11 +03:00
|
|
|
config->colors[GUI_COLOR_SELECTOR_BORDER]);
|
2015-04-16 14:05:51 +03:00
|
|
|
gui_buffer_push_rect(panel->out, bounds.x + 1, bounds.y + 1, bounds.w - 2, bounds.h - 2,
|
|
|
|
config->colors[GUI_COLOR_SELECTOR]);
|
2015-03-20 12:58:11 +03:00
|
|
|
|
2015-04-16 21:05:43 +03:00
|
|
|
button.border = 1;
|
2015-03-20 12:58:11 +03:00
|
|
|
button.y = bounds.y;
|
|
|
|
button.h = bounds.h / 2;
|
2015-04-16 23:04:34 +03:00
|
|
|
button.w = bounds.h - config->item_padding.x;
|
|
|
|
button.x = bounds.x + bounds.w - button.w;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.pad_x = MAX(3, button.h - panel->font.height);
|
|
|
|
button.pad_y = MAX(3, button.h - panel->font.height);
|
2015-04-10 19:35:17 +03:00
|
|
|
button.behavior = GUI_BUTTON_DEFAULT;
|
2015-03-20 12:58:11 +03:00
|
|
|
button.background = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
|
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
2015-04-03 22:09:21 +03:00
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.highlight_content = config->colors[GUI_COLOR_TEXT];
|
2015-03-23 19:18:18 +03:00
|
|
|
button_up_clicked = gui_widget_button_triangle(panel->out, &button, GUI_UP, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
button.y = bounds.y + button.h;
|
2015-03-23 19:18:18 +03:00
|
|
|
button_down_clicked = gui_widget_button_triangle(panel->out, &button, GUI_DOWN, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
item_current = (button_down_clicked && item_current < item_count-1) ? item_current+1:
|
|
|
|
(button_up_clicked && item_current > 0) ? item_current-1 : item_current;
|
|
|
|
|
|
|
|
label_x = bounds.x + config->item_padding.x;
|
|
|
|
label_y = bounds.y + config->item_padding.y;
|
|
|
|
label_w = bounds.w - (button.w + 2 * config->item_padding.x);
|
|
|
|
label_h = bounds.h - 2 * config->item_padding.y;
|
|
|
|
text_len = strsiz(items[item_current]);
|
2015-04-16 14:05:51 +03:00
|
|
|
gui_buffer_push_text(panel->out, panel->font.user, label_x, label_y, label_w, label_h,
|
2015-04-15 15:37:19 +03:00
|
|
|
(const gui_char*)items[item_current], text_len,
|
2015-04-16 14:05:51 +03:00
|
|
|
config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
|
2015-03-20 12:58:11 +03:00
|
|
|
return item_current;
|
2015-03-14 19:05:30 +03:00
|
|
|
}
|
|
|
|
|
2015-03-11 20:17:37 +03:00
|
|
|
gui_int
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_panel_plot(struct gui_panel *panel, const gui_float *values, gui_size count)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_plot plot;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(values);
|
|
|
|
assert(count);
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return -1;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return -1;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
|
|
|
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];
|
2015-03-11 20:17:37 +03:00
|
|
|
plot.highlight = config->colors[GUI_COLOR_PLOT_HIGHLIGHT];
|
2015-03-23 19:18:18 +03:00
|
|
|
return gui_widget_plot(panel->out, &plot, panel->in);
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
gui_int
|
2015-03-11 16:00:59 +03:00
|
|
|
gui_panel_histo(struct gui_panel *panel, const gui_float *values, gui_size count)
|
2015-03-10 15:50:27 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
struct gui_histo histo;
|
2015-03-13 00:53:28 +03:00
|
|
|
const struct gui_config *config;
|
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(panel->config);
|
|
|
|
assert(panel->out);
|
|
|
|
assert(values);
|
|
|
|
assert(count);
|
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
if (!panel || !panel->config || !panel->out) return -1;
|
2015-03-27 17:18:38 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return -1;
|
2015-03-13 00:53:28 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
config = panel->config;
|
2015-03-10 15:50:27 +03:00
|
|
|
|
|
|
|
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.values = values;
|
2015-03-16 11:51:33 +03:00
|
|
|
histo.value_count = count;
|
2015-03-10 15:50:27 +03:00
|
|
|
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];
|
2015-03-23 19:18:18 +03:00
|
|
|
return gui_widget_histo(panel->out, &histo, panel->in);
|
2015-03-10 15:50:27 +03:00
|
|
|
}
|
|
|
|
|
2015-03-30 18:31:55 +03:00
|
|
|
gui_bool
|
2015-04-03 14:21:45 +03:00
|
|
|
gui_panel_tab_begin(struct gui_panel *panel, gui_tab *tab, const char *title)
|
2015-03-30 18:31:55 +03:00
|
|
|
{
|
|
|
|
struct gui_rect bounds;
|
|
|
|
gui_float old_height;
|
|
|
|
gui_size old_cols;
|
|
|
|
gui_flags flags;
|
2015-04-03 16:41:58 +03:00
|
|
|
gui_bool min;
|
2015-03-30 18:31:55 +03:00
|
|
|
|
|
|
|
assert(panel);
|
|
|
|
assert(tab);
|
2015-04-03 14:21:45 +03:00
|
|
|
if (!panel || !tab) return gui_true;
|
2015-04-03 22:36:07 +03:00
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN))
|
|
|
|
return gui_false;
|
2015-03-30 18:31:55 +03:00
|
|
|
|
|
|
|
old_height = panel->row_height;
|
|
|
|
old_cols = panel->row_columns;
|
2015-03-31 19:29:45 +03:00
|
|
|
panel->index = 0;
|
|
|
|
panel->row_columns = 1;
|
|
|
|
panel->row_height = 0;
|
2015-03-30 18:31:55 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
panel->row_columns = old_cols;
|
2015-03-31 19:29:45 +03:00
|
|
|
panel->row_height = old_height;
|
2015-04-03 16:41:58 +03:00
|
|
|
min = tab->minimized;
|
2015-03-30 18:31:55 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_panel_init(tab, panel->config, &panel->font);
|
2015-04-03 16:41:58 +03:00
|
|
|
tab->minimized = min;
|
2015-04-07 19:37:06 +03:00
|
|
|
flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_TAB;
|
2015-03-30 18:31:55 +03:00
|
|
|
gui_panel_begin(tab, panel->out, panel->in, title,
|
2015-03-31 19:29:45 +03:00
|
|
|
bounds.x, bounds.y + 1, bounds.w, null_rect.h, flags);
|
2015-03-30 18:31:55 +03:00
|
|
|
return tab->minimized;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_panel_tab_end(struct gui_panel *panel, struct gui_panel *tab)
|
|
|
|
{
|
2015-03-31 19:29:45 +03:00
|
|
|
assert(tab);
|
2015-04-10 19:35:17 +03:00
|
|
|
assert(panel);
|
|
|
|
if (!panel || !tab || panel->minimized || (panel->flags & GUI_PANEL_HIDDEN))
|
|
|
|
return;
|
|
|
|
|
2015-03-30 18:31:55 +03:00
|
|
|
gui_panel_end(tab);
|
|
|
|
panel->at_y -= panel->row_height;
|
|
|
|
panel->at_y += tab->height + tab->config->item_spacing.y;
|
|
|
|
}
|
|
|
|
|
2015-03-31 19:29:45 +03:00
|
|
|
void
|
2015-04-03 14:21:45 +03:00
|
|
|
gui_panel_group_begin(struct gui_panel *panel, gui_group *group, const char *title)
|
2015-03-31 19:29:45 +03:00
|
|
|
{
|
|
|
|
gui_flags flags;
|
2015-04-03 16:41:58 +03:00
|
|
|
gui_float offset;
|
2015-04-10 19:35:17 +03:00
|
|
|
struct gui_rect bounds;
|
2015-04-03 16:41:58 +03:00
|
|
|
|
2015-03-31 19:29:45 +03:00
|
|
|
assert(panel);
|
|
|
|
assert(group);
|
2015-04-10 19:35:17 +03:00
|
|
|
if (!panel || !group || (panel->flags & GUI_PANEL_HIDDEN) || panel->minimized)
|
|
|
|
return;
|
|
|
|
|
2015-04-03 16:41:58 +03:00
|
|
|
offset = group->offset;
|
2015-03-31 19:29:45 +03:00
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_panel_init(group, panel->config, &panel->font);
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-03 16:41:58 +03:00
|
|
|
group->offset = offset;
|
2015-04-10 19:35:17 +03:00
|
|
|
flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB;
|
2015-03-31 19:29:45 +03:00
|
|
|
gui_panel_begin(group, panel->out, panel->in, title,
|
|
|
|
bounds.x, bounds.y, bounds.w, bounds.h, flags);
|
|
|
|
}
|
|
|
|
|
2015-04-03 14:21:45 +03:00
|
|
|
void
|
|
|
|
gui_panel_group_end(struct gui_panel *panel, gui_group* group)
|
2015-03-31 19:29:45 +03:00
|
|
|
{
|
|
|
|
assert(panel);
|
|
|
|
assert(group);
|
2015-04-03 14:21:45 +03:00
|
|
|
if (!panel || !group) return;
|
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
|
2015-03-31 19:29:45 +03:00
|
|
|
gui_panel_end(group);
|
|
|
|
}
|
|
|
|
|
|
|
|
gui_size
|
2015-04-03 14:21:45 +03:00
|
|
|
gui_panel_shelf_begin(struct gui_panel *panel, gui_shelf *shelf,
|
|
|
|
const char *tabs[], gui_size size, gui_size active)
|
2015-03-31 19:29:45 +03:00
|
|
|
{
|
|
|
|
const struct gui_config *config;
|
|
|
|
gui_float header_x, header_y;
|
|
|
|
gui_float header_w, header_h;
|
2015-04-10 19:35:17 +03:00
|
|
|
struct gui_rect bounds;
|
2015-03-31 19:29:45 +03:00
|
|
|
gui_float item_width;
|
2015-04-03 16:41:58 +03:00
|
|
|
gui_float offset;
|
2015-04-10 19:35:17 +03:00
|
|
|
gui_flags flags;
|
|
|
|
gui_size i;
|
2015-03-31 19:29:45 +03:00
|
|
|
|
|
|
|
assert(panel);
|
|
|
|
assert(tabs);
|
|
|
|
assert(shelf);
|
2015-04-03 14:21:45 +03:00
|
|
|
assert(active < size);
|
|
|
|
if (!panel || !shelf || !tabs || active >= size)
|
|
|
|
return active;
|
2015-03-31 19:29:45 +03:00
|
|
|
if ((panel->flags & GUI_PANEL_HIDDEN) || panel->minimized)
|
2015-04-03 14:21:45 +03:00
|
|
|
return active;
|
2015-03-31 19:29:45 +03:00
|
|
|
|
|
|
|
config = panel->config;
|
|
|
|
gui_panel_alloc_space(&bounds, panel);
|
|
|
|
|
|
|
|
header_x = bounds.x;
|
|
|
|
header_y = bounds.y;
|
|
|
|
header_w = bounds.w;
|
2015-04-15 15:37:19 +03:00
|
|
|
header_h = config->panel_padding.y + 3 * config->item_padding.y + panel->font.height;
|
2015-04-03 22:36:07 +03:00
|
|
|
item_width = (header_w - (gui_float)size) / (gui_float)size;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-03 14:21:45 +03:00
|
|
|
for (i = 0; i < size; i++) {
|
2015-03-31 19:29:45 +03:00
|
|
|
struct gui_button button;
|
|
|
|
button.y = header_y;
|
|
|
|
button.h = header_h;
|
2015-04-03 22:36:07 +03:00
|
|
|
button.x = header_x + ((gui_float)i * (item_width + 1));
|
2015-03-31 19:29:45 +03:00
|
|
|
button.w = item_width;
|
2015-04-15 15:37:19 +03:00
|
|
|
button.border = 1;
|
2015-03-31 19:29:45 +03:00
|
|
|
button.pad_x = config->item_padding.x;
|
|
|
|
button.pad_y = config->item_padding.y;
|
2015-04-10 19:35:17 +03:00
|
|
|
button.behavior = GUI_BUTTON_DEFAULT;
|
|
|
|
button.background = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
|
|
|
|
button.content = config->colors[GUI_COLOR_TEXT];
|
|
|
|
button.highlight = config->colors[GUI_COLOR_BUTTON];
|
|
|
|
button.highlight_content = config->colors[GUI_COLOR_TEXT];
|
|
|
|
if (active != i) {
|
2015-04-03 22:36:07 +03:00
|
|
|
button.y += config->item_padding.y;
|
|
|
|
button.h -= config->item_padding.y;
|
2015-03-31 19:29:45 +03:00
|
|
|
}
|
|
|
|
if (gui_widget_button_text(panel->out, &button, tabs[i], strsiz(tabs[i]),
|
2015-04-15 15:37:19 +03:00
|
|
|
&panel->font, panel->in)) active = i;
|
2015-03-31 19:29:45 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
bounds.y += header_h;
|
|
|
|
bounds.h -= header_h;
|
2015-04-03 16:41:58 +03:00
|
|
|
offset = shelf->offset;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_panel_init(shelf, panel->config, &panel->font);
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-03 16:41:58 +03:00
|
|
|
shelf->offset = offset;
|
2015-03-31 19:29:45 +03:00
|
|
|
flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB;
|
|
|
|
gui_panel_begin(shelf, panel->out, panel->in, NULL,
|
|
|
|
bounds.x, bounds.y, bounds.w, bounds.h, flags);
|
2015-04-03 14:21:45 +03:00
|
|
|
return active;
|
2015-03-31 19:29:45 +03:00
|
|
|
}
|
|
|
|
|
2015-04-03 14:21:45 +03:00
|
|
|
void
|
|
|
|
gui_panel_shelf_end(struct gui_panel *panel, gui_shelf *shelf)
|
2015-03-31 19:29:45 +03:00
|
|
|
{
|
|
|
|
assert(panel);
|
2015-04-03 14:21:45 +03:00
|
|
|
assert(shelf);
|
|
|
|
if (!panel || !shelf) return;
|
|
|
|
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return;
|
|
|
|
gui_panel_end(shelf);
|
2015-03-31 19:29:45 +03:00
|
|
|
}
|
|
|
|
|
2015-03-27 19:19:49 +03:00
|
|
|
void
|
2015-03-16 16:02:47 +03:00
|
|
|
gui_panel_end(struct gui_panel *panel)
|
2015-03-09 22:04:45 +03:00
|
|
|
{
|
2015-03-20 12:58:11 +03:00
|
|
|
const struct gui_config *config;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(panel);
|
2015-03-27 19:19:49 +03:00
|
|
|
if (!panel) return;
|
|
|
|
if (panel->flags & GUI_PANEL_HIDDEN) return;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_pop_clip(panel->out);
|
2015-03-20 12:58:11 +03:00
|
|
|
panel->at_y += panel->row_height;
|
|
|
|
|
|
|
|
config = panel->config;
|
2015-03-16 11:51:33 +03:00
|
|
|
if (panel->flags & GUI_PANEL_SCROLLBAR && !panel->minimized) {
|
2015-03-20 12:58:11 +03:00
|
|
|
gui_float panel_y;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
struct gui_scroll scroll;
|
2015-03-16 11:51:33 +03:00
|
|
|
scroll.x = panel->x + panel->width;
|
2015-03-20 12:58:11 +03:00
|
|
|
scroll.y = (panel->flags & GUI_PANEL_BORDER) ? panel->y + 1 : panel->y;
|
2015-04-10 19:35:17 +03:00
|
|
|
scroll.y += panel->header_height;
|
2015-03-20 12:58:11 +03:00
|
|
|
scroll.w = config->scrollbar_width;
|
2015-04-10 19:35:17 +03:00
|
|
|
scroll.h = panel->height;
|
2015-03-16 16:02:47 +03:00
|
|
|
scroll.offset = panel->offset;
|
|
|
|
scroll.step = panel->height * 0.25f;
|
2015-03-16 11:51:33 +03:00
|
|
|
scroll.background = config->colors[GUI_COLOR_SCROLLBAR];
|
|
|
|
scroll.foreground = config->colors[GUI_COLOR_SCROLLBAR_CURSOR];
|
2015-03-16 16:02:47 +03:00
|
|
|
scroll.border = config->colors[GUI_COLOR_SCROLLBAR_BORDER];
|
2015-04-10 19:35:17 +03:00
|
|
|
if (panel->flags & GUI_PANEL_BORDER)
|
|
|
|
scroll.h -= 1;
|
2015-04-07 19:37:06 +03:00
|
|
|
scroll.target = (panel->at_y - panel->y) - panel->header_height;
|
2015-03-24 15:08:42 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
panel->offset = (gui_float)gui_widget_scroll(panel->out, &scroll, panel->in);
|
2015-03-20 12:58:11 +03:00
|
|
|
panel_y = panel->y + panel->height + panel->header_height - config->panel_padding.y;
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(panel->out, panel->x, panel_y, panel->width, config->panel_padding.y,
|
2015-03-23 19:18:18 +03:00
|
|
|
config->colors[GUI_COLOR_PANEL]);
|
2015-03-24 19:12:42 +03:00
|
|
|
} else panel->height = panel->at_y - panel->y;
|
2015-03-16 16:02:47 +03:00
|
|
|
|
|
|
|
if (panel->flags & GUI_PANEL_BORDER) {
|
2015-03-20 12:58:11 +03:00
|
|
|
const gui_float width = (panel->flags & GUI_PANEL_SCROLLBAR) ?
|
|
|
|
panel->width + config->scrollbar_width : panel->width;
|
2015-03-24 19:12:42 +03:00
|
|
|
const gui_float padding_y = (panel->minimized) ?
|
|
|
|
panel->y + panel->header_height:
|
|
|
|
(panel->flags & GUI_PANEL_SCROLLBAR) ?
|
2015-03-23 19:18:18 +03:00
|
|
|
panel->y + panel->height + panel->header_height:
|
2015-03-24 19:12:42 +03:00
|
|
|
panel->y + panel->height + config->item_padding.y;
|
2015-03-23 19:18:18 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_line(panel->out, panel->x, padding_y, panel->x + width,
|
2015-03-24 15:08:42 +03:00
|
|
|
padding_y, config->colors[GUI_COLOR_BORDER]);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_line(panel->out, panel->x, panel->y, panel->x,
|
2015-03-16 16:02:47 +03:00
|
|
|
padding_y, config->colors[GUI_COLOR_BORDER]);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_line(panel->out, panel->x + width, panel->y, panel->x + width,
|
2015-03-16 16:02:47 +03:00
|
|
|
padding_y, config->colors[GUI_COLOR_BORDER]);
|
2015-03-16 11:51:33 +03:00
|
|
|
}
|
2015-03-08 21:19:07 +03:00
|
|
|
}
|
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
struct gui_context*
|
|
|
|
gui_new(const struct gui_memory *memory, const struct gui_input *input)
|
|
|
|
{
|
|
|
|
void *ptr;
|
|
|
|
gui_size size;
|
|
|
|
struct gui_memory buffer;
|
|
|
|
struct gui_context *ctx;
|
|
|
|
static const gui_size align_panels = ALIGNOF(struct gui_context_panel);
|
2015-04-15 15:37:19 +03:00
|
|
|
static const gui_size align_list = ALIGNOF(struct gui_command_list**);
|
2015-03-30 01:51:07 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(memory);
|
|
|
|
assert(input);
|
|
|
|
if (!memory || !input)
|
|
|
|
return NULL;
|
2015-03-23 19:18:18 +03:00
|
|
|
|
|
|
|
ctx = memory->memory;
|
|
|
|
ctx->width = 0;
|
|
|
|
ctx->height = 0;
|
|
|
|
ctx->input = input;
|
2015-03-24 19:12:42 +03:00
|
|
|
ctx->active = NULL;
|
2015-03-30 15:07:39 +03:00
|
|
|
ctx->free_list = NULL;
|
|
|
|
ctx->stack_begin = NULL;
|
|
|
|
ctx->stack_end = NULL;
|
2015-03-23 19:18:18 +03:00
|
|
|
|
|
|
|
ptr = (gui_byte*)memory->memory + sizeof(struct gui_context);
|
2015-03-30 15:07:39 +03:00
|
|
|
ctx->panel_pool = ALIGN(ptr, align_panels);
|
2015-03-23 19:18:18 +03:00
|
|
|
ctx->panel_capacity = memory->max_panels;
|
|
|
|
ctx->panel_size = 0;
|
|
|
|
|
|
|
|
size = sizeof(struct gui_context_panel) * memory->max_panels;
|
2015-03-30 15:07:39 +03:00
|
|
|
ptr = (gui_byte*)ctx->panel_pool + size;
|
|
|
|
ctx->output_list = ALIGN(ptr, align_list);
|
2015-03-23 19:18:18 +03:00
|
|
|
|
2015-04-15 15:37:19 +03:00
|
|
|
size = sizeof(struct gui_command_list*) * memory->max_panels;
|
2015-03-30 15:07:39 +03:00
|
|
|
buffer.memory = (gui_byte*)ctx->output_list + size;
|
2015-03-23 19:18:18 +03:00
|
|
|
buffer.size = memory->size - (gui_size)((gui_byte*)buffer.memory - (gui_byte*)memory->memory);
|
2015-04-05 18:19:44 +03:00
|
|
|
buffer.max_depth = memory->max_depth;
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_output_begin(&ctx->global_buffer, &buffer);
|
|
|
|
return ctx;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct gui_context_panel*
|
|
|
|
gui_alloc_panel(struct gui_context *ctx)
|
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
2015-03-23 19:18:18 +03:00
|
|
|
if (ctx->free_list) {
|
|
|
|
struct gui_context_panel *panel;
|
|
|
|
panel = ctx->free_list;
|
|
|
|
ctx->free_list = panel->next;
|
|
|
|
panel->next = NULL;
|
2015-03-30 18:31:55 +03:00
|
|
|
panel->prev = NULL;
|
2015-03-23 19:18:18 +03:00
|
|
|
return panel;
|
|
|
|
} else if (ctx->panel_capacity) {
|
|
|
|
ctx->panel_capacity--;
|
2015-03-30 15:07:39 +03:00
|
|
|
return &ctx->panel_pool[ctx->panel_capacity];
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gui_free_panel(struct gui_context *ctx, struct gui_context_panel *panel)
|
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
|
|
|
assert(panel);
|
2015-03-23 19:18:18 +03:00
|
|
|
panel->next = ctx->free_list;
|
|
|
|
ctx->free_list = panel;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-03-30 15:07:39 +03:00
|
|
|
gui_stack_push(struct gui_context *ctx, struct gui_context_panel *panel)
|
2015-03-23 19:18:18 +03:00
|
|
|
{
|
2015-03-30 18:31:55 +03:00
|
|
|
if (!ctx->stack_begin) {
|
2015-03-30 15:07:39 +03:00
|
|
|
ctx->stack_begin = panel;
|
|
|
|
ctx->stack_end = panel;
|
|
|
|
return;
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-30 15:07:39 +03:00
|
|
|
ctx->stack_end->next = panel;
|
|
|
|
panel->prev = ctx->stack_end;
|
|
|
|
panel->next = NULL;
|
|
|
|
ctx->stack_end = panel;
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-03-30 15:07:39 +03:00
|
|
|
gui_stack_remove(struct gui_context *ctx, struct gui_context_panel *panel)
|
2015-03-23 19:18:18 +03:00
|
|
|
{
|
2015-03-30 15:07:39 +03:00
|
|
|
if (panel->prev)
|
|
|
|
panel->prev->next = panel->next;
|
|
|
|
if (panel->next)
|
|
|
|
panel->next->prev = panel->prev;
|
|
|
|
if (ctx->stack_begin == panel)
|
|
|
|
ctx->stack_begin = panel->next;
|
2015-03-30 18:31:55 +03:00
|
|
|
if (ctx->stack_end == panel)
|
|
|
|
ctx->stack_end = panel->prev;
|
2015-03-30 15:07:39 +03:00
|
|
|
panel->next = NULL;
|
|
|
|
panel->prev = NULL;
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
struct gui_panel*
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_new_panel(struct gui_context *ctx, gui_float x, gui_float y, gui_float w, gui_float h,
|
2015-03-23 19:18:18 +03:00
|
|
|
const struct gui_config *config, const struct gui_font *font)
|
|
|
|
{
|
|
|
|
struct gui_context_panel *cpanel;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
|
|
|
assert(config);
|
|
|
|
assert(font);
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!ctx || !config || !font)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
cpanel = gui_alloc_panel(ctx);
|
|
|
|
if (!cpanel) return NULL;
|
|
|
|
cpanel->x = x, cpanel->y = y;
|
|
|
|
cpanel->w = w, cpanel->h = h;
|
2015-03-30 15:07:39 +03:00
|
|
|
cpanel->next = NULL; cpanel->prev = NULL;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-30 15:07:39 +03:00
|
|
|
gui_panel_init(&cpanel->panel, config, font);
|
|
|
|
gui_stack_push(ctx, cpanel);
|
|
|
|
ctx->panel_size++;
|
2015-03-23 19:18:18 +03:00
|
|
|
return &cpanel->panel;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_del_panel(struct gui_context *ctx, struct gui_panel *panel)
|
2015-03-23 19:18:18 +03:00
|
|
|
{
|
|
|
|
struct gui_context_panel *cpanel;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
|
|
|
assert(panel);
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!ctx || !panel) return;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-26 00:52:25 +03:00
|
|
|
cpanel = (struct gui_context_panel*)panel;
|
2015-03-30 15:07:39 +03:00
|
|
|
gui_stack_remove(ctx, cpanel);
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_free_panel(ctx, cpanel);
|
2015-03-30 15:07:39 +03:00
|
|
|
ctx->panel_size--;
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_begin(struct gui_context *ctx, gui_float w, gui_float h)
|
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!ctx) return;
|
|
|
|
ctx->width = w;
|
|
|
|
ctx->height = h;
|
|
|
|
}
|
|
|
|
|
2015-04-07 19:47:32 +03:00
|
|
|
struct gui_vec2
|
|
|
|
gui_get_panel_position(const struct gui_context *ctx, const struct gui_panel *panel)
|
|
|
|
{
|
|
|
|
struct gui_vec2 pos;
|
|
|
|
const struct gui_context_panel *cpanel;
|
|
|
|
|
|
|
|
assert(ctx && panel);
|
|
|
|
pos.x = 0; pos.y = 0;
|
|
|
|
if (!ctx || !panel) return pos;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-07 19:47:32 +03:00
|
|
|
cpanel = (const struct gui_context_panel*)panel;
|
|
|
|
pos.x = cpanel->x;
|
|
|
|
pos.y = cpanel->y;
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct gui_vec2
|
|
|
|
gui_get_panel_size(const struct gui_context *ctx, const struct gui_panel *panel)
|
|
|
|
{
|
|
|
|
struct gui_vec2 size;
|
|
|
|
const struct gui_context_panel *cpanel;
|
|
|
|
|
|
|
|
assert(ctx && panel);
|
|
|
|
size.x = 0; size.y = 0;
|
|
|
|
if (!ctx || !panel) return size;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-07 19:47:32 +03:00
|
|
|
cpanel = (const struct gui_context_panel*)panel;
|
|
|
|
size.x = cpanel->w;
|
|
|
|
size.y = cpanel->h;
|
|
|
|
return size;
|
|
|
|
}
|
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_bool
|
|
|
|
gui_begin_panel(struct gui_context *ctx, struct gui_panel *panel,
|
|
|
|
const char *title, gui_flags flags)
|
|
|
|
{
|
2015-03-24 19:12:42 +03:00
|
|
|
gui_bool active, inpanel;
|
|
|
|
const struct gui_input *in;
|
2015-03-23 19:18:18 +03:00
|
|
|
struct gui_context_panel *cpanel;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_buffer *out;
|
|
|
|
struct gui_command_buffer *global;
|
2015-03-30 01:51:07 +03:00
|
|
|
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
|
|
|
assert(panel);
|
|
|
|
assert(title);
|
2015-03-30 01:51:07 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!ctx || !panel || !title)
|
|
|
|
return gui_false;
|
2015-03-27 17:01:23 +03:00
|
|
|
if (panel->flags & GUI_PANEL_HIDDEN)
|
|
|
|
return gui_false;
|
2015-04-10 19:35:17 +03:00
|
|
|
if (!(flags & GUI_PANEL_TAB))
|
|
|
|
flags |= GUI_PANEL_SCROLLBAR;
|
2015-03-23 19:18:18 +03:00
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
in = ctx->input;
|
2015-03-26 00:52:25 +03:00
|
|
|
cpanel = (struct gui_context_panel*)panel;
|
2015-03-24 19:12:42 +03:00
|
|
|
inpanel = INBOX(in->mouse_prev.x,in->mouse_prev.y, cpanel->x, cpanel->y, cpanel->w, cpanel->h);
|
2015-03-30 18:31:55 +03:00
|
|
|
if (in->mouse_down && in->mouse_clicked && inpanel && cpanel != ctx->active) {
|
2015-03-30 15:07:39 +03:00
|
|
|
struct gui_context_panel *iter = cpanel->next;
|
|
|
|
while (iter) {
|
2015-04-08 12:54:33 +03:00
|
|
|
if (!iter->panel.minimized)
|
|
|
|
if (INBOX(in->mouse_prev.x, in->mouse_prev.y, iter->x, iter->y, iter->w, iter->h))
|
|
|
|
break;
|
2015-03-30 15:07:39 +03:00
|
|
|
iter = iter->next;
|
2015-03-24 21:28:59 +03:00
|
|
|
}
|
2015-03-30 15:07:39 +03:00
|
|
|
if (!iter) {
|
|
|
|
gui_stack_remove(ctx, cpanel);
|
|
|
|
gui_stack_push(ctx, cpanel);
|
2015-03-24 21:28:59 +03:00
|
|
|
ctx->active = cpanel;
|
|
|
|
}
|
2015-03-24 19:12:42 +03:00
|
|
|
}
|
|
|
|
|
2015-04-07 19:37:06 +03:00
|
|
|
if (ctx->active == cpanel && (flags & GUI_PANEL_MOVEABLE)) {
|
2015-03-25 16:19:27 +03:00
|
|
|
gui_bool incursor;
|
2015-03-24 19:12:42 +03:00
|
|
|
const gui_float header_x = cpanel->x;
|
|
|
|
const gui_float header_y = cpanel->y;
|
|
|
|
const gui_float header_w = cpanel->w;
|
|
|
|
const gui_float header_h = cpanel->panel.header_height;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-24 19:12:42 +03:00
|
|
|
incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,header_x, header_y, header_w, header_h);
|
2015-03-25 16:19:27 +03:00
|
|
|
if (in->mouse_down && incursor) {
|
2015-03-24 19:12:42 +03:00
|
|
|
cpanel->x = CLAMP(0, cpanel->x + in->mouse_delta.x, ctx->width - cpanel->w);
|
|
|
|
cpanel->y = CLAMP(0, cpanel->y + in->mouse_delta.y, ctx->height - cpanel->h);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-25 16:15:42 +03:00
|
|
|
if (ctx->active == cpanel && (flags & GUI_PANEL_SCALEABLE) && (flags & GUI_PANEL_SCROLLBAR)) {
|
|
|
|
const struct gui_config *config = cpanel->panel.config;
|
2015-03-25 16:19:27 +03:00
|
|
|
gui_bool incursor;
|
2015-03-25 16:15:42 +03:00
|
|
|
const gui_float scaler_x = cpanel->x;
|
|
|
|
const gui_float scaler_y = (cpanel->y + cpanel->h) - config->scaler_size.y;
|
|
|
|
const gui_float scaler_w = config->scaler_size.x;
|
|
|
|
const gui_float scaler_h = config->scaler_size.y;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-03-25 16:15:42 +03:00
|
|
|
incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,scaler_x, scaler_y, scaler_w, scaler_h);
|
2015-03-25 16:19:27 +03:00
|
|
|
if (in->mouse_down && incursor) {
|
2015-04-17 12:50:47 +03:00
|
|
|
gui_float min_x = config->panel_min_size.x;
|
|
|
|
gui_float min_y = config->panel_min_size.y;
|
2015-03-25 16:15:42 +03:00
|
|
|
cpanel->x = CLAMP(0, cpanel->x + in->mouse_delta.x, ctx->width - cpanel->w);
|
2015-04-17 12:50:47 +03:00
|
|
|
cpanel->w = CLAMP(min_x, cpanel->w - in->mouse_delta.x, ctx->width - cpanel->x);
|
|
|
|
cpanel->h = CLAMP(min_y, cpanel->h + in->mouse_delta.y, ctx->height - cpanel->y);
|
2015-03-25 16:15:42 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
global = &ctx->global_buffer;
|
2015-04-02 21:09:03 +03:00
|
|
|
out = &ctx->current_buffer;
|
2015-04-15 15:37:19 +03:00
|
|
|
out->cmds.begin = global->cmds.end;
|
2015-04-16 16:31:11 +03:00
|
|
|
out->cmds.end = out->cmds.begin;
|
|
|
|
out->cmds.capacity = global->cmds.capacity - global->cmds.size;
|
2015-04-15 15:37:19 +03:00
|
|
|
out->cmds.count = 0;
|
|
|
|
out->cmds.needed = 0;
|
|
|
|
out->cmds.size = 0;
|
2015-04-05 18:19:44 +03:00
|
|
|
out->clip_size = global->clip_size;
|
2015-03-24 15:08:42 +03:00
|
|
|
out->clips = global->clips;
|
|
|
|
out->clip_capacity = global->clip_capacity;
|
2015-03-30 18:31:55 +03:00
|
|
|
in = (ctx->active == cpanel) ? ctx->input : NULL;
|
2015-03-31 19:29:45 +03:00
|
|
|
return gui_panel_begin(panel, out, in, title, cpanel->x, cpanel->y,
|
|
|
|
cpanel->w, cpanel->h, flags);
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_end_panel(struct gui_context *ctx, struct gui_panel *panel,
|
|
|
|
struct gui_memory_status *status)
|
|
|
|
{
|
|
|
|
struct gui_context_panel *cpanel;
|
2015-04-15 15:37:19 +03:00
|
|
|
struct gui_command_buffer *global;
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
|
|
|
assert(panel);
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!ctx || !panel) return;
|
2015-03-26 00:52:25 +03:00
|
|
|
cpanel = (struct gui_context_panel*)panel;
|
2015-04-07 19:20:28 +03:00
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
gui_panel_end(panel);
|
2015-04-07 19:28:29 +03:00
|
|
|
if (!panel->minimized && ctx->active == cpanel && (panel->flags & GUI_PANEL_SCALEABLE) &&
|
2015-04-07 19:20:28 +03:00
|
|
|
(panel->flags & GUI_PANEL_SCROLLBAR)) {
|
|
|
|
const struct gui_config *config = panel->config;
|
|
|
|
struct gui_color col = config->colors[GUI_COLOR_SCALER];
|
|
|
|
const gui_float height = panel->height + panel->header_height;
|
2015-04-10 19:35:17 +03:00
|
|
|
|
2015-04-07 19:20:28 +03:00
|
|
|
gui_float scaler_x = panel->x + config->item_padding.x;
|
|
|
|
gui_float scaler_y = panel->y + height - config->scaler_size.y;
|
|
|
|
gui_float scaler_w = MAX(0, config->scaler_size.x - config->item_padding.x);
|
|
|
|
gui_float scaler_h = MAX(0, config->scaler_size.y - config->item_padding.y);
|
2015-04-15 15:37:19 +03:00
|
|
|
gui_buffer_push_rect(&ctx->current_buffer, scaler_x, scaler_y, scaler_w, scaler_h, col);
|
2015-04-07 19:20:28 +03:00
|
|
|
}
|
|
|
|
|
2015-03-23 19:18:18 +03:00
|
|
|
global = &ctx->global_buffer;
|
2015-04-15 15:37:19 +03:00
|
|
|
global->cmds.count += ctx->current_buffer.cmds.count;
|
|
|
|
global->cmds.needed += ctx->current_buffer.cmds.needed;
|
|
|
|
global->cmds.size += ctx->current_buffer.cmds.size;
|
|
|
|
global->cmds.end = ctx->current_buffer.cmds.end;
|
2015-04-02 21:09:03 +03:00
|
|
|
gui_output_end(&ctx->current_buffer, &cpanel->list, status);
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
gui_end(struct gui_context *ctx, struct gui_output *output,
|
|
|
|
struct gui_memory_status *status)
|
|
|
|
{
|
2015-03-27 18:54:23 +03:00
|
|
|
assert(ctx);
|
2015-03-23 19:18:18 +03:00
|
|
|
if (!ctx) return;
|
|
|
|
if (output) {
|
2015-03-30 15:07:39 +03:00
|
|
|
gui_size n = 0;
|
|
|
|
struct gui_context_panel *iter = ctx->stack_begin;
|
|
|
|
while (iter) {
|
2015-03-30 18:31:55 +03:00
|
|
|
if (!(iter->panel.flags & GUI_PANEL_HIDDEN))
|
|
|
|
ctx->output_list[n++] = &iter->list;
|
2015-03-30 15:07:39 +03:00
|
|
|
iter = iter->next;
|
|
|
|
}
|
2015-03-30 18:31:55 +03:00
|
|
|
output->list_size = n;
|
2015-03-30 15:07:39 +03:00
|
|
|
output->list = ctx->output_list;
|
2015-03-23 19:18:18 +03:00
|
|
|
}
|
|
|
|
gui_output_end(&ctx->global_buffer, NULL, status);
|
|
|
|
}
|
|
|
|
|