mirror of
https://source.denx.de/u-boot/u-boot.git
synced 2025-08-06 23:36:59 +02:00
expo: Begin implementation of a text editor
It is useful to be able to edit text, e.g. to allow the user to edit the environment or the command-line arguments for the OS. Add the beginnings of an implementation. Future work is needed to finish this: keypress handling and scrolling. For now it just displays the text. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
09f6f915fe
commit
e005f18b93
@ -58,7 +58,7 @@ obj-$(CONFIG_CMD_ADTIMG) += image-android-dt.o
|
||||
obj-$(CONFIG_$(PHASE_)LOAD_FIT) += common_fit.o
|
||||
|
||||
obj-$(CONFIG_$(PHASE_)EXPO) += expo.o scene.o expo_build.o
|
||||
obj-$(CONFIG_$(PHASE_)EXPO) += scene_menu.o scene_textline.o
|
||||
obj-$(CONFIG_$(PHASE_)EXPO) += scene_menu.o scene_textline.o scene_textedit.o
|
||||
ifdef CONFIG_COREBOOT_SYSINFO
|
||||
obj-$(CONFIG_$(PHASE_)EXPO) += expo_build_cb.o
|
||||
endif
|
||||
|
@ -82,6 +82,7 @@ int cedit_arange(struct expo *exp, struct video_priv *vpriv, uint scene_id)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_MENU:
|
||||
scene_obj_set_pos(scn, obj->id, 50, y);
|
||||
@ -383,6 +384,7 @@ static int h_write_settings(struct scene_obj *obj, void *vpriv)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_TEXTLINE: {
|
||||
const struct scene_obj_textline *tline;
|
||||
@ -483,6 +485,7 @@ static int h_read_settings(struct scene_obj *obj, void *vpriv)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_TEXTLINE: {
|
||||
const struct scene_obj_textline *tline;
|
||||
@ -555,6 +558,7 @@ static int h_write_settings_env(struct scene_obj *obj, void *vpriv)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_MENU:
|
||||
menu = (struct scene_obj_menu *)obj;
|
||||
@ -639,6 +643,7 @@ static int h_read_settings_env(struct scene_obj *obj, void *vpriv)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_MENU:
|
||||
menu = (struct scene_obj_menu *)obj;
|
||||
|
30
boot/scene.c
30
boot/scene.c
@ -417,13 +417,19 @@ int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
|
||||
*widthp = width;
|
||||
return height;
|
||||
}
|
||||
case SCENEOBJT_TEXT: {
|
||||
struct scene_txt_generic *gen = &((struct scene_obj_txt *)obj)->gen;
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_TEXTEDIT: {
|
||||
struct scene_txt_generic *gen;
|
||||
struct expo *exp = scn->expo;
|
||||
struct vidconsole_bbox bbox;
|
||||
int len, ret, limit;
|
||||
const char *str;
|
||||
|
||||
if (obj->type == SCENEOBJT_TEXT)
|
||||
gen = &((struct scene_obj_txt *)obj)->gen;
|
||||
else
|
||||
gen = &((struct scene_obj_txtedit *)obj)->gen;
|
||||
|
||||
str = expo_get_str(exp, gen->str_id);
|
||||
if (!str)
|
||||
return log_msg_ret("str", -ENOENT);
|
||||
@ -658,6 +664,13 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode)
|
||||
obj->bbox.y1, box->width, vid_priv->colour_fg);
|
||||
break;
|
||||
}
|
||||
case SCENEOBJT_TEXTEDIT: {
|
||||
struct scene_obj_txtedit *ted = (struct scene_obj_txtedit *)obj;
|
||||
|
||||
ret = scene_txt_render(exp, dev, cons, obj, &ted->gen, x, y,
|
||||
theme->menu_inset);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -677,6 +690,7 @@ int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_MENU: {
|
||||
struct scene_obj_menu *menu;
|
||||
@ -736,6 +750,7 @@ int scene_arrange(struct scene *scn)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_MENU: {
|
||||
struct scene_obj_menu *menu;
|
||||
@ -782,6 +797,7 @@ int scene_render_deps(struct scene *scn, uint id)
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_MENU:
|
||||
scene_menu_render_deps(scn,
|
||||
@ -921,6 +937,9 @@ int scene_send_key(struct scene *scn, int key, struct expo_action *event)
|
||||
return log_msg_ret("key", ret);
|
||||
break;
|
||||
}
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
/* TODO(sjg@chromium.org): Implement this */
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -947,6 +966,7 @@ int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox bbox[])
|
||||
case SCENEOBJT_IMAGE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
return -ENOSYS;
|
||||
case SCENEOBJT_MENU: {
|
||||
struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
|
||||
@ -977,6 +997,7 @@ int scene_calc_dims(struct scene *scn, bool do_menus)
|
||||
case SCENEOBJT_NONE:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
case SCENEOBJT_IMAGE: {
|
||||
int width;
|
||||
|
||||
@ -1038,6 +1059,10 @@ int scene_apply_theme(struct scene *scn, struct expo_theme *theme)
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTLINE:
|
||||
break;
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
scene_txted_set_font(scn, obj->id, NULL,
|
||||
theme->font_size);
|
||||
break;
|
||||
case SCENEOBJT_TEXT:
|
||||
scene_txt_set_font(scn, obj->id, NULL,
|
||||
theme->font_size);
|
||||
@ -1079,6 +1104,7 @@ static int scene_obj_open(struct scene *scn, struct scene_obj *obj)
|
||||
case SCENEOBJT_MENU:
|
||||
case SCENEOBJT_TEXT:
|
||||
case SCENEOBJT_BOX:
|
||||
case SCENEOBJT_TEXTEDIT:
|
||||
break;
|
||||
case SCENEOBJT_TEXTLINE:
|
||||
ret = scene_textline_open(scn,
|
||||
|
@ -414,4 +414,16 @@ int scene_textline_close(struct scene *scn, struct scene_obj_textline *tline);
|
||||
*/
|
||||
int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr);
|
||||
|
||||
/**
|
||||
* scene_txt_generic_init() - Set up the generic part of a text object
|
||||
*
|
||||
* @exp: Expo containing the object
|
||||
* @gen: Generic text info
|
||||
* @name: Object name
|
||||
* @str_id: String ID for the text
|
||||
* @str: Initial text string for the object, or NULL to just use str_id
|
||||
*/
|
||||
int scene_txt_generic_init(struct expo *exp, struct scene_txt_generic *gen,
|
||||
const char *name, uint str_id, const char *str);
|
||||
|
||||
#endif /* __SCENE_INTERNAL_H */
|
||||
|
61
boot/scene_textedit.c
Normal file
61
boot/scene_textedit.c
Normal file
@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Implementation of a menu in a scene
|
||||
*
|
||||
* Copyright 2025 Google LLC
|
||||
* Written by Simon Glass <sjg@chromium.org>
|
||||
*/
|
||||
|
||||
#define LOG_CATEGORY LOGC_EXPO
|
||||
|
||||
#include <expo.h>
|
||||
#include <log.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/sizes.h>
|
||||
#include "scene_internal.h"
|
||||
|
||||
enum {
|
||||
INITIAL_SIZE = SZ_4K,
|
||||
};
|
||||
|
||||
int scene_texted(struct scene *scn, const char *name, uint id, uint str_id,
|
||||
struct scene_obj_txtedit **teditp)
|
||||
{
|
||||
struct scene_obj_txtedit *ted;
|
||||
char *buf;
|
||||
int ret;
|
||||
|
||||
ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTEDIT,
|
||||
sizeof(struct scene_obj_txtedit),
|
||||
(struct scene_obj **)&ted);
|
||||
if (ret < 0)
|
||||
return log_msg_ret("obj", ret);
|
||||
|
||||
abuf_init(&ted->buf);
|
||||
if (!abuf_realloc(&ted->buf, INITIAL_SIZE))
|
||||
return log_msg_ret("buf", -ENOMEM);
|
||||
buf = abuf_data(&ted->buf);
|
||||
*buf = '\0';
|
||||
|
||||
ret = scene_txt_generic_init(scn->expo, &ted->gen, name, str_id, buf);
|
||||
if (ret)
|
||||
return log_msg_ret("teg", ret);
|
||||
if (teditp)
|
||||
*teditp = ted;
|
||||
|
||||
return ted->obj.id;
|
||||
}
|
||||
|
||||
int scene_txted_set_font(struct scene *scn, uint id, const char *font_name,
|
||||
uint font_size)
|
||||
{
|
||||
struct scene_obj_txtedit *ted;
|
||||
|
||||
ted = scene_obj_find(scn, id, SCENEOBJT_TEXTEDIT);
|
||||
if (!ted)
|
||||
return log_msg_ret("find", -ENOENT);
|
||||
ted->gen.font_name = font_name;
|
||||
ted->gen.font_size = font_size;
|
||||
|
||||
return 0;
|
||||
}
|
@ -560,6 +560,7 @@ Future ideas
|
||||
Some ideas for future work:
|
||||
|
||||
- Default menu item and a timeout
|
||||
- Complete the text editor
|
||||
- Image formats other than BMP
|
||||
- Use of ANSI sequences to control a serial terminal
|
||||
- Colour selection
|
||||
|
@ -183,12 +183,14 @@ struct scene {
|
||||
* @SCENEOBJT_TEXT: Text line to render
|
||||
* @SCENEOBJT_MENU: Menu containing items the user can select
|
||||
* @SCENEOBJT_TEXTLINE: Line of text the user can edit
|
||||
* @SCENEOBJT_TEXTEDIT: Simple text editor
|
||||
*/
|
||||
enum scene_obj_t {
|
||||
SCENEOBJT_NONE = 0,
|
||||
SCENEOBJT_IMAGE,
|
||||
SCENEOBJT_TEXT,
|
||||
SCENEOBJT_BOX,
|
||||
SCENEOBJT_TEXTEDIT,
|
||||
|
||||
/* types from here on can be highlighted */
|
||||
SCENEOBJT_MENU,
|
||||
@ -464,6 +466,21 @@ struct scene_obj_box {
|
||||
uint width;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct scene_obj_txtedit - information about a box in a scene
|
||||
*
|
||||
* A text editor which allows users to edit a small text file
|
||||
*
|
||||
* @obj: Basic object information
|
||||
* @gen: Generic information common to all objects which show text
|
||||
* @buf: Text buffer containing current text
|
||||
*/
|
||||
struct scene_obj_txtedit {
|
||||
struct scene_obj obj;
|
||||
struct scene_txt_generic gen;
|
||||
struct abuf buf;
|
||||
};
|
||||
|
||||
/**
|
||||
* struct expo_arrange_info - Information used when arranging a scene
|
||||
*
|
||||
@ -741,6 +758,19 @@ int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars,
|
||||
int scene_box(struct scene *scn, const char *name, uint id, uint width,
|
||||
struct scene_obj_box **boxp);
|
||||
|
||||
/**
|
||||
* scene_texted() - create a text editor
|
||||
*
|
||||
* @scn: Scene to update
|
||||
* @name: Name to use (this is allocated by this call)
|
||||
* @id: ID to use for the new object (0 to allocate one)
|
||||
* @strid: ID of the string to edit
|
||||
* @teditp: If non-NULL, returns the new object
|
||||
* Returns: ID number for the object (typically @id), or -ve on error
|
||||
*/
|
||||
int scene_texted(struct scene *scn, const char *name, uint id, uint strid,
|
||||
struct scene_obj_txtedit **teditp);
|
||||
|
||||
/**
|
||||
* scene_txt_set_font() - Set the font for an object
|
||||
*
|
||||
@ -752,6 +782,17 @@ int scene_box(struct scene *scn, const char *name, uint id, uint width,
|
||||
int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
|
||||
uint font_size);
|
||||
|
||||
/**
|
||||
* scene_txted_set_font() - Set the font for an object
|
||||
*
|
||||
* @scn: Scene to update
|
||||
* @id: ID of object to update
|
||||
* @font_name: Font name to use (allocated by caller)
|
||||
* @font_size: Font size to use (nominal height in pixels)
|
||||
*/
|
||||
int scene_txted_set_font(struct scene *scn, uint id, const char *font_name,
|
||||
uint font_size);
|
||||
|
||||
/**
|
||||
* scene_obj_set_pos() - Set the postion of an object
|
||||
*
|
||||
|
@ -30,6 +30,7 @@ enum {
|
||||
OBJ_MENU_TITLE,
|
||||
OBJ_BOX,
|
||||
OBJ_BOX2,
|
||||
OBJ_TEXTED,
|
||||
|
||||
/* strings */
|
||||
STR_SCENE_TITLE,
|
||||
@ -37,6 +38,7 @@ enum {
|
||||
STR_TEXT,
|
||||
STR_TEXT2,
|
||||
STR_TEXT3,
|
||||
STR_TEXTED,
|
||||
STR_MENU_TITLE,
|
||||
STR_POINTER_TEXT,
|
||||
|
||||
@ -462,6 +464,7 @@ static int expo_render_image(struct unit_test_state *uts)
|
||||
{
|
||||
struct scene_obj_menu *menu;
|
||||
struct scene *scn, *scn2;
|
||||
struct abuf orig, *text;
|
||||
struct expo_action act;
|
||||
struct scene_obj *obj;
|
||||
struct udevice *dev;
|
||||
@ -556,6 +559,14 @@ static int expo_render_image(struct unit_test_state *uts)
|
||||
ut_assert(id > 0);
|
||||
ut_assertok(scene_obj_set_bbox(scn, OBJ_BOX, 500, 200, 1000, 350));
|
||||
|
||||
id = scene_texted(scn, "editor", OBJ_TEXTED, STR_TEXTED, NULL);
|
||||
ut_assert(id > 0);
|
||||
ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXTED, 100, 200, 400, 650));
|
||||
ut_assertok(expo_edit_str(exp, STR_TEXTED, &orig, &text));
|
||||
|
||||
abuf_printf(text, "This\nis the initial contents of the text editor "
|
||||
"but it is quite likely that more will be added later");
|
||||
|
||||
scn2 = expo_lookup_scene_id(exp, SCENE1);
|
||||
ut_asserteq_ptr(scn, scn2);
|
||||
scn2 = expo_lookup_scene_id(exp, SCENE2);
|
||||
@ -666,9 +677,12 @@ static int expo_render_image(struct unit_test_state *uts)
|
||||
ut_asserteq(ITEM2, scene_menu_get_cur_item(scn, OBJ_MENU));
|
||||
ut_assertok(scene_arrange(scn));
|
||||
ut_assertok(expo_render(exp));
|
||||
ut_asserteq(16304, video_compress_fb(uts, dev, false));
|
||||
ut_asserteq(19673, video_compress_fb(uts, dev, false));
|
||||
ut_assertok(video_check_copy_fb(uts, dev));
|
||||
|
||||
/* hide the text editor since the following tets don't need it */
|
||||
scene_obj_set_hide(scn, OBJ_TEXTED, true);
|
||||
|
||||
/* do some alignment checks */
|
||||
ut_assertok(scene_obj_set_halign(scn, OBJ_TEXT3, SCENEOA_CENTRE));
|
||||
ut_assertok(expo_render(exp));
|
||||
|
Loading…
Reference in New Issue
Block a user