diff --git a/Readme.md b/Readme.md index e60c50a..be4a732 100644 --- a/Readme.md +++ b/Readme.md @@ -5,143 +5,60 @@ WORK IN PROGRESS: I do not garantee that everything works right now ## Features - Immediate mode graphical user interface toolkit - Written in C89 (ANSI C) -- Small (~2.5kLOC) +- Small codebase with roughly 2kLOC - Focus on portability and minimal internal state - Suited for embedding into graphical applications - No global hidden state - No direct dependencies (not even libc!) +- No memory allocation - Renderer and platform independent - Configurable - UTF-8 supported ## Limitations -- Does NOT provide platform independent window management -- Does NOT provide platform independent input handling +- Does NOT provide window management +- Does NOT provide input handling - Does NOT provide a renderer backend - Does NOT implement a font library Summary: It is only responsible for the actual user interface -## Layer -The gui toolkit consists of three levels of abstraction. First the basic widget layer -for a as pure functional as possible set of widgets functions without -any kind of internal state, with the tradeoff off of a lot of boilerplate code. -Second the panel layer for a static grouping of widgets into a panel with a reduced need for -a lot of the boilerplate code but takes away some freedom of widget placing and -introduces the state of the panel. -Finally there is the context layer which represent the complete window and -enables moveable, scaleable and overlapping panels, but needs complete control -over the panel management and therefore needs the most amount of internal state. -Each higher level of abstraction uses the lower level(s) internally to build -on but offers a little bit different API. - #### Widgets -The widget layer provides the most basic way of creating graphical user interface -elements. It consist only of functions and only operates on the given data. Each -widgets takes in the current input state, font and the basic element configuration -and returns an updated draw buffer and the state of the element. -With each widget the buffer gets filled with a number of primitives that need be -drawn to screen. The main reason for the command buffer to queue up the draw -calls instead of just using a callback to directly draw the primitive lies in -the context which needs control over the drawing order. For a more limited scope -of functionality it would have been better to just use draw callbacks and to not -rely on memory allocation at all. The API will change if I find a way to -combine the buffer needed by the context with the drawing callbacks. - ```c -struct gui_input input = {0}; -struct gui_command_buffer buffer; -struct gui_command_list list; -struct gui_memory_status status; -const struct gui_font font = {...}; -const struct gui_buffer button = {...}; -struct gui_memory memory = {...}; +struct gui_input in = {0}; +struct gui_canvas canvas = {...}; +struct gui_button style = {...}; +gui_default_config(&config); while (1) { gui_input_begin(&input); /* record input */ gui_input_end(&input); - gui_output_begin(&buffer, &memory); - if (gui_widget_button(&buffer, &button, "button", &font, &input)) + if (gui_button_text(&canvas, 50, 50, 100, 30, &style, "button", GUI_BUTTON_DEFAULT, &input)) fprintf(stdout, "button pressed!\n"); - gui_output_end(&buffer, &status, &list); - /* execute command list */ } ``` #### Panels -Panels provide an easy way to group together a number of widgets and reduce -some of the boilerplate code of the widget layer. Most of the boilerplate code -gets reduced by introducing a configration structure to provide a common look. -Instead of having a fixed layout and owning and holding widgets like in classic -graphical user interfaces, panels use an immediate mode approach of just setting -the layout of one row of the panel at a time and filling each row with widgets. -Therefore the only state that is being modfied over the course of setting up the -panel is an index descriping the current position of the next widget and the -current height and number of columns of the current row. In addition panels -provide a number of grouping functionality for widgets with groups, tabs and -shelfs and provide a minimizing and closing functionality. - ```c +struct gui_input in = {0}; struct gui_config config; -struct gui_command_buffer buffer; -struct gui_command_list list; -struct gui_memory_status status; -const struct gui_font font = {...}; -struct gui_memory memory = {...}; struct gui_panel panel = {0}; +struct gui_canvas canvas = {...}; gui_default_config(&config); -gui_panel_init(&panel, &config, &font); while (1) { gui_input_begin(&input); /* record input */ gui_input_end(&input); - gui_output_begin(&buffer, &memory); - gui_panel_begin(&panel, &buffer, &input, "Demo", 50, 50, 400, 300, 0); + gui_panel_begin(&panel, "Demo", panel.x, panel.y, panel.width, panel.height, + GUI_PANEL_CLOSEABLE|GUI_PANEL_MINIMIZABLE|GUI_PANEL_BORDER| + GUI_PANEL_MOVEABLE|GUI_PANEL_SCALEABLE, &config, &canvas, &in); gui_panel_layout(&panel, 30, 1); if (gui_panel_button_text(&panel, "button", GUI_BUTTON_DEFAULT)) fprintf(stdout, "button pressed!\n"); gui_panel_end(&panel); - gui_output_end(&buffer, &status, &list); - /* execute command list */ -} -``` - -#### Context -The context extends the panel functionality with moving, scaling and overlapping -panels which are quite a bit more complicated than just minimzing and closing of -panels. For panel overlapping to work as intented the context needs complete control -over all created panels to control the drawing order. OVerall the expense to -provide overlapping panels is quite hight since draw calls, the context and -all panels need to be managed and allocated. - -```c -struct gui_config config; -struct gui_output output; -struct gui_memory_status status; -const struct gui_font font = {...}; -struct gui_memory memory = {...}; -struct gui_panel *panel; -struct gui_context *ctx; -gui_default_config(&config); -ctx = gui_new(&memory, &input); -panel = gui_new_panel(ctx, 50, 50, 400, 300, &config, &font); - -while (1) { - gui_input_begin(&input); - /* record input */ - gui_input_end(&input); - - gui_begin(ctx, 800, 600); - gui_begin_panel(ctx, panel, "demo", 0); - gui_panel_layout(&panel, 30, 1); - if (gui_panel_button_text(&panel, "button", GUI_BUTTON_DEFAULT)) - fprintf(stdout, "button pressed!\n"); - gui_end_panel(ctx, &panel, NULL); - gui_end(ctx, &output, NULL); - /* execute output lists */ } ``` @@ -198,22 +115,6 @@ 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 do you use fixed size memory management -This is one of the more controversial decision in the toolkit and it comes down -to some preference that I personally build up. There are two general -ways to allocate memory, the standard way of callbacks and preallocation. -Personally I am not a big fan of callbacks even though they have their use cases -for abstraction purposes but are greatly overused in my experience. -Memory callbacks are an edge case for me and definitly shine in cases where a lot -of unpredictable allocation with varying life cycles take place. This toolkit on -the other hand has a relative stable memory allocation behavior. In the worse -case on the highst abstraction layer only the context, panels and the command -buffer need memory. In addition the general memory consumption is not that high -and could even be described as insignificant for the modern memory size. For a -system with a low amount of memory it is even better since there is only a small -limited amount of memory which is easier to optimize for as a fixed amount of memory than -a number of unrelated allocation calls. - ## 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/) diff --git a/demo/xlib.c b/demo/xlib.c index 325f0a5..36242f3 100644 --- a/demo/xlib.c +++ b/demo/xlib.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -11,10 +12,8 @@ #include "../gui.h" /* macros */ -#define MAX_BUFFER 64 -#define MAX_MEMORY (16 * 1024) -#define MAX_DEPTH 8 -#define MAX_PANEL 4 +#define MAX_BUFFER 64 +#define MAX_DEPTH 4 #define WIN_WIDTH 800 #define WIN_HEIGHT 600 #define DTIME 16 @@ -29,38 +28,6 @@ typedef struct XFont XFont; typedef struct XSurface XSurface; typedef struct XWindow XWindow; -struct XFont { - int ascent; - int descent; - int height; - XFontSet set; - XFontStruct *xfont; -}; - -struct XSurface { - GC gc; - Display *dpy; - int screen; - Window root; - Drawable drawable; - unsigned int w, h; -}; - -struct XWindow { - Display *dpy; - Window root; - Visual *vis; - Colormap cmap; - XWindowAttributes attr; - XSetWindowAttributes swa; - Window win; - GC gc; - int screen; - unsigned int width; - unsigned int height; - XSurface surface; -}; - struct demo { gui_char in_buf[MAX_BUFFER]; gui_size in_len; @@ -78,6 +45,38 @@ struct demo { gui_size current; }; +struct XFont { + int ascent; + int descent; + int height; + XFontSet set; + XFontStruct *xfont; +}; + +struct XSurface { + GC gc; + Display *dpy; + int screen; + Window root; + Drawable drawable; + unsigned int w, h; + gui_size clip_depth; + struct gui_rect clips[MAX_DEPTH]; +}; + +struct XWindow { + Display *dpy; + Window root; + Visual *vis; + Colormap cmap; + XWindowAttributes attr; + XSetWindowAttributes swa; + Window win; + int screen; + unsigned int width; + unsigned int height; +}; + static void die(const char *fmt, ...) { @@ -115,122 +114,6 @@ sleep_for(long t) while(-1 == nanosleep(&req, &req)); } -static XSurface* -surface_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) -{ - XSurface *surface = xcalloc(1, sizeof(XSurface)); - surface->w = w; - surface->h = h; - surface->dpy = dpy; - surface->screen = screen; - surface->root = root; - surface->gc = XCreateGC(dpy, root, 0, NULL); - XSetLineAttributes(dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter); - surface->drawable = XCreatePixmap(dpy, root, w, h, (unsigned int)DefaultDepth(dpy, screen)); - return surface; -} - -static void -surface_resize(XSurface *surf, unsigned int w, unsigned int h) { - if(!surf) return; - surf->w = w; surf->h = h; - if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable); - surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h, - (unsigned int)DefaultDepth(surf->dpy, surf->screen)); -} - -static void -surface_scissor(XSurface *surf, int x, int y, unsigned int w, unsigned int h) -{ - XRectangle clip_rect; - clip_rect.x = (short)x; - clip_rect.y = (short)y; - clip_rect.width = (unsigned short)w; - clip_rect.height = (unsigned short)h; - clip_rect.width = (unsigned short)MIN(surf->w, clip_rect.width); - clip_rect.height = (unsigned short)MIN(surf->h, clip_rect.height); - XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted); -} - -static void -surface_draw_line(XSurface *surf, int x0, int y0, int x1, int y1, unsigned long c) -{ - XSetForeground(surf->dpy, surf->gc, c); - XDrawLine(surf->dpy, surf->drawable, surf->gc, x0, y0, x1, y1); -} - -static void -surface_draw_rect(XSurface *surf, int x, int y, unsigned int w, unsigned int h, unsigned long c) -{ - XSetForeground(surf->dpy, surf->gc, c); - XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h); -} - -static void -surface_draw_triangle(XSurface *surf, int x0, int y0, int x1, int y1, int x2, int y2, - unsigned long c) -{ - XPoint pnts[3]; - 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(XSurface *surf, int x, int y, unsigned int radius, unsigned long c) -{ - unsigned int d = radius * 2; - XSetForeground(surf->dpy, surf->gc, c); - x -= (int)radius; - y -= (int)radius; - XFillArc(surf->dpy, surf->drawable, surf->gc, x, y, d, d, 0, 360 * 64); -} - -static void -surface_draw_text(XSurface *surf, XFont *font, int x, int y, unsigned int w, unsigned int h, - const char *text, unsigned int len, unsigned long bg, unsigned long fg) -{ - int i, tx, ty, th, olen; - XSetForeground(surf->dpy, surf->gc, bg); - XFillRectangle(surf->dpy, surf->drawable, surf->gc, x, y, w, h); - if(!text || !font || !len) return; - - th = font->ascent + font->descent; - ty = y + ((int)h / 2) - (th / 2) + font->ascent; - tx = x;/* + ((int)h / 2);*/ - XSetForeground(surf->dpy, surf->gc, fg); - if(font->set) - XmbDrawString(surf->dpy, surf->drawable, font->set, surf->gc, tx, ty, text, (int)len); - else - XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, text, (int)len); -} - -static void -surface_clear(XSurface *surf, unsigned long color) -{ - XSetForeground(surf->dpy, surf->gc, color); - XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h); -} - -static void -surface_blit(Drawable target, XSurface *surf, unsigned int width, unsigned int height) -{ - XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, width, height, 0, 0); -} - -static void -surface_del(XSurface *surf) -{ - XFreePixmap(surf->dpy, surf->drawable); - XFreeGC(surf->dpy, surf->gc); - free(surf); -} - static XFont* font_create(Display *dpy, const char *name) { @@ -295,6 +178,153 @@ font_del(Display *dpy, XFont *font) free(font); } +static unsigned long +color_from_byte(struct gui_color col) +{ + unsigned long res = 0; + res |= (unsigned long)col.r << 16; + res |= (unsigned long)col.g << 8; + res |= (unsigned long)col.b << 0; + return (res); +} + +static XSurface* +surface_create(Display *dpy, int screen, Window root, unsigned int w, unsigned int h) +{ + XSurface *surface = xcalloc(1, sizeof(XSurface)); + surface->w = w; + surface->h = h; + surface->dpy = dpy; + surface->screen = screen; + surface->root = root; + surface->gc = XCreateGC(dpy, root, 0, NULL); + XSetLineAttributes(dpy, surface->gc, 1, LineSolid, CapButt, JoinMiter); + surface->drawable = XCreatePixmap(dpy, root, w, h, (unsigned int)DefaultDepth(dpy, screen)); + return surface; +} + +static void +surface_resize(XSurface *surf, unsigned int w, unsigned int h) { + if(!surf) return; + if (surf->w == w && surf->h == h) return; + surf->w = w; surf->h = h; + if(surf->drawable) XFreePixmap(surf->dpy, surf->drawable); + surf->drawable = XCreatePixmap(surf->dpy, surf->root, w, h, + (unsigned int)DefaultDepth(surf->dpy, surf->screen)); +} + +static void +unify(struct gui_rect *clip, const struct gui_rect *a, const struct gui_rect *b) +{ + 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; + clip_rect.width = (unsigned short)w; + clip_rect.height = (unsigned short)h; + clip_rect.width = (unsigned short)MIN(surf->w, clip_rect.width); + clip_rect.height = (unsigned short)MIN(surf->h, clip_rect.height); + XSetClipRectangles(surf->dpy, surf->gc, 0, 0, &clip_rect, 1, Unsorted); +} + +static void +surface_draw_line(void *handle, gui_float x0, gui_float y0, gui_float x1, gui_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) +{ + 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) +{ + 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; + 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) +{ + 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, + (unsigned)w, (unsigned)h, 0, 360 * 64); +} + +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) +{ + 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); + + XSetForeground(surf->dpy, surf->gc, bg); + XFillRectangle(surf->dpy, surf->drawable, surf->gc, (int)x, (int)y, (unsigned)w, (unsigned)h); + if(!text || !font || !len) return; + + tx = (int)x; + th = font->ascent + font->descent; + ty = (int)y + ((int)h / 2) - (th / 2) + font->ascent; + XSetForeground(surf->dpy, surf->gc, fg); + if(font->set) + XmbDrawString(surf->dpy, surf->drawable, font->set, surf->gc, tx, ty, (const char*)text, (int)len); + else + XDrawString(surf->dpy, surf->drawable, surf->gc, tx, ty, (const char*)text, (int)len); +} + +static void +surface_clear(XSurface *surf, unsigned long color) +{ + XSetForeground(surf->dpy, surf->gc, color); + XFillRectangle(surf->dpy, surf->drawable, surf->gc, 0, 0, surf->w, surf->h); +} + +static void +surface_blit(Drawable target, XSurface *surf, unsigned int width, unsigned int height) +{ + XCopyArea(surf->dpy, surf->drawable, target, surf->gc, 0, 0, width, height, 0, 0); +} + +static void +surface_del(XSurface *surf) +{ + XFreePixmap(surf->dpy, surf->drawable); + XFreeGC(surf->dpy, surf->gc); + free(surf); +} + static void key(struct XWindow *xw, struct gui_input *in, XEvent *evt, gui_bool down) { @@ -329,7 +359,7 @@ motion(struct gui_input *in, XEvent *evt) } static void -button(struct gui_input *in, XEvent *evt, gui_bool down) +btn(struct gui_input *in, XEvent *evt, gui_bool down) { const gui_int x = evt->xbutton.x; const gui_int y = evt->xbutton.y; @@ -346,103 +376,24 @@ resize(struct XWindow *xw, XSurface *surf) surface_resize(surf, xw->width, xw->height); } -static unsigned long -color_from_byte(struct gui_color col) -{ - unsigned long res = 0; - res |= (unsigned long)col.r << 16; - res |= (unsigned long)col.g << 8; - res |= (unsigned long)col.b << 0; - return (res); -} - static void -execute(XSurface *surf, const struct gui_command_list *list) -{ - const struct gui_command *iter = NULL; - if (!list->count) return; - iter = list->begin; - while (iter != list->end) { - switch (iter->type) { - case GUI_COMMAND_NOP: break; - case GUI_COMMAND_CLIP: { - const struct gui_command_clip *clip = (const struct gui_command_clip*)iter; - surface_scissor(surf, (int)clip->x, (int)clip->y, - (unsigned int)clip->w, (unsigned int)clip->h); - } break; - case GUI_COMMAND_LINE: { - const struct gui_command_line *line = (const struct gui_command_line*)iter; - const unsigned long color = color_from_byte(line->color); - surface_draw_line(surf, (int)line->from.x, (int)line->from.y, - (int)line->to.x, (int)line->to.y, color); - } break; - case GUI_COMMAND_RECT: { - const struct gui_command_rect *rect = (const struct gui_command_rect*)iter; - const unsigned long color = color_from_byte(rect->color); - surface_draw_rect(surf, (int)rect->x, (int)rect->y, - (unsigned int)rect->w, (unsigned int)rect->h, color); - } break; - case GUI_COMMAND_CIRCLE: { - const struct gui_command_circle *circle = (const struct gui_command_circle*)iter; - const unsigned long color = color_from_byte(circle->color); - surface_draw_circle(surf, (int)circle->x, (int)circle->y, - (unsigned int)circle->radius, color); - } break; - case GUI_COMMAND_BITMAP: { - const struct gui_command_bitmap *bitmap = (const struct gui_command_bitmap*)iter; - } break; - case GUI_COMMAND_TRIANGLE: { - const struct gui_command_triangle *triangle = (const struct gui_command_triangle*)iter; - const unsigned long color = color_from_byte(triangle->color); - surface_draw_triangle(surf, (int)triangle->pnt[0].x, (int)triangle->pnt[0].y, - (int)triangle->pnt[1].x, (int)triangle->pnt[1].y, (int)triangle->pnt[2].x, - (int)triangle->pnt[2].y, color); - } break; - case GUI_COMMAND_TEXT: { - const struct gui_command_text *text = (const struct gui_command_text*)iter; - const unsigned long bg = color_from_byte(text->background); - const unsigned long fg = color_from_byte(text->foreground); - surface_draw_text(surf, text->font, (int)text->x, (int)text->y, - (unsigned int)text->w, (unsigned int)text->h, - (const char*)text->string, (unsigned int)text->length, bg, fg); - } break; - case GUI_COMMAND_MAX: break; - default: break; - } - iter = iter->next; - } -} - -static void -gui_draw(XSurface *surf, const struct gui_output *out) -{ - gui_size i = 0; - if (!out->list_size) return; - for (i = 0; i < out->list_size; i++) - execute(surf, out->list[i]); -} - -static gui_bool -demo_panel(struct gui_context *ctx, struct gui_panel *panel, struct demo *demo) +demo_panel(struct gui_panel *panel, struct demo *demo) { enum {HISTO, PLOT}; const char *shelfs[] = {"Histogram", "Lines"}; const gui_float values[] = {8.0f, 15.0f, 20.0f, 12.0f, 30.0f}; const char *items[] = {"Fist", "Pistol", "Shotgun", "Railgun", "BFG"}; - gui_bool running; - - running = gui_begin_panel(ctx, panel, "Demo", - GUI_PANEL_CLOSEABLE|GUI_PANEL_MINIMIZABLE|GUI_PANEL_SCALEABLE| - GUI_PANEL_MOVEABLE|GUI_PANEL_BORDER); /* Tabs */ gui_panel_layout(panel, 100, 1); gui_panel_tab_begin(panel, &demo->tab, "Difficulty"); - gui_panel_layout(&demo->tab, 30, 1); + gui_panel_layout(&demo->tab, 30, 3); if (gui_panel_option(&demo->tab, "easy", demo->option == 0)) demo->option = 0; - if (gui_panel_option(&demo->tab, "hard", demo->option == 1)) demo->option = 1; - if (gui_panel_option(&demo->tab, "normal", demo->option == 2)) demo->option = 2; - if (gui_panel_option(&demo->tab, "godlike", demo->option == 3)) demo->option = 3; + if (gui_panel_option(&demo->tab, "normal", demo->option == 1)) demo->option = 1; + if (gui_panel_option(&demo->tab, "hard", demo->option == 2)) demo->option = 2; + if (gui_panel_option(&demo->tab, "hell", demo->option == 3)) demo->option = 3; + if (gui_panel_option(&demo->tab, "doom", demo->option == 4)) demo->option = 4; + if (gui_panel_option(&demo->tab, "godlike", demo->option == 5)) demo->option = 5; gui_panel_tab_end(panel, &demo->tab); /* Shelf */ @@ -466,23 +417,7 @@ demo_panel(struct gui_context *ctx, struct gui_panel *panel, struct demo *demo) demo->prog = gui_panel_progress(&demo->group, demo->prog, 100, gui_true); demo->item_cur = gui_panel_selector(&demo->group, items, LEN(items), demo->item_cur); demo->spin_act = gui_panel_spinner(&demo->group, 0, &demo->spinner, 250, 10, demo->spin_act); - demo->in_act = gui_panel_input(&demo->group, demo->in_buf, &demo->in_len, - MAX_BUFFER, GUI_INPUT_DEFAULT, demo->in_act); gui_panel_group_end(panel, &demo->group); - - gui_end_panel(ctx, panel, NULL); - return running; -} - -static void -message_panel(struct gui_context *ctx, struct gui_panel *panel) -{ - gui_int ret = -1; - gui_begin_panel(ctx, panel, "Error", GUI_PANEL_MOVEABLE|GUI_PANEL_BORDER); - gui_panel_layout(panel, 30, 2); - gui_panel_button_text(panel, "ok", GUI_BUTTON_DEFAULT); - gui_panel_button_text(panel, "cancel", GUI_BUTTON_DEFAULT); - gui_end_panel(ctx, panel, NULL); } int @@ -491,23 +426,19 @@ main(int argc, char *argv[]) long dt; long started; gui_bool running = gui_true; + XWindow xw; /* GUI */ - struct demo demo; + gui_bool checked = gui_false; + gui_float value = 5.0f; + gui_size done = 20; struct gui_input in; struct gui_config config; - struct gui_memory memory; - struct gui_font font; - struct gui_panel *panel; - struct gui_panel *message; - struct gui_context *ctx; - struct gui_output output; + struct gui_canvas canvas; + struct gui_panel panel; + struct demo demo; /* Window */ - XWindow xw; - XSurface *surf; - XFont *xfont; - UNUSED(argc); UNUSED(argv); memset(&xw, 0, sizeof xw); xw.dpy = XOpenDisplay(NULL); @@ -527,22 +458,26 @@ 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; - xfont = font_create(xw.dpy, "fixed"); - surf = surface_create(xw.dpy, xw.screen, xw.win, xw.width, xw.height); /* GUI */ - memory.size = MAX_MEMORY; - memory.memory = calloc(1, memory.size); - memory.max_depth = MAX_DEPTH; - memory.max_panels = MAX_PANEL; - ctx = gui_new(&memory, &in); - - font.user = xfont; - font.height = (gui_float)xfont->height; - font.width = font_get_text_width; + 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); - panel = gui_new_panel(ctx, 50, 50, 400, 300, &config, &font); - message = gui_new_panel(ctx, 150, 150, 200, 100, &config, &font); + memset(&in, 0, sizeof in); + memset(&panel, 0, sizeof panel); + panel.x = 50; panel.y = 50; + /*panel.w = 420; panel.h = 300;*/ + panel.w = 420; panel.h = 200; memset(&demo, 0, sizeof(demo)); demo.tab.minimized = gui_true; @@ -559,25 +494,24 @@ main(int argc, char *argv[]) while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &evt)) { if (evt.type == KeyPress) key(&xw, &in, &evt, gui_true); else if (evt.type == KeyRelease) key(&xw, &in, &evt, gui_false); - else if (evt.type == ButtonPress) button(&in, &evt, gui_true); - else if (evt.type == ButtonRelease) button(&in, &evt, gui_false); + else if (evt.type == ButtonPress) btn(&in, &evt, gui_true); + 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, surf); + resize(&xw, canvas.userdata); } gui_input_end(&in); /* GUI */ - gui_begin(ctx, (gui_float)xw.width, (gui_float)xw.height); - running = demo_panel(ctx, panel, &demo); - message_panel(ctx, message); - gui_end(ctx, &output, NULL); - - /* Draw */ XClearWindow(xw.dpy, xw.win); - surface_clear(surf, 0x00646464); - gui_draw(surf, &output); - surface_blit(xw.win, surf, xw.width, xw.height); + surface_clear(canvas.userdata, 0x002D2D2D); + canvas.width = xw.width; canvas.height = 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); + demo_panel(&panel, &demo); + gui_panel_end(&panel); + surface_blit(xw.win, canvas.userdata, xw.width, xw.height); XFlush(xw.dpy); /* Timing */ @@ -586,9 +520,10 @@ main(int argc, char *argv[]) sleep_for(DTIME - dt); } - free(memory.memory); - font_del(xw.dpy, xfont); - surface_del(surf); + font_del(xw.dpy, canvas.font.userdata); + surface_del(canvas.userdata); + XUnmapWindow(xw.dpy, xw.win); + XFreeColormap(xw.dpy, xw.cmap); XDestroyWindow(xw.dpy, xw.win); XCloseDisplay(xw.dpy); return 0; diff --git a/gui.c b/gui.c index ee75a15..9d7463b 100644 --- a/gui.c +++ b/gui.c @@ -23,8 +23,6 @@ #define ABS(a) (((a) < 0) ? -(a) : (a)) #define BETWEEN(x, a, b) ((a) <= (x) && (x) <= (b)) #define INBOX(px, py, x, y, w, h) (BETWEEN(px, x, x+w) && BETWEEN(py, y, y+h)) -#define ALIGNOF(t) ((char*)(&((struct {char c; t _h;}*)0)->_h) - (char*)0) -#define ALIGN(x, mask) (void*)((gui_size)((gui_byte*)(x) + (mask-1)) & ~(mask-1)) #define col_load(c,j,k,l,m) (c).r = (j), (c).g = (k), (c).b = (l), (c).a = (m) #define vec2_load(v,a,b) (v).x = (a), (v).y = (b) @@ -33,30 +31,6 @@ #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) -struct gui_context_panel { - struct gui_panel panel; - gui_float x, y, w, h; - struct gui_command_list list; - struct gui_context_panel *next; - struct gui_context_panel *prev; -}; - -struct gui_context { - gui_float width, height; - struct gui_command_buffer global_buffer; - struct gui_command_buffer current_buffer; - const struct gui_input *input; - struct gui_context_panel *active; - struct gui_context_panel *panel_pool; - struct gui_context_panel *free_list; - struct gui_context_panel *stack_begin; - struct gui_context_panel *stack_end; - struct gui_command_list **output_list; - gui_size panel_capacity; - gui_size panel_size; -}; - -static const gui_texture null_tex; 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}; static const gui_char utfmask[GUI_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8}; @@ -74,6 +48,14 @@ memcopy(void *dst, const void *src, gui_size size) return dst; } +static void +zero(void *dst, gui_size size) +{ + gui_size i; + char *d = dst; + for (i = 0; i < size; ++i) d[i] = 0; +} + static gui_size strsiz(const char *str) { @@ -124,17 +106,6 @@ itos(char *buffer, gui_int num) return len; } -static void -unify(struct gui_rect *clip, const struct gui_rect *a, const struct gui_rect *b) -{ - 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); -} - static gui_size utf_validate(long *u, gui_size i) { @@ -317,395 +288,146 @@ gui_input_end(struct gui_input *in) vec2_sub(in->mouse_delta, in->mouse_pos, in->mouse_prev); } -static void -gui_command_list_init(struct gui_command_list *list, void *memory, - gui_size size) -{ - list->capacity = size; - list->begin = memory; - list->end = list->begin; - list->size = 0; - list->needed = 0; - list->count = 0; -} - -static void -gui_command_list_clear(struct gui_command_list *list) -{ - list->count = 0; - list->size = 0; - list->needed = 0; - list->end = list->begin; -} - void -gui_output_begin(struct gui_command_buffer *buffer, const struct gui_memory *memory) -{ - void *cmds; - gui_size clip_size; - - assert(buffer); - assert(memory); - if (!buffer || !memory) - return; - - buffer->clips = memory->memory; - buffer->clip_capacity = memory->max_depth; - buffer->clip_size = 0; - 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); -} - -static void* -gui_buffer_push(struct gui_command_buffer *buffer, enum gui_command_type type, - gui_size size) -{ - gui_size alignment; - void *unaligned; - const gui_size align = ALIGNOF(struct gui_command); - struct gui_command_list *list = &buffer->cmds; - struct gui_command *cmd; - list->needed += size; - if ((list->size + size) > list->capacity) return NULL; - - cmd = list->end; - unaligned = (gui_byte*)list->end + size; - list->end = ALIGN(unaligned, align); - alignment = (gui_size)((gui_byte*)list->end - (gui_byte*)unaligned); - list->size += size + alignment; - list->needed += alignment; - list->count++; - - cmd->type = type; - cmd->next = list->end; - return cmd; -} - -static gui_bool -gui_buffer_push_clip(struct gui_command_buffer *buffer, const struct gui_rect *rect) -{ - struct gui_command_clip *cmd; - struct gui_rect clip; - assert(buffer); - assert(rect); - if (!buffer || !rect || buffer->clip_size >= buffer->clip_capacity) - return gui_false; - - cmd = gui_buffer_push(buffer, GUI_COMMAND_CLIP, sizeof(*cmd)); - if (!cmd) return gui_false; - unify(&clip, rect, (!buffer->clip_size) ? &null_rect : &buffer->clips[buffer->clip_size-1]); - buffer->clips[buffer->clip_size] = clip; - buffer->clip_size++; - cmd->x = clip.x; - cmd->y = clip.y; - cmd->w = clip.w; - cmd->h = clip.h; - return gui_true; -} - -static void -gui_buffer_pop_clip(struct gui_command_buffer *buffer) -{ - struct gui_command_clip *cmd; - const struct gui_rect *clip; - assert(buffer); - if (!buffer || !buffer->clip_capacity) return; - if (buffer->clip_size == 0) { - buffer->clips[buffer->clip_size] = null_rect; - buffer->clip_size = 1; - } else { - buffer->clip_size--; - } - - clip = (!buffer->clip_size) ? &null_rect : &buffer->clips[buffer->clip_size-1]; - cmd = gui_buffer_push(buffer, GUI_COMMAND_CLIP, sizeof(*cmd)); - if (!cmd) return; - cmd->x = clip->x; - cmd->y = clip->y; - cmd->w = clip->w; - cmd->h = clip->h; -} - -static void -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) -{ - 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; -} - -static void -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) -{ - 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; -} - -static void -gui_buffer_push_circle(struct gui_command_buffer *buffer, gui_float x, gui_float y, - gui_float r, struct gui_color color) -{ - 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; -} - -static void -gui_buffer_push_triangle(struct gui_command_buffer *buffer, struct gui_vec2 *pos, - struct gui_color color) -{ - 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; -} - -static void -gui_buffer_push_bitmap(struct gui_command_buffer *buffer, const struct gui_rect *src, - const struct gui_rect *dst, gui_texture texture) -{ - struct gui_command_bitmap *bitmap; - bitmap = gui_buffer_push(buffer, GUI_COMMAND_BITMAP, sizeof(*bitmap)); - if (!bitmap) return; - bitmap->src = *src; - bitmap->dst = *dst; - bitmap->texture = texture; -} - -static void -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); -} - -void -gui_output_end(struct gui_command_buffer *buffer, struct gui_command_list *list, - struct gui_memory_status* status) -{ - assert(buffer); - if (!buffer) return; - if (status) { - status->allocated = buffer->cmds.size; - status->needed = buffer->cmds.needed; - } - - if (list) *list = buffer->cmds; - gui_command_list_clear(&buffer->cmds); - buffer->clip_size = 0; -} - -void -gui_widget_text(struct gui_command_buffer *buffer, const struct gui_text *text, - const struct gui_font *font) +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_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(buffer); assert(text); - assert(font); - if (!buffer || !text || !font) - return; + if (!text) return; - text_width = font->width(font->user, (const gui_char*)text->string, text->length); - label_y = text->y + text->pad_y; - label_h = MAX(0, text->h - 2 * text->pad_y); + 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); if (text->align == GUI_TEXT_LEFT) { - label_x = text->x + text->pad_x; - label_w = MAX(0, text->w - 2 * text->pad_x); + label_x = x + text->padding.x; + label_w = MAX(0, w - 2 * text->padding.x); } else if (text->align == GUI_TEXT_CENTERED) { - 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); + label_w = 3 * text->padding.x + (gui_float)text_width; + label_x = (x + text->padding.x + ((w - 2 * text->padding.x)/2)) - (label_w/2); } else if (text->align == GUI_TEXT_RIGHT) { - 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; + label_x = MAX(x, (x + w) - (2 * text->padding.x + (gui_float)text_width)); + label_w = (gui_float)text_width + 2 * text->padding.x; } else return; - 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); -} -void -gui_widget_image(struct gui_command_buffer *buffer, const struct gui_image *image) -{ - struct gui_rect dst; - assert(buffer); - assert(image); - if (!buffer || !image) return; - - dst.x = image->dst.x + image->pad_x; - dst.y = image->dst.y + image->pad_y; - dst.w = MAX(0, image->dst.w - 2 * image->pad_x); - dst.h = MAX(0, image->dst.h - 2 * image->pad_y); - - gui_buffer_push_rect(buffer, image->dst.x, image->dst.y, image->dst.w, image->dst.h, image->background); - gui_buffer_push_bitmap(buffer, &image->src, &dst, image->texture); + clip.x = x; clip.y = y; + clip.w = w; clip.h = h; + canvas->draw_rect(canvas->userdata, x, y, w, h, text->background); + canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h, + (const gui_char*)string, len, font, text->background, text->foreground); } static gui_bool -gui_widget_button(struct gui_command_buffer *buffer, const struct gui_button *button, - const struct gui_input *in) +gui_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) { gui_bool ret = gui_false; struct gui_color background; struct gui_color highlight; + struct gui_rect inner; - assert(buffer); assert(button); - if (!buffer || !button) + if (!button) return gui_false; background = button->background; - if (in && INBOX(in->mouse_pos.x,in->mouse_pos.y,button->x,button->y,button->w,button->h)) { + if (in && INBOX(in->mouse_pos.x,in->mouse_pos.y, x, y, w, h)) { background = button->highlight; - if (INBOX(in->mouse_clicked_pos.x, in->mouse_clicked_pos.y, - button->x, button->y, button->w, button->h)) { - if (button->behavior == GUI_BUTTON_DEFAULT) + if (INBOX(in->mouse_clicked_pos.x, in->mouse_clicked_pos.y, x, y, w, h)) { + if (behavior == GUI_BUTTON_DEFAULT) ret = (in->mouse_down && in->mouse_clicked); else ret = in->mouse_down; } } - 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); + canvas->draw_rect(canvas->userdata, x, y, w, h, button->foreground); + canvas->draw_rect(canvas->userdata, x + button->border, y + button->border, + w - 2 * button->border, h - 2 * button->border, background); return ret; } gui_bool -gui_widget_button_text(struct gui_command_buffer *buffer, const struct gui_button *button, - const char *string, const struct gui_font *font, 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 struct gui_button *button, const char *string, enum gui_button_behavior b, + const struct gui_input *in) { gui_bool ret = gui_false; gui_float button_w, button_h; struct gui_text text; struct gui_color font_color; struct gui_color bg_color; + gui_float inner_x, inner_y; + gui_float inner_w, inner_h; + const struct gui_font *font; - assert(buffer); assert(button); assert(string); - assert(font); - if (!buffer || !button) + assert(canvas); + if (!canvas || !button) return gui_false; + font = &canvas->font; font_color = button->content; bg_color = button->background; - button_w = MAX(button->w, font->height + 2 * button->pad_x); - button_h = MAX(button->h, font->height + 2 * button->pad_y); - if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, button->x, button->y, button_w, button_h)) { + button_w = MAX(w, font->height + 2 * button->padding.x); + button_h = MAX(h, font->height + 2 * button->padding.y); + if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, x, y, button_w, button_h)) { font_color = button->highlight_content; bg_color = button->highlight; } - ret = gui_widget_button(buffer, button, in); + ret = gui_button(canvas, x, y, button_w, button_h, button, in, b); - 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 = strsiz(string); + inner_x = x + button->border; + inner_y = y + button->border; + inner_w = button_w - 2 * button->border; + inner_h = button_h - 2 * button->border; + + text.padding.x = button->padding.x; + text.padding.y = button->padding.y; text.align = GUI_TEXT_CENTERED; - text.font = font->user; text.background = bg_color; text.foreground = font_color; - gui_widget_text(buffer, &text, font); + gui_text(canvas, inner_x, inner_y, inner_w, inner_h, &text, string, strsiz(string)); return ret; } gui_bool -gui_widget_button_triangle(struct gui_command_buffer *buffer, struct gui_button* button, - enum gui_heading heading, 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, + const struct gui_button *button, enum gui_heading heading, enum gui_button_behavior b, + const struct gui_input *in) { gui_bool pressed; struct gui_color col; struct gui_vec2 points[3]; - pressed = gui_widget_button(buffer, button, in); - gui_triangle_from_direction(points, button->x, button->y, button->w, button->h, - button->pad_x, button->pad_y, heading); - col = (in && INBOX(in->mouse_pos.x,in->mouse_pos.y,button->x,button->y,button->w,button->h)) ? - button->highlight_content : button->foreground; - gui_buffer_push_triangle(buffer, points, col); - return pressed; -} - -gui_bool -gui_widget_button_icon(struct gui_command_buffer *buffer, struct gui_button* button, - gui_texture texture, const struct gui_rect *src, const struct gui_input *in) -{ - gui_bool pressed; - struct gui_image image; - struct gui_color col; - - assert(buffer); assert(button); - if (!buffer || !button) + assert(canvas); + if (!canvas || !button) return gui_false; - pressed = gui_widget_button(buffer, button, in); - image.dst.x = button->x + button->pad_x; - image.dst.y = button->y + button->pad_y; - image.dst.w = button->w - 2 * button->pad_x; - image.dst.h = button->h - 2 * button->pad_y; - image.pad_x = button->pad_x; - image.pad_y = button->pad_y; - image.texture = texture; - image.src = *src; - 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; - gui_widget_image(buffer, &image); + pressed = gui_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_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) +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_bool toggle_active; gui_float select_size; @@ -713,20 +435,24 @@ gui_widget_toggle(struct gui_command_buffer *buffer, const struct gui_toggle *to gui_float select_x, select_y; gui_float cursor_x, cursor_y; gui_float cursor_pad, cursor_size; + gui_draw_rect draw[2]; + const struct gui_font *font; - assert(buffer); assert(toggle); - assert(font); - if (!buffer || !toggle || !font) + assert(canvas); + if (!canvas || !toggle) return 0; - toggle_w = MAX(toggle->w, font->height + 2 * toggle->pad_x); - toggle_h = MAX(toggle->h, font->height + 2 * toggle->pad_y); + 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); + toggle_h = MAX(h, font->height + 2 * toggle->padding.y); toggle_active = active; - select_x = toggle->x + toggle->pad_x; - select_y = toggle->y + toggle->pad_y; - select_size = font->height + 2 * toggle->pad_y; + select_x = x + toggle->padding.x; + select_y = y + toggle->padding.y; + select_size = font->height + 2 * toggle->padding.y; cursor_pad = (gui_float)(gui_int)(select_size / 8); cursor_size = select_size - cursor_pad * 2; @@ -738,44 +464,34 @@ gui_widget_toggle(struct gui_command_buffer *buffer, const struct gui_toggle *to 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 { - select_x += select_size / 2; - select_y += select_size / 2; - gui_buffer_push_circle(buffer, select_x, select_y, select_size/2, toggle->background); - if (toggle_active) { - cursor_x += cursor_size / 2; - cursor_y += cursor_size / 2; - gui_buffer_push_circle(buffer, cursor_x, cursor_y, cursor_size/2, toggle->foreground); - } - } + 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); - if (font && toggle->text && toggle->length) { + if (font && string) { 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; + gui_float inner_x, inner_y; + gui_float inner_w, inner_h; + + inner_x = x + select_size + toggle->padding.x * 2; + inner_y = (y + (select_size / 2)) - (font->height / 2); + inner_w = (x + toggle_w) - (inner_x + toggle->padding.x); + inner_h = (y + toggle_h) - (inner_y + toggle->padding.y); + + text.padding.x = 0; + text.padding.y = 0; text.align = GUI_TEXT_LEFT; - text.font = font->user; text.background = toggle->foreground; text.foreground = toggle->font; - gui_widget_text(buffer, &text, font); + gui_text(canvas, inner_x, inner_y, inner_w, inner_h, &text, string, strsiz(string)); } return toggle_active; } gui_float -gui_widget_slider(struct gui_command_buffer *buffer, const struct gui_slider *slider, - const struct gui_input *in) +gui_slider(const struct gui_canvas *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 *slider, const struct gui_input *in) { gui_float slider_range; gui_float slider_min, slider_max; @@ -785,48 +501,47 @@ gui_widget_slider(struct gui_command_buffer *buffer, const struct gui_slider *sl gui_float cursor_x, cursor_y; gui_float cursor_w, cursor_h; - assert(buffer); assert(slider); - if (!buffer || !slider) + assert(canvas); + if (!canvas || !slider) 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); + slider_w = MAX(w, 2 * slider->padding.x); + slider_h = MAX(h, 2 * slider->padding.y); + slider_max = MAX(min, max); + slider_min = MIN(min, max); + slider_value = CLAMP(slider_min, val, slider_max); slider_range = slider_max - slider_min; - slider_steps = slider_range / slider->step; + slider_steps = slider_range / step; - cursor_offset = (slider_value - slider_min) / slider->step; - cursor_w = (slider_w - 2 * slider->pad_x) / (slider_steps + 1); - cursor_h = slider_h - 2 * slider->pad_y; - cursor_x = slider->x + slider->pad_x + (cursor_w * cursor_offset); - cursor_y = slider->y + slider->pad_y; + cursor_offset = (slider_value - slider_min) / step; + cursor_w = (slider_w - 2 * slider->padding.x) / (slider_steps + 1); + cursor_h = slider_h - 2 * slider->padding.y; + cursor_x = x + slider->padding.x + (cursor_w * cursor_offset); + cursor_y = y + slider->padding.y; 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)) + INBOX(in->mouse_pos.x, in->mouse_pos.y, x, y, slider_w, slider_h) && + INBOX(in->mouse_clicked_pos.x,in->mouse_clicked_pos.y, x, y, slider_w, slider_h)) { const float d = in->mouse_pos.x - (cursor_x + cursor_w / 2.0f); - const float pxstep = (slider_w - 2 * slider->pad_x) / slider_steps; + const float pxstep = (slider_w - 2 * slider->padding.x) / slider_steps; if (ABS(d) >= pxstep) { const gui_float steps = (gui_float)((gui_int)(ABS(d) / pxstep)); - slider_value += (d > 0) ? (slider->step * steps) : -(slider->step * steps); + slider_value += (d > 0) ? (step * steps) : -(step * steps); slider_value = CLAMP(slider_min, slider_value, slider_max); - cursor_x = slider->x + slider->pad_x + (cursor_w * (slider_value - slider_min)); + cursor_x = x + slider->padding.x + (cursor_w * (slider_value - slider_min)); } } - - 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); + canvas->draw_rect(canvas->userdata, x, y, slider_w, slider_h, slider->background); + canvas->draw_rect(canvas->userdata, cursor_x, cursor_y, cursor_w, cursor_h, slider->foreground); return slider_value; } gui_size -gui_widget_progress(struct gui_command_buffer *buffer, const struct gui_progress *prog, - const struct gui_input *in) +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; @@ -834,31 +549,29 @@ gui_widget_progress(struct gui_command_buffer *buffer, const struct gui_progress gui_float prog_w, prog_h; gui_size prog_value; - assert(buffer); assert(prog); + assert(canvas); + if (!canvas || !prog) return 0; + prog_w = MAX(w, 2 * prog->padding.x + 1); + prog_h = MAX(h, 2 * prog->padding.y + 1); + prog_value = MIN(value, max); - if (!buffer || !prog) return 0; - 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); - - if (in && prog->modifyable && in->mouse_down && - 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); + 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); } - if (!prog->max) return prog_value; - prog_value = MIN(prog_value, prog->max); - prog_scale = (gui_float)prog_value / (gui_float)prog->max; + if (!max) return prog_value; + prog_value = MIN(prog_value, max); + prog_scale = (gui_float)prog_value / (gui_float)max; - 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; + cursor_h = prog_h - 2 * prog->padding.y; + cursor_w = (prog_w - 2 * prog->padding.x) * prog_scale; + cursor_x = x + prog->padding.x; + cursor_y = y + prog->padding.y; - 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); + canvas->draw_rect(canvas->userdata, x, y, prog_w, prog_h, prog->background); + canvas->draw_rect(canvas->userdata, cursor_x, cursor_y, cursor_w, cursor_h, prog->foreground); return prog_value; } @@ -925,29 +638,30 @@ gui_buffer_input(gui_char *buffer, gui_size length, gui_size max, return text_len; } -gui_bool -gui_widget_input(struct gui_command_buffer *buf, gui_char *buffer, gui_size *length, - const struct gui_input_field *input, const struct gui_font *font, - const struct gui_input *in) +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) { gui_float input_w, input_h; gui_bool input_active; + const struct gui_font *font; - assert(buf); - assert(font); - assert(input); - assert(length); - if (!buffer || !font || !input) + assert(canvas); + assert(buffer); + assert(field); + assert(in); + if (!canvas || !buffer || !field || !in) return 0; - input_w = MAX(input->w, 2 * input->pad_x); - input_h = MAX(input->h, font->height); - input_active = input->active; - 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); + font = &canvas->font; + input_w = MAX(w, 2 * field->padding.x); + input_h = MAX(h, font->height); + input_active = *active; + canvas->draw_rect(canvas->userdata, x, y, input_w, input_h, field->background); + canvas->draw_rect(canvas->userdata, x + 1, y, input_w - 1, input_h, field->foreground); if (in && in->mouse_clicked && in->mouse_down) - input_active = INBOX(in->mouse_pos.x, in->mouse_pos.y, - input->x, input->y, input_w, input_h); + input_active = INBOX(in->mouse_pos.x, in->mouse_pos.y, x, y, input_w, input_h); if (input_active && in) { const struct gui_key *bs = &in->keys[GUI_KEY_BACKSPACE]; @@ -957,46 +671,48 @@ gui_widget_input(struct gui_command_buffer *buf, gui_char *buffer, gui_size *le const struct gui_key *space = &in->keys[GUI_KEY_SPACE]; if ((del->down && del->clicked) || (bs->down && bs->clicked)) - if (*length > 0) *length = *length - 1; + if (len > 0) len = len - 1; if ((enter->down && enter->clicked) || (esc->down && esc->clicked)) input_active = gui_false; - if ((space->down && space->clicked) && (*length < input->max)) - buffer[(*length)++] = ' '; - if (in->text_len && *length < input->max) - *length += gui_buffer_input(buffer, *length, input->max, input->filter, in); + if ((space->down && space->clicked) && (len < max)) + buffer[len++] = ' '; + if (in->text_len && len < max) + len += gui_buffer_input(buffer, len, max, field->filter, in); } - if (font && buffer && length) { + if (font && buffer && len) { gui_size offset = 0; gui_float label_x, label_y, label_h; - gui_float label_w = input_w - 2 * input->pad_x; - gui_size cursor_width = (gui_size)font->width(font->user, (const gui_char*)"X", 1); + gui_float label_w = input_w - 2 * field->padding.x; + gui_size cursor_width = (gui_size)font->width(font->userdata, (const gui_char*)"X", 1); - gui_size text_len = *length; - gui_size text_width = font->width(font->user, buffer, text_len); + gui_size text_len = len; + gui_size text_width = font->width(font->userdata, buffer, text_len); 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; - text_width = font->width(font->user, &buffer[offset], text_len); + text_width = font->width(font->userdata, &buffer[offset], text_len); } - label_x = input->x + input->pad_x; - label_y = input->y + input->pad_y; - label_h = input_h - 2 * input->pad_y; - gui_buffer_push_text(buf, font->user, label_x, label_y, label_w, label_h, - &buffer[offset], text_len, input->foreground, input->background); - if (input_active && input->show_cursor) { - gui_buffer_push_rect(buf, label_x + (gui_float)text_width, label_y, - (gui_float)cursor_width, label_h, input->background); + label_x = x + field->padding.x; + label_y = y + field->padding.y; + label_h = input_h - 2 * field->padding.y; + canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h, + &buffer[offset], text_len, font, field->foreground, field->background); + if (input_active && field->show_cursor) { + canvas->draw_rect(canvas->userdata, label_x + (gui_float)text_width, label_y, + (gui_float)cursor_width, label_h, field->background); } } - return input_active; + *active = input_active; + return len; } gui_int -gui_widget_plot(struct gui_command_buffer *buffer, const struct gui_plot *plot, - const struct gui_input *in) +gui_plot(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w, + gui_float h, const gui_float *values, gui_size value_count, + const struct gui_plot *plot, const struct gui_input *in) { gui_size i; struct gui_color col; @@ -1011,35 +727,35 @@ gui_widget_plot(struct gui_command_buffer *buffer, const struct gui_plot *plot, gui_float plot_max_value, plot_min_value; gui_float plot_value_range, plot_value_ratio; - assert(buffer); + assert(canvas); assert(plot); - if (!buffer || !plot) + if (!canvas || !plot) return plot_selected; col = plot->foreground; - plot_w = MAX(plot->w, 2 * plot->pad_x); - plot_h = MAX(plot->h, 2 * plot->pad_y); - gui_buffer_push_rect(buffer, plot->x, plot->y, plot_w, plot_h, plot->background); - if (!plot->value_count) + plot_w = MAX(w, 2 * plot->padding.x); + plot_h = MAX(h, 2 * plot->padding.y); + canvas->draw_rect(canvas->userdata, x, y, plot_w, plot_h, plot->background); + if (!value_count) return plot_selected; - plot_max_value = plot->values[0]; - plot_min_value = plot->values[0]; - for (i = 0; i < plot->value_count; ++i) { - 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]; + plot_max_value = values[0]; + plot_min_value = values[0]; + for (i = 0; i < value_count; ++i) { + if (values[i] > plot_max_value) + plot_max_value = values[i]; + if (values[i] < plot_min_value) + plot_min_value = values[i]; } - 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); + canvas_x = x + plot->padding.x; + canvas_y = y + plot->padding.y; + canvas_w = MAX(1 + 2 * plot->padding.x, plot_w - 2 * plot->padding.x); + canvas_h = MAX(1 + 2 * plot->padding.y, plot_h - 2 * plot->padding.y); - plot_step = (gui_size)canvas_w / plot->value_count; + plot_step = (gui_size)canvas_w / value_count; plot_value_range = plot_max_value - plot_min_value; - plot_value_ratio = (plot->values[0] - plot_min_value) / plot_value_range; + plot_value_ratio = (values[0] - plot_min_value) / plot_value_range; plot_last_x = canvas_x; plot_last_y = (canvas_y + canvas_h) - plot_value_ratio * (gui_float)canvas_h; @@ -1047,14 +763,14 @@ gui_widget_plot(struct gui_command_buffer *buffer, const struct gui_plot *plot, plot_selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i : -1; col = plot->highlight; } - gui_buffer_push_rect(buffer, plot_last_x - 3, plot_last_y - 3, 6, 6, col); + canvas->draw_rect(canvas->userdata, plot_last_x - 3, plot_last_y - 3, 6, 6, col); - for (i = 1; i < plot->value_count; i++) { + for (i = 1; i < value_count; i++) { gui_float plot_cur_x, plot_cur_y; - plot_value_ratio = (plot->values[i] - plot_min_value) / plot_value_range; + plot_value_ratio = (values[i] - plot_min_value) / plot_value_range; plot_cur_x = canvas_x + (gui_float)(plot_step * i); plot_cur_y = (canvas_y + canvas_h) - (plot_value_ratio * (gui_float)canvas_h); - gui_buffer_push_line(buffer, plot_last_x, plot_last_y, plot_cur_x, plot_cur_y, + canvas->draw_line(canvas->userdata, plot_last_x, plot_last_y, plot_cur_x, plot_cur_y, plot->foreground); if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, plot_cur_x-3, plot_cur_y-3, 6, 6)) { @@ -1062,15 +778,16 @@ gui_widget_plot(struct gui_command_buffer *buffer, const struct gui_plot *plot, col = plot->highlight; } else col = plot->foreground; - gui_buffer_push_rect(buffer, plot_cur_x - 3, plot_cur_y - 3, 6, 6, col); + 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; } return plot_selected; } gui_int -gui_widget_histo(struct gui_command_buffer *buffer, const struct gui_histo *histo, - const struct gui_input *in) +gui_histo(const struct gui_canvas *canvas, gui_float x, gui_float y, gui_float w, + gui_float h, const gui_float *values, gui_size value_count, + const struct gui_histo *histo, const struct gui_input *in) { gui_size i; gui_int selected = -1; @@ -1080,50 +797,52 @@ gui_widget_histo(struct gui_command_buffer *buffer, const struct gui_histo *hist gui_float histo_w, histo_h; gui_float item_w = 0.0f; - assert(buffer); + assert(canvas); assert(histo); - if (!buffer || !histo) + assert(in); + if (!canvas || !histo || !in) return selected; - histo_w = MAX(histo->w, 2 * histo->pad_x); - histo_h = MAX(histo->h, 2 * histo->pad_y); - gui_buffer_push_rect(buffer, histo->x, histo->y, histo_w, histo_h, histo->background); + histo_w = MAX(w, 2 * histo->padding.x); + histo_h = MAX(h, 2 * histo->padding.y); + canvas->draw_rect(canvas->userdata, x, y, histo_w, histo_h, histo->background); - histo_max_value = histo->values[0]; - for (i = 0; i < histo->value_count; ++i) { - if (ABS(histo->values[i]) > histo_max_value) - histo_max_value = histo->values[i]; + histo_max_value = values[0]; + for (i = 0; i < value_count; ++i) { + if (ABS(values[i]) > histo_max_value) + histo_max_value = values[i]; } - 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; - 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); + canvas_x = x + histo->padding.x; + canvas_y = y + histo->padding.y; + canvas_w = histo_w - 2 * histo->padding.x; + canvas_h = histo_h - 2 * histo->padding.y; + if (value_count) { + gui_float padding = (gui_float)(value_count-1) * histo->padding.x; + item_w = (canvas_w - padding) / (gui_float)(value_count); } - for (i = 0; i < histo->value_count; i++) { - 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; + for (i = 0; i < value_count; i++) { + const gui_float histo_ratio = ABS(values[i]) / histo_max_value; + struct gui_color item_color = (values[i] < 0) ? histo->negative: histo->foreground; const gui_float item_h = canvas_h * histo_ratio; const gui_float item_y = (canvas_y + canvas_h) - item_h; gui_float item_x = canvas_x + ((gui_float)i * item_w); - item_x = item_x + ((gui_float)i * histo->pad_y); + item_x = item_x + ((gui_float)i * histo->padding.y); if (in && INBOX(in->mouse_pos.x, in->mouse_pos.y, item_x, item_y, item_w, item_h)) { selected = (in->mouse_down && in->mouse_clicked) ? (gui_int)i: selected; item_color = histo->highlight; } - gui_buffer_push_rect(buffer, item_x, item_y, item_w, item_h, item_color); + canvas->draw_rect(canvas->userdata, item_x, item_y, item_w, item_h, item_color); } return selected; } gui_float -gui_widget_scroll(struct gui_command_buffer *buffer, const struct gui_scroll *scroll, - const struct gui_input *in) +gui_scroll(const struct gui_canvas *canvas, gui_float x, gui_float y, + gui_float w, gui_float h, gui_float offset, gui_float target, + gui_float step, const struct gui_scroll *scroll, const struct gui_input *in) { gui_bool button_up_pressed; gui_bool button_down_pressed; @@ -1138,63 +857,58 @@ gui_widget_scroll(struct gui_command_buffer *buffer, const struct gui_scroll *sc gui_float cursor_w, cursor_h; gui_bool inscroll, incursor; - assert(buffer); + assert(canvas); assert(scroll); - if (!buffer || !scroll) return 0; + if (!canvas || !scroll) return 0; - scroll_w = MAX(scroll->w, 0); - scroll_h = MAX(scroll->h, 2 * scroll_w); - 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); - if (scroll->target <= scroll_h) return 0; + scroll_w = MAX(w, 0); + scroll_h = MAX(h, 2 * scroll_w); + canvas->draw_rect(canvas->userdata, x, y, scroll_w, scroll_h, scroll->background); + if (target <= scroll_h) return 0; - button.x = scroll->x; - button.y = scroll->y; - button.w = scroll_w; - button.h = scroll_w; button.border = 1; - button.pad_x = scroll_w / 4; - button.pad_y = scroll_w / 4; - button.background = scroll->foreground; - button.foreground = scroll->background; - button.highlight = scroll->foreground; - button.highlight_content = scroll->background; - button.behavior = GUI_BUTTON_DEFAULT; - button_up_pressed = gui_widget_button_triangle(buffer, &button, GUI_UP, in); - button.y = scroll->y + scroll_h - button.h; - button_down_pressed = gui_widget_button_triangle(buffer, &button, GUI_DOWN, in); + button.padding.x = scroll_w / 4; + button.padding.y = scroll_w / 4; + button.background = scroll->background; + button.foreground = scroll->foreground; + button.content = scroll->foreground; + button.highlight = scroll->background; + button.highlight_content = scroll->foreground; - scroll_h = scroll_h - 2 * button.h; - scroll_y = scroll->y + button.h; - 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; + button_up_pressed = gui_button_triangle(canvas, x, y, scroll_w, scroll_w, + &button, GUI_UP, GUI_BUTTON_DEFAULT, 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_h = scroll_h - 2 * scroll_w; + scroll_y = y + scroll_w; + scroll_step = MIN(step, scroll_h); + scroll_offset = MIN(offset, target - scroll_h); + scroll_ratio = scroll_h / target; + scroll_off = scroll_offset / target; cursor_h = scroll_ratio * scroll_h; cursor_y = scroll_y + (scroll_off * scroll_h); cursor_w = scroll_w; - cursor_x = scroll->x; + cursor_x = x; if (in) { - inscroll = INBOX(in->mouse_pos.x,in->mouse_pos.y,scroll->x,scroll->y,scroll_w,scroll_h); + inscroll = INBOX(in->mouse_pos.x,in->mouse_pos.y, x, y, scroll_w, scroll_h); incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,cursor_x,cursor_y,cursor_w, cursor_h); 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); + const gui_float delta = (pixel / scroll_h) * target; + scroll_offset = CLAMP(0, scroll_offset + delta, 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): + MIN(scroll_offset + scroll_step, target - scroll_h): MAX(0, scroll_offset - scroll_step); - scroll_off = scroll_offset / scroll->target; + scroll_off = scroll_offset / target; cursor_y = scroll_y + (scroll_off * scroll_h); } } - - 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); + canvas->draw_rect(canvas->userdata, cursor_x, cursor_y, cursor_w, cursor_h, scroll->foreground); return scroll_offset; } @@ -1244,55 +958,32 @@ gui_default_config(struct gui_config *config) col_load(config->colors[GUI_COLOR_SCALER], 100, 100, 100, 255); } -void -gui_panel_init(struct gui_panel *panel, const struct gui_config *config, - const struct gui_font *font) -{ - panel->flags = 0; - panel->x = 0; - panel->y = 0; - panel->at_y = 0; - panel->width = 0; - panel->height = 0; - panel->index = 0; - panel->header_height = 0; - panel->row_height = 0; - panel->row_columns = 0; - panel->offset = 0; - panel->minimized = gui_false; - panel->out = NULL; - panel->in = NULL; - panel->font = *font; - panel->config = config; -} - gui_bool -gui_panel_begin(struct gui_panel *panel, struct gui_command_buffer *out, - const struct gui_input *in, const char *text, gui_float x, gui_float y, - gui_float w, gui_float h, gui_flags f) +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_config *config; const struct gui_color *header; - struct gui_rect clip; - gui_float mouse_x, mouse_y; gui_float clicked_x, clicked_y; gui_float header_x, header_w; gui_bool ret = gui_true; assert(panel); - assert(out); - if (!panel || !out) + assert(canvas); + assert(config); + if (!panel || !canvas || !config) return gui_false; if (panel->flags & GUI_PANEL_HIDDEN) return gui_false; - panel->out = out; panel->in = in; + panel->canvas = canvas; + panel->config = config; panel->x = x; panel->y = y; - panel->width = w; - panel->at_y = y; + panel->w = w; + panel->h = h; panel->index = 0; panel->row_columns = 0; panel->flags = f; @@ -1300,34 +991,69 @@ gui_panel_begin(struct gui_panel *panel, struct gui_command_buffer *out, panel->flags |= GUI_PANEL_SCROLLBAR; config = panel->config; + panel->header_height = canvas->font.height + 3 * config->item_padding.y; + panel->header_height += config->panel_padding.y; + if (panel->flags & GUI_PANEL_MOVEABLE) { + gui_bool incursor; + const gui_float move_x = panel->x; + const gui_float move_y = panel->y; + const gui_float move_w = panel->width; + const gui_float move_h = panel->header_height; + + 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); + } + } + + if (panel->flags & GUI_PANEL_SCALEABLE) { + gui_bool incursor; + gui_float scaler_x = panel->x + config->item_padding.x; + gui_float scaler_y = panel->y + panel->h - 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); + + incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,scaler_x, scaler_y, scaler_w, scaler_h); + 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); + } + } + header = &config->colors[GUI_COLOR_TITLEBAR]; - header_x = x + config->panel_padding.x; - header_w = w - 2 * config->panel_padding.x; + header_x = panel->x + config->panel_padding.x; + header_w = panel->w - 2 * config->panel_padding.x; 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; + panel->width = panel->w; + panel->at_y = panel->y; + canvas->draw_rect(canvas->userdata, panel->x, panel->y, panel->w, panel->header_height, *header); - panel->header_height = panel->font.height + 3 * config->item_padding.y; - panel->header_height += config->panel_padding.y; - gui_buffer_push_rect(out, x, y, w, panel->header_height, *header); - - 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; + panel->clip.x = panel->x; + panel->clip.w = panel->w; + panel->clip.y = panel->y + panel->header_height - 1; + if (panel->flags & GUI_PANEL_SCROLLBAR) { + panel->clip.h = panel->h; + panel->clip.h = panel->h - panel->header_height; + panel->clip.h -= (config->panel_padding.y + config->item_padding.y); + } + else panel->clip.h = null_rect.h; if (panel->flags & GUI_PANEL_CLOSEABLE) { const gui_char *X = (const gui_char*)"x"; - const gui_size text_width = panel->font.width(panel->font.user, X, 1); + const gui_size text_width = canvas->font.width(canvas->font.userdata, X, 1); const gui_float close_x = header_x; - const gui_float close_y = y + config->panel_padding.y; + 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 = 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]); + const gui_float close_h = canvas->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]); header_w -= close_w; header_x += close_h - config->item_padding.x; @@ -1346,14 +1072,13 @@ gui_panel_begin(struct gui_panel *panel, struct gui_command_buffer *out, (const gui_char*)"+": (const gui_char*)"-"; - text_width = panel->font.width(panel->font.user, score, 1); + text_width = canvas->font.width(canvas->font.userdata, score, 1); min_x = header_x; - min_y = y + config->panel_padding.y; + min_y = panel->y + config->panel_padding.y; 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]); - + min_h = canvas->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]); header_w -= min_w; header_x += min_w - config->item_padding.x; @@ -1367,51 +1092,40 @@ gui_panel_begin(struct gui_panel *panel, struct gui_command_buffer *out, if (text) { 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; + 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 = 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]); + const gui_float label_h = canvas->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], + config->colors[GUI_COLOR_TEXT]); } panel->row_height = panel->header_height; if (panel->flags & GUI_PANEL_SCROLLBAR) { const struct gui_color *color = &config->colors[GUI_COLOR_PANEL]; - panel->width -= config->scrollbar_width; - panel->height = h - panel->header_height; + panel->width = panel->w - config->scrollbar_width; + panel->height = panel->h - panel->header_height; if (!panel->minimized) - gui_buffer_push_rect(panel->out, x, y + panel->header_height, w, - h - panel->header_height, *color); + canvas->draw_rect(canvas->userdata, panel->x, panel->y + panel->header_height, + panel->w, panel->h - panel->header_height, *color); } if (panel->flags & GUI_PANEL_BORDER) { - const struct gui_color *color; - color = &config->colors[GUI_COLOR_BORDER]; - gui_buffer_push_line(panel->out, x, y, x + w, y, *color); + const struct gui_color *color = &config->colors[GUI_COLOR_BORDER]; + const gui_float width = (panel->flags & GUI_PANEL_SCROLLBAR) ? + panel->width + config->scrollbar_width : panel->width; + + canvas->draw_line(canvas->userdata, panel->x, panel->y, + panel->x + panel->w, panel->y, *color); + canvas->draw_line(canvas->userdata, panel->x, panel->y, panel->x, + panel->y + panel->header_height, config->colors[GUI_COLOR_BORDER]); + canvas->draw_line(canvas->userdata, panel->x + width, panel->y, panel->x + width, + panel->y + panel->header_height, config->colors[GUI_COLOR_BORDER]); } - gui_buffer_push_clip(out, &clip); + canvas->scissor(canvas->userdata, panel->clip.x, panel->clip.y, panel->clip.w, panel->clip.h); return ret; } -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; -} - -gui_bool -gui_panel_is_hidden(const struct gui_panel *panel) -{ - return panel->flags & GUI_PANEL_HIDDEN; -} - void gui_panel_layout(struct gui_panel *panel, gui_float height, gui_size cols) { @@ -1423,7 +1137,7 @@ gui_panel_layout(struct gui_panel *panel, gui_float height, gui_size cols) if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return; assert(panel->config); - assert(panel->out); + assert(panel->canvas); config = panel->config; color = &config->colors[GUI_COLOR_PANEL]; @@ -1431,8 +1145,8 @@ gui_panel_layout(struct gui_panel *panel, gui_float height, gui_size cols) panel->at_y += panel->row_height; panel->row_columns = cols; panel->row_height = height + config->item_spacing.y; - gui_buffer_push_rect(panel->out, panel->x, panel->at_y, panel->width, - height + config->panel_padding.y, *color); + panel->canvas->draw_rect(panel->canvas->userdata, panel->x, panel->at_y, panel->width, + height + config->panel_padding.y, *color); } void @@ -1442,7 +1156,7 @@ gui_panel_seperator(struct gui_panel *panel, gui_size cols) assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); if (!panel) return; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return; @@ -1497,27 +1211,20 @@ gui_panel_text(struct gui_panel *panel, const char *str, gui_size len, assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(str && len); - if (!panel || !panel->config || !panel->out) return; + if (!panel || !panel->config || !panel->canvas) return; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return; 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; - text.string = str; - text.length = len; + text.padding.x = config->item_padding.x; + text.padding.y = config->item_padding.y; text.align = alignment; - text.font = panel->font.user; text.foreground = config->colors[GUI_COLOR_TEXT]; text.background = config->colors[GUI_COLOR_PANEL]; - gui_widget_text(panel->out, &text, &panel->font); + gui_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, &text, str, len); } gui_bool @@ -1530,27 +1237,23 @@ gui_panel_button_text(struct gui_panel *panel, const char *str, assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); - if (!panel || !panel->config || !panel->out) return 0; + 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.x = bounds.x; - button.y = bounds.y; - button.w = bounds.w; - button.h = bounds.h; button.border = 1; - button.behavior = behavior; - button.pad_x = config->item_padding.x; - button.pad_y = config->item_padding.y; + 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_widget_button_text(panel->out, &button, str, &panel->font, panel->in); + return gui_button_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + &button, str, behavior, panel->in); } gui_bool gui_panel_button_color(struct gui_panel *panel, const struct gui_color color, @@ -1562,26 +1265,21 @@ gui_bool gui_panel_button_color(struct gui_panel *panel, const struct gui_color assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); - if (!panel || !panel->config || !panel->out) return 0; + 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.x = bounds.x; - button.y = bounds.y; - button.w = bounds.w; - button.h = bounds.h; button.border = 1; - button.behavior = behavior; - button.pad_x = config->item_padding.x; - button.pad_y = config->item_padding.y; + button.padding.x = config->item_padding.x; + button.padding.y = config->item_padding.y; button.background = color; button.foreground = color; button.highlight = color; button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER_FONT]; - return gui_widget_button(panel->out, &button, panel->in); + return gui_button(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, &button, panel->in, behavior); } gui_bool @@ -1594,59 +1292,23 @@ gui_panel_button_triangle(struct gui_panel *panel, enum gui_heading heading, assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); - if (!panel || !panel->config || !panel->out) return 0; + 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.x = bounds.x; - button.y = bounds.y; - button.w = bounds.w; - button.h = bounds.h; button.border = 1; - button.behavior = behavior; - button.pad_x = config->item_padding.x; - button.pad_y = config->item_padding.y; + 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_widget_button_triangle(panel->out, &button, heading, panel->in); -} - -gui_bool -gui_panel_button_icon(struct gui_panel *panel, gui_texture tex, - 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->out); - - if (!panel || !panel->config || !panel->out) return 0; - if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return 0; - 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; - button.behavior = behavior; - button.pad_x = config->item_padding.x; - button.pad_y = config->item_padding.y; - button.background = config->colors[GUI_COLOR_BUTTON]; - button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER]; - button.content = config->colors[GUI_COLOR_TEXT]; - button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER]; - button.highlight_content = config->colors[GUI_COLOR_BUTTON_HOVER]; - return gui_widget_button_icon(panel->out, &button, tex, src, panel->in); + return gui_button_triangle(panel->canvas, bounds.x, bounds.y, bounds.w, + bounds.h, &button, heading, behavior, panel->in); } gui_bool @@ -1658,23 +1320,17 @@ gui_panel_button_toggle(struct gui_panel *panel, const char *str, gui_bool value assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(str); - if (!panel || !panel->config || !panel->out) return 0; + 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.x = bounds.x; - button.y = bounds.y; - button.w = bounds.w; - button.h = bounds.h; button.border = 1; - button.behavior = GUI_BUTTON_DEFAULT; - button.pad_x = config->item_padding.x; - button.pad_y = config->item_padding.y; - + button.padding.x = config->item_padding.x; + button.padding.y = config->item_padding.y; if (!value) { button.background = config->colors[GUI_COLOR_BUTTON]; button.foreground = config->colors[GUI_COLOR_BUTTON_BORDER]; @@ -1688,8 +1344,8 @@ gui_panel_button_toggle(struct gui_panel *panel, const char *str, gui_bool value button.highlight = config->colors[GUI_COLOR_BUTTON_HOVER]; button.highlight_content = config->colors[GUI_COLOR_BUTTON]; } - if (gui_widget_button_text(panel->out, &button, str, &panel->font, panel->in)) - value = !value; + if (gui_button_text(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + &button, str, GUI_BUTTON_DEFAULT, panel->in)) value = !value; return value; } @@ -1699,32 +1355,24 @@ gui_panel_check(struct gui_panel *panel, const char *text, gui_bool is_active) struct gui_rect bounds; struct gui_toggle toggle; const struct gui_config *config; - gui_size length; assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(text); - if (!panel || !panel->config || !panel->out) return is_active; + if (!panel || !panel->config || !panel->canvas) return is_active; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return is_active; gui_panel_alloc_space(&bounds, panel); config = panel->config; - length = strsiz(text); - 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_CHECK; + toggle.padding.x = config->item_padding.x; + toggle.padding.y = config->item_padding.y; toggle.font = config->colors[GUI_COLOR_TEXT]; toggle.background = config->colors[GUI_COLOR_CHECK]; toggle.foreground = config->colors[GUI_COLOR_CHECK_ACTIVE]; - return gui_widget_toggle(panel->out, &toggle, is_active, &panel->font, panel->in); + return gui_toggle(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + is_active, text, &toggle, GUI_TOGGLE_CHECK, panel->in); } gui_bool @@ -1733,32 +1381,24 @@ gui_panel_option(struct gui_panel *panel, const char *text, gui_bool is_active) struct gui_rect bounds; struct gui_toggle toggle; const struct gui_config *config; - gui_size length; assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(text); - if (!panel || !panel->config || !panel->out) return is_active; + if (!panel || !panel->config || !panel->canvas) return is_active; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return is_active; gui_panel_alloc_space(&bounds, panel); config = panel->config; - length = strsiz(text); - 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.padding.x = config->item_padding.x; + toggle.padding.y = config->item_padding.y; toggle.font = config->colors[GUI_COLOR_TEXT]; toggle.background = config->colors[GUI_COLOR_CHECK]; toggle.foreground = config->colors[GUI_COLOR_CHECK_ACTIVE]; - return gui_widget_toggle(panel->out, &toggle, is_active, &panel->font, panel->in); + return gui_toggle(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + is_active, text, &toggle, GUI_TOGGLE_OPTION, panel->in); } gui_float @@ -1771,26 +1411,19 @@ gui_panel_slider(struct gui_panel *panel, gui_float min_value, gui_float value, assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); - if (!panel || !panel->config || !panel->out) return value; + if (!panel || !panel->config || !panel->canvas) return value; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return value; gui_panel_alloc_space(&bounds, panel); config = panel->config; - 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.padding.x = config->item_padding.x; + slider.padding.y = config->item_padding.y; slider.background = config->colors[GUI_COLOR_SLIDER]; slider.foreground = config->colors[GUI_COLOR_SLIDER_CURSOR]; - return gui_widget_slider(panel->out, &slider, panel->in); + return gui_slider(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + min_value, value, max_value, value_step, &slider, panel->in); } gui_size @@ -1798,35 +1431,29 @@ gui_panel_progress(struct gui_panel *panel, gui_size cur_value, gui_size max_val gui_bool is_modifyable) { struct gui_rect bounds; - struct gui_progress prog; + struct gui_slider prog; const struct gui_config *config; assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); - if (!panel || !panel->config || !panel->out) return cur_value; + if (!panel || !panel->config || !panel->canvas) return cur_value; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return cur_value; gui_panel_alloc_space(&bounds, panel); config = panel->config; - 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.padding.x = config->item_padding.x; + prog.padding.y = config->item_padding.y; prog.background = config->colors[GUI_COLOR_PROGRESS]; prog.foreground = config->colors[GUI_COLOR_PROGRESS_CURSOR]; - return gui_widget_progress(panel->out, &prog, panel->in); + return gui_progress(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + cur_value, max_value, is_modifyable, &prog, panel->in); } -gui_bool -gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size *length, - gui_size max_length, enum gui_input_filter filter, gui_bool is_active) +gui_size +gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size len, + gui_size max, gui_bool *active, enum gui_input_filter filter) { struct gui_rect bounds; struct gui_input_field field; @@ -1834,29 +1461,23 @@ gui_panel_input(struct gui_panel *panel, gui_char *buffer, gui_size *length, assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(buffer); - assert(length); - if (!panel || !panel->config || !panel->out) return 0; + 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; - 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; + field.padding.x = config->item_padding.x; + field.padding.y = config->item_padding.y; field.filter = filter; - field.active = is_active; field.show_cursor = gui_true; field.font = config->colors[GUI_COLOR_TEXT]; field.background = config->colors[GUI_COLOR_INPUT]; field.foreground = config->colors[GUI_COLOR_INPUT_BORDER]; - return gui_widget_input(panel->out, buffer, length, &field, &panel->font, panel->in); + return gui_input(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + buffer, len, max, active, &field, panel->in); } gui_bool @@ -1865,65 +1486,70 @@ gui_panel_spinner(struct gui_panel *panel, gui_int min, gui_int *value, { struct gui_rect bounds; const struct gui_config *config; + const struct gui_canvas *canvas; struct gui_input_field field; char string[MAX_NUMBER_BUFFER]; gui_size len, old_len; struct gui_button button; + gui_float button_x, button_y; + gui_float button_w, button_h; + gui_float field_x, field_y; + gui_float field_w, field_h; gui_bool is_active, updated = gui_false; gui_bool button_up_clicked, button_down_clicked; assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(value); - if (!panel || !panel->config || !panel->out) return 0; + 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; + canvas = panel->canvas; *value = CLAMP(min, *value, max); len = itos(string, *value); is_active = active; old_len = len; - button.y = bounds.y; - button.h = bounds.h / 2; - button.w = bounds.h - config->item_padding.x; - button.x = bounds.x + bounds.w - button.w; button.border = 1; - button.pad_x = MAX(3, button.h - panel->font.height); - button.pad_y = MAX(3, button.h - panel->font.height); - button.behavior = GUI_BUTTON_DEFAULT; + button_y = bounds.y; + 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.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_widget_button_triangle(panel->out, &button, GUI_UP, panel->in); - button.y = bounds.y + button.h; - button_down_clicked = gui_widget_button_triangle(panel->out, &button, GUI_DOWN, panel->in); + button_up_clicked = gui_button_triangle(canvas, button_x, button_y, button_w, button_h, + &button, GUI_UP, GUI_BUTTON_DEFAULT, 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); 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_x = bounds.x; + field_y = bounds.y; + field_w = bounds.w - button_w; + field_h = bounds.h; + field.padding.x = config->item_padding.x; + field.padding.y = config->item_padding.y; 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]; - is_active = gui_widget_input(panel->out, (gui_char*)string, &len, &field, - &panel->font, panel->in); + len = gui_input(canvas, field_x, field_y, field_w, field_h, (gui_char*)string, + len, MAX_NUMBER_BUFFER, &is_active, &field, panel->in); if (old_len != len) strtoi(value, string, len); return is_active; @@ -1940,52 +1566,58 @@ gui_panel_selector(struct gui_panel *panel, const char *items[], struct gui_rect bounds; struct gui_button button; const struct gui_config *config; + const struct gui_canvas *canvas; gui_bool button_up_clicked, button_down_clicked; + gui_float button_x, button_y; + gui_float button_w, button_h; assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(items); assert(item_count); assert(item_current < item_count); - if (!panel || !panel->config || !panel->out) return 0; + 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; + canvas = panel->canvas; - gui_buffer_push_rect(panel->out, bounds.x, bounds.y, bounds.w, bounds.h, + canvas->draw_rect(canvas->userdata, bounds.x, bounds.y, bounds.w, bounds.h, config->colors[GUI_COLOR_SELECTOR_BORDER]); - gui_buffer_push_rect(panel->out, bounds.x + 1, bounds.y + 1, bounds.w - 2, bounds.h - 2, + canvas->draw_rect(canvas->userdata, bounds.x + 1, bounds.y + 1, bounds.w - 2, bounds.h - 2, config->colors[GUI_COLOR_SELECTOR]); button.border = 1; - button.y = bounds.y; - button.h = bounds.h / 2; - button.w = bounds.h - config->item_padding.x; - button.x = bounds.x + bounds.w - button.w; - button.pad_x = MAX(3, button.h - panel->font.height); - button.pad_y = MAX(3, button.h - panel->font.height); - button.behavior = GUI_BUTTON_DEFAULT; + button_y = bounds.y; + 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.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_widget_button_triangle(panel->out, &button, GUI_UP, panel->in); - button.y = bounds.y + button.h; - button_down_clicked = gui_widget_button_triangle(panel->out, &button, GUI_DOWN, 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; + button_up_clicked = gui_button_triangle(canvas, button_x, button_y, button_w, + button_h, &button, GUI_UP, GUI_BUTTON_DEFAULT, 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); + 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_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]); - gui_buffer_push_text(panel->out, panel->font.user, label_x, label_y, label_w, label_h, - (const gui_char*)items[item_current], text_len, - config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]); + canvas->draw_text(canvas->userdata, label_x, label_y, label_w, label_h, + (const gui_char*)items[item_current], text_len, &canvas->font, + config->colors[GUI_COLOR_PANEL], config->colors[GUI_COLOR_TEXT]); return item_current; } @@ -1998,27 +1630,22 @@ gui_panel_plot(struct gui_panel *panel, const gui_float *values, gui_size count) assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(values); assert(count); - if (!panel || !panel->config || !panel->out) return -1; + if (!panel || !panel->config || !panel->canvas) return -1; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return -1; gui_panel_alloc_space(&bounds, panel); config = panel->config; - 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.padding.x = config->item_padding.x; + plot.padding.y = config->item_padding.y; plot.background = config->colors[GUI_COLOR_PLOT]; plot.foreground = config->colors[GUI_COLOR_PLOT_LINES]; plot.highlight = config->colors[GUI_COLOR_PLOT_HIGHLIGHT]; - return gui_widget_plot(panel->out, &plot, panel->in); + return gui_plot(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + values, count, &plot, panel->in); } gui_int @@ -2030,34 +1657,32 @@ gui_panel_histo(struct gui_panel *panel, const gui_float *values, gui_size count assert(panel); assert(panel->config); - assert(panel->out); + assert(panel->canvas); assert(values); assert(count); - if (!panel || !panel->config || !panel->out) return -1; + if (!panel || !panel->config || !panel->canvas) return -1; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return -1; gui_panel_alloc_space(&bounds, panel); config = panel->config; - 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; - histo.value_count = count; + histo.padding.x = config->item_padding.x; + histo.padding.y = config->item_padding.y; histo.background = config->colors[GUI_COLOR_HISTO]; histo.foreground = config->colors[GUI_COLOR_HISTO_BARS]; histo.negative = config->colors[GUI_COLOR_HISTO_NEGATIVE]; histo.highlight = config->colors[GUI_COLOR_HISTO_HIGHLIGHT]; - return gui_widget_histo(panel->out, &histo, panel->in); + return gui_histo(panel->canvas, bounds.x, bounds.y, bounds.w, bounds.h, + values, count, &histo, panel->in); } gui_bool gui_panel_tab_begin(struct gui_panel *panel, gui_tab *tab, const char *title) { struct gui_rect bounds; + const struct gui_canvas *canvas; + gui_float clip_x, clip_y; + gui_float clip_h, clip_w; gui_float old_height; gui_size old_cols; gui_flags flags; @@ -2066,8 +1691,16 @@ gui_panel_tab_begin(struct gui_panel *panel, gui_tab *tab, const char *title) assert(panel); assert(tab); if (!panel || !tab) return gui_true; - if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) + canvas = panel->canvas; + min = tab->minimized; + zero(tab, sizeof(*tab)); + tab->minimized = min; + if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) { + tab->flags = GUI_PANEL_HIDDEN; + tab->config = panel->config; + tab->canvas = panel->canvas; return gui_false; + } old_height = panel->row_height; old_cols = panel->row_columns; @@ -2077,19 +1710,25 @@ gui_panel_tab_begin(struct gui_panel *panel, gui_tab *tab, const char *title) gui_panel_alloc_space(&bounds, panel); panel->row_columns = old_cols; panel->row_height = old_height; - min = tab->minimized; - gui_panel_init(tab, panel->config, &panel->font); - tab->minimized = min; - flags = GUI_PANEL_BORDER|GUI_PANEL_MINIMIZABLE|GUI_PANEL_TAB; - gui_panel_begin(tab, panel->out, panel->in, title, - bounds.x, bounds.y + 1, bounds.w, null_rect.h, flags); + 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); + + clip_x = MAX(panel->clip.x, tab->clip.x) - 1; + clip_y = MAX(panel->clip.y, tab->clip.y) - 1; + clip_w = MIN(panel->clip.x + panel->clip.w, tab->clip.x + tab->clip.w) - clip_x+ 2; + clip_h = MIN(panel->clip.y + panel->clip.h, tab->clip.y + tab->clip.h) - clip_y + 2; + clip_w = MAX(0, clip_w); + clip_h = MAX(0, clip_h); + canvas->scissor(canvas->userdata, clip_x, clip_y, clip_w, clip_h); return tab->minimized; } void gui_panel_tab_end(struct gui_panel *panel, struct gui_panel *tab) { + const struct gui_canvas *canvas; assert(tab); assert(panel); if (!panel || !tab || panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) @@ -2098,6 +1737,8 @@ gui_panel_tab_end(struct gui_panel *panel, struct gui_panel *tab) gui_panel_end(tab); panel->at_y -= panel->row_height; panel->at_y += tab->height + tab->config->item_spacing.y; + canvas = panel->canvas; + canvas->scissor(canvas->userdata, panel->clip.x, panel->clip.y, panel->clip.w, panel->clip.h); } void @@ -2106,30 +1747,60 @@ gui_panel_group_begin(struct gui_panel *panel, gui_group *group, const char *tit gui_flags flags; gui_float offset; struct gui_rect bounds; + const struct gui_canvas *canvas; + gui_float clip_x, clip_y; + gui_float clip_h, clip_w; assert(panel); assert(group); - if (!panel || !group || (panel->flags & GUI_PANEL_HIDDEN) || panel->minimized) + if (!panel || !group) return; + if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) { + group->flags = GUI_PANEL_HIDDEN; + group->config = panel->config; + group->canvas = panel->canvas; return; + } offset = group->offset; gui_panel_alloc_space(&bounds, panel); - gui_panel_init(group, panel->config, &panel->font); + zero(group, sizeof(*group)); + canvas = panel->canvas; group->offset = offset; flags = GUI_PANEL_BORDER|GUI_PANEL_SCROLLBAR|GUI_PANEL_TAB; - gui_panel_begin(group, panel->out, panel->in, title, - bounds.x, bounds.y, bounds.w, bounds.h, flags); + gui_panel_begin(group, title, bounds.x, bounds.y, bounds.w, bounds.h, flags, + panel->config, panel->canvas, panel->in); + + clip_x = MAX(panel->clip.x, group->clip.x) - 1; + clip_y = MAX(panel->clip.y, group->clip.y) - 1; + clip_w = MIN(panel->clip.x + panel->clip.w, group->clip.x + group->clip.w) - clip_x+ 2; + clip_h = MIN(panel->clip.y + panel->clip.h, group->clip.y + group->clip.h) - clip_y + 2; + clip_w = MAX(0, clip_w); + clip_h = MAX(0, clip_h); + canvas->scissor(canvas->userdata, clip_x, clip_y, clip_w, clip_h); } void gui_panel_group_end(struct gui_panel *panel, gui_group* group) { + gui_float clip_x, clip_y; + gui_float clip_h, clip_w; + const struct gui_canvas *canvas; assert(panel); assert(group); if (!panel || !group) return; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return; + + canvas = panel->canvas; + clip_x = MAX(panel->clip.x, group->clip.x) - 1; + clip_y = MAX(panel->clip.y, group->clip.y) - 1; + clip_w = MIN(panel->clip.x + panel->clip.w, group->x + group->w) - clip_x+ 2; + clip_h = MIN(panel->clip.y + panel->clip.h, group->y + group->h) - clip_y + 2; + clip_w = MAX(0, clip_w); + clip_h = MAX(0, clip_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); } gui_size @@ -2137,8 +1808,11 @@ gui_panel_shelf_begin(struct gui_panel *panel, gui_shelf *shelf, const char *tabs[], gui_size size, gui_size active) { const struct gui_config *config; + const struct gui_canvas *canvas; gui_float header_x, header_y; gui_float header_w, header_h; + gui_float clip_x, clip_y; + gui_float clip_h, clip_w; struct gui_rect bounds; gui_float item_width; gui_float offset; @@ -2151,98 +1825,143 @@ gui_panel_shelf_begin(struct gui_panel *panel, gui_shelf *shelf, assert(active < size); if (!panel || !shelf || !tabs || active >= size) return active; - if ((panel->flags & GUI_PANEL_HIDDEN) || panel->minimized) + + if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) { + shelf->flags = GUI_PANEL_HIDDEN; + shelf->config = panel->config; + shelf->canvas = panel->canvas; return active; + } config = panel->config; + canvas = panel->canvas; + offset = shelf->offset; gui_panel_alloc_space(&bounds, panel); + zero(shelf, sizeof(*shelf)); header_x = bounds.x; header_y = bounds.y; header_w = bounds.w; - header_h = config->panel_padding.y + 3 * config->item_padding.y + panel->font.height; + header_h = config->panel_padding.y + 3 * config->item_padding.y + canvas->font.height; item_width = (header_w - (gui_float)size) / (gui_float)size; for (i = 0; i < size; i++) { struct gui_button button; - button.y = header_y; - button.h = header_h; - button.x = header_x + ((gui_float)i * (item_width + 1)); - button.w = item_width; + gui_float button_x, button_y; + gui_float button_w, button_h; + button_y = header_y; + button_h = header_h; + button_x = header_x + ((gui_float)i * (item_width + 1)); + button_w = item_width; button.border = 1; - button.pad_x = config->item_padding.x; - button.pad_y = config->item_padding.y; - button.behavior = GUI_BUTTON_DEFAULT; + 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]; button.highlight_content = config->colors[GUI_COLOR_TEXT]; if (active != i) { - button.y += config->item_padding.y; - button.h -= config->item_padding.y; + button_y += config->item_padding.y; + button_h -= config->item_padding.y; } - if (gui_widget_button_text(panel->out, &button, tabs[i], - &panel->font, panel->in)) active = i; + if (gui_button_text(canvas, button_x, button_y, button_w, button_h, + &button, tabs[i], GUI_BUTTON_DEFAULT, panel->in)) active = i; } bounds.y += header_h; bounds.h -= header_h; - offset = shelf->offset; - gui_panel_init(shelf, panel->config, &panel->font); shelf->offset = offset; 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); + gui_panel_begin(shelf, NULL, bounds.x, bounds.y, bounds.w, bounds.h, flags, + panel->config, panel->canvas, panel->in); + + clip_x = MAX(panel->clip.x, shelf->clip.x) - 1; + clip_y = MAX(panel->clip.y, shelf->clip.y) - 1; + clip_w = MIN(panel->clip.x + panel->clip.w, shelf->clip.x + shelf->clip.w) - clip_x+ 2; + clip_h = MIN(panel->clip.y + panel->clip.h, shelf->clip.y + shelf->clip.h) - clip_y + 2; + clip_w = MAX(0, clip_w); + clip_h = MAX(0, clip_h); + canvas->scissor(canvas->userdata, clip_x, clip_y, clip_w, clip_h); return active; } void gui_panel_shelf_end(struct gui_panel *panel, gui_shelf *shelf) { + const struct gui_canvas *canvas; + gui_float clip_x, clip_y; + gui_float clip_h, clip_w; + assert(panel); assert(shelf); if (!panel || !shelf) return; if (panel->minimized || (panel->flags & GUI_PANEL_HIDDEN)) return; + + canvas = panel->canvas; + clip_x = MAX(panel->clip.x, shelf->clip.x) - 1; + clip_y = MAX(panel->clip.y, shelf->clip.y) - 1; + clip_w = MIN(panel->clip.x + panel->clip.w, shelf->x + shelf->w) - clip_x+ 2; + clip_h = MIN(panel->clip.y + panel->clip.h, shelf->y + shelf->h) - clip_y + 2; + clip_w = MAX(0, clip_w); + clip_h = MAX(0, clip_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); } void gui_panel_end(struct gui_panel *panel) { const struct gui_config *config; + const struct gui_canvas *canvas; assert(panel); if (!panel) return; if (panel->flags & GUI_PANEL_HIDDEN) return; - gui_buffer_pop_clip(panel->out); panel->at_y += panel->row_height; config = panel->config; + canvas = panel->canvas; + if (!(panel->flags & GUI_PANEL_TAB)) + canvas->scissor(canvas->userdata, panel->x, panel->y, panel->w + 1, panel->h + 1); if (panel->flags & GUI_PANEL_SCROLLBAR && !panel->minimized) { - gui_float panel_y; - struct gui_scroll scroll; - scroll.x = panel->x + panel->width; - scroll.y = (panel->flags & GUI_PANEL_BORDER) ? panel->y + 1 : panel->y; - scroll.y += panel->header_height; - scroll.w = config->scrollbar_width; - scroll.h = panel->height; - scroll.offset = panel->offset; - scroll.step = panel->height * 0.25f; + gui_float panel_y; + gui_float scroll_x, scroll_y; + gui_float scroll_w, scroll_h; + gui_float scroll_target, scroll_offset, scroll_step; + + scroll_x = panel->x + panel->width; + scroll_y = (panel->flags & GUI_PANEL_BORDER) ? panel->y + 1 : panel->y; + scroll_y += panel->header_height; + scroll_w = config->scrollbar_width; + scroll_h = panel->height; + + scroll_offset = panel->offset; + scroll_step = panel->height * 0.25f; scroll.background = config->colors[GUI_COLOR_SCROLLBAR]; scroll.foreground = config->colors[GUI_COLOR_SCROLLBAR_CURSOR]; scroll.border = config->colors[GUI_COLOR_SCROLLBAR_BORDER]; - if (panel->flags & GUI_PANEL_BORDER) - scroll.h -= 1; - scroll.target = (panel->at_y - panel->y) - panel->header_height; + if (panel->flags & GUI_PANEL_BORDER) scroll_h -= 1; + scroll_target = (panel->at_y - panel->y) - panel->header_height; - panel->offset = (gui_float)gui_widget_scroll(panel->out, &scroll, panel->in); + 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; - gui_buffer_push_rect(panel->out, 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; + if (panel->flags & GUI_PANEL_SCALEABLE && !panel->minimized) { + struct gui_color col = config->colors[GUI_COLOR_SCALER]; + gui_float scaler_x = panel->x + config->item_padding.x; + gui_float scaler_y = panel->y + panel->h - 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); + canvas->draw_rect(canvas->userdata, scaler_x, scaler_y, scaler_w, scaler_h, col); + } + if (panel->flags & GUI_PANEL_BORDER) { const gui_float width = (panel->flags & GUI_PANEL_SCROLLBAR) ? panel->width + config->scrollbar_width : panel->width; @@ -2252,328 +1971,13 @@ gui_panel_end(struct gui_panel *panel) panel->y + panel->height + panel->header_height: panel->y + panel->height + config->item_padding.y; - gui_buffer_push_line(panel->out, panel->x, padding_y, panel->x + width, + canvas->draw_line(canvas->userdata, panel->x, padding_y, panel->x + width, padding_y, config->colors[GUI_COLOR_BORDER]); - gui_buffer_push_line(panel->out, panel->x, panel->y, panel->x, + canvas->draw_line(canvas->userdata, panel->x, panel->y, panel->x, padding_y, config->colors[GUI_COLOR_BORDER]); - gui_buffer_push_line(panel->out, panel->x + width, panel->y, panel->x + width, + canvas->draw_line(canvas->userdata, panel->x + width, panel->y, panel->x + width, padding_y, config->colors[GUI_COLOR_BORDER]); } -} - -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); - static const gui_size align_list = ALIGNOF(struct gui_command_list**); - - assert(memory); - assert(input); - if (!memory || !input) - return NULL; - - ctx = memory->memory; - ctx->width = 0; - ctx->height = 0; - ctx->input = input; - ctx->active = NULL; - ctx->free_list = NULL; - ctx->stack_begin = NULL; - ctx->stack_end = NULL; - - ptr = (gui_byte*)memory->memory + sizeof(struct gui_context); - ctx->panel_pool = ALIGN(ptr, align_panels); - ctx->panel_capacity = memory->max_panels; - ctx->panel_size = 0; - - size = sizeof(struct gui_context_panel) * memory->max_panels; - ptr = (gui_byte*)ctx->panel_pool + size; - ctx->output_list = ALIGN(ptr, align_list); - - size = sizeof(struct gui_command_list*) * memory->max_panels; - buffer.memory = (gui_byte*)ctx->output_list + size; - buffer.size = memory->size - (gui_size)((gui_byte*)buffer.memory - (gui_byte*)memory->memory); - buffer.max_depth = memory->max_depth; - gui_output_begin(&ctx->global_buffer, &buffer); - return ctx; -} - -static struct gui_context_panel* -gui_alloc_panel(struct gui_context *ctx) -{ - assert(ctx); - if (ctx->free_list) { - struct gui_context_panel *panel; - panel = ctx->free_list; - ctx->free_list = panel->next; - panel->next = NULL; - panel->prev = NULL; - return panel; - } else if (ctx->panel_capacity) { - ctx->panel_capacity--; - return &ctx->panel_pool[ctx->panel_capacity]; - } - return NULL; -} - -static void -gui_free_panel(struct gui_context *ctx, struct gui_context_panel *panel) -{ - assert(ctx); - assert(panel); - panel->next = ctx->free_list; - ctx->free_list = panel; -} - -static void -gui_stack_push(struct gui_context *ctx, struct gui_context_panel *panel) -{ - if (!ctx->stack_begin) { - ctx->stack_begin = panel; - ctx->stack_end = panel; - return; - } - - ctx->stack_end->next = panel; - panel->prev = ctx->stack_end; - panel->next = NULL; - ctx->stack_end = panel; -} - -static void -gui_stack_remove(struct gui_context *ctx, struct gui_context_panel *panel) -{ - 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; - if (ctx->stack_end == panel) - ctx->stack_end = panel->prev; - panel->next = NULL; - panel->prev = NULL; -} - -struct gui_panel* -gui_new_panel(struct gui_context *ctx, gui_float x, gui_float y, gui_float w, gui_float h, - const struct gui_config *config, const struct gui_font *font) -{ - struct gui_context_panel *cpanel; - assert(ctx); - assert(config); - assert(font); - 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; - cpanel->next = NULL; cpanel->prev = NULL; - - gui_panel_init(&cpanel->panel, config, font); - gui_stack_push(ctx, cpanel); - ctx->panel_size++; - return &cpanel->panel; -} - -void -gui_del_panel(struct gui_context *ctx, struct gui_panel *panel) -{ - struct gui_context_panel *cpanel; - assert(ctx); - assert(panel); - if (!ctx || !panel) return; - - cpanel = (struct gui_context_panel*)panel; - gui_stack_remove(ctx, cpanel); - gui_free_panel(ctx, cpanel); - ctx->panel_size--; -} - -void -gui_begin(struct gui_context *ctx, gui_float w, gui_float h) -{ - assert(ctx); - if (!ctx) return; - ctx->width = w; - ctx->height = h; -} - -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; - - 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; - - cpanel = (const struct gui_context_panel*)panel; - size.x = cpanel->w; - size.y = cpanel->h; - return size; -} - -gui_bool -gui_begin_panel(struct gui_context *ctx, struct gui_panel *panel, - const char *title, gui_flags flags) -{ - gui_bool active, inpanel; - const struct gui_input *in; - struct gui_context_panel *cpanel; - struct gui_command_buffer *out; - struct gui_command_buffer *global; - - assert(ctx); - assert(panel); - assert(title); - - if (!ctx || !panel || !title) - return gui_false; - if (panel->flags & GUI_PANEL_HIDDEN) - return gui_false; - if (!(flags & GUI_PANEL_TAB)) - flags |= GUI_PANEL_SCROLLBAR; - - in = ctx->input; - cpanel = (struct gui_context_panel*)panel; - inpanel = INBOX(in->mouse_prev.x,in->mouse_prev.y, cpanel->x, cpanel->y, cpanel->w, cpanel->h); - if (in->mouse_down && in->mouse_clicked && inpanel && cpanel != ctx->active) { - struct gui_context_panel *iter = cpanel->next; - while (iter) { - if (!iter->panel.minimized) - if (INBOX(in->mouse_prev.x, in->mouse_prev.y, iter->x, iter->y, iter->w, iter->h)) - break; - iter = iter->next; - } - if (!iter) { - gui_stack_remove(ctx, cpanel); - gui_stack_push(ctx, cpanel); - ctx->active = cpanel; - } - } - - if (ctx->active == cpanel && (flags & GUI_PANEL_MOVEABLE)) { - gui_bool incursor; - 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; - - incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,header_x, header_y, header_w, header_h); - if (in->mouse_down && incursor) { - 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); - } - } - - if (ctx->active == cpanel && (flags & GUI_PANEL_SCALEABLE) && (flags & GUI_PANEL_SCROLLBAR)) { - const struct gui_config *config = cpanel->panel.config; - gui_bool incursor; - 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; - - incursor = INBOX(in->mouse_prev.x,in->mouse_prev.y,scaler_x, scaler_y, scaler_w, scaler_h); - if (in->mouse_down && incursor) { - gui_float min_x = config->panel_min_size.x; - gui_float min_y = config->panel_min_size.y; - cpanel->x = CLAMP(0, cpanel->x + in->mouse_delta.x, ctx->width - cpanel->w); - 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); - } - } - - global = &ctx->global_buffer; - out = &ctx->current_buffer; - out->cmds.begin = global->cmds.end; - out->cmds.end = out->cmds.begin; - out->cmds.capacity = global->cmds.capacity - global->cmds.size; - out->cmds.count = 0; - out->cmds.needed = 0; - out->cmds.size = 0; - out->clip_size = global->clip_size; - out->clips = global->clips; - out->clip_capacity = global->clip_capacity; - in = (ctx->active == cpanel) ? ctx->input : NULL; - return gui_panel_begin(panel, out, in, title, cpanel->x, cpanel->y, - cpanel->w, cpanel->h, flags); -} - -void -gui_end_panel(struct gui_context *ctx, struct gui_panel *panel, - struct gui_memory_status *status) -{ - struct gui_context_panel *cpanel; - struct gui_command_buffer *global; - assert(ctx); - assert(panel); - if (!ctx || !panel) return; - cpanel = (struct gui_context_panel*)panel; - - gui_panel_end(panel); - if (!panel->minimized && ctx->active == cpanel && (panel->flags & GUI_PANEL_SCALEABLE) && - (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; - - 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); - gui_buffer_push_rect(&ctx->current_buffer, scaler_x, scaler_y, scaler_w, scaler_h, col); - } - - global = &ctx->global_buffer; - 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; - gui_output_end(&ctx->current_buffer, &cpanel->list, status); -} - -void -gui_end(struct gui_context *ctx, struct gui_output *output, - struct gui_memory_status *status) -{ - assert(ctx); - if (!ctx) return; - if (output) { - gui_size n = 0; - struct gui_context_panel *iter = ctx->stack_begin; - while (iter) { - if (!(iter->panel.flags & GUI_PANEL_HIDDEN)) - ctx->output_list[n++] = &iter->list; - iter = iter->next; - } - output->list_size = n; - output->list = ctx->output_list; - } - gui_output_end(&ctx->global_buffer, NULL, status); + canvas->scissor(canvas->userdata, 0, 0, (gui_float)canvas->width, (gui_float)canvas->height); } diff --git a/gui.h b/gui.h index f78c41d..654df82 100644 --- a/gui.h +++ b/gui.h @@ -42,13 +42,6 @@ typedef unsigned int gui_flag; typedef unsigned long gui_size; #endif -typedef struct gui_panel gui_tab; -typedef struct gui_panel gui_group; -typedef struct gui_panel gui_shelf; -typedef gui_char gui_glyph[GUI_UTF_SIZE]; -typedef union {void* handle; gui_uint id;} gui_texture; -typedef gui_size(*gui_text_width_f)(void*,const gui_char*, gui_size); - enum {gui_false, gui_true}; enum gui_heading {GUI_UP, GUI_RIGHT, GUI_DOWN, GUI_LEFT}; struct gui_color {gui_byte r,g,b,a;}; @@ -56,9 +49,24 @@ struct gui_colorf {gui_float r,g,b,a;}; struct gui_vec2 {gui_float x,y;}; struct gui_rect {gui_float x,y,w,h;}; struct gui_key {gui_bool down, clicked;}; +struct gui_font; +typedef struct gui_panel gui_tab; +typedef struct gui_panel gui_group; +typedef struct gui_panel gui_shelf; +typedef gui_char gui_glyph[GUI_UTF_SIZE]; +typedef union {void* handle; gui_uint id;} gui_texture; +typedef gui_size(*gui_text_width_f)(void*,const gui_char*, gui_size); +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_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); struct gui_font { - void *user; + void *userdata; gui_float height; gui_text_width_f width; }; @@ -86,105 +94,17 @@ struct gui_input { struct gui_vec2 mouse_clicked_pos; }; -struct gui_memory { - void *memory; - gui_size size; - gui_size max_panels; - gui_size max_depth; -}; - -struct gui_memory_status { - gui_size allocated; - gui_size needed; -}; - -enum gui_command_type { - GUI_COMMAND_NOP = 0, - GUI_COMMAND_CLIP, - GUI_COMMAND_LINE, - GUI_COMMAND_RECT, - GUI_COMMAND_CIRCLE, - GUI_COMMAND_BITMAP, - GUI_COMMAND_TRIANGLE, - GUI_COMMAND_TEXT, - GUI_COMMAND_MAX -}; - -struct gui_command { - enum gui_command_type type; - struct gui_command *next; -}; - -struct gui_command_clip { - struct gui_command header; - gui_float x, y; - gui_float w, h; -}; - -struct gui_command_line { - struct gui_command header; - struct gui_color color; - struct gui_vec2 from; - struct gui_vec2 to; -}; - -struct gui_command_rect { - struct gui_command header; - struct gui_color color; - gui_float x, y; - gui_float w, h; -}; - -struct gui_command_circle { - struct gui_command header; - struct gui_color color; - gui_float radius; - gui_float x, y; -}; - -struct gui_command_bitmap { - struct gui_command header; - gui_texture texture; - struct gui_rect src; - struct gui_rect dst; -}; - -struct gui_command_triangle { - struct gui_command header; - struct gui_vec2 pnt[3]; - struct gui_color color; -}; - -struct gui_command_text { - struct gui_command header; - struct gui_color background; - struct gui_color foreground; - void *font; - gui_float x, y; - gui_float w, h; - gui_size length; - gui_byte string[1]; -}; - -struct gui_command_list{ - struct gui_command *begin; - struct gui_command *end; - gui_size count; - gui_size capacity; - gui_size needed; - gui_size size; -}; - -struct gui_command_buffer { - struct gui_command_list cmds; - struct gui_rect *clips; - gui_size clip_capacity; - gui_size clip_size; -}; - -struct gui_output { - struct gui_command_list **list; - gui_size list_size; +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_text draw_text; }; enum gui_text_align { @@ -194,23 +114,14 @@ enum gui_text_align { }; struct gui_text { - void *font; - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; - const char *string; - gui_size length; + struct gui_vec2 padding; enum gui_text_align align; struct gui_color foreground; struct gui_color background; }; struct gui_image { - struct gui_rect src; - struct gui_rect dst; - gui_float pad_x, pad_y; - struct gui_color color; - gui_texture texture; + struct gui_vec2 padding; struct gui_color background; }; @@ -220,11 +131,8 @@ enum gui_button_behavior { }; struct gui_button { - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; gui_float border; - enum gui_button_behavior behavior; + struct gui_vec2 padding; struct gui_color background; struct gui_color foreground; struct gui_color content; @@ -238,45 +146,19 @@ enum gui_toggle_type { }; struct gui_toggle { - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; - const gui_char *text; - gui_size length; - enum gui_toggle_type type; + struct gui_vec2 padding; struct gui_color font; struct gui_color background; struct gui_color foreground; }; struct gui_slider { - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; - gui_float min, max; - gui_float value; - gui_float step; - struct gui_color background; - struct gui_color foreground; -}; - -struct gui_progress { - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; - gui_size current; - gui_size max; - gui_bool modifyable; + struct gui_vec2 padding; struct gui_color background; struct gui_color foreground; }; struct gui_scroll { - gui_float x, y; - gui_float w, h; - gui_float offset; - gui_float target; - gui_float step; struct gui_color background; struct gui_color foreground; struct gui_color border; @@ -292,37 +174,23 @@ enum gui_input_filter { }; struct gui_input_field { - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; - gui_size max; - gui_bool active; + struct gui_vec2 padding; gui_bool show_cursor; enum gui_input_filter filter; - gui_bool password; struct gui_color background; struct gui_color foreground; struct gui_color font; }; struct gui_plot { - gui_float x, y; - gui_float w, h; - gui_float pad_x; - gui_float pad_y; - gui_size value_count; - const gui_float *values; + struct gui_vec2 padding; struct gui_color background; struct gui_color foreground; struct gui_color highlight; }; struct gui_histo { - gui_float x, y; - gui_float w, h; - gui_float pad_x, pad_y; - gui_size value_count; - const gui_float *values; + struct gui_vec2 padding; struct gui_color background; struct gui_color foreground; struct gui_color negative; @@ -393,6 +261,7 @@ enum gui_panel_flags { struct gui_panel { gui_flags flags; gui_float x, y; + gui_float w, h; gui_float at_y; gui_float width, height; gui_size index; @@ -401,10 +270,10 @@ struct gui_panel { gui_size row_columns; gui_float offset; gui_bool minimized; - struct gui_command_buffer *out; - struct gui_font font; + struct gui_rect clip; const struct gui_input *in; const struct gui_config *config; + const struct gui_canvas *canvas; }; /* Input */ @@ -415,46 +284,43 @@ 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*, const struct gui_memory*); -void gui_output_end(struct gui_command_buffer*, struct gui_command_list*, - struct gui_memory_status*); - /* Widgets */ -void gui_widget_text(struct gui_command_buffer*, const struct gui_text*, - const struct gui_font*); -void gui_widget_image(struct gui_command_buffer*, const struct gui_image*); -gui_bool gui_widget_button_text(struct gui_command_buffer*, const struct gui_button*, - const char *text, const struct gui_font*, const struct gui_input*); -gui_bool gui_widget_button_triangle(struct gui_command_buffer*, struct gui_button*, - enum gui_heading, const struct gui_input*); -gui_bool gui_widget_button_icon(struct gui_command_buffer*, struct gui_button*, - gui_texture, const struct gui_rect *source, const struct gui_input*); -gui_bool gui_widget_toggle(struct gui_command_buffer*, const struct gui_toggle*, - gui_bool active, const struct gui_font*, const struct gui_input*); -gui_float gui_widget_slider(struct gui_command_buffer*, const struct gui_slider*, - const struct gui_input*); -gui_size gui_widget_progress(struct gui_command_buffer*, const struct gui_progress*, - const struct gui_input*); -gui_bool gui_widget_input(struct gui_command_buffer*, gui_char*, gui_size*, - const struct gui_input_field*, const struct gui_font*, - const struct gui_input*); -gui_float gui_widget_scroll(struct gui_command_buffer*, const struct gui_scroll*, - const struct gui_input*); -gui_int gui_widget_histo(struct gui_command_buffer*, const struct gui_histo*, - const struct gui_input*); -gui_int gui_widget_plot(struct gui_command_buffer*, const struct gui_plot*, - const struct gui_input*); +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); +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_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_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 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*); +gui_size gui_progress(const struct gui_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*, 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*); +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*); +gui_int gui_plot(const struct gui_canvas*, gui_float x, gui_float y, gui_float w, + gui_float h, const gui_float*, gui_size, + const struct gui_plot*, const struct gui_input*); +gui_float gui_scroll(const struct gui_canvas*, gui_float x, gui_float y, + gui_float w, gui_float h, gui_float offset, gui_float target, + gui_float step, const struct gui_scroll*, const struct gui_input*); /* Panel */ void gui_default_config(struct gui_config*); -void gui_panel_show(struct gui_panel*); -void gui_panel_hide(struct gui_panel*); -void gui_panel_init(struct gui_panel*, const struct gui_config*, const struct gui_font*); gui_bool gui_panel_is_hidden(const struct gui_panel*); -gui_bool gui_panel_begin(struct gui_panel*, struct gui_command_buffer*, - const struct gui_input*, const char*, - gui_float x, gui_float y, gui_float w, gui_float h, gui_flags); +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*); void gui_panel_end(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); @@ -465,14 +331,12 @@ 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*, gui_texture, 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, gui_bool modifyable); -gui_bool gui_panel_input(struct gui_panel*, gui_char *buffer, gui_size *len, - gui_size max, enum gui_input_filter, gui_bool active); +gui_size gui_panel_input(struct gui_panel*, gui_char *buffer, gui_size len, + gui_size max, gui_bool *active, enum gui_input_filter); gui_bool gui_panel_spinner(struct gui_panel*, gui_int min, gui_int *value, gui_int max, gui_int step, gui_bool active); gui_size gui_panel_selector(struct gui_panel*, const char *items[], @@ -487,19 +351,6 @@ gui_size gui_panel_shelf_begin(gui_shelf*, gui_shelf *shelf, const char *tabs[], gui_size size, gui_size active); void gui_panel_shelf_end(struct gui_panel*, gui_shelf *shelf); -/* Context */ -struct gui_context; -struct gui_context *gui_new(const struct gui_memory*, const struct gui_input*); -void gui_begin(struct gui_context*, gui_float width, gui_float height); -void gui_end(struct gui_context*, struct gui_output*, struct gui_memory_status*); -struct gui_panel *gui_new_panel(struct gui_context*, gui_float x, gui_float y, gui_float w, - gui_float h, const struct gui_config* , const struct gui_font*); -void gui_del_panel(struct gui_context*, struct gui_panel*); -struct gui_vec2 gui_get_panel_position(const struct gui_context*, const struct gui_panel*); -struct gui_vec2 gui_get_panel_size(const struct gui_context*, const struct gui_panel*); -gui_bool gui_begin_panel(struct gui_context*, struct gui_panel*, const char *title, gui_flags flags); -void gui_end_panel(struct gui_context*, struct gui_panel*, struct gui_memory_status*); - #ifdef __cplusplus } #endif