mirror of
https://gitee.com/zlgopen/awtk.git
synced 2024-12-02 03:58:33 +08:00
improve rich text
This commit is contained in:
parent
62ffe87669
commit
2b1f40fc41
@ -1,4 +1,4 @@
|
||||
<window anim_hint="htranslate" >
|
||||
<rich_text x="0" y="0" w="100%" h="60" text="<font color="a;red"a; size="a;24"a;>hello</font><font color="a;green"a; size="a;18"a;>&nbsp;world</font><image name="a;earth"a; />" />
|
||||
<rich_text x="0" y="0" w="100%" h="60" text="<font color="a;red"a; size="a;24"a;>hello</font><font color="a;green"a; size="a;20"a;>&nbsp;world</font><image name="a;bricks"a; />" />
|
||||
<button name="close" text="Close" x="c" y="bottom:10" w="25%" h="40" />
|
||||
</window>
|
||||
|
@ -63,9 +63,11 @@ static ret_t rich_text_on_paint_text(widget_t* widget, canvas_t* c) {
|
||||
case RICH_TEXT_IMAGE: {
|
||||
bitmap_t bitmap;
|
||||
const char* name = iter->node->u.image.name;
|
||||
image_draw_type_t draw_type = iter->node->u.image.draw_type;
|
||||
|
||||
if (image_manager_load(image_manager(), name, &bitmap) == RET_OK) {
|
||||
canvas_draw_icon_in_rect(c, &bitmap, r);
|
||||
canvas_draw_image_ex(c, &bitmap, draw_type, r);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
/**
|
||||
* History:
|
||||
* ================================================================
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> adapt from uclib
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> created
|
||||
*
|
||||
*/
|
||||
|
||||
@ -36,6 +36,7 @@ rich_text_node_t* rich_text_text_create_with_len(rich_text_font_t* font, const c
|
||||
node->next = NULL;
|
||||
node->type = RICH_TEXT_TEXT;
|
||||
node->u.text.font = *font;
|
||||
|
||||
if (font->name != NULL) {
|
||||
node->u.text.font.name = tk_strdup(font->name);
|
||||
goto_error_if_fail(node->u.text.font.name != NULL);
|
||||
@ -60,7 +61,8 @@ rich_text_node_t* rich_text_text_create(rich_text_font_t* font, const char* text
|
||||
return rich_text_text_create_with_len(font, text, strlen(text));
|
||||
}
|
||||
|
||||
rich_text_node_t* rich_text_image_create(const char* name, uint32_t w, uint32_t h) {
|
||||
rich_text_node_t* rich_text_image_create(const char* name, uint32_t w, uint32_t h,
|
||||
uint32_t draw_type) {
|
||||
rich_text_node_t* node = NULL;
|
||||
return_value_if_fail(name != NULL, NULL);
|
||||
|
||||
@ -69,11 +71,16 @@ rich_text_node_t* rich_text_image_create(const char* name, uint32_t w, uint32_t
|
||||
|
||||
node->next = NULL;
|
||||
node->type = RICH_TEXT_IMAGE;
|
||||
node->u.image.name = tk_strdup(name);
|
||||
node->u.image.w = w;
|
||||
node->u.image.h = h;
|
||||
node->u.image.draw_type = draw_type;
|
||||
node->u.image.name = tk_strdup(name);
|
||||
goto_error_if_fail(node->u.image.name != NULL);
|
||||
|
||||
return node;
|
||||
error:
|
||||
TKMEM_FREE(node);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret_t rich_text_text_destroy(rich_text_node_t* node) {
|
||||
|
@ -15,7 +15,7 @@
|
||||
/**
|
||||
* History:
|
||||
* ================================================================
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> adapt from uclib
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> created
|
||||
*
|
||||
*/
|
||||
|
||||
@ -27,8 +27,8 @@
|
||||
BEGIN_C_DECLS
|
||||
|
||||
typedef struct _rich_text_font_t {
|
||||
color_t color;
|
||||
char* name;
|
||||
color_t color;
|
||||
uint16_t size;
|
||||
uint16_t bold : 1;
|
||||
uint16_t italic : 1;
|
||||
@ -39,11 +39,12 @@ typedef struct _rich_text_image_t {
|
||||
char* name;
|
||||
uint32_t w;
|
||||
uint32_t h;
|
||||
uint32_t draw_type;
|
||||
} rich_text_image_t;
|
||||
|
||||
typedef struct _rich_text_text_t {
|
||||
rich_text_font_t font;
|
||||
wchar_t* text;
|
||||
rich_text_font_t font;
|
||||
} rich_text_text_t;
|
||||
|
||||
typedef enum _rich_text_node_type_t {
|
||||
@ -63,7 +64,8 @@ typedef struct _rich_text_node_t {
|
||||
rich_text_node_t* rich_text_text_create(rich_text_font_t* font, const char* text);
|
||||
rich_text_node_t* rich_text_text_create_with_len(rich_text_font_t* font, const char* text,
|
||||
uint32_t len);
|
||||
rich_text_node_t* rich_text_image_create(const char* name, uint32_t w, uint32_t h);
|
||||
rich_text_node_t* rich_text_image_create(const char* name, uint32_t w, uint32_t h,
|
||||
uint32_t draw_type);
|
||||
rich_text_node_t* rich_text_node_append(rich_text_node_t* node, rich_text_node_t* next);
|
||||
|
||||
int32_t rich_text_node_count(rich_text_node_t* node);
|
||||
|
@ -15,13 +15,15 @@
|
||||
/**
|
||||
* History:
|
||||
* ================================================================
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> adapt from uclib
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> created
|
||||
*
|
||||
*/
|
||||
|
||||
#include "base/mem.h"
|
||||
#include "base/str.h"
|
||||
#include "base/utils.h"
|
||||
#include "base/enums.h"
|
||||
#include "base/bitmap.h"
|
||||
#include "xml/xml_parser.h"
|
||||
#include "base/color_parser.h"
|
||||
#include "rich_text/rich_text_node.h"
|
||||
@ -92,6 +94,7 @@ static void xml_rich_text_on_start(XmlBuilder* thiz, const char* tag, const char
|
||||
} else if (tk_str_eq(tag, "image")) {
|
||||
int32_t w = 0;
|
||||
int32_t h = 0;
|
||||
int32_t draw_type = IMAGE_DRAW_CENTER;
|
||||
const char* image_name = NULL;
|
||||
|
||||
while (attrs[i]) {
|
||||
@ -103,12 +106,17 @@ static void xml_rich_text_on_start(XmlBuilder* thiz, const char* tag, const char
|
||||
w = tk_atoi(value);
|
||||
} else if (tk_str_eq(key, "h")) {
|
||||
h = tk_atoi(value);
|
||||
} else if (tk_str_eq(key, "draw_type")) {
|
||||
const key_type_value_t* kv = image_draw_type_find(value);
|
||||
if (kv != NULL) {
|
||||
draw_type = kv->value;
|
||||
}
|
||||
}
|
||||
i += 2;
|
||||
}
|
||||
|
||||
if (image_name != NULL) {
|
||||
b->node = rich_text_node_append(b->node, rich_text_image_create(image_name, w, h));
|
||||
b->node = rich_text_node_append(b->node, rich_text_image_create(image_name, w, h, draw_type));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
/**
|
||||
* History:
|
||||
* ================================================================
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> adapt from uclib
|
||||
* 2018-07-27 Li XianJing <xianjimli@hotmail.com> created
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
/**
|
||||
* History:
|
||||
* ================================================================
|
||||
* 2018-07-28 Li XianJing <xianjimli@hotmail.com> adapt from uclib
|
||||
* 2018-07-28 Li XianJing <xianjimli@hotmail.com> created
|
||||
*
|
||||
*/
|
||||
|
||||
@ -28,6 +28,7 @@
|
||||
rich_text_render_node_t* rich_text_render_node_create(rich_text_node_t* node) {
|
||||
rich_text_render_node_t* render_node = NULL;
|
||||
return_value_if_fail(node != NULL, NULL);
|
||||
|
||||
render_node = TKMEM_ZALLOC(rich_text_render_node_t);
|
||||
return_value_if_fail(render_node != NULL, NULL);
|
||||
|
||||
@ -36,6 +37,37 @@ rich_text_render_node_t* rich_text_render_node_create(rich_text_node_t* node) {
|
||||
return render_node;
|
||||
}
|
||||
|
||||
#define MOVE_TO_NEXT_ROW() \
|
||||
x = margin; \
|
||||
y += row_h; \
|
||||
if (row_first_node != NULL) { \
|
||||
rich_text_render_node_tune_row(row_first_node, row_h); \
|
||||
row_first_node = NULL; \
|
||||
}
|
||||
|
||||
rich_text_render_node_t* rich_text_render_node_tune_row(rich_text_render_node_t* row_first_node,
|
||||
int32_t row_h) {
|
||||
rich_text_render_node_t* iter = row_first_node;
|
||||
|
||||
while (iter != NULL) {
|
||||
iter->rect.h = row_h;
|
||||
switch (iter->node->type) {
|
||||
case RICH_TEXT_TEXT: {
|
||||
break;
|
||||
}
|
||||
case RICH_TEXT_IMAGE: {
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
iter = iter->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
rich_text_render_node_t* rich_text_render_node_layout(rich_text_node_t* node, canvas_t* c,
|
||||
int32_t w, int32_t h, int32_t margin) {
|
||||
int32_t row_h = 0;
|
||||
@ -49,48 +81,48 @@ rich_text_render_node_t* rich_text_render_node_layout(rich_text_node_t* node, ca
|
||||
rich_text_node_t* iter = node;
|
||||
rich_text_render_node_t* new_node = NULL;
|
||||
rich_text_render_node_t* render_node = NULL;
|
||||
rich_text_render_node_t* row_first_node = NULL;
|
||||
return_value_if_fail(node != NULL && c != NULL && client_w > 0 && client_h > 0, NULL);
|
||||
|
||||
while (iter != NULL) {
|
||||
switch (iter->type) {
|
||||
case RICH_TEXT_IMAGE: {
|
||||
bitmap_t bitmap;
|
||||
const char* name = iter->u.image.name;
|
||||
rich_text_image_t* image = &(iter->u.image);
|
||||
const char* name = image->name;
|
||||
new_node = rich_text_render_node_create(iter);
|
||||
return_value_if_fail(new_node != NULL, render_node);
|
||||
|
||||
if (image_manager_load(image_manager(), name, &bitmap) == RET_OK) {
|
||||
if (iter->u.image.w == 0) {
|
||||
iter->u.image.w = bitmap.w;
|
||||
if (image->w == 0) {
|
||||
image->w = bitmap.w;
|
||||
}
|
||||
if (iter->u.image.h == 0) {
|
||||
iter->u.image.h = bitmap.h;
|
||||
if (image->h == 0) {
|
||||
image->h = bitmap.h;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter->u.image.w > client_w) {
|
||||
iter->u.image.w = client_h;
|
||||
}
|
||||
|
||||
if ((y + iter->u.image.h) > bottom) {
|
||||
return render_node;
|
||||
}
|
||||
|
||||
if (iter->u.image.w > ICON_SIZE || (x + iter->u.image.w) > right) {
|
||||
x = margin;
|
||||
y += row_h;
|
||||
}
|
||||
|
||||
if (row_h < iter->u.image.h) {
|
||||
row_h = iter->u.image.h;
|
||||
if (image->w > ICON_SIZE || (x + image->w) > right) {
|
||||
MOVE_TO_NEXT_ROW();
|
||||
}
|
||||
|
||||
new_node->rect.x = x;
|
||||
new_node->rect.y = y;
|
||||
new_node->rect.w = iter->u.image.w;
|
||||
new_node->rect.h = iter->u.image.h;
|
||||
new_node->rect.w = image->w;
|
||||
new_node->rect.h = image->h;
|
||||
|
||||
if (image->w > ICON_SIZE) {
|
||||
new_node->rect.w = client_w;
|
||||
}
|
||||
|
||||
if (row_h < image->h) {
|
||||
row_h = image->h;
|
||||
}
|
||||
|
||||
render_node = rich_text_render_node_append(render_node, new_node);
|
||||
if (row_first_node == NULL) {
|
||||
row_first_node = new_node;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case RICH_TEXT_TEXT: {
|
||||
@ -110,18 +142,20 @@ rich_text_render_node_t* rich_text_render_node_layout(rich_text_node_t* node, ca
|
||||
for (i = 0; str[i]; i++) {
|
||||
cw = canvas_measure_text(c, str + i, 1);
|
||||
if ((x + tw + cw) > right) {
|
||||
x = margin;
|
||||
y += row_h;
|
||||
MOVE_TO_NEXT_ROW();
|
||||
|
||||
new_node = rich_text_render_node_create(iter);
|
||||
return_value_if_fail(new_node != NULL, render_node);
|
||||
|
||||
new_node->text = str + start;
|
||||
new_node->size = i - start + 1;
|
||||
new_node->rect = rect_init(x, y + row_h - font_size, tw, font_size);
|
||||
x += tw;
|
||||
new_node->rect = rect_init(x, y, tw, font_size);
|
||||
x += tw + 1;
|
||||
|
||||
render_node = rich_text_render_node_append(render_node, new_node);
|
||||
if (row_first_node == NULL) {
|
||||
row_first_node = new_node;
|
||||
}
|
||||
|
||||
start = i + 1;
|
||||
} else {
|
||||
@ -135,10 +169,13 @@ rich_text_render_node_t* rich_text_render_node_layout(rich_text_node_t* node, ca
|
||||
|
||||
new_node->text = str + start;
|
||||
new_node->size = i - start;
|
||||
new_node->rect = rect_init(x, y + row_h - font_size, tw, font_size);
|
||||
x += tw;
|
||||
new_node->rect = rect_init(x, y, tw, font_size);
|
||||
x += tw + 1;
|
||||
|
||||
render_node = rich_text_render_node_append(render_node, new_node);
|
||||
if (row_first_node == NULL) {
|
||||
row_first_node = new_node;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
@ -149,6 +186,7 @@ rich_text_render_node_t* rich_text_render_node_layout(rich_text_node_t* node, ca
|
||||
|
||||
iter = iter->next;
|
||||
}
|
||||
MOVE_TO_NEXT_ROW();
|
||||
|
||||
return render_node;
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
||||
/**
|
||||
* History:
|
||||
* ================================================================
|
||||
* 2018-07-28 Li XianJing <xianjimli@hotmail.com> adapt from uclib
|
||||
* 2018-07-28 Li XianJing <xianjimli@hotmail.com> created
|
||||
*
|
||||
*/
|
||||
|
||||
@ -30,9 +30,9 @@ BEGIN_C_DECLS
|
||||
typedef struct _rich_text_render_node_t {
|
||||
rich_text_node_t* node;
|
||||
|
||||
rect_t rect;
|
||||
wchar_t* text;
|
||||
uint32_t size;
|
||||
rect_t rect;
|
||||
|
||||
struct _rich_text_render_node_t* next;
|
||||
} rich_text_render_node_t;
|
||||
|
@ -34,6 +34,10 @@ typedef struct _font_stb_t {
|
||||
font_t base;
|
||||
stbtt_fontinfo stb_font;
|
||||
glyph_cache_t cache;
|
||||
int ascent;
|
||||
int descent;
|
||||
int lineGap;
|
||||
|
||||
} font_stb_t;
|
||||
|
||||
static bool_t font_stb_match(font_t* f, const char* name, uint16_t font_size) {
|
||||
@ -46,20 +50,27 @@ static ret_t font_stb_find_glyph(font_t* f, wchar_t c, glyph_t* g, uint16_t font
|
||||
int y = 0;
|
||||
int w = 0;
|
||||
int h = 0;
|
||||
int x1 = 0;
|
||||
int y1 = 0;
|
||||
int x2 = 0;
|
||||
int y2 = 0;
|
||||
int s = font_size;
|
||||
font_stb_t* font = (font_stb_t*)f;
|
||||
stbtt_fontinfo* sf = &(font->stb_font);
|
||||
float scale = stbtt_ScaleForPixelHeight(sf, s);
|
||||
|
||||
if (glyph_cache_lookup(&(font->cache), c, font_size, g) == RET_OK) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
g->data = stbtt_GetCodepointBitmap(sf, 0, stbtt_ScaleForPixelHeight(sf, s), c, &w, &h, &x, &y);
|
||||
g->data = stbtt_GetCodepointBitmap(sf, 0, scale, c, &w, &h, &x, &y);
|
||||
g->x = x;
|
||||
g->y = y;
|
||||
g->w = w;
|
||||
g->h = h;
|
||||
|
||||
glyph_cache_add(&(font->cache), c, font_size, g);
|
||||
stbtt_GetGlyphBitmapBox(sf, c, 0, scale, &x1, &y1, &x2, &y2);
|
||||
|
||||
return g->data != NULL ? RET_OK : RET_NOT_FOUND;
|
||||
}
|
||||
@ -96,6 +107,7 @@ font_t* font_stb_create(const char* name, const uint8_t* buff, uint32_t buff_siz
|
||||
|
||||
glyph_cache_init(&(f->cache), 256, destroy_glyph);
|
||||
stbtt_InitFont(&(f->stb_font), buff, stbtt_GetFontOffsetForIndex(buff, 0));
|
||||
stbtt_GetFontVMetrics(&(f->stb_font), &(f->ascent), &(f->descent), &(f->lineGap));
|
||||
|
||||
return &(f->base);
|
||||
}
|
||||
|
@ -20,7 +20,7 @@ TEST(RichTextNode, text) {
|
||||
}
|
||||
|
||||
TEST(RichTextNode, image) {
|
||||
rich_text_node_t* image = rich_text_image_create("earth", 12, 24);
|
||||
rich_text_node_t* image = rich_text_image_create("earth", 12, 24, 0);
|
||||
|
||||
ASSERT_EQ(image->type, RICH_TEXT_IMAGE);
|
||||
ASSERT_EQ(string(image->u.image.name), string("earth"));
|
||||
@ -39,7 +39,7 @@ TEST(RichTextNode, basic) {
|
||||
ASSERT_EQ(rich_text_node_count(node), 1);
|
||||
node = rich_text_node_append(node, rich_text_text_create(&font, "good"));
|
||||
ASSERT_EQ(rich_text_node_count(node), 2);
|
||||
node = rich_text_node_append(node, rich_text_image_create("earth", 12, 24));
|
||||
node = rich_text_node_append(node, rich_text_image_create("earth", 12, 24, 0));
|
||||
ASSERT_EQ(rich_text_node_count(node), 3);
|
||||
|
||||
rich_text_node_destroy(node);
|
||||
|
Loading…
Reference in New Issue
Block a user