123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268 |
- // SPDX-License-Identifier: GPL-2.0+
- /*
- * Implementation of a expo, a collection of scenes providing menu options
- *
- * Copyright 2022 Google LLC
- * Written by Simon Glass <sjg@chromium.org>
- */
- #define LOG_CATEGORY LOGC_EXPO
- #include <common.h>
- #include <dm.h>
- #include <expo.h>
- #include <malloc.h>
- #include <video.h>
- #include "scene_internal.h"
- int expo_new(const char *name, void *priv, struct expo **expp)
- {
- struct expo *exp;
- exp = calloc(1, sizeof(struct expo));
- if (!exp)
- return log_msg_ret("expo", -ENOMEM);
- exp->name = strdup(name);
- if (!exp->name) {
- free(exp);
- return log_msg_ret("name", -ENOMEM);
- }
- exp->priv = priv;
- INIT_LIST_HEAD(&exp->scene_head);
- INIT_LIST_HEAD(&exp->str_head);
- *expp = exp;
- return 0;
- }
- static void estr_destroy(struct expo_string *estr)
- {
- free(estr);
- }
- void expo_destroy(struct expo *exp)
- {
- struct scene *scn, *next;
- struct expo_string *estr, *enext;
- list_for_each_entry_safe(scn, next, &exp->scene_head, sibling)
- scene_destroy(scn);
- list_for_each_entry_safe(estr, enext, &exp->str_head, sibling)
- estr_destroy(estr);
- free(exp->name);
- free(exp);
- }
- uint resolve_id(struct expo *exp, uint id)
- {
- log_debug("resolve id %d\n", id);
- if (!id)
- id = exp->next_id++;
- else if (id >= exp->next_id)
- exp->next_id = id + 1;
- return id;
- }
- void expo_set_dynamic_start(struct expo *exp, uint dyn_start)
- {
- exp->next_id = dyn_start;
- }
- int expo_str(struct expo *exp, const char *name, uint id, const char *str)
- {
- struct expo_string *estr;
- estr = calloc(1, sizeof(struct expo_string));
- if (!estr)
- return log_msg_ret("obj", -ENOMEM);
- estr->id = resolve_id(exp, id);
- estr->str = str;
- list_add_tail(&estr->sibling, &exp->str_head);
- return estr->id;
- }
- const char *expo_get_str(struct expo *exp, uint id)
- {
- struct expo_string *estr;
- list_for_each_entry(estr, &exp->str_head, sibling) {
- if (estr->id == id)
- return estr->str;
- }
- return NULL;
- }
- int expo_set_display(struct expo *exp, struct udevice *dev)
- {
- struct udevice *cons;
- int ret;
- ret = device_find_first_child_by_uclass(dev, UCLASS_VIDEO_CONSOLE,
- &cons);
- if (ret)
- return log_msg_ret("con", ret);
- exp->display = dev;
- exp->cons = cons;
- return 0;
- }
- int expo_calc_dims(struct expo *exp)
- {
- struct scene *scn;
- int ret;
- if (!exp->cons)
- return log_msg_ret("dim", -ENOTSUPP);
- list_for_each_entry(scn, &exp->scene_head, sibling) {
- /*
- * Do the menus last so that all the menus' text objects
- * are dimensioned
- */
- ret = scene_calc_dims(scn, false);
- if (ret)
- return log_msg_ret("scn", ret);
- ret = scene_calc_dims(scn, true);
- if (ret)
- return log_msg_ret("scn", ret);
- }
- return 0;
- }
- void expo_set_text_mode(struct expo *exp, bool text_mode)
- {
- exp->text_mode = text_mode;
- }
- struct scene *expo_lookup_scene_id(struct expo *exp, uint scene_id)
- {
- struct scene *scn;
- list_for_each_entry(scn, &exp->scene_head, sibling) {
- if (scn->id == scene_id)
- return scn;
- }
- return NULL;
- }
- int expo_set_scene_id(struct expo *exp, uint scene_id)
- {
- struct scene *scn;
- int ret;
- scn = expo_lookup_scene_id(exp, scene_id);
- if (!scn)
- return log_msg_ret("id", -ENOENT);
- ret = scene_arrange(scn);
- if (ret)
- return log_msg_ret("arr", ret);
- exp->scene_id = scene_id;
- return 0;
- }
- int expo_first_scene_id(struct expo *exp)
- {
- struct scene *scn;
- if (list_empty(&exp->scene_head))
- return -ENOENT;
- scn = list_first_entry(&exp->scene_head, struct scene, sibling);
- return scn->id;
- }
- int expo_render(struct expo *exp)
- {
- struct udevice *dev = exp->display;
- struct video_priv *vid_priv = dev_get_uclass_priv(dev);
- struct scene *scn = NULL;
- u32 colour;
- int ret;
- colour = video_index_to_colour(vid_priv, VID_WHITE);
- ret = video_fill(dev, colour);
- if (ret)
- return log_msg_ret("fill", ret);
- if (exp->scene_id) {
- scn = expo_lookup_scene_id(exp, exp->scene_id);
- if (!scn)
- return log_msg_ret("scn", -ENOENT);
- ret = scene_render(scn);
- if (ret)
- return log_msg_ret("ren", ret);
- }
- video_sync(dev, true);
- return scn ? 0 : -ECHILD;
- }
- int expo_send_key(struct expo *exp, int key)
- {
- struct scene *scn = NULL;
- if (exp->scene_id) {
- int ret;
- scn = expo_lookup_scene_id(exp, exp->scene_id);
- if (!scn)
- return log_msg_ret("scn", -ENOENT);
- ret = scene_send_key(scn, key, &exp->action);
- if (ret)
- return log_msg_ret("key", ret);
- /* arrange it to get any changes */
- ret = scene_arrange(scn);
- if (ret)
- return log_msg_ret("arr", ret);
- }
- return scn ? 0 : -ECHILD;
- }
- int expo_action_get(struct expo *exp, struct expo_action *act)
- {
- *act = exp->action;
- exp->action.type = EXPOACT_NONE;
- return act->type == EXPOACT_NONE ? -EAGAIN : 0;
- }
- int expo_apply_theme(struct expo *exp, ofnode node)
- {
- struct scene *scn;
- struct expo_theme *theme = &exp->theme;
- int ret;
- log_debug("Applying theme %s\n", ofnode_get_name(node));
- memset(theme, '\0', sizeof(struct expo_theme));
- ofnode_read_u32(node, "font-size", &theme->font_size);
- ofnode_read_u32(node, "menu-inset", &theme->menu_inset);
- ofnode_read_u32(node, "menuitem-gap-y", &theme->menuitem_gap_y);
- list_for_each_entry(scn, &exp->scene_head, sibling) {
- ret = scene_apply_theme(scn, theme);
- if (ret)
- return log_msg_ret("app", ret);
- }
- return 0;
- }
|