scene.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  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. #define LOG_CATEGORY LOGC_EXPO
  9. #include <common.h>
  10. #include <dm.h>
  11. #include <expo.h>
  12. #include <malloc.h>
  13. #include <mapmem.h>
  14. #include <menu.h>
  15. #include <video.h>
  16. #include <video_console.h>
  17. #include <linux/input.h>
  18. #include "scene_internal.h"
  19. int scene_new(struct expo *exp, const char *name, uint id, struct scene **scnp)
  20. {
  21. struct scene *scn;
  22. scn = calloc(1, sizeof(struct scene));
  23. if (!scn)
  24. return log_msg_ret("expo", -ENOMEM);
  25. scn->name = strdup(name);
  26. if (!scn->name) {
  27. free(scn);
  28. return log_msg_ret("name", -ENOMEM);
  29. }
  30. abuf_init(&scn->buf);
  31. if (!abuf_realloc(&scn->buf, EXPO_MAX_CHARS + 1)) {
  32. free(scn->name);
  33. free(scn);
  34. return log_msg_ret("buf", -ENOMEM);
  35. }
  36. abuf_init(&scn->entry_save);
  37. INIT_LIST_HEAD(&scn->obj_head);
  38. scn->id = resolve_id(exp, id);
  39. scn->expo = exp;
  40. list_add_tail(&scn->sibling, &exp->scene_head);
  41. *scnp = scn;
  42. return scn->id;
  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. void scene_destroy(struct scene *scn)
  52. {
  53. struct scene_obj *obj, *next;
  54. list_for_each_entry_safe(obj, next, &scn->obj_head, sibling)
  55. scene_obj_destroy(obj);
  56. abuf_uninit(&scn->entry_save);
  57. abuf_uninit(&scn->buf);
  58. free(scn->name);
  59. free(scn);
  60. }
  61. int scene_title_set(struct scene *scn, uint id)
  62. {
  63. scn->title_id = id;
  64. return 0;
  65. }
  66. int scene_obj_count(struct scene *scn)
  67. {
  68. struct scene_obj *obj;
  69. int count = 0;
  70. list_for_each_entry(obj, &scn->obj_head, sibling)
  71. count++;
  72. return count;
  73. }
  74. void *scene_obj_find(const struct scene *scn, uint id, enum scene_obj_t type)
  75. {
  76. struct scene_obj *obj;
  77. list_for_each_entry(obj, &scn->obj_head, sibling) {
  78. if (obj->id == id &&
  79. (type == SCENEOBJT_NONE || obj->type == type))
  80. return obj;
  81. }
  82. return NULL;
  83. }
  84. void *scene_obj_find_by_name(struct scene *scn, const char *name)
  85. {
  86. struct scene_obj *obj;
  87. list_for_each_entry(obj, &scn->obj_head, sibling) {
  88. if (!strcmp(name, obj->name))
  89. return obj;
  90. }
  91. return NULL;
  92. }
  93. int scene_obj_add(struct scene *scn, const char *name, uint id,
  94. enum scene_obj_t type, uint size, struct scene_obj **objp)
  95. {
  96. struct scene_obj *obj;
  97. obj = calloc(1, size);
  98. if (!obj)
  99. return log_msg_ret("obj", -ENOMEM);
  100. obj->name = strdup(name);
  101. if (!obj->name) {
  102. free(obj);
  103. return log_msg_ret("name", -ENOMEM);
  104. }
  105. obj->id = resolve_id(scn->expo, id);
  106. obj->scene = scn;
  107. obj->type = type;
  108. list_add_tail(&obj->sibling, &scn->obj_head);
  109. *objp = obj;
  110. return obj->id;
  111. }
  112. int scene_img(struct scene *scn, const char *name, uint id, char *data,
  113. struct scene_obj_img **imgp)
  114. {
  115. struct scene_obj_img *img;
  116. int ret;
  117. ret = scene_obj_add(scn, name, id, SCENEOBJT_IMAGE,
  118. sizeof(struct scene_obj_img),
  119. (struct scene_obj **)&img);
  120. if (ret < 0)
  121. return log_msg_ret("obj", ret);
  122. img->data = data;
  123. if (imgp)
  124. *imgp = img;
  125. return img->obj.id;
  126. }
  127. int scene_txt(struct scene *scn, const char *name, uint id, uint str_id,
  128. struct scene_obj_txt **txtp)
  129. {
  130. struct scene_obj_txt *txt;
  131. int ret;
  132. ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
  133. sizeof(struct scene_obj_txt),
  134. (struct scene_obj **)&txt);
  135. if (ret < 0)
  136. return log_msg_ret("obj", ret);
  137. txt->str_id = str_id;
  138. if (txtp)
  139. *txtp = txt;
  140. return txt->obj.id;
  141. }
  142. int scene_txt_str(struct scene *scn, const char *name, uint id, uint str_id,
  143. const char *str, struct scene_obj_txt **txtp)
  144. {
  145. struct scene_obj_txt *txt;
  146. int ret;
  147. ret = expo_str(scn->expo, name, str_id, str);
  148. if (ret < 0)
  149. return log_msg_ret("str", ret);
  150. if (str_id && ret != str_id)
  151. return log_msg_ret("id", -EEXIST);
  152. str_id = ret;
  153. ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXT,
  154. sizeof(struct scene_obj_txt),
  155. (struct scene_obj **)&txt);
  156. if (ret < 0)
  157. return log_msg_ret("obj", ret);
  158. txt->str_id = str_id;
  159. if (txtp)
  160. *txtp = txt;
  161. return txt->obj.id;
  162. }
  163. int scene_txt_set_font(struct scene *scn, uint id, const char *font_name,
  164. uint font_size)
  165. {
  166. struct scene_obj_txt *txt;
  167. txt = scene_obj_find(scn, id, SCENEOBJT_TEXT);
  168. if (!txt)
  169. return log_msg_ret("find", -ENOENT);
  170. txt->font_name = font_name;
  171. txt->font_size = font_size;
  172. return 0;
  173. }
  174. int scene_obj_set_pos(struct scene *scn, uint id, int x, int y)
  175. {
  176. struct scene_obj *obj;
  177. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  178. if (!obj)
  179. return log_msg_ret("find", -ENOENT);
  180. obj->dim.x = x;
  181. obj->dim.y = y;
  182. return 0;
  183. }
  184. int scene_obj_set_size(struct scene *scn, uint id, int w, int h)
  185. {
  186. struct scene_obj *obj;
  187. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  188. if (!obj)
  189. return log_msg_ret("find", -ENOENT);
  190. obj->dim.w = w;
  191. obj->dim.h = h;
  192. return 0;
  193. }
  194. int scene_obj_set_hide(struct scene *scn, uint id, bool hide)
  195. {
  196. int ret;
  197. ret = scene_obj_flag_clrset(scn, id, SCENEOF_HIDE,
  198. hide ? SCENEOF_HIDE : 0);
  199. if (ret)
  200. return log_msg_ret("flg", ret);
  201. return 0;
  202. }
  203. int scene_obj_flag_clrset(struct scene *scn, uint id, uint clr, uint set)
  204. {
  205. struct scene_obj *obj;
  206. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  207. if (!obj)
  208. return log_msg_ret("find", -ENOENT);
  209. obj->flags &= ~clr;
  210. obj->flags |= set;
  211. return 0;
  212. }
  213. int scene_obj_get_hw(struct scene *scn, uint id, int *widthp)
  214. {
  215. struct scene_obj *obj;
  216. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  217. if (!obj)
  218. return log_msg_ret("find", -ENOENT);
  219. switch (obj->type) {
  220. case SCENEOBJT_NONE:
  221. case SCENEOBJT_MENU:
  222. case SCENEOBJT_TEXTLINE:
  223. break;
  224. case SCENEOBJT_IMAGE: {
  225. struct scene_obj_img *img = (struct scene_obj_img *)obj;
  226. ulong width, height;
  227. uint bpix;
  228. video_bmp_get_info(img->data, &width, &height, &bpix);
  229. if (widthp)
  230. *widthp = width;
  231. return height;
  232. }
  233. case SCENEOBJT_TEXT: {
  234. struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
  235. struct expo *exp = scn->expo;
  236. struct vidconsole_bbox bbox;
  237. const char *str;
  238. int len, ret;
  239. str = expo_get_str(exp, txt->str_id);
  240. if (!str)
  241. return log_msg_ret("str", -ENOENT);
  242. len = strlen(str);
  243. /* if there is no console, make it up */
  244. if (!exp->cons) {
  245. if (widthp)
  246. *widthp = 8 * len;
  247. return 16;
  248. }
  249. ret = vidconsole_measure(scn->expo->cons, txt->font_name,
  250. txt->font_size, str, &bbox);
  251. if (ret)
  252. return log_msg_ret("mea", ret);
  253. if (widthp)
  254. *widthp = bbox.x1;
  255. return bbox.y1;
  256. }
  257. }
  258. return 0;
  259. }
  260. /**
  261. * scene_render_background() - Render the background for an object
  262. *
  263. * @obj: Object to render
  264. * @box_only: true to show a box around the object, but keep the normal
  265. * background colour inside
  266. */
  267. static void scene_render_background(struct scene_obj *obj, bool box_only)
  268. {
  269. struct expo *exp = obj->scene->expo;
  270. const struct expo_theme *theme = &exp->theme;
  271. struct vidconsole_bbox bbox, label_bbox;
  272. struct udevice *dev = exp->display;
  273. struct video_priv *vid_priv;
  274. struct udevice *cons = exp->cons;
  275. struct vidconsole_colour old;
  276. enum colour_idx fore, back;
  277. uint inset = theme->menu_inset;
  278. /* draw a background for the object */
  279. if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
  280. fore = VID_BLACK;
  281. back = VID_WHITE;
  282. } else {
  283. fore = VID_LIGHT_GRAY;
  284. back = VID_BLACK;
  285. }
  286. /* see if this object wants to render a background */
  287. if (scene_obj_calc_bbox(obj, &bbox, &label_bbox))
  288. return;
  289. vidconsole_push_colour(cons, fore, back, &old);
  290. vid_priv = dev_get_uclass_priv(dev);
  291. video_fill_part(dev, label_bbox.x0 - inset, label_bbox.y0 - inset,
  292. label_bbox.x1 + inset, label_bbox.y1 + inset,
  293. vid_priv->colour_fg);
  294. vidconsole_pop_colour(cons, &old);
  295. if (box_only) {
  296. video_fill_part(dev, label_bbox.x0, label_bbox.y0,
  297. label_bbox.x1, label_bbox.y1,
  298. vid_priv->colour_bg);
  299. }
  300. }
  301. /**
  302. * scene_obj_render() - Render an object
  303. *
  304. */
  305. static int scene_obj_render(struct scene_obj *obj, bool text_mode)
  306. {
  307. struct scene *scn = obj->scene;
  308. struct expo *exp = scn->expo;
  309. const struct expo_theme *theme = &exp->theme;
  310. struct udevice *dev = exp->display;
  311. struct udevice *cons = text_mode ? NULL : exp->cons;
  312. int x, y, ret;
  313. x = obj->dim.x;
  314. y = obj->dim.y;
  315. switch (obj->type) {
  316. case SCENEOBJT_NONE:
  317. break;
  318. case SCENEOBJT_IMAGE: {
  319. struct scene_obj_img *img = (struct scene_obj_img *)obj;
  320. if (!cons)
  321. return -ENOTSUPP;
  322. ret = video_bmp_display(dev, map_to_sysmem(img->data), x, y,
  323. true);
  324. if (ret < 0)
  325. return log_msg_ret("img", ret);
  326. break;
  327. }
  328. case SCENEOBJT_TEXT: {
  329. struct scene_obj_txt *txt = (struct scene_obj_txt *)obj;
  330. const char *str;
  331. if (!cons)
  332. return -ENOTSUPP;
  333. if (txt->font_name || txt->font_size) {
  334. ret = vidconsole_select_font(cons,
  335. txt->font_name,
  336. txt->font_size);
  337. } else {
  338. ret = vidconsole_select_font(cons, NULL, 0);
  339. }
  340. if (ret && ret != -ENOSYS)
  341. return log_msg_ret("font", ret);
  342. str = expo_get_str(exp, txt->str_id);
  343. if (str) {
  344. struct video_priv *vid_priv;
  345. struct vidconsole_colour old;
  346. enum colour_idx fore, back;
  347. if (CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK)) {
  348. fore = VID_BLACK;
  349. back = VID_WHITE;
  350. } else {
  351. fore = VID_LIGHT_GRAY;
  352. back = VID_BLACK;
  353. }
  354. vid_priv = dev_get_uclass_priv(dev);
  355. if (obj->flags & SCENEOF_POINT) {
  356. vidconsole_push_colour(cons, fore, back, &old);
  357. video_fill_part(dev, x - theme->menu_inset, y,
  358. x + obj->dim.w,
  359. y + obj->dim.h,
  360. vid_priv->colour_bg);
  361. }
  362. vidconsole_set_cursor_pos(cons, x, y);
  363. vidconsole_put_string(cons, str);
  364. if (obj->flags & SCENEOF_POINT)
  365. vidconsole_pop_colour(cons, &old);
  366. }
  367. break;
  368. }
  369. case SCENEOBJT_MENU: {
  370. struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
  371. if (exp->popup && (obj->flags & SCENEOF_OPEN)) {
  372. if (!cons)
  373. return -ENOTSUPP;
  374. /* draw a background behind the menu items */
  375. scene_render_background(obj, false);
  376. }
  377. /*
  378. * With a vidconsole, the text and item pointer are rendered as
  379. * normal objects so we don't need to do anything here. The menu
  380. * simply controls where they are positioned.
  381. */
  382. if (cons)
  383. return -ENOTSUPP;
  384. ret = scene_menu_display(menu);
  385. if (ret < 0)
  386. return log_msg_ret("img", ret);
  387. break;
  388. }
  389. case SCENEOBJT_TEXTLINE:
  390. if (obj->flags & SCENEOF_OPEN)
  391. scene_render_background(obj, true);
  392. break;
  393. }
  394. return 0;
  395. }
  396. int scene_arrange(struct scene *scn)
  397. {
  398. struct scene_obj *obj;
  399. int ret;
  400. list_for_each_entry(obj, &scn->obj_head, sibling) {
  401. switch (obj->type) {
  402. case SCENEOBJT_NONE:
  403. case SCENEOBJT_IMAGE:
  404. case SCENEOBJT_TEXT:
  405. break;
  406. case SCENEOBJT_MENU: {
  407. struct scene_obj_menu *menu;
  408. menu = (struct scene_obj_menu *)obj,
  409. ret = scene_menu_arrange(scn, menu);
  410. if (ret)
  411. return log_msg_ret("arr", ret);
  412. break;
  413. }
  414. case SCENEOBJT_TEXTLINE: {
  415. struct scene_obj_textline *tline;
  416. tline = (struct scene_obj_textline *)obj,
  417. ret = scene_textline_arrange(scn, tline);
  418. if (ret)
  419. return log_msg_ret("arr", ret);
  420. break;
  421. }
  422. }
  423. }
  424. return 0;
  425. }
  426. int scene_render_deps(struct scene *scn, uint id)
  427. {
  428. struct scene_obj *obj;
  429. int ret;
  430. if (!id)
  431. return 0;
  432. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  433. if (!obj)
  434. return log_msg_ret("obj", -ENOENT);
  435. if (!(obj->flags & SCENEOF_HIDE)) {
  436. ret = scene_obj_render(obj, false);
  437. if (ret && ret != -ENOTSUPP)
  438. return log_msg_ret("ren", ret);
  439. switch (obj->type) {
  440. case SCENEOBJT_NONE:
  441. case SCENEOBJT_IMAGE:
  442. case SCENEOBJT_TEXT:
  443. break;
  444. case SCENEOBJT_MENU:
  445. scene_menu_render_deps(scn,
  446. (struct scene_obj_menu *)obj);
  447. break;
  448. case SCENEOBJT_TEXTLINE:
  449. scene_textline_render_deps(scn,
  450. (struct scene_obj_textline *)obj);
  451. break;
  452. }
  453. }
  454. return 0;
  455. }
  456. int scene_render(struct scene *scn)
  457. {
  458. struct expo *exp = scn->expo;
  459. struct scene_obj *obj;
  460. int ret;
  461. list_for_each_entry(obj, &scn->obj_head, sibling) {
  462. if (!(obj->flags & SCENEOF_HIDE)) {
  463. ret = scene_obj_render(obj, exp->text_mode);
  464. if (ret && ret != -ENOTSUPP)
  465. return log_msg_ret("ren", ret);
  466. }
  467. }
  468. /* render any highlighted object on top of the others */
  469. if (scn->highlight_id && !exp->text_mode) {
  470. ret = scene_render_deps(scn, scn->highlight_id);
  471. if (ret && ret != -ENOTSUPP)
  472. return log_msg_ret("dep", ret);
  473. }
  474. return 0;
  475. }
  476. /**
  477. * send_key_obj() - Handle a keypress for moving between objects
  478. *
  479. * @scn: Scene to receive the key
  480. * @key: Key to send (KEYCODE_UP)
  481. * @event: Returns resulting event from this keypress
  482. * Returns: 0 if OK, -ve on error
  483. */
  484. static void send_key_obj(struct scene *scn, struct scene_obj *obj, int key,
  485. struct expo_action *event)
  486. {
  487. switch (key) {
  488. case BKEY_UP:
  489. while (obj != list_first_entry(&scn->obj_head, struct scene_obj,
  490. sibling)) {
  491. obj = list_entry(obj->sibling.prev,
  492. struct scene_obj, sibling);
  493. if (scene_obj_can_highlight(obj)) {
  494. event->type = EXPOACT_POINT_OBJ;
  495. event->select.id = obj->id;
  496. log_debug("up to obj %d\n", event->select.id);
  497. break;
  498. }
  499. }
  500. break;
  501. case BKEY_DOWN:
  502. while (!list_is_last(&obj->sibling, &scn->obj_head)) {
  503. obj = list_entry(obj->sibling.next, struct scene_obj,
  504. sibling);
  505. if (scene_obj_can_highlight(obj)) {
  506. event->type = EXPOACT_POINT_OBJ;
  507. event->select.id = obj->id;
  508. log_debug("down to obj %d\n", event->select.id);
  509. break;
  510. }
  511. }
  512. break;
  513. case BKEY_SELECT:
  514. if (scene_obj_can_highlight(obj)) {
  515. event->type = EXPOACT_OPEN;
  516. event->select.id = obj->id;
  517. log_debug("open obj %d\n", event->select.id);
  518. }
  519. break;
  520. case BKEY_QUIT:
  521. event->type = EXPOACT_QUIT;
  522. log_debug("obj quit\n");
  523. break;
  524. }
  525. }
  526. int scene_send_key(struct scene *scn, int key, struct expo_action *event)
  527. {
  528. struct scene_obj *obj;
  529. int ret;
  530. event->type = EXPOACT_NONE;
  531. /*
  532. * In 'popup' mode, arrow keys move betwen objects, unless a menu is
  533. * opened
  534. */
  535. if (scn->expo->popup) {
  536. obj = NULL;
  537. if (scn->highlight_id) {
  538. obj = scene_obj_find(scn, scn->highlight_id,
  539. SCENEOBJT_NONE);
  540. }
  541. if (!obj)
  542. return 0;
  543. if (!(obj->flags & SCENEOF_OPEN)) {
  544. send_key_obj(scn, obj, key, event);
  545. return 0;
  546. }
  547. switch (obj->type) {
  548. case SCENEOBJT_NONE:
  549. case SCENEOBJT_IMAGE:
  550. case SCENEOBJT_TEXT:
  551. break;
  552. case SCENEOBJT_MENU: {
  553. struct scene_obj_menu *menu;
  554. menu = (struct scene_obj_menu *)obj,
  555. ret = scene_menu_send_key(scn, menu, key, event);
  556. if (ret)
  557. return log_msg_ret("key", ret);
  558. break;
  559. }
  560. case SCENEOBJT_TEXTLINE: {
  561. struct scene_obj_textline *tline;
  562. tline = (struct scene_obj_textline *)obj,
  563. ret = scene_textline_send_key(scn, tline, key, event);
  564. if (ret)
  565. return log_msg_ret("key", ret);
  566. break;
  567. }
  568. }
  569. return 0;
  570. }
  571. list_for_each_entry(obj, &scn->obj_head, sibling) {
  572. if (obj->type == SCENEOBJT_MENU) {
  573. struct scene_obj_menu *menu;
  574. menu = (struct scene_obj_menu *)obj,
  575. ret = scene_menu_send_key(scn, menu, key, event);
  576. if (ret)
  577. return log_msg_ret("key", ret);
  578. break;
  579. }
  580. }
  581. return 0;
  582. }
  583. int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox *bbox,
  584. struct vidconsole_bbox *label_bbox)
  585. {
  586. switch (obj->type) {
  587. case SCENEOBJT_NONE:
  588. case SCENEOBJT_IMAGE:
  589. case SCENEOBJT_TEXT:
  590. return -ENOSYS;
  591. case SCENEOBJT_MENU: {
  592. struct scene_obj_menu *menu = (struct scene_obj_menu *)obj;
  593. scene_menu_calc_bbox(menu, bbox, label_bbox);
  594. break;
  595. }
  596. case SCENEOBJT_TEXTLINE: {
  597. struct scene_obj_textline *tline;
  598. tline = (struct scene_obj_textline *)obj;
  599. scene_textline_calc_bbox(tline, bbox, label_bbox);
  600. break;
  601. }
  602. }
  603. return 0;
  604. }
  605. int scene_calc_dims(struct scene *scn, bool do_menus)
  606. {
  607. struct scene_obj *obj;
  608. int ret;
  609. list_for_each_entry(obj, &scn->obj_head, sibling) {
  610. switch (obj->type) {
  611. case SCENEOBJT_NONE:
  612. case SCENEOBJT_TEXT:
  613. case SCENEOBJT_IMAGE: {
  614. int width;
  615. if (!do_menus) {
  616. ret = scene_obj_get_hw(scn, obj->id, &width);
  617. if (ret < 0)
  618. return log_msg_ret("get", ret);
  619. obj->dim.w = width;
  620. obj->dim.h = ret;
  621. }
  622. break;
  623. }
  624. case SCENEOBJT_MENU: {
  625. struct scene_obj_menu *menu;
  626. if (do_menus) {
  627. menu = (struct scene_obj_menu *)obj;
  628. ret = scene_menu_calc_dims(menu);
  629. if (ret)
  630. return log_msg_ret("men", ret);
  631. }
  632. break;
  633. }
  634. case SCENEOBJT_TEXTLINE: {
  635. struct scene_obj_textline *tline;
  636. tline = (struct scene_obj_textline *)obj;
  637. ret = scene_textline_calc_dims(tline);
  638. if (ret)
  639. return log_msg_ret("men", ret);
  640. break;
  641. }
  642. }
  643. }
  644. return 0;
  645. }
  646. int scene_apply_theme(struct scene *scn, struct expo_theme *theme)
  647. {
  648. struct scene_obj *obj;
  649. int ret;
  650. /* Avoid error-checking optional items */
  651. scene_txt_set_font(scn, scn->title_id, NULL, theme->font_size);
  652. list_for_each_entry(obj, &scn->obj_head, sibling) {
  653. switch (obj->type) {
  654. case SCENEOBJT_NONE:
  655. case SCENEOBJT_IMAGE:
  656. case SCENEOBJT_MENU:
  657. case SCENEOBJT_TEXTLINE:
  658. break;
  659. case SCENEOBJT_TEXT:
  660. scene_txt_set_font(scn, obj->id, NULL,
  661. theme->font_size);
  662. break;
  663. }
  664. }
  665. ret = scene_arrange(scn);
  666. if (ret)
  667. return log_msg_ret("arr", ret);
  668. return 0;
  669. }
  670. void scene_set_highlight_id(struct scene *scn, uint id)
  671. {
  672. scn->highlight_id = id;
  673. }
  674. void scene_highlight_first(struct scene *scn)
  675. {
  676. struct scene_obj *obj;
  677. list_for_each_entry(obj, &scn->obj_head, sibling) {
  678. if (scene_obj_can_highlight(obj)) {
  679. scene_set_highlight_id(scn, obj->id);
  680. return;
  681. }
  682. }
  683. }
  684. static int scene_obj_open(struct scene *scn, struct scene_obj *obj)
  685. {
  686. int ret;
  687. switch (obj->type) {
  688. case SCENEOBJT_NONE:
  689. case SCENEOBJT_IMAGE:
  690. case SCENEOBJT_MENU:
  691. case SCENEOBJT_TEXT:
  692. break;
  693. case SCENEOBJT_TEXTLINE:
  694. ret = scene_textline_open(scn,
  695. (struct scene_obj_textline *)obj);
  696. if (ret)
  697. return log_msg_ret("op", ret);
  698. break;
  699. }
  700. return 0;
  701. }
  702. int scene_set_open(struct scene *scn, uint id, bool open)
  703. {
  704. struct scene_obj *obj;
  705. int ret;
  706. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  707. if (!obj)
  708. return log_msg_ret("find", -ENOENT);
  709. if (open) {
  710. ret = scene_obj_open(scn, obj);
  711. if (ret)
  712. return log_msg_ret("op", ret);
  713. }
  714. ret = scene_obj_flag_clrset(scn, id, SCENEOF_OPEN,
  715. open ? SCENEOF_OPEN : 0);
  716. if (ret)
  717. return log_msg_ret("flg", ret);
  718. return 0;
  719. }
  720. int scene_iter_objs(struct scene *scn, expo_scene_obj_iterator iter,
  721. void *priv)
  722. {
  723. struct scene_obj *obj;
  724. list_for_each_entry(obj, &scn->obj_head, sibling) {
  725. int ret;
  726. ret = iter(obj, priv);
  727. if (ret)
  728. return log_msg_ret("itr", ret);
  729. }
  730. return 0;
  731. }
  732. int scene_bbox_union(struct scene *scn, uint id, int inset,
  733. struct vidconsole_bbox *bbox)
  734. {
  735. struct scene_obj *obj;
  736. if (!id)
  737. return 0;
  738. obj = scene_obj_find(scn, id, SCENEOBJT_NONE);
  739. if (!obj)
  740. return log_msg_ret("obj", -ENOENT);
  741. if (bbox->valid) {
  742. bbox->x0 = min(bbox->x0, obj->dim.x - inset);
  743. bbox->y0 = min(bbox->y0, obj->dim.y);
  744. bbox->x1 = max(bbox->x1, obj->dim.x + obj->dim.w + inset);
  745. bbox->y1 = max(bbox->y1, obj->dim.y + obj->dim.h);
  746. } else {
  747. bbox->x0 = obj->dim.x - inset;
  748. bbox->y0 = obj->dim.y;
  749. bbox->x1 = obj->dim.x + obj->dim.w + inset;
  750. bbox->y1 = obj->dim.y + obj->dim.h;
  751. bbox->valid = true;
  752. }
  753. return 0;
  754. }