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.
This commit is contained in:
Lephe 2021-02-22 16:39:33 +01:00
parent a086510885
commit bd40a0a41c
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
2 changed files with 82 additions and 6 deletions

View File

@ -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. */

View File

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