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 *cons, *dev = exp->display;
286 ret = device_find_first_child_by_uclass(dev,
287 UCLASS_VIDEO_CONSOLE,
297 case SCENEOBJT_IMAGE: {
298 struct scene_obj_img *img = (struct scene_obj_img *)obj;
302 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
305 return log_msg_ret("img", ret);
308 case SCENEOBJT_TEXT: {
309 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
315 if (txt->font_name || txt->font_size) {
316 ret = vidconsole_select_font(cons,
320 ret = vidconsole_select_font(cons, NULL, 0);
322 if (ret && ret != -ENOSYS)
323 return log_msg_ret("font", ret);
324 vidconsole_set_cursor_pos(cons, x, y);
325 str = expo_get_str(exp, txt->str_id);
327 vidconsole_put_string(cons, str);
330 case SCENEOBJT_MENU: {
331 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
333 * With a vidconsole, the text and item pointer are rendered as
334 * normal objects so we don't need to do anything here. The menu
335 * simply controls where they are positioned.
340 ret = scene_menu_display(menu);
342 return log_msg_ret("img", ret);
351 int scene_arrange(struct scene *scn)
353 struct scene_obj *obj;
356 list_for_each_entry(obj, &scn->obj_head, sibling) {
357 if (obj->type == SCENEOBJT_MENU) {
358 struct scene_obj_menu *menu;
360 menu = (struct scene_obj_menu *)obj,
361 ret = scene_menu_arrange(scn, menu);
363 return log_msg_ret("arr", ret);
370 int scene_render(struct scene *scn)
372 struct expo *exp = scn->expo;
373 struct scene_obj *obj;
376 list_for_each_entry(obj, &scn->obj_head, sibling) {
378 ret = scene_obj_render(obj, exp->text_mode);
379 if (ret && ret != -ENOTSUPP)
380 return log_msg_ret("ren", ret);
387 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
389 struct scene_obj *obj;
392 list_for_each_entry(obj, &scn->obj_head, sibling) {
393 if (obj->type == SCENEOBJT_MENU) {
394 struct scene_obj_menu *menu;
396 menu = (struct scene_obj_menu *)obj,
397 ret = scene_menu_send_key(scn, menu, key, event);
399 return log_msg_ret("key", ret);
401 /* only allow one menu */
402 ret = scene_menu_arrange(scn, menu);
404 return log_msg_ret("arr", ret);