1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Implementation of a menu in a scene 4 * 5 * Copyright 2023 Google LLC 6 * Written by Simon Glass <sjg@chromium.org> 7 */ 8 9#define LOG_CATEGORY LOGC_EXPO 10 11#include <common.h> 12#include <expo.h> 13#include <menu.h> 14#include <video_console.h> 15#include "scene_internal.h" 16 17int scene_textline(struct scene *scn, const char *name, uint id, uint max_chars, 18 struct scene_obj_textline **tlinep) 19{ 20 struct scene_obj_textline *tline; 21 char *buf; 22 int ret; 23 24 if (max_chars >= EXPO_MAX_CHARS) 25 return log_msg_ret("chr", -E2BIG); 26 27 ret = scene_obj_add(scn, name, id, SCENEOBJT_TEXTLINE, 28 sizeof(struct scene_obj_textline), 29 (struct scene_obj **)&tline); 30 if (ret < 0) 31 return log_msg_ret("obj", -ENOMEM); 32 abuf_init(&tline->buf); 33 if (!abuf_realloc(&tline->buf, max_chars + 1)) 34 return log_msg_ret("buf", -ENOMEM); 35 buf = abuf_data(&tline->buf); 36 *buf = '\0'; 37 tline->pos = max_chars; 38 tline->max_chars = max_chars; 39 40 if (tlinep) 41 *tlinep = tline; 42 43 return tline->obj.id; 44} 45 46void scene_textline_calc_bbox(struct scene_obj_textline *tline, 47 struct vidconsole_bbox *bbox, 48 struct vidconsole_bbox *edit_bbox) 49{ 50 const struct expo_theme *theme = &tline->obj.scene->expo->theme; 51 52 bbox->valid = false; 53 scene_bbox_union(tline->obj.scene, tline->label_id, 0, bbox); 54 scene_bbox_union(tline->obj.scene, tline->edit_id, 0, bbox); 55 56 edit_bbox->valid = false; 57 scene_bbox_union(tline->obj.scene, tline->edit_id, theme->menu_inset, 58 edit_bbox); 59} 60 61int scene_textline_calc_dims(struct scene_obj_textline *tline) 62{ 63 struct scene *scn = tline->obj.scene; 64 struct vidconsole_bbox bbox; 65 struct scene_obj_txt *txt; 66 int ret; 67 68 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); 69 if (!txt) 70 return log_msg_ret("dim", -ENOENT); 71 72 ret = vidconsole_nominal(scn->expo->cons, txt->font_name, 73 txt->font_size, tline->max_chars, &bbox); 74 if (ret) 75 return log_msg_ret("nom", ret); 76 77 if (bbox.valid) { 78 tline->obj.dim.w = bbox.x1 - bbox.x0; 79 tline->obj.dim.h = bbox.y1 - bbox.y0; 80 81 scene_obj_set_size(scn, tline->edit_id, tline->obj.dim.w, 82 tline->obj.dim.h); 83 } 84 85 return 0; 86} 87 88int scene_textline_arrange(struct scene *scn, struct scene_obj_textline *tline) 89{ 90 const bool open = tline->obj.flags & SCENEOF_OPEN; 91 bool point; 92 int x, y; 93 int ret; 94 95 x = tline->obj.dim.x; 96 y = tline->obj.dim.y; 97 if (tline->label_id) { 98 ret = scene_obj_set_pos(scn, tline->label_id, tline->obj.dim.x, 99 y); 100 if (ret < 0) 101 return log_msg_ret("tit", ret); 102 103 ret = scene_obj_set_pos(scn, tline->edit_id, 104 tline->obj.dim.x + 200, y); 105 if (ret < 0) 106 return log_msg_ret("tit", ret); 107 108 ret = scene_obj_get_hw(scn, tline->label_id, NULL); 109 if (ret < 0) 110 return log_msg_ret("hei", ret); 111 112 y += ret * 2; 113 } 114 115 point = scn->highlight_id == tline->obj.id; 116 point &= !open; 117 scene_obj_flag_clrset(scn, tline->edit_id, SCENEOF_POINT, 118 point ? SCENEOF_POINT : 0); 119 120 return 0; 121} 122 123int scene_textline_send_key(struct scene *scn, struct scene_obj_textline *tline, 124 int key, struct expo_action *event) 125{ 126 const bool open = tline->obj.flags & SCENEOF_OPEN; 127 128 log_debug("key=%d\n", key); 129 switch (key) { 130 case BKEY_QUIT: 131 if (open) { 132 event->type = EXPOACT_CLOSE; 133 event->select.id = tline->obj.id; 134 135 /* Copy the backup text from the scene buffer */ 136 memcpy(abuf_data(&tline->buf), abuf_data(&scn->buf), 137 abuf_size(&scn->buf)); 138 } else { 139 event->type = EXPOACT_QUIT; 140 log_debug("menu quit\n"); 141 } 142 break; 143 case BKEY_SELECT: 144 if (!open) 145 break; 146 event->type = EXPOACT_CLOSE; 147 event->select.id = tline->obj.id; 148 key = '\n'; 149 fallthrough; 150 default: { 151 struct udevice *cons = scn->expo->cons; 152 int ret; 153 154 ret = vidconsole_entry_restore(cons, &scn->entry_save); 155 if (ret) 156 return log_msg_ret("sav", ret); 157 ret = cread_line_process_ch(&scn->cls, key); 158 ret = vidconsole_entry_save(cons, &scn->entry_save); 159 if (ret) 160 return log_msg_ret("sav", ret); 161 break; 162 } 163 } 164 165 return 0; 166} 167 168int scene_textline_render_deps(struct scene *scn, 169 struct scene_obj_textline *tline) 170{ 171 const bool open = tline->obj.flags & SCENEOF_OPEN; 172 struct udevice *cons = scn->expo->cons; 173 struct scene_obj_txt *txt; 174 int ret; 175 176 scene_render_deps(scn, tline->label_id); 177 scene_render_deps(scn, tline->edit_id); 178 179 /* show the vidconsole cursor if open */ 180 if (open) { 181 /* get the position within the field */ 182 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); 183 if (!txt) 184 return log_msg_ret("cur", -ENOENT); 185 186 if (txt->font_name || txt->font_size) { 187 ret = vidconsole_select_font(cons, 188 txt->font_name, 189 txt->font_size); 190 } else { 191 ret = vidconsole_select_font(cons, NULL, 0); 192 } 193 194 ret = vidconsole_entry_restore(cons, &scn->entry_save); 195 if (ret) 196 return log_msg_ret("sav", ret); 197 198 vidconsole_set_cursor_visible(cons, true, txt->obj.dim.x, 199 txt->obj.dim.y, scn->cls.num); 200 } 201 202 return 0; 203} 204 205int scene_textline_open(struct scene *scn, struct scene_obj_textline *tline) 206{ 207 struct udevice *cons = scn->expo->cons; 208 struct scene_obj_txt *txt; 209 int ret; 210 211 /* Copy the text into the scene buffer in case the edit is cancelled */ 212 memcpy(abuf_data(&scn->buf), abuf_data(&tline->buf), 213 abuf_size(&scn->buf)); 214 215 /* get the position of the editable */ 216 txt = scene_obj_find(scn, tline->edit_id, SCENEOBJT_NONE); 217 if (!txt) 218 return log_msg_ret("cur", -ENOENT); 219 220 vidconsole_set_cursor_pos(cons, txt->obj.dim.x, txt->obj.dim.y); 221 vidconsole_entry_start(cons); 222 cli_cread_init(&scn->cls, abuf_data(&tline->buf), tline->max_chars); 223 scn->cls.insert = true; 224 ret = vidconsole_entry_save(cons, &scn->entry_save); 225 if (ret) 226 return log_msg_ret("sav", ret); 227 228 return 0; 229} 230