Show fractions of MiBs in download progress dialogs.
[elinks/elinks-j605.git] / src / config / dialogs.c
blobcbb51a018a6b00afa54708ac44bc6146027bd597
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 disable_success_msgbox(void *dummy)
37 get_opt_bool("ui.success_msgbox", NULL) = 0;
38 option_changed(NULL, get_opt_rec(config_options, "ui.success_msgbox"));
41 void
42 write_config_dialog(struct terminal *term, unsigned char *config_file,
43 int secsave_error, int stdio_error)
45 /* [gettext_accelerator_context(write_config_dialog)] */
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", NULL)) 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 MSG_BOX_BUTTON(N_("~OK"), NULL, B_ENTER | B_ESC),
58 MSG_BOX_BUTTON(N_("~Do not show anymore"), disable_success_msgbox, 0));
59 return;
62 strerr = secsave_strerror(secsave_error, term);
64 if (stdio_error > 0)
65 errmsg = straconcat(strerr, " (", strerror(stdio_error), ")",
66 (unsigned char *) NULL);
68 info_box(term, MSGBOX_FREE_TEXT,
69 N_("Write config error"), ALIGN_CENTER,
70 msg_text(term, N_("Unable to write to config file %s.\n%s"),
71 config_file, errmsg ? errmsg : strerr));
73 mem_free_if(errmsg);
78 /****************************************************************************
79 Option manager stuff.
80 ****************************************************************************/
82 /* Implementation of the listbox operations */
84 static void
85 lock_option(struct listbox_item *item)
87 object_lock((struct option *) item->udata);
90 static void
91 unlock_option(struct listbox_item *item)
93 object_unlock((struct option *) item->udata);
96 static int
97 is_option_used(struct listbox_item *item)
99 return is_object_used((struct option *) item->udata);
102 static unsigned char *
103 get_range_string(struct option *option)
105 struct string info;
107 if (!init_string(&info)) return NULL;
109 if (option->type == OPT_BOOL)
110 add_to_string(&info, "[0|1]");
111 else if (option->type == OPT_INT || option->type == OPT_LONG)
112 add_format_to_string(&info, "[%li..%li]", option->min, option->max);
114 return info.source;
117 static unsigned char *
118 get_option_text(struct listbox_item *item, struct terminal *term)
120 struct option *option = item->udata;
121 unsigned char *desc = option->capt ? option->capt : option->name;
123 if (option->flags & OPT_TOUCHED)
124 return straconcat(_(desc, term),
125 " (", _("modified", term), ")",
126 (unsigned char *) NULL);
128 return stracpy(_(desc, term));
131 static unsigned char *
132 get_option_info(struct listbox_item *item, struct terminal *term)
134 struct option *option = item->udata;
135 unsigned char *desc, *type;
136 struct string info;
138 if (!init_string(&info)) return NULL;
140 add_format_to_string(&info, "%s: %s", _("Name", term), option->name);
142 type = _(option_types[option->type].name, term);
143 if (option->type == OPT_TREE) {
144 type = straconcat(type, " ",
145 _("(expand by pressing space)", term),
146 (unsigned char *) NULL);
149 add_format_to_string(&info, "\n%s: %s", _("Type", term), type);
151 if (option->type == OPT_TREE) {
152 mem_free(type);
155 if (option_types[option->type].write) {
156 unsigned char *range;
157 struct string value;
159 if (!init_string(&value)) {
160 done_string(&info);
161 return NULL;
164 option_types[option->type].write(option, &value);
166 range = get_range_string(option);
167 if (range) {
168 if (*range) {
169 add_to_string(&info, " ");
170 add_to_string(&info, range);
172 mem_free(range);
174 add_format_to_string(&info, "\n%s: %s", _("Value", term), value.source);
175 done_string(&value);
177 if (option->flags & OPT_TOUCHED)
178 add_to_string(&info, _("\n\nThis value has been changed"
179 " since you last saved your"
180 " configuration.", term));
184 desc = _(option->desc ? option->desc : (unsigned char *) "N/A", term);
185 if (*desc)
186 add_format_to_string(&info, "\n\n%s:\n%s", _("Description", term), desc);
188 return info.source;
191 static struct listbox_item *
192 get_option_root(struct listbox_item *item)
194 struct option *option = item->udata;
196 /* The config_options root has no listbox so return that
197 * we are at the bottom. */
198 if (option->root == config_options) return NULL;
200 return option->root ? option->root->box_item : NULL;
203 static enum listbox_match
204 match_option(struct listbox_item *item, struct terminal *term,
205 unsigned char *text)
207 struct option *option = item->udata;
209 if (option->type == OPT_TREE)
210 return LISTBOX_MATCH_IMPOSSIBLE;
212 if (strcasestr(option->name, text)
213 || (option->capt && strcasestr(_(option->capt, term), text)))
214 return LISTBOX_MATCH_OK;
216 return LISTBOX_MATCH_NO;
219 static int
220 can_delete_option(struct listbox_item *item)
222 struct option *option = item->udata;
224 if (option->root) {
225 struct option *parent_option = option->root;
227 return parent_option->flags & OPT_AUTOCREATE;
230 return 0;
233 static void
234 delete_option_item(struct listbox_item *item, int last)
236 struct option *option = item->udata;
238 assert(!is_object_used(option));
240 /* Only built-in options needs to be marked as deleted, so if the
241 * option is allocated call the cleaner. */
242 if (option->flags & OPT_ALLOC)
243 delete_option(option);
244 else
245 mark_option_as_deleted(option);
248 static const struct listbox_ops options_listbox_ops = {
249 lock_option,
250 unlock_option,
251 is_option_used,
252 get_option_text,
253 get_option_info,
254 NULL,
255 get_option_root,
256 match_option,
257 can_delete_option,
258 delete_option_item,
259 NULL,
260 NULL,
263 /* Button handlers */
265 static widget_handler_status_T
266 check_valid_option(struct dialog_data *dlg_data, struct widget_data *widget_data)
268 struct terminal *term = dlg_data->win->term;
269 struct option *option = dlg_data->dlg->udata;
270 struct session *ses = dlg_data->dlg->udata2;
271 unsigned char *value = widget_data->cdata;
272 unsigned char *chinon;
273 int dummy_line = 0;
275 commandline = 1;
276 chinon = option_types[option->type].read(option, &value, &dummy_line);
277 if (chinon) {
278 if (option_types[option->type].set &&
279 option_types[option->type].set(option, chinon)) {
280 option_changed(ses, option);
282 commandline = 0;
283 mem_free(chinon);
284 return EVENT_PROCESSED;
286 mem_free(chinon);
288 commandline = 0;
290 info_box(term, 0,
291 N_("Error"), ALIGN_LEFT,
292 N_("Bad option value."));
294 return EVENT_NOT_PROCESSED;
297 static void
298 build_edit_dialog(struct terminal *term, struct session *ses,
299 struct option *option)
301 /* [gettext_accelerator_context(.build_edit_dialog)] */
302 #define EDIT_WIDGETS_COUNT 5
303 struct dialog *dlg;
304 unsigned char *value, *name, *desc, *range;
305 struct string tvalue;
307 if (!init_string(&tvalue)) return;
309 commandline = 1;
310 option_types[option->type].write(option, &tvalue);
311 commandline = 0;
313 /* Create the dialog */
314 dlg = calloc_dialog(EDIT_WIDGETS_COUNT, MAX_STR_LEN);
315 if (!dlg) {
316 done_string(&tvalue);
317 return;
320 dlg->title = _("Edit", term);
321 dlg->layouter = generic_dialog_layouter;
322 dlg->udata = option;
323 dlg->udata2 = ses;
325 value = get_dialog_offset(dlg, EDIT_WIDGETS_COUNT);
326 safe_strncpy(value, tvalue.source, MAX_STR_LEN);
327 done_string(&tvalue);
329 name = straconcat(_("Name", term), ": ", option->name, "\n",
330 _("Type", term), ": ",
331 _(option_types[option->type].name, term),
332 (unsigned char *) NULL);
333 desc = straconcat(_("Description", term), ": \n",
334 _(option->desc ? option->desc
335 : (unsigned char *) "N/A", term),
336 (unsigned char *) NULL);
337 range = get_range_string(option);
338 if (range) {
339 if (*range) {
340 unsigned char *tmp;
342 tmp = straconcat(name, " ", range,
343 (unsigned char *) NULL);
344 if (tmp) {
345 mem_free(name);
346 name = tmp;
349 mem_free(range);
352 if (!name || !desc) {
353 mem_free_if(name);
354 mem_free_if(desc);
355 mem_free(dlg);
356 return;
359 /* FIXME: Compute some meaningful maximal width. --pasky */
360 add_dlg_text(dlg, name, ALIGN_LEFT, 0);
361 add_dlg_field_float(dlg, _("Value", term), 0, 0, check_valid_option, MAX_STR_LEN, value, NULL);
363 add_dlg_text(dlg, desc, ALIGN_LEFT, 0);
365 add_dlg_button(dlg, _("~OK", term), B_ENTER, ok_dialog, NULL);
366 add_dlg_button(dlg, _("~Cancel", term), B_ESC, cancel_dialog, NULL);
368 add_dlg_end(dlg, EDIT_WIDGETS_COUNT);
370 do_dialog(term, dlg, getml(dlg, (void *) name, (void *) desc, (void *) NULL));
371 #undef EDIT_WIDGETS_COUNT
374 static widget_handler_status_T
375 push_edit_button(struct dialog_data *dlg_data,
376 struct widget_data *some_useless_info_button)
378 struct terminal *term = dlg_data->win->term;
379 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
380 struct option *option;
382 /* Show history item info */
383 if (!box->sel || !box->sel->udata) return EVENT_PROCESSED;
384 option = box->sel->udata;
386 if (!option_types[option->type].write ||
387 !option_types[option->type].read ||
388 !option_types[option->type].set) {
389 info_box(term, 0,
390 N_("Edit"), ALIGN_LEFT,
391 N_("This option cannot be edited. This means that "
392 "this is some special option like a folder - try "
393 "to press a space in order to see its contents."));
394 return EVENT_PROCESSED;
397 build_edit_dialog(term, dlg_data->dlg->udata, option);
399 return EVENT_PROCESSED;
403 struct add_option_to_tree_ctx {
404 struct option *option;
405 struct widget_data *widget_data;
408 static void
409 add_option_to_tree(void *data, unsigned char *name)
411 struct add_option_to_tree_ctx *ctx = data;
412 struct option *old = get_opt_rec_real(ctx->option, name);
413 struct option *new;
415 if (old && (old->flags & OPT_DELETED)) delete_option(old);
416 /* get_opt_rec() will create the option. */
417 new = get_opt_rec(ctx->option, name);
418 if (new) listbox_sel(ctx->widget_data, new->box_item);
419 /* TODO: If the return value is NULL, we should pop up a msgbox. */
422 static widget_handler_status_T
423 check_option_name(struct dialog_data *dlg_data, struct widget_data *widget_data)
425 unsigned char *p;
427 for (p = widget_data->cdata; *p; p++)
428 /* Not '*' since it is used internally. */
429 if (!isident(*p)) {
430 /* FIXME: Encode '.' into '*'? */
431 info_box(dlg_data->win->term, 0,
432 N_("Bad string"), ALIGN_CENTER,
433 N_("Option names may only contain alpha-numeric characters\n"
434 "in addition to '_' and '-'."));
435 return EVENT_NOT_PROCESSED;
438 return EVENT_PROCESSED;
441 static widget_handler_status_T
442 push_add_button(struct dialog_data *dlg_data,
443 struct widget_data *some_useless_info_button)
445 struct terminal *term = dlg_data->win->term;
446 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
447 struct listbox_item *item = box->sel;
448 struct option *option;
449 struct add_option_to_tree_ctx *ctx;
451 if (!item || !item->udata) {
453 invalid_option:
454 info_box(term, 0, N_("Add option"), ALIGN_CENTER,
455 N_("Cannot add an option here."));
456 return EVENT_PROCESSED;
460 if (item->type == BI_FOLDER && !item->expanded) {
461 item = box->ops->get_root(item);
462 if (!item || !item->udata)
463 goto invalid_option;
466 option = item->udata;
468 if (!(option->flags & OPT_AUTOCREATE)) {
469 if (option->root) option = option->root;
470 if (!option || !(option->flags & OPT_AUTOCREATE))
471 goto invalid_option;
474 ctx = mem_alloc(sizeof(*ctx));
475 if (!ctx) return EVENT_PROCESSED;
476 ctx->option = option;
477 ctx->widget_data = dlg_data->widgets_data;
479 input_dialog(term, getml(ctx, (void *) NULL), N_("Add option"), N_("Name"),
480 ctx, NULL,
481 MAX_STR_LEN, "", 0, 0, check_option_name,
482 add_option_to_tree, NULL);
484 return EVENT_PROCESSED;
488 static widget_handler_status_T
489 push_save_button(struct dialog_data *dlg_data,
490 struct widget_data *some_useless_info_button)
492 write_config(dlg_data->win->term);
494 update_hierbox_browser(&option_browser);
496 return EVENT_PROCESSED;
500 static const struct hierbox_browser_button option_buttons[] = {
501 /* [gettext_accelerator_context(.option_buttons)] */
502 { N_("~Info"), push_hierbox_info_button, 1 },
503 { N_("~Edit"), push_edit_button, 0 },
504 { N_("~Add"), push_add_button, 0 },
505 { N_("~Delete"), push_hierbox_delete_button, 0 },
506 { N_("~Search"), push_hierbox_search_button, 1 },
507 { N_("Sa~ve"), push_save_button, 0 },
510 struct_hierbox_browser(
511 option_browser,
512 N_("Option manager"),
513 option_buttons,
514 &options_listbox_ops
517 /* Builds the "Options manager" dialog */
518 void
519 options_manager(struct session *ses)
521 hierbox_browser(&option_browser, ses);
525 /****************************************************************************
526 Keybinding manager stuff.
527 ****************************************************************************/
529 #ifdef CONFIG_SMALL
530 static int keybinding_text_toggle = 1;
531 #else
532 static int keybinding_text_toggle;
533 #endif
535 /* XXX: ACTION_BOX_SIZE is just a quick hack, we ought to allocate
536 * the sub-arrays separately. --pasky */
537 #define ACTION_BOX_SIZE 128
538 static struct listbox_item *action_box_items[KEYMAP_MAX][ACTION_BOX_SIZE];
540 struct listbox_item *
541 get_keybinding_action_box_item(enum keymap_id keymap_id, action_id_T action_id)
543 assert(action_id < ACTION_BOX_SIZE);
544 if_assert_failed return NULL;
546 return action_box_items[keymap_id][action_id];
549 struct listbox_item *keymap_box_item[KEYMAP_MAX];
551 void
552 init_keybinding_listboxes(struct keymap keymap_table[KEYMAP_MAX],
553 const struct action_list actions[])
555 struct listbox_item *root = &keybinding_browser.root;
556 const struct action *act;
557 enum keymap_id keymap_id;
559 /* Do it backwards because add_listbox_item() add to front
560 * of list. */
561 for (keymap_id = 0; keymap_id < KEYMAP_MAX; keymap_id++) {
562 struct listbox_item *keymap_box;
564 keymap_box = add_listbox_item(NULL, root, BI_FOLDER, &keymap_table[keymap_id], -1);
565 if (!keymap_box) continue;
567 for (act = actions[keymap_id].actions; act->str; act++) {
568 struct listbox_item *item;
570 assert(act->num < ACTION_BOX_SIZE);
571 if_assert_failed continue;
573 if (act->num == ACT_MAIN_SCRIPTING_FUNCTION
574 || act->num == ACT_MAIN_NONE)
575 continue;
577 #ifndef CONFIG_SMALL
578 assert(act->desc);
579 #endif
581 item = add_listbox_item(NULL, keymap_box, BI_FOLDER,
582 (void *) act, -1);
583 if (!item) continue;
585 item->expanded = 1;
587 action_box_items[keymap_id][act->num] = item;
590 keymap_box_item[keymap_id] = keymap_box;
594 void
595 done_keybinding_listboxes(void)
597 struct listbox_item *action;
599 foreach (action, keybinding_browser.root.child) {
600 struct listbox_item *keymap;
602 foreach (keymap, action->child) {
603 free_list(keymap->child);
605 free_list(action->child);
607 free_list(keybinding_browser.root.child);
611 /* Implementation of the listbox operations */
613 /* XXX: If anything but delete button will use these object_*() requiring
614 * functions we have to check if it is action or keymap box items. */
616 static void
617 lock_keybinding(struct listbox_item *item)
619 if (item->depth == 2)
620 object_lock((struct keybinding *) item->udata);
623 static void
624 unlock_keybinding(struct listbox_item *item)
626 if (item->depth == 2)
627 object_unlock((struct keybinding *) item->udata);
630 static int
631 is_keybinding_used(struct listbox_item *item)
633 if (item->depth != 2) return 0;
634 return is_object_used((struct keybinding *) item->udata);
637 static unsigned char *
638 get_keybinding_text(struct listbox_item *item, struct terminal *term)
640 struct keybinding *keybinding = item->udata;
641 struct string info;
643 if (item->depth == 0) {
644 struct keymap *keymap = item->udata;
646 return stracpy(keybinding_text_toggle ? keymap->str
647 : _(keymap->desc, term));
648 } else if (item->depth < 2) {
649 const struct action *action = item->udata;
651 return stracpy(keybinding_text_toggle ? action->str
652 : _(action->desc, term));
655 if (!init_string(&info)) return NULL;
656 add_keystroke_to_string(&info, &keybinding->kbd, 0);
657 return info.source;
660 static unsigned char *
661 get_keybinding_info(struct listbox_item *item, struct terminal *term)
663 struct keybinding *keybinding = item->udata;
664 unsigned char *action, *keymap;
665 struct string info;
667 if (item->depth < 2) return NULL;
668 if (item->type == BI_FOLDER) return NULL;
670 if (!init_string(&info))
671 return NULL;
673 action = get_action_name(keybinding->keymap_id, keybinding->action_id);
674 keymap = get_keymap_name(keybinding->keymap_id);
676 add_format_to_string(&info, "%s: ", _("Keystroke", term));
677 add_keystroke_to_string(&info, &keybinding->kbd, 0);
678 add_format_to_string(&info, "\n%s: %s", _("Action", term), action);
679 add_format_to_string(&info, "\n%s: %s", _("Keymap", term), keymap);
681 return info.source;
684 static struct listbox_item *
685 get_keybinding_root(struct listbox_item *item)
687 /* .. at the bottom */
688 if (item->depth == 0) return NULL;
690 if (item->depth == 1) {
691 const struct action *action = item->udata;
693 return keymap_box_item[action->keymap_id];
694 } else {
695 struct keybinding *kb = item->udata;
697 return get_keybinding_action_box_item(kb->keymap_id, kb->action_id);
701 static enum listbox_match
702 match_keybinding(struct listbox_item *item, struct terminal *term,
703 unsigned char *text)
705 const struct action *action = item->udata;
706 unsigned char *desc;
708 if (item->depth != 1)
709 return LISTBOX_MATCH_IMPOSSIBLE;
711 desc = keybinding_text_toggle
712 ? action->str : _(action->desc, term);
714 if ((desc && strcasestr(desc, text)))
715 return LISTBOX_MATCH_OK;
717 return LISTBOX_MATCH_NO;
720 static int
721 can_delete_keybinding(struct listbox_item *item)
723 return item->depth == 2;
727 static void
728 delete_keybinding_item(struct listbox_item *item, int last)
730 struct keybinding *keybinding = item->udata;
732 assert(item->depth == 2 && !is_object_used(keybinding));
734 free_keybinding(keybinding);
737 static const struct listbox_ops keybinding_listbox_ops = {
738 lock_keybinding,
739 unlock_keybinding,
740 is_keybinding_used,
741 get_keybinding_text,
742 get_keybinding_info,
743 NULL,
744 get_keybinding_root,
745 match_keybinding,
746 can_delete_keybinding,
747 delete_keybinding_item,
748 NULL,
749 NULL,
753 struct kbdbind_add_hop {
754 struct terminal *term;
755 action_id_T action_id;
756 enum keymap_id keymap_id;
757 struct term_event_keyboard kbd;
758 struct widget_data *widget_data;
761 static struct kbdbind_add_hop *
762 new_hop_from(struct kbdbind_add_hop *hop)
764 struct kbdbind_add_hop *new_hop = mem_alloc(sizeof(*new_hop));
766 if (new_hop)
767 copy_struct(new_hop, hop);
769 return new_hop;
772 static void
773 really_really_add_keybinding(void *data)
775 struct kbdbind_add_hop *hop = data;
776 struct keybinding *keybinding;
778 assert(hop);
780 keybinding = add_keybinding(hop->keymap_id, hop->action_id, &hop->kbd,
781 EVENT_NONE);
783 if (keybinding && keybinding->box_item)
784 listbox_sel(hop->widget_data, keybinding->box_item);
787 static void
788 really_add_keybinding(void *data, unsigned char *keystroke)
790 /* [gettext_accelerator_context(.really_add_keybinding.yn)] */
791 struct kbdbind_add_hop *hop = data;
792 action_id_T action_id;
794 /* check_keystroke() has parsed @keystroke to @hop->kbd. */
795 if (keybinding_exists(hop->keymap_id, &hop->kbd, &action_id)
796 && action_id != ACT_MAIN_NONE) {
797 struct kbdbind_add_hop *new_hop;
798 struct string canonical;
800 /* Same keystroke for same action, just return. */
801 if (action_id == hop->action_id) return;
803 /* @*hop is on the memory_list of the input_dialog,
804 * which will be closed when this function returns. */
805 new_hop = new_hop_from(hop);
806 if (!new_hop) return; /* out of mem */
808 /* Try to convert the parsed keystroke back to a
809 * string, so that the "Keystroke already used" box
810 * displays the same canonical name as the keybinding
811 * manager does. If something goes wrong here, then
812 * canonical.length will probably be 0, in which case
813 * we'll use the original @keystroke string instead. */
814 if (init_string(&canonical))
815 add_keystroke_to_string(&canonical, &hop->kbd, 0);
817 msg_box(new_hop->term, getml(new_hop, (void *) NULL), MSGBOX_FREE_TEXT,
818 N_("Keystroke already used"), ALIGN_CENTER,
819 msg_text(new_hop->term, N_("The keystroke \"%s\" "
820 "is currently used for \"%s\".\n"
821 "Are you sure you want to replace it?"),
822 canonical.length ? canonical.source : keystroke,
823 get_action_name(hop->keymap_id, action_id)),
824 new_hop, 2,
825 MSG_BOX_BUTTON(N_("~Yes"), really_really_add_keybinding, B_ENTER),
826 MSG_BOX_BUTTON(N_("~No"), NULL, B_ESC));
828 done_string(&canonical); /* safe even if init failed */
829 return;
832 really_really_add_keybinding((void *) hop);
835 static widget_handler_status_T
836 check_keystroke(struct dialog_data *dlg_data, struct widget_data *widget_data)
838 struct kbdbind_add_hop *hop = dlg_data->dlg->udata2;
839 unsigned char *keystroke = widget_data->cdata;
841 if (parse_keystroke(keystroke, &hop->kbd) >= 0)
842 return EVENT_PROCESSED;
844 info_box(hop->term, 0, N_("Add keybinding"), ALIGN_CENTER,
845 N_("Invalid keystroke."));
847 return EVENT_NOT_PROCESSED;
850 static widget_handler_status_T
851 push_kbdbind_add_button(struct dialog_data *dlg_data,
852 struct widget_data *some_useless_info_button)
854 struct terminal *term = dlg_data->win->term;
855 struct listbox_data *box = get_dlg_listbox_data(dlg_data);
856 struct listbox_item *item = box->sel;
857 struct kbdbind_add_hop *hop;
858 unsigned char *text;
860 if (!item || !item->depth) {
861 info_box(term, 0, N_("Add keybinding"), ALIGN_CENTER,
862 N_("Need to select an action."));
863 return EVENT_PROCESSED;
866 hop = mem_calloc(1, sizeof(*hop));
867 if (!hop) return EVENT_PROCESSED;
868 hop->term = term;
869 hop->widget_data = dlg_data->widgets_data;
871 if (item->depth == 2) {
872 struct keybinding *keybinding = item->udata;
874 hop->action_id = keybinding->action_id;
875 hop->keymap_id = keybinding->keymap_id;
876 } else {
877 const struct action *action = item->udata;
879 hop->action_id = action->num;
880 hop->keymap_id = action->keymap_id;
883 text = msg_text(term,
884 N_("Action: %s\n"
885 "Keymap: %s\n"
886 "\n"
887 "Keystroke should be written in the format: "
888 "[Shift-][Ctrl-][Alt-]Key\n"
889 "Key: a,b,c,...,1,2,3,...,Space,Up,PageDown,"
890 "Tab,Enter,Insert,F5,..."
891 "\n\n"
892 "Keystroke"),
893 get_action_name(hop->keymap_id, hop->action_id),
894 get_keymap_name(hop->keymap_id));
896 input_dialog(term, getml(hop, (void *) text, (void *) NULL),
897 N_("Add keybinding"), text,
898 hop, NULL,
899 MAX_STR_LEN, "", 0, 0, check_keystroke,
900 really_add_keybinding, NULL);
902 return EVENT_PROCESSED;
906 static widget_handler_status_T
907 push_kbdbind_toggle_display_button(struct dialog_data *dlg_data,
908 struct widget_data *some_useless_info_button)
910 #ifndef CONFIG_SMALL
911 keybinding_text_toggle = !keybinding_text_toggle;
912 redraw_dialog(dlg_data, 0);
913 #endif
914 return EVENT_PROCESSED;
918 /* FIXME: Races here, we need to lock the entry..? --pasky */
920 static widget_handler_status_T
921 push_kbdbind_save_button(struct dialog_data *dlg_data,
922 struct widget_data *some_useless_info_button)
924 write_config(dlg_data->win->term);
925 return EVENT_PROCESSED;
929 static const struct hierbox_browser_button keybinding_buttons[] = {
930 /* [gettext_accelerator_context(.keybinding_buttons)] */
931 { N_("~Add"), push_kbdbind_add_button, 0 },
932 { N_("~Delete"), push_hierbox_delete_button, 0 },
933 { N_("~Toggle display"), push_kbdbind_toggle_display_button, 1 },
934 { N_("~Search"), push_hierbox_search_button, 1 },
935 { N_("Sa~ve"), push_kbdbind_save_button, 0 },
938 struct_hierbox_browser(
939 keybinding_browser,
940 N_("Keybinding manager"),
941 keybinding_buttons,
942 &keybinding_listbox_ops
945 /* Builds the "Keybinding manager" dialog */
946 void
947 keybinding_manager(struct session *ses)
949 hierbox_browser(&keybinding_browser, ses);