From f88e92dd430ba306af30f080db90d93b33a5d44a Mon Sep 17 00:00:00 2001 From: vurtun Date: Tue, 27 Oct 2015 12:05:22 +0100 Subject: [PATCH] fixed text overdraw --- demo/demo.c | 1 - demo/opengl/opengl.c | 1 + example/filex/filex.c | 4 +- example/nodedit/nodedit.c | 6 +- zahnrad.c | 154 ++++++++++++++++++++++++-------------- zahnrad.h | 152 +++++++++++++++++++------------------ 6 files changed, 181 insertions(+), 137 deletions(-) diff --git a/demo/demo.c b/demo/demo.c index 06037fb..f681457 100644 --- a/demo/demo.c +++ b/demo/demo.c @@ -550,7 +550,6 @@ struct demo_gui { zr_size w, h; }; - /* ----------------------------------------------------------------- * WIDGETS * ----------------------------------------------------------------- */ diff --git a/demo/opengl/opengl.c b/demo/opengl/opengl.c index 5759523..df56970 100644 --- a/demo/opengl/opengl.c +++ b/demo/opengl/opengl.c @@ -250,6 +250,7 @@ font_bake_and_upload(struct device *dev, struct zr_font *font, dev->null.texture.id = (zr_int)dev->font_tex; dev->null.uv = zr_vec2((custom.x + 0.5f)/(zr_float)img_width, (custom.y + 0.5f)/(zr_float)img_height); + /* setup font with glyphes. IMPORTANT: the font only references the glyphes this was done to have the possibility to have multible fonts with one total glyph array. Not quite sure if it is a good thing since the diff --git a/example/filex/filex.c b/example/filex/filex.c index 8a750f2..a46d4ed 100644 --- a/example/filex/filex.c +++ b/example/filex/filex.c @@ -555,7 +555,7 @@ file_browser_run(struct file_browser *browser, int width, int height) { /* draw one row of icons */ size_t n = j + cols; - zr_layout_row_dynamic(&sub, 120, cols); + zr_layout_row_dynamic(&sub, 130, cols); zr_style_push_color(&browser->config, ZR_COLOR_BUTTON, zr_rgb(45, 45, 45)); zr_style_push_color(&browser->config, ZR_COLOR_BORDER, zr_rgb(45, 45, 45)); for (; j < count && j < n; ++j) { @@ -581,6 +581,7 @@ file_browser_run(struct file_browser *browser, int width, int height) } { /* draw one row of labels */ + zr_style_push_property(&browser->config, ZR_PROPERTY_ITEM_SPACING, zr_vec2(4, 4)); size_t n = k + cols; zr_layout_row_dynamic(&sub, 20, cols); for (; k < count && k < n; k++) { @@ -591,6 +592,7 @@ file_browser_run(struct file_browser *browser, int width, int height) zr_label(&sub,browser->files[t],ZR_TEXT_CENTERED); } } + zr_style_pop_property(&browser->config); } } diff --git a/example/nodedit/nodedit.c b/example/nodedit/nodedit.c index 649e32c..1a072f8 100644 --- a/example/nodedit/nodedit.c +++ b/example/nodedit/nodedit.c @@ -222,9 +222,11 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, /* execute each node as a moveable group */ zr_style_push_color(config, ZR_COLOR_WINDOW, zr_rgb(48, 48, 48)); while (it) { - /* draw node */ + /* calculate node group space */ zr_layout_row_space_push(layout, zr_rect(it->bounds.x - nodedit->scrolling.x, it->bounds.y - nodedit->scrolling.y, it->bounds.w, it->bounds.h)); + + /* execute node window */ zr_group_begin(layout, &node, it->name, ZR_WINDOW_MOVEABLE|ZR_WINDOW_NO_SCROLLBAR, zr_vec2(0,0)); { @@ -394,6 +396,8 @@ node_editor_draw(struct zr_context *layout, struct node_editor *nodedit, } } zr_layout_row_space_end(layout); + + /* window content scrolling */ if (zr_input_is_mouse_hovering_rect(in, layout->bounds) && zr_input_is_mouse_down(in, ZR_BUTTON_MIDDLE)) { nodedit->scrolling.x += in->mouse.delta.x; diff --git a/zahnrad.c b/zahnrad.c index 0bd2605..e50f38b 100644 --- a/zahnrad.c +++ b/zahnrad.c @@ -659,6 +659,85 @@ zr_utf_len(const zr_char *str, zr_size len) } return src_len; } + +static zr_size +zr_user_font_glyph_index_at_pos(const struct zr_user_font *font, const char *text, + zr_size text_len, zr_float xoff) +{ + zr_long unicode; + zr_size glyph_offset = 0; + zr_size glyph_len = zr_utf_decode(text, &unicode, text_len); + zr_size text_width = font->width(font->userdata, text, glyph_len); + zr_size src_len = glyph_len; + + while (text_len && glyph_len) { + if (text_width >= xoff) + return glyph_offset; + glyph_offset++; + text_len -= glyph_len; + glyph_len = zr_utf_decode(text + src_len, &unicode, text_len); + src_len += glyph_len; + text_width = font->width(font->userdata, text, src_len); + } + return glyph_offset; +} + +static zr_size +zr_use_font_glyph_clamp(const struct zr_user_font *font, const char *text, + zr_size text_len, zr_float space, zr_size *glyphes, zr_float *text_width) +{ + zr_size len = 0; + zr_size glyph_len; + zr_float width = 0; + zr_float last_width = 0; + zr_long unicode; + zr_size g = 0; + + glyph_len = zr_utf_decode(text, &unicode, text_len); + while (glyph_len && (width < space) && (len < text_len)) { + zr_size s; + len += glyph_len; + s = font->width(font->userdata, text, len); + last_width = width; + width = (zr_float)s; + glyph_len = zr_utf_decode(&text[len], &unicode, text_len - len); + g++; + } + + *glyphes = g; + *text_width = last_width; + return len; +} + +static zr_size +zr_user_font_glyphes_fitting_in_space(const struct zr_user_font *font, const char *text, + zr_size text_len, zr_float space, zr_size *glyphes, zr_float *text_width) +{ + zr_size glyph_len; + zr_float width = 0; + zr_float last_width = 0; + zr_long unicode; + zr_size offset = 0; + zr_size g = 0; + zr_size s; + + glyph_len = zr_utf_decode(text, &unicode, text_len); + s = font->width(font->userdata, text, glyph_len); + width = last_width = (zr_float)s; + while ((width < space) && text_len) { + g++; + offset += glyph_len; + text_len -= glyph_len; + last_width = width; + glyph_len = zr_utf_decode(&text[offset], &unicode, text_len); + s = font->width(font->userdata, &text[offset], glyph_len); + width += (zr_float)s; + } + + *glyphes = g; + *text_width = last_width; + return offset; +} /* * ============================================================== * @@ -1387,6 +1466,7 @@ zr_command_buffer_push_text(struct zr_command_buffer *b, struct zr_rect r, const zr_char *string, zr_size length, const struct zr_user_font *font, struct zr_color bg, struct zr_color fg) { + zr_size text_width = 0; struct zr_command_text *cmd; ZR_ASSERT(b); ZR_ASSERT(font); @@ -1397,6 +1477,15 @@ zr_command_buffer_push_text(struct zr_command_buffer *b, struct zr_rect r, return; } + /* make sure text fits inside bounds */ + text_width = font->width(font->userdata, string, length); + if (text_width > r.w){ + zr_float txt_width = (zr_float)text_width; + zr_size glyphes = 0; + length = zr_use_font_glyph_clamp(font, string, length, r.w, &glyphes, &txt_width); + } + + if (!length) return; cmd = (struct zr_command_text*) zr_command_buffer_push(b, ZR_COMMAND_TEXT, sizeof(*cmd) + length + 1); if (!cmd) return; @@ -2542,6 +2631,7 @@ zr_draw_list_add_text(struct zr_draw_list *list, const struct zr_user_font *font zr_long unicode, next; zr_size glyph_len, next_glyph_len; struct zr_user_font_glyph g; + ZR_ASSERT(list); if (!list || !len || !text) return; if (rect.x > (list->clip_rect.x + list->clip_rect.w) || @@ -2568,7 +2658,6 @@ zr_draw_list_add_text(struct zr_draw_list *list, const struct zr_user_font *font /* calculate and draw glyph drawing rectangle and image */ gx = x + g.offset.x; - /*gy = rect.y + (font->height/2) + (rect.h/2) - g.offset.y;*/ gy = rect.y + (rect.h/2) - (font->height/2) + g.offset.y; gw = g.width; gh = g.height; char_width = g.xadvance; @@ -2602,6 +2691,7 @@ zr_draw_list_path_line_to(struct zr_draw_list *list, struct zr_vec2 pos) if (!list) return; if (!list->cmd_count) zr_draw_list_add_clip(list, zr_null_rect); + cmd = zr_draw_list_command_last(list); if (cmd->texture.ptr != list->null.texture.ptr) zr_draw_list_push_image(list, list->null.texture); @@ -2668,6 +2758,7 @@ zr_draw_list_path_rect_to(struct zr_draw_list *list, struct zr_vec2 a, r = rounding; r = MIN(r, ((b.x-a.x) < 0) ? -(b.x-a.x): (b.x-a.x)); r = MIN(r, ((b.y-a.y) < 0) ? -(b.y-a.y): (b.y-a.y)); + if (r == 0.0f) { zr_draw_list_path_line_to(list, a); zr_draw_list_path_line_to(list, zr_vec2(b.x,a.y)); @@ -3700,8 +3791,9 @@ zr_widget_text(struct zr_command_buffer *o, struct zr_rect b, label.x = 0; label.w = 0; label.y = b.y + t->padding.y; label.h = MAX(0, b.h - 2 * t->padding.y); + text_width = f->width(f->userdata, (const zr_char*)string, len); - b.w = MAX(b.w, (2 * t->padding.x + (zr_float)text_width)); + text_width += (zr_size)(2 * t->padding.x); if (a == ZR_TEXT_LEFT) { label.x = b.x + t->padding.x; @@ -3709,12 +3801,12 @@ zr_widget_text(struct zr_command_buffer *o, struct zr_rect b, } else if (a == ZR_TEXT_CENTERED) { label.w = MAX(1, 2 * t->padding.x + (zr_float)text_width); label.x = (b.x + t->padding.x + ((b.w - 2 * t->padding.x)/2)); - if (label.x > label.w/2) label.x -= (label.w/2); + if (label.x >= label.w/2) label.x -= (label.w/2); label.x = MAX(b.x + t->padding.x, label.x); label.w = MIN(b.x + b.w, label.x + label.w); - if (label.w > label.x) label.w -= label.x; + if (label.w >= label.x) label.w -= label.x; } else if (a == ZR_TEXT_RIGHT) { - label.x = (b.x + b.w) - (2 * t->padding.x + (zr_float)text_width); + label.x = MAX(b.x + t->padding.x, (b.x + b.w) - (2 * t->padding.x + (zr_float)text_width)); label.w = (zr_float)text_width + 2 * t->padding.x; } else return; zr_command_buffer_push_text(o, label, (const zr_char*)string, @@ -4152,58 +4244,6 @@ zr_widget_progress(struct zr_command_buffer *out, struct zr_rect r, return prog_value; } -static zr_size -zr_user_font_glyph_index_at_pos(const struct zr_user_font *font, const char *text, - zr_size text_len, zr_float xoff) -{ - zr_long unicode; - zr_size glyph_offset = 0; - zr_size glyph_len = zr_utf_decode(text, &unicode, text_len); - zr_size text_width = font->width(font->userdata, text, glyph_len); - zr_size src_len = glyph_len; - - while (text_len && glyph_len) { - if (text_width >= xoff) - return glyph_offset; - glyph_offset++; - text_len -= glyph_len; - glyph_len = zr_utf_decode(text + src_len, &unicode, text_len); - src_len += glyph_len; - text_width = font->width(font->userdata, text, src_len); - } - return glyph_offset; -} - -static zr_size -zr_user_font_glyphes_fitting_in_space(const struct zr_user_font *font, const char *text, - zr_size text_len, zr_float space, zr_size *glyphes, zr_float *text_width) -{ - zr_size glyph_len; - zr_float width = 0; - zr_float last_width = 0; - zr_long unicode; - zr_size offset = 0; - zr_size g = 0; - zr_size s; - - glyph_len = zr_utf_decode(text, &unicode, text_len); - s = font->width(font->userdata, text, glyph_len); - width = last_width = (zr_float)s; - while ((width < space) && text_len) { - g++; - offset += glyph_len; - text_len -= glyph_len; - last_width = width; - glyph_len = zr_utf_decode(&text[offset], &unicode, text_len); - s = font->width(font->userdata, &text[offset], glyph_len); - width += (zr_float)s; - } - - *glyphes = g; - *text_width = last_width; - return offset; -} - void zr_widget_editbox(struct zr_command_buffer *out, struct zr_rect r, struct zr_edit_box *box, const struct zr_edit *field, diff --git a/zahnrad.h b/zahnrad.h index 8ae5bb8..b83ec33 100644 --- a/zahnrad.h +++ b/zahnrad.h @@ -1015,7 +1015,7 @@ const struct zr_command* zr_command_queue_next(struct zr_command_queue*, draw list even with anti-aliasing. The draw list consist internaly of three user provided buffers that will be - filled with data. The first buffer is the the draw command and temporary + filled with data. The first buffer is the draw command and temporary path buffer which permanetly stores all draw batch commands. The vertex and element buffer are the same buffers as their hardware renderer counter-parts, in fact it is even possible to directly map one of these buffers and fill @@ -3561,6 +3561,80 @@ enum zr_tree_node_operation zr_tree_leaf_icon(struct zr_tree*, */ void zr_tree_end(struct zr_context*, struct zr_tree*, struct zr_vec2 *scrollbar); /* this function ends a the tree building process */ +/* -------------------------------------------------------------- + * Group + * -------------------------------------------------------------- + GROUP + A group window represents a window inside a window. The group thereby has a fixed height + but just like a normal window has a scrollbar. It main promise is to group together + a group of widgets into a small space inside a window and to provide a scrollable + space inside a window. + + USAGE + To create a group you first have to allocate space in a window. This is done + by the group row layout API and works the same as widgets. After that the + `zr_group_begin` has to be called with the parent layout to create + the group in and a group layout to create a new window inside the window. + Just like a window layout structures the group layout only has a lifetime + between the `zr_group_begin` and `zr_group_end` and does + not have to be persistent. + + group window API + zr_group_begin -- adds a scrollable fixed space inside the window + zr_group_begin -- ends the scrollable space +*/ +void zr_group_begin(struct zr_context*, struct zr_context *tab, + const char *title, zr_flags, struct zr_vec2); +/* this function adds a grouped group window into the parent window + IMPORTANT: You need to set the height of the group with zr_row_layout + Input: + - group title to write into the header + - group scrollbar offset + Output: + - group layout to fill with widgets +*/ +void zr_group_end(struct zr_context*, struct zr_context*, struct zr_vec2 *scrollbar); +/* this function finishes the previously started group layout + Output: + - The from user input updated group scrollbar pixel offset +*/ +/* -------------------------------------------------------------- + * SHELF + * -------------------------------------------------------------- + SHELF + A shelf extends the concept of a group as an window inside a window + with the possibility to decide which content should be drawn into the group. + This is achieved by tabs on the top of the group window with one selected + tab. The selected tab thereby defines which content should be drawn inside + the group window by an index it returns. So you just have to check the returned + index and depending on it draw the wanted content. + + shelf API + zr_shelf_begin -- begins a shelf with a number of selectable tabs + zr_shelf_end -- ends a previously started shelf build up process + +*/ +zr_size zr_shelf_begin(struct zr_context*, struct zr_context*, + const char *tabs[], zr_size size, + zr_size active, struct zr_vec2 offset); +/* this function adds a shelf child window into the parent window + IMPORTANT: You need to set the height of the shelf with zr_row_layout + Input: + - all possible selectible tabs of the shelf with names as a string array + - number of seletectible tabs + - current active tab array index + - scrollbar pixel offset for the shelf + Output: + - group layout to fill with widgets + - the from user input updated current shelf tab index +*/ +void zr_shelf_end(struct zr_context *p, struct zr_context *s, struct zr_vec2 *scrollbar); +/* this function finishes the previously started shelf layout + Input: + - previously started group layout + Output: + - The from user input updated shelf scrollbar pixel offset +*/ /* -------------------------------------------------------------- * POPUP * -------------------------------------------------------------- @@ -3772,82 +3846,6 @@ void zr_tooltip_begin(struct zr_context *parent, struct zr_context *tip, */ void zr_tooltip_end(struct zr_context *parent, struct zr_context *tip); /* this function ends the tooltip window */ -/* -------------------------------------------------------------- - * Group - * -------------------------------------------------------------- - * - GROUP - A group window represents a window inside a window. The group thereby has a fixed height - but just like a normal window has a scrollbar. It main promise is to group together - a group of widgets into a small space inside a window and to provide a scrollable - space inside a window. - - USAGE - To create a group you first have to allocate space in a window. This is done - by the group row layout API and works the same as widgets. After that the - `zr_group_begin` has to be called with the parent layout to create - the group in and a group layout to create a new window inside the window. - Just like a window layout structures the group layout only has a lifetime - between the `zr_group_begin` and `zr_group_end` and does - not have to be persistent. - - group window API - zr_group_begin -- adds a scrollable fixed space inside the window - zr_group_begin -- ends the scrollable space -*/ -void zr_group_begin(struct zr_context*, struct zr_context *tab, - const char *title, zr_flags, struct zr_vec2); -/* this function adds a grouped group window into the parent window - IMPORTANT: You need to set the height of the group with zr_row_layout - Input: - - group title to write into the header - - group scrollbar offset - Output: - - group layout to fill with widgets -*/ -void zr_group_end(struct zr_context*, struct zr_context*, struct zr_vec2 *scrollbar); -/* this function finishes the previously started group layout - Output: - - The from user input updated group scrollbar pixel offset -*/ -/* -------------------------------------------------------------- - * SHELF - * -------------------------------------------------------------- - SHELF - A shelf extends the concept of a group as an window inside a window - with the possibility to decide which content should be drawn into the group. - This is achieved by tabs on the top of the group window with one selected - tab. The selected tab thereby defines which content should be drawn inside - the group window by an index it returns. So you just have to check the returned - index and depending on it draw the wanted content. - - shelf API - zr_shelf_begin -- begins a shelf with a number of selectable tabs - zr_shelf_end -- ends a previously started shelf build up process - -*/ -zr_size zr_shelf_begin(struct zr_context*, struct zr_context*, - const char *tabs[], zr_size size, - zr_size active, struct zr_vec2 offset); -/* this function adds a shelf child window into the parent window - IMPORTANT: You need to set the height of the shelf with zr_row_layout - Input: - - all possible selectible tabs of the shelf with names as a string array - - number of seletectible tabs - - current active tab array index - - scrollbar pixel offset for the shelf - Output: - - group layout to fill with widgets - - the from user input updated current shelf tab index -*/ -void zr_shelf_end(struct zr_context *p, struct zr_context *s, struct zr_vec2 *scrollbar); -/* this function finishes the previously started shelf layout - Input: - - previously started group layout - Output: - - The from user input updated shelf scrollbar pixel offset -*/ - #ifdef __cplusplus } #endif