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

📄 text.c

📁 一个很有名的浏览器
💻 C
字号:
/* Text widget implementation. *//* $Id: text.c,v 1.116.4.1 2005/04/05 21:11:05 jonas Exp $ */#ifdef HAVE_CONFIG_H#include "config.h"#endif#include <ctype.h>#include <stdlib.h>#include <string.h>#include "elinks.h"#include "bfu/dialog.h"#include "bfu/text.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"#define is_unsplitable(pos) (*(pos) && *(pos) != '\n' && !isspace(*(pos)))voidadd_dlg_text(struct dialog *dlg, unsigned char *text,	     enum format_align align, int bottom_pad){	struct widget *widget;	widget = &dlg->widgets[dlg->number_of_widgets++];	widget->type = WIDGET_TEXT;	widget->text = text;	widget->info.text.align = align;	widget->info.text.is_label = !!bottom_pad;}/* Returns length of substring (from start of @text) before a split. */static inline intsplit_line(unsigned char *text, int max_width){	unsigned char *split = text;	if (max_width <= 0) return 0;	while (*split && *split != '\n') {		unsigned char *next_split = split + 1;		while (is_unsplitable(next_split))			next_split++;		if (next_split - text > max_width) {			/* Force a split if no position was found yet,			 * meaning there's no splittable substring under			 * requested width. */			if (split == text) {				split = &text[max_width];				/* Give preference to split on a punctuation				 * if any. Note that most of the time				 * punctuation char is followed by a space so				 * this rule will not match often.				 * We match dash and quotes too. */				while (--split != text) {					if (!ispunct(*split)) continue;					split++;					break;				}				/* If no way to do a clean split, just return				 * requested maximal width. */				if (split == text)					return max_width;			}			break;		}		split = next_split;	}	return split - text;}#undef is_unsplitable#define LINES_GRANULARITY 0x7#define realloc_lines(x, o, n) mem_align_alloc(x, o, n, unsigned char *, LINES_GRANULARITY)/* Find the start of each line with the current max width */static unsigned char **split_lines(struct widget_data *widget_data, int max_width){	unsigned char *text = widget_data->widget->text;	unsigned char **lines = (unsigned char **) widget_data->cdata;	int line = 0;	if (widget_data->info.text.max_width == max_width) return lines;	/* We want to recalculate the max line width */	widget_data->box.width = 0;	while (*text) {		int width;		/* Skip first leading \n or space. */		if (isspace(*text)) text++;		if (!*text) break;		width = split_line(text, max_width);		/* split_line() may return 0. */		if (width < 1) {			width = 1; /* Infinite loop prevention. */		}		int_lower_bound(&widget_data->box.width, width);		if (!realloc_lines(&lines, line, line + 1))			break;		lines[line++] = text;		text += width;	}	/* Yes it might be a bit ugly on the other hand it will be autofreed	 * for us. */	widget_data->cdata = (unsigned char *) lines;	widget_data->info.text.lines = line;	widget_data->info.text.max_width = max_width;	return lines;}/* Format text according to dialog box and alignment. */voiddlg_format_text_do(struct terminal *term, unsigned char *text,		int x, int *y, int width, int *real_width,		struct color_pair *color, enum format_align align){	int line_width;	int firstline = 1;	for (; *text; text += line_width, (*y)++) {		int shift;		/* Skip first leading \n or space. */		if (!firstline && isspace(*text))			text++;		else			firstline = 0;		if (!*text) break;		line_width = split_line(text, width);		/* split_line() may return 0. */		if (line_width < 1) {			line_width = 1; /* Infinite loop prevention. */			continue;		}		if (real_width) int_lower_bound(real_width, line_width);		if (!term || !line_width) continue;		/* Calculate the number of chars to indent */		if (align == ALIGN_CENTER)			shift = (width - line_width) / 2;		else if (align == ALIGN_RIGHT)			shift = width - line_width;		else			shift = 0;		assert(line_width <= width && shift < width);		draw_text(term, x + shift, *y, text, line_width, 0, color);	}}voiddlg_format_text(struct terminal *term, struct widget_data *widget_data,		int x, int *y, int width, int *real_width, int max_height){	unsigned char *text = widget_data->widget->text;	unsigned char saved = 0;	unsigned char *saved_pos = NULL;	/* If we are drawing set up the box before setting up the	 * scrolling. */	set_box(&widget_data->box, x, *y,		widget_data->box.width, int_max(0, max_height - 3));	if (widget_data->box.height == 0) return;	/* Can we scroll and do we even have to? */	if (widget_data->widget->info.text.is_scrollable	    && (widget_data->info.text.max_width != width		|| widget_data->box.height < widget_data->info.text.lines))	{		unsigned char **lines;		int current;		int visible;		/* Ensure that the current split is valid but don't		 * split if we don't have to */		if (widget_data->box.width != width		    && !split_lines(widget_data, width))			return;		lines = (unsigned char **) widget_data->cdata;		/* Make maximum number of lines available */		visible = int_max(widget_data->info.text.lines - widget_data->box.height,				  widget_data->box.height);		int_bounds(&widget_data->info.text.current, 0, visible);		current = widget_data->info.text.current;		/* Set the current position */		text = lines[current];		/* Do we have to force a text end ? */		visible = widget_data->info.text.lines - current;		if (visible > widget_data->box.height) {			int lines_pos = current + widget_data->box.height;			saved_pos = lines[lines_pos];			/* We save the start of lines so backtrack to see			 * if the previous line has a line end that should			 * also be trimmed. */			if (lines_pos > 0 && saved_pos[-1] == '\n')				saved_pos--;			saved = *saved_pos;			*saved_pos = '\0';		}		/* Force dialog to be the width of the longest line */		if (real_width) int_lower_bound(real_width, widget_data->box.width);	} else {		/* Always reset @current if we do not need to scroll */		widget_data->info.text.current = 0;	}	dlg_format_text_do(term, text,		x, y, width, real_width,		get_bfu_color(term, "dialog.text"),		widget_data->widget->info.text.align);	if (widget_data->widget->info.text.is_label) (*y)--;	/* If we scrolled and something was trimmed restore it */	if (saved && saved_pos) *saved_pos = saved;}static t_handler_event_statusdisplay_text(struct dialog_data *dlg_data, struct widget_data *widget_data){	struct window *win = dlg_data->win;	struct box box;	int scale, current, step;	int lines = widget_data->info.text.lines;	set_box(&box,		dlg_data->box.x + dlg_data->box.width - DIALOG_LEFT_BORDER - 1,		widget_data->box.y,		1,		widget_data->box.height);	if (!text_is_scrollable(widget_data) || box.height <= 0)		return EVENT_PROCESSED;	draw_box(win->term, &box, ' ', 0,		 get_bfu_color(win->term, "dialog.scrollbar"));	current = widget_data->info.text.current;	scale = (box.height + 1) * 100 / lines;	/* Scale the offset of @current */	step = (current + 1) * scale / 100;	int_bounds(&step, 0, widget_data->box.height - 1);	/* Scale the number of visible lines */	box.height = (box.height + 1) * scale / 100;	int_bounds(&box.height, 1, int_max(widget_data->box.height - step, 1));	/* Ensure we always step to the last position too */	if (lines - widget_data->box.height == current) {		step = widget_data->box.height - box.height;	}	box.y += step;#ifdef CONFIG_MOUSE	/* Save infos about selected scrollbar position and size.	 * We'll use it when handling mouse. */	widget_data->info.text.scroller_height = box.height;	widget_data->info.text.scroller_y = box.y;#endif	draw_box(win->term, &box, ' ', 0,		 get_bfu_color(win->term, "dialog.scrollbar-selected"));	/* Hope this is at least a bit reasonable. Set cursor	 * and window pointer to start of the first text line. */	set_cursor(win->term, widget_data->box.x, widget_data->box.y, 1);	set_window_ptr(win, widget_data->box.x, widget_data->box.y);	return EVENT_PROCESSED;}static voidformat_and_display_text(struct widget_data *widget_data,			struct dialog_data *dlg_data,			int current){	struct terminal *term = dlg_data->win->term;	int y = widget_data->box.y;	int height = dialog_max_height(term);	int lines = widget_data->info.text.lines;	assert(lines >= 0);	assert(widget_data->box.height >= 0);	int_bounds(&current, 0, lines - widget_data->box.height);	if (widget_data->info.text.current == current) return;	widget_data->info.text.current = current;	draw_box(term, &widget_data->box, ' ', 0,		 get_bfu_color(term, "dialog.generic"));	dlg_format_text(term, widget_data,			widget_data->box.x, &y, widget_data->box.width, NULL,			height);	display_text(dlg_data, widget_data);	redraw_from_window(dlg_data->win);}static t_handler_event_statuskbd_text(struct dialog_data *dlg_data, struct widget_data *widget_data){	int current = widget_data->info.text.current;	struct term_event *ev = dlg_data->term_event;	switch (kbd_action(KEYMAP_MENU, ev, NULL)) {		case ACT_MENU_UP:			current--;			break;		case ACT_MENU_DOWN:			current++;			break;		case ACT_MENU_PAGE_UP:			current -= widget_data->box.height;			break;		case ACT_MENU_PAGE_DOWN:			current += widget_data->box.height;			break;		case ACT_MENU_HOME:			current = 0;			break;		case ACT_MENU_END:			current = widget_data->info.text.lines;			break;		default:			return EVENT_NOT_PROCESSED;	}	format_and_display_text(widget_data, dlg_data, current);	return EVENT_PROCESSED;}static t_handler_event_statusmouse_text(struct dialog_data *dlg_data, struct widget_data *widget_data){#ifdef CONFIG_MOUSE	int border = DIALOG_LEFT_BORDER + DIALOG_LEFT_INNER_BORDER;	int current = widget_data->info.text.current;	int scroller_y = widget_data->info.text.scroller_y;	int scroller_height = widget_data->info.text.scroller_height;	int scroller_middle = scroller_y + scroller_height/2			      - widget_data->info.text.scroller_last_dir;	struct box scroller_box;	struct term_event *ev = dlg_data->term_event;	set_box(&scroller_box,		dlg_data->box.x + dlg_data->box.width - 1 - border,		widget_data->box.y,		DIALOG_LEFT_INNER_BORDER * 2 + 1,		widget_data->box.height);	/* One can scroll by clicking or rolling the wheel on the scrollbar	 * or one or two cells to its left or its right. */	if (!check_mouse_position(ev, &scroller_box))		return EVENT_NOT_PROCESSED;	switch (get_mouse_button(ev)) {	case B_LEFT:		/* Left click scrolls up or down by one step. */		if (ev->info.mouse.y <= scroller_middle)			current--;		else			current++;		break;	case B_RIGHT:		/* Right click scrolls up or down by more than one step.		 * Faster. */		if (ev->info.mouse.y <= scroller_middle)			current -= 5;		else			current += 5;		break;	case B_WHEEL_UP:		/* Mouse wheel up scrolls up. */		current--;		break;	case B_WHEEL_DOWN:		/* Mouse wheel up scrolls down. */		current++;		break;	default:		return EVENT_NOT_PROCESSED;	}	/* Save last direction used. */	if (widget_data->info.text.current < current)		widget_data->info.text.scroller_last_dir = 1;	else		widget_data->info.text.scroller_last_dir = -1;	format_and_display_text(widget_data, dlg_data, current);#endif /* CONFIG_MOUSE */	return EVENT_PROCESSED;}struct widget_ops text_ops = {	display_text,	NULL,	mouse_text,	kbd_text,	NULL,	NULL,};

⌨️ 快捷键说明

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