big dialogs: set_curosr2 -> set_dlg_cursor.
[elinks.git] / src / bfu / listmenu.c
blobecf95677e6b29243240287e6baa3e9cee1eebf98
1 /* List menus functions */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <ctype.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
12 #include "elinks.h"
14 #include "bfu/listmenu.h"
15 #include "bfu/menu.h"
16 #include "session/session.h"
17 #include "util/conv.h"
18 #include "util/error.h"
19 #include "util/string.h"
20 #include "viewer/text/form.h" /* selected_item() and get_current_state() */
22 /* TODO: massive cleanup, merging, code redundancy tracking between this file
23 * and bfu/menu.c (and perhaps others.)
24 * We should unify and clarify menu-related code. */
26 static int
27 menu_contains(struct menu_item *m, int f)
29 if (m->func != do_select_submenu)
30 return (long) m->data == f;
32 foreach_menu_item (m, m->data) {
33 if (menu_contains(m, f))
34 return 1;
37 return 0;
40 void
41 do_select_submenu(struct terminal *term, void *menu_, void *ses_)
43 struct menu_item *menu = menu_;
44 struct session *ses = ses_;
45 struct menu_item *m;
46 int def = int_max(0, get_current_state(ses));
47 int sel = 0;
49 foreach_menu_item (m, menu) {
50 if (menu_contains(m, def)) {
51 sel = m - menu;
52 break;
56 do_menu_selected(term, menu, ses, sel, 0);
59 void
60 new_menu_item(struct list_menu *menu, unsigned char *name, int data, int fullname)
61 /* name == NULL - up; data == -1 - down */
63 struct menu_item *new_menu_item = NULL; /* no uninitialized warnings */
64 struct menu_item **items;
65 size_t stack_size = menu->stack_size;
67 if (!name) {
68 menu->stack_size--;
69 return;
71 } else if (data != -1 && menu->stack_size == 0) {
72 mem_free(name);
73 return;
76 clr_spaces(name);
77 if (!name[0]) {
78 mem_free(name);
79 name = stracpy(" ");
80 if (!name) return;
83 if (data == -1) {
84 int size = (menu->stack_size + 1) * sizeof(*menu->stack);
85 struct menu_item **stack = mem_realloc(menu->stack, size);
87 if (stack) {
88 menu->stack = stack;
89 new_menu_item = new_menu(NO_INTL);
92 if (!stack || !new_menu_item) {
93 if (new_menu_item) mem_free(new_menu_item);
94 mem_free(name);
95 return;
98 /* Since we increment @stack_size use cached value */
99 menu->stack[menu->stack_size++] = new_menu_item;
101 if (menu->stack_size == 1) {
102 mem_free(name);
103 return;
107 items = &menu->stack[stack_size - 1];
109 if (data == -1) {
110 add_to_menu(items, name, NULL, ACT_MAIN_NONE,
111 do_select_submenu,
112 new_menu_item, SUBMENU);
113 } else {
114 add_to_menu(items, name, NULL, ACT_MAIN_NONE,
115 selected_item,
116 (void *) (long) data, (fullname ? MENU_FULLNAME : 0));
119 if (stack_size >= 2) {
120 struct menu_item *below = menu->stack[stack_size - 2];
122 while (below->text) below++;
123 below[-1].data = *items;
127 void
128 init_menu(struct list_menu *menu)
130 menu->stack_size = 0;
131 menu->stack = NULL;
132 new_menu_item(menu, stracpy(""), -1, 0);
135 /* TODO: merge with free_menu_items() in bfu/menu.h --Zas */
136 void
137 free_menu(struct menu_item *m) /* Grrr. Recursion */
139 struct menu_item *mm;
141 if (!m) return; /* XXX: Who knows... need to be verified */
143 foreach_menu_item (mm, m) {
144 mem_free_if(mm->text);
145 if (mm->func == do_select_submenu) free_menu(mm->data);
148 mem_free(m);
151 struct menu_item *
152 detach_menu(struct list_menu *menu)
154 struct menu_item *i = NULL;
156 if (menu->stack) {
157 if (menu->stack_size) i = menu->stack[0];
158 mem_free(menu->stack);
161 return i;
164 void
165 destroy_menu(struct list_menu *menu)
167 if (menu->stack) free_menu(menu->stack[0]);
168 detach_menu(menu);
171 void
172 menu_labels(struct menu_item *items, unsigned char *base, unsigned char **lbls)
174 struct menu_item *item;
175 unsigned char *bs;
177 foreach_menu_item (item, items) {
178 bs = (item->flags & MENU_FULLNAME) ? (unsigned char *) ""
179 : base;
180 bs = straconcat(bs, item->text, (unsigned char *) NULL);
181 if (!bs) continue;
183 if (item->func == do_select_submenu) {
184 add_to_strn(&bs, " ");
185 menu_labels(item->data, bs, lbls);
186 mem_free(bs);
187 } else {
188 assert(item->func == selected_item);
189 lbls[(long) item->data] = bs;
194 void
195 add_select_item(struct list_menu *menu, struct string *string,
196 struct string *orig_string, unsigned char **value,
197 int order, int dont_add)
199 int pos = order - 1;
201 assert(menu && string);
203 if (!string->source) return;
205 assert(value && pos >= 0);
207 if (!value[pos])
208 /* <select> values are not mangled by various encode_*()
209 * functions, therefore we need to store them in the
210 * original document encoding. */
211 value[pos] = memacpy(orig_string->source, orig_string->length);
213 if (dont_add) {
214 done_string(string);
215 } else {
216 new_menu_item(menu, string->source, pos, 1);
217 string->source = NULL;
218 string->length = 0;
220 done_string(orig_string);