📄 dialog.c
字号:
/* Dialog box implementation. *//* $Id: dialog.c,v 1.188.4.4 2005/04/06 11:00:57 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdlib.h>#include <string.h>#include "elinks.h"#include "bfu/dialog.h"#include "config/kbdbind.h"#include "config/options.h"#include "intl/gettext/libintl.h"#include "terminal/draw.h"#include "lowlevel/select.h"#include "terminal/kbd.h"#include "terminal/terminal.h"#include "terminal/window.h"#include "util/color.h"#include "util/conv.h"#include "util/error.h"#include "util/memlist.h"#include "util/memory.h"#include "util/string.h"static window_handler dialog_func;struct dialog_data *do_dialog(struct terminal *term, struct dialog *dlg, struct memory_list *ml){ struct dialog_data *dlg_data; dlg_data = mem_calloc(1, sizeof(*dlg_data) + sizeof(struct widget_data) * dlg->number_of_widgets); if (!dlg_data) { /* Worry not: freeml() checks whether its argument is NULL. */ freeml(ml); return NULL; } dlg_data->dlg = dlg; dlg_data->number_of_widgets = dlg->number_of_widgets; dlg_data->ml = ml; add_window(term, dialog_func, dlg_data); return dlg_data;}static void cycle_widget_focus(struct dialog_data *dlg_data, int direction);static voidupdate_all_widgets(struct dialog_data *dlg_data){ struct widget_data *widget_data; foreach_widget(dlg_data, widget_data) { display_widget(dlg_data, widget_data); }}voidredraw_dialog(struct dialog_data *dlg_data, int layout){ struct terminal *term = dlg_data->win->term; struct color_pair *title_color; if (layout) { dlg_data->dlg->layouter(dlg_data); /* This might not be the best place. We need to be able * to make focusability of widgets dynamic so widgets * like scrollable text don't receive focus when there * is nothing to scroll. */ if (!widget_is_focusable(selected_widget(dlg_data))) cycle_widget_focus(dlg_data, 1); } if (!dlg_data->dlg->layout.only_widgets) { struct box box; set_box(&box, dlg_data->box.x + (DIALOG_LEFT_BORDER + 1), dlg_data->box.y + (DIALOG_TOP_BORDER + 1), dlg_data->box.width - 2 * (DIALOG_LEFT_BORDER + 1), dlg_data->box.height - 2 * (DIALOG_TOP_BORDER + 1)); draw_border(term, &box, get_bfu_color(term, "dialog.frame"), DIALOG_FRAME); assert(dlg_data->dlg->title); title_color = get_bfu_color(term, "dialog.title"); if (title_color && box.width > 2) { unsigned char *title = dlg_data->dlg->title; int titlelen = int_min(box.width - 2, strlen(title)); int x = (box.width - titlelen) / 2 + box.x; int y = box.y - 1; draw_text(term, x - 1, y, " ", 1, 0, title_color); draw_text(term, x, y, title, titlelen, 0, title_color); draw_text(term, x + titlelen, y, " ", 1, 0, title_color); } } update_all_widgets(dlg_data); redraw_from_window(dlg_data->win);}static voidselect_dlg_item(struct dialog_data *dlg_data, struct widget_data *widget_data){ select_widget(dlg_data, widget_data); if (widget_data->widget->ops->select) widget_data->widget->ops->select(dlg_data, widget_data);}static struct widget_ops *widget_type_to_ops[] = { &checkbox_ops, &field_ops, &field_pass_ops, &button_ops, &listbox_ops, &text_ops,};static struct widget_data *init_widget(struct dialog_data *dlg_data, int i){ struct widget_data *widget_data = &dlg_data->widgets_data[i]; memset(widget_data, 0, sizeof(*widget_data)); widget_data->widget = &dlg_data->dlg->widgets[i]; if (widget_data->widget->datalen) { widget_data->cdata = mem_alloc(widget_data->widget->datalen); if (!widget_data->cdata) { return NULL; } memcpy(widget_data->cdata, widget_data->widget->data, widget_data->widget->datalen); } widget_data->widget->ops = widget_type_to_ops[widget_data->widget->type]; if (widget_has_history(widget_data)) { init_list(widget_data->info.field.history); widget_data->info.field.cur_hist = (struct input_history_entry *) &widget_data->info.field.history; } if (widget_data->widget->ops->init) widget_data->widget->ops->init(dlg_data, widget_data); return widget_data;}voidselect_widget(struct dialog_data *dlg_data, struct widget_data *widget_data){ struct widget_data *previously_selected_widget; previously_selected_widget = selected_widget(dlg_data); dlg_data->selected_widget_id = widget_data - dlg_data->widgets_data; display_widget(dlg_data, previously_selected_widget); display_widget(dlg_data, widget_data);}struct widget_data *select_widget_by_id(struct dialog_data *dlg_data, int i){ struct widget_data *widget_data = &dlg_data->widgets_data[i]; select_widget(dlg_data, widget_data); return widget_data;}static voidcycle_widget_focus(struct dialog_data *dlg_data, int direction){ int prev_selected = dlg_data->selected_widget_id; struct widget_data *previously_selected_widget; previously_selected_widget = selected_widget(dlg_data); do { dlg_data->selected_widget_id += direction; if (dlg_data->selected_widget_id >= dlg_data->number_of_widgets) dlg_data->selected_widget_id = 0; else if (dlg_data->selected_widget_id < 0) dlg_data->selected_widget_id = dlg_data->number_of_widgets - 1; } while (!widget_is_focusable(selected_widget(dlg_data)) && dlg_data->selected_widget_id != prev_selected); display_widget(dlg_data, previously_selected_widget); display_widget(dlg_data, selected_widget(dlg_data)); redraw_from_window(dlg_data->win);}static voiddialog_ev_init(struct dialog_data *dlg_data){ int i; /* TODO: foreachback_widget() */ for (i = dlg_data->number_of_widgets - 1; i >= 0; i--) { struct widget_data *widget_data; widget_data = init_widget(dlg_data, i); /* Make sure the selected widget is focusable */ if (widget_data && widget_is_focusable(widget_data)) dlg_data->selected_widget_id = i; }}#ifdef CONFIG_MOUSEstatic voiddialog_ev_mouse(struct dialog_data *dlg_data){ struct widget_data *widget_data; foreach_widget(dlg_data, widget_data) { if (widget_data->widget->ops->mouse && widget_data->widget->ops->mouse(dlg_data, widget_data) == EVENT_PROCESSED) break; }}#endif /* CONFIG_MOUSE *//* Look up for a button with matching flag. */static voidselect_button_by_flag(struct dialog_data *dlg_data, int flag){ struct widget_data *widget_data; foreach_widget(dlg_data, widget_data) { if (widget_data->widget->type == WIDGET_BUTTON && widget_data->widget->info.button.flags & flag) { select_dlg_item(dlg_data, widget_data); break; } }}/* Look up for a button with matching starting letter. */static voidselect_button_by_key(struct dialog_data *dlg_data){ unsigned char key; struct widget_data *widget_data; struct term_event *ev = dlg_data->term_event; if (!check_kbd_label_key(ev)) return; key = toupper(get_kbd_key(ev)); foreach_widget(dlg_data, widget_data) { int hk_pos; if (widget_data->widget->type != WIDGET_BUTTON) continue; /* We first try to match marked hotkey if there is * one else we fallback to first character in button * name. */ hk_pos = widget_data->widget->info.button.hotkey_pos; if (hk_pos >= 0) { if (toupper(widget_data->widget->text[hk_pos + 1]) != key) continue; } else { if (toupper(widget_data->widget->text[0]) != key) continue; } select_dlg_item(dlg_data, widget_data); break; }}static voiddialog_ev_kbd(struct dialog_data *dlg_data){ struct widget_data *widget_data = selected_widget(dlg_data); struct widget_ops *ops = widget_data->widget->ops; /* XXX: KEYMAP_EDIT ? --pasky */ enum menu_action action; struct term_event *ev = dlg_data->term_event; /* First let the widget try out. */ if (ops->kbd && ops->kbd(dlg_data, widget_data) == EVENT_PROCESSED) return; action = kbd_action(KEYMAP_MENU, ev, NULL); switch (action) { case ACT_MENU_SELECT: /* Can we select? */ if (ops->select) { ops->select(dlg_data, widget_data); } break; case ACT_MENU_ENTER: /* Submit button. */ if (ops->select) { ops->select(dlg_data, widget_data); break; } if (widget_is_textfield(widget_data) || check_kbd_modifier(ev, KBD_CTRL) || check_kbd_modifier(ev, KBD_ALT)) { select_button_by_flag(dlg_data, B_ENTER); } break; case ACT_MENU_CANCEL: /* Cancel button. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -