blob: 6ea072a1c2688bb62a3d4664fd11ad8b9c8df347 [file] [log] [blame]
Simon Glass4db75192023-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
11#include <common.h>
12#include <expo.h>
13#include <menu.h>
14#include <video_console.h>
15#include "scene_internal.h"
16
17int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars,
18 struct scene_obj_textline **tlinep)
19{
20 struct scene_obj_textline *tline;
21 char *buf;
22 int ret;
23
24 if (max_chars >= EXPO_MAX_CHARS)
25 return log_msg_ret("chr", -E2BIG);
26
27 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTLINE,
28 sizeof(struct scene_obj_textline),
29 (struct scene_obj **)&tline);
30 if (ret < 0)
31 return log_msg_ret("obj", -ENOMEM);
32 abuf_init(&tline->buf);
33 if (!abuf_realloc(&tline->buf, max_chars + 1))
34 return log_msg_ret("buf", -ENOMEM);
35 buf = abuf_data(&tline->buf);
36 *buf = '\0';
37 tline->pos = max_chars;
38 tline->max_chars = max_chars;
39
40 if (tlinep)
41 *tlinep = tline;
42
43 return tline->obj.id;
44}
45
46void scene_textline_calc_bbox(struct scene_obj_textline *tline,
47 struct vidconsole_bbox *bbox,
48 struct vidconsole_bbox *edit_bbox)
49{
50 const struct expo_theme *theme = &tline->obj.scene->expo->theme;
51
52 bbox->valid = false;
53 scene_bbox_union(tline->obj.scene, tline->label_id, 0, bbox);
54 scene_bbox_union(tline->obj.scene, tline->edit_id, 0, bbox);
55
56 edit_bbox->valid = false;
57 scene_bbox_union(tline->obj.scene, tline->edit_id, theme->menu_inset,
58 edit_bbox);
59}
60
61int scene_textline_calc_dims(struct scene_obj_textline *tline)
62{
63 struct scene *scn = tline->obj.scene;
64 struct vidconsole_bbox bbox;
65 struct scene_obj_txt *txt;
66 int ret;
67
68 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
69 if (!txt)
70 return log_msg_ret("dim", -ENOENT);
71
72 ret = vidconsole_nominal(scn->expo->cons, txt->font_name,
73 txt->font_size, tline->max_chars, &bbox);
74 if (ret)
75 return log_msg_ret("nom", ret);
76
77 if (bbox.valid) {
78 tline->obj.dim.w = bbox.x1 - bbox.x0;
79 tline->obj.dim.h = bbox.y1 - bbox.y0;
80
81 scene_obj_set_size(scn, tline->edit_id, tline->obj.dim.w,
82 tline->obj.dim.h);
83 }
84
85 return 0;
86}
87
88int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline)
89{
90 const bool open = tline->obj.flags & SCENEOF_OPEN;
91 bool point;
92 int x, y;
93 int ret;
94
95 x = tline->obj.dim.x;
96 y = tline->obj.dim.y;
97 if (tline->label_id) {
98 ret = scene_obj_set_pos(scn, tline->label_id, tline->obj.dim.x,
99 y);
100 if (ret < 0)
101 return log_msg_ret("tit", ret);
102
103 ret = scene_obj_set_pos(scn, tline->edit_id,
104 tline->obj.dim.x + 200, y);
105 if (ret < 0)
106 return log_msg_ret("tit", ret);
107
108 ret = scene_obj_get_hw(scn, tline->label_id, NULL);
109 if (ret < 0)
110 return log_msg_ret("hei", ret);
111
112 y += ret * 2;
113 }
114
115 point = scn->highlight_id == tline->obj.id;
116 point &= !open;
117 scene_obj_flag_clrset(scn, tline->edit_id, SCENEOF_POINT,
118 point ? SCENEOF_POINT : 0);
119
120 return 0;
121}
122
123int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline,
124 int key, struct expo_action *event)
125{
126 const bool open = tline->obj.flags & SCENEOF_OPEN;
127
128 log_debug("key=%d\n", key);
129 switch (key) {
130 case BKEY_QUIT:
131 if (open) {
132 event->type = EXPOACT_CLOSE;
133 event->select.id = tline->obj.id;
134
135 /* Copy the backup text from the scene buffer */
136 memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf),
137 abuf_size(&scn->buf));
138 } else {
139 event->type = EXPOACT_QUIT;
140 log_debug("menu quit\n");
141 }
142 break;
143 case BKEY_SELECT:
144 if (!open)
145 break;
146 event->type = EXPOACT_CLOSE;
147 event->select.id = tline->obj.id;
148 key = '\n';
149 fallthrough;
150 default: {
151 struct udevice *cons = scn->expo->cons;
152 int ret;
153
154 ret = vidconsole_entry_restore(cons, &scn->entry_save);
155 if (ret)
156 return log_msg_ret("sav", ret);
157 ret = cread_line_process_ch(&scn->cls, key);
158 ret = vidconsole_entry_save(cons, &scn->entry_save);
159 if (ret)
160 return log_msg_ret("sav", ret);
161 break;
162 }
163 }
164
165 return 0;
166}
167
168int scene_textline_render_deps(struct scene *scn,
169 struct scene_obj_textline *tline)
170{
171 const bool open = tline->obj.flags & SCENEOF_OPEN;
172 struct udevice *cons = scn->expo->cons;
173 struct scene_obj_txt *txt;
174 int ret;
175
176 scene_render_deps(scn, tline->label_id);
177 scene_render_deps(scn, tline->edit_id);
178
179 /* show the vidconsole cursor if open */
180 if (open) {
181 /* get the position within the field */
182 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
183 if (!txt)
184 return log_msg_ret("cur", -ENOENT);
185
186 if (txt->font_name || txt->font_size) {
187 ret = vidconsole_select_font(cons,
188 txt->font_name,
189 txt->font_size);
190 } else {
191 ret = vidconsole_select_font(cons, NULL, 0);
192 }
193
194 ret = vidconsole_entry_restore(cons, &scn->entry_save);
195 if (ret)
196 return log_msg_ret("sav", ret);
197
198 vidconsole_set_cursor_visible(cons, true, txt->obj.dim.x,
199 txt->obj.dim.y, scn->cls.num);
200 }
201
202 return 0;
203}
204
205int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline)
206{
207 struct udevice *cons = scn->expo->cons;
208 struct scene_obj_txt *txt;
209 int ret;
210
211 /* Copy the text into the scene buffer in case the edit is cancelled */
212 memcpy(abuf_data(&scn->buf), abuf_data(&tline->buf),
213 abuf_size(&scn->buf));
214
215 /* get the position of the editable */
216 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
217 if (!txt)
218 return log_msg_ret("cur", -ENOENT);
219
220 vidconsole_set_cursor_pos(cons, txt->obj.dim.x, txt->obj.dim.y);
221 vidconsole_entry_start(cons);
222 cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars);
223 scn->cls.insert = true;
224 ret = vidconsole_entry_save(cons, &scn->entry_save);
225 if (ret)
226 return log_msg_ret("sav", ret);
227
228 return 0;
229}