]> Git Repo - u-boot.git/blob - boot/scene.c
expo: Set up the width and height of objects
[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 #define LOG_CATEGORY    LOGC_EXPO
10
11 #include <common.h>
12 #include <dm.h>
13 #include <expo.h>
14 #include <malloc.h>
15 #include <mapmem.h>
16 #include <video.h>
17 #include <video_console.h>
18 #include <linux/input.h>
19 #include "scene_internal.h"
20
21 int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
22 {
23         struct scene *scn;
24
25         scn = calloc(1, sizeof(struct scene));
26         if (!scn)
27                 return log_msg_ret("expo", -ENOMEM);
28         scn->name = strdup(name);
29         if (!scn->name) {
30                 free(scn);
31                 return log_msg_ret("name", -ENOMEM);
32         }
33
34         INIT_LIST_HEAD(&scn->obj_head);
35         scn->id = resolve_id(exp, id);
36         scn->expo = exp;
37         list_add_tail(&scn->sibling, &exp->scene_head);
38
39         *scnp = scn;
40
41         return scn->id;
42 }
43
44 void scene_obj_destroy(struct scene_obj *obj)
45 {
46         if (obj->type == SCENEOBJT_MENU)
47                 scene_menu_destroy((struct scene_obj_menu *)obj);
48         free(obj->name);
49         free(obj);
50 }
51
52 void scene_destroy(struct scene *scn)
53 {
54         struct scene_obj *obj, *next;
55
56         list_for_each_entry_safe(obj, next, &scn->obj_head, sibling)
57                 scene_obj_destroy(obj);
58
59         free(scn->name);
60         free(scn);
61 }
62
63 int scene_title_set(struct scene *scn, uint id)
64 {
65         scn->title_id = id;
66
67         return 0;
68 }
69
70 int scene_obj_count(struct scene *scn)
71 {
72         struct scene_obj *obj;
73         int count = 0;
74
75         list_for_each_entry(obj, &scn->obj_head, sibling)
76                 count++;
77
78         return count;
79 }
80
81 void *scene_obj_find(struct scene *scn, uint id, enum scene_obj_t type)
82 {
83         struct scene_obj *obj;
84
85         list_for_each_entry(obj, &scn->obj_head, sibling) {
86                 if (obj->id == id &&
87                     (type == SCENEOBJT_NONE || obj->type == type))
88                         return obj;
89         }
90
91         return NULL;
92 }
93
94 int scene_obj_add(struct scene *scn, const char *name, uint id,
95                   enum scene_obj_t type, uint size, struct scene_obj **objp)
96 {
97         struct scene_obj *obj;
98
99         obj = calloc(1, size);
100         if (!obj)
101                 return log_msg_ret("obj", -ENOMEM);
102         obj->name = strdup(name);
103         if (!obj->name) {
104                 free(obj);
105                 return log_msg_ret("name", -ENOMEM);
106         }
107
108         obj->id = resolve_id(scn->expo, id);
109         obj->scene = scn;
110         obj->type = type;
111         list_add_tail(&obj->sibling, &scn->obj_head);
112         *objp = obj;
113
114         return obj->id;
115 }
116
117 int scene_img(struct scene *scn, const char *name, uint id, char *data,
118               struct scene_obj_img **imgp)
119 {
120         struct scene_obj_img *img;
121         int ret;
122
123         ret = scene_obj_add(scn, name, id, SCENEOBJT_IMAGE,
124                             sizeof(struct scene_obj_img),
125                             (struct scene_obj **)&img);
126         if (ret < 0)
127                 return log_msg_ret("obj", -ENOMEM);
128
129         img->data = data;
130
131         if (imgp)
132                 *imgp = img;
133
134         return img->obj.id;
135 }
136
137 int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
138               struct scene_obj_txt **txtp)
139 {
140         struct scene_obj_txt *txt;
141         int ret;
142
143         ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
144                             sizeof(struct scene_obj_txt),
145                             (struct scene_obj **)&txt);
146         if (ret < 0)
147                 return log_msg_ret("obj", -ENOMEM);
148
149         txt->str_id = str_id;
150
151         if (txtp)
152                 *txtp = txt;
153
154         return txt->obj.id;
155 }
156
157 int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
158                   const char *str, struct scene_obj_txt **txtp)
159 {
160         struct scene_obj_txt *txt;
161         int ret;
162
163         ret = expo_str(scn->expo, name, str_id, str);
164         if (ret < 0)
165                 return log_msg_ret("str", ret);
166         else if (ret != str_id)
167                 return log_msg_ret("id", -EEXIST);
168
169         ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
170                             sizeof(struct scene_obj_txt),
171                             (struct scene_obj **)&txt);
172         if (ret < 0)
173                 return log_msg_ret("obj", -ENOMEM);
174
175         txt->str_id = str_id;
176
177         if (txtp)
178                 *txtp = txt;
179
180         return txt->obj.id;
181 }
182
183 int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
184                        uint font_size)
185 {
186         struct scene_obj_txt *txt;
187
188         txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
189         if (!txt)
190                 return log_msg_ret("find", -ENOENT);
191         txt->font_name = font_name;
192         txt->font_size = font_size;
193
194         return 0;
195 }
196
197 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
198 {
199         struct scene_obj *obj;
200
201         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
202         if (!obj)
203                 return log_msg_ret("find", -ENOENT);
204         obj->dim.x = x;
205         obj->dim.y = y;
206
207         return 0;
208 }
209
210 int scene_obj_set_size(struct scene *scn, uint id, int w, int h)
211 {
212         struct scene_obj *obj;
213
214         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
215         if (!obj)
216                 return log_msg_ret("find", -ENOENT);
217         obj->dim.w = w;
218         obj->dim.h = h;
219
220         return 0;
221 }
222
223 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
224 {
225         int ret;
226
227         ret = scene_obj_flag_clrset(scn, id, SCENEOF_HIDE,
228                                     hide ? SCENEOF_HIDE : 0);
229         if (ret)
230                 return log_msg_ret("flg", ret);
231
232         return 0;
233 }
234
235 int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set)
236 {
237         struct scene_obj *obj;
238
239         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
240         if (!obj)
241                 return log_msg_ret("find", -ENOENT);
242         obj->flags &= ~clr;
243         obj->flags |= set;
244
245         return 0;
246 }
247
248 int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
249 {
250         struct scene_obj *obj;
251
252         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
253         if (!obj)
254                 return log_msg_ret("find", -ENOENT);
255
256         switch (obj->type) {
257         case SCENEOBJT_NONE:
258         case SCENEOBJT_MENU:
259                 break;
260         case SCENEOBJT_IMAGE: {
261                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
262                 ulong width, height;
263                 uint bpix;
264
265                 video_bmp_get_info(img->data, &width, &height, &bpix);
266                 if (widthp)
267                         *widthp = width;
268                 return height;
269         }
270         case SCENEOBJT_TEXT: {
271                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
272                 struct expo *exp = scn->expo;
273                 struct vidconsole_bbox bbox;
274                 const char *str;
275                 int len, ret;
276
277                 str = expo_get_str(exp, txt->str_id);
278                 if (!str)
279                         return log_msg_ret("str", -ENOENT);
280                 len = strlen(str);
281
282                 /* if there is no console, make it up */
283                 if (!exp->cons) {
284                         if (widthp)
285                                 *widthp = 8 * len;
286                         return 16;
287                 }
288
289                 ret = vidconsole_measure(scn->expo->cons, txt->font_name,
290                                          txt->font_size, str, &bbox);
291                 if (ret)
292                         return log_msg_ret("mea", ret);
293                 if (widthp)
294                         *widthp = bbox.x1;
295
296                 return bbox.y1;
297         }
298         }
299
300         return 0;
301 }
302
303 /**
304  * scene_obj_render() - Render an object
305  *
306  */
307 static int scene_obj_render(struct scene_obj *obj, bool text_mode)
308 {
309         struct scene *scn = obj->scene;
310         struct expo *exp = scn->expo;
311         struct udevice *dev = exp->display;
312         struct udevice *cons = text_mode ? NULL : exp->cons;
313         int x, y, ret;
314
315         x = obj->dim.x;
316         y = obj->dim.y;
317
318         switch (obj->type) {
319         case SCENEOBJT_NONE:
320                 break;
321         case SCENEOBJT_IMAGE: {
322                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
323
324                 if (!cons)
325                         return -ENOTSUPP;
326                 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
327                                         true);
328                 if (ret < 0)
329                         return log_msg_ret("img", ret);
330                 break;
331         }
332         case SCENEOBJT_TEXT: {
333                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
334                 const char *str;
335
336                 if (!cons)
337                         return -ENOTSUPP;
338
339                 if (txt->font_name || txt->font_size) {
340                         ret = vidconsole_select_font(cons,
341                                                      txt->font_name,
342                                                      txt->font_size);
343                 } else {
344                         ret = vidconsole_select_font(cons, NULL, 0);
345                 }
346                 if (ret && ret != -ENOSYS)
347                         return log_msg_ret("font", ret);
348                 vidconsole_set_cursor_pos(cons, x, y);
349                 str = expo_get_str(exp, txt->str_id);
350                 if (str)
351                         vidconsole_put_string(cons, str);
352                 break;
353         }
354         case SCENEOBJT_MENU: {
355                 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
356                 /*
357                  * With a vidconsole, the text and item pointer are rendered as
358                  * normal objects so we don't need to do anything here. The menu
359                  * simply controls where they are positioned.
360                  */
361                 if (cons)
362                         return -ENOTSUPP;
363
364                 ret = scene_menu_display(menu);
365                 if (ret < 0)
366                         return log_msg_ret("img", ret);
367
368                 break;
369         }
370         }
371
372         return 0;
373 }
374
375 int scene_arrange(struct scene *scn)
376 {
377         struct scene_obj *obj;
378         int ret;
379
380         list_for_each_entry(obj, &scn->obj_head, sibling) {
381                 if (obj->type == SCENEOBJT_MENU) {
382                         struct scene_obj_menu *menu;
383
384                         menu = (struct scene_obj_menu *)obj,
385                         ret = scene_menu_arrange(scn, menu);
386                         if (ret)
387                                 return log_msg_ret("arr", ret);
388                 }
389         }
390
391         return 0;
392 }
393
394 int scene_render(struct scene *scn)
395 {
396         struct expo *exp = scn->expo;
397         struct scene_obj *obj;
398         int ret;
399
400         list_for_each_entry(obj, &scn->obj_head, sibling) {
401                 if (!(obj->flags & SCENEOF_HIDE)) {
402                         ret = scene_obj_render(obj, exp->text_mode);
403                         if (ret && ret != -ENOTSUPP)
404                                 return log_msg_ret("ren", ret);
405                 }
406         }
407
408         return 0;
409 }
410
411 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
412 {
413         struct scene_obj *obj;
414         int ret;
415
416         list_for_each_entry(obj, &scn->obj_head, sibling) {
417                 if (obj->type == SCENEOBJT_MENU) {
418                         struct scene_obj_menu *menu;
419
420                         menu = (struct scene_obj_menu *)obj,
421                         ret = scene_menu_send_key(scn, menu, key, event);
422                         if (ret)
423                                 return log_msg_ret("key", ret);
424                         break;
425                 }
426         }
427
428         return 0;
429 }
430
431 int scene_calc_dims(struct scene *scn, bool do_menus)
432 {
433         struct scene_obj *obj;
434         int ret;
435
436         list_for_each_entry(obj, &scn->obj_head, sibling) {
437                 switch (obj->type) {
438                 case SCENEOBJT_NONE:
439                 case SCENEOBJT_TEXT:
440                 case SCENEOBJT_IMAGE: {
441                         int width;
442
443                         if (!do_menus) {
444                                 ret = scene_obj_get_hw(scn, obj->id, &width);
445                                 if (ret < 0)
446                                         return log_msg_ret("get", ret);
447                                 obj->dim.w = width;
448                                 obj->dim.h = ret;
449                         }
450                         break;
451                 }
452                 case SCENEOBJT_MENU: {
453                         struct scene_obj_menu *menu;
454
455                         if (do_menus) {
456                                 menu = (struct scene_obj_menu *)obj;
457
458                                 ret = scene_menu_calc_dims(menu);
459                                 if (ret)
460                                         return log_msg_ret("men", ret);
461                         }
462                         break;
463                 }
464                 }
465         }
466
467         return 0;
468 }
This page took 0.055292 seconds and 4 git commands to generate.