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