/* List menus functions */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include #include "elinks.h" #include "bfu/listmenu.h" #include "bfu/menu.h" #include "session/session.h" #include "util/conv.h" #include "util/error.h" #include "util/string.h" #include "viewer/text/form.h" /* selected_item() and get_current_state() */ /* TODO: massive cleanup, merging, code redundancy tracking between this file * and bfu/menu.c (and perhaps others.) * We should unify and clarify menu-related code. */ static int menu_contains(struct menu_item *m, int f) { if (m->func != do_select_submenu) return (long) m->data == f; foreach_menu_item (m, m->data) { if (menu_contains(m, f)) return 1; } return 0; } void do_select_submenu(struct terminal *term, void *menu_, void *ses_) { struct menu_item *menu = menu_; struct session *ses = ses_; struct menu_item *m; int def = int_max(0, get_current_state(ses)); int sel = 0; foreach_menu_item (m, menu) { if (menu_contains(m, def)) { sel = m - menu; break; } } do_menu_selected(term, menu, ses, sel, 0); } void new_menu_item(struct list_menu *menu, unsigned char *name, int data, int fullname) /* name == NULL - up; data == -1 - down */ { struct menu_item *new_menu_item = NULL; /* no uninitialized warnings */ struct menu_item **items; size_t stack_size = menu->stack_size; if (!name) { menu->stack_size--; return; } else if (data != -1 && menu->stack_size == 0) { mem_free(name); return; } clr_spaces(name); if (!name[0]) { mem_free(name); name = stracpy(" "); if (!name) return; } if (data == -1) { int size = (menu->stack_size + 1) * sizeof(*menu->stack); struct menu_item **stack = mem_realloc(menu->stack, size); if (stack) { menu->stack = stack; new_menu_item = new_menu(NO_INTL); } if (!stack || !new_menu_item) { if (new_menu_item) mem_free(new_menu_item); mem_free(name); return; } /* Since we increment @stack_size use cached value */ menu->stack[menu->stack_size++] = new_menu_item; if (menu->stack_size == 1) { mem_free(name); return; } } items = &menu->stack[stack_size - 1]; if (data == -1) { add_to_menu(items, name, NULL, ACT_MAIN_NONE, do_select_submenu, new_menu_item, SUBMENU); } else { add_to_menu(items, name, NULL, ACT_MAIN_NONE, selected_item, (void *) (long) data, (fullname ? MENU_FULLNAME : 0)); } if (stack_size >= 2) { struct menu_item *below = menu->stack[stack_size - 2]; while (below->text) below++; below[-1].data = *items; } } void init_menu(struct list_menu *menu) { menu->stack_size = 0; menu->stack = NULL; new_menu_item(menu, stracpy(""), -1, 0); } /* TODO: merge with free_menu_items() in bfu/menu.h --Zas */ void free_menu(struct menu_item *m) /* Grrr. Recursion */ { struct menu_item *mm; if (!m) return; /* XXX: Who knows... need to be verified */ foreach_menu_item (mm, m) { mem_free_if(mm->text); if (mm->func == do_select_submenu) free_menu(mm->data); } mem_free(m); } struct menu_item * detach_menu(struct list_menu *menu) { struct menu_item *i = NULL; if (menu->stack) { if (menu->stack_size) i = menu->stack[0]; mem_free(menu->stack); } return i; } void destroy_menu(struct list_menu *menu) { if (menu->stack) free_menu(menu->stack[0]); detach_menu(menu); } void menu_labels(struct menu_item *items, unsigned char *base, unsigned char **lbls) { struct menu_item *item; unsigned char *bs; foreach_menu_item (item, items) { bs = (item->flags & MENU_FULLNAME) ? (unsigned char *) "" : base; bs = straconcat(bs, item->text, NULL); if (!bs) continue; if (item->func == do_select_submenu) { add_to_strn(&bs, " "); menu_labels(item->data, bs, lbls); mem_free(bs); } else { assert(item->func == selected_item); lbls[(long) item->data] = bs; } } } void add_select_item(struct list_menu *menu, struct string *string, struct string *orig_string, unsigned char **value, int order, int dont_add) { int pos = order - 1; assert(menu && string); if (!string->source) return; assert(value && pos >= 0); if (!value[pos]) /*