1 // SPDX-License-Identifier: GPL-2.0+
3 * Implementation of a expo, a collection of scenes providing menu options
5 * Copyright 2022 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
9 #define LOG_CATEGORY LOGC_EXPO
15 #include "scene_internal.h"
17 int expo_new(const char *name
, void *priv
, struct expo
**expp
)
21 exp
= calloc(1, sizeof(struct expo
));
23 return log_msg_ret("expo", -ENOMEM
);
24 exp
->name
= strdup(name
);
27 return log_msg_ret("name", -ENOMEM
);
30 INIT_LIST_HEAD(&exp
->scene_head
);
31 INIT_LIST_HEAD(&exp
->str_head
);
32 exp
->next_id
= EXPOID_BASE_ID
;
39 static void estr_destroy(struct expo_string
*estr
)
44 void expo_destroy(struct expo
*exp
)
46 struct scene
*scn
, *next
;
47 struct expo_string
*estr
, *enext
;
49 list_for_each_entry_safe(scn
, next
, &exp
->scene_head
, sibling
)
52 list_for_each_entry_safe(estr
, enext
, &exp
->str_head
, sibling
)
59 uint
resolve_id(struct expo
*exp
, uint id
)
61 log_debug("resolve id %d\n", id
);
64 else if (id
>= exp
->next_id
)
65 exp
->next_id
= id
+ 1;
70 void expo_set_dynamic_start(struct expo
*exp
, uint dyn_start
)
72 exp
->next_id
= dyn_start
;
75 int expo_str(struct expo
*exp
, const char *name
, uint id
, const char *str
)
77 struct expo_string
*estr
;
79 estr
= calloc(1, sizeof(struct expo_string
));
81 return log_msg_ret("obj", -ENOMEM
);
83 estr
->id
= resolve_id(exp
, id
);
85 list_add_tail(&estr
->sibling
, &exp
->str_head
);
90 const char *expo_get_str(struct expo
*exp
, uint id
)
92 struct expo_string
*estr
;
94 list_for_each_entry(estr
, &exp
->str_head
, sibling
) {
102 int expo_set_display(struct expo
*exp
, struct udevice
*dev
)
104 struct udevice
*cons
;
107 ret
= device_find_first_child_by_uclass(dev
, UCLASS_VIDEO_CONSOLE
,
110 return log_msg_ret("con", ret
);
118 int expo_calc_dims(struct expo
*exp
)
124 return log_msg_ret("dim", -ENOTSUPP
);
126 list_for_each_entry(scn
, &exp
->scene_head
, sibling
) {
128 * Do the menus last so that all the menus' text objects
131 ret
= scene_calc_dims(scn
, false);
133 return log_msg_ret("scn", ret
);
134 ret
= scene_calc_dims(scn
, true);
136 return log_msg_ret("scn", ret
);
142 void expo_set_text_mode(struct expo
*exp
, bool text_mode
)
144 exp
->text_mode
= text_mode
;
147 struct scene
*expo_lookup_scene_id(struct expo
*exp
, uint scene_id
)
151 list_for_each_entry(scn
, &exp
->scene_head
, sibling
) {
152 if (scn
->id
== scene_id
)
159 int expo_set_scene_id(struct expo
*exp
, uint scene_id
)
164 scn
= expo_lookup_scene_id(exp
, scene_id
);
166 return log_msg_ret("id", -ENOENT
);
167 ret
= scene_arrange(scn
);
169 return log_msg_ret("arr", ret
);
171 exp
->scene_id
= scene_id
;
176 int expo_first_scene_id(struct expo
*exp
)
180 if (list_empty(&exp
->scene_head
))
183 scn
= list_first_entry(&exp
->scene_head
, struct scene
, sibling
);
188 int expo_render(struct expo
*exp
)
190 struct udevice
*dev
= exp
->display
;
191 struct video_priv
*vid_priv
= dev_get_uclass_priv(dev
);
192 struct scene
*scn
= NULL
;
193 enum colour_idx back
;
197 back
= CONFIG_IS_ENABLED(SYS_WHITE_ON_BLACK
) ? VID_BLACK
: VID_WHITE
;
198 colour
= video_index_to_colour(vid_priv
, back
);
199 ret
= video_fill(dev
, colour
);
201 return log_msg_ret("fill", ret
);
204 scn
= expo_lookup_scene_id(exp
, exp
->scene_id
);
206 return log_msg_ret("scn", -ENOENT
);
208 ret
= scene_render(scn
);
210 return log_msg_ret("ren", ret
);
213 video_sync(dev
, true);
215 return scn
? 0 : -ECHILD
;
218 int expo_send_key(struct expo
*exp
, int key
)
220 struct scene
*scn
= NULL
;
225 scn
= expo_lookup_scene_id(exp
, exp
->scene_id
);
227 return log_msg_ret("scn", -ENOENT
);
229 ret
= scene_send_key(scn
, key
, &exp
->action
);
231 return log_msg_ret("key", ret
);
233 /* arrange it to get any changes */
234 ret
= scene_arrange(scn
);
236 return log_msg_ret("arr", ret
);
239 return scn
? 0 : -ECHILD
;
242 int expo_action_get(struct expo
*exp
, struct expo_action
*act
)
245 exp
->action
.type
= EXPOACT_NONE
;
247 return act
->type
== EXPOACT_NONE
? -EAGAIN
: 0;
250 int expo_apply_theme(struct expo
*exp
, ofnode node
)
253 struct expo_theme
*theme
= &exp
->theme
;
256 log_debug("Applying theme %s\n", ofnode_get_name(node
));
258 memset(theme
, '\0', sizeof(struct expo_theme
));
259 ofnode_read_u32(node
, "font-size", &theme
->font_size
);
260 ofnode_read_u32(node
, "menu-inset", &theme
->menu_inset
);
261 ofnode_read_u32(node
, "menuitem-gap-y", &theme
->menuitem_gap_y
);
262 ofnode_read_u32(node
, "menu-title-margin-x",
263 &theme
->menu_title_margin_x
);
265 list_for_each_entry(scn
, &exp
->scene_head
, sibling
) {
266 ret
= scene_apply_theme(scn
, theme
);
268 return log_msg_ret("app", ret
);
274 int expo_iter_scene_objs(struct expo
*exp
, expo_scene_obj_iterator iter
,
280 list_for_each_entry(scn
, &exp
->scene_head
, sibling
) {
281 ret
= scene_iter_objs(scn
, iter
, priv
);
283 return log_msg_ret("wr", ret
);