X-Git-Url: http://git.ozlabs.org/?p=petitboot;a=blobdiff_plain;f=ui%2Fncurses%2Fnc-menu.c;h=7d4442b8102d739f00cdbe99f10a88b160a3c96f;hp=04207597db289245eef8e2f44372837f53265667;hb=a1fb38f17bfa60aac89d0dd21dd8ccc739d794bf;hpb=ac0f1324b64f7310c31aecb5dbf23b3ae0d5a3e0 diff --git a/ui/ncurses/nc-menu.c b/ui/ncurses/nc-menu.c index 0420759..7d4442b 100644 --- a/ui/ncurses/nc-menu.c +++ b/ui/ncurses/nc-menu.c @@ -16,15 +16,20 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#define _GNU_SOURCE +#if defined(HAVE_CONFIG_H) +#include "config.h" +#endif #include #include #include +#include +#include #include "log/log.h" #include "talloc/talloc.h" #include "ui/common/ui-system.h" +#include "nc-cui.h" #include "nc-menu.h" /** @@ -73,45 +78,102 @@ static void pmenu_resize(struct nc_scr *scr) pmenu_post(scr); } +static int pmenu_item_destructor(void *arg) +{ + struct pmenu_item *item = arg; + free_item(item->nci); + return 0; +} + +static const char *pmenu_item_label(struct pmenu_item *item, const char *name) +{ + static int invalid_idx; + unsigned int i; + wchar_t *tmp; + char *label; + size_t len; + + len = mbstowcs(NULL, name, 0); + + /* if we have an invalid multibyte sequence, create an entirely + * new name, indicating that we had invalid input */ + if (len == SIZE_MAX) { + name = talloc_asprintf(item, "!Invalid option %d\n", + ++invalid_idx); + return name; + } + + tmp = talloc_array(item, wchar_t, len + 1); + mbstowcs(tmp, name, len + 1); + + /* replace anything unprintable with U+FFFD REPLACEMENT CHARACTER */ + for (i = 0; i < len; i++) { + if (!iswprint(tmp[i])) + tmp[i] = 0xfffd; + } + + len = wcstombs(NULL, tmp, 0); + label = talloc_array(item, char, len + 1); + wcstombs(label, tmp, len + 1); + + pb_log("%s: %s\n", __func__, label); + + talloc_free(tmp); + return label; +} + /** - * pmenu_item_init - Allocate and initialize a new pmenu_item instance. + * pmenu_item_create - Allocate and initialize a new pmenu_item instance. * * Returns a pointer the the initialized struct pmenu_item instance or NULL * on error. The caller is responsible for calling talloc_free() for the * returned instance. */ - -struct pmenu_item *pmenu_item_alloc(struct pmenu *menu) +struct pmenu_item *pmenu_item_create(struct pmenu *menu, const char *name) { - /* Items go with the menu, not the pointer array. */ + struct pmenu_item *item = talloc_zero(menu, struct pmenu_item); + const char *label; - struct pmenu_item *i = talloc_zero(menu, struct pmenu_item); + label = pmenu_item_label(item, name); - return i; -} + item->i_sig = pb_item_sig; + item->pmenu = menu; + item->nci = new_item(label, NULL); -struct pmenu_item *pmenu_item_setup(struct pmenu *menu, struct pmenu_item *i, - unsigned int index, const char *name) -{ - assert(i); - - if (!i) + if (!item->nci) { + talloc_free(item); return NULL; + } - i->i_sig = pb_item_sig; - i->pmenu = menu; - i->nci = new_item(name, NULL); + talloc_set_destructor(item, pmenu_item_destructor); - if (!i->nci) { - talloc_free(i); - return NULL; - } + set_item_userptr(item->nci, item); - set_item_userptr(i->nci, i); + return item; +} - menu->items[index] = i->nci; +void pmenu_item_insert(struct pmenu *menu, struct pmenu_item *item, + unsigned int index) +{ + assert(item); + assert(index < menu->item_count); + assert(menu->items[index] == NULL); + assert(menu_items(menu->ncm) == NULL); - return i; + menu->items[index] = item->nci; +} + +static int pmenu_item_get_index(const struct pmenu_item *item) +{ + unsigned int i; + + for (i = 0; i < item->pmenu->item_count; i++) + if (item->pmenu->items[i] == item->nci) + return i; + + pb_log("%s: not found: %p %s\n", __func__, item, + (item ? item->nci->name.str : "(null)")); + return -1; } /** @@ -129,69 +191,77 @@ static void pmenu_move_cursor(struct pmenu *menu, int req) * pmenu_process_key - Process a user keystroke. */ -static void pmenu_process_key(struct nc_scr *scr) +static void pmenu_process_key(struct nc_scr *scr, int key) { struct pmenu *menu = pmenu_from_scr(scr); struct pmenu_item *item = pmenu_find_selected(menu); nc_scr_status_free(&menu->scr); - while (1) { - int c = getch(); - - if (c == ERR) - return; - - /* DBGS("%d (%o)\n", c, c); */ - - if (menu->hot_key) - c = menu->hot_key(menu, item, c); - - switch (c) { - case 27: /* ESC */ - if (menu->on_exit) - menu->on_exit(menu); - nc_flush_keys(); - return; - - case KEY_PPAGE: - pmenu_move_cursor(menu, REQ_SCR_UPAGE); - break; - case KEY_NPAGE: - pmenu_move_cursor(menu, REQ_SCR_DPAGE); - break; - case KEY_HOME: - pmenu_move_cursor(menu, REQ_FIRST_ITEM); - break; - case KEY_END: - pmenu_move_cursor(menu, REQ_LAST_ITEM); - break; - case KEY_UP: - pmenu_move_cursor(menu, REQ_UP_ITEM); - break; - case KEY_DOWN: - case '\t': - pmenu_move_cursor(menu, REQ_DOWN_ITEM); - break; - case KEY_LEFT: - case 'e': - if (item->on_edit) - item->on_edit(item); - break; - case 'o': - DBGS("on_open: %p\n", menu->on_open); - if (menu->on_open) - menu->on_open(menu); - break; - case '\n': - case '\r': - if (item->on_execute) - item->on_execute(item); - break; - default: - menu_driver(menu->ncm, c); - break; - } + if (menu->hot_key) + key = menu->hot_key(menu, item, key); + + switch (key) { + case 27: /* ESC */ + case 'x': + if (menu->on_exit) + menu->on_exit(menu); + nc_flush_keys(); + return; + + case KEY_PPAGE: + pmenu_move_cursor(menu, REQ_SCR_UPAGE); + break; + case KEY_NPAGE: + pmenu_move_cursor(menu, REQ_SCR_DPAGE); + break; + case KEY_HOME: + pmenu_move_cursor(menu, REQ_FIRST_ITEM); + break; + case KEY_END: + pmenu_move_cursor(menu, REQ_LAST_ITEM); + break; + case KEY_UP: + pmenu_move_cursor(menu, REQ_UP_ITEM); + break; + case KEY_BTAB: + pmenu_move_cursor(menu, REQ_PREV_ITEM); + break; + case KEY_DOWN: + pmenu_move_cursor(menu, REQ_DOWN_ITEM); + break; + case '\t': + pmenu_move_cursor(menu, REQ_NEXT_ITEM); + break; + case 'e': + if (item->on_edit) + item->on_edit(item); + break; + case 'n': + if (menu->on_new) + menu->on_new(menu); + break; + case ' ': + case '\n': + case '\r': + if (item->on_execute) + item->on_execute(item); + break; + case 'i': + cui_show_sysinfo(cui_from_arg(scr->ui_ctx)); + break; + case 'c': + cui_show_config(cui_from_arg(scr->ui_ctx)); + break; + case KEY_F(1): + case 'h': + if (menu->help_text) + cui_show_help(cui_from_arg(scr->ui_ctx), + menu->help_title, menu->help_text); + break; + default: + menu_driver(menu->ncm, key); + break; } } @@ -230,19 +300,6 @@ unsigned int pmenu_grow(struct pmenu *menu, unsigned int count) return tmp; } -static int pmenu_item_get_index(const struct pmenu_item *item) -{ - unsigned int i; - - for (i = 0; i < item->pmenu->item_count; i++) - if (item->pmenu->items[i] == item->nci) - return i; - - pb_log("%s: not found: %p %s\n", __func__, item, - (item ? item->nci->name.str : "(null)")); - return -1; -} - /** * pmenu_remove - Remove an item from the item array. * @@ -264,6 +321,8 @@ int pmenu_remove(struct pmenu *menu, struct pmenu_item *item) if (index < 0) return -1; + talloc_free(item); + /* Note that items array has a null terminator. */ menu->insert_pt--; @@ -335,6 +394,8 @@ int pmenu_setup(struct pmenu *menu) /* Makes menu scrollable. */ set_menu_format(menu->ncm, LINES - nc_scr_frame_lines, 1); + set_menu_grey(menu->ncm, A_NORMAL); + return 0; } @@ -345,14 +406,10 @@ int pmenu_setup(struct pmenu *menu) void pmenu_delete(struct pmenu *menu) { - unsigned int i; - assert(menu->scr.sig == pb_pmenu_sig); menu->scr.sig = pb_removed_sig; - for (i = item_count(menu->ncm); i; i--) - free_item(menu->items[i]); - + unpost_menu(menu->ncm); free_menu(menu->ncm); delwin(menu->scr.sub_ncw); delwin(menu->scr.main_ncw);