added buffering

This commit is contained in:
vurtun 2015-04-24 15:17:10 +02:00
parent b41897352e
commit 5fcdfe5dc0
4 changed files with 563 additions and 276 deletions

View File

@ -8,7 +8,7 @@ streamlined user development speed in mind.
## Features
- Immediate mode graphical user interface toolkit
- Written in C89 (ANSI C)
- Small codebase (~2kLOC)
- Small codebase (~2.5kLOC)
- Focus on portability and minimal internal state
- Suited for embedding into graphical applications
- No global hidden state
@ -37,8 +37,7 @@ streamlined user development speed in mind.
- Does NOT provide window management
- Does NOT provide input handling
- Does NOT provide a renderer backend
- Does NOT implement a font library
- Does NOT provide overlapping panels
- Does NOT implement a font library
Summary: It is only responsible for the actual user interface
## IMGUIs
@ -67,6 +66,30 @@ way provided to group widgets together. For this to change there is the panel
layer which is build on top of the widget layer and uses most of the widget API
internally to form groups of widgets into a layout.
### Font
### Canvas
The Canvas is the abstract drawing interface between the GUI toolkit
and the user and contains drawing callbacks for the primitives
scissor, line, rectangle, circle, triangle, bitmap and text which need to be
provided by the user. In addition to the drawing callbacks the canvas contains
font data and the width and height of the canvas drawing area.
Therefore the canvas is the heart of the toolkit and is probably the biggest
chunk of work to be done by the user.
### Commands
### Configuration
The gui toolkit provides a number of different attributes that can be
configured, like spacing, padding, size and color.
While the widget API even expects you to provide the configuration
for each and every widget the panel layer provides you with a set of
attributes in the `gui_config` structure. The structure either needs to be
filled by the user or can be setup with some default values by the function
`gui_default_config`. Modification on the fly to the `gui_config` struct is in
true immedate mode fashion possible and supported.
### Widgets
The minimal widget API provides a basic number of widgets and is designed for
uses cases where only a small number of basic widgets are needed without any kind of
@ -122,33 +145,8 @@ while (1) {
gui_panel_end(&panel);
}
```
## Canvas
The Canvas is the abstract drawing interface between the GUI toolkit
and the user and contains drawing callbacks for the primitives
scissor, line, rectangle, circle, triangle, bitmap and text which need to be
provided by the user. In addition to the drawing callbacks the canvas contains
font data and the width and height of the canvas drawing area.
Therefore the canvas is the heart of the toolkit and is probably the biggest
chunk of work to be done by the user.
## Configuration
The gui toolkit provides a number of different attributes that can be
configured, like spacing, padding, size and color.
While the widget API even expects you to provide the configuration
for each and every widget the panel layer provides you with a set of
attributes in the `gui_config` structure. The structure either needs to be
filled by the user or can be setup with some default values by the function
`gui_default_config`. Modification on the fly to the `gui_config` struct is in
true immedate mode fashion possible and supported.
## FAQ
#### Where is Widget X?
A number of basic widgets are provided but some of the more complex widgets like
comboboxes, tables and trees are not yet implemented. Maybe if I have more
time I will look into adding them. Except for comboboxes which are just
really hard to implement, but for a smaller datasets there is the selector
widget or you could combine a tab with a group and toggle buttons.
#### Where is the demo/example code?
The demo and example code can be found in the demo folder. For now there is
only example code for Linux with X11 and Xlib but a Win32, OpenGL and Directx
@ -182,7 +180,7 @@ to be as indepenedent and out of the users way as possible.
This means in practice a litte bit more work on the users behalf but grants a
lot more freedom especially because the toolkit is designed to be embeddable.
The font management on the other hand it is litte bit more tricky. In the beginning
The font management on the other hand is litte bit more tricky. In the beginning
the toolkit had some basic font handling but I removed it later. This is mainly
a question of if font handling should be part of a gui toolkit or not. As for a
framework the question would definitely be yes but for a toolkit library the
@ -190,22 +188,13 @@ question is not as easy. In the end the project does not have font handling
since there are already a number of font handling libraries in existence or even the
platform (Xlib, Win32) itself already provides a solution.
#### Why are my panels not overlapping properly while being moved?
Since every panel is directly drawn to screen if you have not implement buffering
there is no direct way for the toolkit to decide which panel has to be drawn at which
time. But the functionality can be easily implemented by buffering each drawing
call and managing a panel stack. The panel stack would keep the active panel
(`GUI_PANEL_ACTIVE`) at the top of the stack and keep the rest of the panel in
order and draw each panel from top to down. As for now the overlapping panels
are not implemented but if I have some time and it is a requested feature
I will implement a panel window manager.
## References
- [Tutorial from Jari Komppa about imgui libraries](http://www.johno.se/book/imgui.html)
- [Johannes 'johno' Norneby's article](http://iki.fi/sol/imgui/)
- [Casey Muratori's original introduction to imgui's](http:://mollyrocket.com/861?node=861)
- [Casey Muratori's imgui panel design(1/2)](http://mollyrocket.com/casey/stream_0019.html)
- [Casey Muratori's imgui panel design(2/2)](http://mollyrocket.com/casey/stream_0020.html)
- [Casey Muratori: Designing and Evaluation Reusable Components](http://mollyrocket.com/casey/stream_0028.html)
- [ImGui: The inspiration for this project](https://github.com/ocornut/imgui)
- [Nvidia's imgui toolkit](https://code.google.com/p/nvidia-widgets/)

View File

@ -13,7 +13,8 @@
/* macros */
#define MAX_BUFFER 64
#define MAX_DEPTH 4
#define MAX_MEMORY (16 * 1024)
#define MAX_PANELS 4
#define WIN_WIDTH 800
#define WIN_HEIGHT 600
#define DTIME 16
@ -61,7 +62,6 @@ struct XSurface {
Drawable drawable;
unsigned int w, h;
gui_size clip_depth;
struct gui_rect clips[MAX_DEPTH];
};
struct XWindow {
@ -214,18 +214,8 @@ surface_resize(XSurface *surf, unsigned int w, unsigned int h) {
}
static void
unify(struct gui_rect *clip, const struct gui_rect *a, const struct gui_rect *b)
surface_scissor(XSurface *surf, float x, float y, float w, float h)
{
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;
}
static void
surface_scissor(void *handle, gui_float x, gui_float y, gui_float w, gui_float h)
{
XSurface *surf = handle;
XRectangle clip_rect;
clip_rect.x = (short)x;
clip_rect.y = (short)y;
@ -237,43 +227,40 @@ surface_scissor(void *handle, gui_float x, gui_float y, gui_float w, gui_float h
}
static void
surface_draw_line(void *handle, gui_float x0, gui_float y0, gui_float x1, gui_float y1, struct gui_color col)
surface_draw_line(XSurface *surf, float x0, float y0, float x1, float y1, struct gui_color col)
{
XSurface *surf = handle;
unsigned long c = color_from_byte(col);
XSetForeground(surf->dpy, surf->gc, c);
XDrawLine(surf->dpy, surf->drawable, surf->gc, (int)x0, (int)y0, (int)x1, (int)y1);
}
static void
surface_draw_rect(void *handle, gui_float x, gui_float y, gui_float w, gui_float h, struct gui_color col)
surface_draw_rect(XSurface* surf, float x, float y, float w, float h, struct gui_color col)
{
XSurface *surf = handle;
unsigned long c = color_from_byte(col);
XSetForeground(surf->dpy, surf->gc, c);
XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h);
}
static void
surface_draw_triangle(void *handle, const struct gui_vec2 *src, struct gui_color col)
surface_draw_triangle(XSurface *surf, float x0, float y0, float x1, float y1,
float x2, float y2, struct gui_color col)
{
XPoint pnts[3];
XSurface *surf = handle;
unsigned long c = color_from_byte(col);
pnts[0].x = (short)src[0].x;
pnts[0].y = (short)src[0].y;
pnts[1].x = (short)src[1].x;
pnts[1].y = (short)src[1].y;
pnts[2].x = (short)src[2].x;
pnts[2].y = (short)src[2].y;
pnts[0].x = (short)x0;
pnts[0].y = (short)y0;
pnts[1].x = (short)x1;
pnts[1].y = (short)y1;
pnts[2].x = (short)x2;
pnts[2].y = (short)y2;
XSetForeground(surf->dpy, surf->gc, c);
XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin);
}
static void
surface_draw_circle(void *handle, gui_float x, gui_float y, gui_float w, gui_float h, struct gui_color col)
surface_draw_circle(XSurface *surf, float x, float y, float w, float h, struct gui_color col)
{
XSurface *surf = handle;
unsigned long c = color_from_byte(col);
XSetForeground(surf->dpy, surf->gc, c);
XFillArc(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y,
@ -281,12 +268,10 @@ surface_draw_circle(void *handle, gui_float x, gui_float y, gui_float w, gui_flo
}
static void
surface_draw_text(void *handle, gui_float x, gui_float y, gui_float w, gui_float h, const gui_char *text,
gui_size len, const struct gui_font *f, struct gui_color cbg, struct gui_color cfg)
surface_draw_text(XSurface *surf, float x, float y, float w, float h, const char *text,
size_t len, XFont *font, struct gui_color cbg, struct gui_color cfg)
{
int i, tx, ty, th, olen;
XSurface *surf = handle;
XFont *font = f->userdata;
unsigned long bg = color_from_byte(cbg);
unsigned long fg = color_from_byte(cfg);
@ -325,6 +310,49 @@ surface_del(XSurface *surf)
free(surf);
}
static void
draw(XSurface *surf, struct gui_command_list *list)
{
struct gui_command *cmd;
if (!list->count) return;
cmd = list->begin;
while (cmd != list->end) {
switch (cmd->type) {
case GUI_COMMAND_NOP: break;
case GUI_COMMAND_SCISSOR: {
struct gui_command_scissor *s = (void*)cmd;
surface_scissor(surf, s->x, s->y, s->w, s->h);
} break;
case GUI_COMMAND_LINE: {
struct gui_command_line *l = (void*)cmd;
surface_draw_line(surf, l->begin[0], l->begin[1], l->end[0],
l->end[1], l->color);
} break;
case GUI_COMMAND_RECT: {
struct gui_command_rect *r = (void*)cmd;
surface_draw_rect(surf, r->x, r->y, r->w, r->h, r->color);
} break;
case GUI_COMMAND_CIRCLE: {
struct gui_command_circle *c = (void*)cmd;
surface_draw_circle(surf, c->x, c->y, c->w, c->h, c->color);
} break;
case GUI_COMMAND_TRIANGLE: {
struct gui_command_triangle *t = (void*)cmd;
surface_draw_triangle(surf, t->a[0], t->a[1], t->b[0], t->b[1],
t->c[0], t->c[1], t->color);
} break;
case GUI_COMMAND_TEXT: {
struct gui_command_text *t = (void*)cmd;
surface_draw_text(surf, t->x, t->y, t->w, t->h, (const char*)t->string,
t->length, t->font, t->bg, t->fg);
} break;
default: break;
}
cmd = cmd->next;
}
}
static void
key(struct XWindow *xw, struct gui_input *in, XEvent *evt, gui_bool down)
{
@ -417,7 +445,7 @@ demo_panel(struct gui_panel *panel, struct demo *demo)
demo->slider = gui_panel_slider(&tab, 0, demo->slider, 10, 1.0f);
demo->prog = gui_panel_progress(&tab, demo->prog, 100, gui_true);
demo->item_cur = gui_panel_selector(&tab, items, LEN(items), demo->item_cur);
demo->spin_act = gui_panel_spinner(&tab, 0, &demo->spinner, 250, 10, demo->spin_act);
demo->spinner = gui_panel_spinner(&tab, 0, demo->spinner, 250, 10, &demo->spin_act);
demo->in_len = gui_panel_input(&tab, demo->in_buf, demo->in_len, MAX_BUFFER, &demo->in_act, GUI_INPUT_DEFAULT);
demo->group_offset = gui_panel_group_end(panel, &tab);
}
@ -428,19 +456,24 @@ main(int argc, char *argv[])
long dt;
long started;
gui_bool running = gui_true;
XWindow xw;
/* GUI */
gui_bool checked = gui_false;
gui_float value = 5.0f;
gui_size done = 20;
struct gui_input in;
struct gui_config config;
struct gui_canvas canvas;
struct gui_panel panel;
struct demo demo;
/* GUI */
struct gui_input in;
struct gui_font font_data;
struct gui_memory memory;
struct gui_context *ctx;
struct gui_config config;
struct gui_command_buffer buffer;
struct gui_command_list list;
struct gui_panel panel;
struct gui_canvas canvas;
/* Window */
XWindow xw;
XSurface *surf;
XFont *font;
UNUSED(argc); UNUSED(argv);
memset(&xw, 0, sizeof xw);
xw.dpy = XOpenDisplay(NULL);
@ -460,32 +493,27 @@ main(int argc, char *argv[])
XGetWindowAttributes(xw.dpy, xw.win, &xw.attr);
xw.width = (unsigned int)xw.attr.width;
xw.height = (unsigned int)xw.attr.height;
surf = surface_create(xw.dpy, xw.screen, xw.win, xw.width, xw.height);
font = font_create(xw.dpy, "fixed");
/* GUI */
canvas.userdata = surface_create(xw.dpy, xw.screen, xw.win, xw.width, xw.height);
canvas.width = xw.width;
canvas.height = xw.height;
canvas.scissor = surface_scissor;
canvas.draw_line = surface_draw_line;
canvas.draw_rect = surface_draw_rect;
canvas.draw_circle = surface_draw_circle;
canvas.draw_triangle = surface_draw_triangle;
canvas.draw_text = surface_draw_text;
canvas.font.userdata = font_create(xw.dpy, "fixed");
canvas.font.height = (gui_float)((XFont*)canvas.font.userdata)->height;
canvas.font.width = font_get_text_width;
gui_default_config(&config);
memset(&in, 0, sizeof in);
memset(&panel, 0, sizeof panel);
gui_default_config(&config);
memory.memory = calloc(MAX_MEMORY, 1);
memory.size = MAX_MEMORY;
font_data.userdata = font;
font_data.height = (gui_float)font->height;
font_data.width = font_get_text_width;
panel.x = 50; panel.y = 50;
panel.w = 420; panel.h = 300;
/* Demo */
memset(&demo, 0, sizeof(demo));
demo.tab_minimized = gui_true;
demo.spinner = 100;
demo.slider = 2.0f;
demo.prog = 60;
demo.current = 1;
while (running) {
/* Input */
@ -499,20 +527,24 @@ main(int argc, char *argv[])
else if (evt.type == ButtonRelease) btn(&in, &evt, gui_false);
else if (evt.type == MotionNotify) motion(&in, &evt);
else if (evt.type == Expose || evt.type == ConfigureNotify)
resize(&xw, canvas.userdata);
resize(&xw, surf);
}
gui_input_end(&in);
/* GUI */
XClearWindow(xw.dpy, xw.win);
surface_clear(canvas.userdata, 0x00646464);
canvas.width = xw.width; canvas.height = xw.height;
gui_output_begin_fixed(&buffer, &canvas, &memory, xw.width, xw.height);
running = gui_panel_begin(&panel, "Demo", panel.x, panel.y, panel.w, panel.h,
GUI_PANEL_CLOSEABLE|GUI_PANEL_MINIMIZABLE|GUI_PANEL_BORDER|
GUI_PANEL_MOVEABLE|GUI_PANEL_SCALEABLE, &config, &canvas, &in);
GUI_PANEL_MOVEABLE|GUI_PANEL_SCALEABLE, &config, &canvas, &font_data, &in);
demo_panel(&panel, &demo);
gui_panel_end(&panel);
surface_blit(xw.win, canvas.userdata, xw.width, xw.height);
gui_output_end(&buffer, &list, &canvas, NULL);
/* Draw */
XClearWindow(xw.dpy, xw.win);
surface_clear(surf, 0x00646464);
draw(surf, &list);
surface_blit(xw.win, surf, xw.width, xw.height);
XFlush(xw.dpy);
/* Timing */
@ -521,8 +553,8 @@ main(int argc, char *argv[])
sleep_for(DTIME - dt);
}
font_del(xw.dpy, canvas.font.userdata);
surface_del(canvas.userdata);
font_del(xw.dpy, font);
surface_del(surf);
XUnmapWindow(xw.dpy, xw.win);
XFreeColormap(xw.dpy, xw.cmap);
XDestroyWindow(xw.dpy, xw.win);

411
gui.c
View File

@ -30,6 +30,8 @@
#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)
#define ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0)
#define ALIGN(x, mask) (void*)((gui_size)((gui_byte*)(x) + (mask-1)) & ~(mask-1))
static const struct gui_rect null_rect = {0.0f, 0.0f, 9999.0f, 9999.0f};
static const gui_char utfbyte[GUI_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
@ -301,21 +303,19 @@ gui_input_end(struct gui_input *in)
}
void
gui_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
gui_float h, const struct gui_text *text, const char *string, gui_size len)
gui_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w, gui_float h,
const char *string, gui_size len, const struct gui_text *text, const struct gui_font *font)
{
gui_float label_x;
gui_float label_y;
gui_float label_w;
gui_float label_h;
gui_size text_width;
const struct gui_font *font;
struct gui_rect clip;
assert(text);
if (!text) return;
font = &canvas->font;
text_width = font->width(font->userdata, (const gui_char*)string, len);
label_y = y + text->padding.y;
label_h = MAX(0, h - 2 * text->padding.y);
@ -339,7 +339,7 @@ gui_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
}
static gui_bool
gui_button(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
gui_do_button(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
gui_float h, const struct gui_button *button, const struct gui_input *in,
enum gui_button_behavior behavior)
{
@ -370,9 +370,9 @@ gui_button(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float
}
gui_bool
gui_button_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w, gui_float h,
const struct gui_button *button, const char *string, enum gui_button_behavior b,
const struct gui_input *in)
gui_button_text(const struct gui_canvas *canvas, gui_float x, gui_float y,
gui_float w, gui_float h, const char *string, enum gui_button_behavior b,
const struct gui_button *button, const struct gui_input *in, const struct gui_font *font)
{
gui_bool ret = gui_false;
gui_float button_w, button_h;
@ -381,7 +381,6 @@ gui_button_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_f
struct gui_color bg_color;
gui_float inner_x, inner_y;
gui_float inner_w, inner_h;
const struct gui_font *font;
assert(button);
assert(string);
@ -389,7 +388,6 @@ gui_button_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_f
if (!canvas || !button)
return gui_false;
font = &canvas->font;
font_color = button->content;
bg_color = button->background;
button_w = MAX(w, font->height + 2 * button->padding.x);
@ -398,7 +396,7 @@ gui_button_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_f
font_color = button->highlight_content;
bg_color = button->highlight;
}
ret = gui_button(canvas, x, y, button_w, button_h, button, in, b);
ret = gui_do_button(canvas, x, y, button_w, button_h, button, in, b);
inner_x = x + button->border;
inner_y = y + button->border;
@ -410,14 +408,14 @@ gui_button_text(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_f
text.align = GUI_TEXT_CENTERED;
text.background = bg_color;
text.foreground = font_color;
gui_text(canvas, inner_x, inner_y, inner_w, inner_h, &text, string, strsiz(string));
gui_text(canvas, inner_x, inner_y, inner_w, inner_h, string, strsiz(string), &text, font);
return ret;
}
gui_bool
gui_button_triangle(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w, gui_float h,
const struct gui_button *button, enum gui_heading heading, enum gui_button_behavior b,
const struct gui_input *in)
gui_button_triangle(const struct gui_canvas *canvas, gui_float x, gui_float y,
gui_float w, gui_float h, enum gui_heading heading, enum gui_button_behavior b,
const struct gui_button *button, const struct gui_input *in)
{
gui_bool pressed;
struct gui_color col;
@ -428,40 +426,19 @@ gui_button_triangle(const struct gui_canvas *canvas, gui_float x, gui_float y, g
if (!canvas || !button)
return gui_false;
pressed = gui_button(canvas, x, y, w, h, button, in, b);
pressed = gui_do_button(canvas, x, y, w, h, button, in, b);
gui_triangle_from_direction(points, x, y, w, h, button->padding.x, button->padding.y, heading);
col = (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, x, y, w, h)) ?
button->highlight_content : button->content;
canvas->draw_triangle(canvas->userdata, points, col);
return pressed;
}
gui_bool
gui_button_icon(const struct gui_canvas *canvas, gui_float x, gui_float y,
gui_float w, gui_float h, const struct gui_button *button, void *img,
const struct gui_rect *src, enum gui_button_behavior behavior,
const struct gui_input *in)
{
struct gui_rect dst;
gui_bool pressed;
assert(button);
assert(canvas);
if (!canvas || !button)
return gui_false;
dst.x = x + button->padding.x;
dst.y = x + button->padding.y;
dst.w = w - 2 * button->padding.x;
dst.h = h - 2 * button->padding.y;
pressed = gui_button(canvas, x, y, w, h, button, in, behavior);
canvas->draw_bitmap(canvas->userdata, dst.x, dst.y, dst.w, dst.h, src, img);
canvas->draw_triangle(canvas->userdata, points[0].x, points[0].y,
points[1].x, points[1].y, points[2].x, points[2].y, col);
return pressed;
}
gui_bool
gui_toggle(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
gui_float h, gui_bool active, const char *string, const struct gui_toggle *toggle,
enum gui_toggle_type type, const struct gui_input *in)
gui_float h, gui_bool active, const char *string, enum gui_toggle_type type,
const struct gui_toggle *toggle, const struct gui_input *in, const struct gui_font *font)
{
gui_bool toggle_active;
gui_float select_size;
@ -470,14 +447,12 @@ gui_toggle(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float
gui_float cursor_x, cursor_y;
gui_float cursor_pad, cursor_size;
gui_draw_rect draw[2];
const struct gui_font *font;
assert(toggle);
assert(canvas);
if (!canvas || !toggle)
return 0;
font = &canvas->font;
draw[GUI_TOGGLE_CHECK] = canvas->draw_rect;
draw[GUI_TOGGLE_OPTION] = canvas->draw_circle;
toggle_w = MAX(w, font->height + 2 * toggle->padding.x);
@ -500,7 +475,7 @@ gui_toggle(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float
draw[type](canvas->userdata, select_x, select_y, select_size, select_size, toggle->background);
if (toggle_active)
draw[type](canvas->userdata, cursor_x, cursor_y, cursor_size, cursor_size, toggle->foreground);
draw[type](canvas->userdata,cursor_x,cursor_y,cursor_size,cursor_size,toggle->foreground);
if (font && string) {
struct gui_text text;
@ -517,7 +492,7 @@ gui_toggle(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float
text.align = GUI_TEXT_LEFT;
text.background = toggle->foreground;
text.foreground = toggle->font;
gui_text(canvas, inner_x, inner_y, inner_w, inner_h, &text, string, strsiz(string));
gui_text(canvas, inner_x, inner_y, inner_w, inner_h, string, strsiz(string), &text, font);
}
return toggle_active;
}
@ -577,10 +552,10 @@ gui_progress(const struct gui_canvas *canvas, gui_float x, gui_float y,
gui_float w, gui_float h, gui_size value, gui_size max, gui_bool modifyable,
const struct gui_slider *prog, const struct gui_input *in)
{
gui_float prog_scale;
gui_float cursor_x, cursor_y;
gui_float cursor_w, cursor_h;
gui_float prog_w, prog_h;
gui_float prog_scale;
gui_size prog_value;
assert(prog);
@ -590,7 +565,8 @@ gui_progress(const struct gui_canvas *canvas, gui_float x, gui_float y,
prog_h = MAX(h, 2 * prog->padding.y + 1);
prog_value = MIN(value, max);
if (in && modifyable && in->mouse_down && INBOX(in->mouse_pos.x, in->mouse_pos.y, x, y, prog_w, prog_h)){
if (in && modifyable && in->mouse_down &&
INBOX(in->mouse_pos.x, in->mouse_pos.y, x, y, prog_w, prog_h)){
gui_float ratio = (gui_float)(in->mouse_pos.x - x) / (gui_float)prog_w;
prog_value = (gui_size)((gui_float)max * ratio);
}
@ -675,11 +651,10 @@ gui_buffer_input(gui_char *buffer, gui_size length, gui_size max,
gui_size
gui_input(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
gui_float h, gui_char *buffer, gui_size len, gui_size max, gui_bool *active,
const struct gui_input_field *field, const struct gui_input *in)
const struct gui_input_field *field, const struct gui_input *in, const struct gui_font *font)
{
gui_float input_w, input_h;
gui_bool input_active;
const struct gui_font *font;
assert(canvas);
assert(buffer);
@ -688,7 +663,6 @@ gui_input(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w
if (!canvas || !buffer || !field || !in)
return 0;
font = &canvas->font;
input_w = MAX(w, 2 * field->padding.x);
input_h = MAX(h, font->height);
input_active = *active;
@ -811,7 +785,6 @@ gui_plot(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w,
plot_selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : plot_selected;
col = plot->highlight;
} else col = plot->foreground;
canvas->draw_rect(canvas->userdata, plot_cur_x - 3, plot_cur_y - 3, 6, 6, col);
plot_last_x = plot_cur_x, plot_last_y = plot_cur_y;
}
@ -910,9 +883,9 @@ gui_scroll(const struct gui_canvas *canvas, gui_float x, gui_float y,
button.highlight_content = scroll->foreground;
button_up_pressed = gui_button_triangle(canvas, x, y, scroll_w, scroll_w,
&button, GUI_UP, GUI_BUTTON_DEFAULT, in);
GUI_UP, GUI_BUTTON_DEFAULT, &button, in);
button_down_pressed = gui_button_triangle(canvas, x, y + scroll_h - scroll_w,
scroll_w, scroll_w, &button, GUI_DOWN, GUI_BUTTON_DEFAULT, in);
scroll_w, scroll_w, GUI_DOWN, GUI_BUTTON_DEFAULT, &button, in);
scroll_h = scroll_h - 2 * scroll_w;
scroll_y = y + scroll_w;
@ -942,10 +915,217 @@ gui_scroll(const struct gui_canvas *canvas, gui_float x, gui_float y,
cursor_y = scroll_y + (scroll_off * scroll_h);
}
}
canvas->draw_rect(canvas->userdata, cursor_x, cursor_y, cursor_w, cursor_h, scroll->foreground);
canvas->draw_rect(canvas->userdata,cursor_x,cursor_y,cursor_w,cursor_h,scroll->foreground);
return scroll_offset;
}
void*
gui_output_push(struct gui_command_buffer* buffer,
enum gui_command_type type, gui_size size)
{
static const gui_size align = ALIGNOF(struct gui_command);
struct gui_command *cmd;
gui_size alignment;
void *unaligned;
void *tail;
assert(buffer);
if (!buffer) return NULL;
buffer->needed += size;
unaligned = (gui_byte*)buffer->end + size;
tail = ALIGN(unaligned, align);
alignment = (gui_size)((gui_byte*)tail - (gui_byte*)unaligned);
if ((buffer->allocated + size + alignment) >= buffer->capacity) {
gui_size cap;
if (!buffer->allocator.realloc) return NULL;
cap = (gui_size)((gui_float)buffer->capacity * buffer->grow_factor);
cap = cap + MAX(size, cap - buffer->capacity);
buffer->memory = buffer->allocator.realloc(buffer->memory, cap);
if (!buffer->memory) return NULL;
buffer->capacity = cap;
}
cmd = buffer->end;
cmd->type = type;
cmd->next = tail;
buffer->end = tail;
buffer->allocated += size + alignment;
buffer->count++;
return cmd;
}
void
gui_output_push_scissor(struct gui_command_buffer *buffer, gui_float x, gui_float y,
gui_float w, gui_float h)
{
struct gui_command_scissor *cmd;
if (!buffer) return;
cmd = gui_output_push(buffer, GUI_COMMAND_SCISSOR, sizeof(*cmd));
if (!cmd) return;
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
}
void
gui_output_push_line(struct gui_command_buffer *buffer, gui_float x0, gui_float y0,
gui_float x1, gui_float y1, struct gui_color c)
{
struct gui_command_line *cmd;
if (!buffer) return;
cmd = gui_output_push(buffer, GUI_COMMAND_LINE, sizeof(*cmd));
if (!cmd) return;
cmd->begin[0] = x0;
cmd->begin[1] = y0;
cmd->end[0] = x1;
cmd->end[1] = y1;
cmd->color = c;
}
void
gui_output_push_rect(struct gui_command_buffer *buffer, gui_float x, gui_float y,
gui_float w, gui_float h, struct gui_color c)
{
struct gui_command_rect *cmd;
if (!buffer) return;
cmd = gui_output_push(buffer, GUI_COMMAND_RECT, sizeof(*cmd));
if (!cmd) return;
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->color = c;
}
void
gui_output_push_circle(struct gui_command_buffer *buffer, gui_float x, gui_float y,
gui_float w, gui_float h, struct gui_color c)
{
struct gui_command_circle *cmd;
if (!buffer) return;
cmd = gui_output_push(buffer, GUI_COMMAND_CIRCLE, sizeof(*cmd));
if (!cmd) return;
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->color = c;
}
void
gui_output_push_triangle(struct gui_command_buffer *buffer, gui_float x0, gui_float y0,
gui_float x1, gui_float y1, gui_float x2, gui_float y2, struct gui_color c)
{
struct gui_command_triangle *cmd;
if (!buffer) return;
cmd = gui_output_push(buffer, GUI_COMMAND_TRIANGLE, sizeof(*cmd));
if (!cmd) return;
cmd->a[0] = x0;
cmd->a[1] = y0;
cmd->b[0] = x1;
cmd->b[1] = y1;
cmd->c[0] = x2;
cmd->c[1] = y2;
cmd->color = c;
}
void
gui_output_push_text(struct gui_command_buffer *buffer, gui_float x, gui_float y,
gui_float w, gui_float h, const gui_char *string, gui_size length,
const struct gui_font *font, struct gui_color bg, struct gui_color fg)
{
struct gui_command_text *cmd;
if (!buffer) return;
if (!string || !length) return;
cmd = gui_output_push(buffer, GUI_COMMAND_TEXT, sizeof(*cmd) + length + 1);
if (!cmd) return;
cmd->x = x;
cmd->y = y;
cmd->w = w;
cmd->h = h;
cmd->bg = bg;
cmd->fg = fg;
cmd->font = font->userdata;
cmd->length = length;
memcopy(cmd->string, string, length);
cmd->string[length] = '\0';
}
static void
gui_canvas_init(struct gui_canvas *canvas, struct gui_command_buffer *buffer,
gui_size width, gui_size height)
{
canvas->userdata = buffer;
canvas->width = width;
canvas->height = height;
canvas->scissor = (gui_scissor)gui_output_push_scissor;
canvas->draw_line = (gui_draw_line)gui_output_push_line;
canvas->draw_rect = (gui_draw_rect)gui_output_push_rect;
canvas->draw_circle = (gui_draw_circle)gui_output_push_circle;
canvas->draw_triangle = (gui_draw_triangle)gui_output_push_triangle;
canvas->draw_text = (gui_draw_text)gui_output_push_text;
}
void
gui_output_begin_fixed(struct gui_command_buffer *buffer, struct gui_canvas *canvas,
const struct gui_memory *memory, gui_size width, gui_size height)
{
zero(buffer, sizeof(*buffer));
gui_canvas_init(canvas, buffer, width, height);
buffer->memory = memory->memory;
buffer->capacity = memory->size;
buffer->begin = buffer->memory;
buffer->end = buffer->begin;
}
void
gui_output_begin(struct gui_command_buffer *buffer, struct gui_canvas *canvas,
const struct gui_allocator *memory, gui_size initial_size, gui_float grow_factor,
gui_size width, gui_size height)
{
zero(buffer, sizeof(*buffer));
gui_canvas_init(canvas, buffer, width, height);
buffer->memory = memory->alloc(initial_size);
buffer->allocator = *memory;
buffer->capacity = initial_size;
buffer->begin = buffer->memory;
buffer->end = buffer->begin;
buffer->grow_factor = grow_factor;
}
void
gui_output_end(struct gui_command_buffer *buffer, struct gui_command_list *list,
struct gui_canvas *canvas, struct gui_memory_status *status)
{
assert(buffer);
if (!buffer) return;
if (status) {
status->size = buffer->capacity;
status->allocated = buffer->allocated;
status->needed = buffer->needed;
}
if (list) {
list->count = buffer->count;
list->begin = buffer->begin;
list->end = buffer->end;
}
buffer->capacity = 0;
buffer->needed = 0;
buffer->allocated = 0;
zero(canvas, sizeof(*canvas));
}
void
gui_output_clear(struct gui_command_buffer *buffer)
{
assert(buffer);
if (!buffer || !buffer->memory || !buffer->allocator.free) return;
buffer->allocator.free(buffer->memory);
}
void
gui_default_config(struct gui_config *config)
{
@ -995,7 +1175,7 @@ gui_default_config(struct gui_config *config)
gui_bool
gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_float y,
gui_float w, gui_float h, gui_flags f, const struct gui_config *config,
const struct gui_canvas *canvas, const struct gui_input *in)
const struct gui_canvas *canvas, const struct gui_font *font, const struct gui_input *in)
{
const struct gui_color *header;
gui_float mouse_x, mouse_y;
@ -1021,9 +1201,10 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
panel->index = 0;
panel->row_columns = 0;
panel->flags = f;
panel->font = *font;
config = panel->config;
panel->header_height = canvas->font.height + 3 * config->item_padding.y;
panel->header_height = font->height + 3 * config->item_padding.y;
panel->header_height += config->panel_padding.y;
if (panel->flags & GUI_PANEL_MOVEABLE) {
gui_bool incursor;
@ -1034,8 +1215,8 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y, move_x, move_y, move_w, move_h);
if (in->mouse_down && incursor) {
panel->x = CLAMP(0, panel->x + in->mouse_delta.x, (gui_float)canvas->width - panel->w);
panel->y = CLAMP(0, panel->y + in->mouse_delta.y, (gui_float)canvas->height - panel->h);
panel->x = CLAMP(0, panel->x+in->mouse_delta.x, (gui_float)canvas->width-panel->w);
panel->y = CLAMP(0, panel->y+in->mouse_delta.y, (gui_float)canvas->height-panel->h);
}
}
@ -1050,9 +1231,9 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
if (in->mouse_down && incursor) {
gui_float min_x = config->panel_min_size.x;
gui_float min_y = config->panel_min_size.y;
panel->x = CLAMP(0, panel->x + in->mouse_delta.x, (gui_float)canvas->width - panel->w);
panel->w = CLAMP(min_x, panel->w - in->mouse_delta.x, (gui_float)canvas->width - panel->x);
panel->h = CLAMP(min_y, panel->h + in->mouse_delta.y, (gui_float)canvas->height - panel->y);
panel->x = CLAMP(0, panel->x + in->mouse_delta.x, (gui_float)canvas->width-panel->w);
panel->w = CLAMP(min_x, panel->w-in->mouse_delta.x, (gui_float)canvas->width-panel->x);
panel->h = CLAMP(min_y,panel->h+in->mouse_delta.y,(gui_float)canvas->height-panel->y);
}
}
@ -1066,7 +1247,8 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
header_w = panel->w - 2 * config->panel_padding.x;
panel->width = panel->w;
panel->at_y = panel->y;
canvas->draw_rect(canvas->userdata, panel->x, panel->y, panel->w, panel->header_height, *header);
canvas->draw_rect(canvas->userdata, panel->x, panel->y, panel->w,
panel->header_height, *header);
if (!(panel->flags & GUI_PANEL_TAB)) {
panel->flags |= GUI_PANEL_SCROLLBAR;
@ -1089,13 +1271,13 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
if (panel->flags & GUI_PANEL_CLOSEABLE) {
const gui_char *X = (const gui_char*)"x";
const gui_size text_width = canvas->font.width(canvas->font.userdata, X, 1);
const gui_size text_width = font->width(font->userdata, X, 1);
const gui_float close_x = header_x;
const gui_float close_y = panel->y + config->panel_padding.y;
const gui_float close_w = (gui_float)text_width + 2 * config->item_padding.x;
const gui_float close_h = canvas->font.height + 2 * config->item_padding.y;
const gui_float close_h = font->height + 2 * config->item_padding.y;
canvas->draw_text(canvas->userdata, close_x, close_y, close_w, close_h,
X, 1, &canvas->font, config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
X, 1, font, config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
header_w -= close_w;
header_x += close_h - config->item_padding.x;
@ -1114,13 +1296,14 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
(const gui_char*)"+":
(const gui_char*)"-";
text_width = canvas->font.width(canvas->font.userdata, score, 1);
text_width = font->width(font->userdata, score, 1);
min_x = header_x;
min_y = panel->y + config->panel_padding.y;
min_w = (gui_float)text_width + 3 * config->item_padding.x;
min_h = canvas->font.height + 2 * config->item_padding.y;
min_h = font->height + 2 * config->item_padding.y;
canvas->draw_text(canvas->userdata, min_x, min_y, min_w, min_h,
score, 1, &canvas->font, config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
score, 1, font, config->colors[GUI_COLOR_PANEL],
config->colors[GUI_COLOR_TEXT]);
header_w -= min_w;
header_x += min_w - config->item_padding.x;
@ -1136,9 +1319,9 @@ gui_panel_begin(struct gui_panel *panel, const char *text, gui_float x, gui_floa
const gui_float label_x = header_x + config->item_padding.x;
const gui_float label_y = panel->y + config->panel_padding.y;
const gui_float label_w = header_w - (3 * config->item_padding.x);
const gui_float label_h = canvas->font.height + 2 * config->item_padding.y;
const gui_float label_h = font->height + 2 * config->item_padding.y;
canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h,
(const gui_char*)text, text_len, &canvas->font, config->colors[GUI_COLOR_PANEL],
(const gui_char*)text, text_len, font, config->colors[GUI_COLOR_PANEL],
config->colors[GUI_COLOR_TEXT]);
}
@ -1266,7 +1449,7 @@ gui_panel_text(struct gui_panel *panel, const char *str, gui_size len,
text.align = alignment;
text.foreground = config->colors[GUI_COLOR_TEXT];
text.background = config->colors[GUI_COLOR_PANEL];
gui_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, &text, str, len);
gui_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, str, len, &text, &panel->font);
}
gui_bool
@ -1295,7 +1478,7 @@ gui_panel_button_text(struct gui_panel *panel, const char *str,
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
return gui_button_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
&button, str, behavior, panel->in);
str, behavior, &button, panel->in, &panel->font);
}
gui_bool gui_panel_button_color(struct gui_panel *panel, const struct gui_color color,
@ -1321,7 +1504,8 @@ gui_bool gui_panel_button_color(struct gui_panel *panel, const struct gui_color
button.foreground = color;
button.highlight = color;
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
return gui_button(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, &button, panel->in, behavior);
return gui_do_button(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
&button, panel->in, behavior);
}
gui_bool
@ -1350,7 +1534,7 @@ gui_panel_button_triangle(struct gui_panel *panel, enum gui_heading heading,
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
return gui_button_triangle(panel->canvas, bounds.x, bounds.y, bounds.w,
bounds.h, &button, heading, behavior, panel->in);
bounds.h, heading, behavior, &button, panel->in);
}
gui_bool
@ -1387,39 +1571,10 @@ gui_panel_button_toggle(struct gui_panel *panel, const char *str, gui_bool value
button.highlight_content = config->colors[GUI_COLOR_BUTTON];
}
if (gui_button_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
&button, str, GUI_BUTTON_DEFAULT, panel->in)) value = !value;
str, GUI_BUTTON_DEFAULT, &button, panel->in, &panel->font)) value = !value;
return value;
}
gui_bool
gui_panel_button_icon(struct gui_panel *panel, void *img, const struct gui_rect *src,
enum gui_button_behavior behavior)
{
struct gui_rect bounds;
struct gui_button button;
const struct gui_config *config;
assert(panel);
assert(panel->config);
assert(panel->canvas);
if (!panel || !panel->config || !panel->canvas) return 0;
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
gui_panel_alloc_space(&bounds, panel);
config = panel->config;
button.border = 1;
button.padding.x = config->item_padding.x;
button.padding.y = config->item_padding.y;
button.background = config->colors[GUI_COLOR_BUTTON];
button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER];
button.content = config->colors[GUI_COLOR_TEXT];
button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER];
button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT];
return gui_button_icon(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
&button, img, src, behavior, panel->in);
}
gui_bool
gui_panel_check(struct gui_panel *panel, const char *text, gui_bool is_active)
{
@ -1443,7 +1598,7 @@ gui_panel_check(struct gui_panel *panel, const char *text, gui_bool is_active)
toggle.background = config->colors[GUI_COLOR_CHECK];
toggle.foreground = config->colors[GUI_COLOR_CHECK_ACTIVE];
return gui_toggle(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
is_active, text, &toggle, GUI_TOGGLE_CHECK, panel->in);
is_active, text, GUI_TOGGLE_CHECK, &toggle, panel->in, &panel->font);
}
gui_bool
@ -1469,7 +1624,7 @@ gui_panel_option(struct gui_panel *panel, const char *text, gui_bool is_active)
toggle.background = config->colors[GUI_COLOR_CHECK];
toggle.foreground = config->colors[GUI_COLOR_CHECK_ACTIVE];
return gui_toggle(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
is_active, text, &toggle, GUI_TOGGLE_OPTION, panel->in);
is_active, text, GUI_TOGGLE_OPTION, &toggle, panel->in, &panel->font);
}
gui_float
@ -1548,7 +1703,7 @@ gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size len,
field.background = config->colors[GUI_COLOR_INPUT];
field.foreground = config->colors[GUI_COLOR_INPUT_BORDER];
return gui_input(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h,
buffer, len, max, active, &field, panel->in);
buffer, len, max, active, &field, panel->in, &panel->font);
}
gui_int
@ -1573,7 +1728,6 @@ gui_panel_spinner(struct gui_panel *panel, gui_int min, gui_int value,
assert(panel);
assert(panel->config);
assert(panel->canvas);
assert(value);
if (!panel || !panel->config || !panel->canvas) return 0;
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
@ -1591,18 +1745,18 @@ gui_panel_spinner(struct gui_panel *panel, gui_int min, gui_int value,
button_h = bounds.h / 2;
button_w = bounds.h - config->item_padding.x;
button_x = bounds.x + bounds.w - button_w;
button.padding.x = MAX(3, button_h - canvas->font.height);
button.padding.y = MAX(3, button_h - canvas->font.height);
button.padding.x = MAX(3, button_h - panel->font.height);
button.padding.y = MAX(3, button_h - panel->font.height);
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];
button_up_clicked = gui_button_triangle(canvas, button_x, button_y, button_w, button_h,
&button, GUI_UP, GUI_BUTTON_DEFAULT, panel->in);
GUI_UP, GUI_BUTTON_DEFAULT, &button, panel->in);
button_y = bounds.y + button_h;
button_down_clicked = gui_button_triangle(canvas, button_x, button_y, button_w, button_h,
&button, GUI_DOWN, GUI_BUTTON_DEFAULT, panel->in);
GUI_DOWN, GUI_BUTTON_DEFAULT, &button, panel->in);
if (button_up_clicked || button_down_clicked) {
value += (button_up_clicked) ? step : -step;
value = CLAMP(min, value, max);
@ -1620,7 +1774,7 @@ gui_panel_spinner(struct gui_panel *panel, gui_int min, gui_int value,
field.background = config->colors[GUI_COLOR_SPINNER];
field.foreground = config->colors[GUI_COLOR_SPINNER_BORDER];
len = gui_input(canvas, field_x, field_y, field_w, field_h, (gui_char*)string,
len, MAX_NUMBER_BUFFER, &is_active, &field, panel->in);
len, MAX_NUMBER_BUFFER, &is_active, &field, panel->in, &panel->font);
if (old_len != len)
strtoi(&value, string, len);
*active = is_active;
@ -1639,7 +1793,8 @@ gui_panel_selector(struct gui_panel *panel, const char *items[],
struct gui_button button;
const struct gui_config *config;
const struct gui_canvas *canvas;
gui_bool button_up_clicked, button_down_clicked;
gui_bool button_up_clicked;
gui_bool button_down_clicked;
gui_float button_x, button_y;
gui_float button_w, button_h;
@ -1666,19 +1821,19 @@ gui_panel_selector(struct gui_panel *panel, const char *items[],
button_h = bounds.h / 2;
button_w = bounds.h - config->item_padding.x;
button_x = bounds.x + bounds.w - button_w;
button.padding.x = MAX(3, button_h - canvas->font.height);
button.padding.y = MAX(3, button_h - canvas->font.height);
button.padding.x = MAX(3, button_h - panel->font.height);
button.padding.y = MAX(3, button_h - panel->font.height);
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];
button_up_clicked = gui_button_triangle(canvas, button_x, button_y, button_w,
button_h, &button, GUI_UP, GUI_BUTTON_DEFAULT, panel->in);
button_h, GUI_UP, GUI_BUTTON_DEFAULT, &button, panel->in);
button_y = bounds.y + button_h;
button_down_clicked = gui_button_triangle(canvas, button_x, button_y, button_w,
button_h, &button, GUI_DOWN, GUI_BUTTON_DEFAULT, panel->in);
button_h, GUI_DOWN, GUI_BUTTON_DEFAULT, &button, panel->in);
item_current = (button_down_clicked && item_current < item_count-1) ?
item_current+1 : (button_up_clicked && item_current > 0) ? item_current-1 : item_current;
@ -1688,7 +1843,7 @@ gui_panel_selector(struct gui_panel *panel, const char *items[],
label_h = bounds.h - 2 * config->item_padding.y;
text_len = strsiz(items[item_current]);
canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h,
(const gui_char*)items[item_current], text_len, &canvas->font,
(const gui_char*)items[item_current], text_len, &panel->font,
config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]);
return item_current;
}
@ -1769,7 +1924,7 @@ gui_panel_tab_begin(struct gui_panel *panel, struct gui_panel *tab,
tab->flags = GUI_PANEL_HIDDEN;
tab->config = panel->config;
tab->canvas = panel->canvas;
return gui_false;
return minimized;
}
old_height = panel->row_height;
@ -1783,7 +1938,7 @@ gui_panel_tab_begin(struct gui_panel *panel, struct gui_panel *tab,
flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_TAB;
gui_panel_begin(tab, title, bounds.x, bounds.y + 1, bounds.w, null_rect.h, flags,
panel->config, panel->canvas, panel->in);
panel->config, panel->canvas, &panel->font, panel->in);
unify(&clip, &panel->clip, tab->clip.x, tab->clip.y, tab->clip.x + tab->clip.w,
tab->clip.y + tab->clip.h);
canvas->scissor(canvas->userdata, clip.x, clip.y, clip.w, clip.h);
@ -1832,7 +1987,7 @@ gui_panel_group_begin(struct gui_panel *panel, struct gui_panel *group,
group->offset = offset;
flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB;
gui_panel_begin(group, title, bounds.x, bounds.y, bounds.w, bounds.h, flags,
panel->config, panel->canvas, panel->in);
panel->config, panel->canvas, &panel->font, panel->in);
unify(&clip, &panel->clip, group->clip.x, group->clip.y, group->clip.x + group->clip.w,
group->clip.y + group->clip.h);
canvas->scissor(canvas->userdata, clip.x, clip.y, clip.w, clip.h);
@ -1849,7 +2004,7 @@ gui_panel_group_end(struct gui_panel *panel, struct gui_panel *group)
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
canvas = panel->canvas;
unify(&clip, &panel->clip, group->clip.x, group->clip.y, group->x + group->w, group->y + group->h);
unify(&clip, &panel->clip, group->clip.x, group->clip.y, group->x+group->w, group->y+group->h);
canvas->scissor(canvas->userdata, clip.x, clip.y, clip.w, clip.h);
gui_panel_end(group);
canvas->scissor(canvas->userdata, panel->clip.x, panel->clip.y, panel->clip.w, panel->clip.h);
@ -1892,7 +2047,7 @@ gui_panel_shelf_begin(struct gui_panel *panel, struct gui_panel *shelf,
header_x = bounds.x;
header_y = bounds.y;
header_w = bounds.w;
header_h = config->panel_padding.y + 3 * config->item_padding.y + canvas->font.height;
header_h = config->panel_padding.y + 3 * config->item_padding.y + panel->font.height;
item_width = (header_w - (gui_float)size) / (gui_float)size;
for (i = 0; i < size; i++) {
@ -1916,7 +2071,7 @@ gui_panel_shelf_begin(struct gui_panel *panel, struct gui_panel *shelf,
button_h -= config->item_padding.y;
}
if (gui_button_text(canvas, button_x, button_y, button_w, button_h,
&button, tabs[i], GUI_BUTTON_DEFAULT, panel->in)) active = i;
tabs[i], GUI_BUTTON_DEFAULT, &button, panel->in, &panel->font)) active = i;
}
bounds.y += header_h;
@ -1925,7 +2080,7 @@ gui_panel_shelf_begin(struct gui_panel *panel, struct gui_panel *shelf,
shelf->offset = offset;
flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB;
gui_panel_begin(shelf, NULL, bounds.x, bounds.y, bounds.w, bounds.h, flags,
panel->config, panel->canvas, panel->in);
panel->config, panel->canvas, &panel->font, panel->in);
unify(&clip, &panel->clip, shelf->clip.x, shelf->clip.y,
shelf->clip.x + shelf->clip.w, shelf->clip.y + shelf->clip.h);
@ -1945,7 +2100,7 @@ gui_panel_shelf_end(struct gui_panel *panel, struct gui_panel *shelf)
if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0;
canvas = panel->canvas;
unify(&clip, &panel->clip, shelf->clip.x, shelf->clip.y, shelf->x + shelf->w, shelf->y + shelf->h);
unify(&clip, &panel->clip, shelf->clip.x, shelf->clip.y, shelf->x+shelf->w, shelf->y+shelf->h);
canvas->scissor(canvas->userdata, clip.x, clip.y, clip.w, clip.h);
gui_panel_end(shelf);
canvas->scissor(canvas->userdata, panel->clip.x, panel->clip.y, panel->clip.w, panel->clip.h);
@ -1990,7 +2145,7 @@ gui_panel_end(struct gui_panel *panel)
panel->offset = gui_scroll(canvas, scroll_x, scroll_y, scroll_w, scroll_h,
scroll_offset, scroll_target, scroll_step, &scroll, panel->in);
panel_y = panel->y + panel->height + panel->header_height - config->panel_padding.y;
canvas->draw_rect(canvas->userdata, panel->x, panel_y, panel->width, config->panel_padding.y,
canvas->draw_rect(canvas->userdata, panel->x,panel_y,panel->width,config->panel_padding.y,
config->colors[GUI_COLOR_PANEL]);
} else panel->height = panel->at_y - panel->y;

201
gui.h
View File

@ -57,9 +57,8 @@ typedef void(*gui_scissor)(void*, gui_float, gui_float, gui_float, gui_float);
typedef void(*gui_draw_line)(void*, gui_float, gui_float, gui_float, gui_float, struct gui_color);
typedef void(*gui_draw_rect)(void*, gui_float, gui_float, gui_float, gui_float, struct gui_color);
typedef void(*gui_draw_circle)(void*, gui_float, gui_float, gui_float, gui_float, struct gui_color);
typedef void(*gui_draw_triangle)(void*, const struct gui_vec2*, struct gui_color);
typedef void(*gui_draw_bitmap)(void*, gui_float, gui_float, gui_float, gui_float,
const struct gui_rect*, void*);
typedef void(*gui_draw_triangle)(void*, gui_float, gui_float, gui_float, gui_float,
gui_float, gui_float, struct gui_color);
typedef void(*gui_draw_text)(void*, gui_float, gui_float, gui_float, gui_float,
const gui_char*, gui_size, const struct gui_font*,
struct gui_color, struct gui_color);
@ -86,26 +85,6 @@ struct gui_input {
struct gui_vec2 mouse_clicked_pos;
};
struct gui_font {
void *userdata;
gui_float height;
gui_text_width_f width;
};
struct gui_canvas {
void *userdata;
gui_size width;
gui_size height;
struct gui_font font;
gui_scissor scissor;
gui_draw_line draw_line;
gui_draw_rect draw_rect;
gui_draw_circle draw_circle;
gui_draw_triangle draw_triangle;
gui_draw_bitmap draw_bitmap;
gui_draw_text draw_text;
};
enum gui_text_align {
GUI_TEXT_LEFT,
GUI_TEXT_CENTERED,
@ -119,11 +98,6 @@ struct gui_text {
struct gui_color background;
};
struct gui_image {
struct gui_vec2 padding;
struct gui_color background;
};
enum gui_button_behavior {
GUI_BUTTON_DEFAULT,
GUI_BUTTON_REPEATER
@ -196,6 +170,120 @@ struct gui_histo {
struct gui_color highlight;
};
struct gui_font {
void *userdata;
gui_float height;
gui_text_width_f width;
};
struct gui_canvas {
void *userdata;
gui_size width;
gui_size height;
gui_scissor scissor;
gui_draw_line draw_line;
gui_draw_rect draw_rect;
gui_draw_circle draw_circle;
gui_draw_triangle draw_triangle;
gui_draw_text draw_text;
};
struct gui_memory {
void *memory;
gui_size size;
};
struct gui_allocator {
void*(*alloc)(gui_size);
void*(*realloc)(void*,gui_size);
void(*free)(void*);
};
enum gui_command_type {
GUI_COMMAND_NOP,
GUI_COMMAND_SCISSOR,
GUI_COMMAND_LINE,
GUI_COMMAND_RECT,
GUI_COMMAND_CIRCLE,
GUI_COMMAND_TRIANGLE,
GUI_COMMAND_TEXT
};
struct gui_command {
enum gui_command_type type;
struct gui_command *next;
};
struct gui_command_scissor {
struct gui_command header;
gui_float x, y;
gui_float w, h;
};
struct gui_command_line {
struct gui_command header;
gui_float begin[2];
gui_float end[2];
struct gui_color color;
};
struct gui_command_rect {
struct gui_command header;
gui_float x, y;
gui_float w, h;
struct gui_color color;
};
struct gui_command_circle {
struct gui_command header;
gui_float x, y;
gui_float w, h;
struct gui_color color;
};
struct gui_command_triangle {
struct gui_command header;
gui_float a[2];
gui_float b[2];
gui_float c[2];
struct gui_color color;
};
struct gui_command_text {
struct gui_command header;
gui_float x, y;
gui_float w, h;
gui_size length;
struct gui_color bg;
struct gui_color fg;
void *font;
gui_char string[1];
};
struct gui_command_buffer {
void *memory;
struct gui_allocator allocator;
struct gui_command *begin;
struct gui_command *end;
gui_float grow_factor;
gui_size allocated;
gui_size capacity;
gui_size needed;
gui_size count;
};
struct gui_command_list {
struct gui_command *begin;
struct gui_command *end;
gui_size count;
};
struct gui_memory_status {
gui_size size;
gui_size allocated;
gui_size needed;
};
enum gui_panel_colors {
GUI_COLOR_TEXT,
GUI_COLOR_PANEL,
@ -271,6 +359,7 @@ struct gui_panel {
gui_float offset;
gui_bool minimized;
struct gui_rect clip;
struct gui_font font;
const struct gui_input *in;
const struct gui_config *config;
const struct gui_canvas *canvas;
@ -284,21 +373,45 @@ void gui_input_button(struct gui_input*, gui_int x, gui_int y, gui_bool down);
void gui_input_char(struct gui_input*, const gui_glyph);
void gui_input_end(struct gui_input*);
/* Output */
void gui_output_begin(struct gui_command_buffer*, struct gui_canvas *out,
const struct gui_allocator*, gui_size initial_size,
gui_float grow_factor, gui_size width, gui_size height);
void gui_output_begin_fixed(struct gui_command_buffer*, struct gui_canvas *out,
const struct gui_memory*, gui_size width, gui_size height);
void *gui_output_push(struct gui_command_buffer*,
enum gui_command_type, gui_size size);
void gui_output_push_scissor(struct gui_command_buffer*, gui_float, gui_float,
gui_float, gui_float);
void gui_output_push_line(struct gui_command_buffer*, gui_float, gui_float,
gui_float, gui_float, struct gui_color);
void gui_output_push_rect(struct gui_command_buffer*, gui_float, gui_float,
gui_float, gui_float, struct gui_color);
void gui_output_push_circle(struct gui_command_buffer*, gui_float, gui_float,
gui_float, gui_float, struct gui_color);
void gui_output_push_triangle(struct gui_command_buffer *buffer, gui_float x0, gui_float y0,
gui_float x1, gui_float y1, gui_float x2, gui_float y2, struct gui_color c);
void gui_output_push_text(struct gui_command_buffer*, gui_float, gui_float,
gui_float, gui_float, const gui_char*, gui_size,
const struct gui_font*, struct gui_color, struct gui_color);
void gui_output_clear(struct gui_command_buffer*);
void gui_output_end(struct gui_command_buffer*, struct gui_command_list*,
struct gui_canvas *canvas, struct gui_memory_status*);
/* Widgets */
void gui_text(const struct gui_canvas*, gui_float x, gui_float y, gui_float w, gui_float h,
const struct gui_text*, const char *text, gui_size len);
const char *text, gui_size len, const struct gui_text*, const struct gui_font*);
gui_bool gui_button_text(const struct gui_canvas*, gui_float x, gui_float y,
gui_float w, gui_float h, const struct gui_button*, const char*,
enum gui_button_behavior, const struct gui_input*);
gui_float w, gui_float h, const char*, enum gui_button_behavior,
const struct gui_button*, const struct gui_input*, const struct gui_font*);
gui_bool gui_button_triangle(const struct gui_canvas*, gui_float x, gui_float y,
gui_float w, gui_float h, const struct gui_button*, enum gui_heading,
enum gui_button_behavior, const struct gui_input*);
gui_bool gui_button_icon(const struct gui_canvas*, gui_float x, gui_float y,
gui_float w, gui_float h, const struct gui_button*, void *bitmap,
const struct gui_rect *src, enum gui_button_behavior, const struct gui_input*);
gui_float w, gui_float h, enum gui_heading, enum gui_button_behavior,
const struct gui_button*, const struct gui_input*);
gui_bool gui_toggle(const struct gui_canvas*, gui_float x, gui_float y, gui_float w,
gui_float h, gui_bool, const char*, const struct gui_toggle*,
enum gui_toggle_type, const struct gui_input*);
gui_float h, gui_bool, const char*, enum gui_toggle_type,
const struct gui_toggle*, const struct gui_input*, const struct gui_font*);
gui_float gui_slider(const struct gui_canvas*, gui_float x, gui_float y, gui_float w,
gui_float h, gui_float min, gui_float val, gui_float max, gui_float step,
const struct gui_slider*, const struct gui_input*);
@ -307,7 +420,7 @@ gui_size gui_progress(const struct gui_canvas*, gui_float x, gui_float y, gui_fl
const struct gui_slider*, const struct gui_input*);
gui_size gui_input(const struct gui_canvas*, gui_float x, gui_float y, gui_float w,
gui_float h, gui_char*, gui_size, gui_size max, gui_bool*,
const struct gui_input_field*, const struct gui_input*);
const struct gui_input_field*, const struct gui_input*, const struct gui_font*);
gui_int gui_histo(const struct gui_canvas*, gui_float x, gui_float y, gui_float w,
gui_float h, const gui_float*, gui_size,
const struct gui_histo*, const struct gui_input*);
@ -319,10 +432,10 @@ gui_float gui_scroll(const struct gui_canvas*, gui_float x, gui_float y,
gui_float step, const struct gui_scroll*, const struct gui_input*);
/* Panel */
void gui_default_config(struct gui_config*);
gui_bool gui_panel_begin(struct gui_panel*, const char*, gui_float x, gui_float y,
gui_float w, gui_float h, gui_flags, const struct gui_config*,
const struct gui_canvas*, const struct gui_input*);
const struct gui_canvas*, const struct gui_font*, const struct gui_input*);
void gui_default_config(struct gui_config*);
gui_bool gui_panel_is_hidden(const struct gui_panel*);
void gui_panel_layout(struct gui_panel*, gui_float height, gui_size cols);
void gui_panel_seperator(struct gui_panel*, gui_size cols);
@ -333,8 +446,6 @@ gui_bool gui_panel_button_text(struct gui_panel*, const char*, enum gui_button_b
gui_bool gui_panel_button_color(struct gui_panel*, const struct gui_color, enum gui_button_behavior);
gui_bool gui_panel_button_triangle(struct gui_panel*, enum gui_heading, enum gui_button_behavior);
gui_bool gui_panel_button_toggle(struct gui_panel*, const char*, gui_bool value);
gui_bool gui_panel_button_icon(struct gui_panel*, void *bitmap, const struct gui_rect*,
enum gui_button_behavior);
gui_float gui_panel_slider(struct gui_panel*, gui_float min, gui_float val,
gui_float max, gui_float step);
gui_size gui_panel_progress(struct gui_panel*, gui_size cur, gui_size max,
@ -347,9 +458,9 @@ gui_size gui_panel_selector(struct gui_panel*, const char *items[],
gui_size item_count, gui_size item_current);
gui_int gui_panel_plot(struct gui_panel*, const gui_float *values, gui_size value_count);
gui_int gui_panel_histo(struct gui_panel*, const gui_float *values, gui_size value_count);
gui_bool gui_panel_tab_begin(struct gui_panel*, struct gui_panel*, const char *title, gui_bool minimized);
gui_bool gui_panel_tab_begin(struct gui_panel*, struct gui_panel*, const char*, gui_bool minimized);
void gui_panel_tab_end(struct gui_panel*, struct gui_panel *tab);
void gui_panel_group_begin(struct gui_panel *panel, struct gui_panel*, const char *title, gui_float offset);
void gui_panel_group_begin(struct gui_panel *panel, struct gui_panel*, const char*,gui_float offset);
gui_float gui_panel_group_end(struct gui_panel*, struct gui_panel* tab);
gui_size gui_panel_shelf_begin(struct gui_panel*, struct gui_panel *shelf,
const char *tabs[], gui_size size, gui_size active, gui_float offset);