diff options
| author | Tom Rini <[email protected]> | 2023-10-12 08:15:31 -0400 |
|---|---|---|
| committer | Tom Rini <[email protected]> | 2023-10-12 08:15:31 -0400 |
| commit | f9a47ac8d97da2b3aaf463f268a9a872a8d921df (patch) | |
| tree | 0a67c8aa5bd018d376f8073147cea33c6772861b /drivers | |
| parent | 429d59c3e5e6a3d3d6cd9f3c59c075e9037459c0 (diff) | |
| parent | 7e5b637483e03ce303ce84ec6b24156c6658ef46 (diff) | |
Merge branch '2023-10-12-expo-add-support-for-edting-lines-of-text'
To quote the author:
So far expo only supports menus. These are quite flexible for various
kinds of settings, but cannot deal with free-form input, such as a
serial number or a machine name.
This series adds support for a textline object, which is a single line
of text. It has a maximum length and its value is stored within the expo
structure.
U-Boot already has a command-line editor which provides most of the
features needed by expo. But the code runs in its own loop and only
returns when the line is finished. This is not suitable for expo, which
must handle a keypress at a time, returning to its caller after each
one.
In order to use the CLI code, some significant refactoring is included
here. This mostly involves moving the internal loop of the CLI to a
separate function and recording its state in a struct, just as was done
for single keypresses some time back. A minor addition is support for
Ctrl-W to delete a word, since strangely this is currently only present
in the simple version.
The video-console system provides most of the features needed by
testline, but a few things are missing. This series provides:
- primitive cursor support so the user can see where he is typing
- saving and restoring of the text-entry context, so that expo can allow
the user to continue where he left off, including deleting previously
entered characters correctly (for Truetype)
- obtaining the nominal width of a string of n characters, so that a
suitable width can be chosen for the textline object
Note that no support is provided for clearing the cursor. This was
addressed in a previous series[1] which could perhaps be rebased. For
this implementation, the cursor is therefore not enabled for the normal
command line, only for expo.
Reading and writing textline objects is supported for FDT and
environment, but not for CMOS RAM, since it would likely use too much
RAM to store a string.
In terms of code size, the overall size increase is 180 bytes for
Thumb02 boards, 160 of whcih is the addition of Ctrl-W to delete a word.
[1] https://patchwork.ozlabs.org/project/uboot/list/?series=280178&state=*
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/video/console_core.c | 31 | ||||
| -rw-r--r-- | drivers/video/console_normal.c | 29 | ||||
| -rw-r--r-- | drivers/video/console_truetype.c | 191 | ||||
| -rw-r--r-- | drivers/video/vidconsole-uclass.c | 71 | ||||
| -rw-r--r-- | drivers/video/vidconsole_internal.h | 24 |
5 files changed, 343 insertions, 3 deletions
diff --git a/drivers/video/console_core.c b/drivers/video/console_core.c index b5d0e3dceca..d17764d0b08 100644 --- a/drivers/video/console_core.c +++ b/drivers/video/console_core.c @@ -176,6 +176,37 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri return ret; } +int draw_cursor_vertically(void **line, struct video_priv *vid_priv, + uint height, bool direction) +{ + int step, line_step, pbytes, ret; + uint value; + void *dst; + + ret = check_bpix_support(vid_priv->bpix); + if (ret) + return ret; + + pbytes = VNBYTES(vid_priv->bpix); + if (direction) { + step = -pbytes; + line_step = -vid_priv->line_length; + } else { + step = pbytes; + line_step = vid_priv->line_length; + } + + value = vid_priv->colour_fg; + + for (int row = 0; row < height; row++) { + dst = *line; + for (int col = 0; col < VIDCONSOLE_CURSOR_WIDTH; col++) + fill_pixel_and_goto_next(&dst, value, pbytes, step); + *line += line_step; + } + return ret; +} + int console_probe(struct udevice *dev) { return console_set_font(dev, fonts); diff --git a/drivers/video/console_normal.c b/drivers/video/console_normal.c index 413c7abee9e..a0231293f31 100644 --- a/drivers/video/console_normal.c +++ b/drivers/video/console_normal.c @@ -97,6 +97,34 @@ static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, char ch) return VID_TO_POS(fontdata->width); } +static int console_set_cursor_visible(struct udevice *dev, bool visible, + uint x, uint y, uint index) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + struct console_simple_priv *priv = dev_get_priv(dev); + struct video_fontdata *fontdata = priv->fontdata; + int pbytes = VNBYTES(vid_priv->bpix); + void *start, *line; + + /* for now, this is not used outside expo */ + if (!IS_ENABLED(CONFIG_EXPO)) + return -ENOSYS; + + x += index * fontdata->width; + start = vid_priv->fb + y * vid_priv->line_length + x * pbytes; + + /* place the cursor 1 pixel before the start of the next char */ + x -= 1; + + line = start; + draw_cursor_vertically(&line, vid_priv, vc_priv->y_charsize, + NORMAL_DIRECTION); + + return 0; +} + struct vidconsole_ops console_ops = { .putc_xy = console_putc_xy, .move_rows = console_move_rows, @@ -104,6 +132,7 @@ struct vidconsole_ops console_ops = { .get_font_size = console_simple_get_font_size, .get_font = console_simple_get_font, .select_font = console_simple_select_font, + .set_cursor_visible = console_set_cursor_visible, }; U_BOOT_DRIVER(vidconsole_normal) = { diff --git a/drivers/video/console_truetype.c b/drivers/video/console_truetype.c index 0f9bb49e44f..14fb81e9563 100644 --- a/drivers/video/console_truetype.c +++ b/drivers/video/console_truetype.c @@ -4,6 +4,7 @@ */ #include <common.h> +#include <abuf.h> #include <dm.h> #include <log.h> #include <malloc.h> @@ -175,6 +176,17 @@ struct console_tt_priv { int pos_ptr; }; +/** + * struct console_tt_store - Format used for save/restore of entry information + * + * @priv: Private data + * @cur: Current cursor position + */ +struct console_tt_store { + struct console_tt_priv priv; + struct pos_info cur; +}; + static int console_truetype_set_row(struct udevice *dev, uint row, int clr) { struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent); @@ -706,8 +718,8 @@ static int truetype_select_font(struct udevice *dev, const char *name, return 0; } -int truetype_measure(struct udevice *dev, const char *name, uint size, - const char *text, struct vidconsole_bbox *bbox) +static int truetype_measure(struct udevice *dev, const char *name, uint size, + const char *text, struct vidconsole_bbox *bbox) { struct console_tt_metrics *met; stbtt_fontinfo *font; @@ -750,6 +762,177 @@ int truetype_measure(struct udevice *dev, const char *name, uint size, return 0; } +static int truetype_nominal(struct udevice *dev, const char *name, uint size, + uint num_chars, struct vidconsole_bbox *bbox) +{ + struct console_tt_metrics *met; + stbtt_fontinfo *font; + int lsb, advance; + int width; + int ret; + + ret = get_metrics(dev, name, size, &met); + if (ret) + return log_msg_ret("sel", ret); + + font = &met->font; + width = 0; + + /* First get some basic metrics about this character */ + stbtt_GetCodepointHMetrics(font, 'W', &advance, &lsb); + + width = advance; + + bbox->valid = true; + bbox->x0 = 0; + bbox->y0 = 0; + bbox->x1 = tt_ceil((double)width * num_chars * met->scale); + bbox->y1 = met->font_size; + + return 0; +} + +static int truetype_entry_save(struct udevice *dev, struct abuf *buf) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_tt_priv *priv = dev_get_priv(dev); + struct console_tt_store store; + const uint size = sizeof(store); + + /* + * store the whole priv structure as it is simpler that picking out + * what we need + */ + if (!abuf_realloc(buf, size)) + return log_msg_ret("sav", -ENOMEM); + + store.priv = *priv; + store.cur.xpos_frac = vc_priv->xcur_frac; + store.cur.ypos = vc_priv->ycur; + memcpy(abuf_data(buf), &store, size); + + return 0; +} + +static int truetype_entry_restore(struct udevice *dev, struct abuf *buf) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct console_tt_priv *priv = dev_get_priv(dev); + struct console_tt_store store; + + memcpy(&store, abuf_data(buf), sizeof(store)); + + vc_priv->xcur_frac = store.cur.xpos_frac; + vc_priv->ycur = store.cur.ypos; + priv->pos_ptr = store.priv.pos_ptr; + memcpy(priv->pos, store.priv.pos, + store.priv.pos_ptr * sizeof(struct pos_info)); + + return 0; +} + +static int truetype_set_cursor_visible(struct udevice *dev, bool visible, + uint x, uint y, uint index) +{ + struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev); + struct udevice *vid = dev->parent; + struct video_priv *vid_priv = dev_get_uclass_priv(vid); + struct console_tt_priv *priv = dev_get_priv(dev); + struct console_tt_metrics *met = priv->cur_met; + uint row, width, height, xoff; + void *start, *line; + uint out, val; + int ret; + + if (!visible) + return 0; + + /* + * figure out where to place the cursor. This driver ignores the + * passed-in values, since an entry_restore() must have been done before + * calling this function. + */ + if (index < priv->pos_ptr) + x = VID_TO_PIXEL(priv->pos[index].xpos_frac); + else + x = VID_TO_PIXEL(vc_priv->xcur_frac); + + y = vc_priv->ycur; + height = met->font_size; + xoff = 0; + + val = vid_priv->colour_bg ? 0 : 255; + width = VIDCONSOLE_CURSOR_WIDTH; + + /* Figure out where to write the cursor in the frame buffer */ + start = vid_priv->fb + y * vid_priv->line_length + + x * VNBYTES(vid_priv->bpix); + line = start; + + /* draw a vertical bar in the correct position */ + for (row = 0; row < height; row++) { + switch (vid_priv->bpix) { + case VIDEO_BPP8: + if (IS_ENABLED(CONFIG_VIDEO_BPP8)) { + u8 *dst = line + xoff; + int i; + + out = val; + for (i = 0; i < width; i++) { + if (vid_priv->colour_fg) + *dst++ |= out; + else + *dst++ &= out; + } + } + break; + case VIDEO_BPP16: { + u16 *dst = (u16 *)line + xoff; + int i; + + if (IS_ENABLED(CONFIG_VIDEO_BPP16)) { + for (i = 0; i < width; i++) { + out = val >> 3 | + (val >> 2) << 5 | + (val >> 3) << 11; + if (vid_priv->colour_fg) + *dst++ |= out; + else + *dst++ &= out; + } + } + break; + } + case VIDEO_BPP32: { + u32 *dst = (u32 *)line + xoff; + int i; + + if (IS_ENABLED(CONFIG_VIDEO_BPP32)) { + for (i = 0; i < width; i++) { + int out; + + out = val | val << 8 | val << 16; + if (vid_priv->colour_fg) + *dst++ |= out; + else + *dst++ &= out; + } + } + break; + } + default: + return -ENOSYS; + } + + line += vid_priv->line_length; + } + ret = vidconsole_sync_copy(dev, start, line); + if (ret) + return ret; + + return video_sync(vid, true); +} + const char *console_truetype_get_font_size(struct udevice *dev, uint *sizep) { struct console_tt_priv *priv = dev_get_priv(dev); @@ -802,6 +985,10 @@ struct vidconsole_ops console_truetype_ops = { .get_font_size = console_truetype_get_font_size, .select_font = truetype_select_font, .measure = truetype_measure, + .nominal = truetype_nominal, + .entry_save = truetype_entry_save, + .entry_restore = truetype_entry_restore, + .set_cursor_visible = truetype_set_cursor_visible }; U_BOOT_DRIVER(vidconsole_truetype) = { diff --git a/drivers/video/vidconsole-uclass.c b/drivers/video/vidconsole-uclass.c index b5b3b662590..22d55df71f6 100644 --- a/drivers/video/vidconsole-uclass.c +++ b/drivers/video/vidconsole-uclass.c @@ -10,6 +10,7 @@ #define LOG_CATEGORY UCLASS_VIDEO_CONSOLE #include <common.h> +#include <abuf.h> #include <command.h> #include <console.h> #include <log.h> @@ -47,7 +48,7 @@ int vidconsole_set_row(struct udevice *dev, uint row, int clr) return ops->set_row(dev, row, clr); } -static int vidconsole_entry_start(struct udevice *dev) +int vidconsole_entry_start(struct udevice *dev) { struct vidconsole_ops *ops = vidconsole_get_ops(dev); @@ -618,6 +619,74 @@ int vidconsole_measure(struct udevice *dev, const char *name, uint size, return 0; } +int vidconsole_nominal(struct udevice *dev, const char *name, uint size, + uint num_chars, struct vidconsole_bbox *bbox) +{ + struct vidconsole_priv *priv = dev_get_uclass_priv(dev); + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + int ret; + + if (ops->measure) { + ret = ops->nominal(dev, name, size, num_chars, bbox); + if (ret != -ENOSYS) + return ret; + } + + bbox->valid = true; + bbox->x0 = 0; + bbox->y0 = 0; + bbox->x1 = priv->x_charsize * num_chars; + bbox->y1 = priv->y_charsize; + + return 0; +} + +int vidconsole_entry_save(struct udevice *dev, struct abuf *buf) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + int ret; + + if (ops->measure) { + ret = ops->entry_save(dev, buf); + if (ret != -ENOSYS) + return ret; + } + + /* no data so make sure the buffer is empty */ + abuf_realloc(buf, 0); + + return 0; +} + +int vidconsole_entry_restore(struct udevice *dev, struct abuf *buf) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + int ret; + + if (ops->measure) { + ret = ops->entry_restore(dev, buf); + if (ret != -ENOSYS) + return ret; + } + + return 0; +} + +int vidconsole_set_cursor_visible(struct udevice *dev, bool visible, + uint x, uint y, uint index) +{ + struct vidconsole_ops *ops = vidconsole_get_ops(dev); + int ret; + + if (ops->set_cursor_visible) { + ret = ops->set_cursor_visible(dev, visible, x, y, index); + if (ret != -ENOSYS) + return ret; + } + + return 0; +} + void vidconsole_push_colour(struct udevice *dev, enum colour_idx fg, enum colour_idx bg, struct vidconsole_colour *old) { diff --git a/drivers/video/vidconsole_internal.h b/drivers/video/vidconsole_internal.h index c41edd45249..0ec581b2663 100644 --- a/drivers/video/vidconsole_internal.h +++ b/drivers/video/vidconsole_internal.h @@ -93,6 +93,30 @@ int fill_char_horizontally(uchar *pfont, void **line, struct video_priv *vid_pri struct video_fontdata *fontdata, bool direction); /** + * draw_cursor_vertically() - Draw a simple vertical cursor + * + * @line: pointer to framebuffer buffer: upper left cursor corner + * @vid_priv: driver private data + * @height: height of the cursor in pixels + * @param direction controls cursor orientation. Can be normal or flipped. + * When normal: When flipped: + *|-----------------------------------------------| + *| * | line stepping | + *| ^ * * * * * | | | + *| | * * | v * * | + *| | | * * * * * | + *| line stepping | * | + *| | | + *| stepping -> | <<- stepping | + *|---!!we're starting from upper left char corner| + *|-----------------------------------------------| + * + * Return: 0, if success, or else error code. + */ +int draw_cursor_vertically(void **line, struct video_priv *vid_priv, + uint height, bool direction); + +/** * console probe function. * * @param dev a pointer to device. |
