[PATCH 00/16] expo: Continue preparations for textedit (part D)
From: Simon Glass <simon.glass@canonical.com> At present vidconsole uses a save/restore model for its state. The textline object saves the state, does its drawing, then restores it. This is fairly clumsy and makes textedit harder to implement. This series continues the changes to adjust this, adding a putch() callback to the CLI line-editing code, so that output can (later) be directed to the correct context. It also adds word-wrapping support to the textedit scene object. The remaining patches refactor the textline and textedit code to share common functionality through a new scene_txtin structure and helper functions. This allows textedit to properly calculate its bounding box and dimensions, enabling word-wrapping within the edit area. It also includes an attempted fix for the flaky FPDT test. Overall code-size is neutral, e.g. for Thumb2 with EXPO: 03: cli: Add putch callback to struct cli_line_state arm: (for 1/1 boards) all +92.0 text +92.0 04: cli: Convert ERASE_TO_EOL macro to a function arm: (for 1/1 boards) all -104.0 text -104.0 05: cli: Add cls_putnstr() for string output with callback arm: (for 1/1 boards) all -20.0 text -20.0 Without EXPO, code size reduces by about 56 bytes (e.g. xilinx_versal_virt) Simon Glass (16): test: acpi: Fix flaky dm_test_acpi_fpdt checksum test cli: Add putch callback to struct cli_line_state cli: Convert ERASE_TO_EOL macro to a function cli: Add cls_putnstr() for string output with callback expo: Wire up putch callback for textline editing test: expo: Add a separate test for textedit expo: Refactor textedit to use label_id and edit_id expo: Rename textline max_chars to line_chars expo: Add line_chars to scene_obj_txtedit expo: Add arrangement support for textedit expo: Introduce scene_txtin for common text-input fields expo: Factor out common calc_bbox code into scene_txtin.c expo: Add scene_obj_txtin() helper for text-input objects expo: Add scene_txtin_init() for common text-input init expo: Add scene_txtin_arrange() for common arrangement code expo: Enable textedit dimension calculation for word-wrap boot/Kconfig | 1 + boot/Makefile | 2 +- boot/bootctl/multi_ui.c | 4 +- boot/bootflow_menu.c | 6 +- boot/cedit.c | 12 ++-- boot/expo_build.c | 12 ++-- boot/expo_dump.c | 10 ++- boot/scene.c | 64 ++++++++++--------- boot/scene_internal.h | 78 ++++++++++++++++++++--- boot/scene_textedit.c | 65 +++++++++++++++---- boot/scene_textline.c | 105 ++++++++++++++----------------- boot/scene_txtin.c | 70 +++++++++++++++++++++ cmd/Kconfig | 8 +++ common/cli_readline.c | 121 ++++++++++++++++++++++-------------- doc/usage/cmd/cedit.rst | 2 +- include/cli.h | 2 + include/expo.h | 45 ++++++++------ test/boot/bootctl/bootctl.c | 12 ++-- test/boot/cedit.c | 8 +-- test/boot/expo.c | 105 ++++++++++++++++++++----------- test/dm/acpi.c | 13 ++-- 21 files changed, 495 insertions(+), 250 deletions(-) create mode 100644 boot/scene_txtin.c -- 2.43.0 base-commit: 3e4570227c362cc009a7f308c824c50da750bf1c branch: expd
From: Simon Glass <simon.glass@canonical.com> The test modifies ebs_entry and ebs_exit to 123 and 456, then expects the checksum to become invalid. However, the original values come from timer_get_boot_us() which varies each run. If the byte sum of the timer values coincidentally equals the byte sum of 123 + 456, the checksum remains valid and the test fails. Use 0 for the modified values instead, since the test already verifies the original values are non-zero. This guarantees the checksum changes. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- test/dm/acpi.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/test/dm/acpi.c b/test/dm/acpi.c index 1409c333eb1..588a518bc4f 100644 --- a/test/dm/acpi.c +++ b/test/dm/acpi.c @@ -1012,9 +1012,12 @@ static int dm_test_acpi_fpdt(struct unit_test_state *uts) ut_asserteq_ptr(rec, (struct acpi_fpdt_boot *)(fpdt + 1)); ut_asserteq(1234, rec->reset_end); - /* Update a timing field */ - rec->ebs_entry = 123; - rec->ebs_exit = 456; + /* + * Update timing fields - use 0 since we know the original values are + * non-zero + */ + rec->ebs_entry = 0; + rec->ebs_exit = 0; /* Checksum should now be invalid */ ut_assert(table_compute_checksum(fpdt, fpdt->header.length) != 0); @@ -1026,8 +1029,8 @@ static int dm_test_acpi_fpdt(struct unit_test_state *uts) ut_asserteq(0, table_compute_checksum(fpdt, fpdt->header.length)); /* Verify the updated values are still there */ - ut_asserteq(123, rec->ebs_entry); - ut_asserteq(456, rec->ebs_exit); + ut_asserteq(0, rec->ebs_entry); + ut_asserteq(0, rec->ebs_exit); unmap_sysmem(buf); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add a callback function pointer to struct cli_line_state that allows redirection of character output during line editing. This enables expo textlines to direct output to the correct vidconsole context. Add a new Kconfig option CLI_READLINE_CALLBACK which is selected by EXPO When enabled, the callback is checked before outputting characters. When disabled, the compiler optimises away the check. Update all character-output functions in cli_readline.c to use the new cls_putch() helper, which calls the callback if set or falls back to putc() Add a few comments while we are here. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/Kconfig | 1 + cmd/Kconfig | 8 +++++ common/cli_readline.c | 82 +++++++++++++++++++++++++++---------------- include/cli.h | 2 ++ 4 files changed, 63 insertions(+), 30 deletions(-) diff --git a/boot/Kconfig b/boot/Kconfig index cde4472ca57..7ff0dedb748 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -973,6 +973,7 @@ config EXPO bool "Support for expos - groups of scenes displaying a UI" depends on VIDEO default y if BOOTMETH_VBE + select CLI_READLINE_CALLBACK if CMDLINE_EDITING help An expo is a way of presenting and collecting information from the user. It consists of a collection of 'scenes' of which only one is diff --git a/cmd/Kconfig b/cmd/Kconfig index 072ff879cd8..8a873b1d927 100644 --- a/cmd/Kconfig +++ b/cmd/Kconfig @@ -54,6 +54,14 @@ config CMDLINE_EDITING Enable editing and History functions for interactive command line input operations +config CLI_READLINE_CALLBACK + bool "Support a callback for character output" + depends on CMDLINE_EDITING + help + Enable a callback for character output during line editing. This + allows redirection of output to a different destination, such as + a vidconsole. This is used by expo to support textline editing. + config CMDLINE_PS_SUPPORT bool "Enable support for changing the command prompt string at run-time" depends on HUSH_PARSER diff --git a/common/cli_readline.c b/common/cli_readline.c index 244a287b435..81b0688da38 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -71,9 +71,23 @@ static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen) #define DEL7 ((char)127) #define CREAD_HIST_CHAR ('!') -#define getcmd_putch(ch) putc(ch) #define getcmd_getch() getchar() -#define getcmd_cbeep() getcmd_putch('\a') + +/** + * cls_putch() - Output a character, using callback if available + * + * @cls: CLI line state + * @ch: Character to output + */ +static void cls_putch(struct cli_line_state *cls, int ch) +{ + if (CONFIG_IS_ENABLED(CLI_READLINE_CALLBACK) && cls->putch) + cls->putch(cls, ch); + else + putc(ch); +} + +#define getcmd_cbeep(cls) cls_putch(cls, '\a') #ifdef CONFIG_XPL_BUILD #define HIST_MAX 3 @@ -95,12 +109,19 @@ static char *hist_list[HIST_MAX]; #define add_idx_minus_one() ((hist_add_idx == 0) ? hist_max : hist_add_idx-1) -static void getcmd_putchars(int count, int ch) +/** + * cls_putchars() - Output a character multiple times + * + * @cls: CLI line state + * @count: Number of times to output the character + * @ch: Character to output + */ +static void cls_putchars(struct cli_line_state *cls, int count, int ch) { int i; for (i = 0; i < count; i++) - getcmd_putch(ch); + cls_putch(cls, ch); } static int hist_init(void) @@ -206,7 +227,7 @@ void cread_print_hist_list(void) #define BEGINNING_OF_LINE() { \ while (cls->num) { \ - getcmd_putch(CTL_BACKSPACE); \ + cls_putch(cls, CTL_BACKSPACE); \ cls->num--; \ } \ } @@ -215,7 +236,7 @@ void cread_print_hist_list(void) if (cls->num < cls->eol_num) { \ printf("%*s", (int)(cls->eol_num - cls->num), ""); \ do { \ - getcmd_putch(CTL_BACKSPACE); \ + cls_putch(cls, CTL_BACKSPACE); \ } while (--cls->eol_num > cls->num); \ } \ } @@ -228,15 +249,15 @@ void cread_print_hist_list(void) } \ } -static void cread_add_char(char ichar, int insert, uint *num, - uint *eol_num, char *buf, uint len) +static void cread_add_char(struct cli_line_state *cls, char ichar, int insert, + uint *num, uint *eol_num, char *buf, uint len) { uint wlen; /* room ??? */ if (insert || *num == *eol_num) { if (*eol_num > len - 1) { - getcmd_cbeep(); + getcmd_cbeep(cls); return; } (*eol_num)++; @@ -251,7 +272,7 @@ static void cread_add_char(char ichar, int insert, uint *num, putnstr(buf + *num, wlen); (*num)++; while (--wlen) - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); } else { /* echo the character */ wlen = 1; @@ -261,11 +282,12 @@ static void cread_add_char(char ichar, int insert, uint *num, } } -static void cread_add_str(char *str, int strsize, int insert, - uint *num, uint *eol_num, char *buf, uint len) +static void cread_add_str(struct cli_line_state *cls, char *str, int strsize, + int insert, uint *num, uint *eol_num, char *buf, + uint len) { while (strsize--) { - cread_add_char(*str, insert, num, eol_num, buf, len); + cread_add_char(cls, *str, insert, num, eol_num, buf, len); str++; } } @@ -293,13 +315,13 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) return -EINTR; case CTL_CH('f'): if (cls->num < cls->eol_num) { - getcmd_putch(buf[cls->num]); + cls_putch(cls, buf[cls->num]); cls->num++; } break; case CTL_CH('b'): if (cls->num) { - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); cls->num--; } break; @@ -314,9 +336,9 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) putnstr(buf + cls->num, wlen); } - getcmd_putch(' '); + cls_putch(cls, ' '); do { - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); } while (wlen--); cls->eol_num--; } @@ -346,11 +368,11 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) memmove(&buf[base], &buf[cls->num], cls->eol_num - base + 1); cls->num = base; - getcmd_putchars(wlen, CTL_BACKSPACE); + cls_putchars(cls, wlen, CTL_BACKSPACE); puts(buf + base); - getcmd_putchars(wlen, ' '); - getcmd_putchars(wlen + cls->eol_num - cls->num, - CTL_BACKSPACE); + cls_putchars(cls, wlen, ' '); + cls_putchars(cls, wlen + cls->eol_num - cls->num, + CTL_BACKSPACE); } break; case CTL_CH('x'): @@ -367,11 +389,11 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) wlen = cls->eol_num - cls->num; cls->num--; memmove(&buf[cls->num], &buf[cls->num + 1], wlen); - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); putnstr(buf + cls->num, wlen); - getcmd_putch(' '); + cls_putch(cls, ' '); do { - getcmd_putch(CTL_BACKSPACE); + cls_putch(cls, CTL_BACKSPACE); } while (wlen--); cls->eol_num--; } @@ -387,7 +409,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) hline = hist_next(); if (!hline) { - getcmd_cbeep(); + getcmd_cbeep(cls); break; } @@ -411,7 +433,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) /* do not autocomplete when in the middle */ if (cls->num < cls->eol_num) { - getcmd_cbeep(); + getcmd_cbeep(cls); break; } @@ -427,8 +449,8 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) } fallthrough; default: - cread_add_char(ichar, cls->insert, &cls->num, &cls->eol_num, - buf, cls->len); + cread_add_char(cls, ichar, cls->insert, &cls->num, + &cls->eol_num, buf, cls->len); break; } @@ -451,8 +473,8 @@ void cli_cread_init(struct cli_line_state *cls, char *buf, uint buf_size) cls->len = buf_size; if (init_len) - cread_add_str(buf, init_len, 0, &cls->num, &cls->eol_num, buf, - buf_size); + cread_add_str(cls, buf, init_len, 0, &cls->num, &cls->eol_num, + buf, buf_size); } static int cread_line(const char *const prompt, char *buf, unsigned int *len, diff --git a/include/cli.h b/include/cli.h index e183d561369..88f96c03cb3 100644 --- a/include/cli.h +++ b/include/cli.h @@ -36,6 +36,7 @@ struct cli_ch_state { * be set) * @buf: Buffer containing line * @prompt: Prompt for the line + * @putch: Function to call to output a character (NULL to use putc()) */ struct cli_line_state { uint num; @@ -46,6 +47,7 @@ struct cli_line_state { bool cmd_complete; char *buf; const char *prompt; + void (*putch)(struct cli_line_state *cls, int ch); }; /** -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Convert the ERASE_TO_EOL macro to cread_erase_to_eol() function. This reduces code size by 71 bytes since the function is called from three places. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- common/cli_readline.c | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/common/cli_readline.c b/common/cli_readline.c index 81b0688da38..2e41aa5afef 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -232,13 +232,14 @@ void cread_print_hist_list(void) } \ } -#define ERASE_TO_EOL() { \ - if (cls->num < cls->eol_num) { \ - printf("%*s", (int)(cls->eol_num - cls->num), ""); \ - do { \ - cls_putch(cls, CTL_BACKSPACE); \ - } while (--cls->eol_num > cls->num); \ - } \ +static void cread_erase_to_eol(struct cli_line_state *cls) +{ + if (cls->num < cls->eol_num) { + printf("%*s", (int)(cls->eol_num - cls->num), ""); + do { + cls_putch(cls, CTL_BACKSPACE); + } while (--cls->eol_num > cls->num); + } } #define REFRESH_TO_EOL() { \ @@ -344,7 +345,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) } break; case CTL_CH('k'): - ERASE_TO_EOL(); + cread_erase_to_eol(cls); break; case CTL_CH('e'): REFRESH_TO_EOL(); @@ -378,7 +379,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) case CTL_CH('x'): case CTL_CH('u'): BEGINNING_OF_LINE(); - ERASE_TO_EOL(); + cread_erase_to_eol(cls); break; case DEL: case DEL7: @@ -418,7 +419,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) BEGINNING_OF_LINE(); /* erase to end of line */ - ERASE_TO_EOL(); + cread_erase_to_eol(cls); /* copy new line into place and display */ strcpy(buf, hline); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add cls_putnstr() to output a string of specified length using the putch callback. Update all putnstr() calls to use cls_putnstr() so that string output is also redirected when a callback is set. Remove the now-unused putnstr macro. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- common/cli_readline.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/common/cli_readline.c b/common/cli_readline.c index 2e41aa5afef..4eb34d7cf7c 100644 --- a/common/cli_readline.c +++ b/common/cli_readline.c @@ -64,8 +64,6 @@ static char *delete_char (char *buffer, char *p, int *colp, int *np, int plen) * Author: Janghoon Lyu <nandy@mizi.com> */ -#define putnstr(str, n) printf("%.*s", (int)n, str) - #define CTL_BACKSPACE ('\b') #define DEL ((char)255) #define DEL7 ((char)127) @@ -87,6 +85,12 @@ static void cls_putch(struct cli_line_state *cls, int ch) putc(ch); } +static void cls_putnstr(struct cli_line_state *cls, const char *str, size_t n) +{ + while (n-- > 0) + cls_putch(cls, *str++); +} + #define getcmd_cbeep(cls) cls_putch(cls, '\a') #ifdef CONFIG_XPL_BUILD @@ -245,7 +249,7 @@ static void cread_erase_to_eol(struct cli_line_state *cls) #define REFRESH_TO_EOL() { \ if (cls->num < cls->eol_num) { \ uint wlen = cls->eol_num - cls->num; \ - putnstr(buf + cls->num, wlen); \ + cls_putnstr(cls, buf + cls->num, wlen); \ cls->num = cls->eol_num; \ } \ } @@ -270,7 +274,7 @@ static void cread_add_char(struct cli_line_state *cls, char ichar, int insert, memmove(&buf[*num+1], &buf[*num], wlen-1); buf[*num] = ichar; - putnstr(buf + *num, wlen); + cls_putnstr(cls, buf + *num, wlen); (*num)++; while (--wlen) cls_putch(cls, CTL_BACKSPACE); @@ -278,7 +282,7 @@ static void cread_add_char(struct cli_line_state *cls, char ichar, int insert, /* echo the character */ wlen = 1; buf[*num] = ichar; - putnstr(buf + *num, wlen); + cls_putnstr(cls, buf + *num, wlen); (*num)++; } } @@ -334,7 +338,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) if (wlen) { memmove(&buf[cls->num], &buf[cls->num + 1], wlen); - putnstr(buf + cls->num, wlen); + cls_putnstr(cls, buf + cls->num, wlen); } cls_putch(cls, ' '); @@ -370,7 +374,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) cls->eol_num - base + 1); cls->num = base; cls_putchars(cls, wlen, CTL_BACKSPACE); - puts(buf + base); + cls_putnstr(cls, buf + base, cls->eol_num - base); cls_putchars(cls, wlen, ' '); cls_putchars(cls, wlen + cls->eol_num - cls->num, CTL_BACKSPACE); @@ -391,7 +395,7 @@ int cread_line_process_ch(struct cli_line_state *cls, char ichar) cls->num--; memmove(&buf[cls->num], &buf[cls->num + 1], wlen); cls_putch(cls, CTL_BACKSPACE); - putnstr(buf + cls->num, wlen); + cls_putnstr(cls, buf + cls->num, wlen); cls_putch(cls, ' '); do { cls_putch(cls, CTL_BACKSPACE); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add a scene_textline_putch() callback that outputs characters to the vidconsole using vidconsole_put_char(). Set this callback in scene_textline_open() so that CLI line editing output goes to the correct vidconsole rather than the default console. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene_textline.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 20e2d7f33c4..082b39f2497 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -213,6 +213,22 @@ int scene_textline_render_deps(struct scene *scn, return 0; } +/** + * scene_textline_putch() - Output a character to the vidconsole + * + * This is used as the putch callback for CLI line editing, so that characters + * are sent to the correct vidconsole. + * + * @cls: CLI line state + * @ch: Character to output + */ +static void scene_textline_putch(struct cli_line_state *cls, int ch) +{ + struct scene *scn = container_of(cls, struct scene, cls); + + vidconsole_put_char(scn->expo->cons, ch); +} + int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline) { struct udevice *cons = scn->expo->cons; @@ -232,6 +248,7 @@ int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline) vidconsole_entry_start(cons); cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars); scn->cls.insert = true; + scn->cls.putch = scene_textline_putch; ret = vidconsole_entry_save(cons, &scn->entry_save); if (ret) return log_msg_ret("sav", ret); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add a dedicated test for textedit rendering. Move the textedit creation out of create_test_expo() into its own test function, allowing each test to configure the textedit as needed. Update the checksums in expo_render_image() and expo_render_textline() since the textedit is no longer rendered there. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- test/boot/expo.c | 77 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/test/boot/expo.c b/test/boot/expo.c index 03ad3e2167d..62b0b1a7c1b 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -490,7 +490,6 @@ static int create_test_expo(struct unit_test_state *uts, struct expo **expp, struct scene_obj_menu *menu; struct abuf buf, logo_copy; struct scene *scn; - struct abuf orig, *text; struct udevice *dev; struct expo *exp; int id, size; @@ -595,14 +594,6 @@ static int create_test_expo(struct unit_test_state *uts, struct expo **expp, 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"); - /* * Add an extra text object that overlaps with OBJ_TEXT to test reverse * search order. OBJ_TEXT is at (400, 100), so let's add one nearby @@ -732,17 +723,17 @@ static int expo_render_image(struct unit_test_state *uts) /* render it */ expo_set_scene_id(exp, SCENE1); ut_assertok(expo_render(exp)); - ut_asserteq(19065, video_compress_fb(uts, dev, false)); + ut_asserteq(15711, video_compress_fb(uts, dev, false)); ut_asserteq(0, scn->highlight_id); ut_assertok(scene_arrange(scn)); ut_asserteq(0, scn->highlight_id); ut_assertok(expo_render(exp)); - ut_asserteq(20707, video_compress_fb(uts, dev, false)); + ut_asserteq(17342, video_compress_fb(uts, dev, false)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(20707, video_compress_fb(uts, dev, false)); + ut_asserteq(17342, video_compress_fb(uts, dev, false)); scene_set_highlight_id(scn, OBJ_MENU); ut_asserteq(OBJ_MENU, scn->highlight_id); @@ -754,7 +745,7 @@ static int expo_render_image(struct unit_test_state *uts) ut_assert(!(obj->flags & SCENEOF_HIDE)); ut_assertok(expo_render(exp)); - ut_asserteq(20707, video_compress_fb(uts, dev, false)); + ut_asserteq(17342, video_compress_fb(uts, dev, false)); /* move down */ ut_assertok(expo_send_key(exp, BKEY_DOWN)); @@ -767,12 +758,9 @@ 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(19953, video_compress_fb(uts, dev, false)); + ut_asserteq(16637, video_compress_fb(uts, dev, false)); ut_assertok(video_check_copy_fb(uts, dev)); - /* hide the text editor since the following tests 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)); @@ -1430,13 +1418,13 @@ static int expo_render_textline(struct unit_test_state *uts) expo_set_scene_id(exp, SCENE1); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(21007, video_compress_fb(uts, dev, false)); + ut_asserteq(17714, video_compress_fb(uts, dev, false)); /* highlight the textline and re-render */ scene_set_highlight_id(scn, OBJ_TEXTLINE); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(22693, video_compress_fb(uts, dev, false)); + ut_asserteq(19382, video_compress_fb(uts, dev, false)); /* open the textline and re-render */ ut_assertok(scene_set_open(scn, OBJ_TEXTLINE, true)); @@ -1444,13 +1432,13 @@ static int expo_render_textline(struct unit_test_state *uts) ut_assertok(expo_render(exp)); /* the cursor should be at the end */ - ut_asserteq(22695, video_compress_fb(uts, dev, false)); + ut_asserteq(19347, video_compress_fb(uts, dev, false)); /* send a keypress to add a character */ ut_assertok(expo_send_key(exp, 'a')); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(22818, video_compress_fb(uts, dev, false)); + ut_asserteq(19524, video_compress_fb(uts, dev, false)); /* move cursor left 3 times */ ut_assertok(expo_send_key(exp, CTL_CH('b'))); @@ -1461,7 +1449,7 @@ static int expo_render_textline(struct unit_test_state *uts) ut_asserteq_str("sample hopwinda", abuf_data(&tline->buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(22884, video_compress_fb(uts, dev, false)); + ut_asserteq(19552, video_compress_fb(uts, dev, false)); ut_assertok(expo_send_key(exp, CTL_CH('b'))); ut_assertok(expo_send_key(exp, CTL_CH('b'))); @@ -1473,7 +1461,7 @@ static int expo_render_textline(struct unit_test_state *uts) ut_asserteq_str("sample hopwinda", abuf_data(&tline->buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(22915, video_compress_fb(uts, dev, false)); + ut_asserteq(19570, video_compress_fb(uts, dev, false)); /* delete a character at the cursor */ ut_assertok(expo_send_key(exp, CTL_CH('d'))); @@ -1484,7 +1472,7 @@ static int expo_render_textline(struct unit_test_state *uts) ut_asserteq_str("sample hopwnda", abuf_data(&tline->buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(22856, video_compress_fb(uts, dev, false)); + ut_asserteq(19505, video_compress_fb(uts, dev, false)); /* close the textline with Enter (BKEY_SELECT) */ ut_assertok(expo_send_key(exp, BKEY_SELECT)); @@ -1498,7 +1486,7 @@ static int expo_render_textline(struct unit_test_state *uts) ut_asserteq_str("sample hopwnda", abuf_data(&tline->buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(22839, video_compress_fb(uts, dev, false)); + ut_asserteq(19543, video_compress_fb(uts, dev, false)); abuf_uninit(&buf); abuf_uninit(&logo_copy); @@ -1508,3 +1496,42 @@ static int expo_render_textline(struct unit_test_state *uts) return 0; } BOOTSTD_TEST(expo_render_textline, UTF_DM | UTF_SCAN_FDT | UTF_NO_SILENT); + +/* Check rendering a textedit */ +static int expo_render_textedit(struct unit_test_state *uts) +{ + struct scene_obj_txtedit *ted; + struct scene_obj_menu *menu; + struct abuf buf, logo_copy; + struct abuf orig, *text; + struct scene *scn; + struct udevice *dev; + struct expo *exp; + int id; + + ut_assertok(create_test_expo(uts, &exp, &scn, &menu, &buf, &logo_copy)); + dev = exp->display; + + id = scene_texted(scn, "texted", OBJ_TEXTED, STR_TEXTED, &ted); + ut_asserteq(OBJ_TEXTED, id); + ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXTED, 100, 200, 400, 300)); + ut_assertok(scene_txted_set_font(scn, OBJ_TEXTED, + "nimbus_sans_l_regular", 20)); + 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"); + + expo_set_scene_id(exp, SCENE1); + ut_assertok(scene_arrange(scn)); + ut_assertok(expo_render(exp)); + ut_asserteq(19601, video_compress_fb(uts, dev, false)); + + abuf_uninit(&buf); + abuf_uninit(&logo_copy); + + expo_destroy(exp); + + return 0; +} +BOOTSTD_TEST(expo_render_textedit, UTF_DM | UTF_SCAN_FDT | UTF_NO_SILENT); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Update scene_obj_txtedit to follow the same pattern as textline, with separate label_id and edit_id fields pointing to text objects rather than embedding a scene_txt_generic directly. This allows the label and edit text to be rendered as regular scene objects and enables consistent handling between textline and textedit. Changes include: - Remove gen field from scene_obj_txtedit, add label_id and edit_id - Update scene_texted() to not take a str_id parameter - Update scene_txted_set_font() to set font on the edit text object - Add scene_txted_render_deps() for rendering dependencies - Update expo_dump to show label_id and edit_id - Update test to create label and edit text objects separately Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/expo_dump.c | 6 ++---- boot/scene.c | 18 ++++++------------ boot/scene_textedit.c | 9 ++------- include/expo.h | 11 ++++++----- test/boot/expo.c | 26 +++++++++++++++++--------- 5 files changed, 33 insertions(+), 37 deletions(-) diff --git a/boot/expo_dump.c b/boot/expo_dump.c index eb0c7bce6fc..5f9ea22c50a 100644 --- a/boot/expo_dump.c +++ b/boot/expo_dump.c @@ -116,10 +116,8 @@ static void dump_textline(struct dump_ctx *ctx, static void dump_textedit(struct dump_ctx *ctx, struct scene_obj_txtedit *tedit) { - outf(ctx, "Textedit: str_id %x font_name '%s' font_size %x\n", - tedit->gen.str_id, - tedit->gen.font_name ? tedit->gen.font_name : "(default)", - tedit->gen.font_size); + outf(ctx, "Textedit: label_id %x edit_id %x\n", + tedit->label_id, tedit->edit_id); } static void obj_dump_(struct dump_ctx *ctx, struct scene_obj *obj) diff --git a/boot/scene.c b/boot/scene.c index 5c19bff6011..d515754c702 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -468,6 +468,7 @@ int scene_obj_get_hw(struct scene *scn, uint id, int *widthp) case SCENEOBJT_MENU: case SCENEOBJT_TEXTLINE: case SCENEOBJT_BOX: + case SCENEOBJT_TEXTEDIT: break; case SCENEOBJT_IMAGE: { struct scene_obj_img *img = (struct scene_obj_img *)obj; @@ -479,18 +480,14 @@ int scene_obj_get_hw(struct scene *scn, uint id, int *widthp) *widthp = width; return height; } - case SCENEOBJT_TEXT: - case SCENEOBJT_TEXTEDIT: { + case SCENEOBJT_TEXT: { 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; + gen = &((struct scene_obj_txt *)obj)->gen; str = expo_get_str(exp, gen->str_id); if (!str) @@ -753,14 +750,11 @@ static int scene_obj_render(struct scene_obj *obj, bool text_mode) obj->bbox.y1, box->width, vid_priv->colour_fg, box->fill); 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); + case SCENEOBJT_TEXTEDIT: + if (obj->flags & SCENEOF_OPEN) + scene_render_background(obj, true, false); break; } - } return 0; } diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index 8242eb39806..3c1edf38592 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -18,7 +18,7 @@ enum { INITIAL_SIZE = SZ_4K, }; -int scene_texted(struct scene *scn, const char *name, uint id, uint str_id, +int scene_texted(struct scene *scn, const char *name, uint id, struct scene_obj_txtedit **teditp) { struct scene_obj_txtedit *ted; @@ -37,9 +37,6 @@ int scene_texted(struct scene *scn, const char *name, uint id, uint str_id, 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; @@ -54,8 +51,6 @@ int scene_txted_set_font(struct scene *scn, uint id, const char *font_name, 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; + return scene_txt_set_font(scn, ted->edit_id, font_name, font_size); } diff --git a/include/expo.h b/include/expo.h index f9f85b38b9c..9d6300024fc 100644 --- a/include/expo.h +++ b/include/expo.h @@ -539,17 +539,19 @@ struct scene_obj_box { }; /** - * struct scene_obj_txtedit - information about a box in a scene + * struct scene_obj_txtedit - information about a textedit 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 + * @label_id: ID of the label text object (not string ID), or 0 if none + * @edit_id: ID of the editable text object (not string ID) * @buf: Text buffer containing current text */ struct scene_obj_txtedit { struct scene_obj obj; - struct scene_txt_generic gen; + uint label_id; + uint edit_id; struct abuf buf; }; @@ -890,11 +892,10 @@ int scene_box_set_fill(struct scene *scn, uint id, bool fill); * @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, +int scene_texted(struct scene *scn, const char *name, uint id, struct scene_obj_txtedit **teditp); /** diff --git a/test/boot/expo.c b/test/boot/expo.c index 62b0b1a7c1b..7d76431208a 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -1503,7 +1503,6 @@ static int expo_render_textedit(struct unit_test_state *uts) struct scene_obj_txtedit *ted; struct scene_obj_menu *menu; struct abuf buf, logo_copy; - struct abuf orig, *text; struct scene *scn; struct udevice *dev; struct expo *exp; @@ -1512,20 +1511,29 @@ static int expo_render_textedit(struct unit_test_state *uts) ut_assertok(create_test_expo(uts, &exp, &scn, &menu, &buf, &logo_copy)); dev = exp->display; - id = scene_texted(scn, "texted", OBJ_TEXTED, STR_TEXTED, &ted); - ut_asserteq(OBJ_TEXTED, id); + id = scene_texted(scn, "texted", OBJ_TEXTED, &ted); + ut_assert(id > 0); ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXTED, 100, 200, 400, 300)); - ut_assertok(scene_txted_set_font(scn, OBJ_TEXTED, - "nimbus_sans_l_regular", 20)); - 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"); + /* create the label text object */ + id = scene_txt_str(scn, "ted-label", 0, 0, "Editor:", NULL); + ut_assert(id > 0); + ted->label_id = id; + + /* create the edit text object pointing to the textedit buffer */ + abuf_printf(&ted->buf, "This\nis the initial contents of the text " + "editor but it is quite likely that more will be added later"); + id = scene_txt_str(scn, "ted-edit", STR_TEXTED, 0, abuf_data(&ted->buf), + NULL); + ut_assert(id > 0); + ted->edit_id = id; + ut_assertok(scene_txt_set_font(scn, ted->edit_id, + "nimbus_sans_l_regular", 20)); expo_set_scene_id(exp, SCENE1); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(19601, video_compress_fb(uts, dev, false)); + ut_asserteq(19651, video_compress_fb(uts, dev, false)); abuf_uninit(&buf); abuf_uninit(&logo_copy); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Rename the max_chars field to line_chars to better describe its purpose. This field represents the nominal number of characters in a line, which for textline is also a hard limit. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/cedit.c | 4 ++-- boot/expo_build.c | 6 +++--- boot/expo_dump.c | 2 +- boot/scene_textline.c | 16 ++++++++-------- doc/usage/cmd/cedit.rst | 2 +- include/expo.h | 10 +++++----- 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/boot/cedit.c b/boot/cedit.c index d58ae0ba51c..5a334787453 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -538,7 +538,7 @@ static int h_read_settings(struct scene_obj *obj, void *vpriv) tline = (struct scene_obj_textline *)obj; val = ofnode_read_prop(node, obj->name, &len); - if (len >= tline->max_chars) + if (len >= tline->line_chars) return log_msg_ret("str", -ENOSPC); strcpy(abuf_data(&tline->buf), val); break; @@ -708,7 +708,7 @@ static int h_read_settings_env(struct scene_obj *obj, void *vpriv) tline = (struct scene_obj_textline *)obj; value = env_get(var); - if (value && strlen(value) >= tline->max_chars) + if (value && strlen(value) >= tline->line_chars) return log_msg_ret("str", -ENOSPC); if (!value) value = ""; diff --git a/boot/expo_build.c b/boot/expo_build.c index 60a9cd71b7e..76611b4f6d7 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -328,17 +328,17 @@ static int textline_build(struct build_info *info, ofnode node, uint edit_id; const char *name; char buf[80]; - u32 max_chars; + u32 line_chars; int ret; name = ofnode_get_name(node); info->err_prop = "max-chars"; - ret = ofnode_read_u32(node, "max-chars", &max_chars); + ret = ofnode_read_u32(node, "max-chars", &line_chars); if (ret) return log_msg_ret("max", -ENOENT); - ret = scene_textline(scn, name, id, max_chars, &ted); + ret = scene_textline(scn, name, id, line_chars, &ted); if (ret < 0) return log_msg_ret("ted", ret); diff --git a/boot/expo_dump.c b/boot/expo_dump.c index 5f9ea22c50a..2cd74e137d4 100644 --- a/boot/expo_dump.c +++ b/boot/expo_dump.c @@ -109,7 +109,7 @@ static void dump_textline(struct dump_ctx *ctx, outf(ctx, "Textline: label_id %x edit_id %x\n", tline->label_id, tline->edit_id); ctx->indent += 2; - outf(ctx, "max_chars %x pos %x\n", tline->max_chars, tline->pos); + outf(ctx, "line_chars %x pos %x\n", tline->line_chars, tline->pos); ctx->indent -= 2; } diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 082b39f2497..2270e1496e9 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -16,14 +16,14 @@ #include <linux/string.h> #include "scene_internal.h" -int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars, - struct scene_obj_textline **tlinep) +int scene_textline(struct scene *scn, const char *name, uint id, + uint line_chars, struct scene_obj_textline **tlinep) { struct scene_obj_textline *tline; char *buf; int ret; - if (max_chars >= EXPO_MAX_CHARS) + if (line_chars >= EXPO_MAX_CHARS) return log_msg_ret("chr", -E2BIG); ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTLINE, @@ -31,12 +31,12 @@ int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars, (struct scene_obj **)&tline); if (ret < 0) return log_msg_ret("obj", -ENOMEM); - if (!abuf_init_size(&tline->buf, max_chars + 1)) + if (!abuf_init_size(&tline->buf, line_chars + 1)) return log_msg_ret("buf", -ENOMEM); buf = abuf_data(&tline->buf); *buf = '\0'; - tline->pos = max_chars; - tline->max_chars = max_chars; + tline->pos = line_chars; + tline->line_chars = line_chars; if (tlinep) *tlinep = tline; @@ -73,7 +73,7 @@ int scene_textline_calc_dims(struct scene_obj_textline *tline, return log_msg_ret("dim", -ENOENT); ret = vidconsole_nominal(cons, txt->gen.font_name, txt->gen.font_size, - tline->max_chars, &bbox); + tline->line_chars, &bbox); if (ret) return log_msg_ret("nom", ret); @@ -246,7 +246,7 @@ int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline) vidconsole_set_cursor_pos(cons, txt->obj.bbox.x0, txt->obj.bbox.y0); vidconsole_entry_start(cons); - cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars); + cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->line_chars); scn->cls.insert = true; scn->cls.putch = scene_textline_putch; ret = vidconsole_entry_save(cons, &scn->entry_save); diff --git a/doc/usage/cmd/cedit.rst b/doc/usage/cmd/cedit.rst index 0eb8f09dc2c..5d2071bdd1a 100644 --- a/doc/usage/cmd/cedit.rst +++ b/doc/usage/cmd/cedit.rst @@ -362,7 +362,7 @@ This shows dumping the cedit:: bbox: (0,0)-(0,0) dims: 0x0 Textline: label_id 39 edit_id 18 - max_chars 20 pos 20 + line_chars 14 pos 14 Object 39 (title): type text flags bbox: (0,0)-(0,0) diff --git a/include/expo.h b/include/expo.h index 9d6300024fc..39245228574 100644 --- a/include/expo.h +++ b/include/expo.h @@ -510,7 +510,7 @@ struct scene_menitem { * @obj: Basic object information * @label_id: ID of the label text object (not string ID), or 0 if none * @edit_id: ID of the editable text object (not string ID) - * @max_chars: Maximum number of characters allowed + * @line_chars: Nominal number of characters in a line (also a hard limit) * @buf: Text buffer containing current text * @pos: Cursor position */ @@ -518,7 +518,7 @@ struct scene_obj_textline { struct scene_obj obj; uint label_id; uint edit_id; - uint max_chars; + uint line_chars; struct abuf buf; uint pos; }; @@ -855,12 +855,12 @@ int scene_menu(struct scene *scn, const char *name, uint id, * @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 + * @line_chars: Number of characters in a line (also a hard limit) * @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); +int scene_textline(struct scene *scn, const char *name, uint id, + uint line_chars, struct scene_obj_textline **tlinep); /** * scene_box() - create a box -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add a line_chars field to scene_obj_txtedit to specify the nominal number of characters in a line. This is consistent with the line_chars field in scene_obj_textline. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene_textedit.c | 3 ++- include/expo.h | 5 ++++- test/boot/expo.c | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index 3c1edf38592..a55285f00cd 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -19,7 +19,7 @@ enum { }; int scene_texted(struct scene *scn, const char *name, uint id, - struct scene_obj_txtedit **teditp) + uint line_chars, struct scene_obj_txtedit **teditp) { struct scene_obj_txtedit *ted; char *buf; @@ -36,6 +36,7 @@ int scene_texted(struct scene *scn, const char *name, uint id, return log_msg_ret("buf", -ENOMEM); buf = abuf_data(&ted->buf); *buf = '\0'; + ted->line_chars = line_chars; if (teditp) *teditp = ted; diff --git a/include/expo.h b/include/expo.h index 39245228574..2d57e67d51c 100644 --- a/include/expo.h +++ b/include/expo.h @@ -546,12 +546,14 @@ struct scene_obj_box { * @obj: Basic object information * @label_id: ID of the label text object (not string ID), or 0 if none * @edit_id: ID of the editable text object (not string ID) + * @line_chars: Nominal number of characters in a line * @buf: Text buffer containing current text */ struct scene_obj_txtedit { struct scene_obj obj; uint label_id; uint edit_id; + uint line_chars; struct abuf buf; }; @@ -892,11 +894,12 @@ int scene_box_set_fill(struct scene *scn, uint id, bool fill); * @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) + * @line_chars: Nominal number of characters in a line * @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, - struct scene_obj_txtedit **teditp); + uint line_chars, struct scene_obj_txtedit **teditp); /** * scene_txt_set_font() - Set the font for an object diff --git a/test/boot/expo.c b/test/boot/expo.c index 7d76431208a..dc9ebe702b8 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -1511,7 +1511,7 @@ static int expo_render_textedit(struct unit_test_state *uts) ut_assertok(create_test_expo(uts, &exp, &scn, &menu, &buf, &logo_copy)); dev = exp->display; - id = scene_texted(scn, "texted", OBJ_TEXTED, &ted); + id = scene_texted(scn, "texted", OBJ_TEXTED, 40, &ted); ut_assert(id > 0); ut_assertok(scene_obj_set_bbox(scn, OBJ_TEXTED, 100, 200, 400, 300)); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add scene_txted_arrange() to position the label and edit text objects within a textedit, following the same pattern as textline: - Position the label at the textedit's position - Position edit text after the label (with margin) - Set the SCENEOF_POINT flag when highlighted but not open - Calculate the overall dimensions of the textedit Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene.c | 10 +++++++++- boot/scene_internal.h | 14 ++++++++++++++ boot/scene_textedit.c | 37 +++++++++++++++++++++++++++++++++++++ test/boot/expo.c | 2 +- 4 files changed, 61 insertions(+), 2 deletions(-) diff --git a/boot/scene.c b/boot/scene.c index d515754c702..882a250e17d 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -868,7 +868,6 @@ 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; @@ -888,6 +887,15 @@ int scene_arrange(struct scene *scn) return log_msg_ret("arr", ret); break; } + case SCENEOBJT_TEXTEDIT: { + struct scene_obj_txtedit *ted; + + ted = (struct scene_obj_txtedit *)obj, + ret = scene_txted_arrange(scn, &arr, ted); + if (ret) + return log_msg_ret("arr", ret); + break; + } } } ret = scene_sync_bbox(scn); diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 5cc81f031a0..1e5bd3d2a28 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -162,6 +162,20 @@ int scene_menu_arrange(struct scene *scn, struct expo_arrange_info *arr, int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr, struct scene_obj_textline *tline); +/** + * scene_txted_arrange() - Set the position of things in a textedit + * + * This updates any items associated with a textedit to make sure they are + * positioned correctly relative to the textedit. + * + * @scn: Scene to update + * @arr: Arrangement information + * @ted: textedit to process + * Returns: 0 if OK, -ve on error + */ +int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj_txtedit *ted); + /** * scene_apply_theme() - Apply a theme to a scene * diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index a55285f00cd..8714a4b5705 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -55,3 +55,40 @@ int scene_txted_set_font(struct scene *scn, uint id, const char *font_name, return scene_txt_set_font(scn, ted->edit_id, font_name, font_size); } + +int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj_txtedit *ted) +{ + const bool open = ted->obj.flags & SCENEOF_OPEN; + const struct expo_theme *theme = &scn->expo->theme; + bool point; + int x, y; + int ret; + + x = ted->obj.req_bbox.x0; + y = ted->obj.req_bbox.y0; + if (ted->label_id) { + ret = scene_obj_set_pos(scn, ted->label_id, x, y); + if (ret < 0) + return log_msg_ret("tit", ret); + + x += arr->label_width + theme->textline_label_margin_x; + } + + /* constrain the edit text to fit within the textedit bbox */ + ret = scene_obj_set_bbox(scn, ted->edit_id, x, y, + ted->obj.req_bbox.x1, ted->obj.req_bbox.y1); + if (ret < 0) + return log_msg_ret("edi", ret); + + point = scn->highlight_id == ted->obj.id; + point &= !open; + scene_obj_flag_clrset(scn, ted->edit_id, SCENEOF_POINT, + point ? SCENEOF_POINT : 0); + + ted->obj.dims.x = x - ted->obj.req_bbox.x0; + ted->obj.dims.y = y - ted->obj.req_bbox.y0; + scene_obj_set_size(scn, ted->obj.id, ted->obj.dims.x, ted->obj.dims.y); + + return 0; +} diff --git a/test/boot/expo.c b/test/boot/expo.c index dc9ebe702b8..b6ee4892d7a 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -1533,7 +1533,7 @@ static int expo_render_textedit(struct unit_test_state *uts) expo_set_scene_id(exp, SCENE1); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(19651, video_compress_fb(uts, dev, false)); + ut_asserteq(19493, video_compress_fb(uts, dev, false)); abuf_uninit(&buf); abuf_uninit(&logo_copy); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Create a new struct scene_txtin to hold the common fields shared by textline and textedit objects: label_id, edit_id, line_chars, and buf Both scene_obj_textline and scene_obj_txtedit now contain a 'tin' member of this type, reducing code duplication and making the common interface clearer. Update all references throughout the codebase to use the tin. prefix when accessing these fields. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/bootctl/multi_ui.c | 4 ++-- boot/bootflow_menu.c | 6 +++--- boot/cedit.c | 12 ++++++------ boot/expo_build.c | 6 +++--- boot/expo_dump.c | 6 +++--- boot/scene.c | 2 +- boot/scene_textedit.c | 18 +++++++++--------- boot/scene_textline.c | 38 ++++++++++++++++++------------------- include/expo.h | 35 ++++++++++++++++++---------------- test/boot/bootctl/bootctl.c | 12 ++++++------ test/boot/cedit.c | 8 ++++---- test/boot/expo.c | 32 +++++++++++++++---------------- 12 files changed, 91 insertions(+), 88 deletions(-) diff --git a/boot/bootctl/multi_ui.c b/boot/bootctl/multi_ui.c index 5145e4357cb..c5b50b515d0 100644 --- a/boot/bootctl/multi_ui.c +++ b/boot/bootctl/multi_ui.c @@ -596,7 +596,7 @@ static int multiboot_ui_show_pass(struct udevice *dev, int seq, bool show) SCENEOBJT_TEXTLINE); if (!tline) return log_msg_ret("tln", -ENOENT); - buf = abuf_data(&tline->buf); + buf = abuf_data(&tline->tin.buf); *buf = '\0'; /* Set highlight and open the textline for editing */ @@ -625,7 +625,7 @@ static int multiboot_ui_get_pass(struct udevice *dev, int seq, if (!tline) return log_msg_ret("tln", -ENOENT); - *passp = abuf_data(&tline->buf); + *passp = abuf_data(&tline->tin.buf); return 0; } diff --git a/boot/bootflow_menu.c b/boot/bootflow_menu.c index 909694f6e7b..fdc36348859 100644 --- a/boot/bootflow_menu.c +++ b/boot/bootflow_menu.c @@ -315,14 +315,14 @@ int bootflow_menu_add(struct expo *exp, struct bootflow *bflow, int seq, "Passphrase:", NULL); if (ret < 0) return log_msg_ret("itl", -EINVAL); - tline->label_id = ret; + tline->tin.label_id = ret; snprintf(name, sizeof(name), "item%d.pass.edit", seq); ret = scene_txt_str(scn, name, ITEM_PASS_EDIT + seq, 0, - abuf_data(&tline->buf), &txt); + abuf_data(&tline->tin.buf), &txt); if (ret < 0) return log_msg_ret("ite", -EINVAL); - tline->edit_id = ret; + tline->tin.edit_id = ret; txt->obj.flags |= SCENEOF_PASSWORD; /* Create message text (hidden by default) for success/error feedback */ diff --git a/boot/cedit.c b/boot/cedit.c index 5a334787453..f047849e19d 100644 --- a/boot/cedit.c +++ b/boot/cedit.c @@ -433,7 +433,7 @@ static int h_write_settings(struct scene_obj *obj, void *vpriv) const struct scene_obj_textline *tline; tline = (struct scene_obj_textline *)obj; - ret = write_dt_string(buf, obj->name, abuf_data(&tline->buf)); + ret = write_dt_string(buf, obj->name, abuf_data(&tline->tin.buf)); if (ret) return log_msg_ret("wr2", ret); break; @@ -538,9 +538,9 @@ static int h_read_settings(struct scene_obj *obj, void *vpriv) tline = (struct scene_obj_textline *)obj; val = ofnode_read_prop(node, obj->name, &len); - if (len >= tline->line_chars) + if (len >= tline->tin.line_chars) return log_msg_ret("str", -ENOSPC); - strcpy(abuf_data(&tline->buf), val); + strcpy(abuf_data(&tline->tin.buf), val); break; } case SCENEOBJT_MENU: { @@ -638,7 +638,7 @@ static int h_write_settings_env(struct scene_obj *obj, void *vpriv) const struct scene_obj_textline *tline; tline = (struct scene_obj_textline *)obj; - str = abuf_data(&tline->buf); + str = abuf_data(&tline->tin.buf); ret = env_set(var, str); if (ret) return log_msg_ret("set", ret); @@ -708,13 +708,13 @@ static int h_read_settings_env(struct scene_obj *obj, void *vpriv) tline = (struct scene_obj_textline *)obj; value = env_get(var); - if (value && strlen(value) >= tline->line_chars) + if (value && strlen(value) >= tline->tin.line_chars) return log_msg_ret("str", -ENOSPC); if (!value) value = ""; if (priv->verbose) printf("%s=%s\n", var, value); - strcpy(abuf_data(&tline->buf), value); + strcpy(abuf_data(&tline->tin.buf), value); break; } } diff --git a/boot/expo_build.c b/boot/expo_build.c index 76611b4f6d7..0da3ceceb5d 100644 --- a/boot/expo_build.c +++ b/boot/expo_build.c @@ -347,7 +347,7 @@ static int textline_build(struct build_info *info, ofnode node, ret = add_txt_str(info, node, scn, "title", buf, 0); if (ret < 0) return log_msg_ret("tit", ret); - ted->label_id = ret; + ted->tin.label_id = ret; /* Setup the editor */ info->err_prop = "edit-id"; @@ -356,11 +356,11 @@ static int textline_build(struct build_info *info, ofnode node, return log_msg_ret("id", -ENOENT); snprintf(buf, sizeof(buf), "%s.edit", name); - ret = scene_txt_str(scn, buf, edit_id, 0, abuf_data(&ted->buf), + ret = scene_txt_str(scn, buf, edit_id, 0, abuf_data(&ted->tin.buf), NULL); if (ret < 0) return log_msg_ret("add", ret); - ted->edit_id = ret; + ted->tin.edit_id = ret; return 0; } diff --git a/boot/expo_dump.c b/boot/expo_dump.c index 2cd74e137d4..b2ea60db50c 100644 --- a/boot/expo_dump.c +++ b/boot/expo_dump.c @@ -107,9 +107,9 @@ static void dump_textline(struct dump_ctx *ctx, struct scene_obj_textline *tline) { outf(ctx, "Textline: label_id %x edit_id %x\n", - tline->label_id, tline->edit_id); + tline->tin.label_id, tline->tin.edit_id); ctx->indent += 2; - outf(ctx, "line_chars %x pos %x\n", tline->line_chars, tline->pos); + outf(ctx, "line_chars %x pos %x\n", tline->tin.line_chars, tline->pos); ctx->indent -= 2; } @@ -117,7 +117,7 @@ static void dump_textedit(struct dump_ctx *ctx, struct scene_obj_txtedit *tedit) { outf(ctx, "Textedit: label_id %x edit_id %x\n", - tedit->label_id, tedit->edit_id); + tedit->tin.label_id, tedit->tin.edit_id); } static void obj_dump_(struct dump_ctx *ctx, struct scene_obj *obj) diff --git a/boot/scene.c b/boot/scene.c index 882a250e17d..9c02c9b36be 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -786,7 +786,7 @@ int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr) struct scene_obj_textline *tline; tline = (struct scene_obj_textline *)obj, - label_id = tline->label_id; + label_id = tline->tin.label_id; break; } } diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index 8714a4b5705..de985c6f6e1 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -31,12 +31,12 @@ int scene_texted(struct scene *scn, const char *name, uint id, if (ret < 0) return log_msg_ret("obj", ret); - abuf_init(&ted->buf); - if (!abuf_realloc(&ted->buf, INITIAL_SIZE)) + abuf_init(&ted->tin.buf); + if (!abuf_realloc(&ted->tin.buf, INITIAL_SIZE)) return log_msg_ret("buf", -ENOMEM); - buf = abuf_data(&ted->buf); + buf = abuf_data(&ted->tin.buf); *buf = '\0'; - ted->line_chars = line_chars; + ted->tin.line_chars = line_chars; if (teditp) *teditp = ted; @@ -53,7 +53,7 @@ int scene_txted_set_font(struct scene *scn, uint id, const char *font_name, if (!ted) return log_msg_ret("find", -ENOENT); - return scene_txt_set_font(scn, ted->edit_id, font_name, font_size); + return scene_txt_set_font(scn, ted->tin.edit_id, font_name, font_size); } int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, @@ -67,8 +67,8 @@ int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, x = ted->obj.req_bbox.x0; y = ted->obj.req_bbox.y0; - if (ted->label_id) { - ret = scene_obj_set_pos(scn, ted->label_id, x, y); + if (ted->tin.label_id) { + ret = scene_obj_set_pos(scn, ted->tin.label_id, x, y); if (ret < 0) return log_msg_ret("tit", ret); @@ -76,14 +76,14 @@ int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, } /* constrain the edit text to fit within the textedit bbox */ - ret = scene_obj_set_bbox(scn, ted->edit_id, x, y, + ret = scene_obj_set_bbox(scn, ted->tin.edit_id, x, y, ted->obj.req_bbox.x1, ted->obj.req_bbox.y1); if (ret < 0) return log_msg_ret("edi", ret); point = scn->highlight_id == ted->obj.id; point &= !open; - scene_obj_flag_clrset(scn, ted->edit_id, SCENEOF_POINT, + scene_obj_flag_clrset(scn, ted->tin.edit_id, SCENEOF_POINT, point ? SCENEOF_POINT : 0); ted->obj.dims.x = x - ted->obj.req_bbox.x0; diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 2270e1496e9..c0492896888 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -31,12 +31,12 @@ int scene_textline(struct scene *scn, const char *name, uint id, (struct scene_obj **)&tline); if (ret < 0) return log_msg_ret("obj", -ENOMEM); - if (!abuf_init_size(&tline->buf, line_chars + 1)) + if (!abuf_init_size(&tline->tin.buf, line_chars + 1)) return log_msg_ret("buf", -ENOMEM); - buf = abuf_data(&tline->buf); + buf = abuf_data(&tline->tin.buf); *buf = '\0'; tline->pos = line_chars; - tline->line_chars = line_chars; + tline->tin.line_chars = line_chars; if (tlinep) *tlinep = tline; @@ -52,11 +52,11 @@ void scene_textline_calc_bbox(struct scene_obj_textline *tline, int inset = theme->menu_inset; bbox->valid = false; - scene_bbox_union(tline->obj.scene, tline->label_id, inset, bbox); - scene_bbox_union(tline->obj.scene, tline->edit_id, inset, bbox); + scene_bbox_union(tline->obj.scene, tline->tin.label_id, inset, bbox); + scene_bbox_union(tline->obj.scene, tline->tin.edit_id, inset, bbox); edit_bbox->valid = false; - scene_bbox_union(tline->obj.scene, tline->edit_id, inset, + scene_bbox_union(tline->obj.scene, tline->tin.edit_id, inset, edit_bbox); } @@ -68,12 +68,12 @@ int scene_textline_calc_dims(struct scene_obj_textline *tline, struct scene_obj_txt *txt; int ret; - txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); + txt = scene_obj_find(scn, tline->tin.edit_id, SCENEOBJT_NONE); if (!txt) return log_msg_ret("dim", -ENOENT); ret = vidconsole_nominal(cons, txt->gen.font_name, txt->gen.font_size, - tline->line_chars, &bbox); + tline->tin.line_chars, &bbox); if (ret) return log_msg_ret("nom", ret); @@ -98,19 +98,19 @@ int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr, x = tline->obj.req_bbox.x0; y = tline->obj.req_bbox.y0; - if (tline->label_id) { + if (tline->tin.label_id) { struct scene_obj *edit; - ret = scene_obj_set_pos(scn, tline->label_id, x, y); + ret = scene_obj_set_pos(scn, tline->tin.label_id, x, y); if (ret < 0) return log_msg_ret("tit", ret); x += arr->label_width + theme->textline_label_margin_x; - ret = scene_obj_set_pos(scn, tline->edit_id, x, y); + ret = scene_obj_set_pos(scn, tline->tin.edit_id, x, y); if (ret < 0) return log_msg_ret("til", ret); - edit = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); + edit = scene_obj_find(scn, tline->tin.edit_id, SCENEOBJT_NONE); if (!edit) return log_msg_ret("tie", -ENOENT); x += edit->dims.x; @@ -119,7 +119,7 @@ int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr, point = scn->highlight_id == tline->obj.id; point &= !open; - scene_obj_flag_clrset(scn, tline->edit_id, SCENEOF_POINT, + scene_obj_flag_clrset(scn, tline->tin.edit_id, SCENEOF_POINT, point ? SCENEOF_POINT : 0); tline->obj.dims.x = x - tline->obj.req_bbox.x0; @@ -143,7 +143,7 @@ int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline, event->select.id = tline->obj.id; /* Copy the backup text from the scene buffer */ - memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf), + memcpy(abuf_data(&tline->tin.buf), abuf_data(&scn->buf), abuf_size(&scn->buf)); /* cursor is not needed now */ @@ -181,7 +181,7 @@ int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline, bool scene_textline_within(const struct scene *scn, struct scene_obj_textline *tline, int x, int y) { - return scene_within(scn, tline->edit_id, x, y); + return scene_within(scn, tline->tin.edit_id, x, y); } int scene_textline_render_deps(struct scene *scn, @@ -198,7 +198,7 @@ int scene_textline_render_deps(struct scene *scn, ret = vidconsole_entry_restore(cons, &scn->entry_save); if (ret) return log_msg_ret("sav", ret); - scene_render_obj(scn, tline->edit_id); + scene_render_obj(scn, tline->tin.edit_id); /* move cursor back to the correct position */ for (i = scn->cls.num; i < scn->cls.eol_num; i++) @@ -236,17 +236,17 @@ int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline) int ret; /* Copy the text into the scene buffer in case the edit is cancelled */ - memcpy(abuf_data(&scn->buf), abuf_data(&tline->buf), + memcpy(abuf_data(&scn->buf), abuf_data(&tline->tin.buf), abuf_size(&scn->buf)); /* get the position of the editable */ - txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); + txt = scene_obj_find(scn, tline->tin.edit_id, SCENEOBJT_NONE); if (!txt) return log_msg_ret("cur", -ENOENT); vidconsole_set_cursor_pos(cons, txt->obj.bbox.x0, txt->obj.bbox.y0); vidconsole_entry_start(cons); - cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->line_chars); + cli_cread_init(&scn->cls, abuf_data(&tline->tin.buf), tline->tin.line_chars); scn->cls.insert = true; scn->cls.putch = scene_textline_putch; ret = vidconsole_entry_save(cons, &scn->entry_save); diff --git a/include/expo.h b/include/expo.h index 2d57e67d51c..e3451d8dd23 100644 --- a/include/expo.h +++ b/include/expo.h @@ -503,23 +503,32 @@ struct scene_menitem { }; /** - * struct scene_obj_textline - information about a textline in a scene - * - * A textline has a prompt and a line of editable text + * struct scene_txtin - generic info for text-input objects * - * @obj: Basic object information * @label_id: ID of the label text object (not string ID), or 0 if none * @edit_id: ID of the editable text object (not string ID) - * @line_chars: Nominal number of characters in a line (also a hard limit) + * @line_chars: Nominal number of characters in a line * @buf: Text buffer containing current text - * @pos: Cursor position */ -struct scene_obj_textline { - struct scene_obj obj; +struct scene_txtin { uint label_id; uint edit_id; uint line_chars; struct abuf buf; +}; + +/** + * 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 + * @tin: Text-input info + * @pos: Cursor position + */ +struct scene_obj_textline { + struct scene_obj obj; + struct scene_txtin tin; uint pos; }; @@ -544,17 +553,11 @@ struct scene_obj_box { * A text editor which allows users to edit a small text file * * @obj: Basic object information - * @label_id: ID of the label text object (not string ID), or 0 if none - * @edit_id: ID of the editable text object (not string ID) - * @line_chars: Nominal number of characters in a line - * @buf: Text buffer containing current text + * @tin: Text-input info */ struct scene_obj_txtedit { struct scene_obj obj; - uint label_id; - uint edit_id; - uint line_chars; - struct abuf buf; + struct scene_txtin tin; }; /** diff --git a/test/boot/bootctl/bootctl.c b/test/boot/bootctl/bootctl.c index f251cd18507..ababe6f7b21 100644 --- a/test/boot/bootctl/bootctl.c +++ b/test/boot/bootctl/bootctl.c @@ -384,23 +384,23 @@ static int check_passphrase(struct unit_test_state *uts, /* Type 't', 'e', 's', 't' - each poll processes one character */ ut_asserteq(4, console_in_puts("test")); ut_assertok(bc_ui_poll(ui_dev, &seq_out, &selected)); - ut_asserteq_str("t", abuf_data(&tline->buf)); + ut_asserteq_str("t", abuf_data(&tline->tin.buf)); ut_assertok(bc_ui_poll(ui_dev, &seq_out, &selected)); - ut_asserteq_str("te", abuf_data(&tline->buf)); + ut_asserteq_str("te", abuf_data(&tline->tin.buf)); ut_assertok(bc_ui_poll(ui_dev, &seq_out, &selected)); - ut_asserteq_str("tes", abuf_data(&tline->buf)); + ut_asserteq_str("tes", abuf_data(&tline->tin.buf)); ut_assertok(bc_ui_poll(ui_dev, &seq_out, &selected)); - ut_asserteq_str("test", abuf_data(&tline->buf)); + ut_asserteq_str("test", abuf_data(&tline->tin.buf)); /* Send backspace to remove one character */ ut_asserteq(1, console_in_puts("\b")); ut_assertok(bc_ui_poll(ui_dev, &seq_out, &selected)); - ut_asserteq_str("tes", abuf_data(&tline->buf)); + ut_asserteq_str("tes", abuf_data(&tline->tin.buf)); /* Re-add the 't' and verify */ ut_asserteq(1, console_in_puts("t")); ut_assertok(bc_ui_poll(ui_dev, &seq_out, &selected)); - ut_asserteq_str("test", abuf_data(&tline->buf)); + ut_asserteq_str("test", abuf_data(&tline->tin.buf)); /* Send return key to submit - should close textline and select */ ut_asserteq(1, console_in_puts("\n")); diff --git a/test/boot/cedit.c b/test/boot/cedit.c index b8c46f2d50c..b8574c65e64 100644 --- a/test/boot/cedit.c +++ b/test/boot/cedit.c @@ -89,7 +89,7 @@ static int cedit_fdt(struct unit_test_state *uts) /* get a textline to fiddle with too */ tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_TEXTLINE); ut_assertnonnull(tline); - str = abuf_data(&tline->buf); + str = abuf_data(&tline->tin.buf); strcpy(str, "my-machine"); ut_assertok(run_command("cedit write_fdt hostfs - settings.dtb", 0)); @@ -158,7 +158,7 @@ static int cedit_env(struct unit_test_state *uts) /* get a textline to fiddle with too */ tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_TEXTLINE); ut_assertnonnull(tline); - str = abuf_data(&tline->buf); + str = abuf_data(&tline->tin.buf); strcpy(str, "my-machine"); ut_assertok(run_command("cedit write_env -v", 0)); @@ -398,7 +398,7 @@ static int cedit_render_textline(struct unit_test_state *uts) /* set up an initial value for the textline */ tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_TEXTLINE); ut_assertnonnull(tline); - str = abuf_data(&tline->buf); + str = abuf_data(&tline->tin.buf); strcpy(str, "my-machine"); ut_asserteq(20, tline->pos); @@ -655,7 +655,7 @@ static int cedit_mouse(struct unit_test_state *uts) speed->obj.flags); /* click on the textline */ - ut_assertok(click_check(uts, scn, mach->edit_id, + ut_assertok(click_check(uts, scn, mach->tin.edit_id, EXPOACT_REPOINT_OPEN, &act)); ut_asserteq(ID_MACHINE_NAME, act.select.id); ut_asserteq(ID_CPU_SPEED, act.select.prev_id); diff --git a/test/boot/expo.c b/test/boot/expo.c index b6ee4892d7a..95b029568d0 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -1013,7 +1013,7 @@ static int expo_within_funcs(struct unit_test_state *uts) /* test scene_textline_within() */ tline = scene_obj_find(scn, ID_MACHINE_NAME, SCENEOBJT_NONE); ut_assertnonnull(tline); - obj = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); + obj = scene_obj_find(scn, tline->tin.edit_id, SCENEOBJT_NONE); ut_assertnonnull(obj); /* positive test: point within textline bounds */ @@ -1400,19 +1400,19 @@ static int expo_render_textline(struct unit_test_state *uts) id = scene_textline(scn, "textline", OBJ_TEXTLINE, 20, &tline); ut_assert(id > 0); ut_assertok(scene_obj_set_pos(scn, OBJ_TEXTLINE, 500, 500)); - strcpy(abuf_data(&tline->buf), "sample hopwind"); + strcpy(abuf_data(&tline->tin.buf), "sample hopwind"); /* create the label text object */ id = scene_txt_str(scn, "tline-label", 0, 0, "Label:", NULL); ut_assert(id > 0); - tline->label_id = id; + tline->tin.label_id = id; /* create the edit text object pointing to the textline buffer */ - id = scene_txt_str(scn, "tline-edit", 0, 0, abuf_data(&tline->buf), + id = scene_txt_str(scn, "tline-edit", 0, 0, abuf_data(&tline->tin.buf), NULL); ut_assert(id > 0); - tline->edit_id = id; - ut_assertok(scene_txt_set_font(scn, tline->edit_id, + tline->tin.edit_id = id; + ut_assertok(scene_txt_set_font(scn, tline->tin.edit_id, "nimbus_sans_l_regular", 40)); expo_set_scene_id(exp, SCENE1); @@ -1446,7 +1446,7 @@ static int expo_render_textline(struct unit_test_state *uts) /* check cursor moved back one position, before 'a' */ ut_asserteq(14, scn->cls.num); ut_asserteq(15, scn->cls.eol_num); - ut_asserteq_str("sample hopwinda", abuf_data(&tline->buf)); + ut_asserteq_str("sample hopwinda", abuf_data(&tline->tin.buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); ut_asserteq(19552, video_compress_fb(uts, dev, false)); @@ -1458,7 +1458,7 @@ static int expo_render_textline(struct unit_test_state *uts) /* check cursor moved back three more positions, before 'i' */ ut_asserteq(11, scn->cls.num); ut_asserteq(15, scn->cls.eol_num); - ut_asserteq_str("sample hopwinda", abuf_data(&tline->buf)); + ut_asserteq_str("sample hopwinda", abuf_data(&tline->tin.buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); ut_asserteq(19570, video_compress_fb(uts, dev, false)); @@ -1469,7 +1469,7 @@ static int expo_render_textline(struct unit_test_state *uts) /* check character deleted at cursor position */ ut_asserteq(11, scn->cls.num); ut_asserteq(14, scn->cls.eol_num); - ut_asserteq_str("sample hopwnda", abuf_data(&tline->buf)); + ut_asserteq_str("sample hopwnda", abuf_data(&tline->tin.buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); ut_asserteq(19505, video_compress_fb(uts, dev, false)); @@ -1483,7 +1483,7 @@ static int expo_render_textline(struct unit_test_state *uts) /* check the textline is closed and text was saved */ ut_asserteq(0, tline->obj.flags & SCENEOF_OPEN); - ut_asserteq_str("sample hopwnda", abuf_data(&tline->buf)); + ut_asserteq_str("sample hopwnda", abuf_data(&tline->tin.buf)); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); ut_asserteq(19543, video_compress_fb(uts, dev, false)); @@ -1518,16 +1518,16 @@ static int expo_render_textedit(struct unit_test_state *uts) /* create the label text object */ id = scene_txt_str(scn, "ted-label", 0, 0, "Editor:", NULL); ut_assert(id > 0); - ted->label_id = id; + ted->tin.label_id = id; /* create the edit text object pointing to the textedit buffer */ - abuf_printf(&ted->buf, "This\nis the initial contents of the text " + abuf_printf(&ted->tin.buf, "This\nis the initial contents of the text " "editor but it is quite likely that more will be added later"); - id = scene_txt_str(scn, "ted-edit", STR_TEXTED, 0, abuf_data(&ted->buf), - NULL); + id = scene_txt_str(scn, "ted-edit", STR_TEXTED, 0, + abuf_data(&ted->tin.buf), NULL); ut_assert(id > 0); - ted->edit_id = id; - ut_assertok(scene_txt_set_font(scn, ted->edit_id, + ted->tin.edit_id = id; + ut_assertok(scene_txt_set_font(scn, ted->tin.edit_id, "nimbus_sans_l_regular", 20)); expo_set_scene_id(exp, SCENE1); -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Create a new file scene_txtin.c containing common code for text-input scene objects (textline, textedit). Move the calc_bbox logic into scene_txtin_calc_bbox() which is called directly from scene_obj_calc_bbox() Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/Makefile | 2 +- boot/scene.c | 13 ++++++++++--- boot/scene_internal.h | 15 ++++++++------- boot/scene_textedit.c | 24 ++++++++++++++++++++++++ boot/scene_textline.c | 16 ---------------- boot/scene_txtin.c | 30 ++++++++++++++++++++++++++++++ 6 files changed, 73 insertions(+), 27 deletions(-) create mode 100644 boot/scene_txtin.c diff --git a/boot/Makefile b/boot/Makefile index 39069014310..b9129a174c7 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -61,7 +61,7 @@ obj-$(CONFIG_$(PHASE_)LOAD_FIT) += common_fit.o obj-$(CONFIG_$(PHASE_)EXPO) += expo.o scene.o expo_build.o obj-$(CONFIG_$(PHASE_)EXPO_DUMP) += expo_dump.o -obj-$(CONFIG_$(PHASE_)EXPO) += scene_menu.o scene_textline.o scene_textedit.o +obj-$(CONFIG_$(PHASE_)EXPO) += scene_menu.o scene_textline.o scene_textedit.o scene_txtin.o obj-$(CONFIG_$(PHASE_)EXPO_TEST) += expo_test.o ifdef CONFIG_COREBOOT_SYSINFO obj-$(CONFIG_$(PHASE_)EXPO) += expo_build_cb.o diff --git a/boot/scene.c b/boot/scene.c index 9c02c9b36be..220fbf26b44 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -1440,7 +1440,6 @@ 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; @@ -1452,8 +1451,16 @@ int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox bbox[]) struct scene_obj_textline *tline; tline = (struct scene_obj_textline *)obj; - scene_textline_calc_bbox(tline, &bbox[SCENEBB_all], - &bbox[SCENEBB_label]); + scene_txtin_calc_bbox(obj, &tline->tin, &bbox[SCENEBB_all], + &bbox[SCENEBB_label]); + break; + } + case SCENEOBJT_TEXTEDIT: { + struct scene_obj_txtedit *ted; + + ted = (struct scene_obj_txtedit *)obj; + scene_txtin_calc_bbox(obj, &ted->tin, &bbox[SCENEBB_all], + &bbox[SCENEBB_label]); break; } } diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 1e5bd3d2a28..a3eb720c385 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -20,6 +20,7 @@ struct scene_obj_dims; struct scene_obj_menu; struct scene_obj_textline; struct scene_obj_txtedit; +struct scene_txtin; struct scene_txt_generic; struct udevice; struct vidconsole_bbox; @@ -497,16 +498,16 @@ void scene_menu_calc_bbox(struct scene_obj_menu *menu, struct vidconsole_bbox *bbox); /** - * scene_textline_calc_bbox() - Calculate bounding box for the textline + * scene_txtin_calc_bbox() - Calculate bounding box for a text-input object * - * @textline: Menu to process - * @bbox: Returns bounding box of textline including prompt + * @obj: Object to process + * @tin: Text-input object info + * @bbox: Returns bounding box of object including label * @edit_bbox: Returns bounding box of editable part - * Return: 0 if OK, -ve on error */ -void scene_textline_calc_bbox(struct scene_obj_textline *menu, - struct vidconsole_bbox *bbox, - struct vidconsole_bbox *label_bbox); +void scene_txtin_calc_bbox(struct scene_obj *obj, struct scene_txtin *tin, + struct vidconsole_bbox *bbox, + struct vidconsole_bbox *edit_bbox); /** * scene_obj_calc_bbox() - Calculate bounding boxes for an object diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index de985c6f6e1..37138fc7542 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -56,6 +56,30 @@ int scene_txted_set_font(struct scene *scn, uint id, const char *font_name, return scene_txt_set_font(scn, ted->tin.edit_id, font_name, font_size); } +int scene_txted_calc_dims(struct scene_obj_txtedit *ted, struct udevice *cons) +{ + struct scene *scn = ted->obj.scene; + struct scene_obj_txt *txt; + int ret; + + txt = scene_obj_find(scn, ted->tin.edit_id, SCENEOBJT_NONE); + if (!txt) + return log_msg_ret("txt", -ENOENT); + + /* + * Set the edit text's bbox to match the textedit's bbox. This ensures + * SCENEOF_SIZE_VALID is set so vidconsole_measure() applies the width + * limit for word-wrapping/clipping. + */ + ret = scene_obj_set_bbox(scn, ted->tin.edit_id, + ted->obj.req_bbox.x0, ted->obj.req_bbox.y0, + ted->obj.req_bbox.x1, ted->obj.req_bbox.y1); + if (ret < 0) + return log_msg_ret("sbb", ret); + + return 0; +} + int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, struct scene_obj_txtedit *ted) { diff --git a/boot/scene_textline.c b/boot/scene_textline.c index c0492896888..0f542dd590f 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -44,22 +44,6 @@ int scene_textline(struct scene *scn, const char *name, uint id, 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; - int inset = theme->menu_inset; - - bbox->valid = false; - scene_bbox_union(tline->obj.scene, tline->tin.label_id, inset, bbox); - scene_bbox_union(tline->obj.scene, tline->tin.edit_id, inset, bbox); - - edit_bbox->valid = false; - scene_bbox_union(tline->obj.scene, tline->tin.edit_id, inset, - edit_bbox); -} - int scene_textline_calc_dims(struct scene_obj_textline *tline, struct udevice *cons) { diff --git a/boot/scene_txtin.c b/boot/scene_txtin.c new file mode 100644 index 00000000000..b2d8d0ad49e --- /dev/null +++ b/boot/scene_txtin.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Common code for text-input scene objects (textline, textedit) + * + * Copyright 2026 Canonical Ltd + * Written by Simon Glass <simon.glass@canonical.com> + */ + +#define LOG_CATEGORY LOGC_EXPO + +#include <expo.h> +#include <log.h> +#include <video_console.h> +#include "scene_internal.h" + +void scene_txtin_calc_bbox(struct scene_obj *obj, struct scene_txtin *tin, + struct vidconsole_bbox *bbox, + struct vidconsole_bbox *edit_bbox) +{ + struct scene *scn = obj->scene; + const struct expo_theme *theme = &scn->expo->theme; + int inset = theme->menu_inset; + + bbox->valid = false; + scene_bbox_union(scn, tin->label_id, inset, bbox); + scene_bbox_union(scn, tin->edit_id, inset, bbox); + + edit_bbox->valid = false; + scene_bbox_union(scn, tin->edit_id, inset, edit_bbox); +} -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add a static inline helper to get the scene_txtin pointer from a scene object. This simplifies code that handles both textline and textedit objects, since both have scene_txtin at the same offset. Use this in scene_obj_calc_bbox() to combine the TEXTLINE and TEXTEDIT cases. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene.c | 19 ++++--------------- boot/scene_internal.h | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 15 deletions(-) diff --git a/boot/scene.c b/boot/scene.c index 220fbf26b44..5691cbce847 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -1447,23 +1447,12 @@ int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox bbox[]) scene_menu_calc_bbox(menu, bbox); break; } - case SCENEOBJT_TEXTLINE: { - struct scene_obj_textline *tline; - - tline = (struct scene_obj_textline *)obj; - scene_txtin_calc_bbox(obj, &tline->tin, &bbox[SCENEBB_all], - &bbox[SCENEBB_label]); - break; - } - case SCENEOBJT_TEXTEDIT: { - struct scene_obj_txtedit *ted; - - ted = (struct scene_obj_txtedit *)obj; - scene_txtin_calc_bbox(obj, &ted->tin, &bbox[SCENEBB_all], - &bbox[SCENEBB_label]); + case SCENEOBJT_TEXTLINE: + case SCENEOBJT_TEXTEDIT: + scene_txtin_calc_bbox(obj, scene_obj_txtin(obj), + &bbox[SCENEBB_all], &bbox[SCENEBB_label]); break; } - } return 0; } diff --git a/boot/scene_internal.h b/boot/scene_internal.h index a3eb720c385..cc58a2264f6 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -29,6 +29,20 @@ enum scene_obj_t; typedef int (*expo_scene_obj_iterator)(struct scene_obj *obj, void *priv); +/** + * scene_obj_txtin() - Get text-input info from a scene object + * + * This works for both textline and textedit objects since they have + * struct scene_txtin at the same offset (immediately after struct scene_obj). + * + * @obj: Object to get text-input info from + * Return: pointer to the text-input info + */ +static inline struct scene_txtin *scene_obj_txtin(struct scene_obj *obj) +{ + return (struct scene_txtin *)(obj + 1); +} + /** * enum scene_bbox_t - Parts of an object which can have a bounding box * -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Factor out common init code from scene_textline() and scene_texted() into a new scene_txtin_init() helper. This handles buffer allocation, clearing, and setting line_chars. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene_internal.h | 10 ++++++++++ boot/scene_textedit.c | 10 +++------- boot/scene_textline.c | 9 +++------ boot/scene_txtin.c | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/boot/scene_internal.h b/boot/scene_internal.h index cc58a2264f6..b54bc1d426a 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -511,6 +511,16 @@ int scene_textline_calc_dims(struct scene_obj_textline *tline, void scene_menu_calc_bbox(struct scene_obj_menu *menu, struct vidconsole_bbox *bbox); +/** + * scene_txtin_init() - Initialise common text-input fields + * + * @tin: Text-input info to init + * @size: Size to use for buffer + * @line_chars: Number of characters in the text line + * Return: 0 if OK, -ENOMEM if out of memory + */ +int scene_txtin_init(struct scene_txtin *tin, uint size, uint line_chars); + /** * scene_txtin_calc_bbox() - Calculate bounding box for a text-input object * diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index 37138fc7542..9d0bfb2d552 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -22,7 +22,6 @@ int scene_texted(struct scene *scn, const char *name, uint id, uint line_chars, struct scene_obj_txtedit **teditp) { struct scene_obj_txtedit *ted; - char *buf; int ret; ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTEDIT, @@ -31,12 +30,9 @@ int scene_texted(struct scene *scn, const char *name, uint id, if (ret < 0) return log_msg_ret("obj", ret); - abuf_init(&ted->tin.buf); - if (!abuf_realloc(&ted->tin.buf, INITIAL_SIZE)) - return log_msg_ret("buf", -ENOMEM); - buf = abuf_data(&ted->tin.buf); - *buf = '\0'; - ted->tin.line_chars = line_chars; + ret = scene_txtin_init(&ted->tin, INITIAL_SIZE, line_chars); + if (ret) + return log_msg_ret("tin", ret); if (teditp) *teditp = ted; diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 0f542dd590f..960f5e8861f 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -20,7 +20,6 @@ int scene_textline(struct scene *scn, const char *name, uint id, uint line_chars, struct scene_obj_textline **tlinep) { struct scene_obj_textline *tline; - char *buf; int ret; if (line_chars >= EXPO_MAX_CHARS) @@ -31,12 +30,10 @@ int scene_textline(struct scene *scn, const char *name, uint id, (struct scene_obj **)&tline); if (ret < 0) return log_msg_ret("obj", -ENOMEM); - if (!abuf_init_size(&tline->tin.buf, line_chars + 1)) - return log_msg_ret("buf", -ENOMEM); - buf = abuf_data(&tline->tin.buf); - *buf = '\0'; + ret = scene_txtin_init(&tline->tin, line_chars + 1, line_chars); + if (ret) + return log_msg_ret("tin", ret); tline->pos = line_chars; - tline->tin.line_chars = line_chars; if (tlinep) *tlinep = tline; diff --git a/boot/scene_txtin.c b/boot/scene_txtin.c index b2d8d0ad49e..cd27f9b7115 100644 --- a/boot/scene_txtin.c +++ b/boot/scene_txtin.c @@ -11,8 +11,22 @@ #include <expo.h> #include <log.h> #include <video_console.h> +#include <linux/errno.h> #include "scene_internal.h" +int scene_txtin_init(struct scene_txtin *tin, uint size, uint line_chars) +{ + char *buf; + + if (!abuf_init_size(&tin->buf, size)) + return log_msg_ret("buf", -ENOMEM); + buf = abuf_data(&tin->buf); + *buf = '\0'; + tin->line_chars = line_chars; + + return 0; +} + void scene_txtin_calc_bbox(struct scene_obj *obj, struct scene_txtin *tin, struct vidconsole_bbox *bbox, struct vidconsole_bbox *edit_bbox) -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Factor out common arrangement code from scene_textline_arrange() and scene_txted_arrange() into scene_txtin_arrange() This handles label positioning and setting the SCENEOF_POINT flag. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene_internal.h | 14 ++++++++++++++ boot/scene_textedit.c | 26 ++++++-------------------- boot/scene_textline.c | 39 +++++++++++++-------------------------- boot/scene_txtin.c | 26 ++++++++++++++++++++++++++ 4 files changed, 59 insertions(+), 46 deletions(-) diff --git a/boot/scene_internal.h b/boot/scene_internal.h index b54bc1d426a..8c2196a7b11 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -521,6 +521,20 @@ void scene_menu_calc_bbox(struct scene_obj_menu *menu, */ int scene_txtin_init(struct scene_txtin *tin, uint size, uint line_chars); +/** + * scene_txtin_arrange() - Arrange common parts of a text-input object + * + * Sets the label position and SCENEOF_POINT flag + * + * @scn: Scene containing the object + * @arr: Arrangement info + * @obj: Object to arrange + * @tin: Text-input info + * Return: x position for edit object (positive), or -ve on error + */ +int scene_txtin_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj *obj, struct scene_txtin *tin); + /** * scene_txtin_calc_bbox() - Calculate bounding box for a text-input object * diff --git a/boot/scene_textedit.c b/boot/scene_textedit.c index 9d0bfb2d552..160b9457a50 100644 --- a/boot/scene_textedit.c +++ b/boot/scene_textedit.c @@ -79,35 +79,21 @@ int scene_txted_calc_dims(struct scene_obj_txtedit *ted, struct udevice *cons) int scene_txted_arrange(struct scene *scn, struct expo_arrange_info *arr, struct scene_obj_txtedit *ted) { - const bool open = ted->obj.flags & SCENEOF_OPEN; - const struct expo_theme *theme = &scn->expo->theme; - bool point; - int x, y; + int x; int ret; - x = ted->obj.req_bbox.x0; - y = ted->obj.req_bbox.y0; - if (ted->tin.label_id) { - ret = scene_obj_set_pos(scn, ted->tin.label_id, x, y); - if (ret < 0) - return log_msg_ret("tit", ret); - - x += arr->label_width + theme->textline_label_margin_x; - } + x = scene_txtin_arrange(scn, arr, &ted->obj, &ted->tin); + if (x < 0) + return log_msg_ret("arr", x); /* constrain the edit text to fit within the textedit bbox */ - ret = scene_obj_set_bbox(scn, ted->tin.edit_id, x, y, + ret = scene_obj_set_bbox(scn, ted->tin.edit_id, x, ted->obj.req_bbox.y0, ted->obj.req_bbox.x1, ted->obj.req_bbox.y1); if (ret < 0) return log_msg_ret("edi", ret); - point = scn->highlight_id == ted->obj.id; - point &= !open; - scene_obj_flag_clrset(scn, ted->tin.edit_id, SCENEOF_POINT, - point ? SCENEOF_POINT : 0); - ted->obj.dims.x = x - ted->obj.req_bbox.x0; - ted->obj.dims.y = y - ted->obj.req_bbox.y0; + ted->obj.dims.y = 0; scene_obj_set_size(scn, ted->obj.id, ted->obj.dims.x, ted->obj.dims.y); return 0; diff --git a/boot/scene_textline.c b/boot/scene_textline.c index 960f5e8861f..f940be3ed28 100644 --- a/boot/scene_textline.c +++ b/boot/scene_textline.c @@ -71,37 +71,24 @@ int scene_textline_calc_dims(struct scene_obj_textline *tline, int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr, struct scene_obj_textline *tline) { - const bool open = tline->obj.flags & SCENEOF_OPEN; - const struct expo_theme *theme = &scn->expo->theme; - bool point; + struct scene_obj *edit; int x, y; int ret; - x = tline->obj.req_bbox.x0; + x = scene_txtin_arrange(scn, arr, &tline->obj, &tline->tin); + if (x < 0) + return log_msg_ret("arr", x); + y = tline->obj.req_bbox.y0; - if (tline->tin.label_id) { - struct scene_obj *edit; - - ret = scene_obj_set_pos(scn, tline->tin.label_id, x, y); - if (ret < 0) - return log_msg_ret("tit", ret); - - x += arr->label_width + theme->textline_label_margin_x; - ret = scene_obj_set_pos(scn, tline->tin.edit_id, x, y); - if (ret < 0) - return log_msg_ret("til", ret); - - edit = scene_obj_find(scn, tline->tin.edit_id, SCENEOBJT_NONE); - if (!edit) - return log_msg_ret("tie", -ENOENT); - x += edit->dims.x; - y += edit->dims.y; - } + ret = scene_obj_set_pos(scn, tline->tin.edit_id, x, y); + if (ret < 0) + return log_msg_ret("pos", ret); - point = scn->highlight_id == tline->obj.id; - point &= !open; - scene_obj_flag_clrset(scn, tline->tin.edit_id, SCENEOF_POINT, - point ? SCENEOF_POINT : 0); + edit = scene_obj_find(scn, tline->tin.edit_id, SCENEOBJT_NONE); + if (!edit) + return log_msg_ret("fnd", -ENOENT); + x += edit->dims.x; + y += edit->dims.y; tline->obj.dims.x = x - tline->obj.req_bbox.x0; tline->obj.dims.y = y - tline->obj.req_bbox.y0; diff --git a/boot/scene_txtin.c b/boot/scene_txtin.c index cd27f9b7115..dbd2555f71d 100644 --- a/boot/scene_txtin.c +++ b/boot/scene_txtin.c @@ -27,6 +27,32 @@ int scene_txtin_init(struct scene_txtin *tin, uint size, uint line_chars) return 0; } +int scene_txtin_arrange(struct scene *scn, struct expo_arrange_info *arr, + struct scene_obj *obj, struct scene_txtin *tin) +{ + const bool open = obj->flags & SCENEOF_OPEN; + const struct expo_theme *theme = &scn->expo->theme; + bool point; + int x; + int ret; + + x = obj->req_bbox.x0; + if (tin->label_id) { + ret = scene_obj_set_pos(scn, tin->label_id, x, obj->req_bbox.y0); + if (ret < 0) + return log_msg_ret("lab", ret); + + x += arr->label_width + theme->textline_label_margin_x; + } + + point = scn->highlight_id == obj->id; + point &= !open; + scene_obj_flag_clrset(scn, tin->edit_id, SCENEOF_POINT, + point ? SCENEOF_POINT : 0); + + return x; +} + void scene_txtin_calc_bbox(struct scene_obj *obj, struct scene_txtin *tin, struct vidconsole_bbox *bbox, struct vidconsole_bbox *edit_bbox) -- 2.43.0
From: Simon Glass <simon.glass@canonical.com> Add textedit support to scene_calc_dims() by calling scene_txted_calc_dims(), thus enabling proper dimension-calculation for textedit objects. This is needed for word-wrapping. Update expo_render_textedit() with the new expected value, now that word-wrapping is working. Co-developed-by: Claude Opus 4.5 <noreply@anthropic.com> Signed-off-by: Simon Glass <simon.glass@canonical.com> --- boot/scene.c | 24 ++++++++++++++++-------- boot/scene_internal.h | 39 +++++++++++++++++++++++++-------------- test/boot/expo.c | 2 +- 3 files changed, 42 insertions(+), 23 deletions(-) diff --git a/boot/scene.c b/boot/scene.c index 5691cbce847..3565bfd77de 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -773,7 +773,6 @@ 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; @@ -782,14 +781,11 @@ int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr) label_id = menu->title_id; break; } - case SCENEOBJT_TEXTLINE: { - struct scene_obj_textline *tline; - - tline = (struct scene_obj_textline *)obj, - label_id = tline->tin.label_id; + case SCENEOBJT_TEXTLINE: + case SCENEOBJT_TEXTEDIT: + label_id = scene_obj_txtin(obj)->label_id; break; } - } if (label_id) { int ret; @@ -1517,7 +1513,6 @@ int scene_calc_dims(struct scene *scn) case SCENEOBJT_NONE: case SCENEOBJT_TEXT: case SCENEOBJT_BOX: - case SCENEOBJT_TEXTEDIT: case SCENEOBJT_IMAGE: { int width; @@ -1533,6 +1528,19 @@ int scene_calc_dims(struct scene *scn) } case SCENEOBJT_MENU: break; + case SCENEOBJT_TEXTEDIT: { + struct scene_obj_txtedit *ted; + + ted = (struct scene_obj_txtedit *)obj; + if (!scn->expo->cons || do_menus) + continue; + + ret = scene_txted_calc_dims(ted, scn->expo->cons); + if (ret) + return log_msg_ret("ted", ret); + + break; + } case SCENEOBJT_TEXTLINE: { struct scene_obj_textline *tline; diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 8c2196a7b11..db11f9c0f60 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -29,20 +29,6 @@ enum scene_obj_t; typedef int (*expo_scene_obj_iterator)(struct scene_obj *obj, void *priv); -/** - * scene_obj_txtin() - Get text-input info from a scene object - * - * This works for both textline and textedit objects since they have - * struct scene_txtin at the same offset (immediately after struct scene_obj). - * - * @obj: Object to get text-input info from - * Return: pointer to the text-input info - */ -static inline struct scene_txtin *scene_obj_txtin(struct scene_obj *obj) -{ - return (struct scene_txtin *)(obj + 1); -} - /** * enum scene_bbox_t - Parts of an object which can have a bounding box * @@ -64,6 +50,20 @@ enum scene_bbox_t { SCENEBB_count, }; +/** + * scene_obj_txtin() - Get text-input info from a scene object + * + * This works for both textline and textedit objects since they have + * struct scene_txtin at the same offset (immediately after struct scene_obj). + * + * @obj: Object to get text-input info from + * Return: pointer to the text-input info + */ +static inline struct scene_txtin *scene_obj_txtin(struct scene_obj *obj) +{ + return (struct scene_txtin *)(obj + 1); +} + /** * expo_lookup_scene_id() - Look up a scene ID * @@ -501,6 +501,17 @@ int scene_dims_union(struct scene *scn, uint id, struct scene_obj_dims *dims); int scene_textline_calc_dims(struct scene_obj_textline *tline, struct udevice *cons); +/** + * scene_txted_calc_dims() - Calculate the dimensions of a textedit + * + * Updates the width and height of the textedit based on its contents + * + * @ted: Textedit to update + * @cons: UCLASS_VIDEO_CONSOLE device (cannot be NULL) + * Returns 0 if OK, -ve on error + */ +int scene_txted_calc_dims(struct scene_obj_txtedit *ted, struct udevice *cons); + /** * scene_menu_calc_bbox() - Calculate bounding boxes for the menu * diff --git a/test/boot/expo.c b/test/boot/expo.c index 95b029568d0..97b9bf82bb7 100644 --- a/test/boot/expo.c +++ b/test/boot/expo.c @@ -1533,7 +1533,7 @@ static int expo_render_textedit(struct unit_test_state *uts) expo_set_scene_id(exp, SCENE1); ut_assertok(scene_arrange(scn)); ut_assertok(expo_render(exp)); - ut_asserteq(19493, video_compress_fb(uts, dev, false)); + ut_asserteq(19860, video_compress_fb(uts, dev, false)); abuf_uninit(&buf); abuf_uninit(&logo_copy); -- 2.43.0
participants (1)
-
Simon Glass