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

📄 listbox.c

📁 一个很有名的浏览器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* Listbox widget implementation. *//* $Id: listbox.c,v 1.183.4.5 2005/04/06 08:32:41 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <string.h>#include "elinks.h"#include "bfu/dialog.h"#include "bfu/hierbox.h"#include "bfu/listbox.h"#include "config/kbdbind.h"#include "intl/gettext/libintl.h"#include "terminal/draw.h"#include "terminal/mouse.h"#include "terminal/terminal.h"#include "util/color.h"#include "util/conv.h"#include "util/lists.h"#define VERTICAL_LISTBOX_MARGIN 3voidadd_dlg_listbox(struct dialog *dlg, int height, void *box_data){	struct widget *widget;	widget = &dlg->widgets[dlg->number_of_widgets++];	widget->type = WIDGET_LISTBOX;	widget->info.listbox.height = height;	widget->data = box_data;}struct listbox_data *get_listbox_widget_data(struct widget_data *widget_data){	assert(widget_data->widget->type == WIDGET_LISTBOX);	return ((struct listbox_data *) widget_data->widget->data);}/* Layout for generic boxes */voiddlg_format_listbox(struct terminal *term, struct widget_data *widget_data,	           int x, int *y, int w, int max_height, int *rw,	           enum format_align align){	int min, optimal_h;	set_box(&widget_data->box, x, *y, w, 1);	if (rw) int_bounds(rw, widget_data->box.width, w);	/* Height bussiness follows: */	/* We ignore this one happily now. Rather be Dynamic ;p. */	/* (*y) += widget_data->widget->gid; */	/* This is only weird heuristic, it could scale well I hope. */	optimal_h = max_height * 7 / 10 - VERTICAL_LISTBOX_MARGIN;	min = get_opt_int("ui.dialogs.listbox_min_height");	if (max_height - VERTICAL_LISTBOX_MARGIN < min) {		/* Big trouble: can't satisfy even the minimum :-(. */		widget_data->box.height = max_height - VERTICAL_LISTBOX_MARGIN;	} else if (optimal_h < min) {		widget_data->box.height = min;	} else {		widget_data->box.height = optimal_h;	}	/* DBG("::%d(%d)::%d::%d::", max_y, term?1:2, widget_data->h, *y); */	(*y) += widget_data->box.height;}/* *,item00->prev *|item00->root = NULL  ,item10->prev *|item00->child <----->|item10->root *|item00->next <-.     |item10->child [<->] *|               |     `item10->next *|item01->prev <-' *|item01->root = NULL *|item01->child [<->] *|item01->next <-. *|               | *|item02->prev <-' *|item02->root = NULL  ,item11->prev *|item02->child <----->|item11->root         ,item20->prev *`item02->next       \ |item11->child <----->|item20->root *                    | |item11->next <-.     |item20->child [<->] *                    | |               |     `item20->next *                    | |item12->prev <-' *                    `-|item12->root *                    | |item12->child [<->] *                    | |item12->next <-. *                    | |               | *                    | |item13->prev <-' *                    `-|item13->root         ,item21->prev *                      |item13->child <----->|item21->root *                      `item13->next         |item21->child [<->] *                                            `item21->next * *//* Traverse a hierarchic tree from @item by @offset items, calling @fn, * if it is not NULL, on each item traversed (that is, each of the items * that we move _through_; this means from the passed @item up to, * but not including, the returned item). * * @offset may be negative to indicate that we should traverse upwards. * * Besides the current item, @fn is also passed @d, which is otherwise unused * by traverse_listbox_items_list, and a pointer to @offset, which @fn can set * to 0 to stop traversal or to other values to change the direction in which * or the number of items over which we will traverse. * * @fn should return 1 if it freed its passed item, or return 0 otherwise. * * If the passed @offset is zero, we set @offset to 1 and traverse thru * the list (down) until either we reach the end or @fn sets @offset to 0. *//* From the box structure, we should use only 'items' here. */struct listbox_item *traverse_listbox_items_list(struct listbox_item *item, struct listbox_data *box,			    int offset, int follow_visible,			    int (*fn)(struct listbox_item *, void *, int *),			    void *d){	struct listbox_item *visible_item = item;	int levmove = 0;	int stop = 0;	int infinite = !offset;	if (!item) return NULL;	if (infinite)		offset = 1;	while (offset && !stop) {		/* We need to cache these. Or what will happen if something		 * will free us item too early? However, we rely on item		 * being at least NULL in that case. */		/* There must be no orphaned listbox_items. No free()d roots		 * and no dangling children. */#define	item_cache(item) \	do { \		croot = box->ops->get_root(item); cprev = item->prev; cnext = item->next; \	} while (0)		struct listbox_item *croot, *cprev, *cnext;		item_cache(item);		if (fn && (!follow_visible || item->visible)) {			if (fn(item, d, &offset)) {				/* We was free()d! Let's try to carry on w/ the				 * cached coordinates. */				item = NULL;			}			if (!offset) {				infinite = 0; /* safety (matches) */				continue;			}		}		if (offset > 0) {			/* Otherwise we climb back up when last item in root			 * is a folder. */			struct listbox_item *cragsman = NULL;			/* Direction DOWN. */			if (!infinite) offset--;			if (item && !list_empty(item->child) && item->expanded			    && (!follow_visible || item->visible)) {				/* Descend to children. */				item = item->child.next;				item_cache(item);				goto done_down;			}			while (croot			       && (void *) cnext == &croot->child) {				/* Last item in a non-root list, climb to your				 * root. */				if (!cragsman) cragsman = item;				item = croot;				item_cache(item);			}			if (!croot && (!cnext || (void *) cnext == box->items)) {				/* Last item in the root list, quit.. */				stop = 1;				if (cragsman) {					/* ..and fall back where we were. */					item = cragsman;					item_cache(item);				}			}			/* We're not at the end of anything, go on. */			if (!stop) {				item = cnext;				item_cache(item);			}done_down:			if (!item || (follow_visible && !item->visible)) {				offset++;			} else {				visible_item = item;			}		} else {			/* Direction UP. */			if (!infinite) offset++;			if (croot			    && (void *) cprev == &croot->child) {				/* First item in a non-root list, climb to your				 * root. */				item = croot;				item_cache(item);				levmove = 1;			}			if (!croot && (void *) cprev == box->items) {				/* First item in the root list, quit. */				stop = 1;				levmove = 1;			}			/* We're not at the start of anything, go on. */			if (!levmove && !stop) {				item = cprev;				item_cache(item);				while (item && !list_empty(item->child)					&& item->expanded					&& (!follow_visible || item->visible)) {					/* Descend to children. */					item = item->child.prev;					item_cache(item);				}			} else {				levmove = 0;			}			if (!item || (follow_visible && !item->visible)) {				offset--;			} else {				visible_item = item;			}		}#undef item_cache	}	return visible_item;}/* Takes care about listbox top moving. */static intlistbox_sel_move_do(struct listbox_item *item, void *data_, int *offset){	struct listbox_context *data = data_;	if (item == data->box->top)		data->box->sel_offset = 0; /* assure resync */	if (data->dist > 0) {		if (data->box->sel_offset		    < data->widget_data->box.height - 1) {			data->box->sel_offset++;		} else {			data->box->top =				traverse_listbox_items_list(data->box->top,					data->box, 1, 1, NULL, NULL);		}	} else if (data->dist < 0) {		if (data->box->sel_offset > 0) {			data->box->sel_offset--;		} else {			data->box->top =				traverse_listbox_items_list(data->box->top,					data->box, -1, 1, NULL, NULL);		}	}	return 0;}/* Moves the selected item by [dist] items. If [dist] is out of the current * range, the selected item is moved to the extreme (ie, the top or bottom) */voidlistbox_sel_move(struct widget_data *widget_data, int dist){	struct listbox_data *box = get_listbox_widget_data(widget_data);	if (!list_empty(*box->items)) {		if (!box->top) box->top = box->items->next;		if (!box->sel) box->sel = box->top;	}	/* We want to have these visible if possible. */	if (box->top && !box->top->visible) {		box->top = traverse_listbox_items_list(box->top, box,				1, 1, NULL, NULL);		box->sel = box->top;	}	if (traverse_listbox_items_list(box->sel, box, dist, 1, NULL, NULL)	    != box->sel) {		struct listbox_context data;		memset(&data, 0, sizeof(data));		data.box = box;		data.widget_data = widget_data;		data.dist = dist;		/* XXX: This is ugly, yes; but we don't want to call the		 * callback if we won't move on at all. */		box->sel = traverse_listbox_items_list(box->sel, box, dist, 1,						       listbox_sel_move_do,						       &data);	}}/* Takes care about rendering of each listbox item. */static intdisplay_listbox_item(struct listbox_item *item, void *data_, int *offset){	struct listbox_context *data = data_;	unsigned char *stylename;	int len; /* Length of the current text field. */	struct color_pair *color;	int depth = item->depth + 1;	int d;	int x, y;	stylename = (item == data->box->sel) ? "menu.selected"		  : ((item->marked)	     ? "menu.marked"					     : "menu.normal");	color = get_bfu_color(data->term, stylename);	y = data->widget_data->box.y + data->offset;	for (d = 0; d < depth - 1; d++) {		struct listbox_item *root = item;		struct listbox_item *child = item;		int i, x;

⌨️ 快捷键说明

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