For expo, lineedit only supports a single line. For the CLI, the text can extend across multiple lines. Add support for this in the normal console, calculating the x and y offset of the cursor position based on the display width and font size. The truetype console already works, since it has had this tracking for a while. Signed-off-by: Simon Glass <sjg@chromium.org>
203 lines
5.1 KiB
C
203 lines
5.1 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2015 Google, Inc
|
|
* (C) Copyright 2015
|
|
* Bernecker & Rainer Industrieelektronik GmbH - http://www.br-automation.com
|
|
* (C) Copyright 2023 Dzmitry Sankouski <dsankouski@gmail.com>
|
|
*/
|
|
|
|
#include <charset.h>
|
|
#include <dm.h>
|
|
#include <spl.h>
|
|
#include <video.h>
|
|
#include <video_console.h>
|
|
#include <video_font.h> /* Get font data, width and height */
|
|
#include "vidconsole_internal.h"
|
|
|
|
struct console_store {
|
|
int xpos_frac;
|
|
int ypos;
|
|
int cli_index;
|
|
};
|
|
|
|
static int console_set_row(struct udevice *dev, uint row, int clr)
|
|
{
|
|
struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
|
|
struct console_simple_priv *priv = dev_get_priv(dev);
|
|
struct video_fontdata *fontdata = priv->fontdata;
|
|
void *line, *dst, *end;
|
|
int pixels = fontdata->height * vid_priv->xsize;
|
|
int ret;
|
|
int i;
|
|
int pbytes;
|
|
|
|
ret = check_bpix_support(vid_priv->bpix);
|
|
if (ret)
|
|
return ret;
|
|
|
|
line = vid_priv->fb + row * fontdata->height * vid_priv->line_length;
|
|
dst = line;
|
|
pbytes = VNBYTES(vid_priv->bpix);
|
|
for (i = 0; i < pixels; i++)
|
|
fill_pixel_and_goto_next(&dst, clr, pbytes, pbytes);
|
|
end = dst;
|
|
|
|
video_damage(dev->parent,
|
|
0,
|
|
fontdata->height * row,
|
|
vid_priv->xsize,
|
|
fontdata->height);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int console_move_rows(struct udevice *dev, uint rowdst,
|
|
uint rowsrc, uint count)
|
|
{
|
|
struct video_priv *vid_priv = dev_get_uclass_priv(dev->parent);
|
|
struct console_simple_priv *priv = dev_get_priv(dev);
|
|
struct video_fontdata *fontdata = priv->fontdata;
|
|
void *dst;
|
|
void *src;
|
|
int size;
|
|
|
|
dst = vid_priv->fb + rowdst * fontdata->height * vid_priv->line_length;
|
|
src = vid_priv->fb + rowsrc * fontdata->height * vid_priv->line_length;
|
|
size = fontdata->height * vid_priv->line_length * count;
|
|
memmove(dst, src, size);
|
|
|
|
video_damage(dev->parent,
|
|
0,
|
|
fontdata->height * rowdst,
|
|
vid_priv->xsize,
|
|
fontdata->height * count);
|
|
|
|
return 0;
|
|
}
|
|
|
|
int console_normal_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp)
|
|
{
|
|
struct console_simple_priv *priv = dev_get_priv(dev);
|
|
|
|
return console_fixed_putc_xy(dev, x_frac, y, cp, priv->fontdata);
|
|
}
|
|
|
|
static __maybe_unused int console_get_cursor_info(struct udevice *dev)
|
|
{
|
|
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
|
|
struct console_simple_priv *priv = dev_get_priv(dev);
|
|
struct video_fontdata *fontdata = priv->fontdata;
|
|
struct vidconsole_cursor *curs = &vc_priv->curs;
|
|
int x, y, index, xspace, xpos;
|
|
|
|
/* for now, this is not used outside expo */
|
|
if (!IS_ENABLED(CONFIG_EXPO))
|
|
return -ENOSYS;
|
|
|
|
x = VID_TO_PIXEL(vc_priv->xmark_frac);
|
|
y = vc_priv->ymark;
|
|
index = vc_priv->cli_index;
|
|
|
|
/* rounded up character position in this line */
|
|
xpos = (x + vc_priv->x_charsize - 1) / vc_priv->x_charsize;
|
|
|
|
/* number of characters which can fit on this (first) line */
|
|
xspace = vc_priv->cols - xpos;
|
|
|
|
if (!curs->indent && index > xspace) {
|
|
/* move to the next line */
|
|
y += vc_priv->y_charsize;
|
|
index -= xspace;
|
|
|
|
/* figure out the available space in subsequent lines */
|
|
if (!curs->indent) {
|
|
xspace = vc_priv->cols;
|
|
x = 0;
|
|
}
|
|
|
|
/* calculate the line based on that */
|
|
y += index / xspace;
|
|
x += (index % xspace) * fontdata->width;
|
|
} else {
|
|
x += index * fontdata->width;
|
|
}
|
|
|
|
/* place the cursor 1 pixel before the start of the next char */
|
|
if (x > 0)
|
|
x -= 1;
|
|
|
|
/* Store line pointer and height in cursor struct */
|
|
curs->x = x;
|
|
curs->y = y;
|
|
curs->height = vc_priv->y_charsize;
|
|
curs->index = vc_priv->cli_index;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static __maybe_unused int normal_entry_save(struct udevice *dev,
|
|
struct abuf *buf)
|
|
{
|
|
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
|
|
struct console_store store;
|
|
const uint size = sizeof(store);
|
|
|
|
if (xpl_phase() <= PHASE_SPL)
|
|
return -ENOSYS;
|
|
|
|
if (!abuf_realloc(buf, size))
|
|
return log_msg_ret("sav", -ENOMEM);
|
|
|
|
store.xpos_frac = vc_priv->xcur_frac;
|
|
store.ypos = vc_priv->ycur;
|
|
store.cli_index = vc_priv->cli_index;
|
|
memcpy(abuf_data(buf), &store, size);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static __maybe_unused int normal_entry_restore(struct udevice *dev,
|
|
struct abuf *buf)
|
|
{
|
|
struct vidconsole_priv *vc_priv = dev_get_uclass_priv(dev);
|
|
struct console_store store;
|
|
|
|
if (xpl_phase() <= PHASE_SPL)
|
|
return -ENOSYS;
|
|
|
|
memcpy(&store, abuf_data(buf), sizeof(store));
|
|
|
|
vc_priv->xcur_frac = store.xpos_frac;
|
|
vc_priv->ycur = store.ypos;
|
|
vc_priv->cli_index = store.cli_index;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int console_putc_xy(struct udevice *dev, uint x_frac, uint y, int cp)
|
|
{
|
|
return console_normal_putc_xy(dev, x_frac, y, cp);
|
|
}
|
|
|
|
struct vidconsole_ops console_ops = {
|
|
.putc_xy = console_putc_xy,
|
|
.move_rows = console_move_rows,
|
|
.set_row = console_set_row,
|
|
.get_font_size = console_simple_get_font_size,
|
|
.get_font = console_simple_get_font,
|
|
.select_font = console_simple_select_font,
|
|
#ifdef CONFIG_CURSOR
|
|
.get_cursor_info = console_get_cursor_info,
|
|
.entry_save = normal_entry_save,
|
|
.entry_restore = normal_entry_restore,
|
|
#endif
|
|
};
|
|
|
|
U_BOOT_DRIVER(vidconsole_normal) = {
|
|
.name = "vidconsole0",
|
|
.id = UCLASS_VIDEO_CONSOLE,
|
|
.ops = &console_ops,
|
|
.probe = console_probe,
|
|
.priv_auto = sizeof(struct console_simple_priv),
|
|
};
|