From 9757f59c66b235b70283f84f70bad1587312b4c8 Mon Sep 17 00:00:00 2001 From: vurtun Date: Tue, 26 Jan 2016 14:52:00 +0100 Subject: [PATCH] Finally fixed the oldest bug in this library For now month I failed to find out why text calculation was bugged for zahnrads own vertex buffer font. I finally found the problem and fixed it. --- CONTRIBUTING.md | 1 - Readme.md | 2 +- demo/allegro5_complex/allegro.c | 10 +++- demo/allegro5_simple/allegro.c | 10 +++- demo/glfw/glfw.c | 13 ++++- demo/linuxgl/linuxgl.c | 10 +++- demo/nanovg/nanovg.c | 10 +++- demo/sdl/sdl.c | 10 +++- demo/x11/xlib.c | 10 +++- zahnrad.c | 100 ++++++++++++++++++++++++-------- zahnrad.h | 2 +- 11 files changed, 136 insertions(+), 42 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 358e6ab..830e12c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,6 @@ If you have an idea for new features just [open an issue](https://github.com/vur ## Bugs * Seperator widget is currently bugged and does not work as intended * Text handling is still a little bit janky and probably needs to be further tested and polished - * Text pixel width is bugged at the moment if you edit text with enabled font baking and vertex buffer API. * `zr_edit_buffer` with multiline flag is bugged for '\n', need to differentiate between visible and non-visible characters * `zr_layout_space_xxx` with `ZR_DYNAMIC` currently does not work diff --git a/Readme.md b/Readme.md index c8d4892..ca3583e 100644 --- a/Readme.md +++ b/Readme.md @@ -14,7 +14,7 @@ render backends it only focuses on the actual UI. - Immediate mode graphical user interface toolkit - Written in C89 (ANSI C) - Small codebase (~9kLOC) -- Focus on portability, efficiency, simplicity and minimal internal state +- Focus on portability, efficiency and simplicity - No dependencies (not even the standard library) - No global or hidden state - Configurable style and colors diff --git a/demo/allegro5_complex/allegro.c b/demo/allegro5_complex/allegro.c index 9b06759..6b021d9 100644 --- a/demo/allegro5_complex/allegro.c +++ b/demo/allegro5_complex/allegro.c @@ -288,9 +288,15 @@ input_key(struct zr_context *ctx, ALLEGRO_EVENT *evt, int down) zr_input_key(ctx, ZR_KEY_DEL, down); else if (sym == ALLEGRO_KEY_ENTER) zr_input_key(ctx, ZR_KEY_ENTER, down); - else if (sym == ALLEGRO_KEY_TAB) + else if (sym == ALLEGRO_KEY_TAB) { zr_input_key(ctx, ZR_KEY_TAB, down); - else if (sym == ALLEGRO_KEY_BACKSPACE) + if (!down) { + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + } + } else if (sym == ALLEGRO_KEY_BACKSPACE) zr_input_key(ctx, ZR_KEY_BACKSPACE, down); else if (sym == ALLEGRO_KEY_LEFT) zr_input_key(ctx, ZR_KEY_LEFT, down); diff --git a/demo/allegro5_simple/allegro.c b/demo/allegro5_simple/allegro.c index ff68cbb..5ff840e 100644 --- a/demo/allegro5_simple/allegro.c +++ b/demo/allegro5_simple/allegro.c @@ -120,9 +120,15 @@ input_key(struct zr_context *ctx, ALLEGRO_EVENT *evt, int down) zr_input_key(ctx, ZR_KEY_DEL, down); else if (sym == ALLEGRO_KEY_ENTER) zr_input_key(ctx, ZR_KEY_ENTER, down); - else if (sym == ALLEGRO_KEY_TAB) + else if (sym == ALLEGRO_KEY_TAB) { zr_input_key(ctx, ZR_KEY_TAB, down); - else if (sym == ALLEGRO_KEY_BACKSPACE) + if (!down) { + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + } + } else if (sym == ALLEGRO_KEY_BACKSPACE) zr_input_key(ctx, ZR_KEY_BACKSPACE, down); else if (sym == ALLEGRO_KEY_LEFT) zr_input_key(ctx, ZR_KEY_LEFT, down); diff --git a/demo/glfw/glfw.c b/demo/glfw/glfw.c index c05a0f2..f6f261e 100644 --- a/demo/glfw/glfw.c +++ b/demo/glfw/glfw.c @@ -384,12 +384,19 @@ input_key(GLFWwindow *window, int key, int scancode, int action, int mods) UNUSED(scancode); if (key == GLFW_KEY_RIGHT_SHIFT || key == GLFW_KEY_LEFT_SHIFT) zr_input_key(&gui.ctx, ZR_KEY_SHIFT, down); - else if (key == GLFW_KEY_DELETE) + else if (key == GLFW_KEY_TAB) { + zr_input_key(&gui.ctx, ZR_KEY_TAB, down); + /* because: reasons */ + if (!down) { + zr_input_unicode(&gui.ctx, ' '); + zr_input_unicode(&gui.ctx, ' '); + zr_input_unicode(&gui.ctx, ' '); + zr_input_unicode(&gui.ctx, ' '); + } + } else if (key == GLFW_KEY_DELETE) zr_input_key(&gui.ctx, ZR_KEY_DEL, down); else if (key == GLFW_KEY_ENTER) zr_input_key(&gui.ctx, ZR_KEY_ENTER, down); - else if (key == GLFW_KEY_TAB) - zr_input_key(&gui.ctx, ZR_KEY_TAB, down); else if (key == GLFW_KEY_BACKSPACE) zr_input_key(&gui.ctx, ZR_KEY_BACKSPACE, down); else if (key == GLFW_KEY_LEFT) diff --git a/demo/linuxgl/linuxgl.c b/demo/linuxgl/linuxgl.c index dfed84f..3090418 100644 --- a/demo/linuxgl/linuxgl.c +++ b/demo/linuxgl/linuxgl.c @@ -549,9 +549,15 @@ input_key(struct XWindow *xw, struct zr_context *ctx, XEvent *evt, int down) zr_input_key(ctx, ZR_KEY_DEL, down); else if (*code == XK_Return) zr_input_key(ctx, ZR_KEY_ENTER, down); - else if (*code == XK_Tab) + else if (*code == XK_Tab) { zr_input_key(ctx, ZR_KEY_TAB, down); - else if (*code == XK_space && !down) + if (!down) { + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + } + } else if (*code == XK_space && !down) zr_input_char(ctx, ' '); else if (*code == XK_Left) zr_input_key(ctx, ZR_KEY_LEFT, down); diff --git a/demo/nanovg/nanovg.c b/demo/nanovg/nanovg.c index 7d91a98..3d4def6 100644 --- a/demo/nanovg/nanovg.c +++ b/demo/nanovg/nanovg.c @@ -173,9 +173,15 @@ input_key(struct zr_context *ctx, SDL_Event *evt, int down) zr_input_key(ctx, ZR_KEY_DEL, down); else if (sym == SDLK_RETURN) zr_input_key(ctx, ZR_KEY_ENTER, down); - else if (sym == SDLK_TAB) + else if (sym == SDLK_TAB) { zr_input_key(ctx, ZR_KEY_TAB, down); - else if (sym == SDLK_BACKSPACE) + if (!down) { + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + } + } else if (sym == SDLK_BACKSPACE) zr_input_key(ctx, ZR_KEY_BACKSPACE, down); else if (sym == SDLK_LEFT) zr_input_key(ctx, ZR_KEY_LEFT, down); diff --git a/demo/sdl/sdl.c b/demo/sdl/sdl.c index a5c22c1..246c5ba 100644 --- a/demo/sdl/sdl.c +++ b/demo/sdl/sdl.c @@ -373,9 +373,15 @@ input_key(struct zr_context *ctx, SDL_Event *evt, int down) zr_input_key(ctx, ZR_KEY_DEL, down); else if (sym == SDLK_RETURN) zr_input_key(ctx, ZR_KEY_ENTER, down); - else if (sym == SDLK_TAB) + else if (sym == SDLK_TAB) { zr_input_key(ctx, ZR_KEY_TAB, down); - else if (sym == SDLK_BACKSPACE) + if (!down) { + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + } + } else if (sym == SDLK_BACKSPACE) zr_input_key(ctx, ZR_KEY_BACKSPACE, down); else if (sym == SDLK_LEFT) zr_input_key(ctx, ZR_KEY_LEFT, down); diff --git a/demo/x11/xlib.c b/demo/x11/xlib.c index b6e96f3..b78024f 100644 --- a/demo/x11/xlib.c +++ b/demo/x11/xlib.c @@ -361,9 +361,15 @@ input_key(struct XWindow *xw, struct zr_context *ctx, XEvent *evt, int down) zr_input_key(ctx, ZR_KEY_DEL, down); else if (*code == XK_Return) zr_input_key(ctx, ZR_KEY_ENTER, down); - else if (*code == XK_Tab) + else if (*code == XK_Tab) { zr_input_key(ctx, ZR_KEY_TAB, down); - else if (*code == XK_space && !down) + if (!down) { + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + zr_input_unicode(ctx, ' '); + } + } else if (*code == XK_space && !down) zr_input_char(ctx, ' '); else if (*code == XK_Left) zr_input_key(ctx, ZR_KEY_LEFT, down); diff --git a/zahnrad.c b/zahnrad.c index cec8f58..ac7ee35 100644 --- a/zahnrad.c +++ b/zahnrad.c @@ -1335,24 +1335,53 @@ zr_use_font_glyph_clamp(const struct zr_user_font *font, const char *text, static zr_size zr_user_font_glyphs_fitting_in_space(const struct zr_user_font *font, - const char *text, zr_size text_len, float space, zr_size *row_len, + const char *text, zr_size len, float space, zr_size *row_len, zr_size *glyphs, float *text_width, int has_newline) { zr_size glyph_len; - float width = 0; - float last_width = 0; - + zr_size width = 0; zr_rune unicode = 0; - zr_size offset = 0; - zr_size g = 0; - zr_size l = 0; - zr_size s; + zr_size text_len = 0; + zr_size row_advance = 0; - glyph_len = zr_utf_decode(text, &unicode, text_len); - s = font->width(font->userdata, font->height, text, glyph_len); - width = last_width = (float)s; + ZR_ASSERT(glyphs); + ZR_ASSERT(text_width); + ZR_ASSERT(row_len); - while ((width <= space) && text_len && glyph_len) { + *glyphs = 0; + *row_len = 0; + *text_width = 0; + + glyph_len = text_len = zr_utf_decode(text, &unicode, len); + if (!glyph_len) return 0; + width = font->width(font->userdata, font->height, text, text_len); + while ((width <= space) && (text_len <= len) && glyph_len) { + *text_width = width; + *glyphs+=1; + *row_len = text_len; + row_advance += glyph_len; + + if (has_newline && (unicode == '\n' || unicode == '\r')) { + zr_rune next = 0; + zr_utf_decode(text+text_len, &next, len - text_len); + if (unicode == '\r') { + *row_len-=1; *glyphs-=1; + } else if ((unicode == '\n') && (next == '\r')) { + *row_len-= 2; *glyphs-=2; + } else { + *row_len-=1; *glyphs-=1; + } + *text_width = font->width(font->userdata, font->height, text, *row_len); + break; + } + glyph_len = zr_utf_decode(text + text_len, &unicode, len - text_len); + text_len += glyph_len; + width = font->width(font->userdata, font->height, text, text_len); + } + return row_advance; + +#if 0 + while ((width <= space) && (text_len <= len) && glyph_len) { text_len -= glyph_len; offset += glyph_len; g++; l += glyph_len; @@ -1380,7 +1409,9 @@ zr_user_font_glyphs_fitting_in_space(const struct zr_user_font *font, *text_width = last_width; *row_len = l; return offset; +#endif } + /* ============================================================== * * BUFFER @@ -2694,12 +2725,11 @@ zr_canvas_add_text(struct zr_canvas *list, const struct zr_user_font *font, struct zr_rect rect, const char *text, zr_size len, float font_height, struct zr_color bg, struct zr_color fg) { - float x, scale; + float x; zr_size text_len; zr_rune unicode, next; zr_size glyph_len, next_glyph_len; struct zr_user_font_glyph g; - scale = font_height / font->height; ZR_ASSERT(list); if (!list || !len || !text) return; @@ -2723,14 +2753,14 @@ zr_canvas_add_text(struct zr_canvas *list, const struct zr_user_font *font, /* query currently drawn glyph information */ next_glyph_len = zr_utf_decode(text + text_len, &next, len - text_len); - font->query(font->userdata, font->height, &g, unicode, + font->query(font->userdata, font_height, &g, unicode, (next == ZR_UTF_INVALID) ? '\0' : next); /* calculate and draw glyph drawing rectangle and image */ - gx = x + g.offset.x * scale; - gy = rect.y + (rect.h/2) - (font->height/2) + g.offset.y * scale; - gw = g.width * scale; gh = g.height * scale; - char_width = g.xadvance * scale; + gx = x + g.offset.x; + gy = rect.y + (rect.h/2) - (font->height/2) + g.offset.y; + gw = g.width; gh = g.height; + char_width = g.xadvance; zr_canvas_push_rect_uv(list, zr_vec2(gx,gy), zr_vec2(gx + gw, gy+ gh), g.uv[0], g.uv[1], fg); @@ -3008,7 +3038,8 @@ zr_font_korean_glyph_ranges(void) return ranges; } -void zr_font_bake_memory(zr_size *temp, int *glyph_count, +void +zr_font_bake_memory(zr_size *temp, int *glyph_count, struct zr_font_config *config, int count) { int i, range_count = 0; @@ -3242,6 +3273,8 @@ zr_font_bake(void *image_memory, int width, int height, glyph->x1 = q.x1; glyph->y1 = q.y1; glyph->y0 += (dst_font->ascent + 0.5f); glyph->y1 += (dst_font->ascent + 0.5f); + glyph->w = glyph->x1 - glyph->x0 + 0.5f; + glyph->h = glyph->y1 - glyph->y0; if (cfg->coord_type == ZR_COORD_PIXEL) { glyph->u0 = q.s0 * (float)width; @@ -3365,7 +3398,7 @@ zr_font_text_width(zr_handle handle, float height, const char *text, zr_size len { zr_rune unicode; zr_size text_len = 0; - zr_size text_width = 0; + float text_width = 0; zr_size glyph_len = 0; float scale = 0; @@ -3375,6 +3408,22 @@ zr_font_text_width(zr_handle handle, float height, const char *text, zr_size len return 0; scale = height/font->size; + glyph_len = text_len = zr_utf_decode(text, &unicode, len); + if (!glyph_len) return 0; + while (text_len <= len && glyph_len) { + const struct zr_font_glyph *g; + if (unicode == ZR_UTF_INVALID) break; + + /* query currently drawn glyph information */ + g = zr_font_find_glyph(font, unicode); + text_width += g->xadvance * scale; + + /* offset next glyph */ + glyph_len = zr_utf_decode(text + text_len, &unicode, len - text_len); + text_len += glyph_len; + } + +#if 0 glyph_len = zr_utf_decode(text, &unicode, len); while (text_len < len && glyph_len) { const struct zr_font_glyph *glyph; @@ -3384,7 +3433,8 @@ zr_font_text_width(zr_handle handle, float height, const char *text, zr_size len text_width += (zr_size)((glyph->xadvance * scale)); glyph_len = zr_utf_decode(text + text_len, &unicode, len - text_len); } - return text_width; +#endif + return (zr_size)text_width; } #if ZR_COMPILE_WITH_VERTEX_BUFFER @@ -4919,13 +4969,15 @@ zr_widget_edit_field(struct zr_command_buffer *out, struct zr_rect r, label.x = r.x + field->padding.x + field->border_size; label.y = r.y + field->padding.y + field->border_size; label.h = r.h - (2 * field->padding.y + 2 * field->border_size); - zr_draw_text(out , label, &buffer[offset], text_len, + zr_draw_text(out, label, &buffer[offset], text_len, font, field->background, field->text); /* draw selected text */ if (box->active && field->show_cursor) { if (box->cursor == box->glyphs) { /* draw the cursor at the end of the string */ + text_width = font->width(font->userdata, font->height, + buffer + offset, text_len); zr_draw_rect(out, zr_rect(label.x+(float)text_width, label.y, (float)cursor_w, label.h), 0, field->cursor); } else { @@ -5253,7 +5305,7 @@ zr_widget_edit_box(struct zr_command_buffer *out, struct zr_rect r, /* draw unselected text part */ unselected_text_width = font->width(font->userdata, font->height, &buffer[offset], - (row_len >= sel_len) ? row_len - sel_len: 0); + (row_len >= sel_len) ? row_len - sel_len: 0); zr_draw_text(out , label, &buffer[offset], (row_len >= sel_len) ? row_len - sel_len: 0, font, field->background, field->text); diff --git a/zahnrad.h b/zahnrad.h index 1133b57..b7e2c60 100644 --- a/zahnrad.h +++ b/zahnrad.h @@ -402,7 +402,7 @@ struct zr_font_glyph { /* unicode codepoint */ float xadvance; /* xoffset to the next character */ - float x0, y0, x1, y1; + float x0, y0, x1, y1, w, h; /* glyph bounding points in pixel inside the glyph image with top * left and bottom right */ float u0, v0, u1, v1;