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
6 * Written by Simon Glass <sjg@chromium.org>
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);
72 int scene_title_set(struct scene *scn, const char *title)
75 scn->title = strdup(title);
77 return log_msg_ret("tit", -ENOMEM);
82 int scene_obj_count(struct scene *scn)
84 struct scene_obj *obj;
87 list_for_each_entry(obj, &scn->obj_head, sibling)
93 void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type)
95 struct scene_obj *obj;
97 list_for_each_entry(obj, &scn->obj_head, sibling) {
99 (type == SCENEOBJT_NONE || obj->type == type))
106 int scene_obj_add(struct scene *scn, const char *name, uint id,
107 enum scene_obj_t type, uint size, struct scene_obj **objp)
109 struct scene_obj *obj;
111 obj = calloc(1, size);
113 return log_msg_ret("obj", -ENOMEM);
114 obj->name = strdup(name);
117 return log_msg_ret("name", -ENOMEM);
120 obj->id = resolve_id(scn->expo, id);
123 list_add_tail(&obj->sibling, &scn->obj_head);
129 int scene_img(struct scene *scn, const char *name, uint id, char *data,
130 struct scene_obj_img **imgp)
132 struct scene_obj_img *img;
135 ret = scene_obj_add(scn, name, id, SCENEOBJT_IMAGE,
136 sizeof(struct scene_obj_img),
137 (struct scene_obj **)&img);
139 return log_msg_ret("obj", -ENOMEM);
149 int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
150 struct scene_obj_txt **txtp)
152 struct scene_obj_txt *txt;
155 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
156 sizeof(struct scene_obj_txt),
157 (struct scene_obj **)&txt);
159 return log_msg_ret("obj", -ENOMEM);
161 txt->str_id = str_id;
169 int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
170 const char *str, struct scene_obj_txt **txtp)
172 struct scene_obj_txt *txt;
175 ret = expo_str(scn->expo, name, str_id, str);
177 return log_msg_ret("str", ret);
178 else if (ret != str_id)
179 return log_msg_ret("id", -EEXIST);
181 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
182 sizeof(struct scene_obj_txt),
183 (struct scene_obj **)&txt);
185 return log_msg_ret("obj", -ENOMEM);
187 txt->str_id = str_id;
195 int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
198 struct scene_obj_txt *txt;
200 txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
202 return log_msg_ret("find", -ENOENT);
203 txt->font_name = font_name;
204 txt->font_size = font_size;
209 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
211 struct scene_obj *obj;
213 obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
215 return log_msg_ret("find", -ENOENT);
218 if (obj->type == SCENEOBJT_MENU)
219 scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
224 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
226 struct scene_obj *obj;
228 obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
230 return log_msg_ret("find", -ENOENT);
236 int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
238 struct scene_obj *obj;
240 obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
242 return log_msg_ret("find", -ENOENT);
248 case SCENEOBJT_IMAGE: {
249 struct scene_obj_img *img = (struct scene_obj_img *)obj;
253 video_bmp_get_info(img->data, &width, &height, &bpix);
258 case SCENEOBJT_TEXT: {
259 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
260 struct expo *exp = scn->expo;
263 *widthp = 16; /* fake value for now */
265 return txt->font_size;
267 return video_default_font_height(exp->display);
269 /* use a sensible default */
278 * scene_obj_render() - Render an object
281 static int scene_obj_render(struct scene_obj *obj, bool text_mode)
283 struct scene *scn = obj->scene;
284 struct expo *exp = scn->expo;
285 struct udevice *cons, *dev = exp->display;
290 ret = device_find_first_child_by_uclass(dev,
291 UCLASS_VIDEO_CONSOLE,
301 case SCENEOBJT_IMAGE: {
302 struct scene_obj_img *img = (struct scene_obj_img *)obj;
306 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
309 return log_msg_ret("img", ret);
312 case SCENEOBJT_TEXT: {
313 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
319 if (txt->font_name || txt->font_size) {
320 ret = vidconsole_select_font(cons,
324 ret = vidconsole_select_font(cons, NULL, 0);
326 if (ret && ret != -ENOSYS)
327 return log_msg_ret("font", ret);
328 vidconsole_set_cursor_pos(cons, x, y);
329 str = expo_get_str(exp, txt->str_id);
331 vidconsole_put_string(cons, str);
334 case SCENEOBJT_MENU: {
335 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
337 * With a vidconsole, the text and item pointer are rendered as
338 * normal objects so we don't need to do anything here. The menu
339 * simply controls where they are positioned.
344 ret = scene_menu_display(menu);
346 return log_msg_ret("img", ret);
355 int scene_arrange(struct scene *scn)
357 struct scene_obj *obj;
360 list_for_each_entry(obj, &scn->obj_head, sibling) {
361 if (obj->type == SCENEOBJT_MENU) {
362 struct scene_obj_menu *menu;
364 menu = (struct scene_obj_menu *)obj,
365 ret = scene_menu_arrange(scn, menu);
367 return log_msg_ret("arr", ret);
374 int scene_render(struct scene *scn)
376 struct expo *exp = scn->expo;
377 struct scene_obj *obj;
380 list_for_each_entry(obj, &scn->obj_head, sibling) {
382 ret = scene_obj_render(obj, exp->text_mode);
383 if (ret && ret != -ENOTSUPP)
384 return log_msg_ret("ren", ret);
391 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
393 struct scene_obj *obj;
396 list_for_each_entry(obj, &scn->obj_head, sibling) {
397 if (obj->type == SCENEOBJT_MENU) {
398 struct scene_obj_menu *menu;
400 menu = (struct scene_obj_menu *)obj,
401 ret = scene_menu_send_key(scn, menu, key, event);
403 return log_msg_ret("key", ret);
405 /* only allow one menu */
406 ret = scene_menu_arrange(scn, menu);
408 return log_msg_ret("arr", ret);