expo: Support rendering multiple lines of text
Use the measurement info to write each line of text separately, thus
respecting word-wrapping and newlines.
Fix up the comment for scene_obj_render() while we are here.
Since a lineedit does not support alignment, add a special case to just
display the text if there is no measurement. This happens assuming the
lineedit is initially empty.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c
index 6a37fa8..ab21ed8 100644
--- a/boot/bootflow_menu.c
+++ b/boot/bootflow_menu.c
@@ -241,6 +241,10 @@
if (text_mode)
expo_set_text_mode(exp, text_mode);
+ ret = expo_calc_dims(exp);
+ if (ret)
+ return log_msg_ret("bmd", ret);
+
*expp = exp;
return 0;
diff --git a/boot/scene.c b/boot/scene.c
index aacdccd..72a8e27 100644
--- a/boot/scene.c
+++ b/boot/scene.c
@@ -8,6 +8,7 @@
#define LOG_CATEGORY LOGC_EXPO
+#include <alist.h>
#include <dm.h>
#include <expo.h>
#include <malloc.h>
@@ -163,6 +164,7 @@
}
gen->str_id = str_id;
+ alist_init_struct(&gen->lines, struct vidconsole_mline);
return 0;
}
@@ -336,8 +338,8 @@
struct scene_txt_generic *gen = &((struct scene_obj_txt *)obj)->gen;
struct expo *exp = scn->expo;
struct vidconsole_bbox bbox;
+ int len, ret, limit;
const char *str;
- int len, ret;
str = expo_get_str(exp, gen->str_id);
if (!str)
@@ -351,8 +353,12 @@
return 16;
}
+ limit = obj->flags & SCENEOF_SIZE_VALID ?
+ obj->bbox.x1 - obj->bbox.x0 : -1;
+
ret = vidconsole_measure(scn->expo->cons, gen->font_name,
- gen->font_size, str, -1, &bbox, NULL);
+ gen->font_size, str, limit, &bbox,
+ &gen->lines);
if (ret)
return log_msg_ret("mea", ret);
if (widthp)
@@ -418,6 +424,7 @@
struct scene_txt_generic *gen, int x, int y,
int menu_inset)
{
+ const struct vidconsole_mline *mline;
struct video_priv *vid_priv;
struct vidconsole_colour old;
enum colour_idx fore, back;
@@ -453,8 +460,16 @@
video_fill_part(dev, x - menu_inset, y, obj->bbox.x1,
obj->bbox.y1, vid_priv->colour_bg);
}
+
+ if (!gen->lines.count) {
+ vidconsole_set_cursor_pos(cons, x, y);
+ vidconsole_put_string(cons, str);
+ }
- vidconsole_set_cursor_pos(cons, x, y);
- vidconsole_put_string(cons, str);
+ alist_for_each(mline, &gen->lines) {
+ vidconsole_set_cursor_pos(cons, x + mline->bbox.x0,
+ y + mline->bbox.y0);
+ vidconsole_put_stringn(cons, str + mline->start, mline->len);
+ }
if (obj->flags & SCENEOF_POINT)
vidconsole_pop_colour(cons, &old);
@@ -464,6 +479,9 @@
/**
* scene_obj_render() - Render an object
*
+ * @obj: Object to render
+ * @text_mode: true to use text mode
+ * Return: 0 if OK, -ve on error
*/
static int scene_obj_render(struct scene_obj *obj, bool text_mode)
{
diff --git a/include/expo.h b/include/expo.h
index 7c6ab4b..a79aa1d 100644
--- a/include/expo.h
+++ b/include/expo.h
@@ -8,6 +8,7 @@
#define __EXPO_H
#include <abuf.h>
+#include <alist.h>
#include <dm/ofnode_decl.h>
#include <linux/bitops.h>
#include <linux/list.h>
@@ -296,11 +297,14 @@
* @str_id: ID of the text string to display
* @font_name: Name of font (allocated by caller)
* @font_size: Nominal size of font in pixels
+ * @lines: alist of struct vidconsole_mline with a separate record for each
+ * line of text
*/
struct scene_txt_generic {
uint str_id;
const char *font_name;
uint font_size;
+ struct alist lines;
};
/**
diff --git a/test/boot/expo.c b/test/boot/expo.c
index 6fb9f81..c9ff5b8 100644
--- a/test/boot/expo.c
+++ b/test/boot/expo.c
@@ -25,6 +25,7 @@
OBJ_LOGO,
OBJ_TEXT,
OBJ_TEXT2,
+ OBJ_TEXT3,
OBJ_MENU,
OBJ_MENU_TITLE,
@@ -33,6 +34,7 @@
STR_TEXT,
STR_TEXT2,
+ STR_TEXT3,
STR_MENU_TITLE,
STR_POINTER_TEXT,
@@ -488,6 +490,14 @@
60));
ut_assertok(scene_obj_set_pos(scn, OBJ_TEXT2, 200, 600));
+ id = scene_txt_str(scn, "text", OBJ_TEXT3, STR_TEXT3,
+ "this is yet\nanother string, with word-wrap",
+ NULL);
+ ut_assert(id > 0);
+ ut_assertok(scene_txt_set_font(scn, OBJ_TEXT3, "nimbus_sans_l_regular",
+ 60));
+ ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXT3, 500, 200, 1000, 700));
+
id = scene_menu(scn, "main", OBJ_MENU, &menu);
ut_assert(id > 0);
@@ -646,7 +656,7 @@
ut_assertok(scene_arrange(scn));
ut_assertok(expo_render(exp));
- ut_asserteq(10314, video_compress_fb(uts, dev, false));
+ ut_asserteq(14848, video_compress_fb(uts, dev, false));
ut_assertok(video_check_copy_fb(uts, dev));
/* make sure only the preview for the second item is shown */