[Concept,11/16] expo: Introduce scene_txtin for common text-input fields

Message ID 20260118204303.1982533-12-sjg@u-boot.org
State New
Headers
Series expo: Continue preparations for textedit (part D) |

Commit Message

Simon Glass Jan. 18, 2026, 8:42 p.m. UTC
  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(-)
  

Patch

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);