Make PHP 5 happy.
[elinks.git] / src / config / dialogs.c
blobd649d249aaf57074b3b7914f0951e0c2c6a86cfa
1 /* Options dialogs */
3 #ifndef _GNU_SOURCE
4 #define _GNU_SOURCE /* XXX: we _WANT_ strcasestr() ! */
5 #endif
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
11 #include <string.h>
13 #include "elinks.h"
15 #include "bfu/dialog.h"
16 #include "config/conf.h"
17 #include "config/dialogs.h"
18 #include "config/kbdbind.h"
19 #include "config/options.h"
20 #include "config/opttypes.h"
21 #include "intl/gettext/libintl.h"
22 #include "main/event.h"
23 #include "main/object.h"
24 #include "session/session.h"
25 #include "terminal/kbd.h"
26 #include "terminal/terminal.h"
27 #include "util/color.h"
28 #include "util/error.h"
29 #include "util/lists.h"
30 #include "util/memory.h"
31 #include "util/secsave.h"
34 static void
35 toggle_success_msgbox(void *dummy)
37 /* TODO: option_changed() */
38 get_opt_bool("ui.success_msgbox") = !get_opt_bool("ui.success_msgbox");
39 get_opt_rec(config_options, "ui.success_msgbox")->flags |= OPT_TOUCHED;
42 void
43 write_config_dialog(struct terminal *term, unsigned char *config_file,
44 int secsave_error, int stdio_error)
46 unsigned char *errmsg = NULL;
47 unsigned char *strerr;
49 if (secsave_error == SS_ERR_NONE && !stdio_error) {
50 if (!get_opt_bool("ui.success_msgbox")) return;
52 msg_box(term, NULL, MSGBOX_FREE_TEXT,
53 N_("Write config success"), ALIGN_CENTER,
54 msg_text(term, N_("Options were saved successfully to config file %s."),
55 config_file),
56 NULL, 2,
57 N_("~OK"), NULL, B_ENTER | B_ESC,
58 N_("~Do not show anymore"), toggle_success_msgbox, 0);
59 return;
62 switch (secsave_error) {
63 case SS_ERR_OPEN_READ:
64 strerr = _("Cannot read the file", term);
65 break;
66 case SS_ERR_STAT:
67 strerr = _("Cannot get file status", term);
68 break;
69 case SS_ERR_ACCESS:
70 strerr = _("Cannot access the file", term);
71 break;
72 case SS_ERR_MKSTEMP:
73 strerr = _("Cannot create temp file", term);
74 break;
75 case SS_ERR_RENAME:
76 strerr = _("Cannot rename the file", term);
77 break;
78 case SS_ERR_DISABLED:
79 strerr = _("File saving disabled by option", term);
80 break;
81 case SS_ERR_OUT_OF_MEM:
82 strerr = _("Out of memory", term);
83 break;
84 case SS_ERR_OPEN_WRITE:
85 strerr = _("Cannot write the file", term);
86 break;
87 case SS_ERR_NONE: /* Impossible. */
88 case SS_ERR_OTHER:
89 default:
90 strerr = _("Secure file saving error", term);
91 break;
94 if (stdio_error > 0)
95 errmsg = straconcat(strerr, " (", strerror(stdio_error), ")", NULL);
97 info_box(term, MSGBOX_FREE_TEXT,
98 N_("Write config error"), ALIGN_CENTER,
99 msg_text(term, N_("Unable to write to config file %s.\n%s"),
100 config_file, errmsg ? errmsg : strerr));
102 mem_free_if(errmsg);
107 /****************************************************************************
108 Option manager stuff.
109 ****************************************************************************/
111 /* Implementation of the listbox operations */
113 static void
114 lock_option(struct listbox_item *item)
116 object_lock((struct option *) item->udata);
119 static void
120 unlock_option(struct listbox_item *item)
122 object_unlock((struct option *) item->udata);
125 static int
126 is_option_used(struct listbox_item *item)
128 return is_object_used((struct option *) item->udata);
131 static unsigned char *
132 get_range_string(struct option *option)
134 struct string info;
136 if (!init_string(&info)) return NULL;
138 if (option->type == OPT_BOOL)
139 add_to_string(&info, "[0|1]");
140 else if (option->type == OPT_INT || option->type == OPT_LONG)
141 add_format_to_string(&info, "[%li..%li]", option->min, option->max);
143 return info.source;
146 static unsigned char *
147 get_option_text(struct listbox_item *item, struct terminal *term)
149 struct option *option = item->udata;
150 unsigned char *desc = option->capt ? option->capt : option->name;
152 if (option->flags & OPT_TOUCHED)
153 return straconcat(_(desc, term),
154 " (", _("modified", term), ")", NULL);
156 return stracpy(_(desc, term));
159 static unsigned char *
160 get_option_info(struct listbox_item *item, struct terminal *term)
162 struct option *option = item->udata;
163 unsigned char *desc, *type;
164 struct string info;
166 if (!init_string(&info)) return NULL;
168 add_format_to_string(&info, "%s: %s", _("Name", term), option->name);
170 type = _(option_types[option->type].name, term);
171 if (option->type == OPT_TREE) {
172 type = straconcat(type, " ",
173 _("(expand by pressing space)", term), NULL);
176 add_format_to_string(&info, "\n%s: %s", _("Type", term), type);
178 if (option->type == OPT_TREE) {
179 mem_free(type);
182 if (option_types[option->type].write) {
183 unsigned char *range;
184 struct string value;
186 if (!init_string(&value)) {
187 done_string(&info);
188 return NULL;
191 option_types[option->type].write(option, &value);
193 range = get_range_string(option);
194 if (range) {
195 if (*range) {
196 add_to_string(&info, " ");
197 add_to_string(&info, range);
199 mem_free(range);
201 add_format_to_string(&info, "\n%s: %s", _("Value", term), value.source);
202 done_string(&value);
204 if (option->flags & OPT_TOUCHED)
205 add_to_string(&info, _("\n\nThis value has been changed"
206 " since you last saved your"
207 " configuration.", term));
211 desc = _(option->desc ? option->desc : (unsigned char *) "N/A", term);
212 if (*desc)
213 add_format_to_string(&info, "\n\n%s:\n%s", _("Description", term), desc);
215 return info.source;
218 static struct listbox_item *
219 get_option_root(struct listbox_item *item)
221 struct option *option = item->udata;
223 /* The config_options root has no listbox so return that
224 * we are at the bottom. */
225 if (option->root == config_options) return NULL;
227 return option->root ? option->root->box_item : NULL;
230 static enum listbox_match
231 match_option(struct listbox_item *item, struct terminal *term,
232 unsigned char *text)
234 struct option *option = item->udata;
236 if (option->type == OPT_TREE)
237 return LISTBOX_MATCH_IMPOSSIBLE;
239 if (strcasestr(option->name, text)
240 || (option->capt && strcasestr(_(option->capt, term), text)))
241 return LISTBOX_MATCH_OK;
243 return LISTBOX_MATCH_NO;
246 static int
247 can_delete_option(struct listbox_item *item)
249 struct option *option = item->udata;
251 if (option->root) {
252 struct option *parent_option = option->root;
254 return parent_option->flags & OPT_AUTOCREATE;
257 return 0;
260 static void
261 delete_option_item(struct listbox_item *item, int last)
263 struct option *option = item->udata;
265 assert(!is_object_used(option));
267 /* Only built-in options needs to be marked as deleted, so if the
268 * option is allocated call the cleaner. */
269 if (option->flags & OPT_ALLOC)
270 delete_option(option);
271 else
272 mark_option_as_deleted(option);
275 static struct listbox_ops options_listbox_ops = {
276 lock_option,
277 unlock_option,
278 is_option_used,
279 get_option_text,
280 get_option_info,
281 NULL,
282 get_option_root,
283 match_option,
284 can_delete_option,
285 delete_option_item,
286 NULL,
287 NULL,
290 /* Button handlers */
292 static widget_handler_status_T
293 check_valid_option(struct dialog_data *dlg_data, struct widget_data *widget_data)
295 struct terminal *term = dlg_data->win->term;
296 struct option *option = dlg_data->dlg->udata;
297 struct session *ses = dlg_data->dlg->udata2;
298 unsigned char *value = widget_data->cdata;
299 unsigned char *chinon;
300 int dummy_line = 0;
302 commandline = 1;
303 chinon = option_types[option->type].read(option, &value, &dummy_line);
304 if (chinon) {
305 if (option_types[option->type].set &&
306 option_types[option->type].set(option, chinon)) {
307 struct option *current = option;
309 option_changed(ses, current, option);
311 commandline = 0;
312 mem_free(chinon);
313 return EVENT_PROCESSED;
315 mem_free(chinon);
317 commandline = 0;
319 info_box(term, 0,
320 N_("Error"), ALIGN_LEFT,
321 N_("Bad option value."));
323 return EVENT_NOT_PROCESSED;
326 static void
327 build_edit_dialog(struct terminal *term, struct session *ses,
328 struct option *option)
330 #define EDIT_WIDGETS_COUNT 5
331 struct dialog *dlg;
332 unsigned char *value, *name, *desc, *range;
333 struct string tvalue;
335 if (!init_string(&tvalue)) return;
337 commandline = 1;
338 option_types[option->type].write(option, &tvalue);
339 commandline = 0;
341 /* Create the dialog */
342 dlg = calloc_dialog(EDIT_WIDGETS_COUNT, MAX_STR_LEN);
343 if (!dlg) {
344 done_string(&tvalue);
345 return;
348 dlg->title = _("Edit", term);
349 dlg->layouter = generic_dialog_layouter;
350 dlg->udata = option;
351 dlg->udata2 = ses;
353 value = get_dialog_offset(dlg, EDIT_WIDGETS_COUNT);
354 safe_strncpy(value, tvalue.source, MAX_STR_LEN);
355 done_string(&tvalue);
357 name = straconcat(_("Name", term), ": ", option->name, "\n",
358 _("Type", term), ": ",
359 _(option_types[option->type].name, term), NULL);
360 desc = straconcat(_("Description", term), ": \n",
361 _(option->desc ? option->desc
362 : (unsigned char *) "N/A", term),
363 NULL);
364 range = get_range_string(option);
365 if (range) {
366 if (*range) {
367 unsigned char *tmp;
369 tmp = straconcat(name, " ", range, NULL);
370 if (tmp) {
371 mem_free(name);
372 name = tmp;
375 mem_free(range);
378 if (!name || !desc) {
379 mem_free_if(name);
380 mem_free_if(desc);
381 mem_free(dlg);
382 return;
385 /* FIXME: Compute some meaningful maximal width. --pasky */
386 add_dlg_text(dlg, name, ALIGN_LEFT, 0);
387 add_dlg_field_float(dlg, _("Value", term), 0, 0, check_valid_option, MAX_STR_LEN, value, NULL);
389 add_dlg_text(dlg, desc, ALIGN_LEFT, 0);
391 add_dlg_button(dlg, _("~OK", term), B_ENTER, ok_dialog, NULL);
392 add_dlg_button(dlg, _("~Cancel", term), B_ESC, cancel_dialog, NULL);
394 add_dlg_end(dlg, EDIT_WIDGETS_COUNT);
396 do_dialog(term, dlg, getml(dlg, name, desc, NULL));
397 #undef EDIT_WIDGETS_COUNT
400 static widget_handler_status_T
401 push_edit_button(struct dialog_data *dlg_data,
402 struct widget_data *some_useless_info_button)
404 struct terminal *term = dlg_data->win->term;
405 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
406 struct option *option;
408 /* Show history item info */
409 if (!box->sel || !box->sel->udata) return EVENT_PROCESSED;
410 option = box->sel->udata;
412 if (!option_types[option->type].write ||
413 !option_types[option->type].read ||
414 !option_types[option->type].set) {
415 info_box(term, 0,
416 N_("Edit"), ALIGN_LEFT,
417 N_("This option cannot be edited. This means that "
418 "this is some special option like a folder - try "
419 "to press a space in order to see its contents."));
420 return EVENT_PROCESSED;
423 build_edit_dialog(term, dlg_data->dlg->udata, option);
425 return EVENT_PROCESSED;
429 struct add_option_to_tree_ctx {
430 struct option *option;
431 struct widget_data *widget_data;
434 static void
435 add_option_to_tree(void *data, unsigned char *name)
437 struct add_option_to_tree_ctx *ctx = data;
438 struct option *old = get_opt_rec_real(ctx->option, name);
439 struct option *new;
441 if (old && (old->flags & OPT_DELETED)) delete_option(old);
442 /* get_opt_rec() will create the option. */
443 new = get_opt_rec(ctx->option, name);
444 if (new) listbox_sel(ctx->widget_data, new->box_item);
445 /* TODO: If the return value is NULL, we should pop up a msgbox. */
448 static widget_handler_status_T
449 check_option_name(struct dialog_data *dlg_data, struct widget_data *widget_data)
451 unsigned char *p;
453 for (p = widget_data->cdata; *p; p++)
454 /* Not '*' since it is used internally. */
455 if (!isident(*p)) {
456 /* FIXME: Encode '.' into '*'? */
457 info_box(dlg_data->win->term, 0,
458 N_("Bad string"), ALIGN_CENTER,
459 N_("Option names may only contain alpha-numeric characters\n"
460 "in addition to '_' and '-'."));
461 return EVENT_NOT_PROCESSED;
464 return EVENT_PROCESSED;
466 static widget_handler_status_T
467 push_add_button(struct dialog_data *dlg_data,
468 struct widget_data *some_useless_info_button)
470 struct terminal *term = dlg_data->win->term;
471 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
472 struct listbox_item *item = box->sel;
473 struct option *option;
474 struct add_option_to_tree_ctx *ctx;
476 if (!item || !item->udata) {
478 invalid_option:
479 info_box(term, 0, N_("Add option"), ALIGN_CENTER,
480 N_("Cannot add an option here."));
481 return EVENT_PROCESSED;
485 if (item->type == BI_FOLDER && !item->expanded) {
486 item = box->ops->get_root(item);
487 if (!item || !item->udata)
488 goto invalid_option;
491 option = item->udata;
493 if (!(option->flags & OPT_AUTOCREATE)) {
494 if (option->root) option = option->root;
495 if (!option || !(option->flags & OPT_AUTOCREATE))
496 goto invalid_option;
499 ctx = mem_alloc(sizeof(*ctx));
500 if (!ctx) return EVENT_PROCESSED;
501 ctx->option = option;
502 ctx->widget_data = dlg_data->widgets_data;
504 input_dialog(term, getml(ctx, NULL), N_("Add option"), N_("Name"),
505 ctx, NULL,
506 MAX_STR_LEN, "", 0, 0, check_option_name,
507 add_option_to_tree, NULL);
509 return EVENT_PROCESSED;
513 static widget_handler_status_T
514 push_save_button(struct dialog_data *dlg_data,
515 struct widget_data *some_useless_info_button)
517 write_config(dlg_data->win->term);
519 update_hierbox_browser(&option_browser);
521 return EVENT_PROCESSED;
525 static struct hierbox_browser_button option_buttons[] = {
526 { N_("~Info"), push_hierbox_info_button, 1 },
527 { N_("~Edit"), push_edit_button, 0 },
528 { N_("~Add"), push_add_button, 0 },
529 { N_("~Delete"), push_hierbox_delete_button, 0 },
530 { N_("~Search"), push_hierbox_search_button, 1 },
531 { N_("Sa~ve"), push_save_button, 0 },
534 struct_hierbox_browser(
535 option_browser,
536 N_("Option manager"),
537 option_buttons,
538 &options_listbox_ops
541 /* Builds the "Options manager" dialog */
542 void
543 options_manager(struct session *ses)
545 hierbox_browser(&option_browser, ses);
549 /****************************************************************************
550 Keybinding manager stuff.
551 ****************************************************************************/
553 #ifdef CONFIG_SMALL
554 static int keybinding_text_toggle = 1;
555 #else
556 static int keybinding_text_toggle;
557 #endif
559 /* XXX: ACTION_BOX_SIZE is just a quick hack, we ought to allocate
560 * the sub-arrays separately. --pasky */
561 #define ACTION_BOX_SIZE 128
562 static struct listbox_item *action_box_items[KEYMAP_MAX][ACTION_BOX_SIZE];
564 struct listbox_item *
565 get_keybinding_action_box_item(enum keymap_id keymap_id, action_id_T action_id)
567 assert(action_id < ACTION_BOX_SIZE);
568 if_assert_failed return NULL;
570 return action_box_items[keymap_id][action_id];
573 struct listbox_item *keymap_box_item[KEYMAP_MAX];
575 void
576 init_keybinding_listboxes(struct keymap keymap_table[KEYMAP_MAX], struct action_list actions[])
578 struct listbox_item *root = &keybinding_browser.root;
579 struct action *act;
580 enum keymap_id keymap_id;
582 /* Do it backwards because add_listbox_item() add to front
583 * of list. */
584 for (keymap_id = 0; keymap_id < KEYMAP_MAX; keymap_id++) {
585 struct listbox_item *keymap_box;
587 keymap_box = add_listbox_item(NULL, root, BI_FOLDER, &keymap_table[keymap_id], -1);
588 if (!keymap_box) continue;
590 for (act = actions[keymap_id].actions; act->str; act++) {
591 struct listbox_item *item;
593 assert(act->num < ACTION_BOX_SIZE);
594 if_assert_failed continue;
596 if (act->num == ACT_MAIN_SCRIPTING_FUNCTION
597 || act->num == ACT_MAIN_NONE)
598 continue;
600 #ifndef CONFIG_SMALL
601 assert(act->desc);
602 #endif
604 item = add_listbox_item(NULL, keymap_box, BI_FOLDER, act, -1);
605 if (!item) continue;
607 item->expanded = 1;
609 action_box_items[keymap_id][act->num] = item;
612 keymap_box_item[keymap_id] = keymap_box;
616 void
617 done_keybinding_listboxes(void)
619 struct listbox_item *action;
621 foreach (action, keybinding_browser.root.child) {
622 struct listbox_item *keymap;
624 foreach (keymap, action->child) {
625 free_list(keymap->child);
627 free_list(action->child);
629 free_list(keybinding_browser.root.child);
633 /* Implementation of the listbox operations */
635 /* XXX: If anything but delete button will use these object_*() requiring
636 * functions we have to check if it is action or keymap box items. */
638 static void
639 lock_keybinding(struct listbox_item *item)
641 if (item->depth == 2)
642 object_lock((struct keybinding *) item->udata);
645 static void
646 unlock_keybinding(struct listbox_item *item)
648 if (item->depth == 2)
649 object_unlock((struct keybinding *) item->udata);
652 static int
653 is_keybinding_used(struct listbox_item *item)
655 if (item->depth != 2) return 0;
656 return is_object_used((struct keybinding *) item->udata);
659 static unsigned char *
660 get_keybinding_text(struct listbox_item *item, struct terminal *term)
662 struct keybinding *keybinding = item->udata;
663 struct string info;
665 if (item->depth == 0) {
666 struct keymap *keymap = item->udata;
668 return stracpy(keybinding_text_toggle ? keymap->str
669 : _(keymap->desc, term));
670 } else if (item->depth < 2) {
671 struct action *action = item->udata;
673 return stracpy(keybinding_text_toggle ? action->str
674 : _(action->desc, term));
677 if (!init_string(&info)) return NULL;
678 add_keystroke_to_string(&info, &keybinding->kbd, 0);
679 return info.source;
682 static unsigned char *
683 get_keybinding_info(struct listbox_item *item, struct terminal *term)
685 struct keybinding *keybinding = item->udata;
686 unsigned char *action, *keymap;
687 struct string info;
689 if (item->depth < 2) return NULL;
690 if (item->type == BI_FOLDER) return NULL;
692 if (!init_string(&info))
693 return NULL;
695 action = get_action_name(keybinding->keymap_id, keybinding->action_id);
696 keymap = get_keymap_name(keybinding->keymap_id);
698 add_format_to_string(&info, "%s: ", _("Keystroke", term));
699 add_keystroke_to_string(&info, &keybinding->kbd, 0);
700 add_format_to_string(&info, "\n%s: %s", _("Action", term), action);
701 add_format_to_string(&info, "\n%s: %s", _("Keymap", term), keymap);
703 return info.source;
706 static struct listbox_item *
707 get_keybinding_root(struct listbox_item *item)
709 /* .. at the bottom */
710 if (item->depth == 0) return NULL;
712 if (item->depth == 1) {
713 struct action *action = item->udata;
715 return keymap_box_item[action->keymap_id];
716 } else {
717 struct keybinding *kb = item->udata;
719 return get_keybinding_action_box_item(kb->keymap_id, kb->action_id);
723 static enum listbox_match
724 match_keybinding(struct listbox_item *item, struct terminal *term,
725 unsigned char *text)
727 struct action *action = item->udata;
728 unsigned char *desc;
730 if (item->depth != 1)
731 return LISTBOX_MATCH_IMPOSSIBLE;
733 desc = keybinding_text_toggle
734 ? action->str : _(action->desc, term);
736 if ((desc && strcasestr(desc, text)))
737 return LISTBOX_MATCH_OK;
739 return LISTBOX_MATCH_NO;
742 static int
743 can_delete_keybinding(struct listbox_item *item)
745 return item->depth == 2;
749 static void
750 delete_keybinding_item(struct listbox_item *item, int last)
752 struct keybinding *keybinding = item->udata;
754 assert(item->depth == 2 && !is_object_used(keybinding));
756 free_keybinding(keybinding);
759 static struct listbox_ops keybinding_listbox_ops = {
760 lock_keybinding,
761 unlock_keybinding,
762 is_keybinding_used,
763 get_keybinding_text,
764 get_keybinding_info,
765 NULL,
766 get_keybinding_root,
767 match_keybinding,
768 can_delete_keybinding,
769 delete_keybinding_item,
770 NULL,
771 NULL,
775 struct kbdbind_add_hop {
776 struct terminal *term;
777 action_id_T action_id;
778 enum keymap_id keymap_id;
779 struct term_event_keyboard kbd;
780 struct widget_data *widget_data;
783 struct kbdbind_add_hop *
784 new_hop_from(struct kbdbind_add_hop *hop)
786 struct kbdbind_add_hop *new_hop = mem_alloc(sizeof(*new_hop));
788 if (new_hop)
789 copy_struct(new_hop, hop);
791 return new_hop;
794 static void
795 really_really_add_keybinding(void *data)
797 struct kbdbind_add_hop *hop = data;
798 struct keybinding *keybinding;
800 assert(hop);
802 keybinding = add_keybinding(hop->keymap_id, hop->action_id, &hop->kbd,
803 EVENT_NONE);
805 if (keybinding && keybinding->box_item)
806 listbox_sel(hop->widget_data, keybinding->box_item);
809 static void
810 really_add_keybinding(void *data, unsigned char *keystroke)
812 struct kbdbind_add_hop *hop = data;
813 action_id_T action_id;
815 if (keybinding_exists(hop->keymap_id, &hop->kbd, &action_id)
816 && action_id != ACT_MAIN_NONE) {
817 struct kbdbind_add_hop *new_hop;
819 /* Same keystroke for same action, just return. */
820 if (action_id == hop->action_id) return;
822 new_hop = new_hop_from(hop);
823 if (!new_hop) return; /* out of mem */
825 msg_box(new_hop->term, getml(new_hop, NULL), MSGBOX_FREE_TEXT,
826 N_("Keystroke already used"), ALIGN_CENTER,
827 msg_text(new_hop->term, N_("The keystroke \"%s\" "
828 "is currently used for \"%s\".\n"
829 "Are you sure you want to replace it?"),
830 keystroke, get_action_name(hop->keymap_id, action_id)),
831 new_hop, 2,
832 N_("~Yes"), really_really_add_keybinding, B_ENTER,
833 N_("~No"), NULL, B_ESC);
835 return;
838 really_really_add_keybinding((void *) hop);
841 widget_handler_status_T
842 check_keystroke(struct dialog_data *dlg_data, struct widget_data *widget_data)
844 struct kbdbind_add_hop *hop = dlg_data->dlg->udata2;
845 unsigned char *keystroke = widget_data->cdata;
847 if (parse_keystroke(keystroke, &hop->kbd) >= 0)
848 return EVENT_PROCESSED;
850 info_box(hop->term, 0, N_("Add keybinding"), ALIGN_CENTER,
851 N_("Invalid keystroke."));
853 return EVENT_NOT_PROCESSED;
856 static widget_handler_status_T
857 push_kbdbind_add_button(struct dialog_data *dlg_data,
858 struct widget_data *some_useless_info_button)
860 struct terminal *term = dlg_data->win->term;
861 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
862 struct listbox_item *item = box->sel;
863 struct kbdbind_add_hop *hop;
864 unsigned char *text;
866 if (!item || !item->depth) {
867 info_box(term, 0, N_("Add keybinding"), ALIGN_CENTER,
868 N_("Need to select a keymap."));
869 return EVENT_PROCESSED;
872 hop = mem_calloc(1, sizeof(*hop));
873 if (!hop) return EVENT_PROCESSED;
874 hop->term = term;
875 hop->widget_data = dlg_data->widgets_data;
877 if (item->depth == 2) {
878 struct keybinding *keybinding = item->udata;
880 hop->action_id = keybinding->action_id;
881 hop->keymap_id = keybinding->keymap_id;
882 } else {
883 struct action *action = item->udata;
885 hop->action_id = action->num;
886 hop->keymap_id = action->keymap_id;
889 text = msg_text(term,
890 "Action: %s\n"
891 "Keymap: %s\n"
892 "\n"
893 "Keystroke should be written in the format: "
894 "[Prefix-]Key\n"
895 "Prefix: Shift, Ctrl, Alt\n"
896 "Key: a,b,c,...,1,2,3,...,Space,Up,PageDown,"
897 "Tab,Enter,Insert,F5,..."
898 "\n\n"
899 "Keystroke",
900 get_action_name(hop->keymap_id, hop->action_id),
901 get_keymap_name(hop->keymap_id));
903 input_dialog(term, getml(hop, text, NULL),
904 N_("Add keybinding"), text,
905 hop, NULL,
906 MAX_STR_LEN, "", 0, 0, check_keystroke,
907 really_add_keybinding, NULL);
909 return EVENT_PROCESSED;
913 static widget_handler_status_T
914 push_kbdbind_toggle_display_button(struct dialog_data *dlg_data,
915 struct widget_data *some_useless_info_button)
917 #ifndef CONFIG_SMALL
918 keybinding_text_toggle = !keybinding_text_toggle;
919 clear_dialog(dlg_data, some_useless_info_button);
920 #endif
921 return EVENT_PROCESSED;
925 /* FIXME: Races here, we need to lock the entry..? --pasky */
927 static widget_handler_status_T
928 push_kbdbind_save_button(struct dialog_data *dlg_data,
929 struct widget_data *some_useless_info_button)
931 write_config(dlg_data->win->term);
932 return EVENT_PROCESSED;
936 static INIT_LIST_HEAD(keybinding_dialog_list);
938 static struct hierbox_browser_button keybinding_buttons[] = {
939 { N_("~Add"), push_kbdbind_add_button, 0 },
940 { N_("~Delete"), push_hierbox_delete_button, 0 },
941 { N_("~Toggle display"), push_kbdbind_toggle_display_button, 1 },
942 { N_("~Search"), push_hierbox_search_button, 1 },
943 { N_("Sa~ve"), push_kbdbind_save_button, 0 },
946 struct_hierbox_browser(
947 keybinding_browser,
948 N_("Keybinding manager"),
949 keybinding_buttons,
950 &keybinding_listbox_ops
953 /* Builds the "Keybinding manager" dialog */
954 void
955 keybinding_manager(struct session *ses)
957 hierbox_browser(&keybinding_browser, ses);