blob: bba8663b98da695255696da85b22fb25e6d10110 [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
90int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline)
91{
92 const bool open = tline->obj.flags & SCENEOF_OPEN;
93 bool point;
94 int x, y;
95 int ret;
96
97 x = tline->obj.dim.x;
98 y = tline->obj.dim.y;
99 if (tline->label_id) {
100 ret = scene_obj_set_pos(scn, tline->label_id, tline->obj.dim.x,
101 y);
102 if (ret < 0)
103 return log_msg_ret("tit", ret);
104
105 ret = scene_obj_set_pos(scn, tline->edit_id,
106 tline->obj.dim.x + 200, y);
107 if (ret < 0)
108 return log_msg_ret("tit", ret);
109
110 ret = scene_obj_get_hw(scn, tline->label_id, NULL);
111 if (ret < 0)
112 return log_msg_ret("hei", ret);
113
114 y += ret * 2;
115 }
116
117 point = scn->highlight_id == tline->obj.id;
118 point &= !open;
119 scene_obj_flag_clrset(scn, tline->edit_id, SCENEOF_POINT,
120 point ? SCENEOF_POINT : 0);
121
122 return 0;
123}
124
125int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline,
126 int key, struct expo_action *event)
127{
128 const bool open = tline->obj.flags & SCENEOF_OPEN;
129
130 log_debug("key=%d\n", key);
131 switch (key) {
132 case BKEY_QUIT:
133 if (open) {
134 event->type = EXPOACT_CLOSE;
135 event->select.id = tline->obj.id;
136
137 /* Copy the backup text from the scene buffer */
138 memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf),
139 abuf_size(&scn->buf));
140 } else {
141 event->type = EXPOACT_QUIT;
142 log_debug("menu quit\n");
143 }
144 break;
145 case BKEY_SELECT:
146 if (!open)
147 break;
148 event->type = EXPOACT_CLOSE;
149 event->select.id = tline->obj.id;
150 key = '\n';
151 fallthrough;
152 default: {
153 struct udevice *cons = scn->expo->cons;
154 int ret;
155
156 ret = vidconsole_entry_restore(cons, &scn->entry_save);
157 if (ret)
158 return log_msg_ret("sav", ret);
159 ret = cread_line_process_ch(&scn->cls, key);
160 ret = vidconsole_entry_save(cons, &scn->entry_save);
161 if (ret)
162 return log_msg_ret("sav", ret);
163 break;
164 }
165 }
166
167 return 0;
168}
169
170int scene_textline_render_deps(struct scene *scn,
171 struct scene_obj_textline *tline)
172{
173 const bool open = tline->obj.flags & SCENEOF_OPEN;
174 struct udevice *cons = scn->expo->cons;
175 struct scene_obj_txt *txt;
176 int ret;
177
178 scene_render_deps(scn, tline->label_id);
179 scene_render_deps(scn, tline->edit_id);
180
181 /* show the vidconsole cursor if open */
182 if (open) {
183 /* get the position within the field */
184 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
185 if (!txt)
186 return log_msg_ret("cur", -ENOENT);
187
188 if (txt->font_name || txt->font_size) {
189 ret = vidconsole_select_font(cons,
190 txt->font_name,
191 txt->font_size);
192 } else {
193 ret = vidconsole_select_font(cons, NULL, 0);
194 }
195
196 ret = vidconsole_entry_restore(cons, &scn->entry_save);
197 if (ret)
198 return log_msg_ret("sav", ret);
199
200 vidconsole_set_cursor_visible(cons, true, txt->obj.dim.x,
201 txt->obj.dim.y, scn->cls.num);
202 }
203
204 return 0;
205}
206
207int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline)
208{
209 struct udevice *cons = scn->expo->cons;
210 struct scene_obj_txt *txt;
211 int ret;
212
213 /* Copy the text into the scene buffer in case the edit is cancelled */
214 memcpy(abuf_data(&scn->buf), abuf_data(&tline->buf),
215 abuf_size(&scn->buf));
216
217 /* get the position of the editable */
218 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE);
219 if (!txt)
220 return log_msg_ret("cur", -ENOENT);
221
222 vidconsole_set_cursor_pos(cons, txt->obj.dim.x, txt->obj.dim.y);
223 vidconsole_entry_start(cons);
224 cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars);
225 scn->cls.insert = true;
226 ret = vidconsole_entry_save(cons, &scn->entry_save);
227 if (ret)
228 return log_msg_ret("sav", ret);
229
230 return 0;
231}