From 4e64beeba7de7720b42714cbc542c9f7dfbba841 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 1 Jun 2023 10:22:59 -0600 Subject: expo: Implement the keypress logic for popup menus In 'popup' mode, the expo allows moving around the objects in a scene. When 'enter' is pressed on a menu, it opens and the user can move around the items in the menu. Implement this using keypress handles and actions. Signed-off-by: Simon Glass --- boot/scene.c | 80 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ boot/scene_menu.c | 10 +++++-- 2 files changed, 88 insertions(+), 2 deletions(-) (limited to 'boot') diff --git a/boot/scene.c b/boot/scene.c index bc213bc08b8..ea94b90584e 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -469,11 +470,90 @@ int scene_render(struct scene *scn) return 0; } +/** + * send_key_obj() - Handle a keypress for moving between objects + * + * @scn: Scene to receive the key + * @key: Key to send (KEYCODE_UP) + * @event: Returns resulting event from this keypress + * Returns: 0 if OK, -ve on error + */ +static void send_key_obj(struct scene *scn, struct scene_obj *obj, int key, + struct expo_action *event) +{ + switch (key) { + case BKEY_UP: + while (obj != list_first_entry(&scn->obj_head, struct scene_obj, + sibling)) { + obj = list_entry(obj->sibling.prev, + struct scene_obj, sibling); + if (obj->type == SCENEOBJT_MENU) { + event->type = EXPOACT_POINT_OBJ; + event->select.id = obj->id; + log_debug("up to obj %d\n", event->select.id); + break; + } + } + break; + case BKEY_DOWN: + while (!list_is_last(&obj->sibling, &scn->obj_head)) { + obj = list_entry(obj->sibling.next, struct scene_obj, + sibling); + if (obj->type == SCENEOBJT_MENU) { + event->type = EXPOACT_POINT_OBJ; + event->select.id = obj->id; + log_debug("down to obj %d\n", event->select.id); + break; + } + } + break; + case BKEY_SELECT: + if (obj->type == SCENEOBJT_MENU) { + event->type = EXPOACT_OPEN; + event->select.id = obj->id; + log_debug("open obj %d\n", event->select.id); + } + break; + case BKEY_QUIT: + event->type = EXPOACT_QUIT; + log_debug("obj quit\n"); + break; + } +} + int scene_send_key(struct scene *scn, int key, struct expo_action *event) { + struct scene_obj_menu *menu; struct scene_obj *obj; int ret; + event->type = EXPOACT_NONE; + + /* + * In 'popup' mode, arrow keys move betwen objects, unless a menu is + * opened + */ + if (scn->expo->popup) { + obj = NULL; + if (scn->highlight_id) { + obj = scene_obj_find(scn, scn->highlight_id, + SCENEOBJT_NONE); + } + if (!obj) + return 0; + + if (!(obj->flags & SCENEOF_OPEN)) { + send_key_obj(scn, obj, key, event); + return 0; + } + + menu = (struct scene_obj_menu *)obj, + ret = scene_menu_send_key(scn, menu, key, event); + if (ret) + return log_msg_ret("key", ret); + return 0; + } + list_for_each_entry(obj, &scn->obj_head, sibling) { if (obj->type == SCENEOBJT_MENU) { struct scene_obj_menu *menu; diff --git a/boot/scene_menu.c b/boot/scene_menu.c index 6aab27611d7..dfe5692d6ce 100644 --- a/boot/scene_menu.c +++ b/boot/scene_menu.c @@ -323,6 +323,7 @@ static struct scene_menitem *scene_menu_find_key(struct scene *scn, int scene_menu_send_key(struct scene *scn, struct scene_obj_menu *menu, int key, struct expo_action *event) { + const bool open = menu->obj.flags & SCENEOF_OPEN; struct scene_menitem *item, *cur, *key_item; cur = NULL; @@ -367,8 +368,13 @@ int scene_menu_send_key(struct scene *scn, struct scene_obj_menu *menu, int key, log_debug("select item %d\n", event->select.id); break; case BKEY_QUIT: - event->type = EXPOACT_QUIT; - log_debug("quit\n"); + if (scn->expo->popup && open) { + event->type = EXPOACT_CLOSE; + event->select.id = menu->obj.id; + } else { + event->type = EXPOACT_QUIT; + log_debug("menu quit\n"); + } break; case '0'...'9': key_item = scene_menu_find_key(scn, menu, key); -- cgit v1.2.3