1 // SPDX-License-Identifier: GPL-2.0+
3 * Implementation of a scene, a collection of text/image/menu items in an expo
5 * Copyright 2022 Google LLC
15 #include <video_console.h>
16 #include <linux/input.h>
17 #include "scene_internal.h"
19 uint resolve_id(struct expo *exp, uint id)
23 else if (id >= exp->next_id)
24 exp->next_id = id + 1;
29 int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
33 scn = calloc(1, sizeof(struct scene));
35 return log_msg_ret("expo", -ENOMEM);
36 scn->name = strdup(name);
39 return log_msg_ret("name", -ENOMEM);
42 INIT_LIST_HEAD(&scn->obj_head);
43 scn->id = resolve_id(exp, id);
45 list_add_tail(&scn->sibling, &exp->scene_head);
52 void scene_obj_destroy(struct scene_obj *obj)
54 if (obj->type == SCENEOBJT_MENU)
55 scene_menu_destroy((struct scene_obj_menu *)obj);
60 void scene_destroy(struct scene *scn)
62 struct scene_obj *obj, *next;
64 list_for_each_entry_safe(obj, next, &scn->obj_head, sibling)
65 scene_obj_destroy(obj);
71 int scene_title_set(struct scene *scn, uint id)
78 int scene_obj_count(struct scene *scn)
80 struct scene_obj *obj;
83 list_for_each_entry(obj, &scn->obj_head, sibling)
89 void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type)
91 struct scene_obj *obj;
93 list_for_each_entry(obj, &scn->obj_head, sibling) {
95 (type == SCENEOBJT_NONE || obj->type == type))
102 int scene_obj_add(struct scene *scn, const char *name, uint id,
103 enum scene_obj_t type, uint size, struct scene_obj **objp)
105 struct scene_obj *obj;
107 obj = calloc(1, size);
109 return log_msg_ret("obj", -ENOMEM);
110 obj->name = strdup(name);
113 return log_msg_ret("name", -ENOMEM);
116 obj->id = resolve_id(scn->expo, id);
119 list_add_tail(&obj->sibling, &scn->obj_head);
125 int scene_img(struct scene *scn, const char *name, uint id, char *data,
126 struct scene_obj_img **imgp)
128 struct scene_obj_img *img;
131 ret = scene_obj_add(scn, name, id, SCENEOBJT_IMAGE,
132 sizeof(struct scene_obj_img),
133 (struct scene_obj **)&img);
135 return log_msg_ret("obj", -ENOMEM);
145 int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
146 struct scene_obj_txt **txtp)
148 struct scene_obj_txt *txt;
151 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
152 sizeof(struct scene_obj_txt),
153 (struct scene_obj **)&txt);
155 return log_msg_ret("obj", -ENOMEM);
157 txt->str_id = str_id;
165 int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
166 const char *str, struct scene_obj_txt **txtp)
168 struct scene_obj_txt *txt;
171 ret = expo_str(scn->expo, name, str_id, str);
173 return log_msg_ret("str", ret);
174 else if (ret != str_id)
175 return log_msg_ret("id", -EEXIST);
177 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
178 sizeof(struct scene_obj_txt),
179 (struct scene_obj **)&txt);
181 return log_msg_ret("obj", -ENOMEM);
183 txt->str_id = str_id;
191 int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
194 struct scene_obj_txt *txt;
196 txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
198 return log_msg_ret("find", -ENOENT);
199 txt->font_name = font_name;
200 txt->font_size = font_size;
205 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
207 struct scene_obj *obj;
209 obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
211 return log_msg_ret("find", -ENOENT);
214 if (obj->type == SCENEOBJT_MENU)
215 scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
220 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
222 struct scene_obj *obj;
224 obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
226 return log_msg_ret("find", -ENOENT);
232 int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
234 struct scene_obj *obj;
236 obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
238 return log_msg_ret("find", -ENOENT);
244 case SCENEOBJT_IMAGE: {
245 struct scene_obj_img *img = (struct scene_obj_img *)obj;
249 video_bmp_get_info(img->data, &width, &height, &bpix);
254 case SCENEOBJT_TEXT: {
255 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
256 struct expo *exp = scn->expo;
259 *widthp = 16; /* fake value for now */
261 return txt->font_size;
263 return video_default_font_height(exp->display);
265 /* use a sensible default */
274 * scene_obj_render() - Render an object
277 static int scene_obj_render(struct scene_obj *obj, bool text_mode)
279 struct scene *scn = obj->scene;
280 struct expo *exp = scn->expo;
281 struct udevice *dev = exp->display;
282 struct udevice *cons = text_mode ? NULL : exp->cons;
291 case SCENEOBJT_IMAGE: {
292 struct scene_obj_img *img = (struct scene_obj_img *)obj;
296 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
299 return log_msg_ret("img", ret);
302 case SCENEOBJT_TEXT: {
303 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
309 if (txt->font_name || txt->font_size) {
310 ret = vidconsole_select_font(cons,
314 ret = vidconsole_select_font(cons, NULL, 0);
316 if (ret && ret != -ENOSYS)
317 return log_msg_ret("font", ret);
318 vidconsole_set_cursor_pos(cons, x, y);
319 str = expo_get_str(exp, txt->str_id);
321 vidconsole_put_string(cons, str);
324 case SCENEOBJT_MENU: {
325 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
327 * With a vidconsole, the text and item pointer are rendered as
328 * normal objects so we don't need to do anything here. The menu
329 * simply controls where they are positioned.
334 ret = scene_menu_display(menu);
336 return log_msg_ret("img", ret);
345 int scene_arrange(struct scene *scn)
347 struct scene_obj *obj;
350 list_for_each_entry(obj, &scn->obj_head, sibling) {
351 if (obj->type == SCENEOBJT_MENU) {
352 struct scene_obj_menu *menu;
354 menu = (struct scene_obj_menu *)obj,
355 ret = scene_menu_arrange(scn, menu);
357 return log_msg_ret("arr", ret);
364 int scene_render(struct scene *scn)
366 struct expo *exp = scn->expo;
367 struct scene_obj *obj;
370 list_for_each_entry(obj, &scn->obj_head, sibling) {
372 ret = scene_obj_render(obj, exp->text_mode);
373 if (ret && ret != -ENOTSUPP)
374 return log_msg_ret("ren", ret);
381 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
383 struct scene_obj *obj;
386 list_for_each_entry(obj, &scn->obj_head, sibling) {
387 if (obj->type == SCENEOBJT_MENU) {
388 struct scene_obj_menu *menu;
390 menu = (struct scene_obj_menu *)obj,
391 ret = scene_menu_send_key(scn, menu, key, event);
393 return log_msg_ret("key", ret);
395 /* only allow one menu */
396 ret = scene_menu_arrange(scn, menu);
398 return log_msg_ret("arr", ret);