
From: Simon Glass <sjg@chromium.org> Implement clicking on an object in the scene. For now only menus and textlines respond to this. For menus the behaviour is different for popups than for normal menus. Signed-off-by: Simon Glass <sjg@chromium.org> --- boot/scene.c | 173 ++++++++++++++++++++++++++++++++++++++++++ boot/scene_internal.h | 23 ++++++ 2 files changed, 196 insertions(+) diff --git a/boot/scene.c b/boot/scene.c index e25596366cc..d7e0d008b56 100644 --- a/boot/scene.c +++ b/boot/scene.c @@ -1078,6 +1078,179 @@ bool scene_obj_within(const struct scene *scn, struct scene_obj *obj, int x, return within; } +/** + * scene_find_obj_within() - Find an object that is within the coords + * + * @scn: Scene to check + * @x: X coordinates of the click + * @y: Y coordinate of the click + * Return: object that is being clicked on, NULL if none + */ +static struct scene_obj *scene_find_obj_within(const struct scene *scn, int x, + int y) +{ + struct scene_obj *obj; + + log_debug("within: x %d y %d\n", x, y); + list_for_each_entry(obj, &scn->obj_head, sibling) { + log_debug(" - obj %d '%s' can_highlight %d within %d\n", + obj->id, obj->name, scene_obj_can_highlight(obj), + scene_obj_within(scn, obj, x, y)); + if (scene_obj_can_highlight(obj) && + scene_obj_within(scn, obj, x, y)) { + log_debug("- returning obj %d '%s'\n", obj->id, + obj->name); + return obj; + } + } + log_debug("- no object\n"); + + return NULL; +} + +/** + * send_click_obj() - Handle a click for moving between objects + * + * On entry, scn->highlight_id is set to a menu/textline, but the object is not + * open. + * + * @scn: Scene to receive the click + * @obj: Object to receive the click + * @x: X coordinate of the click + * @y: Y coordinate of the click + * @event: Returns resulting event from this keypress + * Returns: 0 if OK, -ve on error + */ +static void send_click_obj(struct scene *scn, struct scene_obj *obj, int x, + int y, struct expo_action *event) +{ + if (scene_obj_can_highlight(obj) && scene_obj_within(scn, obj, x, y)) { + event->type = EXPOACT_OPEN; + event->select.id = obj->id; + log_debug("open obj %d\n", event->select.id); + return; + } + + log_debug("no object; finding...\n"); + obj = scene_find_obj_within(scn, x, y); + if (obj) { + event->type = EXPOACT_POINT_OPEN; + event->select.id = obj->id; + } +} + +static int scene_click_popup(struct scene *scn, int x, int y, + struct expo_action *event) +{ + struct scene_obj *obj, *chk; + + 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_click_obj(scn, obj, x, y, event); + return 0; + } + + /* check that the click is within our object */ + chk = scene_find_obj_within(scn, x, y); + log_debug("chk %d '%s' (obj %d '%s')\n", chk ? chk->id : -1, + chk ? chk->name : "(none)", obj->id, obj->name); + if (!chk) { + /* click into space */ + event->type = EXPOACT_CLOSE; + event->select.id = obj->id; + return 0; + } else if (chk != obj) { + send_click_obj(scn, chk, x, y, event); + if (event->type == EXPOACT_OPEN) { + event->type = EXPOACT_REPOINT_OPEN; + event->select.prev_id = obj->id; + } + return 0; + } + + /* click within the open object */ + switch (obj->type) { + case SCENEOBJT_NONE: + case SCENEOBJT_IMAGE: + case SCENEOBJT_TEXT: + case SCENEOBJT_BOX: + break; + case SCENEOBJT_MENU: { + struct scene_obj_menu *menu; + + menu = (struct scene_obj_menu *)obj, + scene_menu_send_click(scn, menu, x, y, event); + break; + } + case SCENEOBJT_TEXTLINE: { + struct scene_obj_textline *tline; + + tline = (struct scene_obj_textline *)obj; + // ret = scene_textline_send_click(scn, tline, x, y, event); + // if (ret) + // return log_msg_ret("key", ret); + break; + } + case SCENEOBJT_TEXTEDIT: + /* TODO(sjg@chromium.org): Implement this */ + break; + } + + return 0; +} + +int scene_send_click(struct scene *scn, int x, int y, struct expo_action *event) +{ + struct scene_obj *obj; + + event->type = EXPOACT_NONE; + + if (scn->expo->popup) { + scene_click_popup(scn, x, y, event); + return 0; + } + + obj = scene_find_obj_within(scn, x, y); + log_debug("non-popup obj %d '%s'\n", obj ? obj->id : -1, + obj ? obj->name : "(none)"); + if (!obj) + return 0; + + switch (obj->type) { + case SCENEOBJT_NONE: + case SCENEOBJT_IMAGE: + case SCENEOBJT_TEXT: + case SCENEOBJT_BOX: + /* These objects don't handle clicks directly */ + break; + case SCENEOBJT_MENU: { + struct scene_obj_menu *menu; + + menu = (struct scene_obj_menu *)obj, + scene_menu_send_click(scn, menu, x, y, event); + break; + } + case SCENEOBJT_TEXTLINE: { + /* For now, just highlight the textline */ + scn->highlight_id = obj->id; + break; + } + case SCENEOBJT_TEXTEDIT: + /* For now, just highlight the textedit */ + scn->highlight_id = obj->id; + break; + } + + return 0; +} + int scene_obj_calc_bbox(struct scene_obj *obj, struct vidconsole_bbox bbox[]) { switch (obj->type) { diff --git a/boot/scene_internal.h b/boot/scene_internal.h index 91828538417..0bc6f45cdcb 100644 --- a/boot/scene_internal.h +++ b/boot/scene_internal.h @@ -265,6 +265,18 @@ int scene_send_key(struct scene *scn, int key, struct expo_action *event); */ bool scene_within(const struct scene *scn, uint id, int x, int y); +/** + * scene_obj_within() - check if a point is considered within an object + * + * @scn: Scene to check + * @menu: Menu to check + * @x: X coordinate of the point + * @y: Y coordinate of the point + * Return: true if the point is considered within the object, false if not + */ +bool scene_obj_within(const struct scene *scn, struct scene_obj *obj, + int x, int y); + /** * scene_menu_within() - check if a point is considered within a menu * @@ -290,6 +302,17 @@ struct scene_menitem *scene_menu_within(const struct scene *scn, bool scene_textline_within(const struct scene *scn, struct scene_obj_textline *tline, int x, int y); +/** + * scene_send_click() - process a mouse click in a scene + * + * @scn: Scene to receive the click + * @x: X coordinate of the click + * @y: Y coordinate of the click + * @event: Returns resulting event from this click + * Returns: 0 if OK, -ve on error + */ +int scene_send_click(struct scene *scn, int x, int y, struct expo_action *event); + /** * scene_render_deps() - Render an object and its dependencies * -- 2.43.0