fixed text overdraw

This commit is contained in:
vurtun 2015-10-27 12:05:22 +01:00
parent 4e97a489b2
commit f88e92dd43
6 changed files with 181 additions and 137 deletions

View File

@ -550,7 +550,6 @@ struct demo_gui {
zr_size w, h;
};
/* -----------------------------------------------------------------
* WIDGETS
* ----------------------------------------------------------------- */

View File

@ -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

View File

@ -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);
}
}

View File

@ -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;

154
zahnrad.c
View File

@ -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,

152
zahnrad.h
View File

@ -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