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 <sjg@chromium.org>
This commit is contained in:
Simon Glass 2023-06-01 10:22:59 -06:00 committed by Tom Rini
parent 4c87e073a4
commit 4e64beeba7
4 changed files with 96 additions and 4 deletions

View file

@ -13,6 +13,7 @@
#include <expo.h>
#include <malloc.h>
#include <mapmem.h>
#include <menu.h>
#include <video.h>
#include <video_console.h>
#include <linux/input.h>
@ -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;

View file

@ -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);

View file

@ -178,8 +178,7 @@ Some ideas for future work:
- Image formats other than BMP
- Use of ANSI sequences to control a serial terminal
- Colour selection
- Better support for handling lots of settings, e.g. with multiple menus and
radio/option widgets
- Better support for handling lots of settings, e.g. with radio/option widgets
- Mouse support
- Integrate Nuklear, NxWidgets or some other library for a richer UI
- Optimise rendering by only updating the display with changes since last render

View file

@ -16,14 +16,21 @@ struct udevice;
* enum expoact_type - types of actions reported by the expo
*
* @EXPOACT_NONE: no action
* @EXPOACT_POINT_OBJ: object was highlighted (@id indicates which)
* @EXPOACT_POINT_ITEM: menu item was highlighted (@id indicates which)
* @EXPOACT_SELECT: menu item was selected (@id indicates which)
* @EXPOACT_OPEN: menu was opened, so an item can be selected (@id indicates
* which menu object)
* @EXPOACT_CLOSE: menu was closed (@id indicates which menu object)
* @EXPOACT_QUIT: request to exit the menu
*/
enum expoact_type {
EXPOACT_NONE,
EXPOACT_POINT_OBJ,
EXPOACT_POINT_ITEM,
EXPOACT_SELECT,
EXPOACT_OPEN,
EXPOACT_CLOSE,
EXPOACT_QUIT,
};