⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 hierbox.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Hiearchic listboxes browser dialog commons *//* $Id: hierbox.c,v 1.201.2.7 2005/05/01 21:05:57 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <stdarg.h>#include "elinks.h"#include "bfu/button.h"#include "bfu/dialog.h"#include "bfu/hierbox.h"#include "bfu/inpfield.h"#include "bfu/listbox.h"#include "bfu/msgbox.h"#include "bfu/text.h"#include "config/kbdbind.h"#include "dialogs/download.h"#include "intl/gettext/libintl.h"#include "protocol/uri.h"#include "sched/task.h"#include "terminal/screen.h"#include "terminal/tab.h"#include "terminal/terminal.h"struct hierbox_dialog_list_item {	LIST_HEAD(struct hierbox_dialog_list_item);	struct dialog_data *dlg_data;};voidupdate_hierbox_browser(struct hierbox_browser *browser){	struct hierbox_dialog_list_item *item;	foreach (item, browser->dialogs) {		redraw_from_window(item->dlg_data->win->next);	}}/* Common backend for listbox adding */struct listbox_item *add_listbox_item(struct hierbox_browser *browser, struct listbox_item *root,		 enum listbox_item_type type, void *data, int add_position){	struct listbox_item *item;	if (!root) {		assertm(browser, "Nowhere to add new list box item");		root = &browser->root;	}	item = mem_calloc(1, sizeof(*item));	if (!item) return NULL;	init_list(item->child);	item->visible = 1;	item->udata = data;	item->type = type;	item->depth = root->depth + 1;	/* TODO: Possibility to sort by making add_position into a flag */	if (add_position < 0)		add_to_list_end(root->child, item);	else		add_to_list(root->child, item);	if (browser) update_hierbox_browser(browser);	return item;}/* Find a listbox item to replace @item. This is done by trying first to * traverse down then up, and if both traversals end up returning the @item * (that is, it is the last item in the box), return NULL. */static inline struct listbox_item *replace_listbox_item(struct listbox_item *item, struct listbox_data *data){	struct listbox_item *box;	box = traverse_listbox_items_list(item, data, 1, 1, NULL, NULL);	if (item != box) return box;	box = traverse_listbox_items_list(item, data, -1, 1, NULL, NULL);	return (item == box) ? NULL : box;}voiddone_listbox_item(struct hierbox_browser *browser, struct listbox_item *box_item){	struct listbox_data *box_data;	assert(box_item && list_empty(box_item->child));	/* If we are removing the top or the selected box we have to figure out	 * a replacement. */	foreach (box_data, browser->boxes) {		if (box_data->sel == box_item)			box_data->sel = replace_listbox_item(box_item, box_data);		if (box_data->top == box_item)			box_data->top = replace_listbox_item(box_item, box_data);	}	/* The option dialog needs this test */	if (box_item->next) del_from_list(box_item);	mem_free(box_item);	update_hierbox_browser(browser);}static voidrecursively_set_expanded(struct listbox_item *box, int expanded){	struct listbox_item *child;	if (box->type != BI_FOLDER)		return;	box->expanded = expanded;	foreach (child, box->child)		recursively_set_expanded(child, expanded);}static inttest_search(struct listbox_item *item, void *data_, int *offset){	struct listbox_context *listbox_context = data_;	listbox_context->offset--;	if (item == listbox_context->box->sel) *offset = 0;	return 0;}static t_handler_event_statushierbox_ev_kbd(struct dialog_data *dlg_data){	struct hierbox_browser *browser = dlg_data->dlg->udata2;	struct widget_data *widget_data = dlg_data->widgets_data;	struct widget *widget = widget_data->widget;	struct listbox_data *box;	struct listbox_item *selected;	enum menu_action action;	struct term_event *ev = dlg_data->term_event;	/* Check if listbox has something to say to this */	if (widget->ops->kbd	    && widget->ops->kbd(dlg_data, widget_data)	       == EVENT_PROCESSED)		return EVENT_PROCESSED;	box = get_dlg_listbox_data(dlg_data);	selected = box->sel;	action = kbd_action(KEYMAP_MENU, ev, NULL);	if (action == ACT_MENU_SELECT) {		if (!selected) return EVENT_PROCESSED;		if (selected->type != BI_FOLDER)			return EVENT_NOT_PROCESSED;		selected->expanded = !selected->expanded;	} else if (action == ACT_MENU_UNEXPAND) {		/* Recursively unexpand all folders */		if (!selected) return EVENT_PROCESSED;		/* Special trick: if the folder is already		 * folded, jump at the parent folder, so the		 * next time when user presses the key, the		 * whole parent folder will be closed. */		if (list_empty(selected->child)		    || !selected->expanded) {			struct listbox_item *root = box->ops->get_root(selected);			if (root) {				struct listbox_context ctx;				memset(&ctx, 0, sizeof(ctx));				ctx.box = box;				ctx.offset = 1;				traverse_listbox_items_list(						root, box, 0, 1,						test_search, &ctx);				listbox_sel_move(dlg_data->widgets_data,					         ctx.offset);			}		} else if (selected->type == BI_FOLDER) {			recursively_set_expanded(selected, 0);		}	} else if (action == ACT_MENU_EXPAND) {		/* Recursively expand all folders */		if (!selected || box->sel->type != BI_FOLDER)			return EVENT_PROCESSED;		recursively_set_expanded(box->sel, 1);	} else if (action == ACT_MENU_SEARCH) {		if (!box->ops->match)			return EVENT_NOT_PROCESSED;		push_hierbox_search_button(dlg_data, NULL);		return EVENT_PROCESSED;	} else {		return EVENT_NOT_PROCESSED;	}	if (browser->expansion_callback)		browser->expansion_callback();	display_widget(dlg_data, dlg_data->widgets_data);	return EVENT_PROCESSED;}static t_handler_event_statushierbox_ev_init(struct dialog_data *dlg_data){	struct hierbox_browser *browser = dlg_data->dlg->udata2;	struct hierbox_dialog_list_item *item;	struct listbox_item *litem;	/* If we fail here it only means automatic updating	 * will not be possible so no need to panic. */	item = mem_alloc(sizeof(*item));	if (item) {		item->dlg_data = dlg_data;		add_to_list(browser->dialogs, item);	}	foreach (litem, browser->root.child) {		litem->visible = 1;	}	return EVENT_NOT_PROCESSED;	/* FIXME: is this correct ? --Zas */}static t_handler_event_statushierbox_ev_abort(struct dialog_data *dlg_data){	struct listbox_data *box = get_dlg_listbox_data(dlg_data);	struct hierbox_browser *browser = dlg_data->dlg->udata2;	struct hierbox_dialog_list_item *item;	/* Save state and delete the box structure */	if (!browser->do_not_save_state)		copy_struct(&browser->box_data, box);	del_from_list(box);	/* Delete the dialog list entry */	foreach (item, browser->dialogs) {		if (item->dlg_data == dlg_data) {			del_from_list(item);			mem_free(item);			break;		}	}	return EVENT_NOT_PROCESSED; /* FIXME: is this correct ? --Zas */}/* We install own dialog event handler, so that we can give the listbox widget * an early chance to catch the event. Basically, the listbox widget is itself * unselectable, instead one of the buttons below is always active. So, we * always first let the listbox catch the keypress and handle it, and if it * doesn't care, we pass it on to the button. */static t_handler_event_statushierbox_dialog_event_handler(struct dialog_data *dlg_data){	struct term_event *ev = dlg_data->term_event;	switch (ev->ev) {		case EVENT_KBD:			return hierbox_ev_kbd(dlg_data);		case EVENT_INIT:			return hierbox_ev_init(dlg_data);		case EVENT_RESIZE:		case EVENT_REDRAW:		case EVENT_MOUSE:			return EVENT_NOT_PROCESSED;		case EVENT_ABORT:			return hierbox_ev_abort(dlg_data);	}	return EVENT_NOT_PROCESSED;}struct dialog_data *hierbox_browser(struct hierbox_browser *browser, struct session *ses){	struct terminal *term = ses->tab->term;	struct listbox_data *listbox_data;	struct dialog *dlg;	int button = browser->buttons_size + 2;	int anonymous = get_cmd_opt_bool("anonymous");	assert(ses);	dlg = calloc_dialog(button, sizeof(*listbox_data));	if (!dlg) return NULL;	listbox_data = (struct listbox_data *) get_dialog_offset(dlg, button);	dlg->title = _(browser->title, term);	dlg->layouter = generic_dialog_layouter;	dlg->layout.maximize_width = 1;	dlg->layout.padding_top = 1;	dlg->handle_event = hierbox_dialog_event_handler;	dlg->udata = ses;	dlg->udata2 = browser;	add_dlg_listbox(dlg, 12, listbox_data);	for (button = 0; button < browser->buttons_size; button++) {		struct hierbox_browser_button *but = &browser->buttons[button];		/* Skip buttons that should not be displayed in anonymous mode */		if (anonymous && !but->anonymous) {			anonymous++;			continue;		}		add_dlg_button(dlg, _(but->label, term), B_ENTER, but->handler, NULL);	}	add_dlg_button(dlg, _("Close", term), B_ESC, cancel_dialog, NULL);	/* @anonymous was initially 1 if we are running in anonymous mode so we	 * have to subtract one. */	add_dlg_end(dlg, button + 2 - (anonymous ? anonymous - 1 : 0));	return do_dialog(term, dlg, getml(dlg, NULL));}/* Action info management */static intscan_for_marks(struct listbox_item *item, void *info_, int *offset){	if (item->marked) {		struct listbox_context *context = info_;		context->item = NULL;		*offset = 0;	}	return 0;}static intscan_for_used(struct listbox_item *item, void *info_, int *offset){	struct listbox_context *context = info_;	if (context->box->ops->is_used(item)) {		context->item = item;		*offset = 0;	}	return 0;}static struct listbox_context *init_listbox_context(struct listbox_data *box, struct terminal *term,		     struct listbox_item *item,		     int (*scanner)(struct listbox_item *, void *, int *)){	struct listbox_context *context;	context = mem_calloc(1, sizeof(*context));	if (!context) return NULL;	context->item = item;	context->term = term;	context->box = box;	if (!scanner) return context;	/* Look if it wouldn't be more interesting to blast off the marked	 * item. */	assert(!list_empty(*box->items));	traverse_listbox_items_list(box->items->next, box, 0, 0,				    scanner, context);	return context;}static voiddone_listbox_context(void *context_){	struct listbox_context *context = context_;	if (context->item)		context->box->ops->unlock(context->item);}/* Info action */t_handler_event_statuspush_hierbox_info_button(struct dialog_data *dlg_data, struct widget_data *button){	struct listbox_data *box = get_dlg_listbox_data(dlg_data);	struct terminal *term = dlg_data->win->term;	struct listbox_context *context;	unsigned char *msg;	if (!box->sel) return EVENT_PROCESSED;	assert(box->ops);	context = init_listbox_context(box, term, box->sel, NULL);	if (!context) return EVENT_PROCESSED;	msg = box->ops->get_info(context->item, term);	if (!msg) {		mem_free(context);		if (box->sel->type == BI_FOLDER) {			info_box(term, 0, N_("Info"), ALIGN_CENTER,				 N_("Press space to expand this folder."));		}		return EVENT_PROCESSED;	}	box->ops->lock(context->item);	msg_box(term, getml(context, NULL), MSGBOX_FREE_TEXT /* | MSGBOX_SCROLLABLE */,		N_("Info"), ALIGN_LEFT,		msg,		context, 1,		N_("~OK"), done_listbox_context, B_ESC | B_ENTER);	return EVENT_PROCESSED;}/* Goto action */static voidrecursively_goto_listbox(struct session *ses, struct listbox_item *root,			 struct listbox_data *box){	struct listbox_item *item;	foreach (item, root->child) {		struct uri *uri;		if (item->type == BI_FOLDER) {			recursively_goto_listbox(ses, item, box);			continue;		}		uri = box->ops->get_uri(item);		if (!uri) continue;		open_uri_in_new_tab(ses, uri, 1, 0);		done_uri(uri);	}}static intgoto_marked(struct listbox_item *item, void *data_, int *offset){

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -