From 2cedc57f5dc3a7efc4cdb821d6ce445acf85608d Mon Sep 17 00:00:00 2001 From: vurtun Date: Wed, 16 Mar 2016 13:01:47 +0100 Subject: [PATCH] Extend default draw command API The default draw command buffering API now supports filled and outlined shapes as well as two additional commands: polygon and polyline. While zahnrad only requires a small number of basic filled draw command shapes to actual function the underlying canvas to convert from draw commands to vertex buffer commands allows for lot more. So the gap should now be filled and drawing more complex custom is now a little bit easier. I thought about adding a path drawing API to the draw command API but decided it is not worth the hassle, at least for now. --- Readme.md | 2 +- demo/demo.c | 11 +- demo/x11/xlib.c | 45 +++++++- zahnrad.c | 282 ++++++++++++++++++++++++++++++++++-------------- zahnrad.h | 51 ++++++--- 5 files changed, 290 insertions(+), 101 deletions(-) diff --git a/Readme.md b/Readme.md index c29cd44..fb0f381 100644 --- a/Readme.md +++ b/Readme.md @@ -13,7 +13,7 @@ render backends it only focuses on the actual UI. ## Features - Immediate mode graphical user interface toolkit - Written in C89 (ANSI C) -- Small codebase (~13kLOC) +- Small codebase (~11kLOC) - Focus on portability, efficiency and simplicity - No dependencies (not even the standard library) - No global or hidden state diff --git a/demo/demo.c b/demo/demo.c index 0d24fb9..fb5753c 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -667,7 +667,6 @@ demo_window(struct demo *gui, struct zr_context *ctx) zr_label(ctx, "Property neg:", ZR_TEXT_LEFT); zr_property_int(ctx, "Neg:", -10, &property_neg, 10, 1, 1); - zr_layout_row_dynamic(ctx, 25, 1); zr_label(ctx, "Range:", ZR_TEXT_LEFT); zr_layout_row_dynamic(ctx, 25, 3); @@ -1606,7 +1605,7 @@ ui_piemenu(struct zr_context *ctx, struct zr_vec2 pos, float radius, } /* outer circle */ - zr_draw_circle(out, bounds, zr_rgb(50,50,50)); + zr_draw_circle(out, ZR_FILLED, bounds, zr_rgb(50,50,50)); { /* circle buttons */ float step = (2 * 3.141592654f) / (float)(MAX(1,item_count)); @@ -1621,7 +1620,7 @@ ui_piemenu(struct zr_context *ctx, struct zr_vec2 pos, float radius, for (i = 0; i < item_count; ++i) { struct zr_rect content; float rx, ry, dx, dy, a; - zr_draw_arc(out, center.x, center.y, (bounds.w/2.0f), + zr_draw_arc(out, ZR_FILLED, center.x, center.y, (bounds.w/2.0f), a_min, a_max, (active_item == i) ? zr_rgb(45,100,255): zr_rgb(60,60,60)); /* seperator line */ @@ -1647,7 +1646,7 @@ ui_piemenu(struct zr_context *ctx, struct zr_vec2 pos, float radius, inner.x = bounds.x + bounds.w/2 - bounds.w/4; inner.y = bounds.y + bounds.h/2 - bounds.h/4; inner.w = bounds.w/2; inner.h = bounds.h/2; - zr_draw_circle(out, inner, zr_rgb(45,45,45)); + zr_draw_circle(out, ZR_FILLED, inner, zr_rgb(45,45,45)); /* active icon content */ bounds.w = inner.w / 2.0f; @@ -2618,7 +2617,7 @@ node_editor_demo(struct zr_context *ctx, struct node_editor *nodedit) circle.x = node.bounds.x + node.bounds.w-4; circle.y = node.bounds.y + space * (float)(n+1); circle.w = 8; circle.h = 8; - zr_draw_circle(canvas, circle, zr_rgb(100, 100, 100)); + zr_draw_circle(canvas, ZR_FILLED, circle, zr_rgb(100, 100, 100)); /* start linking process */ if (zr_input_has_mouse_click_down_in_rect(in, ZR_BUTTON_LEFT, circle, zr_true)) { @@ -2645,7 +2644,7 @@ node_editor_demo(struct zr_context *ctx, struct node_editor *nodedit) circle.x = node.bounds.x-4; circle.y = node.bounds.y + space * (float)(n+1); circle.w = 8; circle.h = 8; - zr_draw_circle(canvas, circle, zr_rgb(100, 100, 100)); + zr_draw_circle(canvas, ZR_FILLED, circle, zr_rgb(100, 100, 100)); if (zr_input_is_mouse_released(in, ZR_BUTTON_LEFT) && zr_input_is_mouse_hovering_rect(in, circle) && nodedit->linking.active && nodedit->linking.node != it) { diff --git a/demo/x11/xlib.c b/demo/x11/xlib.c index 277a0ae..7b984c5 100644 --- a/demo/x11/xlib.c +++ b/demo/x11/xlib.c @@ -354,6 +354,41 @@ surface_draw_triangle(XSurface *surf, int16_t x0, int16_t y0, int16_t x1, XFillPolygon(surf->dpy, surf->drawable, surf->gc, pnts, 3, Convex, CoordModeOrigin); } +static void +surface_draw_polygon(XSurface *surf, enum zr_command_drawing_mode type, + const struct zr_vec2i *pnts, int count, struct zr_color col) +{ + int i = 0; + unsigned long c = color_from_byte(&col.r); + XSetForeground(surf->dpy, surf->gc, c); + if (type == ZR_FILLED) { + #define MAX_POINTS 64 + XPoint xpnts[MAX_POINTS]; + + for (i = 0; i < count && i < MAX_POINTS; ++i) { + xpnts[i].x = pnts[i].x; + xpnts[i].y = pnts[i].y; + } + XFillPolygon(surf->dpy, surf->drawable, surf->gc, xpnts, count, Convex, CoordModeOrigin); + #undef MAX_POINTS + } else { + for (i = 1; i < count; ++i) + XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i-1].x, pnts[i-1].y, pnts[i].x, pnts[i].y); + XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[count-1].x, pnts[count-1].y, pnts[0].x, pnts[0].y); + } +} + +static void +surface_draw_polyline(XSurface *surf, + const struct zr_vec2i *pnts, int count, struct zr_color col) +{ + int i = 0; + unsigned long c = color_from_byte(&col.r); + XSetForeground(surf->dpy, surf->gc, c); + for (i = 0; i < count-1; ++i) + XDrawLine(surf->dpy, surf->drawable, surf->gc, pnts[i].x, pnts[i].y, pnts[i+1].x, pnts[i+1].y); +} + static void surface_draw_circle(XSurface *surf, int16_t x, int16_t y, uint16_t w, uint16_t h, struct zr_color col) @@ -489,7 +524,6 @@ surface_del(XSurface *surf) } #if 0 - static XSurface* surface_load(const char *filename, Display *dpy, int screen, Window root) { @@ -699,6 +733,14 @@ main(int argc, char *argv[]) surface_draw_triangle(xw.surf, t->a.x, t->a.y, t->b.x, t->b.y, t->c.x, t->c.y, t->color); } break; + case ZR_COMMAND_POLYGON: { + const struct zr_command_polygon *p = zr_command(polygon, cmd); + surface_draw_polygon(xw.surf, p->mode, p->points, p->point_count, p->color); + } break; + case ZR_COMMAND_POLYLINE: { + const struct zr_command_polyline *p = zr_command(polyline, cmd); + surface_draw_polyline(xw.surf, p->points, p->point_count, p->color); + } break; case ZR_COMMAND_TEXT: { const struct zr_command_text *t = zr_command(text, cmd); surface_draw_text(xw.surf, t->x, t->y, t->w, t->h, @@ -717,6 +759,7 @@ main(int argc, char *argv[]) surface_draw_curve(xw.surf, q->begin, q->ctrl[0], q->ctrl[1], q->end, 22, q->color); } break; + case ZR_COMMAND_RECT_MULTI_COLOR: case ZR_COMMAND_ARC: default: break; } diff --git a/zahnrad.c b/zahnrad.c index 41c5c15..bad6819 100644 --- a/zahnrad.c +++ b/zahnrad.c @@ -2044,8 +2044,8 @@ zr_draw_curve(struct zr_command_buffer *b, float ax, float ay, } void -zr_draw_rect(struct zr_command_buffer *b, struct zr_rect rect, - float rounding, struct zr_color c) +zr_draw_rect(struct zr_command_buffer *b, enum zr_command_drawing_mode mode, + struct zr_rect rect, float rounding, struct zr_color c) { struct zr_command_rect *cmd; ZR_ASSERT(b); @@ -2059,6 +2059,7 @@ zr_draw_rect(struct zr_command_buffer *b, struct zr_rect rect, cmd = (struct zr_command_rect*) zr_command_buffer_push(b, ZR_COMMAND_RECT, sizeof(*cmd)); if (!cmd) return; + cmd->mode = mode; cmd->rounding = (unsigned int)rounding; cmd->x = (short)rect.x; cmd->y = (short)rect.y; @@ -2094,8 +2095,8 @@ zr_draw_rect_multi_color(struct zr_command_buffer *b, struct zr_rect rect, } void -zr_draw_circle(struct zr_command_buffer *b, struct zr_rect r, - struct zr_color c) +zr_draw_circle(struct zr_command_buffer *b, enum zr_command_drawing_mode mode, + struct zr_rect r, struct zr_color c) { struct zr_command_circle *cmd; ZR_ASSERT(b); @@ -2109,6 +2110,7 @@ zr_draw_circle(struct zr_command_buffer *b, struct zr_rect r, cmd = (struct zr_command_circle*) zr_command_buffer_push(b, ZR_COMMAND_CIRCLE, sizeof(*cmd)); if (!cmd) return; + cmd->mode = mode; cmd->x = (short)r.x; cmd->y = (short)r.y; cmd->w = (unsigned short)ZR_MAX(r.w, 0); @@ -2117,13 +2119,14 @@ zr_draw_circle(struct zr_command_buffer *b, struct zr_rect r, } void -zr_draw_arc(struct zr_command_buffer *b, float cx, - float cy, float radius, float a_min, float a_max, struct zr_color c) +zr_draw_arc(struct zr_command_buffer *b, enum zr_command_drawing_mode mode, + float cx, float cy, float radius, float a_min, float a_max, struct zr_color c) { struct zr_command_arc *cmd; cmd = (struct zr_command_arc*) zr_command_buffer_push(b, ZR_COMMAND_ARC, sizeof(*cmd)); if (!cmd) return; + cmd->mode = mode; cmd->cx = (short)cx; cmd->cy = (short)cy; cmd->r = (unsigned short)radius; @@ -2133,8 +2136,8 @@ zr_draw_arc(struct zr_command_buffer *b, float cx, } void -zr_draw_triangle(struct zr_command_buffer *b,float x0,float y0, - float x1, float y1, float x2, float y2, struct zr_color c) +zr_draw_triangle(struct zr_command_buffer *b,enum zr_command_drawing_mode mode, + float x0, float y0, float x1, float y1, float x2, float y2, struct zr_color c) { struct zr_command_triangle *cmd; ZR_ASSERT(b); @@ -2150,6 +2153,7 @@ zr_draw_triangle(struct zr_command_buffer *b,float x0,float y0, cmd = (struct zr_command_triangle*) zr_command_buffer_push(b, ZR_COMMAND_TRIANGLE, sizeof(*cmd)); if (!cmd) return; + cmd->mode = mode; cmd->a.x = (short)x0; cmd->a.y = (short)y0; cmd->b.x = (short)x1; @@ -2182,6 +2186,49 @@ zr_draw_image(struct zr_command_buffer *b, struct zr_rect r, cmd->img = *img; } +void +zr_draw_polygon(struct zr_command_buffer *b, enum zr_command_drawing_mode mode, + float *points, int point_count, struct zr_color col) +{ + int i; + zr_size size = 0; + struct zr_command_polygon *cmd; + + ZR_ASSERT(b); + if (!b) return; + size = sizeof(*cmd) + sizeof(short) * 2 * (zr_size)point_count; + cmd = (struct zr_command_polygon*) zr_command_buffer_push(b, ZR_COMMAND_POLYGON, size); + if (!cmd) return; + cmd->color = col; + cmd->mode = mode; + cmd->point_count = (unsigned short)point_count; + for (i = 0; i < point_count; ++i) { + cmd->points[i].x = (short)points[i*2]; + cmd->points[i].y = (short)points[i*2+1]; + } +} + +void +zr_draw_polyline(struct zr_command_buffer *b, + float *points, int point_count, struct zr_color col) +{ + int i; + zr_size size = 0; + struct zr_command_polyline *cmd; + + ZR_ASSERT(b); + if (!b) return; + size = sizeof(*cmd) + sizeof(short) * 2 * (zr_size)point_count; + cmd = (struct zr_command_polyline*) zr_command_buffer_push(b, ZR_COMMAND_POLYLINE, size); + if (!cmd) return; + cmd->color = col; + cmd->point_count = (unsigned short)point_count; + for (i = 0; i < point_count; ++i) { + cmd->points[i].x = (short)points[i*2]; + cmd->points[i].y = (short)points[i*2+1]; + } +} + void zr_draw_text(struct zr_command_buffer *b, struct zr_rect r, const char *string, zr_size length, const struct zr_user_font *font, @@ -2926,7 +2973,7 @@ zr_canvas_path_stroke(struct zr_canvas *list, struct zr_color color, } static void -zr_canvas_add_line(struct zr_canvas *list, struct zr_vec2 a, +zr_canvas_stroke_line(struct zr_canvas *list, struct zr_vec2 a, struct zr_vec2 b, struct zr_color col, float thickness) { ZR_ASSERT(list); @@ -2937,7 +2984,7 @@ zr_canvas_add_line(struct zr_canvas *list, struct zr_vec2 a, } static void -zr_canvas_add_rect(struct zr_canvas *list, struct zr_rect rect, +zr_canvas_fill_rect(struct zr_canvas *list, struct zr_rect rect, struct zr_color col, float rounding) { ZR_ASSERT(list); @@ -2947,6 +2994,17 @@ zr_canvas_add_rect(struct zr_canvas *list, struct zr_rect rect, zr_canvas_path_fill(list, col); } +static void +zr_canvas_stroke_rect(struct zr_canvas *list, struct zr_rect rect, + struct zr_color col, float rounding, float thickness) +{ + ZR_ASSERT(list); + if (!list || !col.a) return; + zr_canvas_path_rect_to(list, zr_vec2(rect.x + 0.5f, rect.y + 0.5f), + zr_vec2(rect.x + rect.w + 0.5f, rect.y + rect.h + 0.5f), rounding); + zr_canvas_path_stroke(list, col, ZR_STROKE_CLOSED, thickness); +} + static void zr_canvas_add_rect_multi_color(struct zr_canvas *list, struct zr_rect rect, struct zr_color left, struct zr_color top, struct zr_color right, @@ -2980,7 +3038,7 @@ zr_canvas_add_rect_multi_color(struct zr_canvas *list, struct zr_rect rect, } static void -zr_canvas_add_triangle(struct zr_canvas *list, struct zr_vec2 a, +zr_canvas_fill_triangle(struct zr_canvas *list, struct zr_vec2 a, struct zr_vec2 b, struct zr_vec2 c, struct zr_color col) { ZR_ASSERT(list); @@ -2992,7 +3050,19 @@ zr_canvas_add_triangle(struct zr_canvas *list, struct zr_vec2 a, } static void -zr_canvas_add_circle(struct zr_canvas *list, struct zr_vec2 center, +zr_canvas_stroke_triangle(struct zr_canvas *list, struct zr_vec2 a, + struct zr_vec2 b, struct zr_vec2 c, struct zr_color col, float thickness) +{ + ZR_ASSERT(list); + if (!list || !col.a) return; + zr_canvas_path_line_to(list, a); + zr_canvas_path_line_to(list, b); + zr_canvas_path_line_to(list, c); + zr_canvas_path_stroke(list, col, ZR_STROKE_CLOSED, thickness); +} + +static void +zr_canvas_fill_circle(struct zr_canvas *list, struct zr_vec2 center, float radius, struct zr_color col, unsigned int segs) { float a_max; @@ -3003,6 +3073,18 @@ zr_canvas_add_circle(struct zr_canvas *list, struct zr_vec2 center, zr_canvas_path_fill(list, col); } +static void +zr_canvas_stroke_circle(struct zr_canvas *list, struct zr_vec2 center, + float radius, struct zr_color col, unsigned int segs, float thickness) +{ + float a_max; + ZR_ASSERT(list); + if (!list || !col.a) return; + a_max = ZR_PI * 2.0f * ((float)segs - 1.0f) / (float)segs; + zr_canvas_path_arc_to(list, center, radius, 0.0f, a_max, segs); + zr_canvas_path_stroke(list, col, ZR_STROKE_CLOSED, thickness); +} + static void zr_canvas_add_curve(struct zr_canvas *list, struct zr_vec2 p0, struct zr_vec2 cp0, struct zr_vec2 cp1, struct zr_vec2 p1, @@ -3165,7 +3247,7 @@ zr_convert(struct zr_context *ctx, struct zr_buffer *cmds, } break; case ZR_COMMAND_LINE: { const struct zr_command_line *l = zr_command(line, cmd); - zr_canvas_add_line(&ctx->canvas, zr_vec2(l->begin.x, l->begin.y), + zr_canvas_stroke_line(&ctx->canvas, zr_vec2(l->begin.x, l->begin.y), zr_vec2(l->end.x, l->end.y), l->color, line_thickness); } break; case ZR_COMMAND_CURVE: { @@ -3177,8 +3259,13 @@ zr_convert(struct zr_context *ctx, struct zr_buffer *cmds, } break; case ZR_COMMAND_RECT: { const struct zr_command_rect *r = zr_command(rect, cmd); - zr_canvas_add_rect(&ctx->canvas, zr_rect(r->x, r->y, r->w, r->h), - r->color, (float)r->rounding); + if (r->mode == ZR_FILLED) { + zr_canvas_fill_rect(&ctx->canvas, zr_rect(r->x, r->y, r->w, r->h), + r->color, (float)r->rounding); + } else { + zr_canvas_stroke_rect(&ctx->canvas, zr_rect(r->x, r->y, r->w, r->h), + r->color, (float)r->rounding, line_thickness); + } } break; case ZR_COMMAND_RECT_MULTI_COLOR: { const struct zr_command_rect_multi_color *r = zr_command(rect_multi_color, cmd); @@ -3187,21 +3274,56 @@ zr_convert(struct zr_context *ctx, struct zr_buffer *cmds, } break; case ZR_COMMAND_CIRCLE: { const struct zr_command_circle *c = zr_command(circle, cmd); - zr_canvas_add_circle(&ctx->canvas, zr_vec2((float)c->x + (float)c->w/2, - (float)c->y + (float)c->h/2), (float)c->w/2, c->color, - config->circle_segment_count); + if (c->mode == ZR_FILLED) { + zr_canvas_fill_circle(&ctx->canvas, zr_vec2((float)c->x + (float)c->w/2, + (float)c->y + (float)c->h/2), (float)c->w/2, c->color, + config->circle_segment_count); + } else { + zr_canvas_stroke_circle(&ctx->canvas, zr_vec2((float)c->x + (float)c->w/2, + (float)c->y + (float)c->h/2), (float)c->w/2, c->color, + config->circle_segment_count, line_thickness); + } } break; case ZR_COMMAND_ARC: { const struct zr_command_arc *c = zr_command(arc, cmd); zr_canvas_path_line_to(&ctx->canvas, zr_vec2(c->cx, c->cy)); zr_canvas_path_arc_to(&ctx->canvas, zr_vec2(c->cx, c->cy), c->r, c->a[0], c->a[1], config->circle_segment_count); - zr_canvas_path_fill(&ctx->canvas, c->color); + if (c->mode == ZR_FILLED) + zr_canvas_path_fill(&ctx->canvas, c->color); + if (c->mode == ZR_STROKE) + zr_canvas_path_stroke(&ctx->canvas, c->color, ZR_STROKE_CLOSED, line_thickness); } break; case ZR_COMMAND_TRIANGLE: { const struct zr_command_triangle *t = zr_command(triangle, cmd); - zr_canvas_add_triangle(&ctx->canvas, zr_vec2(t->a.x, t->a.y), - zr_vec2(t->b.x, t->b.y), zr_vec2(t->c.x, t->c.y), t->color); + if (t->mode == ZR_FILLED) { + zr_canvas_fill_triangle(&ctx->canvas, zr_vec2(t->a.x, t->a.y), + zr_vec2(t->b.x, t->b.y), zr_vec2(t->c.x, t->c.y), t->color); + } else { + zr_canvas_stroke_triangle(&ctx->canvas, zr_vec2(t->a.x, t->a.y), + zr_vec2(t->b.x, t->b.y), zr_vec2(t->c.x, t->c.y), t->color, + line_thickness); + } + } break; + case ZR_COMMAND_POLYGON: { + int i; + const struct zr_command_polygon *p = zr_command(polygon, cmd); + for (i = 0; i < p->point_count; ++i) { + struct zr_vec2 pnt = zr_vec2((float)p->points[i].x, (float)p->points[i].y); + zr_canvas_path_line_to(&ctx->canvas, pnt); + } + if (p->mode == ZR_STROKE) + zr_canvas_path_stroke(&ctx->canvas, p->color, ZR_STROKE_CLOSED, line_thickness); + else zr_canvas_path_fill(&ctx->canvas, p->color); + } break; + case ZR_COMMAND_POLYLINE: { + int i; + const struct zr_command_polyline *p = zr_command(polyline, cmd); + for (i = 0; i < p->point_count; ++i) { + struct zr_vec2 pnt = zr_vec2((float)p->points[i].x, (float)p->points[i].y); + zr_canvas_path_line_to(&ctx->canvas, pnt); + } + zr_canvas_path_stroke(&ctx->canvas, p->color, ZR_STROKE_OPEN, line_thickness); } break; case ZR_COMMAND_TEXT: { const struct zr_command_text *t = zr_command(text, cmd); @@ -4421,14 +4543,14 @@ zr_draw_symbol(struct zr_command_buffer *out, const struct zr_symbol *sym, case ZR_SYMBOL_RECT_FILLED: { /* simple empty/filled shapes */ if (sym->type == ZR_SYMBOL_RECT || sym->type == ZR_SYMBOL_RECT_FILLED) { - zr_draw_rect(out, content, 0, sym->foreground); + zr_draw_rect(out, ZR_FILLED, content, 0, sym->foreground); if (sym->type == ZR_SYMBOL_RECT_FILLED) - zr_draw_rect(out, zr_shrink_rect(content, + zr_draw_rect(out, ZR_FILLED, zr_shrink_rect(content, sym->border_width), 0, sym->background); } else { - zr_draw_circle(out, content, sym->foreground); + zr_draw_circle(out, ZR_FILLED, content, sym->foreground); if (sym->type == ZR_SYMBOL_CIRCLE_FILLED) - zr_draw_circle(out, zr_shrink_rect(content, 1), + zr_draw_circle(out, ZR_FILLED, zr_shrink_rect(content, 1), sym->background); } } break; @@ -4442,7 +4564,7 @@ zr_draw_symbol(struct zr_command_buffer *out, const struct zr_symbol *sym, (sym->type == ZR_SYMBOL_TRIANGLE_LEFT) ? ZR_LEFT: (sym->type == ZR_SYMBOL_TRIANGLE_UP) ? ZR_UP: ZR_DOWN; zr_triangle_from_direction(points, content, 0, 0, heading); - zr_draw_triangle(out, points[0].x, points[0].y, + zr_draw_triangle(out, ZR_FILLED, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, sym->foreground); } break; default: @@ -4485,8 +4607,8 @@ zr_button_draw(struct zr_command_buffer *o, struct zr_rect r, background = b->active; else background = b->normal; - zr_draw_rect(o, r, b->rounding, b->border); - zr_draw_rect(o, zr_shrink_rect(r, b->border_width), + zr_draw_rect(o, ZR_FILLED, r, b->rounding, b->border); + zr_draw_rect(o, ZR_FILLED, zr_shrink_rect(r, b->border_width), b->rounding, background); } @@ -4754,14 +4876,14 @@ zr_toggle_draw(struct zr_command_buffer *out, /* draw radiobutton/checkbox background */ if (type == ZR_TOGGLE_CHECK) - zr_draw_rect(out, select , toggle->rounding, col); - else zr_draw_circle(out, select, col); + zr_draw_rect(out, ZR_FILLED, select , toggle->rounding, col); + else zr_draw_circle(out, ZR_FILLED, select, col); /* draw radiobutton/checkbox cursor if active */ if (active) { if (type == ZR_TOGGLE_CHECK) - zr_draw_rect(out, cursor, toggle->rounding, toggle->cursor); - else zr_draw_circle(out, cursor, toggle->cursor); + zr_draw_rect(out, ZR_FILLED, cursor, toggle->rounding, toggle->cursor); + else zr_draw_circle(out, ZR_FILLED, cursor, toggle->cursor); } /* draw toggle text */ @@ -4884,9 +5006,9 @@ zr_slider_draw(struct zr_command_buffer *out, fill.w = (cursor.x + (cursor.w/2.0f)) - bar.x; fill.h = bar.h; - zr_draw_rect(out, bar, 0, s->bg); - zr_draw_rect(out, fill, 0, col); - zr_draw_circle(out, cursor, col); + zr_draw_rect(out, ZR_FILLED, bar, 0, s->bg); + zr_draw_rect(out, ZR_FILLED, fill, 0, col); + zr_draw_circle(out, ZR_FILLED, cursor, col); } static float @@ -4992,9 +5114,9 @@ zr_progress_draw(struct zr_command_buffer *out, const struct zr_progress *p, else col = p->normal; prog_scale = (float)value / (float)max; - zr_draw_rect(out, r, 0, p->background); + zr_draw_rect(out, ZR_FILLED, r, 0, p->background); r.w = (r.w - 2) * prog_scale; - zr_draw_rect(out, r, 0, col); + zr_draw_rect(out, ZR_FILLED, r, 0, col); } static zr_size @@ -5096,9 +5218,9 @@ zr_scrollbar_draw(struct zr_command_buffer *out, const struct zr_scrollbar *s, col = s->active; else col = s->normal; - zr_draw_rect(out, zr_shrink_rect(scroll,1), s->rounding, s->border); - zr_draw_rect(out, scroll, s->rounding, s->background); - zr_draw_rect(out, cursor, s->rounding, col); + zr_draw_rect(out, ZR_FILLED, zr_shrink_rect(scroll,1), s->rounding, s->border); + zr_draw_rect(out, ZR_FILLED, scroll, s->rounding, s->background); + zr_draw_rect(out, ZR_FILLED, cursor, s->rounding, col); } static float @@ -5293,8 +5415,8 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, r.h = ZR_MAX(r.h, font->height + (2 * field->padding.y + 2 * field->border_size)); /* draw editbox background and border */ - zr_draw_rect(out, r, field->rounding, field->border); - zr_draw_rect(out, zr_shrink_rect(r, field->border_size), + zr_draw_rect(out, ZR_FILLED, r, field->rounding, field->border); + zr_draw_rect(out, ZR_FILLED, zr_shrink_rect(r, field->border_size), field->rounding, field->background); /* check if the editbox is activated/deactivated */ @@ -5405,7 +5527,7 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, zr_size s = font->width(font->userdata, font->height, buffer + offset, text_len); text_width = (float)s; - zr_draw_rect(out, zr_rect(label.x+(float)text_width, + zr_draw_rect(out, ZR_FILLED, zr_rect(label.x+(float)text_width, label.y, (float)cursor_w, label.h), 0, field->cursor); } else { /* draw text selection */ @@ -5431,7 +5553,7 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, label.w = (float)s; /* draw selected text */ - zr_draw_rect(out, label, 0, field->text); + zr_draw_rect(out, ZR_FILLED, label, 0, field->text); text.padding = zr_vec2(0,0); text.background = field->text; text.text = field->background; @@ -5474,8 +5596,8 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, row_height = (zr_size)(font->height + field->padding.y); /* draw edit field background and border */ - zr_draw_rect(out, r, field->rounding, field->border); - zr_draw_rect(out, zr_shrink_rect(r, field->border_size), + zr_draw_rect(out, ZR_FILLED, r, field->rounding, field->border); + zr_draw_rect(out, ZR_FILLED, zr_shrink_rect(r, field->border_size), field->rounding, field->background); /* check if edit box is big enough to show even a single row */ @@ -5750,7 +5872,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, label.w -= (float)(unselected_text_width); text.background = field->text; text.text = field->background; - zr_draw_rect(out, label, 0, field->text); + zr_draw_rect(out, ZR_FILLED, label, 0, field->text); zr_widget_text(out, label, &buffer[offset+sel_begin], sel_len, &text, ZR_TEXT_LEFT|ZR_TEXT_MIDDLE, font); @@ -5761,7 +5883,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, text.padding = zr_vec2(0,0); text.background = field->text; text.text = field->background; - zr_draw_rect(out, label, 0, field->text); + zr_draw_rect(out, ZR_FILLED, label, 0, field->text); zr_widget_text(out, label, &buffer[offset], row_len, &text, ZR_TEXT_LEFT|ZR_TEXT_MIDDLE, font); } else if (glyph_off > begin && glyph_off + glyphs >= end && @@ -5784,7 +5906,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, text.padding = zr_vec2(0,0); text.background = field->text; text.text = field->background; - zr_draw_rect(out, label, 0, field->text); + zr_draw_rect(out, ZR_FILLED, label, 0, field->text); zr_widget_text(out, label, &buffer[offset], sel_len, &text, ZR_TEXT_LEFT|ZR_TEXT_MIDDLE, font); @@ -5850,7 +5972,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, cur_len = font->width(font->userdata, font->height, &buffer[offset+sel_begin], sel_len); label.w = (float)cur_len; - zr_draw_rect(out, label, 0, field->text); + zr_draw_rect(out, ZR_FILLED, label, 0, field->text); zr_widget_text(out, label, &buffer[offset+sel_begin], sel_len, &text, ZR_TEXT_LEFT|ZR_TEXT_MIDDLE, font); cur_text_width = font->width(font->userdata, font->height, @@ -5886,7 +6008,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, if (box->active && field->show_cursor) { if (box->cursor == box->glyphs) { if (len) label.y -= (font->height + field->padding.y); - zr_draw_rect(out, zr_rect(label.x+(float)text_width, + zr_draw_rect(out, ZR_FILLED, zr_rect(label.x+(float)text_width, label.y, (float)cursor_w, label.h), 0, field->cursor); } } @@ -6069,8 +6191,9 @@ zr_property_draw(struct zr_command_buffer *out, struct zr_text text; /* background */ - zr_draw_rect(out, property, p->rounding, p->border); - zr_draw_rect(out, zr_shrink_rect(property, p->border_size), p->rounding, p->normal); + zr_draw_rect(out, ZR_FILLED, property, p->rounding, p->border); + zr_draw_rect(out, ZR_FILLED, zr_shrink_rect(property, p->border_size), + p->rounding, p->normal); /* buttons */ sym.type = ZR_SYMBOL_TRIANGLE_LEFT; @@ -7232,7 +7355,6 @@ zr_clear(struct zr_context *ctx) } else iter = iter->next; } ctx->seq++; - ctx->next_id = 0; } /* ---------------------------------------------------------------- @@ -8308,10 +8430,10 @@ zr_panel_begin(struct zr_context *ctx, const char *title) /* draw header background */ if (!(layout->flags & ZR_WINDOW_BORDER)) { - zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y, + zr_draw_rect(out, ZR_FILLED, zr_rect(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->header_h), 0, config->colors[ZR_COLOR_HEADER]); } else { - zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y+1, + zr_draw_rect(out, ZR_FILLED, zr_rect(layout->bounds.x, layout->bounds.y+1, layout->bounds.w, layout->header_h), 0, config->colors[ZR_COLOR_HEADER]); } @@ -8362,7 +8484,7 @@ zr_panel_begin(struct zr_context *ctx, const char *title) if (layout->flags & ZR_WINDOW_MINIMIZED) { /* draw window background if minimized */ layout->row.height = 0; - zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y, + zr_draw_rect(out, ZR_FILLED, zr_rect(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->row.height), 0, config->colors[ZR_COLOR_WINDOW]); } else if (!(layout->flags & ZR_WINDOW_DYNAMIC)) { /* draw static window body */ @@ -8371,10 +8493,10 @@ zr_panel_begin(struct zr_context *ctx, const char *title) body.y += layout->header_h; body.h -= layout->header_h; } - zr_draw_rect(out, body, 0, config->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, ZR_FILLED, body, 0, config->colors[ZR_COLOR_WINDOW]); } else { /* draw dynamic window body */ - zr_draw_rect(out, zr_rect(layout->bounds.x, layout->bounds.y, + zr_draw_rect(out, ZR_FILLED, zr_rect(layout->bounds.x, layout->bounds.y, layout->bounds.w, layout->row.height + window_padding.y), 0, config->colors[ZR_COLOR_WINDOW]); } @@ -8483,7 +8605,7 @@ zr_panel_end(struct zr_context *ctx) bounds.y = layout->clip.y; bounds.w = scrollbar_size + item_padding.x; bounds.h = layout->height + item_padding.y; - zr_draw_rect(out, bounds, 0, config->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, ZR_FILLED, bounds, 0, config->colors[ZR_COLOR_WINDOW]); } } else { /* dynamic window with visible scrollbars and therefore bigger footer */ @@ -8494,7 +8616,7 @@ zr_panel_end(struct zr_context *ctx) (layout->flags & ZR_WINDOW_CONTEXTUAL)) footer.y = window->bounds.y + layout->height; else footer.y = window->bounds.y + layout->height + layout->footer_h; - zr_draw_rect(out, footer, 0, config->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, ZR_FILLED, footer, 0, config->colors[ZR_COLOR_WINDOW]); if (!(layout->flags & ZR_WINDOW_COMBO) && !(layout->flags & ZR_WINDOW_MENU)) { /* fill empty scrollbar space */ @@ -8503,7 +8625,7 @@ zr_panel_end(struct zr_context *ctx) bounds.y = window->bounds.y + layout->height; bounds.w = layout->bounds.w; bounds.h = layout->row.height; - zr_draw_rect(out, bounds, 0, config->colors[ZR_COLOR_WINDOW]); + zr_draw_rect(out, ZR_FILLED, bounds, 0, config->colors[ZR_COLOR_WINDOW]); } } } @@ -8580,7 +8702,7 @@ zr_panel_end(struct zr_context *ctx) if (layout->flags & ZR_WINDOW_DYNAMIC) scaler_y = footer.y + layout->footer_h - scaler_size.y; else scaler_y = layout->bounds.y + layout->bounds.h - scaler_size.y; - zr_draw_triangle(out, scaler_x + scaler_w, scaler_y, + zr_draw_triangle(out, ZR_FILLED, scaler_x + scaler_w, scaler_y, scaler_x + scaler_w, scaler_y + scaler_h, scaler_x, scaler_y + scaler_h, col); if (!(window->flags & ZR_WINDOW_ROM)) { @@ -8756,7 +8878,7 @@ zr_panel_layout(const struct zr_context *ctx, struct zr_window *win, layout->row.height = height + item_spacing.y; layout->row.item_offset = 0; if (layout->flags & ZR_WINDOW_DYNAMIC) - zr_draw_rect(out, zr_rect(layout->bounds.x, layout->at_y, + zr_draw_rect(out, ZR_FILLED, zr_rect(layout->bounds.x, layout->at_y, layout->bounds.w, height + panel_padding.y), 0, *color); } @@ -9289,7 +9411,7 @@ zr_layout_push(struct zr_context *ctx, enum zr_layout_node_type type, zr_layout_row_dynamic(ctx, config->font.height + 2 * item_padding.y, 1); widget_state = zr_widget(&header, ctx); if (type == ZR_LAYOUT_TAB) - zr_draw_rect(out, header, 0, config->colors[ZR_COLOR_TAB_HEADER]); + zr_draw_rect(out, ZR_FILLED, header, 0, config->colors[ZR_COLOR_TAB_HEADER]); /* find or create tab persistent state (open/closed) */ title_len = (int)zr_strsiz(title); @@ -9319,7 +9441,7 @@ zr_layout_push(struct zr_context *ctx, enum zr_layout_node_type type, /* calculate the triangle points and draw triangle */ zr_triangle_from_direction(points, sym, 0, 0, heading); - zr_draw_triangle(&win->buffer, points[0].x, points[0].y, + zr_draw_triangle(&win->buffer, ZR_FILLED, points[0].x, points[0].y, points[1].x, points[1].y, points[2].x, points[2].y, config->colors[ZR_COLOR_TEXT]); /* calculate the space the icon occupied */ @@ -9980,7 +10102,7 @@ zr_selectable(struct zr_context *ctx, const char *str, zr_flags align, int *valu text.text = (!*value) ? config->colors[ZR_COLOR_TEXT] : config->colors[ZR_COLOR_SELECTABLE_TEXT]; - zr_draw_rect(&win->buffer, bounds, 0, background); + zr_draw_rect(&win->buffer, ZR_FILLED, bounds, 0, background); zr_widget_text(&win->buffer, bounds, str, zr_strsiz(str), &text, align|ZR_TEXT_MIDDLE, &config->font); return *value != old_value; @@ -10633,7 +10755,7 @@ zr_chart_begin(struct zr_context *ctx, const enum zr_chart_type type, item_padding = zr_get_property(ctx, ZR_PROPERTY_ITEM_PADDING); color = (type == ZR_CHART_LINES) ? config->colors[ZR_COLOR_PLOT]: config->colors[ZR_COLOR_HISTO]; - zr_draw_rect(out, bounds, config->rounding[ZR_ROUNDING_CHART], color); + zr_draw_rect(out, ZR_FILLED, bounds, config->rounding[ZR_ROUNDING_CHART], color); /* setup basic generic chart */ zr_zero(chart, sizeof(*chart)); @@ -10692,7 +10814,7 @@ zr_chart_push_line(struct zr_context *ctx, struct zr_window *win, i->mouse.buttons[ZR_BUTTON_LEFT].clicked) ? ZR_CHART_CLICKED: 0; color = config->colors[ZR_COLOR_PLOT_HIGHLIGHT]; } - zr_draw_rect(out, bounds, 0, color); + zr_draw_rect(out, ZR_FILLED, bounds, 0, color); g->index++; return ret; } @@ -10718,7 +10840,7 @@ zr_chart_push_line(struct zr_context *ctx, struct zr_window *win, color = config->colors[ZR_COLOR_PLOT_HIGHLIGHT]; } } - zr_draw_rect(out, zr_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); + zr_draw_rect(out, ZR_FILLED, zr_rect(cur.x - 2, cur.y - 2, 4, 4), 0, color); /* save current data point position */ g->last.x = cur.x; @@ -10769,7 +10891,7 @@ zr_chart_push_column(const struct zr_context *ctx, struct zr_window *win, in->mouse.buttons[ZR_BUTTON_LEFT].clicked) ? ZR_CHART_CLICKED: 0; color = config->colors[ZR_COLOR_HISTO_HIGHLIGHT]; } - zr_draw_rect(out, item, 0, color); + zr_draw_rect(out, ZR_FILLED, item, 0, color); chart->index++; return ret; } @@ -11524,8 +11646,8 @@ zr_combo_begin_text(struct zr_context *ctx, struct zr_panel *layout, is_active = zr_true; /* draw combo box header background and border */ - zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); - zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + zr_draw_rect(&win->buffer, ZR_FILLED, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, ZR_FILLED, zr_shrink_rect(header, 1), 0, ctx->style.colors[ZR_COLOR_COMBO]); { @@ -11592,8 +11714,8 @@ zr_combo_begin_color(struct zr_context *ctx, struct zr_panel *layout, is_active = !is_active; /* draw combo box header background and border */ - zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); - zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + zr_draw_rect(&win->buffer, ZR_FILLED, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, ZR_FILLED, zr_shrink_rect(header, 1), 0, ctx->style.colors[ZR_COLOR_COMBO]); { @@ -11607,7 +11729,7 @@ zr_combo_begin_color(struct zr_context *ctx, struct zr_panel *layout, content.y = header.y + 2 * item_padding.y; content.x = header.x + 2 * item_padding.x; content.w = header.w - (header.h + 4 * item_padding.x); - zr_draw_rect(&win->buffer, content, 0, color); + zr_draw_rect(&win->buffer, ZR_FILLED, content, 0, color); /* draw open/close symbol */ bounds.y = (header.y + item_padding.y) + (header.h-2.0f*item_padding.y)/2.0f @@ -11654,8 +11776,8 @@ zr_combo_begin_image(struct zr_context *ctx, struct zr_panel *layout, is_active = !is_active; /* draw combo box header background and border */ - zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); - zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + zr_draw_rect(&win->buffer, ZR_FILLED, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, ZR_FILLED, zr_shrink_rect(header, 1), 0, ctx->style.colors[ZR_COLOR_COMBO]); { @@ -11710,8 +11832,8 @@ zr_combo_begin_icon(struct zr_context *ctx, struct zr_panel *layout, is_active = !is_active; /* draw combo box header background and border */ - zr_draw_rect(&win->buffer, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); - zr_draw_rect(&win->buffer, zr_shrink_rect(header, 1), 0, + zr_draw_rect(&win->buffer, ZR_FILLED, header, 0, ctx->style.colors[ZR_COLOR_BORDER]); + zr_draw_rect(&win->buffer, ZR_FILLED, zr_shrink_rect(header, 1), 0, ctx->style.colors[ZR_COLOR_COMBO]); { diff --git a/zahnrad.h b/zahnrad.h index 772259b..709be2a 100644 --- a/zahnrad.h +++ b/zahnrad.h @@ -589,6 +589,8 @@ enum zr_command_type { ZR_COMMAND_CIRCLE, ZR_COMMAND_ARC, ZR_COMMAND_TRIANGLE, + ZR_COMMAND_POLYGON, + ZR_COMMAND_POLYLINE, ZR_COMMAND_TEXT, ZR_COMMAND_IMAGE }; @@ -604,6 +606,11 @@ struct zr_command { #endif }; +enum zr_command_drawing_mode { + ZR_STROKE, + ZR_FILLED +}; + struct zr_command_scissor { struct zr_command header; short x, y; @@ -627,6 +634,7 @@ struct zr_command_curve { struct zr_command_rect { struct zr_command header; + enum zr_command_drawing_mode mode; unsigned int rounding; short x, y; unsigned short w, h; @@ -645,13 +653,30 @@ struct zr_command_rect_multi_color { struct zr_command_circle { struct zr_command header; + enum zr_command_drawing_mode mode; short x, y; unsigned short w, h; struct zr_color color; }; +struct zr_command_polygon { + struct zr_command header; + enum zr_command_drawing_mode mode; + struct zr_color color; + unsigned short point_count; + struct zr_vec2i points[1]; +}; + +struct zr_command_polyline { + struct zr_command header; + struct zr_color color; + unsigned short point_count; + struct zr_vec2i points[1]; +}; + struct zr_command_arc { struct zr_command header; + enum zr_command_drawing_mode mode; short cx, cy; unsigned short r; float a[2]; @@ -660,6 +685,7 @@ struct zr_command_arc { struct zr_command_triangle { struct zr_command header; + enum zr_command_drawing_mode mode; struct zr_vec2i a; struct zr_vec2i b; struct zr_vec2i c; @@ -744,20 +770,25 @@ void zr_draw_line(struct zr_command_buffer*, float, float, float, float, struct zr_color); void zr_draw_curve(struct zr_command_buffer*, float, float, float, float, float, float, float, float, struct zr_color); -void zr_draw_rect(struct zr_command_buffer*, struct zr_rect, - float rounding, struct zr_color); +void zr_draw_rect(struct zr_command_buffer*, enum zr_command_drawing_mode, + struct zr_rect, float rounding, struct zr_color); void zr_draw_rect_multi_color(struct zr_command_buffer*, struct zr_rect, struct zr_color left, struct zr_color top, struct zr_color right, struct zr_color bottom); -void zr_draw_circle(struct zr_command_buffer*, struct zr_rect, struct zr_color); -void zr_draw_arc(struct zr_command_buffer*, float cx, float cy, float radius, - float a_min, float a_max, struct zr_color); -void zr_draw_triangle(struct zr_command_buffer*, float, float, float, float, - float, float, struct zr_color); +void zr_draw_circle(struct zr_command_buffer*, enum zr_command_drawing_mode, + struct zr_rect, struct zr_color); +void zr_draw_arc(struct zr_command_buffer*, enum zr_command_drawing_mode, + float cx, float cy, float radius, float a_min, float a_max, struct zr_color); +void zr_draw_triangle(struct zr_command_buffer*, enum zr_command_drawing_mode, + float, float, float, float, float, float, struct zr_color); void zr_draw_image(struct zr_command_buffer*, struct zr_rect, struct zr_image*); void zr_draw_text(struct zr_command_buffer*, struct zr_rect, const char *text, zr_size len, const struct zr_user_font*, struct zr_color, struct zr_color); +void zr_draw_polygon(struct zr_command_buffer*, enum zr_command_drawing_mode, + float*, int point_count, struct zr_color); +void zr_draw_polyline(struct zr_command_buffer*, float *points, int point_count, + struct zr_color col); #endif /* =============================================================== @@ -1406,12 +1437,6 @@ struct zr_context { struct zr_buffer memory; struct zr_clipboard clip; - zr_hash next_id; - /* hash value taken by the next widget. - * If not directly set by the user it - * will be incremented to ensure - * unique identifiers for every widget. */ - /* private: * should only be modifed if you * know what you are doing*/