From bd40a0a41c93a68a891f00340abd7c52b5bdfb48 Mon Sep 17 00:00:00 2001 From: Lephe Date: Mon, 22 Feb 2021 16:39:33 +0100 Subject: [PATCH] display: add more text size options dnsize() and drsize() * dnsize() works like dsize() but a limit on the number of bytes is specified. This is useful to obtain the length of a substring. * drsize() has a reverse limit; the input specifies a number of pixels and the function determines how much of the input fits. This is useful for word wrapping algorithms. --- include/gint/display.h | 26 ++++++++++++++++++ src/render/topti.c | 62 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 82 insertions(+), 6 deletions(-) diff --git a/include/gint/display.h b/include/gint/display.h index 9681f42..e955b97 100644 --- a/include/gint/display.h +++ b/include/gint/display.h @@ -264,6 +264,32 @@ font_t const *dfont(font_t const *font); @w @h Set to the width and height of the rendered text, may be NULL */ void dsize(char const *str, font_t const *font, int *w, int *h); +/* dnsize(): Get the width and height of rendered text, with character limit + + This function is similar to dsize(), but stops after (size) bytes If + (size < 0), there is no limit and this function is identical to dsize(). + + @str String whose size must be evaluated + @size Maximum number of bytes to read from (str) + @font Font to use; if NULL, defaults to the current font + @w @h Set to the width and height of the rendered text, may be NULL */ +void dnsize(char const *str, int size, font_t const *font, int *w, int *h); + +/* drsize(): Get width of rendered text with reverse size limit + + This function is the opposite of dnsize(). It determines how many characters + of (str) can fit into the specified (width), and returns a pointer to the + first character after that section. If (w) is non-NULL, it it set to the + width of the section, which is typically a couple of pixels smaller than + the provided limit. + + @str String to read characters from + @font Font to use; if NULL, defaults to the current font + @width Maximum width + @w Set to the width of the rendered text, may be NULL + Returns a pointer to first character that doesn't fit, or end-of-str */ +char const *drsize(char const *str, font_t const *font, int width, int *w); + /* Alignment settings for dtext_opt() and dprint_opt(). Combining a vertical and a horizontal alignment option specifies where a given point (x,y) should be relative to the rendered string. */ diff --git a/src/render/topti.c b/src/render/topti.c index 203ae55..0676cbe 100644 --- a/src/render/topti.c +++ b/src/render/topti.c @@ -97,10 +97,11 @@ uint32_t topti_utf8_next(uint8_t const **str_pointer) return 0x20; } -/* dsize(): Get the width and height of rendered text */ -void dsize(char const *str_char, font_t const * f, int *w, int *h) +/* dnsize(): Get the width and height of rendered text, with character limit */ +void dnsize(char const *str_char, int size, font_t const *f, int *w, int *h) { uint8_t const *str = (void *)str_char; + uint8_t const *str0 = str; uint32_t code_point; if(!f) f = topti_font; @@ -112,7 +113,13 @@ void dsize(char const *str_char, font_t const * f, int *w, int *h) if(!f->prop) { int length = 0; - while((code_point = topti_utf8_next(&str))) length++; + while(1) + { + code_point = topti_utf8_next(&str); + if(!code_point || (size >= 0 && str - str0 > size)) + break; + length++; + } *w = (f->width + f->char_spacing) * length - f->char_spacing; return; @@ -124,11 +131,54 @@ void dsize(char const *str_char, font_t const * f, int *w, int *h) while(1) { code_point = topti_utf8_next(&str); - if(!code_point) break; + if(!code_point || (size >= 0 && str - str0 > size)) break; int glyph = topti_glyph_index(f, code_point); - if(glyph < 0) continue; - width += f->glyph_width[glyph] + f->char_spacing; + if(glyph >= 0) + width += f->glyph_width[glyph] + f->char_spacing; } *w = width - f->char_spacing; } + +/* dsize(): Get the width and height of rendered text */ +void dsize(char const *str_char, font_t const *f, int *w, int *h) +{ + return dnsize(str_char, -1, f, w, h); +} + +/* drsize(): Get width of rendered text with reverse size limit */ +char const *drsize(char const *str_char, font_t const *f, int width, int *w) +{ + uint8_t const *str = (void *)str_char; + uint32_t code_point; + + int used_width = 0; + if(!f) f = topti_font; + + while(used_width < width) + { + /* Record that last glyph considered fits */ + str_char = (void *)str; + + code_point = topti_utf8_next(&str); + if(!code_point) + { + str_char = (void *)str; + break; + } + + if(used_width > 0) used_width += f->char_spacing; + if(!f->prop) + { + used_width += f->width; + } + else + { + int glyph = topti_glyph_index(f, code_point); + if(glyph >= 0) used_width += f->glyph_width[glyph]; + } + } + + if(w) *w = used_width; + return str_char; +}