PicoVector: Add optional text max width and max height.

pull/1064/head
Mike Bell 2024-11-17 13:11:56 +00:00 zatwierdzone przez Phil Howard
rodzic 074570f99c
commit c94f4607de
4 zmienionych plików z 49 dodań i 107 usunięć

Wyświetl plik

@ -31,6 +31,7 @@
#include <math.h>
#include <stdbool.h>
#include <wchar.h>
#include <float.h>
#ifdef AF_MALLOC
#ifndef PP_MALLOC
@ -104,8 +105,8 @@ typedef struct {
bool af_load_font_file(AF_FILE file, af_face_t *face);
void af_render_character(af_face_t *face, const char codepoint, af_text_metrics_t *tm);
void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm);
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm);
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm);
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm);
#ifdef AF_USE_PRETTY_POLY
#endif
@ -240,20 +241,30 @@ void af_render_character(af_face_t *face, const char c, af_text_metrics_t *tm) {
af_render_glyph(glyph, tm);
}
int get_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
int line_width = 0;
char *end = (char *)text + tlen;
float get_line_width(af_face_t *face, const char *text, size_t *tlen, float max_line_width, af_text_metrics_t *tm) {
float line_width = 0;
const char *start = text;
const char *end = text + *tlen;
const char *last_space = nullptr;
for(char c = *text; text < end; text++, c = *text) {
af_glyph_t *glyph = find_glyph(face, c);
if(!glyph) {
continue;
}
float char_width;
if(c == L' ') {
line_width += (glyph->advance * tm->word_spacing) / 100.0f;
char_width = (glyph->advance * tm->word_spacing) / 100.0f;
last_space = text;
} else {
line_width += (glyph->advance * tm->letter_spacing) / 100.0f;
char_width = (glyph->advance * tm->letter_spacing) / 100.0f;
}
if (max_line_width > 0 && line_width + char_width > max_line_width && last_space) {
*tlen = last_space - start;
break;
}
line_width += char_width;
}
return line_width;
}
@ -270,14 +281,14 @@ size_t line_length(const char *text, const char *end) {
return line_ending - text;
}
int get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
int max_width = 0;
float get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
float max_width = 0;
char *line = (char *)text;
char *tend = line + tlen;
size_t line_len = line_length(line, tend);
while(line_len) {
int width = get_line_width(face, line, line_len, tm);
float width = get_line_width(face, line, &line_len, 0, tm);
max_width = max_width < width ? width : max_width;
line += line_len + 1;
line_len = line_length(line, tend);
@ -286,7 +297,7 @@ int get_max_line_width(af_face_t *face, const char *text, size_t tlen, af_text_m
return max_width;
}
void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
void af_render(af_face_t *face, const char *text, size_t tlen, float max_line_width, float max_height, af_text_metrics_t *tm) {
char *line = (char *)text;
char *tend = line + tlen;
size_t line_len = 0;
@ -304,15 +315,23 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
caret.y = 0;
// find maximum line length
int max_line_width = get_max_line_width(face, text, tlen, tm);
if (max_line_width == 0.f) {
max_line_width = get_max_line_width(face, text, tlen, tm);
} else {
max_line_width /= scale;
}
if (max_height == 0.f) {
max_height = FLT_MAX;
} else {
max_height /= scale;
}
line_len = line_length(line, tend);
while(line_len) {
while(line_len && caret.y + line_height <= max_height) {
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
char *end = line + line_len;
int line_width = get_line_width(face, line, line_len, tm);
for(char c = *line; line < end; line++, c = *line) {
af_glyph_t *glyph = find_glyph(face, c);
if(!glyph) {
@ -356,10 +375,10 @@ void af_render(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t
}
void _af_render(af_face_t *face, const char *text, af_text_metrics_t *tm) {
af_render(face, text, strlen(text), tm);
af_render(face, text, strlen(text), 0, 0, tm);
}
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_metrics_t *tm) {
pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, float max_line_width, af_text_metrics_t *tm) {
pp_rect_t result;
bool first = true;
char *line = (char *)text;
@ -377,15 +396,14 @@ pp_rect_t af_measure(af_face_t *face, const char *text, size_t tlen, af_text_met
caret.y = 0;
// find maximum line length
int max_line_width = get_max_line_width(face, text, tlen, tm);
if (max_line_width == 0.f) max_line_width = get_max_line_width(face, text, tlen, tm);
line_len = line_length(line, tend);
while(line_len) {
int line_width = get_line_width(face, line, &line_len, max_line_width, tm);
char *end = line + line_len;
int line_width = get_line_width(face, line, line_len, tm);
for(char c = *line; line < end; line++, c = *line) {
af_glyph_t *glyph = find_glyph(face, c);
if(!glyph) {

Wyświetl plik

@ -60,93 +60,13 @@ namespace pimoroni {
}
}
pp_point_t PicoVector::text(std::string_view text, pp_mat3_t *t) {
pp_point_t PicoVector::text(std::string_view text, int max_width, int max_height, pp_mat3_t *t) {
pp_point_t caret = {0, 0};
text_metrics.transform = t;
af_render(text_metrics.face, text.data(), text.size(), &text_metrics);
af_render(text_metrics.face, text.data(), text.size(), max_width, max_height, &text_metrics);
return caret;
/*
// Align text from the bottom left
caret.y += (PP_COORD_TYPE)text_metrics.line_height;
caret = pp_point_transform(&caret, t);
caret.x += offset.x;
caret.y += offset.y;
pp_point_t space;
pp_point_t carriage_return = {0, -(PP_COORD_TYPE)text_metrics.line_height};
char spc = ' ';
space.x = af_measure(text_metrics.face, &spc, &text_metrics).w;
if (space.x == 0) {
space.x = text_metrics.word_spacing;
}
space = pp_point_transform(&space, t);
carriage_return = pp_point_transform(&carriage_return, t);
pp_point_t initial_carriage_return = carriage_return;
size_t i = 0;
while(i < text.length()) {
size_t next_space = text.find(' ', i + 1);
if(next_space == std::string::npos) {
next_space = text.length();
}
size_t next_linebreak = text.find('\n', i + 1);
if(next_linebreak == std::string::npos) {
next_linebreak = text.length();
}
size_t next_break = std::min(next_space, next_linebreak);
uint16_t word_width = 0;
for(size_t j = i; j < next_break; j++) {
word_width += af_measure(text_metrics.face, &text[j], &text_metrics).w;
word_width += text_metrics.letter_spacing;
}
if(caret.x != 0 && caret.x + word_width > graphics->clip.w) {
caret = pp_point_sub(&caret, &carriage_return);
carriage_return = initial_carriage_return;
}
for(size_t j = i; j < std::min(next_break + 1, text.length()); j++) {
if (text[j] == '\n') { // Linebreak
caret = pp_point_sub(&caret, &carriage_return);
carriage_return = initial_carriage_return;
} else if (text[j] == ' ') { // Space
caret = pp_point_add(&caret, &space);
carriage_return = pp_point_add(&carriage_return, &space);
} else {
// apply the caret offset...
pp_mat3_t pos = pp_mat3_identity();
pp_mat3_mul(&pos, t);
pp_mat3_translate(&pos, caret.x, caret.y);
text_metrics.transform = &pos;
af_render_character(text_metrics.face, text[j], &text_metrics);
}
pp_point_t advance = {
(PP_COORD_TYPE)af_measure(text_metrics.face, &text[j], &text_metrics).w + text_metrics.letter_spacing,
(PP_COORD_TYPE)0
};
advance = pp_point_transform(&advance, t);
caret = pp_point_add(&caret, &advance);
carriage_return = pp_point_add(&carriage_return, &advance);
}
i = next_break + 1;
}
return {caret.x, caret.y};
*/
}
}

Wyświetl plik

@ -93,7 +93,7 @@ namespace pimoroni {
pp_rect_t measure_text(std::string_view text, pp_mat3_t *t) {
text_metrics.transform = t;
return af_measure(text_metrics.face, text.data(), text.size(), &text_metrics);
return af_measure(text_metrics.face, text.data(), text.size(), 0, &text_metrics);
}
bool set_font(std::string_view font_path, unsigned int font_size) {
@ -124,7 +124,7 @@ namespace pimoroni {
return result;
}
pp_point_t text(std::string_view text, pp_mat3_t *t=nullptr);
pp_point_t text(std::string_view text, int max_width, int max_height, pp_mat3_t *t=nullptr);
void transform(pp_path_t *path, pp_mat3_t *t);
void transform(pp_poly_t *poly, pp_mat3_t *t);

Wyświetl plik

@ -699,13 +699,15 @@ mp_obj_t VECTOR_set_antialiasing(mp_obj_t self_in, mp_obj_t aa) {
}
mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_angle };
enum { ARG_self, ARG_text, ARG_x, ARG_y, ARG_angle, ARG_max_width, ARG_max_height };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_text, MP_ARG_REQUIRED | MP_ARG_OBJ },
{ MP_QSTR_x, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_y, MP_ARG_REQUIRED | MP_ARG_INT },
{ MP_QSTR_angle, MP_ARG_OBJ, {.u_obj = mp_const_none} }
{ MP_QSTR_angle, MP_ARG_OBJ, {.u_obj = mp_const_none} },
{ MP_QSTR_max_width, MP_ARG_INT, {.u_int = 0} },
{ MP_QSTR_max_height, MP_ARG_INT, {.u_int = 0} }
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
@ -723,6 +725,8 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
int x = args[ARG_x].u_int;
int y = args[ARG_y].u_int;
int max_width = args[ARG_max_width].u_int;
int max_height = args[ARG_max_height].u_int;
pp_mat3_t tt = pp_mat3_identity();
@ -732,7 +736,7 @@ mp_obj_t VECTOR_text(size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args)
pp_mat3_translate(&tt, (float)x, (float)y);
self->vector->text(t, &tt);
self->vector->text(t, max_width, max_height, &tt);
return mp_const_none;
}