]> Git Repo - J-u-boot.git/blob - boot/scene.c
expo: Store the console in the expo
[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 *dev = exp->display;
282         struct udevice *cons = text_mode ? NULL : exp->cons;
283         int x, y, ret;
284
285         x = obj->x;
286         y = obj->y;
287
288         switch (obj->type) {
289         case SCENEOBJT_NONE:
290                 break;
291         case SCENEOBJT_IMAGE: {
292                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
293
294                 if (!cons)
295                         return -ENOTSUPP;
296                 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
297                                         true);
298                 if (ret < 0)
299                         return log_msg_ret("img", ret);
300                 break;
301         }
302         case SCENEOBJT_TEXT: {
303                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
304                 const char *str;
305
306                 if (!cons)
307                         return -ENOTSUPP;
308
309                 if (txt->font_name || txt->font_size) {
310                         ret = vidconsole_select_font(cons,
311                                                      txt->font_name,
312                                                      txt->font_size);
313                 } else {
314                         ret = vidconsole_select_font(cons, NULL, 0);
315                 }
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);
320                 if (str)
321                         vidconsole_put_string(cons, str);
322                 break;
323         }
324         case SCENEOBJT_MENU: {
325                 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
326                 /*
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.
330                  */
331                 if (cons)
332                         return -ENOTSUPP;
333
334                 ret = scene_menu_display(menu);
335                 if (ret < 0)
336                         return log_msg_ret("img", ret);
337
338                 break;
339         }
340         }
341
342         return 0;
343 }
344
345 int scene_arrange(struct scene *scn)
346 {
347         struct scene_obj *obj;
348         int ret;
349
350         list_for_each_entry(obj, &scn->obj_head, sibling) {
351                 if (obj->type == SCENEOBJT_MENU) {
352                         struct scene_obj_menu *menu;
353
354                         menu = (struct scene_obj_menu *)obj,
355                         ret = scene_menu_arrange(scn, menu);
356                         if (ret)
357                                 return log_msg_ret("arr", ret);
358                 }
359         }
360
361         return 0;
362 }
363
364 int scene_render(struct scene *scn)
365 {
366         struct expo *exp = scn->expo;
367         struct scene_obj *obj;
368         int ret;
369
370         list_for_each_entry(obj, &scn->obj_head, sibling) {
371                 if (!obj->hide) {
372                         ret = scene_obj_render(obj, exp->text_mode);
373                         if (ret && ret != -ENOTSUPP)
374                                 return log_msg_ret("ren", ret);
375                 }
376         }
377
378         return 0;
379 }
380
381 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
382 {
383         struct scene_obj *obj;
384         int ret;
385
386         list_for_each_entry(obj, &scn->obj_head, sibling) {
387                 if (obj->type == SCENEOBJT_MENU) {
388                         struct scene_obj_menu *menu;
389
390                         menu = (struct scene_obj_menu *)obj,
391                         ret = scene_menu_send_key(scn, menu, key, event);
392                         if (ret)
393                                 return log_msg_ret("key", ret);
394
395                         /* only allow one menu */
396                         ret = scene_menu_arrange(scn, menu);
397                         if (ret)
398                                 return log_msg_ret("arr", ret);
399                         break;
400                 }
401         }
402
403         return 0;
404 }
This page took 0.049435 seconds and 4 git commands to generate.