]> Git Repo - J-u-boot.git/blob - boot/scene.c
Merge patch series "Enable EFI capsule updates for PHYTEC K3 SoMs"
[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 #define LOG_CATEGORY    LOGC_EXPO
10
11 #include <dm.h>
12 #include <expo.h>
13 #include <malloc.h>
14 #include <mapmem.h>
15 #include <menu.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         abuf_init(&scn->buf);
35         if (!abuf_realloc(&scn->buf, EXPO_MAX_CHARS + 1)) {
36                 free(scn->name);
37                 free(scn);
38                 return log_msg_ret("buf", -ENOMEM);
39         }
40         abuf_init(&scn->entry_save);
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         abuf_uninit(&scn->entry_save);
68         abuf_uninit(&scn->buf);
69         free(scn->name);
70         free(scn);
71 }
72
73 int scene_obj_count(struct scene *scn)
74 {
75         return list_count_nodes(&scn->obj_head);
76 }
77
78 void *scene_obj_find(const struct scene *scn, uint id, enum scene_obj_t type)
79 {
80         struct scene_obj *obj;
81
82         list_for_each_entry(obj, &scn->obj_head, sibling) {
83                 if (obj->id == id &&
84                     (type == SCENEOBJT_NONE || obj->type == type))
85                         return obj;
86         }
87
88         return NULL;
89 }
90
91 void *scene_obj_find_by_name(struct scene *scn, const char *name)
92 {
93         struct scene_obj *obj;
94
95         list_for_each_entry(obj, &scn->obj_head, sibling) {
96                 if (!strcmp(name, obj->name))
97                         return obj;
98         }
99
100         return NULL;
101 }
102
103 int scene_obj_add(struct scene *scn, const char *name, uint id,
104                   enum scene_obj_t type, uint size, struct scene_obj **objp)
105 {
106         struct scene_obj *obj;
107
108         obj = calloc(1, size);
109         if (!obj)
110                 return log_msg_ret("obj", -ENOMEM);
111         obj->name = strdup(name);
112         if (!obj->name) {
113                 free(obj);
114                 return log_msg_ret("name", -ENOMEM);
115         }
116
117         obj->id = resolve_id(scn->expo, id);
118         obj->scene = scn;
119         obj->type = type;
120         list_add_tail(&obj->sibling, &scn->obj_head);
121         *objp = obj;
122
123         return obj->id;
124 }
125
126 int scene_img(struct scene *scn, const char *name, uint id, char *data,
127               struct scene_obj_img **imgp)
128 {
129         struct scene_obj_img *img;
130         int ret;
131
132         ret = scene_obj_add(scn, name, id, SCENEOBJT_IMAGE,
133                             sizeof(struct scene_obj_img),
134                             (struct scene_obj **)&img);
135         if (ret < 0)
136                 return log_msg_ret("obj", ret);
137
138         img->data = data;
139
140         if (imgp)
141                 *imgp = img;
142
143         return img->obj.id;
144 }
145
146 int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
147               struct scene_obj_txt **txtp)
148 {
149         struct scene_obj_txt *txt;
150         int ret;
151
152         ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
153                             sizeof(struct scene_obj_txt),
154                             (struct scene_obj **)&txt);
155         if (ret < 0)
156                 return log_msg_ret("obj", ret);
157
158         txt->str_id = str_id;
159
160         if (txtp)
161                 *txtp = txt;
162
163         return txt->obj.id;
164 }
165
166 int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
167                   const char *str, struct scene_obj_txt **txtp)
168 {
169         struct scene_obj_txt *txt;
170         int ret;
171
172         ret = expo_str(scn->expo, name, str_id, str);
173         if (ret < 0)
174                 return log_msg_ret("str", ret);
175         if (str_id && ret != str_id)
176                 return log_msg_ret("id", -EEXIST);
177         str_id = ret;
178
179         ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
180                             sizeof(struct scene_obj_txt),
181                             (struct scene_obj **)&txt);
182         if (ret < 0)
183                 return log_msg_ret("obj", ret);
184
185         txt->str_id = str_id;
186
187         if (txtp)
188                 *txtp = txt;
189
190         return txt->obj.id;
191 }
192
193 int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
194                        uint font_size)
195 {
196         struct scene_obj_txt *txt;
197
198         txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
199         if (!txt)
200                 return log_msg_ret("find", -ENOENT);
201         txt->font_name = font_name;
202         txt->font_size = font_size;
203
204         return 0;
205 }
206
207 int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
208 {
209         struct scene_obj *obj;
210
211         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
212         if (!obj)
213                 return log_msg_ret("find", -ENOENT);
214         obj->dim.x = x;
215         obj->dim.y = y;
216
217         return 0;
218 }
219
220 int scene_obj_set_size(struct scene *scn, uint id, int w, int h)
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->dim.w = w;
228         obj->dim.h = h;
229
230         return 0;
231 }
232
233 int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
234 {
235         int ret;
236
237         ret = scene_obj_flag_clrset(scn, id, SCENEOF_HIDE,
238                                     hide ? SCENEOF_HIDE : 0);
239         if (ret)
240                 return log_msg_ret("flg", ret);
241
242         return 0;
243 }
244
245 int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set)
246 {
247         struct scene_obj *obj;
248
249         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
250         if (!obj)
251                 return log_msg_ret("find", -ENOENT);
252         obj->flags &= ~clr;
253         obj->flags |= set;
254
255         return 0;
256 }
257
258 int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
259 {
260         struct scene_obj *obj;
261
262         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
263         if (!obj)
264                 return log_msg_ret("find", -ENOENT);
265
266         switch (obj->type) {
267         case SCENEOBJT_NONE:
268         case SCENEOBJT_MENU:
269         case SCENEOBJT_TEXTLINE:
270                 break;
271         case SCENEOBJT_IMAGE: {
272                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
273                 ulong width, height;
274                 uint bpix;
275
276                 video_bmp_get_info(img->data, &width, &height, &bpix);
277                 if (widthp)
278                         *widthp = width;
279                 return height;
280         }
281         case SCENEOBJT_TEXT: {
282                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
283                 struct expo *exp = scn->expo;
284                 struct vidconsole_bbox bbox;
285                 const char *str;
286                 int len, ret;
287
288                 str = expo_get_str(exp, txt->str_id);
289                 if (!str)
290                         return log_msg_ret("str", -ENOENT);
291                 len = strlen(str);
292
293                 /* if there is no console, make it up */
294                 if (!exp->cons) {
295                         if (widthp)
296                                 *widthp = 8 * len;
297                         return 16;
298                 }
299
300                 ret = vidconsole_measure(scn->expo->cons, txt->font_name,
301                                          txt->font_size, str, &bbox);
302                 if (ret)
303                         return log_msg_ret("mea", ret);
304                 if (widthp)
305                         *widthp = bbox.x1;
306
307                 return bbox.y1;
308         }
309         }
310
311         return 0;
312 }
313
314 /**
315  * scene_render_background() - Render the background for an object
316  *
317  * @obj: Object to render
318  * @box_only: true to show a box around the object, but keep the normal
319  * background colour inside
320  */
321 static void scene_render_background(struct scene_obj *obj, bool box_only)
322 {
323         struct expo *exp = obj->scene->expo;
324         const struct expo_theme *theme = &exp->theme;
325         struct vidconsole_bbox bbox, label_bbox;
326         struct udevice *dev = exp->display;
327         struct video_priv *vid_priv;
328         struct udevice *cons = exp->cons;
329         struct vidconsole_colour old;
330         enum colour_idx fore, back;
331         uint inset = theme->menu_inset;
332
333         /* draw a background for the object */
334         if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
335                 fore = VID_DARK_GREY;
336                 back = VID_WHITE;
337         } else {
338                 fore = VID_LIGHT_GRAY;
339                 back = VID_BLACK;
340         }
341
342         /* see if this object wants to render a background */
343         if (scene_obj_calc_bbox(obj, &bbox, &label_bbox))
344                 return;
345
346         vidconsole_push_colour(cons, fore, back, &old);
347         vid_priv = dev_get_uclass_priv(dev);
348         video_fill_part(dev, label_bbox.x0 - inset, label_bbox.y0 - inset,
349                         label_bbox.x1 + inset, label_bbox.y1 + inset,
350                         vid_priv->colour_fg);
351         vidconsole_pop_colour(cons, &old);
352         if (box_only) {
353                 video_fill_part(dev, label_bbox.x0, label_bbox.y0,
354                                 label_bbox.x1, label_bbox.y1,
355                                 vid_priv->colour_bg);
356         }
357 }
358
359 /**
360  * scene_obj_render() - Render an object
361  *
362  */
363 static int scene_obj_render(struct scene_obj *obj, bool text_mode)
364 {
365         struct scene *scn = obj->scene;
366         struct expo *exp = scn->expo;
367         const struct expo_theme *theme = &exp->theme;
368         struct udevice *dev = exp->display;
369         struct udevice *cons = text_mode ? NULL : exp->cons;
370         int x, y, ret;
371
372         x = obj->dim.x;
373         y = obj->dim.y;
374
375         switch (obj->type) {
376         case SCENEOBJT_NONE:
377                 break;
378         case SCENEOBJT_IMAGE: {
379                 struct scene_obj_img *img = (struct scene_obj_img *)obj;
380
381                 if (!cons)
382                         return -ENOTSUPP;
383                 ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
384                                         true);
385                 if (ret < 0)
386                         return log_msg_ret("img", ret);
387                 break;
388         }
389         case SCENEOBJT_TEXT: {
390                 struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
391                 const char *str;
392
393                 if (!cons)
394                         return -ENOTSUPP;
395
396                 if (txt->font_name || txt->font_size) {
397                         ret = vidconsole_select_font(cons,
398                                                      txt->font_name,
399                                                      txt->font_size);
400                 } else {
401                         ret = vidconsole_select_font(cons, NULL, 0);
402                 }
403                 if (ret && ret != -ENOSYS)
404                         return log_msg_ret("font", ret);
405                 str = expo_get_str(exp, txt->str_id);
406                 if (str) {
407                         struct video_priv *vid_priv;
408                         struct vidconsole_colour old;
409                         enum colour_idx fore, back;
410
411                         if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
412                                 fore = VID_BLACK;
413                                 back = VID_WHITE;
414                         } else {
415                                 fore = VID_LIGHT_GRAY;
416                                 back = VID_BLACK;
417                         }
418
419                         vid_priv = dev_get_uclass_priv(dev);
420                         if (obj->flags & SCENEOF_POINT) {
421                                 vidconsole_push_colour(cons, fore, back, &old);
422                                 video_fill_part(dev, x - theme->menu_inset, y,
423                                                 x + obj->dim.w,
424                                                 y + obj->dim.h,
425                                                 vid_priv->colour_bg);
426                         }
427                         vidconsole_set_cursor_pos(cons, x, y);
428                         vidconsole_put_string(cons, str);
429                         if (obj->flags & SCENEOF_POINT)
430                                 vidconsole_pop_colour(cons, &old);
431                 }
432                 break;
433         }
434         case SCENEOBJT_MENU: {
435                 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
436
437                 if (exp->popup && (obj->flags & SCENEOF_OPEN)) {
438                         if (!cons)
439                                 return -ENOTSUPP;
440
441                         /* draw a background behind the menu items */
442                         scene_render_background(obj, false);
443                 }
444                 /*
445                  * With a vidconsole, the text and item pointer are rendered as
446                  * normal objects so we don't need to do anything here. The menu
447                  * simply controls where they are positioned.
448                  */
449                 if (cons)
450                         return -ENOTSUPP;
451
452                 ret = scene_menu_display(menu);
453                 if (ret < 0)
454                         return log_msg_ret("img", ret);
455
456                 break;
457         }
458         case SCENEOBJT_TEXTLINE:
459                 if (obj->flags & SCENEOF_OPEN)
460                         scene_render_background(obj, true);
461                 break;
462         }
463
464         return 0;
465 }
466
467 int scene_calc_arrange(struct scene *scn, struct expo_arrange_info *arr)
468 {
469         struct scene_obj *obj;
470
471         arr->label_width = 0;
472         list_for_each_entry(obj, &scn->obj_head, sibling) {
473                 uint label_id = 0;
474                 int width;
475
476                 switch (obj->type) {
477                 case SCENEOBJT_NONE:
478                 case SCENEOBJT_IMAGE:
479                 case SCENEOBJT_TEXT:
480                         break;
481                 case SCENEOBJT_MENU: {
482                         struct scene_obj_menu *menu;
483
484                         menu = (struct scene_obj_menu *)obj,
485                         label_id = menu->title_id;
486                         break;
487                 }
488                 case SCENEOBJT_TEXTLINE: {
489                         struct scene_obj_textline *tline;
490
491                         tline = (struct scene_obj_textline *)obj,
492                         label_id = tline->label_id;
493                         break;
494                 }
495                 }
496
497                 if (label_id) {
498                         int ret;
499
500                         ret = scene_obj_get_hw(scn, label_id, &width);
501                         if (ret < 0)
502                                 return log_msg_ret("hei", ret);
503                         arr->label_width = max(arr->label_width, width);
504                 }
505         }
506
507         return 0;
508 }
509
510 int scene_arrange(struct scene *scn)
511 {
512         struct expo_arrange_info arr;
513         struct scene_obj *obj;
514         int ret;
515
516         ret = scene_calc_arrange(scn, &arr);
517         if (ret < 0)
518                 return log_msg_ret("arr", ret);
519
520         list_for_each_entry(obj, &scn->obj_head, sibling) {
521                 switch (obj->type) {
522                 case SCENEOBJT_NONE:
523                 case SCENEOBJT_IMAGE:
524                 case SCENEOBJT_TEXT:
525                         break;
526                 case SCENEOBJT_MENU: {
527                         struct scene_obj_menu *menu;
528
529                         menu = (struct scene_obj_menu *)obj,
530                         ret = scene_menu_arrange(scn, &arr, menu);
531                         if (ret)
532                                 return log_msg_ret("arr", ret);
533                         break;
534                 }
535                 case SCENEOBJT_TEXTLINE: {
536                         struct scene_obj_textline *tline;
537
538                         tline = (struct scene_obj_textline *)obj,
539                         ret = scene_textline_arrange(scn, &arr, tline);
540                         if (ret)
541                                 return log_msg_ret("arr", ret);
542                         break;
543                 }
544                 }
545         }
546
547         return 0;
548 }
549
550 int scene_render_deps(struct scene *scn, uint id)
551 {
552         struct scene_obj *obj;
553         int ret;
554
555         if (!id)
556                 return 0;
557         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
558         if (!obj)
559                 return log_msg_ret("obj", -ENOENT);
560
561         if (!(obj->flags & SCENEOF_HIDE)) {
562                 ret = scene_obj_render(obj, false);
563                 if (ret && ret != -ENOTSUPP)
564                         return log_msg_ret("ren", ret);
565
566                 switch (obj->type) {
567                 case SCENEOBJT_NONE:
568                 case SCENEOBJT_IMAGE:
569                 case SCENEOBJT_TEXT:
570                         break;
571                 case SCENEOBJT_MENU:
572                         scene_menu_render_deps(scn,
573                                                (struct scene_obj_menu *)obj);
574                         break;
575                 case SCENEOBJT_TEXTLINE:
576                         scene_textline_render_deps(scn,
577                                         (struct scene_obj_textline *)obj);
578                         break;
579                 }
580         }
581
582         return 0;
583 }
584
585 int scene_render(struct scene *scn)
586 {
587         struct expo *exp = scn->expo;
588         struct scene_obj *obj;
589         int ret;
590
591         list_for_each_entry(obj, &scn->obj_head, sibling) {
592                 if (!(obj->flags & SCENEOF_HIDE)) {
593                         ret = scene_obj_render(obj, exp->text_mode);
594                         if (ret && ret != -ENOTSUPP)
595                                 return log_msg_ret("ren", ret);
596                 }
597         }
598
599         /* render any highlighted object on top of the others */
600         if (scn->highlight_id && !exp->text_mode) {
601                 ret = scene_render_deps(scn, scn->highlight_id);
602                 if (ret && ret != -ENOTSUPP)
603                         return log_msg_ret("dep", ret);
604         }
605
606         return 0;
607 }
608
609 /**
610  * send_key_obj() - Handle a keypress for moving between objects
611  *
612  * @scn: Scene to receive the key
613  * @key: Key to send (KEYCODE_UP)
614  * @event: Returns resulting event from this keypress
615  * Returns: 0 if OK, -ve on error
616  */
617 static void send_key_obj(struct scene *scn, struct scene_obj *obj, int key,
618                          struct expo_action *event)
619 {
620         switch (key) {
621         case BKEY_UP:
622                 while (obj != list_first_entry(&scn->obj_head, struct scene_obj,
623                                                sibling)) {
624                         obj = list_entry(obj->sibling.prev,
625                                          struct scene_obj, sibling);
626                         if (scene_obj_can_highlight(obj)) {
627                                 event->type = EXPOACT_POINT_OBJ;
628                                 event->select.id = obj->id;
629                                 log_debug("up to obj %d\n", event->select.id);
630                                 break;
631                         }
632                 }
633                 break;
634         case BKEY_DOWN:
635                 while (!list_is_last(&obj->sibling, &scn->obj_head)) {
636                         obj = list_entry(obj->sibling.next, struct scene_obj,
637                                          sibling);
638                         if (scene_obj_can_highlight(obj)) {
639                                 event->type = EXPOACT_POINT_OBJ;
640                                 event->select.id = obj->id;
641                                 log_debug("down to obj %d\n", event->select.id);
642                                 break;
643                         }
644                 }
645                 break;
646         case BKEY_SELECT:
647                 if (scene_obj_can_highlight(obj)) {
648                         event->type = EXPOACT_OPEN;
649                         event->select.id = obj->id;
650                         log_debug("open obj %d\n", event->select.id);
651                 }
652                 break;
653         case BKEY_QUIT:
654                 event->type = EXPOACT_QUIT;
655                 log_debug("obj quit\n");
656                 break;
657         }
658 }
659
660 int scene_send_key(struct scene *scn, int key, struct expo_action *event)
661 {
662         struct scene_obj *obj;
663         int ret;
664
665         event->type = EXPOACT_NONE;
666
667         /*
668          * In 'popup' mode, arrow keys move betwen objects, unless a menu is
669          * opened
670          */
671         if (scn->expo->popup) {
672                 obj = NULL;
673                 if (scn->highlight_id) {
674                         obj = scene_obj_find(scn, scn->highlight_id,
675                                              SCENEOBJT_NONE);
676                 }
677                 if (!obj)
678                         return 0;
679
680                 if (!(obj->flags & SCENEOF_OPEN)) {
681                         send_key_obj(scn, obj, key, event);
682                         return 0;
683                 }
684
685                 switch (obj->type) {
686                 case SCENEOBJT_NONE:
687                 case SCENEOBJT_IMAGE:
688                 case SCENEOBJT_TEXT:
689                         break;
690                 case SCENEOBJT_MENU: {
691                         struct scene_obj_menu *menu;
692
693                         menu = (struct scene_obj_menu *)obj,
694                         ret = scene_menu_send_key(scn, menu, key, event);
695                         if (ret)
696                                 return log_msg_ret("key", ret);
697                         break;
698                 }
699                 case SCENEOBJT_TEXTLINE: {
700                         struct scene_obj_textline *tline;
701
702                         tline = (struct scene_obj_textline *)obj,
703                         ret = scene_textline_send_key(scn, tline, key, event);
704                         if (ret)
705                                 return log_msg_ret("key", ret);
706                         break;
707                 }
708                 }
709                 return 0;
710         }
711
712         list_for_each_entry(obj, &scn->obj_head, sibling) {
713                 if (obj->type == SCENEOBJT_MENU) {
714                         struct scene_obj_menu *menu;
715
716                         menu = (struct scene_obj_menu *)obj,
717                         ret = scene_menu_send_key(scn, menu, key, event);
718                         if (ret)
719                                 return log_msg_ret("key", ret);
720                         break;
721                 }
722         }
723
724         return 0;
725 }
726
727 int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox *bbox,
728                         struct vidconsole_bbox *label_bbox)
729 {
730         switch (obj->type) {
731         case SCENEOBJT_NONE:
732         case SCENEOBJT_IMAGE:
733         case SCENEOBJT_TEXT:
734                 return -ENOSYS;
735         case SCENEOBJT_MENU: {
736                 struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
737
738                 scene_menu_calc_bbox(menu, bbox, label_bbox);
739                 break;
740         }
741         case SCENEOBJT_TEXTLINE: {
742                 struct scene_obj_textline *tline;
743
744                 tline = (struct scene_obj_textline *)obj;
745                 scene_textline_calc_bbox(tline, bbox, label_bbox);
746                 break;
747         }
748         }
749
750         return 0;
751 }
752
753 int scene_calc_dims(struct scene *scn, bool do_menus)
754 {
755         struct scene_obj *obj;
756         int ret;
757
758         list_for_each_entry(obj, &scn->obj_head, sibling) {
759                 switch (obj->type) {
760                 case SCENEOBJT_NONE:
761                 case SCENEOBJT_TEXT:
762                 case SCENEOBJT_IMAGE: {
763                         int width;
764
765                         if (!do_menus) {
766                                 ret = scene_obj_get_hw(scn, obj->id, &width);
767                                 if (ret < 0)
768                                         return log_msg_ret("get", ret);
769                                 obj->dim.w = width;
770                                 obj->dim.h = ret;
771                         }
772                         break;
773                 }
774                 case SCENEOBJT_MENU: {
775                         struct scene_obj_menu *menu;
776
777                         if (do_menus) {
778                                 menu = (struct scene_obj_menu *)obj;
779
780                                 ret = scene_menu_calc_dims(menu);
781                                 if (ret)
782                                         return log_msg_ret("men", ret);
783                         }
784                         break;
785                 }
786                 case SCENEOBJT_TEXTLINE: {
787                         struct scene_obj_textline *tline;
788
789                         tline = (struct scene_obj_textline *)obj;
790                         ret = scene_textline_calc_dims(tline);
791                         if (ret)
792                                 return log_msg_ret("men", ret);
793
794                         break;
795                 }
796                 }
797         }
798
799         return 0;
800 }
801
802 int scene_apply_theme(struct scene *scn, struct expo_theme *theme)
803 {
804         struct scene_obj *obj;
805         int ret;
806
807         /* Avoid error-checking optional items */
808         scene_txt_set_font(scn, scn->title_id, NULL, theme->font_size);
809
810         list_for_each_entry(obj, &scn->obj_head, sibling) {
811                 switch (obj->type) {
812                 case SCENEOBJT_NONE:
813                 case SCENEOBJT_IMAGE:
814                 case SCENEOBJT_MENU:
815                 case SCENEOBJT_TEXTLINE:
816                         break;
817                 case SCENEOBJT_TEXT:
818                         scene_txt_set_font(scn, obj->id, NULL,
819                                            theme->font_size);
820                         break;
821                 }
822         }
823
824         ret = scene_arrange(scn);
825         if (ret)
826                 return log_msg_ret("arr", ret);
827
828         return 0;
829 }
830
831 void scene_set_highlight_id(struct scene *scn, uint id)
832 {
833         scn->highlight_id = id;
834 }
835
836 void scene_highlight_first(struct scene *scn)
837 {
838         struct scene_obj *obj;
839
840         list_for_each_entry(obj, &scn->obj_head, sibling) {
841                 if (scene_obj_can_highlight(obj)) {
842                         scene_set_highlight_id(scn, obj->id);
843                         return;
844                 }
845         }
846 }
847
848 static int scene_obj_open(struct scene *scn, struct scene_obj *obj)
849 {
850         int ret;
851
852         switch (obj->type) {
853         case SCENEOBJT_NONE:
854         case SCENEOBJT_IMAGE:
855         case SCENEOBJT_MENU:
856         case SCENEOBJT_TEXT:
857                 break;
858         case SCENEOBJT_TEXTLINE:
859                 ret = scene_textline_open(scn,
860                                           (struct scene_obj_textline *)obj);
861                 if (ret)
862                         return log_msg_ret("op", ret);
863                 break;
864         }
865
866         return 0;
867 }
868
869 int scene_set_open(struct scene *scn, uint id, bool open)
870 {
871         struct scene_obj *obj;
872         int ret;
873
874         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
875         if (!obj)
876                 return log_msg_ret("find", -ENOENT);
877
878         if (open) {
879                 ret = scene_obj_open(scn, obj);
880                 if (ret)
881                         return log_msg_ret("op", ret);
882         }
883
884         ret = scene_obj_flag_clrset(scn, id, SCENEOF_OPEN,
885                                     open ? SCENEOF_OPEN : 0);
886         if (ret)
887                 return log_msg_ret("flg", ret);
888
889         return 0;
890 }
891
892 int scene_iter_objs(struct scene *scn, expo_scene_obj_iterator iter,
893                     void *priv)
894 {
895         struct scene_obj *obj;
896
897         list_for_each_entry(obj, &scn->obj_head, sibling) {
898                 int ret;
899
900                 ret = iter(obj, priv);
901                 if (ret)
902                         return log_msg_ret("itr", ret);
903         }
904
905         return 0;
906 }
907
908 int scene_bbox_union(struct scene *scn, uint id, int inset,
909                      struct vidconsole_bbox *bbox)
910 {
911         struct scene_obj *obj;
912
913         if (!id)
914                 return 0;
915         obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
916         if (!obj)
917                 return log_msg_ret("obj", -ENOENT);
918         if (bbox->valid) {
919                 bbox->x0 = min(bbox->x0, obj->dim.x - inset);
920                 bbox->y0 = min(bbox->y0, obj->dim.y);
921                 bbox->x1 = max(bbox->x1, obj->dim.x + obj->dim.w + inset);
922                 bbox->y1 = max(bbox->y1, obj->dim.y + obj->dim.h);
923         } else {
924                 bbox->x0 = obj->dim.x - inset;
925                 bbox->y0 = obj->dim.y;
926                 bbox->x1 = obj->dim.x + obj->dim.w + inset;
927                 bbox->y1 = obj->dim.y + obj->dim.h;
928                 bbox->valid = true;
929         }
930
931         return 0;
932 }
This page took 0.075842 seconds and 4 git commands to generate.