]> Git Repo - J-u-boot.git/blob - boot/scene.c
expo: Convert to using a string ID for the scene title
[J-u-boot.git] / boot / scene.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Implementation of a scene, a collection of text/image/menu items in an expo
4  *
5  * Copyright 2022 Google LLC
6  * Written by Simon Glass <[email protected]>
7  */
8
9 #include <common.h>
10 #include <dm.h>
11 #include <expo.h>
12 #include <malloc.h>
13 #include <mapmem.h>
14 #include <video.h>
15 #include <video_console.h>
16 #include <linux/input.h>
17 #include "scene_internal.h"
18
19 uint resolve_id(struct expo *exp, uint id)
20 {
21         if (!id)
22                 id = exp->next_id++;
23         else if (id >= exp->next_id)
24                 exp->next_id = id + 1;
25
26         return id;
27 }
28
29 int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
30 {
31         struct scene *scn;
32
33         scn = calloc(1, sizeof(struct scene));
34         if (!scn)
35                 return log_msg_ret("expo", -ENOMEM);
36         scn->name = strdup(name);
37         if (!scn->name) {
38                 free(scn);
39                 return log_msg_ret("name", -ENOMEM);
40         }
41
42         INIT_LIST_HEAD(&scn->obj_head);
43         scn->id = resolve_id(exp, id);
44         scn->expo = exp;
45         list_add_tail(&scn->sibling, &exp->scene_head);
46
47         *scnp = scn;
48
49         return scn->id;
50 }
51
52 void scene_obj_destroy(struct scene_obj *obj)
53 {
54         if (obj->type == SCENEOBJT_MENU)
55                 scene_menu_destroy((struct scene_obj_menu *)obj);
56         free(obj->name);
57         free(obj);
58 }
59
60 void scene_destroy(struct scene *scn)
61 {
62         struct scene_obj *obj, *next;
63
64         list_for_each_entry_safe(obj, next, &scn->obj_head, sibling)
65                 scene_obj_destroy(obj);
66
67         free(scn->name);
68         free(scn);
69 }
70
71 int scene_title_set(struct scene *scn, uint id)
72 {
73         scn->title_id = id;
74
75         return 0;
76 }
77
78 int scene_obj_count(struct scene *scn)
79 {
80         struct scene_obj *obj;
81         int count = 0;
82
83         list_for_each_entry(obj, &scn->obj_head, sibling)
84                 count++;
85
86         return count;
87 }
88
89 void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type)
90 {
91         struct scene_obj *obj;
92
93         list_for_each_entry(obj, &scn->obj_head, sibling) {
94                 if (obj->id == id &&
95                     (type == SCENEOBJT_NONE || obj->type == type))
96                         return obj;
97         }
98
99         return NULL;
100 }
101
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)
104 {
105         struct scene_obj *obj;
106
107         obj = calloc(1, size);
108         if (!obj)
109                 return log_msg_ret("obj", -ENOMEM);
110         obj->name = strdup(name);
111         if (!obj->name) {
112                 free(obj);
113                 return log_msg_ret("name", -ENOMEM);
114         }
115
116         obj->id = resolve_id(scn->expo, id);
117         obj->scene = scn;
118         obj->type = type;
119         list_add_tail(&obj->sibling, &scn->obj_head);
120         *objp = obj;
121
122         return obj->id;
123 }
124
125 int scene_img(struct scene *scn, const char *name, uint id, char *data,
126               struct scene_obj_img **imgp)
127 {
128         struct scene_obj_img *img;
129         int ret;
130
131         ret = scene_obj_add(scn, name, id, SCENEOBJT_IMAGE,
132                             sizeof(struct scene_obj_img),
133                             (struct scene_obj **)&img);
134         if (ret < 0)
135                 return log_msg_ret("obj", -ENOMEM);
136
137         img->data = data;
138
139         if (imgp)
140                 *imgp = img;
141
142         return img->obj.id;
143 }
144
145 int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
146               struct scene_obj_txt **txtp)
147 {
148         struct scene_obj_txt *txt;
149         int ret;
150
151         ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
152                             sizeof(struct scene_obj_txt),
153                             (struct scene_obj **)&txt);
154         if (ret < 0)
155                 return log_msg_ret("obj", -ENOMEM);
156
157         txt->str_id = str_id;
158
159         if (txtp)
160                 *txtp = txt;
161
162         return txt->obj.id;
163 }
164
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)
167 {
168         struct scene_obj_txt *txt;
169         int ret;
170
171         ret = expo_str(scn->expo, name, str_id, str);
172         if (ret < 0)
173                 return log_msg_ret("str", ret);
174         else if (ret != str_id)
175                 return log_msg_ret("id", -EEXIST);
176
177         ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
178                             sizeof(struct scene_obj_txt),
179                             (struct scene_obj **)&txt);
180         if (ret < 0)
181                 return log_msg_ret("obj", -ENOMEM);
182
183         txt->str_id = str_id;
184
185         if (txtp)
186                 *txtp = txt;
187
188         return txt->obj.id;
189 }
190
191 int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
192                        uint font_size)
193 {
194         struct scene_obj_txt *txt;
195
196         txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
197         if (!txt)
198                 return log_msg_ret("find", -ENOENT);
199         txt->font_name = font_name;
200         txt->font_size = font_size;
201
202         return 0;
203 }
204
205 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
206 {
207         struct scene_obj *obj;
208
209         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
210         if (!obj)
211                 return log_msg_ret("find", -ENOENT);
212         obj->x = x;
213         obj->y = y;
214         if (obj->type == SCENEOBJT_MENU)
215                 scene_menu_arrange(scn, (struct scene_obj_menu *)obj);
216
217         return 0;
218 }
219
220 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
221 {
222         struct scene_obj *obj;
223
224         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
225         if (!obj)
226                 return log_msg_ret("find", -ENOENT);
227         obj->hide = hide;
228
229         return 0;
230 }
231
232 int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
233 {
234         struct scene_obj *obj;
235
236         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
237         if (!obj)
238                 return log_msg_ret("find", -ENOENT);
239
240         switch (obj->type) {
241         case SCENEOBJT_NONE:
242         case SCENEOBJT_MENU:
243                 break;
244         case SCENEOBJT_IMAGE: {
245                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
246                 ulong width, height;
247                 uint bpix;
248
249                 video_bmp_get_info(img->data, &width, &height, &bpix);
250                 if (widthp)
251                         *widthp = width;
252                 return height;
253         }
254         case SCENEOBJT_TEXT: {
255                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
256                 struct expo *exp = scn->expo;
257
258                 if (widthp)
259                         *widthp = 16; /* fake value for now */
260                 if (txt->font_size)
261                         return txt->font_size;
262                 if (exp->display)
263                         return video_default_font_height(exp->display);
264
265                 /* use a sensible default */
266                 return 16;
267         }
268         }
269
270         return 0;
271 }
272
273 /**
274  * scene_obj_render() - Render an object
275  *
276  */
277 static int scene_obj_render(struct scene_obj *obj, bool text_mode)
278 {
279         struct scene *scn = obj->scene;
280         struct expo *exp = scn->expo;
281         struct udevice *cons, *dev = exp->display;
282         int x, y, ret;
283
284         cons = NULL;
285         if (!text_mode) {
286                 ret = device_find_first_child_by_uclass(dev,
287                                                         UCLASS_VIDEO_CONSOLE,
288                                                         &cons);
289         }
290
291         x = obj->x;
292         y = obj->y;
293
294         switch (obj->type) {
295         case SCENEOBJT_NONE:
296                 break;
297         case SCENEOBJT_IMAGE: {
298                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
299
300                 if (!cons)
301                         return -ENOTSUPP;
302                 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
303                                         true);
304                 if (ret < 0)
305                         return log_msg_ret("img", ret);
306                 break;
307         }
308         case SCENEOBJT_TEXT: {
309                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
310                 const char *str;
311
312                 if (!cons)
313                         return -ENOTSUPP;
314
315                 if (txt->font_name || txt->font_size) {
316                         ret = vidconsole_select_font(cons,
317                                                      txt->font_name,
318                                                      txt->font_size);
319                 } else {
320                         ret = vidconsole_select_font(cons, NULL, 0);
321                 }
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);
326                 if (str)
327                         vidconsole_put_string(cons, str);
328                 break;
329         }
330         case SCENEOBJT_MENU: {
331                 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
332                 /*
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.
336                  */
337                 if (cons)
338                         return -ENOTSUPP;
339
340                 ret = scene_menu_display(menu);
341                 if (ret < 0)
342                         return log_msg_ret("img", ret);
343
344                 break;
345         }
346         }
347
348         return 0;
349 }
350
351 int scene_arrange(struct scene *scn)
352 {
353         struct scene_obj *obj;
354         int ret;
355
356         list_for_each_entry(obj, &scn->obj_head, sibling) {
357                 if (obj->type == SCENEOBJT_MENU) {
358                         struct scene_obj_menu *menu;
359
360                         menu = (struct scene_obj_menu *)obj,
361                         ret = scene_menu_arrange(scn, menu);
362                         if (ret)
363                                 return log_msg_ret("arr", ret);
364                 }
365         }
366
367         return 0;
368 }
369
370 int scene_render(struct scene *scn)
371 {
372         struct expo *exp = scn->expo;
373         struct scene_obj *obj;
374         int ret;
375
376         list_for_each_entry(obj, &scn->obj_head, sibling) {
377                 if (!obj->hide) {
378                         ret = scene_obj_render(obj, exp->text_mode);
379                         if (ret && ret != -ENOTSUPP)
380                                 return log_msg_ret("ren", ret);
381                 }
382         }
383
384         return 0;
385 }
386
387 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
388 {
389         struct scene_obj *obj;
390         int ret;
391
392         list_for_each_entry(obj, &scn->obj_head, sibling) {
393                 if (obj->type == SCENEOBJT_MENU) {
394                         struct scene_obj_menu *menu;
395
396                         menu = (struct scene_obj_menu *)obj,
397                         ret = scene_menu_send_key(scn, menu, key, event);
398                         if (ret)
399                                 return log_msg_ret("key", ret);
400
401                         /* only allow one menu */
402                         ret = scene_menu_arrange(scn, menu);
403                         if (ret)
404                                 return log_msg_ret("arr", ret);
405                         break;
406                 }
407         }
408
409         return 0;
410 }
This page took 0.049527 seconds and 4 git commands to generate.