"Das U-Boot" Source Tree
at master 932 lines 20 kB view raw
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 <sjg@chromium.org> 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 21int 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 52void 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 60void 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 73int scene_obj_count(struct scene *scn) 74{ 75 return list_count_nodes(&scn->obj_head); 76} 77 78void *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 91void *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 103int 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 126int 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 146int 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 166int 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 193int 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 207int 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 220int 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 233int 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 245int 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 258int 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 */ 321static 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 */ 363static 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 467int 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 510int 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 550int 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 585int 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 */ 617static 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 660int 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 727int 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 753int 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 802int 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 831void scene_set_highlight_id(struct scene *scn, uint id) 832{ 833 scn->highlight_id = id; 834} 835 836void 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 848static 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 869int 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 892int 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 908int 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}