blob: 7bc35a997dcceb8cebb4304d6b44516fee53ca3e [file] [log] [blame]
Simon Glass6116e762023-10-01 19:13:32 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Implementation of a menu in a scene
4 *
5 * Copyright 2023 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
9#define LOG_CATEGORY LOGC_EXPO
10
Simon Glass6116e762023-10-01 19:13:32 -060011#include <expo.h>
12#include <menu.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060013#include <log.h>
Simon Glass6116e762023-10-01 19:13:32 -060014#include <video_console.h>
Tom Rinidec7ea02024-05-20 13:35:03 -060015#include <linux/errno.h>
16#include <linux/string.h>
Simon Glass6116e762023-10-01 19:13:32 -060017#include "scene_internal.h"
18
19int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars,
20 struct scene_obj_textline **tlinep)
21{
22 struct scene_obj_textline *tline;
23 char *buf;
24 int ret;
25
26 if (max_chars >= EXPO_MAX_CHARS)
27 return log_msg_ret("chr", -E2BIG);
28
29 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTLINE,
30 sizeof(struct scene_obj_textline),
31 (struct scene_obj **)&tline);
32 if (ret < 0)
33 return log_msg_ret("obj", -ENOMEM);
Simon Glass6651e942025-05-01 07:37:01 -060034 if (!abuf_init_size(&tline->buf, max_chars + 1))
Simon Glass6116e762023-10-01 19:13:32 -060035 return log_msg_ret("buf", -ENOMEM);
36 buf = abuf_data(&tline->buf);
37 *buf = '\0';
38 tline->pos = max_chars;
39 tline->max_chars = max_chars;
40
41 if (tlinep)
42 *tlinep = tline;
43
44 return tline->obj.id;
45}
46
47void scene_textline_calc_bbox(struct scene_obj_textline *tline,
48 struct vidconsole_bbox *bbox,
49 struct vidconsole_bbox *edit_bbox)
50{
51 const struct expo_theme *theme = &tline->obj.scene->expo->theme;
52
53 bbox->valid = false;
54 scene_bbox_union(tline->obj.scene, tline->label_id, 0, bbox);
55 scene_bbox_union(tline->obj.scene, tline->edit_id, 0, bbox);
56
57 edit_bbox->valid = false;
58 scene_bbox_union(tline->obj.scene, tline->edit_id, theme->menu_inset,
59 edit_bbox);
60}
61
62int scene_textline_calc_dims(struct scene_obj_textline *tline)
63{
Simon Glassebec4972025-05-02 08:46:33 -060064 struct scene_obj *obj = &tline->obj;
65 struct scene *scn = obj->scene;
Simon Glass6116e762023-10-01 19:13:32 -060066 struct vidconsole_bbox bbox;
67 struct scene_obj_txt *txt;
68 int ret;
69
70 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
71 if (!txt)
72 return log_msg_ret("dim", -ENOENT);
73
Simon Glass9ef02aa2025-05-02 08:46:37 -060074 ret = vidconsole_nominal(scn->expo->cons, txt->gen.font_name,
75 txt->gen.font_size, tline->max_chars, &bbox);
Simon Glass6116e762023-10-01 19:13:32 -060076 if (ret)
77 return log_msg_ret("nom", ret);
78
79 if (bbox.valid) {
Simon Glassebec4972025-05-02 08:46:33 -060080 obj->dims.x = bbox.x1 - bbox.x0;
81 obj->dims.y = bbox.y1 - bbox.y0;
82 if (!(obj->flags & SCENEOF_SIZE_VALID)) {
83 obj->bbox.x1 = obj->bbox.x0 + obj->dims.x;
84 obj->bbox.y1 = obj->bbox.y0 + obj->dims.y;
85 obj->flags |= SCENEOF_SIZE_VALID;
86 }
87 scene_obj_set_size(scn, tline->edit_id,
88 obj->bbox.x1 - obj->bbox.x0,
89 obj->bbox.y1 - obj->bbox.y0);
Simon Glass6116e762023-10-01 19:13:32 -060090 }
91
92 return 0;
93}
94
Simon Glass377f18e2024-10-14 16:31:55 -060095int scene_textline_arrange(struct scene *scn, struct expo_arrange_info *arr,
96 struct scene_obj_textline *tline)
Simon Glass6116e762023-10-01 19:13:32 -060097{
98 const bool open = tline->obj.flags & SCENEOF_OPEN;
99 bool point;
100 int x, y;
101 int ret;
102
Simon Glassbc3a15f2025-05-02 08:46:31 -0600103 x = tline->obj.bbox.x0;
104 y = tline->obj.bbox.y0;
Simon Glass6116e762023-10-01 19:13:32 -0600105 if (tline->label_id) {
Simon Glassbc3a15f2025-05-02 08:46:31 -0600106 ret = scene_obj_set_pos(scn, tline->label_id,
107 tline->obj.bbox.x0, y);
Simon Glass6116e762023-10-01 19:13:32 -0600108 if (ret < 0)
109 return log_msg_ret("tit", ret);
110
111 ret = scene_obj_set_pos(scn, tline->edit_id,
Simon Glassbc3a15f2025-05-02 08:46:31 -0600112 tline->obj.bbox.x0 + 200, y);
Simon Glass6116e762023-10-01 19:13:32 -0600113 if (ret < 0)
114 return log_msg_ret("tit", ret);
115
116 ret = scene_obj_get_hw(scn, tline->label_id, NULL);
117 if (ret < 0)
118 return log_msg_ret("hei", ret);
119
120 y += ret * 2;
121 }
122
123 point = scn->highlight_id == tline->obj.id;
124 point &= !open;
125 scene_obj_flag_clrset(scn, tline->edit_id, SCENEOF_POINT,
126 point ? SCENEOF_POINT : 0);
127
128 return 0;
129}
130
131int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline,
132 int key, struct expo_action *event)
133{
134 const bool open = tline->obj.flags & SCENEOF_OPEN;
135
136 log_debug("key=%d\n", key);
137 switch (key) {
138 case BKEY_QUIT:
139 if (open) {
140 event->type = EXPOACT_CLOSE;
141 event->select.id = tline->obj.id;
142
143 /* Copy the backup text from the scene buffer */
144 memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf),
145 abuf_size(&scn->buf));
146 } else {
147 event->type = EXPOACT_QUIT;
148 log_debug("menu quit\n");
149 }
150 break;
151 case BKEY_SELECT:
152 if (!open)
153 break;
154 event->type = EXPOACT_CLOSE;
155 event->select.id = tline->obj.id;
156 key = '\n';
157 fallthrough;
158 default: {
159 struct udevice *cons = scn->expo->cons;
160 int ret;
161
162 ret = vidconsole_entry_restore(cons, &scn->entry_save);
163 if (ret)
164 return log_msg_ret("sav", ret);
165 ret = cread_line_process_ch(&scn->cls, key);
166 ret = vidconsole_entry_save(cons, &scn->entry_save);
167 if (ret)
168 return log_msg_ret("sav", ret);
169 break;
170 }
171 }
172
173 return 0;
174}
175
176int scene_textline_render_deps(struct scene *scn,
177 struct scene_obj_textline *tline)
178{
179 const bool open = tline->obj.flags & SCENEOF_OPEN;
180 struct udevice *cons = scn->expo->cons;
181 struct scene_obj_txt *txt;
182 int ret;
183
184 scene_render_deps(scn, tline->label_id);
185 scene_render_deps(scn, tline->edit_id);
186
187 /* show the vidconsole cursor if open */
188 if (open) {
189 /* get the position within the field */
190 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
191 if (!txt)
192 return log_msg_ret("cur", -ENOENT);
193
Simon Glass9ef02aa2025-05-02 08:46:37 -0600194 if (txt->gen.font_name || txt->gen.font_size) {
Simon Glass6116e762023-10-01 19:13:32 -0600195 ret = vidconsole_select_font(cons,
Simon Glass9ef02aa2025-05-02 08:46:37 -0600196 txt->gen.font_name,
197 txt->gen.font_size);
Simon Glass6116e762023-10-01 19:13:32 -0600198 } else {
199 ret = vidconsole_select_font(cons, NULL, 0);
200 }
201
202 ret = vidconsole_entry_restore(cons, &scn->entry_save);
203 if (ret)
204 return log_msg_ret("sav", ret);
205
Simon Glassbc3a15f2025-05-02 08:46:31 -0600206 vidconsole_set_cursor_visible(cons, true, txt->obj.bbox.x0,
207 txt->obj.bbox.y0, scn->cls.num);
Simon Glass6116e762023-10-01 19:13:32 -0600208 }
209
210 return 0;
211}
212
213int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline)
214{
215 struct udevice *cons = scn->expo->cons;
216 struct scene_obj_txt *txt;
217 int ret;
218
219 /* Copy the text into the scene buffer in case the edit is cancelled */
220 memcpy(abuf_data(&scn->buf), abuf_data(&tline->buf),
221 abuf_size(&scn->buf));
222
223 /* get the position of the editable */
224 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
225 if (!txt)
226 return log_msg_ret("cur", -ENOENT);
227
Simon Glassbc3a15f2025-05-02 08:46:31 -0600228 vidconsole_set_cursor_pos(cons, txt->obj.bbox.x0, txt->obj.bbox.y0);
Simon Glass6116e762023-10-01 19:13:32 -0600229 vidconsole_entry_start(cons);
230 cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars);
231 scn->cls.insert = true;
232 ret = vidconsole_entry_save(cons, &scn->entry_save);
233 if (ret)
234 return log_msg_ret("sav", ret);
235
236 return 0;
237}