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