mirror of
https://github.com/u-boot/u-boot.git
synced 2025-04-24 14:25:56 +00:00
expo: Add basic support for textline objects
A textline is a line of text which can be edited by the user. It has a maximum length (in chracters) but otherwise there are no restrictions. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
93f99b35ec
commit
4db7519032
3 changed files with 272 additions and 1 deletions
|
@ -56,7 +56,8 @@ ifdef CONFIG_SPL_BUILD
|
||||||
obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
|
obj-$(CONFIG_SPL_LOAD_FIT) += common_fit.o
|
||||||
endif
|
endif
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo.o scene.o scene_menu.o expo_build.o
|
obj-$(CONFIG_$(SPL_TPL_)EXPO) += expo.o scene.o expo_build.o
|
||||||
|
obj-$(CONFIG_$(SPL_TPL_)EXPO) += scene_menu.o scene_textline.o
|
||||||
|
|
||||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o
|
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE) += vbe.o
|
||||||
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_REQUEST) += vbe_request.o
|
obj-$(CONFIG_$(SPL_TPL_)BOOTMETH_VBE_REQUEST) += vbe_request.o
|
||||||
|
|
234
boot/scene_textline.c
Normal file
234
boot/scene_textline.c
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0+
|
||||||
|
/*
|
||||||
|
* Implementation of a menu in a scene
|
||||||
|
*
|
||||||
|
* Copyright 2023 Google LLC
|
||||||
|
* Written by Simon Glass <sjg@chromium.org>
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define LOG_CATEGORY LOGC_EXPO
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
#include <expo.h>
|
||||||
|
#include <menu.h>
|
||||||
|
#include <video_console.h>
|
||||||
|
#include "scene_internal.h"
|
||||||
|
|
||||||
|
int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars,
|
||||||
|
struct scene_obj_textline **tlinep)
|
||||||
|
{
|
||||||
|
struct scene_obj_textline *tline;
|
||||||
|
char *buf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (max_chars >= EXPO_MAX_CHARS)
|
||||||
|
return log_msg_ret("chr", -E2BIG);
|
||||||
|
|
||||||
|
ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTLINE,
|
||||||
|
sizeof(struct scene_obj_textline),
|
||||||
|
(struct scene_obj **)&tline);
|
||||||
|
if (ret < 0)
|
||||||
|
return log_msg_ret("obj", -ENOMEM);
|
||||||
|
abuf_init(&tline->buf);
|
||||||
|
if (!abuf_realloc(&tline->buf, max_chars + 1))
|
||||||
|
return log_msg_ret("buf", -ENOMEM);
|
||||||
|
buf = abuf_data(&tline->buf);
|
||||||
|
*buf = '\0';
|
||||||
|
tline->pos = max_chars;
|
||||||
|
tline->max_chars = max_chars;
|
||||||
|
|
||||||
|
if (tlinep)
|
||||||
|
*tlinep = tline;
|
||||||
|
|
||||||
|
return tline->obj.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scene_textline_calc_bbox(struct scene_obj_textline *tline,
|
||||||
|
struct vidconsole_bbox *bbox,
|
||||||
|
struct vidconsole_bbox *edit_bbox)
|
||||||
|
{
|
||||||
|
const struct expo_theme *theme = &tline->obj.scene->expo->theme;
|
||||||
|
|
||||||
|
bbox->valid = false;
|
||||||
|
scene_bbox_union(tline->obj.scene, tline->label_id, 0, bbox);
|
||||||
|
scene_bbox_union(tline->obj.scene, tline->edit_id, 0, bbox);
|
||||||
|
|
||||||
|
edit_bbox->valid = false;
|
||||||
|
scene_bbox_union(tline->obj.scene, tline->edit_id, theme->menu_inset,
|
||||||
|
edit_bbox);
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_textline_calc_dims(struct scene_obj_textline *tline)
|
||||||
|
{
|
||||||
|
struct scene *scn = tline->obj.scene;
|
||||||
|
struct vidconsole_bbox bbox;
|
||||||
|
struct scene_obj_txt *txt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
|
||||||
|
if (!txt)
|
||||||
|
return log_msg_ret("dim", -ENOENT);
|
||||||
|
|
||||||
|
ret = vidconsole_nominal(scn->expo->cons, txt->font_name,
|
||||||
|
txt->font_size, tline->max_chars, &bbox);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("nom", ret);
|
||||||
|
|
||||||
|
if (bbox.valid) {
|
||||||
|
tline->obj.dim.w = bbox.x1 - bbox.x0;
|
||||||
|
tline->obj.dim.h = bbox.y1 - bbox.y0;
|
||||||
|
|
||||||
|
scene_obj_set_size(scn, tline->edit_id, tline->obj.dim.w,
|
||||||
|
tline->obj.dim.h);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline)
|
||||||
|
{
|
||||||
|
const bool open = tline->obj.flags & SCENEOF_OPEN;
|
||||||
|
bool point;
|
||||||
|
int x, y;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
x = tline->obj.dim.x;
|
||||||
|
y = tline->obj.dim.y;
|
||||||
|
if (tline->label_id) {
|
||||||
|
ret = scene_obj_set_pos(scn, tline->label_id, tline->obj.dim.x,
|
||||||
|
y);
|
||||||
|
if (ret < 0)
|
||||||
|
return log_msg_ret("tit", ret);
|
||||||
|
|
||||||
|
ret = scene_obj_set_pos(scn, tline->edit_id,
|
||||||
|
tline->obj.dim.x + 200, y);
|
||||||
|
if (ret < 0)
|
||||||
|
return log_msg_ret("tit", ret);
|
||||||
|
|
||||||
|
ret = scene_obj_get_hw(scn, tline->label_id, NULL);
|
||||||
|
if (ret < 0)
|
||||||
|
return log_msg_ret("hei", ret);
|
||||||
|
|
||||||
|
y += ret * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
point = scn->highlight_id == tline->obj.id;
|
||||||
|
point &= !open;
|
||||||
|
scene_obj_flag_clrset(scn, tline->edit_id, SCENEOF_POINT,
|
||||||
|
point ? SCENEOF_POINT : 0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline,
|
||||||
|
int key, struct expo_action *event)
|
||||||
|
{
|
||||||
|
const bool open = tline->obj.flags & SCENEOF_OPEN;
|
||||||
|
|
||||||
|
log_debug("key=%d\n", key);
|
||||||
|
switch (key) {
|
||||||
|
case BKEY_QUIT:
|
||||||
|
if (open) {
|
||||||
|
event->type = EXPOACT_CLOSE;
|
||||||
|
event->select.id = tline->obj.id;
|
||||||
|
|
||||||
|
/* Copy the backup text from the scene buffer */
|
||||||
|
memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf),
|
||||||
|
abuf_size(&scn->buf));
|
||||||
|
} else {
|
||||||
|
event->type = EXPOACT_QUIT;
|
||||||
|
log_debug("menu quit\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case BKEY_SELECT:
|
||||||
|
if (!open)
|
||||||
|
break;
|
||||||
|
event->type = EXPOACT_CLOSE;
|
||||||
|
event->select.id = tline->obj.id;
|
||||||
|
key = '\n';
|
||||||
|
fallthrough;
|
||||||
|
default: {
|
||||||
|
struct udevice *cons = scn->expo->cons;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
ret = vidconsole_entry_restore(cons, &scn->entry_save);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("sav", ret);
|
||||||
|
ret = cread_line_process_ch(&scn->cls, key);
|
||||||
|
ret = vidconsole_entry_save(cons, &scn->entry_save);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("sav", ret);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_textline_render_deps(struct scene *scn,
|
||||||
|
struct scene_obj_textline *tline)
|
||||||
|
{
|
||||||
|
const bool open = tline->obj.flags & SCENEOF_OPEN;
|
||||||
|
struct udevice *cons = scn->expo->cons;
|
||||||
|
struct scene_obj_txt *txt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
scene_render_deps(scn, tline->label_id);
|
||||||
|
scene_render_deps(scn, tline->edit_id);
|
||||||
|
|
||||||
|
/* show the vidconsole cursor if open */
|
||||||
|
if (open) {
|
||||||
|
/* get the position within the field */
|
||||||
|
txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
|
||||||
|
if (!txt)
|
||||||
|
return log_msg_ret("cur", -ENOENT);
|
||||||
|
|
||||||
|
if (txt->font_name || txt->font_size) {
|
||||||
|
ret = vidconsole_select_font(cons,
|
||||||
|
txt->font_name,
|
||||||
|
txt->font_size);
|
||||||
|
} else {
|
||||||
|
ret = vidconsole_select_font(cons, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = vidconsole_entry_restore(cons, &scn->entry_save);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("sav", ret);
|
||||||
|
|
||||||
|
vidconsole_set_cursor_visible(cons, true, txt->obj.dim.x,
|
||||||
|
txt->obj.dim.y, scn->cls.num);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline)
|
||||||
|
{
|
||||||
|
struct udevice *cons = scn->expo->cons;
|
||||||
|
struct scene_obj_txt *txt;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Copy the text into the scene buffer in case the edit is cancelled */
|
||||||
|
memcpy(abuf_data(&scn->buf), abuf_data(&tline->buf),
|
||||||
|
abuf_size(&scn->buf));
|
||||||
|
|
||||||
|
/* get the position of the editable */
|
||||||
|
txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
|
||||||
|
if (!txt)
|
||||||
|
return log_msg_ret("cur", -ENOENT);
|
||||||
|
|
||||||
|
vidconsole_set_cursor_pos(cons, txt->obj.dim.x, txt->obj.dim.y);
|
||||||
|
vidconsole_entry_start(cons);
|
||||||
|
cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars);
|
||||||
|
scn->cls.insert = true;
|
||||||
|
ret = vidconsole_entry_save(cons, &scn->entry_save);
|
||||||
|
if (ret)
|
||||||
|
return log_msg_ret("sav", ret);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int scene_textline_close(struct scene *scn, struct scene_obj_textline *tline)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -150,6 +150,7 @@ struct scene {
|
||||||
* @SCENEOBJT_IMAGE: Image data to render
|
* @SCENEOBJT_IMAGE: Image data to render
|
||||||
* @SCENEOBJT_TEXT: Text line to render
|
* @SCENEOBJT_TEXT: Text line to render
|
||||||
* @SCENEOBJT_MENU: Menu containing items the user can select
|
* @SCENEOBJT_MENU: Menu containing items the user can select
|
||||||
|
* @SCENEOBJT_TEXTLINE: Line of text the user can edit
|
||||||
*/
|
*/
|
||||||
enum scene_obj_t {
|
enum scene_obj_t {
|
||||||
SCENEOBJT_NONE = 0,
|
SCENEOBJT_NONE = 0,
|
||||||
|
@ -158,6 +159,7 @@ enum scene_obj_t {
|
||||||
|
|
||||||
/* types from here on can be highlighted */
|
/* types from here on can be highlighted */
|
||||||
SCENEOBJT_MENU,
|
SCENEOBJT_MENU,
|
||||||
|
SCENEOBJT_TEXTLINE,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -318,6 +320,27 @@ struct scene_menitem {
|
||||||
struct list_head sibling;
|
struct list_head sibling;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct scene_obj_textline - information about a textline in a scene
|
||||||
|
*
|
||||||
|
* A textline has a prompt and a line of editable text
|
||||||
|
*
|
||||||
|
* @obj: Basic object information
|
||||||
|
* @label_id: ID of the label text, or 0 if none
|
||||||
|
* @edit_id: ID of the editable text
|
||||||
|
* @max_chars: Maximum number of characters allowed
|
||||||
|
* @buf: Text buffer containing current text
|
||||||
|
* @pos: Cursor position
|
||||||
|
*/
|
||||||
|
struct scene_obj_textline {
|
||||||
|
struct scene_obj obj;
|
||||||
|
uint label_id;
|
||||||
|
uint edit_id;
|
||||||
|
uint max_chars;
|
||||||
|
struct abuf buf;
|
||||||
|
uint pos;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* expo_new() - create a new expo
|
* expo_new() - create a new expo
|
||||||
*
|
*
|
||||||
|
@ -552,6 +575,19 @@ int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
|
||||||
int scene_menu(struct scene *scn, const char *name, uint id,
|
int scene_menu(struct scene *scn, const char *name, uint id,
|
||||||
struct scene_obj_menu **menup);
|
struct scene_obj_menu **menup);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* scene_textline() - create a textline
|
||||||
|
*
|
||||||
|
* @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)
|
||||||
|
* @max_chars: Maximum length of the textline in characters
|
||||||
|
* @tlinep: If non-NULL, returns the new object
|
||||||
|
* Returns: ID number for the object (typically @id), or -ve on error
|
||||||
|
*/
|
||||||
|
int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars,
|
||||||
|
struct scene_obj_textline **tlinep);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* scene_txt_set_font() - Set the font for an object
|
* scene_txt_set_font() - Set the font for an object
|
||||||
*
|
*
|
||||||
|
|
Loading…
Add table
Reference in a new issue