kopia lustrzana https://github.com/pimoroni/pimoroni-pico
PicoVector: Add optional text max width and max height.
rodzic
074570f99c
commit
c94f4607de
|
@ -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) {
|
||||
|
|
|
@ -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};
|
||||
*/
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue